From d6634fcd2433e18eea1a9bf31da6d7e531817d77 Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Mon, 22 Oct 2012 19:54:10 -0700
Subject: SH-3405 WIP convert existing stats to lltrace system sanitized param
 block code to accept isValid and isProvided at any point added predicates to
 control serialization

---
 indra/llcommon/CMakeLists.txt  |   2 +
 indra/llcommon/llinitparam.cpp |  35 +++++--
 indra/llcommon/llinitparam.h   | 221 ++++++++++++++++++++++++++---------------
 indra/llcommon/llpredicate.cpp |  33 ++++++
 indra/llcommon/llpredicate.h   | 173 ++++++++++++++++++++++++++++++++
 indra/llcommon/llsdparam.cpp   |   2 +-
 6 files changed, 376 insertions(+), 90 deletions(-)
 create mode 100644 indra/llcommon/llpredicate.cpp
 create mode 100644 indra/llcommon/llpredicate.h

(limited to 'indra')

diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index c0e9266aa9..d876842cf1 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -77,6 +77,7 @@ set(llcommon_SOURCE_FILES
     llmutex.cpp
     lloptioninterface.cpp
     llptrto.cpp 
+    llpredicate.cpp
     llprocess.cpp
     llprocessor.cpp
     llqueuedthread.cpp
@@ -205,6 +206,7 @@ set(llcommon_HEADER_FILES
     llnametable.h
     lloptioninterface.h
     llpointer.h
+    llpredicate.h
     llpreprocessor.h
     llpriqueuemap.h
     llprocess.h
diff --git a/indra/llcommon/llinitparam.cpp b/indra/llcommon/llinitparam.cpp
index 54e98e66f3..a63e792925 100644
--- a/indra/llcommon/llinitparam.cpp
+++ b/indra/llcommon/llinitparam.cpp
@@ -164,24 +164,37 @@ namespace LLInitParam
 
 	bool BaseBlock::validateBlock(bool emit_errors) const
 	{
-		const BlockDescriptor& block_data = mostDerivedBlockDescriptor();
-		for (BlockDescriptor::param_validation_list_t::const_iterator it = block_data.mValidationList.begin(); it != block_data.mValidationList.end(); ++it)
+		// only validate block when it hasn't already passed validation with current data
+		if (!mValidated)
 		{
-			const Param* param = getParamFromHandle(it->first);
-			if (!it->second(param))
+			const BlockDescriptor& block_data = mostDerivedBlockDescriptor();
+			for (BlockDescriptor::param_validation_list_t::const_iterator it = block_data.mValidationList.begin(); it != block_data.mValidationList.end(); ++it)
 			{
-				if (emit_errors)
+				const Param* param = getParamFromHandle(it->first);
+				if (!it->second(param))
 				{
-					llwarns << "Invalid param \"" << getParamName(block_data, param) << "\"" << llendl;
+					if (emit_errors)
+					{
+						llwarns << "Invalid param \"" << getParamName(block_data, param) << "\"" << llendl;
+					}
+					return false;
 				}
-				return false;
 			}
+			mValidated = true;
 		}
-		return true;
+		return mValidated;
 	}
 
-	void BaseBlock::serializeBlock(Parser& parser, Parser::name_stack_t& name_stack, const LLInitParam::BaseBlock* diff_block) const
+	void BaseBlock::serializeBlock(Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const LLInitParam::BaseBlock* diff_block) const
 	{
+		if (!isProvided())
+		{
+			if ((~predicate_rule_t(PROVIDED) && predicate_rule).isTriviallyFalse())
+			{
+				return;
+			}
+		}
+
 		// named param is one like LLView::Params::follows
 		// unnamed param is like LLView::Params::rect - implicit
 		const BlockDescriptor& block_data = mostDerivedBlockDescriptor();
@@ -196,7 +209,7 @@ namespace LLInitParam
 			if (serialize_func)
 			{
 				const Param* diff_param = diff_block ? diff_block->getParamFromHandle(param_handle) : NULL;
-				serialize_func(*param, parser, name_stack, diff_param);
+				serialize_func(*param, parser, name_stack, predicate_rule, diff_param);
 			}
 		}
 
@@ -232,7 +245,7 @@ namespace LLInitParam
 
 				name_stack.push_back(std::make_pair(it->first, !duplicate));
 				const Param* diff_param = diff_block ? diff_block->getParamFromHandle(param_handle) : NULL;
-				serialize_func(*param, parser, name_stack, diff_param);
+				serialize_func(*param, parser, name_stack, predicate_rule, diff_param);
 				name_stack.pop_back();
 			}
 		}
