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