Fix: syscall event rule: emission sites not compared in is_equal
[lttng-tools.git] / src / common / container-wrapper.hpp
1 /*
2 * Copyright (C) 2023 Jérémie Galarneau <jeremie.galarneau@efficios.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-only
5 *
6 */
7
8 #ifndef LTTNG_CONTAINER_WRAPPER_H
9 #define LTTNG_CONTAINER_WRAPPER_H
10
11 #include <common/exception.hpp>
12 #include <common/format.hpp>
13 #include <common/macros.hpp>
14
15 #include <cstddef>
16 #include <iterator>
17
18 namespace lttng {
19 namespace utils {
20
21 /*
22 * random_access_container_wrapper is a helper to provide an idiomatic C++ interface
23 * from a C container API. ElementAccessorCallable and ElementCountAccessorCallable
24 * are two functors which must be provided to allow access to the underlying elements
25 * of the container and to its size.
26 */
27 template <typename ContainerType, typename ElementType, typename ContainerOperations>
28 class random_access_container_wrapper {
29 template <typename IteratorContainerType, typename IteratorElementType>
30 class _iterator : public std::iterator<std::random_access_iterator_tag, std::size_t> {
31 public:
32 explicit _iterator(IteratorContainerType& container, std::size_t start_index = 0) :
33 _container(container), _index(start_index)
34 {
35 }
36
37 _iterator& operator++() noexcept
38 {
39 ++_index;
40 return *this;
41 }
42
43 _iterator& operator--() noexcept
44 {
45 --_index;
46 return *this;
47 }
48
49 _iterator& operator++(int) noexcept
50 {
51 auto this_before_increment = *this;
52
53 _index++;
54 return this_before_increment;
55 }
56
57 _iterator& operator--(int) noexcept
58 {
59 _index--;
60 return *this;
61 }
62
63 ptrdiff_t operator-(const _iterator& other) const
64 {
65 return _index - other._index;
66 }
67
68 bool operator==(const _iterator& other) const noexcept
69 {
70 return _index == other._index;
71 }
72
73 bool operator!=(const _iterator& other) const noexcept
74 {
75 return !(*this == other);
76 }
77
78 typename std::conditional<std::is_pointer<IteratorElementType>::value,
79 IteratorElementType,
80 IteratorElementType&>::type
81 operator*() const
82 {
83 return _container[_index];
84 }
85
86 private:
87 IteratorContainerType& _container;
88 std::size_t _index;
89 };
90
91 using iterator = _iterator<random_access_container_wrapper, ElementType>;
92 using const_iterator = _iterator<const random_access_container_wrapper, const ElementType>;
93
94 public:
95 explicit random_access_container_wrapper(ContainerType container) :
96 _container{ std::move(container) }
97 {
98 }
99
100 iterator begin() noexcept
101 {
102 return iterator(*this);
103 }
104
105 iterator end()
106 {
107 return iterator(*this, size());
108 }
109
110 const_iterator begin() const noexcept
111 {
112 return const_iterator(*this);
113 }
114
115 const_iterator end() const
116 {
117 return const_iterator(*this, size());
118 }
119
120 std::size_t size() const
121 {
122 return ContainerOperations::size(_container);
123 }
124
125 bool empty() const
126 {
127 return size() == 0;
128 }
129
130 typename std::conditional<std::is_pointer<ElementType>::value, ElementType, ElementType&>::type
131 operator[](std::size_t index)
132 {
133 /*
134 * To share code between the const and mutable versions of this operator, 'this'
135 * is casted to a const reference. A const_cast then ensures that a mutable
136 * reference (or pointer) is returned.
137 *
138 * We typically avoid const_cast, but this is safe: if the user is calling the
139 * mutable version of this operator, it had a mutable object anyhow.
140 *
141 * For more information, see Item 3 of Effective C++.
142 */
143 const auto& const_this = static_cast<const random_access_container_wrapper&>(*this);
144
145 /* NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast) */
146 return const_cast<typename std::conditional<std::is_pointer<ElementType>::value,
147 ElementType,
148 ElementType&>::type>(const_this[index]);
149 }
150
151 typename std::conditional<std::is_pointer<ElementType>::value,
152 const ElementType,
153 const ElementType&>::type
154 operator[](std::size_t index) const
155 {
156 if (index >= ContainerOperations::size(_container)) {
157 throw std::invalid_argument(lttng::format(
158 "Out of bound access through random_access_container_wrapper: index={}, size={}",
159 index,
160 size()));
161 }
162
163 return ContainerOperations::get(_container, index);
164 }
165
166 protected:
167 ContainerType _container;
168 };
169 } /* namespace utils */
170 } /* namespace lttng */
171
172 #endif /* LTTNG_CONTAINER_WRAPPER_H */
This page took 0.03256 seconds and 4 git commands to generate.