Import CStringView from the Babeltrace tree
[lttng-tools.git] / src / common / container-wrapper.hpp
index 09097e9358855977837eca2efd86f689f872ea29..25385fc43837961ec4301dd9f7254f0b89ccc3b6 100644 (file)
@@ -8,6 +8,8 @@
 #ifndef LTTNG_CONTAINER_WRAPPER_H
 #define LTTNG_CONTAINER_WRAPPER_H
 
+#include <common/exception.hpp>
+#include <common/format.hpp>
 #include <common/macros.hpp>
 
 #include <cstddef>
@@ -24,10 +26,10 @@ namespace utils {
  */
 template <typename ContainerType, typename ElementType, typename ContainerOperations>
 class random_access_container_wrapper {
+       template <typename IteratorContainerType, typename IteratorElementType>
        class _iterator : public std::iterator<std::random_access_iterator_tag, std::size_t> {
        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<std::is_pointer<ElementType>::value,
-                                         ElementType,
-                                         ElementType&>::type
-               operator*() const noexcept
+               typename std::conditional<std::is_pointer<IteratorElementType>::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<random_access_container_wrapper, ElementType>;
+       using const_iterator = _iterator<const random_access_container_wrapper, const ElementType>;
 
 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<std::is_pointer<ElementType>::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<const random_access_container_wrapper&>(*this);
+
+               /* NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast) */
+               return const_cast<typename std::conditional<std::is_pointer<ElementType>::value,
+                                                           ElementType,
+                                                           ElementType&>::type>(const_this[index]);
        }
 
        typename std::conditional<std::is_pointer<ElementType>::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 */
This page took 0.024836 seconds and 4 git commands to generate.