1 #ifndef BOOST_NUMERIC_SAFE_BASE_HPP
2 #define BOOST_NUMERIC_SAFE_BASE_HPP
4 // Copyright (c) 2012 Robert Ramey
6 // Distributed under the Boost Software License, Version 1.0. (See
7 // accompanying file LICENSE_1_0.txt or copy at
8 // http://www.boost.org/LICENSE_1_0.txt)
11 #include <type_traits> // is_integral, enable_if, conditional is_convertible
12 #include <boost/config.hpp> // BOOST_CLANG
13 #include "concept/exception_policy.hpp"
14 #include "concept/promotion_policy.hpp"
16 #include "safe_common.hpp"
17 #include "exception_policies.hpp"
19 #include "boost/concept/assert.hpp"
22 namespace safe_numerics {
24 /////////////////////////////////////////////////////////////////
25 // forward declarations to support friend function declarations
32 class P, // promotion polic
33 class E // exception policy
44 struct is_safe<safe_base<T, Min, Max, P, E> > : public std::true_type
54 struct get_promotion_policy<safe_base<T, Min, Max, P, E> > {
65 struct get_exception_policy<safe_base<T, Min, Max, P, E> > {
76 struct base_type<safe_base<T, Min, Max, P, E> > {
87 constexpr T base_value(
88 const safe_base<T, Min, Max, P, E> & st
90 return static_cast<T>(st);
96 class P, // promotion policy
97 class E // exception policy
99 class safe_literal_impl;
101 // works for both GCC and clang
103 #pragma GCC diagnostic push
104 #pragma GCC diagnostic ignored "-Wmismatched-tags"
107 /////////////////////////////////////////////////////////////////
108 // Main implementation
114 class P, // promotion polic
115 class E // exception policy
119 BOOST_CONCEPT_ASSERT((PromotionPolicy<P>));
120 BOOST_CONCEPT_ASSERT((ExceptionPolicy<E>));
127 class PX, // promotion polic
128 class EX // exception policy
130 friend class safe_base;
132 friend class std::numeric_limits<safe_base>;
135 constexpr Stored validated_cast(const T & t) const;
139 template<class CharT, class Traits>
140 void output(std::basic_ostream<CharT, Traits> & os) const;
142 // note usage of friend declaration to mark function as
143 // a global function rather than a member function. If
144 // this is not done, the compiler will confuse this with
145 // a member operator overload on the << operator. Weird
146 // I know. But it's documented here
147 // http://en.cppreference.com/w/cpp/language/friend
148 // under the heading "Template friend operators"
149 template<class CharT, class Traits>
150 friend std::basic_ostream<CharT, Traits> &
152 std::basic_ostream<CharT, Traits> & os,
159 template<class CharT, class Traits>
160 void input(std::basic_istream<CharT, Traits> & is);
163 template<class CharT, class Traits>
164 friend inline std::basic_istream<CharT, Traits> &
166 std::basic_istream<CharT, Traits> & is,
174 ////////////////////////////////////////////////////////////
177 constexpr safe_base();
179 struct skip_validation{};
181 constexpr explicit safe_base(const Stored & rhs, skip_validation);
183 // construct an instance of a safe type from an instance of a convertible underlying type.
186 typename std::enable_if<
187 std::is_convertible<T, Stored>::value,
191 constexpr /*explicit*/ safe_base(const T & t);
193 // construct an instance of a safe type from a literal value
194 template<typename T, T N, class Px, class Ex>
195 constexpr /*explicit*/ safe_base(const safe_literal_impl<T, N, Px, Ex> & t);
197 // note: Rule of Five. Supply all or none of the following
198 // a) user-defined destructor
199 ~safe_base() = default;
200 // b) copy-constructor
201 constexpr safe_base(const safe_base &) = default;
202 // c) copy-assignment
203 constexpr safe_base & operator=(const safe_base &) = default;
204 // d) move constructor
205 constexpr safe_base(safe_base &&) = default;
206 // e) move assignment operator
207 constexpr safe_base & operator=(safe_base &&) = default;
209 /////////////////////////////////////////////////////////////////
210 // casting operators for intrinsic integers
211 // convert to any type which is not safe. safe types need to be
212 // excluded to prevent ambiguous function selection which
213 // would otherwise occur. validity of safe types is checked in
214 // the constructor of safe types
217 typename std::enable_if<
218 ! boost::safe_numerics::is_safe<R>::value,
222 constexpr /*explicit*/ operator R () const;
224 /////////////////////////////////////////////////////////////////
225 // modification binary operators
227 constexpr safe_base &
228 operator=(const T & rhs){
229 m_t = validated_cast(rhs);
233 // mutating unary operators
234 safe_base & operator++(){ // pre increment
235 return *this = *this + 1;
237 safe_base & operator--(){ // pre decrement
238 return *this = *this - 1;
240 safe_base operator++(int){ // post increment
241 safe_base old_t = *this;
245 safe_base operator--(int){ // post decrement
246 safe_base old_t = *this;
250 // non mutating unary operators
251 constexpr auto operator+() const { // unary plus
254 // after much consideration, I've permited the resulting value of a unary
255 // - to change the type. The C++ standard does invoke integral promotions
256 // so it's changing the type as well.
258 /* section 5.3.1 &8 of the C++ standard
259 The operand of the unary - operator shall have arithmetic or unscoped
260 enumeration type and the result is the negation of its operand. Integral
261 promotion is performed on integral or enumeration operands. The negative
262 of an unsigned quantity is computed by subtracting its value from 2n,
263 where n is the number of bits in the promoted operand. The type of the
264 result is the type of the promoted operand.
266 constexpr auto operator-() const { // unary minus
267 // if this is a unsigned type and the promotion policy is native
268 // the result will be unsigned. But then the operation will fail
269 // according to the requirements of arithmetic correctness.
270 // if this is an unsigned type and the promotion policy is automatic.
271 // the result will be signed.
274 /* section 5.3.1 &10 of the C++ standard
275 The operand of ~ shall have integral or unscoped enumeration type;
276 the result is the ones’ complement of its operand. Integral promotions
277 are performed. The type of the result is the type of the promoted operand.
279 constexpr auto operator~() const { // complement
280 return ~Stored(0u) ^ *this;
287 /////////////////////////////////////////////////////////////////
288 // numeric limits for safe<int> etc.
301 class numeric_limits<boost::safe_numerics::safe_base<T, Min, Max, P, E> >
302 : public std::numeric_limits<T>
304 using SB = boost::safe_numerics::safe_base<T, Min, Max, P, E>;
306 constexpr static SB lowest() noexcept {
307 return SB(Min, typename SB::skip_validation());
309 constexpr static SB min() noexcept {
310 return SB(Min, typename SB::skip_validation());
312 constexpr static SB max() noexcept {
313 return SB(Max, typename SB::skip_validation());
320 #pragma GCC diagnostic pop
323 #endif // BOOST_NUMERIC_SAFE_BASE_HPP