diff options
Diffstat (limited to 'indra/llcommon')
| -rw-r--r-- | indra/llcommon/llassettype.cpp | 1 | ||||
| -rw-r--r-- | indra/llcommon/llassettype.h | 3 | ||||
| -rw-r--r-- | indra/llcommon/llavatarname.cpp | 131 | ||||
| -rw-r--r-- | indra/llcommon/llavatarname.h | 60 | ||||
| -rw-r--r-- | indra/llcommon/llhandle.h | 13 | ||||
| -rw-r--r-- | indra/llcommon/llinitparam.cpp | 82 | ||||
| -rw-r--r-- | indra/llcommon/llinitparam.h | 1657 | ||||
| -rw-r--r-- | indra/llcommon/llinstancetracker.h | 5 | ||||
| -rw-r--r-- | indra/llcommon/llrefcount.h | 19 | ||||
| -rw-r--r-- | indra/llcommon/llregistry.h | 4 | ||||
| -rw-r--r-- | indra/llcommon/llsdparam.cpp | 51 | ||||
| -rw-r--r-- | indra/llcommon/llthread.h | 17 | ||||
| -rw-r--r-- | indra/llcommon/llversionviewer.h | 4 | ||||
| -rw-r--r-- | indra/llcommon/stdenums.h | 3 | 
14 files changed, 1320 insertions, 730 deletions
| 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/llavatarname.cpp b/indra/llcommon/llavatarname.cpp index 3206843bf4..642bd82e90 100644 --- a/indra/llcommon/llavatarname.cpp +++ b/indra/llcommon/llavatarname.cpp @@ -30,6 +30,7 @@  #include "llavatarname.h"  #include "lldate.h" +#include "llframetimer.h"  #include "llsd.h"  // Store these in pre-built std::strings to avoid memory allocations in @@ -42,6 +43,14 @@ static const std::string IS_DISPLAY_NAME_DEFAULT("is_display_name_default");  static const std::string DISPLAY_NAME_EXPIRES("display_name_expires");  static const std::string DISPLAY_NAME_NEXT_UPDATE("display_name_next_update"); +bool LLAvatarName::sUseDisplayNames = true; + +// Minimum time-to-live (in seconds) for a name entry. +// Avatar name should always guarantee to expire reasonably soon by default +// so if the failure to get a valid expiration time was due to something temporary  +// we will eventually request and get the right data. +const F64 MIN_ENTRY_LIFETIME = 60.0; +  LLAvatarName::LLAvatarName()  :	mUsername(),  	mDisplayName(), @@ -61,6 +70,17 @@ bool LLAvatarName::operator<(const LLAvatarName& rhs) const  		return mUsername < rhs.mUsername;  } +//static  +void LLAvatarName::setUseDisplayNames(bool use) +{ +	sUseDisplayNames = use; +} +//static  +bool LLAvatarName::useDisplayNames()  +{  +	return sUseDisplayNames;  +} +  LLSD LLAvatarName::asLLSD() const  {  	LLSD sd; @@ -85,21 +105,75 @@ void LLAvatarName::fromLLSD(const LLSD& sd)  	mExpires = expires.secondsSinceEpoch();  	LLDate next_update = sd[DISPLAY_NAME_NEXT_UPDATE];  	mNextUpdate = next_update.secondsSinceEpoch(); +	 +	// Some avatars don't have explicit display names set. Force a legible display name here. +	if (mDisplayName.empty()) +	{ +		mDisplayName = mUsername; +	} +} + +// Transform a string (typically provided by the legacy service) into a decent +// avatar name instance. +void LLAvatarName::fromString(const std::string& full_name) +{ +	mDisplayName = full_name; +	std::string::size_type index = full_name.find(' '); +	if (index != std::string::npos) +	{ +		// The name is in 2 parts (first last) +		mLegacyFirstName = full_name.substr(0, index); +		mLegacyLastName = full_name.substr(index+1); +		if (mLegacyLastName != "Resident") +		{ +			mUsername = mLegacyFirstName + "." + mLegacyLastName; +			mDisplayName = full_name; +			LLStringUtil::toLower(mUsername); +		} +		else +		{ +			// Very old names do have a dummy "Resident" last name  +			// that we choose to hide from users. +			mUsername = mLegacyFirstName; +			mDisplayName = mLegacyFirstName; +		} +	} +	else +	{ +		mLegacyFirstName = full_name; +		mLegacyLastName = ""; +		mUsername = full_name; +		mDisplayName = full_name; +	} +	mIsDisplayNameDefault = true; +	mIsTemporaryName = true; +	setExpires(MIN_ENTRY_LIFETIME); +} + +void LLAvatarName::setExpires(F64 expires) +{ +	mExpires = LLFrameTimer::getTotalSeconds() + expires;  }  std::string LLAvatarName::getCompleteName() const  {  	std::string name; -	if (mUsername.empty() || mIsDisplayNameDefault) -	// If the display name feature is off -	// OR this particular display name is defaulted (i.e. based on user name), -	// then display only the easier to read instance of the person's name. +	if (sUseDisplayNames)  	{ -		name = mDisplayName; +		if (mUsername.empty() || mIsDisplayNameDefault) +		{ +			// If this particular display name is defaulted (i.e. based on user name), +			// then display only the easier to read instance of the person's name. +			name = mDisplayName; +		} +		else +		{ +			name = mDisplayName + " (" + mUsername + ")"; +		}  	}  	else  	{ -		name = mDisplayName + " (" + mUsername + ")"; +		name = getUserName();  	}  	return name;  } @@ -118,3 +192,48 @@ std::string LLAvatarName::getLegacyName() const  	name += mLegacyLastName;  	return name;  } + +std::string LLAvatarName::getDisplayName() const +{ +	if (sUseDisplayNames) +	{ +		return mDisplayName; +	} +	else +	{ +		return getUserName(); +	} +} + +std::string LLAvatarName::getUserName() const +{ +	std::string name; +	if (mLegacyLastName.empty() || (mLegacyLastName == "Resident")) +	{ +		if (mLegacyFirstName.empty()) +		{ +			// If we cannot create a user name from the legacy strings, use the display name +			name = mDisplayName; +		} +		else +		{ +			// The last name might be empty if it defaulted to "Resident" +			name = mLegacyFirstName; +		} +	} +	else +	{ +		name = mLegacyFirstName + " " + mLegacyLastName; +	} +	return name; +} + +void LLAvatarName::dump() const +{ +	LL_DEBUGS("AvNameCache") << "LLAvatarName: " +	                         << "user '" << mUsername << "' " +							 << "display '" << mDisplayName << "' " +	                         << "expires in " << mExpires - LLFrameTimer::getTotalSeconds() << " seconds" +							 << LL_ENDL; +} + diff --git a/indra/llcommon/llavatarname.h b/indra/llcommon/llavatarname.h index ba258d6d52..7542a8dece 100644 --- a/indra/llcommon/llavatarname.h +++ b/indra/llcommon/llavatarname.h @@ -39,10 +39,27 @@ public:  	bool operator<(const LLAvatarName& rhs) const; +	// Conversion to and from LLSD (cache file or server response)  	LLSD asLLSD() const; -  	void fromLLSD(const LLSD& sd); +	// Used only in legacy mode when the display name capability is not provided server side +	// or to otherwise create a temporary valid item. +	void fromString(const std::string& full_name); +	 +	// Set the name object to become invalid in "expires" seconds from now +	void setExpires(F64 expires); + +	// Set and get the display name flag set by the user in preferences. +	static void setUseDisplayNames(bool use); +	static bool useDisplayNames(); +	 +	// A name object is valid if not temporary and not yet expired (default is expiration not checked) +	bool isValidName(F64 max_unrefreshed = 0.0f) const { return !mIsTemporaryName && (mExpires >= max_unrefreshed); } +	 +	// Return true if the name is made up from legacy or temporary data +	bool isDisplayNameDefault() const { return mIsDisplayNameDefault; } +	  	// For normal names, returns "James Linden (james.linden)"  	// When display names are disabled returns just "James Linden"  	std::string getCompleteName() const; @@ -51,11 +68,38 @@ public:  	// compatibility with systems like voice and muting  	// *TODO: Eliminate this in favor of username only  	std::string getLegacyName() const; +	 +	// "José Sanchez" or "James Linden", UTF-8 encoded Unicode +	// Takes the display name preference into account. This is truly the name that should  +	// be used for all UI where an avatar name has to be used unless we truly want something else (rare) +	std::string getDisplayName() const; +	 +	// Returns "James Linden" or "bobsmith123 Resident" +	// Used where we explicitely prefer or need a non UTF-8 legacy (ASCII) name +	// Also used for backwards compatibility with systems like voice and muting +	std::string getUserName() const; +	 +	// Returns "james.linden" or the legacy name for very old names +	std::string getAccountName() const { return mUsername; } +	// Debug print of the object +	void dump() const; +	 +	// Names can change, so need to keep track of when name was +	// last checked. +	// Unix time-from-epoch seconds for efficiency +	F64 mExpires; +	 +	// You can only change your name every N hours, so record +	// when the next update is allowed +	// Unix time-from-epoch seconds +	F64 mNextUpdate; +	 +private:  	// "bobsmith123" or "james.linden", US-ASCII only  	std::string mUsername; -	// "Jose' Sanchez" or "James Linden", UTF-8 encoded Unicode +	// "José Sanchez" or "James Linden", UTF-8 encoded Unicode  	// Contains data whether or not user has explicitly set  	// a display name; may duplicate their username.  	std::string mDisplayName; @@ -81,15 +125,9 @@ public:  	// shown in UI, but are not serialized.  	bool mIsTemporaryName; -	// Names can change, so need to keep track of when name was -	// last checked. -	// Unix time-from-epoch seconds for efficiency -	F64 mExpires; -	 -	// You can only change your name every N hours, so record -	// when the next update is allowed -	// Unix time-from-epoch seconds -	F64 mNextUpdate; +	// Global flag indicating if display name should be used or not +	// This will affect the output of the high level "get" methods +	static bool sUseDisplayNames;  };  #endif diff --git a/indra/llcommon/llhandle.h b/indra/llcommon/llhandle.h index 6af5e198d6..401e4d759a 100644 --- a/indra/llcommon/llhandle.h +++ b/indra/llcommon/llhandle.h @@ -194,13 +194,6 @@ public:  		return mHandle;   	} -protected: -	typedef LLHandle<T> handle_type_t; -	LLHandleProvider()  -	{ -		// provided here to enforce T deriving from LLHandleProvider<T> -	}  -  	template <typename U>  	LLHandle<U> getDerivedHandle(typename boost::enable_if< typename boost::is_convertible<U*, T*> >::type* dummy = 0) const  	{ @@ -209,6 +202,12 @@ protected:  		return downcast_handle;  	} +protected: +	typedef LLHandle<T> handle_type_t; +	LLHandleProvider()  +	{ +		// provided here to enforce T deriving from LLHandleProvider<T> +	}   private:  	mutable LLRootHandle<T> mHandle; 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 0dd6030fa2..ae836645b9 100644 --- a/indra/llcommon/llinitparam.h +++ b/indra/llcommon/llinitparam.h @@ -38,6 +38,71 @@  #include "llerror.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  {  	// used to indicate no matching value to a given name when parsing @@ -45,6 +110,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   	{ @@ -79,24 +146,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;  		} @@ -111,15 +277,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)  @@ -132,7 +322,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(); @@ -153,7 +343,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); @@ -195,18 +385,90 @@ 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;  	}; +	// 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> +	{ +	public: +		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) +	{ +			*this = name; +		} + +		self_t& operator =(const std::string& name) +		{ +			if (base_t::getValueFromName(name, ParamValue<std::string>::getValue())) +			{ +				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); @@ -223,82 +485,58 @@ namespace LLInitParam  		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; -	private: -		template<typename T, bool is_enum = boost::is_enum<T>::value> -		struct ReaderWriter -		{ -			static bool read(T& param, Parser* parser) +	public: + +		Parser(parser_read_func_map_t& read_map, parser_write_func_map_t& write_map, parser_inspect_func_map_t& inspect_map) +		:	mParseSilently(false), +			mParserReadFuncs(&read_map), +			mParserWriteFuncs(&write_map), +			mParserInspectFuncs(&inspect_map) +		{} + +		virtual ~Parser(); + +		template <typename T> bool readValue(T& param, typename boost::disable_if<boost::is_enum<T> >::type* dummy = 0)  			{ -				parser_read_func_map_t::iterator found_it = parser->mParserReadFuncs->find(&typeid(T)); -				if (found_it != parser->mParserReadFuncs->end()) +			parser_read_func_map_t::iterator found_it = mParserReadFuncs->find(&typeid(T)); +			if (found_it != mParserReadFuncs->end())  				{ -					return found_it->second(*parser, (void*)¶m); +				return found_it->second(*this, (void*)¶m);  				} +			  				return false;  			} -			static bool write(const T& param, Parser* parser, name_stack_t& name_stack) +		template <typename T> bool readValue(T& param, typename boost::enable_if<boost::is_enum<T> >::type* dummy = 0)  			{ -				parser_write_func_map_t::iterator found_it = parser->mParserWriteFuncs->find(&typeid(T)); -				if (found_it != parser->mParserWriteFuncs->end()) +			parser_read_func_map_t::iterator found_it = mParserReadFuncs->find(&typeid(T)); +			if (found_it != mParserReadFuncs->end())  				{ -					return found_it->second(*parser, (const void*)¶m, name_stack); +				return found_it->second(*this, (void*)¶m);  				} -				return false; -			} -		}; - -		// read enums as ints -		template<typename T> -		struct ReaderWriter<T, true> +			else  		{ -			static bool read(T& param, Parser* parser) -			{ -				// read all enums as ints -				parser_read_func_map_t::iterator found_it = parser->mParserReadFuncs->find(&typeid(S32)); -				if (found_it != parser->mParserReadFuncs->end()) +				found_it = mParserReadFuncs->find(&typeid(S32)); +				if (found_it != mParserReadFuncs->end())  				{ -					S32 value; -					if (found_it->second(*parser, (void*)&value)) -					{ -						param = (T)value; -						return true; +					S32 int_value; +					bool parsed = found_it->second(*this, (void*)&int_value); +					param = (T)int_value; +					return parsed;  					}  				}  				return false;  			} -			static bool write(const T& param, Parser* parser, name_stack_t& name_stack) +		template <typename T> bool writeValue(const T& param, name_stack_t& name_stack)  			{ -				parser_write_func_map_t::iterator found_it = parser->mParserWriteFuncs->find(&typeid(S32)); -				if (found_it != parser->mParserWriteFuncs->end()) +			parser_write_func_map_t::iterator found_it = mParserWriteFuncs->find(&typeid(T)); +			if (found_it != mParserWriteFuncs->end())  				{ -					return found_it->second(*parser, (const void*)¶m, name_stack); +				return found_it->second(*this, (const void*)¶m, name_stack);  				}  				return false;  			} -		}; - -	public: - -		Parser(parser_read_func_map_t& read_map, parser_write_func_map_t& write_map, parser_inspect_func_map_t& inspect_map) -		:	mParseSilently(false), -			mParserReadFuncs(&read_map), -			mParserWriteFuncs(&write_map), -			mParserInspectFuncs(&inspect_map) -		{} - -		virtual ~Parser(); - -		template <typename T> bool readValue(T& param) -	    { -			return ReaderWriter<T>::read(param, this); -	    } - -		template <typename T> bool writeValue(const T& param, name_stack_t& name_stack) -		{ -			return ReaderWriter<T>::write(param, this, name_stack); -		}  		// dispatch inspection to registered inspection functions, for each parameter in a param block  		template <typename T> bool inspectValue(name_stack_t& name_stack, S32 min_count, S32 max_count, const possible_values_t* possible_values) @@ -350,7 +588,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*); @@ -395,6 +633,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;  @@ -410,48 +649,58 @@ namespace LLInitParam  		class BaseBlock*				mCurrentBlockPtr;		// pointer to block currently being constructed  	}; -	class LL_COMMON_API BaseBlock -	{ -	public:  		//TODO: implement in terms of owned_ptr  		template<typename T> -		class Lazy +	class LazyValue  		{  		public: -			Lazy() +		LazyValue()  				: mPtr(NULL)  			{} -			~Lazy() +		~LazyValue()  			{  				delete mPtr;  			} -			Lazy(const Lazy& other) +		LazyValue(const T& value)  			{ -				if (other.mPtr) +			mPtr = new T(value); +		} + +		LazyValue(const LazyValue& other) +		:	mPtr(NULL)  				{ -					mPtr = new T(*other.mPtr); +			*this = other;  				} -				else + +		LazyValue& operator = (const LazyValue& other)  				{ +			if (!other.mPtr) +			{ +				delete mPtr;  					mPtr = NULL;  				} -			} - -			Lazy<T>& operator = (const Lazy<T>& other) +			else  			{ -				if (other.mPtr) +				if (!mPtr)  				{  					mPtr = new T(*other.mPtr);  				}  				else  				{ -					mPtr = NULL; +					*mPtr = *(other.mPtr); +				}  				}  				return *this;  			} +		bool operator==(const LazyValue& other) const +		{ +			if (empty() || other.empty()) return false; +			return *mPtr == *other.mPtr; +		} +  			bool empty() const  			{  				return mPtr == NULL; @@ -459,18 +708,29 @@ namespace LLInitParam  			void set(const T& other)  			{ -				delete mPtr; +			if (!mPtr) +			{  				mPtr = new T(other);  			} +			else +			{ +				*mPtr = other; +			} +		}  			const T& get() const  			{ -				return ensureInstance(); +			return *ensureInstance();  			}  			T& get()  			{ -				return ensureInstance(); +			return *ensureInstance(); +		} + +		operator const T&() const +		{  +			return get();   			}  		private: @@ -485,13 +745,50 @@ namespace LLInitParam  			}  		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);  			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; }; +		}; + +		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  		struct AnyAmount  		{ @@ -557,12 +854,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) @@ -576,10 +873,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); @@ -588,25 +892,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: @@ -635,256 +925,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; -		} - -		operator value_assignment_t() 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; +					(my_addr - (ptrdiff_t)getEnclosingBlockOffset()));  		} -	protected: -		mutable bool 	mValidated; // lazy validation flag -	}; - -	template<typename NAME_VALUE_LOOKUP> -	class ParamValue<std::string, NAME_VALUE_LOOKUP, false> -	: public NAME_VALUE_LOOKUP +		U32 getEnclosingBlockOffset() const  	{ -	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; -		} - -		std::string& getValue() -		{ -			return mValue; +			return ((U32)mEnclosingBlockOffsetHigh << 16) | (U32)mEnclosingBlockOffsetLow;  		} -		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 @@ -893,9 +995,9 @@ namespace LLInitParam  				std::string name;  				// try to parse a known named value -				if(name_value_lookup_t::valueNamesExist() +				if(named_value_t::valueNamesExist()  					&& parser.readValue(name) -					&& name_value_lookup_t::getValueFromName(name, typed_param.getValue())) +					&& named_value_t::getValueFromName(name, typed_param.getValue()))  				{  					typed_param.setValueName(name);  					typed_param.setProvided(); @@ -939,7 +1041,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);  					} @@ -952,22 +1056,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: @@ -992,41 +1097,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 param_value_t::operator(); +		using named_value_t::operator(); +		typedef typename param_value_t::value_t						value_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), -			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); @@ -1034,9 +1145,9 @@ namespace LLInitParam  			{	// try to parse a known named value  				std::string name; -				if(name_value_lookup_t::valueNamesExist() +				if(named_value_t::valueNamesExist()  					&& parser.readValue(name)				 -					&& name_value_lookup_t::getValueFromName(name, typed_param.getValue())) +					&& named_value_t::getValueFromName(name, typed_param.getValue()))  				{  					typed_param.setValueName(name);  					typed_param.setProvided(); @@ -1068,9 +1179,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 @@ -1081,8 +1192,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);  		} @@ -1100,32 +1219,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  			{ @@ -1149,7 +1270,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); @@ -1158,56 +1279,72 @@ 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)  			{	  				std::string name;  				// try to parse a known named value -				if(name_value_lookup_t::valueNamesExist() +				if(named_value_t::valueNamesExist()  					&& parser.readValue(name) -					&& name_value_lookup_t::getValueFromName(name, value)) +					&& named_value_t::getValueFromName(name, value))  				{  					typed_param.add(value);  					typed_param.mValues.back().setValueName(name); @@ -1225,14 +1362,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 @@ -1254,19 +1391,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); @@ -1274,26 +1413,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); @@ -1303,9 +1440,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; @@ -1346,62 +1483,79 @@ 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();  			if (name_stack_range.first == name_stack_range.second)  			{	// try to parse a known named value  				std::string name; -				if(name_value_lookup_t::valueNamesExist() +				if(named_value_t::valueNamesExist()  					&& parser.readValue(name) -					&& name_value_lookup_t::getValueFromName(name, value.getValue())) +					&& named_value_t::getValueFromName(name, value.getValue()))  				{  					typed_param.mValues.back().setValueName(name);  					typed_param.setProvided(); @@ -1410,9 +1564,13 @@ namespace LLInitParam  			}  			// 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;  			} @@ -1428,13 +1586,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()) @@ -1447,16 +1605,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());  		} -		void set(value_assignment_t val, bool flag_as_provided = true) +			value_param.inspectBlock(parser, name_stack, min_count, max_count); +		} + +		void set(const container_t& val, bool flag_as_provided = true)  		{  			mValues = val;  			setProvided(flag_as_provided); @@ -1476,12 +1645,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); @@ -1490,12 +1659,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(); } @@ -1542,6 +1709,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> @@ -1556,13 +1737,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) @@ -1580,7 +1761,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 @@ -1601,38 +1782,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)  					{ @@ -1646,27 +1827,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)  				{ @@ -1681,11 +1862,11 @@ namespace LLInitParam  			}  		private: -			T			mOriginalValue; +			default_value_t mOriginalValue;  		}; -	protected: -		static BlockDescriptor& selfBlockDescriptor() +	public: +		static BlockDescriptor& getBlockDescriptor()  		{  			static BlockDescriptor sBlockDescriptor;  			return sBlockDescriptor; @@ -1705,6 +1886,8 @@ namespace LLInitParam  	:	public BASE_BLOCK  	{  		typedef Block<DERIVED_BLOCK, BASE_BLOCK>	self_t; + +	protected:  		typedef Block<DERIVED_BLOCK, BASE_BLOCK>	block_t;  	public: @@ -1713,80 +1896,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()); @@ -1800,28 +1985,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()); @@ -1834,13 +2020,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( @@ -1851,11 +2039,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)  				{ @@ -1868,19 +2056,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())  			{ @@ -1890,204 +2105,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; -		BatchBlock() +		ParamValue() +		:	mValue(), +			mValidated(false)  		{} -		bool deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack_range, bool new_name) +		ParamValue(const default_value_t& value) +		:	mValue(value), +			mValidated(false) +		{} + +		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  			{ -				*static_cast<DERIVED_BLOCK*>(this) = defaultBatchValue(); -				// merge individual parameters into destination -				return super_t::mergeBlock(super_t::selfBlockDescriptor(), other, overwrite); +			return mValue.inspectBlock(p, name_stack, min_count, max_count);  			} -			return false; + +		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 +			{ +				// clear away what is there and take the new stuff as a whole +				resetToDefault(); +				return mValue.mergeBlock(block_data, source.getValue(), overwrite);  		} -	protected: -		static const DERIVED_BLOCK& defaultBatchValue() +			 + +			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(); +		} + + +		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); -		value_assignment_t operator()() const +				if (deserialize_func  +					&& paramp  +					&& deserialize_func(*paramp, p, name_stack_range, new_name))  		{ -			return *this; +					++mCurParam; +					return true; +				} +				else +				{ +					return false; +				} +		} +			else +			{ +				return mValue.deserializeBlock(p, name_stack_range, new_name); +			} +		} + +		void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const self_t* diff_block = NULL) const +		{ +			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(); +			return mValue.get().getValue();  		} -		operator value_assignment_t() const +		bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name)  		{ -			return mValue.get(); +			return mValue.get().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 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);  		} -		bool deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack_range, bool new_name) +		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().deserializeBlock(p, name_stack_range, new_name); +			return mValue.get().inspectBlock(p, name_stack, min_count, max_count);  		} -		void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block = NULL) const +		bool mergeBlockParam(bool source_provided, bool dst_provided, BlockDescriptor& block_data, const self_t& source, bool overwrite)  		{ -			if (mValue.empty()) return; +			return source.mValue.empty() || mValue.get().mergeBlock(block_data, source.getValue(), overwrite); +		} -			mValue.get().serializeBlock(p, name_stack, diff_block); +		bool validateBlock(bool emit_errors = true) const +		{ +			return mValue.empty() || mValue.get().validateBlock(emit_errors);  		} -		bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const +		static BlockDescriptor& getBlockDescriptor()  		{ -			if (mValue.empty()) return false; +			return value_t::getBlockDescriptor(); +		} -			return mValue.get().inspectBlock(p, name_stack, min_count, max_count); +		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) +		{} +			 +		void setValue(const value_t& val) +		{ +			mValue.set(val); +		} + +		const value_t& getValue() const +		{ +			return mValue.get().getValue(); +		} + +		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  		{ @@ -2106,8 +2537,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 @@ -2117,20 +2547,21 @@ namespace LLInitParam  			BLOCK_AUTHORITATIVE		// mValue is derived from the block parameters, which are authoritative  		} EValueAge; -		typedef ParamValue<T, TypeValues<T> >	derived_t; +		typedef ParamValue<T>			derived_t;  		typedef CustomParamValue<T>				self_t;  		typedef Block<derived_t>				block_t; -		typedef const T&						value_assignment_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 @@ -2141,8 +2572,6 @@ namespace LLInitParam  					typed_param.mValueAge = VALUE_AUTHORITATIVE;  					typed_param.updateBlockFromValue(false); -					typed_param.clearValueName(); -  					return true;  				}  			} @@ -2156,18 +2585,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))  @@ -2197,19 +2616,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) @@ -2217,7 +2623,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; @@ -2247,17 +2652,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; @@ -2269,20 +2672,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 853c427a13..bb0d60247e 100644 --- a/indra/llcommon/llregistry.h +++ b/indra/llcommon/llregistry.h @@ -307,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/llthread.h b/indra/llcommon/llthread.h index 5c8bbca2ca..0fb89c5613 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; @@ -284,6 +285,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/llversionviewer.h b/indra/llcommon/llversionviewer.h index e41c59177a..ca8a05511a 100644 --- a/indra/llcommon/llversionviewer.h +++ b/indra/llcommon/llversionviewer.h @@ -28,8 +28,8 @@  #define LL_LLVERSIONVIEWER_H  const S32 LL_VERSION_MAJOR = 3; -const S32 LL_VERSION_MINOR = 4; -const S32 LL_VERSION_PATCH = 5; +const S32 LL_VERSION_MINOR = 5; +const S32 LL_VERSION_PATCH = 0;  const S32 LL_VERSION_BUILD = 264760;  const char * const LL_CHANNEL = "Second Life Developer"; 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. | 
