Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 6010dfd

Browse files
committed
Aggregator:
- Added runtime typechecks for aggregators and map_reduce
1 parent 139a1b8 commit 6010dfd

4 files changed

Lines changed: 311 additions & 3 deletions

File tree

src/graphlab/aggregation/distributed_aggregator.hpp

Lines changed: 93 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@
3636
#include <graphlab/vertex_program/icontext.hpp>
3737
#include <graphlab/graph/distributed_graph.hpp>
3838
#include <graphlab/util/generics/conditional_addition_wrapper.hpp>
39+
#include <graphlab/util/generics/test_function_or_functor_type.hpp>
40+
3941
#include <graphlab/util/generics/any.hpp>
4042
#include <graphlab/util/timer.hpp>
4143
#include <graphlab/util/mutable_queue.hpp>
@@ -174,7 +176,6 @@ namespace graphlab {
174176
map_reduce_type(VertexMapperType map_vtx_function,
175177
FinalizerType finalize_function)
176178
: map_vtx_function(map_vtx_function),
177-
map_edge_function(NULL),
178179
finalize_function(finalize_function), vertex_map(true) { }
179180

180181
/**
@@ -184,8 +185,7 @@ namespace graphlab {
184185
map_reduce_type(EdgeMapperType map_edge_function,
185186
FinalizerType finalize_function,
186187
bool)
187-
: map_vtx_function(NULL),
188-
map_edge_function(map_edge_function),
188+
: map_edge_function(map_edge_function),
189189
finalize_function(finalize_function), vertex_map(false) { }
190190

191191

@@ -310,6 +310,74 @@ namespace graphlab {
310310
mutable_queue<std::string, float> schedule;
311311
mutex schedule_lock;
312312
size_t ncpus;
313+
314+
template <typename ReductionType, typename F>
315+
static void test_vertex_mapper_type(std::string key = "") {
316+
bool test_result = test_function_or_const_functor_2<F,
317+
ReductionType(icontext_type&,
318+
const vertex_type&),
319+
ReductionType,
320+
icontext_type&,
321+
const vertex_type&>::value;
322+
if (!test_result) {
323+
std::stringstream strm;
324+
strm << "\n";
325+
if (key.empty()) {
326+
strm << "Vertex Map Function does not pass strict runtime type checks. \n";
327+
}
328+
else {
329+
strm << "Map Function in Vertex Aggregator " << key
330+
<< " does not pass strict runtime type checks. \n";
331+
}
332+
if (boost::is_function<typename boost::remove_pointer<F>::type>::value) {
333+
strm
334+
<< "Function prototype should be \n"
335+
<< "\t ReductionType f(icontext_type&, const vertex_type&)\n";
336+
}
337+
else {
338+
strm << "Functor's operator() prototype should be \n"
339+
<< "\t ReductionType operator()(icontext_type&, const vertex_type&) const\n";
340+
}
341+
strm << "If you are not intentionally violating the abstraction,"
342+
<< " we recommend fixing your function for safety reasons";
343+
strm.flush();
344+
logstream(LOG_WARNING) << strm.str() << std::endl;
345+
}
346+
}
347+
348+
template <typename ReductionType, typename F>
349+
static void test_edge_mapper_type(std::string key = "") {
350+
bool test_result = test_function_or_const_functor_2<F,
351+
ReductionType(icontext_type&,
352+
const edge_type&),
353+
ReductionType,
354+
icontext_type&,
355+
const edge_type&>::value;
356+
357+
if (!test_result) {
358+
std::stringstream strm;
359+
strm << "\n";
360+
if (key.empty()) {
361+
strm << "Edge Map Function does not pass strict runtime type checks. \n";
362+
}
363+
else {
364+
strm << "Map Function in Edge Aggregator " << key
365+
<< " does not pass strict runtime type checks. \n";
366+
}
367+
if (boost::is_function<typename boost::remove_pointer<F>::type>::value) {
368+
strm << "Function prototype should be \n"
369+
<< "\t ReductionType f(icontext_type&, const edge_type&)\n";
370+
}
371+
else {
372+
strm << "Functor's operator() prototype should be "
373+
<< "\t ReductionType operator()(icontext_type&, const edge_type&) const\n";
374+
}
375+
strm << "If you are not intentionally violating the abstraction,"
376+
<< " we recommend fixing your function for safety reasons";
377+
logstream(LOG_WARNING) << strm.str() << std::endl;
378+
}
379+
}
380+
313381
public:
314382

315383

@@ -330,6 +398,12 @@ namespace graphlab {
330398
FinalizerType finalize_function) {
331399
if (key.length() == 0) return false;
332400
if (aggregators.count(key) == 0) {
401+
402+
if (rmi.procid() == 0) {
403+
// do a runtime type check
404+
test_vertex_mapper_type<ReductionType, VertexMapperType>(key);
405+
}
406+
333407
aggregators[key] = new map_reduce_type<ReductionType,
334408
VertexMapperType,
335409
typename default_map_types<ReductionType>::edge_map_type,
@@ -386,6 +460,10 @@ namespace graphlab {
386460
FinalizerType finalize_function) {
387461
if (key.length() == 0) return false;
388462
if (aggregators.count(key) == 0) {
463+
if (rmi.procid() == 0) {
464+
// do a runtime type check
465+
test_edge_mapper_type<ReductionType, EdgeMapperType>(key);
466+
}
389467
aggregators[key] = new map_reduce_type<ReductionType,
390468
typename default_map_types<ReductionType>::vertex_map_type,
391469
EdgeMapperType,
@@ -862,6 +940,12 @@ namespace graphlab {
862940
template <typename ResultType, typename MapFunctionType>
863941
ResultType map_reduce_vertices(MapFunctionType mapfunction) {
864942
ASSERT_MSG(graph.is_finalized(), "Graph must be finalized");
943+
944+
if (rmi.procid() == 0) {
945+
// do a runtime type check
946+
test_vertex_mapper_type<ResultType, MapFunctionType>();
947+
}
948+
865949
rmi.barrier();
866950
bool global_result_set = false;
867951
ResultType global_result = ResultType();
@@ -910,6 +994,12 @@ namespace graphlab {
910994
template <typename ResultType, typename MapFunctionType>
911995
ResultType map_reduce_edges(MapFunctionType mapfunction) {
912996
ASSERT_MSG(graph.is_finalized(), "Graph must be finalized");
997+
998+
if (rmi.procid() == 0) {
999+
// do a runtime type check
1000+
test_edge_mapper_type<ResultType, MapFunctionType>();
1001+
}
1002+
9131003
rmi.barrier();
9141004
bool global_result_set = false;
9151005
ResultType global_result = ResultType();
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
#ifndef GRAPHLAB_TEST_FUNCTION_OR_FUNCTOR_TYPE_HPP
2+
#define GRAPHLAB_TEST_FUNCTION_OR_FUNCTOR_TYPE_HPP
3+
#include <boost/type_traits/is_same.hpp>
4+
#include <boost/type_traits/remove_pointer.hpp>
5+
6+
namespace graphlab {
7+
8+
9+
template <typename F,
10+
typename PreferredFunctionForm,
11+
typename RetType,
12+
typename Arg1>
13+
struct test_function_or_functor_1 {
14+
15+
// test if the functor type matches
16+
template <typename T, RetType (T::*)(Arg1)>
17+
struct SFINAE1 {};
18+
19+
template <typename T>
20+
static char test1(SFINAE1<T, &T::operator()>*){}
21+
22+
template <typename T>
23+
static int test1(...){}
24+
25+
static const bool value = ((sizeof(test1<F>(0)) == sizeof(char)) ||
26+
boost::is_same<F, PreferredFunctionForm>::value ||
27+
boost::is_same<typename boost::remove_pointer<F>::type, PreferredFunctionForm>::value);
28+
};
29+
30+
31+
32+
template <typename F,
33+
typename PreferredFunctionForm,
34+
typename RetType,
35+
typename Arg1>
36+
struct test_function_or_const_functor_1 {
37+
38+
// test if the functor type matches
39+
template <typename T, RetType (T::*)(Arg1) const>
40+
struct SFINAE1 {};
41+
42+
template <typename T>
43+
static char test1(SFINAE1<T, &T::operator()>*){}
44+
45+
template <typename T>
46+
static int test1(...){}
47+
48+
static const bool value = ((sizeof(test1<F>(0)) == sizeof(char)) ||
49+
boost::is_same<F, PreferredFunctionForm>::value ||
50+
boost::is_same<typename boost::remove_pointer<F>::type, PreferredFunctionForm>::value);
51+
};
52+
53+
54+
55+
56+
template <typename F,
57+
typename PreferredFunctionForm,
58+
typename RetType,
59+
typename Arg1,
60+
typename Arg2>
61+
struct test_function_or_functor_2 {
62+
63+
// test if the functor type matches
64+
template <typename T, RetType (T::*)(Arg1, Arg2)>
65+
struct SFINAE1 {};
66+
67+
template <typename T>
68+
static char test1(SFINAE1<T, &T::operator()>*){}
69+
70+
template <typename T>
71+
static int test1(...){}
72+
73+
static const bool value = ((sizeof(test1<F>(0)) == sizeof(char)) ||
74+
boost::is_same<F, PreferredFunctionForm>::value ||
75+
boost::is_same<typename boost::remove_pointer<F>::type, PreferredFunctionForm>::value);
76+
};
77+
78+
79+
80+
template <typename F,
81+
typename PreferredFunctionForm,
82+
typename RetType,
83+
typename Arg1,
84+
typename Arg2>
85+
struct test_function_or_const_functor_2 {
86+
87+
// test if the functor type matches
88+
template <typename T, RetType (T::*)(Arg1, Arg2) const>
89+
struct SFINAE1 {};
90+
91+
template <typename T>
92+
static char test1(SFINAE1<T, &T::operator()>*){}
93+
94+
template <typename T>
95+
static int test1(...){}
96+
97+
static const bool value = ((sizeof(test1<F>(0)) == sizeof(char)) ||
98+
boost::is_same<F, PreferredFunctionForm>::value ||
99+
boost::is_same<typename boost::remove_pointer<F>::type, PreferredFunctionForm>::value);
100+
};
101+
102+
103+
104+
} // namespace graphlab
105+
#endif

tests/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,6 @@ add_graphlab_executable(test_parsers test_parsers.cpp)
4444
add_graphlab_executable(synchronous_engine_test synchronous_engine_test.cpp)
4545
add_graphlab_executable(async_consistent_test async_consistent_test.cpp)
4646

47+
add_graphlab_executable(sfinae_function_test sfinae_function_test.cpp)
48+
4749
# copyfile(runtests.sh)

tests/sfinae_function_test.cpp

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
#include <iostream>
2+
#include <graphlab/util/generics/test_function_or_functor_type.hpp>
3+
4+
struct ts{
5+
int i;
6+
};
7+
8+
9+
void by_value(ts) {
10+
}
11+
12+
void by_const_value(const ts) {
13+
}
14+
15+
void by_reference(ts&) {
16+
}
17+
18+
void by_const_reference(const ts&) {
19+
}
20+
21+
22+
struct functor_by_value{
23+
void operator()(ts) { }
24+
};
25+
26+
struct functor_by_const_value{
27+
void operator()(const ts) { }
28+
};
29+
30+
struct functor_by_reference{
31+
void operator()(ts&) { }
32+
};
33+
34+
struct functor_by_const_reference{
35+
void operator()(const ts&) { }
36+
};
37+
38+
39+
struct const_functor_by_value{
40+
void operator()(ts) const { }
41+
};
42+
43+
struct const_functor_by_const_value{
44+
void operator()(const ts) const { }
45+
};
46+
47+
struct const_functor_by_reference{
48+
void operator()(ts&) const { }
49+
};
50+
51+
struct const_functor_by_const_reference{
52+
void operator()(const ts&) const { }
53+
};
54+
55+
56+
57+
struct overload_functor_by_value{
58+
void operator()(ts) { }
59+
void operator()(ts) const { }
60+
};
61+
62+
struct overload_functor_by_const_value{
63+
void operator()(const ts) { }
64+
void operator()(const ts) const { }
65+
};
66+
67+
struct overload_functor_by_reference{
68+
void operator()(ts&) { }
69+
void operator()(ts&) const { }
70+
};
71+
72+
struct overload_functor_by_const_reference{
73+
void operator()(const ts&) { }
74+
void operator()(const ts&) const { }
75+
};
76+
77+
78+
/*
79+
* Returns true if T is a function which matches void(const ts&)
80+
* or if T is a functor with a void operator()(const ts&) const
81+
*/
82+
template <typename T>
83+
int test_function_is_const_ref(T t) {
84+
return graphlab::test_function_or_const_functor_1<T,
85+
void(const ts&), /* function form*/
86+
void, /* return type */
87+
const ts& /* argument 1 */
88+
>::value;
89+
}
90+
91+
int main(int argc, char** argv) {
92+
std::cout << test_function_is_const_ref(by_value) << std::endl;
93+
std::cout << test_function_is_const_ref(by_const_value) << std::endl;
94+
std::cout << test_function_is_const_ref(by_reference) << std::endl;
95+
std::cout << test_function_is_const_ref(by_const_reference) << std::endl;
96+
97+
std::cout << test_function_is_const_ref(functor_by_value()) << std::endl;
98+
std::cout << test_function_is_const_ref(functor_by_const_value()) << std::endl;
99+
std::cout << test_function_is_const_ref(functor_by_reference()) << std::endl;
100+
std::cout << test_function_is_const_ref(functor_by_const_reference()) << std::endl;
101+
102+
std::cout << test_function_is_const_ref(const_functor_by_value()) << std::endl;
103+
std::cout << test_function_is_const_ref(const_functor_by_const_value()) << std::endl;
104+
std::cout << test_function_is_const_ref(const_functor_by_reference()) << std::endl;
105+
std::cout << test_function_is_const_ref(const_functor_by_const_reference()) << std::endl;
106+
107+
std::cout << test_function_is_const_ref(overload_functor_by_value()) << std::endl;
108+
std::cout << test_function_is_const_ref(overload_functor_by_const_value()) << std::endl;
109+
std::cout << test_function_is_const_ref(overload_functor_by_reference()) << std::endl;
110+
std::cout << test_function_is_const_ref(overload_functor_by_const_reference()) << std::endl;
111+
}

0 commit comments

Comments
 (0)