diff --git a/indra/llcommon/llinitparam.h b/indra/llcommon/llinitparam.h
index b7607e91b9..18c9669fba 100644
--- a/indra/llcommon/llinitparam.h
+++ b/indra/llcommon/llinitparam.h
@@ -32,10 +32,11 @@
 #include <boost/function.hpp>
 #include <boost/type_traits/is_convertible.hpp>
 #include <boost/unordered_map.hpp>
-#include <boost/shared_ptr.hpp>
+//#include <boost/shared_ptr.hpp>
 
 #include "llerror.h"
 #include "llstl.h"
+#include "llpredicate.h"
 
 namespace LLInitParam
 {
@@ -211,7 +212,6 @@ namespace LLInitParam
 		LOG_CLASS(Parser);
 
 	public:
-		
 		typedef std::vector<std::pair<std::string, bool> >					name_stack_t;
 		typedef std::pair<name_stack_t::iterator, name_stack_t::iterator>	name_stack_range_t;
 		typedef std::vector<std::string>									possible_values_t;
@@ -293,6 +293,17 @@ namespace LLInitParam
 
 	class Param;
 
+	enum ESerializePredicates
+	{
+		PROVIDED,
+		REQUIRED,
+		VALID,
+		NON_DEFAULT
+	};
+
+	typedef LLPredicate::Rule<ESerializePredicates> predicate_rule_t;
+
+
 	// various callbacks and constraints associated with an individual param
 	struct LL_COMMON_API ParamDescriptor
 	{
@@ -303,8 +314,8 @@ 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 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 void(*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, 
@@ -331,7 +342,7 @@ namespace LLInitParam
 		UserData*			mUserData;
 	};
 
-	typedef boost::shared_ptr<ParamDescriptor> ParamDescriptorPtr;
+	typedef ParamDescriptor* ParamDescriptorPtr;
 
 	// each derived Block class keeps a static data structure maintaining offsets to various params
 	class LL_COMMON_API BlockDescriptor
@@ -484,12 +495,28 @@ namespace LLInitParam
 		LOG_CLASS(BaseBlock);
 		friend class Param;
 
+		BaseBlock()
+		:	mValidated(false),
+			mParamProvided(false)
+		{}
+
 		virtual ~BaseBlock() {}
 		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;
@@ -507,10 +534,19 @@ namespace LLInitParam
 		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) {}
+		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);
-		void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block = NULL) const;
+		void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t rule = predicate_rule_t(), 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(); }
@@ -549,6 +585,9 @@ namespace LLInitParam
 			return sBlockDescriptor;
 		}
 
+		mutable bool 	mValidated; // lazy validation flag
+		bool			mParamProvided;
+
 	private:
 		const std::string& getParamName(const BlockDescriptor& block_data, const Param* paramp) const;
 	};
@@ -688,13 +727,11 @@ namespace LLInitParam
 		typedef ParamValue<T, NAME_VALUE_LOOKUP, true>	self_t;
 
 		ParamValue() 
-		:	T(),
-			mValidated(false)
+		:	T()
 		{}
 
 		ParamValue(value_assignment_t other)
-		:	T(other),
-			mValidated(false)
+		:	T(other)
 		{}
 
 		void setValue(value_assignment_t val)
@@ -736,9 +773,6 @@ namespace LLInitParam
 
 			return *this;
 		}
-
-	protected:
-		mutable bool 	mValidated; // lazy validation flag
 	};
 
 	template<typename NAME_VALUE_LOOKUP>
@@ -836,6 +870,8 @@ namespace LLInitParam
 
 		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);
@@ -870,10 +906,26 @@ namespace LLInitParam
 			return false;
 		}
 
