//private bool LLFloaterMediaSettings::haveValuesChanged() const { bool values_changed = false; // *NOTE: The code below is very inefficient. Better to do this // only when data change. // Every frame, check to see what the values are. If they are not // the same as the initial media data, enable the OK/Apply buttons LLSD settings; sInstance->mPanelMediaSettingsGeneral->getValues( settings ); sInstance->mPanelMediaSettingsSecurity->getValues( settings ); sInstance->mPanelMediaSettingsPermissions->getValues( settings ); LLSD::map_const_iterator iter = settings.beginMap(); LLSD::map_const_iterator end = settings.endMap(); for ( ; iter != end; ++iter ) { const std::string ¤t_key = iter->first; const LLSD ¤t_value = iter->second; if ( ! llsd_equals(current_value, mInitialValues[current_key])) { values_changed = true; break; } } return values_changed; }
void LLPostProcess::resetSelectedEffect() { if(!llsd_equals(mAllEffectInfo[mSelectedEffectName], mSelectedEffectInfo)) { mSelectedEffectInfo = mAllEffectInfo[mSelectedEffectName]; for(std::list<LLPointer<LLPostProcessShader> >::iterator it=mShaders.begin();it!=mShaders.end();++it) { (*it)->loadSettings(mSelectedEffectInfo); } } }
void ensure_llsd_equals(const std::string& msg, const LLSD& expected, const LLSD& actual) { if (!llsd_equals(expected, actual)) { std::string message = msg; message += ": actual: "; message += ll_pretty_print_sd(actual); message += "\n expected: "; message += ll_pretty_print_sd(expected); message += "\n"; ensure(message, false); } }
void LLReqID::stamp(LLSD& response) const { if (! (response.isUndefined() || response.isMap())) { // If 'response' was previously completely empty, it's okay to // turn it into a map. If it was already a map, then it should be // okay to add a key. But if it was anything else (e.g. a scalar), // assigning a ["reqid"] key will DISCARD the previous value, // replacing it with a map. That would be Bad. LL_INFOS("LLReqID") << "stamp(" << mReqid << ") leaving non-map response unmodified: " << response << LL_ENDL; return; } LLSD oldReqid(response["reqid"]); if (! (oldReqid.isUndefined() || llsd_equals(oldReqid, mReqid))) { LL_INFOS("LLReqID") << "stamp(" << mReqid << ") preserving existing [\"reqid\"] value " << oldReqid << " in response: " << response << LL_ENDL; return; } response["reqid"] = mReqid; }
void llsdutil_object::test<9>() { set_test_name("llsd_matches"); // for this test, construct a map of all possible LLSD types LLSD map; map.insert("empty", LLSD()); map.insert("Boolean", LLSD::Boolean()); map.insert("Integer", LLSD::Integer(0)); map.insert("Real", LLSD::Real(0.0)); map.insert("String", LLSD::String("bah")); map.insert("NumString", LLSD::String("1")); map.insert("UUID", LLSD::UUID()); map.insert("Date", LLSD::Date()); map.insert("URI", LLSD::URI()); map.insert("Binary", LLSD::Binary()); map.insert("Map", LLSD().with("foo", LLSD())); // Only an empty array can be constructed on the fly LLSD array; array.append(LLSD()); map.insert("Array", array); // These iterators are declared outside our various for loops to avoid // fatal MSVC warning: "I used to be broken, but I'm all better now!" LLSD::map_const_iterator mi, mend(map.endMap()); /*-------------------------- llsd_matches --------------------------*/ // empty prototype matches anything for (mi = map.beginMap(); mi != mend; ++mi) { ensure_equals(std::string("empty matches ") + mi->first, llsd_matches(LLSD(), mi->second), ""); } LLSD proto_array, data_array; for (int i = 0; i < 3; ++i) { proto_array.append(LLSD()); data_array.append(LLSD()); } // prototype array matches only array for (mi = map.beginMap(); mi != mend; ++mi) { ensure(std::string("array doesn't match ") + mi->first, ! llsd_matches(proto_array, mi->second).empty()); } // data array must be at least as long as prototype array proto_array.append(LLSD()); ensure_equals("data array too short", llsd_matches(proto_array, data_array), "Array size 4 required instead of Array size 3"); data_array.append(LLSD()); ensure_equals("data array just right", llsd_matches(proto_array, data_array), ""); data_array.append(LLSD()); ensure_equals("data array longer", llsd_matches(proto_array, data_array), ""); // array element matching data_array[0] = LLSD::String(); ensure_equals("undefined prototype array entry", llsd_matches(proto_array, data_array), ""); proto_array[0] = LLSD::Binary(); ensure_equals("scalar prototype array entry", llsd_matches(proto_array, data_array), "[0]: Binary required instead of String"); data_array[0] = LLSD::Binary(); ensure_equals("matching prototype array entry", llsd_matches(proto_array, data_array), ""); // build a coupla maps LLSD proto_map, data_map; data_map["got"] = LLSD(); data_map["found"] = LLSD(); for (LLSD::map_const_iterator dmi(data_map.beginMap()), dmend(data_map.endMap()); dmi != dmend; ++dmi) { proto_map[dmi->first] = dmi->second; } proto_map["foo"] = LLSD(); proto_map["bar"] = LLSD(); // prototype map matches only map for (mi = map.beginMap(); mi != mend; ++mi) { ensure(std::string("map doesn't match ") + mi->first, ! llsd_matches(proto_map, mi->second).empty()); } // data map must contain all keys in prototype map std::string error(llsd_matches(proto_map, data_map)); ensure_contains("missing keys", error, "missing keys"); ensure_contains("missing foo", error, "foo"); ensure_contains("missing bar", error, "bar"); ensure_does_not_contain("found found", error, "found"); ensure_does_not_contain("got got", error, "got"); data_map["bar"] = LLSD(); error = llsd_matches(proto_map, data_map); ensure_contains("missing foo", error, "foo"); ensure_does_not_contain("got bar", error, "bar"); data_map["foo"] = LLSD(); ensure_equals("data map just right", llsd_matches(proto_map, data_map), ""); data_map["extra"] = LLSD(); ensure_equals("data map with extra", llsd_matches(proto_map, data_map), ""); // map element matching data_map["foo"] = LLSD::String(); ensure_equals("undefined prototype map entry", llsd_matches(proto_map, data_map), ""); proto_map["foo"] = LLSD::Binary(); ensure_equals("scalar prototype map entry", llsd_matches(proto_map, data_map), "['foo']: Binary required instead of String"); data_map["foo"] = LLSD::Binary(); ensure_equals("matching prototype map entry", llsd_matches(proto_map, data_map), ""); // String { static const char* matches[] = { "String", "NumString", "Boolean", "Integer", "Real", "UUID", "Date", "URI" }; test_matches("String", map, boost::begin(matches), boost::end(matches)); } // Boolean, Integer, Real static const char* numerics[] = { "Boolean", "Integer", "Real" }; for (const char **ni = boost::begin(numerics), **nend = boost::end(numerics); ni != nend; ++ni) { static const char* matches[] = { "Boolean", "Integer", "Real", "String", "NumString" }; test_matches(*ni, map, boost::begin(matches), boost::end(matches)); } // UUID { static const char* matches[] = { "UUID", "String", "NumString" }; test_matches("UUID", map, boost::begin(matches), boost::end(matches)); } // Date { static const char* matches[] = { "Date", "String", "NumString" }; test_matches("Date", map, boost::begin(matches), boost::end(matches)); } // URI { static const char* matches[] = { "URI", "String", "NumString" }; test_matches("URI", map, boost::begin(matches), boost::end(matches)); } // Binary { static const char* matches[] = { "Binary" }; test_matches("Binary", map, boost::begin(matches), boost::end(matches)); } /*-------------------------- llsd_equals ---------------------------*/ // Cross-product of each LLSD type with every other for (LLSD::map_const_iterator lmi(map.beginMap()), lmend(map.endMap()); lmi != lmend; ++lmi) { for (LLSD::map_const_iterator rmi(map.beginMap()), rmend(map.endMap()); rmi != rmend; ++rmi) { // Name this test based on the map keys naming the types of // interest, e.g "String::Integer". // We expect the values (xmi->second) to be equal if and only // if the type names (xmi->first) are equal. ensure(STRINGIZE(lmi->first << "::" << rmi->first), bool(lmi->first == rmi->first) == bool(llsd_equals(lmi->second, rmi->second))); } } // Array cases LLSD rarray; rarray.append(1.0); rarray.append(2); rarray.append("3"); LLSD larray(rarray); ensure("llsd_equals(equal arrays)", llsd_equals(larray, rarray)); rarray[2] = "4"; ensure("llsd_equals(different [2])", ! llsd_equals(larray, rarray)); rarray = larray; rarray.append(LLSD::Date()); ensure("llsd_equals(longer right array)", ! llsd_equals(larray, rarray)); rarray = larray; rarray.erase(2); ensure("llsd_equals(shorter right array)", ! llsd_equals(larray, rarray)); // Map cases LLSD rmap; rmap["San Francisco"] = 65; rmap["Phoenix"] = 92; rmap["Boston"] = 77; LLSD lmap(rmap); ensure("llsd_equals(equal maps)", llsd_equals(lmap, rmap)); rmap["Boston"] = 80; ensure("llsd_equals(different [\"Boston\"])", ! llsd_equals(lmap, rmap)); rmap = lmap; rmap["Atlanta"] = 95; ensure("llsd_equals(superset right map)", ! llsd_equals(lmap, rmap)); rmap = lmap; lmap["Seattle"] = 72; ensure("llsd_equals(superset left map)", ! llsd_equals(lmap, rmap)); }
bool llsd_equals(const LLSD& lhs, const LLSD& rhs, unsigned bits) { // We're comparing strict equality of LLSD representation rather than // performing any conversions. So if the types aren't equal, the LLSD // values aren't equal. if (lhs.type() != rhs.type()) { return false; } // Here we know both types are equal. Now compare values. switch (lhs.type()) { case LLSD::TypeUndefined: // Both are TypeUndefined. There's nothing more to know. return true; case LLSD::TypeReal: // This is where the 'bits' argument comes in handy. If passed // explicitly, it means to use is_approx_equal_fraction() to compare. if (bits >= 0) { return is_approx_equal_fraction(lhs.asReal(), rhs.asReal(), bits); } // Otherwise we compare bit representations, and the usual caveats // about comparing floating-point numbers apply. Omitting 'bits' when // comparing Real values is only useful when we expect identical bit // representation for a given Real value, e.g. for integer-valued // Reals. return (lhs.asReal() == rhs.asReal()); #define COMPARE_SCALAR(type) \ case LLSD::Type##type: \ /* LLSD::URI has operator!=() but not operator==() */ \ /* rely on the optimizer for all others */ \ return (! (lhs.as##type() != rhs.as##type())) COMPARE_SCALAR(Boolean); COMPARE_SCALAR(Integer); COMPARE_SCALAR(String); COMPARE_SCALAR(UUID); COMPARE_SCALAR(Date); COMPARE_SCALAR(URI); COMPARE_SCALAR(Binary); #undef COMPARE_SCALAR case LLSD::TypeArray: { LLSD::array_const_iterator lai(lhs.beginArray()), laend(lhs.endArray()), rai(rhs.beginArray()), raend(rhs.endArray()); // Compare array elements, walking the two arrays in parallel. for ( ; lai != laend && rai != raend; ++lai, ++rai) { // If any one array element is unequal, the arrays are unequal. if (! llsd_equals(*lai, *rai, bits)) return false; } // Here we've reached the end of one or the other array. They're equal // only if they're BOTH at end: that is, if they have equal length too. return (lai == laend && rai == raend); } case LLSD::TypeMap: { // Build a set of all rhs keys. std::set<LLSD::String> rhskeys; for (LLSD::map_const_iterator rmi(rhs.beginMap()), rmend(rhs.endMap()); rmi != rmend; ++rmi) { rhskeys.insert(rmi->first); } // Now walk all the lhs keys. for (LLSD::map_const_iterator lmi(lhs.beginMap()), lmend(lhs.endMap()); lmi != lmend; ++lmi) { // Try to erase this lhs key from the set of rhs keys. If rhs has // no such key, the maps are unequal. erase(key) returns count of // items erased. if (rhskeys.erase(lmi->first) != 1) return false; // Both maps have the current key. Compare values. if (! llsd_equals(lmi->second, rhs[lmi->first], bits)) return false; } // We've now established that all the lhs keys have equal values in // both maps. The maps are equal unless rhs contains a superset of // those keys. return rhskeys.empty(); } default: // We expect that every possible type() value is specifically handled // above. Failing to extend this switch to support a new LLSD type is // an error that must be brought to the coder's attention. LL_ERRS("llsd_equals") << "llsd_equals(" << lhs << ", " << rhs << ", " << bits << "): " "unknown type " << lhs.type() << LL_ENDL; return false; // pacify the compiler } }