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>
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> &) { 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
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
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
174 
175  destruct();
176  deallocate();
177 }
178 
179 //
180 // Inline sizing methods:
181 //
182 template <typename TYPE, unsigned int SIZE>
183 inline void
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
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 */