diff options
author | Andrey Lihatskiy <alihatskiy@productengine.com> | 2020-04-27 15:16:21 +0300 |
---|---|---|
committer | Andrey Lihatskiy <alihatskiy@productengine.com> | 2020-04-27 15:16:21 +0300 |
commit | 94dc8f12f86adb3bf79b44ab0bc98e6c0f6899ee (patch) | |
tree | 7434d3d4dde8eedbad54d5b954579029026f1308 /indra/llcommon | |
parent | a5eb15da0a89c6f9df7d426c0c3c41df445cfd2f (diff) | |
parent | d7f1c88c35849e56f5b352f13c16a08467d1533b (diff) |
Merge branch 'master' into DRTVWR-507-maint
Diffstat (limited to 'indra/llcommon')
-rw-r--r-- | indra/llcommon/indra_constants.cpp | 1 | ||||
-rw-r--r-- | indra/llcommon/indra_constants.h | 1 | ||||
-rw-r--r-- | indra/llcommon/llassettype.cpp | 19 | ||||
-rw-r--r-- | indra/llcommon/llassettype.h | 19 | ||||
-rw-r--r-- | indra/llcommon/llerror.cpp | 58 | ||||
-rw-r--r-- | indra/llcommon/llmemory.cpp | 6 | ||||
-rw-r--r-- | indra/llcommon/llsd.cpp | 26 | ||||
-rw-r--r-- | indra/llcommon/llsd.h | 5 | ||||
-rw-r--r-- | indra/llcommon/llsdserialize.cpp | 10 | ||||
-rw-r--r-- | indra/llcommon/llsdserialize.h | 2 | ||||
-rw-r--r-- | indra/llcommon/llsdutil.cpp | 275 | ||||
-rw-r--r-- | indra/llcommon/llsdutil.h | 96 | ||||
-rw-r--r-- | indra/llcommon/llsingleton.h | 15 | ||||
-rw-r--r-- | indra/llcommon/llunittype.h | 37 | ||||
-rw-r--r-- | indra/llcommon/lluuid.h | 20 |
15 files changed, 521 insertions, 69 deletions
diff --git a/indra/llcommon/indra_constants.cpp b/indra/llcommon/indra_constants.cpp index e13176e8fa..1b48e4daf3 100644 --- a/indra/llcommon/indra_constants.cpp +++ b/indra/llcommon/indra_constants.cpp @@ -64,7 +64,6 @@ const LLUUID IMG_ALPHA_GRAD ("e97cf410-8e61-7005-ec06-629eba4cd1fb"); // VIEW const LLUUID IMG_ALPHA_GRAD_2D ("38b86f85-2575-52a9-a531-23108d8da837"); // VIEWER const LLUUID IMG_TRANSPARENT ("8dcd4a48-2d37-4909-9f78-f7a9eb4ef903"); // VIEWER -const LLUUID IMG_BLOOM1 ("3c59f7fe-9dc8-47f9-8aaf-a9dd1fbc3bef"); // VIEWER const LLUUID TERRAIN_DIRT_DETAIL ("0bc58228-74a0-7e83-89bc-5c23464bcec5"); // VIEWER const LLUUID TERRAIN_GRASS_DETAIL ("63338ede-0037-c4fd-855b-015d77112fc8"); // VIEWER const LLUUID TERRAIN_MOUNTAIN_DETAIL ("303cd381-8560-7579-23f1-f0a880799740"); // VIEWER diff --git a/indra/llcommon/indra_constants.h b/indra/llcommon/indra_constants.h index 0fbf4b966b..e7b0e0ef8e 100644 --- a/indra/llcommon/indra_constants.h +++ b/indra/llcommon/indra_constants.h @@ -200,7 +200,6 @@ LL_COMMON_API extern const LLUUID IMG_ALPHA_GRAD; LL_COMMON_API extern const LLUUID IMG_ALPHA_GRAD_2D; LL_COMMON_API extern const LLUUID IMG_TRANSPARENT; -LL_COMMON_API extern const LLUUID IMG_BLOOM1; LL_COMMON_API extern const LLUUID TERRAIN_DIRT_DETAIL; LL_COMMON_API extern const LLUUID TERRAIN_GRASS_DETAIL; LL_COMMON_API extern const LLUUID TERRAIN_MOUNTAIN_DETAIL; diff --git a/indra/llcommon/llassettype.cpp b/indra/llcommon/llassettype.cpp index 7e5a157cdf..e6cc06e8d0 100644 --- a/indra/llcommon/llassettype.cpp +++ b/indra/llcommon/llassettype.cpp @@ -95,11 +95,14 @@ LLAssetDictionary::LLAssetDictionary() addEntry(LLAssetType::AT_MESH, new AssetEntry("MESH", "mesh", "mesh", false, false, false)); addEntry(LLAssetType::AT_WIDGET, new AssetEntry("WIDGET", "widget", "widget", false, false, false)); addEntry(LLAssetType::AT_PERSON, new AssetEntry("PERSON", "person", "person", false, false, false)); + addEntry(LLAssetType::AT_SETTINGS, new AssetEntry("SETTINGS", "settings", "settings blob", true, true, true)); addEntry(LLAssetType::AT_UNKNOWN, new AssetEntry("UNKNOWN", "invalid", NULL, false, false, false)); - addEntry(LLAssetType::AT_NONE, new AssetEntry("NONE", "-1", NULL, FALSE, FALSE, FALSE)); + addEntry(LLAssetType::AT_NONE, new AssetEntry("NONE", "-1", NULL, FALSE, FALSE, FALSE)); }; +const std::string LLAssetType::BADLOOKUP("llassettype_bad_lookup"); + // static LLAssetType::EType LLAssetType::getType(const std::string& desc_name) { @@ -118,7 +121,7 @@ const std::string &LLAssetType::getDesc(LLAssetType::EType asset_type) } else { - return badLookup(); + return BADLOOKUP; } } @@ -133,7 +136,7 @@ const char *LLAssetType::lookup(LLAssetType::EType asset_type) } else { - return badLookup().c_str(); + return BADLOOKUP.c_str(); } } @@ -171,7 +174,7 @@ const char *LLAssetType::lookupHumanReadable(LLAssetType::EType asset_type) } else { - return badLookup().c_str(); + return BADLOOKUP.c_str(); } } @@ -222,14 +225,6 @@ bool LLAssetType::lookupIsLinkType(EType asset_type) } // static -const std::string &LLAssetType::badLookup() -{ - static const std::string sBadLookup = "llassettype_bad_lookup"; - return sBadLookup; - -} - -// static bool LLAssetType::lookupIsAssetFetchByIDAllowed(EType asset_type) { const LLAssetDictionary *dict = LLAssetDictionary::getInstance(); diff --git a/indra/llcommon/llassettype.h b/indra/llcommon/llassettype.h index 79ab3d7efe..652c548d59 100644 --- a/indra/llcommon/llassettype.h +++ b/indra/llcommon/llassettype.h @@ -116,10 +116,19 @@ public: AT_PERSON = 45, // A user uuid which is not an inventory asset type, used in viewer only for adding a person to a chat via drag and drop. - AT_MESH = 49, - // Mesh data in our proprietary SLM format - - AT_COUNT = 50, + AT_MESH = 49, + // Mesh data in our proprietary SLM format + + AT_RESERVED_1 = 50, + AT_RESERVED_2 = 51, + AT_RESERVED_3 = 52, + AT_RESERVED_4 = 53, + AT_RESERVED_5 = 54, + AT_RESERVED_6 = 55, + + AT_SETTINGS = 56, // Collection of settings + + AT_COUNT = 57, // +*********************************************************+ // | TO ADD AN ELEMENT TO THIS ENUM: | @@ -153,7 +162,7 @@ public: static bool lookupIsAssetFetchByIDAllowed(EType asset_type); // the asset allows direct download static bool lookupIsAssetIDKnowable(EType asset_type); // asset data can be known by the viewer - static const std::string& badLookup(); // error string when a lookup fails + static const std::string BADLOOKUP; protected: LLAssetType() {} diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index 335a0995fe..b46f49ba34 100644 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -181,32 +181,35 @@ namespace { return LLError::getEnabledLogTypesMask() & 0x04; } + LL_FORCE_INLINE std::string createANSI(const std::string& color) + { + std::string ansi_code; + ansi_code += '\033'; + ansi_code += "["; + ansi_code += color; + ansi_code += "m"; + return ansi_code; + } + virtual void recordMessage(LLError::ELevel level, const std::string& message) override - { - if (ANSI_PROBE == mUseANSI) - mUseANSI = (checkANSI() ? ANSI_YES : ANSI_NO); + { + static std::string s_ansi_error = createANSI("31"); // red + static std::string s_ansi_warn = createANSI("34"); // blue + static std::string s_ansi_debug = createANSI("35"); // magenta + + mUseANSI = (ANSI_PROBE == mUseANSI) ? (checkANSI() ? ANSI_YES : ANSI_NO) : mUseANSI; if (ANSI_YES == mUseANSI) { - // Default all message levels to bold so we can distinguish our own messages from those dumped by subprocesses and libraries. - colorANSI("1"); // bold - switch (level) { - case LLError::LEVEL_ERROR: - colorANSI("31"); // red - break; - case LLError::LEVEL_WARN: - colorANSI("34"); // blue - break; - case LLError::LEVEL_DEBUG: - colorANSI("35"); // magenta - break; - default: - break; - } + writeANSI((level == LLError::LEVEL_ERROR) ? s_ansi_error : + (level == LLError::LEVEL_WARN) ? s_ansi_warn : + s_ansi_debug, message); } - fprintf(stderr, "%s\n", message.c_str()); - if (ANSI_YES == mUseANSI) colorANSI("0"); // reset + else + { + fprintf(stderr, "%s\n", message.c_str()); + } } private: @@ -217,11 +220,14 @@ namespace { ANSI_NO } mUseANSI; - void colorANSI(const std::string color) + LL_FORCE_INLINE void writeANSI(const std::string& ansi_code, const std::string& message) { - // ANSI color code escape sequence - fprintf(stderr, "\033[%sm", color.c_str() ); - }; + static std::string s_ansi_bold = createANSI("1"); // bold + static std::string s_ansi_reset = createANSI("0"); // reset + // ANSI color code escape sequence, message, and reset in one fprintf call + // Default all message levels to bold so we can distinguish our own messages from those dumped by subprocesses and libraries. + fprintf(stderr, "%s%s%s\n%s", s_ansi_bold.c_str(), ansi_code.c_str(), message.c_str(), s_ansi_reset.c_str() ); + } bool checkANSI(void) { @@ -232,8 +238,8 @@ namespace { return (0 != isatty(2)) && (NULL == getenv("LL_NO_ANSI_COLOR")); #endif // LL_LINUX - return false; - }; + return FALSE; // works in a cygwin shell... ;) + } }; class RecordToFixedBuffer : public LLError::Recorder diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index b3debf3550..1884d6f04f 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -77,7 +77,7 @@ void ll_assert_aligned_func(uintptr_t ptr,U32 alignment) //static void LLMemory::initMaxHeapSizeGB(F32Gigabytes max_heap_size, BOOL prevent_heap_failure) { - sMaxHeapSizeInKB = max_heap_size; + sMaxHeapSizeInKB = U32Kilobytes::convert(max_heap_size); sEnableMemoryFailurePrevention = prevent_heap_failure ; } @@ -93,9 +93,9 @@ void LLMemory::updateMemoryInfo() return ; } - sAllocatedMemInKB = U64Bytes(counters.WorkingSetSize) ; + sAllocatedMemInKB = U32Kilobytes::convert(U64Bytes(counters.WorkingSetSize)); sample(sAllocatedMem, sAllocatedMemInKB); - sAllocatedPageSizeInKB = U64Bytes(counters.PagefileUsage) ; + sAllocatedPageSizeInKB = U32Kilobytes::convert(U64Bytes(counters.PagefileUsage)); sample(sVirtualMem, sAllocatedPageSizeInKB); U32Kilobytes avail_phys, avail_virtual; diff --git a/indra/llcommon/llsd.cpp b/indra/llcommon/llsd.cpp index 57aa7d9c07..57b746889d 100644 --- a/indra/llcommon/llsd.cpp +++ b/indra/llcommon/llsd.cpp @@ -132,6 +132,7 @@ public: virtual bool has(const String&) const { return false; } virtual LLSD get(const String&) const { return LLSD(); } + virtual LLSD getKeys() const { return LLSD::emptyArray(); } virtual void erase(const String&) { } virtual const LLSD& ref(const String&) const{ return undef(); } @@ -380,7 +381,8 @@ namespace using LLSD::Impl::erase; // Unhiding erase(LLSD::Integer) using LLSD::Impl::ref; // Unhiding ref(LLSD::Integer) virtual LLSD get(const LLSD::String&) const; - void insert(const LLSD::String& k, const LLSD& v); + virtual LLSD getKeys() const; + void insert(const LLSD::String& k, const LLSD& v); virtual void erase(const LLSD::String&); LLSD& ref(const LLSD::String&); virtual const LLSD& ref(const LLSD::String&) const; @@ -421,7 +423,19 @@ namespace DataMap::const_iterator i = mData.find(k); return (i != mData.end()) ? i->second : LLSD(); } - + + LLSD ImplMap::getKeys() const + { + LLSD keys = LLSD::emptyArray(); + DataMap::const_iterator iter = mData.begin(); + while (iter != mData.end()) + { + keys.append((*iter).first); + iter++; + } + return keys; + } + void ImplMap::insert(const LLSD::String& k, const LLSD& v) { mData.insert(DataMap::value_type(k, v)); @@ -502,7 +516,7 @@ namespace virtual LLSD get(LLSD::Integer) const; void set(LLSD::Integer, const LLSD&); void insert(LLSD::Integer, const LLSD&); - void append(const LLSD&); + LLSD& append(const LLSD&); virtual void erase(LLSD::Integer); LLSD& ref(LLSD::Integer); virtual const LLSD& ref(LLSD::Integer) const; @@ -570,9 +584,10 @@ namespace mData.insert(mData.begin() + index, v); } - void ImplArray::append(const LLSD& v) + LLSD& ImplArray::append(const LLSD& v) { mData.push_back(v); + return mData.back(); } void ImplArray::erase(LLSD::Integer i) @@ -862,6 +877,7 @@ LLSD LLSD::emptyMap() bool LLSD::has(const String& k) const { return safe(impl).has(k); } LLSD LLSD::get(const String& k) const { return safe(impl).get(k); } +LLSD LLSD::getKeys() const { return safe(impl).getKeys(); } void LLSD::insert(const String& k, const LLSD& v) { makeMap(impl).insert(k, v); } LLSD& LLSD::with(const String& k, const LLSD& v) @@ -895,7 +911,7 @@ LLSD& LLSD::with(Integer i, const LLSD& v) makeArray(impl).insert(i, v); return *this; } -void LLSD::append(const LLSD& v) { makeArray(impl).append(v); } +LLSD& LLSD::append(const LLSD& v) { return makeArray(impl).append(v); } void LLSD::erase(Integer i) { makeArray(impl).erase(i); } LLSD& LLSD::operator[](Integer i) diff --git a/indra/llcommon/llsd.h b/indra/llcommon/llsd.h index 7b9b1285f5..5b6d5545af 100644 --- a/indra/llcommon/llsd.h +++ b/indra/llcommon/llsd.h @@ -79,7 +79,7 @@ an LLSD array). An array is a sequence of zero or more LLSD values. - + Thread Safety In general, these LLSD classes offer *less* safety than STL container @@ -284,6 +284,7 @@ public: bool has(const String&) const; LLSD get(const String&) const; + LLSD getKeys() const; // Return an LLSD array with keys as strings void insert(const String&, const LLSD&); void erase(const String&); LLSD& with(const String&, const LLSD&); @@ -301,7 +302,7 @@ public: LLSD get(Integer) const; void set(Integer, const LLSD&); void insert(Integer, const LLSD&); - void append(const LLSD&); + LLSD& append(const LLSD&); void erase(Integer); LLSD& with(Integer, const LLSD&); diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp index 1aaff5628f..c3fb4ebc2c 100644 --- a/indra/llcommon/llsdserialize.cpp +++ b/indra/llcommon/llsdserialize.cpp @@ -55,6 +55,7 @@ static const S32 UNZIP_LLSD_MAX_DEPTH = 96; static const char LEGACY_NON_HEADER[] = "<llsd>"; const std::string LLSD_BINARY_HEADER("LLSD/Binary"); const std::string LLSD_XML_HEADER("LLSD/XML"); +const std::string LLSD_NOTATION_HEADER("llsd/notation"); //used to deflate a gzipped asset (currently used for navmeshes) #define windowBits 15 @@ -81,6 +82,11 @@ void LLSDSerialize::serialize(const LLSD& sd, std::ostream& str, ELLSD_Serialize f = new LLSDXMLFormatter; break; + case LLSD_NOTATION: + str << "<? " << LLSD_NOTATION_HEADER << " ?>\n"; + f = new LLSDNotationFormatter; + break; + default: LL_WARNS() << "serialize request for unknown ELLSD_Serialize" << LL_ENDL; } @@ -168,6 +174,10 @@ bool LLSDSerialize::deserialize(LLSD& sd, std::istream& str, S32 max_bytes) { p = new LLSDXMLParser; } + else if (header == LLSD_NOTATION_HEADER) + { + p = new LLSDNotationParser; + } else { LL_WARNS() << "deserialize request for unknown ELLSD_Serialize" << LL_ENDL; diff --git a/indra/llcommon/llsdserialize.h b/indra/llcommon/llsdserialize.h index 8165410e80..fe0f4443ef 100644 --- a/indra/llcommon/llsdserialize.h +++ b/indra/llcommon/llsdserialize.h @@ -706,7 +706,7 @@ class LL_COMMON_API LLSDSerialize public: enum ELLSD_Serialize { - LLSD_BINARY, LLSD_XML + LLSD_BINARY, LLSD_XML, LLSD_NOTATION }; /** diff --git a/indra/llcommon/llsdutil.cpp b/indra/llcommon/llsdutil.cpp index 9d00395c0a..6a23c443a0 100644 --- a/indra/llcommon/llsdutil.cpp +++ b/indra/llcommon/llsdutil.cpp @@ -322,6 +322,180 @@ BOOL compare_llsd_with_template( return TRUE; } +// 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) +{ + if (llsd_to_test.isUndefined() && template_llsd.isDefined()) + { + resultant_llsd = template_llsd; + return true; + } + else if (llsd_to_test.type() != template_llsd.type()) + { + resultant_llsd = LLSD(); + return false; + } + + if (llsd_to_test.isArray()) + { + //they are both arrays + //we loop over all the items in the template + //verifying that the to_test has a subset (in the same order) + //any shortcoming in the testing_llsd are just taken + //to be the rest of the template + LLSD data; + LLSD::array_const_iterator test_iter; + LLSD::array_const_iterator template_iter; + + resultant_llsd = LLSD::emptyArray(); + test_iter = llsd_to_test.beginArray(); + + if (1 == template_llsd.size()) + { + // If the template has a single item, treat it as + // the template for *all* items in the test LLSD. + template_iter = template_llsd.beginArray(); + + for (; test_iter != llsd_to_test.endArray(); ++test_iter) + { + if (! filter_llsd_with_template(*test_iter, *template_iter, data)) + { + resultant_llsd = LLSD(); + return false; + } + else + { + resultant_llsd.append(data); + } + } + } + else + { + // Traditional compare_llsd_with_template matching + + for (template_iter = template_llsd.beginArray(); + template_iter != template_llsd.endArray() && + test_iter != llsd_to_test.endArray(); + ++template_iter, ++test_iter) + { + if (! filter_llsd_with_template(*test_iter, *template_iter, data)) + { + resultant_llsd = LLSD(); + return false; + } + else + { + resultant_llsd.append(data); + } + } + + //so either the test or the template ended + //we do another loop now to the end of the template + //grabbing the default values + for (; + template_iter != template_llsd.endArray(); + ++template_iter) + { + resultant_llsd.append(*template_iter); + } + } + } + else if (llsd_to_test.isMap()) + { + resultant_llsd = LLSD::emptyMap(); + + //now we loop over the keys of the two maps + //any excess is taken from the template + //excess is ignored in the test + + // Special tag for wildcarded LLSD map key templates + const LLSD::String wildcard_tag("*"); + + const bool template_has_wildcard = template_llsd.has(wildcard_tag); + LLSD wildcard_value; + LLSD value; + + const LLSD::map_const_iterator template_iter_end(template_llsd.endMap()); + for (LLSD::map_const_iterator template_iter(template_llsd.beginMap()); + template_iter_end != template_iter; + ++template_iter) + { + if (wildcard_tag == template_iter->first) + { + wildcard_value = template_iter->second; + } + else if (llsd_to_test.has(template_iter->first)) + { + //the test LLSD has the same key + if (! filter_llsd_with_template(llsd_to_test[template_iter->first], + template_iter->second, + value)) + { + resultant_llsd = LLSD(); + return false; + } + else + { + resultant_llsd[template_iter->first] = value; + } + } + else if (! template_has_wildcard) + { + // test llsd doesn't have it...take the + // template as default value + resultant_llsd[template_iter->first] = template_iter->second; + } + } + if (template_has_wildcard) + { + LLSD sub_value; + LLSD::map_const_iterator test_iter; + + for (test_iter = llsd_to_test.beginMap(); + test_iter != llsd_to_test.endMap(); + ++test_iter) + { + if (resultant_llsd.has(test_iter->first)) + { + // Final value has test key, assume more specific + // template matched and we shouldn't modify it again. + continue; + } + else if (! filter_llsd_with_template(test_iter->second, + wildcard_value, + sub_value)) + { + // Test value doesn't match wildcarded template + resultant_llsd = LLSD(); + return false; + } + else + { + // Test value matches template, add the actuals. + resultant_llsd[test_iter->first] = sub_value; + } + } + } + } + else + { + //of same type...take the test llsd's value + resultant_llsd = llsd_to_test; + } + + return true; +} + /***************************************************************************** * Helpers for llsd_matches() *****************************************************************************/ @@ -681,3 +855,104 @@ bool llsd_equals(const LLSD& lhs, const LLSD& rhs, int bits) return false; // pacify the compiler } } + +// Construct a deep partial clone of of an LLSD object. primitive types share +// references, however maps, arrays and binary objects are duplicated. An optional +// filter may be include to exclude/include keys in a map. +LLSD llsd_clone(LLSD value, LLSD filter) +{ + LLSD clone; + bool has_filter(filter.isMap()); + + switch (value.type()) + { + case LLSD::TypeMap: + clone = LLSD::emptyMap(); + for (LLSD::map_const_iterator itm = value.beginMap(); itm != value.endMap(); ++itm) + { + if (has_filter) + { + if (filter.has((*itm).first)) + { + if (!filter[(*itm).first].asBoolean()) + continue; + } + else if (filter.has("*")) + { + if (!filter["*"].asBoolean()) + continue; + } + else + { + continue; + } + } + clone[(*itm).first] = llsd_clone((*itm).second, filter); + } + break; + case LLSD::TypeArray: + clone = LLSD::emptyArray(); + for (LLSD::array_const_iterator ita = value.beginArray(); ita != value.endArray(); ++ita) + { + clone.append(llsd_clone(*ita, filter)); + } + break; + + case LLSD::TypeBinary: + { + LLSD::Binary bin(value.asBinary().begin(), value.asBinary().end()); + clone = LLSD::Binary(bin); + break; + } + default: + clone = value; + } + + return clone; +} + +LLSD llsd_shallow(LLSD value, LLSD filter) +{ + LLSD shallow; + bool has_filter(filter.isMap()); + + if (value.isMap()) + { + shallow = LLSD::emptyMap(); + for (LLSD::map_const_iterator itm = value.beginMap(); itm != value.endMap(); ++itm) + { + if (has_filter) + { + if (filter.has((*itm).first)) + { + if (!filter[(*itm).first].asBoolean()) + continue; + } + else if (filter.has("*")) + { + if (!filter["*"].asBoolean()) + continue; + } + else + { + continue; + } + } + shallow[(*itm).first] = (*itm).second; + } + } + else if (value.isArray()) + { + shallow = LLSD::emptyArray(); + for (LLSD::array_const_iterator ita = value.beginArray(); ita != value.endArray(); ++ita) + { + shallow.append(*ita); + } + } + else + { + return value; + } + + return shallow; +} diff --git a/indra/llcommon/llsdutil.h b/indra/llcommon/llsdutil.h index 01ab6bcb8d..863be04c8a 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 @@ -421,4 +435,86 @@ 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()); + + +// 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: + default: + break; + } + + return seed; + } +}; + #endif // LL_LLSDUTIL_H diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h index 0da6d548ab..7def9b019c 100644 --- a/indra/llcommon/llsingleton.h +++ b/indra/llcommon/llsingleton.h @@ -764,6 +764,17 @@ private: \ DERIVED_CLASS(__VA_ARGS__) /** + * A slight variance from the above, but includes the "override" keyword + */ +#define LLSINGLETON_C11(DERIVED_CLASS) \ +private: \ + /* implement LLSingleton pure virtual method whose sole purpose */ \ + /* is to remind people to use this macro */ \ + virtual void you_must_use_LLSINGLETON_macro() override {} \ + friend class LLSingleton<DERIVED_CLASS>; \ + DERIVED_CLASS() + +/** * Use LLSINGLETON_EMPTY_CTOR(Foo); at the start of an LLSingleton<Foo> * subclass body when the constructor is trivial: * @@ -781,4 +792,8 @@ private: \ /* LLSINGLETON() is carefully implemented to permit exactly this */ \ LLSINGLETON(DERIVED_CLASS) {} +#define LLSINGLETON_EMPTY_CTOR_C11(DERIVED_CLASS) \ + /* LLSINGLETON() is carefully implemented to permit exactly this */ \ + LLSINGLETON_C11(DERIVED_CLASS) {} + #endif diff --git a/indra/llcommon/llunittype.h b/indra/llcommon/llunittype.h index ac8504ca61..81f244e422 100644 --- a/indra/llcommon/llunittype.h +++ b/indra/llcommon/llunittype.h @@ -132,23 +132,34 @@ struct LLUnit return mValue; } - LL_FORCE_INLINE void value(storage_t value) + LL_FORCE_INLINE void value(const storage_t& value) { mValue = value; } template<typename NEW_UNITS> - storage_t valueInUnits() + storage_t valueInUnits() const { return LLUnit<storage_t, NEW_UNITS>(*this).value(); } template<typename NEW_UNITS> - void valueInUnits(storage_t value) + void valueInUnits(const storage_t& value) const { *this = LLUnit<storage_t, NEW_UNITS>(value); } + LL_FORCE_INLINE operator storage_t() const + { + return value(); + } + + /*LL_FORCE_INLINE self_t& operator= (storage_t v) + { + value(v); + return *this; + }*/ + LL_FORCE_INLINE void operator += (self_t other) { mValue += convert(other).mValue; @@ -159,60 +170,60 @@ struct LLUnit mValue -= convert(other).mValue; } - LL_FORCE_INLINE void operator *= (storage_t multiplicand) + LL_FORCE_INLINE void operator *= (const storage_t& multiplicand) { mValue *= multiplicand; } - LL_FORCE_INLINE void operator *= (self_t multiplicand) + LL_FORCE_INLINE void operator *= (const self_t& multiplicand) { // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "Multiplication of unit types not supported."); } - LL_FORCE_INLINE void operator /= (storage_t divisor) + LL_FORCE_INLINE void operator /= (const storage_t& divisor) { mValue /= divisor; } - void operator /= (self_t divisor) + void operator /= (const self_t& divisor) { // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "Illegal in-place division of unit types."); } template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> - LL_FORCE_INLINE bool operator == (LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const + LL_FORCE_INLINE bool operator == (const LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS>& other) const { return mValue == convert(other).value(); } template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> - LL_FORCE_INLINE bool operator != (LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const + LL_FORCE_INLINE bool operator != (const LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS>& other) const { return mValue != convert(other).value(); } template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> - LL_FORCE_INLINE bool operator < (LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const + LL_FORCE_INLINE bool operator < (const LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS>& other) const { return mValue < convert(other).value(); } template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> - LL_FORCE_INLINE bool operator <= (LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const + LL_FORCE_INLINE bool operator <= (const LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS>& other) const { return mValue <= convert(other).value(); } template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> - LL_FORCE_INLINE bool operator > (LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const + LL_FORCE_INLINE bool operator > (const LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS>& other) const { return mValue > convert(other).value(); } template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> - LL_FORCE_INLINE bool operator >= (LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const + LL_FORCE_INLINE bool operator >= (const LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS>& other) const { return mValue >= convert(other).value(); } 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 |