Skip to content
Snippets Groups Projects
llinitparam.h 76.7 KiB
Newer Older
Richard Linden's avatar
Richard Linden committed
	template <typename DERIVED_BLOCK, typename BASE_BLOCK = BaseBlock>
		typedef Block<DERIVED_BLOCK, BASE_BLOCK>	self_t;
Richard Linden's avatar
Richard Linden committed

	protected:
		typedef Block<DERIVED_BLOCK, BASE_BLOCK>	block_t;

	public:
		typedef BASE_BLOCK base_block_t;

		// take all provided params from other and apply to self
		bool overwriteFrom(const self_t& other)
		{
			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(getBlockDescriptor(), other, false);
		virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return getBlockDescriptor(); }
		virtual BlockDescriptor& mostDerivedBlockDescriptor() { return getBlockDescriptor(); }
	protected:
		Block()
		{
			//#pragma message("Parsing LLInitParam::Block")
			BaseBlock::init(getBlockDescriptor(), BASE_BLOCK::getBlockDescriptor(), sizeof(DERIVED_BLOCK));
		template <typename T, typename NAME_VALUE_LOOKUP = typename TypeValues<T>::type_value_t >
		class Optional : public TypedParam<T, NAME_VALUE_LOOKUP, false>
		{
			typedef TypedParam<T, NAME_VALUE_LOOKUP, false>		super_t;
Richard Linden's avatar
Richard Linden committed
			typedef typename super_t::value_t					value_t;
			typedef typename super_t::default_value_t			default_value_t;
Richard Linden's avatar
Richard Linden committed
		public:
			using super_t::operator();
			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")
			}

Richard Linden's avatar
Richard Linden committed
			Optional& operator =(const value_t& val)
Richard Linden's avatar
Richard Linden committed
			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 = typename TypeValues<T>::type_value_t >
		class Mandatory : public TypedParam<T, NAME_VALUE_LOOKUP, false>
		{
			typedef TypedParam<T, NAME_VALUE_LOOKUP, false>		super_t;
Richard Linden's avatar
Richard Linden committed
			typedef typename super_t::value_t					value_t;
			typedef typename super_t::default_value_t			default_value_t;
Richard Linden's avatar
Richard Linden committed
		public:
			using super_t::operator();
			// mandatory parameters require a name to be parseable
			explicit Mandatory(const char* name = "", const default_value_t& val = defaultValue<default_value_t>())
			:	super_t(DERIVED_BLOCK::getBlockDescriptor(), name, val, &validate, 1, 1)
Richard Linden's avatar
Richard Linden committed
			Mandatory& operator =(const value_t& val)
Richard Linden's avatar
Richard Linden committed
			DERIVED_BLOCK& operator()(const value_t& val)
			{
				super_t::set(val);
				return static_cast<DERIVED_BLOCK&>(Param::enclosingBlock());
			}

			static bool validate(const Param* p)
			{
				// valid only if provided
				return static_cast<const self_t*>(p)->isProvided();
			}

		};

		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>
		{
			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;
Richard Linden's avatar
Richard Linden committed
			typedef typename super_t::value_t				value_t;

		public:
			typedef typename super_t::iterator										iterator;
			typedef typename super_t::const_iterator								const_iterator;
			using super_t::operator();
			using super_t::operator const container_t&;

			:	super_t(DERIVED_BLOCK::getBlockDescriptor(), name, container_t(), &validate, RANGE::minCount, RANGE::maxCount)
Richard Linden's avatar
Richard Linden committed
			Multiple& operator =(const container_t& val)
Richard Linden's avatar
Richard Linden committed
			DERIVED_BLOCK& operator()(const container_t& val)
			{
				super_t::set(val);
				return static_cast<DERIVED_BLOCK&>(Param::enclosingBlock());
			}

			static bool validate(const Param* paramp) 
			{
				size_t num_valid = ((super_t*)paramp)->numValidElements();
Richard Nelson's avatar
Richard Nelson committed
				return RANGE::minCount <= num_valid && num_valid <= RANGE::maxCount;
		// can appear in data files, but will ignored during parsing
		// cannot read or write in code
		class Ignored : public Param
			explicit Ignored(const char* name)
			:	Param(DERIVED_BLOCK::getBlockDescriptor().mCurrentBlockPtr)
				BlockDescriptor& block_descriptor = DERIVED_BLOCK::getBlockDescriptor();
				if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING))
					ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor(
													block_descriptor.mCurrentBlockPtr->getHandleFromParam(this),
					block_descriptor.addParam(param_descriptor, 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)
				{
					//std::string message = llformat("Deprecated value %s ignored", getName().c_str());
					//parser.parserWarning(message);
					return true;
				}

				return false;
			}
		};

		// 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) {}

			// 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, typename is_block>
		void changeDefault(TypedParam<T, NAME_VALUE_LOOKUP, multiple, is_block>& param, 
Richard Linden's avatar
Richard Linden committed
			const typename TypedParam<T, NAME_VALUE_LOOKUP, multiple, is_block>::value_t& value)
		{
			if (!param.isProvided())
			{
				param.set(value, false);
			}
		}

	template<typename T, typename BLOCK_T>
