summaryrefslogtreecommitdiff
path: root/indra/llcommon/llsd.h
blob: 97bd6fe01cdd1d6ebbdcca014ec928d1ad603a0f (plain)
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
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
/** 
 * @file llsd.h
 * @brief LLSD flexible data system.
 *
 * Copyright (c) 2005-$CurrentYear$, Linden Research, Inc.
 * $License$
 */

#ifndef LL_LLSD_NEW_H
#define LL_LLSD_NEW_H

#include <map>
#include <string>
#include <vector>

#include "stdtypes.h"

#include "lldate.h"
#include "lluri.h"
#include "../llmath/lluuid.h"

/**
	LLSD provides a flexible data system similar to the data facilities of
	dynamic languages like Perl and Python.  It is created to support exchange
	of structured data between loosly coupled systems.  (Here, "loosly coupled"
	means not compiled together into the same module.)
	
	Data in such exchanges must be highly tollerant of changes on either side
	such as:
			- recompilation
			- implementation in a different langauge
			- addition of extra parameters
			- execution of older versions (with fewer parameters)

	To this aim, the C++ API of LLSD strives to be very easy to use, and to
	default to "the right thing" whereever possible.  It is extremely tollerant
	of errors and unexpected situations.
	
	The fundimental class is LLSD.  LLSD is a value holding object.  It holds
	one value that is either undefined, one of the scalar types, or a map or an
	array.  LLSD objects have value semantics (copying them copies the value,
	though it can be considered efficient, due to shareing.), and mutable.

	Undefined is the singular value given to LLSD objects that are not
	initialized with any data.  It is also used as the return value for
	operations that return an LLSD,
	
	The sclar data types are:
		- Boolean	- true or false
		- Integer	- a 32 bit signed integer
		- Real		- a 64 IEEE 754 floating point value
		- UUID		- a 128 unique value
		- String	- a sequence of zero or more Unicode chracters
		- Date		- an absolute point in time, UTC,
						with resolution to the second
		- URI		- a String that is a URI
		- Binary	- a sequence of zero or more octets (unsigned bytes)
	
	A map is a dictionary mapping String keys to LLSD values.  The keys are
	unique within a map, and have only one value (though that value could be
	an LLSD array).
	
	An array is a sequence of zero or more LLSD values.
	
	@nosubgrouping
*/

class LLSD
{
public:
		LLSD();		///< initially Undefined
		~LLSD();	///< this class may NOT be subclassed

	/** @name Copyable and Assignable */
	//@{
		LLSD(const LLSD&);
		void assign(const LLSD& other);
		LLSD& operator=(const LLSD& other)	{ assign(other); return *this; }

	//@}

	void clear();	///< resets to Undefined


	/** @name Scalar Types
	    The scalar types, and how they map onto C++
	*/
	//@{
		typedef bool			Boolean;
		typedef S32				Integer;
		typedef F64				Real;
		typedef std::string		String;
		typedef LLUUID			UUID;
		typedef LLDate			Date;
		typedef LLURI			URI;
		typedef std::vector<U8>	Binary;
	//@}
	
	/** @name Scalar Constructors */
	//@{
		LLSD(Boolean);
		LLSD(Integer);
		LLSD(Real);
		LLSD(const String&);
		LLSD(const UUID&);
		LLSD(const Date&);
		LLSD(const URI&);
		LLSD(const Binary&);
	//@}

	/** @name Convenience Constructors */
	//@{
		LLSD(F32); // F32 -> Real
	//@}
	
	/** @name Scalar Assignment */
	//@{
		void assign(Boolean);
		void assign(Integer);
		void assign(Real);
		void assign(const String&);
		void assign(const UUID&);
		void assign(const Date&);
		void assign(const URI&);
		void assign(const Binary&);
		
