X-Git-Url: https://git.lttng.org/?a=blobdiff_plain;f=src%2Fcommon%2Fcontainer-wrapper.hpp;h=25385fc43837961ec4301dd9f7254f0b89ccc3b6;hb=HEAD;hp=09097e9358855977837eca2efd86f689f872ea29;hpb=b17ed2ad7083d1b0bf45fe3e1bfc4e4ad787aaf3;p=lttng-tools.git diff --git a/src/common/container-wrapper.hpp b/src/common/container-wrapper.hpp index 09097e935..25385fc43 100644 --- a/src/common/container-wrapper.hpp +++ b/src/common/container-wrapper.hpp @@ -8,6 +8,8 @@ #ifndef LTTNG_CONTAINER_WRAPPER_H #define LTTNG_CONTAINER_WRAPPER_H +#include +#include #include #include @@ -24,10 +26,10 @@ namespace utils { */ template class random_access_container_wrapper { + template class _iterator : public std::iterator { public: - explicit _iterator(const random_access_container_wrapper& container, - std::size_t start_index = 0) : + explicit _iterator(IteratorContainerType& container, std::size_t start_index = 0) : _container(container), _index(start_index) { } @@ -58,6 +60,11 @@ class random_access_container_wrapper { return *this; } + ptrdiff_t operator-(const _iterator& other) const + { + return _index - other._index; + } + bool operator==(const _iterator& other) const noexcept { return _index == other._index; @@ -68,23 +75,25 @@ class random_access_container_wrapper { return !(*this == other); } - typename std::conditional::value, - ElementType, - ElementType&>::type - operator*() const noexcept + typename std::conditional::value, + IteratorElementType, + IteratorElementType&>::type + operator*() const { return _container[_index]; } private: - const random_access_container_wrapper& _container; + IteratorContainerType& _container; std::size_t _index; }; - using iterator = _iterator; + using iterator = _iterator; + using const_iterator = _iterator; public: - explicit random_access_container_wrapper(ContainerType container) : _container{ container } + explicit random_access_container_wrapper(ContainerType container) : + _container{ std::move(container) } { } @@ -93,21 +102,50 @@ public: return iterator(*this); } - iterator end() noexcept + iterator end() + { + return iterator(*this, size()); + } + + const_iterator begin() const noexcept { - return iterator(*this, ContainerOperations::size(_container)); + return const_iterator(*this); } - std::size_t size() const noexcept + const_iterator end() const + { + return const_iterator(*this, size()); + } + + std::size_t size() const { return ContainerOperations::size(_container); } + bool empty() const + { + return size() == 0; + } + typename std::conditional::value, ElementType, ElementType&>::type operator[](std::size_t index) { - LTTNG_ASSERT(index < ContainerOperations::size(_container)); - return ContainerOperations::get(_container, index); + /* + * To share code between the const and mutable versions of this operator, 'this' + * is casted to a const reference. A const_cast then ensures that a mutable + * reference (or pointer) is returned. + * + * We typically avoid const_cast, but this is safe: if the user is calling the + * mutable version of this operator, it had a mutable object anyhow. + * + * For more information, see Item 3 of Effective C++. + */ + const auto& const_this = static_cast(*this); + + /* NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast) */ + return const_cast::value, + ElementType, + ElementType&>::type>(const_this[index]); } typename std::conditional::value, @@ -115,11 +153,17 @@ public: const ElementType&>::type operator[](std::size_t index) const { - LTTNG_ASSERT(index < ContainerOperations::size(_container)); + if (index >= ContainerOperations::size(_container)) { + throw std::invalid_argument(lttng::format( + "Out of bound access through random_access_container_wrapper: index={}, size={}", + index, + size())); + } + return ContainerOperations::get(_container, index); } -private: +protected: ContainerType _container; }; } /* namespace utils */