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.
27size_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.
40pointer_list_base::list_block*
41pointer_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).
55pointer_list_base::allocator::nelt() const
62 * @brief Current number of allocated chunks.
66pointer_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.
78pointer_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.
89pointer_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.
102pointer_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.
114template <size_t NELT>
117pointer_list<NELT>::iterator::operator== (const iterator& other) const
119 return m_p == other.m_p;
124 * @brief Inequality comparison.
126template <size_t NELT>
129pointer_list<NELT>::iterator::operator!= (const iterator& other) const
131 return m_p != other.m_p;
136 * @brief Dereference.
138template <size_t NELT>
140typename pointer_list<NELT>::iterator::reference
141pointer_list<NELT>::iterator::operator*()
148 * @brief Advance (pre-increment).
150template <size_t NELT>
152typename pointer_list<NELT>::iterator&
153pointer_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).
173template <size_t NELT>
175typename pointer_list<NELT>::iterator
176pointer_list<NELT>::iterator::operator++(int)
178 iterator ret = *this;
185 * @brief Constructor.
186 * @param p A value within a @c pointer_list.
188template <size_t NELT>
190pointer_list<NELT>::iterator::iterator (value_type* p)
196//****************************************************************************
200 * @brief Constructor.
201 * @param pool The allocator for this container.
204pointer_list_base::pointer_list_base (pool_type& pool)
214 * @brief Add a new element to the end of the container. O(1)
217void 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)
246size_t pointer_list_base::size() const
253 * @brief Test to see if the container is empty.
256bool pointer_list_base::empty() const
263 * @brief Constructor.
264 * @param pool The allocator for this container.
266template <size_t NELT>
268pointer_list<NELT>::pointer_list (pool_type& pool)
269 : pointer_list_base (pool)
275 * @brief Iterator at the beginning of the container.
277template <size_t NELT>
279typename 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.
290template <size_t NELT>
292typename 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.
304template <size_t NELT>
305void 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