Skip to content

Commit

Permalink
Differentiate between precondition checks and internal assertions
Browse files Browse the repository at this point in the history
  • Loading branch information
foonathan committed Dec 24, 2016
1 parent f91299e commit 07a6a42
Show file tree
Hide file tree
Showing 15 changed files with 64 additions and 36 deletions.
16 changes: 15 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,26 @@ project(TYPE_SAFE)
include(external/external.cmake)

# options
option(TYPE_SAFE_ENABLE_ASSERTIONS "whether or not to enable assertions for the type_safe library" ON)
if(CMAKE_BUILD_TYPE MATCHES Debug)
set(_type_safe_default_assertions ON)
else()
set(_type_safe_default_assertions OFF)
endif()

option(TYPE_SAFE_ENABLE_ASSERTIONS "whether or not to enable internal assertions for the type_safe library" ${_type_safe_default_assertions})
if(${TYPE_SAFE_ENABLE_ASSERTIONS})
set(_type_safe_enable_assertions 1)
else()
set(_type_safe_enable_assertions 0)
endif()

option(TYPE_SAFE_ENABLE_PRECONDITION_CHECKS "whether or not to enable precondition checks" ON)
if(${TYPE_SAFE_ENABLE_PRECONDITION_CHECKS})
set(_type_safe_enable_precondition_checks 1)
else()
set(_type_safe_enable_precondition_checks 0)
endif()

