PageRenderTime 67ms CodeModel.GetById 13ms app.highlight 48ms RepoModel.GetById 2ms app.codeStats 0ms

/indra/llcommon/llsd.h

https://bitbucket.org/lindenlab/viewer-beta/
C++ Header | 485 lines | 201 code | 50 blank | 234 comment | 12 complexity | 92279f6ec298b14aac39086f9a15418b MD5 | raw file
  1/** 
  2 * @file llsd.h
  3 * @brief LLSD flexible data system.
  4 *
  5 * $LicenseInfo:firstyear=2005&license=viewerlgpl$
  6 * Second Life Viewer Source Code
  7 * Copyright (C) 2010, Linden Research, Inc.
  8 * 
  9 * This library is free software; you can redistribute it and/or
 10 * modify it under the terms of the GNU Lesser General Public
 11 * License as published by the Free Software Foundation;
 12 * version 2.1 of the License only.
 13 * 
 14 * This library is distributed in the hope that it will be useful,
 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17 * Lesser General Public License for more details.
 18 * 
 19 * You should have received a copy of the GNU Lesser General Public
 20 * License along with this library; if not, write to the Free Software
 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 22 * 
 23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 24 * $/LicenseInfo$
 25 */
 26
 27#ifndef LL_LLSD_NEW_H
 28#define LL_LLSD_NEW_H
 29
 30#include <map>
 31#include <string>
 32#include <vector>
 33
 34#include "stdtypes.h"
 35
 36#include "lldate.h"
 37#include "lluri.h"
 38#include "lluuid.h"
 39
 40/**
 41	LLSD provides a flexible data system similar to the data facilities of
 42	dynamic languages like Perl and Python.  It is created to support exchange
 43	of structured data between loosely coupled systems.  (Here, "loosely coupled"
 44	means not compiled together into the same module.)
 45	
 46	Data in such exchanges must be highly tolerant of changes on either side
 47	such as:
 48			- recompilation
 49			- implementation in a different langauge
 50			- addition of extra parameters
 51			- execution of older versions (with fewer parameters)
 52
 53	To this aim, the C++ API of LLSD strives to be very easy to use, and to
 54	default to "the right thing" wherever possible.  It is extremely tolerant
 55	of errors and unexpected situations.
 56	
 57	The fundamental class is LLSD.  LLSD is a value holding object.  It holds
 58	one value that is either undefined, one of the scalar types, or a map or an
 59	array.  LLSD objects have value semantics (copying them copies the value,
 60	though it can be considered efficient, due to sharing), and mutable.
 61
 62	Undefined is the singular value given to LLSD objects that are not
 63	initialized with any data.  It is also used as the return value for
 64	operations that return an LLSD.
 65	
 66	The scalar data types are:
 67		- Boolean	- true or false
 68		- Integer	- a 32 bit signed integer
 69		- Real		- a 64 IEEE 754 floating point value
 70		- UUID		- a 128 unique value
 71		- String	- a sequence of zero or more Unicode chracters
 72		- Date		- an absolute point in time, UTC,
 73						with resolution to the second
 74		- URI		- a String that is a URI
 75		- Binary	- a sequence of zero or more octets (unsigned bytes)
 76	
 77	A map is a dictionary mapping String keys to LLSD values.  The keys are
 78	unique within a map, and have only one value (though that value could be
 79	an LLSD array).
 80	
 81	An array is a sequence of zero or more LLSD values.
 82	
 83	Thread Safety
 84
 85	In general, these LLSD classes offer *less* safety than STL container
 86	classes.  Implementations prior to this one were unsafe even when
 87	completely unrelated LLSD trees were in two threads due to reference
 88	sharing of special 'undefined' values that participated in the reference
 89	counting mechanism.
 90
 91	The dereference-before-refcount and aggressive tree sharing also make
 92	it impractical to share an LLSD across threads.  A strategy of passing
 93	ownership or a copy to another thread is still difficult due to a lack
 94	of a cloning interface but it can be done with some care.
 95
 96	One way of transferring ownership is as follows:
 97
 98		void method(const LLSD input) {
 99		...
100		LLSD * xfer_tree = new LLSD();
101		{
102			// Top-level values
103			(* xfer_tree)['label'] = "Some text";
104			(* xfer_tree)['mode'] = APP_MODE_CONSTANT;
105
106			// There will be a second-level
107			LLSD subtree(LLSD::emptyMap());
108			(* xfer_tree)['subtree'] = subtree;
109
110			// Do *not* copy from LLSD objects via LLSD
111			// intermediaries.  Only use plain-old-data
112			// types as intermediaries to prevent reference
113			// sharing.
114			subtree['value1'] = input['value1'].asInteger();
115			subtree['value2'] = input['value2'].asString();
116
117			// Close scope and drop 'subtree's reference.
118			// Only xfer_tree has a reference to the second
119			// level data.
120		}
121		...
122		// Transfer the LLSD pointer to another thread.  Ownership
123		// transfers, this thread no longer has a reference to any
124		// part of the xfer_tree and there's nothing to free or
125		// release here.  Receiving thread does need to delete the
126		// pointer when it is done with the LLSD.  Transfer
127		// mechanism must perform correct data ordering operations
128		// as dictated by architecture.
129		other_thread.sendMessageAndPointer("Take This", xfer_tree);
130		xfer_tree = NULL;
131
132
133	Avoid this pattern which provides half of a race condition:
134	
135		void method(const LLSD input) {
136		...
137		LLSD xfer_tree(LLSD::emptyMap());
138		xfer_tree['label'] = "Some text";
139		xfer_tree['mode'] = APP_MODE_CONSTANT;
140		...
141		other_thread.sendMessageAndPointer("Take This", xfer_tree);
142
143	
144	@nosubgrouping
145*/
146
147// Normally undefined, used for diagnostics
148//#define LLSD_DEBUG_INFO	1
149
150class LL_COMMON_API LLSD
151{
152public:
153		LLSD();		///< initially Undefined
154		~LLSD();	///< this class may NOT be subclassed
155
156	/** @name Copyable and Assignable */
157	//@{
158		LLSD(const LLSD&);
159		void assign(const LLSD& other);
160		LLSD& operator=(const LLSD& other)	{ assign(other); return *this; }
161
162	//@}
163
164	void clear();	///< resets to Undefined
165
166
167	/** @name Scalar Types
168	    The scalar types, and how they map onto C++
169	*/
170	//@{
171		typedef bool			Boolean;
172		typedef S32				Integer;
173		typedef F64				Real;
174		typedef std::string		String;
175		typedef LLUUID			UUID;
176		typedef LLDate			Date;
177		typedef LLURI			URI;
178		typedef std::vector<U8>	Binary;
179	//@}
180	
181	/** @name Scalar Constructors */
182	//@{
183		LLSD(Boolean);
184		LLSD(Integer);
185		LLSD(Real);
186		LLSD(const String&);
187		LLSD(const UUID&);
188		LLSD(const Date&);
189		LLSD(const URI&);
190		LLSD(const Binary&);
191	//@}
192
193	/** @name Convenience Constructors */
194	//@{
195		LLSD(F32); // F32 -> Real
196	//@}
197	
198	/** @name Scalar Assignment */
199	//@{
200		void assign(Boolean);
201		void assign(Integer);
202		void assign(Real);
203		void assign(const String&);
204		void assign(const UUID&);
205		void assign(const Date&);
206		void assign(const URI&);
207		void assign(const Binary&);
208		
209		LLSD& operator=(Boolean v)			{ assign(v); return *this; }
210		LLSD& operator=(Integer v)			{ assign(v); return *this; }
211		LLSD& operator=(Real v)				{ assign(v); return *this; }
212		LLSD& operator=(const String& v)	{ assign(v); return *this; }
213		LLSD& operator=(const UUID& v)		{ assign(v); return *this; }
214		LLSD& operator=(const Date& v)		{ assign(v); return *this; }
215		LLSD& operator=(const URI& v)		{ assign(v); return *this; }
216		LLSD& operator=(const Binary& v)	{ assign(v); return *this; }
217	//@}
218
219	/**
220		@name Scalar Accessors
221		@brief Fetch a scalar value, converting if needed and possible
222		
223		Conversion among the basic types, Boolean, Integer, Real and String, is
224		fully defined.  Each type can be converted to another with a reasonable
225		interpretation.  These conversions can be used as a convenience even
226		when you know the data is in one format, but you want it in another.  Of
227		course, many of these conversions lose information.
228
229		Note: These conversions are not the same as Perl's.  In particular, when
230		converting a String to a Boolean, only the empty string converts to
231		false.  Converting the String "0" to Boolean results in true.
232
233		Conversion to and from UUID, Date, and URI is only defined to and from
234		String.  Conversion is defined to be information preserving for valid
235		values of those types.  These conversions can be used when one needs to
236		convert data to or from another system that cannot handle these types
237		natively, but can handle strings.
238
239		Conversion to and from Binary isn't defined.
240
241		Conversion of the Undefined value to any scalar type results in a
242		reasonable null or zero value for the type.
243	*/
244	//@{
245		Boolean	asBoolean() const;
246		Integer	asInteger() const;
247		Real	asReal() const;
248		String	asString() const;
249		UUID	asUUID() const;
250		Date	asDate() const;
251		URI		asURI() const;
252		Binary	asBinary() const;
253
254		operator Boolean() const	{ return asBoolean(); }
255		operator Integer() const	{ return asInteger(); }
256		operator Real() const		{ return asReal(); }
257		operator String() const		{ return asString(); }
258		operator UUID() const		{ return asUUID(); }
259		operator Date() const		{ return asDate(); }
260		operator URI() const		{ return asURI(); }
261		operator Binary() const		{ return asBinary(); }
262
263		// This is needed because most platforms do not automatically
264		// convert the boolean negation as a bool in an if statement.
265		bool operator!() const {return !asBoolean();}
266	//@}
267	
268	/** @name Character Pointer Helpers
269		These are helper routines to make working with char* as easy as
270		working with strings.
271	 */
272	//@{
273		LLSD(const char*);
274		void assign(const char*);
275		LLSD& operator=(const char* v)	{ assign(v); return *this; }
276	//@}
277	
278	/** @name Map Values */
279	//@{
280		static LLSD emptyMap();
281		
282		bool has(const String&) const;
283		LLSD get(const String&) const;
284		void insert(const String&, const LLSD&);
285		void erase(const String&);
286		LLSD& with(const String&, const LLSD&);
287		
288		LLSD& operator[](const String&);
289		LLSD& operator[](const char* c)			{ return (*this)[String(c)]; }
290		const LLSD& operator[](const String&) const;
291		const LLSD& operator[](const char* c) const	{ return (*this)[String(c)]; }
292	//@}
293	
294	/** @name Array Values */
295	//@{
296		static LLSD emptyArray();
297		
298		LLSD get(Integer) const;
299		void set(Integer, const LLSD&);
300		void insert(Integer, const LLSD&);
301		void append(const LLSD&);
302		void erase(Integer);
303		LLSD& with(Integer, const LLSD&);
304		
305		const LLSD& operator[](Integer) const;
306		LLSD& operator[](Integer);
307	//@}
308
309	/** @name Iterators */
310	//@{
311		int size() const;
312
313		typedef std::map<String, LLSD>::iterator		map_iterator;
314		typedef std::map<String, LLSD>::const_iterator	map_const_iterator;
315		
316		map_iterator		beginMap();
317		map_iterator		endMap();
318		map_const_iterator	beginMap() const;
319		map_const_iterator	endMap() const;
320		
321		typedef std::vector<LLSD>::iterator			array_iterator;
322		typedef std::vector<LLSD>::const_iterator	array_const_iterator;
323		
324		array_iterator			beginArray();
325		array_iterator			endArray();
326		array_const_iterator	beginArray() const;
327		array_const_iterator	endArray() const;
328	//@}
329	
330	/** @name Type Testing */
331	//@{
332		enum Type {
333			TypeUndefined = 0,
334			TypeBoolean,
335			TypeInteger,
336			TypeReal,
337			TypeString,
338			TypeUUID,
339			TypeDate,
340			TypeURI,
341			TypeBinary,
342			TypeMap,
343			TypeArray,
344			TypeLLSDTypeEnd,
345			TypeLLSDTypeBegin = TypeUndefined,
346			TypeLLSDNumTypes = (TypeLLSDTypeEnd - TypeLLSDTypeBegin)
347		};
348		
349		Type type() const;
350		
351		bool isUndefined() const	{ return type() == TypeUndefined; }
352		bool isDefined() const		{ return type() != TypeUndefined; }
353		bool isBoolean() const		{ return type() == TypeBoolean; }
354		bool isInteger() const		{ return type() == TypeInteger; }
355		bool isReal() const			{ return type() == TypeReal; }
356		bool isString() const		{ return type() == TypeString; }
357		bool isUUID() const			{ return type() == TypeUUID; }
358		bool isDate() const			{ return type() == TypeDate; }
359		bool isURI() const			{ return type() == TypeURI; }
360		bool isBinary() const		{ return type() == TypeBinary; }
361		bool isMap() const			{ return type() == TypeMap; }
362		bool isArray() const		{ return type() == TypeArray; }
363	//@}
364
365	/** @name Automatic Cast Protection
366		These are not implemented on purpose.  Without them, C++ can perform
367		some conversions that are clearly not what the programmer intended.
368		
369		If you get a linker error about these being missing, you have made
370		mistake in your code.  DO NOT IMPLEMENT THESE FUNCTIONS as a fix.
371		
372		All of these problems stem from trying to support char* in LLSD or in
373		std::string.  There are too many automatic casts that will lead to
374		using an arbitrary pointer or scalar type to std::string.
375	 */
376	//@{
377		LLSD(const void*);				///< construct from aribrary pointers
378		void assign(const void*);		///< assign from arbitrary pointers
379		LLSD& operator=(const void*);	///< assign from arbitrary pointers
380		
381		bool has(Integer) const;		///< has() only works for Maps
382	//@}
383	
384	/** @name Implementation */
385	//@{
386public:
387		class Impl;
388private:
389		Impl* impl;
390		friend class LLSD::Impl;
391	//@}
392
393private:
394	/** @name Debugging Interface */
395	//@{
396		/// Returns XML version of llsd -- only to be called from debugger
397		static const char *dumpXML(const LLSD &llsd);
398
399		/// Returns Notation version of llsd -- only to be called from debugger
400		static const char *dump(const LLSD &llsd);
401	//@}
402
403public:
404
405	static std::string		typeString(Type type);		// Return human-readable type as a string
406};
407
408struct llsd_select_bool : public std::unary_function<LLSD, LLSD::Boolean>
409{
410	LLSD::Boolean operator()(const LLSD& sd) const
411	{
412		return sd.asBoolean();
413	}
414};
415struct llsd_select_integer : public std::unary_function<LLSD, LLSD::Integer>
416{
417	LLSD::Integer operator()(const LLSD& sd) const
418	{
419		return sd.asInteger();
420	}
421};
422struct llsd_select_real : public std::unary_function<LLSD, LLSD::Real>
423{
424	LLSD::Real operator()(const LLSD& sd) const
425	{
426		return sd.asReal();
427	}
428};
429struct llsd_select_float : public std::unary_function<LLSD, F32>
430{
431	F32 operator()(const LLSD& sd) const
432	{
433		return (F32)sd.asReal();
434	}
435};
436struct llsd_select_uuid : public std::unary_function<LLSD, LLSD::UUID>
437{
438	LLSD::UUID operator()(const LLSD& sd) const
439	{
440		return sd.asUUID();
441	}
442};
443struct llsd_select_string : public std::unary_function<LLSD, LLSD::String>
444{
445	LLSD::String operator()(const LLSD& sd) const
446	{
447		return sd.asString();
448	}
449};
450
451LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLSD& llsd);
452
453namespace llsd
454{
455
456#ifdef LLSD_DEBUG_INFO
457/** @name Unit Testing Interface */
458//@{
459	LL_COMMON_API void dumpStats(const LLSD&);	///< Output information on object and usage
460
461	/// @warn THE FOLLOWING COUNTS WILL NOT BE ACCURATE IN A MULTI-THREADED
462	/// ENVIRONMENT.
463	///
464	/// These counts track LLSD::Impl (hidden) objects.
465	LL_COMMON_API U32 allocationCount();	///< how many Impls have been made
466	LL_COMMON_API U32 outstandingCount();	///< how many Impls are still alive
467
468	/// These counts track LLSD (public) objects.
469	LL_COMMON_API extern S32 sLLSDAllocationCount;	///< Number of LLSD objects ever created
470	LL_COMMON_API extern S32 sLLSDNetObjects;		///< Number of LLSD objects that exist
471#endif
472//@}
473
474} // namespace llsd
475
476/** QUESTIONS & TO DOS
477	- Would Binary be more convenient as unsigned char* buffer semantics?
478	- Should Binary be convertible to/from String, and if so how?
479		- as UTF8 encoded strings (making not like UUID<->String)
480		- as Base64 or Base96 encoded (making like UUID<->String)
481	- Conversions to std::string and LLUUID do not result in easy assignment
482		to std::string, std::string or LLUUID due to non-unique conversion paths
483*/
484
485#endif // LL_LLSD_NEW_H