1 #ifndef _DEAPPENDLIST_HPP
2 #define _DEAPPENDLIST_HPP
3 /*-------------------------------------------------------------------------
4 * drawElements C++ Base Library
5 * -----------------------------
7 * Copyright 2015 The Android Open Source Project
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
23 * \brief Fast ordered append-only container
24 *//*--------------------------------------------------------------------*/
35 /*--------------------------------------------------------------------*//*!
36 * \brief Fast ordered append-only container
38 * AppendList provides data structure for recording ordered list of elements
39 * quickly, while still providing good sequential read access speed.
40 * It is good for example logging.
42 * AppendList allocates memory in blocks of blockSize elements. Choosing
43 * too small blockSize will affect performance.
45 * Elements can be appended from multiple threads simultaneously but if
46 * current block runs out, allocation of next block will happen in a single
47 * thread and block others from inserting further elements until completed.
48 * For that reason shared AppendList should not be used if there is a lot
49 * of contention and instead per-thread AppendList's are recommended.
50 *//*--------------------------------------------------------------------*/
51 template<typename ElementType>
55 AppendList (size_t blockSize);
58 void append (const ElementType& value);
60 size_t size (void) const { return m_numElements; }
63 AppendList (const AppendList<ElementType>&);
64 AppendList<ElementType>& operator= (const AppendList<ElementType>&);
68 const size_t blockNdx;
69 ElementType* elements;
72 Block (size_t blockNdx_, size_t size)
73 : blockNdx (blockNdx_)
74 , elements (reinterpret_cast<ElementType*>(deAlignedMalloc(sizeof(ElementType)*size,
75 deAlign32((deUint32)alignOf<ElementType>(), (deUint32)sizeof(void*)))))
82 deAlignedFree(reinterpret_cast<void*>(elements));
86 const size_t m_blockSize;
87 volatile size_t m_numElements;
89 Block* volatile m_last;
92 template<typename CompatibleType>
96 Iterator (Block* curBlock_, size_t blockSize_, size_t slotNdx_)
97 : m_curBlock (curBlock_)
98 , m_blockSize (blockSize_)
99 , m_slotNdx (slotNdx_)
102 bool operator!= (const Iterator<CompatibleType>& other) const
104 return m_curBlock != other.m_curBlock || m_slotNdx != other.m_slotNdx;
106 bool operator== (const Iterator<CompatibleType>& other) const
108 return m_curBlock == other.m_curBlock && m_slotNdx == other.m_slotNdx;
111 Iterator<CompatibleType>& operator++ (void)
115 if (m_slotNdx == m_blockSize)
118 m_curBlock = m_curBlock->next;
124 Iterator<CompatibleType> operator++ (int) const
126 Iterator<CompatibleType> copy(*this);
130 CompatibleType& operator* (void) const
132 return m_curBlock->elements[m_slotNdx];
135 operator Iterator<const CompatibleType> (void) const
137 return Iterator<const CompatibleType>(m_curBlock, m_blockSize, m_slotNdx);
146 typedef Iterator<const ElementType> const_iterator;
147 typedef Iterator<ElementType> iterator;
149 const_iterator begin (void) const;
150 iterator begin (void);
152 const_iterator end (void) const;
156 template<typename ElementType>
157 AppendList<ElementType>::AppendList (size_t blockSize)
158 : m_blockSize (blockSize)
160 , m_first (new Block(0, blockSize))
165 template<typename ElementType>
166 AppendList<ElementType>::~AppendList (void)
168 size_t elementNdx = 0;
169 Block* curBlock = m_first;
173 Block* const delBlock = curBlock;
175 curBlock = delBlock->next;
177 // Call destructor for allocated elements
178 for (; elementNdx < min(m_numElements, delBlock->blockNdx*m_blockSize); ++elementNdx)
179 delBlock->elements[elementNdx%m_blockSize].~ElementType();
185 template<typename ElementType>
186 void AppendList<ElementType>::append (const ElementType& value)
188 // Fetch curBlock first before allocating slot. Otherwise m_last might get updated before
189 // this thread gets chance of reading it, leading to curBlock->blockNdx > blockNdx.
190 Block* curBlock = m_last;
192 deMemoryReadWriteFence();
195 const size_t elementNdx = deAtomicIncrementUSize(&m_numElements) - 1;
196 const size_t blockNdx = elementNdx / m_blockSize;
197 const size_t slotNdx = elementNdx - (blockNdx * m_blockSize);
199 while (curBlock->blockNdx != blockNdx)
202 curBlock = curBlock->next;
205 // Other thread(s) are currently allocating additional block(s)
210 // Did we allocate last slot? If so, add a new block
211 if (slotNdx+1 == m_blockSize)
213 Block* const newBlock = new Block(blockNdx+1, m_blockSize);
215 deMemoryReadWriteFence();
217 // At this point if any other thread is trying to allocate more blocks
218 // they are being blocked by curBlock->next being null. This guarantees
219 // that this thread has exclusive modify access to m_last.
221 deMemoryReadWriteFence();
223 // At this point other threads might have skipped to newBlock, but we
224 // still have exclusive modify access to curBlock->next.
225 curBlock->next = newBlock;
226 deMemoryReadWriteFence();
229 new (&curBlock->elements[slotNdx]) ElementType(value);
233 template<typename ElementType>
234 typename AppendList<ElementType>::const_iterator AppendList<ElementType>::begin (void) const
236 return const_iterator(m_first, m_blockSize, 0);
239 template<typename ElementType>
240 typename AppendList<ElementType>::iterator AppendList<ElementType>::begin (void)
242 return iterator(m_first, m_blockSize, 0);
245 template<typename ElementType>
246 typename AppendList<ElementType>::const_iterator AppendList<ElementType>::end (void) const
248 return const_iterator(m_last, m_blockSize, m_numElements%m_blockSize);
251 template<typename ElementType>
252 typename AppendList<ElementType>::iterator AppendList<ElementType>::end (void)
254 return iterator(m_last, m_blockSize, m_numElements%m_blockSize);
257 void AppendList_selfTest (void);
261 #endif // _DEAPPENDLIST_HPP