diff --git a/Builds/VisualStudio2013/RippleD.vcxproj b/Builds/VisualStudio2013/RippleD.vcxproj
index 90f82f345..fd6110a9d 100644
--- a/Builds/VisualStudio2013/RippleD.vcxproj
+++ b/Builds/VisualStudio2013/RippleD.vcxproj
@@ -2767,6 +2767,10 @@
True
True
+
+ True
+ True
+
True
True
@@ -2887,6 +2891,8 @@
+
+
@@ -2963,6 +2969,10 @@
True
True
+
+ True
+ True
+
True
True
@@ -2995,6 +3005,10 @@
True
True
+
+ True
+ True
+
@@ -3007,6 +3021,8 @@
+
+
Document
protoc --cpp_out=..\..\build\proto --proto_path=%(RelativeDir) %(Identity)
diff --git a/Builds/VisualStudio2013/RippleD.vcxproj.filters b/Builds/VisualStudio2013/RippleD.vcxproj.filters
index 2136ad6e7..e0e7611ba 100644
--- a/Builds/VisualStudio2013/RippleD.vcxproj.filters
+++ b/Builds/VisualStudio2013/RippleD.vcxproj.filters
@@ -3486,6 +3486,9 @@
ripple\protocol\impl
+
+ ripple\protocol\impl
+
ripple\protocol\impl
@@ -3582,6 +3585,9 @@
ripple\protocol
+
+ ripple\protocol
+
ripple\protocol
@@ -3690,6 +3696,9 @@
ripple\protocol\tests
+
+ ripple\protocol\tests
+
ripple\protocol\tests
@@ -3714,6 +3723,9 @@
ripple\protocol\tests
+
+ ripple\protocol\tests
+
ripple\protocol
@@ -3732,6 +3744,9 @@
ripple\protocol
+
+ ripple\protocol
+
ripple\proto
diff --git a/src/ripple/protocol/IOUAmount.h b/src/ripple/protocol/IOUAmount.h
new file mode 100644
index 000000000..8dca03395
--- /dev/null
+++ b/src/ripple/protocol/IOUAmount.h
@@ -0,0 +1,142 @@
+//------------------------------------------------------------------------------
+/*
+ This file is part of rippled: https://github.com/ripple/rippled
+ Copyright (c) 2012, 2013 Ripple Labs Inc.
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+//==============================================================================
+
+#ifndef RIPPLE_PROTOCOL_IOUAMOUNT_H_INCLUDED
+#define RIPPLE_PROTOCOL_IOUAMOUNT_H_INCLUDED
+
+#include
+#include
+#include
+#include
+#include
+
+using beast::zero;
+
+namespace ripple {
+
+/** Floating point representation of amounts with high dynamic range
+
+ Amounts are stored as a normalized signed mantissa and an exponent. The
+ range of the normalized exponent is [-96,80] and the range of the absolute
+ value of the normalized mantissa is [1000000000000000, 9999999999999999].
+
+ Arithmetic operations can throw std::overflow_error during normalization
+ if the amount exceeds the largest representable amount, but underflows
+ will silently trunctate to zero.
+*/
+class IOUAmount
+ : private boost::totally_ordered
+ , private boost::additive
+{
+private:
+ std::int64_t mantissa_;
+ int exponent_;
+
+ /** Adjusts the mantissa and exponent to the proper range.
+
+ This can throw if the amount cannot be normalized, or is larger than
+ the largest value that can be represented as an IOU amount. Amounts
+ that are too small to be represented normalize to 0.
+ */
+ void
+ normalize ();
+
+public:
+ IOUAmount () = default;
+ IOUAmount (IOUAmount const& other) = default;
+ IOUAmount&operator= (IOUAmount const& other) = default;
+
+ IOUAmount (beast::Zero)
+ {
+ *this = zero;
+ }
+
+ IOUAmount (std::int64_t mantissa, int exponent)
+ : mantissa_ (mantissa)
+ , exponent_ (exponent)
+ {
+ normalize ();
+ }
+
+ IOUAmount&
+ operator= (beast::Zero)
+ {
+ // The -100 is used to allow 0 to sort less than small positive values
+ // which will have a large negative exponent.
+ mantissa_ = 0;
+ exponent_ = -100;
+ return *this;
+ }
+
+ IOUAmount&
+ operator+= (IOUAmount const& other);
+
+ IOUAmount&
+ operator-= (IOUAmount const& other)
+ {
+ *this += -other;
+ return *this;
+ }
+
+ IOUAmount
+ operator- () const
+ {
+ return { -mantissa_, exponent_ };
+ }
+
+ bool
+ operator==(IOUAmount const& other) const
+ {
+ return exponent_ == other.exponent_ &&
+ mantissa_ == other.mantissa_;
+ }
+
+ bool
+ operator<(IOUAmount const& other) const;
+
+ /** Returns true if the amount is not zero */
+ explicit
+ operator bool() const noexcept
+ {
+ return mantissa_ != 0;
+ }
+
+ /** Return the sign of the amount */
+ int
+ signum() const noexcept
+ {
+ return (mantissa_ < 0) ? -1 : (mantissa_ ? 1 : 0);
+ }
+
+ int
+ exponent() const noexcept
+ {
+ return exponent_;
+ }
+
+ std::int64_t
+ mantissa() const noexcept
+ {
+ return mantissa_;
+ }
+};
+
+}
+
+#endif
diff --git a/src/ripple/protocol/XRPAmount.h b/src/ripple/protocol/XRPAmount.h
new file mode 100644
index 000000000..44ee4d0a1
--- /dev/null
+++ b/src/ripple/protocol/XRPAmount.h
@@ -0,0 +1,126 @@
+//------------------------------------------------------------------------------
+/*
+ This file is part of rippled: https://github.com/ripple/rippled
+ Copyright (c) 2012, 2013 Ripple Labs Inc.
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+//==============================================================================
+
+#ifndef RIPPLE_PROTOCOL_XRPAMOUNT_H_INCLUDED
+#define RIPPLE_PROTOCOL_XRPAMOUNT_H_INCLUDED
+
+#include
+#include
+#include
+#include
+#include
+
+using beast::zero;
+
+namespace ripple {
+
+class XRPAmount
+ : private boost::totally_ordered
+ , private boost::additive
+{
+private:
+ std::int64_t value_;
+
+public:
+ /** @{ */
+ XRPAmount () = default;
+ XRPAmount (XRPAmount const& other) = default;
+ XRPAmount& operator= (XRPAmount const& other) = default;
+
+ XRPAmount (beast::Zero)
+ : value_ (0)
+ {
+ }
+
+ XRPAmount&
+ operator= (beast::Zero)
+ {
+ value_ = 0;
+ return *this;
+ }
+
+ XRPAmount (std::int64_t value)
+ : value_ (value)
+ {
+ }
+
+ XRPAmount&
+ operator= (std::int64_t v)
+ {
+ value_ = v;
+ return *this;
+ }
+
+ XRPAmount&
+ operator+= (XRPAmount const& other)
+ {
+ value_ += other.value_;
+ return *this;
+ }
+
+ XRPAmount&
+ operator-= (XRPAmount const& other)
+ {
+ value_ -= other.value_;
+ return *this;
+ }
+
+ XRPAmount
+ operator- () const
+ {
+ return { -value_ };
+ }
+
+ bool
+ operator==(XRPAmount const& other) const
+ {
+ return value_ == other.value_;
+ }
+
+ bool
+ operator<(XRPAmount const& other) const
+ {
+ return value_ < other.value_;
+ }
+
+ /** Returns true if the amount is not zero */
+ explicit
+ operator bool() const noexcept
+ {
+ return value_ != 0;
+ }
+
+ /** Return the sign of the amount */
+ int
+ signum() const noexcept
+ {
+ return (value_ < 0) ? -1 : (value_ ? 1 : 0);
+ }
+};
+
+/** Returns true if the amount does not exceed the initial XRP in existence. */
+inline
+bool isLegalAmount (XRPAmount const& amount)
+{
+ return amount <= SYSTEM_CURRENCY_START;
+}
+
+}
+
+#endif
diff --git a/src/ripple/protocol/impl/IOUAmount.cpp b/src/ripple/protocol/impl/IOUAmount.cpp
new file mode 100644
index 000000000..207549242
--- /dev/null
+++ b/src/ripple/protocol/impl/IOUAmount.cpp
@@ -0,0 +1,148 @@
+//------------------------------------------------------------------------------
+/*
+ This file is part of rippled: https://github.com/ripple/rippled
+ Copyright (c) 2012, 2013 Ripple Labs Inc.
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+//==============================================================================
+
+#include
+#include
+#include
+
+namespace ripple {
+
+void
+IOUAmount::normalize ()
+{
+ /* The range for the exponent when normalized */
+ static int const minExponent = -96;
+ static int const maxExponent = 80;
+
+ /* The range for the mantissa when normalized */
+ static std::int64_t const minMantissa = 1000000000000000ull;
+ static std::int64_t const maxMantissa = 9999999999999999ull;
+
+ if (mantissa_ == 0)
+ {
+ *this = zero;
+ return;
+ }
+
+ bool const negative = (mantissa_ < 0);
+
+ if (negative)
+ mantissa_ = -mantissa_;
+
+ while ((mantissa_ < minMantissa) && (exponent_ > minExponent))
+ {
+ mantissa_ *= 10;
+ --exponent_;
+ }
+
+ while (mantissa_ > maxMantissa)
+ {
+ if (exponent_ >= maxExponent)
+ throw std::overflow_error ("IOUAmount::normalize");
+
+ mantissa_ /= 10;
+ ++exponent_;
+ }
+
+ if ((exponent_ < minExponent) || (mantissa_ < minMantissa))
+ {
+ *this = zero;
+ return;
+ }
+
+ if (exponent_ > maxExponent)
+ throw std::overflow_error ("value overflow");
+
+ if (negative)
+ mantissa_ = -mantissa_;
+}
+
+IOUAmount&
+IOUAmount::operator+= (IOUAmount const& other)
+{
+ if (other == zero)
+ return *this;
+
+ if (*this == zero)
+ {
+ *this = other;
+ return *this;
+ }
+
+ auto m = other.mantissa_;
+ auto e = other.exponent_;
+
+ while (exponent_ < e)
+ {
+ mantissa_ /= 10;
+ ++exponent_;
+ }
+
+ while (e < exponent_)
+ {
+ m /= 10;
+ ++e;
+ }
+
+ // This addition cannot overflow an std::int64_t but we may throw from
+ // normalize if the result isn't representable.
+ mantissa_ += m;
+
+ if (mantissa_ >= -10 && mantissa_ <= 10)
+ {
+ *this = zero;
+ return *this;
+ }
+
+ normalize ();
+
+ return *this;
+}
+
+bool
+IOUAmount::operator<(IOUAmount const& other) const
+{
+ // If the two amounts have different signs (zero is treated as positive)
+ // then the comparison is true iff the left is negative.
+ bool const lneg = mantissa_ < 0;
+ bool const rneg = other.mantissa_ < 0;
+
+ if (lneg != rneg)
+ return lneg;
+
+ // Both have same sign and the left is zero: the right must be
+ // greater than 0.
+ if (mantissa_ == 0)
+ return other.mantissa_ > 0;
+
+ // Both have same sign, the right is zero and the left is non-zero.
+ if (other.mantissa_ == 0)
+ return false;
+
+ // Both have the same sign, compare by exponents:
+ if (exponent_ > other.exponent_)
+ return lneg;
+ if (exponent_ < other.exponent_)
+ return !lneg;
+
+ // If equal exponents, compare mantissas
+ return mantissa_ < other.mantissa_;
+}
+
+}
diff --git a/src/ripple/protocol/impl/STAmount.cpp b/src/ripple/protocol/impl/STAmount.cpp
index 4f32250e5..438a99921 100644
--- a/src/ripple/protocol/impl/STAmount.cpp
+++ b/src/ripple/protocol/impl/STAmount.cpp
@@ -18,6 +18,8 @@
//==============================================================================
#include
+
+#include
#include
#include
#include
@@ -621,7 +623,9 @@ void STAmount::canonicalize ()
if ((mOffset < cMinOffset) || (mValue < cMinValue))
{
mValue = 0;
- mOffset = 0;
+ mIsNegative = false;
+ mOffset = -100;
+ return;
}
if (mOffset > cMaxOffset)
@@ -913,7 +917,6 @@ operator- (STAmount const& value)
// Arithmetic
//
//------------------------------------------------------------------------------
-
STAmount
divide (STAmount const& num, STAmount const& den, Issue const& issue)
{
diff --git a/src/ripple/protocol/tests/IOUAmount.test.cpp b/src/ripple/protocol/tests/IOUAmount.test.cpp
new file mode 100644
index 000000000..45e110951
--- /dev/null
+++ b/src/ripple/protocol/tests/IOUAmount.test.cpp
@@ -0,0 +1,161 @@
+//------------------------------------------------------------------------------
+/*
+ This file is part of rippled: https://github.com/ripple/rippled
+ Copyright (c) 2012, 2013 Ripple Labs Inc.
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+//==============================================================================
+
+#include
+#include
+#include
+
+namespace ripple {
+
+class IOUAmount_test : public beast::unit_test::suite
+{
+public:
+ void testZero ()
+ {
+ testcase ("zero");
+
+ IOUAmount const z (0, 0);
+
+ expect (z.mantissa () == 0);
+ expect (z.exponent () == -100);
+ expect (!z);
+ expect (z.signum () == 0);
+ expect (z == zero);
+
+ expect ((z + z) == z);
+ expect ((z - z) == z);
+ expect (z == -z);
+
+ IOUAmount const zz (zero);
+ expect (z == zz);
+ }
+
+ void testSigNum ()
+ {
+ testcase ("signum");
+
+ IOUAmount const neg (-1, 0);
+ expect (neg.signum () < 0);
+
+ IOUAmount const zer (0, 0);
+ expect (zer.signum () == 0);
+
+ IOUAmount const pos (1, 0);
+ expect (pos.signum () > 0);
+ }
+
+ void testBeastZero ()
+ {
+ testcase ("beast::Zero Comparisons");
+
+ {
+ IOUAmount z (zero);
+ expect (z == zero);
+ expect (z >= zero);
+ expect (z <= zero);
+ unexpected (z != zero);
+ unexpected (z > zero);
+ unexpected (z < zero);
+ }
+
+ {
+ IOUAmount const neg (-2, 0);
+ expect (neg < zero);
+ expect (neg <= zero);
+ expect (neg != zero);
+ unexpected (neg == zero);
+ }
+
+ {
+ IOUAmount const pos (2, 0);
+ expect (pos > zero);
+ expect (pos >= zero);
+ expect (pos != zero);
+ unexpected (pos == zero);
+ }
+ }
+
+ void testComparisons ()
+ {
+ testcase ("IOU Comparisons");
+
+ IOUAmount const n (-2, 0);
+ IOUAmount const z (0, 0);
+ IOUAmount const p (2, 0);
+
+ expect (z == z);
+ expect (z >= z);
+ expect (z <= z);
+ expect (z == -z);
+ unexpected (z > z);
+ unexpected (z < z);
+ unexpected (z != z);
+ unexpected (z != -z);
+
+ expect (n < z);
+ expect (n <= z);
+ expect (n != z);
+ unexpected (n > z);
+ unexpected (n >= z);
+ unexpected (n == z);
+
+ expect (p > z);
+ expect (p >= z);
+ expect (p != z);
+ unexpected (p < z);
+ unexpected (p <= z);
+ unexpected (p == z);
+
+ expect (n < p);
+ expect (n <= p);
+ expect (n != p);
+ unexpected (n > p);
+ unexpected (n >= p);
+ unexpected (n == p);
+
+ expect (p > n);
+ expect (p >= n);
+ expect (p != n);
+ unexpected (p < n);
+ unexpected (p <= n);
+ unexpected (p == n);
+
+ expect (p > -p);
+ expect (p >= -p);
+ expect (p != -p);
+
+ expect (n < -n);
+ expect (n <= -n);
+ expect (n != -n);
+ }
+
+ //--------------------------------------------------------------------------
+
+ void run ()
+ {
+ testZero ();
+ testSigNum ();
+ testBeastZero ();
+ testComparisons ();
+ }
+};
+
+BEAST_DEFINE_TESTSUITE(IOUAmount,protocol,ripple);
+
+} // ripple
diff --git a/src/ripple/protocol/tests/XRPAmount.test.cpp b/src/ripple/protocol/tests/XRPAmount.test.cpp
new file mode 100644
index 000000000..cb7d0e8be
--- /dev/null
+++ b/src/ripple/protocol/tests/XRPAmount.test.cpp
@@ -0,0 +1,125 @@
+//------------------------------------------------------------------------------
+/*
+ This file is part of rippled: https://github.com/ripple/rippled
+ Copyright (c) 2012, 2013 Ripple Labs Inc.
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+//==============================================================================
+
+#include
+#include
+#include
+
+namespace ripple {
+
+class XRPAmount_test : public beast::unit_test::suite
+{
+public:
+ void testSigNum ()
+ {
+ testcase ("signum");
+
+ for (auto i : { -1, 0, 1})
+ {
+ XRPAmount const x(i);
+
+ if (i < 0)
+ expect (x.signum () < 0);
+ else if (i > 0)
+ expect (x.signum () > 0);
+ else
+ expect (x.signum () == 0);
+ }
+ }
+
+ void testBeastZero ()
+ {
+ testcase ("beast::Zero Comparisons");
+
+ for (auto i : { -1, 0, 1})
+ {
+ XRPAmount const x (i);
+
+ expect ((i == 0) == (x == zero));
+ expect ((i != 0) == (x != zero));
+ expect ((i < 0) == (x < zero));
+ expect ((i > 0) == (x > zero));
+ expect ((i <= 0) == (x <= zero));
+ expect ((i >= 0) == (x >= zero));
+
+ expect ((0 == i) == (zero == x));
+ expect ((0 != i) == (zero != x));
+ expect ((0 < i) == (zero < x));
+ expect ((0 > i) == (zero > x));
+ expect ((0 <= i) == (zero <= x));
+ expect ((0 >= i) == (zero >= x));
+ }
+ }
+
+ void testComparisons ()
+ {
+ testcase ("XRP Comparisons");
+
+ for (auto i : { -1, 0, 1})
+ {
+ XRPAmount const x (i);
+
+ for (auto j : { -1, 0, 1})
+ {
+ XRPAmount const y (j);
+
+ expect ((i == j) == (x == y));
+ expect ((i != j) == (x != y));
+ expect ((i < j) == (x < y));
+ expect ((i > j) == (x > y));
+ expect ((i <= j) == (x <= y));
+ expect ((i >= j) == (x >= y));
+ }
+ }
+ }
+
+ void testAddSub ()
+ {
+ testcase ("Addition & Subtraction");
+
+ for (auto i : { -1, 0, 1})
+ {
+ XRPAmount const x (i);
+
+ for (auto j : { -1, 0, 1})
+ {
+ XRPAmount const y (j);
+
+ expect (XRPAmount(i + j) == (x + y));
+ expect (XRPAmount(i - j) == (x - y));
+
+ expect ((x + y) == (y + x)); // addition is commutative
+ }
+ }
+ }
+
+ //--------------------------------------------------------------------------
+
+ void run ()
+ {
+ testSigNum ();
+ testBeastZero ();
+ testComparisons ();
+ testAddSub ();
+ }
+};
+
+BEAST_DEFINE_TESTSUITE(XRPAmount,protocol,ripple);
+
+} // ripple
diff --git a/src/ripple/unity/protocol.cpp b/src/ripple/unity/protocol.cpp
index 7aba59f52..254a4dab0 100644
--- a/src/ripple/unity/protocol.cpp
+++ b/src/ripple/unity/protocol.cpp
@@ -56,10 +56,12 @@
#include
#include
#include
+#include
#include
#include
+#include
#include
#include
#include
@@ -68,6 +70,7 @@
#include
#include
#include
+#include
#if DOXYGEN
#include