diff --git a/.gitignore b/.gitignore index 9eec30f..aa6ca48 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,6 @@ Makefile /examples/libdl_shared.so /install_manifest.txt /doc/multi_methods.xml +/build +*.sdf +*.suo diff --git a/CMakeLists.txt b/CMakeLists.txt index cd358da..e5ac4a5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,6 +26,10 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") set(CMAKE_CXX_FLAGS "-std=c++11") endif() +if(MSVC) + set(CMAKE_CXX_FLAGS "-D_SCL_SECURE_NO_WARNINGS /EHsc") +endif() + add_subdirectory (src) add_subdirectory (tests) add_subdirectory (examples) diff --git a/examples/asteroids.cpp b/examples/asteroids.cpp index af1a7e3..4b1f0cd 100644 --- a/examples/asteroids.cpp +++ b/examples/asteroids.cpp @@ -9,6 +9,7 @@ #include #include +#include using namespace std; using yorel::multi_methods::virtual_; diff --git a/include/yorel/multi_methods/detail.hpp b/include/yorel/multi_methods/detail.hpp index 0893961..8c2e574 100644 --- a/include/yorel/multi_methods/detail.hpp +++ b/include/yorel/multi_methods/detail.hpp @@ -212,6 +212,11 @@ struct init_ptr<> { } }; +template +struct signature { + using type = SIG; +}; + template<> struct get_mm_table { using class_of_type = std::unordered_map*>; @@ -322,7 +327,7 @@ struct multi_method_implementation : multi_method_base { template template method_base* multi_method_implementation::add_spec() { - using method_signature = decltype(M::body); + using method_signature = typename M::body_signature::type; using target = typename wrapper::type; using method_virtuals = typename extract_method_virtuals::type; diff --git a/include/yorel/multi_methods/macros.hpp b/include/yorel/multi_methods/macros.hpp index fddfe31..0469211 100644 --- a/include/yorel/multi_methods/macros.hpp +++ b/include/yorel/multi_methods/macros.hpp @@ -7,40 +7,41 @@ // http://www.boost.org/LICENSE_1_0.txt) #undef MM_CLASS -#define MM_CLASS(CLASS, BASES...) \ - using _yomm11_base_list = ::yorel::multi_methods::mm_class::base_list; \ - virtual void _yomm11_init_class_() { &::yorel::multi_methods::mm_class::initializer>::the; } +#define MM_CLASS(CLASS, ...) \ + using _yomm11_base_list = ::yorel::multi_methods::mm_class::base_list<__VA_ARGS__>; \ + virtual void _yomm11_init_class_() { &::yorel::multi_methods::mm_class::initializer>::the; } #undef MM_EXTERN_CLASS #define MM_EXTERN_CLASS(CLASS) -#define MM_FOREIGN_CLASS(CLASS, BASES...) \ - static_assert(::yorel::multi_methods::detail::check_bases>::value, "error in MM_FOREIGN_CLASS(): not a base in base list"); \ +#define MM_FOREIGN_CLASS(CLASS, ...) \ + static_assert(::yorel::multi_methods::detail::check_bases>::value, "error in MM_FOREIGN_CLASS(): not a base in base list"); \ static_assert(std::is_polymorphic::value, "error: class must be polymorphic"); \ - namespace { ::yorel::multi_methods::mm_class::initializer> _yomm11_add_class_ ## CLASS; } + namespace { ::yorel::multi_methods::mm_class::initializer> _yomm11_add_class_ ## CLASS; } #define MM_INIT() \ ::yorel::multi_methods::detail::init_ptr<_yomm11_base_list>::init(this) #undef MM_CLASS_MULTI -#define MM_CLASS_MULTI(CLASS, BASE, BASES...) \ - MM_CLASS(CLASS, BASE, BASES); \ +#define MM_CLASS_MULTI(CLASS, BASE, ...) \ + MM_CLASS(CLASS, BASE, __VA_ARGS__); \ std::vector* _get_yomm11_ptbl() const { return BASE::_yomm11_ptbl; } #define MM_INIT_MULTI(BASE) \ this->BASE::_init_yomm11_ptr(this) #undef MULTI_METHOD -#define MULTI_METHOD(ID, RETURN_TYPE, ARGS...) \ +#define MULTI_METHOD(ID, RETURN_TYPE, ...) \ template struct ID ## _specialization; \ - constexpr ::yorel::multi_methods::multi_method ID{} + const ::yorel::multi_methods::multi_method ID -#define BEGIN_SPECIALIZATION(ID, RESULT, ARGS...) \ +#define BEGIN_SPECIALIZATION(ID, RESULT, ...) \ template<> \ - struct ID ## _specialization : decltype(ID)::specialization> { \ - virtual void* _yomm11_install() { return &decltype(ID)::register_spec::the; } \ - static RESULT body(ARGS) { + struct ID ## _specialization : std::remove_const::type::specialization< ID ## _specialization > { \ + virtual void* _yomm11_install() { return &::yorel::multi_methods::register_spec::the; } \ + using body_signature = ::yorel::multi_methods::detail::signature; \ + static RESULT body(__VA_ARGS__) { #define END_SPECIALIZATION } }; -#define GET_SPECIALIZATION(ID, RESULT, ARGS...) ID ## _specialization::body +#define GET_SPECIALIZATION(ID, RESULT, ...) ID ## _specialization::body diff --git a/include/yorel/multi_methods/no_macros.hpp b/include/yorel/multi_methods/no_macros.hpp index a895334..92a1b9f 100644 --- a/include/yorel/multi_methods/no_macros.hpp +++ b/include/yorel/multi_methods/no_macros.hpp @@ -9,6 +9,16 @@ // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +// Copied from Boost. +#ifdef _MSVC_VER +#pragma warning( push ) +#pragma warning( disable: 4250 ) +#pragma warning( disable: 4284 ) +#pragma warning( disable: 4996 ) +#elif defined(__GNUC__) && (__GNUC__ >= 4) +#pragma GCC system_header +#endif + #include #include #include @@ -30,14 +40,6 @@ #define YOREL_MM_TRACE(e) #endif -// Copied from Boost. -#ifdef _MSVC_VER -#pragma warning( push ) -#pragma warning( disable : 4584 4250) -#elif defined(__GNUC__) && (__GNUC__ >= 4) -#pragma GCC system_header -#endif - namespace yorel { namespace multi_methods { @@ -79,7 +81,7 @@ class bitvec { ref(word* p, int i) : p(p), i(i) { } operator bool() const { - return p[i / bpw] & (1 << (i % bpw)); + return (p[i / bpw] & (1 << (i % bpw))) != 0; } ref& operator =(bool val) { if (val) { @@ -147,7 +149,7 @@ class bitvec { } bool operator [](int i) const { - return p[i / bpw] & (1 << (i % bpw)); + return (p[i / bpw] & (1 << (i % bpw))) != 0; } ref operator [](int i) { return ref(p, i); } @@ -254,7 +256,7 @@ struct mm_class { std::vector rooted_here; // multi_methods rooted here for one or more args. bool abstract; - static std::unique_ptr> to_initialize; + static std::unordered_set* to_initialize; static void add_to_initialize(mm_class* pc); static void remove_from_initialize(mm_class* pc); @@ -349,7 +351,7 @@ struct multi_method_base { std::vector methods; std::vector steps; - static std::unique_ptr> to_initialize; + static std::unordered_set* to_initialize; static void add_to_initialize(multi_method_base* pm); static void remove_from_initialize(multi_method_base* pm); }; @@ -407,7 +409,7 @@ struct multi_method { using implementation = detail::multi_method_implementation; static implementation& the(); - static std::unique_ptr impl; + static implementation* impl; template static bool specialize() { @@ -415,14 +417,6 @@ struct multi_method { return true; } - template - struct register_spec { - register_spec() { - specialize(); - } - static register_spec the; - }; - template struct specialization { static method_pointer_type next; @@ -431,18 +425,26 @@ struct multi_method { }; }; +template +struct register_spec { + register_spec() { + Method::template specialize(); + + } + static register_spec the; + +}; + +template +register_spec register_spec::the; + template class Method, typename R, typename... P> template typename multi_method::method_pointer_type multi_method::specialization::next; template class Method, typename R, typename... P> -template -multi_method::register_spec -multi_method::register_spec::the; - -template class Method, typename R, typename... P> -std::unique_ptr::implementation> multi_method::impl; +typename multi_method::implementation* multi_method::impl; template class Method, typename R, typename... P> template @@ -451,7 +453,7 @@ typename multi_method::method_pointer_type multi_method class Method, typename R, typename... P> typename multi_method::implementation& multi_method::the() { if (!impl) { - impl.reset(new implementation); + impl = new implementation; } return *impl; @@ -471,4 +473,7 @@ inline R multi_method::method(typename detail::remove_virtual

