├── .clang-format ├── .github └── workflows │ ├── main.yml │ └── probe.yml ├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── CMakePresets.json ├── CODEOWNERS ├── LICENSE ├── README.md ├── ce ├── 2-method-vptr-final.cpp ├── 2-method-vptr.cpp ├── 2-method.cpp ├── CMakeLists.txt ├── README.md ├── uni-method-vptr-final.cpp ├── uni-method-vptr.cpp ├── uni-method.cpp ├── virtual-double.cpp └── virtual.cpp ├── clang-llvm ├── cmake └── YOMM2Config.cmake.in ├── dev ├── __init__.py ├── bm2md ├── bm2mdplot ├── bmutils.py ├── check-index ├── ci-pre-configure-clang ├── ci-pre-configure-gcc ├── clang-format-all ├── code2md ├── compilation-benchmark ├── container ├── create-docker-image ├── extract-dump ├── md2md ├── mdgen.py ├── ppfc ├── presetgen ├── reformat ├── run-benchmarks ├── run-benchmarks-here ├── run-cmake ├── run-iwyu ├── run-target ├── run-tests ├── vs-cmake.bat └── yomm2filt ├── docker ├── Dockerfile ├── build-image ├── run └── yomm2-init-image.sh ├── docs.in ├── CMakeLists.txt ├── README.md ├── reference │ ├── CMakeLists.txt │ ├── RestrictedOutputStream.md │ ├── RuntimeClass.md │ ├── YOMM2_GENSYM.md │ ├── YOMM2_STATIC.md │ ├── YOMM2_SYMBOL.cpp │ ├── aggregate.cpp │ ├── apply_product.cpp │ ├── class_declaration.md │ ├── declare_method.md │ ├── declare_static_method.cpp │ ├── define_method.cpp │ ├── define_method_inline.md │ ├── error.md │ ├── friend_method.md │ ├── generator.md │ ├── method.cpp │ ├── method_call_error.md │ ├── method_class.cpp │ ├── method_container.cpp │ ├── method_definition.md │ ├── not_defined.md │ ├── policy-basic_error_output.md │ ├── policy-basic_policy.md │ ├── policy-basic_trace_output.md │ ├── policy-checked_perfect_hash.md │ ├── policy-deferred_static_rtti.md │ ├── policy-error_handler.md │ ├── policy-error_output.md │ ├── policy-fast_perfect_hash.md │ ├── policy-minimal_rtti.cpp │ ├── policy-rtti.md │ ├── policy-std_rtti.md │ ├── policy-throw_error.cpp │ ├── policy-trace_output.md │ ├── policy-type_hash.md │ ├── policy-vectored_error.md │ ├── policy-vptr_map.md │ ├── policy-vptr_placement.cpp │ ├── policy-vptr_vector.md │ ├── product.cpp │ ├── register_class.md │ ├── set_error_handler.cpp │ ├── static_object.md │ ├── template_.cpp │ ├── templates.md │ ├── type_id.md │ ├── types.md │ ├── update.md │ ├── update_methods.md │ ├── use_classes.cpp │ ├── use_definitions.cpp │ ├── virtual_.cpp │ └── virtual_ptr.cpp └── tutorials │ ├── CMakeLists.txt │ ├── api.cpp │ ├── api.md │ ├── custom_rtti_tutorial.cpp │ ├── custom_rtti_tutorial.md │ ├── templates_tutorial.cpp │ ├── templates_tutorial.md │ ├── templates_tutorial_matrix_1.cpp │ ├── templates_tutorial_matrix_2.cpp │ ├── templates_tutorial_vector_1.cpp │ └── templates_tutorial_vector_2.cpp ├── docs ├── README.md ├── articles │ └── performance.md ├── benchmarks │ ├── 1vec.euclid.clang.json │ ├── 1vec.euclid.clang.md │ ├── 4vec.euclid.clang.json │ ├── 4vec.euclid.clang.md │ ├── v010500.euclid.clang.json │ ├── v010500.euclid.clang.md │ └── v140.euclid.clang.md ├── ce │ ├── 2d-vs-2m-ref.html │ ├── 2d-vs-2m-vptr.html │ ├── slides.html │ ├── vf-vs-1m-ref.html │ ├── vf-vs-1m-vptr.html │ └── vptr-final.html ├── cppnow2018 │ ├── ast.cpp │ ├── call_pay.s │ ├── cppnow2018.md │ ├── index.html │ ├── pay-decl.cpp │ ├── preprocess.sh │ ├── rolex.cpp │ ├── yomm2 - Fast, Orthogonal, Open Methods.pdf │ └── yomm2 - Fast, Orthogonal, Open Methods_files │ │ ├── black.css │ │ ├── head.min.js │ │ ├── highlight.js │ │ ├── livereload.js │ │ ├── markdown.js │ │ ├── marked.js │ │ ├── notes.js │ │ ├── paper.css │ │ ├── reveal.css │ │ ├── reveal.js │ │ └── zenburn.css ├── reference │ ├── RestrictedOutputStream.md │ ├── RuntimeClass.md │ ├── YOMM2_GENSYM.md │ ├── YOMM2_STATIC.md │ ├── YOMM2_SYMBOL.md │ ├── aggregate.md │ ├── apply_product.md │ ├── class_declaration.md │ ├── declare_method.md │ ├── declare_static_method.md │ ├── define_method.md │ ├── define_method_inline.md │ ├── error.md │ ├── friend_method.md │ ├── generator.md │ ├── method.md │ ├── method_call_error.md │ ├── method_class.md │ ├── method_container.md │ ├── method_definition.md │ ├── not_defined.md │ ├── policy-basic_error_output.md │ ├── policy-basic_policy.md │ ├── policy-basic_trace_output.md │ ├── policy-checked_perfect_hash.md │ ├── policy-deferred_static_rtti.md │ ├── policy-error_handler.md │ ├── policy-error_output.md │ ├── policy-fast_perfect_hash.md │ ├── policy-minimal_rtti.md │ ├── policy-rtti.md │ ├── policy-std_rtti.md │ ├── policy-throw_error.md │ ├── policy-trace_output.md │ ├── policy-type_hash.md │ ├── policy-vectored_error.md │ ├── policy-vptr_map.md │ ├── policy-vptr_placement.md │ ├── policy-vptr_vector.md │ ├── product.md │ ├── register_class.md │ ├── set_error_handler.md │ ├── static_object.md │ ├── template_.md │ ├── templates.md │ ├── type_id.md │ ├── types.md │ ├── update.md │ ├── update_methods.md │ ├── use_classes.md │ ├── use_definitions.md │ ├── virtual_.md │ └── virtual_ptr.md ├── slides │ ├── YOMM2-corecpp.pdf │ ├── YOMM2-using-std-cpp-2024.pdf │ ├── YOMM2.pdf │ ├── deck │ │ ├── 01-title.md │ │ ├── 02-expression-problem.md │ │ ├── 03-ast.md │ │ ├── 04-open-methods.md │ │ ├── 05-inside.md │ │ ├── 06-evolution.md │ │ └── 99-qa.md │ ├── resources │ │ ├── corecpp2024.png │ │ ├── qr.png │ │ └── slides-on-compiler-explorer.png │ ├── run │ ├── run-release │ └── theme │ │ └── yomm2.css └── tutorials │ ├── api.md │ ├── custom_rtti_tutorial.md │ └── templates_tutorial.md ├── examples ├── CMakeLists.txt ├── README.cpp ├── README.md ├── accept_no_visitors.cpp ├── adventure.cpp ├── api.md ├── asteroids.cpp ├── cmakeyomm2 │ ├── CMakeLists.txt │ ├── README.md │ └── adventure.cpp ├── conan │ ├── CMakeLists.txt │ ├── README.md │ ├── adventure.cpp │ └── conanfile.txt ├── containers │ ├── CMakeLists.txt │ ├── README.md │ ├── arc_painter.cpp │ ├── concrete_shape_painters.cpp │ ├── geometries.hpp │ ├── line_painter.cpp │ ├── line_painter.hpp │ ├── main.cpp │ ├── painter.cpp │ ├── painter.hpp │ ├── segment_painter.cpp │ ├── shape_painter.cpp │ └── shape_painter.hpp ├── dl.hpp ├── dl_main.cpp ├── dl_shared.cpp ├── generator │ ├── CMakeLists.txt │ ├── README.md │ ├── animals.cpp │ ├── animals.hpp │ ├── generator_app.cpp │ └── generator_gen.cpp ├── matrix.cpp ├── next.cpp ├── slides.cpp ├── synopsis.cpp └── vcpkg │ ├── CMakeLists.txt │ ├── CMakePresets.json │ ├── adventure.cpp │ └── vcpkg.json ├── include └── yorel │ ├── yomm2.hpp │ └── yomm2 │ ├── core.hpp │ ├── cute.hpp │ ├── decode.hpp │ ├── detail.hpp │ ├── detail │ ├── compiler.hpp │ ├── ostdstream.hpp │ ├── static_list.hpp │ ├── trace.hpp │ └── types.hpp │ ├── generator.hpp │ ├── keywords.hpp │ ├── macros.hpp │ ├── policies │ ├── basic_error_output.hpp │ ├── basic_indirect_vptr.hpp │ ├── basic_trace_output.hpp │ ├── core.hpp │ ├── fast_perfect_hash.hpp │ ├── minimal_rtti.hpp │ ├── std_rtti.hpp │ ├── throw_error.hpp │ ├── vectored_error.hpp │ ├── vptr_map.hpp │ └── vptr_vector.hpp │ ├── policy.hpp │ ├── symbols.hpp │ └── templates.hpp ├── reference.boilerplate ├── class.cpp ├── class.md └── member.md ├── src ├── CMakeLists.txt └── yomm2.cpp ├── tests ├── CMakeLists.txt ├── benchmark_rdtsc.cpp ├── benchmarks.cpp ├── benchmarks_parameters.hpp ├── run-rdtsc-benchmark ├── test_blackbox.cpp ├── test_compiler.cpp ├── test_core.cpp ├── test_custom_rtti.cpp ├── test_generator.cpp ├── test_generator_domain.cpp ├── test_generator_domain.hpp ├── test_generator_forward_decls.cpp ├── test_generator_gen.cpp ├── test_lab.cpp ├── test_manual_call.cpp ├── test_member_method.cpp ├── test_move.cpp ├── test_namespaces.cpp ├── test_pointer_to_method.cpp ├── test_pss1.cpp ├── test_rolex.cpp ├── test_static_list.cpp ├── test_templates.cpp ├── test_util.hpp ├── test_virtual_ptr.cpp ├── test_virtual_ptr_all.cpp └── test_virtual_ptr_basic.cpp ├── vcpkg-configuration.json ├── vcpkg.json └── yomm11-yomm2.md /.github/workflows/probe.yml: -------------------------------------------------------------------------------- 1 | name: Probe Workflow 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | jobs: 7 | probe: 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - name: List available compilers 12 | run: | 13 | lsb_release -a 14 | apt list --installed | grep clang 15 | apt list --installed | grep g++ 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .hrefs 2 | .rtags 3 | build/ 4 | builds/ 5 | **/#*# 6 | dependencies/* 7 | extern/* 8 | tests/benchmarks_parameters.hpp 9 | **/vcpkg_installed 10 | .venv/ 11 | 12 | # ides 13 | .vscode/ 14 | .vs/ 15 | CMakeSettings.json 16 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "vcpkg"] 2 | path = vcpkg 3 | url = https://github.com/microsoft/vcpkg 4 | branch = 1de2026f 5 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @jll63 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Boost Software License - Version 1.0 - August 17th, 2003 2 | 3 | Permission is hereby granted, free of charge, to any person or organization 4 | obtaining a copy of the software and accompanying documentation covered by 5 | this license (the "Software") to use, reproduce, display, distribute, 6 | execute, and transmit the Software, and to prepare derivative works of the 7 | Software, and to permit third-parties to whom the Software is furnished to 8 | do so, all subject to the following: 9 | 10 | The copyright notices in the Software and this entire statement, including 11 | the above license grant, this restriction and the following disclaimer, 12 | must be included in all copies of the Software, in whole or in part, and 13 | all derivative works of the Software, unless such copies or derivative 14 | works are solely in the form of machine-executable object code generated by 15 | a source language processor. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /ce/2-method-vptr-final.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | struct Animal { 6 | const char* name; 7 | Animal(const char* name) : name(name) { 8 | } 9 | }; 10 | 11 | struct Dog : Animal { 12 | using Animal::Animal; 13 | }; 14 | 15 | struct Cat : Animal { 16 | using Animal::Animal; 17 | }; 18 | 19 | register_classes(Animal, Dog, Cat); 20 | 21 | using yorel::yomm2::virtual_ptr; 22 | 23 | declare_method( 24 | void, meet, (virtual_ptr, virtual_ptr, std::ostream&)); 25 | 26 | define_method( 27 | void, meet, (virtual_ptr a1, virtual_ptr a2, std::ostream& os)) { 28 | os << a1->name << " ignores " << a2->name << "\n"; 29 | } 30 | 31 | define_method( 32 | void, meet, (virtual_ptr a1, virtual_ptr a2, std::ostream& os)) { 33 | os << a1->name << " chases " << a2->name << "\n"; 34 | } 35 | 36 | define_method( 37 | void, meet, (virtual_ptr a1, virtual_ptr a2, std::ostream& os)) { 38 | os << a1->name << " runs away from " << a2->name << "\n"; 39 | } 40 | 41 | define_method( 42 | void, meet, (virtual_ptr a1, virtual_ptr a2, std::ostream& os)) { 43 | os << a1->name << " wags tail at " << a2->name << "\n"; 44 | } 45 | 46 | void meet_animals( 47 | const std::vector>& animals, std::ostream& os) { 48 | for (auto animal : animals) { 49 | for (auto other : animals) { 50 | if (&animal != &other) { 51 | meet(animal, other, os); 52 | } 53 | } 54 | } 55 | } 56 | 57 | int main() { 58 | yorel::yomm2::update(); 59 | 60 | Dog hector{"Hector"}, snoopy{"Snoopy"}; 61 | Cat felix{"Felix"}, sylvester{"Sylvester"}; 62 | std::vector> animals = { 63 | virtual_ptr::final(hector), virtual_ptr::final(felix), 64 | virtual_ptr::final(sylvester), virtual_ptr::final(snoopy)}; 65 | 66 | meet_animals(animals, std::cout); 67 | } 68 | -------------------------------------------------------------------------------- /ce/2-method-vptr.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | struct Animal { 6 | const char* name; 7 | Animal(const char* name) : name(name) { 8 | } 9 | virtual ~Animal() { 10 | } 11 | }; 12 | 13 | struct Dog : Animal { 14 | using Animal::Animal; 15 | }; 16 | 17 | struct Cat : Animal { 18 | using Animal::Animal; 19 | }; 20 | 21 | register_classes(Animal, Dog, Cat); 22 | 23 | using yorel::yomm2::virtual_ptr; 24 | 25 | declare_method( 26 | void, meet, (virtual_ptr, virtual_ptr, std::ostream&)); 27 | 28 | define_method( 29 | void, meet, (virtual_ptr a1, virtual_ptr a2, std::ostream& os)) { 30 | os << a1->name << " ignores " << a2->name << "\n"; 31 | } 32 | 33 | define_method( 34 | void, meet, (virtual_ptr a1, virtual_ptr a2, std::ostream& os)) { 35 | os << a1->name << " chases " << a2->name << "\n"; 36 | } 37 | 38 | define_method( 39 | void, meet, (virtual_ptr a1, virtual_ptr a2, std::ostream& os)) { 40 | os << a1->name << " runs away from " << a2->name << "\n"; 41 | } 42 | 43 | define_method( 44 | void, meet, (virtual_ptr a1, virtual_ptr a2, std::ostream& os)) { 45 | os << a1->name << " wags tail at " << a2->name << "\n"; 46 | } 47 | 48 | void meet_animals(const std::vector>& animals, std::ostream& os) { 49 | for (auto animal : animals) { 50 | for (auto other : animals) { 51 | if (&animal != &other) { 52 | meet(animal, other, os); 53 | } 54 | } 55 | } 56 | } 57 | 58 | int main() { 59 | yorel::yomm2::update(); 60 | 61 | Dog hector{"Hector"}, snoopy{"Snoopy"}; 62 | Cat felix{"Felix"}, sylvester{"Sylvester"}; 63 | std::vector> animals = { 64 | hector, felix, sylvester, snoopy}; 65 | 66 | meet_animals(animals, std::cout); 67 | } 68 | -------------------------------------------------------------------------------- /ce/2-method.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | struct Animal { 6 | const char* name; 7 | Animal(const char* name) : name(name) { 8 | } 9 | virtual ~Animal() { 10 | } 11 | }; 12 | 13 | struct Dog : Animal { 14 | using Animal::Animal; 15 | }; 16 | 17 | struct Cat : Animal { 18 | using Animal::Animal; 19 | }; 20 | 21 | register_classes(Animal, Dog, Cat); 22 | 23 | declare_method( 24 | void, meet, (virtual_, virtual_, std::ostream&)); 25 | 26 | define_method(void, meet, (Cat& a1, Cat& a2, std::ostream& os)) { 27 | os << a1.name << " ignores " << a2.name << "\n"; 28 | } 29 | 30 | define_method(void, meet, (Dog& a1, Cat& a2, std::ostream& os)) { 31 | os << a1.name << " chases " << a2.name << "\n"; 32 | } 33 | 34 | define_method(void, meet, (Cat& a1, Dog& a2, std::ostream& os)) { 35 | os << a1.name << " runs away from " << a2.name << "\n"; 36 | } 37 | 38 | define_method(void, meet, (Dog& a1, Dog& a2, std::ostream& os)) { 39 | os << a1.name << " wags tail at " << a2.name << "\n"; 40 | } 41 | 42 | void meet_animals(const std::vector& animals, std::ostream& os) { 43 | for (auto animal : animals) { 44 | for (auto other : animals) { 45 | if (&animal !=&other) { 46 | meet(*animal, *other, os); 47 | } 48 | } 49 | } 50 | } 51 | 52 | int main() { 53 | yorel::yomm2::update(); 54 | 55 | Dog hector{"Hector"}, snoopy{"Snoopy"}; 56 | Cat felix{"Felix"}, sylvester{"Sylvester"}; 57 | std::vector animals = {&hector,&felix,&sylvester,&snoopy}; 58 | 59 | meet_animals(animals, std::cout); 60 | } 61 | -------------------------------------------------------------------------------- /ce/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2024 Jean-Louis Leroy 2 | # Distributed uce_nder the Boost Software License, Version 1.0. 3 | # See accompanying filce_e LICENSE_1_0.txt 4 | # or copy at hce_ttp://www.boost.oce_rg/LICENSE_1_0.txt) 5 | 6 | add_executable(ce_virtual virtual.cpp) 7 | target_link_libraries(ce_virtual YOMM2::yomm2) 8 | add_test(NAME ce_virtual COMMAND ce_virtual) 9 | 10 | add_executable(ce_uni-method uni-method.cpp) 11 | target_link_libraries(ce_uni-method YOMM2::yomm2) 12 | add_test(NAME ce_uni-method COMMAND ce_uni-method) 13 | 14 | add_executable(ce_uni-method-vptr uni-method-vptr.cpp) 15 | target_link_libraries(ce_uni-method-vptr YOMM2::yomm2) 16 | add_test(NAME ce_uni-method-vptr COMMAND ce_uni-method-vptr) 17 | 18 | add_executable(ce_virtual-double virtual-double.cpp) 19 | target_link_libraries(ce_virtual-double YOMM2::yomm2) 20 | add_test(NAME ce_virtual-double COMMAND ce_virtual-double) 21 | 22 | add_executable(ce_2-method 2-method.cpp) 23 | target_link_libraries(ce_2-method YOMM2::yomm2) 24 | add_test(NAME ce_2-method COMMAND ce_2-method) 25 | 26 | add_executable(ce_2-method-vptr 2-method-vptr.cpp) 27 | target_link_libraries(ce_2-method-vptr YOMM2::yomm2) 28 | add_test(NAME ce_2-method-vptr COMMAND ce_2-method-vptr) 29 | 30 | add_executable(ce_2-method-vptr-final 2-method-vptr-final.cpp) 31 | target_link_libraries(ce_2-method-vptr-final YOMM2::yomm2) 32 | add_test(NAME ce_2-method-vptr-fince_al COMMAND ce_2-method-vptr-final) 33 | 34 | add_executable(ce_uni-method-vptr-final uni-method-vptr-final.cpp) 35 | target_link_libraries(ce_uni-method-vptr-final YOMM2::yomm2) 36 | add_test(NAME ce_uni-method-vptr-fce_inal COMMAND ce_uni-method-vptr-final) 37 | -------------------------------------------------------------------------------- /ce/README.md: -------------------------------------------------------------------------------- 1 | # YOMM2 on Compiler Explorer 2 | 3 | YOMM2 is available on Compiler Explorer. Make sure that you also select Boost 4 | version 1.74 or above, and you probably want to add the `-O3 -DNDEBUG` compiler 5 | switches. 6 | 7 | The following examples are available: 8 | 9 | * The [examples](https://jll63.github.io/yomm2/ce/slides.html) from the slides. 10 | * The matrix example from the GitHub langing page. 11 | 12 | The following examples use the diff mode to compare open methods with the 13 | equivalent (closed) virtual function based approaches. 14 | 15 | * [virtual function call vs uni-method call via plain reference](https://jll63.github.io/yomm2/ce/vf-vs-1m-ref.html) 16 | * [virtual function call vs uni-method call via virtual_ptr ](https://jll63.github.io/yomm2/ce/vf-vs-1m-vptr.html) 17 | * [double dispatch vs multi-method call via plain reference](https://jll63.github.io/yomm2/ce/2d-vs-2m-ref.html) 18 | * [double dispatch vs multi-method call via virtual_ptr ](https://jll63.github.io/yomm2/ce/2d-vs-2m-vptr.html) 19 | 20 | YOMM2 can also [add polymorphic operations to non-polymorphic 21 | classes](https://jll63.github.io/yomm2/ce/vptr-final.html). 22 | 23 | When `virtual_ptr` is used in combination with generated static offsets, method 24 | dispatch matches the speed of virtual functions. It is also possible to generate 25 | dispatch data that can be installed without calling `update`, a fairly expensive 26 | operaiton. See [this example](https://jll63.github.io/yomm2/ce/generator.html). 27 | -------------------------------------------------------------------------------- /ce/uni-method-vptr-final.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | struct Animal { 7 | const char* name; 8 | Animal(const char* name) : name(name) { 9 | } 10 | }; 11 | 12 | struct Dog : Animal { 13 | using Animal::Animal; 14 | }; 15 | 16 | struct Cat : Animal { 17 | using Animal::Animal; 18 | }; 19 | 20 | register_classes(Animal, Dog, Cat); 21 | 22 | using yorel::yomm2::virtual_ptr; 23 | using yorel::yomm2::final_virtual_ptr; 24 | 25 | declare_method(void, kick, (virtual_ptr, std::ostream&)); 26 | 27 | define_method(void, kick, (virtual_ptr animal, std::ostream& os)) { 28 | os << animal->name << " hisses.\n"; 29 | } 30 | 31 | define_method(void, kick, (virtual_ptr animal, std::ostream& os)) { 32 | os << animal->name << " barks.\n"; 33 | } 34 | 35 | void kick_animals( 36 | const std::vector>& animals, std::ostream& os) { 37 | for (auto animal : animals) { 38 | kick(animal, os); 39 | } 40 | } 41 | 42 | int main() { 43 | yorel::yomm2::update(); 44 | 45 | Dog hector{"Hector"}, snoopy{"Snoopy"}; 46 | Cat felix{"Felix"}, sylvester{"Sylvester"}; 47 | std::vector> animals = { 48 | final_virtual_ptr(hector), virtual_ptr::final(felix), 49 | final_virtual_ptr(sylvester), virtual_ptr::final(snoopy)}; 50 | 51 | kick_animals(animals, std::cout); 52 | } 53 | -------------------------------------------------------------------------------- /ce/uni-method-vptr.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | struct Animal { 6 | const char* name; 7 | Animal(const char* name) : name(name) { 8 | } 9 | virtual ~Animal() {} 10 | }; 11 | 12 | struct Dog : Animal { 13 | using Animal::Animal; 14 | }; 15 | 16 | struct Cat : Animal { 17 | using Animal::Animal; 18 | }; 19 | 20 | register_classes(Animal, Dog, Cat); 21 | 22 | using yorel::yomm2::virtual_ptr; 23 | 24 | declare_method(void, kick, (virtual_ptr, std::ostream&)); 25 | 26 | define_method(void, kick, (virtual_ptr animal, std::ostream& os)) { 27 | os << animal->name << " hisses.\n"; 28 | } 29 | 30 | define_method(void, kick, (virtual_ptr animal, std::ostream& os)) { 31 | os << animal->name << " barks.\n"; 32 | } 33 | 34 | void kick_animals( 35 | const std::vector>& animals, std::ostream& os) { 36 | for (auto animal : animals) { 37 | kick(animal, os); 38 | } 39 | } 40 | 41 | int main() { 42 | yorel::yomm2::update(); 43 | 44 | Dog hector{"Hector"}, snoopy{"Snoopy"}; 45 | Cat felix{"Felix"}, sylvester{"Sylvester"}; 46 | std::vector> animals = { 47 | hector, felix, sylvester, snoopy}; 48 | 49 | kick_animals(animals, std::cout); 50 | } 51 | -------------------------------------------------------------------------------- /ce/uni-method.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | struct Animal { 6 | const char* name; 7 | Animal(const char* name) : name(name) { 8 | } 9 | virtual ~Animal() { 10 | } 11 | }; 12 | 13 | struct Dog : Animal { 14 | using Animal::Animal; 15 | }; 16 | 17 | struct Cat : Animal { 18 | using Animal::Animal; 19 | }; 20 | 21 | register_classes(Animal, Dog, Cat); 22 | 23 | declare_method(void, kick, (virtual_, std::ostream&)); 24 | 25 | define_method(void, kick, (Cat& animal, std::ostream& os)) { 26 | os << animal.name << " hisses.\n"; 27 | } 28 | 29 | define_method(void, kick, (Dog& animal, std::ostream& os)) { 30 | os << animal.name << " barks.\n"; 31 | } 32 | 33 | void kick_animals(const std::vector& animals, std::ostream& os) { 34 | for (auto animal : animals) { 35 | kick(*animal, os); 36 | } 37 | } 38 | 39 | int main() { 40 | yorel::yomm2::update(); 41 | 42 | Dog hector{"Hector"}, snoopy{"Snoopy"}; 43 | Cat felix{"Felix"}, sylvester{"Sylvester"}; 44 | std::vector animals = {&hector, &felix, &sylvester, &snoopy}; 45 | 46 | kick_animals(animals, std::cout); 47 | } 48 | -------------------------------------------------------------------------------- /ce/virtual-double.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct Cat; 5 | struct Dog; 6 | 7 | struct Animal { 8 | const char* name; 9 | Animal(const char* name) : name(name) { 10 | } 11 | virtual ~Animal() { 12 | } 13 | virtual void meet(Animal& other, std::ostream& os) = 0; 14 | virtual void meet_cat(Cat& other, std::ostream& os) = 0; 15 | virtual void meet_dog(Dog& other, std::ostream& os) = 0; 16 | }; 17 | 18 | struct Cat : Animal { 19 | using Animal::Animal; 20 | void meet(Animal& other, std::ostream& os) override; 21 | void meet_cat(Cat& other, std::ostream& os) override; 22 | void meet_dog(Dog& other, std::ostream& os) override; 23 | }; 24 | 25 | struct Dog : Animal { 26 | using Animal::Animal; 27 | void meet(Animal& other, std::ostream& os) override; 28 | void meet_cat(Cat& other, std::ostream& os) override; 29 | void meet_dog(Dog& other, std::ostream& os) override; 30 | }; 31 | 32 | void meet_animals(const std::vector& animals, std::ostream& os) { 33 | for (auto animal : animals) { 34 | for (auto other : animals) { 35 | if (animal != other) { 36 | animal->meet(*other, os); 37 | } 38 | } 39 | } 40 | } 41 | 42 | int main() { 43 | Dog hector{"Hector"}, snoopy{"Snoopy"}; 44 | Cat felix{"Felix"}, sylvester{"Sylvester"}; 45 | std::vector animals = {&hector, &felix, &sylvester, &snoopy}; 46 | meet_animals(animals, std::cout); 47 | } 48 | 49 | void Cat::meet(Animal& other, std::ostream& os) { 50 | other.meet_cat(*this, os); 51 | } 52 | 53 | void Cat::meet_cat(Cat& other, std::ostream& os) { 54 | os << name << " ignores " << other.name << "\n"; 55 | } 56 | 57 | void Cat::meet_dog(Dog& other, std::ostream& os) { 58 | os << name << " runs away from " << other.name << "\n"; 59 | } 60 | 61 | void Dog::meet(Animal& other, std::ostream& os) { 62 | other.meet_dog(*this, os); 63 | } 64 | void Dog::meet_cat(Cat& other, std::ostream& os) { 65 | os << name << " chases " << other.name << "\n"; 66 | } 67 | void Dog::meet_dog(Dog& other, std::ostream& os) { 68 | os << name << " wags tail at " << other.name << "\n"; 69 | } 70 | -------------------------------------------------------------------------------- /ce/virtual.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct Animal { 5 | const char* name; 6 | Animal(const char* name) : name(name) { 7 | } 8 | virtual ~Animal() { 9 | } 10 | virtual void kick(std::ostream& os) = 0; 11 | }; 12 | 13 | struct Dog : Animal { 14 | using Animal::Animal; 15 | void kick(std::ostream& os) override { 16 | os << name << " barks.\n"; 17 | } 18 | }; 19 | 20 | struct Cat : Animal { 21 | using Animal::Animal; 22 | void kick(std::ostream& os) override { 23 | os << name << " hisses.\n"; 24 | } 25 | }; 26 | 27 | void kick_animals(const std::vector& animals, std::ostream& os) { 28 | for (auto animal : animals) { 29 | animal->kick(os); 30 | } 31 | } 32 | 33 | int main() { 34 | Dog hector{"Hector"}, snoopy{"Snoopy"}; 35 | Cat felix{"Felix"}, sylvester{"Sylvester"}; 36 | std::vector animals = {&hector, &felix, &sylvester, &snoopy}; 37 | kick_animals(animals, std::cout); 38 | } 39 | -------------------------------------------------------------------------------- /cmake/YOMM2Config.cmake.in: -------------------------------------------------------------------------------- 1 | @PACKAGE_INIT@ 2 | 3 | include(CMakeFindDependencyMacro) 4 | 5 | # Tell library users about the Boost dependency 6 | find_dependency(Boost 1.74... REQUIRED) 7 | 8 | # Add the targets file 9 | include("${CMAKE_CURRENT_LIST_DIR}/YOMM2Targets.cmake") 10 | 11 | check_required_components(YOMM2) 12 | -------------------------------------------------------------------------------- /dev/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jll63/yomm2/6c2204c5e6d3733bff7bc59ee1d2e95bdbff1bff/dev/__init__.py -------------------------------------------------------------------------------- /dev/check-index: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import mdgen 4 | 5 | from pathlib import Path 6 | 7 | refs = set("home reference static_object virtual_ptr-final".split()) 8 | 9 | with open(mdgen.repository.joinpath("docs.in", "README.md")) as ref: 10 | for line in ref.readlines(): 11 | if line.startswith("| ->"): 12 | refs.add(line.split()[1].replace("->", "")) 13 | 14 | for ref in mdgen.hrefs: 15 | if ref not in refs: 16 | print(ref) 17 | -------------------------------------------------------------------------------- /dev/ci-pre-configure-clang: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | wget https://apt.llvm.org/llvm.sh 4 | chmod +x llvm.sh 5 | sudo ./llvm.sh $1 6 | -------------------------------------------------------------------------------- /dev/ci-pre-configure-gcc: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | sudo add-apt-repository ppa:ubuntu-toolchain-r/ppa 4 | sudo apt update 5 | sudo apt install -y g++-$1 6 | -------------------------------------------------------------------------------- /dev/clang-format-all: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | find include src examples tests docs.in -type f -name "*.?pp" | xargs clang-format -i 4 | -------------------------------------------------------------------------------- /dev/compilation-benchmark: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import time 4 | import subprocess as sp 5 | 6 | COMPILE_FORMAT = ( 7 | "clang++ -c -std=c++17 -I include -I build/code/dependencies/Boost/include" 8 | " -DBREADTH={breadth} -DDEPTH={depth} -DMETHOD={method} tests/lab.cpp" 9 | ) 10 | RUNS = 20 11 | 12 | 13 | def compile(**kwargs): 14 | sp.check_call(COMPILE_FORMAT.format(**kwargs), shell=True, stderr=sp.DEVNULL) 15 | 16 | 17 | for breadth in range(1, 20 + 1): 18 | print(f"\n{breadth=}") 19 | died = [] 20 | for depth in range(1, 50 + 1): 21 | tara = 0 22 | print(f"{depth:>2d}", end="") 23 | 24 | for method in range(1, 3 + 1): 25 | if method in died: 26 | print(" -", end="") 27 | continue 28 | 29 | sum = 0 30 | try: 31 | for _ in range(RUNS): 32 | start = time.perf_counter() 33 | compile(breadth=breadth, depth=depth, method=method) 34 | sum += time.perf_counter() - start 35 | print(f" {(sum - tara)/RUNS:6.2f}", end="") 36 | except sp.CalledProcessError: 37 | died.append(method) 38 | print(" -", end="") 39 | 40 | print() 41 | -------------------------------------------------------------------------------- /dev/container: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | repo=$(realpath $(dirname 0)/..) 4 | 5 | docker run -it --rm -v $repo:$repo yomm2:latest "$@" 6 | -------------------------------------------------------------------------------- /dev/create-docker-image: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | docker build \ 4 | --build-arg USER=$USER --build-arg UID=$(id -u) \ 5 | --build-arg GROUP=$(id -g -n jll) --build-arg GID=$(id -g) \ 6 | -t yomm2:latest $(dirname $0)/../docker 7 | -------------------------------------------------------------------------------- /dev/extract-dump: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import argparse 4 | import fileinput 5 | from itertools import count 6 | import re 7 | 8 | parser = argparse.ArgumentParser() 9 | parser.add_argument("-s", "--simplify", nargs="*", default=[]) 10 | parser.add_argument("files", nargs="*", default=("-")) 11 | args = parser.parse_args() 12 | 13 | DUMP_RX = r"std::is_same_v<(.*),\s*yorel::yomm2::yomm2_end_of_dump>" 14 | SIMPLIFICATIONS = [r"(boost|yorel)::(\w+::)+", r",hash_factors_in_globals"] 15 | 16 | input = [] 17 | 18 | for line in fileinput.input(files=args.files): 19 | input.append(line) 20 | if match := re.search(DUMP_RX, line): 21 | output = re.sub(r"\s+", "", match.group(1)) 22 | for rx in SIMPLIFICATIONS + args.simplify: 23 | output = re.sub(rx, "", output) 24 | print(output) 25 | exit(0) 26 | 27 | print("no dump found in:") 28 | for line in input: 29 | print(line) -------------------------------------------------------------------------------- /dev/md2md: -------------------------------------------------------------------------------- 1 | #!/bin/env python3 2 | 3 | import contextlib 4 | from pathlib import Path 5 | import os 6 | import sys 7 | 8 | import mdgen 9 | 10 | out_path = Path(sys.argv[2]).absolute() 11 | 12 | source = os.path.abspath(sys.argv[1]).replace(os.path.abspath(mdgen.repository), "") 13 | 14 | with open(sys.argv[1]) as rh: 15 | text = rh.read() 16 | 17 | with contextlib.suppress(FileNotFoundError): 18 | out_path.chmod(0o600) 19 | 20 | with open(out_path, "w") as wh: 21 | text = mdgen.replace_md(text, source=source) 22 | print(text, file=wh, end="") 23 | 24 | out_path.chmod(0o400) 25 | -------------------------------------------------------------------------------- /dev/ppfc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import re 5 | from subprocess import Popen, PIPE 6 | import sys 7 | 8 | preprocess = [] 9 | compile = [] 10 | args = iter(sys.argv[1:]) 11 | verbose = int(os.environ.get("VERBOSE", 0)) != 0 12 | 13 | while True: 14 | arg = next(args, None) 15 | if arg is None: 16 | break 17 | 18 | if arg == "-c": 19 | preprocess.append("-E") 20 | compile.append(arg) 21 | continue 22 | 23 | if arg == "-o": 24 | compile.append(arg) 25 | o_file = next(args) 26 | ii_file = o_file[:-1] + "ii" 27 | compile.append(o_file) 28 | continue 29 | 30 | if arg.endswith(".cpp"): 31 | cpp_file = arg 32 | continue 33 | 34 | if arg in ("-I", "-isystem"): 35 | preprocess.append(arg) 36 | preprocess.append(next(args)) 37 | continue 38 | 39 | if arg.startswith("-I") or arg.startswith("-isystem"): 40 | preprocess.append(arg) 41 | continue 42 | 43 | preprocess.append(arg) 44 | compile.append(arg) 45 | 46 | preprocess.append(cpp_file) 47 | compile.append(os.path.realpath(ii_file)) 48 | 49 | if verbose: 50 | print(*preprocess) 51 | 52 | with open(ii_file, "w") as ii, Popen( 53 | preprocess, stdout=PIPE, encoding="ascii" 54 | ) as pp, Popen("clang-format", stdin=PIPE, stdout=ii, encoding="ascii") as cf: 55 | while True: 56 | line = pp.stdout.readline() 57 | if not line: 58 | break 59 | if not re.match(r"\s*#\s*\d+", line): 60 | cf.stdin.write(line) 61 | 62 | if verbose: 63 | print(*compile) 64 | 65 | os.execv(compile[0], compile) 66 | -------------------------------------------------------------------------------- /dev/reformat: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd "$(dirname $0)/.." 4 | 5 | srcs=$(find include src examples tests \ 6 | -name '*.?pp' | grep -v cmake_fetchcontent | grep -v /CMakeFiles) 7 | 8 | clang-format-15 -i --verbose $srcs 9 | -------------------------------------------------------------------------------- /dev/run-benchmarks: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd ./build/$1/Release/tests 4 | ../../../../dev/run-benchmarks-here -------------------------------------------------------------------------------- /dev/run-benchmarks-here: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | make -j4 benchmarks && \ 4 | ./benchmarks --benchmark_color=false --benchmark_repetitions=10 | perl -ne "$(cat <<'PERCENTS' 5 | if (s/_median//) { 6 | if ($n0) { 7 | s{\d+(?:\.\d+)? ns\s+(\d+(?:\.\d+)?) ns.*}{$1 . sprintf " ns %+2.1f%%\n", ($1 - $n0) / $n0 * 100}e or die; 8 | $n0 = 0; 9 | } else { 10 | s/\d+(?:\.\d+)? ns\s+(\d+(?:\.\d+)?) ns.*/$1 ns/; 11 | $n0 = $1 12 | } 13 | print; 14 | } 15 | PERCENTS 16 | )" 17 | -------------------------------------------------------------------------------- /dev/run-cmake: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | COMPILER=$1 4 | shift 5 | BUILD=$1 6 | shift 7 | mkdir -p build/$COMPILER/$BUILD 8 | cd build/$COMPILER/$BUILD 9 | cmake -DCMAKE_CXX_COMPILER=$COMPILER -DCMAKE_BUILD_TYPE=$BUILD -DCMAKE_EXPORT_COMPILE_COMMANDS=1 -DYOMM2_ENABLE_TESTS=1 -DYOMM2_ENABLE_BENCHMARKS=1 "$@" ../../.. 10 | -------------------------------------------------------------------------------- /dev/run-iwyu: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd $(dirname $0)/.. 4 | mkdir -p build/iwyu 5 | cd build/iwyu 6 | export CXXFLAGS="-isystem /usr/lib/gcc/x86_64-linux-gnu/9/include" 7 | cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=1 ../.. 8 | iwyu_tool -p . | tee iwyu.out 9 | 10 | -------------------------------------------------------------------------------- /dev/run-target: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | COMPILER=$1 4 | BUILD=$2 5 | TARGET=$3 6 | cd build/$COMPILER/$BUILD && make $TARGET && find . -name $TARGET -type f -exec $YOMM2_RUN_TARGET_PREFIX {} \; 7 | -------------------------------------------------------------------------------- /dev/run-tests: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | COMPILER=$1 4 | BUILD=$2 5 | shift 2 6 | cd build/$COMPILER/$BUILD && make -j4 && ctest $* 7 | -------------------------------------------------------------------------------- /dev/vs-cmake.bat: -------------------------------------------------------------------------------- 1 | cmake -G "Visual Studio 15 2017" -DYOMM2_ENABLE_TESTS=1 -DYOMM2_ENABLE_BENCHMARKS=1 -DBOOST_ROOT=d:\dev\boost .. -------------------------------------------------------------------------------- /dev/yomm2filt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import argparse 4 | import fileinput 5 | import re 6 | from subprocess import Popen, PIPE 7 | import threading 8 | 9 | parser = argparse.ArgumentParser() 10 | parser.add_argument("-s", "--scope", help="do not simplify scopes") 11 | parser.add_argument("-y", "--prefix", help="do not remove YOMM2 prefixes") 12 | parser.add_argument("-p", "--policy", help="do not remove policy") 13 | parser.add_argument("files", nargs="*", default=("-")) 14 | args = parser.parse_args() 15 | 16 | def process(fh): 17 | while True: 18 | line = fh.readline() 19 | if not line: 20 | return 21 | if not args.prefix: 22 | line = re.sub(r"\s*,\s*yorel::yomm2::policy::\w+", "", line) 23 | if not args.scope: 24 | line = re.sub(r"(\w+::)+", "", line) 25 | if not args.prefix: 26 | line = re.sub(r"YoMm2_S_", "", line) 27 | print(line, end="") 28 | 29 | i = 0 30 | 31 | with Popen( 32 | "/usr/bin/c++filt --types".split(), stdin=PIPE, stdout=PIPE, encoding="ascii" 33 | ) as cppfilt: 34 | demangler = threading.Thread(target=process, args=[cppfilt.stdout]) 35 | demangler.start() 36 | for line in fileinput.input(files=args.files): 37 | print(line, file=cppfilt.stdin, end="") 38 | cppfilt.stdin.close() 39 | demangler.join() -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:latest 2 | 3 | ARG USER 4 | ARG UID 5 | ARG GROUP 6 | ARG GID 7 | 8 | COPY yomm2-init-image.sh /tmp/yomm2-init-image.sh 9 | 10 | RUN /tmp/yomm2-init-image.sh $USER $UID $GROUP $GID && rm /tmp/yomm2-init-image.sh 11 | 12 | USER $UID:$GID 13 | RUN echo 'export PS1="[\u@docker] \W $ "' >> /home/$USER/.bashrc 14 | WORKDIR /home/$USER 15 | -------------------------------------------------------------------------------- /docker/build-image: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | docker build \ 4 | --build-arg="USER=$(id -u -n)" --build-arg="UID=$(id -u)" \ 5 | --build-arg="GROUP=$(id -g -n)" --build-arg="GID=$(id -g)" \ 6 | --tag yomm2:latest . 7 | -------------------------------------------------------------------------------- /docker/run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | docker run --rm -it -v $(realpath ..):/home/$(id -u -n)/yomm2 "$@" yomm2:latest bash 4 | -------------------------------------------------------------------------------- /docker/yomm2-init-image.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | user=$1 6 | shift 7 | uid=$1 8 | shift 9 | group=$1 10 | shift 11 | gid=$1 12 | shift 13 | 14 | mkdir /etc/sudoers.d 15 | echo "ALL ALL=(ALL:ALL) NOPASSWD: ALL" > /etc/sudoers.d/sudoall 16 | chmod 0440 /etc/sudoers.d/sudoall 17 | 18 | export DEBIAN_FRONTEND=noninteractive 19 | apt-get update 20 | apt-get install -y tzdata 21 | ln -fs /usr/share/zoneinfo/America/New_York /etc/localtime 22 | dpkg-reconfigure --frontend noninteractive tzdata 23 | 24 | apt-get install -y cmake git clang++-15 g++15 sudo 25 | 26 | groupadd -g $gid $group 27 | useradd -g $gid -m $user 28 | -------------------------------------------------------------------------------- /docs.in/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(reference) 2 | add_subdirectory(tutorials) 3 | -------------------------------------------------------------------------------- /docs.in/reference/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2024 Jean-Louis Leroy 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # See accompanying file LICENSE_1_0.txt 4 | # or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | set(code_deps "${CMAKE_SOURCE_DIR}/dev/code2md;${CMAKE_SOURCE_DIR}/dev/md2md;${CMAKE_SOURCE_DIR}/dev/mdgen.py") 7 | file(GLOB cpps "*.cpp") 8 | set(entries "") 9 | 10 | foreach(cpp ${cpps}) 11 | cmake_path(REMOVE_EXTENSION cpp LAST_ONLY OUTPUT_VARIABLE md) 12 | 13 | set(md "${md}.md") 14 | string(REPLACE "docs.in" "docs" md_out "${md}") 15 | add_custom_command( 16 | OUTPUT "${md_out}" 17 | COMMAND "${YOMM2_PYTHON}" ${CMAKE_SOURCE_DIR}/dev/code2md "${cpp}" "${md_out}" 18 | DEPENDS "${cpp};${code_deps}") 19 | list(APPEND entries "${md_out}") 20 | 21 | cmake_path(GET cpp STEM exe) 22 | set(exe "ref_${exe}") 23 | add_executable("${exe}" "${cpp}") 24 | add_compile_definitions(YOMM2_CODE) 25 | target_link_libraries("${exe}" YOMM2::yomm2) 26 | add_test(NAME "${exe}" COMMAND "${exe}") 27 | endforeach() 28 | 29 | file(GLOB_RECURSE MDs "*.md") 30 | 31 | foreach(MD ${MDs}) 32 | string(REPLACE "docs.in" "docs" MD_out "${MD}") 33 | add_custom_command( 34 | OUTPUT "${MD_out}" 35 | COMMAND "${YOMM2_PYTHON}" ${CMAKE_SOURCE_DIR}/dev/md2md "${MD}" "${MD_out}" 36 | DEPENDS "${MD};${code_deps}") 37 | list(APPEND entries "${MD_out}") 38 | endforeach() 39 | 40 | add_custom_target(REFERENCE DEPENDS "${entries}") 41 | add_dependencies(DOCS REFERENCE) 42 | -------------------------------------------------------------------------------- /docs.in/reference/RestrictedOutputStream.md: -------------------------------------------------------------------------------- 1 | macro: RestrictedOutputStream 2 | 3 | Stream& operator<<(Stream& os, const std::string_view& view); 4 | Stream& operator<<(Stream& os, const void* value); 5 | Stream& operator<<(Stream& os, size_t value); 6 | 7 | (where `Stream` is the type of the `error_stream` data member) 8 | -------------------------------------------------------------------------------- /docs.in/reference/RuntimeClass.md: -------------------------------------------------------------------------------- 1 | macro: RuntimeClass 2 | 3 | This concept specifies the operations available on the objects in the range 4 | passed to `publish_vptrs` function of facet ->`policy-vptr_vector`, and the 5 | `hash_initialize` function of facet ->`policy-type_hash`. 6 | 7 | 8 | ## Member functions 9 | 10 | ### type_id_begin 11 | 12 | ```c++ 13 | ForwardIterator type_id_begin() const 14 | ``` 15 | 16 | Return the beginning of a range of `type_id`s for the class. 17 | 18 | ### type_id_end 19 | 20 | ```c++ 21 | ForwardIterator type_id_end() const 22 | ``` 23 | Return the end of a range of `type_id`s for the class. 24 | 25 | ### vptr 26 | 27 | ```c++ 28 | const std::uintptr_t* vptr() const 29 | ``` 30 | 31 | Return a pointer to the v-table for the class. The pointer changes every time 32 | `update` is called. 33 | 34 | ### indirect_vptr 35 | 36 | ```c++ 37 | const std::uintptr_t* const* indirect_vptr() const 38 | ``` 39 | 40 | Return a pointer to a pointer to the v-table. This pointer to the pointer is 41 | stable across calls to `update`, although the pointer itself changes. 42 | -------------------------------------------------------------------------------- /docs.in/reference/YOMM2_GENSYM.md: -------------------------------------------------------------------------------- 1 | macro: YOMM2_GENSYM 2 | headers: yorel/yomm2/symbols.hpp, yorel/yomm2/keywords.hpp 3 | 4 | `YOMM2_GENSYM` expands to a new C++ identifier each time it is called. The 5 | symbol is based on the `__COUNTER__` preprocessor macro, and decorated in such a 6 | way that it is unlikely to clash with user-defined symbols. 7 | 8 | `YOMM2_GENSYM` provides a convenient way of allocating [static 9 | objects](static_object.md) for registering classes, methods, or definitions. 10 | 11 | ### Example 12 | 13 | ```c++ 14 | int YOMM2_GENSYM; 15 | int YOMM2_GENSYM; // not a redefinition, this is a new symbol 16 | ``` 17 | -------------------------------------------------------------------------------- /docs.in/reference/YOMM2_STATIC.md: -------------------------------------------------------------------------------- 1 | # YOMM2_STATIC 2 | headers: yorel/yomm2/symbols.hpp, yorel/yomm2/keywords.hpp 3 | 4 | ```c++ 5 | #define YOMM2_STATIC(...) static __VA_ARGS__ YOMM2_GENSYM 6 | ``` 7 | 8 | `YOMM2_STATIC` provides a convenient way to create a static object just for 9 | executing its constructor at static initialization time. The macro creates an 10 | obfuscated name for the object, which is unlikely to clash with any other name. 11 | 12 | ### Example 13 | 14 | ```c++ 15 | // Instantiate a 'use_classes' object to register three classes. 16 | YOMM2_STATIC(yorel::yomm2::use_classes); 17 | ``` 18 | -------------------------------------------------------------------------------- /docs.in/reference/YOMM2_SYMBOL.cpp: -------------------------------------------------------------------------------- 1 | #ifdef YOMM2_MD 2 | 3 | macro: YOMM2_SYMBOL 4 | headers: yorel/yomm2/symbols.hpp, yorel/yomm2/keywords.hpp 5 | 6 | ```c++ 7 | #define YOMM2_SYMBOL(seed) /*unspecified*/ 8 | ``` 9 | 10 | Macro `YOMM2_SYMBOL` expands to an obfuscated symbol, unlikely 11 | to clash with other names in scope. 12 | 13 | ## Example 14 | 15 | #endif 16 | 17 | #define BOOST_TEST_MODULE yomm2 18 | #include 19 | 20 | #ifdef YOMM2_CODE 21 | 22 | #include 23 | 24 | BOOST_AUTO_TEST_CASE(ref_example) { 25 | int foo = 1; 26 | int YOMM2_SYMBOL(foo) = 2; 27 | BOOST_TEST(foo == 1); 28 | BOOST_TEST(YOMM2_SYMBOL(foo) == 2); 29 | } 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /docs.in/reference/aggregate.cpp: -------------------------------------------------------------------------------- 1 | #ifdef YOMM2_MD 2 | 3 | entry: aggregate 4 | headers: yorel/yomm2/core.hpp, yorel/yomm2/keywords.hpp 5 | 6 | ```c++ 7 | template struct aggregate; 8 | ``` 9 | 10 | An instance of `aggregate` contains one `T` sub-object for each 11 | specified `T`, just like a `std::tuple`. 12 | `aggregate` provides a convenient way to instantiate a collection of [YOMM2 13 | registration objects](static_object.md). Typically, the name of the variable 14 | does not matter, and ->YOMM2_GENSYM can be used to generated that single-use 15 | identifier. 16 | Unlike typical `std::tuple` implementations, `aggregate` can 17 | handle large numbers of `T`s. For example, clang++-12 has a limit of 1024 18 | types, which can be reached easily when writing templatized method 19 | definitions. 20 | ## Example 21 | 22 | #endif 23 | 24 | int main() {} 25 | 26 | #ifdef YOMM2_CODE 27 | 28 | #include 29 | #include 30 | 31 | using namespace yorel::yomm2; 32 | 33 | struct Animal { virtual ~Animal() {} }; 34 | struct Dog : Animal {}; 35 | struct Cat : Animal {}; 36 | 37 | aggregate< 38 | class_declaration>, 39 | class_declaration>, 40 | class_declaration> 41 | > YOMM2_GENSYM; 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /docs.in/reference/apply_product.cpp: -------------------------------------------------------------------------------- 1 | #ifdef YOMM2_MD 2 | 3 | experimental: yorel::yomm2::apply_product 4 | headers: yorel/yomm2/templates.hpp 5 | 6 | ```c++ 7 | template 8 | using apply_product = /*unspecified*/; 9 | ``` 10 | 11 | `apply_product` takes a ->templates list and list of ->types lists, and 12 | evaluates to a `types` list consisting of the application of each template to 13 | the n-fold Cartesian product of the input `types` lists. 14 | 15 | ## Example 16 | 17 | #endif 18 | 19 | // clang-format off 20 | 21 | #ifdef YOMM2_CODE 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | using namespace yorel::yomm2; 28 | 29 | struct a; 30 | struct b; 31 | struct x; 32 | struct y; 33 | struct z; 34 | 35 | template struct bin1; 36 | template struct bin2; 37 | 38 | static_assert( 39 | std::is_same_v< 40 | apply_product< 41 | templates, 42 | types, 43 | types 44 | >, 45 | types< 46 | bin1, bin1, bin1, 47 | bin1, bin1, bin1, 48 | 49 | bin2, bin2, bin2, 50 | bin2, bin2, bin2 51 | > 52 | >); 53 | 54 | #endif 55 | 56 | int main() {} 57 | -------------------------------------------------------------------------------- /docs.in/reference/class_declaration.md: -------------------------------------------------------------------------------- 1 | entry: class_declaration 2 | headers: yorel/yomm2/core.hpp, yorel/yomm2/keywords.hpp 3 | 4 | ```c++ 5 | template 6 | struct class_declaration; 7 | ``` 8 | 9 | ### Usage 10 | ```c++ 11 | class_declaration identifier; 12 | class_declaration> identifier; 13 | ``` 14 | Register `Class` and its direct `Bases`. 15 | 16 | All classes that potentially take part in a method call must be registered with 17 | `class_declaration`, along with the inheritance relationships. 18 | 19 | Note that the registration requirement does not only apply to classes used as 20 | virtual parameters, and the classes used as parameters in method definitions 21 | that correspond to virtual parameters. The runtime class of all the objects 22 | potentially partaking in method *calls* must be registered. For example, given 23 | the hierarchy Animal -> Dog -> Bulldog; if a method declaration takes a 24 | `virtual_`; if the method has two definitions, one for Animal, and one 25 | for Bulldog; and the program calls the method for a Dog (that is not a Bulldog); 26 | then Dog must be registered as well. 27 | 28 | ## Example 29 | ```c++ 30 | struct Animal { virtual ~Animal() {} }; 31 | struct Dog : Animal {}; 32 | struct Bulldog : Dog {}; 33 | struct Cat : Animal {}; 34 | 35 | class_declaration> register_animal; 36 | class_declaration> register_dog; 37 | class_declaration> register_bulldog; 38 | class_declaration> register_cat; 39 | ``` 40 | 41 | ## See also 42 | `class_declaration` is a low level construct. It is recommended to use 43 | ->use_classes instead, which can register many classes, and their inheritance 44 | relationships, using a single [registration object](static_object.md). 45 | -------------------------------------------------------------------------------- /docs.in/reference/declare_method.md: -------------------------------------------------------------------------------- 1 | hrefs: YOMM2_DECLARE 2 | macro: declare_method 3 | headers: yorel/yomm2/cute.hpp, yorel/yomm2/keywords.hpp 4 | 5 | ```c++ 6 | #define declare_method(return-type, method, (types)) /*unspecified*/ 7 | ``` 8 | 9 | ### Usage 10 | 11 | ``` 12 | declare_method(return-type, method, (types)) { 13 | ... 14 | } 15 | ``` 16 | 17 | Declare a method. 18 | 19 | Create an inline function `method` that returns `return-type` and takes a 20 | parameter list consisting of `types`. At least one of `types` (but not 21 | necessarily all) must be a *virtual parameter*, i.e. in the form 22 | [`virtual_`](virtual_.md), or [`virtual_ptr`](virtual_ptr.md). The 23 | `virtual_` decorator is stripped from `types`. 24 | 25 | When `method` is called, the dynamic types of the virtual arguments are 26 | examined, and the most specific definition compatible with `unspecified_type...` 27 | is called. If no compatible definition exists, or if several compatible 28 | definitions exist but none of them is more specific than all the others, the 29 | call is illegal and an error handler is executed. By default it writes a 30 | diagnostic on `std::cerr ` and terminates the program via `abort`. The handler 31 | can be customized. 32 | 33 | NOTE: 34 | 35 | * The method parameter list _must_ be surrounded by parentheses. 36 | 37 | * The parameters in `types` consist of _just_ a type, e.g. `int` is correct 38 | but `int i` is not. 39 | 40 | * Types that contain commas (e.g. `tuple`) cannot be used directly as 41 | macro arguments. The workarounds are: 42 | * using an alias, e.g. `using int_char = tuple` 43 | * using any C++ construct that puts parentheses around the commas, 44 | e.g. `decltype(std::tuple())` 45 | * [`BOOST_IDENTITY_TYPE`](https://www.boost.org/doc/libs/1_82_0/libs/utility/identity_type/doc/html/index.html) 46 | 47 | ## synonym 48 | YOMM2_DECLARE, defined in , also provided by . 49 | 50 | ## Example 51 | ``` 52 | declare_method(std::string, kick, (virtual_)); 53 | declare_method(std::string, meet, (virtual_, virtual_)); 54 | declare_method(bool, approve, (virtual_, virtual_), double); 55 | ``` 56 | -------------------------------------------------------------------------------- /docs.in/reference/define_method_inline.md: -------------------------------------------------------------------------------- 1 | macro: define_method_inline 2 | headers: yorel/yomm2/cute.hpp, yorel/yomm2/keywords.hpp 3 | hrefs: YOMM2_DEFINE_INLINE 4 | 5 | ``` 6 | #define define_method_inline(container, return-type, name, (function-parameter-list)) /*unspecified*/ 7 | ``` 8 | 9 | Add an definition to a method, inside a container, and make it inline. 10 | 11 | Like ->define_method, but the definition has the `inline` storage class, and 12 | thus can be placed in a header file and is a potential candidate for inlining. 13 | 14 | Note that inlining is only supported for definitions placed inside a container. 15 | Inlining implementations defined outside of a container would make no sense, as 16 | there would be no way of referencing them. 17 | 18 | See the documentation of ->method_container for more information on method 19 | containers. 20 | 21 | See the documentation of ->declare_method for information on handling types that 22 | contain commas. 23 | 24 | ## synonym 25 | YOMM2_METHOD_INLINE, defined in , also provided by . 26 | -------------------------------------------------------------------------------- /docs.in/reference/friend_method.md: -------------------------------------------------------------------------------- 1 | macro: friend_method 2 | headers: yorel/yomm2/cute.hpp, yorel/yomm2/keywords.hpp 3 | 4 | macro: YOMM2_FRIEND 5 | headers: yorel/yomm2/macros.hpp, yorel/yomm2.hpp 6 | 7 | ``` 8 | #define friend_method(container) 9 | #define friend_method(container, return_type, name, (function-parameter-list)) 10 | ``` 11 | 12 | Grant friendship to all the methods inside a container friend of a class, or to 13 | a specific method. 14 | 15 | ## Example 16 | See the [containers](https://github.com/jll63/yomm2/tree/master/examples/containers) example. 17 | -------------------------------------------------------------------------------- /docs.in/reference/method_call_error.md: -------------------------------------------------------------------------------- 1 | entry: method_call_error 2 | entry: method_call_error_handler 3 | entry: set_method_call_error_handler 4 | headers: yorel/yomm2/core.hpp, yorel/yomm2/keywords.hpp 5 | 6 | ```c++ 7 | struct method_call_error { 8 | enum type { not_implemented = 0, ambiguous = 1 } code; 9 | std::string_view method_name; 10 | }; 11 | using method_call_error_handler = void (*)( 12 | const method_call_error &error, size_t arity, const std::type_info* const tis[]); 13 | 14 | method_call_error_handler set_method_call_error_handler( 15 | method_call_error_handler handler); 16 | ``` 17 | 18 | This mechanism is **deprecated**. Please use the new [error handler 19 | mechanism](set_error_handler.md) instead. 20 | 21 | If a method call cannot be dispatched, an error handler is called with a 22 | reference to a `method_call_error` structure, which contains the method's name 23 | in an unspecified format, and a code identifying the error. 24 | 25 | The default error handler terminates the program with `abort()`. A different 26 | handler can be installed with `set_method_call_error_handler`, which returns the 27 | previous handler. The handler *may not* return. It may throw an exception. 28 | -------------------------------------------------------------------------------- /docs.in/reference/method_class.cpp: -------------------------------------------------------------------------------- 1 | /*** 2 | macro: method_class 3 | headers: yorel/yomm2/keywords.hpp 4 | macro: YOMM2_METHOD_CLASS 5 | headers: yorel/yomm2/macros.hpp 6 | 7 | ```c++ 8 | #define method_class(RETURN_TYPE, NAME, ARGS [, POLICY]) 9 | #define YOMM2_METHOD_CLASS(RETURN_TYPE, NAME, ARGS [, POLICY]) 10 | ``` 11 | 12 | Both macros take the same arguments as ->`declare_method`, and return the 13 | corresponding core type ->`method`. 14 | 15 | ## Example 16 | ***/ 17 | 18 | #define BOOST_TEST_MODULE checked_perfect_hash 19 | #include 20 | 21 | #include 22 | 23 | #include 24 | 25 | struct Animal { 26 | virtual ~Animal() { 27 | } 28 | }; 29 | 30 | struct Dog : Animal {}; 31 | 32 | register_classes(Animal, Dog); 33 | 34 | declare_method(std::string, kick, (virtual_)); 35 | 36 | define_method(std::string, kick, (Dog & dog)) { 37 | return "bark"; 38 | } 39 | 40 | BOOST_AUTO_TEST_CASE(ref_method_class) { 41 | yomm2::update(); 42 | 43 | Animal&& dog = Dog(); 44 | using X = YOMM2_METHOD_CLASS(std::string, kick, (virtual_)); 45 | auto reply = YOMM2_METHOD_CLASS(std::string, kick, (virtual_))::fn(dog); 46 | BOOST_TEST(reply == "bark"); 47 | } 48 | -------------------------------------------------------------------------------- /docs.in/reference/method_definition.md: -------------------------------------------------------------------------------- 1 | hrefs: YOMM2_DEFINITION 2 | 3 | macro: method_definition 4 | headers: yorel/yomm2/cute.hpp, yorel/yomm2/keywords.hpp 5 | 6 | ```c++ 7 | #define method_definition(CONTAINER, RETURN_TYPE, FUNCTION_PARAMETER_LIST) 8 | ``` 9 | 10 | Retrieve a method definition with a given return type and signature from a 11 | container. 12 | 13 | The resulting method can be used as a normal function reference. It can be 14 | called, and its address can be taken. In particular, this makes it possible for 15 | a method definition to call a base method as part of its implementation, in the 16 | same manner as an ordinary virtual function can call a specific base function 17 | by prefixing its name with a base class name. 18 | 19 | Note that the preferred way of calling the overriden method is via `next`. In 20 | normal circumstances, a method definition cannot assume which "super" or "base" 21 | function is the best choice, since the set of methods pertaining to the same 22 | declaration is open. 23 | 24 | ## synonym 25 | YOMM2_DEFINITION, defined in , also provided by . 26 | 27 | ## Example 28 | See the [containers](https://github.com/jll63/yomm2/tree/master/examples/containers) example. 29 | -------------------------------------------------------------------------------- /docs.in/reference/not_defined.md: -------------------------------------------------------------------------------- 1 | experimental: yorel::yomm2::not_defined 2 | headers: yorel/yomm2/template.hpp 3 | 4 | ```c++ 5 | struct not_defined {}; 6 | ``` 7 | 8 | Classes derived from `not_defined` are discarded by ->use_classes. 9 | 10 | ## Example 11 | 12 | See the [use_classes example](use_classes.md#example) 13 | -------------------------------------------------------------------------------- /docs.in/reference/policy-basic_error_output.md: -------------------------------------------------------------------------------- 1 | entry: policy::basic_error_output 2 | headers: yorel/yomm2/policy.hpp,yorel/yomm2/core.hpp,yorel/yomm2/keywords.hpp 3 | 4 | ```c++ 5 | template 6 | struct basic_error_output; 7 | ``` 8 | 9 | `basic_error_output` implements the ->`policy-error_output` facet. 10 | 11 | ## Template parameters 12 | 13 | * **Policy**: The policy containing the facet. Since `basic_error_output` has 14 | static state, making the policy a template parameter ensures that each policy 15 | has its wn set of static member variables. 16 | 17 | * **Stream**: `Stream` can be any type that satisfies the requirements of 18 | ->`RestrictedOutputStream`. The default value is a lightweight version of 19 | `std::ostream` that writes to `stderr`, using low-level C functions. 20 | 21 | ## Static member variables 22 | 23 | | Name | Value | 24 | | ---------------------------------------- | ---------------------- | 25 | | Stream [**error_stream**](#error_stream) | the stream to print to | 26 | 27 | ### error_stream 28 | 29 | Initialized by the default constructor of `Stream`. It is the responsibility of 30 | the program to perform further initialization if needed - for example, open a 31 | `std::ofstream`, before calling `update`. 32 | -------------------------------------------------------------------------------- /docs.in/reference/policy-basic_trace_output.md: -------------------------------------------------------------------------------- 1 | entry: policy::**basic_trace_output** 2 | headers: yorel/yomm2/policy.hpp,yorel/yomm2/core.hpp,yorel/yomm2/keywords.hpp 3 | 4 | ```c++ 5 | template 6 | struct basic_trace_output; 7 | ``` 8 | 9 | `basic_trace_output` implements the ->`policy-trace_output` facet. 10 | 11 | ## Template parameters 12 | 13 | * **Policy**: the policy containing the facet. Since `basic_trace_output` has 14 | static state, making the policy a template parameter ensures that each policy 15 | has its own set of static member variables. 16 | 17 | * **Stream**: - `Stream` can be any type that satisfies the requirements of 18 | ->`RestrictedOutputStream`. The default value is a lightweight version of 19 | `std::ostream` that writes to `stderr`, using low-level C functions. 20 | 21 | ## Static member variables 22 | 23 | | Name | Value | 24 | | ---------------------------------------- | ----------------------- | 25 | | bool [**trace_enabled**](#trace_enabled) | enable or disable trace | 26 | | Stream [**trace_stream**](#trace_stream) | the stream to print to | 27 | 28 | ### trace_enabled 29 | 30 | Controls whether information is printed to `trace_stream`. The flag is 31 | initialized by examining the `YOMM2_TRACE` environment variable. If it is set, 32 | and its value is `1`, trace is enabled. Other values are reserved for possible 33 | future use. 34 | 35 | ### trace_stream 36 | 37 | Initialized by the default constructor of `Stream`. It is the responsibility of 38 | the program to perform further initialization if needed - for example, open a 39 | `std::ofstream`, before calling `update`. 40 | -------------------------------------------------------------------------------- /docs.in/reference/policy-checked_perfect_hash.md: -------------------------------------------------------------------------------- 1 | entry: policy::checked_perfect_hash 2 | headers: yorel/yomm2/policy.hpp, yorel/yomm2/core.hpp, yorel/yomm2/keywords.hpp 3 | ``` 4 | template 5 | struct checked_perfect_hash; 6 | ``` 7 | 8 | 9 | `checked_perfect_hash` is a subclass of ->`policy-fast_perfect_hash`. It checks 10 | that the id passed to `hash_type_index` is valid, i.e. was in the set of ids 11 | registered via `hash_initialize`. 12 | 13 | ## Template parameters 14 | 15 | **Policy** - the policy containing the facet. 16 | 17 | ## Static member functions 18 | 19 | | Name | Description | 20 | | ----------------------------------- | ---------------------------- | 21 | | [hash_initialize](#hash_initialize) | finds a hash function | 22 | | [hash_type_id](#hash_type_id) | returns the hashed `type_id` | 23 | 24 | ### hash_initialize 25 | 26 | ```c++ 27 | template 28 | template 29 | static size_t hash_initialize(ForwardIterator first, ForwardIterator last) 30 | ``` 31 | 32 | Calls 33 | [`fast_perfect_hash::hash_initialize`](policy-fast_perfect_hash.html#hash_initialize). 34 | Also build a reverse mapping, from hashed ids to registered ids. 35 | 36 | 37 | #### Parameters 38 | 39 | **first**, **last** - a range of `type_id`s 40 | 41 | #### Return value 42 | 43 | None. 44 | 45 | #### Errors 46 | 47 | * Any exception thrown by Allocator::allocate() (typically std::bad_alloc). 48 | 49 | ### hash_type_id 50 | 51 | ```c++ 52 | template 53 | static type_id hash_type_id(type_id type) 54 | ``` 55 | 56 | Retrieve the registered id corresponding to the hashed id. Compare it with 57 | `type`. If they are the same, return the hashed value. If not, report an error 58 | via `Policy::error` if `Policy` has an `error_handler` facet; otherwise, 59 | abort the program. 60 | 61 | #### Parameters 62 | 63 | **type** - a `type_id` 64 | 65 | #### Return value 66 | 67 | None. 68 | 69 | #### Errors 70 | 71 | * ->`unknown_class_error`, with `context` set to `unknown_class_error::update`. 72 | 73 | ## Interactions with other facets 74 | 75 | * `error_handler` - to report error conditions. 76 | * `error_output` - for diagnostics. 77 | * `trace_output` - for trace. 78 | -------------------------------------------------------------------------------- /docs.in/reference/policy-deferred_static_rtti.md: -------------------------------------------------------------------------------- 1 | entry: policy::deferred_static_rtti 2 | 3 | ```c++ 4 | struct deferred_static_rtti : virtual rtti {}; 5 | ``` 6 | 7 | The `deferred_static_rtti` facet, derived from `rtti`, directs YOMM2 to defer 8 | collection of static type information until `update` is called. This makes it 9 | possible to interface with custom RTTI systems that use static constructors to 10 | assign type information. 11 | 12 | ## See also 13 | 14 | The custom RTTI [tutorial](/yomm2/tutorials/custom_rtti_tutorial.html). 15 | -------------------------------------------------------------------------------- /docs.in/reference/policy-error_handler.md: -------------------------------------------------------------------------------- 1 | entry: policy::error_handler 2 | headers: yorel/yomm2/core.hpp,yorel/yomm2/keywords.hpp 3 | 4 | ```c+ 5 | struct error_handler; 6 | ``` 7 | 8 | The `error_handler` is used by YOMM2 to handle error conditions. If it is 9 | present, its static member `error` is called with a variant describing the 10 | error. If the function returns normally, the program is terminated by a call to 11 | `abort`. 12 | 13 | ## Requirements for implementations of **error_handler** 14 | 15 | | | | 16 | | --------------------------------- | -------------------------------- | 17 | | _unspecified_ [**error**](#error) | called when an error is detected | 18 | 19 | (all members are static) 20 | 21 | ### error 22 | 23 | Handle the error condition. `error` can be a function or a function or a 24 | functor, taking a single `const error_type&` argument, and returning `void`. It 25 | can throw an exception, derived from class ->`error`, to prevent program 26 | termination. 27 | 28 | ## Implementations of `error_handler` 29 | 30 | | | | 31 | | ----------------------- | ---------------------------------------------------------------------- | 32 | | ->policy-throw_error | throw the error as an exception | 33 | | ->policy-vectored_error | implement `error` as `std::function`; default value prints diagnostics | 34 | -------------------------------------------------------------------------------- /docs.in/reference/policy-error_output.md: -------------------------------------------------------------------------------- 1 | entry: policy::error_output 2 | headers: yorel/yomm2/policy.hpp,yorel/yomm2/core.hpp,yorel/yomm2/keywords.hpp 3 | 4 | struct error_output; 5 | 6 | The `error_output` facet is used to print diagnostics about error conditions. 7 | 8 | **Requirements for implementations of `error_output`** 9 | 10 | | | | 11 | | ------------------------------------- | ---------------------------- | 12 | | `static /*unspeficied*/ error_stream` | a ->`RestrictedOutputStream` | 13 | 14 | **Implementations of `error_output`** 15 | 16 | | | | 17 | | --------------------------- | ----------------------------------------- | 18 | | ->policy-basic_error_output | print to a `Stream` local to the `Policy` | 19 | -------------------------------------------------------------------------------- /docs.in/reference/policy-minimal_rtti.cpp: -------------------------------------------------------------------------------- 1 | /*** 2 | entry: policy::minimal_rtti 3 | headers: yorel/yomm2/policy.hpp, yorel/yomm2/core.hpp, yorel/yomm2/keywords.hpp 4 | 5 | ```c++ 6 | struct minimal_rtti; 7 | ``` 8 | 9 | Minimal implementation of ->`policy-rtti` that does not use any actual _runtime_ 10 | type information. This facet can be used in programs that call methods solely 11 | via ->`virtual_ptr`s created using the ->virtual_ptr-final constructs. Virtual 12 | inheritance is not supported. Classes are not required to be polymorphic. 13 | 14 | ## Static member functions 15 | 16 | | Name | Description | 17 | | --------------------------------------------- | ----------------------------------------------- | 18 | | type_id [**static_type\**](#static_type) | return a `type_id` for `T` | 19 | 20 | ### static_type 21 | 22 | ```c++ 23 | template 24 | static type_id static_type(); 25 | ``` 26 | 27 | Allocate a static `char` variable and return its address, cast to ->`type_id`. 28 | 29 | **Template parameters** 30 | 31 | * Class: a class registered via ->register_classes or ->use_classes. 32 | 33 | ## Example 34 | 35 | ***/ 36 | 37 | #define BOOST_TEST_MODULE checked_perfect_hash 38 | #include 39 | 40 | //*** 41 | #include 42 | #include 43 | 44 | #include 45 | using namespace yorel::yomm2; 46 | 47 | struct Animal {}; 48 | struct Cat : Animal {}; 49 | struct Dog : Animal {}; 50 | 51 | struct final_policy : policy::basic_policy { 52 | }; 53 | 54 | template 55 | using vptr = virtual_ptr; 56 | 57 | register_classes(Animal, Dog, Cat, final_policy); 58 | 59 | declare_method(std::string, kick, (vptr), final_policy); 60 | 61 | define_method(std::string, kick, (vptr cat)) { 62 | return "hiss"; 63 | } 64 | 65 | define_method(std::string, kick, (vptr dog)) { 66 | return "bark"; 67 | } 68 | 69 | BOOST_AUTO_TEST_CASE(ref_static_rtti) { 70 | update(); 71 | 72 | Cat felix; 73 | Dog snoopy; 74 | 75 | // type erasure: 76 | std::vector> animals = { 77 | vptr::final(felix), 78 | vptr::final(snoopy), 79 | }; 80 | 81 | BOOST_TEST(kick(animals[0]) == "hiss"); 82 | BOOST_TEST(kick(animals[1]) == "bark"); 83 | } 84 | //*** 85 | -------------------------------------------------------------------------------- /docs.in/reference/policy-throw_error.cpp: -------------------------------------------------------------------------------- 1 | /*** 2 | entry: policy::throw_error 3 | location: policy;yorel/yomm2/core.hpp,yorel/yomm2/keywords.hpp 4 | 5 | struct throw_error; 6 | 7 | `throw_error` implements ->`policy-error_handler` by throwing errors as 8 | exceptions. 9 | 10 | If exceptions are disabled, `throw_error` is not defined. 11 | 12 | ## Static member functions 13 | 14 | | | | 15 | | --------------------------------- | ------------------------------- | 16 | | [**error**](#error) | throw the error variant's value | 17 | 18 | ### error 19 | 20 | ```c++ 21 | static void error(const error_type& error_variant); 22 | ``` 23 | 24 | Extract the value of `error_variant`, and throw it as an exception. 25 | 26 | ## Example 27 | ***/ 28 | 29 | #define BOOST_TEST_MODULE checked_perfect_hash 30 | #include 31 | 32 | //*** 33 | 34 | #include 35 | 36 | namespace yomm2 = yorel::yomm2; 37 | using yomm2::virtual_; 38 | 39 | struct Animal { 40 | virtual ~Animal() { 41 | } 42 | }; 43 | 44 | struct Dog : Animal {}; 45 | 46 | using throw_policy = yomm2::default_policy::replace< 47 | yomm2::policy::error_handler, yomm2::policy::throw_error>; 48 | 49 | register_classes(Animal, Dog, throw_policy); 50 | 51 | declare_method(void, kick, (virtual_), throw_policy); 52 | 53 | BOOST_AUTO_TEST_CASE(ref_throw_error) { 54 | yomm2::update(); 55 | 56 | bool threw = false; 57 | 58 | try { 59 | Animal&& dog = Dog(); 60 | kick(dog); 61 | } catch (yomm2::resolution_error& error) { 62 | BOOST_TEST(error.status == yomm2::resolution_error::no_definition); 63 | BOOST_TEST( 64 | error.method_name == 65 | typeid(method_class(void, kick, (virtual_), throw_policy)) 66 | .name()); 67 | BOOST_TEST(error.arity == 1); 68 | BOOST_TEST(error.types[0] == throw_policy::static_type()); 69 | threw = true; 70 | } 71 | 72 | BOOST_TEST(threw); 73 | } 74 | 75 | //*** 76 | -------------------------------------------------------------------------------- /docs.in/reference/policy-trace_output.md: -------------------------------------------------------------------------------- 1 | entry: policy::trace_output 2 | headers: yorel/yomm2/policy.hpp,yorel/yomm2/core.hpp,yorel/yomm2/keywords.hpp 3 | 4 | struct trace_output; 5 | 6 | The `trace_output` facet enables the YOMM2 runtime to print information about 7 | the data structures used at dispatch time, and how they are derived. This 8 | includes deduction of inheritance lattices, v-table slot allocation, dispatch 9 | table construction, hash parameters, etc. This can help troubleshoot common 10 | errors, like missing class registrations, ambiguities in method definitions, 11 | etc. 12 | 13 | The format of the information is not documented, beyond that it is useful. It 14 | may change without notice. 15 | 16 | **Requirements for implementations of `trace_output`** 17 | 18 | | | | 19 | | ------------------------------------- | ---------------------------- | 20 | | `static /*unspeficied*/ trace_stream` | a ->`RestrictedOutputStream` | 21 | | `static bool trace_enabled` | enable trace if `true` | 22 | 23 | 24 | 25 | **Implementations of `trace_output`** 26 | 27 | | | | 28 | | ----------------------------- | ------------------------------------- | 29 | | ->`policy-basic_trace_output` | print to a `Stream` local to `Policy` | 30 | -------------------------------------------------------------------------------- /docs.in/reference/policy-type_hash.md: -------------------------------------------------------------------------------- 1 | entry: policy::type_hash 2 | headers: yorel/yomm2/policy.hpp, yorel/yomm2/core.hpp, yorel/yomm2/keywords.hpp 3 | refs: type_hash 4 | 5 | ``` 6 | struct type_hash {}; 7 | ``` 8 | 9 | The `type_hash` facet projects a sparse range of ->`type_id`s to a dense range. 10 | 11 | ### Requirements for implementations of `type_hash` 12 | 13 | An implementation of `type_hash` must provide the following static functions: 14 | 15 | | | | 16 | | ----------------------------------- | --------------------------- | 17 | | [hash_initialize](#hash_initialize) | implementation dependent | 18 | | [hash_type_id](#hash_type_id) | return the hashed `type_id` | 19 | 20 | ### Implementations of `type_hash` 21 | 22 | | | | 23 | | ----------------------------- | ------------------------------------------------------------- | 24 | | ->policy-fast_perfect_hash | use a fast, perfect, but not minimal integer hash | 25 | | ->policy-checked_perfect_hash | like `fast_perfect_hash`, also check for unregistered classes | 26 | 27 | 28 | ### hash_initialize 29 | 30 | ```c++ 31 | template 32 | static size_t hash_initialize(ForwardIterator first, ForwardIterator last); 33 | ``` 34 | 35 | Called by another facet in the policy if it requires hashing. 36 | ->`policy-vptr_vector` in the default policy does that. 37 | 38 | The function takes a range of ->`type_id`s, and finds a hash function for that 39 | specific set of values. 40 | 41 | ### hash_type_id 42 | 43 | ```c++ 44 | static type_id hash_type_id(type_id type); 45 | ``` 46 | 47 | Called during method dispatch. Returns the corresponding value in the dense 48 | range. `type` must be one of the `type_id`s passed to `hash_initialize`. 49 | -------------------------------------------------------------------------------- /docs.in/reference/policy-vectored_error.md: -------------------------------------------------------------------------------- 1 | entry: policy::vectored_error 2 | headers: yorel/yomm2/core.hpp,yorel/yomm2/keywords.hpp 3 | 4 | ```c++ 5 | template 6 | struct vectored_error; 7 | ``` 8 | 9 | `vectored_error` implements ->`policy-error_handler` using a static 10 | `std::function`. 11 | 12 | ## Template parameters 13 | 14 | | Name | Value | 15 | | --------------------------- | ------------------------------- | 16 | | class [**Policy**](#policy) | the policy containing the facet | 17 | 18 | ### Policy 19 | 20 | The policy containing the facet. Since `vectored_error` has a static member 21 | variable, making the policy a template parameter ensures that each policy has 22 | its own copy. 23 | 24 | **Static member variables** 25 | 26 | | | | 27 | | -------------------------------------- | --------------------- | 28 | | error_handler_type [**error**](#error) | current error handler | 29 | 30 | ### error 31 | 32 | ```c++ 33 | static error_handler_type error; 34 | ``` 35 | 36 | A `std::function` (see ->`error_handler_type`), initialized to 37 | `default_error_handler`. 38 | 39 | The function may throw an exception (unless they have been disabled), thus 40 | preventing program termination. 41 | 42 | **Static member functions** 43 | 44 | | | | 45 | | ------------------------------------------------- | ----------------- | 46 | | [`default_error_handler`](#default_error_handler) | print diagnostics | 47 | 48 | ### default_error_handler 49 | 50 | ```c++ 51 | static void default_error_handler(const error_type& error_v) 52 | ``` 53 | 54 | If ->`policy-error_output` is available in `Policy`, use it to print a 55 | description of `error`. Return normally, causing the program to be aborted. 56 | 57 | 58 | ## Interactions with other facets 59 | 60 | * ->`policy-error_output`: for diagnostics. 61 | -------------------------------------------------------------------------------- /docs.in/reference/policy-vptr_map.md: -------------------------------------------------------------------------------- 1 | entry: policy::vptr_map 2 | headers: yorel/yomm2/policy.hpp, yorel/yomm2/core.hpp, yorel/yomm2/keywords.hpp 3 | 4 | ```c++ 5 | template 6 | struct vptr_map; 7 | ``` 8 | 9 | `vptr_map` is an implementation of ->`policy-external_vptr` that stores the 10 | pointers to the v-tables in a `std::unordered_map` keyed by the ->`type_id`s of 11 | the classes. This makes method dispatch slower than ->`policy-vptr_vector` with 12 | ->`policy-fast_perfect_hash` (75% slower than native virtual function). However, 13 | `vptr_map` has some advantages: `fast_perfect_hash` takes more time to 14 | initialize. It also sacrifices memory space for speed, as it uses a hash 15 | function that is not suitable for perfect _and_ minimal hashing. Using 16 | `virtual_ptr`s extensively can mitigate the speed disadvantage of `vptr_map`. 17 | 18 | ## Template parameters 19 | 20 | **Policy** - the policy containing the facet. 21 | 22 | ## static member functions 23 | | | | 24 | | ------------------------------- | ----------------------------------------------- | 25 | | [dynamic_vptr](#dynamic_vptr) | return the address of the v-table for an object | 26 | | [publish_vptrs](#publish_vptrs) | store the vptrs | 27 | 28 | ### dynamic_vptr 29 | 30 | ```c++ 31 | template 32 | template 33 | const std::uintptr_t* vptr_map::dynamic_vptr(const Class& object); 34 | ``` 35 | 36 | Return a pointer to the v-table for `object`. 37 | 38 | Call `Policy::dynamic_type` for `object`. Return the vptr associated to the 39 | resulting ->`type_id`. 40 | 41 | ### publish_vptrs 42 | 43 | ```c++ 44 | template 45 | template 46 | void vptr_map::publish_vptrs(ForwardIterator first, ForwardIterator last); 47 | ``` 48 | 49 | Store the pointers to the v-tables. 50 | -------------------------------------------------------------------------------- /docs.in/reference/policy-vptr_vector.md: -------------------------------------------------------------------------------- 1 | entry: policy::vptr_vector 2 | headers: yorel/yomm2/policy.hpp, yorel/yomm2/core.hpp, yorel/yomm2/keywords.hpp 3 | 4 | ```c++ 5 | template 6 | struct vptr_vector : virtual external_vptr { ... }; 7 | ``` 8 | 9 | `vptr_vector` is an implementation of ->`policy-external_vptr that stores the 10 | pointers to the v-tables in a `std::vector`. If the policy contains a 11 | ->`policy-type_hash` facet, it is used to convert the ->`type_id` to an index in the 12 | vector; otherwise, the `type_id` is used as the index. 13 | 14 | The default policy uses ->`policy-std_rtti`, ->`policy-fast_perfect_hash` and 15 | `vptr_vector` to implement efficient method dispatch. Calling a method with a 16 | single virtual parameter takes only ~33% more time than calling a native virtual 17 | function call. 18 | 19 | ## Template parameters 20 | 21 | **Policy** - the policy containing the facet. 22 | 23 | ## Static member functions 24 | 25 | | | | 26 | | ------------------------------- | -------------------------------------------------- | 27 | | [dynamic_vptr](#dynamic_vptr) | return the address of the v-table for an object | 28 | | [publish_vptrs](#publish_vptrs) | store the vptrs, initialize `type_hash` if present | 29 | 30 | ### dynamic_vptr 31 | 32 | ```c++ 33 | template 34 | template 35 | const std::uintptr_t* vptr_vector::dynamic_vptr(const Class& object); 36 | ``` 37 | 38 | Return a pointer to the v-table for `object`. 39 | 40 | Call `Policy::dynamic_type` for `object`. If `Policy` contains a `type_hash` 41 | facet, use it to convert the resulting `type_id` to an index; otherwise, use the 42 | `type_id` as the index. 43 | 44 | ### publish_vptrs 45 | 46 | ```c++ 47 | template 48 | template 49 | void vptr_vector::publish_vptrs(ForwardIterator first, ForwardIterator last); 50 | ``` 51 | 52 | If `Policy` contains a `type_hash` facet, call its `hash_initialize` 53 | function. 54 | 55 | Store the pointers to the v-tables in a vector, indexed by the (possibly hashed) 56 | `type_id`s. 57 | -------------------------------------------------------------------------------- /docs.in/reference/product.cpp: -------------------------------------------------------------------------------- 1 | #ifdef YOMM2_MD 2 | 3 | experimental: yorel::yomm2::product 4 | headers:yorel/yomm2/templates.hpp> 5 | ``` 6 | template 7 | using product = /*unspecified*/; 8 | ``` 9 | `product` takes a list of ->types lists, and evaluates to a `types` list 10 | consisting of the n-fold Cartesian product of the input lists. 11 | 12 | ## Example 13 | 14 | #endif 15 | 16 | // clang-format off 17 | 18 | #ifdef YOMM2_CODE 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | namespace yomm2 = yorel::yomm2; 25 | 26 | struct a; 27 | struct b; 28 | struct x; 29 | struct y; 30 | struct z; 31 | 32 | static_assert( 33 | std::is_same_v< 34 | yomm2::product< 35 | yomm2::types, 36 | yomm2::types 37 | >, 38 | yomm2::types< 39 | yomm2::types, yomm2::types, yomm2::types, 40 | yomm2::types, yomm2::types, yomm2::types 41 | > 42 | >); 43 | 44 | #endif 45 | 46 | int main() {} 47 | -------------------------------------------------------------------------------- /docs.in/reference/register_class.md: -------------------------------------------------------------------------------- 1 | macro: register_class, YOMM2_CLASS 2 | headers: yorel/yomm2/macros.hpp, yorel/yomm2/cute.hpp, yorel/yomm2/keywords.hpp> 3 | 4 | These macros are deprecated. Use ->register_classes or ->YOMM2_CLASSES. 5 | -------------------------------------------------------------------------------- /docs.in/reference/set_error_handler.cpp: -------------------------------------------------------------------------------- 1 | #ifdef YOMM2_MD 2 | headers: yorel/yomm2/core.hpp, yorel/yomm2/keywords.hpp, yorel/yomm2.hpp 3 | 4 | ```c++ 5 | error_handler_type set_error_handler(error_handler_type handler); 6 | ``` 7 | 8 | All errors are reported via an indirect call to a handler, passing it a 9 | `std::variant` that identifies the specific error. The handler can be set to 10 | a user-defined function with `set_error_handler`. The library calls `abort()` 11 | immediately after calling the handler, but the handler can prevent program 12 | termination by throwing an exception. The default handler writes an error 13 | message to `stderr` in debug mode. 14 | 15 | `set_error_handler` returns the previous handler. 16 | 17 | ## Example 18 | 19 | #endif 20 | 21 | #define BOOST_TEST_MODULE runtime 22 | #include 23 | 24 | #define BOOST_TEST_MODULE runtime 25 | #include 26 | 27 | #ifdef YOMM2_CODE 28 | 29 | #include 30 | #include 31 | 32 | struct Animal { 33 | virtual ~Animal() { 34 | } 35 | }; 36 | 37 | struct Dog : Animal {}; 38 | 39 | register_classes(Animal, Dog); 40 | 41 | declare_method(void, kick, (virtual_)); 42 | 43 | using namespace yorel::yomm2; // for brevity 44 | 45 | error_handler_type next_error_handler; 46 | 47 | void no_definition_handler(const error_type& ev) { 48 | if (auto error = std::get_if(&ev)) { 49 | if (error->status == resolution_error::no_definition) { 50 | throw std::runtime_error("not defined"); 51 | } 52 | } 53 | 54 | next_error_handler(ev); 55 | } 56 | 57 | BOOST_AUTO_TEST_CASE(ref_set_error_handler_example) { 58 | next_error_handler = set_error_handler(no_definition_handler); 59 | update(); 60 | 61 | try { 62 | Dog snoopy; 63 | kick(snoopy); 64 | } catch (const std::runtime_error& error) { 65 | BOOST_TEST(error.what() == "not defined"); 66 | return; 67 | } 68 | 69 | BOOST_FAIL("did not throw"); 70 | } 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /docs.in/reference/static_object.md: -------------------------------------------------------------------------------- 1 | # YOMM2 static objects 2 | 3 | hrefs: static_object 4 | 5 | // YOMM2 uses instances of various classes to register user classes, methods, and 6 | method definitions. The constructors adds the object to an intrusive forward 7 | list, and relies on underlying plain pointers to be zero-initialized. Thus, 8 | these objects must be defined at file scope, or as as `static` variables inside 9 | a function or a class. 10 | 11 | The static objects constructor do not allocate memory from the heap. 12 | 13 | ## See also 14 | 15 | The ->`YOMM2_STATIC` macro is a convenient way of creating static registration 16 | objects with an obfuscated name. 17 | -------------------------------------------------------------------------------- /docs.in/reference/template_.cpp: -------------------------------------------------------------------------------- 1 | #ifdef YOMM2_MD 2 | experimental: yorel::yomm2::template_ 3 | headers: 4 | 5 | ```c++ 6 | template typename Template> 7 | struct template_ { 8 | template 9 | using fn = /*unspecified*/; 10 | }; 11 | ``` 12 | 13 | `template_` wraps a template in a type, making it possible to appear in 14 | ->types lists. Nested template `fn` evaluates to the instantiation of 15 | the template with the specified types. 16 | 17 | ## Example 18 | 19 | #endif 20 | 21 | // clang-format off 22 | 23 | #ifdef YOMM2_CODE 24 | 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | 31 | using namespace yorel::yomm2; 32 | 33 | struct a; 34 | struct b; 35 | 36 | static_assert( 37 | std::is_same_v< 38 | template_::fn, 39 | std::pair 40 | >); 41 | 42 | #endif 43 | 44 | int main() {} 45 | -------------------------------------------------------------------------------- /docs.in/reference/templates.md: -------------------------------------------------------------------------------- 1 | experimental: yorel::yomm2::templates 2 | headers: yorel/yomm2/core.hpp 3 | 4 | ```c++ 5 | template typename... Templates> 6 | using templates = types...>; 7 | ``` 8 | `templates` wraps a sequence of templates in a ->types list of ->template_ 9 | wrappers. 10 | -------------------------------------------------------------------------------- /docs.in/reference/type_id.md: -------------------------------------------------------------------------------- 1 | entry: type_id 2 | headers: yorel/yomm2/policy.hpp, yorel/yomm2/core.hpp, yorel/yomm2/keywords.hpp 3 | ``` 4 | using type_id = std::uintptr_t; 5 | ``` 6 | -------------------------------------------------------------------------------- /docs.in/reference/types.md: -------------------------------------------------------------------------------- 1 | entry: types 2 | headers: yorel/yomm2/core.hpp 3 | 4 | ``` 5 | template 6 | struct types; 7 | ``` 8 | 9 | `types` is a sequence of types, similar to `boost:mp11::mp_list`, except that 10 | it does not have a definition 11 | -------------------------------------------------------------------------------- /docs.in/reference/update.md: -------------------------------------------------------------------------------- 1 | entry: update 2 | headers:yorel/yomm2/core.hpp, yorel/yomm2/keywords.hpp 3 | 4 | ```c++ 5 | /* compiler */ update(); (1) (since 1.6.0) 6 | /* compiler */ template void update(); (2) (since 1.6.0) 7 | 8 | void update(); (3) (until 1.6.0) 9 | templatevoid update(); (4) (until 1.6.0) 10 | ``` 11 | Initialize the data used during method dispatch. 12 | 13 | This function must be called before any method is called (typically in `main`). 14 | It must also be called after a shared library is dynamically loaded or unloaded, 15 | if the library adds method declarations, method definitions, or classes derived 16 | from classes that are used as virtual arguments. 17 | 18 | (1) and (3) operate on the default policy. (2) and (4) operate on the specified 19 | policy. 20 | 21 | Since version 1.6.0, `update` returns a "compiler" object of an unspecified 22 | type, which contains information gathered while compiling dispatch data. The 23 | only documented member is `report`, a struct containing the following values: 24 | 25 | | Name | Description | 26 | | --------------- | -------------------------------------------------------------------------------- | 27 | | cells | total number of cells used by v-tables and multi-method dispatch tables | 28 | | not_implemented | total number of argument combinations with no applicable definition | 29 | | ambiguous | total number of argument combinations that cannot be resolved due to ambiguities | 30 | 31 | 32 | 33 | ```c++ 34 | int main() { 35 | yorel::yomm2::update(); 36 | // call methods 37 | 38 | // if using dynamically loaded libraries 39 | void* handle = dlopen("mylib.so", RTLD_NOW); 40 | yorel::yomm2::update(); 41 | // classes, methods, and definitions from mylib.so are available 42 | 43 | dlclose(handle); 44 | yorel::yomm2::update(); 45 | // classes, methods, and definitions from mylib.so are no longer available 46 | 47 | return 0; 48 | } 49 | ``` 50 | -------------------------------------------------------------------------------- /docs.in/reference/update_methods.md: -------------------------------------------------------------------------------- 1 | entry: update_methods 2 | headers:yorel/yomm2/core.hpp, yorel/yomm2/keywords.hpp 3 | 4 | Initialize the data used during method dispatch. 5 | 6 | This function must be called before any method is called (typically in `main`). 7 | It must also be called after a shared library is dynamically loaded or unloaded, 8 | if the library adds method declarations, method definitions, or classes derived 9 | from classes that are used as virtual arguments. 10 | 11 | ### Example 12 | 13 | ```c++ 14 | int main() { 15 | yorel::yomm2::update_methods(); 16 | // call methods 17 | 18 | // if using dynamically loaded libraries 19 | void* handle = dlopen("mylib.so", RTLD_NOW); 20 | yorel::yomm2::update_methods(); 21 | // classes, methods, and definitions from mylib.so are available 22 | 23 | dlclose(handle); 24 | yorel::yomm2::update_methods(); 25 | // classes, methods, and definitions from mylib.so are no longer available 26 | 27 | return 0; 28 | } 29 | ``` 30 | -------------------------------------------------------------------------------- /docs.in/reference/virtual_.cpp: -------------------------------------------------------------------------------- 1 | #ifdef YOMM2_MD 2 | 3 | entry: virtual_ 4 | headers: yorel/yomm2/core.hpp, yorel/yomm2/keywords.hpp, yorel/yomm2.hpp 5 | ``` 6 | template 7 | struct virtual_; 8 | ``` 9 | Mark a method parameter as virtual. 10 | 11 | `type` must be a reference, a rvalue reference, a pointer or a 12 | `std::shared_ptr` to a polymorphic type, possibly qualified with `const`. 13 | 14 | ## Examples 15 | 16 | #endif 17 | 18 | int main() {} 19 | 20 | #ifdef YOMM2_CODE 21 | 22 | #include 23 | 24 | struct Animal { 25 | virtual ~Animal() {} 26 | }; 27 | 28 | declare_method(void, kick, (virtual_)); 29 | declare_method(void, kick, (virtual_)); 30 | declare_method(void, kick, (virtual_)); 31 | declare_method(void, kick, (virtual_>)); 32 | declare_method(void, kick, (virtual_&>)); 33 | declare_method(void, kick, (virtual_)); 34 | declare_method(void, kick, (virtual_)); 35 | declare_method(void, kick, (virtual_>)); 36 | declare_method(void, kick, (virtual_&>)); 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /docs.in/tutorials/templates_tutorial_matrix_1.cpp: -------------------------------------------------------------------------------- 1 | #define COMPILE_MATRIX 2 | #define INCREMENTAL 3 | 4 | #include "templates_tutorial.cpp" 5 | -------------------------------------------------------------------------------- /docs.in/tutorials/templates_tutorial_matrix_2.cpp: -------------------------------------------------------------------------------- 1 | #define COMPILE_MATRIX 2 | 3 | #include "templates_tutorial.cpp" 4 | -------------------------------------------------------------------------------- /docs.in/tutorials/templates_tutorial_vector_1.cpp: -------------------------------------------------------------------------------- 1 | #define COMPILE_VECTOR 2 | #define INCREMENTAL 3 | 4 | #include "templates_tutorial.cpp" 5 | -------------------------------------------------------------------------------- /docs.in/tutorials/templates_tutorial_vector_2.cpp: -------------------------------------------------------------------------------- 1 | #define COMPILE_VECTOR 2 | 3 | #include "templates_tutorial.cpp" 4 | -------------------------------------------------------------------------------- /docs/benchmarks/1vec.euclid.clang.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ## Context 6 | 7 | 100 hierarchies of 1000 objects 8 | Compiler: clang 14.0.0 9 | Build type: release 10 | Load average: 0.93, 1.18, 0.99 11 | Run on `euclid` on 2023-04-16T10:43:11-04:00 12 | 16 X 3300 MHZ CPUs 13 | CPU caches: 14 |   L1 Data 32768 KiB (x2) 15 |   L1 Instruction 32768 KiB (x2) 16 |   L2 Unified 524288 KiB (x2) 17 |   L3 Unified 4194304 KiB (x8) 18 | command line: dev/bm2md --prefix docs/benchmarks/1vec --log-level info 19 | max cv = 1.5% 20 | ## arity 1, ordinary base 21 | 22 | |dispatch|avg|ratio| 23 | | ---: | ---: | ---: | 24 | |virtual function| 66.3|1.00| 25 | |hash factors in globals| 92.5| 1.40| 26 | |hash factors in method| 93.4| 1.41| 27 | |direct intrusive| 70.1| 1.06| 28 | |indirect intrusive| 75.4| 1.14| 29 | 30 | max cv = 1.5% 31 | ## arity 2, ordinary base 32 | 33 | |dispatch|avg|ratio| 34 | | ---: | ---: | ---: | 35 | |virtual function| 106.2|1.00| 36 | |hash factors in globals| 138.5| 1.30| 37 | |hash factors in method| 137.4| 1.29| 38 | |direct intrusive| 121.3| 1.14| 39 | |indirect intrusive| 125.6| 1.18| 40 | 41 | max cv = 0.7% 42 | ## arity 1, virtual base 43 | 44 | |dispatch|avg|ratio| 45 | | ---: | ---: | ---: | 46 | |virtual function| 83.3|1.00| 47 | |hash factors in globals| 180.8| 2.17| 48 | |hash factors in method| 181.1| 2.17| 49 | |direct intrusive| 169.8| 2.04| 50 | |indirect intrusive| 179.0| 2.15| 51 | 52 | max cv = 0.4% 53 | ## arity 2, virtual base 54 | 55 | |dispatch|avg|ratio| 56 | | ---: | ---: | ---: | 57 | |virtual function| 121.1|1.00| 58 | |hash factors in globals| 260.3| 2.15| 59 | |hash factors in method| 258.4| 2.13| 60 | |direct intrusive| 242.5| 2.00| 61 | |indirect intrusive| 249.3| 2.06| 62 | 63 | max cv = 1.2% -------------------------------------------------------------------------------- /docs/benchmarks/4vec.euclid.clang.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ## Context 6 | 7 | 100 hierarchies of 1000 objects 8 | Compiler: clang 14.0.0 9 | Build type: release 10 | Load average: 0.23, 0.18, 0.34 11 | Run on `euclid` on 2023-04-16T10:31:13-04:00 12 | 16 X 3300 MHZ CPUs 13 | CPU caches: 14 |   L1 Data 32768 KiB (x2) 15 |   L1 Instruction 32768 KiB (x2) 16 |   L2 Unified 524288 KiB (x2) 17 |   L3 Unified 4194304 KiB (x8) 18 | command line: dev/bm2md --prefix docs/benchmarks/3vec --log-level info 19 | max cv = 1.5% 20 | ## arity 1, ordinary base 21 | 22 | |dispatch|avg|ratio| 23 | | ---: | ---: | ---: | 24 | |virtual function| 66.5|1.00| 25 | |hash factors in globals| 95.6| 1.44| 26 | |hash factors in method| 95.5| 1.43| 27 | |direct intrusive| 71.6| 1.08| 28 | |indirect intrusive| 75.9| 1.14| 29 | 30 | max cv = 1.5% 31 | ## arity 2, ordinary base 32 | 33 | |dispatch|avg|ratio| 34 | | ---: | ---: | ---: | 35 | |virtual function| 106.3|1.00| 36 | |hash factors in globals| 140.2| 1.32| 37 | |hash factors in method| 139.9| 1.32| 38 | |direct intrusive| 121.9| 1.15| 39 | |indirect intrusive| 126.4| 1.19| 40 | 41 | max cv = 0.2% 42 | ## arity 1, virtual base 43 | 44 | |dispatch|avg|ratio| 45 | | ---: | ---: | ---: | 46 | |virtual function| 89.2|1.00| 47 | |hash factors in globals| 186.6| 2.09| 48 | |hash factors in method| 187.6| 2.10| 49 | |direct intrusive| 173.5| 1.94| 50 | |indirect intrusive| 180.7| 2.03| 51 | 52 | max cv = 1.3% 53 | ## arity 2, virtual base 54 | 55 | |dispatch|avg|ratio| 56 | | ---: | ---: | ---: | 57 | |virtual function| 123.6|1.00| 58 | |hash factors in globals| 272.4| 2.20| 59 | |hash factors in method| 265.1| 2.15| 60 | |direct intrusive| 250.1| 2.02| 61 | |indirect intrusive| 252.5| 2.04| 62 | 63 | max cv = 0.5% -------------------------------------------------------------------------------- /docs/benchmarks/v010500.euclid.clang.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ## Context 6 | 7 | 100 hierarchies of 1000 objects 8 | Compiler: clang 16.0.6 9 | Build type: release 10 | Load average: 1.56, 1.61, 1.66 11 | Run on `euclid` on 2024-04-26T11:05:55-04:00 12 | 16 X 3300 MHZ CPUs 13 | CPU caches: 14 |   L1 Data 32768 KiB (x2) 15 |   L1 Instruction 32768 KiB (x2) 16 |   L2 Unified 524288 KiB (x2) 17 |   L3 Unified 4194304 KiB (x8) 18 | command line: dev/bm2md --prefix docs/benchmarks/v010500 --log-level info 19 | max cv = 1.1% 20 | ## arity 1, ordinary base 21 | 22 | |dispatch|avg|ratio| 23 | | ---: | ---: | ---: | 24 | |virtual function| 60.1|1.00| 25 | |basic policy| 80.4| 1.34| 26 | |std map policy| 97.2| 1.62| 27 | |flat map policy| 88.5| 1.47| 28 | |direct intrusive| 65.4| 1.09| 29 | |indirect intrusive| 80.6| 1.34| 30 | |direct virtual ptr| 10.5| 0.18| 31 | |indirect virtual ptr| 12.2| 0.20| 32 | 33 | max cv = 1.1% 34 | ## arity 2, ordinary base 35 | 36 | |dispatch|avg|ratio| 37 | | ---: | ---: | ---: | 38 | |virtual function| 93.2|1.00| 39 | |basic policy| 124.0| 1.33| 40 | |std map policy| 143.0| 1.53| 41 | |flat map policy| 131.3| 1.41| 42 | |direct intrusive| 108.0| 1.16| 43 | |indirect intrusive| 121.5| 1.30| 44 | |direct virtual ptr| 19.4| 0.21| 45 | |indirect virtual ptr| 20.5| 0.22| 46 | 47 | max cv = 0.9% 48 | ## arity 1, virtual base 49 | 50 | |dispatch|avg|ratio| 51 | | ---: | ---: | ---: | 52 | |virtual function| 74.3|1.00| 53 | |basic policy| 162.7| 2.19| 54 | |std map policy| 183.8| 2.47| 55 | |flat map policy| 174.9| 2.35| 56 | |direct intrusive| 152.2| 2.05| 57 | |indirect intrusive| 161.4| 2.17| 58 | |direct virtual ptr| 156.9| 2.11| 59 | |indirect virtual ptr| 154.5| 2.08| 60 | 61 | max cv = 0.6% 62 | ## arity 2, virtual base 63 | 64 | |dispatch|avg|ratio| 65 | | ---: | ---: | ---: | 66 | |virtual function| 107.3|1.00| 67 | |basic policy| 233.6| 2.18| 68 | |std map policy| 264.1| 2.46| 69 | |flat map policy| 261.8| 2.44| 70 | |direct intrusive| 219.7| 2.05| 71 | |indirect intrusive| 237.1| 2.21| 72 | |direct virtual ptr| 231.9| 2.16| 73 | |indirect virtual ptr| 228.9| 2.13| 74 | 75 | max cv = 0.3% -------------------------------------------------------------------------------- /docs/ce/2d-vs-2m-ref.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/ce/2d-vs-2m-vptr.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/ce/slides.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/ce/vf-vs-1m-ref.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/ce/vf-vs-1m-vptr.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/ce/vptr-final.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/cppnow2018/call_pay.s: -------------------------------------------------------------------------------- 1 | 2 | call_pay_vfunc(Employee const&): 3 | movq (%rdi), %rax 4 | jmp *16(%rax) 5 | 6 | call_pay_method(Employee const&): 7 | 8 | ;;; clang 5.0 9 | movq dispatch_data(%rip), %rax ; hash table 10 | movb dispatch_data+32(%rip), %cl ; shift factor 11 | movslq method::slots_strides(%rip), %rdx ; slot 12 | movq (%rdi), %rsi ; vptr 13 | movq -8(%rsi), %rsi ; type_info ptr 14 | imulq dispatch_data+24(%rip), %rsi ; hash: multiply 15 | shrq %cl, %rsi ; hash: shift 16 | movq (%rax,%rsi,8), %rax ; method table 17 | jmpq *(%rax,%rdx,8) # TAILCALL ; call function 18 | 19 | ;;; gdc 6.0 20 | movq (%rdi), %rax ; vptr 21 | movq dispatch_data+32(%rip), %rcx ; shift factor 22 | movslq method::slots_strides(%rip), %rdx ; slot 23 | movq -8(%rax), %rax ; type_info ptr 24 | imulq dispatch_data+24(%rip), %rax ; hash: multiply 25 | shrq %cl, %rax ; hash: shift 26 | movq dispatch_data(%rip), %rcx ; hash table 27 | movq (%rcx,%rax,8), %rax ; method table 28 | jmp *(%rax,%rdx,8) ; call function 29 | -------------------------------------------------------------------------------- /docs/cppnow2018/pay-decl.cpp: -------------------------------------------------------------------------------- 1 | // (setq c-basic-offset 2) 2 | 3 | struct _yomm2_method_pay; 4 | namespace { namespace YoMm2_nS_10 { 5 | using _yOMM2_method = 6 | method), 8 | default_policy>; 9 | _yOMM2_method::init_method init = "pay" 10 | "(virtual_)"; 11 | } 12 | } 13 | YoMm2_nS_10::_yOMM2_method 14 | pay(discriminator, 15 | virtual_arg_t> a0); 16 | inline double 17 | pay(virtual_arg_t> a0) { 18 | auto pf = reinterpret_cast> a0)>( 20 | YoMm2_nS_10::_yOMM2_method::resolve(a0)); 21 | return pf(std::forward< 22 | virtual_arg_t>>( 23 | a0)); 24 | }; 25 | -------------------------------------------------------------------------------- /docs/cppnow2018/preprocess.sh: -------------------------------------------------------------------------------- 1 | clang++-5.0 -std=c++17 -I ~/dev/yomm2/include -E rolex.cpp \ 2 | | clang-format \ 3 | | perl -pe ' 4 | s/::yorel::yomm2::(detail::)?//g; 5 | s/virtual_arg_t]+)>>/$1/g; 6 | s/ / /g; 7 | ' 8 | -------------------------------------------------------------------------------- /docs/cppnow2018/rolex.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct Role { 4 | virtual ~Role() {} 5 | }; 6 | 7 | struct Employee : Role { 8 | virtual double pay() const; 9 | }; 10 | 11 | struct Manager : Employee { 12 | virtual double pay() const; 13 | }; 14 | 15 | struct Founder : Role {}; 16 | 17 | struct Expense { 18 | virtual ~Expense() {} 19 | }; 20 | 21 | struct Public : Expense {}; 22 | struct Bus : Public {}; 23 | struct Metro : Public {}; 24 | struct Taxi : Expense {}; 25 | struct Jet : Expense {}; 26 | 27 | register_class(Role); 28 | register_class(Employee, Role); 29 | register_class(Manager, Employee); 30 | register_class(Founder, Role); 31 | register_class(Expense); 32 | register_class(Public, Expense); 33 | register_class(Bus, Public); 34 | register_class(Metro, Public); 35 | register_class(Taxi, Expense); 36 | register_class(Jet, Expense); 37 | 38 | declare_method(double, pay, (virtual_)); 39 | declare_method(bool, approve, (virtual_, virtual_, double)); 40 | 41 | define_method(double, pay, (const Employee&)) { 42 | return 3000; 43 | } 44 | 45 | define_method(double, pay, (const Manager& exec)) { 46 | return next(exec) + 2000; 47 | } 48 | 49 | define_method(bool, approve, (const Role& r, const Expense& e, double amount)) { 50 | return false; 51 | } 52 | 53 | define_method(bool, approve, (const Employee& r, const Public& e, double amount)) { 54 | return true; 55 | } 56 | 57 | define_method(bool, approve, (const Manager& r, const Taxi& e, double amount)) { 58 | return true; 59 | } 60 | 61 | define_method(bool, approve, (const Founder& r, const Expense& e, double amount)) { 62 | return true; 63 | } 64 | 65 | double call_pay(const Employee& emp) { 66 | return pay(emp); 67 | } 68 | 69 | double Employee::pay() const { 70 | return 3000; 71 | } 72 | 73 | double Manager::pay() const { 74 | return Employee::pay() + 2000; 75 | } 76 | 77 | double call_pay_vfunc(const Employee& emp) { 78 | return emp.pay(); 79 | } 80 | -------------------------------------------------------------------------------- /docs/cppnow2018/yomm2 - Fast, Orthogonal, Open Methods.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jll63/yomm2/6c2204c5e6d3733bff7bc59ee1d2e95bdbff1bff/docs/cppnow2018/yomm2 - Fast, Orthogonal, Open Methods.pdf -------------------------------------------------------------------------------- /docs/cppnow2018/yomm2 - Fast, Orthogonal, Open Methods_files/zenburn.css: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Zenburn style from voldmar.ru (c) Vladimir Epifanov 4 | based on dark.css by Ivan Sagalaev 5 | 6 | */ 7 | 8 | .hljs { 9 | display: block; 10 | overflow-x: auto; 11 | padding: 0.5em; 12 | background: #3f3f3f; 13 | color: #dcdcdc; 14 | } 15 | 16 | .hljs-keyword, 17 | .hljs-selector-tag, 18 | .hljs-tag { 19 | color: #e3ceab; 20 | } 21 | 22 | .hljs-template-tag { 23 | color: #dcdcdc; 24 | } 25 | 26 | .hljs-number { 27 | color: #8cd0d3; 28 | } 29 | 30 | .hljs-variable, 31 | .hljs-template-variable, 32 | .hljs-attribute { 33 | color: #efdcbc; 34 | } 35 | 36 | .hljs-literal { 37 | color: #efefaf; 38 | } 39 | 40 | .hljs-subst { 41 | color: #8f8f8f; 42 | } 43 | 44 | .hljs-title, 45 | .hljs-name, 46 | .hljs-selector-id, 47 | .hljs-selector-class, 48 | .hljs-section, 49 | .hljs-type { 50 | color: #efef8f; 51 | } 52 | 53 | .hljs-symbol, 54 | .hljs-bullet, 55 | .hljs-link { 56 | color: #dca3a3; 57 | } 58 | 59 | .hljs-deletion, 60 | .hljs-string, 61 | .hljs-built_in, 62 | .hljs-builtin-name { 63 | color: #cc9393; 64 | } 65 | 66 | .hljs-addition, 67 | .hljs-comment, 68 | .hljs-quote, 69 | .hljs-meta { 70 | color: #7f9f7f; 71 | } 72 | 73 | 74 | .hljs-emphasis { 75 | font-style: italic; 76 | } 77 | 78 | .hljs-strong { 79 | font-weight: bold; 80 | } 81 | -------------------------------------------------------------------------------- /docs/reference/RestrictedOutputStream.md: -------------------------------------------------------------------------------- 1 | RestrictedOutputStream

