Commit | Line | Data |
---|---|---|
b17ed2ad JG |
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/macros.hpp> | |
12 | ||
13 | #include <cstddef> | |
14 | #include <iterator> | |
15 | ||
16 | namespace lttng { | |
17 | namespace utils { | |
18 | ||
19 | /* | |
20 | * random_access_container_wrapper is a helper to provide an idiomatic C++ interface | |
21 | * from a C container API. ElementAccessorCallable and ElementCountAccessorCallable | |
22 | * are two functors which must be provided to allow access to the underlying elements | |
23 | * of the container and to its size. | |
24 | */ | |
25 | template <typename ContainerType, typename ElementType, typename ContainerOperations> | |
26 | class random_access_container_wrapper { | |
27 | class _iterator : public std::iterator<std::random_access_iterator_tag, std::size_t> { | |
28 | public: | |
29 | explicit _iterator(const random_access_container_wrapper& container, | |
30 | std::size_t start_index = 0) : | |
31 | _container(container), _index(start_index) | |
32 | { | |
33 | } | |
34 | ||
35 | _iterator& operator++() noexcept | |
36 | { | |
37 | ++_index; | |
38 | return *this; | |
39 | } | |
40 | ||
41 | _iterator& operator--() noexcept | |
42 | { | |
43 | --_index; | |
44 | return *this; | |
45 | } | |
46 | ||
47 | _iterator& operator++(int) noexcept | |
48 | { | |
49 | auto this_before_increment = *this; | |
50 | ||
51 | _index++; | |
52 | return this_before_increment; | |
53 | } | |
54 | ||
55 | _iterator& operator--(int) noexcept | |
56 | { | |
57 | _index--; | |
58 | return *this; | |
59 | } | |
60 | ||
61 | bool operator==(const _iterator& other) const noexcept | |
62 | { | |
63 | return _index == other._index; | |
64 | } | |
65 | ||
66 | bool operator!=(const _iterator& other) const noexcept | |
67 | { | |
68 | return !(*this == other); | |
69 | } | |
70 | ||
71 | typename std::conditional<std::is_pointer<ElementType>::value, | |
72 | ElementType, | |
73 | ElementType&>::type | |
74 | operator*() const noexcept | |
75 | { | |
76 | return _container[_index]; | |
77 | } | |
78 | ||
79 | private: | |
80 | const random_access_container_wrapper& _container; | |
81 | std::size_t _index; | |
82 | }; | |
83 | ||
84 | using iterator = _iterator; | |
85 | ||
86 | public: | |
87 | explicit random_access_container_wrapper(ContainerType container) : _container{ container } | |
88 | { | |
89 | } | |
90 | ||
91 | iterator begin() noexcept | |
92 | { | |
93 | return iterator(*this); | |
94 | } | |
95 | ||
96 | iterator end() noexcept | |
97 | { | |
98 | return iterator(*this, ContainerOperations::size(_container)); | |
99 | } | |
100 | ||
101 | std::size_t size() const noexcept | |
102 | { | |
103 | return ContainerOperations::size(_container); | |
104 | } | |
105 | ||
106 | typename std::conditional<std::is_pointer<ElementType>::value, ElementType, ElementType&>::type | |
107 | operator[](std::size_t index) | |
108 | { | |
109 | LTTNG_ASSERT(index < ContainerOperations::size(_container)); | |
110 | return ContainerOperations::get(_container, index); | |
111 | } | |
112 | ||
113 | typename std::conditional<std::is_pointer<ElementType>::value, | |
114 | const ElementType, | |
115 | const ElementType&>::type | |
116 | operator[](std::size_t index) const | |
117 | { | |
118 | LTTNG_ASSERT(index < ContainerOperations::size(_container)); | |
119 | return ContainerOperations::get(_container, index); | |
120 | } | |
121 | ||
122 | private: | |
123 | ContainerType _container; | |
124 | }; | |
125 | } /* namespace utils */ | |
126 | } /* namespace lttng */ | |
127 | ||
128 | #endif /* LTTNG_CONTAINER_WRAPPER_H */ |