1 /*
2 * Copyright (c) 2016, Facebook, Inc.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the root directory of this source tree. An additional grant
7 * of patent rights can be found in the PATENTS file in the same directory.
8 */
9
10 #ifndef FATAL_INCLUDE_fatal_test_string_h
11 #define FATAL_INCLUDE_fatal_test_string_h
12
13 #include <fatal/string/string_view.h>
14 #include <fatal/time/time.h>
15 #include <fatal/type/tag.h>
16
17 #include <chrono>
18 #include <stdexcept>
19 #include <string>
20 #include <type_traits>
21
22 #include <cstring>
23
24 namespace fatal {
25
append(std::string & out,bool from)26 inline void append(std::string &out, bool from) {
27 out.append(from ? "true" : "false");
28 }
29
30 template <typename T, typename = decltype(std::to_string(std::declval<T>()))>
append(std::string & out,T from)31 void append(std::string &out, T from) {
32 out.append(std::to_string(from));
33 }
34
35 template <typename R, typename P>
append(std::string & out,std::chrono::duration<R,P> from)36 void append(std::string &out, std::chrono::duration<R, P> from) {
37 append(out, from.count());
38 out.append(time::suffix(from));
39 }
40
append(std::string & out,std::string const & from)41 inline void append(std::string &out, std::string const &from) {
42 out.append(from);
43 }
44
append(std::string & out,string_view from)45 inline void append(std::string &out, string_view from) {
46 out.append(from.data(), from.size());
47 }
48
append(std::string & out,char from)49 inline void append(std::string &out, char from) {
50 out.push_back(from);
51 }
52
append(std::string & out,char const * from)53 inline void append(std::string &out, char const *from) {
54 out.append(from);
55 }
56
57 namespace detail {
58 namespace string_impl {
59
parse(tag<bool>,std::string const & from)60 inline bool parse(tag<bool>, std::string const &from) {
61 // TODO: use a compile-time trie??
62 if (from == "true") {
63 return true;
64 }
65
66 if (from == "false") {
67 return false;
68 }
69
70 throw std::invalid_argument("unrecognized boolean");
71 }
72
parse(tag<short>,std::string const & from)73 inline short parse(tag<short>, std::string const &from) {
74 return static_cast<short>(std::stoi(from));
75 }
76
parse(tag<int>,std::string const & from)77 inline int parse(tag<int>, std::string const &from) {
78 return std::stoi(from);
79 }
80
parse(tag<long>,std::string const & from)81 inline long parse(tag<long>, std::string const &from) {
82 return std::stol(from);
83 }
84
parse(tag<long long>,std::string const & from)85 inline long long parse(tag<long long>, std::string const &from) {
86 return std::stoll(from);
87 }
88
parse(tag<unsigned long>,std::string const & from)89 inline unsigned long parse(tag<unsigned long>, std::string const &from) {
90 return std::stoul(from);
91 }
92
parse(tag<unsigned long long>,std::string const & from)93 inline unsigned long long parse(
94 tag<unsigned long long>, std::string const &from
95 ) {
96 return std::stoull(from);
97 }
98
parse(tag<float>,std::string const & from)99 inline float parse(tag<float>, std::string const &from) {
100 return std::stof(from);
101 }
102
parse(tag<double>,std::string const & from)103 inline double parse(tag<double>, std::string const &from) {
104 return std::stod(from);
105 }
106
parse(tag<long double>,std::string const & from)107 inline long double parse(tag<long double>, std::string const &from) {
108 return std::stold(from);
109 }
110
parse(tag<std::string>,std::string const & from)111 inline std::string parse(tag<std::string>, std::string const &from) {
112 return from;
113 }
114
to_string_impl(std::string &)115 void to_string_impl(std::string &) {}
116
117 template <typename T, typename... Args>
to_string_impl(std::string & out,T && value,Args &&...args)118 void to_string_impl(std::string &out, T &&value, Args &&...args) {
119 append(out, std::forward<T>(value));
120
121 to_string_impl(out, std::forward<Args>(args)...);
122 }
123
124 } // namespace string_impl {
125 } // namespace detail {
126
127 // for internal tests only - no guaranteed efficiency
128 // TODO: TEST
129 template <typename To>
parse(std::string const & from)130 To parse(std::string const &from) {
131 return detail::string_impl::parse(tag<To>(), from);
132 }
133
134 // for internal tests only - no guaranteed efficiency
135 // TODO: TEST
136 template <typename... Args>
append_to_string(std::string & out,Args &&...args)137 std::string &append_to_string(std::string &out, Args &&...args) {
138 detail::string_impl::to_string_impl(out, std::forward<Args>(args)...);
139
140 return out;
141 }
142
143 // TODO: TEST
144 template <typename... Args>
to_string(Args &&...args)145 std::string to_string(Args &&...args) {
146 std::string out;
147
148 append_to_string(out, std::forward<Args>(args)...);
149
150 return out;
151 }
152
to_string(std::string const & s)153 std::string const &to_string(std::string const &s) { return s; }
to_string(std::string & s)154 std::string &to_string(std::string &s) { return s; }
to_string(std::string && s)155 std::string &&to_string(std::string &&s) { return std::move(s); }
156
157 } // namespace fatal {
158
159 #endif // FATAL_INCLUDE_fatal_test_string_h
160