2 | 3 | Stream& operator<<(Stream& os, const std::string_view& view); 4 | Stream& operator<<(Stream& os, const void* value); 5 | Stream& operator<<(Stream& os, size_t value); 6 | 7 | (where `Stream` is the type of the `error_stream` data member) 8 | -------------------------------------------------------------------------------- /docs/reference/RuntimeClass.md: -------------------------------------------------------------------------------- 1 | RuntimeClass

2 | 3 | This concept specifies the operations available on the objects in the range 4 | passed to `publish_vptrs` function of facet [`vptr_vector`](/yomm2/reference/policy-vptr_vector.html), and the 5 | `hash_initialize` function of facet [`type_hash`](/yomm2/reference/policy-type_hash.html). 6 | 7 | 8 | ## Member functions 9 | 10 | ### type_id_begin 11 | 12 | ```c++ 13 | ForwardIterator type_id_begin() const 14 | ``` 15 | 16 | Return the beginning of a range of `type_id`s for the class. 17 | 18 | ### type_id_end 19 | 20 | ```c++ 21 | ForwardIterator type_id_end() const 22 | ``` 23 | Return the end of a range of `type_id`s for the class. 24 | 25 | ### vptr 26 | 27 | ```c++ 28 | const std::uintptr_t* vptr() const 29 | ``` 30 | 31 | Return a pointer to the v-table for the class. The pointer changes every time 32 | `update` is called. 33 | 34 | ### indirect_vptr 35 | 36 | ```c++ 37 | const std::uintptr_t* const* indirect_vptr() const 38 | ``` 39 | 40 | Return a pointer to a pointer to the v-table. This pointer to the pointer is 41 | stable across calls to `update`, although the pointer itself changes. 42 | -------------------------------------------------------------------------------- /docs/reference/YOMM2_GENSYM.md: -------------------------------------------------------------------------------- 1 | YOMM2_GENSYM

