All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends
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 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 
49 template <typename TYPE, unsigned int SIZE, bool POD_TYPE = false>
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:
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 
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, bool POD_TYPE>
101 inline void
102 StackBuffer<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 
113 template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
114 inline void
115 StackBuffer<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 //
129 template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
130 inline void
131 StackBuffer<TYPE,SIZE,POD_TYPE>::construct() {
132 
133  for (size_type i = 0; i < _size; ++i) {
134  (void) new (&_data[i]) TYPE;
135  }
136 }
137 template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
138 inline void
139 StackBuffer<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 //
149 template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
150 inline
152  _data(reinterpret_cast<TYPE*>(_staticData)),
153  _size(0),
154  _capacity(SIZE),
155  _dynamicData(0) {
156 
157 }
158 
159 template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
160 inline
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 
175 template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
176 inline
178 
179  if (!POD_TYPE) {
180  destruct();
181  }
182  deallocate();
183 }
184 
185 //
186 // Inline sizing methods:
187 //
188 template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
189 inline void
191 
192  if (capacity > _capacity) {
193  if (!POD_TYPE) {
194  destruct();
195  }
196  deallocate();
197  allocate(capacity);
198  }
199 }
200 
201 template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
202 inline void
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
224 using namespace OPENSUBDIV_VERSION;
225 } // end namespace OpenSubdiv
226 
227 #endif /* OPENSUBDIV3_VTR_STACK_BUFFER_H */