Skip to content

Commit 587658b

Browse files
committed
Merge Boost.Function fixes from trunk
[SVN r49361]
1 parent 83309a3 commit 587658b

File tree

10 files changed

+696
-201
lines changed

10 files changed

+696
-201
lines changed

doc/history.xml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,26 @@
1313

1414
<itemizedlist spacing="compact">
1515

16+
<listitem><para><bold>Version 1.37.0</bold>: </para>
17+
<itemizedlist spacing="compact">
18+
<listitem><para>Improved the performance of Boost.Function's
19+
swap() operation for large function objects. Original patch
20+
contributed by Niels Dekker.</para></listitem>
21+
22+
<listitem><para>Added a new header &lt;boost/function/function_typeof.hpp&gt; that provides support for using the Boost.Typeof library on Boost.Function objects.</para></listitem>
23+
24+
<listitem><para>Added a new header &lt;boost/function/function_fwd.hpp&gt; that provides support for using the Boost.Typeof library on Boost.Function objects.</para></listitem>
25+
26+
<listitem><para>The <methodname alt="boost::function::target">target</methodname>()
27+
function now respects the cv-qualifiers of function objects
28+
stored by reference
29+
(using <classname>boost::reference_wrapper</classname>), such
30+
that a reference to a <code>const</code> function object cannot
31+
be accessed as a reference to a non-<code>const</code> function
32+
object.</para></listitem>
33+
</itemizedlist>
34+
</listitem>
35+
1636
<listitem><para><bold>Version 1.36.0</bold>: </para>
1737
<itemizedlist spacing="compact">
1838
<listitem><para>Boost.Function now implements allocator support

include/boost/function/function_base.hpp

Lines changed: 111 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,11 @@
1818
#include <typeinfo>
1919
#include <boost/config.hpp>
2020
#include <boost/assert.hpp>
21+
#include <boost/type_traits/is_const.hpp>
2122
#include <boost/type_traits/is_integral.hpp>
23+
#include <boost/type_traits/is_volatile.hpp>
2224
#include <boost/type_traits/composite_traits.hpp>
25+
#include <boost/type_traits/ice.hpp>
2326
#include <boost/ref.hpp>
2427
#include <boost/mpl/if.hpp>
2528
#include <boost/detail/workaround.hpp>
@@ -30,6 +33,7 @@
3033
# include "boost/mpl/bool.hpp"
3134
#endif
3235
#include <boost/function_equal.hpp>
36+
#include <boost/function/function_fwd.hpp>
3337

3438
#if defined(BOOST_MSVC)
3539
# pragma warning( push )
@@ -63,22 +67,7 @@
6367
# define BOOST_FUNCTION_TARGET_FIX(x)
6468
#endif // not MSVC
6569

