OpenSubdiv
Loading...
Searching...
No Matches
stackBuffer.h
Go to the documentation of this file.
1//
2// Copyright 2015 DreamWorks Animation LLC.
3//
4// Licensed under the terms set forth in the LICENSE.txt file available at
5// https://opensubdiv.org/license.
6//
7#ifndef OPENSUBDIV3_VTR_STACK_BUFFER_H
8#define OPENSUBDIV3_VTR_STACK_BUFFER_H
9
10#include "../version.h"
11
12namespace OpenSubdiv {
13namespace OPENSUBDIV_VERSION {
14
15namespace Vtr {
16namespace internal {
17
18//
19// The StackBuffer class is intended solely to take the place of VLAs (Variable
20// Length Arrays) which most compilers support, but are not strictly standard C++.
21// Portability concerns forces us to make use of either alloca() or some other
22// mechanism to create small arrays on the stack that are typically based on the
23// valence of a vertex -- small in general, but occasionally large.
24//
25// Note also that since the intent of this is to replace VLAs -- not general
26// std::vectors -- support for std::vector functionality is intentionally limited
27// and STL-like naming is avoided. Like a VLA there is no incremental growth.
28// Support for resizing is available to reuse an instance at the beginning of a
29// loop with a new size, but resizing in this case reinitializes all elements.
30//
31
32template <typename TYPE, unsigned int SIZE, bool POD_TYPE = false>
33class StackBuffer
34{
35public:
36 typedef unsigned int size_type;
37
38public:
39 // Constructors and destructor -- declared inline below:
40 StackBuffer();
41 StackBuffer(size_type size);
42 ~StackBuffer();
43
44public:
45 // Note the reliance on implicit casting so that it can be used similar to
46 // a VLA. This removes the need for operator[] as the resulting TYPE* will
47 // natively support []. (The presence of both TYPE* and operator[] also
48 // causes an ambiguous overloading error with 32-bit MSVC builds.)
49
50 operator TYPE const * () const { return _data; }
51 operator TYPE * () { return _data; }
52
53 size_type GetSize() const { return _size; }
54
55 void SetSize(size_type size);
56 void Reserve(size_type capacity);
57
58private:
59 // Non-copyable:
60 StackBuffer(const StackBuffer<TYPE,SIZE,POD_TYPE> &) { }
61 StackBuffer& operator=(const StackBuffer<TYPE,SIZE,POD_TYPE> &) { return *this; }
62
63 void allocate(size_type capacity);
64 void deallocate();
65 void construct();
66 void destruct();
67
68private:
69 TYPE * _data;
70 size_type _size;
71 size_type _capacity;
72
73 // Is alignment an issue here? The staticData arena will at least be double-word
74 // aligned within this struct, which meets current and most anticipated needs.
75 char _staticData[SIZE * sizeof(TYPE)];
76 char * _dynamicData;
77};
78
79
80//
81// Core allocation/deallocation methods:
82//
83template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
84inline void
85StackBuffer<TYPE,SIZE,POD_TYPE>::allocate(size_type capacity) {
86
87 // Again, is alignment an issue here? C++ spec says new will return pointer
88 // "suitably aligned" for conversion to pointers of other types, which implies
89 // at least an alignment of 16.
90 _dynamicData = static_cast<char*>(::operator new(capacity * sizeof(TYPE)));
91
92 _data = reinterpret_cast<TYPE*>(_dynamicData);
93 _capacity = capacity;
94}
95
96template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
97inline void
98StackBuffer<TYPE,SIZE,POD_TYPE>::deallocate() {
99
100 ::operator delete(_dynamicData);
101 _dynamicData = nullptr;
102
103 _data = reinterpret_cast<TYPE*>(_staticData);
104 _capacity = SIZE;
105}
106
107//
108// Explicit element-wise construction and destruction within allocated memory.
109// Compilers do not always optimize out the iteration here even when there is
110// no construction or destruction, so the POD_TYPE arguement can be used to
111// force this when/if it becomes an issue (and it has been in some cases).
112//
113template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
114inline void
115StackBuffer<TYPE,SIZE,POD_TYPE>::construct() {
116
117 for (size_type i = 0; i < _size; ++i) {
118 (void) new (&_data[i]) TYPE;
119 }
120}
121template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
122inline void
123StackBuffer<TYPE,SIZE,POD_TYPE>::destruct() {
124
125 for (size_type i = 0; i < _size; ++i) {
126 _data[i].~TYPE();
127 }
128}
129
130//
131// Inline constructors and destructor:
132//
133template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
134inline
135StackBuffer<TYPE,SIZE,POD_TYPE>::StackBuffer() :
136 _data(reinterpret_cast<TYPE*>(_staticData)),
137 _size(0),
138 _capacity(SIZE),
139 _dynamicData(nullptr) {
140
141}
142
143template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
144inline
145StackBuffer<TYPE,SIZE,POD_TYPE>::StackBuffer(size_type size) :
146 _data(reinterpret_cast<TYPE*>(_staticData)),
147 _size(size),
148 _capacity(SIZE),
149 _dynamicData(nullptr) {
150
151 if (size > SIZE) {
152 allocate(size);
153 }
154 if (!POD_TYPE) {
155 construct();
156 }
157}
158
159template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
160inline
161StackBuffer<TYPE,SIZE,POD_TYPE>::~StackBuffer() {
162
163 if (!POD_TYPE) {
164 destruct();
165 }
166 deallocate();
167}
168
169//
170// Inline sizing methods:
171//
172template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
173inline void
174StackBuffer<TYPE,SIZE,POD_TYPE>::Reserve(size_type capacity) {
175
176 if (capacity > _capacity) {
177 if (!POD_TYPE) {
178 destruct();
179 }
180 deallocate();
181 allocate(capacity);
182 }
183}
184
185template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
186inline void
187StackBuffer<TYPE,SIZE,POD_TYPE>::SetSize(size_type size)
188{
189 if (!POD_TYPE) {
190 destruct();
191 }
192 if (size == 0) {
193 deallocate();
194 } else if (size > _capacity) {
195 deallocate();
196 allocate(size);
197 }
198 _size = size;
199 if (!POD_TYPE) {
200 construct();
201 }
202}
203
204} // end namespace internal
205} // end namespace Vtr
206
207} // end namespace OPENSUBDIV_VERSION
208using namespace OPENSUBDIV_VERSION;
209} // end namespace OpenSubdiv
210
211#endif /* OPENSUBDIV3_VTR_STACK_BUFFER_H */