-		static void serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const Param* diff_param)
+		static void serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const Param* diff_param)
 		{
 			const self_t& typed_param = static_cast<const self_t&>(param);
-			if (!typed_param.isProvided()) return;
+			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(NON_DEFAULT);
+			}
+			if (typed_param.isValid())
+			{
+				predicate.set(VALID);
+				if (typed_param.anyProvided())
+				{
+					predicate.set(PROVIDED);
+				}
+			}
+
+			if (!predicate_rule.check(predicate)) return;
 
 			if (!name_stack.empty())
 			{
@@ -886,18 +938,18 @@ namespace LLInitParam
 
 			if (!key.empty())
 			{
-				if (!diff_param || !ParamCompare<std::string>::equals(static_cast<const self_t*>(diff_param)->getValueName(), key))
+				if (!diff_typed_param || !ParamCompare<std::string>::equals(diff_typed_param->getValueName(), key))
 				{
 					parser.writeValue(key, name_stack);
 				}
 			}
 			// then try to serialize value directly
-			else if (!diff_param || !ParamCompare<T>::equals(typed_param.getValue(), static_cast<const self_t*>(diff_param)->getValue()))
+			else if (!diff_typed_param || ParamCompare<T>::equals(typed_param.getValue(), diff_typed_param->getValue()))
 			{
 				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 (!diff_typed_param || !ParamCompare<std::string>::equals(diff_typed_param->getValueName(), calculated_key))
 					{
 						parser.writeValue(calculated_key, name_stack);
 					}
@@ -1014,10 +1066,26 @@ namespace LLInitParam
 			return false;
 		}
 
-		static void serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const Param* diff_param)
+		static void serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const Param* diff_param)
 		{
 			const self_t& typed_param = static_cast<const self_t&>(param);
-			if (!typed_param.isProvided()) return;
+			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(NON_DEFAULT);
+			}
+			if (typed_param.isValid())
+			{
+				predicate.set(VALID);
+				if (typed_param.anyProvided())
+				{
+					predicate.set(PROVIDED);
+				}
+			}
+
+			if (!predicate_rule.check(predicate)) return;
 
 			if (!name_stack.empty())
 			{
@@ -1034,7 +1102,7 @@ namespace LLInitParam
 			}
 			else
 			{
-				typed_param.serializeBlock(parser, name_stack, static_cast<const self_t*>(diff_param));
+				typed_param.serializeBlock(parser, name_stack, predicate_rule, static_cast<const self_t*>(diff_param));
 			}
 		}
 
@@ -1049,23 +1117,16 @@ namespace LLInitParam
 		// *and* the block as a whole validates
 		bool isProvided() const 
 		{ 
-			// only validate block when it hasn't already passed validation with current data
-			if (Param::anyProvided() && !param_value_t::mValidated)
-			{
-				// a sub-block is "provided" when it has been filled in enough to be valid
-				param_value_t::mValidated = param_value_t::validateBlock(false);
-			}
-			return Param::anyProvided() && param_value_t::mValidated;
+			return Param::anyProvided() && isValid();
 		}
 
+		using param_value_t::isValid;
+
 		// assign block contents to this param-that-is-a-block
 		void set(value_assignment_t val, bool flag_as_provided = true)
 		{
 			setValue(val);
 			param_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);
 		}
 
@@ -1080,9 +1141,6 @@ namespace LLInitParam
 			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();
 			}
@@ -1134,7 +1192,9 @@ namespace LLInitParam
 		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)
+		:	Param(block_descriptor.mCurrentBlockPtr),
+			mMinCount(min_count),
+			mMaxCount(max_count)
 		{
 			std::copy(value.begin(), value.end(), std::back_inserter(mValues));
 
@@ -1152,7 +1212,13 @@ namespace LLInitParam
 			}
 		} 
 
-		bool isProvided() const { return Param::anyProvided(); }
+		bool isProvided() const { return Param::anyProvided() && isValid(); }
+
+		bool isValid() const 
+		{ 
+			size_t num_elements = numValidElements();
+			return mMinCount < num_elements && num_elements < mMaxCount;
+		}
 
 		static bool deserializeParam(Param& param, Parser& parser, const Parser::name_stack_range_t& name_stack_range, bool new_name)
 		{ 
@@ -1197,7 +1263,7 @@ namespace LLInitParam
 			return false;
 		}
 
-		static void serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const Param* diff_param)
+		static void serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const Param* diff_param)
 		{
 			const self_t& typed_param = static_cast<const self_t&>(param);
 			if (!typed_param.isProvided()) return;
@@ -1293,7 +1359,7 @@ namespace LLInitParam
 		bool empty() const { return mValues.empty(); }
 		size_t size() const { return mValues.size(); }
 
-		U32 numValidElements() const
+		size_t numValidElements() const
 		{
 			return mValues.size();
 		}
@@ -1323,6 +1389,8 @@ namespace LLInitParam
 		}
 
 		container_t		mValues;
