ATLAS Offline Software
Loading...
Searching...
No Matches
pointer_list.icc
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration
3*/
4
5// $Id$
6/**
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.
11 */
12
13
14#include <cassert>
15#include <algorithm>
16
17
18namespace CxxUtils {
19
20
21/**
22 * @brief Size in bytes of a block holding @c nelt elements.
23 * (excluding the end-pointer).
24 * @param nelt Number of elements.
25 */
26inline
27size_t pointer_list_base::list_block::size (size_t nelt)
28{
29 return sizeof(list_block) + nelt * sizeof(value_type);
30}
31
32
33//****************************************************************************
34
35
36/**
37 * @brief Allocate a new block.
38 */
39inline
40pointer_list_base::list_block*
41pointer_list_base::allocator::allocate()
42{
43 // Get a new chunk if needed.
44 if (m_nthis == m_nblock)
45 refill();
46 return &m_chunks->m_blocks[(m_nthis++) * (m_nelt+1)];
47}
48
49
50/**
51 * @brief Return the number of pointers per block (excluding the end-pointer).
52 */
53inline
54size_t
55pointer_list_base::allocator::nelt() const
56{
57 return m_nelt;
58}
59
60
61/**
62 * @brief Current number of allocated chunks.
63 */
64inline
65size_t
66pointer_list_base::allocator::nchunks() const
67{
68 return m_nchunks;
69}
70
71
72/**
73 * @brief Test to see if we're looking at the end of a block.
74 * @param p The pointer to test.
75 */
76inline
77bool
78pointer_list_base::allocator::at_end (const void* p) const
79{
80 return (reinterpret_cast<unsigned long>(p) & m_end_mask) == m_end_offs;
81}
82
83
84/**
85 * @brief Constructor.
86 * @param nblock Number of blocks to allocate per chunk.
87 */
88template <size_t NELT>
89pointer_list<NELT>::allocator::allocator (size_t nblock /*= 100*/)
90 : pointer_list_base::allocator (NELT, nblock, END_MASK, END_OFFS)
91{
92}
93
94
95/**
96 * @brief Test to see if we're looking at the end of a block.
97 * @param p The pointer to test.
98 */
99template <size_t NELT>
100inline
101bool
102pointer_list<NELT>::allocator::at_end_static (const void* p)
103{
104 return (reinterpret_cast<unsigned long>(p) & END_MASK) == END_OFFS;
105}
106
107
108//****************************************************************************
109
110
111/**
112 * @brief Equality comparison.
113 */
114template <size_t NELT>
115inline
116bool
117pointer_list<NELT>::iterator::operator== (const iterator& other) const
118{
119 return m_p == other.m_p;
120}
121
122
123/**
124 * @brief Inequality comparison.
125 */
126template <size_t NELT>
127inline
128bool
129pointer_list<NELT>::iterator::operator!= (const iterator& other) const
130{
131 return m_p != other.m_p;
132}
133
134
135/**
136 * @brief Dereference.
137 */
138template <size_t NELT>
139inline
140typename pointer_list<NELT>::iterator::reference
141pointer_list<NELT>::iterator::operator*()
142{
143 return *m_p;
144}
145
146
147/**
148 * @brief Advance (pre-increment).
149 */
150template <size_t NELT>
151inline
152typename pointer_list<NELT>::iterator&
153pointer_list<NELT>::iterator::operator++()
154{
155 // Move forward.
156 ++m_p;
157
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);
163 if (next)
164 m_p = &next->m_data[0];
165 }
166 return *this;
167}
168
169
170/**
171 * @brief Advance (post-increment).
172 */
173template <size_t NELT>
174inline
175typename pointer_list<NELT>::iterator
176pointer_list<NELT>::iterator::operator++(int)
177{
178 iterator ret = *this;
179 ++*this;
180 return ret;
181}
182
183
184/**
185 * @brief Constructor.
186 * @param p A value within a @c pointer_list.
187 */
188template <size_t NELT>
189inline
190pointer_list<NELT>::iterator::iterator (value_type* p)
191 : m_p (p)
192{
193}
194
195
196//****************************************************************************
197
198
199/**
200 * @brief Constructor.
201 * @param pool The allocator for this container.
202 */
203inline
204pointer_list_base::pointer_list_base (pool_type& pool)
205 : m_head (0),
206 m_insert (0),
207 m_size (0),
208 m_pool (pool)
209{
210}
211
212
213/**
214 * @brief Add a new element to the end of the container. O(1)
215 */
216inline
217void pointer_list_base::push_back (value_type p)
218{
219 // If the container is empty, allocate the first block.
220 if (!m_head)
221 firstblock();
222
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))
225 nextblock();
226
227 // Add the value to the list.
228 *m_insert = p;
229 ++m_insert;
230 ++m_size;
231
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;
236 if (next)
237 m_insert = reinterpret_cast<value_type*> (next);
238 }
239}
240
241
242/**
243 * @brief The current size of the container. O(1)
244 */
245inline
246size_t pointer_list_base::size() const
247{
248 return m_size;
249}
250
251
252/**
253 * @brief Test to see if the container is empty.
254 */
255inline
256bool pointer_list_base::empty() const
257{
258 return m_size == 0;
259}
260
261
262/**
263 * @brief Constructor.
264 * @param pool The allocator for this container.
265 */
266template <size_t NELT>
267inline
268pointer_list<NELT>::pointer_list (pool_type& pool)
269 : pointer_list_base (pool)
270{
271}
272
273
274/**
275 * @brief Iterator at the beginning of the container.
276 */
277template <size_t NELT>
278inline
279typename pointer_list<NELT>::iterator pointer_list<NELT>::begin()
280{
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);
284}
285
286
287/**
288 * @brief Iterator at the end of the container.
289 */
290template <size_t NELT>
291inline
292typename pointer_list<NELT>::iterator pointer_list<NELT>::end()
293{
294 // Point at the current insertion point.
295 // (This will be null if the container's empty.)
296 return iterator (m_insert);
297}
298
299
300/**
301 * @brief Erase one element. O(n)
302 * @param it The element to erase.
303 */
304template <size_t NELT>
305void pointer_list<NELT>::erase (iterator it)
306{
307 // We just copy the elements back by one.
308 iterator next = it;
309 ++next;
310 next = std::copy (next, end(), it);
311
312 // New insertion point is where the copy stopped.
313 m_insert = next.m_p;
314
315 // One less element.
316 --m_size;
317}
318
319
320} // namespace CxxXUtils