		LLSD& operator=(Boolean v)			{ assign(v); return *this; }
		LLSD& operator=(Integer v)			{ assign(v); return *this; }
		LLSD& operator=(Real v)				{ assign(v); return *this; }
		LLSD& operator=(const String& v)	{ assign(v); return *this; }
		LLSD& operator=(const UUID& v)		{ assign(v); return *this; }
		LLSD& operator=(const Date& v)		{ assign(v); return *this; }
		LLSD& operator=(const URI& v)		{ assign(v); return *this; }
		LLSD& operator=(const Binary& v)	{ assign(v); return *this; }
	//@}

	/**
		@name Scalar Accessors
		@brief Fetch a scalar value, converting if needed and possible
		
		Conversion among the basic types, Boolean, Integer, Real and String, is
		fully defined.  Each type can be converted to another with a reasonable
		interpretation.  These conversions can be used as a convenience even
		when you know the data is in one format, but you want it in another.  Of
		course, many of these conversions lose information.

		Note: These conversions are not the same as Perl's.  In particular, when
		converting a String to a Boolean, only the empty string converts to
		false.  Converting the String "0" to Boolean results in true.

		Conversion to and from UUID, Date, and URI is only defined to and from
		String.  Conversion is defined to be information preserving for valid
		values of those types.  These conversions can be used when one needs to
		convert data to or from another system that cannot handle these types
		natively, but can handle strings.

		Conversion to and from Binary isn't defined.

		Conversion of the Undefined value to any scalar type results in a
		reasonable null or zero value for the type.
	*/
	//@{
		Boolean	asBoolean() const;
		Integer	asInteger() const;
		Real	asReal() const;
		String	asString() const;
		UUID	asUUID() const;
		Date	asDate() const;
		URI		asURI() const;
		Binary	asBinary() const;

		operator Boolean() const	{ return asBoolean(); }
		operator Integer() const	{ return asInteger(); }
		operator Real() const		{ return asReal(); }
		operator String() const		{ return asString(); }
		operator UUID() const		{ return asUUID(); }
		operator Date() const		{ return asDate(); }
		operator URI() const		{ return asURI(); }
		operator Binary() const		{ return asBinary(); }

		// This is needed because most platforms do not automatically
		// convert the boolean negation as a bool in an if statement.
		bool operator!() const {return !asBoolean();}
	//@}
	
	/** @name Character Pointer Helpers
		These are helper routines to make working with char* the same as easy as
		working with strings.
	 */
	//@{
		LLSD(const char*);
		void assign(const char*);
		LLSD& operator=(const char* v)	{ assign(v); return *this; }
	//@}
	
	/** @name Map Values */
	//@{
		static LLSD emptyMap();
		
		bool has(const String&) const;
		LLSD get(const String&) const;
		void insert(const String&, const LLSD&);
		void erase(const String&);
		
		LLSD& operator[](const String&);
		LLSD& operator[](const char* c)			{ return (*this)[String(c)]; }
		const LLSD& operator[](const String&) const;
		const LLSD& operator[](const char* c) const	{ return (*this)[String(c)]; }
	//@}
	
	/** @name Array Values */
	//@{
		static LLSD emptyArray();
		
		LLSD get(Integer) const;
		void set(Integer, const LLSD&);
		void insert(Integer, const LLSD&);
		void append(const LLSD&);
		void erase(Integer);
		
		const LLSD& operator[](Integer) const;
		LLSD& operator[](Integer);
	//@}

	/** @name Iterators */
	//@{
		int size() const;

		typedef std::map<String, LLSD>::iterator		map_iterator;
		typedef std::map<String, LLSD>::const_iterator	map_const_iterator;
		
		map_iterator		beginMap();
		map_iterator		endMap();
		map_const_iterator	beginMap() const;
		map_const_iterator	endMap() const;
		
		typedef std::vector<LLSD>::iterator			array_iterator;
		typedef std::vector<LLSD>::const_iterator	array_const_iterator;
		