+		size_t			mMinCount,
+						mMaxCount;
 	};
 
 	// container of block parameters
@@ -1339,7 +1407,9 @@ namespace LLInitParam
 		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)
+		:	Param(block_descriptor.mCurrentBlockPtr),
+			mMinCount(min_count),
+			mMaxCount(max_count)
 		{
 			std::copy(value.begin(), value.end(), back_inserter(mValues));
 
@@ -1357,7 +1427,14 @@ namespace LLInitParam
 			}
 		} 
 
-		bool isProvided() const { return Param::anyProvided(); }
+		bool isProvided() const { return Param::anyProvided() && isValid(); }
+
+		bool isValid() const 
+		{ 
+			size_t num_elements = numValidElements();
+			return mMinCount < num_elements && num_elements < mMaxCount;
+		}
+
 
 		static bool deserializeParam(Param& param, Parser& parser, const Parser::name_stack_range_t& name_stack_range, bool new_name) 
 		{ 
@@ -1420,9 +1497,13 @@ namespace LLInitParam
 			return false;
 		}
 
-		static void serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const Param* diff_param)
+		static void serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const Param* diff_param)
 		{
 			const self_t& typed_param = static_cast<const self_t&>(param);
+
+			LLPredicate::Value<ESerializePredicates> predicate_value;
+			if (typed_param.isProvided()) predicate_value.set(PROVIDED);
+			
 			if (!typed_param.isProvided()) return;
 
 			for (const_iterator it = typed_param.mValues.begin(), end_it = typed_param.mValues.end();
@@ -1437,10 +1518,10 @@ namespace LLInitParam
 					parser.writeValue(key, name_stack);
 				}
 				// Not parsed via named values, write out value directly
-				// NOTE: currently we don't worry about removing default values in Multiple
+				// NOTE: currently we don't do diffing of Multiples
 				else 
 				{
-					it->serializeBlock(parser, name_stack, NULL);
+					it->serializeBlock(parser, name_stack, predicate_rule, NULL);
 				}
 
 				name_stack.pop_back();
@@ -1500,14 +1581,14 @@ namespace LLInitParam
 		bool empty() const { return mValues.empty(); }
 		size_t size() const { return mValues.size(); }
 
-		U32 numValidElements() const
+		size_t numValidElements() const
 		{
-			U32 count = 0;
+			size_t count = 0;
 			for (const_iterator it = mValues.begin(), end_it = mValues.end();
 				it != end_it;
 				++it)
 			{
-				if(it->validateBlock(false)) count++;
+				if(it->isValid()) count++;
 			}
 			return count;
 		}
@@ -1539,6 +1620,8 @@ namespace LLInitParam
 		}
 
 		container_t			mValues;
+		size_t				mMinCount,
+							mMaxCount;
 	};
 
 	template <typename DERIVED_BLOCK, typename BASE_BLOCK = BaseBlock>
@@ -1826,7 +1909,7 @@ namespace LLInitParam
 
 			static bool validate(const Param* paramp) 
 			{
-				U32 num_valid = ((super_t*)paramp)->numValidElements();
+				size_t num_valid = ((super_t*)paramp)->numValidElements();
 				return RANGE::minCount <= num_valid && num_valid <= RANGE::maxCount;
 			}
 		};
@@ -1943,13 +2026,11 @@ namespace LLInitParam
 		typedef block_t value_t;
 
 		ParamValue()
-		:	block_t(),
-			mValidated(false)
+		:	block_t()
 		{}
 
 		ParamValue(value_assignment_t other)
-		:	block_t(other),
-			mValidated(false)
+		:	block_t(other)
 		{
 		}
 
@@ -1977,9 +2058,6 @@ namespace LLInitParam
 		{
 			return *this;
 		}
-
-	protected:
-		mutable bool 	mValidated; // lazy validation flag
 	};
 
 	template<typename T, bool IS_BLOCK>
@@ -1994,13 +2072,11 @@ namespace LLInitParam
 		typedef T value_t;
 	
 		ParamValue()
-		:	mValue(),
-			mValidated(false)
+		:	mValue()
 		{}
 
 		ParamValue(value_assignment_t other)
-		:	mValue(other),
-			mValidated(false)
+		:	mValue(other)
 		{}
 
 		void setValue(value_assignment_t val)
