PageRenderTime 99ms CodeModel.GetById 20ms app.highlight 71ms RepoModel.GetById 1ms app.codeStats 1ms

/indra/llcommon/llsd.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 982 lines | 706 code | 193 blank | 83 comment | 45 complexity | 70ed38c4930ec45d26fa9af28ba7a347 MD5 | raw file
  1/** 
  2 * @file llsd.cpp
  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// Must turn on conditional declarations in header file so definitions end up
 28// with proper linkage.
 29#define LLSD_DEBUG_INFO
 30#include "linden_common.h"
 31#include "llsd.h"
 32
 33#include "llerror.h"
 34#include "../llmath/llmath.h"
 35#include "llformat.h"
 36#include "llsdserialize.h"
 37#include "stringize.h"
 38
 39#ifndef LL_RELEASE_FOR_DOWNLOAD
 40#define NAME_UNNAMED_NAMESPACE
 41#endif
 42
 43#ifdef NAME_UNNAMED_NAMESPACE
 44namespace LLSDUnnamedNamespace 
 45#else
 46namespace 
 47#endif
 48{
 49	class ImplMap;
 50	class ImplArray;
 51}
 52
 53#ifdef NAME_UNNAMED_NAMESPACE
 54using namespace LLSDUnnamedNamespace;
 55#endif
 56
 57namespace llsd
 58{
 59
 60// statics
 61S32	sLLSDAllocationCount = 0;
 62S32 sLLSDNetObjects = 0;
 63
 64} // namespace llsd
 65
 66#define	ALLOC_LLSD_OBJECT			{ llsd::sLLSDNetObjects++;	llsd::sLLSDAllocationCount++;	}
 67#define	FREE_LLSD_OBJECT			{ llsd::sLLSDNetObjects--;									}
 68
 69class LLSD::Impl
 70	/**< This class is the abstract base class of the implementation of LLSD
 71		 It provides the reference counting implementation, and the default
 72		 implementation of most methods for most data types.  It also serves
 73		 as a working implementation of the Undefined type.
 74		
 75	*/
 76{
 77protected:
 78	Impl();
 79
 80	enum StaticAllocationMarker { STATIC_USAGE_COUNT = 0xFFFFFFFF };
 81	Impl(StaticAllocationMarker);
 82		///< This constructor is used for static objects and causes the
 83		//   suppresses adjusting the debugging counters when they are
 84		//	 finally initialized.
 85		
 86	virtual ~Impl();
 87	
 88	bool shared() const							{ return (mUseCount > 1) && (mUseCount != STATIC_USAGE_COUNT); }
 89	
 90	U32 mUseCount;
 91
 92public:
 93	static void reset(Impl*& var, Impl* impl);
 94		///< safely set var to refer to the new impl (possibly shared)
 95		
 96	static       Impl& safe(      Impl*);
 97	static const Impl& safe(const Impl*);
 98		///< since a NULL Impl* is used for undefined, this ensures there is
 99		//	 always an object you call virtual member functions on
100		
101	virtual ImplMap& makeMap(Impl*& var);
102	virtual ImplArray& makeArray(Impl*& var);
103		///< sure var is a modifiable, non-shared map or array
104	
105	virtual LLSD::Type type() const				{ return LLSD::TypeUndefined; }
106	
107	static  void assignUndefined(LLSD::Impl*& var);
108	static  void assign(LLSD::Impl*& var, const LLSD::Impl* other);
109	
110	virtual void assign(Impl*& var, LLSD::Boolean);
111	virtual void assign(Impl*& var, LLSD::Integer);
112	virtual void assign(Impl*& var, LLSD::Real);
113	virtual void assign(Impl*& var, const LLSD::String&);
114	virtual void assign(Impl*& var, const LLSD::UUID&);
115	virtual void assign(Impl*& var, const LLSD::Date&);
116	virtual void assign(Impl*& var, const LLSD::URI&);
117	virtual void assign(Impl*& var, const LLSD::Binary&);
118		///< If the receiver is the right type and unshared, these are simple
119		//   data assignments, othewise the default implementation handless
120		//   constructing the proper Impl subclass
121		 
122	virtual Boolean	asBoolean() const			{ return false; }
123	virtual Integer	asInteger() const			{ return 0; }
124	virtual Real	asReal() const				{ return 0.0; }
125	virtual String	asString() const			{ return std::string(); }
126	virtual UUID	asUUID() const				{ return LLUUID(); }
127	virtual Date	asDate() const				{ return LLDate(); }
128	virtual URI		asURI() const				{ return LLURI(); }
129	virtual Binary	asBinary() const			{ return std::vector<U8>(); }
130	
131	virtual bool has(const String&) const		{ return false; }
132	virtual LLSD get(const String&) const		{ return LLSD(); }
133	virtual void erase(const String&)			{ }
134	virtual const LLSD& ref(const String&) const{ return undef(); }
135	
136	virtual int size() const					{ return 0; }
137	virtual LLSD get(Integer) const				{ return LLSD(); }
138	virtual void erase(Integer)					{ }
139	virtual const LLSD& ref(Integer) const		{ return undef(); }
140
141	virtual LLSD::map_const_iterator beginMap() const { return endMap(); }
142	virtual LLSD::map_const_iterator endMap() const { static const std::map<String, LLSD> empty; return empty.end(); }
143	virtual LLSD::array_const_iterator beginArray() const { return endArray(); }
144	virtual LLSD::array_const_iterator endArray() const { static const std::vector<LLSD> empty; return empty.end(); }
145
146	virtual void dumpStats() const;
147	virtual void calcStats(S32 type_counts[], S32 share_counts[]) const;
148	// Container subclasses contain LLSD objects, rather than directly
149	// containing Impl objects. This helper forwards through LLSD.
150	void calcStats(const LLSD& llsd, S32 type_counts[], S32 share_counts[]) const
151	{
152		safe(llsd.impl).calcStats(type_counts, share_counts);
153	}
154
155	static const Impl& getImpl(const LLSD& llsd)	{ return safe(llsd.impl); }
156	static Impl& getImpl(LLSD& llsd)				{ return safe(llsd.impl); }
157
158	static const LLSD& undef();
159	
160	static U32 sAllocationCount;
161	static U32 sOutstandingCount;
162};
163
164#ifdef NAME_UNNAMED_NAMESPACE
165namespace LLSDUnnamedNamespace 
166#else
167namespace 
168#endif
169{
170	template<LLSD::Type T, class Data, class DataRef = Data>
171	class ImplBase : public LLSD::Impl
172		///< This class handles most of the work for a subclass of Impl
173		//   for a given simple data type.  Subclasses of this provide the
174		//   conversion functions and a constructor.
175	{
176	protected:
177		Data mValue;
178		
179		typedef ImplBase Base;
180
181	public:
182		ImplBase(DataRef value) : mValue(value) { }
183		
184		virtual LLSD::Type type() const { return T; }
185
186		using LLSD::Impl::assign; // Unhiding base class virtuals...
187		virtual void assign(LLSD::Impl*& var, DataRef value) {
188			if (shared())
189			{
190				Impl::assign(var, value);
191			}
192			else
193			{
194				mValue = value;
195			}
196		}
197	};
198
199	
200	class ImplBoolean
201		: public ImplBase<LLSD::TypeBoolean, LLSD::Boolean>
202	{
203	public:
204		ImplBoolean(LLSD::Boolean v) : Base(v) { }
205		
206		virtual LLSD::Boolean	asBoolean() const	{ return mValue; }
207		virtual LLSD::Integer	asInteger() const	{ return mValue ? 1 : 0; }
208		virtual LLSD::Real		asReal() const		{ return mValue ? 1 : 0; }
209		virtual LLSD::String	asString() const;
210	};
211
212	LLSD::String ImplBoolean::asString() const
213		// *NOTE: The reason that false is not converted to "false" is
214		// because that would break roundtripping,
215		// e.g. LLSD(false).asString().asBoolean().  There are many
216		// reasons for wanting LLSD("false").asBoolean() == true, such
217		// as "everything else seems to work that way".
218		{ return mValue ? "true" : ""; }
219
220
221	class ImplInteger
222		: public ImplBase<LLSD::TypeInteger, LLSD::Integer>
223	{
224	public:
225		ImplInteger(LLSD::Integer v) : Base(v) { }
226		
227		virtual LLSD::Boolean	asBoolean() const	{ return mValue != 0; }
228		virtual LLSD::Integer	asInteger() const	{ return mValue; }
229		virtual LLSD::Real		asReal() const		{ return mValue; }
230		virtual LLSD::String	asString() const;
231	};
232
233	LLSD::String ImplInteger::asString() const
234		{ return llformat("%d", mValue); }
235
236
237	class ImplReal
238		: public ImplBase<LLSD::TypeReal, LLSD::Real>
239	{
240	public:
241		ImplReal(LLSD::Real v) : Base(v) { }
242				
243		virtual LLSD::Boolean	asBoolean() const;
244		virtual LLSD::Integer	asInteger() const;
245		virtual LLSD::Real		asReal() const		{ return mValue; }
246		virtual LLSD::String	asString() const;
247	};
248
249	LLSD::Boolean ImplReal::asBoolean() const
250		{ return !llisnan(mValue)  &&  mValue != 0.0; }
251		
252	LLSD::Integer ImplReal::asInteger() const
253		{ return !llisnan(mValue) ? (LLSD::Integer)mValue : 0; }
254		
255	LLSD::String ImplReal::asString() const
256		{ return llformat("%lg", mValue); }
257
258
259	class ImplString
260		: public ImplBase<LLSD::TypeString, LLSD::String, const LLSD::String&>
261	{
262	public:
263		ImplString(const LLSD::String& v) : Base(v) { }
264				
265		virtual LLSD::Boolean	asBoolean() const	{ return !mValue.empty(); }
266		virtual LLSD::Integer	asInteger() const;
267		virtual LLSD::Real		asReal() const;
268		virtual LLSD::String	asString() const	{ return mValue; }
269		virtual LLSD::UUID		asUUID() const	{ return LLUUID(mValue); }
270		virtual LLSD::Date		asDate() const	{ return LLDate(mValue); }
271		virtual LLSD::URI		asURI() const	{ return LLURI(mValue); }
272	};
273	
274	LLSD::Integer	ImplString::asInteger() const
275	{
276		// This must treat "1.23" not as an error, but as a number, which is
277		// then truncated down to an integer.  Hence, this code doesn't call
278		// std::istringstream::operator>>(int&), which would not consume the
279		// ".23" portion.
280		
281		return (int)asReal();
282	}
283	
284	LLSD::Real		ImplString::asReal() const
285	{
286		F64 v = 0.0;
287		std::istringstream i_stream(mValue);
288		i_stream >> v;
289
290		// we would probably like to ignore all trailing whitespace as
291		// well, but for now, simply eat the next character, and make
292		// sure we reached the end of the string.
293		// *NOTE: gcc 2.95 does not generate an eof() event on the
294		// stream operation above, so we manually get here to force it
295		// across platforms.
296		int c = i_stream.get();
297		return ((EOF ==c) ? v : 0.0);
298	}
299	
300
301	class ImplUUID
302		: public ImplBase<LLSD::TypeUUID, LLSD::UUID, const LLSD::UUID&>
303	{
304	public:
305		ImplUUID(const LLSD::UUID& v) : Base(v) { }
306				
307		virtual LLSD::String	asString() const{ return mValue.asString(); }
308		virtual LLSD::UUID		asUUID() const	{ return mValue; }
309	};
310
311
312	class ImplDate
313		: public ImplBase<LLSD::TypeDate, LLSD::Date, const LLSD::Date&>
314	{
315	public:
316		ImplDate(const LLSD::Date& v)
317			: ImplBase<LLSD::TypeDate, LLSD::Date, const LLSD::Date&>(v)
318			{ }
319		
320		virtual LLSD::Integer asInteger() const
321		{
322			return (LLSD::Integer)(mValue.secondsSinceEpoch());
323		}
324		virtual LLSD::Real asReal() const
325		{
326			return mValue.secondsSinceEpoch();
327		}
328		virtual LLSD::String	asString() const{ return mValue.asString(); }
329		virtual LLSD::Date		asDate() const	{ return mValue; }
330	};
331
332
333	class ImplURI
334		: public ImplBase<LLSD::TypeURI, LLSD::URI, const LLSD::URI&>
335	{
336	public:
337		ImplURI(const LLSD::URI& v) : Base(v) { }
338				
339		virtual LLSD::String	asString() const{ return mValue.asString(); }
340		virtual LLSD::URI		asURI() const	{ return mValue; }
341	};
342
343
344	class ImplBinary
345		: public ImplBase<LLSD::TypeBinary, LLSD::Binary, const LLSD::Binary&>
346	{
347	public:
348		ImplBinary(const LLSD::Binary& v) : Base(v) { }
349				
350		virtual LLSD::Binary	asBinary() const{ return mValue; }
351	};
352
353
354	class ImplMap : public LLSD::Impl
355	{
356	private:
357		typedef std::map<LLSD::String, LLSD>	DataMap;
358		
359		DataMap mData;
360		
361	protected:
362		ImplMap(const DataMap& data) : mData(data) { }
363		
364	public:
365		ImplMap() { }
366		
367		virtual ImplMap& makeMap(LLSD::Impl*&);
368
369		virtual LLSD::Type type() const { return LLSD::TypeMap; }
370
371		virtual LLSD::Boolean asBoolean() const { return !mData.empty(); }
372
373		virtual bool has(const LLSD::String&) const; 
374
375		using LLSD::Impl::get; // Unhiding get(LLSD::Integer)
376		using LLSD::Impl::erase; // Unhiding erase(LLSD::Integer)
377		using LLSD::Impl::ref; // Unhiding ref(LLSD::Integer)
378		virtual LLSD get(const LLSD::String&) const; 
379		void insert(const LLSD::String& k, const LLSD& v);
380		virtual void erase(const LLSD::String&);
381		              LLSD& ref(const LLSD::String&);
382		virtual const LLSD& ref(const LLSD::String&) const;
383
384		virtual int size() const { return mData.size(); }
385
386		LLSD::map_iterator beginMap() { return mData.begin(); }
387		LLSD::map_iterator endMap() { return mData.end(); }
388		virtual LLSD::map_const_iterator beginMap() const { return mData.begin(); }
389		virtual LLSD::map_const_iterator endMap() const { return mData.end(); }
390
391		virtual void dumpStats() const;
392		virtual void calcStats(S32 type_counts[], S32 share_counts[]) const;
393	};
394	
395	ImplMap& ImplMap::makeMap(LLSD::Impl*& var)
396	{
397		if (shared())
398		{
399			ImplMap* i = new ImplMap(mData);
400			Impl::assign(var, i);
401			return *i;
402		}
403		else
404		{
405			return *this;
406		}
407	}
408	
409	bool ImplMap::has(const LLSD::String& k) const
410	{
411		DataMap::const_iterator i = mData.find(k);
412		return i != mData.end();
413	}
414	
415	LLSD ImplMap::get(const LLSD::String& k) const
416	{
417		DataMap::const_iterator i = mData.find(k);
418		return (i != mData.end()) ? i->second : LLSD();
419	}
420	
421	void ImplMap::insert(const LLSD::String& k, const LLSD& v)
422	{
423		mData.insert(DataMap::value_type(k, v));
424	}
425	
426	void ImplMap::erase(const LLSD::String& k)
427	{
428		mData.erase(k);
429	}
430	
431	LLSD& ImplMap::ref(const LLSD::String& k)
432	{
433		return mData[k];
434	}
435	
436	const LLSD& ImplMap::ref(const LLSD::String& k) const
437	{
438		DataMap::const_iterator i = mData.lower_bound(k);
439		if (i == mData.end()  ||  mData.key_comp()(k, i->first))
440		{
441			return undef();
442		}
443		
444		return i->second;
445	}
446
447	void ImplMap::dumpStats() const
448	{
449		std::cout << "Map size: " << mData.size() << std::endl;
450
451		std::cout << "LLSD Net Objects: " << llsd::sLLSDNetObjects << std::endl;
452		std::cout << "LLSD allocations: " << llsd::sLLSDAllocationCount << std::endl;
453
454		std::cout << "LLSD::Impl Net Objects: " << sOutstandingCount << std::endl;
455		std::cout << "LLSD::Impl allocations: " << sAllocationCount << std::endl;
456
457		Impl::dumpStats();
458	}
459
460	void ImplMap::calcStats(S32 type_counts[], S32 share_counts[]) const
461	{
462		LLSD::map_const_iterator iter = beginMap();
463		while (iter != endMap())
464		{
465			//std::cout << "  " << (*iter).first << ": " << (*iter).second << std::endl;
466			Impl::calcStats((*iter).second, type_counts, share_counts);
467			iter++;
468		}
469
470		// Add in the values for this map
471		Impl::calcStats(type_counts, share_counts);
472	}
473
474
475	class ImplArray : public LLSD::Impl
476	{
477	private:
478		typedef std::vector<LLSD>	DataVector;
479		
480		DataVector mData;
481		
482	protected:
483		ImplArray(const DataVector& data) : mData(data) { }
484		
485	public:
486		ImplArray() { }
487		
488		virtual ImplArray& makeArray(Impl*&);
489
490		virtual LLSD::Type type() const { return LLSD::TypeArray; }
491
492		virtual LLSD::Boolean asBoolean() const { return !mData.empty(); }
493
494		using LLSD::Impl::get; // Unhiding get(LLSD::String)
495		using LLSD::Impl::erase; // Unhiding erase(LLSD::String)
496		using LLSD::Impl::ref; // Unhiding ref(LLSD::String)
497		virtual int size() const; 
498		virtual LLSD get(LLSD::Integer) const;
499		        void set(LLSD::Integer, const LLSD&);
500		        void insert(LLSD::Integer, const LLSD&);
501		        void append(const LLSD&);
502		virtual void erase(LLSD::Integer);
503		              LLSD& ref(LLSD::Integer);
504		virtual const LLSD& ref(LLSD::Integer) const; 
505
506		LLSD::array_iterator beginArray() { return mData.begin(); }
507		LLSD::array_iterator endArray() { return mData.end(); }
508		virtual LLSD::array_const_iterator beginArray() const { return mData.begin(); }
509		virtual LLSD::array_const_iterator endArray() const { return mData.end(); }
510
511		virtual void calcStats(S32 type_counts[], S32 share_counts[]) const;
512	};
513
514	ImplArray& ImplArray::makeArray(Impl*& var)
515	{
516		if (shared())
517		{
518			ImplArray* i = new ImplArray(mData);
519			Impl::assign(var, i);
520			return *i;
521		}
522		else
523		{
524			return *this;
525		}
526	}
527	
528	int ImplArray::size() const		{ return mData.size(); }
529	
530	LLSD ImplArray::get(LLSD::Integer i) const
531	{
532		if (i < 0) { return LLSD(); }
533		DataVector::size_type index = i;
534		
535		return (index < mData.size()) ? mData[index] : LLSD();
536	}
537	
538	void ImplArray::set(LLSD::Integer i, const LLSD& v)
539	{
540		if (i < 0) { return; }
541		DataVector::size_type index = i;
542		
543		if (index >= mData.size())
544		{
545			mData.resize(index + 1);
546		}
547		
548		mData[index] = v;
549	}
550	
551	void ImplArray::insert(LLSD::Integer i, const LLSD& v)
552	{
553		if (i < 0) 
554		{
555			return;
556		}
557		DataVector::size_type index = i;
558		
559		if (index >= mData.size())	// tbd - sanity check limit for index ?
560		{
561			mData.resize(index + 1);
562		}
563		
564		mData.insert(mData.begin() + index, v);
565	}
566	
567	void ImplArray::append(const LLSD& v)
568	{
569		mData.push_back(v);
570	}
571	
572	void ImplArray::erase(LLSD::Integer i)
573	{
574		if (i < 0) { return; }
575		DataVector::size_type index = i;
576		
577		if (index < mData.size())
578		{
579			mData.erase(mData.begin() + index);
580		}
581	}
582	
583	LLSD& ImplArray::ref(LLSD::Integer i)
584	{
585		DataVector::size_type index = i >= 0 ? i : 0;
586		
587		if (index >= mData.size())
588		{
589			mData.resize(i + 1);
590		}
591		
592		return mData[index];
593	}
594
595	const LLSD& ImplArray::ref(LLSD::Integer i) const
596	{
597		if (i < 0) { return undef(); }
598		DataVector::size_type index = i;
599		
600		if (index >= mData.size())
601		{
602			return undef();
603		}
604		
605		return mData[index];
606	}
607
608	void ImplArray::calcStats(S32 type_counts[], S32 share_counts[]) const
609	{
610		LLSD::array_const_iterator iter = beginArray();
611		while (iter != endArray())
612		{	// Add values for all items held in the array
613			Impl::calcStats((*iter), type_counts, share_counts);
614			iter++;
615		}
616
617		// Add in the values for this array
618		Impl::calcStats(type_counts, share_counts);
619	}
620}
621
622LLSD::Impl::Impl()
623	: mUseCount(0)
624{
625	++sAllocationCount;
626	++sOutstandingCount;
627}
628
629LLSD::Impl::Impl(StaticAllocationMarker)
630	: mUseCount(0)
631{
632}
633
634LLSD::Impl::~Impl()
635{
636	--sOutstandingCount;
637}
638
639void LLSD::Impl::reset(Impl*& var, Impl* impl)
640{
641	if (impl && impl->mUseCount != STATIC_USAGE_COUNT) 
642	{
643		++impl->mUseCount;
644	}
645	if (var  &&  var->mUseCount != STATIC_USAGE_COUNT && --var->mUseCount == 0)
646	{
647		delete var;
648	}
649	var = impl;
650}
651
652LLSD::Impl& LLSD::Impl::safe(Impl* impl)
653{
654	static Impl theUndefined(STATIC_USAGE_COUNT);
655	return impl ? *impl : theUndefined;
656}
657
658const LLSD::Impl& LLSD::Impl::safe(const Impl* impl)
659{
660	static Impl theUndefined(STATIC_USAGE_COUNT);
661	return impl ? *impl : theUndefined;
662}
663
664ImplMap& LLSD::Impl::makeMap(Impl*& var)
665{
666	ImplMap* im = new ImplMap;
667	reset(var, im);
668	return *im;
669}
670
671ImplArray& LLSD::Impl::makeArray(Impl*& var)
672{
673	ImplArray* ia = new ImplArray;
674	reset(var, ia);
675	return *ia;
676}
677
678
679void LLSD::Impl::assign(Impl*& var, const Impl* other)
680{
681	reset(var, const_cast<Impl*>(other));
682}
683
684void LLSD::Impl::assignUndefined(Impl*& var)
685{
686	reset(var, 0);
687}
688
689void LLSD::Impl::assign(Impl*& var, LLSD::Boolean v)
690{
691	reset(var, new ImplBoolean(v));
692}
693
694void LLSD::Impl::assign(Impl*& var, LLSD::Integer v)
695{
696	reset(var, new ImplInteger(v));
697}
698
699void LLSD::Impl::assign(Impl*& var, LLSD::Real v)
700{
701	reset(var, new ImplReal(v));
702}
703
704void LLSD::Impl::assign(Impl*& var, const LLSD::String& v)
705{
706	reset(var, new ImplString(v));
707}
708
709void LLSD::Impl::assign(Impl*& var, const LLSD::UUID& v)
710{
711	reset(var, new ImplUUID(v));
712}
713
714void LLSD::Impl::assign(Impl*& var, const LLSD::Date& v)
715{
716	reset(var, new ImplDate(v));
717}
718
719void LLSD::Impl::assign(Impl*& var, const LLSD::URI& v)
720{
721	reset(var, new ImplURI(v));
722}
723
724void LLSD::Impl::assign(Impl*& var, const LLSD::Binary& v)
725{
726	reset(var, new ImplBinary(v));
727}
728
729
730const LLSD& LLSD::Impl::undef()
731{
732	static const LLSD immutableUndefined;
733	return immutableUndefined;
734}
735
736void LLSD::Impl::dumpStats() const
737{
738	S32 type_counts[LLSD::TypeLLSDNumTypes + 1];
739	memset(&type_counts, 0, sizeof(type_counts));
740
741	S32 share_counts[LLSD::TypeLLSDNumTypes + 1];
742	memset(&share_counts, 0, sizeof(share_counts));
743
744	// Add info from all the values this object has
745	calcStats(type_counts, share_counts);
746
747	S32 type_index = LLSD::TypeLLSDTypeBegin;
748	while (type_index != LLSD::TypeLLSDTypeEnd)
749	{
750		std::cout << LLSD::typeString((LLSD::Type)type_index) << " type "
751			<< type_counts[type_index] << " objects, "
752			<< share_counts[type_index] << " shared"
753			<< std::endl;
754		type_index++;
755	}
756}
757
758
759void LLSD::Impl::calcStats(S32 type_counts[], S32 share_counts[]) const
760{
761	S32 tp = S32(type());
762	if (0 <= tp && tp < LLSD::TypeLLSDNumTypes)
763	{
764		type_counts[tp]++;	
765		if (shared())
766		{
767			share_counts[tp]++;
768		}
769	}
770}
771
772
773U32 LLSD::Impl::sAllocationCount = 0;
774U32 LLSD::Impl::sOutstandingCount = 0;
775
776
777
778#ifdef NAME_UNNAMED_NAMESPACE
779namespace LLSDUnnamedNamespace 
780#else
781namespace 
782#endif
783{
784	inline LLSD::Impl& safe(LLSD::Impl* impl)
785		{ return LLSD::Impl::safe(impl); }
786		
787	inline const LLSD::Impl& safe(const LLSD::Impl* impl)
788		{ return LLSD::Impl::safe(impl); }
789		
790	inline ImplMap& makeMap(LLSD::Impl*& var)
791		{ return safe(var).makeMap(var); }
792		
793	inline ImplArray& makeArray(LLSD::Impl*& var)
794		{ return safe(var).makeArray(var); }
795}
796
797
798LLSD::LLSD() : impl(0)					{ ALLOC_LLSD_OBJECT; }
799LLSD::~LLSD()							{ FREE_LLSD_OBJECT; Impl::reset(impl, 0); }
800
801LLSD::LLSD(const LLSD& other) : impl(0) { ALLOC_LLSD_OBJECT;  assign(other); }
802void LLSD::assign(const LLSD& other)	{ Impl::assign(impl, other.impl); }
803
804
805void LLSD::clear()						{ Impl::assignUndefined(impl); }
806
807LLSD::Type LLSD::type() const			{ return safe(impl).type(); }
808
809// Scalar Constructors
810LLSD::LLSD(Boolean v) : impl(0)			{ ALLOC_LLSD_OBJECT;	assign(v); }
811LLSD::LLSD(Integer v) : impl(0)			{ ALLOC_LLSD_OBJECT;	assign(v); }
812LLSD::LLSD(Real v) : impl(0)			{ ALLOC_LLSD_OBJECT;	assign(v); }
813LLSD::LLSD(const UUID& v) : impl(0)		{ ALLOC_LLSD_OBJECT;	assign(v); }
814LLSD::LLSD(const String& v) : impl(0)	{ ALLOC_LLSD_OBJECT;	assign(v); }
815LLSD::LLSD(const Date& v) : impl(0)		{ ALLOC_LLSD_OBJECT;	assign(v); }
816LLSD::LLSD(const URI& v) : impl(0)		{ ALLOC_LLSD_OBJECT;	assign(v); }
817LLSD::LLSD(const Binary& v) : impl(0)	{ ALLOC_LLSD_OBJECT;	assign(v); }
818
819// Convenience Constructors
820LLSD::LLSD(F32 v) : impl(0)				{ ALLOC_LLSD_OBJECT;	assign((Real)v); }
821
822// Scalar Assignment
823void LLSD::assign(Boolean v)			{ safe(impl).assign(impl, v); }
824void LLSD::assign(Integer v)			{ safe(impl).assign(impl, v); }
825void LLSD::assign(Real v)				{ safe(impl).assign(impl, v); }
826void LLSD::assign(const String& v)		{ safe(impl).assign(impl, v); }
827void LLSD::assign(const UUID& v)		{ safe(impl).assign(impl, v); }
828void LLSD::assign(const Date& v)		{ safe(impl).assign(impl, v); }
829void LLSD::assign(const URI& v)			{ safe(impl).assign(impl, v); }
830void LLSD::assign(const Binary& v)		{ safe(impl).assign(impl, v); }
831
832// Scalar Accessors
833LLSD::Boolean	LLSD::asBoolean() const	{ return safe(impl).asBoolean(); }
834LLSD::Integer	LLSD::asInteger() const	{ return safe(impl).asInteger(); }
835LLSD::Real		LLSD::asReal() const	{ return safe(impl).asReal(); }
836LLSD::String	LLSD::asString() const	{ return safe(impl).asString(); }
837LLSD::UUID		LLSD::asUUID() const	{ return safe(impl).asUUID(); }
838LLSD::Date		LLSD::asDate() const	{ return safe(impl).asDate(); }
839LLSD::URI		LLSD::asURI() const		{ return safe(impl).asURI(); }
840LLSD::Binary	LLSD::asBinary() const	{ return safe(impl).asBinary(); }
841
842// const char * helpers
843LLSD::LLSD(const char* v) : impl(0)		{ ALLOC_LLSD_OBJECT;	assign(v); }
844void LLSD::assign(const char* v)
845{
846	if(v) assign(std::string(v));
847	else assign(std::string());
848}
849
850
851LLSD LLSD::emptyMap()
852{
853	LLSD v;
854	makeMap(v.impl);
855	return v;
856}
857
858bool LLSD::has(const String& k) const	{ return safe(impl).has(k); }
859LLSD LLSD::get(const String& k) const	{ return safe(impl).get(k); } 
860void LLSD::insert(const String& k, const LLSD& v) {	makeMap(impl).insert(k, v); }
861
862LLSD& LLSD::with(const String& k, const LLSD& v)
863										{ 
864											makeMap(impl).insert(k, v); 
865											return *this;
866										}
867void LLSD::erase(const String& k)		{ makeMap(impl).erase(k); }
868
869LLSD&		LLSD::operator[](const String& k)
870										{ return makeMap(impl).ref(k); }
871const LLSD& LLSD::operator[](const String& k) const
872										{ return safe(impl).ref(k); }
873
874
875LLSD LLSD::emptyArray()
876{
877	LLSD v;
878	makeArray(v.impl);
879	return v;
880}
881
882int LLSD::size() const					{ return safe(impl).size(); }
883 
884LLSD LLSD::get(Integer i) const			{ return safe(impl).get(i); } 
885void LLSD::set(Integer i, const LLSD& v){ makeArray(impl).set(i, v); }
886void LLSD::insert(Integer i, const LLSD& v) { makeArray(impl).insert(i, v); }
887
888LLSD& LLSD::with(Integer i, const LLSD& v)
889										{ 
890											makeArray(impl).insert(i, v); 
891											return *this;
892										}
893void LLSD::append(const LLSD& v)		{ makeArray(impl).append(v); }
894void LLSD::erase(Integer i)				{ makeArray(impl).erase(i); }
895
896LLSD&		LLSD::operator[](Integer i)
897										{ return makeArray(impl).ref(i); }
898const LLSD& LLSD::operator[](Integer i) const
899										{ return safe(impl).ref(i); }
900
901static const char *llsd_dump(const LLSD &llsd, bool useXMLFormat)
902{
903	// sStorage is used to hold the string representation of the llsd last
904	// passed into this function.  If this function is never called (the
905	// normal case when not debugging), nothing is allocated.  Otherwise
906	// sStorage will point to the result of the last call.  This will actually
907	// be one leak, but since this is used only when running under the
908	// debugger, it should not be an issue.
909	static char *sStorage = NULL;
910	delete[] sStorage;
911	std::string out_string;
912	{
913		std::ostringstream out;
914		if (useXMLFormat)
915			out << LLSDXMLStreamer(llsd);
916		else
917			out << LLSDNotationStreamer(llsd);
918		out_string = out.str();
919	}
920	int len = out_string.length();
921	sStorage = new char[len + 1];
922	memcpy(sStorage, out_string.c_str(), len);
923	sStorage[len] = '\0';
924	return sStorage;
925}
926
927/// Returns XML version of llsd -- only to be called from debugger
928const char *LLSD::dumpXML(const LLSD &llsd)
929{
930	return llsd_dump(llsd, true);
931}
932
933/// Returns Notation version of llsd -- only to be called from debugger
934const char *LLSD::dump(const LLSD &llsd)
935{
936	return llsd_dump(llsd, false);
937}
938
939LLSD::map_iterator			LLSD::beginMap()		{ return makeMap(impl).beginMap(); }
940LLSD::map_iterator			LLSD::endMap()			{ return makeMap(impl).endMap(); }
941LLSD::map_const_iterator	LLSD::beginMap() const	{ return safe(impl).beginMap(); }
942LLSD::map_const_iterator	LLSD::endMap() const	{ return safe(impl).endMap(); }
943
944LLSD::array_iterator		LLSD::beginArray()		{ return makeArray(impl).beginArray(); }
945LLSD::array_iterator		LLSD::endArray()		{ return makeArray(impl).endArray(); }
946LLSD::array_const_iterator	LLSD::beginArray() const{ return safe(impl).beginArray(); }
947LLSD::array_const_iterator	LLSD::endArray() const	{ return safe(impl).endArray(); }
948
949namespace llsd
950{
951
952U32 allocationCount()								{ return LLSD::Impl::sAllocationCount; }
953U32 outstandingCount()								{ return LLSD::Impl::sOutstandingCount; }
954
955// Diagnostic dump of contents in an LLSD object
956void dumpStats(const LLSD& llsd)					{ LLSD::Impl::getImpl(llsd).dumpStats(); }
957
958} // namespace llsd
959
960// static
961std::string		LLSD::typeString(Type type)
962{
963	static const char * sTypeNameArray[] = {
964		"Undefined",
965		"Boolean",
966		"Integer",
967		"Real",
968		"String",
969		"UUID",
970		"Date",
971		"URI",
972		"Binary",
973		"Map",
974		"Array"
975	};
976
977	if (0 <= type && type < LL_ARRAY_SIZE(sTypeNameArray))
978	{
979		return sTypeNameArray[type];
980	}
981	return STRINGIZE("** invalid type value " << type);
982}