mirror of
https://github.com/wesnoth/wesnoth
synced 2025-04-27 21:01:30 +00:00
Add a way to add a copy policy to an existing class with minimal changes.
This commit is contained in:
parent
e5756e7b68
commit
5da72257c6
@ -22,7 +22,12 @@
|
||||
* operator which does a shallow copy and then call copy() (copy() test for self
|
||||
* assignment, but the assignment operator can also do the test.
|
||||
*
|
||||
* See tests/test_policy.cpp for an example implementation of this policy.
|
||||
* Another option is to use the tcopy_policy class, which uses the default
|
||||
* constructor, copy constructor and assignment operator of the class. This way
|
||||
* it can easily be added to an existing class without changes.
|
||||
*
|
||||
* See tests/test_policy.cpp for an example implementation of this policy, both
|
||||
* the intrusive and non-intrusive version.
|
||||
*/
|
||||
|
||||
#ifndef COPY_POLICY_HPP_INCLUDED
|
||||
@ -151,6 +156,53 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper class to add a policy to an existing class.
|
||||
*
|
||||
* This
|
||||
*/
|
||||
template <
|
||||
class base,
|
||||
template<class> class copy_policy
|
||||
>
|
||||
struct tcopy_policy : public base, public copy_policy<tcopy_policy<base, copy_policy> >
|
||||
{
|
||||
typedef copy_policy<tcopy_policy<base, copy_policy> > policy;
|
||||
typedef typename tcopy_policy<base, copy_policy>::rhs_type rhs_type;
|
||||
|
||||
tcopy_policy()
|
||||
: base()
|
||||
, policy()
|
||||
{
|
||||
#if COPY_POLICY_DEBUG
|
||||
std::cerr << "tcopy_policy: default constructor.\n";
|
||||
#endif
|
||||
}
|
||||
|
||||
tcopy_policy(rhs_type rhs)
|
||||
: base(rhs)
|
||||
, policy(rhs)
|
||||
{
|
||||
#if COPY_POLICY_DEBUG
|
||||
std::cerr << "tcopy_policy: copy constructor.\n";
|
||||
#endif
|
||||
copy(rhs);
|
||||
}
|
||||
|
||||
tcopy_policy& operator=(rhs_type rhs)
|
||||
{
|
||||
#if COPY_POLICY_DEBUG
|
||||
std::cerr << "tcopy_policy: assignment operator.\n";
|
||||
#endif
|
||||
static_cast<base>(*this) = rhs;
|
||||
static_cast<policy>(*this) = rhs;
|
||||
|
||||
copy(rhs);
|
||||
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace policy
|
||||
|
||||
#endif
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
#include "copy_policy.hpp"
|
||||
|
||||
|
||||
/** Set to 1 if you want debug output to std::cerr. */
|
||||
#define TEST_POLICY_DEBUG 0
|
||||
|
||||
@ -25,7 +26,8 @@
|
||||
|
||||
BOOST_AUTO_TEST_SUITE( policy )
|
||||
|
||||
namespace {
|
||||
|
||||
namespace intrusive {
|
||||
|
||||
/** Class to test the copy policies. */
|
||||
template <template<class> class copy_policy >
|
||||
@ -176,7 +178,129 @@ void test(const bool orig_invalidated, const bool copy_cloned)
|
||||
assign_test<T>(orig_invalidated, copy_cloned);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace intrusive
|
||||
|
||||
namespace non_intrusive {
|
||||
|
||||
struct ttest
|
||||
{
|
||||
ttest()
|
||||
: cloned_(false)
|
||||
, invalidated_(false)
|
||||
{
|
||||
#if TEST_POLICY_DEBUG
|
||||
std::cerr << "Default constructor " << __func__ << ".\n";
|
||||
#endif
|
||||
}
|
||||
|
||||
#if TEST_POLICY_DEBUG
|
||||
|
||||
ttest(const ttest& rhs)
|
||||
: cloned_(rhs.cloned_)
|
||||
, invalidated_(rhs.invalidated_)
|
||||
{
|
||||
std::cerr << "Copy constructor " << __func__ << ".\n";
|
||||
}
|
||||
|
||||
ttest& operator=(const ttest& rhs)
|
||||
{
|
||||
std::cerr << "Assign operator " << __func__ << ".\n";
|
||||
|
||||
cloned_ = rhs.cloned_;
|
||||
invalidated_ = rhs.invalidated_;
|
||||
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
/** Mandatory helper for the tmove_copy policy. */
|
||||
void invalidate() { invalidated_ = true; }
|
||||
|
||||
/** Mandatory helper for the tdeep_copy policy. */
|
||||
void clone() { cloned_ = true; }
|
||||
|
||||
/** A group helper variables */
|
||||
bool cloned_, invalidated_;
|
||||
};
|
||||
|
||||
// Not really required but doesn't hurt.
|
||||
#if TEST_POLICY_DEBUG
|
||||
static std::ostream& operator<<(std::ostream &s, const ttest& test)
|
||||
{
|
||||
s << "cloned_ " << test.cloned_
|
||||
<< " invalidated_ " << test.invalidated_
|
||||
;
|
||||
|
||||
return s;
|
||||
}
|
||||
#endif
|
||||
|
||||
/** Tests the copy constructor of the policy. */
|
||||
template<class T, template<class >class U>
|
||||
void copy_test(const bool orig_invalidated, const bool copy_cloned)
|
||||
{
|
||||
#if TEST_POLICY_DEBUG
|
||||
std::cerr << __func__ << ".\n";
|
||||
#endif
|
||||
|
||||
policies::tcopy_policy<T, U> orig;
|
||||
policies::tcopy_policy<T, U> cpy(orig);
|
||||
|
||||
#if TEST_POLICY_DEBUG
|
||||
std::cerr << "orig " << orig
|
||||
<< "\ncopy " << cpy
|
||||
<< ".\n";
|
||||
#endif
|
||||
|
||||
BOOST_REQUIRE_EQUAL(orig.cloned_, false);
|
||||
BOOST_REQUIRE_EQUAL(orig.invalidated_, orig_invalidated);
|
||||
|
||||
BOOST_REQUIRE_EQUAL(cpy.cloned_, copy_cloned);
|
||||
BOOST_REQUIRE_EQUAL(cpy.invalidated_, false);
|
||||
}
|
||||
|
||||
/** Tests the assignment operator of the policy. */
|
||||
template<class T, template<class >class U>
|
||||
void assign_test(const bool orig_invalidated, const bool copy_cloned)
|
||||
{
|
||||
#if TEST_POLICY_DEBUG
|
||||
std::cerr << __func__ << ".\n";
|
||||
#endif
|
||||
policies::tcopy_policy<T, U> orig;
|
||||
policies::tcopy_policy<T, U> cpy;
|
||||
|
||||
cpy = orig;
|
||||
|
||||
#if TEST_POLICY_DEBUG
|
||||
std::cerr << "orig " << orig
|
||||
<< "\ncopy " << cpy
|
||||
<< ".\n";
|
||||
#endif
|
||||
|
||||
BOOST_REQUIRE_EQUAL(orig.cloned_, false);
|
||||
BOOST_REQUIRE_EQUAL(orig.invalidated_, orig_invalidated);
|
||||
|
||||
BOOST_REQUIRE_EQUAL(cpy.cloned_, copy_cloned);
|
||||
BOOST_REQUIRE_EQUAL(cpy.invalidated_, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests a policy.
|
||||
*
|
||||
* @param orig_invalidated Should the original object be invalidated when
|
||||
* used as rhs in an assignment or as parameter
|
||||
* in a copy constructor.
|
||||
* @param copy_cloned Should the copy be cloned when use as lhs in
|
||||
* an assignment or when being copy constructed.
|
||||
*/
|
||||
template<class T, template<class >class U>
|
||||
void test(const bool orig_invalidated, const bool copy_cloned)
|
||||
{
|
||||
copy_test<T, U>(orig_invalidated, copy_cloned);
|
||||
assign_test<T, U>(orig_invalidated, copy_cloned);
|
||||
}
|
||||
|
||||
} // namespace non_intrusive
|
||||
|
||||
BOOST_AUTO_TEST_CASE( test_copy_policy )
|
||||
{
|
||||
@ -184,18 +308,18 @@ BOOST_AUTO_TEST_CASE( test_copy_policy )
|
||||
* The no copy policy shouldn't compile so it's commented out. The first part
|
||||
* enables the basics and can also test whether the compiler does a RVO [1],
|
||||
* if the compiler does the copy1 can be constructed. The second part should
|
||||
* always fail.
|
||||
* always fail. (The non intrusive version is not added here.)
|
||||
*
|
||||
* [1] http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.9
|
||||
*/
|
||||
#if 0
|
||||
ttest<policies::tno_copy> orig;
|
||||
intrusive::ttest<policies::tno_copy> orig;
|
||||
|
||||
// Might or might not compile.
|
||||
ttest<policies::tno_copy> copy1(ttest<policies::tno_copy>());
|
||||
intrusive::ttest<policies::tno_copy> copy1(ttest<policies::tno_copy>());
|
||||
#if 0
|
||||
// Must fail to compile.
|
||||
ttest<policies::tno_copy> copy2(orig);
|
||||
intrusive::ttest<policies::tno_copy> copy2(orig);
|
||||
|
||||
// Must fail to compile.
|
||||
orig = orig;
|
||||
@ -206,20 +330,40 @@ BOOST_AUTO_TEST_CASE( test_copy_policy )
|
||||
std::cerr << std::boolalpha;
|
||||
#endif
|
||||
|
||||
#if TEST_POLICY_DEBUG
|
||||
std::cerr << "Test shallow copy\n";
|
||||
#endif
|
||||
test<policies::tshallow_copy>(false, false);
|
||||
/* Intrusive tests */
|
||||
|
||||
#if TEST_POLICY_DEBUG
|
||||
std::cerr << "\n\nTest deep copy\n";
|
||||
std::cerr << "Test intrusive shallow copy\n";
|
||||
#endif
|
||||
test<policies::tdeep_copy>(false, true);
|
||||
intrusive::test<policies::tshallow_copy>(false, false);
|
||||
|
||||
#if TEST_POLICY_DEBUG
|
||||
std::cerr << "\n\nTest move copy\n";
|
||||
std::cerr << "\n\nTest intrusive deep copy\n";
|
||||
#endif
|
||||
test<policies::tmove_copy>(true, false);
|
||||
intrusive::test<policies::tdeep_copy>(false, true);
|
||||
|
||||
#if TEST_POLICY_DEBUG
|
||||
std::cerr << "\n\nTest intrusive move copy\n";
|
||||
#endif
|
||||
intrusive::test<policies::tmove_copy>(true, false);
|
||||
|
||||
/* Non-intrusive tests */
|
||||
|
||||
#if TEST_POLICY_DEBUG
|
||||
std::cerr << "Test non-intrusive shallow copy\n";
|
||||
#endif
|
||||
non_intrusive::test<non_intrusive::ttest, policies::tshallow_copy>(false, false);
|
||||
|
||||
#if TEST_POLICY_DEBUG
|
||||
std::cerr << "\n\nTest non-intrusive deep copy\n";
|
||||
#endif
|
||||
non_intrusive::test<non_intrusive::ttest, policies::tdeep_copy>(false, true);
|
||||
|
||||
#if TEST_POLICY_DEBUG
|
||||
std::cerr << "\n\nTest non-intrusive move copy\n";
|
||||
#endif
|
||||
non_intrusive::test<non_intrusive::ttest, policies::tmove_copy>(true, false);
|
||||
|
||||
}
|
||||
|
||||
/* vim: set ts=4 sw=4: */
|
||||
|
Loading…
x
Reference in New Issue
Block a user