ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
Loading...
Searching...
No Matches
NumeratedContainer.hpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2015-2022 The ESPResSo project
3 *
4 * This file is part of ESPResSo.
5 *
6 * ESPResSo is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * ESPResSo is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#pragma once
21
22/** @file
23 * Keep an enumerated list of T objects, managed by the class.
24 */
25
26#include <cassert>
27#include <cstddef>
28#include <set>
29#include <unordered_map>
30
31namespace Utils {
32
33/**
34 * @brief Container for objects that are identified by a numeric id.
35 *
36 * This class implements a container that holds T instances and references
37 * them by an integral index. New elements get the lowest free index
38 * and indexes are reused. The Container keeps a copy of the objects added.
39 */
40template <class T, typename index_type = int> class NumeratedContainer {
41public:
42 using iterator = std::unordered_map<index_type, T>::iterator;
43 using const_iterator = std::unordered_map<index_type, T>::const_iterator;
44 using value_type = std::unordered_map<index_type, T>::value_type;
45
47 m_free_indices.insert(0);
48 m_free_indices.insert(1);
49 }
50
51 /**
52 * @brief Construct from list of key-value pairs.
53 * The keys have to be unique.
54 */
55 explicit NumeratedContainer(std::initializer_list<value_type> l)
57 for (auto const &e : l) {
58 m_container[e.first] = e.second;
59 /* Remove the index from the index set if it exists. */
60 if (auto it = m_free_indices.find(e.first); it != m_free_indices.end()) {
61 m_free_indices.erase(it);
62 }
63 }
64
65 /* Refill the index set */
66 for (index_type it(0); m_free_indices.size() < 2; ++it) {
67 if (m_container.find(it) == m_container.end()) {
68 m_free_indices.insert(it);
69 }
70 }
71 }
72
73 /**
74 * @brief Copy c into the container.
75 *
76 * Assign a free id to c and copy it into the container.
77 *
78 * @param c The object to add.
79 */
80 index_type add(const T &c) {
81 const index_type ind = get_index();
82 m_container[ind] = c;
83 return ind;
84 }
85
86 /** @overload */
87 index_type add(T &&c) {
88 const index_type ind = get_index();
89 m_container[ind] = std::move(c);
90 return ind;
91 }
92
93 /**
94 * @brief Remove element from container
95 *
96 * Remove element i and add i to the free
97 * indices.
98 *
99 * @param i The object to remove.
100 */
102 /* Check that the object actually exists */
103 assert(m_container.find(i) != m_container.end());
104
105 m_container.erase(i);
106 m_free_indices.insert(i);
107 }
108
109 /**
110 * @brief Get element from container
111 *
112 * @param i The object to get.
113 * @return Reference to the object with id i.
114 */
115 T &operator[](index_type i) { return m_container.at(i); }
116
117 /**
118 * @brief Get element from container
119 *
120 * @param i The object to get.
121 * @return Reference to the object with id i.
122 */
123 const T &operator[](index_type i) const { return m_container.at(i); }
124
125 /**
126 * @brief Get iterator to beginning of the container.
127 */
128 iterator begin() { return m_container.begin(); }
129
130 /**
131 * @brief Get a const iterator to beginning of the container.
132 */
133 const_iterator begin() const { return m_container.begin(); }
134
135 /**
136 * @brief Get an iterator to end of the container.
137 */
138 iterator end() { return m_container.end(); }
139
140 /**
141 * @brief Get a const iterator to end of the container.
142 */
143 const_iterator end() const { return m_container.end(); }
144
145 /**
146 * @brief find object by id.
147 *
148 * @param id id of the object to find.
149 * @return Iterator to the object if found or end().
150 */
151 iterator find(int id) { return m_container.find(id); }
152
153 /**
154 * @brief find object by id.
155 *
156 * @param id id of the object to find.
157 * @return Iterator to the object if found or end().
158 */
159 const_iterator find(int id) const { return m_container.find(id); }
160
161 std::size_t size() const { return m_container.size(); }
162
163private:
164 /** Data storage */
165 std::unordered_map<index_type, T> m_container;
166 /** Set for free index bookkeeping */
167 std::set<index_type> m_free_indices;
168
169 /**
170 * @brief Get the next free index.
171 *
172 * This function gets the lowest free index by
173 * popping the first element from the ordered set
174 * of free indices.
175 * If there is only 1 or less elements in the free
176 * index set, we reused all indices that were ever
177 * freed and we add a new one at the end of the set.
178 *
179 * @return Free index.
180 */
181 index_type get_index() {
182 /* Get lowest free index */
183 /* If we don't have a free index, sth went wrong. */
184 assert(!m_free_indices.empty());
185 const index_type index = *m_free_indices.begin();
186 /* and remove it from the list */
187 m_free_indices.erase(index);
188
189 /* If there is only on left, it is the highest ever seen, so we can safely
190 * add +1 */
191 if (m_free_indices.size() == 1) {
192 m_free_indices.insert(*(--m_free_indices.end()) + 1);
193 }
194
195 return index;
196 }
197};
198} // namespace Utils
Container for objects that are identified by a numeric id.
std::unordered_map< index_type, T >::iterator iterator
std::unordered_map< index_type, T >::const_iterator const_iterator
const_iterator find(int id) const
find object by id.
const T & operator[](index_type i) const
Get element from container.
std::unordered_map< index_type, T >::value_type value_type
iterator find(int id)
find object by id.
index_type add(const T &c)
Copy c into the container.
const_iterator begin() const
Get a const iterator to beginning of the container.
void remove(index_type i)
Remove element from container.
iterator end()
Get an iterator to end of the container.
const_iterator end() const
Get a const iterator to end of the container.
index_type add(T &&c)
This is an overloaded member function, provided for convenience. It differs from the above function o...
iterator begin()
Get iterator to beginning of the container.
NumeratedContainer(std::initializer_list< value_type > l)
Construct from list of key-value pairs.
T & operator[](index_type i)
Get element from container.
cudaStream_t stream[1]
CUDA streams for parallel computing on CPU and GPU.