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>
Adam Moss
committed
#include <boost/function.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/type_traits/is_convertible.hpp>
#include <boost/type_traits/is_enum.hpp>
Adam Moss
committed
Leslie Linden
committed
#include "llerror.h"
#include "llstl.h"
#include "llpredicate.h"
Leslie Linden
committed
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;
};
}
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
// 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;
}
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;
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
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
template<typename T, typename VALUE_IS_BLOCK = typename IsBlock<T>::value_t>
class ParamValue
{
typedef ParamValue<T, VALUE_IS_BLOCK> self_t;
public:
typedef T default_value_t;
typedef T value_t;
ParamValue(): mValue() {}
ParamValue(const default_value_t& other) : mValue(other) {}
void setValue(const value_t& val)
{
mValue = val;
}
const value_t& getValue() const
{
return mValue;
}
T& getValue()
{
return mValue;
}
protected:
T mValue;
};
template<typename T>
class ParamValue<T, IS_A_BLOCK>
: public T
{
typedef ParamValue<T, IS_A_BLOCK> self_t;
public:
typedef T default_value_t;
typedef T value_t;
ParamValue()
{}
void setValue(const value_t& val)
{
*this = val;
}
const value_t& getValue() const
{
return *this;
}
T& getValue()
{
return *this;
}
};
Adam Moss
committed
Richard Linden
committed
// empty default implementation of key cache
// leverages empty base class optimization
Adam Moss
committed
template <typename T>
class TypeValues
: public ParamValue<typename LLTypeTags::Sorted<T>::value_t>
Adam Moss
committed
{
private:
struct Inaccessable{};
Adam Moss
committed
public:
Richard Linden
committed
typedef std::map<std::string, T> value_name_map_t;
typedef Inaccessable name_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)
Richard Linden
committed
void setValueName(const std::string& key) {}
std::string getValueName() const { return ""; }
std::string calcValueName(const value_t& value) const { return ""; }
Richard Linden
committed
void clearValueName() const {}
static bool getValueFromName(const std::string& name, value_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
}
void assignNamedValue(const Inaccessable& name)
{}
operator const value_t&() const
{
return param_value_t::getValue();
return param_value_t::getValue();
Richard Linden
committed
static value_name_map_t* getValueNames() {return NULL;}
Adam Moss
committed
};
// 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 >
Adam Moss
committed
class TypeValuesHelper
: public ParamValue<typename LLTypeTags::Sorted<T>::value_t>
Adam Moss
committed
{
typedef TypeValuesHelper<T, DERIVED_TYPE, IS_SPECIALIZED> self_t;
Adam Moss
committed
public:
typedef typename std::map<std::string, T> value_name_map_t;
typedef std::string name_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)
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
{
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
static bool getValueFromName(const std::string& name, value_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 value_t& value)
Adam Moss
committed
{
Richard Linden
committed
(*getValueNames())[name] = value;
Adam Moss
committed
}
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();
return param_value_t::getValue();
Richard Linden
committed
protected:
static void getName(const std::string& name, const value_t& value)
Richard Linden
committed
{}
mutable std::string mValueName;
Adam Moss
committed
};
// string types can support custom named values, but need
// to disambiguate in code between a string that is a named value
// and a string that is a name
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;
: base_t(val)
{
*this = name;
}
self_t& operator =(const std::string& name)
{
if (base_t::getValueFromName(name, ParamValue<std::string>::getValue()))
}
return *this;
}
operator const value_t&() const
{
// parser base class with mechanisms for registering readers/writers/inspectors of different types
Adam Moss
committed
{
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;
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> 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;
Adam Moss
committed
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
{}
Adam Moss
committed
virtual ~Parser();
Richard Linden
committed
template <typename T> bool readValue(T& param, typename boost::disable_if<boost::is_enum<T> >::type* dummy = 0)
Richard Linden
committed
{
Richard Linden
committed
parser_read_func_map_t::iterator found_it = mParserReadFuncs->find(&typeid(T));
if (found_it != mParserReadFuncs->end())
Richard Linden
committed
{
Richard Linden
committed
return found_it->second(*this, (void*)¶m);
Richard Linden
committed
return false;
}
Richard Linden
committed
template <typename T> bool readValue(T& param, typename boost::enable_if<boost::is_enum<T> >::type* dummy = 0)
Richard Linden
committed
{
Richard Linden
committed
parser_read_func_map_t::iterator found_it = mParserReadFuncs->find(&typeid(T));
if (found_it != mParserReadFuncs->end())
Richard Linden
committed
{
Richard Linden
committed
return found_it->second(*this, (void*)¶m);
Richard Linden
committed
}
Richard Linden
committed
else
Richard Linden
committed
{
Richard Linden
committed
found_it = mParserReadFuncs->find(&typeid(S32));
if (found_it != mParserReadFuncs->end())
AlexanderP ProductEngine
committed
{
Richard Linden
committed
S32 int_value;
bool parsed = found_it->second(*this, (void*)&int_value);
param = (T)int_value;
return parsed;
Richard Linden
committed
return false;
}
template <typename T> bool writeValue(const T& param, name_stack_t& name_stack)
Richard Linden
committed
{
Richard Linden
committed
parser_write_func_map_t::iterator found_it = mParserWriteFuncs->find(&typeid(T));
if (found_it != mParserWriteFuncs->end())
Richard Linden
committed
{
Richard Linden
committed
return found_it->second(*this, (const void*)¶m, name_stack);
Richard Linden
committed
return false;
}
Adam Moss
committed
// 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 std::string getCurrentFileName() = 0;
Adam Moss
committed
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
enum ESerializePredicates
{
PROVIDED,
REQUIRED,
VALID,
HAS_DEFAULT_VALUE,
EMPTY
};
typedef LLPredicate::Rule<ESerializePredicates> predicate_rule_t;
predicate_rule_t default_parse_rules();
Adam Moss
committed
// various callbacks and constraints associated with an individual param
Adam Moss
committed
{
Richard Linden
committed
struct UserData
{
Richard Linden
committed
};
Adam Moss
committed
typedef bool(*merge_func_t)(Param&, const Param&, bool);
Richard Linden
committed
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);
Adam Moss
committed
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
};
typedef boost::shared_ptr<ParamDescriptor> ParamDescriptorPtr;
Richard Linden
committed
Adam Moss
committed
// each derived Block class keeps a static data structure maintaining offsets to various params
Adam Moss
committed
{
public:
Richard Linden
committed
BlockDescriptor();
Adam Moss
committed
typedef enum e_initialization_state
{
UNINITIALIZED,
INITIALIZING,
INITIALIZED
} EInitializationState;
void aggregateBlockData(BlockDescriptor& src_block_data);
void addParam(ParamDescriptorPtr param, const char* name);
Adam Moss
committed
typedef absl::node_hash_map<std::string, ParamDescriptorPtr> param_map_t;
Richard Linden
committed
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
};
//TODO: implement in terms of owned_ptr
template<typename T>
: mPtr(NULL)
{}
{
delete mPtr;
}
: mPtr(NULL)
*this = other;
LazyValue& operator = (const LazyValue& other)
if (!other.mPtr)
delete mPtr;
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;
}
Richard Linden
committed
bool empty() const
{
return mPtr == NULL;
}
void set(const T& other)
{
if (!mPtr)
{
mPtr = new T(other);
}
else
{
*mPtr = other;
}
const T& get() const
{
}
T& get()
{
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;
};
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;
Richard Linden
committed
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; };
};
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, NOT_A_BLOCK> >
{
};
};
// "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;
BaseBlock()
: mValidated(false),
mParamProvided(false)
{}
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
bool isProvided() const
{
return mParamProvided;
}
bool isValid() const
{
return validateBlock(false);
}
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
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;
}
}
Adam Moss
committed
Richard Linden
committed
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;
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
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
mutable bool mValidated; // lazy validation flag
bool mParamProvided;
Adam Moss
committed
private:
const std::string& getParamName(const BlockDescriptor& block_data, const Param* paramp) const;
};
{
public:
void setProvided(bool is_provided = true)
{
mIsProvided = is_provided;
enclosingBlock().paramChanged(*this, is_provided);
}
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)getEnclosingBlockOffset()));
}
U32 getEnclosingBlockOffset() const
Richard Linden
committed
{
return ((U32)mEnclosingBlockOffsetHigh << 16) | (U32)mEnclosingBlockOffsetLow;
//24 bits for member offset field and 1 bit for provided flag
U16 mEnclosingBlockOffsetLow;
U8 mEnclosingBlockOffsetHigh:7;
U8 mIsProvided:1;
Richard Linden
committed
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;
Richard Linden
committed
};
// wrapper for parameter with a known type
// specialized to handle 4 cases:
// simple "scalar" value
// parameter that is itself a block
// multiple scalar values, stored in a vector
// multiple blocks, stored in a vector