diff options
Diffstat (limited to 'indra/llcommon/llsdutil.h')
-rw-r--r-- | indra/llcommon/llsdutil.h | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/indra/llcommon/llsdutil.h b/indra/llcommon/llsdutil.h index 01ab6bcb8d..8678ca97f2 100644 --- a/indra/llcommon/llsdutil.h +++ b/indra/llcommon/llsdutil.h @@ -30,6 +30,7 @@ #define LL_LLSDUTIL_H #include "llsd.h" +#include <boost/functional/hash.hpp> // U32 LL_COMMON_API LLSD ll_sd_from_U32(const U32); @@ -70,6 +71,19 @@ LL_COMMON_API BOOL compare_llsd_with_template( const LLSD& template_llsd, LLSD& resultant_llsd); +// filter_llsd_with_template() is a direct clone (copy-n-paste) of +// compare_llsd_with_template with the following differences: +// (1) bool vs BOOL return types +// (2) A map with the key value "*" is a special value and maps any key in the +// test llsd that doesn't have an explicitly matching key in the template. +// (3) The element of an array with exactly one element is taken as a template +// for *all* the elements of the test array. If the template array is of +// different size, compare_llsd_with_template() semantics apply. +bool filter_llsd_with_template( + const LLSD & llsd_to_test, + const LLSD & template_llsd, + LLSD & resultant_llsd); + /** * Recursively determine whether a given LLSD data block "matches" another * LLSD prototype. The returned string is empty() on success, non-empty() on @@ -129,6 +143,16 @@ LL_COMMON_API std::string llsd_matches(const LLSD& prototype, const LLSD& data, /// equality rather than bitwise equality, pass @a bits as for /// is_approx_equal_fraction(). LL_COMMON_API bool llsd_equals(const LLSD& lhs, const LLSD& rhs, int bits=-1); +/// If you don't care about LLSD::Real equality +inline bool operator==(const LLSD& lhs, const LLSD& rhs) +{ + return llsd_equals(lhs, rhs); +} +inline bool operator!=(const LLSD& lhs, const LLSD& rhs) +{ + // operator!=() should always be the negation of operator==() + return ! (lhs == rhs); +} // Simple function to copy data out of input & output iterators if // there is no need for casting. @@ -142,6 +166,31 @@ template<typename Input> LLSD llsd_copy_array(Input iter, Input end) return dest; } +namespace llsd +{ + +/** + * Drill down to locate an element in 'blob' according to 'path', where 'path' + * is one of the following: + * + * - LLSD::String: 'blob' is an LLSD::Map. Find the entry with key 'path'. + * - LLSD::Integer: 'blob' is an LLSD::Array. Find the entry with index 'path'. + * - Any other 'path' type will be interpreted as LLSD::Array, and 'blob' is a + * nested structure. For each element of 'path': + * - If it's an LLSD::Integer, select the entry with that index from an + * LLSD::Array at that level. + * - If it's an LLSD::String, select the entry with that key from an + * LLSD::Map at that level. + * - Anything else is an error. + * + * By implication, if path.isUndefined() or otherwise equivalent to an empty + * LLSD::Array, drill() returns 'blob' as is. + */ +LLSD drill(const LLSD& blob, const LLSD& path); +LLSD& drill( LLSD& blob, const LLSD& path); + +} + /***************************************************************************** * LLSDArray *****************************************************************************/ @@ -211,6 +260,36 @@ private: LLSD _data; }; +namespace llsd +{ + +/** + * Construct an LLSD::Array inline, using modern C++ variadic arguments. + */ + +// recursion tail +inline +void array_(LLSD&) {} + +// recursive call +template <typename T0, typename... Ts> +void array_(LLSD& data, T0&& v0, Ts&&... vs) +{ + data.append(std::forward<T0>(v0)); + array_(data, std::forward<Ts>(vs)...); +} + +// public interface +template <typename... Ts> +LLSD array(Ts&&... vs) +{ + LLSD data; + array_(data, std::forward<Ts>(vs)...); + return data; +} + +} // namespace llsd + /***************************************************************************** * LLSDMap *****************************************************************************/ @@ -255,6 +334,36 @@ private: LLSD _data; }; +namespace llsd +{ + +/** + * Construct an LLSD::Map inline, using modern C++ variadic arguments. + */ + +// recursion tail +inline +void map_(LLSD&) {} + +// recursive call +template <typename T0, typename... Ts> +void map_(LLSD& data, const LLSD::String& k0, T0&& v0, Ts&&... vs) +{ + data[k0] = v0; + map_(data, std::forward<Ts>(vs)...); +} + +// public interface +template <typename... Ts> +LLSD map(Ts&&... vs) +{ + LLSD data; + map_(data, std::forward<Ts>(vs)...); + return data; +} + +} // namespace llsd + /***************************************************************************** * LLSDParam *****************************************************************************/ @@ -421,4 +530,98 @@ private: } // namespace llsd + +// Creates a deep clone of an LLSD object. Maps, Arrays and binary objects +// are duplicated, atomic primitives (Boolean, Integer, Real, etc) simply +// use a shared reference. +// Optionally a filter may be specified to control what is duplicated. The +// map takes the form "keyname/boolean". +// If the value is true the value will be duplicated otherwise it will be skipped +// when encountered in a map. A key name of "*" can be specified as a wild card +// and will specify the default behavior. If no wild card is given and the clone +// encounters a name not in the filter, that value will be skipped. +LLSD llsd_clone(LLSD value, LLSD filter = LLSD()); + +// Creates a shallow copy of a map or array. If passed any other type of LLSD +// object it simply returns that value. See llsd_clone for a description of +// the filter parameter. +LLSD llsd_shallow(LLSD value, LLSD filter = LLSD()); + +namespace llsd +{ + +// llsd namespace aliases +inline +LLSD clone (LLSD value, LLSD filter=LLSD()) { return llsd_clone (value, filter); } +inline +LLSD shallow(LLSD value, LLSD filter=LLSD()) { return llsd_shallow(value, filter); } + +} // namespace llsd + +// Specialization for generating a hash value from an LLSD block. +namespace boost +{ +template <> +struct hash<LLSD> +{ + typedef LLSD argument_type; + typedef std::size_t result_type; + result_type operator()(argument_type const& s) const + { + result_type seed(0); + + LLSD::Type stype = s.type(); + boost::hash_combine(seed, (S32)stype); + + switch (stype) + { + case LLSD::TypeBoolean: + boost::hash_combine(seed, s.asBoolean()); + break; + case LLSD::TypeInteger: + boost::hash_combine(seed, s.asInteger()); + break; + case LLSD::TypeReal: + boost::hash_combine(seed, s.asReal()); + break; + case LLSD::TypeURI: + case LLSD::TypeString: + boost::hash_combine(seed, s.asString()); + break; + case LLSD::TypeUUID: + boost::hash_combine(seed, s.asUUID()); + break; + case LLSD::TypeDate: + boost::hash_combine(seed, s.asDate().secondsSinceEpoch()); + break; + case LLSD::TypeBinary: + { + const LLSD::Binary &b(s.asBinary()); + boost::hash_range(seed, b.begin(), b.end()); + break; + } + case LLSD::TypeMap: + { + for (LLSD::map_const_iterator itm = s.beginMap(); itm != s.endMap(); ++itm) + { + boost::hash_combine(seed, (*itm).first); + boost::hash_combine(seed, (*itm).second); + } + break; + } + case LLSD::TypeArray: + for (LLSD::array_const_iterator ita = s.beginArray(); ita != s.endArray(); ++ita) + { + boost::hash_combine(seed, (*ita)); + } + break; + case LLSD::TypeUndefined: + default: + break; + } + + return seed; + } +}; +} #endif // LL_LLSDUTIL_H |