#include #include +#include #include #include @@ -119,13 +120,12 @@ void mm_class::initialize(const vector& b) { }); } -unique_ptr> mm_class::to_initialize; - +unordered_set* mm_class::to_initialize; void mm_class::add_to_initialize(mm_class* pc) { YOREL_MM_TRACE(cout << "add to initialize: " << pc << endl); if (!to_initialize) { - to_initialize.reset(new unordered_set); + to_initialize = new unordered_set; } to_initialize->insert(pc); @@ -138,7 +138,8 @@ void mm_class::remove_from_initialize(mm_class* pc) { to_initialize->erase(pc); if (to_initialize->empty()) { - to_initialize.reset(); + delete to_initialize; + to_initialize = nullptr; } } } @@ -247,11 +248,11 @@ void hierarchy_initializer::assign_slots() { void initialize() { while (mm_class::to_initialize) { auto pc = *mm_class::to_initialize->begin(); - if (pc->is_root()) { - hierarchy_initializer::initialize(*pc); - } else { - mm_class::remove_from_initialize(pc); - } + if (pc->is_root()) { + hierarchy_initializer::initialize(*pc); + } else { + mm_class::remove_from_initialize(pc); + } } while (multi_method_base::to_initialize) { @@ -272,7 +273,7 @@ bool method_base::specializes(method_base* other) const { bool result = false; - for (int dim = 0; dim < args.size(); dim++) { + for (size_t dim = 0; dim < args.size(); dim++) { if (args[dim] != other->args[dim]) { if (args[dim]->specializes(*other->args[dim])) { result = true; @@ -344,11 +345,11 @@ void multi_method_base::invalidate() { add_to_initialize(this); } -unique_ptr> multi_method_base::to_initialize; +unordered_set* multi_method_base::to_initialize; void multi_method_base::add_to_initialize(multi_method_base* pm) { if (!to_initialize) { - to_initialize.reset(new unordered_set); + to_initialize = new unordered_set; } to_initialize->insert(pm); @@ -359,7 +360,8 @@ void multi_method_base::remove_from_initialize(multi_method_base* pm) { to_initialize->erase(pm); if (to_initialize->empty()) { - to_initialize.reset(); + delete to_initialize; + to_initialize = nullptr; } } } @@ -484,7 +486,7 @@ method_base* grouping_resolver::find_best(const vector& candidates while (best_iter != best.end()) { if (method->specializes(*best_iter)) { YOREL_MM_TRACE(cout << method << " specializes " << *best_iter << ", removed\n"); - best.erase(best_iter); + best_iter = best.erase(best_iter); } else if ((*best_iter)->specializes(method)) { YOREL_MM_TRACE(cout << *best_iter << " specializes " << method << ", removed\n"); best_iter = best.end(); diff --git a/tests/tests.cpp b/tests/tests.cpp index a4c2a78..f2f524c 100644 --- a/tests/tests.cpp +++ b/tests/tests.cpp @@ -68,6 +68,17 @@ bool throws(function fun) { return false; } +unsigned long binary(const char* digits) { + unsigned long bits = 0; + + while (*digits) { + bits <<= 1; + bits |= *digits++ == '1'; + } + + return bits; +} + DO { cout << boolalpha; } @@ -185,7 +196,7 @@ BEGIN_SPECIALIZATION(display, action, const Animal& a, const Mobile& b) { } -#ifndef __clang__ +#if !defined(__clang__) && !defined(_MSC_VER) namespace init_tests { @@ -306,7 +317,8 @@ BEGIN_SPECIALIZATION(display, action, Animal& a, Terminal& b) { struct Donkey : Herbivore { }; template<> -struct encounter_specialization : decltype(encounter)::specialization> { +struct encounter_specialization : remove_const::type::specialization> { + using body_signature = ::yorel::multi_methods::detail::signature; static string body(Cow&, Cow&) { return "moo!"; } @@ -585,7 +597,7 @@ int main() { } { - bitvec v(n, 0b101); + bitvec v(n, binary("101")); test(v[0], true); test(v[1], false); test(v[2], true); @@ -644,7 +656,7 @@ int main() { v[0] = 1; v[n - 1] = 1; test(v.none(), false); - v |= bitvec(n, 0b10); + v |= bitvec(n, binary("10")); test(v[0], true); test(v[1], true); test(v[n - 1], true); @@ -718,19 +730,19 @@ int main() { } { - bitvec v(3, 0b111); + bitvec v(3, binary("111")); test(v.size(), 3); - test(v[0], 1); - test(v[1], 1); - test(v[2], 1); + test(v[0], true); + test(v[1], true); + test(v[2], true); v.resize(2); test(v.size(), 2); - test(v[0], 1); - test(v[1], 1); + test(v[0], true); + test(v[1], true); v.resize(3); - test(v[0], 1); - test(v[1], 1); - test(v[2], 0); + test(v[0], true); + test(v[1], true); + test(v[2], false); } } @@ -765,14 +777,14 @@ int main() { test( init.nodes[7], &mm_class::of::the() ); init.make_masks(); - testx( init.nodes[0]->mask, bitvec(8, 0b11111111) ); // X - testx( init.nodes[1]->mask, bitvec(8, 0b01111110) ); // A - testx( init.nodes[2]->mask, bitvec(8, 0b00010100) ); // B - testx( init.nodes[3]->mask, bitvec(8, 0b01011000) ); // C - testx( init.nodes[4]->mask, bitvec(8, 0b00010000) ); // BC - testx( init.nodes[5]->mask, bitvec(8, 0b01100000) ); // D - testx( init.nodes[6]->mask, bitvec(8, 0b01000000) ); // CD - testx( init.nodes[7]->mask, bitvec(8, 0b10000000) ); // Y + testx( init.nodes[0]->mask, bitvec(8, binary("11111111")) ); // X + testx( init.nodes[1]->mask, bitvec(8, binary("01111110")) ); // A + testx( init.nodes[2]->mask, bitvec(8, binary("00010100")) ); // B + testx( init.nodes[3]->mask, bitvec(8, binary("01011000")) ); // C + testx( init.nodes[4]->mask, bitvec(8, binary("00010000")) ); // BC + testx( init.nodes[5]->mask, bitvec(8, binary("01100000")) ); // D + testx( init.nodes[6]->mask, bitvec(8, binary("01000000")) ); // CD + testx( init.nodes[7]->mask, bitvec(8, binary("10000000")) ); // Y init.assign_slots(); test(m_x.the().slots[0], 0); @@ -1123,7 +1135,8 @@ int main() { test( multi_method_base::to_initialize != nullptr, true ); test( multi_method_base::to_initialize->size(), 1 ); - encounter.impl.reset(); + delete encounter.impl; + encounter.impl = nullptr; test( mm_class::of::the().rooted_here.size(), 1 ); test( !multi_method_base::to_initialize, true );