Skip to content

Commit

Permalink
update from main repo
Browse files Browse the repository at this point in the history
  • Loading branch information
treh committed Dec 2, 2015
1 parent 4782871 commit 262fb81
Show file tree
Hide file tree
Showing 68 changed files with 5,938 additions and 2,793 deletions.
58 changes: 0 additions & 58 deletions Library/ErrorReporting/UnitTest.h

This file was deleted.

67 changes: 33 additions & 34 deletions Library/ErrorReporting/functors.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
////////////////////////////////
// functor equivalents for operators, free functions and member functions

#include <cstdlib>
#include "tc_move.h"
#include "Library/Utilities/return_decltype.h"

#include <boost/type_traits/has_dereference.hpp>
#include <boost/preprocessor/seq/for_each_i.hpp>
#include <boost/preprocessor/control/if.hpp>
#include "Library/Utilities/decltype_return.h"

#include "tc_move.h"
#include <cstdlib>

// DEFINE_FN(func) always defines a function void func(define_fn_dummy)
// If that function did not exist, -> decltype( func(...) ) would not be
Expand All @@ -20,14 +20,14 @@ struct define_fn_dummy {};
#define DEFINE_FN2( func, name ) \
struct name { \
template< typename A0, typename ...Args > /*require at least one argument*/ \
auto operator()( A0 && a0, Args && ... args) const \
return_decltype( func(std::forward<A0>(a0), std::forward<Args>(args)...) ) \
auto operator()( A0&& a0, Args&& ... args) const \
return_decltype_rvalue_by_ref( func(std::forward<A0>(a0), std::forward<Args>(args)...) ) \
};

#define DEFINE_MEM_FN_BODY_( ... ) \
template< typename O, typename ...__A > \
auto operator()( O && o, __A && ... __a ) const \
return_decltype( std::forward<O>(o) __VA_ARGS__ ( std::forward<__A>(__a)... ) )
auto operator()( O&& o, __A&& ... __a ) const \
return_decltype_rvalue_by_ref( std::forward<O>(o) __VA_ARGS__ ( std::forward<__A>(__a)... ) )

// boost::mem_fn (C++11 standard 20.8.2) knows the type it can apply its member function pointer to and
// dereferences via operator* until it reaches that something of that type. We cannot do that because
Expand All @@ -37,26 +37,26 @@ struct define_fn_dummy {};
// member access via operator->, with the small addition that if operator-> does not exist, we use the
// the dot operator, in the spirit of dereferencing as much as possible.

#define DEFINE_MEM_FN_AUTO_BODY_( ... ) \
template< typename O, typename ...__A > \
auto operator()( O && o, __A && ... __a ) const \
enable_if_return_decltype( boost::has_dereference<O>::value, \
std::forward<O>(o)-> __VA_ARGS__ ( std::forward<__A>(__a)... ) ) \
template< typename O, typename ...__A > \
auto operator()( O && o, __A && ... __a ) const \
enable_if_return_decltype( !boost::has_dereference<O>::value, \
std::forward<O>(o). __VA_ARGS__ ( std::forward<__A>(__a)... ) )
#define DEFINE_MEM_FN_AUTO_BODY_( ... ) \
template< typename O, typename ...__A, std::enable_if_t<boost::has_dereference<O>::value>* = nullptr > \
auto operator()( O&& o, __A&& ... __a ) const \
return_decltype_rvalue_by_ref( std::forward<O>(o)-> __VA_ARGS__ ( std::forward<__A>(__a)... ) ) \
template< typename O, typename ...__A, std::enable_if_t<!boost::has_dereference<O>::value>* = nullptr > \
auto operator()( O&& o, __A&& ... __a ) const \
return_decltype_rvalue_by_ref( std::forward<O>(o). __VA_ARGS__ ( std::forward<__A>(__a)... ) )

// When a functor must be declared in class-scope, e.g., to access a protected member function,
// you should use DEFINE_MEM_FN instead of DEFINE_FN.
// DEFINE_FN always has to define a function named "void func(define_fn_dummy)" which may
// shadow inherited members named func.
#define DEFINE_MEM_FN( func ) \
struct dot_member_ ## func { \
template< typename O > auto operator()( O & o ) const return_variable_by_ref( o.func ) \
template< typename O > auto operator()( O const& o ) const return_variable_by_ref( o.func ) \
template< typename O > auto operator()( O&& o ) const enable_if_return_decltype_rvalue_by_ref( !std::is_reference<O>::value, tc_move(tc_move(o).func) ) \
template< typename O > auto operator()( O & o ) const return_variable_by_ref( o.func ) \
template< typename O > auto operator()( O const& o ) const return_variable_by_ref( o.func ) \
template< typename O, std::enable_if_t<!std::is_reference<O>::value>* = nullptr > \
auto operator()( O&& o ) const return_decltype_rvalue_by_ref( tc_move(tc_move(o).func) ) \
}; \
std::true_type returns_reference_to_argument(dot_member_ ## func); /*mark as returning reference to argument*/ \
struct dot_mem_fn_ ## func { \
DEFINE_MEM_FN_BODY_( .func ) \
}; \
Expand Down Expand Up @@ -96,7 +96,6 @@ struct define_fn_dummy {};
DEFINE_FN2( std::max, fn_std_max );
DEFINE_FN2( std::min, fn_std_min );
DEFINE_FN2( std::abs, fn_std_abs );
template<typename T> DEFINE_FN2( T, fn_ctor );
DEFINE_FN2( operator delete, fn_operator_delete )