2 | defined in , also provided by
3 | 4 | `YOMM2_GENSYM` expands to a new C++ identifier each time it is called. The 5 | symbol is based on the `__COUNTER__` preprocessor macro, and decorated in such a 6 | way that it is unlikely to clash with user-defined symbols. 7 | 8 | `YOMM2_GENSYM` provides a convenient way of allocating [static 9 | objects](static_object.md) for registering classes, methods, or definitions. 10 | 11 | ### Example 12 | 13 | ```c++ 14 | int YOMM2_GENSYM; 15 | int YOMM2_GENSYM; // not a redefinition, this is a new symbol 16 | ``` 17 | -------------------------------------------------------------------------------- /docs/reference/YOMM2_STATIC.md: -------------------------------------------------------------------------------- 1 | # YOMM2_STATIC 2 | defined in , also provided by
3 | 4 | ```c++ 5 | #define YOMM2_STATIC(...) static __VA_ARGS__ YOMM2_GENSYM 6 | ``` 7 | 8 | `YOMM2_STATIC` provides a convenient way to create a static object just for 9 | executing its constructor at static initialization time. The macro creates an 10 | obfuscated name for the object, which is unlikely to clash with any other name. 11 | 12 | ### Example 13 | 14 | ```c++ 15 | // Instantiate a 'use_classes' object to register three classes. 16 | YOMM2_STATIC(yorel::yomm2::use_classes); 17 | ``` 18 | -------------------------------------------------------------------------------- /docs/reference/YOMM2_SYMBOL.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | YOMM2_SYMBOL

