Skip to content
Snippets Groups Projects
llinitparam.h 66.3 KiB
Newer Older
  • Learn to ignore specific revisions
  •  * @brief parameter block abstraction for creating complex objects and 
     * parsing construction parameters from xml and LLSD
     *
    
     * $LicenseInfo:firstyear=2008&license=viewerlgpl$
    
     * Copyright (C) 2010, Linden Research, Inc.
     * 
     * This library is free software; you can redistribute it and/or
     * modify it under the terms of the GNU Lesser General Public
     * License as published by the Free Software Foundation;
     * version 2.1 of the License only.
    
     * This library is distributed in the hope that it will be useful,
     * but WITHOUT ANY WARRANTY; without even the implied warranty of
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     * Lesser General Public License for more details.
    
     * You should have received a copy of the GNU Lesser General Public
     * License along with this library; if not, write to the Free Software
     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
    
     * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
    
     * $/LicenseInfo$
     */
    
    #ifndef LL_LLPARAM_H
    #define LL_LLPARAM_H
    
    #include <vector>
    #include <boost/function.hpp>
    
    #include <boost/type_traits/is_convertible.hpp>
    
    #include <boost/unordered_map.hpp>
    
    #include "llpredicate.h"
    
    Richard Nelson's avatar
    Richard Nelson committed
    	// used to indicate no matching value to a given name when parsing
    	struct Flag{};
    
    
    	template<typename T> const T& defaultValue() { static T value; return value; }
    
    Richard Nelson's avatar
    Richard Nelson committed
    	template <typename T, bool IS_BOOST_FUNCTION = boost::is_convertible<T, boost::function_base>::value >
    
        struct ParamCompare 
    	{
        	static bool equals(const T &a, const T &b)
    		{
    			return a == b;
    		}
    
    	// boost function types are not comparable
    	template<typename T>
    
    Richard Nelson's avatar
    Richard Nelson committed
    	struct ParamCompare<T, true>
    
    	{
    		static bool equals(const T&a, const T &b)
    		{
    			return false;
    		}
    	};
    
    		static bool equals(const LLSD &a, const LLSD &b) { return false; }
    
    Richard Nelson's avatar
    Richard Nelson committed
    	template<>
    	struct ParamCompare<Flag, false>
    	{
    		static bool equals(const Flag& a, const Flag& b) { return false; }
    	};
    
    
    	// helper functions and classes
    	typedef ptrdiff_t param_handle_t;
    
    
    	// empty default implementation of key cache
    	// leverages empty base class optimization
    
    	private:
    		struct Inaccessable{};
    
    		typedef std::map<std::string, T> value_name_map_t;
    
    		typedef Inaccessable name_t;
    
    
    		void setValueName(const std::string& key) {}
    		std::string getValueName() const { return ""; }
    
    		std::string calcValueName(const T& value) const { return ""; }
    
    		void clearValueName() const {}
    
    		static bool getValueFromName(const std::string& name, T& value)
    
    		static std::vector<std::string>* getPossibleValues()
    
    		static value_name_map_t* getValueNames() {return NULL;}
    
    	};
    
    	template <typename T, typename DERIVED_TYPE = TypeValues<T> >
    	class TypeValuesHelper
    	{
    	public:
    
    Leslie Linden's avatar
    Leslie Linden committed
    		typedef typename std::map<std::string, T> value_name_map_t;
    
    		typedef std::string name_t;
    
    
    		//TODO: cache key by index to save on param block size
    
    		void setValueName(const std::string& value_name) 
    
    		std::string getValueName() const
    		{ 
    			return mValueName; 
    		}
    
    		std::string calcValueName(const T& value) const
    		{
    			value_name_map_t* map = getValueNames();
    
    			for (typename value_name_map_t::iterator it = map->begin(), end_it = map->end();
    
    				it != end_it;
    				++it)
    			{
    				if (ParamCompare<T>::equals(it->second, value))
    				{
    					return it->first;
    				}
    			}
    
    			return "";
    		}
    
    
    		static bool getValueFromName(const std::string& name, T& value)
    
    Leslie Linden's avatar
    Leslie Linden committed
    			typename value_name_map_t::iterator found_it = map->find(name);
    
    			if (found_it == map->end()) return false;
    
    			static value_name_map_t sMap;
    			static bool sInitialized = false;
    
    				sInitialized = true;
    				DERIVED_TYPE::declareValues();
    
    		static std::vector<std::string>* getPossibleValues()
    		{
    			static std::vector<std::string> sValues;
    
    			value_name_map_t* map = getValueNames();
    
    Leslie Linden's avatar
    Leslie Linden committed
    			for (typename value_name_map_t::iterator it = map->begin(), end_it = map->end();
    
    				 it != end_it;
    				 ++it)
    			{
    				sValues.push_back(it->first);
    			}
    			return &sValues;
    		}
    
    
    		static void declare(const std::string& name, const T& value)
    		{
    
    	protected:
    		static void getName(const std::string& name, const T& value)
    		{}
    
    		mutable std::string	mValueName;
    
    Richard Linden's avatar
    Richard Linden committed
    	class LL_COMMON_API Parser
    
    		typedef std::vector<std::pair<std::string, bool> >					name_stack_t;
    		typedef std::pair<name_stack_t::iterator, name_stack_t::iterator>	name_stack_range_t;
    		typedef std::vector<std::string>									possible_values_t;
    
    		typedef bool (*parser_read_func_t)(Parser& parser, void* output);
    
    		typedef bool (*parser_write_func_t)(Parser& parser, const void*, name_stack_t&);
    		typedef boost::function<void (name_stack_t&, S32, S32, const possible_values_t*)>	parser_inspect_func_t;
    
    		typedef std::map<const std::type_info*, parser_read_func_t>		parser_read_func_map_t;
    		typedef std::map<const std::type_info*, parser_write_func_t>	parser_write_func_map_t;
    		typedef std::map<const std::type_info*, parser_inspect_func_t>	parser_inspect_func_map_t;
    
    		Parser(parser_read_func_map_t& read_map, parser_write_func_map_t& write_map, parser_inspect_func_map_t& inspect_map)
    
    			mParserReadFuncs(&read_map),
    			mParserWriteFuncs(&write_map),
    			mParserInspectFuncs(&inspect_map)
    
    		{}
    		virtual ~Parser();
    
    		template <typename T> bool readValue(T& param)
    	    {
    
    		    parser_read_func_map_t::iterator found_it = mParserReadFuncs->find(&typeid(T));
    		    if (found_it != mParserReadFuncs->end())
    
    			    return found_it->second(*this, (void*)&param);
    
    		template <typename T> bool writeValue(const T& param, name_stack_t& name_stack)
    
    		    parser_write_func_map_t::iterator found_it = mParserWriteFuncs->find(&typeid(T));
    		    if (found_it != mParserWriteFuncs->end())
    
    			    return found_it->second(*this, (const void*)&param, name_stack);
    
    		    }
    		    return false;
    		}
    
    		// 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)
    
    		    parser_inspect_func_map_t::iterator found_it = mParserInspectFuncs->find(&typeid(T));
    		    if (found_it != mParserInspectFuncs->end())
    
    			    found_it->second(name_stack, min_count, max_count, possible_values);
    
    				return true;
    		    }
    			return false;
    		}
    
    		virtual std::string getCurrentElementName() = 0;
    		virtual void parserWarning(const std::string& message);
    		virtual void parserError(const std::string& message);
    		void setParseSilently(bool silent) { mParseSilently = silent; }
    
    	protected:
    		template <typename T>
    
    		void registerParserFuncs(parser_read_func_t read_func, parser_write_func_t write_func = NULL)
    
    			mParserReadFuncs->insert(std::make_pair(&typeid(T), read_func));
    			mParserWriteFuncs->insert(std::make_pair(&typeid(T), write_func));
    
    		}
    
    		template <typename T>
    		void registerInspectFunc(parser_inspect_func_t inspect_func)
    		{
    
    			mParserInspectFuncs->insert(std::make_pair(&typeid(T), inspect_func));
    
    		parser_read_func_map_t*		mParserReadFuncs;
    		parser_write_func_map_t*	mParserWriteFuncs;
    		parser_inspect_func_map_t*	mParserInspectFuncs;
    
    	enum ESerializePredicates
    	{
    		PROVIDED,
    		REQUIRED,
    		VALID,
    
    		HAS_DEFAULT_VALUE,
    		EMPTY
    
    	};
    
    	typedef LLPredicate::Rule<ESerializePredicates> predicate_rule_t;
    
    
    	predicate_rule_t default_parse_rules();
    
    	// various callbacks and constraints associated with an individual param
    
    Richard Linden's avatar
    Richard Linden committed
    	struct LL_COMMON_API ParamDescriptor
    
    		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(*serialize_func_t)(const Param&, Parser&, Parser::name_stack_t&, const predicate_rule_t, const Param*);
    
    		typedef void(*inspect_func_t)(const Param&, Parser&, Parser::name_stack_t&, S32, S32);
    
    		typedef bool(*validation_func_t)(const Param*);
    
    		ParamDescriptor(param_handle_t p, 
    
    						merge_func_t merge_func, 
    						deserialize_func_t deserialize_func, 
    						serialize_func_t serialize_func,
    						validation_func_t validation_func,
    						inspect_func_t inspect_func,
    						S32 min_count,
    						S32 max_count);
    
    
    		param_handle_t		mParamHandle;
    		merge_func_t		mMergeFunc;
    		deserialize_func_t	mDeserializeFunc;
    		serialize_func_t	mSerializeFunc;
    		inspect_func_t		mInspectFunc;
    		validation_func_t	mValidationFunc;
    		S32					mMinCount;
    		S32					mMaxCount;
    		S32					mNumRefs;
    
    	typedef ParamDescriptor* ParamDescriptorPtr;
    
    	// each derived Block class keeps a static data structure maintaining offsets to various params
    
    Richard Linden's avatar
    Richard Linden committed
    	class LL_COMMON_API BlockDescriptor
    
    
    		typedef enum e_initialization_state
    		{
    			UNINITIALIZED,
    			INITIALIZING,
    			INITIALIZED
    		} EInitializationState;
    
    		void aggregateBlockData(BlockDescriptor& src_block_data);
    
    
    		typedef boost::unordered_map<const std::string, ParamDescriptorPtr>						param_map_t; 
    		typedef std::vector<ParamDescriptorPtr>													param_list_t; 
    
    		typedef std::list<ParamDescriptorPtr>													all_params_list_t;
    
    		typedef std::vector<std::pair<param_handle_t, ParamDescriptor::validation_func_t> >		param_validation_list_t;
    
    
    		param_map_t						mNamedParams;			// parameters with associated names
    		param_list_t					mUnnamedParams;			// parameters with_out_ associated names
    		param_validation_list_t			mValidationList;		// parameters that must be validated
    		all_params_list_t				mAllParams;				// all parameters, owns descriptors
    
    		size_t							mMaxParamOffset;
    		EInitializationState			mInitializationState;	// whether or not static block data has been initialized
    
    		class BaseBlock*				mCurrentBlockPtr;		// pointer to block currently being constructed
    
    Richard Linden's avatar
    Richard Linden committed
    	class LL_COMMON_API BaseBlock
    
    		//TODO: implement in terms of owned_ptr
    		template<typename T>
    		class Lazy
    		{
    		public:
    			Lazy()
    				: mPtr(NULL)
    			{}
    
    			~Lazy()
    			{
    				delete mPtr;
    			}
    
    			Lazy(const Lazy& other)
    			{
    				if (other.mPtr)
    				{
    					mPtr = new T(*other.mPtr);
    				}
    				else
    				{
    					mPtr = NULL;
    				}
    			}
    
    			Lazy<T>& operator = (const Lazy<T>& other)
    			{
    				if (other.mPtr)
    				{
    					mPtr = new T(*other.mPtr);
    				}
    				else
    				{
    					mPtr = NULL;
    				}
    				return *this;
    			}
    
    			bool empty() const
    			{
    				return mPtr == NULL;
    			}
    
    			void set(const T& other)
    			{
    				delete mPtr;
    				mPtr = new T(other);
    			}
    
    			const T& get() const
    			{
    				return ensureInstance();
    			}
    
    			T& get()
    			{
    				return ensureInstance();
    			}
    
    		private:
    			// lazily allocate an instance of T
    			T* ensureInstance() const
    			{
    				if (mPtr == NULL)
    				{
    					mPtr = new T();
    				}
    				return mPtr;
    			}
    
    		private:
    			// if you get a compilation error with this, that means you are using a forward declared struct for T
    			// unfortunately, the type traits we rely on don't work with forward declared typed
    			//static const int dummy = sizeof(T);
    
    			mutable T* mPtr;
    		};
    
    
    		// "Multiple" constraint types, put here in root class to avoid ambiguity during use
    
    		struct AnyAmount
    		{
    
    Richard Nelson's avatar
    Richard Nelson committed
    			enum { minCount = 0 };
    			enum { maxCount = U32_MAX };
    
    		};
    
    		template<U32 MIN_AMOUNT>
    		struct AtLeast
    		{
    
    Richard Nelson's avatar
    Richard Nelson committed
    			enum { minCount = MIN_AMOUNT };
    			enum { maxCount = U32_MAX };
    
    		};
    
    		template<U32 MAX_AMOUNT>
    		struct AtMost
    		{
    
    Richard Nelson's avatar
    Richard Nelson committed
    			enum { minCount = 0 };
    			enum { maxCount = MAX_AMOUNT };
    
    		};
    
    		template<U32 MIN_AMOUNT, U32 MAX_AMOUNT>
    		struct Between
    		{
    
    Richard Nelson's avatar
    Richard Nelson committed
    			enum { minCount = MIN_AMOUNT };
    			enum { maxCount = MAX_AMOUNT };
    
    		};
    
    		template<U32 EXACT_COUNT>
    		struct Exactly
    		{
    
    Richard Nelson's avatar
    Richard Nelson committed
    			enum { minCount = EXACT_COUNT };
    			enum { maxCount = EXACT_COUNT };
    
    		// this typedef identifies derived classes as being blocks
    		typedef void baseblock_base_class_t;
    		LOG_CLASS(BaseBlock);
    		friend class Param;
    
    
    		BaseBlock()
    		:	mValidated(false),
    			mParamProvided(false)
    		{}
    
    
    		bool submitValue(Parser::name_stack_t& name_stack, Parser& p, bool silent=false);
    
    
    		param_handle_t getHandleFromParam(const Param* param) const;
    
    		bool validateBlock(bool emit_errors = true) const;
    
    		bool isProvided() const
    		{
    			return mParamProvided;
    		}
    
    		bool isValid() const
    		{
    			return validateBlock(false);
    		}
    
    
    
    		Param* getParamFromHandle(const param_handle_t param_handle)
    		{
    			if (param_handle == 0) return NULL;
    
    			U8* baseblock_address = reinterpret_cast<U8*>(this);
    			return reinterpret_cast<Param*>(baseblock_address + param_handle);
    		}
    
    		const Param* getParamFromHandle(const param_handle_t param_handle) const
    		{
    			const U8* baseblock_address = reinterpret_cast<const U8*>(this);
    			return reinterpret_cast<const Param*>(baseblock_address + param_handle);
    		}
    
    		void addSynonym(Param& param, const std::string& synonym);
    
    		// Blocks can override this to do custom tracking of changes
    
    		virtual void paramChanged(const Param& changed_param, bool user_provided) 
    		{
    			if (user_provided)
    			{
    				// a child param has been explicitly changed
    				// so *some* aspect of this block is now provided
    				mValidated = false;
    				mParamProvided = true;
    			}
    		}
    
    		bool deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack_range, bool new_name);
    
    		bool serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t rule, 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(); }
    
    
    		// take all provided params from other and apply to self
    		bool overwriteFrom(const BaseBlock& other)
    		{
    			return false;
    		}
    
    		// take all provided params that are not already provided, and apply to self
    		bool fillFrom(const BaseBlock& other)
    		{
    			return false;
    		}
    
    
    		static void addParam(BlockDescriptor& block_data, ParamDescriptorPtr param, const char* name);
    
    		ParamDescriptorPtr findParamDescriptor(const Param& param);
    
    
    	protected:
    		void init(BlockDescriptor& descriptor, BlockDescriptor& base_descriptor, size_t block_size);
    
    
    
    Richard Nelson's avatar
    Richard Nelson committed
    		bool mergeBlockParam(bool source_provided, bool dst_provided, BlockDescriptor& block_data, const BaseBlock& source, bool overwrite)
    
    Richard Nelson's avatar
    Richard Nelson committed
    			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;
    		}
    
    		mutable bool 	mValidated; // lazy validation flag
    		bool			mParamProvided;
    
    
    	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(); }
    	};
    
    
    Richard Linden's avatar
    Richard Linden committed
    	class LL_COMMON_API Param
    
    	{
    	public:
    		void setProvided(bool is_provided = true)
    		{
    			mIsProvided = is_provided;
    			enclosingBlock().paramChanged(*this, is_provided);
    		}
    
    			mIsProvided = other.mIsProvided;
    			// don't change mEnclosingblockoffset
    
    	protected:
    
    		bool anyProvided() const { return mIsProvided; }
    
    		Param(BaseBlock* enclosing_block);
    
    		// store pointer to enclosing block as offset to reduce space and allow for quick copying
    		BaseBlock& enclosingBlock() const
    		{ 
    			const U8* my_addr = reinterpret_cast<const U8*>(this);
    			// 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:
    
    Richard Linden's avatar
    Richard Linden committed
    		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>
    
    	{
    		static const bool value = false;
    
    		struct EmptyBase {};
    		typedef EmptyBase base_class_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 ParamValue<T, NAME_VALUE_LOOKUP, VALUE_IS_BLOCK>	self_t;
    
    Richard Nelson's avatar
    Richard Nelson committed
    		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;
    		}
    
    
    Richard Nelson's avatar
    Richard Nelson committed
    		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;
    		}
    
    
    		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 ParamValue<T, NAME_VALUE_LOOKUP, true>	self_t;
    
    Richard Nelson's avatar
    Richard Nelson committed
    		ParamValue(value_assignment_t other)
    
    
    		void setValue(value_assignment_t val)
    		{
    			*this = val;
    		}
    
    		value_assignment_t getValue() const
    		{
    			return *this;
    		}
    
    		T& getValue()
    		{
    			return *this;
    		}
    
    Richard Nelson's avatar
    Richard Nelson committed
    
    		operator value_assignment_t() const
    		{
    			return *this;
    		}
    		
    		value_assignment_t operator()() const
    		{
    			return *this;
    		}
    
    Richard Nelson's avatar
    Richard Nelson committed
    
    
    		void operator ()(const typename NAME_VALUE_LOOKUP::name_t& name)
    		{
    			*this = name;
    		}
    
    Richard Nelson's avatar
    Richard Nelson committed
    
    
    		self_t& operator =(const typename NAME_VALUE_LOOKUP::name_t& name)
    		{
    
    Richard Linden's avatar
    Richard Linden committed
    			if (NAME_VALUE_LOOKUP::getValueFromName(name, *this))
    
    	template<typename NAME_VALUE_LOOKUP>
    	class ParamValue<std::string, NAME_VALUE_LOOKUP, false>
    	: public NAME_VALUE_LOOKUP
    	{
    	public:
    		typedef const std::string&	value_assignment_t;
    
    		typedef 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;
    		}
    
    		operator value_assignment_t() const
    		{
    			return mValue;
    		}
    
    		value_assignment_t operator()() const
    		{
    			return mValue;
    		}
    
    	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;
    	};
    
    
    	// specialize for custom parsing/decomposition of specific classes
    	// e.g. TypedParam<LLRect> has left, top, right, bottom, etc...
    	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>
    
    	:	public Param, 
    		public ParamValue<T, NAME_VALUE_LOOKUP>
    
    	{
    	public:
    		typedef	TypedParam<T, NAME_VALUE_LOOKUP, HAS_MULTIPLE_VALUES, VALUE_IS_BLOCK>		self_t;
    
    Leslie Linden's avatar
    Leslie Linden committed
    		typedef ParamValue<T, NAME_VALUE_LOOKUP>											param_value_t;
    
    Richard Linden's avatar
    Richard Linden committed
    		typedef typename param_value_t::value_assignment_t				value_assignment_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) 
    		:	Param(block_descriptor.mCurrentBlockPtr)
    		{
    
    			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,
    
    				BaseBlock::addParam(block_descriptor, param_descriptor, name);
    			}
    
    
    		bool isProvided() const { return Param::anyProvided(); }
    
    		bool isValid() const { return true; }
    
    
    		static bool deserializeParam(Param& param, Parser& parser, const 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
    
    			if (name_stack_range.first == name_stack_range.second)
    
    				if (parser.readValue(typed_param.getValue()))
    
    					typed_param.setProvided();
    
    				if(name_value_lookup_t::valueNamesExist())
    
    				{
    					// try to parse a known named value
    					std::string name;
    
    					if (parser.readValue(name))
    
    						if (name_value_lookup_t::getValueFromName(name, typed_param.getValue()))
    
    							typed_param.setProvided();
    
    		static bool serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const Param* diff_param)
    
    			bool serialized = false;
    
    			const self_t& typed_param = static_cast<const self_t&>(param);
    
    			const self_t* diff_typed_param = static_cast<const self_t*>(diff_param);
    
    			LLPredicate::Value<ESerializePredicates> predicate;
    
    			if (diff_typed_param && ParamCompare<T>::equals(typed_param.getValue(), diff_typed_param->getValue()))
    			{
    				predicate.set(HAS_DEFAULT_VALUE);
    			}
    
    
    			if (typed_param.isValid())
    
    				predicate.set(VALID, true);
    				predicate.set(PROVIDED, typed_param.anyProvided());
    
    				predicate.set(VALID, false);
    				predicate.set(PROVIDED, false);
    
    			predicate.set(EMPTY, false);
    
    
    			if (!predicate_rule.check(predicate)) return false;
    
    				name_stack.back().second = true;
    
    			std::string key = typed_param.getValueName();
    
    
    			// first try to write out name of name/value pair
    
    			if (!key.empty())
    			{
    
    				if (!diff_typed_param || !ParamCompare<std::string>::equals(diff_typed_param->getValueName(), key))
    
    					serialized = parser.writeValue(key, name_stack);
    
    			else if (!diff_typed_param || ParamCompare<T>::equals(typed_param.getValue(), diff_typed_param->getValue()))
    
    				serialized = parser.writeValue(typed_param.getValue(), name_stack);
    				if (!serialized) 
    
    					std::string calculated_key = typed_param.calcValueName(typed_param.getValue());
    
    					if (!diff_typed_param || !ParamCompare<std::string>::equals(diff_typed_param->getValueName(), calculated_key))
    
    						serialized = parser.writeValue(calculated_key, name_stack);
    
    		}
    
    		static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count)
    		{
    			// 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())
    
    				parser.inspectValue<std::string>(name_stack, min_count, max_count, name_value_lookup_t::getPossibleValues());
    
    			}
    		}
    
    		void set(value_assignment_t val, bool flag_as_provided = true)
    		{
    
    Leslie Linden's avatar
    Leslie Linden committed
    			param_value_t::clearValueName();
    
    		self_t& operator =(const typename NAME_VALUE_LOOKUP::name_t& name)
    		{
    			return static_cast<self_t&>(param_value_t::operator =(name));
    		}
    
    
    	protected:
    
    		self_t& operator =(const self_t& other)
    
    			param_value_t::operator =(other);
    			Param::operator =(other);