Newer
Older
Adam Moss
committed
/**
Richard Linden
committed
* @file llinitparam.h
Adam Moss
committed
* @brief parameter block abstraction for creating complex objects and
* parsing construction parameters from xml and LLSD
*
* $LicenseInfo:firstyear=2008&license=viewerlgpl$
Adam Moss
committed
* 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.
Adam Moss
committed
*
* 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.
Adam Moss
committed
*
* 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
Adam Moss
committed
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
Adam Moss
committed
* $/LicenseInfo$
*/
#ifndef LL_LLPARAM_H
#define LL_LLPARAM_H
#include <vector>
#include <boost/function.hpp>
#include <boost/type_traits/is_convertible.hpp>
#include <boost/unordered_map.hpp>
Richard Linden
committed
#include <boost/shared_ptr.hpp>
Adam Moss
committed
Leslie Linden
committed
#include "llerror.h"
Adam Moss
committed
namespace LLInitParam
{
// used to indicate no matching value to a given name when parsing
struct Flag{};
Richard Linden
committed
template<typename T> const T& defaultValue() { static T value; return value; }
Richard Nelson
committed
template <typename T, bool IS_BOOST_FUNCTION = boost::is_convertible<T, boost::function_base>::value >
struct ParamCompare
{
static bool equals(const T &a, const T &b)
{
return a == b;
}
Adam Moss
committed
};
// boost function types are not comparable
template<typename T>
{
static bool equals(const T&a, const T &b)
{
return false;
}
};
Adam Moss
committed
Richard Linden
committed
template<>
struct ParamCompare<LLSD, false>
Adam Moss
committed
{
Richard Linden
committed
static bool equals(const LLSD &a, const LLSD &b) { return false; }
Adam Moss
committed
};
template<>
struct ParamCompare<Flag, false>
{
static bool equals(const Flag& a, const Flag& b) { return false; }
};
Adam Moss
committed
// helper functions and classes
typedef ptrdiff_t param_handle_t;
Richard Linden
committed
// empty default implementation of key cache
// leverages empty base class optimization
Adam Moss
committed
template <typename T>
class TypeValues
{
private:
struct Inaccessable{};
Adam Moss
committed
public:
Richard Linden
committed
typedef std::map<std::string, T> value_name_map_t;
typedef Inaccessable name_t;
Richard Linden
committed
void setValueName(const std::string& key) {}
std::string getValueName() const { return ""; }
std::string calcValueName(const T& value) const { return ""; }
Richard Linden
committed
void clearValueName() const {}
static bool getValueFromName(const std::string& name, T& value)
Adam Moss
committed
{
Richard Linden
committed
return false;
}
Adam Moss
committed
Richard Linden
committed
static bool valueNamesExist()
Adam Moss
committed
{
return false;
}
Richard Linden
committed
static std::vector<std::string>* getPossibleValues()
Adam Moss
committed
{
Richard Linden
committed
return NULL;
Adam Moss
committed
}
Richard Linden
committed
static value_name_map_t* getValueNames() {return NULL;}
Adam Moss
committed
};
template <typename T, typename DERIVED_TYPE = TypeValues<T> >
class TypeValuesHelper
{
public:
typedef typename std::map<std::string, T> value_name_map_t;
typedef std::string name_t;
Adam Moss
committed
//TODO: cache key by index to save on param block size
Richard Linden
committed
void setValueName(const std::string& value_name)
Adam Moss
committed
{
Richard Linden
committed
mValueName = value_name;
}
Adam Moss
committed
Richard Linden
committed
std::string getValueName() const
{
return mValueName;
}
Adam Moss
committed
std::string calcValueName(const T& value) const
{
value_name_map_t* map = getValueNames();
for (typename value_name_map_t::iterator it = map->begin(), end_it = map->end();
it != end_it;
++it)
{
if (ParamCompare<T>::equals(it->second, value))
{
return it->first;
}
}
return "";
}
Richard Linden
committed
void clearValueName() const
{
mValueName.clear();
}
Adam Moss
committed
Richard Linden
committed
static bool getValueFromName(const std::string& name, T& value)
Adam Moss
committed
{
Richard Linden
committed
value_name_map_t* map = getValueNames();
typename value_name_map_t::iterator found_it = map->find(name);
Richard Linden
committed
if (found_it == map->end()) return false;
Adam Moss
committed
Richard Linden
committed
value = found_it->second;
Adam Moss
committed
return true;
}
Richard Linden
committed
static bool valueNamesExist()
Adam Moss
committed
{
Richard Linden
committed
return !getValueNames()->empty();
Adam Moss
committed
}
Richard Linden
committed
static value_name_map_t* getValueNames()
Adam Moss
committed
{
Richard Linden
committed
static value_name_map_t sMap;
static bool sInitialized = false;
Adam Moss
committed
Richard Linden
committed
if (!sInitialized)
Adam Moss
committed
{
Richard Linden
committed
sInitialized = true;
DERIVED_TYPE::declareValues();
Adam Moss
committed
}
Richard Linden
committed
return &sMap;
Adam Moss
committed
}
Richard Linden
committed
static std::vector<std::string>* getPossibleValues()
{
static std::vector<std::string> sValues;
value_name_map_t* map = getValueNames();
for (typename value_name_map_t::iterator it = map->begin(), end_it = map->end();
Richard Linden
committed
it != end_it;
++it)
{
sValues.push_back(it->first);
}
return &sValues;
}
Adam Moss
committed
static void declare(const std::string& name, const T& value)
{
Richard Linden
committed
(*getValueNames())[name] = value;
Adam Moss
committed
}
Richard Linden
committed
protected:
static void getName(const std::string& name, const T& value)
{}
mutable std::string mValueName;
Adam Moss
committed
};
class Parser
{
LOG_CLASS(Parser);
public:
struct CompareTypeID
{
bool operator()(const std::type_info* lhs, const std::type_info* rhs) const
{
return lhs->before(*rhs);
}
};
typedef std::vector<std::pair<std::string, bool> > name_stack_t;
typedef std::pair<name_stack_t::iterator, name_stack_t::iterator> name_stack_range_t;
typedef std::vector<std::string> possible_values_t;
Adam Moss
committed
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;
Adam Moss
committed
typedef std::map<const std::type_info*, parser_read_func_t, CompareTypeID> parser_read_func_map_t;
typedef std::map<const std::type_info*, parser_write_func_t, CompareTypeID> parser_write_func_map_t;
typedef std::map<const std::type_info*, parser_inspect_func_t, CompareTypeID> parser_inspect_func_map_t;
Parser(parser_read_func_map_t& read_map, parser_write_func_map_t& write_map, parser_inspect_func_map_t& inspect_map)
Adam Moss
committed
: mParseSilently(false),
mParserReadFuncs(&read_map),
mParserWriteFuncs(&write_map),
mParserInspectFuncs(&inspect_map)
Adam Moss
committed
{}
virtual ~Parser();
template <typename T> bool readValue(T& param)
{
parser_read_func_map_t::iterator found_it = mParserReadFuncs->find(&typeid(T));
if (found_it != mParserReadFuncs->end())
Adam Moss
committed
{
return found_it->second(*this, (void*)¶m);
Adam Moss
committed
}
return false;
}
template <typename T> bool writeValue(const T& param, name_stack_t& name_stack)
Adam Moss
committed
{
parser_write_func_map_t::iterator found_it = mParserWriteFuncs->find(&typeid(T));
if (found_it != mParserWriteFuncs->end())
Adam Moss
committed
{
return found_it->second(*this, (const void*)¶m, name_stack);
Adam Moss
committed
}
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)
Adam Moss
committed
{
parser_inspect_func_map_t::iterator found_it = mParserInspectFuncs->find(&typeid(T));
if (found_it != mParserInspectFuncs->end())
Adam Moss
committed
{
found_it->second(name_stack, min_count, max_count, possible_values);
return true;
}
return false;
}
virtual std::string getCurrentElementName() = 0;
virtual void parserWarning(const std::string& message);
virtual void parserError(const std::string& message);
void setParseSilently(bool silent) { mParseSilently = silent; }
protected:
template <typename T>
void registerParserFuncs(parser_read_func_t read_func, parser_write_func_t write_func = NULL)
Adam Moss
committed
{
mParserReadFuncs->insert(std::make_pair(&typeid(T), read_func));
mParserWriteFuncs->insert(std::make_pair(&typeid(T), write_func));
Adam Moss
committed
}
template <typename T>
void registerInspectFunc(parser_inspect_func_t inspect_func)
{
mParserInspectFuncs->insert(std::make_pair(&typeid(T), inspect_func));
Adam Moss
committed
}
bool mParseSilently;
private:
parser_read_func_map_t* mParserReadFuncs;
parser_write_func_map_t* mParserWriteFuncs;
parser_inspect_func_map_t* mParserInspectFuncs;
Adam Moss
committed
};
Adam Moss
committed
// various callbacks and constraints associated with an individual param
struct ParamDescriptor
{
Richard Linden
committed
struct UserData
{
virtual ~UserData() {}
};
Adam Moss
committed
typedef bool(*merge_func_t)(Param&, const Param&, bool);
typedef bool(*deserialize_func_t)(Param&, Parser&, const Parser::name_stack_range_t&, bool);
Adam Moss
committed
typedef void(*serialize_func_t)(const Param&, Parser&, Parser::name_stack_t&, const Param* diff_param);
typedef void(*inspect_func_t)(const Param&, Parser&, Parser::name_stack_t&, S32 min_count, S32 max_count);
typedef bool(*validation_func_t)(const Param*);
ParamDescriptor(param_handle_t p,
Richard Linden
committed
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);
Adam Moss
committed
Richard Linden
committed
ParamDescriptor();
~ParamDescriptor();
Adam Moss
committed
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;
Richard Linden
committed
UserData* mUserData;
Adam Moss
committed
};
Richard Linden
committed
typedef boost::shared_ptr<ParamDescriptor> ParamDescriptorPtr;
Adam Moss
committed
// each derived Block class keeps a static data structure maintaining offsets to various params
class BlockDescriptor
{
public:
Richard Linden
committed
BlockDescriptor();
Adam Moss
committed
typedef enum e_initialization_state
{
UNINITIALIZED,
INITIALIZING,
INITIALIZED
} EInitializationState;
void aggregateBlockData(BlockDescriptor& src_block_data);
Richard Linden
committed
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;
Richard Linden
committed
typedef std::vector<std::pair<param_handle_t, ParamDescriptor::validation_func_t> > param_validation_list_t;
Adam Moss
committed
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
Adam Moss
committed
};
Richard Linden
committed
struct IS_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
{
static const bool value = false;
typedef NOT_BLOCK value_t;
};
template<typename T>
struct IsBlock<T, typename T::baseblock_base_class_t>
{
static const bool value = true;
typedef IS_BLOCK value_t;
};
Adam Moss
committed
class BaseBlock
{
public:
//TODO: implement in terms of owned_ptr
Richard Linden
committed
template<typename T, bool IS_BLOCK = true>
class Lazy
{
public:
: mPtr(NULL)
{}
~Lazy()
{
delete mPtr;
}
Lazy(const T& value)
{
mPtr = new T(value);
}
Lazy(const Lazy& other)
{
if (other.mPtr)
{
mPtr = new T(*other.mPtr);
}
else
{
mPtr = NULL;
}
}
Richard Linden
committed
Lazy& operator = (const Lazy& other)
{
if (other.mPtr)
{
mPtr = new T(*other.mPtr);
}
else
{
mPtr = NULL;
}
return *this;
}
bool empty() const
{
return mPtr == NULL;
}
void set(const T& other)
{
delete mPtr;
mPtr = new T(other);
}
const T& get() const
{
return *ensureInstance();
}
T& get()
{
return *ensureInstance();
}
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:
// if you get a compilation error with this, that means you are using a forward declared struct for T
// unfortunately, the type traits we rely on don't work with forward declared typed
//static const int dummy = sizeof(T);
mutable T* mPtr;
};
Richard Linden
committed
// "Multiple" constraint types, put here in root class to avoid ambiguity during use
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 };
Adam Moss
committed
// this typedef identifies derived classes as being blocks
typedef void baseblock_base_class_t;
LOG_CLASS(BaseBlock);
friend class Param;
Richard Linden
committed
virtual ~BaseBlock() {}
bool submitValue(Parser::name_stack_t& name_stack, Parser& p, bool silent=false);
Adam Moss
committed
param_handle_t getHandleFromParam(const Param* param) const;
bool validateBlock(bool emit_errors = true) const;
Adam Moss
committed
Param* getParamFromHandle(const param_handle_t param_handle)
{
if (param_handle == 0) return NULL;
Richard Linden
committed
Adam Moss
committed
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
Richard Linden
committed
virtual void paramChanged(const Param& changed_param, bool user_provided) {}
Adam Moss
committed
bool deserializeBlock(Parser& p, Parser::name_stack_range_t name_stack_range, bool new_name);
void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block = NULL) const;
Richard Linden
committed
bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const;
Adam Moss
committed
virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return getBlockDescriptor(); }
virtual BlockDescriptor& mostDerivedBlockDescriptor() { return getBlockDescriptor(); }
Adam Moss
committed
// 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;
}
Richard Linden
committed
static void addParam(BlockDescriptor& block_data, ParamDescriptorPtr param, const char* name);
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;
}
Adam Moss
committed
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)
Richard Linden
committed
{
Richard Linden
committed
}
Adam Moss
committed
private:
const std::string& getParamName(const BlockDescriptor& block_data, const Param* paramp) const;
};
Richard Linden
committed
class Param
{
public:
void setProvided(bool is_provided = true)
{
mIsProvided = is_provided;
enclosingBlock().paramChanged(*this, is_provided);
}
Richard Linden
committed
Param& operator =(const Param& other)
{
mIsProvided = other.mIsProvided;
// don't change mEnclosingblockoffset
Richard Linden
committed
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)(S32)mEnclosingBlockOffset));
}
private:
U32 mEnclosingBlockOffset:31;
U32 mIsProvided:1;
};
Adam Moss
committed
Richard Linden
committed
template<typename T, typename NAME_VALUE_LOOKUP, bool VALUE_IS_BLOCK = IsBlock<T>::value>
class ParamValue : public NAME_VALUE_LOOKUP
{
public:
typedef const T& value_assignment_t;
Richard Linden
committed
typedef T value_t;
typedef ParamValue<T, NAME_VALUE_LOOKUP, VALUE_IS_BLOCK> self_t;
Richard Linden
committed
ParamValue(): mValue() {}
ParamValue(value_assignment_t other) : mValue(other) {}
Richard Linden
committed
void setValue(value_assignment_t val)
{
mValue = val;
}
value_assignment_t getValue() const
{
return mValue;
}
T& getValue()
{
return mValue;
}
operator value_assignment_t() const
{
return mValue;
}
value_assignment_t operator()() const
{
return mValue;
}
void operator ()(const typename NAME_VALUE_LOOKUP::name_t& name)
{
*this = name;
}
self_t& operator =(const typename NAME_VALUE_LOOKUP::name_t& name)
{
if (NAME_VALUE_LOOKUP::getValueFromName(name, mValue))
{
setValueName(name);
}
return *this;
}
Richard Linden
committed
T mValue;
};
template<typename T, typename NAME_VALUE_LOOKUP>
class ParamValue<T, NAME_VALUE_LOOKUP, true>
: public T,
public NAME_VALUE_LOOKUP
{
public:
typedef const T& value_assignment_t;
Richard Linden
committed
typedef T value_t;
typedef ParamValue<T, NAME_VALUE_LOOKUP, true> self_t;
Richard Linden
committed
ParamValue()
: T(),
mValidated(false)
{}
Richard Linden
committed
: T(other),
mValidated(false)
Richard Linden
committed
void setValue(value_assignment_t val)
{
*this = val;
}
value_assignment_t getValue() const
{
return *this;
}
T& getValue()
{
return *this;
}
operator value_assignment_t() const
{
return *this;
}
value_assignment_t operator()() const
{
return *this;
}
void operator ()(const typename NAME_VALUE_LOOKUP::name_t& name)
{
*this = name;
}
self_t& operator =(const typename NAME_VALUE_LOOKUP::name_t& name)
{
{
setValueName(name);
}
return *this;
}
protected:
mutable bool mValidated; // lazy validation flag
Richard Linden
committed
};
Richard Linden
committed
template<typename NAME_VALUE_LOOKUP>
class ParamValue<std::string, NAME_VALUE_LOOKUP, false>
: public NAME_VALUE_LOOKUP
{
public:
typedef const std::string& value_assignment_t;
Richard Linden
committed
typedef std::string value_t;
Richard Linden
committed
typedef ParamValue<std::string, NAME_VALUE_LOOKUP, false> self_t;
ParamValue(): mValue() {}
ParamValue(value_assignment_t other) : mValue(other) {}
void setValue(value_assignment_t val)
{
if (NAME_VALUE_LOOKUP::getValueFromName(val, mValue))
{
NAME_VALUE_LOOKUP::setValueName(val);
Richard Linden
committed
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
}
else
{
mValue = val;
}
}
value_assignment_t getValue() const
{
return mValue;
}
std::string& getValue()
{
return mValue;
}
operator value_assignment_t() const
{
return mValue;
}
value_assignment_t operator()() const
{
return mValue;
}
protected:
std::string mValue;
};
Richard Linden
committed
template<typename T, typename NAME_VALUE_LOOKUP = TypeValues<T> >
struct ParamIterator
{
typedef typename std::vector<ParamValue<T, NAME_VALUE_LOOKUP> >::const_iterator const_iterator;
typedef typename std::vector<ParamValue<T, NAME_VALUE_LOOKUP> >::iterator iterator;
};
Adam Moss
committed
// specialize for custom parsing/decomposition of specific classes
// e.g. TypedParam<LLRect> has left, top, right, bottom, etc...
template<typename T,
typename NAME_VALUE_LOOKUP = TypeValues<T>,
bool HAS_MULTIPLE_VALUES = false,
Richard Linden
committed
bool VALUE_IS_BLOCK = IsBlock<T>::value>
Adam Moss
committed
class TypedParam
Richard Linden
committed
: public Param,
public ParamValue<T, NAME_VALUE_LOOKUP>
Adam Moss
committed
{
public:
typedef TypedParam<T, NAME_VALUE_LOOKUP, HAS_MULTIPLE_VALUES, VALUE_IS_BLOCK> self_t;
typedef ParamValue<T, NAME_VALUE_LOOKUP> param_value_t;
typedef typename param_value_t::value_assignment_t value_assignment_t;
Adam Moss
committed
Richard Linden
committed
using param_value_t::operator();
TypedParam(BlockDescriptor& block_descriptor, const char* name, const T& value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count)
: Param(block_descriptor.mCurrentBlockPtr),
param_value_t(value)
Adam Moss
committed
{
if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING))
Adam Moss
committed
{
Richard Linden
committed
ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor(
block_descriptor.mCurrentBlockPtr->getHandleFromParam(this),
Adam Moss
committed
&mergeWith,
&deserializeParam,
&serializeParam,
validate_func,
&inspectParam,
Richard Linden
committed
min_count, max_count));
Adam Moss
committed
BaseBlock::addParam(block_descriptor, param_descriptor, name);
}
}
bool isProvided() const { return Param::anyProvided(); }
Adam Moss
committed
static bool deserializeParam(Param& param, Parser& parser, const Parser::name_stack_range_t& name_stack_range, bool new_name)
Adam Moss
committed
{
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)
Adam Moss
committed
{
Richard Linden
committed
if (parser.readValue(typed_param.getValue()))
Adam Moss
committed
{
Richard Linden
committed
typed_param.clearValueName();
typed_param.setProvided();
Adam Moss
committed
return true;
}
// try to parse a known named value
if(param_value_t::valueNamesExist())
Adam Moss
committed
{
// try to parse a known named value
std::string name;
Adam Moss
committed
{
// try to parse a per type named value
if (param_value_t::getValueFromName(name, typed_param.getValue()))
Adam Moss
committed
{
Richard Linden
committed
typed_param.setValueName(name);
typed_param.setProvided();
Adam Moss
committed
return true;
}
}
}
}
return false;
}
static void serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const Param* diff_param)
{
const self_t& typed_param = static_cast<const self_t&>(param);
if (!typed_param.isProvided()) return;
if (!name_stack.empty())
{
name_stack.back().second = true;
Adam Moss
committed
}
Richard Linden
committed
std::string key = typed_param.getValueName();
Adam Moss
committed
// first try to write out name of name/value pair
if (!key.empty())
{
Richard Linden
committed
if (!diff_param || !ParamCompare<std::string>::equals(static_cast<const self_t*>(diff_param)->getValueName(), key))
Adam Moss
committed
{
parser.writeValue(key, name_stack);
Adam Moss
committed
}
}
// then try to serialize value directly
Richard Linden
committed
else if (!diff_param || !ParamCompare<T>::equals(typed_param.getValue(), static_cast<const self_t*>(diff_param)->getValue()))
{
if (!parser.writeValue(typed_param.getValue(), name_stack))
Adam Moss
committed
{
std::string calculated_key = typed_param.calcValueName(typed_param.getValue());
if (!diff_param || !ParamCompare<std::string>::equals(static_cast<const self_t*>(diff_param)->getValueName(), calculated_key))
{
parser.writeValue(calculated_key, name_stack);
}
Adam Moss
committed
}
}
}
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 (param_value_t::getPossibleValues())
Adam Moss
committed
{
parser.inspectValue<std::string>(name_stack, min_count, max_count, param_value_t::getPossibleValues());
Adam Moss
committed
}
}
void set(value_assignment_t val, bool flag_as_provided = true)
{
Adam Moss
committed
setProvided(flag_as_provided);
}
Richard Linden
committed
self_t& operator =(const typename NAME_VALUE_LOOKUP::name_t& name)
{
return static_cast<self_t&>(param_value_t::operator =(name));
}
protected:
self_t& operator =(const self_t& other)
param_value_t::operator =(other);
Param::operator =(other);
Adam Moss
committed
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);
Richard Linden
committed
Adam Moss
committed
if (src_typed_param.isProvided()
&& (overwrite || !dst_typed_param.isProvided()))
{
Richard Linden
committed
dst_typed_param.set(src_typed_param.getValue());
Adam Moss
committed
return true;
}
return false;
}
};
// parameter that is a block
template <typename T, typename NAME_VALUE_LOOKUP>
class TypedParam<T, NAME_VALUE_LOOKUP, false, true>
Richard Linden
committed
: public Param,
public ParamValue<T, NAME_VALUE_LOOKUP>
Adam Moss
committed
{
public:
Richard Linden
committed
typedef ParamValue<T, NAME_VALUE_LOOKUP> param_value_t;
typedef typename param_value_t::value_assignment_t value_assignment_t;
typedef TypedParam<T, NAME_VALUE_LOOKUP, false, true> self_t;
Adam Moss
committed
Richard Linden
committed
using param_value_t::operator();
TypedParam(BlockDescriptor& block_descriptor, const char* name, const T& value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count)
Adam Moss
committed
: Param(block_descriptor.mCurrentBlockPtr),
Adam Moss
committed
{
if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING))
Adam Moss
committed
{
Richard Linden
committed
ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor(
block_descriptor.mCurrentBlockPtr->getHandleFromParam(this),
Adam Moss
committed
&mergeWith,
&deserializeParam,
&serializeParam,
validate_func,
&inspectParam,
Richard Linden
committed
min_count, max_count));
Adam Moss
committed
BaseBlock::addParam(block_descriptor, param_descriptor, name);
}
}
static bool deserializeParam(Param& param, Parser& parser, const Parser::name_stack_range_t& name_stack_range, bool new_name)
Adam Moss
committed
{
self_t& typed_param = static_cast<self_t&>(param);
// attempt to parse block...
if(typed_param.deserializeBlock(parser, name_stack_range, new_name))
Adam Moss
committed
{
Richard Linden
committed
typed_param.clearValueName();