320 lines
11 KiB
C++
320 lines
11 KiB
C++
|
/*!
|
||
|
@file
|
||
|
Defines `boost::hana::string`.
|
||
|
|
||
|
@copyright Louis Dionne 2013-2016
|
||
|
Distributed under the Boost Software License, Version 1.0.
|
||
|
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
|
||
|
*/
|
||
|
|
||
|
#ifndef BOOST_HANA_STRING_HPP
|
||
|
#define BOOST_HANA_STRING_HPP
|
||
|
|
||
|
#include <boost/hana/fwd/string.hpp>
|
||
|
|
||
|
#include <boost/hana/bool.hpp>
|
||
|
#include <boost/hana/config.hpp>
|
||
|
#include <boost/hana/core/make.hpp>
|
||
|
#include <boost/hana/detail/algorithm.hpp>
|
||
|
#include <boost/hana/detail/operators/adl.hpp>
|
||
|
#include <boost/hana/detail/operators/comparable.hpp>
|
||
|
#include <boost/hana/detail/operators/iterable.hpp>
|
||
|
#include <boost/hana/detail/operators/orderable.hpp>
|
||
|
#include <boost/hana/fwd/at.hpp>
|
||
|
#include <boost/hana/fwd/contains.hpp>
|
||
|
#include <boost/hana/fwd/core/tag_of.hpp>
|
||
|
#include <boost/hana/fwd/core/to.hpp>
|
||
|
#include <boost/hana/fwd/drop_front.hpp>
|
||
|
#include <boost/hana/fwd/equal.hpp>
|
||
|
#include <boost/hana/fwd/find.hpp>
|
||
|
#include <boost/hana/fwd/front.hpp>
|
||
|
#include <boost/hana/fwd/hash.hpp>
|
||
|
#include <boost/hana/fwd/is_empty.hpp>
|
||
|
#include <boost/hana/fwd/length.hpp>
|
||
|
#include <boost/hana/fwd/less.hpp>
|
||
|
#include <boost/hana/fwd/plus.hpp>
|
||
|
#include <boost/hana/fwd/unpack.hpp>
|
||
|
#include <boost/hana/fwd/zero.hpp>
|
||
|
#include <boost/hana/if.hpp>
|
||
|
#include <boost/hana/integral_constant.hpp>
|
||
|
#include <boost/hana/optional.hpp>
|
||
|
#include <boost/hana/type.hpp>
|
||
|
|
||
|
#include <utility>
|
||
|
#include <cstddef>
|
||
|
#include <type_traits>
|
||
|
|
||
|
|
||
|
BOOST_HANA_NAMESPACE_BEGIN
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
// string<>
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
//! @cond
|
||
|
namespace detail {
|
||
|
template <char ...s>
|
||
|
constexpr char const string_storage[sizeof...(s) + 1] = {s..., '\0'};
|
||
|
}
|
||
|
|
||
|
template <char ...s>
|
||
|
struct string
|
||
|
: detail::operators::adl<string<s...>>
|
||
|
, detail::iterable_operators<string<s...>>
|
||
|
{
|
||
|
static constexpr char const* c_str() {
|
||
|
return &detail::string_storage<s...>[0];
|
||
|
}
|
||
|
};
|
||
|
//! @endcond
|
||
|
|
||
|
template <char ...s>
|
||
|
struct tag_of<string<s...>> {
|
||
|
using type = string_tag;
|
||
|
};
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
// make<string_tag>
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
template <>
|
||
|
struct make_impl<string_tag> {
|
||
|
template <typename ...Chars>
|
||
|
static constexpr auto apply(Chars const& ...) {
|
||
|
return hana::string<hana::value<Chars>()...>{};
|
||
|
}
|
||
|
};
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
// BOOST_HANA_STRING
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
namespace string_detail {
|
||
|
template <typename S, std::size_t ...N>
|
||
|
constexpr string<S::get()[N]...>
|
||
|
prepare_impl(S, std::index_sequence<N...>)
|
||
|
{ return {}; }
|
||
|
|
||
|
template <typename S>
|
||
|
constexpr decltype(auto) prepare(S s) {
|
||
|
return prepare_impl(s,
|
||
|
std::make_index_sequence<sizeof(S::get()) - 1>{});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#define BOOST_HANA_STRING(s) \
|
||
|
(::boost::hana::string_detail::prepare([]{ \
|
||
|
struct tmp { \
|
||
|
static constexpr decltype(auto) get() { return s; } \
|
||
|
}; \
|
||
|
return tmp{}; \
|
||
|
}())) \
|
||
|
/**/
|
||
|
|
||
|
#ifdef BOOST_HANA_CONFIG_ENABLE_STRING_UDL
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
// _s user-defined literal
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
namespace literals {
|
||
|
template <typename CharT, CharT ...s>
|
||
|
constexpr auto operator"" _s() {
|
||
|
static_assert(std::is_same<CharT, char>::value,
|
||
|
"hana::string: Only narrow string literals are supported with "
|
||
|
"the _s string literal right now. See https://goo.gl/fBbKD7 "
|
||
|
"if you need support for fancier types of compile-time strings.");
|
||
|
return hana::string_c<s...>;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
// Operators
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
namespace detail {
|
||
|
template <>
|
||
|
struct comparable_operators<string_tag> {
|
||
|
static constexpr bool value = true;
|
||
|
};
|
||
|
template <>
|
||
|
struct orderable_operators<string_tag> {
|
||
|
static constexpr bool value = true;
|
||
|
};
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
// to<char const*>
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
template <>
|
||
|
struct to_impl<char const*, string_tag> {
|
||
|
template <char ...c>
|
||
|
static constexpr char const* apply(string<c...> const&)
|
||
|
{ return string<c...>::c_str(); }
|
||
|
};
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
// Comparable
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
template <>
|
||
|
struct equal_impl<string_tag, string_tag> {
|
||
|
template <typename S>
|
||
|
static constexpr auto apply(S const&, S const&)
|
||
|
{ return hana::true_c; }
|
||
|
|
||
|
template <typename S1, typename S2>
|
||
|
static constexpr auto apply(S1 const&, S2 const&)
|
||
|
{ return hana::false_c; }
|
||
|
};
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
// Orderable
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
template <>
|
||
|
struct less_impl<string_tag, string_tag> {
|
||
|
template <char ...s1, char ...s2>
|
||
|
static constexpr auto
|
||
|
apply(string<s1...> const&, string<s2...> const&) {
|
||
|
// We put a '\0' at the end only to avoid empty arrays.
|
||
|
constexpr char const c_str1[] = {s1..., '\0'};
|
||
|
constexpr char const c_str2[] = {s2..., '\0'};
|
||
|
return hana::bool_c<detail::lexicographical_compare(
|
||
|
c_str1, c_str1 + sizeof...(s1),
|
||
|
c_str2, c_str2 + sizeof...(s2)
|
||
|
)>;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
// Monoid
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
template <>
|
||
|
struct plus_impl<string_tag, string_tag> {
|
||
|
template <char ...s1, char ...s2>
|
||
|
static constexpr auto
|
||
|
apply(string<s1...> const&, string<s2...> const&) {
|
||
|
return string<s1..., s2...>{};
|
||
|
}
|
||
|
};
|
||
|
|
||
|
template <>
|
||
|
struct zero_impl<string_tag> {
|
||
|
static constexpr auto apply() {
|
||
|
return string<>{};
|
||
|
}
|
||
|
};
|
||
|
|
||
|
template <char ...s1, char ...s2>
|
||
|
constexpr auto operator+(string<s1...> const&, string<s2...> const&) {
|
||
|
return hana::string<s1..., s2...>{};
|
||
|
}
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
// Foldable
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
template <>
|
||
|
struct unpack_impl<string_tag> {
|
||
|
template <char ...s, typename F>
|
||
|
static constexpr decltype(auto) apply(string<s...> const&, F&& f)
|
||
|
{ return static_cast<F&&>(f)(char_<s>{}...); }
|
||
|
};
|
||
|
|
||
|
template <>
|
||
|
struct length_impl<string_tag> {
|
||
|
template <char ...s>
|
||
|
static constexpr auto apply(string<s...> const&)
|
||
|
{ return hana::size_c<sizeof...(s)>; }
|
||
|
};
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
// Iterable
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
template <>
|
||
|
struct front_impl<string_tag> {
|
||
|
template <char x, char ...xs>
|
||
|
static constexpr auto apply(string<x, xs...> const&)
|
||
|
{ return hana::char_c<x>; }
|
||
|
};
|
||
|
|
||
|
template <>
|
||
|
struct drop_front_impl<string_tag> {
|
||
|
template <std::size_t N, char ...xs, std::size_t ...i>
|
||
|
static constexpr auto helper(string<xs...> const&, std::index_sequence<i...>) {
|
||
|
constexpr char s[] = {xs...};
|
||
|
return hana::string_c<s[i + N]...>;
|
||
|
}
|
||
|
|
||
|
template <char ...xs, typename N>
|
||
|
static constexpr auto apply(string<xs...> const& s, N const&) {
|
||
|
return helper<N::value>(s, std::make_index_sequence<
|
||
|
N::value < sizeof...(xs) ? sizeof...(xs) - N::value : 0
|
||
|
>{});
|
||
|
}
|
||
|
|
||
|
template <typename N>
|
||
|
static constexpr auto apply(string<> const& s, N const&)
|
||
|
{ return s; }
|
||
|
};
|
||
|
|
||
|
template <>
|
||
|
struct is_empty_impl<string_tag> {
|
||
|
template <char ...s>
|
||
|
static constexpr auto apply(string<s...> const&)
|
||
|
{ return hana::bool_c<sizeof...(s) == 0>; }
|
||
|
};
|
||
|
|
||
|
template <>
|
||
|
struct at_impl<string_tag> {
|
||
|
template <char ...s, typename N>
|
||
|
static constexpr auto apply(string<s...> const&, N const&) {
|
||
|
// We put a '\0' at the end to avoid an empty array.
|
||
|
constexpr char characters[] = {s..., '\0'};
|
||
|
constexpr auto n = N::value;
|
||
|
return hana::char_c<characters[n]>;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
// Searchable
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
template <>
|
||
|
struct contains_impl<string_tag> {
|
||
|
template <char ...s, typename C>
|
||
|
static constexpr auto
|
||
|
helper(string<s...> const&, C const&, hana::true_) {
|
||
|
constexpr char const characters[] = {s..., '\0'};
|
||
|
constexpr char c = hana::value<C>();
|
||
|
return hana::bool_c<
|
||
|
detail::find(characters, characters + sizeof...(s), c)
|
||
|
!= characters + sizeof...(s)
|
||
|
>;
|
||
|
}
|
||
|
|
||
|
template <typename S, typename C>
|
||
|
static constexpr auto helper(S const&, C const&, hana::false_)
|
||
|
{ return hana::false_c; }
|
||
|
|
||
|
template <typename S, typename C>
|
||
|
static constexpr auto apply(S const& s, C const& c)
|
||
|
{ return helper(s, c, hana::bool_c<hana::Constant<C>::value>); }
|
||
|
};
|
||
|
|
||
|
template <>
|
||
|
struct find_impl<string_tag> {
|
||
|
template <char ...s, typename Char>
|
||
|
static constexpr auto apply(string<s...> const& str, Char const& c) {
|
||
|
return hana::if_(contains_impl<string_tag>::apply(str, c),
|
||
|
hana::just(c),
|
||
|
hana::nothing
|
||
|
);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
// Hashable
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
template <>
|
||
|
struct hash_impl<string_tag> {
|
||
|
template <typename String>
|
||
|
static constexpr auto apply(String const&) {
|
||
|
return hana::type_c<String>;
|
||
|
}
|
||
|
};
|
||
|
BOOST_HANA_NAMESPACE_END
|
||
|
|
||
|
#endif // !BOOST_HANA_STRING_HPP
|