diff options
Diffstat (limited to 'indra/llcommon')
-rw-r--r-- | indra/llcommon/llsdutil.h | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/indra/llcommon/llsdutil.h b/indra/llcommon/llsdutil.h index bb8c0690b1..58ccc59f5e 100644 --- a/indra/llcommon/llsdutil.h +++ b/indra/llcommon/llsdutil.h @@ -138,4 +138,192 @@ template<typename Input> LLSD llsd_copy_array(Input iter, Input end) return dest; } +/***************************************************************************** +* LLSDArray +*****************************************************************************/ +/** + * Construct an LLSD::Array inline, with implicit conversion to LLSD. Usage: + * + * @code + * void somefunc(const LLSD&); + * ... + * somefunc(LLSDArray("text")(17)(3.14)); + * @endcode + * + * For completeness, LLSDArray() with no args constructs an empty array, so + * <tt>LLSDArray()("text")(17)(3.14)</tt> produces an array equivalent to the + * above. But for most purposes, LLSD() is already equivalent to an empty + * array, and if you explicitly want an empty isArray(), there's + * LLSD::emptyArray(). However, supporting a no-args LLSDArray() constructor + * follows the principle of least astonishment. + */ +class LLSDArray +{ +public: + LLSDArray(): + _data(LLSD::emptyArray()) + {} + LLSDArray(const LLSD& value): + _data(LLSD::emptyArray()) + { + _data.append(value); + } + + LLSDArray& operator()(const LLSD& value) + { + _data.append(value); + return *this; + } + + operator LLSD() const { return _data; } + LLSD get() const { return _data; } + +private: + LLSD _data; +}; + +/***************************************************************************** +* LLSDMap +*****************************************************************************/ +/** + * Construct an LLSD::Map inline, with implicit conversion to LLSD. Usage: + * + * @code + * void somefunc(const LLSD&); + * ... + * somefunc(LLSDMap("alpha", "abc")("number", 17)("pi", 3.14)); + * @endcode + * + * For completeness, LLSDMap() with no args constructs an empty map, so + * <tt>LLSDMap()("alpha", "abc")("number", 17)("pi", 3.14)</tt> produces a map + * equivalent to the above. But for most purposes, LLSD() is already + * equivalent to an empty map, and if you explicitly want an empty isMap(), + * there's LLSD::emptyMap(). However, supporting a no-args LLSDMap() + * constructor follows the principle of least astonishment. + */ +class LLSDMap +{ +public: + LLSDMap(): + _data(LLSD::emptyMap()) + {} + LLSDMap(const LLSD::String& key, const LLSD& value): + _data(LLSD::emptyMap()) + { + _data[key] = value; + } + + LLSDMap& operator()(const LLSD::String& key, const LLSD& value) + { + _data[key] = value; + return *this; + } + + operator LLSD() const { return _data; } + LLSD get() const { return _data; } + +private: + LLSD _data; +}; + +/***************************************************************************** +* LLSDParam +*****************************************************************************/ +/** + * LLSDParam is a customization point for passing LLSD values to function + * parameters of more or less arbitrary type. LLSD provides a small set of + * native conversions; but if a generic algorithm explicitly constructs an + * LLSDParam object in the function's argument list, a consumer can provide + * LLSDParam specializations to support more different parameter types than + * LLSD's native conversions. + * + * Usage: + * + * @code + * void somefunc(const paramtype&); + * ... + * somefunc(..., LLSDParam<paramtype>(someLLSD), ...); + * @endcode + */ +template <typename T> +class LLSDParam +{ +public: + /** + * Default implementation converts to T on construction, saves converted + * value for later retrieval + */ + LLSDParam(const LLSD& value): + _value(value) + {} + + operator T() const { return _value; } + +private: + T _value; +}; + +/** + * LLSDParam<const char*> is an example of the kind of conversion you can + * support with LLSDParam beyond native LLSD conversions. Normally you can't + * pass an LLSD object to a function accepting const char* -- but you can + * safely pass an LLSDParam<const char*>(yourLLSD). + */ +template <> +class LLSDParam<const char*> +{ +private: + // The difference here is that we store a std::string rather than a const + // char*. It's important that the LLSDParam object own the std::string. + std::string _value; + // We don't bother storing the incoming LLSD object, but we do have to + // distinguish whether _value is an empty string because the LLSD object + // contains an empty string or because it's isUndefined(). + bool _undefined; + +public: + LLSDParam(const LLSD& value): + _value(value), + _undefined(value.isUndefined()) + {} + + // The const char* we retrieve is for storage owned by our _value member. + // That's how we guarantee that the const char* is valid for the lifetime + // of this LLSDParam object. Constructing your LLSDParam in the argument + // list should ensure that the LLSDParam object will persist for the + // duration of the function call. + operator const char*() const + { + if (_undefined) + { + // By default, an isUndefined() LLSD object's asString() method + // will produce an empty string. But for a function accepting + // const char*, it's often important to be able to pass NULL, and + // isUndefined() seems like the best way. If you want to pass an + // empty string, you can still pass LLSD(""). Without this special + // case, though, no LLSD value could pass NULL. + return NULL; + } + return _value.c_str(); + } +}; + +/** + * LLSDParam<float> resolves conversion ambiguity. g++ considers F64, S32 and + * bool equivalent candidates for implicit conversion to float. (/me rolls eyes) + */ +template <> +class LLSDParam<float> +{ +private: + float _value; + +public: + LLSDParam(const LLSD& value): + _value(value.asReal()) + {} + + operator float() const { return _value; } +}; + #endif // LL_LLSDUTIL_H |