diff options
Diffstat (limited to 'indra/llcommon')
| -rw-r--r-- | indra/llcommon/indra_constants.h | 1 | ||||
| -rw-r--r-- | indra/llcommon/llassettype.cpp | 1 | ||||
| -rw-r--r-- | indra/llcommon/llassettype.h | 3 | ||||
| -rwxr-xr-x[-rw-r--r--] | indra/llcommon/llfoldertype.h | 0 | ||||
| -rw-r--r-- | indra/llcommon/llinitparam.cpp | 82 | ||||
| -rw-r--r-- | indra/llcommon/llinitparam.h | 1664 | ||||
| -rw-r--r-- | indra/llcommon/llinstancetracker.h | 5 | ||||
| -rw-r--r-- | indra/llcommon/llrefcount.h | 19 | ||||
| -rw-r--r-- | indra/llcommon/llregistry.h | 34 | ||||
| -rw-r--r-- | indra/llcommon/llsdparam.cpp | 51 | ||||
| -rw-r--r-- | indra/llcommon/llstl.h | 51 | ||||
| -rw-r--r-- | indra/llcommon/llthread.h | 17 | ||||
| -rw-r--r-- | indra/llcommon/lltypeinfolookup.h | 141 | ||||
| -rw-r--r-- | indra/llcommon/stdenums.h | 3 | 
14 files changed, 1286 insertions, 786 deletions
diff --git a/indra/llcommon/indra_constants.h b/indra/llcommon/indra_constants.h index 0745696ef3..0da83720bd 100644 --- a/indra/llcommon/indra_constants.h +++ b/indra/llcommon/indra_constants.h @@ -62,6 +62,7 @@ enum LAND_STAT_FLAGS  	STAT_FILTER_BY_PARCEL	= 0x00000001,  	STAT_FILTER_BY_OWNER	= 0x00000002,  	STAT_FILTER_BY_OBJECT	= 0x00000004, +	STAT_FILTER_BY_PARCEL_NAME	= 0x00000008,  	STAT_REQUEST_LAST_ENTRY	= 0x80000000,  }; diff --git a/indra/llcommon/llassettype.cpp b/indra/llcommon/llassettype.cpp index 5e566d6c7c..5ae2df3994 100644 --- a/indra/llcommon/llassettype.cpp +++ b/indra/llcommon/llassettype.cpp @@ -95,6 +95,7 @@ LLAssetDictionary::LLAssetDictionary()  	addEntry(LLAssetType::AT_LINK_FOLDER, 		new AssetEntry("FOLDER_LINK",		"link_f", 	"sym folder link",	false,		false,		true));  	addEntry(LLAssetType::AT_MESH,              new AssetEntry("MESH",              "mesh",     "mesh",             false,      false,      false));  	addEntry(LLAssetType::AT_WIDGET,            new AssetEntry("WIDGET",            "widget",   "widget",           false,      false,      false)); +	addEntry(LLAssetType::AT_PERSON,            new AssetEntry("PERSON",            "person",   "person",           false,      false,      false));  	addEntry(LLAssetType::AT_NONE, 				new AssetEntry("NONE",				"-1",		NULL,		  		FALSE,		FALSE,		FALSE));  }; diff --git a/indra/llcommon/llassettype.h b/indra/llcommon/llassettype.h index d538accbf7..69b01731e5 100644 --- a/indra/llcommon/llassettype.h +++ b/indra/llcommon/llassettype.h @@ -112,6 +112,9 @@ public:  		AT_WIDGET = 40,  			// UI Widget: this is *not* an inventory asset type, only a viewer side asset (e.g. button, other ui items...) +		AT_PERSON = 45, +			// A user uuid  which is not an inventory asset type, used in viewer only for adding a person to a chat via drag and drop. +  		AT_MESH = 49,  			// Mesh data in our proprietary SLM format diff --git a/indra/llcommon/llfoldertype.h b/indra/llcommon/llfoldertype.h index a0c847914f..a0c847914f 100644..100755 --- a/indra/llcommon/llfoldertype.h +++ b/indra/llcommon/llfoldertype.h diff --git a/indra/llcommon/llinitparam.cpp b/indra/llcommon/llinitparam.cpp index db72aa19b9..89c831d296 100644 --- a/indra/llcommon/llinitparam.cpp +++ b/indra/llcommon/llinitparam.cpp @@ -40,7 +40,9 @@ namespace LLInitParam  	{  		const U8* my_addr = reinterpret_cast<const U8*>(this);  		const U8* block_addr = reinterpret_cast<const U8*>(enclosing_block); -		mEnclosingBlockOffset = 0x7FFFffff & (U32)(my_addr - block_addr); +		U32 enclosing_block_offset = 0x7FFFffff & (U32)(my_addr - block_addr); +		mEnclosingBlockOffsetLow = enclosing_block_offset & 0x0000ffff; +		mEnclosingBlockOffsetHigh = (enclosing_block_offset & 0x007f0000) >> 16;  	}  	// @@ -112,6 +114,35 @@ namespace LLInitParam  		std::copy(src_block_data.mAllParams.begin(), src_block_data.mAllParams.end(), std::back_inserter(mAllParams));  	} +	void BlockDescriptor::addParam(const ParamDescriptorPtr in_param, const char* char_name) +	{ +		// create a copy of the param descriptor in mAllParams +		// so other data structures can store a pointer to it +		mAllParams.push_back(in_param); +		ParamDescriptorPtr param(mAllParams.back()); + +		std::string name(char_name); +		if ((size_t)param->mParamHandle > mMaxParamOffset) +		{ +			llerrs << "Attempted to register param with block defined for parent class, make sure to derive from LLInitParam::Block<YOUR_CLASS, PARAM_BLOCK_BASE_CLASS>" << llendl; +		} + +		if (name.empty()) +		{ +			mUnnamedParams.push_back(param); +		} +		else +		{ +			// don't use insert, since we want to overwrite existing entries +			mNamedParams[name] = param; +		} + +		if (param->mValidationFunc) +		{ +			mValidationList.push_back(std::make_pair(param->mParamHandle, param->mValidationFunc)); +		} +	} +  	BlockDescriptor::BlockDescriptor()  	:	mMaxParamOffset(0),  		mInitializationState(UNINITIALIZED), @@ -150,7 +181,8 @@ namespace LLInitParam  	bool BaseBlock::submitValue(Parser::name_stack_t& name_stack, Parser& p, bool silent)  	{ -		if (!deserializeBlock(p, std::make_pair(name_stack.begin(), name_stack.end()), true)) +		Parser::name_stack_range_t range = std::make_pair(name_stack.begin(), name_stack.end()); +		if (!deserializeBlock(p, range, true))  		{  			if (!silent)  			{ @@ -196,12 +228,7 @@ namespace LLInitParam  			if (serialize_func)  			{  				const Param* diff_param = diff_block ? diff_block->getParamFromHandle(param_handle) : NULL; -				// each param descriptor remembers its serial number -				// so we can inspect the same param under different names -				// and see that it has the same number -				name_stack.push_back(std::make_pair("", true));  				serialize_func(*param, parser, name_stack, diff_param); -				name_stack.pop_back();  			}  		} @@ -295,7 +322,7 @@ namespace LLInitParam  		return true;  	} -	bool BaseBlock::deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack_range, bool ignored) +	bool BaseBlock::deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool ignored)  	{  		BlockDescriptor& block_data = mostDerivedBlockDescriptor();  		bool names_left = name_stack_range.first != name_stack_range.second; @@ -308,15 +335,12 @@ namespace LLInitParam  		{  			const std::string& top_name = name_stack_range.first->first; -			ParamDescriptor::deserialize_func_t deserialize_func = NULL; -			Param* paramp = NULL; -  			BlockDescriptor::param_map_t::iterator found_it = block_data.mNamedParams.find(top_name);  			if (found_it != block_data.mNamedParams.end())  			{  				// find pointer to member parameter from offset table -				paramp = getParamFromHandle(found_it->second->mParamHandle); -				deserialize_func = found_it->second->mDeserializeFunc; +				Param* paramp = getParamFromHandle(found_it->second->mParamHandle); +				ParamDescriptor::deserialize_func_t deserialize_func = found_it->second->mDeserializeFunc;  				Parser::name_stack_range_t new_name_stack(name_stack_range.first, name_stack_range.second);  				++new_name_stack.first; @@ -358,36 +382,6 @@ namespace LLInitParam  		return false;  	} -	//static  -	void BaseBlock::addParam(BlockDescriptor& block_data, const ParamDescriptorPtr in_param, const char* char_name) -	{ -		// create a copy of the param descriptor in mAllParams -		// so other data structures can store a pointer to it -		block_data.mAllParams.push_back(in_param); -		ParamDescriptorPtr param(block_data.mAllParams.back()); - -		std::string name(char_name); -		if ((size_t)param->mParamHandle > block_data.mMaxParamOffset) -		{ -			llerrs << "Attempted to register param with block defined for parent class, make sure to derive from LLInitParam::Block<YOUR_CLASS, PARAM_BLOCK_BASE_CLASS>" << llendl; -		} - -		if (name.empty()) -		{ -			block_data.mUnnamedParams.push_back(param); -		} -		else -		{ -			// don't use insert, since we want to overwrite existing entries -			block_data.mNamedParams[name] = param; -		} - -		if (param->mValidationFunc) -		{ -			block_data.mValidationList.push_back(std::make_pair(param->mParamHandle, param->mValidationFunc)); -		} -	} -  	void BaseBlock::addSynonym(Param& param, const std::string& synonym)  	{  		BlockDescriptor& block_data = mostDerivedBlockDescriptor(); @@ -460,7 +454,7 @@ namespace LLInitParam  			if (merge_func)  			{  				Param* paramp = getParamFromHandle((*it)->mParamHandle); -				llassert(paramp->mEnclosingBlockOffset == (*it)->mParamHandle); +				llassert(paramp->getEnclosingBlockOffset() == (*it)->mParamHandle);  				some_param_changed |= merge_func(*paramp, *other_paramp, overwrite);  			}  		} diff --git a/indra/llcommon/llinitparam.h b/indra/llcommon/llinitparam.h index 99983a19cb..be07ccc0f8 100644 --- a/indra/llcommon/llinitparam.h +++ b/indra/llcommon/llinitparam.h @@ -35,7 +35,72 @@  #include <boost/shared_ptr.hpp>  #include "llerror.h" -#include "lltypeinfolookup.h" +#include "llstl.h" + +namespace LLTypeTags +{ +	template <typename INNER_TYPE, int _SORT_ORDER> +	struct TypeTagBase +	{ +		typedef void		is_tag_t; +		typedef INNER_TYPE	inner_t; +		static const int	SORT_ORDER=_SORT_ORDER; +	}; + +	template <int VAL1, int VAL2> +	struct GreaterThan +	{ +		static const bool value = VAL1 > VAL2; +	}; + +	template<typename ITEM, typename REST, bool NEEDS_SWAP = GreaterThan<ITEM::SORT_ORDER, REST::SORT_ORDER>::value > +	struct Swap +	{ +		typedef typename ITEM::template Cons<REST>::value_t value_t; +	}; + +	template<typename ITEM, typename REST> +	struct Swap<ITEM, REST, true> +	{ +		typedef typename REST::template Cons<Swap<ITEM, typename REST::inner_t>::value_t>::value_t value_t; +	}; + +	template<typename T, typename SORTABLE = void> +	struct IsSortable +	{ +		static const bool value = false; +	}; + +	template<typename T> +	struct IsSortable<T, typename T::is_tag_t> +	{ +		static const bool value = true; +	}; + +	template<typename ITEM, typename REST, bool IS_REST_SORTABLE = IsSortable<REST>::value> +	struct InsertInto +	{ +		typedef typename ITEM::template Cons<REST>::value_t value_t; +	}; + +	template<typename ITEM, typename REST> +	struct InsertInto <ITEM, REST, true> +	{ +		typedef typename Swap<ITEM, REST>::value_t value_t; +	}; + +	template<typename T, bool SORTABLE = IsSortable<T>::value> +	struct Sorted +	{ +		typedef T value_t; +	}; + +	template<typename T> +	struct Sorted <T, true> +	{ +		typedef typename InsertInto<T, typename Sorted<typename T::inner_t>::value_t>::value_t value_t; +	}; +}  namespace LLInitParam  { @@ -44,6 +109,8 @@ namespace LLInitParam  	template<typename T> const T& defaultValue() { static T value; return value; } +	// wraps comparison operator between any 2 values of the same type +	// specialize to handle cases where equality isn't defined well, or at all  	template <typename T, bool IS_BOOST_FUNCTION = boost::is_convertible<T, boost::function_base>::value >      struct ParamCompare   	{ @@ -78,24 +145,123 @@ namespace LLInitParam  	// helper functions and classes  	typedef ptrdiff_t param_handle_t; +	struct IS_A_BLOCK {}; +	struct NOT_BLOCK {}; + +	// these templates allow us to distinguish between template parameters +	// that derive from BaseBlock and those that don't +	template<typename T, typename BLOCK_IDENTIFIER = void> +	struct IsBlock +	{ +		typedef NOT_BLOCK value_t; +	}; + +	template<typename T> +	struct IsBlock<T, typename T::baseblock_base_class_t> +	{ +		typedef IS_A_BLOCK value_t; +	}; + +	// ParamValue class directly manages the wrapped value +	// by holding on to a copy (scalar params) +	// or deriving from it (blocks) +	// has specializations for custom value behavior +	// and "tag" values like Lazy and Atomic +	template<typename T, typename VALUE_IS_BLOCK = typename IsBlock<T>::value_t> +	class ParamValue +	{ +		typedef ParamValue<T, VALUE_IS_BLOCK>	self_t; + +	public: +		typedef T	default_value_t; +		typedef T	value_t; + +		ParamValue(): mValue() {} +		ParamValue(const default_value_t& other) : mValue(other) {} + +		void setValue(const value_t& val) +		{ +			mValue = val; +		} + +		const value_t& getValue() const +		{ +			return mValue; +		} + +		T& getValue() +		{ +			return mValue; +		} + +	protected: +		T mValue; +	}; + +	template<typename T> +	class ParamValue<T, IS_A_BLOCK>  +	:	public T +	{ +		typedef ParamValue<T, IS_A_BLOCK>	self_t; +	public: +		typedef T	default_value_t; +		typedef T	value_t; + +		ParamValue()  +		:	T(), +			mValidated(false) +		{} + +		ParamValue(const default_value_t& other) +		:	T(other), +			mValidated(false) +		{} + +		void setValue(const value_t& val) +		{ +			*this = val; +		} + +		const value_t& getValue() const +		{ +			return *this; +		} + +		T& getValue() +		{ +			return *this; +		} + +	protected: +		mutable bool 	mValidated; // lazy validation flag +	}; +  	// empty default implementation of key cache  	// leverages empty base class optimization  	template <typename T>  	class TypeValues +	:	public ParamValue<typename LLTypeTags::Sorted<T>::value_t>  	{  	private:  		struct Inaccessable{};  	public:  		typedef std::map<std::string, T> value_name_map_t;  		typedef Inaccessable name_t; +		typedef TypeValues<T> type_value_t; +		typedef ParamValue<typename LLTypeTags::Sorted<T>::value_t>	param_value_t; +		typedef typename param_value_t::value_t	value_t; + +		TypeValues(const typename param_value_t::value_t& val) +		:	param_value_t(val) +		{}  		void setValueName(const std::string& key) {}  		std::string getValueName() const { return ""; } -		std::string calcValueName(const T& value) const { return ""; } +		std::string calcValueName(const value_t& value) const { return ""; }  		void clearValueName() const {} -		static bool getValueFromName(const std::string& name, T& value) +		static bool getValueFromName(const std::string& name, value_t& value)  		{  			return false;  		} @@ -110,15 +276,39 @@ namespace LLInitParam  			return NULL;  		} +		void assignNamedValue(const Inaccessable& name) +		{} + +		operator const value_t&() const +		{ +			return param_value_t::getValue(); +		} + +		const value_t& operator()() const +		{ +			return param_value_t::getValue(); +		} +  		static value_name_map_t* getValueNames() {return NULL;}  	}; -	template <typename T, typename DERIVED_TYPE = TypeValues<T> > +	// helper class to implement name value lookups +	// and caching of last used name +	template <typename T, typename DERIVED_TYPE = TypeValues<T>, bool IS_SPECIALIZED = true >  	class TypeValuesHelper +	:	public ParamValue<typename LLTypeTags::Sorted<T>::value_t>  	{ +		typedef TypeValuesHelper<T, DERIVED_TYPE, IS_SPECIALIZED> self_t;  	public:  		typedef typename std::map<std::string, T> value_name_map_t;  		typedef std::string name_t; +		typedef self_t type_value_t; +		typedef ParamValue<typename LLTypeTags::Sorted<T>::value_t> param_value_t; +		typedef typename param_value_t::value_t	value_t; + +		TypeValuesHelper(const typename param_value_t::value_t& val) +		:	param_value_t(val) +		{}  		//TODO: cache key by index to save on param block size  		void setValueName(const std::string& value_name)  @@ -131,7 +321,7 @@ namespace LLInitParam  			return mValueName;   		} -		std::string calcValueName(const T& value) const +		std::string calcValueName(const value_t& value) const  		{  			value_name_map_t* map = getValueNames();  			for (typename value_name_map_t::iterator it = map->begin(), end_it = map->end(); @@ -152,7 +342,7 @@ namespace LLInitParam  			mValueName.clear();  		} -		static bool getValueFromName(const std::string& name, T& value) +		static bool getValueFromName(const std::string& name, value_t& value)  		{  			value_name_map_t* map = getValueNames();  			typename value_name_map_t::iterator found_it = map->find(name); @@ -194,32 +384,96 @@ namespace LLInitParam  			return &sValues;  		} -		static void declare(const std::string& name, const T& value) +		static void declare(const std::string& name, const value_t& value)  		{  			(*getValueNames())[name] = value;  		} +		void operator ()(const std::string& name) +		{ +			*this = name; +		} + +		void assignNamedValue(const std::string& name) +		{ +			if (getValueFromName(name, param_value_t::getValue())) +			{ +				setValueName(name); +			} +		} + +		operator const value_t&() const +		{ +			return param_value_t::getValue(); +		} + +		const value_t& operator()() const +		{ +			return param_value_t::getValue(); +		} +  	protected: -		static void getName(const std::string& name, const T& value) +		static void getName(const std::string& name, const value_t& value)  		{}  		mutable std::string	mValueName;  	}; -	class LL_COMMON_API Parser +	// string types can support custom named values, but need +	// to disambiguate in code between a string that is a named value +	// and a string that is a name +	template <typename DERIVED_TYPE> +	class TypeValuesHelper<std::string, DERIVED_TYPE, true> +	:	public TypeValuesHelper<std::string, DERIVED_TYPE, false>  	{ -		LOG_CLASS(Parser); -  	public: -		 -		struct CompareTypeID +		typedef TypeValuesHelper<std::string, DERIVED_TYPE, true> self_t; +		typedef TypeValuesHelper<std::string, DERIVED_TYPE, false> base_t; +		typedef std::string value_t; +		typedef std::string name_t; +		typedef self_t type_value_t; + +		TypeValuesHelper(const std::string& val) +		:	TypeValuesHelper(val) +		{} + +		void operator ()(const std::string& name)  		{ -			bool operator()(const std::type_info* lhs, const std::type_info* rhs) const +			*this = name; +		} + +		self_t& operator =(const std::string& name) +		{ +			if (base_t::getValueFromName(name, ParamValue<std::string>::getValue()))  			{ -				return lhs->before(*rhs); +				base_t::setValueName(name);  			} -		}; +			else +			{ +				ParamValue<std::string>::setValue(name); +			} +			return *this; +		} +		 +		operator const value_t&() const +		{ +			return ParamValue<std::string>::getValue(); +		} + +		const value_t& operator()() const +		{ +			return ParamValue<std::string>::getValue(); +		} +	}; + +	// parser base class with mechanisms for registering readers/writers/inspectors of different types +	class LL_COMMON_API Parser +	{ +		LOG_CLASS(Parser); + +	public: +		  		typedef std::vector<std::pair<std::string, bool> >					name_stack_t;  		typedef std::pair<name_stack_t::iterator, name_stack_t::iterator>	name_stack_range_t;  		typedef std::vector<std::string>									possible_values_t; @@ -228,9 +482,9 @@ namespace LLInitParam  		typedef bool (*parser_write_func_t)(Parser& parser, const void*, name_stack_t&);  		typedef boost::function<void (name_stack_t&, S32, S32, const possible_values_t*)>	parser_inspect_func_t; -		typedef LLTypeInfoLookup<parser_read_func_t>		parser_read_func_map_t; -		typedef LLTypeInfoLookup<parser_write_func_t>		parser_write_func_map_t; -		typedef LLTypeInfoLookup<parser_inspect_func_t>		parser_inspect_func_map_t; +		typedef std::map<const std::type_info*, parser_read_func_t>		parser_read_func_map_t; +		typedef std::map<const std::type_info*, parser_write_func_t>	parser_write_func_map_t; +		typedef std::map<const std::type_info*, parser_inspect_func_t>	parser_inspect_func_map_t;  		Parser(parser_read_func_map_t& read_map, parser_write_func_map_t& write_map, parser_inspect_func_map_t& inspect_map)  		:	mParseSilently(false), @@ -310,7 +564,7 @@ namespace LLInitParam  		};  		typedef bool(*merge_func_t)(Param&, const Param&, bool); -		typedef bool(*deserialize_func_t)(Param&, Parser&, const Parser::name_stack_range_t&, bool); +		typedef bool(*deserialize_func_t)(Param&, Parser&, Parser::name_stack_range_t&, bool);  		typedef void(*serialize_func_t)(const Param&, Parser&, Parser::name_stack_t&, const Param* diff_param);  		typedef void(*inspect_func_t)(const Param&, Parser&, Parser::name_stack_t&, S32 min_count, S32 max_count);  		typedef bool(*validation_func_t)(const Param*); @@ -355,6 +609,7 @@ namespace LLInitParam  		} EInitializationState;  		void aggregateBlockData(BlockDescriptor& src_block_data); +		void addParam(ParamDescriptorPtr param, const char* name);  		typedef boost::unordered_map<const std::string, ParamDescriptorPtr>						param_map_t;   		typedef std::vector<ParamDescriptorPtr>													param_list_t;  @@ -370,86 +625,144 @@ namespace LLInitParam  		class BaseBlock*				mCurrentBlockPtr;		// pointer to block currently being constructed  	}; -	class LL_COMMON_API BaseBlock +	//TODO: implement in terms of owned_ptr +	template<typename T> +	class LazyValue  	{ -	public: -		//TODO: implement in terms of owned_ptr -		template<typename T> -		class Lazy -		{  		public: -			Lazy() -				: mPtr(NULL) -			{} +		LazyValue() +		: mPtr(NULL) +		{} + +		~LazyValue() +		{ +			delete mPtr; +		} + +		LazyValue(const T& value) +		{ +			mPtr = new T(value); +		} + +		LazyValue(const LazyValue& other) +		:	mPtr(NULL) +		{ +			*this = other; +		} -			~Lazy() +		LazyValue& operator = (const LazyValue& other) +		{ +			if (!other.mPtr)  			{  				delete mPtr; +				mPtr = NULL;  			} - -			Lazy(const Lazy& other) +			else  			{ -				if (other.mPtr) +				if (!mPtr)  				{  					mPtr = new T(*other.mPtr);  				}  				else  				{ -					mPtr = NULL; +					*mPtr = *(other.mPtr);  				}  			} +			return *this; +		} -			Lazy<T>& operator = (const Lazy<T>& other) -			{ -				if (other.mPtr) -				{ -					mPtr = new T(*other.mPtr); -				} -				else -				{ -					mPtr = NULL; -				} -				return *this; -			} +		bool operator==(const LazyValue& other) const +		{ +			if (empty() || other.empty()) return false; +			return *mPtr == *other.mPtr; +		} -			bool empty() const -			{ -				return mPtr == NULL; -			} +		bool empty() const +		{ +			return mPtr == NULL; +		} -			void set(const T& other) +		void set(const T& other) +		{ +			if (!mPtr)  			{ -				delete mPtr;  				mPtr = new T(other);  			} - -			const T& get() const +			else  			{ -				return ensureInstance(); +				*mPtr = other;  			} +		} -			T& get() -			{ -				return ensureInstance(); -			} +		const T& get() const +		{ +			return *ensureInstance(); +		} -		private: -			// lazily allocate an instance of T -			T* ensureInstance() const +		T& get() +		{ +			return *ensureInstance(); +		} + +		operator const T&() const +		{  +			return get();  +		} + +	private: +		// lazily allocate an instance of T +		T* ensureInstance() const +		{ +			if (mPtr == NULL)  			{ -				if (mPtr == NULL) -				{ -					mPtr = new T(); -				} -				return mPtr; -			} +				mPtr = new T();			 +                        } +			return mPtr; +		} -		private: -			// if you get a compilation error with this, that means you are using a forward declared struct for T -			// unfortunately, the type traits we rely on don't work with forward declared typed -			//static const int dummy = sizeof(T); +	private: + +		mutable T* mPtr; +	}; + +	// root class of all parameter blocks + +	class LL_COMMON_API BaseBlock +	{ +	public: +		// lift block tags into baseblock namespace so derived classes do not need to qualify them +		typedef LLInitParam::IS_A_BLOCK IS_A_BLOCK; +		typedef LLInitParam::NOT_BLOCK NOT_A_BLOCK; + +		template<typename T> +		struct Sequential : public LLTypeTags::TypeTagBase<T, 2> +		{ +			template <typename S> struct Cons { typedef Sequential<ParamValue<S> > value_t; }; +			template <typename S> struct Cons<Sequential<S> > { typedef Sequential<S> value_t; }; +		}; -			mutable T* mPtr; +		template<typename T> +		struct Atomic : public LLTypeTags::TypeTagBase<T, 1> +		{ +			template <typename S> struct Cons { typedef Atomic<ParamValue<S> > value_t; }; +			template <typename S> struct Cons<Atomic<S> > { typedef Atomic<S> value_t; }; +		}; + +		template<typename T, typename BLOCK_T = typename IsBlock<T>::value_t > +		struct Lazy : public LLTypeTags::TypeTagBase<T, 0> +		{ +			template <typename S> struct Cons +			{ +				typedef Lazy<ParamValue<S, BLOCK_T>, BLOCK_T> value_t; +			}; +			template <typename S> struct Cons<Lazy<S, IS_A_BLOCK> > +			{ +				typedef Lazy<S, IS_A_BLOCK> value_t; +			}; +			template <typename S> struct Cons<Lazy<S, NOT_A_BLOCK> > +			{ +				typedef Lazy<S, BLOCK_T> value_t; +			};  		};  		// "Multiple" constraint types, put here in root class to avoid ambiguity during use @@ -517,12 +830,12 @@ namespace LLInitParam  		// Blocks can override this to do custom tracking of changes  		virtual void paramChanged(const Param& changed_param, bool user_provided) {} -		bool deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack_range, bool new_name); +		bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name);  		void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block = NULL) const;  		bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const; -		virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return selfBlockDescriptor(); } -		virtual BlockDescriptor& mostDerivedBlockDescriptor() { return selfBlockDescriptor(); } +		virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return getBlockDescriptor(); } +		virtual BlockDescriptor& mostDerivedBlockDescriptor() { return getBlockDescriptor(); }  		// take all provided params from other and apply to self  		bool overwriteFrom(const BaseBlock& other) @@ -536,10 +849,17 @@ namespace LLInitParam  			return false;  		} -		static void addParam(BlockDescriptor& block_data, ParamDescriptorPtr param, const char* name); -  		ParamDescriptorPtr findParamDescriptor(const Param& param); +		// take all provided params from other and apply to self +		bool mergeBlock(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite); + +		static BlockDescriptor& getBlockDescriptor() +		{ +			static BlockDescriptor sBlockDescriptor; +			return sBlockDescriptor; +		} +  	protected:  		void init(BlockDescriptor& descriptor, BlockDescriptor& base_descriptor, size_t block_size); @@ -548,25 +868,11 @@ namespace LLInitParam  		{  			return mergeBlock(block_data, source, overwrite);  		} -		// take all provided params from other and apply to self -		bool mergeBlock(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite); - -		static BlockDescriptor& selfBlockDescriptor() -		{ -			static BlockDescriptor sBlockDescriptor; -			return sBlockDescriptor; -		}  	private:  		const std::string& getParamName(const BlockDescriptor& block_data, const Param* paramp) const;  	}; -	template<typename T> -	struct ParamCompare<BaseBlock::Lazy<T>, false > -	{ -		static bool equals(const BaseBlock::Lazy<T>& a, const BaseBlock::Lazy<T>& b) { return !a.empty() || !b.empty(); } -	}; -  	class LL_COMMON_API Param  	{  	public: @@ -595,256 +901,68 @@ namespace LLInitParam  			// get address of enclosing BLOCK class using stored offset to enclosing BaseBlock class  			return *const_cast<BaseBlock*>  				(reinterpret_cast<const BaseBlock*> -					(my_addr - (ptrdiff_t)(S32)mEnclosingBlockOffset)); -		} - -	private: -		friend class BaseBlock; - -		U32		mEnclosingBlockOffset:31; -		U32		mIsProvided:1; - -	}; - -	// these templates allow us to distinguish between template parameters -	// that derive from BaseBlock and those that don't -	template<typename T, typename Void = void> -	struct IsBlock -	{ -		static const bool value = false; -		struct EmptyBase {}; -		typedef EmptyBase base_class_t; -	}; - -	template<typename T> -	struct IsBlock<T, typename T::baseblock_base_class_t> -	{ -		static const bool value = true; -		typedef BaseBlock base_class_t; -	}; - -	template<typename T> -	struct IsBlock<BaseBlock::Lazy<T>, typename T::baseblock_base_class_t > -	{ -		static const bool value = true; -		typedef BaseBlock base_class_t; -	}; - -	template<typename T, typename NAME_VALUE_LOOKUP, bool VALUE_IS_BLOCK = IsBlock<T>::value> -	class ParamValue : public NAME_VALUE_LOOKUP -	{ -	public: -		typedef const T&							value_assignment_t; -		typedef T									value_t; -		typedef ParamValue<T, NAME_VALUE_LOOKUP, VALUE_IS_BLOCK>	self_t; - -		ParamValue(): mValue() {} -		ParamValue(value_assignment_t other) : mValue(other) {} - -		void setValue(value_assignment_t val) -		{ -			mValue = val; -		} - -		value_assignment_t getValue() const -		{ -			return mValue; -		} - -		T& getValue() -		{ -			return mValue; -		} - -		operator value_assignment_t() const -		{ -			return mValue; -		} - -		value_assignment_t operator()() const -		{ -			return mValue; -		} - -		void operator ()(const typename NAME_VALUE_LOOKUP::name_t& name) -		{ -			*this = name; -		} - -		self_t& operator =(const typename NAME_VALUE_LOOKUP::name_t& name) -		{ -			if (NAME_VALUE_LOOKUP::getValueFromName(name, mValue)) -			{ -				setValueName(name); -			} - -			return *this; -		} - -	protected: -		T mValue; -	}; - -	template<typename T, typename NAME_VALUE_LOOKUP> -	class ParamValue<T, NAME_VALUE_LOOKUP, true>  -	:	public T, -		public NAME_VALUE_LOOKUP -	{ -	public: -		typedef const T&							value_assignment_t; -		typedef T									value_t; -		typedef ParamValue<T, NAME_VALUE_LOOKUP, true>	self_t; - -		ParamValue()  -		:	T(), -			mValidated(false) -		{} - -		ParamValue(value_assignment_t other) -		:	T(other), -			mValidated(false) -		{} - -		void setValue(value_assignment_t val) -		{ -			*this = val; -		} - -		value_assignment_t getValue() const -		{ -			return *this; -		} - -		T& getValue() -		{ -			return *this; +					(my_addr - (ptrdiff_t)getEnclosingBlockOffset()));  		} -		operator value_assignment_t() const +		U32 getEnclosingBlockOffset() const  		{ -			return *this; -		} -		 -		value_assignment_t operator()() const -		{ -			return *this; -		} - -		void operator ()(const typename NAME_VALUE_LOOKUP::name_t& name) -		{ -			*this = name; -		} - -		self_t& operator =(const typename NAME_VALUE_LOOKUP::name_t& name) -		{ -			if (NAME_VALUE_LOOKUP::getValueFromName(name, *this)) -			{ -				setValueName(name); -			} - -			return *this; -		} - -	protected: -		mutable bool 	mValidated; // lazy validation flag -	}; - -	template<typename NAME_VALUE_LOOKUP> -	class ParamValue<std::string, NAME_VALUE_LOOKUP, false> -	: public NAME_VALUE_LOOKUP -	{ -	public: -		typedef const std::string&	value_assignment_t; -		typedef std::string			value_t; -		typedef ParamValue<std::string, NAME_VALUE_LOOKUP, false>	self_t; - -		ParamValue(): mValue() {} -		ParamValue(value_assignment_t other) : mValue(other) {} - -		void setValue(value_assignment_t val) -		{ -			if (NAME_VALUE_LOOKUP::getValueFromName(val, mValue)) -			{ -				NAME_VALUE_LOOKUP::setValueName(val); -			} -			else -			{ -				mValue = val; -			} -		} - -		value_assignment_t getValue() const -		{ -			return mValue; +			return ((U32)mEnclosingBlockOffsetHigh << 16) | (U32)mEnclosingBlockOffsetLow;  		} -		std::string& getValue() -		{ -			return mValue; -		} - -		operator value_assignment_t() const -		{ -			return mValue; -		} +	private: +		friend class BaseBlock; -		value_assignment_t operator()() const -		{ -			return mValue; -		} +		//24 bits for member offset field and 1 bit for provided flag +		U16		mEnclosingBlockOffsetLow; +		U8		mEnclosingBlockOffsetHigh:7; +		U8		mIsProvided:1; -	protected: -		std::string mValue;  	}; -  	template<typename T, typename NAME_VALUE_LOOKUP = TypeValues<T> >  	struct ParamIterator  	{ -		typedef typename std::vector<ParamValue<T, NAME_VALUE_LOOKUP> >::const_iterator		const_iterator; -		typedef typename std::vector<ParamValue<T, NAME_VALUE_LOOKUP> >::iterator			iterator; +		typedef typename std::vector<typename NAME_VALUE_LOOKUP::type_value_t >::const_iterator	const_iterator; +		typedef typename std::vector<typename NAME_VALUE_LOOKUP::type_value_t >::iterator			iterator;  	}; -	// specialize for custom parsing/decomposition of specific classes -	// e.g. TypedParam<LLRect> has left, top, right, bottom, etc... +	// wrapper for parameter with a known type +	// specialized to handle 4 cases: +	// simple "scalar" value +	// parameter that is itself a block +	// multiple scalar values, stored in a vector +	// multiple blocks, stored in a vector  	template<typename	T,  			typename	NAME_VALUE_LOOKUP = TypeValues<T>,  			bool		HAS_MULTIPLE_VALUES = false, -			bool		VALUE_IS_BLOCK = IsBlock<ParamValue<T, NAME_VALUE_LOOKUP> >::value> +			typename	VALUE_IS_BLOCK = typename IsBlock<ParamValue<typename LLTypeTags::Sorted<T>::value_t> >::value_t>  	class TypedParam   	:	public Param,  -		public ParamValue<T, NAME_VALUE_LOOKUP> +		public NAME_VALUE_LOOKUP::type_value_t  	{ +	protected: +		typedef	TypedParam<T, NAME_VALUE_LOOKUP, HAS_MULTIPLE_VALUES, VALUE_IS_BLOCK>	self_t; +		typedef ParamValue<typename LLTypeTags::Sorted<T>::value_t>						param_value_t; +		typedef typename param_value_t::default_value_t									default_value_t; +		typedef typename NAME_VALUE_LOOKUP::type_value_t								named_value_t;  	public: -		typedef	TypedParam<T, NAME_VALUE_LOOKUP, HAS_MULTIPLE_VALUES, VALUE_IS_BLOCK>		self_t; -		typedef ParamValue<T, NAME_VALUE_LOOKUP>											param_value_t; -		typedef typename param_value_t::value_assignment_t				value_assignment_t; -		typedef NAME_VALUE_LOOKUP															name_value_lookup_t; +		typedef typename param_value_t::value_t											value_t; -		using param_value_t::operator(); +		using named_value_t::operator(); -		TypedParam(BlockDescriptor& block_descriptor, const char* name, value_assignment_t value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count)  -		:	Param(block_descriptor.mCurrentBlockPtr) +		TypedParam(BlockDescriptor& block_descriptor, const char* name, const default_value_t& value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count) +		:	Param(block_descriptor.mCurrentBlockPtr), +			named_value_t(value)  		{  			if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING))  			{ - 				ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( -												block_descriptor.mCurrentBlockPtr->getHandleFromParam(this), -												&mergeWith, -												&deserializeParam, -												&serializeParam, -												validate_func, -												&inspectParam, -												min_count, max_count)); -				BaseBlock::addParam(block_descriptor, param_descriptor, name); +				init(block_descriptor, validate_func, min_count, max_count, name);  			} - -			setValue(value);  		}   		bool isProvided() const { return Param::anyProvided(); } -		static bool deserializeParam(Param& param, Parser& parser, const Parser::name_stack_range_t& name_stack_range, bool new_name) +		static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name)  		{   			self_t& typed_param = static_cast<self_t&>(param);  			// no further names in stack, attempt to parse value now @@ -858,14 +976,15 @@ namespace LLInitParam  				}  				// try to parse a known named value -				if(name_value_lookup_t::valueNamesExist()) +				if(named_value_t::valueNamesExist())  				{  					// try to parse a known named value  					std::string name;  					if (parser.readValue(name))  					{  						// try to parse a per type named value -						if (name_value_lookup_t::getValueFromName(name, typed_param.getValue())) + +						if (named_value_t::getValueFromName(name, typed_param.getValue()))  						{  							typed_param.setValueName(name);  							typed_param.setProvided(); @@ -905,7 +1024,9 @@ namespace LLInitParam  				if (!parser.writeValue(typed_param.getValue(), name_stack))   				{  					std::string calculated_key = typed_param.calcValueName(typed_param.getValue()); -					if (!diff_param || !ParamCompare<std::string>::equals(static_cast<const self_t*>(diff_param)->getValueName(), calculated_key)) +					if (calculated_key.size()  +						&& (!diff_param  +							|| !ParamCompare<std::string>::equals(static_cast<const self_t*>(diff_param)->getValueName(), calculated_key)))  					{  						parser.writeValue(calculated_key, name_stack);  					} @@ -918,22 +1039,23 @@ namespace LLInitParam  			// tell parser about our actual type  			parser.inspectValue<T>(name_stack, min_count, max_count, NULL);  			// then tell it about string-based alternatives ("red", "blue", etc. for LLColor4) -			if (name_value_lookup_t::getPossibleValues()) +			if (named_value_t::getPossibleValues())  			{ -				parser.inspectValue<std::string>(name_stack, min_count, max_count, name_value_lookup_t::getPossibleValues()); +				parser.inspectValue<std::string>(name_stack, min_count, max_count, named_value_t::getPossibleValues());  			}  		} -		void set(value_assignment_t val, bool flag_as_provided = true) +		void set(const value_t& val, bool flag_as_provided = true)  		{ -			param_value_t::clearValueName(); +			named_value_t::clearValueName();  			setValue(val);  			setProvided(flag_as_provided);  		} -		self_t& operator =(const typename NAME_VALUE_LOOKUP::name_t& name) +		self_t& operator =(const typename named_value_t::name_t& name)  		{ -			return static_cast<self_t&>(param_value_t::operator =(name)); +			named_value_t::assignNamedValue(name); +			return *this;  		}  	protected: @@ -958,41 +1080,47 @@ namespace LLInitParam  			}  			return false;  		} +	private: +		void init( BlockDescriptor &block_descriptor, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count, const char* name )  +		{ +			ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( +				block_descriptor.mCurrentBlockPtr->getHandleFromParam(this), +				&mergeWith, +				&deserializeParam, +				&serializeParam, +				validate_func, +				&inspectParam, +				min_count, max_count)); +			block_descriptor.addParam(param_descriptor, name); +		}  	};  	// parameter that is a block  	template <typename T, typename NAME_VALUE_LOOKUP> -	class TypedParam<T, NAME_VALUE_LOOKUP, false, true>  +	class TypedParam<T, NAME_VALUE_LOOKUP, false, IS_A_BLOCK>   	:	public Param, -		public ParamValue<T, NAME_VALUE_LOOKUP> +		public NAME_VALUE_LOOKUP::type_value_t  	{ +	protected: +		typedef ParamValue<typename LLTypeTags::Sorted<T>::value_t>	param_value_t; +		typedef typename param_value_t::default_value_t				default_value_t; +		typedef TypedParam<T, NAME_VALUE_LOOKUP, false, IS_A_BLOCK>	self_t; +		typedef typename NAME_VALUE_LOOKUP::type_value_t			named_value_t;  	public: -		typedef ParamValue<T, NAME_VALUE_LOOKUP>				param_value_t; -		typedef typename param_value_t::value_assignment_t		value_assignment_t; -		typedef TypedParam<T, NAME_VALUE_LOOKUP, false, true>	self_t; -		typedef NAME_VALUE_LOOKUP								name_value_lookup_t; +		using named_value_t::operator(); +		typedef typename param_value_t::value_t						value_t; -		using param_value_t::operator(); - -		TypedParam(BlockDescriptor& block_descriptor, const char* name, value_assignment_t value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count) +		TypedParam(BlockDescriptor& block_descriptor, const char* name, const default_value_t& value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count)  		:	Param(block_descriptor.mCurrentBlockPtr), -			param_value_t(value) +			named_value_t(value)  		{  			if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING))  			{ -				ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( -												block_descriptor.mCurrentBlockPtr->getHandleFromParam(this), -												&mergeWith, -												&deserializeParam, -												&serializeParam, -												validate_func,  -												&inspectParam, -												min_count, max_count)); -				BaseBlock::addParam(block_descriptor, param_descriptor, name); +				init(block_descriptor, validate_func, min_count, max_count, name);  			}  		} -		static bool deserializeParam(Param& param, Parser& parser, const Parser::name_stack_range_t& name_stack_range, bool new_name) +		static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name)  		{   			self_t& typed_param = static_cast<self_t&>(param);  			// attempt to parse block... @@ -1003,14 +1131,14 @@ namespace LLInitParam  				return true;  			} -			if(name_value_lookup_t::valueNamesExist()) +			if(named_value_t::valueNamesExist())  			{  				// try to parse a known named value  				std::string name;  				if (parser.readValue(name))  				{  					// try to parse a per type named value -					if (name_value_lookup_t::getValueFromName(name, typed_param.getValue())) +					if (named_value_t::getValueFromName(name, typed_param.getValue()))  					{  						typed_param.setValueName(name);  						typed_param.setProvided(); @@ -1035,9 +1163,9 @@ namespace LLInitParam  			std::string key = typed_param.getValueName();  			if (!key.empty())  			{ -				if (!parser.writeValue(key, name_stack)) +				if (!diff_param || !ParamCompare<std::string>::equals(static_cast<const self_t*>(diff_param)->getValueName(), key))  				{ -					return; +					parser.writeValue(key, name_stack);  				}  			}  			else @@ -1048,8 +1176,16 @@ namespace LLInitParam  		static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count)  		{ -			// I am a param that is also a block, so just recurse into my contents  			const self_t& typed_param = static_cast<const self_t&>(param); + +			// tell parser about our actual type +			parser.inspectValue<value_t>(name_stack, min_count, max_count, NULL); +			// then tell it about string-based alternatives ("red", "blue", etc. for LLColor4) +			if (named_value_t::getPossibleValues()) +			{ +				parser.inspectValue<std::string>(name_stack, min_count, max_count, named_value_t::getPossibleValues()); +			} +  			typed_param.inspectBlock(parser, name_stack, min_count, max_count);  		} @@ -1067,32 +1203,34 @@ namespace LLInitParam  		}  		// assign block contents to this param-that-is-a-block -		void set(value_assignment_t val, bool flag_as_provided = true) +		void set(const value_t& val, bool flag_as_provided = true)  		{  			setValue(val); -			param_value_t::clearValueName(); +			named_value_t::clearValueName();  			// force revalidation of block  			// next call to isProvided() will update provision status based on validity  			param_value_t::mValidated = false;  			setProvided(flag_as_provided);  		} -		self_t& operator =(const typename NAME_VALUE_LOOKUP::name_t& name) +		self_t& operator =(const typename named_value_t::name_t& name)  		{ -			return static_cast<self_t&>(param_value_t::operator =(name)); +			named_value_t::assignNamedValue(name); +			return *this;  		}  		// propagate changed status up to enclosing block  		/*virtual*/ void paramChanged(const Param& changed_param, bool user_provided)  		{   			param_value_t::paramChanged(changed_param, user_provided); +  			if (user_provided)  			{  				// a child param has been explicitly changed  				// so *some* aspect of this block is now provided  				param_value_t::mValidated = false;  				setProvided(); -				param_value_t::clearValueName(); +				named_value_t::clearValueName();  			}  			else  			{ @@ -1116,7 +1254,7 @@ namespace LLInitParam  			if (src_typed_param.anyProvided())  			{ -				if (dst_typed_param.mergeBlockParam(src_typed_param.isProvided(), dst_typed_param.isProvided(), param_value_t::selfBlockDescriptor(), src_typed_param, overwrite)) +				if (dst_typed_param.mergeBlockParam(src_typed_param.isProvided(), dst_typed_param.isProvided(), param_value_t::getBlockDescriptor(), src_typed_param, overwrite))  				{  					dst_typed_param.clearValueName();  					dst_typed_param.setProvided(true); @@ -1125,49 +1263,65 @@ namespace LLInitParam  			}  			return false;  		} + +	private: +		void init( BlockDescriptor &block_descriptor, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count, const char* name )  +		{ +			ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( +				block_descriptor.mCurrentBlockPtr->getHandleFromParam(this), +				&mergeWith, +				&deserializeParam, +				&serializeParam, +				validate_func,  +				&inspectParam, +				min_count, max_count)); +			block_descriptor.addParam(param_descriptor, name); +		}  	}; -	// container of non-block parameters +	// list of non-block parameters  	template <typename VALUE_TYPE, typename NAME_VALUE_LOOKUP> -	class TypedParam<VALUE_TYPE, NAME_VALUE_LOOKUP, true, false>  +	class TypedParam<VALUE_TYPE, NAME_VALUE_LOOKUP, true, NOT_BLOCK>   	:	public Param  	{ +	protected: +		typedef TypedParam<VALUE_TYPE, NAME_VALUE_LOOKUP, true, NOT_BLOCK>		self_t; +		typedef ParamValue<typename LLTypeTags::Sorted<VALUE_TYPE>::value_t>	param_value_t; +		typedef typename std::vector<typename NAME_VALUE_LOOKUP::type_value_t>	container_t; +		typedef container_t														default_value_t; +		typedef typename NAME_VALUE_LOOKUP::type_value_t						named_value_t; +		  	public: -		typedef TypedParam<VALUE_TYPE, NAME_VALUE_LOOKUP, true, false>		self_t; -		typedef ParamValue<VALUE_TYPE, NAME_VALUE_LOOKUP>					param_value_t; -		typedef typename std::vector<param_value_t>							container_t; -		typedef const container_t&											value_assignment_t; -  		typedef typename param_value_t::value_t								value_t; -		typedef NAME_VALUE_LOOKUP											name_value_lookup_t; -		TypedParam(BlockDescriptor& block_descriptor, const char* name, value_assignment_t value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count)  +		TypedParam(BlockDescriptor& block_descriptor, const char* name, const default_value_t& value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count)  		:	Param(block_descriptor.mCurrentBlockPtr)  		{  			std::copy(value.begin(), value.end(), std::back_inserter(mValues));  			if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING))  			{ -				ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( -												block_descriptor.mCurrentBlockPtr->getHandleFromParam(this), -												&mergeWith, -												&deserializeParam, -												&serializeParam, -												validate_func, -												&inspectParam, -												min_count, max_count)); -				BaseBlock::addParam(block_descriptor, param_descriptor, name); +				init(block_descriptor, validate_func, min_count, max_count, name); +  			}  		}   		bool isProvided() const { return Param::anyProvided(); } -		static bool deserializeParam(Param& param, Parser& parser, const Parser::name_stack_range_t& name_stack_range, bool new_name) +		static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name)  		{  +			Parser::name_stack_range_t new_name_stack_range(name_stack_range);  			self_t& typed_param = static_cast<self_t&>(param);  			value_t value; + +			// pop first element if empty string +			if (new_name_stack_range.first != new_name_stack_range.second && new_name_stack_range.first->first.empty()) +			{ +				++new_name_stack_range.first; +			} +  			// no further names in stack, attempt to parse value now -			if (name_stack_range.first == name_stack_range.second) +			if (new_name_stack_range.first == new_name_stack_range.second)  			{  				// attempt to read value directly  				if (parser.readValue(value)) @@ -1177,14 +1331,14 @@ namespace LLInitParam  				}  				// try to parse a known named value -				if(name_value_lookup_t::valueNamesExist()) +				if(named_value_t::valueNamesExist())  				{  					// try to parse a known named value  					std::string name;  					if (parser.readValue(name))  					{  						// try to parse a per type named value -						if (name_value_lookup_t::getValueFromName(name, value)) +						if (named_value_t::getValueFromName(name, value))  						{  							typed_param.add(value);  							typed_param.mValues.back().setValueName(name); @@ -1200,14 +1354,14 @@ namespace LLInitParam  		static void serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const Param* diff_param)  		{  			const self_t& typed_param = static_cast<const self_t&>(param); -			if (!typed_param.isProvided() || name_stack.empty()) return; +			if (!typed_param.isProvided()) return;  			for (const_iterator it = typed_param.mValues.begin(), end_it = typed_param.mValues.end();  				it != end_it;  				++it)  			{  				std::string key = it->getValueName(); -				name_stack.back().second = true; +				name_stack.push_back(std::make_pair(std::string(), true));  				if(key.empty())  				// not parsed via name values, write out value directly @@ -1229,19 +1383,21 @@ namespace LLInitParam  						break;  					}  				} + +				name_stack.pop_back();  			}  		}  		static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count)  		{  			parser.inspectValue<VALUE_TYPE>(name_stack, min_count, max_count, NULL); -			if (name_value_lookup_t::getPossibleValues()) +			if (named_value_t::getPossibleValues())  			{ -				parser.inspectValue<std::string>(name_stack, min_count, max_count, name_value_lookup_t::getPossibleValues()); +				parser.inspectValue<std::string>(name_stack, min_count, max_count, named_value_t::getPossibleValues());  			}  		} -		void set(value_assignment_t val, bool flag_as_provided = true) +		void set(const container_t& val, bool flag_as_provided = true)  		{  			mValues = val;  			setProvided(flag_as_provided); @@ -1249,26 +1405,24 @@ namespace LLInitParam  		param_value_t& add()  		{ -			mValues.push_back(param_value_t(value_t())); +			mValues.push_back(value_t());  			Param::setProvided();  			return mValues.back();  		}  		self_t& add(const value_t& item)  		{ -			param_value_t param_value; -			param_value.setValue(item); -			mValues.push_back(param_value); +			mValues.push_back(item);  			setProvided();  			return *this;  		} -		self_t& add(const typename name_value_lookup_t::name_t& name) +		self_t& add(const typename named_value_t::name_t& name)  		{  			value_t value;  			// try to parse a per type named value -			if (name_value_lookup_t::getValueFromName(name, value)) +			if (named_value_t::getValueFromName(name, value))  			{  				add(value);  				mValues.back().setValueName(name); @@ -1278,9 +1432,9 @@ namespace LLInitParam  		}  		// implicit conversion -		operator value_assignment_t() const { return mValues; }  +		operator const container_t&() const { return mValues; }   		// explicit conversion		 -		value_assignment_t operator()() const { return mValues; } +		const container_t& operator()() const { return mValues; }  		typedef typename container_t::iterator iterator;  		typedef typename container_t::const_iterator const_iterator; @@ -1321,72 +1475,97 @@ namespace LLInitParam  		}  		container_t		mValues; + +	private: +		void init( BlockDescriptor &block_descriptor, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count, const char* name )  +		{ +			ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( +				block_descriptor.mCurrentBlockPtr->getHandleFromParam(this), +				&mergeWith, +				&deserializeParam, +				&serializeParam, +				validate_func, +				&inspectParam, +				min_count, max_count)); +			block_descriptor.addParam(param_descriptor, name); +		}  	}; -	// container of block parameters +	// list of block parameters  	template <typename VALUE_TYPE, typename NAME_VALUE_LOOKUP> -	class TypedParam<VALUE_TYPE, NAME_VALUE_LOOKUP, true, true>  +	class TypedParam<VALUE_TYPE, NAME_VALUE_LOOKUP, true, IS_A_BLOCK>   	:	public Param  	{ +	protected: +		typedef TypedParam<VALUE_TYPE, NAME_VALUE_LOOKUP, true, IS_A_BLOCK>		self_t; +		typedef ParamValue<typename LLTypeTags::Sorted<VALUE_TYPE>::value_t>	param_value_t; +		typedef typename std::vector<typename NAME_VALUE_LOOKUP::type_value_t>	container_t; +		typedef typename NAME_VALUE_LOOKUP::type_value_t						named_value_t; +		typedef container_t														default_value_t; +		typedef typename container_t::iterator									iterator; +		typedef typename container_t::const_iterator							const_iterator;  	public: -		typedef TypedParam<VALUE_TYPE, NAME_VALUE_LOOKUP, true, true>	self_t; -		typedef ParamValue<VALUE_TYPE, NAME_VALUE_LOOKUP>				param_value_t; -		typedef typename std::vector<param_value_t>						container_t; -		typedef const container_t&										value_assignment_t;  		typedef typename param_value_t::value_t							value_t; -		typedef NAME_VALUE_LOOKUP										name_value_lookup_t; -		TypedParam(BlockDescriptor& block_descriptor, const char* name, value_assignment_t value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count)  +		TypedParam(BlockDescriptor& block_descriptor, const char* name, const default_value_t& value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count)  		:	Param(block_descriptor.mCurrentBlockPtr)  		{  			std::copy(value.begin(), value.end(), back_inserter(mValues));  			if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING))  			{ -				ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( -												block_descriptor.mCurrentBlockPtr->getHandleFromParam(this), -												&mergeWith, -												&deserializeParam, -												&serializeParam, -												validate_func, -												&inspectParam, -												min_count, max_count)); -				BaseBlock::addParam(block_descriptor, param_descriptor, name); +				init(block_descriptor, validate_func, min_count, max_count, name);  			}  		}   		bool isProvided() const { return Param::anyProvided(); } -		static bool deserializeParam(Param& param, Parser& parser, const Parser::name_stack_range_t& name_stack_range, bool new_name)  +		static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name)   		{  +			Parser::name_stack_range_t new_name_stack_range(name_stack_range);  			self_t& typed_param = static_cast<self_t&>(param);  			bool new_value = false; +			bool new_array_value = false; -			if (new_name || typed_param.mValues.empty()) +			// pop first element if empty string +			if (new_name_stack_range.first != new_name_stack_range.second && new_name_stack_range.first->first.empty()) +			{ +				new_array_value = new_name_stack_range.first->second; +				++new_name_stack_range.first; +			} + +			if (new_name || new_array_value || typed_param.mValues.empty())  			{  				new_value = true;  				typed_param.mValues.push_back(value_t());  			} -  			param_value_t& value = typed_param.mValues.back();  			// attempt to parse block... -			if(value.deserializeBlock(parser, name_stack_range, new_name)) +			if(value.deserializeBlock(parser, new_name_stack_range, new_name))  			{  				typed_param.setProvided(); +				if (new_array_value) +				{ +					name_stack_range.first->second = false; +				}  				return true;  			} -			else if(name_value_lookup_t::valueNamesExist()) +			else if(named_value_t::valueNamesExist())  			{  				// try to parse a known named value  				std::string name;  				if (parser.readValue(name))  				{  					// try to parse a per type named value -					if (name_value_lookup_t::getValueFromName(name, value.getValue())) +					if (named_value_t::getValueFromName(name, value.getValue()))  					{  						typed_param.mValues.back().setValueName(name);  						typed_param.setProvided(); +						if (new_array_value) +						{ +							name_stack_range.first->second = false; +						}  						return true;  					} @@ -1404,13 +1583,13 @@ namespace LLInitParam  		static void serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const Param* diff_param)  		{  			const self_t& typed_param = static_cast<const self_t&>(param); -			if (!typed_param.isProvided() || name_stack.empty()) return; +			if (!typed_param.isProvided()) return;  			for (const_iterator it = typed_param.mValues.begin(), end_it = typed_param.mValues.end();  				it != end_it;  				++it)  			{ -				name_stack.back().second = true; +				name_stack.push_back(std::make_pair(std::string(), true));  				std::string key = it->getValueName();  				if (!key.empty()) @@ -1423,16 +1602,27 @@ namespace LLInitParam  				{  					it->serializeBlock(parser, name_stack, NULL);  				} + +				name_stack.pop_back();  			}  		}  		static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count)  		{ -			// I am a vector of blocks, so describe my contents recursively -			param_value_t(value_t()).inspectBlock(parser, name_stack, min_count, max_count); +			const param_value_t& value_param = param_value_t(value_t()); + +			// tell parser about our actual type +			parser.inspectValue<value_t>(name_stack, min_count, max_count, NULL); +			// then tell it about string-based alternatives ("red", "blue", etc. for LLColor4) +			if (named_value_t::getPossibleValues()) +			{ +				parser.inspectValue<std::string>(name_stack, min_count, max_count, named_value_t::getPossibleValues()); +		} + +			value_param.inspectBlock(parser, name_stack, min_count, max_count);  		} -		void set(value_assignment_t val, bool flag_as_provided = true) +		void set(const container_t& val, bool flag_as_provided = true)  		{  			mValues = val;  			setProvided(flag_as_provided); @@ -1452,12 +1642,12 @@ namespace LLInitParam  			return *this;  		} -		self_t& add(const typename name_value_lookup_t::name_t& name) +		self_t& add(const typename named_value_t::name_t& name)  		{  			value_t value;  			// try to parse a per type named value -			if (name_value_lookup_t::getValueFromName(name, value)) +			if (named_value_t::getValueFromName(name, value))  			{  				add(value);  				mValues.back().setValueName(name); @@ -1466,12 +1656,10 @@ namespace LLInitParam  		}  		// implicit conversion -		operator value_assignment_t() const { return mValues; }  +		operator const container_t&() const { return mValues; }   		// explicit conversion -		value_assignment_t operator()() const { return mValues; } +		const container_t& operator()() const { return mValues; } -		typedef typename container_t::iterator iterator; -		typedef typename container_t::const_iterator const_iterator;  		iterator begin() { return mValues.begin(); }  		iterator end() { return mValues.end(); }  		const_iterator begin() const { return mValues.begin(); } @@ -1518,6 +1706,20 @@ namespace LLInitParam  		}  		container_t			mValues; + +	private: +		void init( BlockDescriptor &block_descriptor, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count, const char* name )  +		{ +			ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( +				block_descriptor.mCurrentBlockPtr->getHandleFromParam(this), +				&mergeWith, +				&deserializeParam, +				&serializeParam, +				validate_func, +				&inspectParam, +				min_count, max_count)); +			block_descriptor.addParam(param_descriptor, name); +		}  	};  	template <typename DERIVED_BLOCK, typename BASE_BLOCK = BaseBlock> @@ -1532,13 +1734,13 @@ namespace LLInitParam  		// take all provided params from other and apply to self  		bool overwriteFrom(const self_t& other)  		{ -			return static_cast<DERIVED_BLOCK*>(this)->mergeBlock(selfBlockDescriptor(), other, true); +			return static_cast<DERIVED_BLOCK*>(this)->mergeBlock(getBlockDescriptor(), other, true);  		}  		// take all provided params that are not already provided, and apply to self  		bool fillFrom(const self_t& other)  		{ -			return static_cast<DERIVED_BLOCK*>(this)->mergeBlock(selfBlockDescriptor(), other, false); +			return static_cast<DERIVED_BLOCK*>(this)->mergeBlock(getBlockDescriptor(), other, false);  		}  		bool mergeBlockParam(bool source_provided, bool dest_provided, BlockDescriptor& block_data, const self_t& source, bool overwrite) @@ -1556,7 +1758,7 @@ namespace LLInitParam  		bool mergeBlock(BlockDescriptor& block_data, const self_t& other, bool overwrite)  		{  			mCurChoice = other.mCurChoice; -			return base_block_t::mergeBlock(selfBlockDescriptor(), other, overwrite); +			return base_block_t::mergeBlock(getBlockDescriptor(), other, overwrite);  		}  		// clear out old choice when param has changed @@ -1577,38 +1779,38 @@ namespace LLInitParam  			base_block_t::paramChanged(changed_param, user_provided);  		} -		virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return selfBlockDescriptor(); } -		virtual BlockDescriptor& mostDerivedBlockDescriptor() { return selfBlockDescriptor(); } +		virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return getBlockDescriptor(); } +		virtual BlockDescriptor& mostDerivedBlockDescriptor() { return getBlockDescriptor(); }  	protected:  		ChoiceBlock()  		:	mCurChoice(0)  		{ -			BaseBlock::init(selfBlockDescriptor(), base_block_t::selfBlockDescriptor(), sizeof(DERIVED_BLOCK)); +			BaseBlock::init(getBlockDescriptor(), base_block_t::getBlockDescriptor(), sizeof(DERIVED_BLOCK));  		}  		// Alternatives are mutually exclusive wrt other Alternatives in the same block.    		// One alternative in a block will always have isChosen() == true.  		// At most one alternative in a block will have isProvided() == true. -		template <typename T, typename NAME_VALUE_LOOKUP = TypeValues<T> > +		template <typename T, typename NAME_VALUE_LOOKUP = typename TypeValues<T>::type_value_t >  		class Alternative : public TypedParam<T, NAME_VALUE_LOOKUP, false>  		{ +			typedef TypedParam<T, NAME_VALUE_LOOKUP, false>	super_t; +			typedef typename super_t::value_t				value_t; +			typedef typename super_t::default_value_t		default_value_t; +  		public:  			friend class ChoiceBlock<DERIVED_BLOCK>; -			typedef Alternative<T, NAME_VALUE_LOOKUP>									self_t; -			typedef TypedParam<T, NAME_VALUE_LOOKUP, false, IsBlock<ParamValue<T, NAME_VALUE_LOOKUP> >::value>		super_t; -			typedef typename super_t::value_assignment_t								value_assignment_t; -  			using super_t::operator =; -			explicit Alternative(const char* name = "", value_assignment_t val = defaultValue<T>()) -			:	super_t(DERIVED_BLOCK::selfBlockDescriptor(), name, val, NULL, 0, 1), +			explicit Alternative(const char* name = "", const default_value_t& val = defaultValue<default_value_t>()) +			:	super_t(DERIVED_BLOCK::getBlockDescriptor(), name, val, NULL, 0, 1),  				mOriginalValue(val)  			{  				// assign initial choice to first declared option -				DERIVED_BLOCK* blockp = ((DERIVED_BLOCK*)DERIVED_BLOCK::selfBlockDescriptor().mCurrentBlockPtr); -				if (LL_UNLIKELY(DERIVED_BLOCK::selfBlockDescriptor().mInitializationState == BlockDescriptor::INITIALIZING)) +				DERIVED_BLOCK* blockp = ((DERIVED_BLOCK*)DERIVED_BLOCK::getBlockDescriptor().mCurrentBlockPtr); +				if (LL_UNLIKELY(DERIVED_BLOCK::getBlockDescriptor().mInitializationState == BlockDescriptor::INITIALIZING))  				{  					if(blockp->mCurChoice == 0)  					{ @@ -1622,27 +1824,27 @@ namespace LLInitParam  				static_cast<enclosing_block_t&>(Param::enclosingBlock()).paramChanged(*this, true);  			} -			void chooseAs(value_assignment_t val) +			void chooseAs(const value_t& val)  			{  				super_t::set(val);  			} -			void operator =(value_assignment_t val) +			void operator =(const value_t& val)  			{  				super_t::set(val);  			} -			void operator()(typename super_t::value_assignment_t val)  +			void operator()(const value_t& val)   			{   				super_t::set(val);  			} -			operator value_assignment_t() const  +			operator const value_t&() const   			{  				return (*this)();  			}  -			value_assignment_t operator()() const  +			const value_t& operator()() const   			{   				if (static_cast<enclosing_block_t&>(Param::enclosingBlock()).getCurrentChoice() == this)  				{ @@ -1657,11 +1859,11 @@ namespace LLInitParam  			}  		private: -			T			mOriginalValue; +			default_value_t mOriginalValue;  		}; -	protected: -		static BlockDescriptor& selfBlockDescriptor() +	public: +		static BlockDescriptor& getBlockDescriptor()  		{  			static BlockDescriptor sBlockDescriptor;  			return sBlockDescriptor; @@ -1681,6 +1883,8 @@ namespace LLInitParam  	:	public BASE_BLOCK  	{  		typedef Block<DERIVED_BLOCK, BASE_BLOCK>	self_t; + +	protected:  		typedef Block<DERIVED_BLOCK, BASE_BLOCK>	block_t;  	public: @@ -1689,80 +1893,82 @@ namespace LLInitParam  		// take all provided params from other and apply to self  		bool overwriteFrom(const self_t& other)  		{ -			return static_cast<DERIVED_BLOCK*>(this)->mergeBlock(selfBlockDescriptor(), other, true); +			return static_cast<DERIVED_BLOCK*>(this)->mergeBlock(getBlockDescriptor(), other, true);  		}  		// take all provided params that are not already provided, and apply to self  		bool fillFrom(const self_t& other)  		{ -			return static_cast<DERIVED_BLOCK*>(this)->mergeBlock(selfBlockDescriptor(), other, false); +			return static_cast<DERIVED_BLOCK*>(this)->mergeBlock(getBlockDescriptor(), other, false);  		} -		virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return selfBlockDescriptor(); } -		virtual BlockDescriptor& mostDerivedBlockDescriptor() { return selfBlockDescriptor(); } +		virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return getBlockDescriptor(); } +		virtual BlockDescriptor& mostDerivedBlockDescriptor() { return getBlockDescriptor(); }  	protected:  		Block()  		{  			//#pragma message("Parsing LLInitParam::Block") -			BaseBlock::init(selfBlockDescriptor(), BASE_BLOCK::selfBlockDescriptor(), sizeof(DERIVED_BLOCK)); +			BaseBlock::init(getBlockDescriptor(), BASE_BLOCK::getBlockDescriptor(), sizeof(DERIVED_BLOCK));  		}  		//  		// Nested classes for declaring parameters  		// -		template <typename T, typename NAME_VALUE_LOOKUP = TypeValues<T> > +		template <typename T, typename NAME_VALUE_LOOKUP = typename TypeValues<T>::type_value_t >  		class Optional : public TypedParam<T, NAME_VALUE_LOOKUP, false>  		{ -		public: -			typedef TypedParam<T, NAME_VALUE_LOOKUP, false, IsBlock<ParamValue<T, NAME_VALUE_LOOKUP> >::value>		super_t; -			typedef typename super_t::value_assignment_t								value_assignment_t; +			typedef TypedParam<T, NAME_VALUE_LOOKUP, false>		super_t; +			typedef typename super_t::value_t					value_t; +			typedef typename super_t::default_value_t			default_value_t; +		public:  			using super_t::operator();  			using super_t::operator =; -			explicit Optional(const char* name = "", value_assignment_t val = defaultValue<T>()) -			:	super_t(DERIVED_BLOCK::selfBlockDescriptor(), name, val, NULL, 0, 1) +			explicit Optional(const char* name = "", const default_value_t& val = defaultValue<default_value_t>()) +			:	super_t(DERIVED_BLOCK::getBlockDescriptor(), name, val, NULL, 0, 1)  			{  				//#pragma message("Parsing LLInitParam::Block::Optional")  			} -			Optional& operator =(value_assignment_t val) +			Optional& operator =(const value_t& val)  			{  				set(val);  				return *this;  			} -			DERIVED_BLOCK& operator()(value_assignment_t val) +			DERIVED_BLOCK& operator()(const value_t& val)  			{  				super_t::set(val);  				return static_cast<DERIVED_BLOCK&>(Param::enclosingBlock());  			}  		}; -		template <typename T, typename NAME_VALUE_LOOKUP = TypeValues<T> > +		template <typename T, typename NAME_VALUE_LOOKUP = typename TypeValues<T>::type_value_t >  		class Mandatory : public TypedParam<T, NAME_VALUE_LOOKUP, false>  		{ -		public: -			typedef TypedParam<T, NAME_VALUE_LOOKUP, false, IsBlock<ParamValue<T, NAME_VALUE_LOOKUP> >::value>		super_t; +			typedef TypedParam<T, NAME_VALUE_LOOKUP, false>		super_t;  			typedef Mandatory<T, NAME_VALUE_LOOKUP>										self_t; -			typedef typename super_t::value_assignment_t								value_assignment_t; +			typedef typename super_t::value_t					value_t; +			typedef typename super_t::default_value_t			default_value_t; +		public:  			using super_t::operator();  			using super_t::operator =;  			// mandatory parameters require a name to be parseable -			explicit Mandatory(const char* name = "", value_assignment_t val = defaultValue<T>()) -			:	super_t(DERIVED_BLOCK::selfBlockDescriptor(), name, val, &validate, 1, 1) +			explicit Mandatory(const char* name = "", const default_value_t& val = defaultValue<default_value_t>()) +			:	super_t(DERIVED_BLOCK::getBlockDescriptor(), name, val, &validate, 1, 1)  			{} -			Mandatory& operator =(value_assignment_t val) +			Mandatory& operator =(const value_t& val)  			{  				set(val);  				return *this;  			} -			DERIVED_BLOCK& operator()(typename super_t::value_assignment_t val) +			DERIVED_BLOCK& operator()(const value_t& val)  			{  				super_t::set(val);  				return static_cast<DERIVED_BLOCK&>(Param::enclosingBlock()); @@ -1776,28 +1982,29 @@ namespace LLInitParam  		}; -		template <typename T, typename RANGE = BaseBlock::AnyAmount, typename NAME_VALUE_LOOKUP = TypeValues<T> > +		template <typename T, typename RANGE = BaseBlock::AnyAmount, typename NAME_VALUE_LOOKUP = typename TypeValues<T>::type_value_t >  		class Multiple : public TypedParam<T, NAME_VALUE_LOOKUP, true>  		{ -		public: -			typedef TypedParam<T, NAME_VALUE_LOOKUP, true, IsBlock<ParamValue<T, NAME_VALUE_LOOKUP> >::value>	super_t; +			typedef TypedParam<T, NAME_VALUE_LOOKUP, true>	super_t;  			typedef Multiple<T, RANGE, NAME_VALUE_LOOKUP>							self_t;  			typedef typename super_t::container_t									container_t; -			typedef typename super_t::value_assignment_t							value_assignment_t; +			typedef typename super_t::value_t				value_t; + +		public:  			typedef typename super_t::iterator										iterator;  			typedef typename super_t::const_iterator								const_iterator;  			explicit Multiple(const char* name = "") -			:	super_t(DERIVED_BLOCK::selfBlockDescriptor(), name, container_t(), &validate, RANGE::minCount, RANGE::maxCount) +			:	super_t(DERIVED_BLOCK::getBlockDescriptor(), name, container_t(), &validate, RANGE::minCount, RANGE::maxCount)  			{} -			Multiple& operator =(value_assignment_t val) +			Multiple& operator =(const container_t& val)  			{  				set(val);  				return *this;  			} -			DERIVED_BLOCK& operator()(typename super_t::value_assignment_t val) +			DERIVED_BLOCK& operator()(const container_t& val)  			{  				super_t::set(val);  				return static_cast<DERIVED_BLOCK&>(Param::enclosingBlock()); @@ -1810,13 +2017,15 @@ namespace LLInitParam  			}  		}; -		class Deprecated : public Param +		// can appear in data files, but will ignored during parsing +		// cannot read or write in code +		class Ignored : public Param  		{  		public: -			explicit Deprecated(const char* name) -			:	Param(DERIVED_BLOCK::selfBlockDescriptor().mCurrentBlockPtr) +			explicit Ignored(const char* name) +			:	Param(DERIVED_BLOCK::getBlockDescriptor().mCurrentBlockPtr)  			{ -				BlockDescriptor& block_descriptor = DERIVED_BLOCK::selfBlockDescriptor(); +				BlockDescriptor& block_descriptor = DERIVED_BLOCK::getBlockDescriptor();  				if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING))  				{  					ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( @@ -1827,11 +2036,11 @@ namespace LLInitParam  													NULL,  													NULL,   													0, S32_MAX)); -					BaseBlock::addParam(block_descriptor, param_descriptor, name); +					block_descriptor.addParam(param_descriptor, name);  				}  			} -			static bool deserializeParam(Param& param, Parser& parser, const Parser::name_stack_range_t& name_stack_range, bool new_name) +			static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name)  			{  				if (name_stack_range.first == name_stack_range.second)  				{ @@ -1844,19 +2053,46 @@ namespace LLInitParam  			}  		}; -		// different semantics for documentation purposes, but functionally identical -		typedef Deprecated Ignored; +		// can appear in data files, or be written to in code, but data will be ignored +		// cannot be read in code +		class Deprecated : public Ignored +		{ +		public: +			explicit Deprecated(const char* name) : Ignored(name) {} -	protected: -		static BlockDescriptor& selfBlockDescriptor() +			// dummy writer interfaces +			template<typename T> +			Deprecated& operator =(const T& val) +			{ +				// do nothing +				return *this; +			} + +			template<typename T> +			DERIVED_BLOCK& operator()(const T& val) +			{ +				// do nothing +				return static_cast<DERIVED_BLOCK&>(Param::enclosingBlock()); +			} + +			template<typename T> +			void set(const T& val, bool flag_as_provided = true) +			{ +				// do nothing +			} +		}; + +	public: +		static BlockDescriptor& getBlockDescriptor()  		{  			static BlockDescriptor sBlockDescriptor;  			return sBlockDescriptor;  		} -		template <typename T, typename NAME_VALUE_LOOKUP, bool multiple, bool is_block> +	protected: +		template <typename T, typename NAME_VALUE_LOOKUP, bool multiple, typename is_block>  		void changeDefault(TypedParam<T, NAME_VALUE_LOOKUP, multiple, is_block>& param,  -			typename TypedParam<T, NAME_VALUE_LOOKUP, multiple, is_block>::value_assignment_t value) +			const typename TypedParam<T, NAME_VALUE_LOOKUP, multiple, is_block>::value_t& value)  		{  			if (!param.isProvided())  			{ @@ -1866,204 +2102,420 @@ namespace LLInitParam  	}; -	template <typename DERIVED_BLOCK, typename BASE_BLOCK = BaseBlock> -	class BatchBlock -	:	public Block<DERIVED_BLOCK, BASE_BLOCK> +	template<typename T, typename BLOCK_T> +	struct IsBlock<ParamValue<BaseBlock::Lazy<T, BaseBlock::IS_A_BLOCK>, BLOCK_T >, void> +	{ +		typedef IS_A_BLOCK value_t; +	}; + +	template<typename T, typename BLOCK_T> +	struct IsBlock<ParamValue<BaseBlock::Lazy<T, BaseBlock::NOT_A_BLOCK>, BLOCK_T >, void> +	{ +		typedef NOT_BLOCK value_t; +	}; + +	template<typename T, typename BLOCK_IDENTIFIER> +	struct IsBlock<ParamValue<BaseBlock::Atomic<T>, typename IsBlock<BaseBlock::Atomic<T> >::value_t >, BLOCK_IDENTIFIER> +	{ +		typedef typename IsBlock<T>::value_t value_t; +	}; + +	template<typename T, typename BLOCK_IDENTIFIER> +	struct IsBlock<ParamValue<BaseBlock::Sequential<T>, typename IsBlock<BaseBlock::Sequential<T> >::value_t >, BLOCK_IDENTIFIER> +	{ +		typedef typename IsBlock<T>::value_t value_t; +	}; + + +	template<typename T> +	struct InnerMostType +	{ +		typedef T value_t; +	}; + +	template<typename T> +	struct InnerMostType<ParamValue<T, NOT_BLOCK> >  	{ +		typedef typename InnerMostType<T>::value_t value_t; +	}; + +	template<typename T> +	struct InnerMostType<ParamValue<T, IS_A_BLOCK> > +	{ +		typedef typename InnerMostType<T>::value_t value_t; +	}; + +	template<typename T, typename BLOCK_T> +	class ParamValue <BaseBlock::Atomic<T>, BLOCK_T> +	{ +		typedef ParamValue <BaseBlock::Atomic<T>, BLOCK_T> self_t; +  	public: -		typedef BatchBlock<DERIVED_BLOCK, BASE_BLOCK> self_t; -		typedef Block<DERIVED_BLOCK, BASE_BLOCK> super_t; +		typedef typename InnerMostType<T>::value_t	value_t; +		typedef T									default_value_t; + +		ParamValue() +		:	mValue(), +			mValidated(false) +		{} -		BatchBlock() +		ParamValue(const default_value_t& value) +		:	mValue(value), +			mValidated(false)  		{} -		bool deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack_range, bool new_name) +		void setValue(const value_t& val) +		{ +			mValue.setValue(val); +		} + +		const value_t& getValue() const +		{ +			return mValue.getValue(); +		} + +		value_t& getValue() +		{ +			return mValue.getValue(); +		} + +		bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name)  		{  			if (new_name)  			{ -				// reset block -				*static_cast<DERIVED_BLOCK*>(this) = defaultBatchValue(); +				resetToDefault();  			} -			return super_t::deserializeBlock(p, name_stack_range, new_name); +			return mValue.deserializeBlock(p, name_stack_range, new_name);  		} -		bool mergeBlock(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite) +		void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const self_t* diff_block = NULL) const  		{ -			if (overwrite) +			const BaseBlock* base_block = diff_block +				? &(diff_block->mValue) +				: NULL; +			mValue.serializeBlock(p, name_stack, base_block); +		} + +		bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const +		{ +			return mValue.inspectBlock(p, name_stack, min_count, max_count); +		} + +		bool mergeBlockParam(bool source_provided, bool dst_provided, BlockDescriptor& block_data, const self_t& source, bool overwrite) +		{ +			if ((overwrite && source_provided) // new values coming in on top or... +				|| (!overwrite && !dst_provided)) // values being pushed under with nothing already there  			{ -				*static_cast<DERIVED_BLOCK*>(this) = defaultBatchValue(); -				// merge individual parameters into destination -				return super_t::mergeBlock(super_t::selfBlockDescriptor(), other, overwrite); +				// clear away what is there and take the new stuff as a whole +				resetToDefault(); +				return mValue.mergeBlock(block_data, source.getValue(), overwrite);  			} -			return false; +			 + +			return mValue.mergeBlock(block_data, source.getValue(), overwrite);  		} -	protected: -		static const DERIVED_BLOCK& defaultBatchValue() + +		bool validateBlock(bool emit_errors = true) const +		{ +			return mValue.validateBlock(emit_errors); +		} + +		static BlockDescriptor& getBlockDescriptor() +		{ +			return value_t::getBlockDescriptor(); +		} + + +		mutable bool 	mValidated; // lazy validation flag + +	private: +		void resetToDefault()  		{ -			static DERIVED_BLOCK default_value; -			return default_value; +			static T default_value; +			mValue = default_value;  		} + +		T	mValue;  	}; -	// FIXME: this specialization is not currently used, as it only matches against the BatchBlock base class -	// and not the derived class with the actual params -	template<typename DERIVED_BLOCK, -			typename BASE_BLOCK, -			typename NAME_VALUE_LOOKUP> -	class ParamValue <BatchBlock<DERIVED_BLOCK, BASE_BLOCK>, -					NAME_VALUE_LOOKUP, -					true> -	:	public NAME_VALUE_LOOKUP, -		protected BatchBlock<DERIVED_BLOCK, BASE_BLOCK> +	template<typename T> +	class ParamValue <BaseBlock::Sequential<T>, IS_A_BLOCK>  	{ +		typedef ParamValue <BaseBlock::Sequential<T>, IS_A_BLOCK> self_t; +  	public: -		typedef BatchBlock<DERIVED_BLOCK, BASE_BLOCK> block_t; -		typedef const BatchBlock<DERIVED_BLOCK, BASE_BLOCK>&	value_assignment_t; -		typedef block_t value_t; +		typedef typename InnerMostType<T>::value_t	value_t; +		typedef T									default_value_t;  		ParamValue() -		:	block_t(), +		:	mValue(),  			mValidated(false) -		{} +		{ +			mCurParam = getBlockDescriptor().mAllParams.begin(); +		} -		ParamValue(value_assignment_t other) -		:	block_t(other), +		ParamValue(const default_value_t& value) +		:	mValue(value),  			mValidated(false)  		{ +			mCurParam = getBlockDescriptor().mAllParams.begin();  		} -		void setValue(value_assignment_t val) +		void setValue(const value_t& val)  		{ -			*this = val; +			mValue.setValue(val);  		} -		value_assignment_t getValue() const +		const value_t& getValue() const  		{ -			return *this; +			return mValue.getValue();  		} -		BatchBlock<DERIVED_BLOCK, BASE_BLOCK>& getValue() +		value_t& getValue()  		{ -			return *this; +			return mValue.getValue();  		} -		operator value_assignment_t() const +		bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name)  		{ -			return *this; +			if (new_name) +			{ +				mCurParam = getBlockDescriptor().mAllParams.begin(); +			} +			if (name_stack_range.first == name_stack_range.second  +				&& mCurParam != getBlockDescriptor().mAllParams.end()) +			{ +				// deserialize to mCurParam +				ParamDescriptor& pd = *(*mCurParam); +				ParamDescriptor::deserialize_func_t deserialize_func = pd.mDeserializeFunc; +				Param* paramp = mValue.getParamFromHandle(pd.mParamHandle); + +				if (deserialize_func  +					&& paramp  +					&& deserialize_func(*paramp, p, name_stack_range, new_name)) +				{ +					++mCurParam; +					return true; +				} +				else +				{ +					return false; +				} +			} +			else +			{ +				return mValue.deserializeBlock(p, name_stack_range, new_name); +			}  		} -		value_assignment_t operator()() const +		void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const self_t* diff_block = NULL) const  		{ -			return *this; +			const BaseBlock* base_block = diff_block +				? &(diff_block->mValue) +				: NULL; +			mValue.serializeBlock(p, name_stack, base_block); +		} + +		bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const +		{ +			return mValue.inspectBlock(p, name_stack, min_count, max_count); +		} + +		bool mergeBlockParam(bool source_provided, bool dst_provided, BlockDescriptor& block_data, const self_t& source, bool overwrite) +		{ +			return mValue.mergeBlock(block_data, source.getValue(), overwrite); +		} + +		bool validateBlock(bool emit_errors = true) const +		{ +			return mValue.validateBlock(emit_errors); +		} + +		static BlockDescriptor& getBlockDescriptor() +		{ +			return value_t::getBlockDescriptor();  		} -	protected:  		mutable bool 	mValidated; // lazy validation flag + +	private: + +		BlockDescriptor::all_params_list_t::iterator	mCurParam; +		T												mValue;  	}; -	template<typename T, bool IS_BLOCK> -	class ParamValue <BaseBlock::Lazy<T>, -					TypeValues<T>, -					IS_BLOCK> -	:	public IsBlock<T>::base_class_t +	template<typename T> +	class ParamValue <BaseBlock::Sequential<T>, NOT_BLOCK> +	: public T  	{ +		typedef ParamValue <BaseBlock::Sequential<T>, NOT_BLOCK> self_t; +  	public: -		typedef ParamValue <BaseBlock::Lazy<T>, TypeValues<T>, false> self_t; -		typedef const T& value_assignment_t; -		typedef T value_t; +		typedef typename InnerMostType<T>::value_t	value_t; +		typedef T									default_value_t; + +		ParamValue() +		:	T(), +			mValidated(false) +		{} + +		ParamValue(const default_value_t& value) +		:	T(value.getValue()), +			mValidated(false) +		{} + +		mutable bool 	mValidated; // lazy validation flag +	}; + +	template<typename T, typename BLOCK_T> +	class ParamValue <BaseBlock::Lazy<T, IS_A_BLOCK>, BLOCK_T>  +	{ +		typedef ParamValue <BaseBlock::Lazy<T, IS_A_BLOCK>, BLOCK_T> self_t; + +	public: +		typedef typename InnerMostType<T>::value_t	value_t; +		typedef LazyValue<T>						default_value_t;  		ParamValue()  		:	mValue(),  			mValidated(false)  		{} -		ParamValue(value_assignment_t other) +		ParamValue(const default_value_t& other)  		:	mValue(other),  			mValidated(false)  		{} -		void setValue(value_assignment_t val) +		ParamValue(const T& value) +		:	mValue(value), +			mValidated(false) +		{} + +		void setValue(const value_t& val)  		{  			mValue.set(val);  		} -		value_assignment_t getValue() const +		const value_t& getValue() const  		{ -			return mValue.get(); +			return mValue.get().getValue();  		} -		T& getValue() +		value_t& getValue() +		{ +			return mValue.get().getValue(); +		} + +		bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name) +		{ +			return mValue.get().deserializeBlock(p, name_stack_range, new_name); +		} + +		void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const self_t* diff_block = NULL) const  		{ -			return mValue.get(); +			if (mValue.empty()) return; +			 +			const BaseBlock* base_block = (diff_block && !diff_block->mValue.empty()) +											? &(diff_block->mValue.get().getValue()) +											: NULL; +			mValue.get().serializeBlock(p, name_stack, base_block);  		} -		operator value_assignment_t() const +		bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const  		{ -			return mValue.get(); +			return mValue.get().inspectBlock(p, name_stack, min_count, max_count);  		} -		value_assignment_t operator()() const +		bool mergeBlockParam(bool source_provided, bool dst_provided, BlockDescriptor& block_data, const self_t& source, bool overwrite)  		{ -			return mValue.get(); +			return source.mValue.empty() || mValue.get().mergeBlock(block_data, source.getValue(), overwrite);  		} -		bool deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack_range, bool new_name) +		bool validateBlock(bool emit_errors = true) const  		{ -			return mValue.get().deserializeBlock(p, name_stack_range, new_name); +			return mValue.empty() || mValue.get().validateBlock(emit_errors);  		} -		void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block = NULL) const +		static BlockDescriptor& getBlockDescriptor()  		{ -			if (mValue.empty()) return; +			return value_t::getBlockDescriptor(); +		} + +		mutable bool 	mValidated; // lazy validation flag + +	private: +		LazyValue<T>	mValue; +	}; + +	template<typename T, typename BLOCK_T> +	class ParamValue <BaseBlock::Lazy<T, NOT_BLOCK>, BLOCK_T> +		{ +		typedef ParamValue <BaseBlock::Lazy<T, NOT_BLOCK>, BLOCK_T> self_t; + +	public: +		typedef typename InnerMostType<T>::value_t	value_t; +		typedef LazyValue<T>						default_value_t; + +		ParamValue() +		:	mValue(), +			mValidated(false) +		{} + +		ParamValue(const default_value_t& other) +		:	mValue(other), +			mValidated(false) +		{} + +		ParamValue(const T& value) +		:	mValue(value), +			mValidated(false) +		{} -			mValue.get().serializeBlock(p, name_stack, diff_block); +		void setValue(const value_t& val) +		{ +			mValue.set(val);  		} -		bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const +		const value_t& getValue() const  		{ -			if (mValue.empty()) return false; +			return mValue.get().getValue(); +		} -			return mValue.get().inspectBlock(p, name_stack, min_count, max_count); +		value_t& getValue() +		{ +			return mValue.get().getValue();  		} -	protected:  		mutable bool 	mValidated; // lazy validation flag  	private: -		BaseBlock::Lazy<T>	mValue; +		LazyValue<T>	mValue;  	};  	template <> -	class ParamValue <LLSD, -					TypeValues<LLSD>, -					false> -	:	public TypeValues<LLSD>, -		public BaseBlock +	class ParamValue <LLSD, NOT_BLOCK> +	:	public BaseBlock  	{  	public: -		typedef ParamValue<LLSD, TypeValues<LLSD>, false> self_t; -		typedef const LLSD&	value_assignment_t; +		typedef LLSD			value_t; +		typedef LLSD			default_value_t;  		ParamValue()  		:	mValidated(false)  		{} -		ParamValue(value_assignment_t other) +		ParamValue(const default_value_t& other)  		:	mValue(other),  			mValidated(false)  		{} -		void setValue(value_assignment_t val) { mValue = val; } +		void setValue(const value_t& val) { mValue = val; } -		value_assignment_t getValue() const { return mValue; } +		const value_t& getValue() const { return mValue; }  		LLSD& getValue() { return mValue; } -		operator value_assignment_t() const { return mValue; } -		value_assignment_t operator()() const { return mValue; } -		 -  		// block param interface -		LL_COMMON_API bool deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack_range, bool new_name); +		LL_COMMON_API bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name);  		LL_COMMON_API void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block = NULL) const;  		bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const  		{ @@ -2082,8 +2534,7 @@ namespace LLInitParam  	template<typename T>  	class CustomParamValue -	:	public Block<ParamValue<T, TypeValues<T> > >, -		public TypeValues<T> +	:	public Block<ParamValue<T> >  	{  	public:  		typedef enum e_value_age @@ -2093,20 +2544,21 @@ namespace LLInitParam  			BLOCK_AUTHORITATIVE		// mValue is derived from the block parameters, which are authoritative  		} EValueAge; -		typedef ParamValue<T, TypeValues<T> >	derived_t; -		typedef CustomParamValue<T>				self_t; -		typedef Block<derived_t>				block_t; -		typedef const T&						value_assignment_t; -		typedef T								value_t; +		typedef ParamValue<T>			derived_t; +		typedef CustomParamValue<T>		self_t; +		typedef Block<derived_t>		block_t; +		typedef T						default_value_t; +		typedef T						value_t; +		typedef void					baseblock_base_class_t; -		CustomParamValue(const T& value = T()) +		CustomParamValue(const default_value_t& value = T())  		:	mValue(value),  			mValueAge(VALUE_AUTHORITATIVE),  			mValidated(false)  		{} -		bool deserializeBlock(Parser& parser, Parser::name_stack_range_t name_stack_range, bool new_name) +		bool deserializeBlock(Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name)  		{  			derived_t& typed_param = static_cast<derived_t&>(*this);  			// try to parse direct value T @@ -2117,8 +2569,6 @@ namespace LLInitParam  					typed_param.mValueAge = VALUE_AUTHORITATIVE;  					typed_param.updateBlockFromValue(false); -					typed_param.clearValueName(); -  					return true;  				}  			} @@ -2132,18 +2582,8 @@ namespace LLInitParam  			const derived_t& typed_param = static_cast<const derived_t&>(*this);  			const derived_t* diff_param = static_cast<const derived_t*>(diff_block); -			std::string key = typed_param.getValueName(); - -			// first try to write out name of name/value pair -			if (!key.empty()) -			{ -				if (!diff_param || !ParamCompare<std::string>::equals(diff_param->getValueName(), key)) -				{ -					parser.writeValue(key, name_stack); -				} -			}  			// then try to serialize value directly -			else if (!diff_param || !ParamCompare<T>::equals(typed_param.getValue(), diff_param->getValue())) +			if (!diff_param || !ParamCompare<T>::equals(typed_param.getValue(), diff_param->getValue()))              {  				if (!parser.writeValue(typed_param.getValue(), name_stack))  @@ -2173,19 +2613,6 @@ namespace LLInitParam  			}  		} -		bool inspectBlock(Parser& parser, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const -		{ -			// first, inspect with actual type... -			parser.inspectValue<T>(name_stack, min_count, max_count, NULL); -			if (TypeValues<T>::getPossibleValues()) -			{ -				//...then inspect with possible string values... -				parser.inspectValue<std::string>(name_stack, min_count, max_count, TypeValues<T>::getPossibleValues()); -			} -			// then recursively inspect contents... -			return block_t::inspectBlock(parser, name_stack, min_count, max_count); -		} -  		bool validateBlock(bool emit_errors = true) const  		{  			if (mValueAge == VALUE_NEEDS_UPDATE) @@ -2193,7 +2620,6 @@ namespace LLInitParam  				if (block_t::validateBlock(emit_errors))  				{  					// clear stale keyword associated with old value -					TypeValues<T>::clearValueName();  					mValueAge = BLOCK_AUTHORITATIVE;  					static_cast<derived_t*>(const_cast<self_t*>(this))->updateValueFromBlock();  					return true; @@ -2223,17 +2649,15 @@ namespace LLInitParam  			}  		} -		void setValue(value_assignment_t val) +		void setValue(const value_t& val)  		{ -			derived_t& typed_param = static_cast<derived_t&>(*this);  			// set param version number to be up to date, so we ignore block contents  			mValueAge = VALUE_AUTHORITATIVE;  			mValue = val; -			typed_param.clearValueName();  			static_cast<derived_t*>(this)->updateBlockFromValue(false);  		} -		value_assignment_t getValue() const +		const value_t& getValue() const  		{  			validateBlock(true);  			return mValue; @@ -2245,20 +2669,10 @@ namespace LLInitParam  			return mValue;  		} -		operator value_assignment_t() const -		{ -			return getValue(); -		} - -		value_assignment_t operator()() const -		{ -			return getValue(); -		} -  	protected:  		// use this from within updateValueFromBlock() to set the value without making it authoritative -		void updateValue(value_assignment_t value) +		void updateValue(const value_t& value)  		{  			mValue = value;  		} diff --git a/indra/llcommon/llinstancetracker.h b/indra/llcommon/llinstancetracker.h index 403df08990..1eab270e3c 100644 --- a/indra/llcommon/llinstancetracker.h +++ b/indra/llcommon/llinstancetracker.h @@ -43,7 +43,7 @@   * semantics: one instance per process, rather than one instance per module as   * sometimes happens with data simply declared static.   */ -class LL_COMMON_API LLInstanceTrackerBase : public boost::noncopyable +class LL_COMMON_API LLInstanceTrackerBase  {  protected:  	/// Get a process-unique void* pointer slot for the specified type_info @@ -210,6 +210,9 @@ protected:  	virtual const KEY& getKey() const { return mInstanceKey; }  private: +	LLInstanceTracker( const LLInstanceTracker& ); +	const LLInstanceTracker& operator=( const LLInstanceTracker& ); +  	void add_(KEY key)   	{   		mInstanceKey = key;  diff --git a/indra/llcommon/llrefcount.h b/indra/llcommon/llrefcount.h index 8eb5d53f3f..32ae15435a 100644 --- a/indra/llcommon/llrefcount.h +++ b/indra/llcommon/llrefcount.h @@ -27,6 +27,7 @@  #define LLREFCOUNT_H  #include <boost/noncopyable.hpp> +#include <boost/intrusive_ptr.hpp>  #define LL_REF_COUNT_DEBUG 0  #if LL_REF_COUNT_DEBUG @@ -86,4 +87,22 @@ private:  #endif  }; +/** + * intrusive pointer support + * this allows you to use boost::intrusive_ptr with any LLRefCount-derived type + */ +namespace boost +{ +	inline void intrusive_ptr_add_ref(LLRefCount* p) +	{ +		p->ref(); +	} + +	inline void intrusive_ptr_release(LLRefCount* p) +	{ +		p->unref(); +	} +}; + +  #endif diff --git a/indra/llcommon/llregistry.h b/indra/llcommon/llregistry.h index 36d7f7a44c..bb0d60247e 100644 --- a/indra/llcommon/llregistry.h +++ b/indra/llcommon/llregistry.h @@ -31,30 +31,16 @@  #include <boost/type_traits.hpp>  #include "llsingleton.h" -#include "lltypeinfolookup.h" +#include "llstl.h"  template <typename T> -class LLRegistryDefaultComparator +struct LLRegistryDefaultComparator  { -	bool operator()(const T& lhs, const T& rhs) { return lhs < rhs; } -}; - -template <typename KEY, typename VALUE> -struct LLRegistryMapSelector -{ -    typedef std::map<KEY, VALUE> type; -}; - -template <typename VALUE> -struct LLRegistryMapSelector<std::type_info*, VALUE> -{ -    typedef LLTypeInfoLookup<VALUE> type; -}; - -template <typename VALUE> -struct LLRegistryMapSelector<const std::type_info*, VALUE> -{ -    typedef LLTypeInfoLookup<VALUE> type; +	bool operator()(const T& lhs, const T& rhs) const +	{ +		using std::less; +		return less<T>()(lhs, rhs); +	}  };  template <typename KEY, typename VALUE, typename COMPARATOR = LLRegistryDefaultComparator<KEY> > @@ -72,7 +58,7 @@ public:  	{  		friend class LLRegistry<KEY, VALUE, COMPARATOR>;  	public: -		typedef typename LLRegistryMapSelector<KEY, VALUE>::type registry_map_t; +		typedef std::map<KEY, VALUE, COMPARATOR> registry_map_t;  		bool add(ref_const_key_t key, ref_const_value_t value)  		{ @@ -321,6 +307,10 @@ public:  		virtual ~StaticRegistrar() {}  		StaticRegistrar(ref_const_key_t key, ref_const_value_t value)  		{ +			if (singleton_t::instance().exists(key)) +			{ +				llerrs << "Duplicate registry entry under key \"" << key << "\"" << llendl; +			}  			singleton_t::instance().mStaticScope->add(key, value);  		}  	}; diff --git a/indra/llcommon/llsdparam.cpp b/indra/llcommon/llsdparam.cpp index 0e29873bb0..9f4460a988 100644 --- a/indra/llcommon/llsdparam.cpp +++ b/indra/llcommon/llsdparam.cpp @@ -223,10 +223,14 @@ LLSD& LLParamSDParserUtilities::getSDWriteNode(LLSD& input, LLInitParam::Parser:  	{  		bool new_traversal = it->second; -		LLSD* child_sd = it->first.empty() ? sd_to_write : &(*sd_to_write)[it->first]; - -		if (child_sd->isArray()) +		LLSD* child_sd; +		if (it->first.empty())  		{ +			child_sd = sd_to_write; +			if (child_sd->isUndefined()) +			{ +				*child_sd = LLSD::emptyArray(); +			}  			if (new_traversal)  			{  				// write to new element at end @@ -240,22 +244,7 @@ LLSD& LLParamSDParserUtilities::getSDWriteNode(LLSD& input, LLInitParam::Parser:  		}  		else  		{ -			if (new_traversal  -				&& child_sd->isDefined()  -				&& !child_sd->isArray()) -			{ -				// copy child contents into first element of an array -				LLSD new_array = LLSD::emptyArray(); -				new_array.append(*child_sd); -				// assign array to slot that previously held the single value -				*child_sd = new_array; -				// return next element in that array -				sd_to_write = &((*child_sd)[1]); -			} -			else -			{ -				sd_to_write = child_sd; -			} +			sd_to_write = &(*sd_to_write)[it->first];  		}  		it->second = false;  	} @@ -283,8 +272,9 @@ void LLParamSDParserUtilities::readSDValues(read_sd_cb_t cb, const LLSD& sd, LLI  			it != sd.endArray();  			++it)  		{ -			stack.back().second = true; +			stack.push_back(make_pair(std::string(), true));  			readSDValues(cb, *it, stack); +			stack.pop_back();  		}  	}  	else if (sd.isUndefined()) @@ -313,8 +303,14 @@ namespace LLInitParam  {  	// LLSD specialization  	// block param interface -	bool ParamValue<LLSD, TypeValues<LLSD>, false>::deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack, bool new_name) +	bool ParamValue<LLSD, NOT_BLOCK>::deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack, bool new_name)  	{ +		if (name_stack.first == name_stack.second +			&& p.readValue<LLSD>(mValue)) +		{ +			return true; +		} +  		LLSD& sd = LLParamSDParserUtilities::getSDWriteNode(mValue, name_stack);  		LLSD::String string; @@ -328,15 +324,18 @@ namespace LLInitParam  	}  	//static -	void ParamValue<LLSD, TypeValues<LLSD>, false>::serializeElement(Parser& p, const LLSD& sd, Parser::name_stack_t& name_stack) +	void ParamValue<LLSD, NOT_BLOCK>::serializeElement(Parser& p, const LLSD& sd, Parser::name_stack_t& name_stack)  	{  		p.writeValue<LLSD::String>(sd.asString(), name_stack);  	} -	void ParamValue<LLSD, TypeValues<LLSD>, false>::serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block) const +	void ParamValue<LLSD, NOT_BLOCK>::serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block) const  	{ -		// read from LLSD value and serialize out to parser (which could be LLSD, XUI, etc) -		Parser::name_stack_t stack; -		LLParamSDParserUtilities::readSDValues(boost::bind(&serializeElement, boost::ref(p), _1, _2), mValue, stack); +		// attempt to write LLSD out directly +		if (!p.writeValue<LLSD>(mValue, name_stack)) +		{ +			// otherwise read from LLSD value and serialize out to parser (which could be LLSD, XUI, etc) +			LLParamSDParserUtilities::readSDValues(boost::bind(&serializeElement, boost::ref(p), _1, _2), mValue, name_stack); +		}  	}  } diff --git a/indra/llcommon/llstl.h b/indra/llcommon/llstl.h index 8ad12c9a03..d3941e1bc9 100644 --- a/indra/llcommon/llstl.h +++ b/indra/llcommon/llstl.h @@ -33,6 +33,7 @@  #include <vector>  #include <set>  #include <deque> +#include <typeinfo>  // Use to compare the first element only of a pair  // e.g. typedef std::set<std::pair<int, Data*>, compare_pair<int, Data*> > some_pair_set_t;  @@ -470,4 +471,54 @@ llbind2nd(const _Operation& __oper, const _Tp& __x)    return llbinder2nd<_Operation>(__oper, _Arg2_type(__x));  } +/** + * Compare std::type_info* pointers a la std::less. We break this out as a + * separate function for use in two different std::less specializations. + */ +inline +bool before(const std::type_info* lhs, const std::type_info* rhs) +{ +#if LL_LINUX && defined(__GNUC__) && ((__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ < 4)) +    // If we're building on Linux with gcc, and it's either gcc 3.x or +    // 4.{0,1,2,3}, then we have to use a workaround. Note that we use gcc on +    // Mac too, and some people build with gcc on Windows (cygwin or mingw). +    // On Linux, different load modules may produce different type_info* +    // pointers for the same type. Have to compare name strings to get good +    // results. +    return strcmp(lhs->name(), rhs->name()) < 0; +#else  // not Linux, or gcc 4.4+ +    // Just use before(), as we normally would +    return lhs->before(*rhs); +#endif +} + +/** + * Specialize std::less<std::type_info*> to use std::type_info::before(). + * See MAINT-1175. It is NEVER a good idea to directly compare std::type_info* + * because, on Linux, you might get different std::type_info* pointers for the + * same type (from different load modules)! + */ +namespace std +{ +	template <> +	struct less<const std::type_info*>: +		public std::binary_function<const std::type_info*, const std::type_info*, bool> +	{ +		bool operator()(const std::type_info* lhs, const std::type_info* rhs) const +		{ +			return before(lhs, rhs); +		} +	}; + +	template <> +	struct less<std::type_info*>: +		public std::binary_function<std::type_info*, std::type_info*, bool> +	{ +		bool operator()(std::type_info* lhs, std::type_info* rhs) const +		{ +			return before(lhs, rhs); +		} +	}; +} // std +  #endif // LL_LLSTL_H diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h index 115bf47553..c7984d6dbc 100644 --- a/indra/llcommon/llthread.h +++ b/indra/llcommon/llthread.h @@ -30,6 +30,7 @@  #include "llapp.h"  #include "llapr.h"  #include "apr_thread_cond.h" +#include "boost/intrusive_ptr.hpp"  class LLThread;  class LLMutex; @@ -279,6 +280,22 @@ private:  	S32	mRef;   }; +/** + * intrusive pointer support for LLThreadSafeRefCount + * this allows you to use boost::intrusive_ptr with any LLThreadSafeRefCount-derived type + */ +namespace boost +{ +	inline void intrusive_ptr_add_ref(LLThreadSafeRefCount* p)  +	{ +		p->ref(); +	} + +	inline void intrusive_ptr_release(LLThreadSafeRefCount* p)  +	{ +		p->unref();  +	} +};  //============================================================================  // Simple responder for self destructing callbacks diff --git a/indra/llcommon/lltypeinfolookup.h b/indra/llcommon/lltypeinfolookup.h index 7510cc12ed..0b6862444e 100644 --- a/indra/llcommon/lltypeinfolookup.h +++ b/indra/llcommon/lltypeinfolookup.h @@ -12,10 +12,50 @@  #if ! defined(LL_LLTYPEINFOLOOKUP_H)  #define LL_LLTYPEINFOLOOKUP_H -#include "llsortedvector.h" +#include <boost/unordered_map.hpp> +#include <boost/functional/hash.hpp> +#include <boost/optional.hpp> +#include <functional>               // std::binary_function  #include <typeinfo>  /** + * The following helper classes are based on the Boost.Unordered documentation: + * http://www.boost.org/doc/libs/1_45_0/doc/html/unordered/hash_equality.html + */ + +/** + * Compute hash for a string passed as const char* + */ +struct const_char_star_hash: public std::unary_function<const char*, std::size_t> +{ +    std::size_t operator()(const char* str) const +    { +        std::size_t seed = 0; +        for ( ; *str; ++str) +        { +            boost::hash_combine(seed, *str); +        } +        return seed; +    } +}; + +/** + * Compute equality for strings passed as const char* + * + * I (nat) suspect that this is where the default behavior breaks for the + * const char* values returned from std::type_info::name(). If you compare the + * two const char* pointer values, as a naive, unspecialized implementation + * will surely do, they'll compare unequal. + */ +struct const_char_star_equal: public std::binary_function<const char*, const char*, bool> +{ +    bool operator()(const char* lhs, const char* rhs) const +    { +        return strcmp(lhs, rhs) == 0; +    } +}; + +/**   * LLTypeInfoLookup is specifically designed for use cases for which you might   * consider std::map<std::type_info*, VALUE>. We have several such data   * structures in the viewer. The trouble with them is that at least on Linux, @@ -23,88 +63,55 @@   * different load modules will produce different std::type_info*.   * LLTypeInfoLookup contains a workaround to address this issue.   * - * Specifically, when we don't find the passed std::type_info*, - * LLTypeInfoLookup performs a linear search over registered entries to - * compare name() strings. Presuming that this succeeds, we cache the new - * (previously unrecognized) std::type_info* to speed future lookups. - * - * This worst-case fallback search (linear search with string comparison) - * should only happen the first time we look up a given type from a particular - * load module other than the one from which we initially registered types. - * (However, a lookup which wouldn't succeed anyway will always have - * worst-case performance.) This class is probably best used with less than a - * few dozen different types. + * The API deliberately diverges from std::map in several respects: + * * It avoids iterators, not only begin()/end() but also as return values + *   from insert() and find(). This bypasses transform_iterator overhead. + * * Since we literally use compile-time types as keys, the essential insert() + *   and find() methods accept the key type as a @em template parameter, + *   accepting and returning value_type as a normal runtime value. This is to + *   permit future optimization (e.g. compile-time type hashing) without + *   changing the API.   */  template <typename VALUE>  class LLTypeInfoLookup  { +    // Use this for our underlying implementation: lookup by +    // std::type_info::name() string. This is one of the rare cases in which I +    // dare use const char* directly, rather than std::string, because I'm +    // sure that every value returned by std::type_info::name() is static. +    // HOWEVER, specify our own hash + equality functors: naively comparing +    // distinct const char* values won't work. +    typedef boost::unordered_map<const char*, VALUE, +                                 const_char_star_hash, const_char_star_equal> impl_map_type; +  public: -    typedef LLTypeInfoLookup<VALUE> self; -    typedef LLSortedVector<const std::type_info*, VALUE> vector_type; -    typedef typename vector_type::key_type key_type; -    typedef typename vector_type::mapped_type mapped_type; -    typedef typename vector_type::value_type value_type; -    typedef typename vector_type::iterator iterator; -    typedef typename vector_type::const_iterator const_iterator; +    typedef VALUE value_type;      LLTypeInfoLookup() {} -    iterator begin() { return mVector.begin(); } -    iterator end()   { return mVector.end(); } -    const_iterator begin() const { return mVector.begin(); } -    const_iterator end()   const { return mVector.end(); } -    bool empty() const { return mVector.empty(); } -    std::size_t size() const { return mVector.size(); } - -    std::pair<iterator, bool> insert(const std::type_info* key, const VALUE& value) -    { -        return insert(value_type(key, value)); -    } - -    std::pair<iterator, bool> insert(const value_type& pair) -    { -        return mVector.insert(pair); -    } +    bool empty() const { return mMap.empty(); } +    std::size_t size() const { return mMap.size(); } -    // const find() forwards to non-const find(): this can alter mVector! -    const_iterator find(const std::type_info* key) const +    template <typename KEY> +    bool insert(const value_type& value)      { -        return const_cast<self*>(this)->find(key); +        // Obtain and store the std::type_info::name() string as the key. +        // Return just the bool from std::map::insert()'s return pair. +        return mMap.insert(typename impl_map_type::value_type(typeid(KEY).name(), value)).second;      } -    // non-const find() caches previously-unknown type_info* to speed future -    // lookups. -    iterator find(const std::type_info* key) +    template <typename KEY> +    boost::optional<value_type> find() const      { -        iterator found = mVector.find(key); -        if (found != mVector.end()) -        { -            // If LLSortedVector::find() found, great, we're done. -            return found; -        } -        // Here we didn't find the passed type_info*. On Linux, though, even -        // for the same type, typeid(sametype) produces a different type_info* -        // when used in different load modules. So the fact that we didn't -        // find the type_info* we seek doesn't mean this type isn't -        // registered. Scan for matching name() string. -        for (typename vector_type::iterator ti(mVector.begin()), tend(mVector.end()); -             ti != tend; ++ti) -        { -            if (std::string(ti->first->name()) == key->name()) -            { -                // This unrecognized 'key' is for the same type as ti->first. -                // To speed future lookups, insert a new entry that lets us -                // look up ti->second using this same 'key'. -                return insert(key, ti->second).first; -            } -        } -        // We simply have never seen a type with this type_info* from any load -        // module. -        return mVector.end(); +        // Use the std::type_info::name() string as the key. +        typename impl_map_type::const_iterator found = mMap.find(typeid(KEY).name()); +        if (found == mMap.end()) +            return boost::optional<value_type>(); +        return found->second;      }  private: -    vector_type mVector; +    impl_map_type mMap;  };  #endif /* ! defined(LL_LLTYPEINFOLOOKUP_H) */ diff --git a/indra/llcommon/stdenums.h b/indra/llcommon/stdenums.h index 40b3364b36..efcbe76795 100644 --- a/indra/llcommon/stdenums.h +++ b/indra/llcommon/stdenums.h @@ -51,7 +51,8 @@ enum EDragAndDropType  	DAD_LINK			= 14,  	DAD_MESH            = 15,  	DAD_WIDGET          = 16, -	DAD_COUNT           = 17,   // number of types in this enum +	DAD_PERSON          = 17, +	DAD_COUNT           = 18,   // number of types in this enum  };  // Reasons for drags to be denied.  | 