@@ -2033,11 +2109,11 @@ namespace LLInitParam
 			return mValue.get().deserializeBlock(p, name_stack_range, new_name);
 		}
 
-		void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block = NULL) const
+		void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const BaseBlock* diff_block = NULL) const
 		{
 			if (mValue.empty()) return;
 			
-			mValue.get().serializeBlock(p, name_stack, diff_block);
+			mValue.get().serializeBlock(p, name_stack, predicate_rule, diff_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
@@ -2047,9 +2123,6 @@ namespace LLInitParam
 			return mValue.get().inspectBlock(p, name_stack, min_count, max_count);
 		}
 
-	protected:
-		mutable bool 	mValidated; // lazy validation flag
-
 	private:
 		BaseBlock::Lazy<T>	mValue;
 	};
@@ -2066,12 +2139,10 @@ namespace LLInitParam
 		typedef const LLSD&	value_assignment_t;
 
 		ParamValue()
-		:	mValidated(false)
 		{}
 
 		ParamValue(value_assignment_t other)
-		:	mValue(other),
-			mValidated(false)
+		:	mValue(other)
 		{}
 
 		void setValue(value_assignment_t val) { mValue = val; }
@@ -2085,16 +2156,13 @@ namespace LLInitParam
 
 		// block param interface
 		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;
+		LL_COMMON_API void 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;
 		}
 
-	protected:
-		mutable bool 	mValidated; // lazy validation flag
-
 	private:
 		static void serializeElement(Parser& p, const LLSD& sd, Parser::name_stack_t& name_stack);
 
@@ -2123,8 +2191,7 @@ namespace LLInitParam
 
 		CustomParamValue(const T& value = T())
 		:	mValue(value),
-			mValueAge(VALUE_AUTHORITATIVE),
-			mValidated(false)
+			mValueAge(VALUE_AUTHORITATIVE)
 		{}
 
 		bool deserializeBlock(Parser& parser, Parser::name_stack_range_t name_stack_range, bool new_name)
@@ -2148,7 +2215,7 @@ namespace LLInitParam
 			return typed_param.BaseBlock::deserializeBlock(parser, name_stack_range, new_name);
 		}
 
-		void serializeBlock(Parser& parser, Parser::name_stack_t& name_stack, const BaseBlock* diff_block = NULL) const
+		void 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);
@@ -2184,11 +2251,11 @@ namespace LLInitParam
 						// and serialize those params
 						derived_t copy(typed_param);
 						copy.updateBlockFromValue(true);
-						copy.block_t::serializeBlock(parser, name_stack, NULL);
+						copy.block_t::serializeBlock(parser, name_stack, predicate_rule, NULL);
 					}
 					else
 					{
-						block_t::serializeBlock(parser, name_stack, NULL);
+						block_t::serializeBlock(parser, name_stack, predicate_rule, NULL);
 					}
 				}
 			}
@@ -2309,8 +2376,6 @@ namespace LLInitParam
 			return block_t::mergeBlock(block_data, source, overwrite);
 		}
 
-		mutable bool 		mValidated; // lazy validation flag
-
 	private:
 		mutable T			mValue;
 		mutable EValueAge	mValueAge;
