]> git.mxchange.org Git - simgear.git/commitdiff
Add ListDiff helper (for fast array differences).
authorThomas Geymayer <tomgey@gmail.com>
Sun, 8 Dec 2013 17:48:19 +0000 (18:48 +0100)
committerThomas Geymayer <tomgey@gmail.com>
Sun, 8 Dec 2013 17:48:57 +0000 (18:48 +0100)
simgear/misc/CMakeLists.txt
simgear/misc/ListDiff.hxx [new file with mode: 0644]

index 11c43d6f1205c897778b4f81e7b9eac689d69759..89a2f6ade2beed9a2afcae5f2e9e24c9af86783c 100644 (file)
@@ -3,6 +3,7 @@ include (SimGearComponent)
 
 set(HEADERS 
     CSSBorder.hxx
+    ListDiff.hxx
     ResourceManager.hxx
     interpolator.hxx
     make_new.hxx
diff --git a/simgear/misc/ListDiff.hxx b/simgear/misc/ListDiff.hxx
new file mode 100644 (file)
index 0000000..2db9234
--- /dev/null
@@ -0,0 +1,85 @@
+///@file
+/// Compare lists and get differences
+///
+// Copyright (C) 2013  Thomas Geymayer <tomgey@gmail.com>
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
+
+#ifndef SG_LISTDIFF_HXX_
+#define SG_LISTDIFF_HXX_
+
+#include <vector>
+#include <boost/function.hpp>
+
+namespace simgear
+{
+
+  template<class T>
+  struct ListDiff
+  {
+    typedef std::vector<T> List;
+    typedef boost::function<void (T)> Callback;
+
+    /**
+     * Perform list diff in-place (modifies both lists) and call cb_add for
+     * every element in new_list not in old_list and cb_remove for every element
+     * in old_list not in new_list.
+     */
+    static void inplace( List& old_list,
+                         List& new_list,
+                         Callback cb_add,
+                         Callback cb_remove )
+    {
+      // Check which elements have been removed. (Removing first and adding
+      // second should keep the memory usage lower - not for this function, but
+      // probably for users of this function which use the callbacks to delete
+      // and create objects)
+      while( !old_list.empty() )
+      {
+        T& old_el = old_list.front();
+        typename List::iterator new_el =
+          std::find(new_list.begin(), new_list.end(), old_el);
+
+        if( new_el == new_list.end() )
+        {
+          if( cb_remove )
+            cb_remove(old_el);
+        }
+        else
+        {
+          // Element is in both lists -> just ignore
+          *new_el = new_list.back();
+          new_list.pop_back();
+        }
+
+        old_list.front() = old_list.back();
+        old_list.pop_back();
+      }
+
+      // All remaing elements in new_list have not been in old_list, so call
+      // the add callback for every element if required.
+      if( cb_add )
+      {
+        for( typename List::iterator it = new_list.begin();
+                                     it != new_list.end();
+                                   ++it )
+          cb_add(*it);
+      }
+    }
+  };
+
+} // namespace simgear
+
+#endif /* SG_LISTDIFF_HXX_ */