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
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;
137 template<typename T, T N, class P1, class E1>
138 constexpr Stored validated_cast(
139 const safe_literal_impl<T, N, P1, E1> & t
144 template<class CharT, class Traits>
145 void output(std::basic_ostream<CharT, Traits> & os) const;
147 // note usage of friend declaration to mark function as
148 // a global function rather than a member function. If
149 // this is not done, the compiler will confuse this with
150 // a member operator overload on the << operator. Weird
151 // I know. But it's documented here
152 // http://en.cppreference.com/w/cpp/language/friend
153 // under the heading "Template friend operators"
154 template<class CharT, class Traits>
155 friend std::basic_ostream<CharT, Traits> &
157 std::basic_ostream<CharT, Traits> & os,
164 template<class CharT, class Traits>
165 void input(std::basic_istream<CharT, Traits> & is);
168 template<class CharT, class Traits>
169 friend inline std::basic_istream<CharT, Traits> &
171 std::basic_istream<CharT, Traits> & is,
179 ////////////////////////////////////////////////////////////
182 struct skip_validation{};
184 constexpr explicit safe_base(const Stored & rhs, skip_validation);
186 constexpr safe_base();
188 // construct an instance of a safe type
189 // from an instance of a convertible underlying type.
192 constexpr /*explicit*/ safe_base(
194 typename std::enable_if<
201 constexpr /*explicit*/ safe_base(
203 typename std::enable_if<
204 std::is_integral<T>::value,
209 template<class T, T value>
210 constexpr /*explicit*/ safe_base(
211 const std::integral_constant<T, value> &
214 // note: Rule of Five. Supply all or none of the following
215 // a) user-defined destructor
216 ~safe_base() = default;
217 // b) copy-constructor
218 constexpr safe_base(const safe_base &) = default;
219 // c) copy-assignment
220 constexpr safe_base & operator=(const safe_base &) = default;
221 // d) move constructor
222 constexpr safe_base(safe_base &&) = default;
223 // e) move assignment operator
224 constexpr safe_base & operator=(safe_base &&) = default;
226 /////////////////////////////////////////////////////////////////
227 // casting operators for intrinsic integers
228 // convert to any type which is not safe. safe types need to be
229 // excluded to prevent ambiguous function selection which
230 // would otherwise occur. validity of safe types is checked in
231 // the constructor of safe types
234 typename std::enable_if<
235 ! boost::safe_numerics::is_safe<R>::value,
239 constexpr /*explicit*/ operator R () const;
241 constexpr /*explicit*/ operator Stored () const;
243 /////////////////////////////////////////////////////////////////
244 // modification binary operators
246 constexpr safe_base &
247 operator=(const T & rhs){
248 m_t = validated_cast(rhs);
252 // required to passify VS2017
253 constexpr safe_base &
254 operator=(const Stored & rhs){
255 m_t = validated_cast(rhs);
259 // mutating unary operators
260 safe_base & operator++(){ // pre increment
261 return *this = *this + 1;
263 safe_base & operator--(){ // pre decrement
264 return *this = *this - 1;
266 safe_base operator++(int){ // post increment
267 safe_base old_t = *this;
271 safe_base operator--(int){ // post decrement
272 safe_base old_t = *this;
276 // non mutating unary operators
277 constexpr auto operator+() const { // unary plus
280 // after much consideration, I've permited the resulting value of a unary
281 // - to change the type. The C++ standard does invoke integral promotions
282 // so it's changing the type as well.
284 /* section 5.3.1 &8 of the C++ standard
285 The operand of the unary - operator shall have arithmetic or unscoped
286 enumeration type and the result is the negation of its operand. Integral
287 promotion is performed on integral or enumeration operands. The negative
288 of an unsigned quantity is computed by subtracting its value from 2n,
289 where n is the number of bits in the promoted operand. The type of the
290 result is the type of the promoted operand.
292 constexpr auto operator-() const { // unary minus
293 // if this is a unsigned type and the promotion policy is native
294 // the result will be unsigned. But then the operation will fail
295 // according to the requirements of arithmetic correctness.
296 // if this is an unsigned type and the promotion policy is automatic.
297 // the result will be signed.
300 /* section 5.3.1 &10 of the C++ standard
301 The operand of ~ shall have integral or unscoped enumeration type;
302 the result is the ones’ complement of its operand. Integral promotions
303 are performed. The type of the result is the type of the promoted operand.
305 constexpr auto operator~() const { // complement
306 return ~Stored(0u) ^ *this;
313 /////////////////////////////////////////////////////////////////
314 // numeric limits for safe<int> etc.
327 class numeric_limits<boost::safe_numerics::safe_base<T, Min, Max, P, E> >
328 : public std::numeric_limits<T>
330 using SB = boost::safe_numerics::safe_base<T, Min, Max, P, E>;
332 constexpr static SB lowest() noexcept {
333 return SB(Min, typename SB::skip_validation());
335 constexpr static SB min() noexcept {
336 return SB(Min, typename SB::skip_validation());
338 constexpr static SB max() noexcept {
339 return SB(Max, typename SB::skip_validation());
346 #pragma GCC diagnostic pop
349 #endif // BOOST_NUMERIC_SAFE_BASE_HPP