Loading [MathJax]/extensions/TeX/AMSmath.js
ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages Concepts
BondList.hpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2020-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#ifndef ESPRESSO_BONDLIST_HPP
20#define ESPRESSO_BONDLIST_HPP
21
23
24#include <boost/container/vector.hpp>
25#include <boost/iterator/iterator_facade.hpp>
26#include <boost/serialization/access.hpp>
27#include <boost/serialization/array.hpp>
28#include <boost/version.hpp>
29
30#include <algorithm>
31#include <cassert>
32#include <cstddef>
33#include <memory>
34#include <span>
35#include <type_traits>
36
37/**
38 * @brief Immutable view on a bond.
39 *
40 * The bond id and ids of the partner particles
41 * of a bond can be inspected (but not changed)
42 * via this view.
43 */
44class BondView {
45 /* Bond id */
46 int m_id = -1;
47 std::span<const int> m_partners;
48
49public:
50 BondView() = default;
51 BondView(int id, std::span<const int> partners)
52 : m_id(id), m_partners(partners) {}
53
54 int bond_id() const { return m_id; }
55 auto const &partner_ids() const { return m_partners; }
56
57 bool operator==(BondView const &rhs) const {
58 return m_id == rhs.m_id and std::ranges::equal(m_partners, rhs.m_partners);
59 }
60
61 bool operator!=(BondView const &rhs) const { return not(*this == rhs); }
62};
63
64/**
65 * @brief Bond storage.
66 *
67 * This holds the bonds of a particle.
68 *
69 * Implementation notes:
70 * Internally the bond list is represented as a sequence of
71 * integers. For each bond, first the ids of the bond partners
72 * are stored (which are positive numbers), then the negative
73 * of the value of the id of the bond plus one (which also is positive) is
74 * stored. This way we can use the sign bit of the int as a delimiter,
75 * every time a negative number is encountered one bond ends, and
76 * a new one starts. This mechanism allows us to efficiently store
77 * bonds of different numbers of partners in contiguous memory.
78 *
79 * This is hidden from the client by providing access to the
80 * bonds only thru iterators that restore the semantic meanings
81 * of the entries, and know how to proceed to the next bond.
82 *
83 */
84class BondList {
85public:
87
88private:
89 using storage_iterator = storage_type::const_iterator;
90
91 /**
92 * @brief Find the end of bond.
93 *
94 * @param it Valid iterator into the underlying storage.
95 * @return iterator pointing to the last element of the bond.
96 */
97 static storage_iterator find_end(storage_iterator it) {
98 while (*it >= 0) {
99 ++it;
100 }
101 return it;
102 }
103
104 storage_type m_storage;
105
106 friend boost::serialization::access;
107 template <class Archive> void serialize(Archive &ar, long int /* version */) {
108 if (Archive::is_loading::value) {
109 std::size_t size{};
110 ar & size;
111 m_storage.resize(size);
112 }
113
114 if (Archive::is_saving::value) {
115 auto size = m_storage.size();
116 ar & size;
117 }
118
119 ar &boost::serialization::make_array(m_storage.data(), m_storage.size());
120 }
121
122public:
124 : public boost::iterator_facade<Iterator, BondView,
125 boost::forward_traversal_tag, BondView> {
126 public:
127 explicit Iterator(storage_iterator it) : m_it(it) {}
128
129 private:
130 /** Iterator into the bond list */
131 storage_iterator m_it;
132
133 friend BondList;
134 friend boost::iterator_core_access;
135 void increment() { m_it = std::next(find_end(m_it)); }
136 bool equal(Iterator const &other) const { return this->m_it == other.m_it; }
137 BondView dereference() const {
138 auto const id_pos = find_end(m_it);
139 auto const partners_begin = m_it;
140 auto const partners_end = id_pos;
141 auto const dist = std::distance(partners_begin, partners_end);
142 return {-(*id_pos) - 1, std::span(std::addressof(*partners_begin),
143 static_cast<size_type>(dist))};
144 }
145 };
146
147public:
149 using reference = std::add_lvalue_reference_t<BondView>;
150 using const_reference = std::add_const_t<reference>;
151 using size_type = std::size_t;
152 using difference_type = std::ptrdiff_t;
155
156 BondList() = default;
157 BondList(BondList const &) = default;
158 BondList(BondList &&) = default;
160 if (this != std::addressof(rhs)) {
161 m_storage = rhs.m_storage;
162 }
163
164 return *this;
165 }
166 // NOLINTNEXTLINE(bugprone-exception-escape)
167 BondList &operator=(BondList &&rhs) noexcept {
168 if (this != std::addressof(rhs)) {
169 std::swap(m_storage, rhs.m_storage);
170 }
171
172 return *this;
173 }
174
175 /**
176 * @brief Iterator to the beginning of the range of bonds in the list.
177 */
178 const_iterator begin() const { return Iterator{m_storage.begin()}; }
179 /**
180 * @brief Iterator past the end of the range of bonds in the list.
181 */
182 const_iterator end() const { return Iterator{m_storage.end()}; }
183
184 /**
185 * @brief Add a bond to the list.
186 *
187 * @param bond Bond to add.
188 */
189 void insert(BondView const &bond) {
190 std::ranges::copy(bond.partner_ids(), std::back_inserter(m_storage));
191 assert(bond.bond_id() >= 0);
192 m_storage.push_back(-(bond.bond_id() + 1));
193 }
194
195 /**
196 * @brief Erase a bond from the list.
197 * @param pos Iterator pointing to element to erase.
198 * @return iterator pointing one past the erased element.
199 */
201 return Iterator{m_storage.erase(pos.m_it, std::next(find_end(pos.m_it)))};
202 }
203
204 /**
205 * @brief Number of bonds.
206 * @return The number of bonds in the list.
207 */
208 auto size() const {
209 return static_cast<size_type>(std::distance(begin(), end()));
210 }
211
212 /**
213 * @brief Erase all bonds from the list.
214 */
215 void clear() { m_storage.clear(); }
216
217 /**
218 * @brief Check if the are any bonds in the list.
219 */
220 bool empty() const { return m_storage.empty(); }
221
222 // NOLINTNEXTLINE(bugprone-exception-escape)
223 friend void swap(BondList &lhs, BondList &rhs) {
224 using std::swap;
225
226 swap(lhs.m_storage, rhs.m_storage);
227 }
228};
229
230/**
231 * @brief Check if there is a specific bond in a bond list.
232 *
233 * @param bonds List of bonds to check
234 * @param partner_id Id of the bond partner
235 * @param bond_id Id of the bond parameters.
236 * @return True iff there is a bond to the specified id of the specified type.
237 */
238inline bool pair_bond_exists_on(BondList const &bonds, int partner_id,
239 int bond_id) {
240 return std::any_of(bonds.begin(), bonds.end(), [=](BondView const &bond) {
241 return (bond.bond_id() == bond_id) and
242 (bond.partner_ids()[0] == partner_id);
243 });
244}
245
246#endif // ESPRESSO_BONDLIST_HPP
bool pair_bond_exists_on(BondList const &bonds, int partner_id, int bond_id)
Check if there is a specific bond in a bond list.
Definition BondList.hpp:238
Iterator(storage_iterator it)
Definition BondList.hpp:127
Bond storage.
Definition BondList.hpp:84
BondList(BondList const &)=default
const_iterator erase(const_iterator pos)
Erase a bond from the list.
Definition BondList.hpp:200
BondList(BondList &&)=default
BondList & operator=(BondList const &rhs)
Definition BondList.hpp:159
friend void swap(BondList &lhs, BondList &rhs)
Definition BondList.hpp:223
const_iterator begin() const
Iterator to the beginning of the range of bonds in the list.
Definition BondList.hpp:178
std::add_const_t< reference > const_reference
Definition BondList.hpp:150
Utils::compact_vector< int > storage_type
Definition BondList.hpp:86
void insert(BondView const &bond)
Add a bond to the list.
Definition BondList.hpp:189
auto size() const
Number of bonds.
Definition BondList.hpp:208
std::ptrdiff_t difference_type
Definition BondList.hpp:152
void clear()
Erase all bonds from the list.
Definition BondList.hpp:215
const_iterator end() const
Iterator past the end of the range of bonds in the list.
Definition BondList.hpp:182
BondList()=default
bool empty() const
Check if the are any bonds in the list.
Definition BondList.hpp:220
std::add_lvalue_reference_t< BondView > reference
Definition BondList.hpp:149
BondList & operator=(BondList &&rhs) noexcept
Definition BondList.hpp:167
std::size_t size_type
Definition BondList.hpp:151
Immutable view on a bond.
Definition BondList.hpp:44
auto const & partner_ids() const
Definition BondList.hpp:55
int bond_id() const
Definition BondList.hpp:54
bool operator!=(BondView const &rhs) const
Definition BondList.hpp:61
bool operator==(BondView const &rhs) const
Definition BondList.hpp:57
BondView()=default
BondView(int id, std::span< const int > partners)
Definition BondList.hpp:51