diff --git a/src/util/lexcmp_def.hpp b/src/util/lexcmp_def.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d1c3e8a3bfc63341070b55b1320de03583797bbe --- /dev/null +++ b/src/util/lexcmp_def.hpp @@ -0,0 +1,40 @@ +#pragma once + +/* + * Macro definitions for defining comparison operators for + * record-like types. + * + * Use: + * + * To define comparison operations for a record type xyzzy + * with fields foo, bar and baz: + * + * DEFINE_LEXICOGRAPHIC_ORDERING(xyzzy,(a.foo,a.bar,a.baz),(b.foo,b.bar,b.baz)) + * + * The explicit use of 'a' and 'b' in the second and third parameters + * is needed only to save a heroic amount of preprocessor macro + * deep magic. + * + */ + +#include <tuple> + +#define DEFINE_LEXICOGRAPHIC_ORDERING_IMPL_(proxy,op,type,a_fields,b_fields) \ +inline bool operator op(const type &a,const type &b) { return proxy a_fields op proxy b_fields; } + +#define DEFINE_LEXICOGRAPHIC_ORDERING(type,a_fields,b_fields) \ +DEFINE_LEXICOGRAPHIC_ORDERING_IMPL_(std::tie,<,type,a_fields,b_fields) \ +DEFINE_LEXICOGRAPHIC_ORDERING_IMPL_(std::tie,>,type,a_fields,b_fields) \ +DEFINE_LEXICOGRAPHIC_ORDERING_IMPL_(std::tie,<=,type,a_fields,b_fields) \ +DEFINE_LEXICOGRAPHIC_ORDERING_IMPL_(std::tie,>=,type,a_fields,b_fields) \ +DEFINE_LEXICOGRAPHIC_ORDERING_IMPL_(std::tie,!=,type,a_fields,b_fields) \ +DEFINE_LEXICOGRAPHIC_ORDERING_IMPL_(std::tie,==,type,a_fields,b_fields) + +#define DEFINE_LEXICOGRAPHIC_ORDERING_BY_VALUE(type,a_fields,b_fields) \ +DEFINE_LEXICOGRAPHIC_ORDERING_IMPL_(std::make_tuple,<,type,a_fields,b_fields) \ +DEFINE_LEXICOGRAPHIC_ORDERING_IMPL_(std::make_tuple,>,type,a_fields,b_fields) \ +DEFINE_LEXICOGRAPHIC_ORDERING_IMPL_(std::make_tuple,<=,type,a_fields,b_fields) \ +DEFINE_LEXICOGRAPHIC_ORDERING_IMPL_(std::make_tuple,>=,type,a_fields,b_fields) \ +DEFINE_LEXICOGRAPHIC_ORDERING_IMPL_(std::make_tuple,!=,type,a_fields,b_fields) \ +DEFINE_LEXICOGRAPHIC_ORDERING_IMPL_(std::make_tuple,==,type,a_fields,b_fields) + diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt index a3a2d55333f6316b133bff3982ec58e1b03d525d..61d713bc831e7ec63dfaf370f7931e204c7d9e45 100644 --- a/tests/unit/CMakeLists.txt +++ b/tests/unit/CMakeLists.txt @@ -16,6 +16,7 @@ set(TEST_SOURCES test_event_queue.cpp test_fvm.cpp test_cell_group.cpp + test_lexcmp.cpp test_matrix.cpp test_mechanisms.cpp test_optional.cpp diff --git a/tests/unit/test_lexcmp.cpp b/tests/unit/test_lexcmp.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a02ac0765823f61d54e8acee3cf38611552d9dd7 --- /dev/null +++ b/tests/unit/test_lexcmp.cpp @@ -0,0 +1,110 @@ +#include "gtest.h" + +#include <util/lexcmp_def.hpp> + +struct lexcmp_test_one { + int foo; +}; + +DEFINE_LEXICOGRAPHIC_ORDERING(lexcmp_test_one, (a.foo), (b.foo)) + +TEST(lexcmp_def,one) { + lexcmp_test_one p{3}, q{4}, r{4}; + + EXPECT_LE(p,q); + EXPECT_LT(p,q); + EXPECT_NE(p,q); + EXPECT_GE(q,p); + EXPECT_GT(q,p); + + EXPECT_LE(q,r); + EXPECT_GE(q,r); + EXPECT_EQ(q,r); +} + +struct lexcmp_test_three { + int x; + std::string y; + double z; +}; + +// test fields in reverse order: z, y, x +DEFINE_LEXICOGRAPHIC_ORDERING(lexcmp_test_three, (a.z,a.y,a.x), (b.z,b.y,b.x)) + +TEST(lexcmp_def,three) { + lexcmp_test_three p{1,"foo",2}; + lexcmp_test_three q{1,"foo",3}; + lexcmp_test_three r{1,"bar",2}; + lexcmp_test_three s{5,"foo",2}; + + EXPECT_LE(p,q); + EXPECT_LT(p,q); + EXPECT_NE(p,q); + EXPECT_GE(q,p); + EXPECT_GT(q,p); + + EXPECT_LE(r,p); + EXPECT_LT(r,p); + EXPECT_NE(p,r); + EXPECT_GE(p,r); + EXPECT_GT(p,r); + + EXPECT_LE(p,s); + EXPECT_LT(p,s); + EXPECT_NE(p,s); + EXPECT_GE(s,p); + EXPECT_GT(s,p); +} + +// test fields accessed by reference-returning member function + +class lexcmp_test_refmemfn { +public: + explicit lexcmp_test_refmemfn(int foo): foo_(foo) {} + + const int &foo() const { return foo_; } + int &foo() { return foo_; } + +private: + int foo_; +}; + +DEFINE_LEXICOGRAPHIC_ORDERING(lexcmp_test_refmemfn, (a.foo()), (b.foo())) + +TEST(lexcmp_def,refmemfn) { + lexcmp_test_refmemfn p{3}; + const lexcmp_test_refmemfn q{4}; + + EXPECT_LE(p,q); + EXPECT_LT(p,q); + EXPECT_NE(p,q); + EXPECT_GE(q,p); + EXPECT_GT(q,p); +} + +// test comparison via proxy tuple object + +class lexcmp_test_valmemfn { +public: + explicit lexcmp_test_valmemfn(int foo, int bar): foo_(foo), bar_(bar) {} + int foo() const { return foo_; } + int bar() const { return bar_; } + +private: + int foo_; + int bar_; +}; + +DEFINE_LEXICOGRAPHIC_ORDERING_BY_VALUE(lexcmp_test_valmemfn, (a.foo(),a.bar()), (b.foo(),b.bar())) + +TEST(lexcmp_def,proxy) { + lexcmp_test_valmemfn p{3,2}, q{3,4}; + + EXPECT_LE(p,q); + EXPECT_LT(p,q); + EXPECT_NE(p,q); + EXPECT_GE(q,p); + EXPECT_GT(q,p); +} + +