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 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
29namespace OpenSubdiv {
30namespace OPENSUBDIV_VERSION {
31
32namespace Vtr {
33namespace internal {
34
35//
36// The StackBuffer class is intended solely to take the place of VLAs (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 occasionally large.
41//
42// Note also that since the intent of this is to replace VLAs -- 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
49template <typename TYPE, unsigned int SIZE, bool POD_TYPE = false>
50class StackBuffer
51{
52public:
53 typedef unsigned int size_type;
54
55public:
56 // Constructors and destructor -- declared inline below:
57 StackBuffer();
58 StackBuffer(size_type size);
59 ~StackBuffer();
60
61public:
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
75private:
76 // Non-copyable:
77 StackBuffer(const StackBuffer<TYPE,SIZE,POD_TYPE> &) { }
78 StackBuffer& operator=(const StackBuffer<TYPE,SIZE,POD_TYPE> &) { return *this; }
79
80 void allocate(size_type capacity);
81 void deallocate();
82 void construct();
83 void destruct();
84
85private:
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//
100template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
101inline void
102StackBuffer<TYPE,SIZE,POD_TYPE>::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
113template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
114inline void
115StackBuffer<TYPE,SIZE,POD_TYPE>::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.
125// Compilers do not always optimize out the iteration here even when there is
126// no construction or destruction, so the POD_TYPE arguement can be used to
127// force this when/if it becomes an issue (and it has been in some cases).
128//
129template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
130inline void
131StackBuffer<TYPE,SIZE,POD_TYPE>::construct() {
132
133 for (size_type i = 0; i < _size; ++i) {
134 (void) new (&_data[i]) TYPE;
135 }
136}
137template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
138inline void
139StackBuffer<TYPE,SIZE,POD_TYPE>::destruct() {
140
141 for (size_type i = 0; i < _size; ++i) {
142 _data[i].~TYPE();
143 }
144}
145
146//
147// Inline constructors and destructor:
148//
149template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
150inline
151StackBuffer<TYPE,SIZE,POD_TYPE>::StackBuffer() :
152 _data(reinterpret_cast<TYPE*>(_staticData)),
153 _size(0),
154 _capacity(SIZE),
155 _dynamicData(0) {
156
157}
158
159template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
160inline
161StackBuffer<TYPE,SIZE,POD_TYPE>::StackBuffer(size_type size) :
162 _data(reinterpret_cast<TYPE*>(_staticData)),
163 _size(size),
164 _capacity(SIZE),
165 _dynamicData(0) {
166
167 if (size > SIZE) {
168 allocate(size);
169 }
170 if (!POD_TYPE) {
171 construct();
172 }
173}
174
175template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
176inline
177StackBuffer<TYPE,SIZE,POD_TYPE>::~StackBuffer() {
178
179 if (!POD_TYPE) {
180 destruct();
181 }
182 deallocate();
183}
184
185//
186// Inline sizing methods:
187//
188template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
189inline void
190StackBuffer<TYPE,SIZE,POD_TYPE>::Reserve(size_type capacity) {
191
192 if (capacity > _capacity) {
193 if (!POD_TYPE) {
194 destruct();
195 }
196 deallocate();
197 allocate(capacity);
198 }
199}
200
201template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
202inline void
203StackBuffer<TYPE,SIZE,POD_TYPE>::SetSize(size_type size)
204{
205 if (!POD_TYPE) {
206 destruct();
207 }
208 if (size == 0) {
209 deallocate();
210 } else if (size > _capacity) {
211 deallocate();
212 allocate(size);
213 }
214 _size = size;
215 if (!POD_TYPE) {
216 construct();
217 }
218}
219
220} // end namespace internal
221} // end namespace Vtr
222
223} // end namespace OPENSUBDIV_VERSION
224using namespace OPENSUBDIV_VERSION;
225} // end namespace OpenSubdiv
226
227#endif /* OPENSUBDIV3_VTR_STACK_BUFFER_H */