DEFINE_FN( first );
Expand All @@ -109,7 +108,7 @@ DEFINE_FN(emplace_back);
#define DEFINE_CAST_(name) \
template <typename To> \
struct fn_ ## name { \
template<typename From> auto operator()(From && from) const \
template<typename From> auto operator()(From&& from) const \
return_decltype( name <To>(std::forward<From>(from))) \
};

Expand All @@ -122,30 +121,30 @@ DEFINE_CAST_(const_cast)
namespace tc {
struct fn_subscript {
template<typename Lhs, typename Rhs>
auto operator()( Lhs && lhs, Rhs && rhs ) const
return_decltype( std::forward<Lhs>(lhs)[std::forward<Rhs>(rhs)] )
auto operator()( Lhs&& lhs, Rhs&& rhs ) const
return_decltype_rvalue_by_ref( std::forward<Lhs>(lhs)[std::forward<Rhs>(rhs)] )
};
}

struct fn_indirection {
template<typename Lhs>
auto operator()( Lhs && lhs ) const
return_decltype( *std::forward<Lhs>(lhs))
};
/* indirection operator, aka dereference operator */
struct fn_indirection {
template<typename Lhs>
auto operator()( Lhs&& lhs ) const
return_decltype_rvalue_by_ref( *std::forward<Lhs>(lhs))
};
std::true_type returns_reference_to_argument(fn_indirection); // mark as returning reference to argument

namespace tc {
struct fn_logical_not {
template<typename Lhs>
auto operator()( Lhs && lhs ) const
return_decltype( !std::forward<Lhs>(lhs))
auto operator()( Lhs&& lhs ) const
return_decltype_rvalue_by_ref( !std::forward<Lhs>(lhs))
};
}

#define INFIX_FN_( name, op ) \
struct fn_ ## name { \
template<typename Lhs, typename Rhs> \
auto operator()( Lhs && lhs, Rhs && rhs ) const \
return_decltype(std::forward<Lhs>(lhs) op std::forward<Rhs>(rhs)) \
auto operator()( Lhs&& lhs, Rhs&& rhs ) const \
return_decltype_rvalue_by_ref(std::forward<Lhs>(lhs) op std::forward<Rhs>(rhs)) \
};

INFIX_FN_( bit_or, | )
Expand Down
18 changes: 0 additions & 18 deletions Library/ErrorReporting/make_lvalue.h

This file was deleted.

103 changes: 85 additions & 18 deletions Library/ErrorReporting/storage_for.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
#ifndef RANGE_PROPOSAL_BUILD_STANDALONE
#include "assert_fwd.h"
#endif
#include "Library/Utilities/is_constructible.h"

#include <boost/implicit_cast.hpp>

