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
102 _data = reinterpret_cast<TYPE*>(_staticData);
103 _capacity = SIZE;
104}
105
106//
107// Explicit element-wise construction and destruction within allocated memory.
108// Compilers do not always optimize out the iteration here even when there is
109// no construction or destruction, so the POD_TYPE arguement can be used to
110// force this when/if it becomes an issue (and it has been in some cases).
111//
112template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
113inline void
114StackBuffer<TYPE,SIZE,POD_TYPE>::construct() {
115
116 for (size_type i = 0; i < _size; ++i) {
117 (void) new (&_data[i]) TYPE;
118 }
119}
120template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
121inline void
122StackBuffer<TYPE,SIZE,POD_TYPE>::destruct() {
123
124 for (size_type i = 0; i < _size; ++i) {
125 _data[i].~TYPE();
126 }
127}
128
129//
130// Inline constructors and destructor:
131//
132template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
133inline
134StackBuffer<TYPE,SIZE,POD_TYPE>::StackBuffer() :
135 _data(reinterpret_cast<TYPE*>(_staticData)),
136 _size(0),
137 _capacity(SIZE),
138 _dynamicData(0) {
139
140}
141
142template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
143inline
144StackBuffer<TYPE,SIZE,POD_TYPE>::StackBuffer(size_type size) :
145 _data(reinterpret_cast<TYPE*>(_staticData)),
146 _size(size),
147 _capacity(SIZE),
148 _dynamicData(0) {
149
150 if (size > SIZE) {
151 allocate(size);
152 }
153 if (!POD_TYPE) {
154 construct();
155 }
156}
157
158template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
159inline
160StackBuffer<TYPE,SIZE,POD_TYPE>::~StackBuffer() {
161
162 if (!POD_TYPE) {
163 destruct();
164 }
165 deallocate();
166}
167
168//
169// Inline sizing methods:
170//
171template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
172inline void
173StackBuffer<TYPE,SIZE,POD_TYPE>::Reserve(size_type capacity) {
174
175 if (capacity > _capacity) {
176 if (!POD_TYPE) {
177 destruct();
178 }
179 deallocate();
180 allocate(capacity);
181 }
182}
183
184template <typename TYPE, unsigned int SIZE, bool POD_TYPE>
185inline void
186StackBuffer<TYPE,SIZE,POD_TYPE>::SetSize(size_type size)
187{
188 if (!POD_TYPE) {
189 destruct();
190 }
191 if (size == 0) {
192 deallocate();
193 } else if (size > _capacity) {
194 deallocate();
195 allocate(size);
196 }
197 _size = size;
198 if (!POD_TYPE) {
199 construct();
200 }
201}
202
203} // end namespace internal
204} // end namespace Vtr
205
206} // end namespace OPENSUBDIV_VERSION
207using namespace OPENSUBDIV_VERSION;
208} // end namespace OpenSubdiv
209
210#endif /* OPENSUBDIV3_VTR_STACK_BUFFER_H */