Merge pull request #66 from boostorg/feature/value-init

Add a new value_init test, change implementation to not depend on TypeTraits
This commit is contained in:
Andrey Semashev 2020-05-27 12:51:45 +03:00 committed by GitHub
commit a4feaf4f24
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 244 additions and 70 deletions

View File

@ -1,4 +1,5 @@
// (C) Copyright 2002-2008, Fernando Luis Cacciola Carballal.
// Copyright 2020 Peter Dimov
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@ -21,15 +22,10 @@
// issues, by clearing the bytes of T, before constructing the T object it
// contains. More details on these issues are at libs/utility/value_init.htm
#include <boost/aligned_storage.hpp>
#include <boost/config.hpp> // For BOOST_NO_COMPLETE_VALUE_INITIALIZATION.
#include <boost/detail/workaround.hpp>
#include <boost/static_assert.hpp>
#include <boost/type_traits/cv_traits.hpp>
#include <boost/type_traits/alignment_of.hpp>
#include <boost/swap.hpp>
#include <cstring>
#include <new>
#include <cstddef>
#ifdef BOOST_MSVC
#pragma warning(push)
@ -60,92 +56,58 @@
namespace boost {
namespace detail {
struct zero_init
{
zero_init()
{
}
zero_init( void * p, std::size_t n )
{
std::memset( p, 0, n );
}
};
} // namespace detail
template<class T>
class initialized
#if BOOST_DETAIL_VALUE_INIT_WORKAROUND
: detail::zero_init
#endif
{
private :
struct wrapper
{
#if !BOOST_WORKAROUND(BOOST_BORLANDC, BOOST_TESTED_AT(0x592))
typename
#endif
remove_const<T>::type data;
private:
BOOST_GPU_ENABLED
wrapper()
:
data()
{
}
BOOST_GPU_ENABLED
wrapper(T const & arg)
:
data(arg)
{
}
};
mutable
#if !BOOST_WORKAROUND(BOOST_BORLANDC, BOOST_TESTED_AT(0x592))
typename
#endif
aligned_storage<sizeof(wrapper), alignment_of<wrapper>::value>::type x;
BOOST_GPU_ENABLED
wrapper * wrapper_address() const
{
return static_cast<wrapper *>( static_cast<void*>(&x));
}
T data_;
public :
BOOST_GPU_ENABLED
initialized()
{
initialized():
#if BOOST_DETAIL_VALUE_INIT_WORKAROUND
std::memset(&x, 0, sizeof(x));
zero_init( &const_cast< char& >( reinterpret_cast<char const volatile&>( data_ ) ), sizeof( data_ ) ),
#endif
new (wrapper_address()) wrapper();
data_()
{
}
BOOST_GPU_ENABLED
initialized(initialized const & arg)
explicit initialized(T const & arg): data_( arg )
{
new (wrapper_address()) wrapper( static_cast<wrapper const &>(*(arg.wrapper_address())));
}
BOOST_GPU_ENABLED
explicit initialized(T const & arg)
{
new (wrapper_address()) wrapper(arg);
}
BOOST_GPU_ENABLED
initialized & operator=(initialized const & arg)
{
// Assignment is only allowed when T is non-const.
BOOST_STATIC_ASSERT( ! is_const<T>::value );
*wrapper_address() = static_cast<wrapper const &>(*(arg.wrapper_address()));
return *this;
}
BOOST_GPU_ENABLED
~initialized()
{
wrapper_address()->wrapper::~wrapper();
}
BOOST_GPU_ENABLED
T const & data() const
{
return wrapper_address()->data;
return data_;
}
BOOST_GPU_ENABLED
T& data()
{
return wrapper_address()->data;
return data_;
}
BOOST_GPU_ENABLED
@ -157,13 +119,13 @@ class initialized
BOOST_GPU_ENABLED
operator T const &() const
{
return wrapper_address()->data;
return data_;
}
BOOST_GPU_ENABLED
operator T&()
{
return wrapper_address()->data;
return data_;
}
} ;

View File

@ -36,6 +36,8 @@ run string_view_test2.cpp ;
run string_view_test_io.cpp ;
run value_init_test.cpp ;
run value_init_test2.cpp ;
run value_init_test3.cpp ;
run value_init_workaround_test.cpp ;
run initialized_test.cpp ;
compile-fail value_init_test_fail1.cpp ;

View File

@ -22,6 +22,7 @@
#endif
#include <boost/core/lightweight_test.hpp>
#include <boost/config/workaround.hpp>
//
// Sample POD type

169
test/value_init_test2.cpp Normal file
View File

@ -0,0 +1,169 @@
// Copyright 2010, Niels Dekker.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// Test program for the boost::value_initialized<T> workaround.
//
// 17 June 2010 (Created) Niels Dekker
#include <boost/utility/value_init.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/config/workaround.hpp>
#include <iostream>
namespace
{
struct empty_struct
{
};
// A POD aggregate struct derived from an empty struct.
// Similar to struct Foo1 from Microsoft Visual C++ bug report 484295,
// "VC++ does not value-initialize members of derived classes without
// user-declared constructor", reported in 2009 by Sylvester Hesp:
// https://connect.microsoft.com/VisualStudio/feedback/details/484295
struct derived_struct: empty_struct
{
int data;
};
bool is_value_initialized(const derived_struct& arg)
{
return arg.data == 0;
}
class virtual_destructor_holder
{
public:
int i;
virtual ~virtual_destructor_holder()
{
}
};
bool is_value_initialized(const virtual_destructor_holder& arg)
{
return arg.i == 0;
}
// Equivalent to the Stats class from GCC Bug 33916,
// "Default constructor fails to initialize array members", reported in 2007 by
// Michael Elizabeth Chastain: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=33916
// and fixed for GCC 4.2.4.
class private_int_array_pair
{
friend bool is_value_initialized(const private_int_array_pair& arg);
private:
int first[12];
int second[12];
};
bool is_value_initialized(const private_int_array_pair& arg)
{
for ( unsigned i = 0; i < 12; ++i)
{
if ( (arg.first[i] != 0) || (arg.second[i] != 0) )
{
return false;
}
}
return true;
}
struct int_pair_struct
{
int first;
int second;
};
typedef int int_pair_struct::*ptr_to_member_type;
struct ptr_to_member_struct
{
ptr_to_member_type data;
};
bool is_value_initialized(const ptr_to_member_struct& arg)
{
return arg.data == 0;
}
template <typename T>
bool is_value_initialized(const T(& arg)[2])
{
return
is_value_initialized(arg[0]) &&
is_value_initialized(arg[1]);
}
template <typename T>
bool is_value_initialized(const boost::value_initialized<T>& arg)
{
return is_value_initialized(arg.data());
}
// Returns zero when the specified object is value-initializated, and one otherwise.
// Prints a message to standard output if the value-initialization has failed.
template <class T>
unsigned failed_to_value_initialized(const T& object, const char *const object_name)
{
if ( is_value_initialized(object) )
{
return 0u;
}
else
{
std::cout << "Note: Failed to value-initialize " << object_name << '.' << std::endl;
return 1u;
}
}
// A macro that passed both the name and the value of the specified object to
// the function above here.
#define FAILED_TO_VALUE_INITIALIZE(value) failed_to_value_initialized(value, #value)
// Equivalent to the dirty_stack() function from GCC Bug 33916,
// "Default constructor fails to initialize array members", reported in 2007 by
// Michael Elizabeth Chastain: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=33916
void dirty_stack()
{
unsigned char array_on_stack[4096];
for (unsigned i = 0; i < sizeof(array_on_stack); ++i)
{
array_on_stack[i] = 0x11;
}
}
}
int main()
{
#ifdef BOOST_DETAIL_VALUE_INIT_WORKAROUND_SUGGESTED
std::cout << "BOOST_DETAIL_VALUE_INIT_WORKAROUND_SUGGESTED is defined.\n\n";
#endif
dirty_stack();
BOOST_TEST( is_value_initialized( boost::value_initialized<derived_struct>() ) );
BOOST_TEST( is_value_initialized( boost::value_initialized<virtual_destructor_holder[2]>() ) );
BOOST_TEST( is_value_initialized( boost::value_initialized<private_int_array_pair>() ) );
#if !BOOST_WORKAROUND( BOOST_MSVC, BOOST_TESTED_AT(1925) )
// Null pointers to data members are represented as -1 in MSVC, but
// value initialization sets them to all zero. The workaround employed
// by value_initialized<> is to memset the storage to all zero, which
// doesn't help.
BOOST_TEST( is_value_initialized( boost::value_initialized<ptr_to_member_struct>() ) );
#endif
return boost::report_errors();
}

40
test/value_init_test3.cpp Normal file
View File

@ -0,0 +1,40 @@
// Copyright 2020 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt)
#include <boost/utility/value_init.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/config.hpp>
#include <boost/config/pragma_message.hpp>
#if __cplusplus >= 201103L || ( defined(BOOST_MSVC) && BOOST_MSVC >= 1900 )
struct X
{
int a;
char b;
};
struct Y: boost::value_initialized<X>
{
char c = 42;
};
int main()
{
Y y;
BOOST_TEST_EQ( y.data().a, 0 );
BOOST_TEST_EQ( y.data().b, 0 );
BOOST_TEST_EQ( y.c, 42 );
return boost::report_errors();
}
#else
BOOST_PRAGMA_MESSAGE( "Skipping test because compiler doesn't support in-class member initializers" )
int main() {}
#endif