Expand All @@ -12,48 +11,116 @@
namespace tc {

template< typename T >
class storage_for {
static_assert( std::is_same< typename std::remove_const<T>::type, typename std::decay<T>::type >::value, "only const allowed as qualification" );
typename std::aligned_storage<sizeof(T),std::alignment_of<T>::value>::type m_buffer;
struct storage_for_without_dtor : tc::nonmovable {
protected:
static_assert( tc::is_decayed< std::remove_const_t<T> >::value, "only const allowed as qualification" );
std::aligned_storage_t<sizeof(T),std::alignment_of<T>::value> m_buffer;
public:
typename std::remove_const<T>::type* uninitialized_addressof() {
return reinterpret_cast<typename std::remove_const<T>::type*>(&m_buffer);
std::remove_const_t<T>* uninitialized_addressof() noexcept {
return reinterpret_cast< std::remove_const_t<T>*>(&m_buffer);
}
void ctor() {
// This check is not strict enough. The following struct is !std::is_trivially_default_constructible,
// but ctor_default does not initialize n to 0, while ctor_value does:
// struct Foo {
// std::string n; // has user-defined default ctor
// std::string s; // has user-defined default ctor
// int n; // has no user-defined default ctor
// };
static_assert(!tc::is_trivially_default_constructible<T>::value, "You must decide between ctor_default and ctor_value!");
new (&m_buffer) T;
static_assert(!std::is_trivially_default_constructible<T>::value, "You must decide between ctor_default and ctor_value!");
::new (static_cast<void*>(&m_buffer)) T; // :: ensures that non-class scope operator new is used, cast to void* ensures that built-in placement new is used (18.6.1.3)
}
void ctor_default() {
new (&m_buffer) T;
::new (static_cast<void*>(&m_buffer)) T; // :: ensures that non-class scope operator new is used, cast to void* ensures that built-in placement new is used (18.6.1.3)
}
void ctor_value() {
new (&m_buffer) T();
::new (static_cast<void*>(&m_buffer)) T(); // :: ensures that non-class scope operator new is used, cast to void* ensures that built-in placement new is used (18.6.1.3)
}
template<typename First, typename... Args>
void ctor(First&& first, Args&&... args) {
new (&m_buffer) T(std::forward<First>(first),std::forward<Args>(args)...);
void ctor(First&& first, Args&& ... args) {
// In C++, new T(...) is direct initialization just like T t(...).
// For non-class types, only implicit conversions are considered, so it is equivalent to T t=...
// For class types, explicit conversions are considered, unlike for T t=...
::new (static_cast<void*>(&m_buffer)) T(std::forward<First>(first), std::forward<Args>(args)...); // :: ensures that non-class scope operator new is used, cast to void* ensures that built-in placement new is used (18.6.1.3)
}
operator T const&() const {
operator T const&() const noexcept {
static_assert( sizeof(*this)==sizeof(T), "" ); // no extra members, important for arrays
return reinterpret_cast<T const&>(m_buffer);
}
operator T &() {
operator T &() noexcept {
return tc::make_mutable(boost::implicit_cast<T const&>(tc::make_const(*this)));
}
T const* operator->() const {
T const* operator->() const noexcept {
return std::addressof(boost::implicit_cast<T const&>(*this));
}
T* operator->() {
T* operator->() noexcept {
return std::addressof(boost::implicit_cast<T&>(*this));
}
void dtor() const {
T const& operator*() const noexcept {
return boost::implicit_cast<T const&>(*this);
}
T& operator*() noexcept {
return boost::implicit_cast<T&>(*this);
}
void dtor() const noexcept {
boost::implicit_cast<T const&>(*this).~T();
}
};

template< typename T >
struct storage_for : storage_for_without_dtor <T> {
#if defined(_CHECKS) && !defined(RANGE_PROPOSAL_BUILD_STANDALONE)
storage_for() {
tc::fill_with_dead_pattern(this->m_buffer);
}
~storage_for() noexcept {
check_pattern();
}
void ctor() {
check_pattern();
try {
storage_for_without_dtor <T>::ctor();
} catch (...) {
tc::fill_with_dead_pattern(this->m_buffer);
throw;
}
}
void ctor_default() {
check_pattern();
try {
storage_for_without_dtor <T>::ctor_default();
} catch (...) {
tc::fill_with_dead_pattern(this->m_buffer);
throw;
}
}
void ctor_value() {
check_pattern();
try {
storage_for_without_dtor <T>::ctor_value();
} catch (...) {
tc::fill_with_dead_pattern(this->m_buffer);
throw;
}
}
template<typename First, typename... Args>
void ctor(First&& first, Args&& ... args) {
check_pattern();
try {
storage_for_without_dtor <T>::ctor(std::forward<First>(first), std::forward<Args>(args)...);
} catch (...) {
tc::fill_with_dead_pattern(this->m_buffer);
throw;
}
}
void dtor() const noexcept {
storage_for_without_dtor <T>::dtor();
tc::fill_with_dead_pattern(tc::make_mutable(this->m_buffer));
}

private:
void check_pattern() const noexcept {
tc::assert_dead_pattern(this->m_buffer);
}
#endif
};
}
15 changes: 8 additions & 7 deletions Library/ErrorReporting/tc_move.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,26 @@
// safer variants of std::move

template<typename T>
T&& tc_move_impl(typename std::remove_reference<T>::type& t) {
T&& tc_move_impl(std::remove_reference_t<T>& t) {
static_assert(!std::is_lvalue_reference<T>::value, "");
static_assert(!std::is_const<typename std::remove_reference<T>::type>::value, "");
static_assert(!std::is_const<std::remove_reference_t<T>>::value, "");
return static_cast<T&&>(t);
}

template<typename T>
T&& tc_move_impl(typename std::remove_reference<T>::type&& t) {
T&& tc_move_impl(std::remove_reference_t<T>&& t) {
static_assert(!std::is_lvalue_reference<T>::value, "");
static_assert(!std::is_const<typename std::remove_reference<T>::type>::value, "");
static_assert(!std::is_const<std::remove_reference_t<T>>::value, "");
// TODO: static_assert(std::is_nothrow_move_constructible<std::remove_reference_t<T>>::value, "" );
return static_cast<T&&>(t);
}

#define tc_move(t) tc_move_impl<decltype(t)>(t)
#define tc_move_if_owned(t) std::forward<decltype(t)>(t)

template<typename T>
typename std::remove_reference<T>::type&& tc_move_always(T&& t) { // same as std::move, but asserts on non-constness of argument
static_assert(!std::is_const<typename std::remove_reference<T>::type>::value, "");
return static_cast<typename std::remove_reference<T>::type&&>(t);
std::remove_reference_t<T>&& tc_move_always(T&& t) { // same as std::move, but asserts on non-constness of argument
static_assert(!std::is_const<std::remove_reference_t<T>>::value, "");
return static_cast<std::remove_reference_t<T>&&>(t);
}

Loading

0 comments on commit 262fb81

Please sign in to comment.