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