66-
#if defined(__sgi) && defined(_COMPILER_VERSION) && _COMPILER_VERSION <= 730 && !defined(BOOST_STRICT_CONFIG)
67-
// Work around a compiler bug.
68-
// boost::python::objects::function has to be seen by the compiler before the
69-
// boost::function class template.
70-
namespace boost { namespace python { namespace objects {
71-
class function;
72-
}}}
73-
#endif
74-
75-
#if defined (BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) \
76-
|| defined(BOOST_BCB_PARTIAL_SPECIALIZATION_BUG) \
77-
|| !(BOOST_STRICT_CONFIG || !defined(__SUNPRO_CC) || __SUNPRO_CC > 0x540)
78-
# define BOOST_FUNCTION_NO_FUNCTION_TYPE_SYNTAX
79-
#endif
80-
81-
#if !BOOST_WORKAROUND(__BORLANDC__, < 0x600)
70+
#if !BOOST_WORKAROUND(__BORLANDC__, < 0x5A0)
8271
# define BOOST_FUNCTION_ENABLE_IF_NOT_INTEGRAL(Functor,Type) \
8372
typename ::boost::enable_if_c<(::boost::type_traits::ice_not< \
8473
(::boost::is_integral<Functor>::value)>::value), \
@@ -92,22 +81,6 @@ namespace boost { namespace python { namespace objects {
9281
Type>::type
9382
#endif
9483

95-
#if !defined(BOOST_FUNCTION_NO_FUNCTION_TYPE_SYNTAX)
96-
namespace boost {
97-
98-
template<typename Signature>
99-
class function;
100-
101-
template<typename Signature>
102-
inline void swap(function<Signature>& f1,
103-
function<Signature>& f2)
104-
{
105-
f1.swap(f2);
106-
}
107-
108-
} // end namespace boost
109-
#endif // have partial specialization
110-
11184
namespace boost {
11285
namespace detail {
11386
namespace function {
@@ -122,11 +95,18 @@ namespace boost {
12295
union function_buffer
12396
{
12497
// For pointers to function objects
125-
void* obj_ptr;
98+
mutable void* obj_ptr;
12699

127100
// For pointers to std::type_info objects
128-
// (get_functor_type_tag, check_functor_type_tag).
129-
const void* const_obj_ptr;
101+
struct type_t {
102+
// (get_functor_type_tag, check_functor_type_tag).
103+
const BOOST_FUNCTION_STD_NS::type_info* type;
104+
105+
// Whether the type is const-qualified.
106+
bool const_qualified;
107+
// Whether the type is volatile-qualified.
108+
bool volatile_qualified;
109+
} type;
130110

131111
// For function pointers of all kinds
132112
mutable void (*func_ptr)();
@@ -137,6 +117,14 @@ namespace boost {
137117
void* obj_ptr;
138118
} bound_memfunc_ptr;
139119

120+
// For references to function objects. We explicitly keep
121+
// track of the cv-qualifiers on the object referenced.
122+
struct obj_ref_t {
123+
mutable void* obj_ptr;
124+
bool is_const_qualified;
125+
bool is_volatile_qualified;
126+
} obj_ref;
127+
140128
// To relax aliasing constraints
141129
mutable char data;
142130
};
@@ -168,6 +156,7 @@ namespace boost {
168156
// The operation type to perform on the given functor/function pointer
169157
enum functor_manager_operation_type {
170158
clone_functor_tag,
159+
move_functor_tag,
171160
destroy_functor_tag,
172161
check_functor_type_tag,
173162
get_functor_type_tag
@@ -204,34 +193,45 @@ namespace boost {
204193
struct reference_manager
205194
{
206195
static inline void
207-
get(const function_buffer& in_buffer, function_buffer& out_buffer,
208-
functor_manager_operation_type op)
196+
manage(const function_buffer& in_buffer, function_buffer& out_buffer,
197+
functor_manager_operation_type op)
209198
{
210199
switch (op) {
211200
case clone_functor_tag:
212-
out_buffer.obj_ptr = in_buffer.obj_ptr;
201+
out_buffer.obj_ref.obj_ptr = in_buffer.obj_ref.obj_ptr;
202+
return;
203+
204+
case move_functor_tag:
205+
out_buffer.obj_ref.obj_ptr = in_buffer.obj_ref.obj_ptr;
206+
in_buffer.obj_ref.obj_ptr = 0;
213207
return;
214208

215209
case destroy_functor_tag:
216-
out_buffer.obj_ptr = 0;
210+
out_buffer.obj_ref.obj_ptr = 0;
217211
return;
218212

219213
case check_functor_type_tag:
220214
{
221-
// DPG TBD: Since we're only storing a pointer, it's
222-
// possible that the user could ask for a base class or
223-
// derived class. Is that okay?
224-
const BOOST_FUNCTION_STD_NS::type_info& check_type =
225-
*static_cast<const BOOST_FUNCTION_STD_NS::type_info*>(out_buffer.const_obj_ptr);
226-
if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(F)))
227-
out_buffer.obj_ptr = in_buffer.obj_ptr;
215+
const BOOST_FUNCTION_STD_NS::type_info& check_type
216+
= *out_buffer.type.type;
217+
218+
// Check whether we have the same type. We can add
219+
// cv-qualifiers, but we can't take them away.
220+
if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(F))
221+
&& (!in_buffer.obj_ref.is_const_qualified
222+
|| out_buffer.type.const_qualified)
223+
&& (!in_buffer.obj_ref.is_volatile_qualified
224+
|| out_buffer.type.volatile_qualified))
225+
out_buffer.obj_ptr = in_buffer.obj_ref.obj_ptr;
228226
else
229227
out_buffer.obj_ptr = 0;
230228
}
231229
return;
232230

233231
case get_functor_type_tag:
234-
out_buffer.const_obj_ptr = &typeid(F);
232+
out_buffer.type.type = &typeid(F);
233+
out_buffer.type.const_qualified = in_buffer.obj_ref.is_const_qualified;
234+
out_buffer.type.volatile_qualified = in_buffer.obj_ref.is_volatile_qualified;
235235
return;
236236
}
237237
}
@@ -277,15 +277,22 @@ namespace boost {
277277
{
278278
if (op == clone_functor_tag)
279279
out_buffer.func_ptr = in_buffer.func_ptr;
280-
else if (op == destroy_functor_tag)
280+
else if (op == move_functor_tag) {
281+
out_buffer.func_ptr = in_buffer.func_ptr;
282+
in_buffer.func_ptr = 0;
283+
} else if (op == destroy_functor_tag)
281284
out_buffer.func_ptr = 0;
282-
else /* op == check_functor_type_tag */ {
283-
const BOOST_FUNCTION_STD_NS::type_info& check_type =
284-
*static_cast<const BOOST_FUNCTION_STD_NS::type_info*>(out_buffer.const_obj_ptr);
285+
else if (op == check_functor_type_tag) {
286+
const BOOST_FUNCTION_STD_NS::type_info& check_type
287+
= *out_buffer.type.type;
285288
if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(Functor)))
286289
out_buffer.obj_ptr = &in_buffer.func_ptr;
287290
else
288291
out_buffer.obj_ptr = 0;
292+
} else /* op == get_functor_type_tag */ {
293+
out_buffer.type.type = &typeid(Functor);
294+
out_buffer.type.const_qualified = false;
295+
out_buffer.type.volatile_qualified = false;
289296
}
290297
}
291298

@@ -294,20 +301,28 @@ namespace boost {
294301
manage_small(const function_buffer& in_buffer, function_buffer& out_buffer,
295302
functor_manager_operation_type op)
296303
{
297-
if (op == clone_functor_tag) {
304+
if (op == clone_functor_tag || op == move_functor_tag) {
298305
const functor_type* in_functor =
299306
reinterpret_cast<const functor_type*>(&in_buffer.data);
300307
new ((void*)&out_buffer.data) functor_type(*in_functor);
308+
309+
if (op == move_functor_tag) {
310+
reinterpret_cast<functor_type*>(&in_buffer.data)->~Functor();
311+
}
301312
} else if (op == destroy_functor_tag) {
302313
// Some compilers (Borland, vc6, ...) are unhappy with ~functor_type.
303314
reinterpret_cast<functor_type*>(&out_buffer.data)->~Functor();
304-
} else /* op == check_functor_type_tag */ {
305-
const BOOST_FUNCTION_STD_NS::type_info& check_type =
306-
*static_cast<const BOOST_FUNCTION_STD_NS::type_info*>(out_buffer.const_obj_ptr);
315+
} else if (op == check_functor_type_tag) {
316+
const BOOST_FUNCTION_STD_NS::type_info& check_type
317+
= *out_buffer.type.type;
307318
if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(Functor)))
308319
out_buffer.obj_ptr = &in_buffer.data;
309320
else
310321
out_buffer.obj_ptr = 0;
322+
} else /* op == get_functor_type_tag */ {
323+
out_buffer.type.type = &typeid(Functor);
324+
out_buffer.type.const_qualified = false;
325+
out_buffer.type.volatile_qualified = false;
311326
}
312327
}
313328
};
@@ -347,19 +362,26 @@ namespace boost {
347362
(const functor_type*)(in_buffer.obj_ptr);
348363
functor_type* new_f = new functor_type(*f);
349364
out_buffer.obj_ptr = new_f;
365+
} else if (op == move_functor_tag) {
366+
out_buffer.obj_ptr = in_buffer.obj_ptr;
367+
in_buffer.obj_ptr = 0;
350368
} else if (op == destroy_functor_tag) {
351369
/* Cast from the void pointer to the functor pointer type */
352370
functor_type* f =
353371
static_cast<functor_type*>(out_buffer.obj_ptr);
354372
delete f;
355373
out_buffer.obj_ptr = 0;
356-
} else /* op == check_functor_type_tag */ {
357-
const BOOST_FUNCTION_STD_NS::type_info& check_type =
358-
*static_cast<const BOOST_FUNCTION_STD_NS::type_info*>(out_buffer.const_obj_ptr);
374+
} else if (op == check_functor_type_tag) {
375+
const BOOST_FUNCTION_STD_NS::type_info& check_type
376+
= *out_buffer.type.type;
359377
if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(Functor)))
360378
out_buffer.obj_ptr = in_buffer.obj_ptr;
361379
else
362380
out_buffer.obj_ptr = 0;
381+
} else /* op == get_functor_type_tag */ {
382+
out_buffer.type.type = &typeid(Functor);
383+
out_buffer.type.const_qualified = false;
384+
out_buffer.type.volatile_qualified = false;
363385
}
364386
}
365387

@@ -374,6 +396,14 @@ namespace boost {
374396
mpl::bool_<(function_allows_small_object_optimization<functor_type>::value)>());
375397
}
376398

399+
// For member pointers, we use the small-object optimization buffer.
400+
static inline void
401+
manager(const function_buffer& in_buffer, function_buffer& out_buffer,
402+
functor_manager_operation_type op, member_ptr_tag)
403+
{
404+
manager(in_buffer, out_buffer, op, mpl::true_());
405+
}
406+
377407
public:
378408
/* Dispatch to an appropriate manager based on whether we have a
379409
function pointer or a function object pointer. */
@@ -384,7 +414,9 @@ namespace boost {
384414
typedef typename get_function_tag<functor_type>::type tag_type;
385415
switch (op) {
386416
case get_functor_type_tag:
387-
out_buffer.const_obj_ptr = &typeid(functor_type);
417+
out_buffer.type.type = &typeid(functor_type);
418+
out_buffer.type.const_qualified = false;
419+
out_buffer.type.volatile_qualified = false;
388420
return;
389421

390422
default:
@@ -439,6 +471,9 @@ namespace boost {
439471
// Get back to the original pointer type
440472
functor_wrapper_type* new_f = static_cast<functor_wrapper_type*>(copy);
441473
out_buffer.obj_ptr = new_f;
474+
} else if (op == move_functor_tag) {
475+
out_buffer.obj_ptr = in_buffer.obj_ptr;
476+
in_buffer.obj_ptr = 0;
442477
} else if (op == destroy_functor_tag) {
443478
/* Cast from the void pointer to the functor_wrapper_type */
444479
functor_wrapper_type* victim =
@@ -447,13 +482,17 @@ namespace boost {
447482
wrapper_allocator.destroy(victim);
448483
wrapper_allocator.deallocate(victim,1);
449484
out_buffer.obj_ptr = 0;
450-
} else /* op == check_functor_type_tag */ {
451-
const BOOST_FUNCTION_STD_NS::type_info& check_type =
452-
*static_cast<const BOOST_FUNCTION_STD_NS::type_info*>(out_buffer.const_obj_ptr);
485+
} else if (op == check_functor_type_tag) {
486+
const BOOST_FUNCTION_STD_NS::type_info& check_type
487+
= *out_buffer.type.type;
453488
if (BOOST_FUNCTION_COMPARE_TYPE_ID(check_type, typeid(Functor)))
454489
out_buffer.obj_ptr = in_buffer.obj_ptr;
455490
else
456491
out_buffer.obj_ptr = 0;
492+
} else /* op == get_functor_type_tag */ {
493+
out_buffer.type.type = &typeid(Functor);
494+
out_buffer.type.const_qualified = false;
495+
out_buffer.type.volatile_qualified = false;
457496
}
458497
}
459498

@@ -478,7 +517,9 @@ namespace boost {
478517
typedef typename get_function_tag<functor_type>::type tag_type;
479518
switch (op) {
480519
case get_functor_type_tag:
481-
out_buffer.const_obj_ptr = &typeid(functor_type);
520+
out_buffer.type.type = &typeid(functor_type);
521+
out_buffer.type.const_qualified = false;
522+
out_buffer.type.volatile_qualified = false;
482523
return;
483524

484525
default:
@@ -556,7 +597,6 @@ namespace boost {
556597
*/
557598
struct vtable_base
558599
{
559-
vtable_base() : manager(0) { }
560600
void (*manager)(const function_buffer& in_buffer,
561601
function_buffer& out_buffer,
562602
functor_manager_operation_type op);
@@ -586,7 +626,7 @@ class function_base
586626

587627
detail::function::function_buffer type;
588628
vtable->manager(functor, type, detail::function::get_functor_type_tag);
589-
return *static_cast<const BOOST_FUNCTION_STD_NS::type_info*>(type.const_obj_ptr);
629+
return *type.type.type;
590630
}
591631

592632
template<typename Functor>
@@ -595,7 +635,9 @@ class function_base
595635
if (!vtable) return 0;
596636

597637
detail::function::function_buffer type_result;
598-
type_result.const_obj_ptr = &typeid(Functor);
638+
type_result.type.type = &typeid(Functor);
639+
type_result.type.const_qualified = is_const<Functor>::value;
640+
type_result.type.volatile_qualified = is_volatile<Functor>::value;
599641
vtable->manager(functor, type_result,
600642
detail::function::check_functor_type_tag);
601643
return static_cast<Functor*>(type_result.obj_ptr);
@@ -611,7 +653,9 @@ class function_base
611653
if (!vtable) return 0;
612654

613655
detail::function::function_buffer type_result;
614-
type_result.const_obj_ptr = &typeid(Functor);
656+
type_result.type.type = &typeid(Functor);
657+
type_result.type.const_qualified = true;
658+
type_result.type.volatile_qualified = is_volatile<Functor>::value;
615659
vtable->manager(functor, type_result,
616660
detail::function::check_functor_type_tag);
617661
// GCC 2.95.3 gets the CV qualifiers wrong here, so we

0 commit comments

Comments
 (0)