base: Use constexpr in Cycles
authorAndreas Sandberg <Andreas.Sandberg@ARM.com>
Fri, 7 Aug 2015 08:59:12 +0000 (09:59 +0100)
committerAndreas Sandberg <Andreas.Sandberg@ARM.com>
Fri, 7 Aug 2015 08:59:12 +0000 (09:59 +0100)
Declare the constructor and all of the operators that don't change the
state of a Cycles instance as constexpr. This makes it possible to use
Cycles as a static constant and allows the compiler to evaulate simple
expressions at compile time. An unfortunate side-effect of this is
that we cannot use assertions since C++11 doesn't support them in
constexpr functions. As a workaround, we throw an invalid_argument
exception when the assert would have triggered. A nice side-effect of
this is that the compiler will evaluate the "assertion" at compile
time when an expression involving Cycles can be statically evaluated.

src/base/types.hh

index 2b6e3f11bcb3a8ed851d948c98f541ec1271e891..3d53e6ba07ff6ef93151c4c1797ec1f2e631d91a 100644 (file)
@@ -42,6 +42,7 @@
 #include <cassert>
 #include <memory>
 #include <ostream>
+#include <stdexcept>
 
 #include "base/refcnt.hh"
 
@@ -90,8 +91,12 @@ class Cycles
 
   public:
 
+#ifndef SWIG // SWIG gets confused by constexpr
     /** Explicit constructor assigning a value. */
+    explicit constexpr Cycles(uint64_t _c) : c(_c) { }
+#else
     explicit Cycles(uint64_t _c) : c(_c) { }
+#endif
 
     /** Default constructor for parameter classes. */
     Cycles() : c(0) { }
@@ -99,7 +104,7 @@ class Cycles
 #ifndef SWIG // keep the operators away from SWIG
 
     /** Converting back to the value type. */
-    operator uint64_t() const { return c; }
+    constexpr operator uint64_t() const { return c; }
 
     /** Prefix increment operator. */
     Cycles& operator++()
@@ -110,23 +115,26 @@ class Cycles
     { assert(c != 0); --c; return *this; }
 
     /** In-place addition of cycles. */
-    const Cycles& operator+=(const Cycles& cc)
+    Cycles& operator+=(const Cycles& cc)
     { c += cc.c; return *this; }
 
     /** Greater than comparison used for > Cycles(0). */
-    bool operator>(const Cycles& cc) const
+    constexpr bool operator>(const Cycles& cc) const
     { return c > cc.c; }
 
-    const Cycles operator +(const Cycles& b) const
+    constexpr Cycles operator +(const Cycles& b) const
     { return Cycles(c + b.c); }
 
-    const Cycles operator -(const Cycles& b) const
-    { assert(c >= b.c); return Cycles(c - b.c); }
+    constexpr Cycles operator -(const Cycles& b) const
+    {
+        return c >= b.c ? Cycles(c - b.c) :
+            throw std::invalid_argument("RHS cycle value larger than LHS");
+    }
 
-    const Cycles operator <<(const int32_t shift)
+    constexpr Cycles operator <<(const int32_t shift) const
     { return Cycles(c << shift); }
 
-    const Cycles operator >>(const int32_t shift)
+    constexpr Cycles operator >>(const int32_t shift) const
     { return Cycles(c >> shift); }
 
     friend std::ostream& operator<<(std::ostream &out, const Cycles & cycles);