From f25abad9d7583c7c2c4e534d2d9831087e1f911f Mon Sep 17 00:00:00 2001
From: Thomas Geymayer <tomgey@gmail.com>
Date: Tue, 22 Jul 2014 00:36:17 +0200
Subject: [PATCH] Move overflow protected add helpers to math.

---
 simgear/canvas/layout/BoxLayout.cxx | 12 ++++++------
 simgear/canvas/layout/Layout.cxx    |  9 ---------
 simgear/canvas/layout/Layout.hxx    |  5 -----
 simgear/math/SGMisc.hxx             | 24 ++++++++++++++++++++++++
 simgear/math/SGVec2.hxx             | 11 +++++++++++
 simgear/math/SGVec3.hxx             | 12 ++++++++++++
 simgear/math/SGVec4.hxx             | 13 +++++++++++++
 7 files changed, 66 insertions(+), 20 deletions(-)

diff --git a/simgear/canvas/layout/BoxLayout.cxx b/simgear/canvas/layout/BoxLayout.cxx
index ec2aee53..3da5d98e 100644
--- a/simgear/canvas/layout/BoxLayout.cxx
+++ b/simgear/canvas/layout/BoxLayout.cxx
@@ -305,9 +305,9 @@ namespace canvas
       }
 
       // Add sizes of all children in layout direction
-      safeAdd(min_size.x(),  item_data.min_size);
-      safeAdd(max_size.x(),  item_data.max_size);
-      safeAdd(size_hint.x(), item_data.size_hint);
+      SGMisc<int>::addClipOverflowInplace(min_size.x(),  item_data.min_size);
+      SGMisc<int>::addClipOverflowInplace(max_size.x(),  item_data.max_size);
+      SGMisc<int>::addClipOverflowInplace(size_hint.x(), item_data.size_hint);
 
       // Take maximum in fixed (non-layouted) direction
       min_size.y()  = std::max( min_size.y(),
@@ -320,9 +320,9 @@ namespace canvas
       _layout_data.has_hfw = _layout_data.has_hfw || item.hasHeightForWidth();
     }
 
-    safeAdd(min_size.x(),  _layout_data.padding);
-    safeAdd(max_size.x(),  _layout_data.padding);
-    safeAdd(size_hint.x(), _layout_data.padding);
+    SGMisc<int>::addClipOverflowInplace(min_size.x(),  _layout_data.padding);
+    SGMisc<int>::addClipOverflowInplace(max_size.x(),  _layout_data.padding);
+    SGMisc<int>::addClipOverflowInplace(size_hint.x(), _layout_data.padding);
 
     _layout_data.min_size = min_size.x();
     _layout_data.max_size = max_size.x();
diff --git a/simgear/canvas/layout/Layout.cxx b/simgear/canvas/layout/Layout.cxx
index 8ae4e6e8..d3ae3886 100644
--- a/simgear/canvas/layout/Layout.cxx
+++ b/simgear/canvas/layout/Layout.cxx
@@ -108,15 +108,6 @@ namespace canvas
       return layout_item->minimumSize().y();
   }
 
