summaryrefslogtreecommitdiff
path: root/indra/llcommon/llsdutil.h
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llcommon/llsdutil.h')
-rw-r--r--indra/llcommon/llsdutil.h203
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