Skip to content
Snippets Groups Projects
llinitparam.h 67.9 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>
    
    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
    	{
    
    Richard Linden's avatar
    Richard Linden committed
    		typedef typename ITEM::template Cons<REST>::value_t value_t;
    
    	};
    
    	template<typename ITEM, typename REST>
    	struct Swap<ITEM, REST, true>
    	{
    
    Richard Linden's avatar
    Richard Linden committed
    		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
    	{
    
    Richard Linden's avatar
    Richard Linden committed
    		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;
    	};
    }
    
    
    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 Linden's avatar
    Richard Linden committed
    	// wraps comparison operator between any 2 values of the same type
    	// specialize to handle cases where equality isn't defined well, or at all
    
    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;
    
    Richard Linden's avatar
    Richard Linden committed
    	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;
    	};
    
    
    Richard Linden's avatar
    Richard Linden committed
    	// 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
    
    Richard Linden's avatar
    Richard Linden committed
    	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> 
    
    Richard Linden's avatar
    Richard Linden committed
    	{
    		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
    
    	:	public ParamValue<typename LLTypeTags::Sorted<T>::value_t>
    
    	private:
    		struct Inaccessable{};
    
    		typedef std::map<std::string, T> value_name_map_t;
    
    		typedef Inaccessable name_t;
    
    Richard Linden's avatar
    Richard Linden committed
    		typedef TypeValues<T> type_value_t;
    
    Richard Linden's avatar
    Richard Linden committed
    		typedef ParamValue<typename LLTypeTags::Sorted<T>::value_t>	param_value_t;
    
    		typedef typename param_value_t::value_t	value_t;
    
    Richard Linden's avatar
    Richard Linden committed
    
    
    		TypeValues(const typename param_value_t::value_t& val)
    		:	param_value_t(val)
    
    Richard Linden's avatar
    Richard Linden committed
    		{}
    
    
    		void setValueName(const std::string& key) {}
    		std::string getValueName() const { return ""; }
    
    Richard Linden's avatar
    Richard Linden committed
    		std::string calcValueName(const value_t& value) const { return ""; }
    
    Richard Linden's avatar
    Richard Linden committed
    		static bool getValueFromName(const std::string& name, value_t& value)
    
    		static std::vector<std::string>* getPossibleValues()
    
    Richard Linden's avatar
    Richard Linden committed
    		void assignNamedValue(const Inaccessable& name)
    		{}
    
    		operator const value_t&() const
    		{
    
    			return param_value_t::getValue();
    
    Richard Linden's avatar
    Richard Linden committed
    		}
    
    		const value_t& operator()() const
    		{
    
    			return param_value_t::getValue();
    
    Richard Linden's avatar
    Richard Linden committed
    		}
    
    
    		static value_name_map_t* getValueNames() {return NULL;}
    
    Richard Linden's avatar
    Richard Linden committed
    	// helper class to implement name value lookups
    	// and caching of last used name
    
    Richard Linden's avatar
    Richard Linden committed
    	template <typename T, typename DERIVED_TYPE = TypeValues<T>, bool IS_SPECIALIZED = true >
    
    	:	public ParamValue<typename LLTypeTags::Sorted<T>::value_t>
    
    Richard Linden's avatar
    Richard Linden committed
    		typedef TypeValuesHelper<T, DERIVED_TYPE, IS_SPECIALIZED> self_t;
    
    Leslie Linden's avatar
    Leslie Linden committed
    		typedef typename std::map<std::string, T> value_name_map_t;
    
    		typedef std::string name_t;
    
    Richard Linden's avatar
    Richard Linden committed
    		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;
    
    Richard Linden's avatar
    Richard Linden committed
    
    
    		TypeValuesHelper(const typename param_value_t::value_t& val)
    		:	param_value_t(val)
    
    Richard Linden's avatar
    Richard Linden committed
    		{}
    
    
    		//TODO: cache key by index to save on param block size
    
    		void setValueName(const std::string& value_name) 
    
    		std::string getValueName() const
    		{ 
    			return mValueName; 
    		}
    
    Richard Linden's avatar
    Richard Linden committed
    		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();
    
    				it != end_it;
    				++it)
    			{
    				if (ParamCompare<T>::equals(it->second, value))
    				{
    					return it->first;
    				}
    			}
    
    			return "";
    		}
    
    
    Richard Linden's avatar
    Richard Linden committed
    		static bool getValueFromName(const std::string& name, value_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;
    		}
    
    Richard Linden's avatar
    Richard Linden committed
    		static void declare(const std::string& name, const value_t& value)
    
    Richard Linden's avatar
    Richard Linden committed
    		void operator ()(const std::string& name)
    		{
    			*this = name;
    		}
    
    		void assignNamedValue(const std::string& name)
    		{
    
    			if (getValueFromName(name, param_value_t::getValue()))
    
    Richard Linden's avatar
    Richard Linden committed
    			{
    				setValueName(name);
    			}
    		}
    
    		operator const value_t&() const
    		{
    
    			return param_value_t::getValue();
    
    Richard Linden's avatar
    Richard Linden committed
    		}
    
    		const value_t& operator()() const
    		{
    
    			return param_value_t::getValue();
    
    Richard Linden's avatar
    Richard Linden committed
    		}
    
    
    Richard Linden's avatar
    Richard Linden committed
    		static void getName(const std::string& name, const value_t& value)
    
    Richard Linden's avatar
    Richard Linden committed
    	// 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
    
    Richard Linden's avatar
    Richard Linden committed
    	template <typename DERIVED_TYPE>
    	class TypeValuesHelper<std::string, DERIVED_TYPE, true>
    	:	public TypeValuesHelper<std::string, DERIVED_TYPE, false>
    	{
    	public:
    
    Richard Linden's avatar
    Richard Linden committed
    		typedef TypeValuesHelper<std::string, DERIVED_TYPE, true> self_t;
    
    		typedef TypeValuesHelper<std::string, DERIVED_TYPE, false> base_t;
    
    Richard Linden's avatar
    Richard Linden committed
    		typedef std::string value_t;
    		typedef std::string name_t;
    		typedef self_t type_value_t;
    
    
    Richard Linden's avatar
    Richard Linden committed
    		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()))
    
    Richard Linden's avatar
    Richard Linden committed
    			{
    
    				base_t::setValueName(name);
    
    Richard Linden's avatar
    Richard Linden committed
    			}
    			else
    			{
    
    				ParamValue<std::string>::setValue(name);
    
    Richard Linden's avatar
    Richard Linden committed
    			}
    			return *this;
    		}
    		
    		operator const value_t&() const
    		{
    
    			return ParamValue<std::string>::getValue();
    
    Richard Linden's avatar
    Richard Linden committed
    		}
    
    		const value_t& operator()() const
    		{
    
    			return ParamValue<std::string>::getValue();
    
    Richard Linden's avatar
    Richard Linden committed
    	// parser base class with mechanisms for registering readers/writers/inspectors of different types
    
    	class Parser
    	{
    		LOG_CLASS(Parser);
    
    	public:
    		
    		struct CompareTypeID
    		{
    			bool operator()(const std::type_info* lhs, const std::type_info* rhs) const
    			{
    				return lhs->before(*rhs);
    			}
    		};
    
    
    		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, CompareTypeID>		parser_read_func_map_t;
    		typedef std::map<const std::type_info*, parser_write_func_t, CompareTypeID>		parser_write_func_map_t;
    		typedef std::map<const std::type_info*, parser_inspect_func_t, CompareTypeID>	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;
    
    
    	// various callbacks and constraints associated with an individual param
    	struct 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 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*);
    
    		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 boost::shared_ptr<ParamDescriptor> ParamDescriptorPtr;
    
    
    	// each derived Block class keeps a static data structure maintaining offsets to various params
    	class BlockDescriptor
    	{
    	public:
    
    
    		typedef enum e_initialization_state
    		{
    			UNINITIALIZED,
    			INITIALIZING,
    			INITIALIZED
    		} 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; 
    
    		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
    	//TODO: implement in terms of owned_ptr
    	template<typename T>
    	class LazyValue
    
    Richard Linden's avatar
    Richard Linden committed
    		LazyValue()
    
    Richard Linden's avatar
    Richard Linden committed
    		~LazyValue()
    		{
    			delete mPtr;
    		}
    
    Richard Linden's avatar
    Richard Linden committed
    		LazyValue(const T& value)
    
    Richard Linden's avatar
    Richard Linden committed
    			mPtr = new T(value);
    		}
    
    Richard Linden's avatar
    Richard Linden committed
    		LazyValue(const LazyValue& other)
    
    Richard Linden's avatar
    Richard Linden committed
    		LazyValue& operator = (const LazyValue& other)
    		{
    
    Richard Linden's avatar
    Richard Linden committed
    			else
    
    				if (!mPtr)
    				{
    					mPtr = new T(*other.mPtr);
    				}
    				else
    				{
    					*mPtr = *(other.mPtr);
    				}
    
    Richard Linden's avatar
    Richard Linden committed
    			return *this;
    		}
    
    Richard Linden's avatar
    Richard Linden committed
    		bool operator==(const LazyValue& other) const
    		{
    			if (empty() || other.empty()) return false;
    			return *mPtr == *other.mPtr;
    		}
    
    Richard Linden's avatar
    Richard Linden committed
    		bool empty() const
    		{
    			return mPtr == NULL;
    		}
    
    Richard Linden's avatar
    Richard Linden committed
    		void set(const T& other)
    		{
    
    Richard Linden's avatar
    Richard Linden committed
    		const T& get() const
    		{
    			return *ensureInstance();
    		}
    
    Richard Linden's avatar
    Richard Linden committed
    		T& get()
    		{
    			return *ensureInstance();
    		}
    
    Richard Linden's avatar
    Richard Linden committed
    		operator const T&() const
    		{ 
    			return get(); 
    		}
    
    Richard Linden's avatar
    Richard Linden committed
    	private: 
    		// lazily allocate an instance of T
    		T* ensureInstance() const
    		{
    			if (mPtr == NULL)
    
    Richard Linden's avatar
    Richard Linden committed
    				mPtr = new T();
    
    Richard Linden's avatar
    Richard Linden committed
    			return mPtr;
    		}
    
    Richard Linden's avatar
    Richard Linden committed
    	private:
    
    Richard Linden's avatar
    Richard Linden committed
    		mutable T* mPtr;
    	};
    
    
    Richard Linden's avatar
    Richard Linden committed
    	// root class of all parameter blocks
    
    
    Richard Linden's avatar
    Richard Linden committed
    	class BaseBlock
    	{
    	public:
    		// lift block tags into baseblock namespace so derived classes do not need to qualify them
    
    Richard Linden's avatar
    Richard Linden committed
    		typedef LLInitParam::IS_A_BLOCK IS_A_BLOCK;
    		typedef LLInitParam::NOT_BLOCK NOT_A_BLOCK;
    
    Richard Linden's avatar
    Richard Linden committed
    
    		template<typename T>
    
    		struct Atomic : public LLTypeTags::TypeTagBase<T, 1>
    		{
    			template <typename S> struct Cons { typedef Atomic<ParamValue<S> > value_t; };
    
    Richard Linden's avatar
    Richard Linden committed
    			template <typename S> struct Cons<Atomic<S> > { typedef Atomic<S> value_t; };
    
    Richard Linden's avatar
    Richard Linden committed
    
    		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;
    			};
    
    Richard Linden's avatar
    Richard Linden committed
    			template <typename S> struct Cons<Lazy<S, IS_A_BLOCK> >
    
    Richard Linden's avatar
    Richard Linden committed
    				typedef Lazy<S, IS_A_BLOCK> value_t;
    
    Richard Linden's avatar
    Richard Linden committed
    			template <typename S> struct Cons<Lazy<S, NOT_A_BLOCK> >
    
    Richard Linden's avatar
    Richard Linden committed
    				typedef Lazy<S, BLOCK_T> value_t;
    
    		// "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;
    
    
    		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;
    
    
    		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) {}
    
    		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 getBlockDescriptor(); }
    		virtual BlockDescriptor& mostDerivedBlockDescriptor() { return getBlockDescriptor(); }
    
    
    		// 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;
    		}
    
    
    		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);
    
    
    
    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);
    
    
    	private:
    		const std::string& getParamName(const BlockDescriptor& block_data, const Param* paramp) const;
    	};
    
    
    	{
    	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;
    
    	};
    
    Richard Linden's avatar
    Richard Linden committed
    	
    
    	template<typename T, typename NAME_VALUE_LOOKUP = TypeValues<T> >
    	struct ParamIterator
    	{
    
    Richard Linden's avatar
    Richard Linden committed
    		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;
    
    Richard Linden's avatar
    Richard Linden committed
    	// 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,
    
    			typename	VALUE_IS_BLOCK = typename IsBlock<ParamValue<typename LLTypeTags::Sorted<T>::value_t> >::value_t>
    
    Richard Linden's avatar
    Richard Linden committed
    		public NAME_VALUE_LOOKUP::type_value_t
    
    Richard Linden's avatar
    Richard Linden committed
    	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;
    
    Richard Linden's avatar
    Richard Linden committed
    		typedef typename NAME_VALUE_LOOKUP::type_value_t								named_value_t;
    
    Richard Linden's avatar
    Richard Linden committed
    	public:
    
    Richard Linden's avatar
    Richard Linden committed
    		typedef typename param_value_t::value_t											value_t;
    
    
    Richard Linden's avatar
    Richard Linden committed
    		using named_value_t::operator();
    
    		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),
    
    Richard Linden's avatar
    Richard Linden committed
    			named_value_t(value)
    
    			if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING))
    
    				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)
    
    		{ 
    			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();
    
    Richard Linden's avatar
    Richard Linden committed
    				if(named_value_t::valueNamesExist())
    
    				{
    					// try to parse a known named value
    					std::string name;
    
    					if (parser.readValue(name))
    
    Richard Linden's avatar
    Richard Linden committed
    						if (named_value_t::getValueFromName(name, typed_param.getValue()))
    
    							typed_param.setProvided();
    
    							return true;
    						}
    
    					}
    				}
    			}
    			return false;
    		}
    
    		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()) return;
    
    			if (!name_stack.empty())
    			{
    
    				name_stack.back().second = true;