Darwin Neuroevolution Framework
stringify.h
1 // Copyright 2018 The Darwin Neuroevolution Framework Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #pragma once
16 
17 #include "utils.h"
18 #include "exception.h"
19 #include "io_utils.h"
20 
21 #include <assert.h>
22 #include <initializer_list>
23 #include <map>
24 #include <sstream>
25 #include <string>
26 #include <type_traits>
27 #include <unordered_map>
28 #include <utility>
29 #include <vector>
30 using namespace std;
31 
32 // TODO: test cases
33 
34 namespace core {
35 
36 template <class T>
37 struct TypeTag {};
38 
41 template <class T>
42 class Stringify {
43  public:
44  virtual ~Stringify() = default;
45 
47  virtual string toString(const T& value) const = 0;
48 
50  virtual T fromString(const string& str) const = 0;
51 
53  virtual vector<string> knownValues() const = 0;
54 };
55 
58 template <class T>
59 class GenericStringify : public Stringify<T> {
60  public:
61  string toString(const T& value) const override {
62  stringstream ss;
63  ss << std::boolalpha << value;
64  return ss.str();
65  }
66 
67  T fromString(const string& str) const override {
68  stringstream ss(str);
69  T value = {};
70  ss >> std::boolalpha >> value;
71  if (!ss.eof()) {
72  // make sure the only thing left, if any, are whitespaces
73  ss >> std::ws;
74  }
75  if (ss.fail() || !ss.eof())
76  throw Exception("invalid value string: '%s'", str.c_str());
77  return value;
78  }
79 
80  vector<string> knownValues() const override { return {}; }
81 };
82 
84 template <class T>
85 class StringifyKnownValues : public Stringify<T> {
86  public:
87  StringifyKnownValues(initializer_list<pair<T, string>> known_values) {
88  for (const auto& value_str : known_values) {
89  CHECK(value_to_string_.insert(value_str).second);
90  CHECK(string_to_value_.insert({ value_str.second, value_str.first }).second);
91  }
92  }
93 
94  string toString(const T& value) const override {
95  auto it = value_to_string_.find(value);
96  if (it == value_to_string_.end())
97  throw Exception("Unknown value");
98  return it->second;
99  }
100 
101  T fromString(const string& str) const override {
102  auto it = string_to_value_.find(str);
103  if (it == string_to_value_.end()) {
104  stringstream msg;
105  msg << "Unknown value: '" << str << "'\n"
106  << " Valid values: [";
107  bool first = true;
108  for (const auto& kv : string_to_value_) {
109  if (!first) {
110  msg << ", ";
111  }
112  msg << "'" << kv.first << "'";
113  first = false;
114  }
115  msg << "]\n";
116  throw Exception(msg.str());
117  }
118  return it->second;
119  }
120 
121  vector<string> knownValues() const override {
122  vector<string> values;
123  for (const auto& kv : string_to_value_)
124  values.push_back(kv.first);
125  return values;
126  }
127 
128  private:
129  unordered_map<T, string> value_to_string_;
130  map<string, T> string_to_value_;
131 };
132 
135 class StringifyStrings : public Stringify<string> {
136  public:
137  string toString(const string& value) const override { return value; }
138 
139  string fromString(const string& str) const override { return str; }
140 
141  vector<string> knownValues() const override { return {}; }
142 };
143 
144 // the default "catch all" using the GenericStringify<T>
145 template <class T>
146 auto customStringify(core::TypeTag<T>) {
147  static auto stringify = new GenericStringify<T>();
148  return stringify;
149 }
150 
151 inline auto customStringify(core::TypeTag<bool>) {
152  static auto stringify = new StringifyKnownValues<bool>{
153  { true, "true" },
154  { false, "false" },
155  };
156  return stringify;
157 }
158 
159 inline auto customStringify(core::TypeTag<string>) {
160  static auto stringify = new StringifyStrings();
161  return stringify;
162 }
163 
165 template <class T>
167  return customStringify(TypeTag<T>{});
168 }
169 
171 template <class T>
172 string toString(const T& value) {
173  return stringify<T>()->toString(value);
174 }
175 
177 template <class T>
178 T fromString(const string& str) {
179  return stringify<T>()->fromString(str);
180 }
181 
183 template <class T>
184 vector<string> knownValues() {
185  return stringify<T>()->knownValues();
186 }
187 
188 } // namespace core
string toString(const T &value) const override
Value to string conversion.
Definition: stringify.h:94
T fromString(const string &str) const override
String to value conversion.
Definition: stringify.h:101
vector< string > knownValues() const override
The list of known values for type T, if available (for example enumerations)
Definition: stringify.h:121
The base for exception types in the Darwin framework.
Definition: exception.h:27
Maps strings unmodified (going through I/O operators doesn&#39;t handle strings with embedded whitespace)...
Definition: stringify.h:135
Generic utilities.
Definition: exception.h:24
STL namespace.
T fromString(const string &str)
Convenience helper to parse a string value.
Definition: stringify.h:178
Interface for converting values to/from strings (the default implementation uses iostream I/O operato...
Definition: stringify.h:42
Use iostream I/O operators for the argument type.
Definition: stringify.h:59
T fromString(const string &str) const override
String to value conversion.
Definition: stringify.h:67
string toString(const T &value)
Convenience helper to stringify a value.
Definition: stringify.h:172
Handles types with a fixed, known set of values (enumerations for example)
Definition: stringify.h:85
vector< string > knownValues()
Convenience helper to return the set of known values.
Definition: stringify.h:184
const Stringify< T > * stringify()
Returns the stringifier for type T.
Definition: stringify.h:166
vector< string > knownValues() const override
The list of known values for type T, if available (for example enumerations)
Definition: stringify.h:141
string toString(const T &value) const override
Value to string conversion.
Definition: stringify.h:61
vector< string > knownValues() const override
The list of known values for type T, if available (for example enumerations)
Definition: stringify.h:80