Commit d7ecc1fa authored by Davis King's avatar Davis King

Made the member_function_pointer more robust to the amount of memory in its stack

based block of memory not being big enough.  We should now be guaranteed that it
will either fit or it won't compile.

--HG--
extra : convert_revision : svn%3Afdd8eb12-d10e-0410-9acb-85c331704f74/trunk%402630
parent 5faacf97
...@@ -25,9 +25,9 @@ namespace dlib ...@@ -25,9 +25,9 @@ namespace dlib
//----------- kernels --------------- //----------- kernels ---------------
// kernel_1a // kernel_1a
typedef member_function_pointer_kernel_1<PARAM1,PARAM2,PARAM3,PARAM4> typedef mfpk1<PARAM1,PARAM2,PARAM3,PARAM4>
kernel_1a; kernel_1a;
typedef member_function_pointer_kernel_c<kernel_1a> typedef mfpkc<kernel_1a>
kernel_1a_c; kernel_1a_c;
......
...@@ -19,7 +19,7 @@ namespace dlib ...@@ -19,7 +19,7 @@ namespace dlib
typename PARAM3 = void, typename PARAM3 = void,
typename PARAM4 = void typename PARAM4 = void
> >
class member_function_pointer_kernel_1; class mfpk1;
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
...@@ -76,6 +76,17 @@ namespace dlib ...@@ -76,6 +76,17 @@ namespace dlib
mp_impl_T() : mp_impl(0,0) {} mp_impl_T() : mp_impl(0,0) {}
mp_impl_T(void* ptr, mfp_pointer_type cb) : mp_impl(ptr,cb) {} mp_impl_T(void* ptr, mfp_pointer_type cb) : mp_impl(ptr,cb) {}
template <unsigned long mem_size>
void safe_clone(char (&buf)[mem_size])
{
// This is here just to validate the assumption that our block of memory we have made
// in mp_memory.data is the right size to store the data for this object. If you
// get a compiler error on this line then email me :)
COMPILE_TIME_ASSERT(sizeof(*this) <= mem_size);
clone(buf);
}
void clone (void* ptr) const { new(ptr) mp_impl_T(this->o,this->callback); } void clone (void* ptr) const { new(ptr) mp_impl_T(this->o,this->callback); }
bool is_same (const mp_base_base* item) const bool is_same (const mp_base_base* item) const
{ {
...@@ -92,7 +103,8 @@ namespace dlib ...@@ -92,7 +103,8 @@ namespace dlib
} }
}; };
struct dummy { void nonnull() {}; }; struct dummy_base { virtual void nonnull() {}; int a; };
struct dummy : virtual public dummy_base{ void nonnull() {}; };
typedef mp_impl_T<mp_null<dummy> > mp_null_impl; typedef mp_impl_T<mp_null<dummy> > mp_null_impl;
public: public:
...@@ -102,7 +114,7 @@ namespace dlib ...@@ -102,7 +114,7 @@ namespace dlib
) { item.mp()->clone(mp_memory.data); } ) { item.mp()->clone(mp_memory.data); }
mfp_kernel_1_base_class ( mfp_kernel_1_base_class (
) { mp_null_impl().clone(mp_memory.data); } ) { mp_null_impl().safe_clone(mp_memory.data); }
bool operator == ( bool operator == (
const mfp_kernel_1_base_class& item const mfp_kernel_1_base_class& item
...@@ -184,7 +196,7 @@ namespace dlib ...@@ -184,7 +196,7 @@ namespace dlib
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
template <> template <>
class member_function_pointer_kernel_1<void,void,void,void> : public mfp_kernel_1_base_class<0> class mfpk1<void,void,void,void> : public mfp_kernel_1_base_class<0>
{ {
class mp_base : public mp_base_base { class mp_base : public mp_base_base {
public: public:
...@@ -220,21 +232,14 @@ namespace dlib ...@@ -220,21 +232,14 @@ namespace dlib
void operator() () const { static_cast<const mp_base*>((const void*)mp_memory.data)->call(); } void operator() () const { static_cast<const mp_base*>((const void*)mp_memory.data)->call(); }
// This is here just to validate the assumption that our block of memory we have made
// in mp_memory.data is the right size to store the data for this object. If you
// get a compiler error on this line then email me :)
member_function_pointer_kernel_1()
{ COMPILE_TIME_ASSERT(sizeof(mp_memory.data) >= sizeof(mp_impl_T<mp_impl<dummy> >));
COMPILE_TIME_ASSERT(sizeof(mp_memory.data) >= sizeof(mp_impl_T<mp_impl_const<dummy> >)); }
// the reason for putting disable_if on this function is that it avoids an overload // the reason for putting disable_if on this function is that it avoids an overload
// resolution bug in visual studio. // resolution bug in visual studio.
template <typename T> typename disable_if<is_const_type<T>,void>::type template <typename T> typename disable_if<is_const_type<T>,void>::type
set(T& object, typename mp_impl<T>::mfp_pointer_type cb) set(T& object, typename mp_impl<T>::mfp_pointer_type cb)
{ destroy_mp_memory(); mp_impl_T<mp_impl<T> >(&object,cb).clone(mp_memory.data); } { destroy_mp_memory(); mp_impl_T<mp_impl<T> >(&object,cb).safe_clone(mp_memory.data); }
template <typename T> void set(const T& object, typename mp_impl_const<T>::mfp_pointer_type cb) template <typename T> void set(const T& object, typename mp_impl_const<T>::mfp_pointer_type cb)
{ destroy_mp_memory(); mp_impl_T<mp_impl_const<T> >((void*)&object,cb).clone(mp_memory.data); } { destroy_mp_memory(); mp_impl_T<mp_impl_const<T> >((void*)&object,cb).safe_clone(mp_memory.data); }
}; };
...@@ -243,7 +248,7 @@ namespace dlib ...@@ -243,7 +248,7 @@ namespace dlib
template < template <
typename PARAM1 typename PARAM1
> >
class member_function_pointer_kernel_1<PARAM1,void,void,void> : public mfp_kernel_1_base_class<1> class mfpk1<PARAM1,void,void,void> : public mfp_kernel_1_base_class<1>
{ {
class mp_base : public mp_base_base { class mp_base : public mp_base_base {
public: public:
...@@ -279,21 +284,14 @@ namespace dlib ...@@ -279,21 +284,14 @@ namespace dlib
void operator() (PARAM1 p1) const { static_cast<const mp_base*>((const void*)mp_memory.data)->call(p1); } void operator() (PARAM1 p1) const { static_cast<const mp_base*>((const void*)mp_memory.data)->call(p1); }
// This is here just to validate the assumption that our block of memory we have made
// in mp_memory.data is the right size to store the data for this object. If you
// get a compiler error on this line then email me :)
member_function_pointer_kernel_1()
{ COMPILE_TIME_ASSERT(sizeof(mp_memory.data) >= sizeof(mp_impl_T<mp_impl<dummy> >));
COMPILE_TIME_ASSERT(sizeof(mp_memory.data) >= sizeof(mp_impl_T<mp_impl_const<dummy> >)); }
// the reason for putting disable_if on this function is that it avoids an overload // the reason for putting disable_if on this function is that it avoids an overload
// resolution bug in visual studio. // resolution bug in visual studio.
template <typename T> typename disable_if<is_const_type<T>,void>::type template <typename T> typename disable_if<is_const_type<T>,void>::type
set(T& object, typename mp_impl<T>::mfp_pointer_type cb) set(T& object, typename mp_impl<T>::mfp_pointer_type cb)
{ destroy_mp_memory(); mp_impl_T<mp_impl<T> >(&object,cb).clone(mp_memory.data); } { destroy_mp_memory(); mp_impl_T<mp_impl<T> >(&object,cb).safe_clone(mp_memory.data); }
template <typename T> void set(const T& object, typename mp_impl_const<T>::mfp_pointer_type cb) template <typename T> void set(const T& object, typename mp_impl_const<T>::mfp_pointer_type cb)
{ destroy_mp_memory(); mp_impl_T<mp_impl_const<T> >((void*)&object,cb).clone(mp_memory.data); } { destroy_mp_memory(); mp_impl_T<mp_impl_const<T> >((void*)&object,cb).safe_clone(mp_memory.data); }
}; };
...@@ -303,7 +301,7 @@ namespace dlib ...@@ -303,7 +301,7 @@ namespace dlib
typename PARAM1, typename PARAM1,
typename PARAM2 typename PARAM2
> >
class member_function_pointer_kernel_1<PARAM1,PARAM2,void,void> : public mfp_kernel_1_base_class<2> class mfpk1<PARAM1,PARAM2,void,void> : public mfp_kernel_1_base_class<2>
{ {
class mp_base : public mp_base_base { class mp_base : public mp_base_base {
public: public:
...@@ -339,21 +337,14 @@ namespace dlib ...@@ -339,21 +337,14 @@ namespace dlib
void operator() (PARAM1 p1, PARAM2 p2) const { static_cast<const mp_base*>((const void*)mp_memory.data)->call(p1,p2); } void operator() (PARAM1 p1, PARAM2 p2) const { static_cast<const mp_base*>((const void*)mp_memory.data)->call(p1,p2); }
// This is here just to validate the assumption that our block of memory we have made
// in mp_memory.data is the right size to store the data for this object. If you
// get a compiler error on this line then email me :)
member_function_pointer_kernel_1()
{ COMPILE_TIME_ASSERT(sizeof(mp_memory.data) >= sizeof(mp_impl_T<mp_impl<dummy> >));
COMPILE_TIME_ASSERT(sizeof(mp_memory.data) >= sizeof(mp_impl_T<mp_impl_const<dummy> >)); }
// the reason for putting disable_if on this function is that it avoids an overload // the reason for putting disable_if on this function is that it avoids an overload
// resolution bug in visual studio. // resolution bug in visual studio.
template <typename T> typename disable_if<is_const_type<T>,void>::type template <typename T> typename disable_if<is_const_type<T>,void>::type
set(T& object, typename mp_impl<T>::mfp_pointer_type cb) set(T& object, typename mp_impl<T>::mfp_pointer_type cb)
{ destroy_mp_memory(); mp_impl_T<mp_impl<T> >(&object,cb).clone(mp_memory.data); } { destroy_mp_memory(); mp_impl_T<mp_impl<T> >(&object,cb).safe_clone(mp_memory.data); }
template <typename T> void set(const T& object, typename mp_impl_const<T>::mfp_pointer_type cb) template <typename T> void set(const T& object, typename mp_impl_const<T>::mfp_pointer_type cb)
{ destroy_mp_memory(); mp_impl_T<mp_impl_const<T> >((void*)&object,cb).clone(mp_memory.data); } { destroy_mp_memory(); mp_impl_T<mp_impl_const<T> >((void*)&object,cb).safe_clone(mp_memory.data); }
}; };
...@@ -364,7 +355,7 @@ namespace dlib ...@@ -364,7 +355,7 @@ namespace dlib
typename PARAM2, typename PARAM2,
typename PARAM3 typename PARAM3
> >
class member_function_pointer_kernel_1<PARAM1,PARAM2,PARAM3,void> : public mfp_kernel_1_base_class<3> class mfpk1<PARAM1,PARAM2,PARAM3,void> : public mfp_kernel_1_base_class<3>
{ {
class mp_base : public mp_base_base { class mp_base : public mp_base_base {
public: public:
...@@ -400,21 +391,14 @@ namespace dlib ...@@ -400,21 +391,14 @@ namespace dlib
void operator() (PARAM1 p1, PARAM2 p2, PARAM3 p3) const { static_cast<const mp_base*>((const void*)mp_memory.data)->call(p1,p2,p3); } void operator() (PARAM1 p1, PARAM2 p2, PARAM3 p3) const { static_cast<const mp_base*>((const void*)mp_memory.data)->call(p1,p2,p3); }
// This is here just to validate the assumption that our block of memory we have made
// in mp_memory.data is the right size to store the data for this object. If you
// get a compiler error on this line then email me :)
member_function_pointer_kernel_1()
{ COMPILE_TIME_ASSERT(sizeof(mp_memory.data) >= sizeof(mp_impl_T<mp_impl<dummy> >));
COMPILE_TIME_ASSERT(sizeof(mp_memory.data) >= sizeof(mp_impl_T<mp_impl_const<dummy> >)); }
// the reason for putting disable_if on this function is that it avoids an overload // the reason for putting disable_if on this function is that it avoids an overload
// resolution bug in visual studio. // resolution bug in visual studio.
template <typename T> typename disable_if<is_const_type<T>,void>::type template <typename T> typename disable_if<is_const_type<T>,void>::type
set(T& object, typename mp_impl<T>::mfp_pointer_type cb) set(T& object, typename mp_impl<T>::mfp_pointer_type cb)
{ destroy_mp_memory(); mp_impl_T<mp_impl<T> >(&object,cb).clone(mp_memory.data); } { destroy_mp_memory(); mp_impl_T<mp_impl<T> >(&object,cb).safe_clone(mp_memory.data); }
template <typename T> void set(const T& object, typename mp_impl_const<T>::mfp_pointer_type cb) template <typename T> void set(const T& object, typename mp_impl_const<T>::mfp_pointer_type cb)
{ destroy_mp_memory(); mp_impl_T<mp_impl_const<T> >((void*)&object,cb).clone(mp_memory.data); } { destroy_mp_memory(); mp_impl_T<mp_impl_const<T> >((void*)&object,cb).safe_clone(mp_memory.data); }
}; };
...@@ -426,7 +410,7 @@ namespace dlib ...@@ -426,7 +410,7 @@ namespace dlib
typename PARAM3, typename PARAM3,
typename PARAM4 typename PARAM4
> >
class member_function_pointer_kernel_1 : public mfp_kernel_1_base_class<4> class mfpk1 : public mfp_kernel_1_base_class<4>
{ {
class mp_base : public mp_base_base { class mp_base : public mp_base_base {
public: public:
...@@ -463,21 +447,14 @@ namespace dlib ...@@ -463,21 +447,14 @@ namespace dlib
void operator() (PARAM1 p1, PARAM2 p2, PARAM3 p3, PARAM4 p4) const void operator() (PARAM1 p1, PARAM2 p2, PARAM3 p3, PARAM4 p4) const
{ static_cast<const mp_base*>((const void*)mp_memory.data)->call(p1,p2,p3,p4); } { static_cast<const mp_base*>((const void*)mp_memory.data)->call(p1,p2,p3,p4); }
// This is here just to validate the assumption that our block of memory we have made
// in mp_memory.data is the right size to store the data for this object. If you
// get a compiler error on this line then email me :)
member_function_pointer_kernel_1()
{ COMPILE_TIME_ASSERT(sizeof(mp_memory.data) >= sizeof(mp_impl_T<mp_impl<dummy> >));
COMPILE_TIME_ASSERT(sizeof(mp_memory.data) >= sizeof(mp_impl_T<mp_impl_const<dummy> >)); }
// the reason for putting disable_if on this function is that it avoids an overload // the reason for putting disable_if on this function is that it avoids an overload
// resolution bug in visual studio. // resolution bug in visual studio.
template <typename T> typename disable_if<is_const_type<T>,void>::type template <typename T> typename disable_if<is_const_type<T>,void>::type
set(T& object, typename mp_impl<T>::mfp_pointer_type cb) set(T& object, typename mp_impl<T>::mfp_pointer_type cb)
{ destroy_mp_memory(); mp_impl_T<mp_impl<T> >(&object,cb).clone(mp_memory.data); } { destroy_mp_memory(); mp_impl_T<mp_impl<T> >(&object,cb).safe_clone(mp_memory.data); }
template <typename T> void set(const T& object, typename mp_impl_const<T>::mfp_pointer_type cb) template <typename T> void set(const T& object, typename mp_impl_const<T>::mfp_pointer_type cb)
{ destroy_mp_memory(); mp_impl_T<mp_impl_const<T> >((void*)&object,cb).clone(mp_memory.data); } { destroy_mp_memory(); mp_impl_T<mp_impl_const<T> >((void*)&object,cb).safe_clone(mp_memory.data); }
}; };
......
...@@ -248,7 +248,7 @@ namespace dlib ...@@ -248,7 +248,7 @@ namespace dlib
void (T::*cb)(PARAM1)const void (T::*cb)(PARAM1)const
); );
operator bool ( operator some_undefined_pointer_type (
) const; ) const;
bool operator! ( bool operator! (
...@@ -315,7 +315,7 @@ namespace dlib ...@@ -315,7 +315,7 @@ namespace dlib
void (T::*cb)(PARAM1,PARAM2)const void (T::*cb)(PARAM1,PARAM2)const
); );
operator bool ( operator some_undefined_pointer_type (
) const; ) const;
bool operator! ( bool operator! (
...@@ -384,7 +384,7 @@ namespace dlib ...@@ -384,7 +384,7 @@ namespace dlib
void (T::*cb)(PARAM1,PARAM2,PARAM3)const void (T::*cb)(PARAM1,PARAM2,PARAM3)const
); );
operator bool ( operator some_undefined_pointer_type (
) const; ) const;
bool operator! ( bool operator! (
...@@ -455,7 +455,7 @@ namespace dlib ...@@ -455,7 +455,7 @@ namespace dlib
void (T::*cb)(PARAM1,PARAM2,PARAM3,PARAM4)const void (T::*cb)(PARAM1,PARAM2,PARAM3,PARAM4)const
); );
operator bool ( operator some_undefined_pointer_type (
) const; ) const;
bool operator! ( bool operator! (
......
...@@ -17,14 +17,14 @@ namespace dlib ...@@ -17,14 +17,14 @@ namespace dlib
typename PARAM3 = typename mfpb::param3_type, typename PARAM3 = typename mfpb::param3_type,
typename PARAM4 = typename mfpb::param4_type typename PARAM4 = typename mfpb::param4_type
> >
class member_function_pointer_kernel_c; class mfpkc;
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
template < template <
typename mfpb typename mfpb
> >
class member_function_pointer_kernel_c<mfpb,void,void,void,void> : class mfpkc<mfpb,void,void,void,void> :
public mfpb public mfpb
{ {
public: public:
...@@ -88,7 +88,7 @@ namespace dlib ...@@ -88,7 +88,7 @@ namespace dlib
typename mfpb, typename mfpb,
typename PARAM1 typename PARAM1
> >
class member_function_pointer_kernel_c<mfpb,PARAM1,void,void,void> : class mfpkc<mfpb,PARAM1,void,void,void> :
public mfpb public mfpb
{ {
public: public:
...@@ -154,7 +154,7 @@ namespace dlib ...@@ -154,7 +154,7 @@ namespace dlib
typename PARAM1, typename PARAM1,
typename PARAM2 typename PARAM2
> >
class member_function_pointer_kernel_c<mfpb,PARAM1,PARAM2,void,void> : class mfpkc<mfpb,PARAM1,PARAM2,void,void> :
public mfpb public mfpb
{ {
public: public:
...@@ -222,7 +222,7 @@ namespace dlib ...@@ -222,7 +222,7 @@ namespace dlib
typename PARAM2, typename PARAM2,
typename PARAM3 typename PARAM3
> >
class member_function_pointer_kernel_c<mfpb,PARAM1,PARAM2,PARAM3,void> : class mfpkc<mfpb,PARAM1,PARAM2,PARAM3,void> :
public mfpb public mfpb
{ {
public: public:
...@@ -292,7 +292,7 @@ namespace dlib ...@@ -292,7 +292,7 @@ namespace dlib
typename PARAM3, typename PARAM3,
typename PARAM4 typename PARAM4
> >
class member_function_pointer_kernel_c : class mfpkc :
public mfpb public mfpb
{ {
public: public:
......
...@@ -122,11 +122,11 @@ namespace ...@@ -122,11 +122,11 @@ namespace
mfp<int,int,int> a3, b3; mfp<int,int,int> a3, b3;
mfp<int,int,int,int> a4, b4; mfp<int,int,int,int> a4, b4;
member_function_pointer_kernel_c<mfp<> > a0c, b0c; mfpkc<mfp<> > a0c, b0c;
member_function_pointer_kernel_c<mfp<int> > a1c, b1c; mfpkc<mfp<int> > a1c, b1c;
member_function_pointer_kernel_c<mfp<int,int> > a2c, b2c; mfpkc<mfp<int,int> > a2c, b2c;
member_function_pointer_kernel_c<mfp<int,int,int> > a3c, b3c; mfpkc<mfp<int,int,int> > a3c, b3c;
member_function_pointer_kernel_c<mfp<int,int,int,int> > a4c, b4c; mfpkc<mfp<int,int,int,int> > a4c, b4c;
DLIB_CASSERT(a0c == b0c, ""); DLIB_CASSERT(a0c == b0c, "");
DLIB_CASSERT(a1c == b1c, ""); DLIB_CASSERT(a1c == b1c, "");
...@@ -543,8 +543,8 @@ namespace ...@@ -543,8 +543,8 @@ namespace
void perform_test ( void perform_test (
) )
{ {
member_function_pointer_kernel_test<member_function_pointer_kernel_1,mfp_test_helper>(); member_function_pointer_kernel_test<mfpk1,mfp_test_helper>();
member_function_pointer_kernel_test<member_function_pointer_kernel_1,mfp_test_helper_const>(); member_function_pointer_kernel_test<mfpk1,mfp_test_helper_const>();
} }
} a; } a;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment