add operator== to Functor, initiated by Eric Beyeler

git-svn-id: svn://svn.code.sf.net/p/loki-lib/code/trunk@662 7ec92016-0320-0410-acc4-a06ded1c099a
This commit is contained in:
syntheticpp 2006-06-01 12:33:05 +00:00
parent c272535c72
commit 50d35c6196
2 changed files with 244 additions and 12 deletions

View file

@ -34,6 +34,12 @@
//#define LOKI_FUNCTOR_IS_NOT_A_SMALLOBJECT //#define LOKI_FUNCTOR_IS_NOT_A_SMALLOBJECT
#endif #endif
#ifndef LOKI_FUNCTORS_ARE_COMPARABLE
//#define LOKI_FUNCTORS_ARE_COMPARABLE
#endif
//#define LOKI_FUNCTOR_DEBUG
/// \namespace Loki /// \namespace Loki
/// All classes of Loki are in the Loki namespace /// All classes of Loki are in the Loki namespace
namespace Loki namespace Loki
@ -58,6 +64,7 @@ namespace Loki
#endif #endif
typedef R ResultType; typedef R ResultType;
typedef FunctorImplBase<R, ThreadingModel> FunctorImplBaseType;
typedef EmptyType Parm1; typedef EmptyType Parm1;
typedef EmptyType Parm2; typedef EmptyType Parm2;
@ -85,10 +92,25 @@ namespace Loki
static U* Clone(U* pObj) static U* Clone(U* pObj)
{ {
if (!pObj) return 0; if (!pObj) return 0;
#ifdef LOKI_FUNCTOR_DEBUG
U* pClone = dynamic_cast<U*>(pObj->DoClone());
#else
U* pClone = static_cast<U*>(pObj->DoClone()); U* pClone = static_cast<U*>(pObj->DoClone());
#endif
assert(typeid(*pClone) == typeid(*pObj)); assert(typeid(*pClone) == typeid(*pObj));
return pClone; return pClone;
} }
#ifdef LOKI_FUNCTORS_ARE_COMPARABLE
virtual bool operator==(const FunctorImplBase&) const = 0;
// there is no static information if Functor holds a member function
// or a free function; this is the main difference to tr1::function
virtual bool isMemberFuncPtr() const = 0;
#endif
}; };
} }
@ -936,6 +958,28 @@ namespace Loki
LOKI_DEFINE_CLONE_FUNCTORIMPL(FunctorHandler) LOKI_DEFINE_CLONE_FUNCTORIMPL(FunctorHandler)
#ifdef LOKI_FUNCTORS_ARE_COMPARABLE
bool isMemberFuncPtr() const
{
return false;
}
bool operator==(const typename Base::FunctorImplBaseType& rhs) const
{
if( rhs.isMemberFuncPtr() )
return false; // cannot be equal
#ifdef LOKI_FUNCTOR_DEBUG
const FunctorHandler& fh = dynamic_cast<const FunctorHandler&>(rhs);
#else
const FunctorHandler& fh = static_cast<const FunctorHandler&>(rhs);
#endif
// if this line gives a compiler error, you are using a function object.
// you need to implement bool MyFnObj::operator == (const MyFnObj&) const;
return f_==fh.f_;
}
#endif
// operator() implementations for up to 15 arguments // operator() implementations for up to 15 arguments
ResultType operator()() ResultType operator()()
@ -1045,6 +1089,30 @@ namespace Loki
LOKI_DEFINE_CLONE_FUNCTORIMPL(MemFunHandler) LOKI_DEFINE_CLONE_FUNCTORIMPL(MemFunHandler)
#ifdef LOKI_FUNCTORS_ARE_COMPARABLE
bool isMemberFuncPtr() const
{
return true;
}
bool operator==(const typename Base::FunctorImplBaseType& rhs) const
{
if(!rhs.isMemberFuncPtr())
return false;
#ifdef LOKI_FUNCTOR_DEBUG
const MemFunHandler& mfh = dynamic_cast<const MemFunHandler&>(rhs);
#else
const MemFunHandler& mfh = static_cast<const MemFunHandler&>(rhs);
#endif
// if this line gives a compiler error, you are using a function object.
// you need to implement bool MyFnObj::operator == (const MyFnObj&) const;
return pObj_==mfh.pObj_ && pMemFn_==mfh.pMemFn_;
}
#endif
ResultType operator()() ResultType operator()()
{ return ((*pObj_).*pMemFn_)(); } { return ((*pObj_).*pMemFn_)(); }
@ -1162,6 +1230,13 @@ namespace Loki
/// It often helps against crashes when using static Functors and multi threading. /// It often helps against crashes when using static Functors and multi threading.
/// Defining also removes problems when unloading Dlls which hosts /// Defining also removes problems when unloading Dlls which hosts
/// static Functor objects. /// static Functor objects.
///
/// \par Macro: LOKI_FUNCTORS_ARE_COMPARABLE
/// To enable the operator== define the macro
/// \code LOKI_FUNCTORS_ARE_COMPARABLE \endcode
/// The macro is disabled by default, because it breaks compiling functor
/// objects which have no operator== implemented, keep in mind when you enable
/// operator==.
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
template <typename R = void, class TList = NullType, template <typename R = void, class TList = NullType,
template<class, class> class ThreadingModel = LOKI_DEFAULT_THREADING_NO_OBJ_LEVEL> template<class, class> class ThreadingModel = LOKI_DEFAULT_THREADING_NO_OBJ_LEVEL>
@ -1239,6 +1314,34 @@ namespace Loki
} }
#endif #endif
#ifdef LOKI_FUNCTORS_ARE_COMPARABLE
bool isMemberFuncPtr() const
{
if(spImpl_.get()!=0)
return spImpl_.get()->isMemberFuncPtr();
else
return false;
}
bool operator==(const Functor& rhs) const
{
if(spImpl_.get()==0 && rhs.spImpl_.get()==0)
return true;
if(spImpl_.get()!=0 && rhs.spImpl_.get()!=0)
return *spImpl_.get() == *rhs.spImpl_.get();
else
return false;
}
bool operator!=(const Functor& rhs) const
{
return !(*this==rhs);
}
#endif
// operator() implementations for up to 15 arguments
ResultType operator()() const ResultType operator()() const
{ {
LOKI_FUNCTION_THROW_BAD_FUNCTION_CALL LOKI_FUNCTION_THROW_BAD_FUNCTION_CALL
@ -1357,6 +1460,13 @@ namespace Loki
std::auto_ptr<Impl> spImpl_; std::auto_ptr<Impl> spImpl_;
}; };
////////////////////////////////////////////////////////////////////////////////
//
// BindersFirst and Chainer
//
////////////////////////////////////////////////////////////////////////////////
namespace Private namespace Private
{ {
template <class Fctor> struct BinderFirstTraits; template <class Fctor> struct BinderFirstTraits;
@ -1444,6 +1554,29 @@ namespace Loki
LOKI_DEFINE_CLONE_FUNCTORIMPL(BinderFirst) LOKI_DEFINE_CLONE_FUNCTORIMPL(BinderFirst)
#ifdef LOKI_FUNCTORS_ARE_COMPARABLE
bool isMemberFuncPtr() const
{
return f_.isMemberFuncPtr();
}
bool operator==(const typename Base::FunctorImplBaseType& rhs) const
{
isMemberFuncPtr();
// if this line gives a compiler error, you are using a function object.
// you need to implement bool MyFnObj::operator == (const MyFnObj&) const;
#ifdef LOKI_FUNCTOR_DEBUG
return f_ == ((dynamic_cast<const BinderFirst&> (rhs)).f_) &&
b_ == ((dynamic_cast<const BinderFirst&> (rhs)).b_);
#else
return f_ == ((static_cast<const BinderFirst&> (rhs)).f_) &&
b_ == ((static_cast<const BinderFirst&> (rhs)).b_);
#endif
}
#endif
// operator() implementations for up to 15 arguments // operator() implementations for up to 15 arguments
ResultType operator()() ResultType operator()()
@ -1563,6 +1696,29 @@ namespace Loki
LOKI_DEFINE_CLONE_FUNCTORIMPL(Chainer) LOKI_DEFINE_CLONE_FUNCTORIMPL(Chainer)
#ifdef LOKI_FUNCTORS_ARE_COMPARABLE
bool isMemberFuncPtr() const
{
assert(0);
return false;
}
bool operator==(const typename Base::Impl::FunctorImplBaseType& rhs) const
{
// if this line gives a compiler error, you are using a function object.
// you need to implement bool MyFnObj::operator == (const MyFnObj&) const;
#ifdef LOKI_FUNCTOR_DEBUG
return f1_ == ((dynamic_cast<const Chainer&> (rhs)).f2_) &&
f2_ == ((dynamic_cast<const Chainer&> (rhs)).f1_);
#else
return f1_ == ((static_cast<const Chainer&> (rhs)).f2_) &&
f2_ == ((static_cast<const Chainer&> (rhs)).f1_);
#endif
}
#endif
// operator() implementations for up to 15 arguments // operator() implementations for up to 15 arguments
ResultType operator()() ResultType operator()()
@ -1689,6 +1845,9 @@ namespace Loki
#endif // FUNCTOR_INC_ #endif // FUNCTOR_INC_
// $Log$ // $Log$
// Revision 1.21 2006/06/01 12:33:05 syntheticpp
// add operator== to Functor, initiated by Eric Beyeler
//
// Revision 1.20 2006/05/20 10:23:07 syntheticpp // Revision 1.20 2006/05/20 10:23:07 syntheticpp
// add warnings in the documentation about the special lifetime when using SmallObjects // add warnings in the documentation about the special lifetime when using SmallObjects
// //

View file

@ -2,16 +2,18 @@
// Unit Test for Loki // Unit Test for Loki
// //
// Copyright Terje Slettebø and Pavel Vozenilek 2002. // Copyright Terje Slettebø and Pavel Vozenilek 2002.
// // Copyright Peter Kümmel, 2006
// Permission to use, copy, modify, and distribute this software for any // Permission to use, copy, modify, and distribute this software for any
// purpose is hereby granted without fee, provided that this copyright and // purpose is hereby granted without fee, provided that this copyright and
// permissions notice appear in all copies and derivatives. // permissions notice appear in all copies and derivatives.
// //
// This software is provided "as is" without express or implied warranty. // This software is provided "as is" without express or implied warranty.
// //
// Last update: September 16, 2002
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// $Header:
#ifndef FUNCTORTEST_H #ifndef FUNCTORTEST_H
#define FUNCTORTEST_H #define FUNCTORTEST_H
@ -21,6 +23,11 @@
// FunctorTest // FunctorTest
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
void free_function(bool &result)
{
result=true;
}
class FunctorTest : public Test class FunctorTest : public Test
{ {
public: public:
@ -40,16 +47,33 @@ public:
#ifndef LOKI_DISABLE_TYPELIST_MACROS #ifndef LOKI_DISABLE_TYPELIST_MACROS
Functor<void,LOKI_TYPELIST_1(bool &)> function(testFunction); Functor<void,LOKI_TYPELIST_1(bool &)> function(testFunction);
Functor<void,LOKI_TYPELIST_1(bool &)> function2(testFunction);
Functor<void,LOKI_TYPELIST_1(bool &)> functor(testFunctor); Functor<void,LOKI_TYPELIST_1(bool &)> functor(testFunctor);
Functor<void,LOKI_TYPELIST_1(bool &)> functor2(testFunctor);
Functor<void,LOKI_TYPELIST_1(bool &)> classFunctor(&testClass,&TestClass::member); Functor<void,LOKI_TYPELIST_1(bool &)> classFunctor(&testClass,&TestClass::member);
Functor<void,LOKI_TYPELIST_1(bool &)> classFunctor2(&testClass,&TestClass::member);
Functor<void,LOKI_TYPELIST_1(bool &)> functorCopy(function); Functor<void,LOKI_TYPELIST_1(bool &)> functorCopy(function);
Functor<void,LOKI_TYPELIST_1(bool &)> functorCopy2(function);
Functor<void,NullType> bindFunctor(BindFirst(function,testResult)); Functor<void,NullType> bindFunctor(BindFirst(function,testResult));
Functor<void,NullType> bindFunctor2(BindFirst(function,testResult));
Functor<void> chainFunctor(Chain(bindFunctor,bindFunctor)); Functor<void> chainFunctor(Chain(bindFunctor,bindFunctor));
Functor<void> chainFunctor2(Chain(bindFunctor,bindFunctor));
Functor<void,LOKI_TYPELIST_1(bool &)> member_func(&testClass,&TestClass::member);
Functor<void,LOKI_TYPELIST_1(bool &)> free_func(&free_function);
Functor<void,LOKI_TYPELIST_1(bool &)> NULL_func;
Functor<void,LOKI_TYPELIST_1(bool &)> NULL_func0;
#else #else
Functor<void,Seq<bool &> > function(testFunction); Functor<void,Seq<bool &> > function(testFunction);
Functor<void,Seq<bool &> > function2(testFunction);
Functor<void,Seq<bool &> > functor(testFunctor); Functor<void,Seq<bool &> > functor(testFunctor);
Functor<void,Seq<bool &> > functor2(testFunctor);
Functor<void,Seq<bool &> > classFunctor(&testClass,&TestClass::member); Functor<void,Seq<bool &> > classFunctor(&testClass,&TestClass::member);
Functor<void,Seq<bool &> > classFunctor2(&testClass,&TestClass::member);
Functor<void,Seq<bool &> > functorCopy(function); Functor<void,Seq<bool &> > functorCopy(function);
Functor<void,Seq<bool &> > functorCopy2(function);
//TODO: //TODO:
//Functor<void,NullType> bindFunctor(BindFirst(function,testResult)); //Functor<void,NullType> bindFunctor(BindFirst(function,testResult));
//Functor<void> chainFunctor(Chain(bindFunctor,bindFunctor)); //Functor<void> chainFunctor(Chain(bindFunctor,bindFunctor));
@ -71,7 +95,52 @@ public:
functorCopy(testResult); functorCopy(testResult);
bool functorCopyResult=testResult; bool functorCopyResult=testResult;
#ifdef LOKI_FUNCTORS_ARE_COMPARABLE
bool functionCompare = function==function2;
bool functorCompare = functor!=functor2; // is this a bug?
bool classFunctorCompare = classFunctor==classFunctor2;
bool functorCopyCompare = functorCopy==functorCopy2;
bool free_mem = free_func!=member_func;
bool mem_free = member_func!=free_func;
bool null0 = NULL_func == NULL_func0;
bool null1 = NULL_func != free_func;
bool null2 = NULL_func != member_func;
bool null3 = free_func != NULL_func;
bool null4 = member_func != NULL_func;
#ifdef LOKI_DISABLE_TYPELIST_MACROS
bool bindFunctorCompare = bindFunctor==bindFunctor2;
bool chainFunctorCompare = chainFunctor==chainFunctor2;
#endif
bool compare = functionCompare &&
functorCompare &&
classFunctorCompare &&
functorCopyCompare &&
mem_free &&
free_mem &&
null0 &&
null1 &&
null2 &&
null3 &&
null4
#ifndef LOKI_DISABLE_TYPELIST_MACROS #ifndef LOKI_DISABLE_TYPELIST_MACROS
;
#else
&& bindFunctorCompare
&& chainFunctorCompare;
#endif
#else
bool compare=true;
#endif //LOKI_FUNCTORS_ARE_COMPARABLE
#ifdef LOKI_DISABLE_TYPELIST_MACROS
testResult=false; testResult=false;
bindFunctor(); bindFunctor();
bool bindFunctorResult=testResult; bool bindFunctorResult=testResult;
@ -81,12 +150,11 @@ public:
bool chainFunctorResult=testResult; bool chainFunctorResult=testResult;
r=functionResult && functorResult && classFunctorResult && functorCopyResult && bindFunctorResult && r=functionResult && functorResult && classFunctorResult && functorCopyResult && bindFunctorResult &&
chainFunctorResult; chainFunctorResult && compare;
#else #else
//TODO! //TODO!
r=functionResult && functorResult && classFunctorResult && functorCopyResult; r=functionResult && functorResult && classFunctorResult && functorCopyResult && compare;
#endif #endif
testAssert("Functor",r,result); testAssert("Functor",r,result);
std::cout << '\n'; std::cout << '\n';
@ -107,6 +175,11 @@ private:
{ {
result=true; result=true;
} }
bool operator==(const TestFunctor& rhs) const
{
const TestFunctor* p = &rhs;
return this==p;
}
}; };
class TestClass class TestClass
@ -123,6 +196,6 @@ bool FunctorTest::testResult;
#ifndef SMALLOBJ_CPP #ifndef SMALLOBJ_CPP
# define SMALLOBJ_CPP # define SMALLOBJ_CPP
# include "../../SmallObj.cpp" # include "../../src/SmallObj.cpp"
#endif #endif
#endif #endif