//------------------------------------------------------------------------------ /* This file is part of Beast: https://github.com/vinniefalco/Beast Copyright 2013, Vinnie Falco Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ //============================================================================== #ifndef BEAST_CONTAINER_BUFFER_VIEW_H_INCLUDED #define BEAST_CONTAINER_BUFFER_VIEW_H_INCLUDED #include #include #include // #include #include #include #include #include #include // namespace beast { namespace detail { template >::value> struct apply_const { using type = U; }; template struct apply_const { using type = const U; }; // is_contiguous is true if C is a contiguous container template struct is_contiguous : public std::false_type { }; template struct is_contiguous : public is_contiguous { }; template struct is_contiguous > : public std::true_type { }; template struct is_contiguous > : public std::true_type { }; template struct is_contiguous > : public std::true_type { }; // True if T is const or U is not const template struct buffer_view_const_compatible : std::integral_constant ::value || ! std::is_const::value > { }; // True if T and U are the same or differ only in const, or // if T and U are equally sized integral types. template struct buffer_view_ptr_compatible : std::integral_constant , std::remove_const >::value) || (std::is_integral ::value && std::is_integral ::value && sizeof (U) == sizeof (T)) > { }; // Determine if buffer_view is constructible from U* template struct buffer_view_convertible : std::integral_constant ::value && buffer_view_ptr_compatible ::value > { }; // True if C is a container that can be used to construct a buffer_view template struct buffer_view_container_compatible : std::integral_constant ::value && buffer_view_convertible ::type>::value > { }; } // detail struct buffer_view_default_tag { }; //------------------------------------------------------------------------------ /** A view into a range of contiguous container elements. The size of the view is determined at the time of construction. This tries to emulate the interface of std::vector as closely as possible, with the constraint that the size of the container cannot be changed. @tparam T The underlying element type. If T is const, member functions which can modify elements are removed from the interface. @tparam Tag A type used to prevent two views with the same T from being comparable or assignable. */ template < class T, class Tag = buffer_view_default_tag > class buffer_view { private: T* m_base; std::size_t m_size; static_assert (std::is_same >::value, "T may not be a reference type"); static_assert (! std::is_same ::value, "T may not be void"); static_assert (std::is_same , std::remove_reference_t const>::value, "Expected std::add_const to produce T const"); template void assign (Iter first, Iter last) noexcept { using U = typename std::iterator_traits ::value_type; static_assert (detail::buffer_view_const_compatible ::value, "Cannot convert from 'U const' to 'T', " "conversion loses const qualifiers"); static_assert (detail::buffer_view_ptr_compatible ::value, "Cannot convert from 'U*' to 'T*, " "types are incompatible"); if (first == last) { m_base = nullptr; m_size = 0; } else { #if 0 // fails on gcc m_base = reinterpret_cast ( std::addressof (*first)); #else m_base = reinterpret_cast (&*first); #endif m_size = std::distance (first, last); } } public: using value_type = T; using size_type = std::size_t; using difference_type = std::ptrdiff_t; using reference = T&; using const_reference = T const&; using pointer = T*; using const_pointer = T const*; using iterator = T*; using const_iterator = T const*; using reverse_iterator = std::reverse_iterator ; using const_reverse_iterator = std::reverse_iterator ; // default construct buffer_view () noexcept : m_base (nullptr) , m_size (0) { } // copy construct template ::value> > buffer_view (buffer_view v) noexcept { assign (v.begin(), v.end()); } // construct from container template ::value > > buffer_view (C& c) noexcept { assign (c.begin(), c.end()); } // construct from pointer range template ::value> > buffer_view (U* first, U* last) noexcept { assign (first, last); } // construct from base and size template ::value> > buffer_view (U* u, std::size_t n) noexcept : m_base (u) , m_size (n) { } // assign from container template ::value > > buffer_view& operator= (C& c) noexcept { assign (c.begin(), c.end()); return *this; } // // Element access // reference at (size_type pos) { if (! (pos < size())) throw std::out_of_range ("bad array index"); return m_base [pos]; } const_reference at (size_type pos) const { if (! (pos < size())) throw std::out_of_range ("bad array index"); return m_base [pos]; } reference operator[] (size_type pos) noexcept { return m_base [pos]; } const_reference operator[] (size_type pos) const noexcept { return m_base [pos]; } reference back() noexcept { return m_base [m_size - 1]; } const_reference back() const noexcept { return m_base [m_size - 1]; } reference front() noexcept { return *m_base; } const_reference front() const noexcept { return *m_base; } pointer data() noexcept { return m_base; } const_pointer data() const noexcept { return m_base; } // // Iterators // iterator begin() noexcept { return m_base; } const_iterator begin() const noexcept { return m_base; } const_iterator cbegin() const noexcept { return m_base; } iterator end() noexcept { return m_base + m_size; } const_iterator end() const noexcept { return m_base + m_size; } const_iterator cend() const noexcept { return m_base + m_size; } reverse_iterator rbegin() noexcept { return reverse_iterator (end()); } const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator (cend()); } const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator (cend()); } reverse_iterator rend() noexcept { return reverse_iterator (begin()); } const_reverse_iterator rend() const noexcept { return const_reverse_iterator (cbegin()); } const_reverse_iterator crend() const noexcept { return const_reverse_iterator (cbegin()); } // // Capacity // bool empty() const noexcept { return m_size == 0; } size_type size() const noexcept { return m_size; } size_type max_size() const noexcept { return size(); } size_type capacity() const noexcept { return size(); } // // Modifiers // template friend void swap (buffer_view & lhs, buffer_view & rhs) noexcept; }; //------------------------------------------------------------------------------ template inline bool operator== (buffer_view lhs, buffer_view rhs) { return std::equal ( lhs.cbegin(), lhs.cend(), rhs.cbegin(), rhs.cend()); } template inline bool operator!= (buffer_view lhs, buffer_view rhs) { return ! (lhs == rhs); } template inline bool operator< (buffer_view lhs, buffer_view rhs) { return std::lexicographical_compare ( lhs.cbegin(), lhs.cend(), rhs.cbegin(), rhs.cend()); } template inline bool operator>= (buffer_view lhs, buffer_view rhs) { return ! (lhs < rhs); } template inline bool operator> (buffer_view lhs, buffer_view rhs) { return rhs < lhs; } template inline bool operator<= (buffer_view lhs, buffer_view rhs) { return ! (rhs < lhs); } template inline void swap (buffer_view & lhs, buffer_view & rhs) noexcept { std::swap (lhs.m_base, rhs.m_base); std::swap (lhs.m_size, rhs.m_size); } //------------------------------------------------------------------------------ template < class T, class Tag = buffer_view_default_tag > using const_buffer_view = buffer_view < std::add_const_t , Tag>; } #endif