2 Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
7 * @file CxxUtils/pointer_list.icc
8 * @author scott snyder <snyder@bnl.gov>
9 * @date Oct, 2009, from earlier code.
10 * @brief A fast way to store a variable-sized collection of pointers.
22 * @brief Size in bytes of a block holding @c nelt elements.
23 * (excluding the end-pointer).
24 * @param nelt Number of elements.
27 size_t pointer_list_base::list_block::size (size_t nelt)
29 return sizeof(list_block) + nelt * sizeof(value_type);
33 //****************************************************************************
37 * @brief Allocate a new block.
40 pointer_list_base::list_block*
41 pointer_list_base::allocator::allocate()
43 // Get a new chunk if needed.
44 if (m_nthis == m_nblock)
46 return &m_chunks->m_blocks[(m_nthis++) * (m_nelt+1)];
51 * @brief Return the number of pointers per block (excluding the end-pointer).
55 pointer_list_base::allocator::nelt() const
62 * @brief Current number of allocated chunks.
66 pointer_list_base::allocator::nchunks() const
73 * @brief Test to see if we're looking at the end of a block.
74 * @param p The pointer to test.
78 pointer_list_base::allocator::at_end (const void* p) const
80 return (reinterpret_cast<unsigned long>(p) & m_end_mask) == m_end_offs;
86 * @param nblock Number of blocks to allocate per chunk.
88 template <size_t NELT>
89 pointer_list<NELT>::allocator::allocator (size_t nblock /*= 100*/)
90 : pointer_list_base::allocator (NELT, nblock, END_MASK, END_OFFS)
96 * @brief Test to see if we're looking at the end of a block.
97 * @param p The pointer to test.
99 template <size_t NELT>
102 pointer_list<NELT>::allocator::at_end_static (const void* p)
104 return (reinterpret_cast<unsigned long>(p) & END_MASK) == END_OFFS;
108 //****************************************************************************
112 * @brief Equality comparison.
114 template <size_t NELT>
117 pointer_list<NELT>::iterator::operator== (const iterator& other) const
119 return m_p == other.m_p;
124 * @brief Inequality comparison.
126 template <size_t NELT>
129 pointer_list<NELT>::iterator::operator!= (const iterator& other) const
131 return m_p != other.m_p;
136 * @brief Dereference.
138 template <size_t NELT>
140 typename pointer_list<NELT>::iterator::reference
141 pointer_list<NELT>::iterator::operator*()
148 * @brief Advance (pre-increment).
150 template <size_t NELT>
152 typename pointer_list<NELT>::iterator&
153 pointer_list<NELT>::iterator::operator++()
158 // If we've hit the end, chain to the next block,
159 // if there is one. Otherwise, stay at the end;
160 // that will be where the end iterator points.
161 if (pointer_list::allocator::at_end_static (m_p)) {
162 list_block* next = reinterpret_cast<list_block*> (*m_p);
164 m_p = &next->m_data[0];
171 * @brief Advance (post-increment).
173 template <size_t NELT>
175 typename pointer_list<NELT>::iterator
176 pointer_list<NELT>::iterator::operator++(int)
178 iterator ret = *this;
185 * @brief Constructor.
186 * @param p A value within a @c pointer_list.
188 template <size_t NELT>
190 pointer_list<NELT>::iterator::iterator (value_type* p)
196 //****************************************************************************
200 * @brief Constructor.
201 * @param pool The allocator for this container.
204 pointer_list_base::pointer_list_base (pool_type& pool)
214 * @brief Add a new element to the end of the container. O(1)
217 void pointer_list_base::push_back (value_type p)
219 // If the container is empty, allocate the first block.
223 // Otherwise, if we're at the end of the current block, allocate a new one.
224 else if (m_pool.at_end (m_insert))
227 // Add the value to the list.
232 // If we're at the end of this block, and a following block exists,
233 // move to the following block.
234 if (m_pool.at_end (m_insert)) {
235 value_type next = *m_insert;
237 m_insert = reinterpret_cast<value_type*> (next);
243 * @brief The current size of the container. O(1)
246 size_t pointer_list_base::size() const
253 * @brief Test to see if the container is empty.
256 bool pointer_list_base::empty() const
263 * @brief Constructor.
264 * @param pool The allocator for this container.
266 template <size_t NELT>
268 pointer_list<NELT>::pointer_list (pool_type& pool)
269 : pointer_list_base (pool)
275 * @brief Iterator at the beginning of the container.
277 template <size_t NELT>
279 typename pointer_list<NELT>::iterator pointer_list<NELT>::begin()
281 // Start by pointing at the first element
282 // (or null, if the container's empty).
283 return iterator (m_head ? &m_head->m_data[0] : 0);
288 * @brief Iterator at the end of the container.
290 template <size_t NELT>
292 typename pointer_list<NELT>::iterator pointer_list<NELT>::end()
294 // Point at the current insertion point.
295 // (This will be null if the container's empty.)
296 return iterator (m_insert);
301 * @brief Erase one element. O(n)
302 * @param it The element to erase.
304 template <size_t NELT>
305 void pointer_list<NELT>::erase (iterator it)
307 // We just copy the elements back by one.
310 next = std::copy (next, end(), it);
312 // New insertion point is where the copy stopped.
320 } // namespace CxxXUtils