4 | defined in , also provided by
5 | 6 | ```c++ 7 | #define YOMM2_SYMBOL(seed) /*unspecified*/ 8 | ``` 9 | 10 | Macro `YOMM2_SYMBOL` expands to an obfuscated symbol, unlikely 11 | to clash with other names in scope. 12 | 13 | ## Example 14 | 15 | 16 | ```c++ 17 | #include 18 | 19 | BOOST_AUTO_TEST_CASE(ref_example) { 20 | int foo = 1; 21 | int YOMM2_SYMBOL(foo) = 2; 22 | BOOST_TEST(foo == 1); 23 | BOOST_TEST(YOMM2_SYMBOL(foo) == 2); 24 | } 25 | ``` 26 | -------------------------------------------------------------------------------- /docs/reference/aggregate.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | yorel::yomm2::aggregate
4 | defined in , also provided by
5 | 6 | ```c++ 7 | template struct aggregate; 8 | ``` 9 | 10 | An instance of `aggregate` contains one `T` sub-object for each 11 | specified `T`, just like a `std::tuple`. 12 | `aggregate` provides a convenient way to instantiate a collection of [YOMM2 13 | registration objects](static_object.md). Typically, the name of the variable 14 | does not matter, and [YOMM2_GENSYM](/yomm2/reference/YOMM2_GENSYM.html) can be used to generated that single-use 15 | identifier. 16 | Unlike typical `std::tuple` implementations, `aggregate` can 17 | handle large numbers of `T`s. For example, clang++-12 has a limit of 1024 18 | types, which can be reached easily when writing templatized method 19 | definitions. 20 | ## Example 21 | 22 | 23 | ```c++ 24 | #include 25 | #include 26 | 27 | using namespace yorel::yomm2; 28 | 29 | struct Animal { virtual ~Animal() {} }; 30 | struct Dog : Animal {}; 31 | struct Cat : Animal {}; 32 | 33 | aggregate< 34 | class_declaration>, 35 | class_declaration>, 36 | class_declaration> 37 | > YOMM2_GENSYM; 38 | ``` 39 | -------------------------------------------------------------------------------- /docs/reference/apply_product.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | **yorel::yomm2::apply_product** (experimental)
4 | defined in
5 | 6 | ```c++ 7 | template 8 | using apply_product = /*unspecified*/; 9 | ``` 10 | 11 | `apply_product` takes a [templates](/yomm2/reference/templates.html) list and list of [types](/yomm2/reference/types.html) lists, and 12 | evaluates to a `types` list consisting of the application of each template to 13 | the n-fold Cartesian product of the input `types` lists. 14 | 15 | ## Example 16 | 17 | 18 | ```c++ 19 | #include 20 | #include 21 | #include 22 | 23 | using namespace yorel::yomm2; 24 | 25 | struct a; 26 | struct b; 27 | struct x; 28 | struct y; 29 | struct z; 30 | 31 | template struct bin1; 32 | template struct bin2; 33 | 34 | static_assert( 35 | std::is_same_v< 36 | apply_product< 37 | templates, 38 | types, 39 | types 40 | >, 41 | types< 42 | bin1, bin1, bin1, 43 | bin1, bin1, bin1, 44 | 45 | bin2, bin2, bin2, 46 | bin2, bin2, bin2 47 | > 48 | >); 49 | ``` 50 | -------------------------------------------------------------------------------- /docs/reference/class_declaration.md: -------------------------------------------------------------------------------- 1 | yorel::yomm2::class_declaration
2 | defined in , also provided by
3 | 4 | ```c++ 5 | template 6 | struct class_declaration; 7 | ``` 8 | 9 | ### Usage 10 | ```c++ 11 | class_declaration identifier; 12 | class_declaration> identifier; 13 | ``` 14 | Register `Class` and its direct `Bases`. 15 | 16 | All classes that potentially take part in a method call must be registered with 17 | `class_declaration`, along with the inheritance relationships. 18 | 19 | Note that the registration requirement does not only apply to classes used as 20 | virtual parameters, and the classes used as parameters in method definitions 21 | that correspond to virtual parameters. The runtime class of all the objects 22 | potentially partaking in method *calls* must be registered. For example, given 23 | the hierarchy Animal -> Dog -> Bulldog; if a method declaration takes a 24 | `virtual_`; if the method has two definitions, one for Animal, and one 25 | for Bulldog; and the program calls the method for a Dog (that is not a Bulldog); 26 | then Dog must be registered as well. 27 | 28 | ## Example 29 | ```c++ 30 | struct Animal { virtual ~Animal() {} }; 31 | struct Dog : Animal {}; 32 | struct Bulldog : Dog {}; 33 | struct Cat : Animal {}; 34 | 35 | class_declaration> register_animal; 36 | class_declaration> register_dog; 37 | class_declaration> register_bulldog; 38 | class_declaration> register_cat; 39 | ``` 40 | 41 | ## See also 42 | `class_declaration` is a low level construct. It is recommended to use 43 | [use_classes](/yomm2/reference/use_classes.html) instead, which can register many classes, and their inheritance 44 | relationships, using a single [registration object](static_object.md). 45 | -------------------------------------------------------------------------------- /docs/reference/declare_method.md: -------------------------------------------------------------------------------- 1 | 2 | declare_method