		array_iterator			beginArray();
		array_iterator			endArray();
		array_const_iterator	beginArray() const;
		array_const_iterator	endArray() const;
	//@}
	
	/** @name Type Testing */
	//@{
		enum Type {
			TypeUndefined,
			TypeBoolean,
			TypeInteger,
			TypeReal,
			TypeString,
			TypeUUID,
			TypeDate,
			TypeURI,
			TypeBinary,
			TypeMap,
			TypeArray
		};
		
		Type type() const;
		
		bool isUndefined() const	{ return type() == TypeUndefined; }
		bool isDefined() const		{ return type() != TypeUndefined; }
		bool isBoolean() const		{ return type() == TypeBoolean; }
		bool isInteger() const		{ return type() == TypeInteger; }
		bool isReal() const			{ return type() == TypeReal; }
		bool isString() const		{ return type() == TypeString; }
		bool isUUID() const			{ return type() == TypeUUID; }
		bool isDate() const			{ return type() == TypeDate; }
		bool isURI() const			{ return type() == TypeURI; }
		bool isBinary() const		{ return type() == TypeBinary; }
		bool isMap() const			{ return type() == TypeMap; }
		bool isArray() const		{ return type() == TypeArray; }
	//@}

	/** @name Automatic Cast Protection
		These are not implemented on purpose.  Without them, C++ can perform
		some conversions that are clearly not what the programmer intended.
		
		If you get a linker error about these being missing, you have made
		mistake in your code.  DO NOT IMPLEMENT THESE FUNCTIONS as a fix.
		
		All of thse problems stem from trying to support char* in LLSD or in
		std::string.  There are too many automatic casts that will lead to
		using an arbitrary pointer or scalar type to std::string.
	 */
	//@{
		LLSD(const void*);				///< construct from aribrary pointers
		void assign(const void*);		///< assign from arbitrary pointers
		LLSD& operator=(const void*);	///< assign from arbitrary pointers
		
		bool has(Integer) const;		///< has only works for Maps
	//@}
	
	/** @name Implementation */
	//@{
public:
		class Impl;
private:
		Impl* impl;
	//@}
	
	/** @name Unit Testing Interface */
	//@{
public:
		static U32 allocationCount();	///< how many Impls have been made
		static U32 outstandingCount();	///< how many Impls are still alive
	//@}
};

struct llsd_select_bool : public std::unary_function<LLSD, LLSD::Boolean>
{
	LLSD::Boolean operator()(const LLSD& sd) const
	{
		return sd.asBoolean();
	}
};
struct llsd_select_integer : public std::unary_function<LLSD, LLSD::Integer>
{
	LLSD::Integer operator()(const LLSD& sd) const
	{
		return sd.asInteger();
	}
};
struct llsd_select_real : public std::unary_function<LLSD, LLSD::Real>
{
	LLSD::Real operator()(const LLSD& sd) const
	{
		return sd.asReal();
	}
};
struct llsd_select_float : public std::unary_function<LLSD, F32>
{
	F32 operator()(const LLSD& sd) const
	{
		return (F32)sd.asReal();
	}
};
struct llsd_select_uuid : public std::unary_function<LLSD, LLSD::UUID>
{
	LLSD::UUID operator()(const LLSD& sd) const
	{
		return sd.asUUID();
	}
};
struct llsd_select_string : public std::unary_function<LLSD, LLSD::String>
{
	LLSD::String operator()(const LLSD& sd) const
	{
		return sd.asString();
	}
};


/** QUESTIONS & TO DOS
	- Would Binary be more convenient as usigned char* buffer semantics?
	- Should Binary be convertable to/from String, and if so how?
		- as UTF8 encoded strings (making not like UUID<->String)
		- as Base64 or Base96 encoded (making like UUID<->String)
	- Conversions to std::string and LLUUID do not result in easy assignment
		to std::string, LLString or LLUUID due to non-unique conversion paths
*/

#endif // LL_LLSD_NEW_H