/* vim: set et ft=cpp.doxygen sts=2 sw=2 ts=8 : */ /** * Copyright © 2013 Saleem Abdulrasool <compnerd@compnerd.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. **/ /*! * \note § 6.5.4 The range-based for statement [stmt.ranged] * * A range-based for statement is equivalent to: * * \code{c++} * { * auto && __range = range-init; * for ( auto __begin = begin-expr, * __end = end-expr; * __begin != __end; * ++__begin ) { * for-range-declaration = *__begin; * statement * } * } * \endcode * * where \c __range, \c __begin, and \c __end are variables defined for * exposition only, and \c _RangeT is the type of the expression, and * \c begin-expr and \c end-expr are determined as follows: * * - if \c _RangeT is an array type, \c begin-expr and \c end-expr are * \c __range and \c __range \c + \c __bound, respectively, where \c __bound * is the array bound. If \c _RangeT is an array of unknown size or an array * of incomplete type, the program is ill-formed. * - otherwise, \c begin-expr and \c end-expr are \c begin(__range) and * \c end(__range), respectively, where \c begin and \c end are looked up * with argument-dependent lookup. For the purposes of this name lookup, * namespace \c std is an associated namespace. */ #include <iterator> #include <type_traits> template <typename type_, int> struct reverse_iteration_proxy; template <typename type_, size_t bound_> class reverse_iteration_proxy<type_[bound_], 0> { private: type_ (&range_)[bound_]; public: typedef std::reverse_iterator<type_ *> iterator; reverse_iteration_proxy(type_ (&range)[bound_]) : range_(range) { } reverse_iteration_proxy(type_ (&&)[bound_]) = delete; iterator begin() const noexcept { return iterator(range_ + bound_); } iterator end() const noexcept { return iterator(range_); } }; template <typename type_> class reverse_iteration_proxy<type_, 1> { private: type_ & range_; public: typedef decltype(range_.rbegin()) iterator; reverse_iteration_proxy(type_ & range) : range_(range) { } reverse_iteration_proxy(type_ &&) = delete; iterator begin() const noexcept { return range_.rbegin(); } iterator end() const noexcept { return range_.rend(); } }; template <typename type_> class reverse_iteration_proxy<type_, 2> { private: type_ & range_; public: typedef std::reverse_iterator<decltype(std::end(range_))> iterator; reverse_iteration_proxy(type_ & range) : range_(range) { } reverse_iteration_proxy(type_ &&) = delete; iterator begin() const noexcept { return iterator(std::end(range_)); } iterator end() const noexcept { return iterator(std::begin(range_)); } }; template <typename type_, size_t bound_> inline constexpr reverse_iteration_proxy<type_[bound_], 0> select_reverse_iteration_proxy(type_ (&range)[bound_], int) { return reverse_iteration_proxy<type_[bound_], 0>{ range }; } template <typename type_, typename = decltype(std::declval<type_>().rbegin())> inline constexpr reverse_iteration_proxy<type_, 1> select_reverse_iteration_proxy(type_ & range, int) { static_assert(std::is_same<decltype(std::declval<type_>().rbegin()), decltype(std::declval<type_>().rend())>::value, "iterator type mismatch"); return reverse_iteration_proxy<type_, 1>{ range }; } template <typename type_> inline constexpr reverse_iteration_proxy<type_, 2> select_reverse_iteration_proxy(type_ & range, long) { return reverse_iteration_proxy<type_, 2>{ range }; } template <typename type_> inline constexpr auto reverse(type_ & range) -> decltype(select_reverse_iteration_proxy(range, 0)) { return select_reverse_iteration_proxy(range, 0); }