// array_view - non-owning range view of array // Copyright snsinfu 2018. // Distributed under the Boost Software License, Version 1.0. // // Permission is hereby granted, free of charge, to any person or organization // obtaining a copy of the software and accompanying documentation covered by // this license (the "Software") to use, reproduce, display, distribute, // execute, and transmit the Software, and to prepare derivative works of the // Software, and to permit third-parties to whom the Software is furnished to // do so, all subject to the following: // // The copyright notices in the Software and this entire statement, including // the above license grant, this restriction and the following disclaimer, // must be included in all copies of the Software, in whole or in part, and // all derivative works of the Software, unless such copies or derivative // works are solely in the form of machine-executable object code generated by // a source language processor. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT // SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE // FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. #ifndef INCLUDED_ARRAY_VIEW_HPP #define INCLUDED_ARRAY_VIEW_HPP #include #include #include #include #include namespace cxx { namespace array_view_detail { // data returns a pointer to the first element of a contiguous container // or an array. template constexpr auto data(Cont& cont) noexcept -> decltype(cont.data()) { return cont.data(); } template constexpr auto data(T(& arr)[N]) noexcept -> T* { return arr; } // size returns the number of elements in a container or an array. template constexpr auto size(Cont const& cont) noexcept -> decltype(cont.size()) { return cont.size(); } template constexpr auto size(T(&)[N]) noexcept -> std::size_t { return N; } } // array_view is an non-owning range view of an array. It is similar to // GSL's span but uses size_t for indexing, for better compatibility with // the standard library. template class array_view { public: // value_type is the non-qualified type of the elements. using value_type = typename std::remove_cv::type; // pointer is the type of a pointer to an element. using pointer = T*; // reference is the type of a reference to an element. using reference = T&; // size_type is the type of size and index values. using size_type = std::size_t; // iterator is the type of iterators. Guaranteed to be a random access // iterator. Currently this is implemented as an alias of T* but this // may change in the future. using iterator = T*; // reverse_iterator is the type of reverse iterators. Guaranteed to be // a random access iterator. using reverse_iterator = std::reverse_iterator; // const_array_view is the type of read-only array_view with the same // value_type. This is the same as array_view if T is already const // qualified. using const_array_view = array_view; // array_view is default constructible. array_view() = default; // array_view is copy constructible. array_view(array_view&) = default; // array_view is copy constructible. array_view(array_view const&) = default; // array_view is constructible from a raw memory span [p, p + n). The // behavior is undefined if the memory region is invalid. constexpr array_view(pointer p, size_type n) : data_{p}, size_{n} { } // array_view is implicitly convertible from a contiguous container like // std::vector. template< typename Container, typename P = decltype(array_view_detail::data(std::declval())), typename S = decltype(array_view_detail::size(std::declval())), typename = typename std::enable_if< std::is_convertible::type(*)[], T(*)[]>::value, int >::type, typename = typename std::enable_if< !std::is_same>::value, int >::type > constexpr array_view(Container& container) noexcept : array_view{array_view_detail::data(container), array_view_detail::size(container)} { } // array_view is implicitly convertible to a read-only view. constexpr operator const_array_view() const noexcept { return {data(), size()}; } // empty returns true if the view is empty. constexpr bool empty() const noexcept { return size() == 0; } // size returns the number of elements. constexpr size_type size() const noexcept { return size_; } // data r eturns a pointer to the first element. The pointer may or may // not be null if the view is empty. constexpr pointer data() const noexcept { return data_; } // front returns a reference to the first element. The behavior is // undefined if the view is empty. constexpr reference front() const { return operator[](0); } // back returns a reference to the last element. The behavior is // undefined if the view is empty. constexpr reference back() const { return operator[](size() - 1); } // Indexing operator returns a reference to the idx-th element. The // behavior is undefined if the index is out of bounds. constexpr reference operator[](size_type idx) const { return data()[idx]; } // at returns a reference to the idx-th element. It throws // std::out_of_range if the index is out of bounds. reference at(size_type idx) const { if (idx >= size()) { throw std::out_of_range("array_view access out-of-bounds"); } return operator[](idx); } // begin returns an iterator to the beginning of the viewed array. constexpr iterator begin() const noexcept { return data(); } // end returns an iterator to the end of the viewed array. constexpr iterator end() const noexcept { return data() + size(); } // rbegin returns a reverse iterator to the reverse beginning. reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; } // rend returns a reverse iterator to the reverse end. reverse_iterator rend() const noexcept { return reverse_iterator{begin()}; } // as_const returns a read-only view of the same array. constexpr const_array_view as_const() const noexcept { return {data(), size()}; } // swap swaps the viewed array with other. void swap(array_view& other) noexcept { auto const copy = *this; *this = other; other = copy; } // subview returns a view of the subarray with given region. constexpr array_view subview(size_type offset, size_type count) const { return {data() + offset, count}; } // first returns a view of the first count elements. constexpr array_view first(size_type count) const { return subview(0, count); } /// last returns a view of the last count elements. constexpr array_view last(size_type count) const { return subview(size() - count, count); } private: pointer data_ = nullptr; size_type size_ = 0; }; } #endif