Newer
Older
Adam Moss
committed
template <typename DERIVED_BLOCK, typename BASE_BLOCK = BaseBlock>
Adam Moss
committed
class Block
: public BASE_BLOCK
{
Richard Linden
committed
typedef Block<DERIVED_BLOCK, BASE_BLOCK> self_t;
Richard Linden
committed
typedef Block<DERIVED_BLOCK, BASE_BLOCK> block_t;
Adam Moss
committed
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);
Adam Moss
committed
}
// 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);
Adam Moss
committed
}
Richard Nelson
committed
virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return getBlockDescriptor(); }
virtual BlockDescriptor& mostDerivedBlockDescriptor() { return getBlockDescriptor(); }
Richard Nelson
committed
Adam Moss
committed
protected:
Block()
{
//#pragma message("Parsing LLInitParam::Block")
BaseBlock::init(getBlockDescriptor(), BASE_BLOCK::getBlockDescriptor(), sizeof(DERIVED_BLOCK));
Adam Moss
committed
}
//
// Nested classes for declaring parameters
//
template <typename T, typename NAME_VALUE_LOOKUP = typename TypeValues<T>::type_value_t >
Adam Moss
committed
class Optional : public TypedParam<T, NAME_VALUE_LOOKUP, false>
{
typedef TypedParam<T, NAME_VALUE_LOOKUP, false> super_t;
typedef typename super_t::default_value_t default_value_t;
Adam Moss
committed
using super_t::operator();
Richard Linden
committed
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)
Adam Moss
committed
{
//#pragma message("Parsing LLInitParam::Block::Optional")
}
Adam Moss
committed
{
super_t::set(val);
Adam Moss
committed
return *this;
}
DERIVED_BLOCK& operator()(const value_t& val)
Adam Moss
committed
{
super_t::set(val);
return static_cast<DERIVED_BLOCK&>(Param::enclosingBlock());
}
};
template <typename T, typename NAME_VALUE_LOOKUP = typename TypeValues<T>::type_value_t >
Adam Moss
committed
class Mandatory : public TypedParam<T, NAME_VALUE_LOOKUP, false>
{
typedef TypedParam<T, NAME_VALUE_LOOKUP, false> super_t;
Graham Madarasz (Graham Linden)
committed
typedef Mandatory<T, NAME_VALUE_LOOKUP> self_t;
typedef typename super_t::default_value_t default_value_t;
Adam Moss
committed
using super_t::operator();
Richard Linden
committed
using super_t::operator =;
Adam Moss
committed
// 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)
Adam Moss
committed
{}
Adam Moss
committed
{
super_t::set(val);
Adam Moss
committed
return *this;
}
Adam Moss
committed
{
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 >
Adam Moss
committed
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:
Richard Linden
committed
typedef typename super_t::iterator iterator;
typedef typename super_t::const_iterator const_iterator;
Adam Moss
committed
using super_t::operator();
using super_t::operator const container_t&;
Richard Linden
committed
explicit Multiple(const char* name = "")
: super_t(DERIVED_BLOCK::getBlockDescriptor(), name, container_t(), &validate, RANGE::minCount, RANGE::maxCount)
Adam Moss
committed
{}
Adam Moss
committed
{
super_t::set(val);
Adam Moss
committed
return *this;
}
Richard Linden
committed
Adam Moss
committed
{
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;
Adam Moss
committed
}
};
// can appear in data files, but will ignored during parsing
// cannot read or write in code
class Ignored : public Param
Adam Moss
committed
{
public:
: Param(DERIVED_BLOCK::getBlockDescriptor().mCurrentBlockPtr)
Adam Moss
committed
{
BlockDescriptor& block_descriptor = DERIVED_BLOCK::getBlockDescriptor();
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
NULL,
&deserializeParam,
NULL,
NULL,
NULL,
Richard Linden
committed
0, S32_MAX));
block_descriptor.addParam(param_descriptor, name);
Adam Moss
committed
}
}
Richard Linden
committed
static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name)
Adam Moss
committed
{
if (name_stack_range.first == name_stack_range.second)
Adam Moss
committed
{
//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
}
};
Adam Moss
committed
public:
static BlockDescriptor& getBlockDescriptor()
Richard Nelson
committed
{
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);
}
}
Adam Moss
committed
};
template<typename T, typename BLOCK_T>
struct IsBlock<ParamValue<BaseBlock::Lazy<T, BaseBlock::IS_A_BLOCK>, BLOCK_T >, void>
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;
};
Richard Linden
committed
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>
typedef ParamValue <BaseBlock::Atomic<T>, BLOCK_T> self_t;
typedef typename InnerMostType<T>::value_t value_t;
typedef T default_value_t;
ParamValue(const default_value_t& value)
mValue.setValue(val);
const value_t& getValue() const
return mValue.getValue();
value_t& getValue()
return mValue.getValue();
Richard Linden
committed
bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name)
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
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:
static T default_value;
Richard Linden
committed
template<typename T>
class ParamValue <BaseBlock::Sequential<T>, IS_A_BLOCK>
Richard Linden
committed
typedef ParamValue <BaseBlock::Sequential<T>, IS_A_BLOCK> self_t;
Richard Linden
committed
typedef typename InnerMostType<T>::value_t value_t;
typedef T default_value_t;
Richard Linden
committed
{
mCurParam = getBlockDescriptor().mAllParams.begin();
}
Richard Linden
committed
ParamValue(const default_value_t& value)
Richard Linden
committed
mCurParam = getBlockDescriptor().mAllParams.begin();
Richard Linden
committed
void setValue(const value_t& val)
Richard Linden
committed
mValue.setValue(val);
Richard Linden
committed
const value_t& getValue() const
Richard Linden
committed
return mValue.getValue();
Richard Linden
committed
value_t& getValue()
Richard Linden
committed
return mValue.getValue();
Richard Linden
committed
bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name)
Richard Linden
committed
if (new_name)
{
mCurParam = getBlockDescriptor().mAllParams.begin();
Richard Linden
committed
if (name_stack_range.first == name_stack_range.second
&& mCurParam != getBlockDescriptor().mAllParams.end())
{
// deserialize to mCurParam
Richard Linden
committed
ParamDescriptor::deserialize_func_t deserialize_func = pd.mDeserializeFunc;
Param* paramp = mValue.getParamFromHandle(pd.mParamHandle);
Richard Linden
committed
if (deserialize_func
&& paramp
&& deserialize_func(*paramp, p, name_stack_range, new_name))
Richard Linden
committed
++mCurParam;
return true;
}
else
{
return false;
}
Richard Linden
committed
else
{
return mValue.deserializeBlock(p, name_stack_range, new_name);
}
bool serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const self_t* diff_block = NULL) const
Richard Linden
committed
const BaseBlock* base_block = diff_block
? &(diff_block->mValue)
: NULL;
return mValue.serializeBlock(p, name_stack, predicate_rule, base_block);
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
{
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);
}
Richard Linden
committed
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
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()
Richard Linden
committed
{}
Richard Linden
committed
ParamValue(const default_value_t& value)
Richard Linden
committed
{}
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;
typedef typename InnerMostType<T>::value_t value_t;
typedef LazyValue<T> default_value_t;
ParamValue(const default_value_t& other)
ParamValue(const T& value)
{}
{
mValue.set(val);
}
return mValue.get().getValue();
value_t& getValue()
return mValue.get().getValue();
Richard Linden
committed
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
Richard Linden
committed
const BaseBlock* base_block = (diff_block && !diff_block->mValue.empty())
? &(diff_block->mValue.get().getValue())
Richard Linden
committed
: 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
{
Richard Linden
committed
return mValue.empty() || mValue.get().validateBlock(emit_errors);
}
bool isValid() const
{
return validateBlock(false);
}
static BlockDescriptor& getBlockDescriptor()
{
return value_t::getBlockDescriptor();
}
template<typename T, typename BLOCK_T>
typedef ParamValue <BaseBlock::Lazy<T, NOT_BLOCK>, BLOCK_T> self_t;
typedef typename InnerMostType<T>::value_t value_t;
typedef LazyValue<T> default_value_t;
{}
ParamValue(const default_value_t& other)
{}
ParamValue(const T& value)
{
mValue.set(val);
return mValue.get().getValue();
value_t& getValue()
return mValue.get().getValue();
bool isValid() const
{
return true;
}
private:
class ParamValue <LLSD, NOT_BLOCK>
: public BaseBlock
typedef LLSD value_t;
typedef LLSD default_value_t;
ParamValue()
{}
ParamValue(const default_value_t& 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;
};
Richard Linden
committed
template<typename T>
class CustomParamValue
Adam Moss
committed
{
public:
typedef enum e_value_age
{
Richard Linden
committed
VALUE_NEEDS_UPDATE, // mValue needs to be refreshed from the block parameters
VALUE_AUTHORITATIVE, // mValue holds the authoritative value (which has been replicated to the block parameters via updateBlockFromValue)
BLOCK_AUTHORITATIVE // mValue is derived from the block parameters, which are authoritative
typedef TypeValues<T> derived_t;
typedef CustomParamValue<T> self_t;
typedef Block<ParamValue<T> > block_t;
Richard Linden
committed
Adam Moss
committed
CustomParamValue(const default_value_t& value = T())
Richard Linden
committed
: mValue(value),
mValueAge(VALUE_AUTHORITATIVE)
Richard Linden
committed
{}
Adam Moss
committed
Richard Linden
committed
bool deserializeBlock(Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name)
Adam Moss
committed
{
Richard Linden
committed
derived_t& typed_param = static_cast<derived_t&>(*this);
// try to parse direct value T
if (name_stack_range.first == name_stack_range.second)
Adam Moss
committed
{
Richard Linden
committed
if(parser.readValue(typed_param.mValue))
Adam Moss
committed
{
Richard Linden
committed
typed_param.mValueAge = VALUE_AUTHORITATIVE;
typed_param.updateBlockFromValue(false);
Adam Moss
committed
return true;
}
}
// fall back on parsing block components for T
return typed_param.BaseBlock::deserializeBlock(parser, name_stack_range, new_name);
Adam Moss
committed
}
bool serializeBlock(Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const BaseBlock* diff_block = NULL) const
Adam Moss
committed
{
const derived_t& typed_param = static_cast<const derived_t&>(*this);
const derived_t* diff_param = static_cast<const derived_t*>(diff_block);
Adam Moss
committed
//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);
// }
//}
Adam Moss
committed
// then try to serialize value directly
if (!diff_param || !ParamCompare<T>::equals(typed_param.getValue(), diff_param->getValue()))
Adam Moss
committed
{
if (parser.writeValue(typed_param.getValue(), name_stack))
{
return true;
}
else
Adam Moss
committed
{
Richard Linden
committed
//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);
Adam Moss
committed
}
}
Adam Moss
committed
}
Richard Linden
committed
bool validateBlock(bool emit_errors = true) const
Adam Moss
committed
{
Richard Linden
committed
if (mValueAge == VALUE_NEEDS_UPDATE)
Adam Moss
committed
{
Richard Linden
committed
if (block_t::validateBlock(emit_errors))
Adam Moss
committed
{
// clear stale keyword associated with old value
Richard Linden
committed
mValueAge = BLOCK_AUTHORITATIVE;
static_cast<derived_t*>(const_cast<self_t*>(this))->updateValueFromBlock();
Adam Moss
committed
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;
}
Adam Moss
committed
}
// propagate change status up to enclosing block
Richard Linden
committed
/*virtual*/ void paramChanged(const Param& changed_param, bool user_provided)
Adam Moss
committed
{
Richard Linden
committed
BaseBlock::paramChanged(changed_param, user_provided);
Adam Moss
committed
if (user_provided)
// a parameter changed, so our value is out of date
Richard Linden
committed
mValueAge = VALUE_NEEDS_UPDATE;
Adam Moss
committed
}
}
Richard Linden
committed
Adam Moss
committed
{
Richard Linden
committed
// 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);
Adam Moss
committed
}
Richard Linden
committed
{
validateBlock(true);
return mValue;
}
Richard Linden
committed
T& getValue()
Adam Moss
committed
{
Richard Linden
committed
validateBlock(true);
return mValue;
}
Adam Moss
committed
Richard Linden
committed
protected:
Adam Moss
committed
Richard Linden
committed
// use this from within updateValueFromBlock() to set the value without making it authoritative
Adam Moss
committed
{
Richard Linden
committed
mValue = value;
}
Adam Moss
committed
bool mergeBlockParam(bool source_provided, bool dst_provided, BlockDescriptor& block_data, const BaseBlock& source, bool overwrite)
Richard Linden
committed
{
bool source_override = source_provided && (overwrite || !dst_provided);
Richard Linden
committed
const derived_t& src_typed_param = static_cast<const derived_t&>(source);
Richard Linden
committed
if (source_override && src_typed_param.mValueAge == VALUE_AUTHORITATIVE)
Adam Moss
committed
{
Richard Linden
committed
// copy value over
setValue(src_typed_param.getValue());
Adam Moss
committed
return true;
}
// merge individual parameters into destination
if (mValueAge == VALUE_AUTHORITATIVE)
Richard Linden
committed
{
static_cast<derived_t*>(this)->updateBlockFromValue(dst_provided);
Richard Linden
committed
}
return mergeBlock(block_data, source, overwrite);
}
bool mergeBlock(BlockDescriptor& block_data, const BaseBlock& source, bool overwrite)
{
return block_t::mergeBlock(block_data, source, overwrite);
Adam Moss
committed
}
Richard Linden
committed
private:
mutable T mValue;
mutable EValueAge mValueAge;
};
Adam Moss
committed
}
Richard Linden
committed
Adam Moss
committed
#endif // LL_LLPARAM_H