##// END OF EJS Templates
Removed CMake scripts :)
Removed CMake scripts :)

File last commit:

r4:96a6baa9f92b
r93:63c6ae3895dd
Show More
numeric_typedef.hpp
260 lines | 10.0 KiB | text/x-c++hdr | CppLexer
/ include / opaque / numeric_typedef.hpp
Introduced opaque library from Kyle Markley and improved DateTimeRange...
r4 #ifndef OPAQUE_NUMERIC_TYPEDEF_HPP
#define OPAQUE_NUMERIC_TYPEDEF_HPP
//
// Copyright (c) 2015, 2016
// Kyle Markley. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// 3. Neither the name of the author nor the names of any contributors may be
// used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
#include "binop/binop_inherit.hpp"
#include "data.hpp"
#include <type_traits>
#include <utility>
namespace opaque {
/// \addtogroup typedefs
/// @{
///
/// Numeric opaque typedef base type
///
/// Same as numeric_typedef, but without providing operator@ in terms of
/// operator@= by default. (Deriving from this rather than numeric_typedef
/// can avoid the need to remove a provided operator@ via a template
/// specialization.)
///
/// This is a suitable base class when you want to control the interface of
/// your type, including its interoperability with itself and other types.
/// Delete operations that you do not want, and add operations that you do
/// want.
///
/// You may define the behavior of mixed-type operator@ in your subclass by
/// inheriting from the opaque::binop::opname classes and providing the type
/// details. The list of template arguments for these classes is:
/// -# return type
/// -# commutative (bool)
/// -# type of left operand
/// -# type of right operand
/// -# type to convert left operand to
/// -# type to convert right operand to
///
/// If you do not desire certain standard numeric operations, simply delete
/// them in your subclass. (Note that it is simpler to delete an unwanted
/// operation than to supply a missing one that is desired.)
///
template <typename U, typename O, typename S = unsigned>
struct numeric_typedef_base : data<U,O> {
private:
using base = opaque::data<U,O>;
public:
using typename base::underlying_type;
using typename base::opaque_type;
typedef S shift_type;
using base::value;
constexpr14 opaque_type& operator*=(const opaque_type& peer) &
noexcept(noexcept( value *= peer.value )) {
value *= peer.value;
return downcast(); }
constexpr14 opaque_type& operator/=(const opaque_type& peer) &
noexcept(noexcept( value /= peer.value )) {
value /= peer.value;
return downcast(); }
constexpr14 opaque_type& operator%=(const opaque_type& peer) &
noexcept(noexcept( value %= peer.value )) {
value %= peer.value;
return downcast(); }
constexpr14 opaque_type& operator+=(const opaque_type& peer) &
noexcept(noexcept( value += peer.value )) {
value += peer.value;
return downcast(); }
constexpr14 opaque_type& operator-=(const opaque_type& peer) &
noexcept(noexcept( value -= peer.value )) {
value -= peer.value;
return downcast(); }
constexpr14 opaque_type& operator<<=(const shift_type& count) &
noexcept(noexcept( value <<= count )) {
value <<= count;
return downcast(); }
constexpr14 opaque_type& operator>>=(const shift_type& count) &
noexcept(noexcept( value >>= count )) {
value >>= count;
return downcast(); }
constexpr14 opaque_type& operator&=(const opaque_type& peer) &
noexcept(noexcept( value &= peer.value )) {
value &= peer.value;
return downcast(); }
constexpr14 opaque_type& operator^=(const opaque_type& peer) &
noexcept(noexcept( value ^= peer.value )) {
value ^= peer.value;
return downcast(); }
constexpr14 opaque_type& operator|=(const opaque_type& peer) &
noexcept(noexcept( value |= peer.value )) {
value |= peer.value;
return downcast(); }
constexpr14 opaque_type& operator++() &
noexcept(noexcept( ++value )) {
++value;
return downcast(); }
constexpr14 opaque_type& operator--() &
noexcept(noexcept( --value )) {
--value;
return downcast(); }
constexpr14 opaque_type operator++(int) & noexcept(noexcept(
std::declval<numeric_typedef_base&>().operator++()) and
std::is_nothrow_constructible<opaque_type, underlying_type>::value) {
opaque_type r(value); operator++(); return r; }
constexpr14 opaque_type operator--(int) & noexcept(noexcept(
std::declval<numeric_typedef_base&>().operator++()) and
std::is_nothrow_constructible<opaque_type, underlying_type>::value) {
opaque_type r(value); operator--(); return r; }
constexpr opaque_type operator+() const &
noexcept(noexcept( opaque_type(+ value ) )) {
return opaque_type(+ value ); }
constexpr14 opaque_type operator+() &&
noexcept(noexcept( opaque_type(+opaque::move(value)) )) {
return opaque_type(+opaque::move(value)); }
constexpr opaque_type operator-() const &
noexcept(noexcept( opaque_type(- value ) )) {
return opaque_type(- value ); }
constexpr14 opaque_type operator-() &&
noexcept(noexcept( opaque_type(-opaque::move(value)) )) {
return opaque_type(-opaque::move(value)); }
constexpr opaque_type operator~() const &
noexcept(noexcept( opaque_type(~ value ) )) {
return opaque_type(~ value ); }
constexpr14 opaque_type operator~() &&
noexcept(noexcept( opaque_type(~opaque::move(value)) )) {
return opaque_type(~opaque::move(value)); }
constexpr bool operator!() const
noexcept(noexcept( !value )) {
return !value; }
constexpr bool operator==(const opaque_type& peer) const
noexcept(noexcept( value == peer.value )) {
return value == peer.value; }
constexpr bool operator!=(const opaque_type& peer) const
noexcept(noexcept( value != peer.value )) {
return value != peer.value; }
constexpr bool operator< (const opaque_type& peer) const
noexcept(noexcept( value < peer.value )) {
return value < peer.value; }
constexpr bool operator> (const opaque_type& peer) const
noexcept(noexcept( value > peer.value )) {
return value > peer.value; }
constexpr bool operator<=(const opaque_type& peer) const
noexcept(noexcept( value <= peer.value )) {
return value <= peer.value; }
constexpr bool operator>=(const opaque_type& peer) const
noexcept(noexcept( value >= peer.value )) {
return value >= peer.value; }
/// Check whether the underlying value is nonzero
explicit constexpr operator bool() const
noexcept(noexcept( static_cast<bool>(value) )) {
return static_cast<bool>(value); }
using base::base;
explicit numeric_typedef_base() = default;
numeric_typedef_base(const numeric_typedef_base& ) = default;
numeric_typedef_base( numeric_typedef_base&&) = default;
numeric_typedef_base& operator=(const numeric_typedef_base& ) & = default;
numeric_typedef_base& operator=( numeric_typedef_base&&) & = default;
protected:
~numeric_typedef_base() = default;
using base::downcast;
};
///
/// Numeric opaque typedef
///
/// This is a base class providing wrappers for numeric operations on a
/// user-supplied type, which may be user-defined or built-in. The purpose of
/// this type is to easily enable the creation of several rigorously separate
/// numeric types so that they cannot be accidentally mixed in expressions,
/// implicitly converted, and also to enable overloading.
///
/// For example, you could create separate types for coordinates in each of
/// several dimensions, and it would be a compile-time error to mix those types
/// in a single expression, even if the the same underlying type was used to
/// represent all of them.
///
/// Template arguments for numeric_typedef:
/// -# U : The underlying type holding the value
/// -# O : The opaque type, your subclass
/// -# S : The right-hand operand type for shift operations
///
template <typename U, typename O, typename S = unsigned>
struct numeric_typedef : numeric_typedef_base<U,O,S>
, binop::multipliable <O>
, binop::dividable <O>
, binop::modulable <O>
, binop::addable <O>
, binop::subtractable <O>
, binop::left_shiftable <O, false, O, S>
, binop::right_shiftable<O, false, O, S>
, binop::bitandable <O>
, binop::bitxorable <O>
, binop::bitorable <O>
{
using numeric_typedef_base<U,O,S>::numeric_typedef_base;
explicit numeric_typedef() = default;
numeric_typedef(const numeric_typedef& ) = default;
numeric_typedef( numeric_typedef&&) = default;
numeric_typedef& operator=(const numeric_typedef& ) & = default;
numeric_typedef& operator=( numeric_typedef&&) & = default;
protected:
~numeric_typedef() = default;
};
/// @}
}
#endif