2 * Copyright (C) 2023 Jérémie Galarneau <jeremie.galarneau@efficios.com>
4 * SPDX-License-Identifier: LGPL-2.1-only
8 #ifndef LTTNG_CONTAINER_WRAPPER_H
9 #define LTTNG_CONTAINER_WRAPPER_H
11 #include <common/exception.hpp>
12 #include <common/format.hpp>
13 #include <common/macros.hpp>
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.
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> {
32 explicit _iterator(IteratorContainerType& container, std::size_t start_index = 0) :
33 _container(container), _index(start_index)
37 _iterator& operator++() noexcept
43 _iterator& operator--() noexcept
49 _iterator& operator++(int) noexcept
51 auto this_before_increment = *this;
54 return this_before_increment;
57 _iterator& operator--(int) noexcept
63 bool operator==(const _iterator& other) const noexcept
65 return _index == other._index;
68 bool operator!=(const _iterator& other) const noexcept
70 return !(*this == other);
73 typename std::conditional<std::is_pointer<IteratorElementType>::value,
75 IteratorElementType&>::type
78 return _container[_index];
82 IteratorContainerType& _container;
86 using iterator = _iterator<random_access_container_wrapper, ElementType>;
87 using const_iterator = _iterator<const random_access_container_wrapper, const ElementType>;
90 explicit random_access_container_wrapper(ContainerType container) :
91 _container{ std::move(container) }
95 iterator begin() noexcept
97 return iterator(*this);
102 return iterator(*this, size());
105 const_iterator begin() const noexcept
107 return const_iterator(*this);
110 const_iterator end() const
112 return const_iterator(*this, size());
115 std::size_t size() const
117 return ContainerOperations::size(_container);
120 typename std::conditional<std::is_pointer<ElementType>::value, ElementType, ElementType&>::type
121 operator[](std::size_t index)
124 * To share code between the const and mutable versions of this operator, 'this'
125 * is casted to a const reference. A const_cast then ensures that a mutable
126 * reference (or pointer) is returned.
128 * We typically avoid const_cast, but this is safe: if the user is calling the
129 * mutable version of this operator, it had a mutable object anyhow.
131 * For more information, see Item 3 of Effective C++.
133 const auto& const_this = static_cast<const decltype(*this)&>(*this);
135 /* NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast) */
136 return const_cast<typename std::conditional<std::is_pointer<ElementType>::value,
138 ElementType&>::type>(const_this[index]);
141 typename std::conditional<std::is_pointer<ElementType>::value,
143 const ElementType&>::type
144 operator[](std::size_t index) const
146 if (index >= ContainerOperations::size(_container)) {
147 LTTNG_THROW_INVALID_ARGUMENT_ERROR(lttng::format(
148 "Out of bound access through random_access_container_wrapper: index={}, size={}",
153 return ContainerOperations::get(_container, index);
157 ContainerType _container;
159 } /* namespace utils */
160 } /* namespace lttng */
162 #endif /* LTTNG_CONTAINER_WRAPPER_H */