summaryrefslogtreecommitdiff
path: root/indra/llcommon/llinitparam.h
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llcommon/llinitparam.h')
-rw-r--r--indra/llcommon/llinitparam.h5580
1 files changed, 2790 insertions, 2790 deletions
diff --git a/indra/llcommon/llinitparam.h b/indra/llcommon/llinitparam.h
index e0d0ab9ac7..206aa51ba3 100644
--- a/indra/llcommon/llinitparam.h
+++ b/indra/llcommon/llinitparam.h
@@ -1,26 +1,26 @@
-/**
+/**
* @file llinitparam.h
- * @brief parameter block abstraction for creating complex objects and
+ * @brief parameter block abstraction for creating complex objects and
* parsing construction parameters from xml and LLSD
*
* $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$
*/
@@ -43,2796 +43,2796 @@
namespace LLTypeTags
{
- template <typename INNER_TYPE, int _SORT_ORDER>
- struct TypeTagBase
- {
- typedef void is_tag_t;
- typedef INNER_TYPE inner_t;
- static const int SORT_ORDER=_SORT_ORDER;
- };
-
- template <int VAL1, int VAL2>
- struct GreaterThan
- {
- static const bool value = VAL1 > VAL2;
- };
-
- template<typename ITEM, typename REST, bool NEEDS_SWAP = GreaterThan<ITEM::SORT_ORDER, REST::SORT_ORDER>::value >
- struct Swap
- {
- typedef typename ITEM::template Cons<REST>::value_t value_t;
- };
-
- template<typename ITEM, typename REST>
- struct Swap<ITEM, REST, true>
- {
- typedef typename REST::template Cons<Swap<ITEM, typename REST::inner_t>::value_t>::value_t value_t;
- };
-
- template<typename T, typename SORTABLE = void>
- struct IsSortable
- {
- static const bool value = false;
- };
-
- template<typename T>
- struct IsSortable<T, typename T::is_tag_t>
- {
- static const bool value = true;
- };
-
- template<typename ITEM, typename REST, bool IS_REST_SORTABLE = IsSortable<REST>::value>
- struct InsertInto
- {
- typedef typename ITEM::template Cons<REST>::value_t value_t;
- };
-
- template<typename ITEM, typename REST>
- struct InsertInto <ITEM, REST, true>
- {
- typedef typename Swap<ITEM, REST>::value_t value_t;
- };
-
- template<typename T, bool SORTABLE = IsSortable<T>::value>
- struct Sorted
- {
- typedef T value_t;
- };
-
- template<typename T>
- struct Sorted <T, true>
- {
- typedef typename InsertInto<T, typename Sorted<typename T::inner_t>::value_t>::value_t value_t;
- };
+ template <typename INNER_TYPE, int _SORT_ORDER>
+ struct TypeTagBase
+ {
+ typedef void is_tag_t;
+ typedef INNER_TYPE inner_t;
+ static const int SORT_ORDER=_SORT_ORDER;
+ };
+
+ template <int VAL1, int VAL2>
+ struct GreaterThan
+ {
+ static const bool value = VAL1 > VAL2;
+ };
+
+ template<typename ITEM, typename REST, bool NEEDS_SWAP = GreaterThan<ITEM::SORT_ORDER, REST::SORT_ORDER>::value >
+ struct Swap
+ {
+ typedef typename ITEM::template Cons<REST>::value_t value_t;
+ };
+
+ template<typename ITEM, typename REST>
+ struct Swap<ITEM, REST, true>
+ {
+ typedef typename REST::template Cons<Swap<ITEM, typename REST::inner_t>::value_t>::value_t value_t;
+ };
+
+ template<typename T, typename SORTABLE = void>
+ struct IsSortable
+ {
+ static const bool value = false;
+ };
+
+ template<typename T>
+ struct IsSortable<T, typename T::is_tag_t>
+ {
+ static const bool value = true;
+ };
+
+ template<typename ITEM, typename REST, bool IS_REST_SORTABLE = IsSortable<REST>::value>
+ struct InsertInto
+ {
+ typedef typename ITEM::template Cons<REST>::value_t value_t;
+ };
+
+ template<typename ITEM, typename REST>
+ struct InsertInto <ITEM, REST, true>
+ {
+ typedef typename Swap<ITEM, REST>::value_t value_t;
+ };
+
+ template<typename T, bool SORTABLE = IsSortable<T>::value>
+ struct Sorted
+ {
+ typedef T value_t;
+ };
+
+ template<typename T>
+ struct Sorted <T, true>
+ {
+ typedef typename InsertInto<T, typename Sorted<typename T::inner_t>::value_t>::value_t value_t;
+ };
}
namespace LLInitParam
{
- // used to indicate no matching value to a given name when parsing
- struct Flag{};
-
- template<typename T> const T& defaultValue() { static T value; return value; }
-
- // wraps comparison operator between any 2 values of the same type
- // specialize to handle cases where equality isn't defined well, or at all
- template <typename T, bool IS_BOOST_FUNCTION = boost::is_convertible<T, boost::function_base>::value >
- struct ParamCompare
- {
- static bool equals(const T &a, const T &b)
- {
- return a == b;
- }
+ // 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; }
+
+ // wraps comparison operator between any 2 values of the same type
+ // specialize to handle cases where equality isn't defined well, or at all
+ template <typename T, bool IS_BOOST_FUNCTION = boost::is_convertible<T, boost::function_base>::value >
+ struct ParamCompare
+ {
+ static bool equals(const T &a, const T &b)
+ {
+ return a == b;
+ }
+ };
+
+ // boost function types are not comparable
+ template<typename T>
+ struct ParamCompare<T, true>
+ {
+ static bool equals(const T&a, const T &b)
+ {
+ return false;
+ }
+ };
+
+ template<>
+ struct ParamCompare<LLSD, false>
+ {
+ static bool equals(const LLSD &a, const LLSD &b) { return false; }
+ };
+
+ 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;
+ struct IS_A_BLOCK {};
+ struct NOT_BLOCK {};
+
+ // these templates allow us to distinguish between template parameters
+ // that derive from BaseBlock and those that don't
+ template<typename T, typename BLOCK_IDENTIFIER = void>
+ struct IsBlock
+ {
+ typedef NOT_BLOCK value_t;
+ };
+
+ template<typename T>
+ struct IsBlock<T, typename T::baseblock_base_class_t>
+ {
+ typedef IS_A_BLOCK value_t;
+ };
+
+ // ParamValue class directly manages the wrapped value
+ // by holding on to a copy (scalar params)
+ // or deriving from it (blocks)
+ // has specializations for custom value behavior
+ // and "tag" values like Lazy and Atomic
+ template<typename T, typename VALUE_IS_BLOCK = typename IsBlock<T>::value_t>
+ class ParamValue
+ {
+ typedef ParamValue<T, VALUE_IS_BLOCK> self_t;
+
+ public:
+ typedef T default_value_t;
+ typedef T value_t;
+
+ ParamValue(): mValue() {}
+ ParamValue(const default_value_t& other) : mValue(other) {}
+
+ void setValue(const value_t& val)
+ {
+ mValue = val;
+ }
+
+ const value_t& getValue() const
+ {
+ return mValue;
+ }
+
+ T& getValue()
+ {
+ return mValue;
+ }
+
+ bool isValid() const { return true; }
+
+ protected:
+ T mValue;
+ };
+
+ template<typename T>
+ class ParamValue<T, IS_A_BLOCK>
+ : public T
+ {
+ typedef ParamValue<T, IS_A_BLOCK> self_t;
+ public:
+ typedef T default_value_t;
+ typedef T value_t;
+
+ ParamValue()
+ : T()
+ {}
+
+ ParamValue(const default_value_t& other)
+ : T(other)
+ {}
+
+ void setValue(const value_t& val)
+ {
+ *this = val;
+ }
+
+ const value_t& getValue() const
+ {
+ return *this;
+ }
+
+ T& getValue()
+ {
+ return *this;
+ }
};
- // boost function types are not comparable
- template<typename T>
- struct ParamCompare<T, true>
- {
- static bool equals(const T&a, const T &b)
- {
- return false;
- }
- };
-
- template<>
- struct ParamCompare<LLSD, false>
- {
- static bool equals(const LLSD &a, const LLSD &b) { return false; }
- };
-
- 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;
- struct IS_A_BLOCK {};
- struct NOT_BLOCK {};
-
- // these templates allow us to distinguish between template parameters
- // that derive from BaseBlock and those that don't
- template<typename T, typename BLOCK_IDENTIFIER = void>
- struct IsBlock
- {
- typedef NOT_BLOCK value_t;
- };
-
- template<typename T>
- struct IsBlock<T, typename T::baseblock_base_class_t>
- {
- typedef IS_A_BLOCK value_t;
- };
-
- // ParamValue class directly manages the wrapped value
- // by holding on to a copy (scalar params)
- // or deriving from it (blocks)
- // has specializations for custom value behavior
- // and "tag" values like Lazy and Atomic
- template<typename T, typename VALUE_IS_BLOCK = typename IsBlock<T>::value_t>
- class ParamValue
- {
- typedef ParamValue<T, VALUE_IS_BLOCK> self_t;
-
- public:
- typedef T default_value_t;
- typedef T value_t;
-
- ParamValue(): mValue() {}
- ParamValue(const default_value_t& other) : mValue(other) {}
-
- void setValue(const value_t& val)
- {
- mValue = val;
- }
-
- const value_t& getValue() const
- {
- return mValue;
- }
-
- T& getValue()
- {
- return mValue;
- }
-
- bool isValid() const { return true; }
-
- protected:
- T mValue;
- };
-
- template<typename T>
- class ParamValue<T, IS_A_BLOCK>
- : public T
- {
- typedef ParamValue<T, IS_A_BLOCK> self_t;
- public:
- typedef T default_value_t;
- typedef T value_t;
-
- ParamValue()
- : T()
- {}
-
- ParamValue(const default_value_t& other)
- : T(other)
- {}
-
- void setValue(const value_t& val)
- {
- *this = val;
- }
-
- const value_t& getValue() const
- {
- return *this;
- }
-
- T& getValue()
- {
- return *this;
- }
- };
-
-
- // empty default implementation of key cache
- // leverages empty base class optimization
- template <typename T>
- class TypeValues
- : public ParamValue<typename LLTypeTags::Sorted<T>::value_t>
- {
- private:
- struct Inaccessable{};
- public:
- typedef std::map<std::string, T> value_name_map_t;
- typedef Inaccessable name_t;
- typedef TypeValues<T> type_value_t;
- typedef ParamValue<typename LLTypeTags::Sorted<T>::value_t> param_value_t;
- typedef typename param_value_t::value_t value_t;
-
- TypeValues(const typename param_value_t::value_t& val)
- : param_value_t(val)
- {}
-
- void setValueName(const std::string& key) {}
- std::string getValueName() const { return ""; }
- std::string calcValueName(const value_t& value) const { return ""; }
- void clearValueName() const {}
-
- static bool getValueFromName(const std::string& name, value_t& value)
- {
- return false;
- }
-
- static bool valueNamesExist()
- {
- return false;
- }
-
- static std::vector<std::string>* getPossibleValues()
- {
- return NULL;
- }
-
- void assignNamedValue(const Inaccessable& name)
- {}
-
- operator const value_t&() const
- {
- return param_value_t::getValue();
- }
-
- const value_t& operator()() const
- {
- return param_value_t::getValue();
- }
-
- static value_name_map_t* getValueNames() {return NULL;}
- };
-
- // helper class to implement name value lookups
- // and caching of last used name
- template <typename T, typename DERIVED_TYPE = TypeValues<T>, bool IS_SPECIALIZED = true >
- class TypeValuesHelper
- : public ParamValue<typename LLTypeTags::Sorted<T>::value_t>
- {
- typedef TypeValuesHelper<T, DERIVED_TYPE, IS_SPECIALIZED> self_t;
- public:
- typedef typename std::map<std::string, T> value_name_map_t;
- typedef std::string name_t;
- typedef self_t type_value_t;
- typedef ParamValue<typename LLTypeTags::Sorted<T>::value_t> param_value_t;
- typedef typename param_value_t::value_t value_t;
-
- TypeValuesHelper(const typename param_value_t::value_t& val)
- : param_value_t(val)
- {}
-
- //TODO: cache key by index to save on param block size
- void setValueName(const std::string& value_name)
- {
- mValueName = value_name;
- }
-
- std::string getValueName() const
- {
- return mValueName;
- }
-
- std::string calcValueName(const value_t& value) const
- {
- value_name_map_t* map = getValueNames();
- for (typename value_name_map_t::value_type& map_pair : *map)
- {
- if (ParamCompare<T>::equals(map_pair.second, value))
- {
- return map_pair.first;
- }
- }
-
- return "";
- }
-
- void clearValueName() const
- {
- mValueName.clear();
- }
-
- static bool getValueFromName(const std::string& name, value_t& value)
- {
- value_name_map_t* map = getValueNames();
- typename value_name_map_t::iterator found_it = map->find(name);
- if (found_it == map->end()) return false;
-
- value = found_it->second;
- return true;
- }
-
- static bool valueNamesExist()
- {
- return !getValueNames()->empty();
- }
-
- static value_name_map_t* getValueNames()
- {
- static value_name_map_t sMap;
- static bool sInitialized = false;
-
- if (!sInitialized)
- {
- sInitialized = true;
- DERIVED_TYPE::declareValues();
- }
- return &sMap;
- }
-
- static std::vector<std::string>* getPossibleValues()
- {
- static std::vector<std::string> sValues;
-
- value_name_map_t* map = getValueNames();
- for (typename value_name_map_t::value_type& map_pair : *map)
- {
- sValues.push_back(map_pair.first);
- }
- return &sValues;
- }
-
- static void declare(const std::string& name, const value_t& value)
- {
- (*getValueNames())[name] = value;
- }
-
- void operator ()(const std::string& name)
- {
- *this = name;
- }
-
- void assignNamedValue(const std::string& name)
- {
- if (getValueFromName(name, param_value_t::getValue()))
- {
- setValueName(name);
- }
- }
-
- operator const value_t&() const
- {
- return param_value_t::getValue();
- }
-
- const value_t& operator()() const
- {
- return param_value_t::getValue();
- }
-
- protected:
- static void getName(const std::string& name, const value_t& value)
- {}
-
- mutable std::string mValueName;
- };
-
- // string types can support custom named values, but need
- // to disambiguate in code between a string that is a named value
- // and a string that is a name
- template <typename DERIVED_TYPE>
- class TypeValuesHelper<std::string, DERIVED_TYPE, true>
- : public TypeValuesHelper<std::string, DERIVED_TYPE, false>
- {
- public:
- typedef TypeValuesHelper<std::string, DERIVED_TYPE, true> self_t;
- typedef TypeValuesHelper<std::string, DERIVED_TYPE, false> base_t;
- typedef std::string value_t;
- typedef std::string name_t;
- typedef self_t type_value_t;
-
- TypeValuesHelper(const std::string& val)
- : base_t(val)
- {}
-
- void operator ()(const std::string& name)
- {
- *this = name;
- }
-
- self_t& operator =(const std::string& name)
- {
- if (base_t::getValueFromName(name, ParamValue<std::string>::getValue()))
- {
- base_t::setValueName(name);
- }
- else
- {
- ParamValue<std::string>::setValue(name);
- }
- return *this;
- }
-
- operator const value_t&() const
- {
- return ParamValue<std::string>::getValue();
- }
-
- const value_t& operator()() const
- {
- return ParamValue<std::string>::getValue();
- }
-
- };
-
- // parser base class with mechanisms for registering readers/writers/inspectors of different types
- class LL_COMMON_API Parser
- {
- LOG_CLASS(Parser);
- 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;
-
- 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;
-
- public:
-
- Parser(parser_read_func_map_t& read_map, parser_write_func_map_t& write_map, parser_inspect_func_map_t& inspect_map)
- : mParseSilently(false),
- mParserReadFuncs(&read_map),
- mParserWriteFuncs(&write_map),
- mParserInspectFuncs(&inspect_map)
- {}
-
- virtual ~Parser();
-
- template <typename T> bool readValue(T& param, typename boost::disable_if<boost::is_enum<T> >::type* dummy = 0)
- {
- parser_read_func_map_t::iterator found_it = mParserReadFuncs->find(&typeid(T));
- if (found_it != mParserReadFuncs->end())
- {
- return found_it->second(*this, (void*)&param);
- }
-
- return false;
- }
-
- template <typename T> bool readValue(T& param, typename boost::enable_if<boost::is_enum<T> >::type* dummy = 0)
- {
- parser_read_func_map_t::iterator found_it = mParserReadFuncs->find(&typeid(T));
- if (found_it != mParserReadFuncs->end())
- {
- return found_it->second(*this, (void*)&param);
- }
- else
- {
- found_it = mParserReadFuncs->find(&typeid(S32));
- if (found_it != mParserReadFuncs->end())
- {
- S32 int_value;
- bool parsed = found_it->second(*this, (void*)&int_value);
- param = (T)int_value;
- return parsed;
- }
- }
- return false;
- }
-
- 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 std::string getCurrentFileName() = 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));
- }
-
- bool mParseSilently;
-
- private:
- parser_read_func_map_t* mParserReadFuncs;
- parser_write_func_map_t* mParserWriteFuncs;
- parser_inspect_func_map_t* mParserInspectFuncs;
- };
-
- class Param;
-
- 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
- struct LL_COMMON_API ParamDescriptor
- {
- struct UserData
- {
- virtual ~UserData() {}
- };
-
- typedef bool(*merge_func_t)(Param&, const Param&, bool);
- typedef bool(*deserialize_func_t)(Param&, Parser&, Parser::name_stack_range_t&, bool);
- typedef bool(*serialize_func_t)(const Param&, Parser&, Parser::name_stack_t&, const predicate_rule_t rules, 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);
-
- ParamDescriptor();
- ~ParamDescriptor();
-
- 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;
- UserData* mUserData;
- };
-
- typedef std::shared_ptr<ParamDescriptor> ParamDescriptorPtr;
-
- // each derived Block class keeps a static data structure maintaining offsets to various params
- class LL_COMMON_API BlockDescriptor
- {
- public:
- BlockDescriptor();
-
- 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
- };
-
- //TODO: implement in terms of owned_ptr
- template<typename T>
- class LazyValue
- {
- public:
- LazyValue()
- : mPtr(NULL)
- {}
-
- ~LazyValue()
- {
- delete mPtr;
- }
-
- LazyValue(const T& value)
- {
- mPtr = new T(value);
- }
-
- LazyValue(const LazyValue& other)
- : mPtr(NULL)
- {
- *this = other;
- }
-
- LazyValue& operator = (const LazyValue& other)
- {
- if (!other.mPtr)
- {
- delete mPtr;
- mPtr = NULL;
- }
- else
- {
- if (!mPtr)
- {
- mPtr = new T(*other.mPtr);
- }
- else
- {
- *mPtr = *(other.mPtr);
- }
- }
- return *this;
- }
-
- bool operator==(const LazyValue& other) const
- {
- if (empty() || other.empty()) return false;
- return *mPtr == *other.mPtr;
- }
-
- bool empty() const
- {
- return mPtr == NULL;
- }
-
- void set(const T& other)
- {
- if (!mPtr)
- {
- mPtr = new T(other);
- }
- else
- {
- *mPtr = other;
- }
- }
-
- const T& get() const
- {
- return *ensureInstance();
- }
-
- T& get()
- {
- return *ensureInstance();
- }
-
- operator const T&() const
- {
- return get();
- }
-
- private:
- // lazily allocate an instance of T
- T* ensureInstance() const
- {
- if (mPtr == NULL)
- {
- mPtr = new T();
- }
- return mPtr;
- }
-
- private:
-
- mutable T* mPtr;
- };
-
- // root class of all parameter blocks
-
- class LL_COMMON_API BaseBlock
- {
- public:
- // lift block tags into baseblock namespace so derived classes do not need to qualify them
- typedef LLInitParam::IS_A_BLOCK IS_A_BLOCK;
- typedef LLInitParam::NOT_BLOCK NOT_A_BLOCK;
-
- template<typename T>
- struct Sequential : public LLTypeTags::TypeTagBase<T, 2>
- {
- template <typename S> struct Cons { typedef Sequential<ParamValue<S> > value_t; };
- template <typename S> struct Cons<Sequential<S> > { typedef Sequential<S> value_t; };
- };
-
- template<typename T>
- struct Atomic : public LLTypeTags::TypeTagBase<T, 1>
- {
- template <typename S> struct Cons { typedef Atomic<ParamValue<S> > value_t; };
- template <typename S> struct Cons<Atomic<S> > { typedef Atomic<S> value_t; };
- };
-
- template<typename T, typename BLOCK_T = typename IsBlock<T>::value_t >
- struct Lazy : public LLTypeTags::TypeTagBase<T, 0>
- {
- template <typename S> struct Cons
- {
- typedef Lazy<ParamValue<S, BLOCK_T>, BLOCK_T> value_t;
- };
- template <typename S> struct Cons<Lazy<S, IS_A_BLOCK> >
- {
- typedef Lazy<S, IS_A_BLOCK> value_t;
- };
- template <typename S> struct Cons<Lazy<S, NOT_A_BLOCK> >
- {
- typedef Lazy<S, BLOCK_T> value_t;
- };
- };
-
- // "Multiple" constraint types, put here in root class to avoid ambiguity during use
- struct AnyAmount
- {
- enum { minCount = 0 };
- enum { maxCount = U32_MAX };
- };
-
- template<U32 MIN_AMOUNT>
- struct AtLeast
- {
- enum { minCount = MIN_AMOUNT };
- enum { maxCount = U32_MAX };
- };
-
- template<U32 MAX_AMOUNT>
- struct AtMost
- {
- enum { minCount = 0 };
- enum { maxCount = MAX_AMOUNT };
- };
-
- template<U32 MIN_AMOUNT, U32 MAX_AMOUNT>
- struct Between
- {
- enum { minCount = MIN_AMOUNT };
- enum { maxCount = MAX_AMOUNT };
- };
-
- template<U32 EXACT_COUNT>
- struct Exactly
- {
- 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)
- {}
-
- 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;
-
- 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 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);
-
-
- bool mergeBlockParam(bool source_provided, bool dst_provided, BlockDescriptor& block_data, const BaseBlock& source, bool overwrite)
- {
- return mergeBlock(block_data, source, overwrite);
- }
-
- mutable bool mValidated; // lazy validation flag
- bool mParamProvided;
-
- private:
- const std::string& getParamName(const BlockDescriptor& block_data, const Param* paramp) const;
- };
-
- class LL_COMMON_API Param
- {
- public:
- void setProvided(bool is_provided = true)
- {
- mIsProvided = is_provided;
- enclosingBlock().paramChanged(*this, is_provided);
- }
-
- Param& operator =(const Param& other)
- {
- mIsProvided = other.mIsProvided;
- // don't change mEnclosingblockoffset
- return *this;
- }
- 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)getEnclosingBlockOffset()));
- }
-
- U32 getEnclosingBlockOffset() const
- {
- return ((U32)mEnclosingBlockOffsetHigh << 16) | (U32)mEnclosingBlockOffsetLow;
- }
-
- private:
- friend class BaseBlock;
-
- //24 bits for member offset field and 1 bit for provided flag
- U16 mEnclosingBlockOffsetLow;
- U8 mEnclosingBlockOffsetHigh:7;
- U8 mIsProvided:1;
-
- };
-
- template<typename T, typename NAME_VALUE_LOOKUP = TypeValues<T> >
- struct ParamIterator
- {
- 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;
- };
-
- // 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>
- class TypedParam
- : public Param,
- public NAME_VALUE_LOOKUP::type_value_t
- {
- protected:
- typedef TypedParam<T, NAME_VALUE_LOOKUP, HAS_MULTIPLE_VALUES, VALUE_IS_BLOCK> self_t;
- typedef ParamValue<typename LLTypeTags::Sorted<T>::value_t> param_value_t;
- typedef typename param_value_t::default_value_t default_value_t;
- typedef typename NAME_VALUE_LOOKUP::type_value_t named_value_t;
- public:
- typedef typename param_value_t::value_t value_t;
-
- 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),
- 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(); }
-
- bool isValid() const { return true; }
-
- static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name)
- {
- self_t& typed_param = static_cast<self_t&>(param);
- // no further names in stack, attempt to parse value now
- if (name_stack_range.first == name_stack_range.second)
- {
- std::string name;
-
- // try to parse a known named value
- if(named_value_t::valueNamesExist()
- && parser.readValue(name)
- && named_value_t::getValueFromName(name, typed_param.getValue()))
- {
- typed_param.setValueName(name);
- typed_param.setProvided();
- return true;
- }
- // try to read value directly
- else if (parser.readValue(typed_param.getValue()))
- {
- typed_param.clearValueName();
- typed_param.setProvided();
- return true;
- }
- }
- return false;
- }
-
- 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);
- }
-
- predicate.set(VALID, typed_param.isValid());
- predicate.set(PROVIDED, typed_param.anyProvided());
- predicate.set(EMPTY, false);
-
- if (!predicate_rule.check(predicate)) return false;
-
- if (!name_stack.empty())
- {
- 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);
- }
- }
- // then try to serialize value directly
- 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 (calculated_key.size()
- && (!diff_typed_param
- || !ParamCompare<std::string>::equals(static_cast<const self_t*>(diff_param)->getValueName(), calculated_key)))
- {
- serialized = parser.writeValue(calculated_key, name_stack);
- }
- }
- }
- return serialized;
- }
-
- 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 (named_value_t::getPossibleValues())
- {
- parser.inspectValue<std::string>(name_stack, min_count, max_count, named_value_t::getPossibleValues());
- }
- }
-
- void set(const value_t& val, bool flag_as_provided = true)
- {
- named_value_t::clearValueName();
- named_value_t::setValue(val);
- setProvided(flag_as_provided);
- }
-
- self_t& operator =(const typename named_value_t::name_t& name)
- {
- named_value_t::assignNamedValue(name);
- return *this;
- }
-
- protected:
-
- self_t& operator =(const self_t& other)
- {
- param_value_t::operator =(other);
- Param::operator =(other);
- return *this;
- }
-
- static bool mergeWith(Param& dst, const Param& src, bool overwrite)
- {
- const self_t& src_typed_param = static_cast<const self_t&>(src);
- self_t& dst_typed_param = static_cast<self_t&>(dst);
-
- if (src_typed_param.isProvided()
- && (overwrite || !dst_typed_param.isProvided()))
- {
- dst_typed_param.set(src_typed_param.getValue());
- return true;
- }
- return false;
- }
- private:
- void init( BlockDescriptor &block_descriptor, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count, const char* name )
- {
- ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor(
- block_descriptor.mCurrentBlockPtr->getHandleFromParam(this),
- &mergeWith,
- &deserializeParam,
- &serializeParam,
- validate_func,
- &inspectParam,
- min_count, max_count));
- block_descriptor.addParam(param_descriptor, name);
- }
- };
-
- // parameter that is a block
- template <typename BLOCK_T, typename NAME_VALUE_LOOKUP>
- class TypedParam<BLOCK_T, NAME_VALUE_LOOKUP, false, IS_A_BLOCK>
- : public Param,
- public NAME_VALUE_LOOKUP::type_value_t
- {
- protected:
- typedef ParamValue<typename LLTypeTags::Sorted<BLOCK_T>::value_t> param_value_t;
- typedef typename param_value_t::default_value_t default_value_t;
- typedef TypedParam<BLOCK_T, NAME_VALUE_LOOKUP, false, IS_A_BLOCK> self_t;
- typedef typename NAME_VALUE_LOOKUP::type_value_t named_value_t;
- public:
- using named_value_t::operator();
- typedef typename param_value_t::value_t value_t;
-
- TypedParam(BlockDescriptor& block_descriptor, const char* name, const default_value_t& value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count)
- : Param(block_descriptor.mCurrentBlockPtr),
- named_value_t(value)
- {
- if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING))
- {
- init(block_descriptor, validate_func, min_count, max_count, name);
- }
- }
-
- static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name)
- {
- self_t& typed_param = static_cast<self_t&>(param);
-
- if (name_stack_range.first == name_stack_range.second)
- { // try to parse a known named value
- std::string name;
-
- if(named_value_t::valueNamesExist()
- && parser.readValue(name)
- && named_value_t::getValueFromName(name, typed_param.getValue()))
- {
- typed_param.setValueName(name);
- typed_param.setProvided();
- return true;
- }
- }
-
- if(typed_param.deserializeBlock(parser, name_stack_range, new_name))
- { // attempt to parse block...
- typed_param.clearValueName();
- typed_param.setProvided();
- return true;
- }
-
-
- return false;
- }
-
- static bool 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;
-
- predicate.set(VALID, typed_param.isValid());
- predicate.set(PROVIDED, typed_param.anyProvided());
-
- if (!predicate_rule.check(predicate)) return false;
-
- if (!name_stack.empty())
- {
- name_stack.back().second = true;
- }
-
- std::string key = typed_param.getValueName();
- if (!key.empty())
- {
- if (!diff_param || !ParamCompare<std::string>::equals(static_cast<const self_t*>(diff_param)->getValueName(), key))
- {
- parser.writeValue(key, name_stack);
- return true;
- }
- }
- else
- {
- return typed_param.serializeBlock(parser, name_stack, predicate_rule, static_cast<const self_t*>(diff_param));
- }
-
- return false;
- }
-
- static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count)
- {
- const self_t& typed_param = static_cast<const self_t&>(param);
-
- // tell parser about our actual type
- parser.inspectValue<value_t>(name_stack, min_count, max_count, NULL);
- // then tell it about string-based alternatives ("red", "blue", etc. for LLColor4)
- if (named_value_t::getPossibleValues())
- {
- parser.inspectValue<std::string>(name_stack, min_count, max_count, named_value_t::getPossibleValues());
- }
-
- typed_param.inspectBlock(parser, name_stack, min_count, max_count);
- }
-
- // a param-that-is-a-block is provided when the user has set one of its child params
- // *and* the block as a whole validates
- bool isProvided() const
- {
- return Param::anyProvided() && isValid();
- }
-
- bool isValid() const
- {
- return param_value_t::isValid();
- }
-
- // assign block contents to this param-that-is-a-block
- void set(const value_t& val, bool flag_as_provided = true)
- {
- named_value_t::setValue(val);
- named_value_t::clearValueName();
- setProvided(flag_as_provided);
- }
-
- self_t& operator =(const typename named_value_t::name_t& name)
- {
- named_value_t::assignNamedValue(name);
- return *this;
- }
-
- // propagate changed status up to enclosing block
- /*virtual*/ void paramChanged(const Param& changed_param, bool user_provided)
- {
- param_value_t::paramChanged(changed_param, user_provided);
-
- if (user_provided)
- {
- setProvided();
- named_value_t::clearValueName();
- }
- else
- {
- Param::enclosingBlock().paramChanged(*this, user_provided);
- }
- }
-
- protected:
-
- self_t& operator =(const self_t& other)
- {
- param_value_t::operator =(other);
- Param::operator =(other);
- return *this;
- }
-
- static bool mergeWith(Param& dst, const Param& src, bool overwrite)
- {
- const self_t& src_typed_param = static_cast<const self_t&>(src);
- self_t& dst_typed_param = static_cast<self_t&>(dst);
-
- if (src_typed_param.anyProvided())
- {
- if (dst_typed_param.mergeBlockParam(src_typed_param.isProvided(), dst_typed_param.isProvided(), param_value_t::getBlockDescriptor(), src_typed_param, overwrite))
- {
- dst_typed_param.clearValueName();
- dst_typed_param.setProvided(true);
- return true;
- }
- }
- return false;
- }
-
- private:
- void init( BlockDescriptor &block_descriptor, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count, const char* name )
- {
- ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor(
- block_descriptor.mCurrentBlockPtr->getHandleFromParam(this),
- &mergeWith,
- &deserializeParam,
- &serializeParam,
- validate_func,
- &inspectParam,
- min_count, max_count));
- block_descriptor.addParam(param_descriptor, name);
- }
- };
-
- // list of non-block parameters
- template <typename MULTI_VALUE_T, typename NAME_VALUE_LOOKUP>
- class TypedParam<MULTI_VALUE_T, NAME_VALUE_LOOKUP, true, NOT_BLOCK>
- : public Param
- {
- protected:
- typedef TypedParam<MULTI_VALUE_T, NAME_VALUE_LOOKUP, true, NOT_BLOCK> self_t;
- typedef ParamValue<typename LLTypeTags::Sorted<MULTI_VALUE_T>::value_t> param_value_t;
- typedef typename std::vector<typename NAME_VALUE_LOOKUP::type_value_t> container_t;
- typedef container_t default_value_t;
- typedef typename NAME_VALUE_LOOKUP::type_value_t named_value_t;
-
- public:
- typedef typename param_value_t::value_t value_t;
-
- 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),
- mMinCount(min_count),
- mMaxCount(max_count)
- {
- std::copy(value.begin(), value.end(), std::back_inserter(mValues));
-
- if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING))
- {
- init(block_descriptor, validate_func, min_count, max_count, name);
-
- }
- }
-
- 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, Parser::name_stack_range_t& name_stack_range, bool new_name)
- {
- Parser::name_stack_range_t new_name_stack_range(name_stack_range);
- self_t& typed_param = static_cast<self_t&>(param);
- value_t value;
-
- // pop first element if empty string
- if (new_name_stack_range.first != new_name_stack_range.second && new_name_stack_range.first->first.empty())
- {
- ++new_name_stack_range.first;
- }
-
- // no further names in stack, attempt to parse value now
- if (new_name_stack_range.first == new_name_stack_range.second)
- {
- std::string name;
-
- // try to parse a known named value
- if(named_value_t::valueNamesExist()
- && parser.readValue(name)
- && named_value_t::getValueFromName(name, value))
- {
- typed_param.add(value);
- typed_param.mValues.back().setValueName(name);
- return true;
- }
- else if (parser.readValue(value)) // attempt to read value directly
- {
- typed_param.add(value);
- return true;
- }
- }
- return false;
- }
-
- 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);
-
- LLPredicate::Value<ESerializePredicates> predicate;
-
- predicate.set(REQUIRED, typed_param.mMinCount > 0);
- predicate.set(VALID, typed_param.isValid());
- predicate.set(PROVIDED, typed_param.anyProvided());
- predicate.set(EMPTY, typed_param.mValues.empty());
-
- if (!predicate_rule.check(predicate)) return false;
-
- for (const_iterator it = typed_param.mValues.begin(), end_it = typed_param.mValues.end();
- it != end_it;
- ++it)
- {
- std::string key = it->getValueName();
- name_stack.push_back(std::make_pair(std::string(), true));
-
- if(key.empty())
- // not parsed via name values, write out value directly
- {
- bool value_written = parser.writeValue(*it, name_stack);
- if (!value_written)
- {
- std::string calculated_key = it->calcValueName(it->getValue());
- if (parser.writeValue(calculated_key, name_stack))
- {
- serialized = true;
- }
- else
- {
- break;
- }
- }
- }
- else
- {
- if(parser.writeValue(key, name_stack))
- {
- serialized = true;
- }
- else
- {
- break;
- }
- }
- }
-
- return serialized;
- }
-
- static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count)
- {
- parser.inspectValue<MULTI_VALUE_T>(name_stack, min_count, max_count, NULL);
- if (named_value_t::getPossibleValues())
- {
- parser.inspectValue<std::string>(name_stack, min_count, max_count, named_value_t::getPossibleValues());
- }
- }
-
- void set(const container_t& val, bool flag_as_provided = true)
- {
- mValues = val;
- setProvided(flag_as_provided);
- }
-
- param_value_t& add()
- {
- mValues.push_back(value_t());
- Param::setProvided();
- return mValues.back();
- }
-
- self_t& add(const value_t& item)
- {
- mValues.push_back(item);
- setProvided();
- return *this;
- }
-
- self_t& add(const typename named_value_t::name_t& name)
- {
- value_t value;
-
- // try to parse a per type named value
- if (named_value_t::getValueFromName(name, value))
- {
- add(value);
- mValues.back().setValueName(name);
- }
-
- return *this;
- }
-
- // implicit conversion
- operator const container_t&() const { return mValues; }
- // explicit conversion
- const container_t& operator()() const { return mValues; }
-
- typedef typename container_t::iterator iterator;
- typedef typename container_t::const_iterator const_iterator;
- iterator begin() { return mValues.begin(); }
- iterator end() { return mValues.end(); }
- const_iterator begin() const { return mValues.begin(); }
- const_iterator end() const { return mValues.end(); }
- bool empty() const { return mValues.empty(); }
- size_t size() const { return mValues.size(); }
-
- size_t numValidElements() const
- {
- return mValues.size();
- }
-
- protected:
- static bool mergeWith(Param& dst, const Param& src, bool overwrite)
- {
- const self_t& src_typed_param = static_cast<const self_t&>(src);
- self_t& dst_typed_param = static_cast<self_t&>(dst);
-
- if (overwrite)
- {
- std::copy(src_typed_param.begin(), src_typed_param.end(), std::back_inserter(dst_typed_param.mValues));
- }
- else
- {
- container_t new_values(src_typed_param.mValues);
- std::copy(dst_typed_param.begin(), dst_typed_param.end(), std::back_inserter(new_values));
- std::swap(dst_typed_param.mValues, new_values);
- }
-
- if (src_typed_param.begin() != src_typed_param.end())
- {
- dst_typed_param.setProvided();
- }
- return true;
- }
-
- container_t mValues;
- size_t mMinCount,
- mMaxCount;
-
- private:
- void init( BlockDescriptor &block_descriptor, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count, const char* name )
- {
- ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor(
- block_descriptor.mCurrentBlockPtr->getHandleFromParam(this),
- &mergeWith,
- &deserializeParam,
- &serializeParam,
- validate_func,
- &inspectParam,
- min_count, max_count));
- block_descriptor.addParam(param_descriptor, name);
- }
- };
-
- // list of block parameters
- template <typename MULTI_BLOCK_T, typename NAME_VALUE_LOOKUP>
- class TypedParam<MULTI_BLOCK_T, NAME_VALUE_LOOKUP, true, IS_A_BLOCK>
- : public Param
- {
- protected:
- typedef TypedParam<MULTI_BLOCK_T, NAME_VALUE_LOOKUP, true, IS_A_BLOCK> self_t;
- typedef ParamValue<typename LLTypeTags::Sorted<MULTI_BLOCK_T>::value_t> param_value_t;
- typedef typename std::vector<typename NAME_VALUE_LOOKUP::type_value_t> container_t;
- typedef typename NAME_VALUE_LOOKUP::type_value_t named_value_t;
- typedef container_t default_value_t;
- typedef typename container_t::iterator iterator;
- typedef typename container_t::const_iterator const_iterator;
- public:
- typedef typename param_value_t::value_t value_t;
-
- 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),
- mMinCount(min_count),
- mMaxCount(max_count)
- {
- std::copy(value.begin(), value.end(), back_inserter(mValues));
-
- if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING))
- {
- init(block_descriptor, validate_func, min_count, max_count, name);
- }
- }
-
- 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, Parser::name_stack_range_t& name_stack_range, bool new_name)
- {
- Parser::name_stack_range_t new_name_stack_range(name_stack_range);
- self_t& typed_param = static_cast<self_t&>(param);
- bool new_value = false;
- bool new_array_value = false;
-
- // pop first element if empty string
- if (new_name_stack_range.first != new_name_stack_range.second && new_name_stack_range.first->first.empty())
- {
- new_array_value = new_name_stack_range.first->second;
- ++new_name_stack_range.first;
- }
-
- if (new_name || new_array_value || typed_param.mValues.empty())
- {
- new_value = true;
- typed_param.mValues.push_back(value_t());
- }
- param_value_t& value = typed_param.mValues.back();
-
- if (new_name_stack_range.first == new_name_stack_range.second)
- { // try to parse a known named value
- std::string name;
-
- if(named_value_t::valueNamesExist()
- && parser.readValue(name)
- && named_value_t::getValueFromName(name, value.getValue()))
- {
- typed_param.mValues.back().setValueName(name);
- typed_param.setProvided();
- if (new_array_value)
- {
- name_stack_range.first->second = false;
- }
- return true;
- }
- }
-
- // attempt to parse block...
- if(value.deserializeBlock(parser, new_name_stack_range, new_name))
- {
- typed_param.setProvided();
- if (new_array_value)
- {
- name_stack_range.first->second = false;
- }
- return true;
- }
-
-
- if (new_value)
- { // failed to parse new value, pop it off
- typed_param.mValues.pop_back();
- }
-
- return false;
- }
-
- 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);
- LLPredicate::Value<ESerializePredicates> predicate;
-
- predicate.set(REQUIRED, typed_param.mMinCount > 0);
- predicate.set(VALID, typed_param.isValid());
- predicate.set(PROVIDED, typed_param.anyProvided());
- predicate.set(EMPTY, typed_param.mValues.empty());
-
- if (!predicate_rule.check(predicate)) return false;
-
- for (const_iterator it = typed_param.mValues.begin(), end_it = typed_param.mValues.end();
- it != end_it;
- ++it)
- {
- name_stack.push_back(std::make_pair(std::string(), true));
-
- std::string key = it->getValueName();
- if (!key.empty())
- {
- serialized |= parser.writeValue(key, name_stack);
- }
- // Not parsed via named values, write out value directly
- // NOTE: currently we don't do diffing of Multiples
- else
- {
- serialized = it->serializeBlock(parser, name_stack, predicate_rule, NULL);
- }
-
- name_stack.pop_back();
- }
-
- if (!serialized && predicate_rule.check(ll_make_predicate(EMPTY)))
- {
- serialized |= parser.writeValue(Flag(), name_stack);
- }
-
- return serialized;
- }
-
- static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count)
- {
- const param_value_t& value_param = param_value_t(value_t());
-
- // tell parser about our actual type
- parser.inspectValue<value_t>(name_stack, min_count, max_count, NULL);
- // then tell it about string-based alternatives ("red", "blue", etc. for LLColor4)
- if (named_value_t::getPossibleValues())
- {
- parser.inspectValue<std::string>(name_stack, min_count, max_count, named_value_t::getPossibleValues());
- }
-
- value_param.inspectBlock(parser, name_stack, min_count, max_count);
- }
-
- void set(const container_t& val, bool flag_as_provided = true)
- {
- mValues = val;
- setProvided(flag_as_provided);
- }
-
- param_value_t& add()
- {
- mValues.push_back(value_t());
- setProvided();
- return mValues.back();
- }
-
- self_t& add(const value_t& item)
- {
- mValues.push_back(item);
- setProvided();
- return *this;
- }
-
- self_t& add(const typename named_value_t::name_t& name)
- {
- value_t value;
-
- // try to parse a per type named value
- if (named_value_t::getValueFromName(name, value))
- {
- add(value);
- mValues.back().setValueName(name);
- }
- return *this;
- }
-
- // implicit conversion
- operator const container_t&() const { return mValues; }
- // explicit conversion
- const container_t& operator()() const { return mValues; }
-
- iterator begin() { return mValues.begin(); }
- iterator end() { return mValues.end(); }
- const_iterator begin() const { return mValues.begin(); }
- const_iterator end() const { return mValues.end(); }
- bool empty() const { return mValues.empty(); }
- size_t size() const { return mValues.size(); }
-
- size_t numValidElements() const
- {
- size_t count = 0;
- for (const_iterator it = mValues.begin(), end_it = mValues.end();
- it != end_it;
- ++it)
- {
- if(it->isValid()) count++;
- }
- return count;
- }
-
- protected:
-
- static bool mergeWith(Param& dst, const Param& src, bool overwrite)
- {
- const self_t& src_typed_param = static_cast<const self_t&>(src);
- self_t& dst_typed_param = static_cast<self_t&>(dst);
-
- if (overwrite)
- {
- std::copy(src_typed_param.begin(), src_typed_param.end(), std::back_inserter(dst_typed_param.mValues));
- }
- else
- {
- container_t new_values(src_typed_param.mValues);
- std::copy(dst_typed_param.begin(), dst_typed_param.end(), std::back_inserter(new_values));
- std::swap(dst_typed_param.mValues, new_values);
- }
-
- if (src_typed_param.begin() != src_typed_param.end())
- {
- dst_typed_param.setProvided();
- }
-
- return true;
- }
-
- container_t mValues;
- size_t mMinCount,
- mMaxCount;
-
- private:
- void init( BlockDescriptor &block_descriptor, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count, const char* name )
- {
- ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor(
- block_descriptor.mCurrentBlockPtr->getHandleFromParam(this),
- &mergeWith,
- &deserializeParam,
- &serializeParam,
- validate_func,
- &inspectParam,
- min_count, max_count));
- block_descriptor.addParam(param_descriptor, name);
- }
- };
-
- template <typename DERIVED_BLOCK, typename BASE_BLOCK = BaseBlock>
- class ChoiceBlock : public BASE_BLOCK
- {
- typedef ChoiceBlock<DERIVED_BLOCK, BASE_BLOCK> self_t;
- typedef ChoiceBlock<DERIVED_BLOCK, BASE_BLOCK> enclosing_block_t;
- typedef BASE_BLOCK base_block_t;
-
- LOG_CLASS(self_t);
- public:
- // 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);
- }
-
- bool mergeBlockParam(bool source_provided, bool dest_provided, BlockDescriptor& block_data, const self_t& source, bool overwrite)
- {
- bool source_override = source_provided && (overwrite || !dest_provided);
-
- if (source_override || source.mCurChoice == mCurChoice)
- {
- return mergeBlock(block_data, source, overwrite);
- }
- return false;
- }
-
- // merge with other block
- bool mergeBlock(BlockDescriptor& block_data, const self_t& other, bool overwrite)
- {
- mCurChoice = other.mCurChoice;
- return base_block_t::mergeBlock(getBlockDescriptor(), other, overwrite);
- }
-
- // clear out old choice when param has changed
- /*virtual*/ void paramChanged(const Param& changed_param, bool user_provided)
- {
- param_handle_t changed_param_handle = base_block_t::getHandleFromParam(&changed_param);
- // if we have a new choice...
- if (changed_param_handle != mCurChoice)
- {
- // clear provided flag on previous choice
- Param* previous_choice = base_block_t::getParamFromHandle(mCurChoice);
- if (previous_choice)
- {
- previous_choice->setProvided(false);
- }
- mCurChoice = changed_param_handle;
- }
- base_block_t::paramChanged(changed_param, user_provided);
- }
-
- virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return getBlockDescriptor(); }
- virtual BlockDescriptor& mostDerivedBlockDescriptor() { return getBlockDescriptor(); }
-
- protected:
- ChoiceBlock()
- : mCurChoice(0)
- {
- BaseBlock::init(getBlockDescriptor(), base_block_t::getBlockDescriptor(), sizeof(DERIVED_BLOCK));
- }
-
- // Alternatives are mutually exclusive wrt other Alternatives in the same block.
- // One alternative in a block will always have isChosen() == true.
- // At most one alternative in a block will have isProvided() == true.
- template <typename T, typename NAME_VALUE_LOOKUP = typename TypeValues<T>::type_value_t >
- class Alternative : public TypedParam<T, NAME_VALUE_LOOKUP, false>
- {
- typedef TypedParam<T, NAME_VALUE_LOOKUP, false> super_t;
- typedef typename super_t::value_t value_t;
- typedef typename super_t::default_value_t default_value_t;
-
- public:
- friend class ChoiceBlock<DERIVED_BLOCK>;
-
- using super_t::operator =;
-
- explicit Alternative(const char* name = "", const default_value_t& val = defaultValue<default_value_t>())
- : super_t(DERIVED_BLOCK::getBlockDescriptor(), name, val, NULL, 0, 1),
- mOriginalValue(val)
- {
- // assign initial choice to first declared option
- DERIVED_BLOCK* blockp = ((DERIVED_BLOCK*)DERIVED_BLOCK::getBlockDescriptor().mCurrentBlockPtr);
- if (LL_UNLIKELY(DERIVED_BLOCK::getBlockDescriptor().mInitializationState == BlockDescriptor::INITIALIZING))
- {
- if(blockp->mCurChoice == 0)
- {
- blockp->mCurChoice = Param::enclosingBlock().getHandleFromParam(this);
- }
- }
- }
-
- void choose()
- {
- static_cast<enclosing_block_t&>(Param::enclosingBlock()).paramChanged(*this, true);
- }
-
- void chooseAs(const value_t& val)
- {
- super_t::set(val);
- }
-
- void operator =(const value_t& val)
- {
- super_t::set(val);
- }
-
- void operator()(const value_t& val)
- {
- super_t::set(val);
- }
-
- operator const value_t&() const
- {
- return (*this)();
- }
-
- const value_t& operator()() const
- {
- if (static_cast<enclosing_block_t&>(Param::enclosingBlock()).getCurrentChoice() == this)
- {
- return super_t::getValue();
- }
- return mOriginalValue;
- }
-
- bool isChosen() const
- {
- return static_cast<enclosing_block_t&>(Param::enclosingBlock()).getCurrentChoice() == this;
- }
-
- private:
- default_value_t mOriginalValue;
- };
-
- public:
- static BlockDescriptor& getBlockDescriptor()
- {
- static BlockDescriptor sBlockDescriptor;
- return sBlockDescriptor;
- }
-
- private:
- param_handle_t mCurChoice;
-
- const Param* getCurrentChoice() const
- {
- return base_block_t::getParamFromHandle(mCurChoice);
- }
- };
-
- template <typename DERIVED_BLOCK, typename BASE_BLOCK = BaseBlock>
- class Block
- : public BASE_BLOCK
- {
- typedef Block<DERIVED_BLOCK, BASE_BLOCK> self_t;
-
- 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));
- }
-
- //
- // Nested classes for declaring parameters
- //
- 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;
- typedef typename super_t::value_t value_t;
- typedef typename super_t::default_value_t default_value_t;
-
- public:
- using super_t::operator();
- using super_t::operator =;
-
- explicit Optional(const char* name = "", const default_value_t& val = defaultValue<default_value_t>())
- : super_t(DERIVED_BLOCK::getBlockDescriptor(), name, val, NULL, 0, 1)
- {
- //#pragma message("Parsing LLInitParam::Block::Optional")
- }
-
- Optional& operator =(const value_t& val)
- {
- super_t::set(val);
- return *this;
- }
-
- 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;
- typedef Mandatory<T, NAME_VALUE_LOOKUP> self_t;
- typedef typename super_t::value_t value_t;
- typedef typename super_t::default_value_t default_value_t;
-
- public:
- using super_t::operator();
- using super_t::operator =;
-
- // mandatory parameters require a name to be parseable
- explicit Mandatory(const char* name = "", const default_value_t& val = defaultValue<default_value_t>())
- : super_t(DERIVED_BLOCK::getBlockDescriptor(), name, val, &validate, 1, 1)
- {}
-
- Mandatory& operator =(const value_t& val)
- {
- super_t::set(val);
- return *this;
- }
-
- 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;
- 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&;
-
- explicit Multiple(const char* name = "")
- : super_t(DERIVED_BLOCK::getBlockDescriptor(), name, container_t(), &validate, RANGE::minCount, RANGE::maxCount)
- {}
-
- Multiple& operator =(const container_t& val)
- {
- super_t::set(val);
- return *this;
- }
-
- 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();
- 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
- {
- public:
- 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),
- NULL,
- &deserializeParam,
- NULL,
- NULL,
- NULL,
- 0, S32_MAX));
- 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;
- }
-
- protected:
- template <typename T, typename NAME_VALUE_LOOKUP, bool multiple, typename is_block>
- void changeDefault(TypedParam<T, NAME_VALUE_LOOKUP, multiple, is_block>& param,
- 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>
- struct IsBlock<ParamValue<BaseBlock::Lazy<T, BaseBlock::IS_A_BLOCK>, BLOCK_T >, void>
- {
- typedef IS_A_BLOCK value_t;
- };
-
- template<typename T, typename BLOCK_T>
- struct IsBlock<ParamValue<BaseBlock::Lazy<T, BaseBlock::NOT_A_BLOCK>, BLOCK_T >, void>
- {
- typedef NOT_BLOCK value_t;
- };
-
- template<typename T, typename BLOCK_IDENTIFIER>
- struct IsBlock<ParamValue<BaseBlock::Atomic<T>, typename IsBlock<BaseBlock::Atomic<T> >::value_t >, BLOCK_IDENTIFIER>
- {
- typedef typename IsBlock<T>::value_t value_t;
- };
-
- template<typename T, typename BLOCK_IDENTIFIER>
- struct IsBlock<ParamValue<BaseBlock::Sequential<T>, typename IsBlock<BaseBlock::Sequential<T> >::value_t >, BLOCK_IDENTIFIER>
- {
- typedef typename IsBlock<T>::value_t value_t;
- };
-
-
- template<typename T>
- struct InnerMostType
- {
- typedef T value_t;
- };
-
- template<typename T>
- struct InnerMostType<ParamValue<T, NOT_BLOCK> >
- {
- typedef typename InnerMostType<T>::value_t value_t;
- };
-
- template<typename T>
- struct InnerMostType<ParamValue<T, IS_A_BLOCK> >
- {
- typedef typename InnerMostType<T>::value_t value_t;
- };
-
- template<typename T, typename BLOCK_T>
- class ParamValue <BaseBlock::Atomic<T>, BLOCK_T>
- {
- typedef ParamValue <BaseBlock::Atomic<T>, BLOCK_T> self_t;
-
- public:
- typedef typename InnerMostType<T>::value_t value_t;
- typedef T default_value_t;
-
- ParamValue()
- : mValue()
- {}
-
- ParamValue(const default_value_t& value)
- : mValue(value)
- {}
-
- void setValue(const value_t& val)
- {
- mValue.setValue(val);
- }
-
- const value_t& getValue() const
- {
- return mValue.getValue();
- }
-
- value_t& getValue()
- {
- return mValue.getValue();
- }
-
- bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name)
- {
- if (new_name)
- {
- resetToDefault();
- }
- 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)
- {
- if ((overwrite && source_provided) // new values coming in on top or...
- || (!overwrite && !dst_provided)) // values being pushed under with nothing already there
- {
- // clear away what is there and take the new stuff as a whole
- resetToDefault();
- return mValue.mergeBlock(block_data, source.getValue(), overwrite);
- }
- 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:
- void resetToDefault()
- {
- static T default_value;
- mValue = default_value;
- }
-
- T mValue;
- };
-
- template<typename T>
- class ParamValue <BaseBlock::Sequential<T>, IS_A_BLOCK>
- {
- typedef ParamValue <BaseBlock::Sequential<T>, IS_A_BLOCK> self_t;
-
- public:
- typedef typename InnerMostType<T>::value_t value_t;
- typedef T default_value_t;
-
- ParamValue()
- : mValue()
- {
- mCurParam = getBlockDescriptor().mAllParams.begin();
- }
-
- ParamValue(const default_value_t& value)
- : mValue(value)
- {
- mCurParam = getBlockDescriptor().mAllParams.begin();
- }
-
- void setValue(const value_t& val)
- {
- mValue.setValue(val);
- }
-
- const value_t& getValue() const
- {
- return mValue.getValue();
- }
-
- value_t& getValue()
- {
- return mValue.getValue();
- }
-
- bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name)
- {
- if (new_name)
- {
- mCurParam = getBlockDescriptor().mAllParams.begin();
- }
- if (name_stack_range.first == name_stack_range.second
- && mCurParam != getBlockDescriptor().mAllParams.end())
- {
- // deserialize to mCurParam
- ParamDescriptor& pd = *(*mCurParam);
- ParamDescriptor::deserialize_func_t deserialize_func = pd.mDeserializeFunc;
- Param* paramp = mValue.getParamFromHandle(pd.mParamHandle);
-
- if (deserialize_func
- && paramp
- && deserialize_func(*paramp, p, name_stack_range, new_name))
- {
- ++mCurParam;
- return true;
- }
- else
- {
- return false;
- }
- }
- 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
- {
- 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>
- class ParamValue <BaseBlock::Lazy<T, IS_A_BLOCK>, BLOCK_T>
- {
- typedef ParamValue <BaseBlock::Lazy<T, IS_A_BLOCK>, BLOCK_T> self_t;
-
- public:
- typedef typename InnerMostType<T>::value_t value_t;
- typedef LazyValue<T> default_value_t;
-
- ParamValue()
- : mValue()
- {}
-
- ParamValue(const default_value_t& other)
- : mValue(other)
- {}
-
- ParamValue(const T& value)
- : mValue(value)
- {}
-
- void setValue(const value_t& val)
- {
- mValue.set(val);
- }
-
- const value_t& getValue() const
- {
- return mValue.get().getValue();
- }
-
- value_t& getValue()
- {
- return mValue.get().getValue();
- }
-
- 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())
- : NULL;
- 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();
- }
-
- private:
- LazyValue<T> mValue;
- };
-
- template<typename T, typename BLOCK_T>
- class ParamValue <BaseBlock::Lazy<T, NOT_BLOCK>, BLOCK_T>
- {
- typedef ParamValue <BaseBlock::Lazy<T, NOT_BLOCK>, BLOCK_T> self_t;
-
- public:
- typedef typename InnerMostType<T>::value_t value_t;
- typedef LazyValue<T> default_value_t;
-
- ParamValue()
- : mValue()
- {}
-
- ParamValue(const default_value_t& other)
- : mValue(other)
- {}
-
- ParamValue(const T& value)
- : mValue(value)
- {}
-
- void setValue(const value_t& val)
- {
- mValue.set(val);
- }
-
- const value_t& getValue() const
- {
- return mValue.get().getValue();
- }
-
- value_t& getValue()
- {
- return mValue.get().getValue();
- }
-
- bool isValid() const
- {
- return true;
- }
-
- private:
- LazyValue<T> mValue;
- };
-
- template <>
- class ParamValue <LLSD, NOT_BLOCK>
- : public BaseBlock
- {
- public:
- typedef LLSD value_t;
- typedef LLSD default_value_t;
-
- ParamValue()
- {}
-
- ParamValue(const default_value_t& other)
- : mValue(other)
- {}
-
- void setValue(const value_t& val) { mValue = val; }
-
- 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;
- };
-
- template<typename T>
- class CustomParamValue
- : public Block<ParamValue<T> >
- {
- public:
- typedef enum e_value_age
- {
- 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
- } EValueAge;
-
- typedef TypeValues<T> derived_t;
- typedef CustomParamValue<T> self_t;
- typedef Block<ParamValue<T> > block_t;
- typedef T default_value_t;
- typedef T value_t;
- typedef void baseblock_base_class_t;
-
-
- CustomParamValue(const default_value_t& value = T())
- : mValue(value),
- 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)
- {
- if(parser.readValue(typed_param.mValue))
- {
- typed_param.mValueAge = VALUE_AUTHORITATIVE;
- typed_param.updateBlockFromValue(false);
-
- return true;
- }
- }
-
- // fall back on parsing block components for T
- 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);
- // }
- //}
- // then try to serialize value directly
- 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);
- }
- else
- {
- return block_t::serializeBlock(parser, name_stack, predicate_rule, NULL);
- }
- }
- }
- return false;
- }
-
- bool validateBlock(bool emit_errors = true) const
- {
- if (mValueAge == VALUE_NEEDS_UPDATE)
- {
- if (block_t::validateBlock(emit_errors))
- {
- // 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;
- }
- }
-
- // propagate change status up to enclosing block
- /*virtual*/ void paramChanged(const Param& changed_param, bool user_provided)
- {
- BaseBlock::paramChanged(changed_param, user_provided);
- if (user_provided)
- {
- // a parameter changed, so our value is out of date
- mValueAge = VALUE_NEEDS_UPDATE;
- }
- }
-
- 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);
- }
-
- const value_t& getValue() const
- {
- validateBlock(true);
- return mValue;
- }
-
- T& getValue()
- {
- validateBlock(true);
- return mValue;
- }
-
- protected:
-
- // use this from within updateValueFromBlock() to set the value without making it authoritative
- void updateValue(const value_t& value)
- {
- mValue = value;
- }
-
- bool mergeBlockParam(bool source_provided, bool dst_provided, BlockDescriptor& block_data, const BaseBlock& source, bool overwrite)
- {
- bool source_override = source_provided && (overwrite || !dst_provided);
-
- const derived_t& src_typed_param = static_cast<const derived_t&>(source);
-
- if (source_override && src_typed_param.mValueAge == VALUE_AUTHORITATIVE)
- {
- // copy value over
- setValue(src_typed_param.getValue());
- return true;
- }
- // merge individual parameters into destination
- if (mValueAge == VALUE_AUTHORITATIVE)
- {
- static_cast<derived_t*>(this)->updateBlockFromValue(dst_provided);
- }
- 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;
- };
+
+ // empty default implementation of key cache
+ // leverages empty base class optimization
+ template <typename T>
+ class TypeValues
+ : public ParamValue<typename LLTypeTags::Sorted<T>::value_t>
+ {
+ private:
+ struct Inaccessable{};
+ public:
+ typedef std::map<std::string, T> value_name_map_t;
+ typedef Inaccessable name_t;
+ typedef TypeValues<T> type_value_t;
+ typedef ParamValue<typename LLTypeTags::Sorted<T>::value_t> param_value_t;
+ typedef typename param_value_t::value_t value_t;
+
+ TypeValues(const typename param_value_t::value_t& val)
+ : param_value_t(val)
+ {}
+
+ void setValueName(const std::string& key) {}
+ std::string getValueName() const { return ""; }
+ std::string calcValueName(const value_t& value) const { return ""; }
+ void clearValueName() const {}
+
+ static bool getValueFromName(const std::string& name, value_t& value)
+ {
+ return false;
+ }
+
+ static bool valueNamesExist()
+ {
+ return false;
+ }
+
+ static std::vector<std::string>* getPossibleValues()
+ {
+ return NULL;
+ }
+
+ void assignNamedValue(const Inaccessable& name)
+ {}
+
+ operator const value_t&() const
+ {
+ return param_value_t::getValue();
+ }
+
+ const value_t& operator()() const
+ {
+ return param_value_t::getValue();
+ }
+
+ static value_name_map_t* getValueNames() {return NULL;}
+ };
+
+ // helper class to implement name value lookups
+ // and caching of last used name
+ template <typename T, typename DERIVED_TYPE = TypeValues<T>, bool IS_SPECIALIZED = true >
+ class TypeValuesHelper
+ : public ParamValue<typename LLTypeTags::Sorted<T>::value_t>
+ {
+ typedef TypeValuesHelper<T, DERIVED_TYPE, IS_SPECIALIZED> self_t;
+ public:
+ typedef typename std::map<std::string, T> value_name_map_t;
+ typedef std::string name_t;
+ typedef self_t type_value_t;
+ typedef ParamValue<typename LLTypeTags::Sorted<T>::value_t> param_value_t;
+ typedef typename param_value_t::value_t value_t;
+
+ TypeValuesHelper(const typename param_value_t::value_t& val)
+ : param_value_t(val)
+ {}
+
+ //TODO: cache key by index to save on param block size
+ void setValueName(const std::string& value_name)
+ {
+ mValueName = value_name;
+ }
+
+ std::string getValueName() const
+ {
+ return mValueName;
+ }
+
+ std::string calcValueName(const value_t& value) const
+ {
+ value_name_map_t* map = getValueNames();
+ for (typename value_name_map_t::value_type& map_pair : *map)
+ {
+ if (ParamCompare<T>::equals(map_pair.second, value))
+ {
+ return map_pair.first;
+ }
+ }
+
+ return "";
+ }
+
+ void clearValueName() const
+ {
+ mValueName.clear();
+ }
+
+ static bool getValueFromName(const std::string& name, value_t& value)
+ {
+ value_name_map_t* map = getValueNames();
+ typename value_name_map_t::iterator found_it = map->find(name);
+ if (found_it == map->end()) return false;
+
+ value = found_it->second;
+ return true;
+ }
+
+ static bool valueNamesExist()
+ {
+ return !getValueNames()->empty();
+ }
+
+ static value_name_map_t* getValueNames()
+ {
+ static value_name_map_t sMap;
+ static bool sInitialized = false;
+
+ if (!sInitialized)
+ {
+ sInitialized = true;
+ DERIVED_TYPE::declareValues();
+ }
+ return &sMap;
+ }
+
+ static std::vector<std::string>* getPossibleValues()
+ {
+ static std::vector<std::string> sValues;
+
+ value_name_map_t* map = getValueNames();
+ for (typename value_name_map_t::value_type& map_pair : *map)
+ {
+ sValues.push_back(map_pair.first);
+ }
+ return &sValues;
+ }
+
+ static void declare(const std::string& name, const value_t& value)
+ {
+ (*getValueNames())[name] = value;
+ }
+
+ void operator ()(const std::string& name)
+ {
+ *this = name;
+ }
+
+ void assignNamedValue(const std::string& name)
+ {
+ if (getValueFromName(name, param_value_t::getValue()))
+ {
+ setValueName(name);
+ }
+ }
+
+ operator const value_t&() const
+ {
+ return param_value_t::getValue();
+ }
+
+ const value_t& operator()() const
+ {
+ return param_value_t::getValue();
+ }
+
+ protected:
+ static void getName(const std::string& name, const value_t& value)
+ {}
+
+ mutable std::string mValueName;
+ };
+
+ // string types can support custom named values, but need
+ // to disambiguate in code between a string that is a named value
+ // and a string that is a name
+ template <typename DERIVED_TYPE>
+ class TypeValuesHelper<std::string, DERIVED_TYPE, true>
+ : public TypeValuesHelper<std::string, DERIVED_TYPE, false>
+ {
+ public:
+ typedef TypeValuesHelper<std::string, DERIVED_TYPE, true> self_t;
+ typedef TypeValuesHelper<std::string, DERIVED_TYPE, false> base_t;
+ typedef std::string value_t;
+ typedef std::string name_t;
+ typedef self_t type_value_t;
+
+ TypeValuesHelper(const std::string& val)
+ : base_t(val)
+ {}
+
+ void operator ()(const std::string& name)
+ {
+ *this = name;
+ }
+
+ self_t& operator =(const std::string& name)
+ {
+ if (base_t::getValueFromName(name, ParamValue<std::string>::getValue()))
+ {
+ base_t::setValueName(name);
+ }
+ else
+ {
+ ParamValue<std::string>::setValue(name);
+ }
+ return *this;
+ }
+
+ operator const value_t&() const
+ {
+ return ParamValue<std::string>::getValue();
+ }
+
+ const value_t& operator()() const
+ {
+ return ParamValue<std::string>::getValue();
+ }
+
+ };
+
+ // parser base class with mechanisms for registering readers/writers/inspectors of different types
+ class LL_COMMON_API Parser
+ {
+ LOG_CLASS(Parser);
+ 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;
+
+ 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;
+
+ public:
+
+ Parser(parser_read_func_map_t& read_map, parser_write_func_map_t& write_map, parser_inspect_func_map_t& inspect_map)
+ : mParseSilently(false),
+ mParserReadFuncs(&read_map),
+ mParserWriteFuncs(&write_map),
+ mParserInspectFuncs(&inspect_map)
+ {}
+
+ virtual ~Parser();
+
+ template <typename T> bool readValue(T& param, typename boost::disable_if<boost::is_enum<T> >::type* dummy = 0)
+ {
+ parser_read_func_map_t::iterator found_it = mParserReadFuncs->find(&typeid(T));
+ if (found_it != mParserReadFuncs->end())
+ {
+ return found_it->second(*this, (void*)&param);
+ }
+
+ return false;
+ }
+
+ template <typename T> bool readValue(T& param, typename boost::enable_if<boost::is_enum<T> >::type* dummy = 0)
+ {
+ parser_read_func_map_t::iterator found_it = mParserReadFuncs->find(&typeid(T));
+ if (found_it != mParserReadFuncs->end())
+ {
+ return found_it->second(*this, (void*)&param);
+ }
+ else
+ {
+ found_it = mParserReadFuncs->find(&typeid(S32));
+ if (found_it != mParserReadFuncs->end())
+ {
+ S32 int_value;
+ bool parsed = found_it->second(*this, (void*)&int_value);
+ param = (T)int_value;
+ return parsed;
+ }
+ }
+ return false;
+ }
+
+ 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 std::string getCurrentFileName() = 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));
+ }
+
+ bool mParseSilently;
+
+ private:
+ parser_read_func_map_t* mParserReadFuncs;
+ parser_write_func_map_t* mParserWriteFuncs;
+ parser_inspect_func_map_t* mParserInspectFuncs;
+ };
+
+ class Param;
+
+ 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
+ struct LL_COMMON_API ParamDescriptor
+ {
+ struct UserData
+ {
+ virtual ~UserData() {}
+ };
+
+ typedef bool(*merge_func_t)(Param&, const Param&, bool);
+ typedef bool(*deserialize_func_t)(Param&, Parser&, Parser::name_stack_range_t&, bool);
+ typedef bool(*serialize_func_t)(const Param&, Parser&, Parser::name_stack_t&, const predicate_rule_t rules, 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);
+
+ ParamDescriptor();
+ ~ParamDescriptor();
+
+ 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;
+ UserData* mUserData;
+ };
+
+ typedef std::shared_ptr<ParamDescriptor> ParamDescriptorPtr;
+
+ // each derived Block class keeps a static data structure maintaining offsets to various params
+ class LL_COMMON_API BlockDescriptor
+ {
+ public:
+ BlockDescriptor();
+
+ 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
+ };
+
+ //TODO: implement in terms of owned_ptr
+ template<typename T>
+ class LazyValue
+ {
+ public:
+ LazyValue()
+ : mPtr(NULL)
+ {}
+
+ ~LazyValue()
+ {
+ delete mPtr;
+ }
+
+ LazyValue(const T& value)
+ {
+ mPtr = new T(value);
+ }
+
+ LazyValue(const LazyValue& other)
+ : mPtr(NULL)
+ {
+ *this = other;
+ }
+
+ LazyValue& operator = (const LazyValue& other)
+ {
+ if (!other.mPtr)
+ {
+ delete mPtr;
+ mPtr = NULL;
+ }
+ else
+ {
+ if (!mPtr)
+ {
+ mPtr = new T(*other.mPtr);
+ }
+ else
+ {
+ *mPtr = *(other.mPtr);
+ }
+ }
+ return *this;
+ }
+
+ bool operator==(const LazyValue& other) const
+ {
+ if (empty() || other.empty()) return false;
+ return *mPtr == *other.mPtr;
+ }
+
+ bool empty() const
+ {
+ return mPtr == NULL;
+ }
+
+ void set(const T& other)
+ {
+ if (!mPtr)
+ {
+ mPtr = new T(other);
+ }
+ else
+ {
+ *mPtr = other;
+ }
+ }
+
+ const T& get() const
+ {
+ return *ensureInstance();
+ }
+
+ T& get()
+ {
+ return *ensureInstance();
+ }
+
+ operator const T&() const
+ {
+ return get();
+ }
+
+ private:
+ // lazily allocate an instance of T
+ T* ensureInstance() const
+ {
+ if (mPtr == NULL)
+ {
+ mPtr = new T();
+ }
+ return mPtr;
+ }
+
+ private:
+
+ mutable T* mPtr;
+ };
+
+ // root class of all parameter blocks
+
+ class LL_COMMON_API BaseBlock
+ {
+ public:
+ // lift block tags into baseblock namespace so derived classes do not need to qualify them
+ typedef LLInitParam::IS_A_BLOCK IS_A_BLOCK;
+ typedef LLInitParam::NOT_BLOCK NOT_A_BLOCK;
+
+ template<typename T>
+ struct Sequential : public LLTypeTags::TypeTagBase<T, 2>
+ {
+ template <typename S> struct Cons { typedef Sequential<ParamValue<S> > value_t; };
+ template <typename S> struct Cons<Sequential<S> > { typedef Sequential<S> value_t; };
+ };
+
+ template<typename T>
+ struct Atomic : public LLTypeTags::TypeTagBase<T, 1>
+ {
+ template <typename S> struct Cons { typedef Atomic<ParamValue<S> > value_t; };
+ template <typename S> struct Cons<Atomic<S> > { typedef Atomic<S> value_t; };
+ };
+
+ template<typename T, typename BLOCK_T = typename IsBlock<T>::value_t >
+ struct Lazy : public LLTypeTags::TypeTagBase<T, 0>
+ {
+ template <typename S> struct Cons
+ {
+ typedef Lazy<ParamValue<S, BLOCK_T>, BLOCK_T> value_t;
+ };
+ template <typename S> struct Cons<Lazy<S, IS_A_BLOCK> >
+ {
+ typedef Lazy<S, IS_A_BLOCK> value_t;
+ };
+ template <typename S> struct Cons<Lazy<S, NOT_A_BLOCK> >
+ {
+ typedef Lazy<S, BLOCK_T> value_t;
+ };
+ };
+
+ // "Multiple" constraint types, put here in root class to avoid ambiguity during use
+ struct AnyAmount
+ {
+ enum { minCount = 0 };
+ enum { maxCount = U32_MAX };
+ };
+
+ template<U32 MIN_AMOUNT>
+ struct AtLeast
+ {
+ enum { minCount = MIN_AMOUNT };
+ enum { maxCount = U32_MAX };
+ };
+
+ template<U32 MAX_AMOUNT>
+ struct AtMost
+ {
+ enum { minCount = 0 };
+ enum { maxCount = MAX_AMOUNT };
+ };
+
+ template<U32 MIN_AMOUNT, U32 MAX_AMOUNT>
+ struct Between
+ {
+ enum { minCount = MIN_AMOUNT };
+ enum { maxCount = MAX_AMOUNT };
+ };
+
+ template<U32 EXACT_COUNT>
+ struct Exactly
+ {
+ 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)
+ {}
+
+ 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;
+
+ 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 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);
+
+
+ bool mergeBlockParam(bool source_provided, bool dst_provided, BlockDescriptor& block_data, const BaseBlock& source, bool overwrite)
+ {
+ return mergeBlock(block_data, source, overwrite);
+ }
+
+ mutable bool mValidated; // lazy validation flag
+ bool mParamProvided;
+
+ private:
+ const std::string& getParamName(const BlockDescriptor& block_data, const Param* paramp) const;
+ };
+
+ class LL_COMMON_API Param
+ {
+ public:
+ void setProvided(bool is_provided = true)
+ {
+ mIsProvided = is_provided;
+ enclosingBlock().paramChanged(*this, is_provided);
+ }
+
+ Param& operator =(const Param& other)
+ {
+ mIsProvided = other.mIsProvided;
+ // don't change mEnclosingblockoffset
+ return *this;
+ }
+ 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)getEnclosingBlockOffset()));
+ }
+
+ U32 getEnclosingBlockOffset() const
+ {
+ return ((U32)mEnclosingBlockOffsetHigh << 16) | (U32)mEnclosingBlockOffsetLow;
+ }
+
+ private:
+ friend class BaseBlock;
+
+ //24 bits for member offset field and 1 bit for provided flag
+ U16 mEnclosingBlockOffsetLow;
+ U8 mEnclosingBlockOffsetHigh:7;
+ U8 mIsProvided:1;
+
+ };
+
+ template<typename T, typename NAME_VALUE_LOOKUP = TypeValues<T> >
+ struct ParamIterator
+ {
+ 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;
+ };
+
+ // 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>
+ class TypedParam
+ : public Param,
+ public NAME_VALUE_LOOKUP::type_value_t
+ {
+ protected:
+ typedef TypedParam<T, NAME_VALUE_LOOKUP, HAS_MULTIPLE_VALUES, VALUE_IS_BLOCK> self_t;
+ typedef ParamValue<typename LLTypeTags::Sorted<T>::value_t> param_value_t;
+ typedef typename param_value_t::default_value_t default_value_t;
+ typedef typename NAME_VALUE_LOOKUP::type_value_t named_value_t;
+ public:
+ typedef typename param_value_t::value_t value_t;
+
+ 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),
+ 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(); }
+
+ bool isValid() const { return true; }
+
+ static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name)
+ {
+ self_t& typed_param = static_cast<self_t&>(param);
+ // no further names in stack, attempt to parse value now
+ if (name_stack_range.first == name_stack_range.second)
+ {
+ std::string name;
+
+ // try to parse a known named value
+ if(named_value_t::valueNamesExist()
+ && parser.readValue(name)
+ && named_value_t::getValueFromName(name, typed_param.getValue()))
+ {
+ typed_param.setValueName(name);
+ typed_param.setProvided();
+ return true;
+ }
+ // try to read value directly
+ else if (parser.readValue(typed_param.getValue()))
+ {
+ typed_param.clearValueName();
+ typed_param.setProvided();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ 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);
+ }
+
+ predicate.set(VALID, typed_param.isValid());
+ predicate.set(PROVIDED, typed_param.anyProvided());
+ predicate.set(EMPTY, false);
+
+ if (!predicate_rule.check(predicate)) return false;
+
+ if (!name_stack.empty())
+ {
+ 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);
+ }
+ }
+ // then try to serialize value directly
+ 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 (calculated_key.size()
+ && (!diff_typed_param
+ || !ParamCompare<std::string>::equals(static_cast<const self_t*>(diff_param)->getValueName(), calculated_key)))
+ {
+ serialized = parser.writeValue(calculated_key, name_stack);
+ }
+ }
+ }
+ return serialized;
+ }
+
+ 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 (named_value_t::getPossibleValues())
+ {
+ parser.inspectValue<std::string>(name_stack, min_count, max_count, named_value_t::getPossibleValues());
+ }
+ }
+
+ void set(const value_t& val, bool flag_as_provided = true)
+ {
+ named_value_t::clearValueName();
+ named_value_t::setValue(val);
+ setProvided(flag_as_provided);
+ }
+
+ self_t& operator =(const typename named_value_t::name_t& name)
+ {
+ named_value_t::assignNamedValue(name);
+ return *this;
+ }
+
+ protected:
+
+ self_t& operator =(const self_t& other)
+ {
+ param_value_t::operator =(other);
+ Param::operator =(other);
+ return *this;
+ }
+
+ static bool mergeWith(Param& dst, const Param& src, bool overwrite)
+ {
+ const self_t& src_typed_param = static_cast<const self_t&>(src);
+ self_t& dst_typed_param = static_cast<self_t&>(dst);
+
+ if (src_typed_param.isProvided()
+ && (overwrite || !dst_typed_param.isProvided()))
+ {
+ dst_typed_param.set(src_typed_param.getValue());
+ return true;
+ }
+ return false;
+ }
+ private:
+ void init( BlockDescriptor &block_descriptor, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count, const char* name )
+ {
+ ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor(
+ block_descriptor.mCurrentBlockPtr->getHandleFromParam(this),
+ &mergeWith,
+ &deserializeParam,
+ &serializeParam,
+ validate_func,
+ &inspectParam,
+ min_count, max_count));
+ block_descriptor.addParam(param_descriptor, name);
+ }
+ };
+
+ // parameter that is a block
+ template <typename BLOCK_T, typename NAME_VALUE_LOOKUP>
+ class TypedParam<BLOCK_T, NAME_VALUE_LOOKUP, false, IS_A_BLOCK>
+ : public Param,
+ public NAME_VALUE_LOOKUP::type_value_t
+ {
+ protected:
+ typedef ParamValue<typename LLTypeTags::Sorted<BLOCK_T>::value_t> param_value_t;
+ typedef typename param_value_t::default_value_t default_value_t;
+ typedef TypedParam<BLOCK_T, NAME_VALUE_LOOKUP, false, IS_A_BLOCK> self_t;
+ typedef typename NAME_VALUE_LOOKUP::type_value_t named_value_t;
+ public:
+ using named_value_t::operator();
+ typedef typename param_value_t::value_t value_t;
+
+ TypedParam(BlockDescriptor& block_descriptor, const char* name, const default_value_t& value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count)
+ : Param(block_descriptor.mCurrentBlockPtr),
+ named_value_t(value)
+ {
+ if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING))
+ {
+ init(block_descriptor, validate_func, min_count, max_count, name);
+ }
+ }
+
+ static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name)
+ {
+ self_t& typed_param = static_cast<self_t&>(param);
+
+ if (name_stack_range.first == name_stack_range.second)
+ { // try to parse a known named value
+ std::string name;
+
+ if(named_value_t::valueNamesExist()
+ && parser.readValue(name)
+ && named_value_t::getValueFromName(name, typed_param.getValue()))
+ {
+ typed_param.setValueName(name);
+ typed_param.setProvided();
+ return true;
+ }
+ }
+
+ if(typed_param.deserializeBlock(parser, name_stack_range, new_name))
+ { // attempt to parse block...
+ typed_param.clearValueName();
+ typed_param.setProvided();
+ return true;
+ }
+
+
+ return false;
+ }
+
+ static bool 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;
+
+ predicate.set(VALID, typed_param.isValid());
+ predicate.set(PROVIDED, typed_param.anyProvided());
+
+ if (!predicate_rule.check(predicate)) return false;
+
+ if (!name_stack.empty())
+ {
+ name_stack.back().second = true;
+ }
+
+ std::string key = typed_param.getValueName();
+ if (!key.empty())
+ {
+ if (!diff_param || !ParamCompare<std::string>::equals(static_cast<const self_t*>(diff_param)->getValueName(), key))
+ {
+ parser.writeValue(key, name_stack);
+ return true;
+ }
+ }
+ else
+ {
+ return typed_param.serializeBlock(parser, name_stack, predicate_rule, static_cast<const self_t*>(diff_param));
+ }
+
+ return false;
+ }
+
+ static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count)
+ {
+ const self_t& typed_param = static_cast<const self_t&>(param);
+
+ // tell parser about our actual type
+ parser.inspectValue<value_t>(name_stack, min_count, max_count, NULL);
+ // then tell it about string-based alternatives ("red", "blue", etc. for LLColor4)
+ if (named_value_t::getPossibleValues())
+ {
+ parser.inspectValue<std::string>(name_stack, min_count, max_count, named_value_t::getPossibleValues());
+ }
+
+ typed_param.inspectBlock(parser, name_stack, min_count, max_count);
+ }
+
+ // a param-that-is-a-block is provided when the user has set one of its child params
+ // *and* the block as a whole validates
+ bool isProvided() const
+ {
+ return Param::anyProvided() && isValid();
+ }
+
+ bool isValid() const
+ {
+ return param_value_t::isValid();
+ }
+
+ // assign block contents to this param-that-is-a-block
+ void set(const value_t& val, bool flag_as_provided = true)
+ {
+ named_value_t::setValue(val);
+ named_value_t::clearValueName();
+ setProvided(flag_as_provided);
+ }
+
+ self_t& operator =(const typename named_value_t::name_t& name)
+ {
+ named_value_t::assignNamedValue(name);
+ return *this;
+ }
+
+ // propagate changed status up to enclosing block
+ /*virtual*/ void paramChanged(const Param& changed_param, bool user_provided)
+ {
+ param_value_t::paramChanged(changed_param, user_provided);
+
+ if (user_provided)
+ {
+ setProvided();
+ named_value_t::clearValueName();
+ }
+ else
+ {
+ Param::enclosingBlock().paramChanged(*this, user_provided);
+ }
+ }
+
+ protected:
+
+ self_t& operator =(const self_t& other)
+ {
+ param_value_t::operator =(other);
+ Param::operator =(other);
+ return *this;
+ }
+
+ static bool mergeWith(Param& dst, const Param& src, bool overwrite)
+ {
+ const self_t& src_typed_param = static_cast<const self_t&>(src);
+ self_t& dst_typed_param = static_cast<self_t&>(dst);
+
+ if (src_typed_param.anyProvided())
+ {
+ if (dst_typed_param.mergeBlockParam(src_typed_param.isProvided(), dst_typed_param.isProvided(), param_value_t::getBlockDescriptor(), src_typed_param, overwrite))
+ {
+ dst_typed_param.clearValueName();
+ dst_typed_param.setProvided(true);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private:
+ void init( BlockDescriptor &block_descriptor, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count, const char* name )
+ {
+ ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor(
+ block_descriptor.mCurrentBlockPtr->getHandleFromParam(this),
+ &mergeWith,
+ &deserializeParam,
+ &serializeParam,
+ validate_func,
+ &inspectParam,
+ min_count, max_count));
+ block_descriptor.addParam(param_descriptor, name);
+ }
+ };
+
+ // list of non-block parameters
+ template <typename MULTI_VALUE_T, typename NAME_VALUE_LOOKUP>
+ class TypedParam<MULTI_VALUE_T, NAME_VALUE_LOOKUP, true, NOT_BLOCK>
+ : public Param
+ {
+ protected:
+ typedef TypedParam<MULTI_VALUE_T, NAME_VALUE_LOOKUP, true, NOT_BLOCK> self_t;
+ typedef ParamValue<typename LLTypeTags::Sorted<MULTI_VALUE_T>::value_t> param_value_t;
+ typedef typename std::vector<typename NAME_VALUE_LOOKUP::type_value_t> container_t;
+ typedef container_t default_value_t;
+ typedef typename NAME_VALUE_LOOKUP::type_value_t named_value_t;
+
+ public:
+ typedef typename param_value_t::value_t value_t;
+
+ 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),
+ mMinCount(min_count),
+ mMaxCount(max_count)
+ {
+ std::copy(value.begin(), value.end(), std::back_inserter(mValues));
+
+ if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING))
+ {
+ init(block_descriptor, validate_func, min_count, max_count, name);
+
+ }
+ }
+
+ 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, Parser::name_stack_range_t& name_stack_range, bool new_name)
+ {
+ Parser::name_stack_range_t new_name_stack_range(name_stack_range);
+ self_t& typed_param = static_cast<self_t&>(param);
+ value_t value;
+
+ // pop first element if empty string
+ if (new_name_stack_range.first != new_name_stack_range.second && new_name_stack_range.first->first.empty())
+ {
+ ++new_name_stack_range.first;
+ }
+
+ // no further names in stack, attempt to parse value now
+ if (new_name_stack_range.first == new_name_stack_range.second)
+ {
+ std::string name;
+
+ // try to parse a known named value
+ if(named_value_t::valueNamesExist()
+ && parser.readValue(name)
+ && named_value_t::getValueFromName(name, value))
+ {
+ typed_param.add(value);
+ typed_param.mValues.back().setValueName(name);
+ return true;
+ }
+ else if (parser.readValue(value)) // attempt to read value directly
+ {
+ typed_param.add(value);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ 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);
+
+ LLPredicate::Value<ESerializePredicates> predicate;
+
+ predicate.set(REQUIRED, typed_param.mMinCount > 0);
+ predicate.set(VALID, typed_param.isValid());
+ predicate.set(PROVIDED, typed_param.anyProvided());
+ predicate.set(EMPTY, typed_param.mValues.empty());
+
+ if (!predicate_rule.check(predicate)) return false;
+
+ for (const_iterator it = typed_param.mValues.begin(), end_it = typed_param.mValues.end();
+ it != end_it;
+ ++it)
+ {
+ std::string key = it->getValueName();
+ name_stack.push_back(std::make_pair(std::string(), true));
+
+ if(key.empty())
+ // not parsed via name values, write out value directly
+ {
+ bool value_written = parser.writeValue(*it, name_stack);
+ if (!value_written)
+ {
+ std::string calculated_key = it->calcValueName(it->getValue());
+ if (parser.writeValue(calculated_key, name_stack))
+ {
+ serialized = true;
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+ else
+ {
+ if(parser.writeValue(key, name_stack))
+ {
+ serialized = true;
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+
+ return serialized;
+ }
+
+ static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count)
+ {
+ parser.inspectValue<MULTI_VALUE_T>(name_stack, min_count, max_count, NULL);
+ if (named_value_t::getPossibleValues())
+ {
+ parser.inspectValue<std::string>(name_stack, min_count, max_count, named_value_t::getPossibleValues());
+ }
+ }
+
+ void set(const container_t& val, bool flag_as_provided = true)
+ {
+ mValues = val;
+ setProvided(flag_as_provided);
+ }
+
+ param_value_t& add()
+ {
+ mValues.push_back(value_t());
+ Param::setProvided();
+ return mValues.back();
+ }
+
+ self_t& add(const value_t& item)
+ {
+ mValues.push_back(item);
+ setProvided();
+ return *this;
+ }
+
+ self_t& add(const typename named_value_t::name_t& name)
+ {
+ value_t value;
+
+ // try to parse a per type named value
+ if (named_value_t::getValueFromName(name, value))
+ {
+ add(value);
+ mValues.back().setValueName(name);
+ }
+
+ return *this;
+ }
+
+ // implicit conversion
+ operator const container_t&() const { return mValues; }
+ // explicit conversion
+ const container_t& operator()() const { return mValues; }
+
+ typedef typename container_t::iterator iterator;
+ typedef typename container_t::const_iterator const_iterator;
+ iterator begin() { return mValues.begin(); }
+ iterator end() { return mValues.end(); }
+ const_iterator begin() const { return mValues.begin(); }
+ const_iterator end() const { return mValues.end(); }
+ bool empty() const { return mValues.empty(); }
+ size_t size() const { return mValues.size(); }
+
+ size_t numValidElements() const
+ {
+ return mValues.size();
+ }
+
+ protected:
+ static bool mergeWith(Param& dst, const Param& src, bool overwrite)
+ {
+ const self_t& src_typed_param = static_cast<const self_t&>(src);
+ self_t& dst_typed_param = static_cast<self_t&>(dst);
+
+ if (overwrite)
+ {
+ std::copy(src_typed_param.begin(), src_typed_param.end(), std::back_inserter(dst_typed_param.mValues));
+ }
+ else
+ {
+ container_t new_values(src_typed_param.mValues);
+ std::copy(dst_typed_param.begin(), dst_typed_param.end(), std::back_inserter(new_values));
+ std::swap(dst_typed_param.mValues, new_values);
+ }
+
+ if (src_typed_param.begin() != src_typed_param.end())
+ {
+ dst_typed_param.setProvided();
+ }
+ return true;
+ }
+
+ container_t mValues;
+ size_t mMinCount,
+ mMaxCount;
+
+ private:
+ void init( BlockDescriptor &block_descriptor, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count, const char* name )
+ {
+ ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor(
+ block_descriptor.mCurrentBlockPtr->getHandleFromParam(this),
+ &mergeWith,
+ &deserializeParam,
+ &serializeParam,
+ validate_func,
+ &inspectParam,
+ min_count, max_count));
+ block_descriptor.addParam(param_descriptor, name);
+ }
+ };
+
+ // list of block parameters
+ template <typename MULTI_BLOCK_T, typename NAME_VALUE_LOOKUP>
+ class TypedParam<MULTI_BLOCK_T, NAME_VALUE_LOOKUP, true, IS_A_BLOCK>
+ : public Param
+ {
+ protected:
+ typedef TypedParam<MULTI_BLOCK_T, NAME_VALUE_LOOKUP, true, IS_A_BLOCK> self_t;
+ typedef ParamValue<typename LLTypeTags::Sorted<MULTI_BLOCK_T>::value_t> param_value_t;
+ typedef typename std::vector<typename NAME_VALUE_LOOKUP::type_value_t> container_t;
+ typedef typename NAME_VALUE_LOOKUP::type_value_t named_value_t;
+ typedef container_t default_value_t;
+ typedef typename container_t::iterator iterator;
+ typedef typename container_t::const_iterator const_iterator;
+ public:
+ typedef typename param_value_t::value_t value_t;
+
+ 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),
+ mMinCount(min_count),
+ mMaxCount(max_count)
+ {
+ std::copy(value.begin(), value.end(), back_inserter(mValues));
+
+ if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING))
+ {
+ init(block_descriptor, validate_func, min_count, max_count, name);
+ }
+ }
+
+ 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, Parser::name_stack_range_t& name_stack_range, bool new_name)
+ {
+ Parser::name_stack_range_t new_name_stack_range(name_stack_range);
+ self_t& typed_param = static_cast<self_t&>(param);
+ bool new_value = false;
+ bool new_array_value = false;
+
+ // pop first element if empty string
+ if (new_name_stack_range.first != new_name_stack_range.second && new_name_stack_range.first->first.empty())
+ {
+ new_array_value = new_name_stack_range.first->second;
+ ++new_name_stack_range.first;
+ }
+
+ if (new_name || new_array_value || typed_param.mValues.empty())
+ {
+ new_value = true;
+ typed_param.mValues.push_back(value_t());
+ }
+ param_value_t& value = typed_param.mValues.back();
+
+ if (new_name_stack_range.first == new_name_stack_range.second)
+ { // try to parse a known named value
+ std::string name;
+
+ if(named_value_t::valueNamesExist()
+ && parser.readValue(name)
+ && named_value_t::getValueFromName(name, value.getValue()))
+ {
+ typed_param.mValues.back().setValueName(name);
+ typed_param.setProvided();
+ if (new_array_value)
+ {
+ name_stack_range.first->second = false;
+ }
+ return true;
+ }
+ }
+
+ // attempt to parse block...
+ if(value.deserializeBlock(parser, new_name_stack_range, new_name))
+ {
+ typed_param.setProvided();
+ if (new_array_value)
+ {
+ name_stack_range.first->second = false;
+ }
+ return true;
+ }
+
+
+ if (new_value)
+ { // failed to parse new value, pop it off
+ typed_param.mValues.pop_back();
+ }
+
+ return false;
+ }
+
+ 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);
+ LLPredicate::Value<ESerializePredicates> predicate;
+
+ predicate.set(REQUIRED, typed_param.mMinCount > 0);
+ predicate.set(VALID, typed_param.isValid());
+ predicate.set(PROVIDED, typed_param.anyProvided());
+ predicate.set(EMPTY, typed_param.mValues.empty());
+
+ if (!predicate_rule.check(predicate)) return false;
+
+ for (const_iterator it = typed_param.mValues.begin(), end_it = typed_param.mValues.end();
+ it != end_it;
+ ++it)
+ {
+ name_stack.push_back(std::make_pair(std::string(), true));
+
+ std::string key = it->getValueName();
+ if (!key.empty())
+ {
+ serialized |= parser.writeValue(key, name_stack);
+ }
+ // Not parsed via named values, write out value directly
+ // NOTE: currently we don't do diffing of Multiples
+ else
+ {
+ serialized = it->serializeBlock(parser, name_stack, predicate_rule, NULL);
+ }
+
+ name_stack.pop_back();
+ }
+
+ if (!serialized && predicate_rule.check(ll_make_predicate(EMPTY)))
+ {
+ serialized |= parser.writeValue(Flag(), name_stack);
+ }
+
+ return serialized;
+ }
+
+ static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count)
+ {
+ const param_value_t& value_param = param_value_t(value_t());
+
+ // tell parser about our actual type
+ parser.inspectValue<value_t>(name_stack, min_count, max_count, NULL);
+ // then tell it about string-based alternatives ("red", "blue", etc. for LLColor4)
+ if (named_value_t::getPossibleValues())
+ {
+ parser.inspectValue<std::string>(name_stack, min_count, max_count, named_value_t::getPossibleValues());
+ }
+
+ value_param.inspectBlock(parser, name_stack, min_count, max_count);
+ }
+
+ void set(const container_t& val, bool flag_as_provided = true)
+ {
+ mValues = val;
+ setProvided(flag_as_provided);
+ }
+
+ param_value_t& add()
+ {
+ mValues.push_back(value_t());
+ setProvided();
+ return mValues.back();
+ }
+
+ self_t& add(const value_t& item)
+ {
+ mValues.push_back(item);
+ setProvided();
+ return *this;
+ }
+
+ self_t& add(const typename named_value_t::name_t& name)
+ {
+ value_t value;
+
+ // try to parse a per type named value
+ if (named_value_t::getValueFromName(name, value))
+ {
+ add(value);
+ mValues.back().setValueName(name);
+ }
+ return *this;
+ }
+
+ // implicit conversion
+ operator const container_t&() const { return mValues; }
+ // explicit conversion
+ const container_t& operator()() const { return mValues; }
+
+ iterator begin() { return mValues.begin(); }
+ iterator end() { return mValues.end(); }
+ const_iterator begin() const { return mValues.begin(); }
+ const_iterator end() const { return mValues.end(); }
+ bool empty() const { return mValues.empty(); }
+ size_t size() const { return mValues.size(); }
+
+ size_t numValidElements() const
+ {
+ size_t count = 0;
+ for (const_iterator it = mValues.begin(), end_it = mValues.end();
+ it != end_it;
+ ++it)
+ {
+ if(it->isValid()) count++;
+ }
+ return count;
+ }
+
+ protected:
+
+ static bool mergeWith(Param& dst, const Param& src, bool overwrite)
+ {
+ const self_t& src_typed_param = static_cast<const self_t&>(src);
+ self_t& dst_typed_param = static_cast<self_t&>(dst);
+
+ if (overwrite)
+ {
+ std::copy(src_typed_param.begin(), src_typed_param.end(), std::back_inserter(dst_typed_param.mValues));
+ }
+ else
+ {
+ container_t new_values(src_typed_param.mValues);
+ std::copy(dst_typed_param.begin(), dst_typed_param.end(), std::back_inserter(new_values));
+ std::swap(dst_typed_param.mValues, new_values);
+ }
+
+ if (src_typed_param.begin() != src_typed_param.end())
+ {
+ dst_typed_param.setProvided();
+ }
+
+ return true;
+ }
+
+ container_t mValues;
+ size_t mMinCount,
+ mMaxCount;
+
+ private:
+ void init( BlockDescriptor &block_descriptor, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count, const char* name )
+ {
+ ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor(
+ block_descriptor.mCurrentBlockPtr->getHandleFromParam(this),
+ &mergeWith,
+ &deserializeParam,
+ &serializeParam,
+ validate_func,
+ &inspectParam,
+ min_count, max_count));
+ block_descriptor.addParam(param_descriptor, name);
+ }
+ };
+
+ template <typename DERIVED_BLOCK, typename BASE_BLOCK = BaseBlock>
+ class ChoiceBlock : public BASE_BLOCK
+ {
+ typedef ChoiceBlock<DERIVED_BLOCK, BASE_BLOCK> self_t;
+ typedef ChoiceBlock<DERIVED_BLOCK, BASE_BLOCK> enclosing_block_t;
+ typedef BASE_BLOCK base_block_t;
+
+ LOG_CLASS(self_t);
+ public:
+ // 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);
+ }
+
+ bool mergeBlockParam(bool source_provided, bool dest_provided, BlockDescriptor& block_data, const self_t& source, bool overwrite)
+ {
+ bool source_override = source_provided && (overwrite || !dest_provided);
+
+ if (source_override || source.mCurChoice == mCurChoice)
+ {
+ return mergeBlock(block_data, source, overwrite);
+ }
+ return false;
+ }
+
+ // merge with other block
+ bool mergeBlock(BlockDescriptor& block_data, const self_t& other, bool overwrite)
+ {
+ mCurChoice = other.mCurChoice;
+ return base_block_t::mergeBlock(getBlockDescriptor(), other, overwrite);
+ }
+
+ // clear out old choice when param has changed
+ /*virtual*/ void paramChanged(const Param& changed_param, bool user_provided)
+ {
+ param_handle_t changed_param_handle = base_block_t::getHandleFromParam(&changed_param);
+ // if we have a new choice...
+ if (changed_param_handle != mCurChoice)
+ {
+ // clear provided flag on previous choice
+ Param* previous_choice = base_block_t::getParamFromHandle(mCurChoice);
+ if (previous_choice)
+ {
+ previous_choice->setProvided(false);
+ }
+ mCurChoice = changed_param_handle;
+ }
+ base_block_t::paramChanged(changed_param, user_provided);
+ }
+
+ virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return getBlockDescriptor(); }
+ virtual BlockDescriptor& mostDerivedBlockDescriptor() { return getBlockDescriptor(); }
+
+ protected:
+ ChoiceBlock()
+ : mCurChoice(0)
+ {
+ BaseBlock::init(getBlockDescriptor(), base_block_t::getBlockDescriptor(), sizeof(DERIVED_BLOCK));
+ }
+
+ // Alternatives are mutually exclusive wrt other Alternatives in the same block.
+ // One alternative in a block will always have isChosen() == true.
+ // At most one alternative in a block will have isProvided() == true.
+ template <typename T, typename NAME_VALUE_LOOKUP = typename TypeValues<T>::type_value_t >
+ class Alternative : public TypedParam<T, NAME_VALUE_LOOKUP, false>
+ {
+ typedef TypedParam<T, NAME_VALUE_LOOKUP, false> super_t;
+ typedef typename super_t::value_t value_t;
+ typedef typename super_t::default_value_t default_value_t;
+
+ public:
+ friend class ChoiceBlock<DERIVED_BLOCK>;
+
+ using super_t::operator =;
+
+ explicit Alternative(const char* name = "", const default_value_t& val = defaultValue<default_value_t>())
+ : super_t(DERIVED_BLOCK::getBlockDescriptor(), name, val, NULL, 0, 1),
+ mOriginalValue(val)
+ {
+ // assign initial choice to first declared option
+ DERIVED_BLOCK* blockp = ((DERIVED_BLOCK*)DERIVED_BLOCK::getBlockDescriptor().mCurrentBlockPtr);
+ if (LL_UNLIKELY(DERIVED_BLOCK::getBlockDescriptor().mInitializationState == BlockDescriptor::INITIALIZING))
+ {
+ if(blockp->mCurChoice == 0)
+ {
+ blockp->mCurChoice = Param::enclosingBlock().getHandleFromParam(this);
+ }
+ }
+ }
+
+ void choose()
+ {
+ static_cast<enclosing_block_t&>(Param::enclosingBlock()).paramChanged(*this, true);
+ }
+
+ void chooseAs(const value_t& val)
+ {
+ super_t::set(val);
+ }
+
+ void operator =(const value_t& val)
+ {
+ super_t::set(val);
+ }
+
+ void operator()(const value_t& val)
+ {
+ super_t::set(val);
+ }
+
+ operator const value_t&() const
+ {
+ return (*this)();
+ }
+
+ const value_t& operator()() const
+ {
+ if (static_cast<enclosing_block_t&>(Param::enclosingBlock()).getCurrentChoice() == this)
+ {
+ return super_t::getValue();
+ }
+ return mOriginalValue;
+ }
+
+ bool isChosen() const
+ {
+ return static_cast<enclosing_block_t&>(Param::enclosingBlock()).getCurrentChoice() == this;
+ }
+
+ private:
+ default_value_t mOriginalValue;
+ };
+
+ public:
+ static BlockDescriptor& getBlockDescriptor()
+ {
+ static BlockDescriptor sBlockDescriptor;
+ return sBlockDescriptor;
+ }
+
+ private:
+ param_handle_t mCurChoice;
+
+ const Param* getCurrentChoice() const
+ {
+ return base_block_t::getParamFromHandle(mCurChoice);
+ }
+ };
+
+ template <typename DERIVED_BLOCK, typename BASE_BLOCK = BaseBlock>
+ class Block
+ : public BASE_BLOCK
+ {
+ typedef Block<DERIVED_BLOCK, BASE_BLOCK> self_t;
+
+ 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));
+ }
+
+ //
+ // Nested classes for declaring parameters
+ //
+ 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;
+ typedef typename super_t::value_t value_t;
+ typedef typename super_t::default_value_t default_value_t;
+
+ public:
+ using super_t::operator();
+ using super_t::operator =;
+
+ explicit Optional(const char* name = "", const default_value_t& val = defaultValue<default_value_t>())
+ : super_t(DERIVED_BLOCK::getBlockDescriptor(), name, val, NULL, 0, 1)
+ {
+ //#pragma message("Parsing LLInitParam::Block::Optional")
+ }
+
+ Optional& operator =(const value_t& val)
+ {
+ super_t::set(val);
+ return *this;
+ }
+
+ 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;
+ typedef Mandatory<T, NAME_VALUE_LOOKUP> self_t;
+ typedef typename super_t::value_t value_t;
+ typedef typename super_t::default_value_t default_value_t;
+
+ public:
+ using super_t::operator();
+ using super_t::operator =;
+
+ // mandatory parameters require a name to be parseable
+ explicit Mandatory(const char* name = "", const default_value_t& val = defaultValue<default_value_t>())
+ : super_t(DERIVED_BLOCK::getBlockDescriptor(), name, val, &validate, 1, 1)
+ {}
+
+ Mandatory& operator =(const value_t& val)
+ {
+ super_t::set(val);
+ return *this;
+ }
+
+ 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;
+ 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&;
+
+ explicit Multiple(const char* name = "")
+ : super_t(DERIVED_BLOCK::getBlockDescriptor(), name, container_t(), &validate, RANGE::minCount, RANGE::maxCount)
+ {}
+
+ Multiple& operator =(const container_t& val)
+ {
+ super_t::set(val);
+ return *this;
+ }
+
+ 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();
+ 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
+ {
+ public:
+ 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),
+ NULL,
+ &deserializeParam,
+ NULL,
+ NULL,
+ NULL,
+ 0, S32_MAX));
+ 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;
+ }
+
+ protected:
+ template <typename T, typename NAME_VALUE_LOOKUP, bool multiple, typename is_block>
+ void changeDefault(TypedParam<T, NAME_VALUE_LOOKUP, multiple, is_block>& param,
+ 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>
+ struct IsBlock<ParamValue<BaseBlock::Lazy<T, BaseBlock::IS_A_BLOCK>, BLOCK_T >, void>
+ {
+ typedef IS_A_BLOCK value_t;
+ };
+
+ template<typename T, typename BLOCK_T>
+ struct IsBlock<ParamValue<BaseBlock::Lazy<T, BaseBlock::NOT_A_BLOCK>, BLOCK_T >, void>
+ {
+ typedef NOT_BLOCK value_t;
+ };
+
+ template<typename T, typename BLOCK_IDENTIFIER>
+ struct IsBlock<ParamValue<BaseBlock::Atomic<T>, typename IsBlock<BaseBlock::Atomic<T> >::value_t >, BLOCK_IDENTIFIER>
+ {
+ typedef typename IsBlock<T>::value_t value_t;
+ };
+
+ template<typename T, typename BLOCK_IDENTIFIER>
+ struct IsBlock<ParamValue<BaseBlock::Sequential<T>, typename IsBlock<BaseBlock::Sequential<T> >::value_t >, BLOCK_IDENTIFIER>
+ {
+ typedef typename IsBlock<T>::value_t value_t;
+ };
+
+
+ template<typename T>
+ struct InnerMostType
+ {
+ typedef T value_t;
+ };
+
+ template<typename T>
+ struct InnerMostType<ParamValue<T, NOT_BLOCK> >
+ {
+ typedef typename InnerMostType<T>::value_t value_t;
+ };
+
+ template<typename T>
+ struct InnerMostType<ParamValue<T, IS_A_BLOCK> >
+ {
+ typedef typename InnerMostType<T>::value_t value_t;
+ };
+
+ template<typename T, typename BLOCK_T>
+ class ParamValue <BaseBlock::Atomic<T>, BLOCK_T>
+ {
+ typedef ParamValue <BaseBlock::Atomic<T>, BLOCK_T> self_t;
+
+ public:
+ typedef typename InnerMostType<T>::value_t value_t;
+ typedef T default_value_t;
+
+ ParamValue()
+ : mValue()
+ {}
+
+ ParamValue(const default_value_t& value)
+ : mValue(value)
+ {}
+
+ void setValue(const value_t& val)
+ {
+ mValue.setValue(val);
+ }
+
+ const value_t& getValue() const
+ {
+ return mValue.getValue();
+ }
+
+ value_t& getValue()
+ {
+ return mValue.getValue();
+ }
+
+ bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name)
+ {
+ if (new_name)
+ {
+ resetToDefault();
+ }
+ 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)
+ {
+ if ((overwrite && source_provided) // new values coming in on top or...
+ || (!overwrite && !dst_provided)) // values being pushed under with nothing already there
+ {
+ // clear away what is there and take the new stuff as a whole
+ resetToDefault();
+ return mValue.mergeBlock(block_data, source.getValue(), overwrite);
+ }
+ 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:
+ void resetToDefault()
+ {
+ static T default_value;
+ mValue = default_value;
+ }
+
+ T mValue;
+ };
+
+ template<typename T>
+ class ParamValue <BaseBlock::Sequential<T>, IS_A_BLOCK>
+ {
+ typedef ParamValue <BaseBlock::Sequential<T>, IS_A_BLOCK> self_t;
+
+ public:
+ typedef typename InnerMostType<T>::value_t value_t;
+ typedef T default_value_t;
+
+ ParamValue()
+ : mValue()
+ {
+ mCurParam = getBlockDescriptor().mAllParams.begin();
+ }
+
+ ParamValue(const default_value_t& value)
+ : mValue(value)
+ {
+ mCurParam = getBlockDescriptor().mAllParams.begin();
+ }
+
+ void setValue(const value_t& val)
+ {
+ mValue.setValue(val);
+ }
+
+ const value_t& getValue() const
+ {
+ return mValue.getValue();
+ }
+
+ value_t& getValue()
+ {
+ return mValue.getValue();
+ }
+
+ bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name)
+ {
+ if (new_name)
+ {
+ mCurParam = getBlockDescriptor().mAllParams.begin();
+ }
+ if (name_stack_range.first == name_stack_range.second
+ && mCurParam != getBlockDescriptor().mAllParams.end())
+ {
+ // deserialize to mCurParam
+ ParamDescriptor& pd = *(*mCurParam);
+ ParamDescriptor::deserialize_func_t deserialize_func = pd.mDeserializeFunc;
+ Param* paramp = mValue.getParamFromHandle(pd.mParamHandle);
+
+ if (deserialize_func
+ && paramp
+ && deserialize_func(*paramp, p, name_stack_range, new_name))
+ {
+ ++mCurParam;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ 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
+ {
+ 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>
+ class ParamValue <BaseBlock::Lazy<T, IS_A_BLOCK>, BLOCK_T>
+ {
+ typedef ParamValue <BaseBlock::Lazy<T, IS_A_BLOCK>, BLOCK_T> self_t;
+
+ public:
+ typedef typename InnerMostType<T>::value_t value_t;
+ typedef LazyValue<T> default_value_t;
+
+ ParamValue()
+ : mValue()
+ {}
+
+ ParamValue(const default_value_t& other)
+ : mValue(other)
+ {}
+
+ ParamValue(const T& value)
+ : mValue(value)
+ {}
+
+ void setValue(const value_t& val)
+ {
+ mValue.set(val);
+ }
+
+ const value_t& getValue() const
+ {
+ return mValue.get().getValue();
+ }
+
+ value_t& getValue()
+ {
+ return mValue.get().getValue();
+ }
+
+ 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())
+ : NULL;
+ 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();
+ }
+
+ private:
+ LazyValue<T> mValue;
+ };
+
+ template<typename T, typename BLOCK_T>
+ class ParamValue <BaseBlock::Lazy<T, NOT_BLOCK>, BLOCK_T>
+ {
+ typedef ParamValue <BaseBlock::Lazy<T, NOT_BLOCK>, BLOCK_T> self_t;
+
+ public:
+ typedef typename InnerMostType<T>::value_t value_t;
+ typedef LazyValue<T> default_value_t;
+
+ ParamValue()
+ : mValue()
+ {}
+
+ ParamValue(const default_value_t& other)
+ : mValue(other)
+ {}
+
+ ParamValue(const T& value)
+ : mValue(value)
+ {}
+
+ void setValue(const value_t& val)
+ {
+ mValue.set(val);
+ }
+
+ const value_t& getValue() const
+ {
+ return mValue.get().getValue();
+ }
+
+ value_t& getValue()
+ {
+ return mValue.get().getValue();
+ }
+
+ bool isValid() const
+ {
+ return true;
+ }
+
+ private:
+ LazyValue<T> mValue;
+ };
+
+ template <>
+ class ParamValue <LLSD, NOT_BLOCK>
+ : public BaseBlock
+ {
+ public:
+ typedef LLSD value_t;
+ typedef LLSD default_value_t;
+
+ ParamValue()
+ {}
+
+ ParamValue(const default_value_t& other)
+ : mValue(other)
+ {}
+
+ void setValue(const value_t& val) { mValue = val; }
+
+ 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;
+ };
+
+ template<typename T>
+ class CustomParamValue
+ : public Block<ParamValue<T> >
+ {
+ public:
+ typedef enum e_value_age
+ {
+ 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
+ } EValueAge;
+
+ typedef TypeValues<T> derived_t;
+ typedef CustomParamValue<T> self_t;
+ typedef Block<ParamValue<T> > block_t;
+ typedef T default_value_t;
+ typedef T value_t;
+ typedef void baseblock_base_class_t;
+
+
+ CustomParamValue(const default_value_t& value = T())
+ : mValue(value),
+ 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)
+ {
+ if(parser.readValue(typed_param.mValue))
+ {
+ typed_param.mValueAge = VALUE_AUTHORITATIVE;
+ typed_param.updateBlockFromValue(false);
+
+ return true;
+ }
+ }
+
+ // fall back on parsing block components for T
+ 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);
+ // }
+ //}
+ // then try to serialize value directly
+ 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);
+ }
+ else
+ {
+ return block_t::serializeBlock(parser, name_stack, predicate_rule, NULL);
+ }
+ }
+ }
+ return false;
+ }
+
+ bool validateBlock(bool emit_errors = true) const
+ {
+ if (mValueAge == VALUE_NEEDS_UPDATE)
+ {
+ if (block_t::validateBlock(emit_errors))
+ {
+ // 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;
+ }
+ }
+
+ // propagate change status up to enclosing block
+ /*virtual*/ void paramChanged(const Param& changed_param, bool user_provided)
+ {
+ BaseBlock::paramChanged(changed_param, user_provided);
+ if (user_provided)
+ {
+ // a parameter changed, so our value is out of date
+ mValueAge = VALUE_NEEDS_UPDATE;
+ }
+ }
+
+ 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);
+ }
+
+ const value_t& getValue() const
+ {
+ validateBlock(true);
+ return mValue;
+ }
+
+ T& getValue()
+ {
+ validateBlock(true);
+ return mValue;
+ }
+
+ protected:
+
+ // use this from within updateValueFromBlock() to set the value without making it authoritative
+ void updateValue(const value_t& value)
+ {
+ mValue = value;
+ }
+
+ bool mergeBlockParam(bool source_provided, bool dst_provided, BlockDescriptor& block_data, const BaseBlock& source, bool overwrite)
+ {
+ bool source_override = source_provided && (overwrite || !dst_provided);
+
+ const derived_t& src_typed_param = static_cast<const derived_t&>(source);
+
+ if (source_override && src_typed_param.mValueAge == VALUE_AUTHORITATIVE)
+ {
+ // copy value over
+ setValue(src_typed_param.getValue());
+ return true;
+ }
+ // merge individual parameters into destination
+ if (mValueAge == VALUE_AUTHORITATIVE)
+ {
+ static_cast<derived_t*>(this)->updateBlockFromValue(dst_provided);
+ }
+ 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;
+ };
}