Richard Linden's avatar
Richard Linden committed
	struct IsBlock<ParamValue<BaseBlock::Lazy<T, BaseBlock::IS_A_BLOCK>, BLOCK_T >, void>
Richard Nelson's avatar
Richard Nelson committed
	{
Richard Linden's avatar
Richard Linden committed
		typedef IS_A_BLOCK value_t;
	template<typename T, typename BLOCK_T>
Richard Linden's avatar
Richard Linden committed
	struct IsBlock<ParamValue<BaseBlock::Lazy<T, BaseBlock::NOT_A_BLOCK>, BLOCK_T >, void>
	template<typename T, typename BLOCK_IDENTIFIER>
Richard Linden's avatar
Richard Linden committed
	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>
Richard Linden's avatar
Richard Linden committed
	class ParamValue <BaseBlock::Atomic<T>, BLOCK_T>
Richard Nelson's avatar
Richard Nelson committed
	{
Richard Linden's avatar
Richard Linden committed
		typedef ParamValue <BaseBlock::Atomic<T>, BLOCK_T> self_t;
Richard Nelson's avatar
Richard Nelson committed
	public:
		typedef typename InnerMostType<T>::value_t	value_t;
		typedef T									default_value_t;
Richard Nelson's avatar
Richard Nelson committed

		ParamValue()
		:	mValue()
		ParamValue(const default_value_t& value)
		:	mValue(value)
Richard Linden's avatar
Richard Linden committed
		void setValue(const value_t& val)
Richard Nelson's avatar
Richard Nelson committed
		{
Richard Nelson's avatar
Richard Nelson committed
		{
Richard Nelson's avatar
Richard Nelson committed
		{
		bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name)
Richard Nelson's avatar
Richard Nelson committed
		{
Richard Nelson's avatar
Richard Nelson committed
			{
Richard Linden's avatar
Richard Linden committed
				resetToDefault();
Richard Nelson's avatar
Richard Nelson committed
			}
			return mValue.deserializeBlock(p, name_stack_range, new_name);
		bool serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const self_t* diff_block = NULL) const
		{
			const BaseBlock* base_block = diff_block
				? &(diff_block->mValue)
				: NULL;
			return mValue.serializeBlock(p, name_stack, predicate_rule, 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)
Richard Nelson's avatar
Richard Nelson committed
		{
			if ((overwrite && source_provided) // new values coming in on top or...
				|| (!overwrite && !dst_provided)) // values being pushed under with nothing already there
Richard Nelson's avatar
Richard Nelson committed
			{
				// clear away what is there and take the new stuff as a whole
Richard Linden's avatar
Richard Linden committed
				resetToDefault();
				return mValue.mergeBlock(block_data, source.getValue(), overwrite);
Richard Nelson's avatar
Richard Nelson committed
			}
			return mValue.mergeBlock(block_data, source.getValue(), overwrite);
Richard Nelson's avatar
Richard Nelson committed
		}

		bool validateBlock(bool emit_errors = true) const
		{
			return mValue.validateBlock(emit_errors);
		}

		bool isValid() const
		{
			return validateBlock(false);
		}

		static BlockDescriptor& getBlockDescriptor()
		{
			return value_t::getBlockDescriptor();
Richard Linden's avatar
Richard Linden committed
		void resetToDefault()
Richard Nelson's avatar
Richard Nelson committed
		{
			static T default_value;
Richard Linden's avatar
Richard Linden committed
			mValue = default_value;
Richard Nelson's avatar
Richard Nelson committed
		}
	template<typename T>
	class ParamValue <BaseBlock::Sequential<T>, IS_A_BLOCK>
Richard Nelson's avatar
Richard Nelson committed
	{
		typedef ParamValue <BaseBlock::Sequential<T>, IS_A_BLOCK> self_t;

		typedef typename InnerMostType<T>::value_t	value_t;
		typedef T									default_value_t;
Richard Nelson's avatar
Richard Nelson committed

		ParamValue()
		:	mValue()
		{
			mCurParam = getBlockDescriptor().mAllParams.begin();
		}
		ParamValue(const default_value_t& value)
		:	mValue(value)
Richard Nelson's avatar
Richard Nelson committed
		{
			mCurParam = getBlockDescriptor().mAllParams.begin();
Richard Nelson's avatar
Richard Nelson committed
		{
Richard Nelson's avatar
Richard Nelson committed
		{
Richard Nelson's avatar
Richard Nelson committed
		{
		bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name)
Richard Nelson's avatar
Richard Nelson committed
		{
			if (new_name)
			{
				mCurParam = getBlockDescriptor().mAllParams.begin();
			if (name_stack_range.first == name_stack_range.second 
				&& mCurParam != getBlockDescriptor().mAllParams.end())
			{
				// deserialize to mCurParam
Richard Linden's avatar
Richard Linden committed
				ParamDescriptor& pd = *(*mCurParam);
				ParamDescriptor::deserialize_func_t deserialize_func = pd.mDeserializeFunc;
Richard Linden's avatar
Richard Linden committed
				Param* paramp = mValue.getParamFromHandle(pd.mParamHandle);
Richard Linden's avatar
Richard Linden committed
					&& deserialize_func(*paramp, p, name_stack_range, new_name))
			else
			{
				return mValue.deserializeBlock(p, name_stack_range, new_name);
			}
		bool serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const self_t* diff_block = NULL) const
Richard Nelson's avatar
Richard Nelson committed
		{
			const BaseBlock* base_block = diff_block
				? &(diff_block->mValue)
				: NULL;
			return mValue.serializeBlock(p, name_stack, predicate_rule, 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);
		}

		bool isValid() const
		{
			return validateBlock(false);
		}

		static BlockDescriptor& getBlockDescriptor()
		{
			return value_t::getBlockDescriptor();
		}

	private:

		BlockDescriptor::all_params_list_t::iterator	mCurParam;
		T												mValue;
	};

	template<typename T>
	class ParamValue <BaseBlock::Sequential<T>, NOT_BLOCK>
	: public T
	{
		typedef ParamValue <BaseBlock::Sequential<T>, NOT_BLOCK> self_t;

	public:
		typedef typename InnerMostType<T>::value_t	value_t;
		typedef T									default_value_t;

		ParamValue()
		:	T()
		ParamValue(const default_value_t& value)
		:	T(value.getValue())
		bool isValid() const { return true; }
	template<typename T, typename BLOCK_T>
Richard Linden's avatar
Richard Linden committed
	class ParamValue <BaseBlock::Lazy<T, IS_A_BLOCK>, BLOCK_T> 
Richard Linden's avatar
Richard Linden committed
		typedef ParamValue <BaseBlock::Lazy<T, IS_A_BLOCK>, BLOCK_T> self_t;
		typedef typename InnerMostType<T>::value_t	value_t;
		typedef LazyValue<T>						default_value_t;
		ParamValue(const default_value_t& other)
		:	mValue(value)
Richard Linden's avatar
Richard Linden committed
		void setValue(const value_t& val)
Richard Linden's avatar
Richard Linden committed
		const value_t& getValue() const
		bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name)
		{
			return mValue.get().deserializeBlock(p, name_stack_range, new_name);
		}

		bool serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const self_t* diff_block = NULL) const
			if (mValue.empty()) return false;
			const BaseBlock* base_block = (diff_block && !diff_block->mValue.empty())
											? &(diff_block->mValue.get().getValue())
			return mValue.get().serializeBlock(p, name_stack, predicate_rule, 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.get().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 source.mValue.empty() || mValue.get().mergeBlock(block_data, source.getValue(), overwrite);
		bool validateBlock(bool emit_errors = true) const
		{
			return mValue.empty() || mValue.get().validateBlock(emit_errors);
		bool isValid() const
		{
			return validateBlock(false);
		}

		static BlockDescriptor& getBlockDescriptor()
		{
			return value_t::getBlockDescriptor();
Richard Linden's avatar
Richard Linden committed
		LazyValue<T>	mValue;
	template<typename T, typename BLOCK_T>
Richard Linden's avatar
Richard Linden committed
	class ParamValue <BaseBlock::Lazy<T, NOT_BLOCK>, BLOCK_T>
Richard Linden's avatar
Richard Linden committed
		typedef ParamValue <BaseBlock::Lazy<T, NOT_BLOCK>, BLOCK_T> self_t;
		typedef typename InnerMostType<T>::value_t	value_t;
		typedef LazyValue<T>						default_value_t;
		:	mValue()
		{}

		ParamValue(const default_value_t& other)
		:	mValue(other)
		:	mValue(value)
Richard Linden's avatar
Richard Linden committed
		void setValue(const value_t& val)
Richard Linden's avatar
Richard Linden committed
		const value_t& getValue() const
Richard Nelson's avatar
Richard Nelson committed

		bool isValid() const
		{
			return true;
Richard Linden's avatar
Richard Linden committed
		LazyValue<T>	mValue;
Richard Linden's avatar
Richard Linden committed
	class ParamValue <LLSD, NOT_BLOCK>
	:	public BaseBlock
Richard Linden's avatar
Richard Linden committed
		typedef LLSD			value_t;
		typedef LLSD			default_value_t;
		ParamValue(const default_value_t& other)
Richard Linden's avatar
Richard Linden committed
		void setValue(const value_t& val) { mValue = val; }
Richard Linden's avatar
Richard Linden committed
		const value_t& getValue() const { return mValue; }
		LLSD& getValue() { 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 serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_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
		{
			//TODO: implement LLSD params as schema type Any
			return true;
		}

	private:
		static void serializeElement(Parser& p, const LLSD& sd, Parser::name_stack_t& name_stack);

		LLSD mValue;
	};

Richard Linden's avatar
Richard Linden committed
	:	public Block<ParamValue<T> >
			VALUE_NEEDS_UPDATE,		// mValue needs to be refreshed from the block parameters
			VALUE_AUTHORITATIVE,	// mValue holds the authoritative value (which has been replicated to the block parameters via updateBlockFromValue)
			BLOCK_AUTHORITATIVE		// mValue is derived from the block parameters, which are authoritative
		typedef TypeValues<T>			derived_t;
		typedef CustomParamValue<T>		self_t;
		typedef Block<ParamValue<T> >	block_t;
Richard Linden's avatar
Richard Linden committed
		typedef T						default_value_t;
		typedef T						value_t;
Richard Linden's avatar
Richard Linden committed
		typedef void					baseblock_base_class_t;
		CustomParamValue(const default_value_t& value = T())
			mValueAge(VALUE_AUTHORITATIVE)
		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
			if (name_stack_range.first == name_stack_range.second)
					typed_param.mValueAge = VALUE_AUTHORITATIVE;
					typed_param.updateBlockFromValue(false);

			return typed_param.BaseBlock::deserializeBlock(parser, name_stack_range, new_name);
		bool serializeBlock(Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const BaseBlock* diff_block = NULL) const
			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))
			//	{
			//		return parser.writeValue(key, name_stack);
			//	}
			//}
Richard Linden's avatar
Richard Linden committed
			if (!diff_param || !ParamCompare<T>::equals(typed_param.getValue(), diff_param->getValue()))
				if (parser.writeValue(typed_param.getValue(), name_stack)) 
				{
					return true;
				}
				else
					//RN: *always* serialize provided components of BlockValue (don't pass diff_param on),
					// since these tend to be viewed as the constructor arguments for the value T.  It seems
					// cleaner to treat the uniqueness of a BlockValue according to the generated value, and
					// not the individual components.  This way <color red="0" green="1" blue="0"/> will not
					// be exported as <color green="1"/>, since it was probably the intent of the user to 
					// be specific about the RGB color values.  This also fixes an issue where we distinguish
					// between rect.left not being provided and rect.left being explicitly set to 0 (same as default)
					if (typed_param.mValueAge == VALUE_AUTHORITATIVE)
					{
						// if the value is authoritative but the parser doesn't accept the value type
						// go ahead and make a copy, and splat the value out to its component params
						// and serialize those params
						derived_t copy(typed_param);
						copy.updateBlockFromValue(true);
						return copy.block_t::serializeBlock(parser, name_stack, predicate_rule, NULL);
						return block_t::serializeBlock(parser, name_stack, predicate_rule, NULL);
		bool validateBlock(bool emit_errors = true) const
				{
					// clear stale keyword associated with old value
					mValueAge = BLOCK_AUTHORITATIVE;
					static_cast<derived_t*>(const_cast<self_t*>(this))->updateValueFromBlock();
					return true;
				}
				else
				{
					//block value incomplete, so not considered provided
					// will attempt to revalidate on next call to isProvided()
					return false;  
				}
			}
			else
			{
				// we have a valid value in hand
				return true;
			}
		/*virtual*/ void paramChanged(const Param& changed_param, bool user_provided)
			BaseBlock::paramChanged(changed_param, user_provided);
				// a parameter changed, so our value is out of date
Richard Linden's avatar
Richard Linden committed
		void setValue(const value_t& val)
			// set param version number to be up to date, so we ignore block contents
			mValueAge = VALUE_AUTHORITATIVE;
			mValue = val;
			static_cast<derived_t*>(this)->updateBlockFromValue(false);
Richard Linden's avatar
Richard Linden committed
		const value_t& getValue() const
		// use this from within updateValueFromBlock() to set the value without making it authoritative
Richard Linden's avatar
Richard Linden committed
		void updateValue(const value_t& value)
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
			bool source_override = source_provided && (overwrite || !dst_provided);
Richard Nelson's avatar
Richard Nelson committed
			const derived_t& src_typed_param = static_cast<const derived_t&>(source);
Richard Nelson's avatar
Richard Nelson committed
			if (source_override && src_typed_param.mValueAge == VALUE_AUTHORITATIVE)
				// copy value over
				setValue(src_typed_param.getValue());
Richard Nelson's avatar
Richard Nelson committed
			// merge individual parameters into destination
			if (mValueAge == VALUE_AUTHORITATIVE)
Richard Nelson's avatar
Richard Nelson committed
				static_cast<derived_t*>(this)->updateBlockFromValue(dst_provided);
Richard Nelson's avatar
Richard Nelson committed
			return mergeBlock(block_data, source, overwrite);
		}

		bool mergeBlock(BlockDescriptor& block_data, const BaseBlock& source, bool overwrite)
		{
			return block_t::mergeBlock(block_data, source, overwrite);
	private:
		mutable T			mValue;
		mutable EValueAge	mValueAge;