option(TYPE_SAFE_ENABLE_WRAPPER "whether or not the wrappers in types.hpp are used" ON)
if(${TYPE_SAFE_ENABLE_WRAPPER})
set(_type_safe_enable_wrapper 1)
Expand Down Expand Up @@ -66,6 +79,7 @@ target_sources(type_safe INTERFACE ${detail_header_files} ${header_files})
target_include_directories(type_safe INTERFACE include/)
target_compile_definitions(type_safe INTERFACE
TYPE_SAFE_ENABLE_ASSERTIONS=${_type_safe_enable_assertions}
TYPE_SAFE_ENABLE_PRECONDITION_CHECKS=${_type_safe_enable_precondition_checks}
TYPE_SAFE_ENABLE_WRAPPER=${_type_safe_enable_wrapper}
TYPE_SAFE_ARITHMETIC_UB=${_type_safe_arithmetic_ub})
target_link_libraries(type_safe INTERFACE debug_assert)
Expand Down
14 changes: 8 additions & 6 deletions include/type_safe/arithmetic_policy.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ namespace type_safe
TYPE_SAFE_FORCE_INLINE static constexpr T do_addition(const T& a, const T& b) noexcept
{
return detail::will_addition_error(detail::arithmetic_tag_for<T>{}, a, b) ?
(DEBUG_UNREACHABLE(detail::assert_handler{},
(DEBUG_UNREACHABLE(detail::precondition_error_handler{},
"addition will result in overflow"),
a) :
a + b;
Expand All @@ -148,7 +148,7 @@ namespace type_safe
TYPE_SAFE_FORCE_INLINE static constexpr T do_subtraction(const T& a, const T& b) noexcept
{
return detail::will_subtraction_error(detail::arithmetic_tag_for<T>{}, a, b) ?
(DEBUG_UNREACHABLE(detail::assert_handler{},
(DEBUG_UNREACHABLE(detail::precondition_error_handler{},
"subtraction will result in underflow"),
a) :
a - b;
Expand All @@ -158,7 +158,7 @@ namespace type_safe
TYPE_SAFE_FORCE_INLINE static constexpr T do_multiplication(const T& a, const T& b) noexcept
{
return detail::will_multiplication_error(detail::arithmetic_tag_for<T>{}, a, b) ?
(DEBUG_UNREACHABLE(detail::assert_handler{},
(DEBUG_UNREACHABLE(detail::precondition_error_handler{},
"multiplication will result in overflow"),
a) :
a * b;
Expand All @@ -168,7 +168,8 @@ namespace type_safe
TYPE_SAFE_FORCE_INLINE static constexpr T do_division(const T& a, const T& b) noexcept
{
return detail::will_division_error(detail::arithmetic_tag_for<T>{}, a, b) ?
(DEBUG_UNREACHABLE(detail::assert_handler{}, "division by zero/overflow"),
(DEBUG_UNREACHABLE(detail::precondition_error_handler{},
"division by zero/overflow"),
a) :
a / b;
}
Expand All @@ -177,7 +178,8 @@ namespace type_safe
TYPE_SAFE_FORCE_INLINE static constexpr T do_modulo(const T& a, const T& b) noexcept
{
return detail::will_modulo_error(detail::arithmetic_tag_for<T>{}, a, b) ?
(DEBUG_UNREACHABLE(detail::assert_handler{}, "modulo by zero"), a) :
(DEBUG_UNREACHABLE(detail::precondition_error_handler{}, "modulo by zero"),
a) :
a % b;
}
};
Expand All @@ -195,7 +197,7 @@ namespace type_safe
error(const char* msg) : std::range_error(msg)
{
#if !TYPE_SAFE_USE_EXCEPTIONS
DEBUG_UNREACHABLE(detail::assert_handler{}, msg);
DEBUG_UNREACHABLE(detail::precondition_error_handler{}, msg);
#endif
}
};
Expand Down
2 changes: 1 addition & 1 deletion include/type_safe/compact_optional.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ namespace type_safe
typename std::enable_if<std::is_constructible<value_type, Args&&...>::value>::type
{
storage_ = static_cast<storage_type>(value_type(std::forward<Args>(args)...));
DEBUG_ASSERT(has_value(), detail::assert_handler{},
DEBUG_ASSERT(has_value(), detail::precondition_error_handler{},
"create_value() called creating an invalid value");
}

Expand Down
6 changes: 5 additions & 1 deletion include/type_safe/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@
#include <cstdlib>

#ifndef TYPE_SAFE_ENABLE_ASSERTIONS
#define TYPE_SAFE_ENABLE_ASSERTIONS 1
#define TYPE_SAFE_ENABLE_ASSERTIONS 0
#endif

#ifndef TYPE_SAFE_ENABLE_PRECONDITION_CHECKS
#define TYPE_SAFE_ENABLE_PRECONDITION_CHECKS 1
#endif

#ifndef TYPE_SAFE_ENABLE_WRAPPER
Expand Down
5 changes: 3 additions & 2 deletions include/type_safe/constrained_type.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ namespace type_safe
template <typename Value, typename Predicate>
static void verify(const Value& val, const Predicate& p)
{
DEBUG_ASSERT(p(val), detail::assert_handler{}, "value does not fulfill constraint");
DEBUG_ASSERT(p(val), detail::precondition_error_handler{},
"value does not fulfill constraint");
}
};

Expand Down Expand Up @@ -185,7 +186,7 @@ namespace type_safe
/// \requires It must not be in the moved-from state.
value_type& get() noexcept
{
DEBUG_ASSERT(value_, detail::assert_handler{});
DEBUG_ASSERT(value_, detail::precondition_error_handler{});
return value_->value_;
}

Expand Down
10 changes: 5 additions & 5 deletions include/type_safe/deferred_construction.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ namespace type_safe
template <typename... Args>
void emplace(Args&&... args)
{
DEBUG_ASSERT(!has_value(), detail::assert_handler{});
DEBUG_ASSERT(!has_value(), detail::precondition_error_handler{});
::new (as_void()) value_type(std::forward<Args>(args)...);
initialized_ = true;
}
Expand All @@ -129,15 +129,15 @@ namespace type_safe
/// \requires `has_value() == true`.
value_type& value() TYPE_SAFE_LVALUE_REF noexcept
{
DEBUG_ASSERT(has_value(), detail::assert_handler{});
DEBUG_ASSERT(has_value(), detail::precondition_error_handler{});
return *static_cast<value_type*>(as_void());
}

/// \returns A `const` reference to the stored value.
/// \requires `has_value() == true`.
const value_type& value() const TYPE_SAFE_LVALUE_REF noexcept
{
DEBUG_ASSERT(has_value(), detail::assert_handler{});
DEBUG_ASSERT(has_value(), detail::precondition_error_handler{});
return *static_cast<const value_type*>(as_void());
}

Expand All @@ -146,15 +146,15 @@ namespace type_safe
/// \requires `has_value() == true`.
value_type&& value() && noexcept
{
DEBUG_ASSERT(has_value(), detail::assert_handler{});
DEBUG_ASSERT(has_value(), detail::precondition_error_handler{});
return std::move(*static_cast<value_type*>(as_void()));
}

/// \returns An rvalue reference to the stored value.
/// \requires `has_value() == true`.
const value_type&& value() const && noexcept
{
DEBUG_ASSERT(has_value(), detail::assert_handler{});
DEBUG_ASSERT(has_value(), detail::precondition_error_handler{});
return std::move(*static_cast<const value_type*>(as_void()));
}
#endif
Expand Down
6 changes: 6 additions & 0 deletions include/type_safe/detail/assert.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ namespace type_safe
debug_assert::default_handler
{
};

struct precondition_error_handler
: debug_assert::set_level<TYPE_SAFE_ENABLE_PRECONDITION_CHECKS>,
debug_assert::default_handler
{
};
} // namespace detail
} // namespace type_safe

Expand Down
2 changes: 1 addition & 1 deletion include/type_safe/flag.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ namespace type_safe
template <typename T, typename = detail::enable_boolean<T>>
void change(T new_state) noexcept
{
DEBUG_ASSERT(state_ != new_state, detail::assert_handler{});
DEBUG_ASSERT(state_ != new_state, detail::precondition_error_handler{});
state_ = new_state;
}

Expand Down
2 changes: 1 addition & 1 deletion include/type_safe/index.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ namespace type_safe
{
DEBUG_ASSERT(detail::index_valid(detail::member_size{}, obj,
static_cast<std::size_t>(get(index))),
detail::assert_handler{});
detail::precondition_error_handler{});
return std::forward<Indexable>(obj)[static_cast<std::size_t>(get(index))];
}

Expand Down
14 changes: 7 additions & 7 deletions include/type_safe/integer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -352,9 +352,9 @@ namespace type_safe
using result_type = make_signed_t<Integer>;
return i <= Integer(std::numeric_limits<result_type>::max()) ?
static_cast<result_type>(i) :
(DEBUG_UNREACHABLE(detail::assert_handler{}, "conversion "
"would "
"overflow"),
(DEBUG_UNREACHABLE(detail::precondition_error_handler{}, "conversion "
"would "
"overflow"),
result_type());
}

Expand Down Expand Up @@ -383,10 +383,10 @@ namespace type_safe
TYPE_SAFE_FORCE_INLINE constexpr make_unsigned_t<Integer> make_unsigned(const Integer& i)
{
using result_type = make_unsigned_t<Integer>;
return i >= Integer(0) ?
static_cast<result_type>(i) :
(DEBUG_UNREACHABLE(detail::assert_handler{}, "conversion would underflow"),
result_type(0));
return i >= Integer(0) ? static_cast<result_type>(i) :
(DEBUG_UNREACHABLE(detail::precondition_error_handler{},
"conversion would underflow"),
result_type(0));
}

/// \returns A new [ts::integer]() of the corresponding unsigned integer type.
Expand Down
3 changes: 2 additions & 1 deletion include/type_safe/narrow_cast.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ namespace type_safe
TYPE_SAFE_FORCE_INLINE constexpr Target narrow_cast(const Source& source) noexcept
{
return detail::is_narrowing<Target>(source) ?
(DEBUG_UNREACHABLE(detail::assert_handler{}, "conversion would truncate value"),
(DEBUG_UNREACHABLE(detail::precondition_error_handler{},
"conversion would truncate value"),
Target()) :
static_cast<Target>(source);
}
Expand Down
8 changes: 4 additions & 4 deletions include/type_safe/optional.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ namespace type_safe
/// \requires `has_value() == true`.
auto value() TYPE_SAFE_LVALUE_REF noexcept -> decltype(std::declval<storage&>().get_value())
{
DEBUG_ASSERT(has_value(), detail::assert_handler{});
DEBUG_ASSERT(has_value(), detail::precondition_error_handler{});
return get_storage().get_value();
}

Expand All @@ -384,7 +384,7 @@ namespace type_safe
auto value() const TYPE_SAFE_LVALUE_REF noexcept
-> decltype(std::declval<const storage&>().get_value())
{
DEBUG_ASSERT(has_value(), detail::assert_handler{});
DEBUG_ASSERT(has_value(), detail::precondition_error_handler{});
return get_storage().get_value();
}

Expand All @@ -393,15 +393,15 @@ namespace type_safe
/// \requires `has_value() == true`.
auto value() && noexcept -> decltype(std::declval<storage&&>().get_value())
{
DEBUG_ASSERT(has_value(), detail::assert_handler{});
DEBUG_ASSERT(has_value(), detail::precondition_error_handler{});
return std::move(get_storage()).get_value();
}

/// \returns An rvalue reference to the stored value.
/// \requires `has_value() == true`.
auto value() const && noexcept -> decltype(std::declval<const storage&&>().get_value())
{
DEBUG_ASSERT(has_value(), detail::assert_handler{});
DEBUG_ASSERT(has_value(), detail::precondition_error_handler{});
return std::move(get_storage()).get_value();
}
#endif
Expand Down
2 changes: 1 addition & 1 deletion include/type_safe/tagged_union.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ namespace type_safe
template <typename T>
void check(union_type<T> type) const noexcept
{
DEBUG_ASSERT(cur_type_ == type, detail::assert_handler{},
DEBUG_ASSERT(cur_type_ == type, detail::precondition_error_handler{},
"different type stored in union");
}

Expand Down
6 changes: 3 additions & 3 deletions include/type_safe/variant.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,15 +142,15 @@ namespace type_safe
/// \group ctor_union
explicit basic_variant(const tagged_union<HeadT, TailT...>& u)
{
DEBUG_ASSERT(allow_empty::value || u.has_value(), detail::assert_handler{});
DEBUG_ASSERT(allow_empty::value || u.has_value(), detail::precondition_error_handler{});
if (u.has_value())
copy(storage_.get_union(), u);
}

/// \group ctor_union
explicit basic_variant(tagged_union<HeadT, TailT...>&& u)
{
DEBUG_ASSERT(allow_empty::value || u.has_value(), detail::assert_handler{});
DEBUG_ASSERT(allow_empty::value || u.has_value(), detail::precondition_error_handler{});
if (u.has_value())
move(storage_.get_union(), std::move(u));
}
Expand Down Expand Up @@ -358,7 +358,7 @@ namespace type_safe
/// \requires The variant must be empty.
nullvar_t value(variant_type<nullvar_t>) const noexcept
{
DEBUG_ASSERT(!has_value(), detail::assert_handler{});
DEBUG_ASSERT(!has_value(), detail::precondition_error_handler{});
return nullvar;
}

Expand Down
4 changes: 2 additions & 2 deletions include/type_safe/visitor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ namespace type_safe
std::forward<Visitor>(visitor), std::forward<Args>(args)..., nullvar))
{
DEBUG_ASSERT(std::decay<Variant>::type::allow_empty::value && !variant.has_value(),
assert_handler{}, "variant in invalid state for visitor");
precondition_error_handler{}, "variant in invalid state for visitor");
return visit_variant_impl<AllowIncomplete, Visitor>::call(std::forward<Visitor>(
visitor),
std::forward<Args>(
Expand Down Expand Up @@ -265,7 +265,7 @@ namespace type_safe
std::forward<Args>(args)..., nullvar))
{
DEBUG_ASSERT(std::decay<Variant>::type::allow_empty::value && !variant.has_value(),
assert_handler{}, "variant in invalid state for visitor");
precondition_error_handler{}, "variant in invalid state for visitor");
return visit_variant_impl<AllowIncomplete, Visitor,
Rest...>::call(std::forward<Visitor>(visitor),
std::forward<Rest>(rest)...,
Expand Down

0 comments on commit 07a6a42

Please sign in to comment.