boost/parser/detail/text/detail/begin_end.hpp
// Copyright (C) 2022 T. Zachary Laine
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PARSER_DETAIL_TEXT_BEGIN_END_HPP
#define BOOST_PARSER_DETAIL_TEXT_BEGIN_END_HPP
#include <boost/parser/detail/detection.hpp>
#include <initializer_list>
namespace boost::parser::detail { namespace text { namespace detail {
template<typename T>
T decay_copy(T) noexcept;
template<typename T>
struct static_const
{
static constexpr T value{};
};
template<typename T>
constexpr T static_const<T>::value;
namespace begin_impl {
template<typename T>
void begin(T &&) = delete;
template<typename T>
void begin(std::initializer_list<T>) = delete;
template<typename T>
using member_begin_expr = decltype(std::declval<T &>().begin());
template<typename T>
using adl_begin_expr = decltype(begin(std::declval<T &>()));
template<typename T>
constexpr bool has_member_begin_v = is_detected_v<member_begin_expr, T>;
template<typename T>
constexpr bool has_adl_begin_v = is_detected_v<adl_begin_expr, T>;
template<typename R>
using member_return_t =
decltype(detail::decay_copy(std::declval<R &>().begin()));
template<typename R>
using adl_return_t =
decltype(detail::decay_copy(begin(std::declval<R &>)));
struct impl
{
template<typename R, std::size_t N>
void operator()(R (&&)[N]) const = delete;
template<typename R, std::size_t N>
constexpr R * operator()(R (&array)[N]) const
{
return array;
}
template<typename R>
constexpr std::
enable_if_t<has_member_begin_v<R>, member_return_t<R>>
operator()(R && r) const
{
return r.begin();
}
template<typename R>
constexpr std::enable_if_t<
!has_member_begin_v<R> && has_adl_begin_v<R>,
adl_return_t<R>>
operator()(R && r) const
{
return begin(r);
}
};
}
#if 201703L <= __cplusplus
namespace _ {
inline constexpr begin_impl::impl begin;
}
using namespace _;
#else
namespace {
constexpr auto & begin = static_const<begin_impl::impl>::value;
}
#endif
namespace end_impl {
template<typename T>
void end(T &&) = delete;
template<typename T>
void end(std::initializer_list<T>) = delete;
template<typename T>
using member_end_expr = decltype(std::declval<T &>().end());
template<typename T>
using adl_end_expr = decltype(end(std::declval<T &>()));
template<typename T>
constexpr bool has_member_end_v = is_detected_v<member_end_expr, T>;
template<typename T>
constexpr bool has_adl_end_v = is_detected_v<adl_end_expr, T>;
template<typename R>
using member_return_t =
decltype(detail::decay_copy(std::declval<R &>().end()));
template<typename R>
using adl_return_t =
decltype(detail::decay_copy(end(std::declval<R &>)));
struct impl
{
template<typename R, std::size_t N>
void operator()(R (&&)[N]) const = delete;
template<typename R, std::size_t N>
constexpr R * operator()(R (&array)[N]) const
{
return array + N;
}
template<typename R>
constexpr std::enable_if_t<has_member_end_v<R>, member_return_t<R>>
operator()(R && r) const
{
return r.end();
}
template<typename R>
constexpr std::enable_if_t<
!has_member_end_v<R> && has_adl_end_v<R>,
adl_return_t<R>>
operator()(R && r) const
{
return end(r);
}
};
}
#if 201703L <= __cplusplus
namespace _ {
inline constexpr end_impl::impl end;
}
using namespace _;
#else
namespace {
constexpr auto & end = static_const<end_impl::impl>::value;
}
#endif
}}}
#endif