-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathvalue.h
342 lines (275 loc) · 8.57 KB
/
value.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
/*
* Copyright (C) Alex Nekipelov ([email protected])
* License: BSD
*/
#ifndef CPPTL_VALUE_H
#define CPPTL_VALUE_H
#include <typeinfo>
#include <string>
#include <iostream>
#include <map>
#include <vector>
#include <stdint.h>
#include <boost/shared_ptr.hpp>
#include <boost/scoped_ptr.hpp>
namespace cpptl {
class Holder;
class Value {
public:
enum Type {
Null = 0,
// Base types
Bool = 1,
Int = 2,
Integer = 2, // alias for Int
Double = 3,
String = 4,
Array = 5,
Object = 6,
UserType = 7,
UnsafeString = 8,
Last = 0xFFFFFFFF
};
struct ObjectTag {};
struct ArrayTag {};
struct UnsafeStringTag {};
Value();
Value(Type type);
Value(const struct ObjectTag &);
Value(const struct ArrayTag &);
Value(bool b);
Value(int i);
Value(unsigned int i);
Value(int64_t ii);
Value(uint64_t ii);
Value(double d);
Value(const char *s);
Value(const std::string &s);
Value(const char *s, const UnsafeStringTag &);
Value(const std::string &s, const UnsafeStringTag &);
~Value();
Type type() const;
bool isNull() const;
bool isObject() const;
bool isArray() const;
bool isNumeric() const;
bool toBool() const;
int toInt() const;
unsigned int toUInt() const;
int64_t toInt64() const;
uint64_t toUInt64() const;
double toDouble() const;
std::string toString() const;
//TODO get(index), get(name), isValidIndex(int), size
//TODO isEmpty for NULL, empty string, empty object, empty array...
//TODO append for array, object
/* object and array */
size_t size() const;
bool isEmpty() const;
/* object */
bool hasMember(const std::string &name) const;
Value member(const std::string &name);
const Value member(const std::string &name) const;
Value &operator[] (const std::string &propertyName);
const Value operator[] (const std::string &propertyName) const;
/* array */
Value append(const Value &value);
Value at(size_t arrayIndex);
const Value at(size_t arrayIndex) const;
Value &operator[] (size_t arrayIndex);
const Value operator[] (size_t arrayIndex) const;
class ValueIteratorPrivate;
class ValueIterator {
public:
ValueIterator(const Value &value);
~ValueIterator();
bool hasNext() const;
bool hasPrev() const;
const Value &next();
const Value &prev();
Value value() const;
private:
boost::scoped_ptr<ValueIteratorPrivate> pimpl;
};
template<typename T>
static Value fromValue(const T &value);
template<typename T>
T toValue() const;
/* for debug */
void dump(int level = 0) const;
protected:
static int64_t safeCastToNumber(const Value &);
static bool convertHelper(const Value &v, Value::Type type, void *ptr);
private:
struct UserTypeHolderBase {
virtual ~UserTypeHolderBase() {};
virtual const std::type_info &type() const = 0;
};
template<typename T>
struct UserTypeHolder : public UserTypeHolderBase {
UserTypeHolder(const T &t) : t(t) {}
virtual const std::type_info &type() const {
return typeid(T);
}
T t;
private:
UserTypeHolder();
UserTypeHolder(const Holder &);
UserTypeHolder & operator = (const Holder &);
};
class Holder {
public:
Holder();
~Holder();
union {
bool b;
int64_t i;
double d;
std::string *string;
std::vector<Value> *array;
std::map<std::string, Value> *members;
void *ptr;
UserTypeHolderBase *userType;
} data;
Value::Type type;
};
mutable boost::shared_ptr<Holder> holder;
friend class ValueIterator;
friend Value operator + (const Value &lhs, const Value &rhs);
friend Value operator - (const Value &lhs, const Value &rhs);
friend Value operator * (const Value &lhs, const Value &rhs);
friend Value operator / (const Value &lhs, const Value &rhs);
friend bool operator == (const Value &lhs, const Value &rhs);
friend bool operator != (const Value &lhs, const Value &rhs);
friend bool operator >= (const Value &lhs, const Value &rhs);
friend bool operator > (const Value &lhs, const Value &rhs);
friend bool operator <= (const Value &lhs, const Value &rhs);
friend bool operator < (const Value &lhs, const Value &rhs);
};
Value operator + (const Value &lhs, const Value &rhs);
Value operator - (const Value &lhs, const Value &rhs);
Value operator * (const Value &lhs, const Value &rhs);
Value operator / (const Value &lhs, const Value &rhs);
bool operator == (const Value &lhs, const Value &rhs);
bool operator != (const Value &lhs, const Value &rhs);
bool operator >= (const Value &lhs, const Value &rhs);
bool operator > (const Value &lhs, const Value &rhs);
bool operator <= (const Value &lhs, const Value &rhs);
bool operator < (const Value &lhs, const Value &rhs);
template<typename T>
struct ValueTypeInfo {
enum {
id = Value::UserType
};
typedef T value_type;
static Value::Type typeId() {
return static_cast<Value::Type>(id);
}
};
#define VALUE_DECLARE_METATYPE(TYPE,STORE_TYPE,NAME) \
template<> \
struct ValueTypeInfo<TYPE> { \
enum { \
id = Value::NAME \
}; \
typedef STORE_TYPE value_type; \
static Value::Type typeId() { \
return static_cast<Value::Type>(id); \
} \
};
VALUE_DECLARE_METATYPE(bool, bool, Value::Bool)
VALUE_DECLARE_METATYPE(int, int64_t, Value::Int)
VALUE_DECLARE_METATYPE(unsigned int, uint64_t, Value::Int)
VALUE_DECLARE_METATYPE(int64_t,int64_t, Value::Int)
VALUE_DECLARE_METATYPE(uint64_t, uint64_t, Value::Int)
VALUE_DECLARE_METATYPE(double, double, Value::Double)
VALUE_DECLARE_METATYPE(std::string, std::string, Value::String)
#undef VALUE_DECLARE_METATYPE
template<typename T>
T Value::toValue() const
{
if( holder && isNull() == false )
{
Value::Type toType = ValueTypeInfo<T>::typeId();
if( toType == UserType )
{
if( typeid(T) == holder->data.userType->type() ) {
return static_cast<UserTypeHolder<T>*>( holder->data.userType )->t;
}
}
else if( toType == type() )
{
switch(type())
{
case String:
case Array:
case Object:
case UserType:
return *reinterpret_cast<const typename ValueTypeInfo<T>::value_type *>( holder->data.ptr );
default:
return *reinterpret_cast<const typename ValueTypeInfo<T>::value_type *>( &holder->data );
}
}
else if( type() == Array || type() == Object )
{
return T(); // Can`t convert
}
else
{
typename ValueTypeInfo<T>::value_type t;
if( Value::convertHelper(*this, ValueTypeInfo<T>::typeId(), &t) )
return t;
}
}
//assert(false);
std::cerr << "invalid type " << type() << " " << ValueTypeInfo<T>::typeId() << std::endl;
return T();
}
template<>
inline bool Value::toValue<bool>() const
{
if( holder && isNull() == false )
{
if( type() == Array || type() == Object || type() == UserType )
return true;
else if( type() == Bool )
return holder->data.b;
int64_t result;
convertHelper(*this, ValueTypeInfo<bool>::typeId(), &result);
return result != 0;
}
else
{
return false;
}
}
#define VALUE_FROM_VALUE_HELPER(TYPE) \
template<> \
inline Value Value::fromValue<TYPE>(const TYPE &value) { \
return Value(value); \
} \
VALUE_FROM_VALUE_HELPER(Value)
VALUE_FROM_VALUE_HELPER(bool)
VALUE_FROM_VALUE_HELPER(int)
VALUE_FROM_VALUE_HELPER(unsigned int)
VALUE_FROM_VALUE_HELPER(int64_t)
VALUE_FROM_VALUE_HELPER(uint64_t)
VALUE_FROM_VALUE_HELPER(double)
VALUE_FROM_VALUE_HELPER(std::string)
#undef VALUE_FROM_VALUE_HELPER
template<>
inline Value Value::fromValue< std::vector<Value> >(const std::vector<Value> &vector) {
Value result(Value::Array);
result.holder->data.array->assign(vector.begin(), vector.end());
return result;
}
template<typename T>
inline Value Value::fromValue(const T &value) {
Value result;
result.holder.reset( new Holder );
result.holder->type = UserType;
result.holder->data.userType = new UserTypeHolder<T>(value);
return result;
}
} // namespace cpptl
#endif // CPPTL_VALUE_H