diff --git a/indra/llcommon/llpredicate.cpp b/indra/llcommon/llpredicate.cpp
new file mode 100644
index 0000000000..8dcd9247b7
--- /dev/null
+++ b/indra/llcommon/llpredicate.cpp
@@ -0,0 +1,33 @@
+/** 
+ * @file llpredicate.cpp
+ * @brief abstraction for filtering objects by predicates, with arbitrary boolean expressions
+ *
+ * $LicenseInfo:firstyear=2008&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * 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$
+ */
+#include "linden_common.h"
+
+#include "llpredicate.h"
+
+namespace LLPredicate
+{
+	EmptyRule make_rule() { return EmptyRule(); }
+}
diff --git a/indra/llcommon/llpredicate.h b/indra/llcommon/llpredicate.h
new file mode 100644
index 0000000000..ad5ab363fa
--- /dev/null
+++ b/indra/llcommon/llpredicate.h
@@ -0,0 +1,173 @@
+/** 
+ * @file llpredicate.h
+ * @brief abstraction for filtering objects by predicates, with arbitrary boolean expressions
+ *
+ * $LicenseInfo:firstyear=2008&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * 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_LLPREDICATE_H
+#define LL_LLPREDICATE_H
+
+#include "llerror.h"
+
+namespace LLPredicate
+{
+	template<typename ENUM> class Rule;
+
+	template<typename ENUM>
+	struct Value
+	{
+		friend Rule<ENUM>;
+	public:
+		Value(ENUM e)
+		:	mPredicateFlags(0x1),
+			mPredicateCombinationFlags(0x1)
+		{
+			set(e);
+		}
+
+		Value()
+			:	mPredicateFlags(0x1),
+			mPredicateCombinationFlags(0x1)
+		{}
+
+		void set(ENUM predicate)
+		{
+			llassert(predicate <= 5);
+			int predicate_flag = 0x1 << (0x1 << (int)predicate);
+			if (!(mPredicateFlags & predicate_flag))
+			{
+				mPredicateCombinationFlags *= predicate_flag;
+				mPredicateFlags |= predicate_flag;
+			}
+		}
+
+		bool get(ENUM predicate)
+		{
+			int predicate_flag = 0x1 << (0x1 << (int)predicate);
+			return (mPredicateFlags & predicate_flag) != 0;
+		}
+
+		void clear(ENUM predicate)
+		{
+			llassert(predicate <= 5);
+			int predicate_flag = 0x1 << (0x1 << (int)predicate);
+			if (mPredicateFlags & predicate_flag)
+			{
+				mPredicateCombinationFlags /= predicate_flag;
+				mPredicateFlags &= ~predicate_flag;
+			}
+		}
+
+	private:
+		int mPredicateCombinationFlags;
+		int mPredicateFlags;
+	};
+
+	struct EmptyRule {};
+
+	template<typename ENUM>
+	class Rule
+	{
+	public:
+		Rule(EmptyRule e)
+			:	mPredicateRequirements(0x1)
+		{}
+
+		Rule(ENUM value)
+			:	mPredicateRequirements(predicateFromValue(value))
+		{}
+
+		Rule()
+			:	mPredicateRequirements(0x1)
+		{}
+
+		Rule operator~()
+		{
+			Rule new_rule;
+			new_rule.mPredicateRequirements = ~mPredicateRequirements;
+			return new_rule;
+		}
+
+		Rule operator &&(const Rule& other)
+		{
+			Rule new_rule;
+			new_rule.mPredicateRequirements = mPredicateRequirements & other.mPredicateRequirements;
+			return new_rule;
+		}
+
+		Rule operator ||(const Rule& other)
+		{
+			Rule new_rule;
+			new_rule.mPredicateRequirements = mPredicateRequirements | other.mPredicateRequirements;
+			return new_rule;
+		}
+
+		bool check(const Value<ENUM>& value) const
+		{
+			return ((value.mPredicateCombinationFlags | 0x1) & mPredicateRequirements) != 0;
+		}
+
+		static int predicateFromValue(ENUM value)
+		{
+			int countdown = value;
+			bool bit_val = false;
+
+			int predicate = 0x0;
+
+			for (int bit_index = 0; bit_index < 32; bit_index++)
+			{
+				if (bit_val)
+				{
+					predicate |= 0x1 << bit_index;
+				}
+
+				if (countdown-- == 0)
+				{
+					countdown = value;
+					bit_val = !bit_val;
+				}
+			}
+			return predicate;
+		}
+
+		bool isTriviallyTrue() const
+		{
+			return mPredicateRequirements & 0x1;
+		}
+
+		bool isTriviallyFalse() const
+		{
+			return mPredicateRequirements == 0;
+		}
+
+	private:
+		int mPredicateRequirements;
+	};
+
+	template<typename ENUM>
+	Rule<ENUM> make_rule(ENUM e) { return Rule<ENUM>(e);}
+
+	EmptyRule make_rule();
+
+}
+#endif // LL_LLPREDICATE_H
diff --git a/indra/llcommon/llsdparam.cpp b/indra/llcommon/llsdparam.cpp
index 4b8a8dba5c..713f5ac605 100644
--- a/indra/llcommon/llsdparam.cpp
+++ b/indra/llcommon/llsdparam.cpp
@@ -329,7 +329,7 @@ namespace LLInitParam
 		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, TypeValues<LLSD>, false>::serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const BaseBlock* diff_block) const
 	{
 		// attempt to write LLSD out directly
 		if (!p.writeValue<LLSD>(mValue, name_stack))
-- 
cgit v1.2.3