diff options
| author | Rider Linden <rider@lindenlab.com> | 2017-11-27 10:19:43 -0800 | 
|---|---|---|
| committer | Rider Linden <rider@lindenlab.com> | 2017-11-27 10:19:43 -0800 | 
| commit | 66ba27cb91b4f81625b8ab535f41bcf38a2aae99 (patch) | |
| tree | a542d46607c4360a1648fd53c8dbe03f4690a9a7 | |
| parent | 0bf6386c61c0c28b298c2cccd82c786f754024af (diff) | |
Added boost::hash<> spec for LLSD
| -rw-r--r-- | indra/llcommon/llsdutil.h | 65 | ||||
| -rw-r--r-- | indra/llcommon/lluuid.h | 20 | ||||
| -rw-r--r-- | indra/newview/llsettingsbase.cpp | 6 | ||||
| -rw-r--r-- | indra/newview/llsettingsbase.h | 6 | ||||
| -rw-r--r-- | indra/test/llsdutil_tut.cpp | 45 | 
5 files changed, 140 insertions, 2 deletions
diff --git a/indra/llcommon/llsdutil.h b/indra/llcommon/llsdutil.h index 99cb79aa54..595bb91411 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); @@ -419,4 +420,68 @@ private:  } // namespace llsd + +// Specialization for generating a hash value from an LLSD block.  +template <> +struct boost::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: +            break; +        } + +        return seed; +    } +}; +  #endif // LL_LLSDUTIL_H diff --git a/indra/llcommon/lluuid.h b/indra/llcommon/lluuid.h index dd8660a3c8..fe7482ba29 100644 --- a/indra/llcommon/lluuid.h +++ b/indra/llcommon/lluuid.h @@ -31,6 +31,7 @@  #include <vector>  #include "stdtypes.h"  #include "llpreprocessor.h" +#include <boost/functional/hash.hpp>  class LLMutex; @@ -164,6 +165,25 @@ public:  	LLAssetID makeAssetID(const LLUUID& session) const;  }; +// Generate a hash of an LLUUID object using the boost hash templates.  +template <> +struct boost::hash<LLUUID> +{ +    typedef LLUUID argument_type; +    typedef std::size_t result_type; +    result_type operator()(argument_type const& s) const +    { +        result_type seed(0); + +        for (S32 i = 0; i < UUID_BYTES; ++i) +        { +            boost::hash_combine(seed, s.mData[i]); +        } + +        return seed; +    } +}; +  #endif diff --git a/indra/newview/llsettingsbase.cpp b/indra/newview/llsettingsbase.cpp index 904d0dd07c..e36c6d4a84 100644 --- a/indra/newview/llsettingsbase.cpp +++ b/indra/newview/llsettingsbase.cpp @@ -48,13 +48,15 @@ const F32Seconds LLSettingsBlender::DEFAULT_THRESHOLD(0.01);  //=========================================================================  LLSettingsBase::LLSettingsBase():      mSettings(LLSD::emptyMap()), -    mDirty(true) +    mDirty(true), +    mHashValue(0)  {  }  LLSettingsBase::LLSettingsBase(const LLSD setting) :      mSettings(setting), -    mDirty(true) +    mDirty(true), +    mHashValue(0)  {  } diff --git a/indra/newview/llsettingsbase.h b/indra/newview/llsettingsbase.h index d32fcb26e8..d304b8702a 100644 --- a/indra/newview/llsettingsbase.h +++ b/indra/newview/llsettingsbase.h @@ -67,6 +67,11 @@ public:      inline bool isDirty() const { return mDirty; }      inline void setDirtyFlag(bool dirty) { mDirty = dirty; } +    inline size_t getHash() const +    { +        return boost::hash<LLSD>{}(mSettings); +    } +      inline LLUUID getId() const      {          return getValue(SETTING_ID).asUUID(); @@ -227,6 +232,7 @@ protected:  private:      bool    mDirty; +    size_t  mHashValue;      LLSD    combineSDMaps(const LLSD &first, const LLSD &other) const; diff --git a/indra/test/llsdutil_tut.cpp b/indra/test/llsdutil_tut.cpp index 140f4b832b..6fce53f335 100644 --- a/indra/test/llsdutil_tut.cpp +++ b/indra/test/llsdutil_tut.cpp @@ -386,4 +386,49 @@ namespace tut          lmap["Seattle"] = 72;          ensure("llsd_equals(superset left map)", ! llsd_equals(lmap, rmap));      } + +    template<> template<>  +    void llsdutil_object::test<10>() +    { +        set_test_name("llsd_hashing"); + +        { +            LLSD data_s1 = LLSD::String("The quick brown aardvark jumped over the lazy lemming."); +            LLSD data_s2 = LLSD::String("The quick brown aardvark jumped over the lazy lemming."); + +            ensure("hash: Identical string hashes match.", boost::hash<LLSD>{}(data_s1) == boost::hash<LLSD>{}(data_s2)); +        } +        { +            LLSD data_r1 = LLSD::Real(3.0f); +            LLSD data_i1 = LLSD::Integer(3); +            ensure("hash: equivalent values but different types do not match.", boost::hash<LLSD>{}(data_r1) != boost::hash<LLSD>{}(data_i1)); +        } +        { +            LLSD data_a1 = LLSDArray("A")("B")("C"); +            LLSD data_a2 = LLSDArray("A")("B")("C"); + +            ensure("hash: identical arrays produce identical results", boost::hash<LLSD>{}(data_a1) == boost::hash<LLSD>{}(data_a2)); + +            data_a2.append(LLSDArray(1)(2)); + +            ensure("hash: changing the array changes the hash.", boost::hash<LLSD>{}(data_a1) != boost::hash<LLSD>{}(data_a2)); + +            data_a1.append(LLSDArray(1)(2)); +            ensure("hash: identical arrays produce identical results with nested arrays", boost::hash<LLSD>{}(data_a1) == boost::hash<LLSD>{}(data_a2)); +        } +        { +            LLSD data_m1 = LLSDMap("key1", LLSD::Real(3.0))("key2", "value2")("key3", LLSDArray(1)(2)(3)); +            LLSD data_m2 = LLSDMap("key1", LLSD::Real(3.0))("key2", "value2")("key3", LLSDArray(1)(2)(3)); + +            ensure("hash: identical maps produce identical results", boost::hash<LLSD>{}(data_m1) == boost::hash<LLSD>{}(data_m2)); + +            LLSD data_m3 = LLSDMap("key1", LLSD::Real(5.0))("key2", "value2")("key3", LLSDArray(1)(2)(3)); +            ensure("hash: Different values in the map produce different hashes.", boost::hash<LLSD>{}(data_m1) != boost::hash<LLSD>{}(data_m3)); + +            LLSD data_m4 = LLSDMap("keyA", LLSD::Real(3.0))("key2", "value2")("key3", LLSDArray(1)(2)(3)); +            ensure("hash: Different keys in the map produce different hashes.", boost::hash<LLSD>{}(data_m1) != boost::hash<LLSD>{}(data_m4)); + +        } +    } +  }  | 
