• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*!
2 @file
3 Defines `boost::hana::string`.
4 
5 @copyright Louis Dionne 2013-2017
6 Distributed under the Boost Software License, Version 1.0.
7 (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
8  */
9 
10 #ifndef BOOST_HANA_STRING_HPP
11 #define BOOST_HANA_STRING_HPP
12 
13 #include <boost/hana/fwd/string.hpp>
14 
15 #include <boost/hana/bool.hpp>
16 #include <boost/hana/concept/constant.hpp>
17 #include <boost/hana/config.hpp>
18 #include <boost/hana/core/make.hpp>
19 #include <boost/hana/detail/algorithm.hpp>
20 #include <boost/hana/detail/operators/adl.hpp>
21 #include <boost/hana/detail/operators/comparable.hpp>
22 #include <boost/hana/detail/operators/iterable.hpp>
23 #include <boost/hana/detail/operators/orderable.hpp>
24 #include <boost/hana/fwd/at.hpp>
25 #include <boost/hana/fwd/contains.hpp>
26 #include <boost/hana/fwd/core/tag_of.hpp>
27 #include <boost/hana/fwd/core/to.hpp>
28 #include <boost/hana/fwd/drop_front.hpp>
29 #include <boost/hana/fwd/equal.hpp>
30 #include <boost/hana/fwd/find.hpp>
31 #include <boost/hana/fwd/front.hpp>
32 #include <boost/hana/fwd/hash.hpp>
33 #include <boost/hana/fwd/is_empty.hpp>
34 #include <boost/hana/fwd/length.hpp>
35 #include <boost/hana/fwd/less.hpp>
36 #include <boost/hana/fwd/plus.hpp>
37 #include <boost/hana/fwd/unpack.hpp>
38 #include <boost/hana/fwd/zero.hpp>
39 #include <boost/hana/if.hpp>
40 #include <boost/hana/integral_constant.hpp>
41 #include <boost/hana/optional.hpp>
42 #include <boost/hana/type.hpp>
43 
44 #include <utility>
45 #include <cstddef>
46 #include <type_traits>
47 
48 
49 BOOST_HANA_NAMESPACE_BEGIN
50     //////////////////////////////////////////////////////////////////////////
51     // string<>
52     //////////////////////////////////////////////////////////////////////////
53     //! @cond
54     namespace detail {
55         template <char ...s>
56         constexpr char const string_storage[sizeof...(s) + 1] = {s..., '\0'};
57     }
58 
59     template <char ...s>
60     struct string
61         : detail::operators::adl<string<s...>>
62         , detail::iterable_operators<string<s...>>
63     {
c_strstring64         static constexpr char const* c_str() {
65             return &detail::string_storage<s...>[0];
66         }
67     };
68     //! @endcond
69 
70     template <char ...s>
71     struct tag_of<string<s...>> {
72         using type = string_tag;
73     };
74 
75     //////////////////////////////////////////////////////////////////////////
76     // make<string_tag>
77     //////////////////////////////////////////////////////////////////////////
78     template <>
79     struct make_impl<string_tag> {
80         template <typename ...Chars>
applymake_impl81         static constexpr auto apply(Chars const& ...) {
82             return hana::string<hana::value<Chars>()...>{};
83         }
84     };
85 
86     //////////////////////////////////////////////////////////////////////////
87     // BOOST_HANA_STRING
88     //////////////////////////////////////////////////////////////////////////
89     namespace string_detail {
90         template <typename S, std::size_t ...N>
91         constexpr string<S::get()[N]...>
prepare_impl(S,std::index_sequence<N...>)92         prepare_impl(S, std::index_sequence<N...>)
93         { return {}; }
94 
95         template <typename S>
prepare(S s)96         constexpr decltype(auto) prepare(S s) {
97             return prepare_impl(s,
98                 std::make_index_sequence<sizeof(S::get()) - 1>{});
99         }
100     }
101 
102 #define BOOST_HANA_STRING(s)                                                \
103     (::boost::hana::string_detail::prepare([]{                              \
104         struct tmp {                                                        \
105             static constexpr decltype(auto) get() { return s; }             \
106         };                                                                  \
107         return tmp{};                                                       \
108     }()))                                                                   \
109 /**/
110 
111 #ifdef BOOST_HANA_CONFIG_ENABLE_STRING_UDL
112     //////////////////////////////////////////////////////////////////////////
113     // _s user-defined literal
114     //////////////////////////////////////////////////////////////////////////
115     namespace literals {
116         template <typename CharT, CharT ...s>
operator ""_s()117         constexpr auto operator"" _s() {
118             static_assert(std::is_same<CharT, char>::value,
119             "hana::string: Only narrow string literals are supported with "
120             "the _s string literal right now. See https://goo.gl/fBbKD7 "
121             "if you need support for fancier types of compile-time strings.");
122             return hana::string_c<s...>;
123         }
124     }
125 #endif
126 
127     //////////////////////////////////////////////////////////////////////////
128     // Operators
129     //////////////////////////////////////////////////////////////////////////
130     namespace detail {
131         template <>
132         struct comparable_operators<string_tag> {
133             static constexpr bool value = true;
134         };
135         template <>
136         struct orderable_operators<string_tag> {
137             static constexpr bool value = true;
138         };
139     }
140 
141     //////////////////////////////////////////////////////////////////////////
142     // to<char const*>
143     //////////////////////////////////////////////////////////////////////////
144     template <>
145     struct to_impl<char const*, string_tag> {
146         template <char ...c>
applyto_impl147         static constexpr char const* apply(string<c...> const&)
148         { return string<c...>::c_str(); }
149     };
150 
151     //////////////////////////////////////////////////////////////////////////
152     // to<string_tag>
153     //////////////////////////////////////////////////////////////////////////
154     namespace detail {
cx_strlen(char const * s)155         constexpr std::size_t cx_strlen(char const* s) {
156           std::size_t n = 0u;
157           while (*s != '\0')
158             ++s, ++n;
159           return n;
160         }
161 
162         template <typename S, std::size_t ...I>
expand(std::index_sequence<I...>)163         constexpr hana::string<hana::value<S>()[I]...> expand(std::index_sequence<I...>)
164         { return {}; }
165     }
166 
167     template <typename IC>
168     struct to_impl<hana::string_tag, IC, hana::when<
169         hana::Constant<IC>::value &&
170         std::is_convertible<typename IC::value_type, char const*>::value
171     >> {
172         template <typename S>
applyto_impl173         static constexpr auto apply(S const&) {
174             constexpr char const* s = hana::value<S>();
175             constexpr std::size_t len = detail::cx_strlen(s);
176             return detail::expand<S>(std::make_index_sequence<len>{});
177         }
178     };
179 
180     //////////////////////////////////////////////////////////////////////////
181     // Comparable
182     //////////////////////////////////////////////////////////////////////////
183     template <>
184     struct equal_impl<string_tag, string_tag> {
185         template <typename S>
applyequal_impl186         static constexpr auto apply(S const&, S const&)
187         { return hana::true_c; }
188 
189         template <typename S1, typename S2>
applyequal_impl190         static constexpr auto apply(S1 const&, S2 const&)
191         { return hana::false_c; }
192     };
193 
194     //////////////////////////////////////////////////////////////////////////
195     // Orderable
196     //////////////////////////////////////////////////////////////////////////
197     template <>
198     struct less_impl<string_tag, string_tag> {
199         template <char ...s1, char ...s2>
200         static constexpr auto
applyless_impl201         apply(string<s1...> const&, string<s2...> const&) {
202             // We put a '\0' at the end only to avoid empty arrays.
203             constexpr char const c_str1[] = {s1..., '\0'};
204             constexpr char const c_str2[] = {s2..., '\0'};
205             return hana::bool_c<detail::lexicographical_compare(
206                 c_str1, c_str1 + sizeof...(s1),
207                 c_str2, c_str2 + sizeof...(s2)
208             )>;
209         }
210     };
211 
212     //////////////////////////////////////////////////////////////////////////
213     // Monoid
214     //////////////////////////////////////////////////////////////////////////
215     template <>
216     struct plus_impl<string_tag, string_tag> {
217         template <char ...s1, char ...s2>
218         static constexpr auto
applyplus_impl219         apply(string<s1...> const&, string<s2...> const&) {
220             return string<s1..., s2...>{};
221         }
222     };
223 
224     template <>
225     struct zero_impl<string_tag> {
applyzero_impl226         static constexpr auto apply() {
227             return string<>{};
228         }
229     };
230 
231     template <char ...s1, char ...s2>
operator +(string<s1...> const &,string<s2...> const &)232     constexpr auto operator+(string<s1...> const&, string<s2...> const&) {
233         return hana::string<s1..., s2...>{};
234     }
235 
236     //////////////////////////////////////////////////////////////////////////
237     // Foldable
238     //////////////////////////////////////////////////////////////////////////
239     template <>
240     struct unpack_impl<string_tag> {
241         template <char ...s, typename F>
applyunpack_impl242         static constexpr decltype(auto) apply(string<s...> const&, F&& f)
243         { return static_cast<F&&>(f)(char_<s>{}...); }
244     };
245 
246     template <>
247     struct length_impl<string_tag> {
248         template <char ...s>
applylength_impl249         static constexpr auto apply(string<s...> const&)
250         { return hana::size_c<sizeof...(s)>; }
251     };
252 
253     //////////////////////////////////////////////////////////////////////////
254     // Iterable
255     //////////////////////////////////////////////////////////////////////////
256     template <>
257     struct front_impl<string_tag> {
258         template <char x, char ...xs>
applyfront_impl259         static constexpr auto apply(string<x, xs...> const&)
260         { return hana::char_c<x>; }
261     };
262 
263     template <>
264     struct drop_front_impl<string_tag> {
265         template <std::size_t N, char ...xs, std::size_t ...i>
helperdrop_front_impl266         static constexpr auto helper(string<xs...> const&, std::index_sequence<i...>) {
267             constexpr char s[] = {xs...};
268             return hana::string_c<s[i + N]...>;
269         }
270 
271         template <char ...xs, typename N>
applydrop_front_impl272         static constexpr auto apply(string<xs...> const& s, N const&) {
273             return helper<N::value>(s, std::make_index_sequence<
274                 (N::value < sizeof...(xs)) ? sizeof...(xs) - N::value : 0
275             >{});
276         }
277 
278         template <typename N>
applydrop_front_impl279         static constexpr auto apply(string<> const& s, N const&)
280         { return s; }
281     };
282 
283     template <>
284     struct is_empty_impl<string_tag> {
285         template <char ...s>
applyis_empty_impl286         static constexpr auto apply(string<s...> const&)
287         { return hana::bool_c<sizeof...(s) == 0>; }
288     };
289 
290     template <>
291     struct at_impl<string_tag> {
292         template <char ...s, typename N>
applyat_impl293         static constexpr auto apply(string<s...> const&, N const&) {
294             // We put a '\0' at the end to avoid an empty array.
295             constexpr char characters[] = {s..., '\0'};
296             constexpr auto n = N::value;
297             return hana::char_c<characters[n]>;
298         }
299     };
300 
301     //////////////////////////////////////////////////////////////////////////
302     // Searchable
303     //////////////////////////////////////////////////////////////////////////
304     template <>
305     struct contains_impl<string_tag> {
306         template <char ...s, typename C>
307         static constexpr auto
helpercontains_impl308         helper(string<s...> const&, C const&, hana::true_) {
309             constexpr char const characters[] = {s..., '\0'};
310             constexpr char c = hana::value<C>();
311             return hana::bool_c<
312                 detail::find(characters, characters + sizeof...(s), c)
313                     != characters + sizeof...(s)
314             >;
315         }
316 
317         template <typename S, typename C>
helpercontains_impl318         static constexpr auto helper(S const&, C const&, hana::false_)
319         { return hana::false_c; }
320 
321         template <typename S, typename C>
applycontains_impl322         static constexpr auto apply(S const& s, C const& c)
323         { return helper(s, c, hana::bool_c<hana::Constant<C>::value>); }
324     };
325 
326     template <>
327     struct find_impl<string_tag> {
328         template <char ...s, typename Char>
applyfind_impl329         static constexpr auto apply(string<s...> const& str, Char const& c) {
330             return hana::if_(contains_impl<string_tag>::apply(str, c),
331                 hana::just(c),
332                 hana::nothing
333             );
334         }
335     };
336 
337     //////////////////////////////////////////////////////////////////////////
338     // Hashable
339     //////////////////////////////////////////////////////////////////////////
340     template <>
341     struct hash_impl<string_tag> {
342         template <typename String>
applyhash_impl343         static constexpr auto apply(String const&) {
344             return hana::type_c<String>;
345         }
346     };
347 BOOST_HANA_NAMESPACE_END
348 
349 #endif // !BOOST_HANA_STRING_HPP
350