3 | defined in , also provided by
4 | 5 | ```c++ 6 | #define declare_method(return-type, method, (types)) /*unspecified*/ 7 | ``` 8 | 9 | ### Usage 10 | 11 | ``` 12 | declare_method(return-type, method, (types)) { 13 | ... 14 | } 15 | ``` 16 | 17 | Declare a method. 18 | 19 | Create an inline function `method` that returns `return-type` and takes a 20 | parameter list consisting of `types`. At least one of `types` (but not 21 | necessarily all) must be a *virtual parameter*, i.e. in the form 22 | [`virtual_`](virtual_.md), or [`virtual_ptr`](virtual_ptr.md). The 23 | `virtual_` decorator is stripped from `types`. 24 | 25 | When `method` is called, the dynamic types of the virtual arguments are 26 | examined, and the most specific definition compatible with `unspecified_type...` 27 | is called. If no compatible definition exists, or if several compatible 28 | definitions exist but none of them is more specific than all the others, the 29 | call is illegal and an error handler is executed. By default it writes a 30 | diagnostic on `std::cerr ` and terminates the program via `abort`. The handler 31 | can be customized. 32 | 33 | NOTE: 34 | 35 | * The method parameter list _must_ be surrounded by parentheses. 36 | 37 | * The parameters in `types` consist of _just_ a type, e.g. `int` is correct 38 | but `int i` is not. 39 | 40 | * Types that contain commas (e.g. `tuple`) cannot be used directly as 41 | macro arguments. The workarounds are: 42 | * using an alias, e.g. `using int_char = tuple` 43 | * using any C++ construct that puts parentheses around the commas, 44 | e.g. `decltype(std::tuple())` 45 | * [`BOOST_IDENTITY_TYPE`](https://www.boost.org/doc/libs/1_82_0/libs/utility/identity_type/doc/html/index.html) 46 | 47 | ## synonym 48 | YOMM2_DECLARE, defined in , also provided by . 49 | 50 | ## Example 51 | ``` 52 | declare_method(std::string, kick, (virtual_)); 53 | declare_method(std::string, meet, (virtual_, virtual_)); 54 | declare_method(bool, approve, (virtual_, virtual_), double); 55 | ``` 56 | -------------------------------------------------------------------------------- /docs/reference/define_method_inline.md: -------------------------------------------------------------------------------- 1 | define_method_inline

2 | defined in , also provided by
3 | 4 | 5 | ``` 6 | #define define_method_inline(container, return-type, name, (function-parameter-list)) /*unspecified*/ 7 | ``` 8 | 9 | Add an definition to a method, inside a container, and make it inline. 10 | 11 | Like [define_method](/yomm2/reference/define_method.html), but the definition has the `inline` storage class, and 12 | thus can be placed in a header file and is a potential candidate for inlining. 13 | 14 | Note that inlining is only supported for definitions placed inside a container. 15 | Inlining implementations defined outside of a container would make no sense, as 16 | there would be no way of referencing them. 17 | 18 | See the documentation of [method_container](/yomm2/reference/method_container.html) for more information on method 19 | containers. 20 | 21 | See the documentation of [declare_method](/yomm2/reference/declare_method.html) for information on handling types that 22 | contain commas. 23 | 24 | ## synonym 25 | YOMM2_METHOD_INLINE, defined in , also provided by . 26 | -------------------------------------------------------------------------------- /docs/reference/friend_method.md: -------------------------------------------------------------------------------- 1 | friend_method

2 | defined in , also provided by
3 | 4 | YOMM2_FRIEND

5 | defined in , also provided by
6 | 7 | ``` 8 | #define friend_method(container) 9 | #define friend_method(container, return_type, name, (function-parameter-list)) 10 | ``` 11 | 12 | Grant friendship to all the methods inside a container friend of a class, or to 13 | a specific method. 14 | 15 | ## Example 16 | See the [containers](https://github.com/jll63/yomm2/tree/master/examples/containers) example. 17 | -------------------------------------------------------------------------------- /docs/reference/method_call_error.md: -------------------------------------------------------------------------------- 1 | yorel::yomm2::method_call_error
2 | yorel::yomm2::method_call_error_handler
3 | yorel::yomm2::set_method_call_error_handler
4 | defined in , also provided by
5 | 6 | ```c++ 7 | struct method_call_error { 8 | enum type { not_implemented = 0, ambiguous = 1 } code; 9 | std::string_view method_name; 10 | }; 11 | using method_call_error_handler = void (*)( 12 | const method_call_error &error, size_t arity, const std::type_info* const tis[]); 13 | 14 | method_call_error_handler set_method_call_error_handler( 15 | method_call_error_handler handler); 16 | ``` 17 | 18 | This mechanism is **deprecated**. Please use the new [error handler 19 | mechanism](set_error_handler.md) instead. 20 | 21 | If a method call cannot be dispatched, an error handler is called with a 22 | reference to a `method_call_error` structure, which contains the method's name 23 | in an unspecified format, and a code identifying the error. 24 | 25 | The default error handler terminates the program with `abort()`. A different 26 | handler can be installed with `set_method_call_error_handler`, which returns the 27 | previous handler. The handler *may not* return. It may throw an exception. 28 | -------------------------------------------------------------------------------- /docs/reference/method_class.md: -------------------------------------------------------------------------------- 1 | 2 | method_class

3 | defined in
4 | YOMM2_METHOD_CLASS

5 | defined in
6 | 7 | ```c++ 8 | #define method_class(RETURN_TYPE, NAME, ARGS [, POLICY]) 9 | #define YOMM2_METHOD_CLASS(RETURN_TYPE, NAME, ARGS [, POLICY]) 10 | ``` 11 | 12 | Both macros take the same arguments as [`declare_method`](/yomm2/reference/declare_method.html), and return the 13 | corresponding core type [`method`](/yomm2/reference/method.html). 14 | 15 | ## Example 16 | 17 | -------------------------------------------------------------------------------- /docs/reference/method_definition.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | method_definition