-  //----------------------------------------------------------------------------
-  void Layout::safeAdd(int& a, int b)
-  {
-    if( SGLimits<int>::max() - b < a )
-      a = SGLimits<int>::max();
-    else
-      a += b;
-  }
-
   //----------------------------------------------------------------------------
   void Layout::distribute(std::vector<ItemData>& items, const ItemData& space)
   {
diff --git a/simgear/canvas/layout/Layout.hxx b/simgear/canvas/layout/Layout.hxx
index b91767f4..f28763cb 100644
--- a/simgear/canvas/layout/Layout.hxx
+++ b/simgear/canvas/layout/Layout.hxx
@@ -104,11 +104,6 @@ namespace canvas
        */
       virtual void doLayout(const SGRecti& geom) = 0;
 
-      /**
-       * Add two integers taking care of overflow (limit to INT_MAX)
-       */
-      static void safeAdd(int& a, int b);
-
       /**
        * Distribute the available @a space to all @a items
        */
diff --git a/simgear/math/SGMisc.hxx b/simgear/math/SGMisc.hxx
index 0f57edf1..abf162d8 100644
--- a/simgear/math/SGMisc.hxx
+++ b/simgear/math/SGMisc.hxx
@@ -41,6 +41,30 @@ public:
   static T clip(const T& a, const T& _min, const T& _max)
   { return max(_min, min(_max, a)); }
 
+
+  /// Add two (integer) values taking care of overflows.
+  static T addClipOverflow(T a, T b)
+  {
+    if( b > 0 )
+    {
+      if( SGLimits<T>::max() - b < a )
+        return SGLimits<T>::max();
+    }
+    else
+    {
+      if( SGLimits<T>::min() - b > a )
+        return SGLimits<T>::min();
+    }
+
+    return a + b;
+  }
+
+  /// Add two (integer) values in place, taking care of overflows.
+  static T& addClipOverflowInplace(T& a, T b)
+  {
+    return a = addClipOverflow(a, b);
+  }
+
   /**
    * Seek a variable towards a target value with given rate and timestep
    *
diff --git a/simgear/math/SGVec2.hxx b/simgear/math/SGVec2.hxx
index 0695cded..1ed150d8 100644
--- a/simgear/math/SGVec2.hxx
+++ b/simgear/math/SGVec2.hxx
@@ -196,6 +196,17 @@ SGVec2<T>
 max(S s, const SGVec2<T>& v)
 { return SGVec2<T>(SGMisc<T>::max(s, v(0)), SGMisc<T>::max(s, v(1))); }
 
+/// Add two vectors taking care of (integer) overflows. The values are limited
+/// to the respective minimum and maximum values.
+template<class T>
+SGVec2<T> addClipOverflow(SGVec2<T> const& lhs, SGVec2<T> const& rhs)
+{
+  return SGVec2<T>(
+    SGMisc<T>::addClipOverflow(lhs.x(), rhs.x()),
+    SGMisc<T>::addClipOverflow(lhs.y(), rhs.y())
+  );
+}
+
 /// Scalar dot product
 template<typename T>
 inline
diff --git a/simgear/math/SGVec3.hxx b/simgear/math/SGVec3.hxx
index dbc8af54..b0f6b206 100644
--- a/simgear/math/SGVec3.hxx
+++ b/simgear/math/SGVec3.hxx
@@ -288,6 +288,18 @@ max(S s, const SGVec3<T>& v)
                    SGMisc<T>::max(s, v(2)));
 }
 
+/// Add two vectors taking care of (integer) overflows. The values are limited
+/// to the respective minimum and maximum values.
+template<class T>
+SGVec3<T> addClipOverflow(SGVec3<T> const& lhs, SGVec3<T> const& rhs)
+{
+  return SGVec3<T>(
+    SGMisc<T>::addClipOverflow(lhs.x(), rhs.x()),
+    SGMisc<T>::addClipOverflow(lhs.y(), rhs.y()),
+    SGMisc<T>::addClipOverflow(lhs.z(), rhs.z())
+  );
+}
+
 /// Scalar dot product
 template<typename T>
 inline
diff --git a/simgear/math/SGVec4.hxx b/simgear/math/SGVec4.hxx
index 301aaca3..4339dfd9 100644
--- a/simgear/math/SGVec4.hxx
+++ b/simgear/math/SGVec4.hxx
@@ -244,6 +244,19 @@ max(S s, const SGVec4<T>& v)
                    SGMisc<T>::max(s, v(3)));
 }
 
+/// Add two vectors taking care of (integer) overflows. The values are limited
+/// to the respective minimum and maximum values.
+template<class T>
+SGVec4<T> addClipOverflow(SGVec4<T> const& lhs, SGVec4<T> const& rhs)
+{
+  return SGVec4<T>(
+    SGMisc<T>::addClipOverflow(lhs.x(), rhs.x()),
+    SGMisc<T>::addClipOverflow(lhs.y(), rhs.y()),
+    SGMisc<T>::addClipOverflow(lhs.z(), rhs.z()),
+    SGMisc<T>::addClipOverflow(lhs.w(), rhs.w())
+  );
+}
+
 /// Scalar dot product
 template<typename T>
 inline
-- 
2.39.5