From e51ccdac0e3595a476dbc2d8580a3fb1780cdb4c Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Sat, 5 Feb 2011 23:31:11 -0500
Subject: Introduce zipmap() function and use it in place of frequent loops.
 One operation we often use is to take an LLSD array of param names, a
 corresponding LLSD array of values, and create from them a name=value LLSD
 map. Instead of doing that "by hand" every time, use a function.

---
 indra/llcommon/tests/lleventdispatcher_test.cpp | 79 ++++++++++++++-----------
 1 file changed, 44 insertions(+), 35 deletions(-)

diff --git a/indra/llcommon/tests/lleventdispatcher_test.cpp b/indra/llcommon/tests/lleventdispatcher_test.cpp
index c31f037d7f..30d3c42554 100644
--- a/indra/llcommon/tests/lleventdispatcher_test.cpp
+++ b/indra/llcommon/tests/lleventdispatcher_test.cpp
@@ -322,14 +322,12 @@ namespace tut
         LLSD required;
         // Parameter names for freena(), freenb()
         LLSD params;
-        // Full defaults arrays for params for freena(), freenb()
-        LLSD dft_array_full;
+        // Full, partial defaults arrays for params for freena(), freenb()
+        LLSD dft_array_full, dft_array_partial;
         // Start index of partial defaults arrays
         const LLSD::Integer partial_offset;
-        // Full defaults maps for params for freena(), freenb()
-        LLSD dft_map_full;
-        // Partial defaults maps for params for freena(), freenb()
-        LLSD dft_map_partial;
+        // Full, partial defaults maps for params for freena(), freenb()
+        LLSD dft_map_full, dft_map_partial;
         // Most of the above are indexed by "a" or "b". Useful to have an
         // array containing those strings for iterating.
         std::vector<LLSD::String> ab;
@@ -447,20 +445,20 @@ namespace tut
                                                    (binary));
             cout << "dft_array_full:\n" << dft_array_full << std::endl;
             // Partial defaults arrays.
-            LLSD dft_array_partial(
-                LLSDMap("a", llsd_copy_array(dft_array_full["a"].beginArray() + partial_offset,
-                                             dft_array_full["a"].endArray()))
-                       ("b", llsd_copy_array(dft_array_full["b"].beginArray() + partial_offset,
-                                             dft_array_full["b"].endArray())));
+            foreach(LLSD::String a, ab)
+            {
+                LLSD::Integer partition(std::min(partial_offset, dft_array_full[a].size()));
+                dft_array_partial[a] =
+                    llsd_copy_array(dft_array_full[a].beginArray() + partition,
+                                    dft_array_full[a].endArray());
+            }
             cout << "dft_array_partial:\n" << dft_array_partial << std::endl;
 
-            // Generate full defaults maps by zipping (params, dft_array_full).
             foreach(LLSD::String a, ab)
             {
-                for (LLSD::Integer ix = 0, ixend = params[a].size(); ix < ixend; ++ix)
-                {
-                    dft_map_full[a][params[a][ix].asString()] = dft_array_full[a][ix];
-                }
+                // Generate full defaults maps by zipping (params, dft_array_full).
+                dft_map_full[a] = zipmap(params[a], dft_array_full[a]);
+
                 // Generate partial defaults map by zipping alternate entries from
                 // (params, dft_array_full). Part of the point of using map-style
                 // defaults is to allow any subset of the target function's
@@ -638,6 +636,20 @@ namespace tut
             return meta;
         }
 
+        // From two related LLSD arrays, e.g. a param-names array and a values
+        // array, zip them together into an LLSD map.
+        LLSD zipmap(const LLSD& keys, const LLSD& values)
+        {
+            LLSD map;
+            for (LLSD::Integer i = 0, iend = keys.size(); i < iend; ++i)
+            {
+                // Have to select asString() since you can index an LLSD
+                // object with either String or Integer.
+                map[keys[i].asString()] = values[i];
+            }
+            return map;
+        }
+
         // If I call this ensure_equals(), it blocks visibility of all other
         // ensure_equals() overloads. Normally I could say 'using
         // baseclass::ensure_equals;' and fix that, but I don't know what the
@@ -904,17 +916,21 @@ namespace tut
         LLSD allreq, leftreq, rightdft;
         foreach(LLSD::String a, ab)
         {
-            for (LLSD::Integer pi(0), pend(std::min(partial_offset, params[a].size()));
-                 pi < pend; ++pi)
-            {
-                allreq [a][params[a][pi].asString()] = LLSD();
-                leftreq[a][params[a][pi].asString()] = LLSD();
-            }
-            for (LLSD::Integer pi(partial_offset), pend(params[a].size()); pi < pend; ++pi)
-            {
-                allreq  [a][params[a][pi].asString()] = LLSD();
-                rightdft[a][params[a][pi].asString()] = dft_array_full[a][pi];
-            }
+            // The map in which all params are required uses params[a] as
+            // keys, with all isUndefined() as values. We can accomplish that
+            // by passing zipmap() an empty values array.
+            allreq[a] = zipmap(params[a], LLSD::emptyArray());
+            // Same for leftreq, save that we use the subset of the params not
+            // supplied by dft_array_partial[a].
+            LLSD::Integer partition(params[a].size() - dft_array_partial[a].size());
+            leftreq[a] = zipmap(llsd_copy_array(params[a].beginArray(),
+                                                params[a].beginArray() + partition),
+                                LLSD::emptyArray());
+            // Generate map pairing dft_array_partial[a] values with their
+            // param names.
+            rightdft[a] = zipmap(llsd_copy_array(params[a].beginArray() + partition,
+                                                 params[a].endArray()),
+                                 dft_array_partial[a]);
         }
         cout << "allreq:\n" << allreq << "\nleftreq:\n" << leftreq << "\nrightdft:\n" << rightdft << std::endl;
 
@@ -1178,10 +1194,7 @@ namespace tut
         LLSD expect;
         foreach(LLSD::String a, ab)
         {
-            for (LLSD::Integer i(0), iend(params[a].size()); i < iend; ++i)
-            {
-                expect[a][params[a][i].asString()] = args[a][i];
-            }
+            expect[a] = zipmap(params[a], args[a]);
         }
         // Adjust expect["a"]["cp"] for special Vars::cp treatment.
         expect["a"]["cp"] = std::string("'") + expect["a"]["cp"].asString() + "'";
@@ -1216,8 +1229,4 @@ namespace tut
             }
         }
     }
-
-    // TODO:
-    // - function to build a map from keys array, values array (or
-    //   vice-versa?)
 } // namespace tut
-- 
cgit v1.2.3