RetroLinker
Linker for several 8-bit, 16-bit and 32-bit formats
Loading...
Searching...
No Matches
value.h
1#ifndef VALUE_H
2#define VALUE_H
3
4#include <iostream>
5#include <map>
6#include <sstream>
7#include <string>
8#include <variant>
9#include <vector>
10#include "../common.h"
11
12namespace Runtime
13{
15 class Value
16 {
17 public:
18 typedef struct { } Empty;
19 typedef std::string String;
20 typedef offset_t Integer;
21 typedef bool Logical;
22 typedef std::vector<Value> List;
23 typedef std::map<std::string, Value> Table;
24
25 std::variant<
26 Empty,
27 String,
28 Integer,
29 Logical,
30 List,
31 Table
32 > content;
33
34 Value() : content(Empty {}) { }
35 Value(const Empty& content) : content(Empty {}) { }
36 Value(const String& content) : content(content) { }
37 Value(const char * content) : content(String(content)) { }
38 Value(Integer content) : content(content) { }
39 explicit Value(Logical content) : content(content) { }
40 Value(const List& content) : content(content) { }
41 Value(const Table& content) : content(content) { }
42
43 static Value MakeList()
44 {
45 return Value(List{});
46 }
47
48 static Value MakeTable()
49 {
50 return Value(Table{});
51 }
52
53 bool IsEmpty() const
54 {
55 return std::holds_alternative<Empty>(content);
56 }
57
58 String * GetString()
59 {
60 return std::get_if<String>(&content);
61 }
62
63 const String * GetString() const
64 {
65 return std::get_if<String>(&content);
66 }
67
68 Integer * GetInteger()
69 {
70 return std::get_if<Integer>(&content);
71 }
72
73 const Integer * GetInteger() const
74 {
75 return std::get_if<Integer>(&content);
76 }
77
78 Logical * GetLogical()
79 {
80 return std::get_if<Logical>(&content);
81 }
82
83 const Logical * GetLogical() const
84 {
85 return std::get_if<Logical>(&content);
86 }
87
88 List * GetList()
89 {
90 return std::get_if<List>(&content);
91 }
92
93 const List * GetList() const
94 {
95 return std::get_if<List>(&content);
96 }
97
98 Table * GetTable()
99 {
100 return std::get_if<Table>(&content);
101 }
102
103 const Table * GetTable() const
104 {
105 return std::get_if<Table>(&content);
106 }
107
108 String ToString()
109 {
110 if(IsEmpty())
111 {
112 return "";
113 }
114 else if(String * string = GetString())
115 {
116 return *string;
117 }
118 else if(Integer * integer = GetInteger())
119 {
120 std::ostringstream oss;
121 oss << *integer;
122 return oss.str();
123 }
124 else if(Logical * logical = GetLogical())
125 {
126 return *logical ? "true" : "false";
127 }
128 else
129 {
130 Linker::FatalError("Fatal error: unable to convert value to string");
131 }
132 }
133
134 Integer ToInteger()
135 {
136 if(String * string = GetString())
137 {
138 const char * text;
139 int base;
140 if(starts_with(*string, "0x"))
141 {
142 text = string->c_str() + 2;
143 base = 16;
144 }
145 else if(starts_with(*string, "0o"))
146 {
147 text = string->c_str() + 2;
148 base = 8;
149 }
150 else if(starts_with(*string, "0b"))
151 {
152 text = string->c_str() + 2;
153 base = 2;
154 }
155 else if(starts_with(*string, "0"))
156 {
157 text = string->c_str() + 1;
158 base = 8;
159 }
160 else
161 {
162 text = string->c_str();
163 base = 10;
164 }
165
166 if(text[0] != '\0')
167 {
168 char * tail;
169 errno = 0;
170 offset_t result = strtoll(text, &tail, base);
171 if(tail[0] == '\0' && errno == 0)
172 {
173 return result;
174 }
175 }
176 }
177 else if(Integer * integer = GetInteger())
178 {
179 return *integer;
180 }
181
182 Linker::FatalError("Fatal error: unable to convert value to integer");
183 }
184
185 Value& operator[](Value value)
186 {
187 if(Table * table = GetTable())
188 {
189 return (*table)[value.ToString()];
190 }
191 else if(List * list = GetList())
192 {
193 return (*list)[value.ToInteger()];
194 }
195 else
196 {
197 Linker::FatalError("Fatal error: not an aggregate type, cannot call [] operator");
198 }
199 }
200
201 const Value& operator[](Value value) const
202 {
203 if(const Table * table = GetTable())
204 {
205 return table->find(value.ToString())->second;
206 }
207 else if(const List * list = GetList())
208 {
209 return (*list)[value.ToInteger()];
210 }
211 else
212 {
213 Linker::FatalError("Fatal error: not an aggregate type, cannot call [] operator");
214 }
215 }
216 };
217
218 static inline std::ostream& operator <<(std::ostream& out, const Value& value)
219 {
220 std::visit([&out](auto&& value)
221 {
222 using T = std::decay_t<decltype(value)>;
223 if constexpr(std::is_same_v<T, Value::Empty>)
224 {
225 out << "null";
226 }
227 else if constexpr(std::is_same_v<T, Value::String>)
228 {
229 out << '"' << value << '"';
230 }
231 else if constexpr(std::is_same_v<T, Value::Integer>)
232 {
233 out << value;
234 }
235 else if constexpr(std::is_same_v<T, Value::Logical>)
236 {
237 out << (value ? "true" : "false");
238 }
239 else if constexpr(std::is_same_v<T, Value::List>)
240 {
241 out << '[';
242 bool started = false;
243 for(auto& element : value)
244 {
245 if(started)
246 out << ", ";
247 else
248 started = true;
249 out << element;
250 }
251 out << ']';
252 }
253 else if constexpr(std::is_same_v<T, Value::Table>)
254 {
255 out << '{';
256 bool started = false;
257 for(auto& pair : value)
258 {
259 if(started)
260 out << ", ";
261 else
262 started = true;
263 out << '"' << pair.first << "\": " << pair.second;
264 }
265 out << '}';
266 }
267 else
268 {
269 static_assert(false);
270 }
271 }, value.content);
272 return out;
273 }
274}
275
276#endif /* VALUE_H */
A YAML/JSON-like data format.
Definition value.h:16
Definition value.h:18