diff options
| -rw-r--r-- | indra/llcommon/lleventcoro.cpp | 50 | ||||
| -rw-r--r-- | indra/llcommon/llsdutil.cpp | 67 | ||||
| -rw-r--r-- | indra/llcommon/llsdutil.h | 25 | 
3 files changed, 97 insertions, 45 deletions
| diff --git a/indra/llcommon/lleventcoro.cpp b/indra/llcommon/lleventcoro.cpp index 56367b8f54..43e41f250d 100644 --- a/indra/llcommon/lleventcoro.cpp +++ b/indra/llcommon/lleventcoro.cpp @@ -36,6 +36,7 @@  // external library headers  // other Linden headers  #include "llsdserialize.h" +#include "llsdutil.h"  #include "llerror.h"  #include "llcoros.h"  #include "llmake.h" @@ -92,57 +93,16 @@ std::string listenerNameForCoro()   * In the degenerate case in which @a path is an empty array, @a dest will   * @em become @a value rather than @em containing it.   */ -void storeToLLSDPath(LLSD& dest, const LLSD& rawPath, const LLSD& value) +void storeToLLSDPath(LLSD& dest, const LLSD& path, const LLSD& value)  { -    if (rawPath.isUndefined()) +    if (path.isUndefined())      {          // no-op case          return;      } -    // Arrange to treat rawPath uniformly as an array. If it's not already an -    // array, store it as the only entry in one. -    LLSD path; -    if (rawPath.isArray()) -    { -        path = rawPath; -    } -    else -    { -        path.append(rawPath); -    } - -    // Need to indicate a current destination -- but that current destination -    // needs to change as we step through the path array. Where normally we'd -    // use an LLSD& to capture a subscripted LLSD lvalue, this time we must -    // instead use a pointer -- since it must be reassigned. -    LLSD* pdest = &dest; - -    // Now loop through that array -    for (LLSD::Integer i = 0; i < path.size(); ++i) -    { -        if (path[i].isString()) -        { -            // *pdest is an LLSD map -            pdest = &((*pdest)[path[i].asString()]); -        } -        else if (path[i].isInteger()) -        { -            // *pdest is an LLSD array -            pdest = &((*pdest)[path[i].asInteger()]); -        } -        else -        { -            // What do we do with Real or Array or Map or ...? -            // As it's a coder error -- not a user error -- rub the coder's -            // face in it so it gets fixed. -            LL_ERRS("lleventcoro") << "storeToLLSDPath(" << dest << ", " << rawPath << ", " << value -                                   << "): path[" << i << "] bad type " << path[i].type() << LL_ENDL; -        } -    } - -    // Here *pdest is where we should store value. -    *pdest = value; +    // Drill down to where we should store 'value'. +    llsd::drill(dest, path) = value;  }  /// For LLCoros::Future<LLSD>::make_callback(), the callback has a signature diff --git a/indra/llcommon/llsdutil.cpp b/indra/llcommon/llsdutil.cpp index 9d00395c0a..ad27f19e85 100644 --- a/indra/llcommon/llsdutil.cpp +++ b/indra/llcommon/llsdutil.cpp @@ -681,3 +681,70 @@ bool llsd_equals(const LLSD& lhs, const LLSD& rhs, int bits)          return false;               // pacify the compiler      }  } + +/***************************************************************************** +*   llsd::drill() +*****************************************************************************/ +namespace llsd +{ + +LLSD& drill(LLSD& blob, const LLSD& rawPath) +{ +    // Treat rawPath uniformly as an array. If it's not already an array, +    // store it as the only entry in one. +    LLSD path; +    if (rawPath.isArray()) +    { +        path = rawPath; +    } +    else +    { +        path.append(rawPath); +    } + +    // Need to indicate a current destination -- but that current destination +    // must change as we step through the path array. Where normally we'd use +    // an LLSD& to capture a subscripted LLSD lvalue, this time we must +    // instead use a pointer -- since it must be reassigned. +    // Start by pointing to the input blob exactly as is. +    LLSD* located{&blob}; + +    // Extract the element of interest by walking path. Use an explicit index +    // so that, in case of a bogus type in path, we can identify the specific +    // path entry that's bad. +    for (LLSD::Integer i = 0; i < path.size(); ++i) +    { +        const LLSD& key{path[i]}; +        if (key.isString()) +        { +            // a string path element is a map key +            located = &((*located)[key.asString()]); +        } +        else if (key.isInteger()) +        { +            // an integer path element is an array index +            located = &((*located)[key.asInteger()]); +        } +        else +        { +            // What do we do with Real or Array or Map or ...? +            // As it's a coder error -- not a user error -- rub the coder's +            // face in it so it gets fixed. +            LL_ERRS("llsdutil") << "drill(" << blob << ", " << rawPath +                                << "): path[" << i << "] bad type " +                                << sTypes.lookup(key.type()) << LL_ENDL; +        } +    } + +    // dereference the pointer to return a reference to the element we found +    return *located; +} + +LLSD drill(const LLSD& blob, const LLSD& path) +{ +    // non-const drill() does exactly what we want. Temporarily cast away +    // const-ness and use that. +    return drill(const_cast<LLSD&>(blob), path); +} + +} // namespace llsd diff --git a/indra/llcommon/llsdutil.h b/indra/llcommon/llsdutil.h index 01ab6bcb8d..e659aa574e 100644 --- a/indra/llcommon/llsdutil.h +++ b/indra/llcommon/llsdutil.h @@ -142,6 +142,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  *****************************************************************************/ | 