4 | defined in , also provided by
5 | 6 | ```c++ 7 | #define method_definition(CONTAINER, RETURN_TYPE, FUNCTION_PARAMETER_LIST) 8 | ``` 9 | 10 | Retrieve a method definition with a given return type and signature from a 11 | container. 12 | 13 | The resulting method can be used as a normal function reference. It can be 14 | called, and its address can be taken. In particular, this makes it possible for 15 | a method definition to call a base method as part of its implementation, in the 16 | same manner as an ordinary virtual function can call a specific base function 17 | by prefixing its name with a base class name. 18 | 19 | Note that the preferred way of calling the overriden method is via `next`. In 20 | normal circumstances, a method definition cannot assume which "super" or "base" 21 | function is the best choice, since the set of methods pertaining to the same 22 | declaration is open. 23 | 24 | ## synonym 25 | YOMM2_DEFINITION, defined in , also provided by . 26 | 27 | ## Example 28 | See the [containers](https://github.com/jll63/yomm2/tree/master/examples/containers) example. 29 | -------------------------------------------------------------------------------- /docs/reference/not_defined.md: -------------------------------------------------------------------------------- 1 | **yorel::yomm2::not_defined** (experimental)
2 | defined in
3 | 4 | ```c++ 5 | struct not_defined {}; 6 | ``` 7 | 8 | Classes derived from `not_defined` are discarded by [use_classes](/yomm2/reference/use_classes.html). 9 | 10 | ## Example 11 | 12 | See the [use_classes example](use_classes.md#example) 13 | -------------------------------------------------------------------------------- /docs/reference/policy-basic_error_output.md: -------------------------------------------------------------------------------- 1 | yorel::yomm2::policy::basic_error_output
2 | defined in , also provided by ,
3 | 4 | ```c++ 5 | template 6 | struct basic_error_output; 7 | ``` 8 | 9 | `basic_error_output` implements the [`error_output`](/yomm2/reference/policy-error_output.html) facet. 10 | 11 | ## Template parameters 12 | 13 | * **Policy**: The policy containing the facet. Since `basic_error_output` has 14 | static state, making the policy a template parameter ensures that each policy 15 | has its wn set of static member variables. 16 | 17 | * **Stream**: `Stream` can be any type that satisfies the requirements of 18 | [`RestrictedOutputStream`](/yomm2/reference/RestrictedOutputStream.html). The default value is a lightweight version of 19 | `std::ostream` that writes to `stderr`, using low-level C functions. 20 | 21 | ## Static member variables 22 | 23 | | Name | Value | 24 | | ---------------------------------------- | ---------------------- | 25 | | Stream [**error_stream**](#error_stream) | the stream to print to | 26 | 27 | ### error_stream 28 | 29 | Initialized by the default constructor of `Stream`. It is the responsibility of 30 | the program to perform further initialization if needed - for example, open a 31 | `std::ofstream`, before calling `update`. 32 | -------------------------------------------------------------------------------- /docs/reference/policy-basic_trace_output.md: -------------------------------------------------------------------------------- 1 | yorel::yomm2::policy::**basic_trace_output**
2 | defined in , also provided by ,
3 | 4 | ```c++ 5 | template 6 | struct basic_trace_output; 7 | ``` 8 | 9 | `basic_trace_output` implements the [`trace_output`](/yomm2/reference/policy-trace_output.html) facet. 10 | 11 | ## Template parameters 12 | 13 | * **Policy**: the policy containing the facet. Since `basic_trace_output` has 14 | static state, making the policy a template parameter ensures that each policy 15 | has its own set of static member variables. 16 | 17 | * **Stream**: - `Stream` can be any type that satisfies the requirements of 18 | [`RestrictedOutputStream`](/yomm2/reference/RestrictedOutputStream.html). The default value is a lightweight version of 19 | `std::ostream` that writes to `stderr`, using low-level C functions. 20 | 21 | ## Static member variables 22 | 23 | | Name | Value | 24 | | ---------------------------------------- | ----------------------- | 25 | | bool [**trace_enabled**](#trace_enabled) | enable or disable trace | 26 | | Stream [**trace_stream**](#trace_stream) | the stream to print to | 27 | 28 | ### trace_enabled 29 | 30 | Controls whether information is printed to `trace_stream`. The flag is 31 | initialized by examining the `YOMM2_TRACE` environment variable. If it is set, 32 | and its value is `1`, trace is enabled. Other values are reserved for possible 33 | future use. 34 | 35 | ### trace_stream 36 | 37 | Initialized by the default constructor of `Stream`. It is the responsibility of 38 | the program to perform further initialization if needed - for example, open a 39 | `std::ofstream`, before calling `update`. 40 | -------------------------------------------------------------------------------- /docs/reference/policy-checked_perfect_hash.md: -------------------------------------------------------------------------------- 1 | yorel::yomm2::policy::checked_perfect_hash
2 | defined in , also provided by ,
3 | ``` 4 | template 5 | struct checked_perfect_hash; 6 | ``` 7 | 8 | 9 | `checked_perfect_hash` is a subclass of [`fast_perfect_hash`](/yomm2/reference/policy-fast_perfect_hash.html). It checks 10 | that the id passed to `hash_type_index` is valid, i.e. was in the set of ids 11 | registered via `hash_initialize`. 12 | 13 | ## Template parameters 14 | 15 | **Policy** - the policy containing the facet. 16 | 17 | ## Static member functions 18 | 19 | | Name | Description | 20 | | ----------------------------------- | ---------------------------- | 21 | | [hash_initialize](#hash_initialize) | finds a hash function | 22 | | [hash_type_id](#hash_type_id) | returns the hashed `type_id` | 23 | 24 | ### hash_initialize 25 | 26 | ```c++ 27 | template 28 | template 29 | static size_t hash_initialize(ForwardIterator first, ForwardIterator last) 30 | ``` 31 | 32 | Calls 33 | [`fast_perfect_hash::hash_initialize`](policy-fast_perfect_hash.html#hash_initialize). 34 | Also build a reverse mapping, from hashed ids to registered ids. 35 | 36 | 37 | #### Parameters 38 | 39 | **first**, **last** - a range of `type_id`s 40 | 41 | #### Return value 42 | 43 | None. 44 | 45 | #### Errors 46 | 47 | * Any exception thrown by Allocator::allocate() (typically std::bad_alloc). 48 | 49 | ### hash_type_id 50 | 51 | ```c++ 52 | template 53 | static type_id hash_type_id(type_id type) 54 | ``` 55 | 56 | Retrieve the registered id corresponding to the hashed id. Compare it with 57 | `type`. If they are the same, return the hashed value. If not, report an error 58 | via `Policy::error` if `Policy` has an `error_handler` facet; otherwise, 59 | abort the program. 60 | 61 | #### Parameters 62 | 63 | **type** - a `type_id` 64 | 65 | #### Return value 66 | 67 | None. 68 | 69 | #### Errors 70 | 71 | * [`unknown_class_error`](/yomm2/reference/error.html), with `context` set to `unknown_class_error::update`. 72 | 73 | ## Interactions with other facets 74 | 75 | * `error_handler` - to report error conditions. 76 | * `error_output` - for diagnostics. 77 | * `trace_output` - for trace. 78 | -------------------------------------------------------------------------------- /docs/reference/policy-deferred_static_rtti.md: -------------------------------------------------------------------------------- 1 | yorel::yomm2::policy::deferred_static_rtti
2 | 3 | ```c++ 4 | struct deferred_static_rtti : virtual rtti {}; 5 | ``` 6 | 7 | The `deferred_static_rtti` facet, derived from `rtti`, directs YOMM2 to defer 8 | collection of static type information until `update` is called. This makes it 9 | possible to interface with custom RTTI systems that use static constructors to 10 | assign type information. 11 | 12 | ## See also 13 | 14 | The custom RTTI [tutorial](/yomm2/tutorials/custom_rtti_tutorial.html). 15 | -------------------------------------------------------------------------------- /docs/reference/policy-error_handler.md: -------------------------------------------------------------------------------- 1 | yorel::yomm2::policy::error_handler
2 | defined in , also provided by
3 | 4 | ```c+ 5 | struct error_handler; 6 | ``` 7 | 8 | The `error_handler` is used by YOMM2 to handle error conditions. If it is 9 | present, its static member `error` is called with a variant describing the 10 | error. If the function returns normally, the program is terminated by a call to 11 | `abort`. 12 | 13 | ## Requirements for implementations of **error_handler** 14 | 15 | | | | 16 | | --------------------------------- | -------------------------------- | 17 | | _unspecified_ [**error**](#error) | called when an error is detected | 18 | 19 | (all members are static) 20 | 21 | ### error 22 | 23 | Handle the error condition. `error` can be a function or a function or a 24 | functor, taking a single `const error_type&` argument, and returning `void`. It 25 | can throw an exception, derived from class [`error`](/yomm2/reference/error.html), to prevent program 26 | termination. 27 | 28 | ## Implementations of `error_handler` 29 | 30 | | | | 31 | | ----------------------- | ---------------------------------------------------------------------- | 32 | | [throw_error](/yomm2/reference/policy-throw_error.html) | throw the error as an exception | 33 | | [vectored_error](/yomm2/reference/policy-vectored_error.html) | implement `error` as `std::function`; default value prints diagnostics | 34 | -------------------------------------------------------------------------------- /docs/reference/policy-error_output.md: -------------------------------------------------------------------------------- 1 | yorel::yomm2::policy::error_output
2 | defined in , also provided by ,
3 | 4 | struct error_output; 5 | 6 | The `error_output` facet is used to print diagnostics about error conditions. 7 | 8 | **Requirements for implementations of `error_output`** 9 | 10 | | | | 11 | | ------------------------------------- | ---------------------------- | 12 | | `static /*unspeficied*/ error_stream` | a [`RestrictedOutputStream`](/yomm2/reference/RestrictedOutputStream.html) | 13 | 14 | **Implementations of `error_output`** 15 | 16 | | | | 17 | | --------------------------- | ----------------------------------------- | 18 | | [basic_error_output](/yomm2/reference/policy-basic_error_output.html) | print to a `Stream` local to the `Policy` | 19 | -------------------------------------------------------------------------------- /docs/reference/policy-throw_error.md: -------------------------------------------------------------------------------- 1 | 2 | yorel::yomm2::policy::throw_error
3 | defined in yorel::yomm2::policy by , also provided by 4 | 5 | 6 | struct throw_error; 7 | 8 | `throw_error` implements [`error_handler`](/yomm2/reference/policy-error_handler.html) by throwing errors as 9 | exceptions. 10 | 11 | If exceptions are disabled, `throw_error` is not defined. 12 | 13 | ## Static member functions 14 | 15 | | | | 16 | | --------------------------------- | ------------------------------- | 17 | | [**error**](#error) | throw the error variant's value | 18 | 19 | ### error 20 | 21 | ```c++ 22 | static void error(const error_type& error_variant); 23 | ``` 24 | 25 | Extract the value of `error_variant`, and throw it as an exception. 26 | 27 | ## Example 28 | 29 | ```c++ 30 | #include 31 | 32 | namespace yomm2 = yorel::yomm2; 33 | using yomm2::virtual_; 34 | 35 | struct Animal { 36 | virtual ~Animal() { 37 | } 38 | }; 39 | 40 | struct Dog : Animal {}; 41 | 42 | using throw_policy = yomm2::default_policy::replace< 43 | yomm2::policy::error_handler, yomm2::policy::throw_error>; 44 | 45 | register_classes(Animal, Dog, throw_policy); 46 | 47 | declare_method(void, kick, (virtual_), throw_policy); 48 | 49 | BOOST_AUTO_TEST_CASE(ref_throw_error) { 50 | yomm2::update(); 51 | 52 | bool threw = false; 53 | 54 | try { 55 | Animal&& dog = Dog(); 56 | kick(dog); 57 | } catch (yomm2::resolution_error& error) { 58 | BOOST_TEST(error.status == yomm2::resolution_error::no_definition); 59 | BOOST_TEST( 60 | error.method_name == 61 | typeid(method_class(void, kick, (virtual_), throw_policy)) 62 | .name()); 63 | BOOST_TEST(error.arity == 1); 64 | BOOST_TEST(error.types[0] == throw_policy::static_type()); 65 | threw = true; 66 | } 67 | 68 | BOOST_TEST(threw); 69 | } 70 | ``` 71 | -------------------------------------------------------------------------------- /docs/reference/policy-trace_output.md: -------------------------------------------------------------------------------- 1 | yorel::yomm2::policy::trace_output
2 | defined in , also provided by ,
3 | 4 | struct trace_output; 5 | 6 | The `trace_output` facet enables the YOMM2 runtime to print information about 7 | the data structures used at dispatch time, and how they are derived. This 8 | includes deduction of inheritance lattices, v-table slot allocation, dispatch 9 | table construction, hash parameters, etc. This can help troubleshoot common 10 | errors, like missing class registrations, ambiguities in method definitions, 11 | etc. 12 | 13 | The format of the information is not documented, beyond that it is useful. It 14 | may change without notice. 15 | 16 | **Requirements for implementations of `trace_output`** 17 | 18 | | | | 19 | | ------------------------------------- | ---------------------------- | 20 | | `static /*unspeficied*/ trace_stream` | a [`RestrictedOutputStream`](/yomm2/reference/RestrictedOutputStream.html) | 21 | | `static bool trace_enabled` | enable trace if `true` | 22 | 23 | 24 | 25 | **Implementations of `trace_output`** 26 | 27 | | | | 28 | | ----------------------------- | ------------------------------------- | 29 | | [`basic_trace_output`](/yomm2/reference/policy-basic_trace_output.html) | print to a `Stream` local to `Policy` | 30 | -------------------------------------------------------------------------------- /docs/reference/policy-type_hash.md: -------------------------------------------------------------------------------- 1 | yorel::yomm2::policy::type_hash
2 | defined in , also provided by ,
3 | refs: type_hash 4 | 5 | ``` 6 | struct type_hash {}; 7 | ``` 8 | 9 | The `type_hash` facet projects a sparse range of [`type_id`](/yomm2/reference/type_id.html)s to a dense range. 10 | 11 | ### Requirements for implementations of `type_hash` 12 | 13 | An implementation of `type_hash` must provide the following static functions: 14 | 15 | | | | 16 | | ----------------------------------- | --------------------------- | 17 | | [hash_initialize](#hash_initialize) | implementation dependent | 18 | | [hash_type_id](#hash_type_id) | return the hashed `type_id` | 19 | 20 | ### Implementations of `type_hash` 21 | 22 | | | | 23 | | ----------------------------- | ------------------------------------------------------------- | 24 | | [fast_perfect_hash](/yomm2/reference/policy-fast_perfect_hash.html) | use a fast, perfect, but not minimal integer hash | 25 | | [checked_perfect_hash](/yomm2/reference/policy-checked_perfect_hash.html) | like `fast_perfect_hash`, also check for unregistered classes | 26 | 27 | 28 | ### hash_initialize 29 | 30 | ```c++ 31 | template 32 | static size_t hash_initialize(ForwardIterator first, ForwardIterator last); 33 | ``` 34 | 35 | Called by another facet in the policy if it requires hashing. 36 | [`vptr_vector`](/yomm2/reference/policy-vptr_vector.html) in the default policy does that. 37 | 38 | The function takes a range of [`type_id`](/yomm2/reference/type_id.html)s, and finds a hash function for that 39 | specific set of values. 40 | 41 | ### hash_type_id 42 | 43 | ```c++ 44 | static type_id hash_type_id(type_id type); 45 | ``` 46 | 47 | Called during method dispatch. Returns the corresponding value in the dense 48 | range. `type` must be one of the `type_id`s passed to `hash_initialize`. 49 | -------------------------------------------------------------------------------- /docs/reference/policy-vectored_error.md: -------------------------------------------------------------------------------- 1 | yorel::yomm2::policy::vectored_error
2 | defined in , also provided by
3 | 4 | ```c++ 5 | template 6 | struct vectored_error; 7 | ``` 8 | 9 | `vectored_error` implements [`error_handler`](/yomm2/reference/policy-error_handler.html) using a static 10 | `std::function`. 11 | 12 | ## Template parameters 13 | 14 | | Name | Value | 15 | | --------------------------- | ------------------------------- | 16 | | class [**Policy**](#policy) | the policy containing the facet | 17 | 18 | ### Policy 19 | 20 | The policy containing the facet. Since `vectored_error` has a static member 21 | variable, making the policy a template parameter ensures that each policy has 22 | its own copy. 23 | 24 | **Static member variables** 25 | 26 | | | | 27 | | -------------------------------------- | --------------------- | 28 | | error_handler_type [**error**](#error) | current error handler | 29 | 30 | ### error 31 | 32 | ```c++ 33 | static error_handler_type error; 34 | ``` 35 | 36 | A `std::function` (see [`error_handler_type`](/yomm2/reference/error.html)), initialized to 37 | `default_error_handler`. 38 | 39 | The function may throw an exception (unless they have been disabled), thus 40 | preventing program termination. 41 | 42 | **Static member functions** 43 | 44 | | | | 45 | | ------------------------------------------------- | ----------------- | 46 | | [`default_error_handler`](#default_error_handler) | print diagnostics | 47 | 48 | ### default_error_handler 49 | 50 | ```c++ 51 | static void default_error_handler(const error_type& error_v) 52 | ``` 53 | 54 | If [`error_output`](/yomm2/reference/policy-error_output.html) is available in `Policy`, use it to print a 55 | description of `error`. Return normally, causing the program to be aborted. 56 | 57 | 58 | ## Interactions with other facets 59 | 60 | * [`error_output`](/yomm2/reference/policy-error_output.html): for diagnostics. 61 | -------------------------------------------------------------------------------- /docs/reference/policy-vptr_map.md: -------------------------------------------------------------------------------- 1 | yorel::yomm2::policy::vptr_map
2 | defined in , also provided by ,
3 | 4 | ```c++ 5 | template 6 | struct vptr_map; 7 | ``` 8 | 9 | `vptr_map` is an implementation of [`external_vptr`](/yomm2/reference/policy-vptr_placement.html) that stores the 10 | pointers to the v-tables in a `std::unordered_map` keyed by the [`type_id`](/yomm2/reference/type_id.html)s of 11 | the classes. This makes method dispatch slower than [`vptr_vector`](/yomm2/reference/policy-vptr_vector.html) with 12 | [`fast_perfect_hash`](/yomm2/reference/policy-fast_perfect_hash.html) (75% slower than native virtual function). However, 13 | `vptr_map` has some advantages: `fast_perfect_hash` takes more time to 14 | initialize. It also sacrifices memory space for speed, as it uses a hash 15 | function that is not suitable for perfect _and_ minimal hashing. Using 16 | `virtual_ptr`s extensively can mitigate the speed disadvantage of `vptr_map`. 17 | 18 | ## Template parameters 19 | 20 | **Policy** - the policy containing the facet. 21 | 22 | ## static member functions 23 | | | | 24 | | ------------------------------- | ----------------------------------------------- | 25 | | [dynamic_vptr](#dynamic_vptr) | return the address of the v-table for an object | 26 | | [publish_vptrs](#publish_vptrs) | store the vptrs | 27 | 28 | ### dynamic_vptr 29 | 30 | ```c++ 31 | template 32 | template 33 | const std::uintptr_t* vptr_map::dynamic_vptr(const Class& object); 34 | ``` 35 | 36 | Return a pointer to the v-table for `object`. 37 | 38 | Call `Policy::dynamic_type` for `object`. Return the vptr associated to the 39 | resulting [`type_id`](/yomm2/reference/type_id.html). 40 | 41 | ### publish_vptrs 42 | 43 | ```c++ 44 | template 45 | template 46 | void vptr_map::publish_vptrs(ForwardIterator first, ForwardIterator last); 47 | ``` 48 | 49 | Store the pointers to the v-tables. 50 | -------------------------------------------------------------------------------- /docs/reference/policy-vptr_vector.md: -------------------------------------------------------------------------------- 1 | yorel::yomm2::policy::vptr_vector
2 | defined in , also provided by ,
3 | 4 | ```c++ 5 | template 6 | struct vptr_vector : virtual external_vptr { ... }; 7 | ``` 8 | 9 | `vptr_vector` is an implementation of [`external_vptr](/yomm2/reference/policy-vptr_placement.html) that stores the 10 | pointers to the v-tables in a `std::vector`. If the policy contains a 11 | [`type_hash`](/yomm2/reference/policy-type_hash.html) facet, it is used to convert the [`type_id`](/yomm2/reference/type_id.html) to an index in the 12 | vector; otherwise, the `type_id` is used as the index. 13 | 14 | The default policy uses [`std_rtti`](/yomm2/reference/policy-std_rtti.html), [`fast_perfect_hash`](/yomm2/reference/policy-fast_perfect_hash.html) and 15 | `vptr_vector` to implement efficient method dispatch. Calling a method with a 16 | single virtual parameter takes only ~33% more time than calling a native virtual 17 | function call. 18 | 19 | ## Template parameters 20 | 21 | **Policy** - the policy containing the facet. 22 | 23 | ## Static member functions 24 | 25 | | | | 26 | | ------------------------------- | -------------------------------------------------- | 27 | | [dynamic_vptr](#dynamic_vptr) | return the address of the v-table for an object | 28 | | [publish_vptrs](#publish_vptrs) | store the vptrs, initialize `type_hash` if present | 29 | 30 | ### dynamic_vptr 31 | 32 | ```c++ 33 | template 34 | template 35 | const std::uintptr_t* vptr_vector::dynamic_vptr(const Class& object); 36 | ``` 37 | 38 | Return a pointer to the v-table for `object`. 39 | 40 | Call `Policy::dynamic_type` for `object`. If `Policy` contains a `type_hash` 41 | facet, use it to convert the resulting `type_id` to an index; otherwise, use the 42 | `type_id` as the index. 43 | 44 | ### publish_vptrs 45 | 46 | ```c++ 47 | template 48 | template 49 | void vptr_vector::publish_vptrs(ForwardIterator first, ForwardIterator last); 50 | ``` 51 | 52 | If `Policy` contains a `type_hash` facet, call its `hash_initialize` 53 | function. 54 | 55 | Store the pointers to the v-tables in a vector, indexed by the (possibly hashed) 56 | `type_id`s. 57 | -------------------------------------------------------------------------------- /docs/reference/product.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | **yorel::yomm2::product** (experimental)
4 | defined in >
5 | ``` 6 | template 7 | using product = /*unspecified*/; 8 | ``` 9 | `product` takes a list of [types](/yomm2/reference/types.html) lists, and evaluates to a `types` list 10 | consisting of the n-fold Cartesian product of the input lists. 11 | 12 | ## Example 13 | 14 | 15 | ```c++ 16 | #include 17 | #include 18 | #include 19 | 20 | namespace yomm2 = yorel::yomm2; 21 | 22 | struct a; 23 | struct b; 24 | struct x; 25 | struct y; 26 | struct z; 27 | 28 | static_assert( 29 | std::is_same_v< 30 | yomm2::product< 31 | yomm2::types, 32 | yomm2::types 33 | >, 34 | yomm2::types< 35 | yomm2::types, yomm2::types, yomm2::types, 36 | yomm2::types, yomm2::types, yomm2::types 37 | > 38 | >); 39 | ``` 40 | -------------------------------------------------------------------------------- /docs/reference/register_class.md: -------------------------------------------------------------------------------- 1 | register_class
YOMM2_CLASS

2 | defined in , also provided by , >
3 | 4 | These macros are deprecated. Use [register_classes](/yomm2/reference/use_classes.html) or [YOMM2_CLASSES](/yomm2/reference/use_classes.html). 5 | -------------------------------------------------------------------------------- /docs/reference/set_error_handler.md: -------------------------------------------------------------------------------- 1 | 2 | defined in , also provided by ,
3 | 4 | ```c++ 5 | error_handler_type set_error_handler(error_handler_type handler); 6 | ``` 7 | 8 | All errors are reported via an indirect call to a handler, passing it a 9 | `std::variant` that identifies the specific error. The handler can be set to 10 | a user-defined function with `set_error_handler`. The library calls `abort()` 11 | immediately after calling the handler, but the handler can prevent program 12 | termination by throwing an exception. The default handler writes an error 13 | message to `stderr` in debug mode. 14 | 15 | `set_error_handler` returns the previous handler. 16 | 17 | ## Example 18 | 19 | 20 | ```c++ 21 | #include 22 | #include 23 | 24 | struct Animal { 25 | virtual ~Animal() { 26 | } 27 | }; 28 | 29 | struct Dog : Animal {}; 30 | 31 | register_classes(Animal, Dog); 32 | 33 | declare_method(void, kick, (virtual_)); 34 | 35 | using namespace yorel::yomm2; // for brevity 36 | 37 | error_handler_type next_error_handler; 38 | 39 | void no_definition_handler(const error_type& ev) { 40 | if (auto error = std::get_if(&ev)) { 41 | if (error->status == resolution_error::no_definition) { 42 | throw std::runtime_error("not defined"); 43 | } 44 | } 45 | 46 | next_error_handler(ev); 47 | } 48 | 49 | BOOST_AUTO_TEST_CASE(ref_set_error_handler_example) { 50 | next_error_handler = set_error_handler(no_definition_handler); 51 | update(); 52 | 53 | try { 54 | Dog snoopy; 55 | kick(snoopy); 56 | } catch (const std::runtime_error& error) { 57 | BOOST_TEST(error.what() == "not defined"); 58 | return; 59 | } 60 | 61 | BOOST_FAIL("did not throw"); 62 | } 63 | ``` 64 | -------------------------------------------------------------------------------- /docs/reference/static_object.md: -------------------------------------------------------------------------------- 1 | # YOMM2 static objects 2 | 3 | 4 | 5 | // YOMM2 uses instances of various classes to register user classes, methods, and 6 | method definitions. The constructors adds the object to an intrusive forward 7 | list, and relies on underlying plain pointers to be zero-initialized. Thus, 8 | these objects must be defined at file scope, or as as `static` variables inside 9 | a function or a class. 10 | 11 | The static objects constructor do not allocate memory from the heap. 12 | 13 | ## See also 14 | 15 | The [`YOMM2_STATIC`](/yomm2/reference/YOMM2_STATIC.html) macro is a convenient way of creating static registration 16 | objects with an obfuscated name. 17 | -------------------------------------------------------------------------------- /docs/reference/template_.md: -------------------------------------------------------------------------------- 1 | 2 | **yorel::yomm2::template_** (experimental)
3 | defined in <>
4 | 5 | ```c++ 6 | template typename Template> 7 | struct template_ { 8 | template 9 | using fn = /*unspecified*/; 10 | }; 11 | ``` 12 | 13 | `template_` wraps a template in a type, making it possible to appear in 14 | [types](/yomm2/reference/types.html) lists. Nested template `fn` evaluates to the instantiation of 15 | the template with the specified types. 16 | 17 | ## Example 18 | 19 | 20 | ```c++ 21 | #include 22 | #include 23 | 24 | #include 25 | #include 26 | 27 | using namespace yorel::yomm2; 28 | 29 | struct a; 30 | struct b; 31 | 32 | static_assert( 33 | std::is_same_v< 34 | template_::fn, 35 | std::pair 36 | >); 37 | ``` 38 | -------------------------------------------------------------------------------- /docs/reference/templates.md: -------------------------------------------------------------------------------- 1 | **yorel::yomm2::templates** (experimental)
2 | defined in
3 | 4 | ```c++ 5 | template typename... Templates> 6 | using templates = types...>; 7 | ``` 8 | `templates` wraps a sequence of templates in a [types](/yomm2/reference/types.html) list of [template_](/yomm2/reference/template_.html) 9 | wrappers. 10 | -------------------------------------------------------------------------------- /docs/reference/type_id.md: -------------------------------------------------------------------------------- 1 | yorel::yomm2::type_id
2 | defined in , also provided by ,
3 | ``` 4 | using type_id = std::uintptr_t; 5 | ``` 6 | -------------------------------------------------------------------------------- /docs/reference/types.md: -------------------------------------------------------------------------------- 1 | yorel::yomm2::types
2 | defined in
3 | 4 | ``` 5 | template 6 | struct types; 7 | ``` 8 | 9 | `types` is a sequence of types, similar to `boost:mp11::mp_list`, except that 10 | it does not have a definition 11 | -------------------------------------------------------------------------------- /docs/reference/update.md: -------------------------------------------------------------------------------- 1 | yorel::yomm2::update
2 | defined in , also provided by
3 | 4 | ```c++ 5 | /* compiler */ update(); (1) (since 1.6.0) 6 | /* compiler */ template void update(); (2) (since 1.6.0) 7 | 8 | void update(); (3) (until 1.6.0) 9 | templatevoid update(); (4) (until 1.6.0) 10 | ``` 11 | Initialize the data used during method dispatch. 12 | 13 | This function must be called before any method is called (typically in `main`). 14 | It must also be called after a shared library is dynamically loaded or unloaded, 15 | if the library adds method declarations, method definitions, or classes derived 16 | from classes that are used as virtual arguments. 17 | 18 | (1) and (3) operate on the default policy. (2) and (4) operate on the specified 19 | policy. 20 | 21 | Since version 1.6.0, `update` returns a "compiler" object of an unspecified 22 | type, which contains information gathered while compiling dispatch data. The 23 | only documented member is `report`, a struct containing the following values: 24 | 25 | | Name | Description | 26 | | --------------- | -------------------------------------------------------------------------------- | 27 | | cells | total number of cells used by v-tables and multi-method dispatch tables | 28 | | not_implemented | total number of argument combinations with no applicable definition | 29 | | ambiguous | total number of argument combinations that cannot be resolved due to ambiguities | 30 | 31 | 32 | 33 | ```c++ 34 | int main() { 35 | yorel::yomm2::update(); 36 | // call methods 37 | 38 | // if using dynamically loaded libraries 39 | void* handle = dlopen("mylib.so", RTLD_NOW); 40 | yorel::yomm2::update(); 41 | // classes, methods, and definitions from mylib.so are available 42 | 43 | dlclose(handle); 44 | yorel::yomm2::update(); 45 | // classes, methods, and definitions from mylib.so are no longer available 46 | 47 | return 0; 48 | } 49 | ``` 50 | -------------------------------------------------------------------------------- /docs/reference/update_methods.md: -------------------------------------------------------------------------------- 1 | yorel::yomm2::update_methods
2 | defined in , also provided by
3 | 4 | Initialize the data used during method dispatch. 5 | 6 | This function must be called before any method is called (typically in `main`). 7 | It must also be called after a shared library is dynamically loaded or unloaded, 8 | if the library adds method declarations, method definitions, or classes derived 9 | from classes that are used as virtual arguments. 10 | 11 | ### Example 12 | 13 | ```c++ 14 | int main() { 15 | yorel::yomm2::update_methods(); 16 | // call methods 17 | 18 | // if using dynamically loaded libraries 19 | void* handle = dlopen("mylib.so", RTLD_NOW); 20 | yorel::yomm2::update_methods(); 21 | // classes, methods, and definitions from mylib.so are available 22 | 23 | dlclose(handle); 24 | yorel::yomm2::update_methods(); 25 | // classes, methods, and definitions from mylib.so are no longer available 26 | 27 | return 0; 28 | } 29 | ``` 30 | -------------------------------------------------------------------------------- /docs/reference/virtual_.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | yorel::yomm2::virtual_
4 | defined in , also provided by ,
5 | ``` 6 | template 7 | struct virtual_; 8 | ``` 9 | Mark a method parameter as virtual. 10 | 11 | `type` must be a reference, a rvalue reference, a pointer or a 12 | `std::shared_ptr` to a polymorphic type, possibly qualified with `const`. 13 | 14 | ## Examples 15 | 16 | 17 | ```c++ 18 | #include 19 | 20 | struct Animal { 21 | virtual ~Animal() {} 22 | }; 23 | 24 | declare_method(void, kick, (virtual_)); 25 | declare_method(void, kick, (virtual_)); 26 | declare_method(void, kick, (virtual_)); 27 | declare_method(void, kick, (virtual_>)); 28 | declare_method(void, kick, (virtual_&>)); 29 | declare_method(void, kick, (virtual_)); 30 | declare_method(void, kick, (virtual_)); 31 | declare_method(void, kick, (virtual_>)); 32 | declare_method(void, kick, (virtual_&>)); 33 | ``` 34 | -------------------------------------------------------------------------------- /docs/slides/YOMM2-corecpp.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jll63/yomm2/6c2204c5e6d3733bff7bc59ee1d2e95bdbff1bff/docs/slides/YOMM2-corecpp.pdf -------------------------------------------------------------------------------- /docs/slides/YOMM2-using-std-cpp-2024.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jll63/yomm2/6c2204c5e6d3733bff7bc59ee1d2e95bdbff1bff/docs/slides/YOMM2-using-std-cpp-2024.pdf -------------------------------------------------------------------------------- /docs/slides/YOMM2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jll63/yomm2/6c2204c5e6d3733bff7bc59ee1d2e95bdbff1bff/docs/slides/YOMM2.pdf -------------------------------------------------------------------------------- /docs/slides/deck/01-title.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
7 |
8 | -------------------------------------------------------------------------------- /docs/slides/deck/02-expression-problem.md: -------------------------------------------------------------------------------- 1 | 2 | # If YOMM2 is the solution, 3 | # what is the problem? 4 | 5 | 6 | 7 | 8 | 9 | ## The Expression Problem 10 | 11 | *in a polymorphic system...* 12 | 13 | * existing operations += new types? 14 | * existing types += new operations? 15 | 16 |

should be possible, easy

17 | 18 | 19 | 20 | ## C++ compile-time polymorphism 21 | 22 | (aka templates) 23 | 24 | * existing operations += new types? **easy** 25 | * existing types += new operations? **easy** 26 | 27 | to wit: the STL 28 | 29 | 30 | 31 | ## C++ run-time polymorphism 32 | 33 | * existing operations += new types?
34 | **easy: virtual functions, derivation** 35 | 36 | * existing types += new operations?
37 | **emmmm...** 38 | -------------------------------------------------------------------------------- /docs/slides/deck/99-qa.md: -------------------------------------------------------------------------------- 1 | ## Q&A 2 | 3 |
4 | 5 | GitHub: 6 |
7 | 8 |
9 | 10 |
11 | 12 | examples are on Compiler Explorer: https://jll63.github.io/yomm2/ce/slides.html
(redirects to volatile godbolt.org short URL)
13 | -------------------------------------------------------------------------------- /docs/slides/resources/corecpp2024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jll63/yomm2/6c2204c5e6d3733bff7bc59ee1d2e95bdbff1bff/docs/slides/resources/corecpp2024.png -------------------------------------------------------------------------------- /docs/slides/resources/qr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jll63/yomm2/6c2204c5e6d3733bff7bc59ee1d2e95bdbff1bff/docs/slides/resources/qr.png -------------------------------------------------------------------------------- /docs/slides/resources/slides-on-compiler-explorer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jll63/yomm2/6c2204c5e6d3733bff7bc59ee1d2e95bdbff1bff/docs/slides/resources/slides-on-compiler-explorer.png -------------------------------------------------------------------------------- /docs/slides/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bash 2 | docker run --rm -p 8000:8000 -p 35729:35729 \ 3 | -v /home/jll/dev/yomm2/docs/slides/deck:/reveal/docs/slides \ 4 | -v /home/jll/dev/yomm2/docs/slides/resources:/reveal/resources \ 5 | -v /home/jll/dev/yomm2/docs/slides/theme:/reveal/dist/theme \ 6 | -e TITLE=YOMM2 -e THEME_CSS=yomm2.css \ 7 | -e ADDITIONAL_REVEAL_OPTIONS=center:false,controls:false -e MARGIN=0 \ 8 | "$@" cloudogu/reveal.js:dev 9 | -------------------------------------------------------------------------------- /docs/slides/run-release: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bash 2 | docker run --rm -p 8080:8080 \ 3 | -v /home/jll/dev/yomm2/docs/slides/deck:/reveal/docs/slides \ 4 | -v /home/jll/dev/yomm2/docs/slides/resources:/reveal/resources \ 5 | -v /home/jll/dev/yomm2/docs/slides/theme:/reveal/dist/theme \ 6 | -e TITLE=YOMM2 -e THEME_CSS=yomm2.css \ 7 | -e ADDITIONAL_REVEAL_OPTIONS=center:false,controls:false -e MARGIN=0 \ 8 | "$@" cloudogu/reveal.js 9 | -------------------------------------------------------------------------------- /examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2024 Jean-Louis Leroy 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # See accompanying file LICENSE_1_0.txt 4 | # or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | add_executable(README README.cpp) 7 | target_link_libraries(README YOMM2::yomm2) 8 | add_test(NAME README COMMAND README) 9 | 10 | add_executable(slides slides.cpp) 11 | target_link_libraries(slides YOMM2::yomm2) 12 | add_test(NAME slides COMMAND slides) 13 | 14 | add_executable(synopsis synopsis.cpp) 15 | target_link_libraries(synopsis YOMM2::yomm2) 16 | add_test(NAME synopsis COMMAND synopsis) 17 | 18 | add_executable(matrix matrix.cpp) 19 | target_link_libraries(matrix YOMM2::yomm2) 20 | add_test(NAME matrix COMMAND matrix) 21 | 22 | add_executable(accept_no_visitors accept_no_visitors.cpp) 23 | target_link_libraries(accept_no_visitors YOMM2::yomm2) 24 | add_test(NAME accept_no_visitors COMMAND accept_no_visitors) 25 | 26 | add_executable(adventure adventure.cpp) 27 | target_link_libraries(adventure YOMM2::yomm2) 28 | add_test(NAME adventure COMMAND adventure) 29 | 30 | add_executable(next next.cpp) 31 | target_link_libraries(next YOMM2::yomm2) 32 | add_test(NAME next COMMAND next) 33 | 34 | add_executable(asteroids asteroids.cpp) 35 | target_link_libraries(asteroids YOMM2::yomm2) 36 | add_test(NAME asteroids COMMAND asteroids) 37 | 38 | add_subdirectory(containers) 39 | add_test(NAME containers COMMAND containers) 40 | 41 | if (NOT (WIN32 OR APPLE)) 42 | message(STATUS "Building dlopen example.") 43 | add_executable(dl_main dl_main.cpp) 44 | add_library(dl_shared SHARED dl_shared.cpp) 45 | get_target_property(YOMM2_INCLUDE_DIRS YOMM2::yomm2 INTERFACE_INCLUDE_DIRECTORIES) 46 | target_include_directories(dl_shared PUBLIC ${YOMM2_INCLUDE_DIRS}) 47 | add_dependencies(dl_main dl_shared) 48 | set_target_properties(dl_main PROPERTIES LINK_FLAGS "-Wl,-export-dynamic") 49 | target_link_libraries(dl_main YOMM2::yomm2 dl) 50 | target_link_libraries(dl_shared YOMM2::yomm2) 51 | add_test(NAME dlopen COMMAND dl_main) 52 | endif() 53 | 54 | if (NOT (MSVC AND YOMM2_SHARED)) 55 | # Running this example with a Windows DLL is too much of a hassle, because we 56 | # would need to add the path to the directory containing yomm2.dll to PATH. 57 | # Anyway, if it works with static linking, it is very unlikely that it fails 58 | # with the runtime in a DLL. 59 | add_subdirectory(generator) 60 | endif() 61 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Examples 2 | 3 | * [accept_no_visitors](accept_no_visitors.cpp)
4 | Inspired by [a talk by Yuriy 5 | Solodkyy](https://www.youtube.com/watch?v=QhJguzpZOrk&t=1467s), this example 6 | shows how open methods are better than visitor at traversing ASTs. 7 | 8 | 9 | * [adventure](adventure.cpp)
10 | Yes, YOMM2 methods can have more than two virtual parameters. This example is 11 | inspired by a scene from[Colossal Cave 12 | Adventure](https://en.wikipedia.org/wiki/Colossal_Cave_Adventure), where a 13 | Player uses an Object to fight a Foe (thus, a triple dispatch): 14 | - KILL DRAGON 15 | - WITH WHAT? YOUR BARE HANDS? 16 | - YES 17 | - CONGRATULATIONS! YOU HAVE JUST VANQUISHED A DRAGON WITH YOUR BARE HANDS! 18 | (UNBELIEVABLE, ISN'T IT?) 19 | 20 | * [asteroids](asteroids.cpp)
21 | Many explanations of multi-methods use the 22 | [Asteroids](https://en.wikipedia.org/wiki/Asteroids_(video_game)) video game as 23 | an example. Here is the YOMM2 version. 24 | 25 | * [vcpkg](vcpkg) 26 | Demonstrates how to use YOMM2 with vcpkg. 27 | 28 | * [cmakeyomm2](cmakeyomm2)
29 | Demonstrates how to use YOMM2 in a cmake project. 30 | 31 | * [dl_main](dl_main.cpp), [dl_shared](dl_shared.cpp)
32 | Demonstrates how to dynamically load new classes and method definitions. 33 | 34 | * [matrix](matrix.cpp)
35 | Another example of double dispatch. 36 | 37 | * [next](next.cpp)
38 | Demonstrates how a method definition can call the next most specialised 39 | definition. This is similar to a virtual function override calling the base 40 | version of the function, or calling `super` in languages like Smalltalk or 41 | Python. 42 | 43 | * [synopsis](synopsis.cpp)
44 | A heavily annotated example, for people who prefer to learn by reading code, 45 | not documentation. At the bottom of the file, the assembler code generated for 46 | calling 1- and a 2-virtual argument methods is listed and commented. 47 | -------------------------------------------------------------------------------- /examples/api.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jll63/yomm2/6c2204c5e6d3733bff7bc59ee1d2e95bdbff1bff/examples/api.md -------------------------------------------------------------------------------- /examples/asteroids.cpp: -------------------------------------------------------------------------------- 1 | // asteroids.cpp 2 | // Copyright (c) 2018-2021 Jean-Louis Leroy 3 | // Distributed under the Boost Software License, Version 1.0. (See 4 | // accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | // Example for Wikipedia 8 | 9 | #include 10 | 11 | class Thing { 12 | public: 13 | virtual ~Thing() { 14 | } 15 | }; 16 | 17 | class Asteroid : public Thing {}; 18 | 19 | class Spaceship : public Thing {}; 20 | 21 | register_classes(Thing, Spaceship, Asteroid); 22 | 23 | declare_method(void, collideWith, (virtual_, virtual_)); 24 | 25 | define_method(void, collideWith, (Thing & left, Thing& right)) { 26 | // default collision handling 27 | } 28 | 29 | define_method(void, collideWith, (Asteroid & left, Asteroid& right)) { 30 | // handle Asteroid-Asteroid collision 31 | } 32 | 33 | define_method(void, collideWith, (Asteroid & left, Spaceship& right)) { 34 | // handle Asteroid-Spaceship collision 35 | } 36 | 37 | define_method(void, collideWith, (Spaceship & left, Asteroid& right)) { 38 | // handle Spaceship-Asteroid collision 39 | } 40 | 41 | define_method(void, collideWith, (Spaceship & left, Spaceship& right)) { 42 | // handle Spaceship-Spaceship collision 43 | } 44 | 45 | int main() { 46 | yorel::yomm2::update(); 47 | 48 | Asteroid a1, a2; 49 | Spaceship s1, s2; 50 | 51 | collideWith(a1, a2); 52 | collideWith(a1, s1); 53 | 54 | collideWith(s1, s2); 55 | collideWith(s1, a1); 56 | 57 | return 0; 58 | } 59 | -------------------------------------------------------------------------------- /examples/cmakeyomm2/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2024 Jean-Louis Leroy 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # See accompanying file LICENSE_1_0.txt 4 | # or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | cmake_minimum_required(VERSION 3.20) 7 | cmake_policy(SET CMP0057 NEW) 8 | project(CMAKEYOMM2 VERSION 1.0.0) 9 | 10 | if(NOT CMAKE_CXX_STANDARD) 11 | set(CMAKE_CXX_STANDARD 17) 12 | endif() 13 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 14 | 15 | find_package(YOMM2) 16 | 17 | add_executable(adventure adventure.cpp) 18 | target_link_libraries(adventure YOMM2::yomm2) 19 | -------------------------------------------------------------------------------- /examples/cmakeyomm2/README.md: -------------------------------------------------------------------------------- 1 | # cmake + YOMM2 2 | 3 | This example demonstrates how include YOMM2 in a `cmake` project. -------------------------------------------------------------------------------- /examples/conan/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15) 2 | 3 | project(adventure CXX) 4 | 5 | find_package(YOMM2) 6 | 7 | set(CMAKE_CXX_STANDARD 17) 8 | 9 | add_executable(adventure adventure.cpp) 10 | 11 | target_link_libraries(adventure PRIVATE YOMM2::yomm2) 12 | -------------------------------------------------------------------------------- /examples/conan/README.md: -------------------------------------------------------------------------------- 1 | # conan2 example 2 | 3 | ``` 4 | conan install conanfile.txt --build=missing 5 | cmake --preset conan-release 6 | cmake --build build/Release 7 | ./build/Release/adventure 8 | ``` 9 | -------------------------------------------------------------------------------- /examples/conan/adventure.cpp: -------------------------------------------------------------------------------- 1 | ../adventure.cpp -------------------------------------------------------------------------------- /examples/conan/conanfile.txt: -------------------------------------------------------------------------------- 1 | [requires] 2 | yomm2/1.6.0 3 | [generators] 4 | CMakeDeps 5 | CMakeToolchain 6 | [layout] 7 | cmake_layout 8 | -------------------------------------------------------------------------------- /examples/containers/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2021 Jean-Louis Leroy 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # See accompanying file LICENSE_1_0.txt 4 | # or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | add_executable( 7 | containers 8 | main.cpp 9 | shape_painter.cpp concrete_shape_painters.cpp 10 | line_painter.cpp arc_painter.cpp segment_painter.cpp 11 | painter.cpp) 12 | target_link_libraries(containers YOMM2::yomm2) 13 | -------------------------------------------------------------------------------- /examples/containers/arc_painter.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Jean-Louis Leroy 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // See accompanying file LICENSE_1_0.txt 4 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | // This exmaple is based on sample code provided by Github user matpen in 7 | // https://github.com/jll63/yomm2/issues/7 8 | 9 | #include 10 | 11 | #include 12 | 13 | #include "geometries.hpp" 14 | #include "painter.hpp" 15 | #include "line_painter.hpp" 16 | 17 | register_class(geometries::Arc, geometries::Line); 18 | 19 | namespace painter { 20 | namespace paint1d { 21 | 22 | define_method( 23 | painters, void, paintObject, 24 | (Painter & painter, const geometries::Arc& arc)) { 25 | ++painter.counter; 26 | method_definition(painters, void, (Painter&, const geometries::Line&))( 27 | painter, arc); 28 | std::cout << " " 29 | << "painting arc\n"; 30 | } 31 | 32 | } // namespace paint1d 33 | } // namespace painter 34 | -------------------------------------------------------------------------------- /examples/containers/concrete_shape_painters.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Jean-Louis Leroy 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // See accompanying file LICENSE_1_0.txt 4 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | // This exmaple is based on sample code provided by Github user matpen in 7 | // https://github.com/jll63/yomm2/issues/7 8 | 9 | #include 10 | 11 | #include "geometries.hpp" 12 | #include "shape_painter.hpp" 13 | 14 | register_class(geometries::Shape, geometries::Geometry); 15 | register_class(geometries::Square, geometries::Shape); 16 | register_class(geometries::Circle, geometries::Shape); 17 | 18 | namespace painter { 19 | namespace paint2d { 20 | 21 | define_method( 22 | painters, void, paintObject, 23 | (Painter & painter, const geometries::Square& square)) { 24 | method_definition(painters, void, (Painter&, const geometries::Shape&))( 25 | painter, square); 26 | std::cout << "painting square\n"; 27 | } 28 | 29 | define_method( 30 | painters, void, paintObject, 31 | (Painter & painter, const geometries::Circle& circle)) { 32 | method_definition(painters, void, (Painter&, const geometries::Shape&))( 33 | painter, circle); 34 | std::cout << "painting Circle\n"; 35 | } 36 | 37 | } // namespace paint2d 38 | } // namespace painter 39 | -------------------------------------------------------------------------------- /examples/containers/geometries.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Jean-Louis Leroy 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // See accompanying file LICENSE_1_0.txt 4 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | // This exmaple is based on sample code provided by Github user matpen in 7 | // https://github.com/jll63/yomm2/issues/7 8 | 9 | #ifndef GEOMETRY_DEFINED 10 | #define GEOMETRY_DEFINED 11 | 12 | namespace geometries { 13 | 14 | class Geometry { 15 | public: 16 | virtual ~Geometry() { 17 | } 18 | }; 19 | 20 | class Line : public Geometry {}; 21 | 22 | class Arc : public Line {}; 23 | 24 | class Segment : public Line {}; 25 | 26 | class Shape : public Geometry {}; 27 | 28 | class Square : public Shape {}; 29 | 30 | class Circle : public Shape {}; 31 | 32 | } // namespace geometries 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /examples/containers/line_painter.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Jean-Louis Leroy 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // See accompanying file LICENSE_1_0.txt 4 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | // This exmaple is based on sample code provided by Github user matpen in 7 | // https://github.com/jll63/yomm2/issues/7 8 | 9 | #include 10 | 11 | #include "geometries.hpp" 12 | #include "painter.hpp" 13 | 14 | register_class(geometries::Line, geometries::Geometry); 15 | -------------------------------------------------------------------------------- /examples/containers/line_painter.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Jean-Louis Leroy 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // See accompanying file LICENSE_1_0.txt 4 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | // This exmaple is based on sample code provided by Github user matpen in 7 | // https://github.com/jll63/yomm2/issues/7 8 | 9 | #ifndef LINE_PAINTER_DEFINED 10 | #define LINE_PAINTER_DEFINED 11 | 12 | #include "painter.hpp" 13 | 14 | namespace painter { 15 | namespace paint1d { 16 | 17 | define_method_inline( 18 | painters, void, paintObject, 19 | (Painter & painter, const geometries::Line& arc)) { 20 | std::cout << "#" << painter.counter; 21 | } 22 | 23 | } // namespace paint1d 24 | } // namespace painter 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /examples/containers/main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Jean-Louis Leroy 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // See accompanying file LICENSE_1_0.txt 4 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | // This exmaple is based on sample code provided by Github user matpen in 7 | // https://github.com/jll63/yomm2/issues/7 8 | 9 | #include 10 | 11 | #include 12 | 13 | #include "geometries.hpp" 14 | #include "painter.hpp" 15 | 16 | using std::cout; 17 | using yorel::yomm2::virtual_; 18 | 19 | int main() { 20 | yorel::yomm2::update(); 21 | 22 | const geometries::Geometry& arc = geometries::Arc(); 23 | const geometries::Geometry& segment = geometries::Segment(); 24 | const geometries::Geometry& square = geometries::Square(); 25 | const geometries::Geometry& circle = geometries::Circle(); 26 | 27 | painter::Painter painter; 28 | painter.paint(arc); 29 | painter.paint(segment); 30 | painter.paint(square); 31 | painter.paint(circle); 32 | } 33 | -------------------------------------------------------------------------------- /examples/containers/painter.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Jean-Louis Leroy 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // See accompanying file LICENSE_1_0.txt 4 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | // This exmaple is based on sample code provided by Github user matpen in 7 | // https://github.com/jll63/yomm2/issues/7 8 | 9 | #include "geometries.hpp" 10 | #include "painter.hpp" 11 | 12 | register_class(geometries::Geometry); 13 | -------------------------------------------------------------------------------- /examples/containers/painter.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Jean-Louis Leroy 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // See accompanying file LICENSE_1_0.txt 4 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | // This exmaple is based on sample code provided by Github user matpen in 7 | // https://github.com/jll63/yomm2/issues/7 8 | 9 | #ifndef PAINTER_DEFINED 10 | #define PAINTER_DEFINED 11 | 12 | #include "geometries.hpp" 13 | 14 | #include 15 | 16 | namespace painter { 17 | 18 | namespace paint1d { 19 | method_container(painters); 20 | } 21 | namespace paint2d { 22 | method_container(painters); 23 | } 24 | 25 | class Painter { 26 | public: 27 | void paint(const geometries::Geometry& geometry); 28 | int painted() const; 29 | 30 | private: 31 | int counter = 0; 32 | friend_method(paint1d::painters); 33 | friend_method( 34 | paint2d::painters, void, (Painter&, const geometries::Shape&)); 35 | }; 36 | 37 | // Implements paint 38 | declare_method( 39 | void, paintObject, 40 | (Painter&, yorel::yomm2::virtual_)); 41 | 42 | inline void Painter::paint(const geometries::Geometry& geometry) { 43 | paintObject(*this, geometry); 44 | } 45 | 46 | inline int Painter::painted() const { 47 | return counter; 48 | } 49 | 50 | } // namespace painter 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /examples/containers/segment_painter.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Jean-Louis Leroy 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // See accompanying file LICENSE_1_0.txt 4 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | // This exmaple is based on sample code provided by Github user matpen in 7 | // https://github.com/jll63/yomm2/issues/7 8 | 9 | #include 10 | 11 | #include 12 | 13 | #include "geometries.hpp" 14 | #include "painter.hpp" 15 | #include "line_painter.hpp" 16 | 17 | register_class(geometries::Segment, geometries::Line); 18 | 19 | namespace painter { 20 | namespace paint1d { 21 | 22 | define_method( 23 | painters, void, paintObject, 24 | (Painter & painter, const geometries::Segment& segment)) { 25 | ++painter.counter; 26 | method_definition(painters, void, (Painter&, const geometries::Line&))( 27 | painter, segment); 28 | std::cout << " " 29 | << "painting segment\n"; 30 | } 31 | 32 | } // namespace paint1d 33 | } // namespace painter 34 | -------------------------------------------------------------------------------- /examples/containers/shape_painter.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Jean-Louis Leroy 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // See accompanying file LICENSE_1_0.txt 4 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | // This exmaple is based on sample code provided by Github user matpen in 7 | // https://github.com/jll63/yomm2/issues/7 8 | 9 | #include 10 | 11 | #include "painter.hpp" 12 | 13 | register_class(geometries::Shape, geometries::Geometry); 14 | 15 | namespace painter { 16 | namespace paint2d { 17 | 18 | define_method( 19 | painters, void, paintObject, 20 | (Painter & painter, const geometries::Shape& shape)) { 21 | ++painter.counter; 22 | static int counter; 23 | ++counter; 24 | std::cout << "#" << painter.counter << " #" << counter << " "; 25 | } 26 | 27 | } // namespace paint2d 28 | } // namespace painter 29 | -------------------------------------------------------------------------------- /examples/containers/shape_painter.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Jean-Louis Leroy 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // See accompanying file LICENSE_1_0.txt 4 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | // This exmaple is based on sample code provided by Github user matpen in 7 | // https://github.com/jll63/yomm2/issues/7 8 | 9 | #ifndef SHAPE_PAINTER_DEFINED 10 | #define SHAPE_PAINTER_DEFINED 11 | 12 | #include "painter.hpp" 13 | 14 | namespace painter { 15 | namespace paint2d { 16 | 17 | method_container( 18 | painters, void, paintObject, 19 | (Painter & painter, const geometries::Shape& shape)); 20 | 21 | } 22 | } // namespace painter 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /examples/dl.hpp: -------------------------------------------------------------------------------- 1 | // dl.hpp 2 | // Copyright (c) 2018-2021 Jean-Louis Leroy 3 | // Distributed under the Boost Software License, Version 1.0. (See 4 | // accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef DL_DEFINED 8 | #define DL_DEFINED 9 | 10 | #include 11 | 12 | #include 13 | 14 | struct Animal { 15 | virtual ~Animal() { 16 | } 17 | }; 18 | 19 | register_classes(Animal); 20 | 21 | struct Herbivore : Animal {}; 22 | 23 | register_classes(Herbivore, Animal); 24 | 25 | struct Carnivore : Animal {}; 26 | 27 | register_classes(Carnivore, Animal); 28 | 29 | struct Cow : Herbivore {}; 30 | 31 | register_classes(Cow, Herbivore); 32 | 33 | struct Wolf : Carnivore {}; 34 | 35 | register_classes(Wolf, Carnivore); 36 | 37 | declare_method( 38 | std::string, encounter, (virtual_, virtual_)); 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /examples/dl_main.cpp: -------------------------------------------------------------------------------- 1 | // dl_main.cpp 2 | // Copyright (c) 2018-2021 Jean-Louis Leroy 3 | // Distributed under the Boost Software License, Version 1.0. (See 4 | // accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include "dl.hpp" 15 | 16 | using namespace std; 17 | 18 | define_method(string, encounter, (const Animal&, const Animal&)) { 19 | return "ignore"; 20 | } 21 | 22 | int main() { 23 | yorel::yomm2::update(); 24 | 25 | cout << "Before loading library\n"; 26 | cout << "encounter(Cow(), Wolf()) -> " << encounter(Cow(), Wolf()) << endl; 27 | cout << "encounter(Wolf(), Cow()) -> " << encounter(Wolf(), Cow()) << endl; 28 | 29 | char dl_path[4096]; 30 | dl_path[readlink("/proc/self/exe", dl_path, sizeof(dl_path))] = 0; 31 | *strrchr(dl_path, '/') = 0; 32 | 33 | #ifdef __APPLE__ 34 | strcat(dl_path, "/libdl_shared.dylib"); 35 | #else 36 | strcat(dl_path, "/libdl_shared.so"); 37 | #endif 38 | 39 | void* handle = dlopen(dl_path, RTLD_NOW); 40 | 41 | if (!handle) { 42 | cout << "dlopen() failed: " << dlerror() << "\n"; 43 | exit(1); 44 | } 45 | 46 | cout << "\nAfter loading library\n"; 47 | yorel::yomm2::update(); 48 | 49 | using make_tyget_type = Animal* (*)(); 50 | make_tyget_type make_tiger = 51 | reinterpret_cast(dlsym(handle, "make_tiger")); 52 | 53 | if (!make_tiger) { 54 | cout << "dlsym() failed: " << dlerror() << "\n"; 55 | exit(1); 56 | } 57 | 58 | cout << "encounter(Cow(), *make_tiger()) -> " 59 | << encounter(Cow(), *make_tiger()) << endl; 60 | cout << "encounter(Wolf(), Cow()) -> " << encounter(Wolf(), Cow()) << endl; 61 | 62 | dlclose(handle); 63 | 64 | cout << "\nAfter unloading library\n"; 65 | yorel::yomm2::update(); 66 | 67 | cout << "encounter(Cow(), Wolf()) -> " << encounter(Cow(), Wolf()) << endl; 68 | cout << "encounter(Wolf(), Cow()) -> " << encounter(Wolf(), Cow()) << endl; 69 | 70 | return 0; 71 | } 72 | -------------------------------------------------------------------------------- /examples/dl_shared.cpp: -------------------------------------------------------------------------------- 1 | // dl_shared.cpp 2 | // Copyright (c) 2018-2021 Jean-Louis Leroy 3 | // Distributed under the Boost Software License, Version 1.0. (See 4 | // accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | #include "dl.hpp" 13 | 14 | using namespace std; 15 | 16 | define_method(string, encounter, (const Herbivore&, const Carnivore&)) { 17 | return "run"; 18 | } 19 | 20 | struct Tiger : Carnivore {}; 21 | 22 | register_classes(Tiger, Carnivore); 23 | 24 | extern "C" Tiger* make_tiger() { 25 | return new Tiger; 26 | } 27 | 28 | define_method(string, encounter, (const Carnivore&, const Herbivore&)) { 29 | return "hunt"; 30 | } 31 | -------------------------------------------------------------------------------- /examples/generator/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2024 Jean-Louis Leroy 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # See accompanying file LICENSE_1_0.txt 4 | # or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | add_library(generator_lib OBJECT animals.cpp) 7 | target_link_libraries(generator_lib YOMM2::yomm2) 8 | 9 | add_executable(generator_gen generator_gen.cpp) 10 | target_link_libraries(generator_gen generator_lib YOMM2::yomm2) 11 | 12 | set(GENERATED_FILES 13 | "${CMAKE_CURRENT_BINARY_DIR}/slots.hpp" 14 | "${CMAKE_CURRENT_BINARY_DIR}/tables.hpp" 15 | ) 16 | add_custom_command( 17 | OUTPUT ${GENERATED_FILES} 18 | COMMAND generator_gen 19 | DEPENDS generator_gen 20 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} 21 | ) 22 | add_custom_target(generator_generate DEPENDS ${GENERATED_FILES}) 23 | add_library(generator_generated_lib INTERFACE) 24 | add_dependencies(generator_generated_lib generator_generate) 25 | target_include_directories(generator_generated_lib INTERFACE ${CMAKE_CURRENT_BINARY_DIR}) 26 | 27 | add_executable(generator_app generator_app.cpp) 28 | target_include_directories(generator_app PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) 29 | target_link_libraries(generator_app PRIVATE generator_generated_lib generator_lib YOMM2::yomm2) 30 | add_test(NAME generator_app COMMAND generator_app) 31 | -------------------------------------------------------------------------------- /examples/generator/animals.cpp: -------------------------------------------------------------------------------- 1 | #include "animals.hpp" 2 | 3 | Animal::~Animal() { 4 | } 5 | 6 | register_classes(Animal, Dog, Cat); 7 | 8 | define_method(void, kick, (virtual_ptr)) { 9 | std::cout << "hiss\n"; 10 | } 11 | 12 | define_method(void, kick, (virtual_ptr)) { 13 | std::cout << "bark\n"; 14 | } 15 | 16 | // 'meet' catch-all implementation. 17 | define_method(void, meet, (virtual_ptr, virtual_ptr)) { 18 | std::cout << "ignore\n"; 19 | } 20 | 21 | // Add definitions for specific pairs of animals. 22 | define_method(void, meet, (virtual_ptr dog1, virtual_ptr dog2)) { 23 | std::cout << "wag tail\n"; 24 | } 25 | 26 | define_method(void, meet, (virtual_ptr dog, virtual_ptr cat)) { 27 | std::cout << "chase\n"; 28 | } 29 | 30 | define_method(void, meet, (virtual_ptr cat, virtual_ptr dog)) { 31 | std::cout << "run\n"; 32 | } 33 | -------------------------------------------------------------------------------- /examples/generator/animals.hpp: -------------------------------------------------------------------------------- 1 | #ifndef ANIMALS_HPP 2 | #define ANIMALS_HPP 3 | 4 | #include 5 | 6 | #include 7 | 8 | #ifdef NDEBUG 9 | // Override the default policy with a minimal policy: 10 | // * no external vptr table, because we will only use 'final' 11 | // * therefore, no need for a hash function 12 | // We use only the 'std_rtti' facet, which is needed by the generator. If this 13 | // was not acceptable, we could build the 'generate' program with RTTI enabled, 14 | // and the application without RTTI. This would require building the 'animals' 15 | // classes twice, but the debug build could be used for the generation. 16 | struct animals_policy : yorel::yomm2::policy::basic_policy< 17 | animals_policy, yorel::yomm2::policy::std_rtti> {}; 18 | 19 | #define YOMM2_DEFAULT_POLICY animals_policy 20 | #endif 21 | 22 | #include 23 | 24 | using yorel::yomm2::virtual_ptr; 25 | 26 | struct Animal { 27 | virtual ~Animal(); 28 | virtual void kick() = 0; 29 | }; 30 | 31 | struct Dog : Animal { 32 | virtual void kick() { 33 | } 34 | }; 35 | 36 | struct Cat : Animal { 37 | virtual void kick() { 38 | } 39 | }; 40 | 41 | declare_method(void, kick, (virtual_ptr)); 42 | declare_method(void, meet, (virtual_ptr, virtual_ptr)); 43 | 44 | #if __has_include("slots.hpp") 45 | #include "slots.hpp" 46 | #endif 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /examples/generator/generator_app.cpp: -------------------------------------------------------------------------------- 1 | #include "animals.hpp" 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | void call_vf(Animal& a) { 8 | // yardstick 9 | a.kick(); 10 | // mov rax, qword ptr [rdi] 11 | // jmp qword ptr [rax + 16] # TAILCALL 12 | } 13 | 14 | void call_kick(virtual_ptr animal) { 15 | kick(animal); 16 | // mov rax, qword ptr [rsi + 16] 17 | // jmp rax # TAILCALL 18 | } 19 | 20 | void call_meet(virtual_ptr a1, virtual_ptr a2) { 21 | meet(a1, a2); 22 | // mov rax, qword ptr [rsi] 23 | // mov r8, qword ptr [rcx + 8] 24 | // lea r8, [r8 + 2*r8] 25 | // mov rax, qword ptr [rax + 8*r8] 26 | // jmp rax # TAILCALL 27 | } 28 | 29 | int main() { 30 | using namespace yorel::yomm2; 31 | 32 | #include "tables.hpp" 33 | 34 | Cat felix; 35 | auto cat = virtual_ptr::final(felix); 36 | Dog snoopy; 37 | virtual_ptr dog = virtual_ptr::final(snoopy); 38 | 39 | // // our yardstick: an ordinary virtual function call 40 | // felix.kick(); 41 | 42 | call_kick(cat); 43 | call_meet(dog, cat); 44 | 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /examples/generator/generator_gen.cpp: -------------------------------------------------------------------------------- 1 | #include "animals.hpp" 2 | 3 | #include 4 | 5 | #include 6 | 7 | int main(int argc, char* argv[]) { 8 | using namespace yorel::yomm2; 9 | 10 | auto compiler = update(); 11 | generator generator; 12 | 13 | std::ofstream slots("slots.hpp"); 14 | generator 15 | .write_static_offsets))>( 16 | slots) 17 | .write_static_offsets, virtual_ptr))>(slots); 19 | 20 | std::ofstream tables("tables.hpp"); 21 | generator.encode_dispatch_data(compiler, tables); 22 | 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /examples/next.cpp: -------------------------------------------------------------------------------- 1 | // next.cpp 2 | // Copyright (c) 2018-2021 Jean-Louis Leroy 3 | // Distributed under the Boost Software License, Version 1.0. (See 4 | // accompanying file LICENSE_1_0.txt or copy at 5 | // http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | // Example taken Dylan's documentation, see 8 | // http://opendylan.org/documentation/intro-dylan/multiple-dispatch.html 9 | 10 | #include 11 | 12 | #include 13 | 14 | using namespace std; 15 | 16 | struct Vehicle { 17 | virtual ~Vehicle() { 18 | } 19 | }; 20 | 21 | //[ car 22 | struct Car : Vehicle {}; 23 | 24 | struct Truck : Vehicle {}; 25 | 26 | struct Inspector { 27 | virtual ~Inspector() { 28 | } 29 | }; 30 | 31 | struct StateInspector : Inspector {}; 32 | 33 | register_classes(Vehicle, Car, Truck, Inspector, StateInspector); 34 | 35 | declare_method( 36 | void, inspect, (virtual_, virtual_)); 37 | 38 | define_method(void, inspect, (const Vehicle& v, const Inspector& i)) { 39 | cout << "Inspect vehicle.\n"; 40 | } 41 | 42 | define_method(void, inspect, (const Car& v, const Inspector& i)) { 43 | next(v, i); 44 | cout << "Inspect seat belts.\n"; 45 | } 46 | 47 | define_method(void, inspect, (const Car& v, const StateInspector& i)) { 48 | next(v, i); 49 | cout << "Check road tax.\n"; 50 | } 51 | 52 | int main() { 53 | yorel::yomm2::update(); 54 | 55 | const Vehicle& vehicle1 = Car(); 56 | const Inspector& inspector1 = StateInspector(); 57 | const Vehicle& vehicle2 = Truck(); 58 | const Inspector& inspector2 = Inspector(); 59 | 60 | cout << "First inspection:\n"; 61 | inspect(vehicle1, inspector1); 62 | 63 | cout << "\nSecond inspection:\n"; 64 | inspect(vehicle2, inspector2); 65 | 66 | return 0; 67 | } 68 | -------------------------------------------------------------------------------- /examples/vcpkg/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15) 2 | 3 | project(adventure CXX) 4 | 5 | find_package(YOMM2 CONFIG REQUIRED) 6 | 7 | set(CMAKE_CXX_STANDARD 17) 8 | 9 | add_executable(adventure adventure.cpp) 10 | 11 | target_link_libraries(adventure PRIVATE YOMM2::yomm2) 12 | -------------------------------------------------------------------------------- /examples/vcpkg/CMakePresets.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 2, 3 | "configurePresets": [ 4 | { 5 | "name": "default", 6 | "generator": "Ninja", 7 | "binaryDir": "${sourceDir}/build", 8 | "cacheVariables": { 9 | "CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake" 10 | } 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /examples/vcpkg/adventure.cpp: -------------------------------------------------------------------------------- 1 | ../adventure.cpp -------------------------------------------------------------------------------- /examples/vcpkg/vcpkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": [ 3 | "yomm2" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /include/yorel/yomm2.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-2024 Jean-Louis Leroy 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // See accompanying file LICENSE_1_0.txt 4 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef YOREL_YOMM2_HPP 7 | #define YOREL_YOMM2_HPP 8 | 9 | #include // IWYU pragma: keep 10 | #include 11 | #include // IWYU pragma: keep 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /include/yorel/yomm2/cute.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-2021 Jean-Louis Leroy 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // See accompanying file LICENSE_1_0.txt 4 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef YOREL_YOMM2_CUTE_HPP 7 | #define YOREL_YOMM2_CUTE_HPP 8 | 9 | #include 10 | 11 | #define register_class YOMM2_CLASS 12 | #define register_classes YOMM2_CLASSES 13 | 14 | #define declare_method YOMM2_DECLARE 15 | #define declare_static_method YOMM2_STATIC_DECLARE 16 | #define define_method YOMM2_DEFINE 17 | #define define_method_inline YOMM2_DEFINE_INLINE 18 | #define method_class YOMM2_METHOD_CLASS 19 | 20 | #define method_container YOMM2_DECLARE_METHOD_CONTAINER 21 | #define friend_method YOMM2_FRIEND 22 | #define method_definition YOMM2_DEFINITION 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /include/yorel/yomm2/detail/ostdstream.hpp: -------------------------------------------------------------------------------- 1 | #ifndef YOREL_YOMM2_DETAIL_OSTDSTREAM_HPP 2 | #define YOREL_YOMM2_DETAIL_OSTDSTREAM_HPP 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace yorel { 10 | namespace yomm2 { 11 | namespace detail { 12 | 13 | // ----------------------------------------------------------------------------- 14 | // lightweight ostream 15 | 16 | struct ostdstream { 17 | FILE* stream = nullptr; 18 | 19 | ostdstream(FILE* stream = nullptr) : stream(stream) { 20 | } 21 | 22 | void on(FILE* stream = stderr) { 23 | this->stream = stream; 24 | } 25 | 26 | void off() { 27 | this->stream = nullptr; 28 | } 29 | 30 | bool is_on() const { 31 | return stream != nullptr; 32 | } 33 | }; 34 | 35 | struct ostderr : ostdstream { 36 | ostderr() : ostdstream(stderr) { 37 | } 38 | }; 39 | 40 | inline ostdstream cerr; 41 | 42 | inline ostdstream& operator<<(ostdstream& os, const char* str) { 43 | if (os.stream) { 44 | fputs(str, os.stream); 45 | } 46 | 47 | return os; 48 | } 49 | 50 | inline ostdstream& operator<<(ostdstream& os, const std::string_view& view) { 51 | if (os.stream) { 52 | fwrite(view.data(), sizeof(*view.data()), view.length(), os.stream); 53 | } 54 | 55 | return os; 56 | } 57 | 58 | inline ostdstream& operator<<(ostdstream& os, const void* value) { 59 | if (os.stream) { 60 | std::array str; 61 | auto end = std::to_chars( 62 | str.data(), str.data() + str.size(), 63 | reinterpret_cast(value), 16) 64 | .ptr; 65 | os << std::string_view(str.data(), end - str.data()); 66 | } 67 | 68 | return os; 69 | } 70 | 71 | inline ostdstream& operator<<(ostdstream& os, std::size_t value) { 72 | if (os.stream) { 73 | std::array str; 74 | auto end = 75 | std::to_chars(str.data(), str.data() + str.size(), value).ptr; 76 | os << std::string_view(str.data(), end - str.data()); 77 | } 78 | 79 | return os; 80 | } 81 | 82 | } // namespace detail 83 | } // namespace yomm2 84 | } // namespace yorel 85 | 86 | #endif 87 | -------------------------------------------------------------------------------- /include/yorel/yomm2/detail/types.hpp: -------------------------------------------------------------------------------- 1 | #ifndef YOREL_YOMM2_DETAIL_TYPES_HPP 2 | #define YOREL_YOMM2_DETAIL_TYPES_HPP 3 | 4 | #include 5 | #include 6 | 7 | #if defined(YOMM2_SHARED) 8 | #if defined(_MSC_VER) 9 | #if !defined(yOMM2_API_msc) 10 | #define yOMM2_API_msc __declspec(dllimport) 11 | #endif 12 | #endif 13 | #endif 14 | 15 | #if !defined(yOMM2_API_gcc) 16 | #define yOMM2_API_gcc 17 | #endif 18 | 19 | #if !defined(yOMM2_API_msc) 20 | #define yOMM2_API_msc 21 | #endif 22 | 23 | #define yOMM2_API yOMM2_API_gcc yOMM2_API_msc 24 | 25 | namespace yorel { 26 | namespace yomm2 { 27 | 28 | using type_id = std::uintptr_t; 29 | constexpr type_id invalid_type = (std::numeric_limits::max)(); 30 | 31 | namespace detail { 32 | 33 | template 34 | struct types; 35 | 36 | } 37 | } // namespace yomm2 38 | } // namespace yorel 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /include/yorel/yomm2/keywords.hpp: -------------------------------------------------------------------------------- 1 | #ifndef YOREL_YOMM2_KEYWORDS_HPP 2 | #define YOREL_YOMM2_KEYWORDS_HPP 3 | 4 | #include 5 | #include 6 | 7 | namespace yomm2 = yorel::yomm2; 8 | using yomm2::virtual_; 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /include/yorel/yomm2/policies/basic_error_output.hpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright (c) 2018-2024 Jean-Louis Leroy 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef YOREL_YOMM2_POLICY_BASIC_ERROR_OUTPUT_HPP 8 | #define YOREL_YOMM2_POLICY_BASIC_ERROR_OUTPUT_HPP 9 | 10 | #include 11 | 12 | namespace yorel { 13 | namespace yomm2 { 14 | namespace policy { 15 | 16 | template 17 | struct yOMM2_API_gcc basic_error_output : virtual error_output { 18 | static Stream error_stream; 19 | }; 20 | 21 | template 22 | Stream basic_error_output::error_stream; 23 | 24 | } 25 | } 26 | } 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /include/yorel/yomm2/policies/basic_indirect_vptr.hpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright (c) 2018-2024 Jean-Louis Leroy 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef YOREL_YOMM2_POLICY_BASIC_INDIRECT_VPTR_HPP 8 | #define YOREL_YOMM2_POLICY_BASIC_INDIRECT_VPTR_HPP 9 | 10 | #include 11 | 12 | namespace yorel { 13 | namespace yomm2 { 14 | namespace policy { 15 | 16 | template 17 | struct yOMM2_API_gcc basic_indirect_vptr : virtual indirect_vptr { 18 | static std::vector indirect_vptrs; 19 | }; 20 | 21 | template 22 | std::vector 23 | basic_indirect_vptr::indirect_vptrs; 24 | 25 | } 26 | } 27 | } 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /include/yorel/yomm2/policies/basic_trace_output.hpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright (c) 2018-2024 Jean-Louis Leroy 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef YOREL_YOMM2_POLICY_BASIC_TRACE_OUTPUT_HPP 8 | #define YOREL_YOMM2_POLICY_BASIC_TRACE_OUTPUT_HPP 9 | 10 | #include 11 | 12 | namespace yorel { 13 | namespace yomm2 { 14 | namespace policy { 15 | 16 | template 17 | struct yOMM2_API_gcc basic_trace_output : virtual trace_output { 18 | static Stream trace_stream; 19 | static bool trace_enabled; 20 | }; 21 | 22 | template 23 | Stream basic_trace_output::trace_stream; 24 | 25 | template 26 | bool basic_trace_output::trace_enabled([]() { 27 | auto env = getenv("YOMM2_TRACE"); 28 | return env && *env++ == '1' && *env++ == 0; 29 | }()); 30 | 31 | } 32 | } 33 | } 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /include/yorel/yomm2/policies/minimal_rtti.hpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright (c) 2018-2024 Jean-Louis Leroy 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef YOREL_YOMM2_POLICY_MINIMAL_RTTI_HPP 8 | #define YOREL_YOMM2_POLICY_MINIMAL_RTTI_HPP 9 | 10 | #include 11 | 12 | namespace yorel { 13 | namespace yomm2 { 14 | namespace policy { 15 | 16 | struct minimal_rtti : virtual rtti { 17 | template 18 | static type_id static_type() { 19 | static char id; 20 | return reinterpret_cast(&id); 21 | } 22 | }; 23 | 24 | } 25 | } 26 | } 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /include/yorel/yomm2/policies/std_rtti.hpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright (c) 2018-2024 Jean-Louis Leroy 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef YOREL_YOMM2_POLICY_STD_RTTI_HPP 8 | #define YOREL_YOMM2_POLICY_STD_RTTI_HPP 9 | 10 | #include 11 | 12 | #ifndef BOOST_NO_RTTI 13 | #include 14 | #include 15 | #include 16 | #endif 17 | 18 | namespace yorel { 19 | namespace yomm2 { 20 | namespace policy { 21 | 22 | struct std_rtti : virtual rtti { 23 | #ifndef BOOST_NO_RTTI 24 | template 25 | static type_id static_type() { 26 | auto tip = &typeid(Class); 27 | return reinterpret_cast(tip); 28 | } 29 | 30 | template 31 | static type_id dynamic_type(const Class& obj) { 32 | auto tip = &typeid(obj); 33 | return reinterpret_cast(tip); 34 | } 35 | 36 | template 37 | static void type_name(type_id type, Stream& stream) { 38 | stream << boost::core::demangle( 39 | reinterpret_cast(type)->name()); 40 | } 41 | 42 | static std::type_index type_index(type_id type) { 43 | return std::type_index(*reinterpret_cast(type)); 44 | } 45 | 46 | template 47 | static D dynamic_cast_ref(B&& obj) { 48 | return dynamic_cast(obj); 49 | } 50 | #endif 51 | }; 52 | 53 | } 54 | } 55 | } 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /include/yorel/yomm2/policies/throw_error.hpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright (c) 2018-2024 Jean-Louis Leroy 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef YOREL_YOMM2_POLICY_THROW_ERROR_HPP 8 | #define YOREL_YOMM2_POLICY_THROW_ERROR_HPP 9 | 10 | #include 11 | 12 | namespace yorel { 13 | namespace yomm2 { 14 | namespace policy { 15 | struct yOMM2_API_gcc throw_error : virtual error_handler { 16 | static void error(const error_type& error_v) { 17 | std::visit([](auto&& arg) { throw arg; }, error_v); 18 | } 19 | }; 20 | 21 | } 22 | } 23 | } 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /include/yorel/yomm2/policies/vptr_map.hpp: -------------------------------------------------------------------------------- 1 | 2 | // Copyright (c) 2018-2024 Jean-Louis Leroy 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef YOREL_YOMM2_POLICY_VPTR_MAP_HPP 8 | #define YOREL_YOMM2_POLICY_VPTR_MAP_HPP 9 | 10 | #include 11 | 12 | namespace yorel { 13 | namespace yomm2 { 14 | namespace policy { 15 | 16 | template< 17 | class Policy, 18 | class Map = std::unordered_map> 19 | struct yOMM2_API_gcc vptr_map : virtual external_vptr { 20 | static Map vptrs; 21 | 22 | template 23 | static void publish_vptrs(ForwardIterator first, ForwardIterator last) { 24 | for (auto iter = first; iter != last; ++iter) { 25 | for (auto type_iter = iter->type_id_begin(); 26 | type_iter != iter->type_id_end(); ++type_iter) { 27 | vptrs[*type_iter] = iter->vptr(); 28 | } 29 | } 30 | } 31 | 32 | template 33 | static auto dynamic_vptr(const Class& arg) { 34 | return vptrs.find(Policy::dynamic_type(arg))->second; 35 | } 36 | }; 37 | 38 | template 39 | Map vptr_map::vptrs; 40 | 41 | } 42 | } 43 | } 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /include/yorel/yomm2/symbols.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-2024 Jean-Louis Leroy 2 | 3 | #ifndef YOMM2_GENSYM 4 | 5 | #include 6 | 7 | #define YOMM2_GENSYM BOOST_PP_CAT(YoMm2_gS_, __COUNTER__) 8 | 9 | #define YOMM2_STATIC(...) static __VA_ARGS__ YOMM2_GENSYM 10 | 11 | #define YOMM2_SYMBOL(ID) BOOST_PP_CAT(YoMm2_S_, ID) 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /reference.boilerplate/class.cpp: -------------------------------------------------------------------------------- 1 | #define BOOST_TEST_MODULE CLASS 2 | #include 3 | 4 | /*** 5 | 6 | / ->home / ->reference 7 | 8 | entry: yorel::yomm2::CLASS 9 | headers: yorel/yomm2/core.hpp, yorel/yomm2/keywords.hpp 10 | 11 | --- 12 | ``` 13 | struct CLASS; 14 | ``` 15 | 16 | TODO 17 | 18 | ## Template parameters 19 | 20 | **TODO** - TODO 21 | 22 | ## Static member functions 23 | | | | 24 | | ---- | ---- | 25 | | TODO | TODO | 26 | 27 | ### TODO 28 | 29 | ```c++ 30 | TODO 31 | ``` 32 | 33 | TODO 34 | 35 | #### Parameters 36 | 37 | **TODO** - TODO. 38 | 39 | #### Return value 40 | 41 | TODO. 42 | 43 | #### Errors 44 | 45 | * TODO 46 | 47 | 48 | ### Example 49 | 50 | ***/ 51 | 52 | //*** 53 | #include 54 | 55 | // for brevity 56 | using namespace yorel::yomm2; 57 | 58 | BOOST_AUTO_TEST_CASE(ref_TODO) { 59 | TODO 60 | } 61 | 62 | //*** 63 | -------------------------------------------------------------------------------- /reference.boilerplate/class.md: -------------------------------------------------------------------------------- 1 | # yorel::yomm2::**CLASS** 2 | headers: yorel/yomm2/core.hpp,yorel/yomm2/keywords.hpp 3 | 4 | template 5 | struct CLASS; 6 | 7 | TODO 8 | 9 | ## Template parameters 10 | 11 | ### TP 12 | 13 | # Member functions 14 | 15 | | | | 16 | | --- | ---- | 17 | | FUN | TODO | 18 | 19 | ### Fun 20 | 21 | **Example** 22 | 23 | //*** 24 | 25 | ```c++ 26 | #include 27 | 28 | // for brevity 29 | using namespace yorel::yomm2; 30 | 31 | BOOST_AUTO_TEST_CASE(ref_TODO) { 32 | TODO 33 | } 34 | ``` 35 | 36 | //*** 37 | -------------------------------------------------------------------------------- /reference.boilerplate/member.md: -------------------------------------------------------------------------------- 1 | ## yorel::yomm2::CLASS::**MEMBER** 2 | headers: yorel/yomm2/core.hpp,yorel/yomm2/keywords.hpp 3 | 4 | MEMBER; 5 | 6 | TODO 7 | 8 | **Parameters** 9 | 10 | * TODO: TODO. 11 | 12 | **Return value** 13 | 14 | TODO. 15 | 16 | **Errors** 17 | 18 | * TODO 19 | 20 | 21 | **Example** 22 | 23 | ```c++ 24 | #include 25 | 26 | // for brevity 27 | using namespace yorel::yomm2; 28 | 29 | BOOST_AUTO_TEST_CASE(ref_TODO) { 30 | TODO 31 | } 32 | ``` 33 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2018-2021 Jean-Louis Leroy 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # See accompanying file LICENSE_1_0.txt 4 | # or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | if(YOMM2_SHARED) 7 | message(STATUS "Building a shared library") 8 | add_library(yomm2 SHARED) 9 | target_sources(yomm2 PRIVATE yomm2.cpp) 10 | if(NOT WIN32) 11 | target_compile_options(yomm2 PRIVATE -fvisibility=hidden) 12 | endif() 13 | target_compile_definitions(yomm2 PUBLIC YOMM2_SHARED=1) 14 | target_include_directories( 15 | yomm2 PUBLIC 16 | $ 17 | $ 18 | PUBLIC $ 19 | ) 20 | target_link_libraries(yomm2 PUBLIC Boost::headers) 21 | target_compile_features(yomm2 PUBLIC cxx_std_17) 22 | if (${YOMM2_CHECK_ABI_COMPATIBILITY}) 23 | message(STATUS "type: ${CMAKE_BUILD_TYPE} FLAGS: ${CMAKE_CXX_FLAGS_RELEASE}") 24 | if(CMAKE_BUILD_TYPE STREQUAL "Debug") 25 | set_target_properties(yomm2 PROPERTIES COMPILE_FLAGS "${CMAKE_CXX_FLAGS_RELEASE}" ) 26 | endif() 27 | endif() 28 | else() 29 | if (${YOMM2_CHECK_ABI_COMPATIBILITY}) 30 | message(FATAL_ERROR "YOMM2_CHECK_ABI_COMPATIBILITY does not make sense for headers only mode." ) 31 | endif() 32 | message(STATUS "Building a headers only library") 33 | add_library(yomm2 INTERFACE) 34 | target_include_directories( 35 | yomm2 INTERFACE 36 | $ 37 | $ 38 | ) 39 | target_link_libraries(yomm2 INTERFACE Boost::headers) 40 | target_compile_features(yomm2 INTERFACE cxx_std_17) 41 | endif() 42 | 43 | install(TARGETS yomm2 44 | EXPORT YOMM2Targets 45 | LIBRARY DESTINATION lib 46 | ARCHIVE DESTINATION lib 47 | RUNTIME DESTINATION bin 48 | ) 49 | 50 | add_library(YOMM2::yomm2 ALIAS yomm2) 51 | -------------------------------------------------------------------------------- /tests/benchmarks_parameters.hpp: -------------------------------------------------------------------------------- 1 | #ifdef _WIN32 2 | #define YOMM2_BENCHMARK_HIERARCHIES 20 3 | #else 4 | #define YOMM2_BENCHMARK_HIERARCHIES 100 5 | #endif 6 | -------------------------------------------------------------------------------- /tests/run-rdtsc-benchmark: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright (c) 2018-2024 Jean-Louis Leroy 4 | # Distributed under the Boost Software License, Version 1.0. 5 | # See accompanying file LICENSE_1_0.txt 6 | # or copy at http://www.boost.org/LICENSE_1_0.txt) 7 | 8 | count=$1 9 | cache_state=$2 10 | prog=./benchmark_rdtsc 11 | 12 | for i in $(seq $count); do 13 | for dispatch in 'ovh' 'vf' 'ref' 'vp' 'iptr' 'sum' 'fum' 'stat_ref' 'stat_vp' 'stat_iptr' 'stat_sum' 'stat_fum'; do 14 | $prog $dispatch 1 $cache_state 15 | done 16 | echo 17 | done 18 | -------------------------------------------------------------------------------- /tests/test_generator.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-2024 Jean-Louis Leroy 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // See accompanying file LICENSE_1_0.txt 4 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #include 7 | #include 8 | 9 | #include "test_generator_domain.hpp" 10 | 11 | #include 12 | 13 | using namespace yorel::yomm2; 14 | 15 | static_assert(detail::has_static_offsets, std::ostream&))>::value); 17 | static_assert( 18 | detail::has_static_offsets, virtual_, std::ostream&))>::value); 21 | static_assert( 22 | detail::has_static_offsets, std::ostream&))>::value); 24 | 25 | #define BOOST_TEST_MODULE test_generator 26 | #include 27 | #include 28 | 29 | using namespace yorel::yomm2; 30 | 31 | BOOST_AUTO_TEST_CASE(test_generator) { 32 | #include "test_generator_tables.hpp" 33 | 34 | std::ostringstream os; 35 | 36 | auto animal = std::make_unique(); 37 | auto cat = std::make_unique("Alice"); 38 | auto dog = std::make_unique("Bob"); 39 | 40 | kick(*cat, os); 41 | BOOST_TEST(os.str() == "hiss"); 42 | 43 | os.str(""); 44 | kick(*dog, os); 45 | BOOST_TEST(os.str() == "bark"); 46 | 47 | try { 48 | kick(*animal, os); 49 | BOOST_FAIL("should have thrown"); 50 | } catch (const resolution_error& e) { 51 | } 52 | 53 | os.str(""); 54 | meet(*dog, *cat, os); 55 | BOOST_TEST(os.str() == "chase"); 56 | 57 | try { 58 | meet(*animal, *animal, os); 59 | BOOST_FAIL("should have thrown"); 60 | } catch (const resolution_error& e) { 61 | } 62 | 63 | try { 64 | meet(*cat, *dog, os); 65 | BOOST_FAIL("should have thrown"); 66 | } catch (const resolution_error& e) { 67 | } 68 | 69 | os.str(""); 70 | identify(*cat, os); 71 | BOOST_TEST(os.str() == "Alice's cat"); 72 | 73 | os.str(""); 74 | identify(*dog, os); 75 | BOOST_TEST(os.str() == "Bob's dog"); 76 | } 77 | -------------------------------------------------------------------------------- /tests/test_generator_domain.cpp: -------------------------------------------------------------------------------- 1 | #include "test_generator_domain.hpp" 2 | 3 | register_classes(Animal, Cat, Dog, Property, DomesticCat, DomesticDog); 4 | 5 | define_method(void, kick, (Dog&, std::ostream& os)) { 6 | os << "bark"; 7 | } 8 | 9 | define_method(void, kick, (Cat&, std::ostream& os)) { 10 | os << "hiss"; 11 | } 12 | 13 | // create an ambiguity with the following two definitions 14 | define_method(void, meet, (Cat&, Animal&, std::ostream& os)) { 15 | os << "ignore"; 16 | } 17 | 18 | define_method(void, meet, (Animal&, Dog&, std::ostream& os)) { 19 | os << "wag tail"; 20 | } 21 | // ^^^ ambiguous 22 | 23 | define_method(void, meet, (Dog&, Cat&, std::ostream& os)) { 24 | os << "chase"; 25 | } 26 | 27 | define_method(void, identify, (DomesticCat & animal, std::ostream& os)) { 28 | os << animal.owner << "'s" 29 | << " cat"; 30 | } 31 | 32 | define_method(void, identify, (DomesticDog & animal, std::ostream& os)) { 33 | os << animal.owner << "'s" 34 | << " dog"; 35 | } 36 | -------------------------------------------------------------------------------- /tests/test_generator_domain.hpp: -------------------------------------------------------------------------------- 1 | #ifndef TEST_GENERATOR_DOMAIN_HPP 2 | #define TEST_GENERATOR_DOMAIN_HPP 3 | 4 | #include 5 | #include 6 | 7 | struct throw_policy 8 | : yorel::yomm2::default_policy::rebind::replace< 9 | yorel::yomm2::policy::error_handler, 10 | yorel::yomm2::policy::throw_error> {}; 11 | 12 | #define YOMM2_DEFAULT_POLICY throw_policy 13 | 14 | #include 15 | 16 | #ifndef _MSC_VER 17 | // Because MSC is believes that forward declaring with 'struct' or 'class' makes 18 | // a difference. 19 | #if __has_include("test_generator_slots.hpp") 20 | #include "test_generator_slots.hpp" 21 | #endif 22 | #endif 23 | 24 | struct Animal { 25 | virtual ~Animal() { 26 | } 27 | }; 28 | 29 | struct Cat : Animal {}; 30 | struct Dog : Animal {}; 31 | 32 | struct Property { 33 | explicit Property(std::string owner) : owner(owner) { 34 | } 35 | 36 | virtual ~Property() { 37 | } 38 | 39 | std::string owner; 40 | }; 41 | 42 | struct DomesticCat : Cat, Property { 43 | using Property::Property; 44 | }; 45 | 46 | struct DomesticDog : Dog, Property { 47 | using Property::Property; 48 | }; 49 | 50 | declare_method(void, kick, (virtual_, std::ostream&)); 51 | declare_method( 52 | void, meet, (virtual_, virtual_, std::ostream&)); 53 | declare_method(void, identify, (virtual_, std::ostream&)); 54 | 55 | #ifdef _MSC_VER 56 | // Because MSC is believes that forward declaring with 'struct' or 'class' makes 57 | // a difference. 58 | #if __has_include("test_generator_slots.hpp") 59 | #include "test_generator_slots.hpp" 60 | #endif 61 | #endif 62 | 63 | #endif // TEST_GENERATOR_DOMAIN_HPP 64 | -------------------------------------------------------------------------------- /tests/test_generator_gen.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-2024 Jean-Louis Leroy 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // See accompanying file LICENSE_1_0.txt 4 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #include "test_generator_domain.hpp" 7 | 8 | #include 9 | #include 10 | 11 | int main(int argc, char* argv[]) { 12 | using namespace yorel::yomm2; 13 | 14 | auto compiler = update(); 15 | generator generator; 16 | 17 | std::ofstream slots("test_generator_slots.hpp"); 18 | #ifndef _MSC_VER 19 | generator.add_forward_declarations().write_forward_declarations(slots); 20 | #endif 21 | generator.write_static_offsets(slots); 22 | 23 | std::ofstream tables("test_generator_tables.hpp"); 24 | generator.encode_dispatch_data(compiler, tables); 25 | 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /tests/test_lab.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Jean-Louis Leroy 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // See accompanying file LICENSE_1_0.txt 4 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | using std::cout; 13 | using yorel::yomm2::virtual_; 14 | 15 | // register_class(classes); 16 | 17 | // declare_method(return, name, (params)); 18 | 19 | // define_method(return, name, (params)) { 20 | // } 21 | 22 | int main() { 23 | yorel::yomm2::update(); 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /tests/test_member_method.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2021 Jean-Louis Leroy 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // See accompanying file LICENSE_1_0.txt 4 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace yorel::yomm2; 13 | using std::cout; 14 | 15 | struct Role { 16 | virtual ~Role() { 17 | } 18 | }; 19 | 20 | struct Employee : Role {}; 21 | 22 | struct Manager : Employee {}; 23 | 24 | register_classes(Role, Employee, Manager); 25 | 26 | struct Payroll { 27 | int balance{10000}; 28 | 29 | void pay(const Role& role) { 30 | pay_method::fn(this, role); 31 | } 32 | 33 | private: 34 | struct YOMM2_SYMBOL(pay); 35 | using pay_method = 36 | method)>; 37 | 38 | void pay_employee(const Employee&) { 39 | balance -= 2000; 40 | } 41 | void pay_manager(const Manager&) { 42 | balance -= 3000; 43 | } 44 | 45 | public: 46 | using pay_functions = Payroll::pay_method::add_member_functions< 47 | &Payroll::pay_employee, &Payroll::pay_manager>; 48 | }; 49 | 50 | YOMM2_STATIC(Payroll::pay_functions); 51 | 52 | #define BOOST_TEST_MODULE yomm2 53 | #include 54 | 55 | BOOST_AUTO_TEST_CASE(member_method) { 56 | update(); 57 | 58 | Payroll pr; 59 | const Employee& alice = Employee(); 60 | const Manager& bob = Manager(); 61 | 62 | pr.pay(alice); 63 | BOOST_TEST(pr.balance == 8000); 64 | pr.pay(bob); 65 | BOOST_TEST(pr.balance == 5000); 66 | } 67 | -------------------------------------------------------------------------------- /tests/test_pointer_to_method.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-2021 Jean-Louis Leroy 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // See accompanying file LICENSE_1_0.txt 4 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #include 7 | 8 | #include 9 | 10 | #define BOOST_TEST_MODULE yomm2 11 | #include 12 | 13 | using yorel::yomm2::virtual_; 14 | 15 | class Animal { 16 | public: 17 | virtual ~Animal() { 18 | } 19 | }; 20 | 21 | class Dog : public Animal {}; 22 | 23 | register_class(Animal); 24 | register_class(Dog, Animal); 25 | 26 | declare_method(std::string, kick, (virtual_)); 27 | 28 | define_method(std::string, kick, (Dog & dog)) { 29 | return "bark"; 30 | } 31 | 32 | BOOST_AUTO_TEST_CASE(noadl) { 33 | yorel::yomm2::update(); 34 | auto stimulus = &kick; 35 | Dog snoopy; 36 | Animal& animal = snoopy; 37 | BOOST_TEST(stimulus(snoopy) == "bark"); 38 | } 39 | -------------------------------------------------------------------------------- /tests/test_pss1.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018-2021 Jean-Louis Leroy 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // See accompanying file LICENSE_1_0.txt 4 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #include 7 | #include 8 | 9 | using std::string; 10 | 11 | #include 12 | 13 | using yorel::yomm2::virtual_; 14 | 15 | struct A { 16 | virtual ~A() { 17 | } 18 | }; 19 | struct B : A {}; 20 | struct C : A {}; 21 | struct D : B, C {}; 22 | 23 | register_class(A); 24 | register_class(B, A); 25 | register_class(C, A); 26 | register_class(D, B, C); 27 | 28 | declare_method(string, foobar, (virtual_)); 29 | 30 | define_method(string, foobar, (A&)) { 31 | return "foobar(A)"; 32 | } 33 | 34 | define_method(string, foobar, (C&)) { 35 | return "foobar(C)"; 36 | } 37 | 38 | #include 39 | #include 40 | 41 | int main() { 42 | yorel::yomm2::update(); 43 | 44 | D d; 45 | B& db = d; // B part of D 46 | C& dc = d; // C part of D 47 | std::cout << foobar(db) << "\n"; 48 | std::cout << foobar(dc) << "\n"; 49 | //std::cout << foobar(d) << "\n"; 50 | } 51 | -------------------------------------------------------------------------------- /tests/test_rolex.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct Role { 4 | virtual ~Role() { 5 | } 6 | }; 7 | 8 | struct Employee : Role { 9 | virtual double pay() const; 10 | }; 11 | 12 | struct Manager : Employee { 13 | virtual double pay() const; 14 | }; 15 | 16 | struct Founder : Role {}; 17 | 18 | struct Expense { 19 | virtual ~Expense() { 20 | } 21 | }; 22 | 23 | struct Public : Expense {}; 24 | struct Bus : Public {}; 25 | struct Metro : Public {}; 26 | struct Taxi : Expense {}; 27 | struct Jet : Expense {}; 28 | 29 | register_class(Role); 30 | register_class(Employee, Role); 31 | register_class(Manager, Employee); 32 | register_class(Founder, Role); 33 | register_class(Expense); 34 | register_class(Public, Expense); 35 | register_class(Bus, Public); 36 | register_class(Metro, Public); 37 | register_class(Taxi, Expense); 38 | register_class(Jet, Expense); 39 | 40 | declare_method(double, pay, (virtual_)); 41 | declare_method( 42 | bool, approve, (virtual_, virtual_, double)); 43 | 44 | define_method(double, pay, (const Employee&)) { 45 | return 3000; 46 | } 47 | 48 | define_method(double, pay, (const Manager& exec)) { 49 | return next(exec) + 2000; 50 | } 51 | 52 | define_method(bool, approve, (const Role& r, const Expense& e, double amount)) { 53 | return false; 54 | } 55 | 56 | define_method( 57 | bool, approve, (const Employee& r, const Public& e, double amount)) { 58 | return true; 59 | } 60 | 61 | define_method(bool, approve, (const Manager& r, const Taxi& e, double amount)) { 62 | return true; 63 | } 64 | 65 | define_method( 66 | bool, approve, (const Founder& r, const Expense& e, double amount)) { 67 | return true; 68 | } 69 | 70 | int main() { 71 | yorel::yomm2::update(); 72 | } 73 | 74 | double call_pay(const Employee& emp) { 75 | return pay(emp); 76 | } 77 | 78 | double Employee::pay() const { 79 | return 3000; 80 | } 81 | 82 | double Manager::pay() const { 83 | return Employee::pay() + 2000; 84 | } 85 | 86 | double call_pay_vfunc(const Employee& emp) { 87 | return emp.pay(); 88 | } 89 | 90 | bool call_approve(const Role& r, const Expense& e, double a) { 91 | return approve(r, e, a); 92 | } 93 | -------------------------------------------------------------------------------- /tests/test_util.hpp: -------------------------------------------------------------------------------- 1 | #ifndef YOMM2_TEST_HELPERS_HPP 2 | #define YOMM2_TEST_HELPERS_HPP 3 | 4 | #include 5 | 6 | template 7 | struct test_policy_ : 8 | #ifdef NDEBUG 9 | yorel::yomm2::policy::release::rebind> 10 | #else 11 | yorel::yomm2::policy::debug::rebind> 12 | #endif 13 | { 14 | }; 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /vcpkg-configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "default-registry": { 3 | "kind": "git", 4 | "baseline": "afa12e7292fb47771e619675d7915645fe0adb1b", 5 | "repository": "https://github.com/microsoft/vcpkg" 6 | }, 7 | "registries": [ 8 | { 9 | "kind": "artifact", 10 | "location": "https://github.com/microsoft/vcpkg-ce-catalog/archive/refs/heads/main.zip", 11 | "name": "microsoft" 12 | } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /vcpkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "yomm2", 3 | "version": "1.6.0", 4 | "dependencies": [ 5 | "benchmark", 6 | "boost-core", 7 | "boost-dynamic-bitset", 8 | "boost-mp11", 9 | "boost-preprocessor", 10 | "boost-test", 11 | "vcpkg-tool-ninja" 12 | ] 13 | } 14 | --------------------------------------------------------------------------------