diff --git a/CMakeLists.txt b/CMakeLists.txt index f65ae39..ab1aad5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,7 +17,7 @@ option( RABERU_BUILD_DOCUMENTATION "Build Doxygen for Raberu" OFF ) ##====================================================================================================================== set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/cmake ${COPACABANA_SOURCE_DIR}/copacabana/cmake) include(${COPACABANA_SOURCE_DIR}/copacabana/cmake/copacabana.cmake) -copa_project_version(MAJOR 1 MINOR 0 PATCH 0) +copa_project_version(MAJOR 1 MINOR 1 PATCH 0) ##====================================================================================================================== ## Summary Display diff --git a/doc/Doxyfile b/doc/Doxyfile index 2b2aa46..fe0b438 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -33,6 +33,11 @@ STRIP_FROM_INC_PATH = $(DOXYGEN_STRIP)/include STRIP_FROM_PATH = $(DOXYGEN_STRIP)/src STRIP_FROM_PATH += $(DOXYGEN_STRIP)/include + +EXAMPLE_PATH = ../test/doc \ + ../test/integration \ + . + SEPARATE_MEMBER_PAGES = YES TAB_SIZE = 2 diff --git a/doc/base.html b/doc/base.html index af8f89d..de6d745 100644 --- a/doc/base.html +++ b/doc/base.html @@ -36,7 +36,7 @@
- + diff --git a/doc/changelog.md b/doc/changelog.md index fea420d..a19da81 100644 --- a/doc/changelog.md +++ b/doc/changelog.md @@ -1,102 +1,37 @@ Change Log {#changelog} ========== -# Version 2.2 - Aubrey Bradimore +# Version 2.0 - Past Prologue -## What's Changed +## Bug Fixes +* Moved from `pragma once` to `#ifndef` to allow for multiple raberu files to coexist in multiple projects. +* Fixed a regression in Visual Studio that affected ability to run tests. +* Fix #6 - Compile-time ID are now properly displayed and compared without any issues due to terminal `\0`. -### Infrastructure - * **We are now under the Boost Software Licence 1.0** - * Enable Android tests and support - * Clarify some output when failures occur +## New Features +* Fix #4 - Simplify and generalize custom keyword generation + A new CRTP class `rbr::as_keyword` streamlines the definition of compact keyword by users while + supporting the whole range of built-in keywords. Associated documentation has been updated. -### New Features - * Implement ALL_EQUAL - * Test can now use configurable, automatic data generator (https://github.com/jfalcou/tts/pull/53) - * `TTS_EXPECT_COMPILES/COMPILE_NOT` check if a fragment of code can be compiled or not - * Reimplement `TTS_WHEN` and `TTS_AND_THEN` to support sub-tests - * Add typed tests that checks both value and exact type +* Fix #2 - Implement direct keyword value access + Keyword can now fetch themselves from a bundles of options. E.g -### Bug Fixes - * Fix Visual Studio interaction with constexpr tests - * Improve random generators and seed management + ``` c++ + inline constexpr auto coord_ = "coord"_kw; + inline constexpr auto is_modal_ = "is_modal"_fl; -## Detective who? -[Aubrey Bradimore](https://en.wikipedia.org/wiki/Aubrey_Bradimore), this is a Christmas Release afterall + auto x = coord_(coord_ = "Jane"s, is_modal_); + ``` -# Version 2.1 - Cordelia Gray +* Fix #5 - Mass extractors for keyword and values + `rbr::keywords` and`rbr::values` can be used to retrieve a tuple-like object containing all the + keywords or values from a bundle of options. -## What's Changed - * Fix #42 - Proper FetchContent support - * Better compatibility - * Enable EMSCRIPTEN tests and supports - * Add tests over sequences +* `rbr::get_type` is removed and is replaced by `rbr::fetch` and `rbr::result::fetch_t`. + This functions provides an infix syntax for options access. -## Detective who? -[Cordelia Gray](https://en.wikipedia.org/wiki/Cordelia_Gray), a very suitable detective +# Version 1.0 - Emissary -# Version 2.0 - Kay Scarpetta +## First autonomous public release. -**TTS** version 2.0 is taking a major break from an earlier version. Compile-time was creeping upward -and some features were not that useful. So the code base got streamlined and simplified. - -This version is a **Major Release With API Changes** release: - -**Breaking API Changes**: - + Removal of support for colors - + Removal of support for sub-scenario - + Silent mode for tests is the default. The only information displayed concerns failures - -**Features:** - + Improved compile-times - + Output streamlined to fit machine processing in CI context or scripts - + Better handling of template test cases: less generated symbol, better flexibility in inputs (list of types or types list generator) - -## Detective who? -[Kay Scarpetta](https://en.wikipedia.org/wiki/Kay_Scarpetta), the private forensic consultant. - -# Version 1.0 - Phoebe Daring - -This version is a **Major Release With API Changes** release: - -**Breaking API Changes**: - -To support some of the new feature and simplify some macros, **TTS** API is now based on a -lambda system. If this doesn't change the way tests are performed, it now requires to end all -tests cases by a `;`. - -**Bug Fixes:** - - * Fix #3 - `TTS_TPL_CASES` now use meta-function based system for types generation - * Fix #32 - Provide a way to log arbitrary data when failures occur - * Fix #33 - Provide the `REQUIRED` option on tests to halt tests at first failure - * Fix #34 - Provide a command-line option to fix precision when displaying floating points - * Fix #37 - Stop displaying `char const*` as a string. - -## Detective who? -[Phoebe Daring](https://en.wikipedia.org/wiki/Phoebe_Daring), the first half of the Daring Twins since 1912. - -# Version 0.2 - Kate Fansler - -This version is a fix+features release: - - * Fix #20 - Make string and pointers display in a more intuitive way - * Fix #23 - Add proper parens in `EXPECT` macro - * Add support for `constexpr` expectation and relational tests - * `TTS_CASE_TPL` now generates one scenario per type - * Fix #21 - Add runtime filtering for tests based on description string - -## Detective who? -[Kate Fansler](https://en.wikipedia.org/wiki/Kate_Fansler), solving academic crimes since 1964. - -# Version 0.1 - Cadfael - -## First public release. - -**TTS** first complete release enables numerically oriented TDD including: - - precision testing - - checks over the data set - - easy to customize the use of user-defined types. - -## Detective who? -[Cadfael](https://en.wikipedia.org/wiki/Cadfael) is probably the eldest of all amateur detectives in history. +**RABERU** (ラベル組) is now independent of the OFW repository. diff --git a/doc/custom.hpp b/doc/custom.hpp new file mode 100644 index 0000000..c36432d --- /dev/null +++ b/doc/custom.hpp @@ -0,0 +1,102 @@ +#error DO NOT INCLUDE - DOCUMENTATION PURPOSE ONLY + +//================================================================================================== +/** + \page custom Tutorial: Customizing Keyword + + @tableofcontents + + \section custom_01 Using Pre-bound keyword + + Sometimes you wish you could have a terser syntax for keyword parameters. + Let's say you want to pass a compile-time unrolling factor to some algorithm. + + @code + // This is working but a bit verbose + using namespace rbr::literals; + inline constexpr auto unroll = rbr::keyword("unrolling"_id); + + auto x = my_algorithm( unroll = std::integral_constant{}); + @endcode + + One idea is to defines a **pre-bound keyword parameter**, i.e constructs an inline + variable initialized with the result of the assignment of a value to a keyword. + + @code + using namespace rbr::literals; + inline constexpr auto unrolling = rbr::keyword("unrolling"_id); + + template inline constexpr auto unroll = (unrolling = std::integral_constant{}); + @endcode + + `unroll` is now ready to be passed around. To retrieve it, you'll need to use + the `unrolling` keyword. + + @include doc/tutorial04.cpp + + \section custom_02 Custom RABERU Keywords + + The keywords provided by **RABERU** can also be extended to propose a better user experience. + This includes using user-defined type instead of **RABERU** long symbol to improve diagnostic + , complex checks or provide custom display when using stream insertion of settings. + + \subsection custom-extension Extending RABERU Keywords + Let's start again with our unrolling option. This time we want to be able to be sure nobody + will use it with a non integral constant value and to display the value in a more informative way. + To do so, we can inherits from `rbr::as_keyword`, a CRTP enabled base class: + + @code + struct unrolling : rbr::as_keyword + { + template + constexpr auto operator=(std::integral_constant const&) const noexcept + { + return rbr::option>{}; + } + + std::ostream& display(std::ostream& os, auto v) const { return os << "Unroll Factor: " << v; } + }; + + template inline constexpr auto unroll = (unrolling{} = std::integral_constant{}); + @endcode + + What if we call `f( unrolling{} = 3.f );` ? Well, we go this error message: + + @code + example.cpp:25:18: error: no viable overloaded '=' + f( unrolling{} = 3.f ); + ~~~~~~~~~~~ ^ ~~~ + :8:18: note: candidate template ignored: could not match 'integral_constant' against 'float' + constexpr auto operator=(std::integral_constant const&) const noexcept + @endcode + + \subsection custom-display Custom Keywords Display + Let's now improve the output of the option. Currently, the output is like: + + @code + [unrolling] : 8 (std::integral_constant) + @endcode + + A bit verbose especially for end-user. + Keyword-like entity can specialize a `display` member function to replace this output by a custom one. + + @code + struct unrolling : rbr::as_keyword + { + template + constexpr auto operator=(std::integral_constant const&) const noexcept + { + return rbr::option>{}; + } + + std::ostream& display(std::ostream& os, auto v) const { return os << "Unroll Factor: " << v; } + }; + @endcode + + The `display` member takes the output stream and the actual value of the option to be displayed. + One can then arrange those as they see fit, leading to a better output: + + @include doc/tutorial05.cpp + +**/ +//================================================================================================== diff --git a/doc/layout.xml b/doc/layout.xml index 54f090b..aff55f9 100644 --- a/doc/layout.xml +++ b/doc/layout.xml @@ -3,39 +3,26 @@ - - - - - - - - - - - - - - - - - - - - - - + + + + + - - - - + + + + + + + + - - - + + + + - diff --git a/doc/licence.md b/doc/licence.md index 858f5bc..478b52e 100644 --- a/doc/licence.md +++ b/doc/licence.md @@ -1,23 +1,25 @@ Licence {#licence} ======= -This library is licensed under the [MIT License](http://opensource.org/licenses/MIT): +This library is licensed under the [Boost Software License](https://opensource.org/licenses/BSL-1.0): ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ none -Copyright : EVE Contributors & Maintainers +Copyright : RABERU Project Contributors -Permission is hereby granted, free of charge, to any person obtaining a copy of this software -and associated documentation files (the “Software”), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, -sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the +software and accompanying documentation covered by this license (the "Software") to use, reproduce, +display, distribute, execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the +following: -The above copyright notice and this permission notice shall be included in all copies or substantial -portions of the Software. +The copyright notices in the Software and this entire statement, including the above license grant, +this restriction and the following disclaimer, must be included in all copies of the Software, in +whole or in part, and all derivative works of the Software, unless such copies or derivative works +are solely in the form of machine-executable object code generated by a source language processor. -THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT -NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT +NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND +NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE +BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/doc/page01_setup.md b/doc/page01_setup.md deleted file mode 100644 index 191a573..0000000 --- a/doc/page01_setup.md +++ /dev/null @@ -1,62 +0,0 @@ -# Setup - -## Direct file download - -1. Download the one header file `raberu.hpp` : - ``` - wget https://raw.githubusercontent.com/jfalcou/raberu/main/include/raberu.hpp - ``` -2. Copy it in the location of your choice. - -Using **Raberu** boils down to including `raberu.hpp` and compile using C++20. - -``` bash -g++ my_app.cpp -I/path/to/raberu -std=c++20 -``` - -## CMake FetchContent - -You can also use CMake FetchContent operation and use the `raberu::raberu` library -target that our CMake exports. - -``` cmake -##================================================================================================== -## Your project setup -##================================================================================================== -cmake_minimum_required(VERSION 3.2) -project(test_raberu LANGUAGES CXX) - -include(FetchContent) - -##================================================================================================== -## Fetch Raberu and disable its test targets -##================================================================================================== -set(KUMI_BUILD_TEST OFF CACHE INTERNAL "OFF") -FetchContent_Declare( raberu - GIT_REPOSITORY https://github.com/jfalcou/raberu.git - GIT_TAG main - ) - -FetchContent_MakeAvailable(raberu) - -##================================================================================================== -## Using Raberu -##================================================================================================== -add_executable( my_app my_app.cpp) -target_link_libraries(my_app raberu::raberu) -``` - -## CPM Integration -You can install **Raberu** directly via [CPM](https://github.com/cpm-cmake/CPM.cmake). After -[adding CPM to your CMake setup](https://github.com/cpm-cmake/CPM.cmake#adding-cpm), just -add the following commands: - -```cmake -include(CPM) - -CPMAddPackage ( NAME raberu - URL https://github.com/jfalcou/raberu/archive/refs/tags/v2.0.zip - VERSION 2.0 - OPTIONS "RABERU_BUILD_TEST OFF" - ) -``` diff --git a/doc/page02_tutorial.hpp b/doc/page02_tutorial.hpp deleted file mode 100644 index 797b31d..0000000 --- a/doc/page02_tutorial.hpp +++ /dev/null @@ -1,132 +0,0 @@ -#error DO NOT INCLUDE - DOCUMENTATION PURPOSE ONLY - -//================================================================================================== -//! \page tutorial Tutorial: Basic of RABERU -//! -//! **RABERU** main tool is the rbr::settings class that helps aggregate values into a set of parameters that later be queried. Let's build a small example of a function building a string from the replication of a given character. -//! -//! \section tutorial_01 Tutorial Keyword, Options, Settings -//! -//! Let's define a small function - `replicate` - that takes a character `c` and an integer `n` as parameters and return a string containing `c` repeated `n` times. -//! As we want our users to have maximum flexibility, we will pass those parameters as keyword/value pairs. -//! -//! @include doc/tutorial01.cpp -//! -//! Let's decompose this code: -//! -//! + First, we define the `replicate` function. It takes two parameters which model -//! rbr::concepts::option, ensuring the parameters are valid **RABERU** key/value pairs. -//! + Those parameters are then turned into an instance of rbr::settings which will provide the interface to query values from the bundle of parameters. -//! + We retrieve the value associated to the `"replication"_kw` and `"letter"_kw` keywords. -//! + In the `main` function, we call `replicate` by passing key/value pairs. Note that the keys are the exact same identifiers than those used inside the function. Their order is irrelevant. -//! -//! That's it. The `replicate` function can now takes keywords arguments and as long as the proper keywords are used, it will work as intended. -//! -//! \section tutorial_02 Flavor of Keywords -//! -//! ## Regular keywords -//! -//! Let's say you want to pass a compile-time unrolling factor to some algorithm. -//! You can use a regular keyword as seen in the tutorial: -//! -//! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ c++ -//! auto x = my_algorithm( "unroll"_kw = std::integral_constant{}); -//! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -//! -//! This is working but a bit verbose. Another issue can be that documenting the fact -//! that your functions awaits a `"unroll"_kw` maybe cumbersome. -//! -//! A nicer way to simplify the user experience is to preemptively defines a keyword variable. -//! -//! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ c++ -//! inline constexpr auto unroll = "unroll"_kw; -//! -//! auto x = my_algorithm( unroll = std::integral_constant{}); -//! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -//! -//! Slightly terser and far easier to document. -//! You can also use the rbr::keyword factory that takes an ID and returns a keyword instance -//! -//! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ c++ -//! inline constexpr auto unroll = rbr::keyword("unroll"_id); -//! -//! auto x = my_algorithm( unroll = std::integral_constant{}); -//! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -//! -//! ## Flags -//! Sometimes, you just want to check if a given parameter has been passed but you don't really care about an associated value. Such keyword parameters are **flags**, carrying information about their sole presence without the need ot be bound to a value. -//! -//! They work in a similar way than regular keyword parameters but use the `_fl` user-defined literal -//! ior the rbr::flag factory. Their value can be retrieved via rbr::settings::operator[]. If present, the value returned is `std::true_type`, otherwise `std::false_type` is returned. -//! -//! @include doc/tutorial02.cpp -//! -//! ## Checked keywords -//! Regular keywords accept value of any types. Flag keyword implicitly behaves as boolean parameters. -//! What if you need to have a keyword accepting values of a specific type ? Or, in more complex -//! context, what if you need a keyword accepting values which types satisfy an arbitrary set of -//! constraints ? -//! -//! To do so, we'll need to use the rbr::keyword factory function that -//! accepts an optional template parameter. If this template parameter is a type, -//! the keyword is setup to only accept value of this exact type. -//! -//! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ c++ -//! using namespace rbr::literals; -//! -//! // color can only accept unsigned 32 bits integer -//! auto color = rbr::keyword("color"_id); -//! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -//! -//! If this template parameter is a unary template meta-function `F`, the keyword is setup to only -//! accept value which type satisfy `F::value == true`. -//! -//! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ c++ -//! using namespace rbr::literals; -//! -//! template struct large_type -//! { -//! static constexpr auto value = sizeof(T) >= 4; -//! }; -//! -//! // entropy can only accept types of at least 32 bits -//! inline constexpr auto entropy = rbr::keyword( "entropy"_id); -//! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -//! -//! \section tutorial_03 Settings -//! -//! Another important **RABERU** component is rbr::settings. It aggregates key/value pairs in a way their -//! exploitation is simplified. rbr::settings provides functions for retrieving value from keywords, -//! inspect the stored keywords and more. -//! -//! ## Defining a Settings -//! rbr::settings can be directly constructed from an arbitrary list of options, ie values bound to -//! a keyword. Once constructed, its operator[] can be used to fetch the value of a given keyword. -//! -//! @include doc/tutorial03.cpp -//! -//! ## Stream insertion -//! rbr::settings can be streamed to display the list of keyword/value pairs it contains -//! -//! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ c++ -//! #include -//! #include -//! -//! int main() -//! { -//! using namespace rbr::literals; -//! -//! auto values = rbr::settings("size"_kw = 75ULL, "transparent"_fl, "value"_kw = 7.7f); -//! -//! std::cout << values << "\n"; -//! } -//! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -//! -//! The expected output should be: -//! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -//! 'size' : 75 (long long unsigned int) -//! 'transparent' : 1 (std::integral_constant) -//! 'value' : 7.7 (float) -//! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -//! -//================================================================================================== diff --git a/doc/page03_custom.hpp b/doc/page03_custom.hpp deleted file mode 100644 index df1cb6d..0000000 --- a/doc/page03_custom.hpp +++ /dev/null @@ -1,98 +0,0 @@ -#error DO NOT INCLUDE - DOCUMENTATION PURPOSE ONLY - -//================================================================================================== -//! \page custom Tutorial: Customizing Keyword -//! -//! \section custom_01 Using Pre-bound keyword -//! -//! Sometimes you wish you could have a terser syntax for keyword parameters. -//! Let's say you want to pass a compile-time unrolling factor to some algorithm. -//! -//! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ c++ -//! // This is working but a bit verbose -//! using namespace rbr::literals; -//! inline constexpr auto unroll = rbr::keyword("unrolling"_id); -//! -//! auto x = my_algorithm( unroll = std::integral_constant{}); -//! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -//! -//! One idea is to defines a **pre-bound keyword parameter**, i.e constructs an inline -//! variable initialized with the result of the assignment of a value to a keyword. -//! -//! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ c++ -//! using namespace rbr::literals; -//! inline constexpr auto unrolling = rbr::keyword("unrolling"_id); -//! -//! template inline constexpr auto unroll = (unrolling = std::integral_constant{}); -//! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -//! -//! `unroll` is now ready to be passed around. To retrieve it, you'll need to use -//! the `unrolling` keyword. -//! -//! @include doc/tutorial04.cpp -//! -//! \section custom_02 Custom RABERU Keywords -//! -//! THe keywords provided by **RABERU** can also be extended to propose a better user experience. -//! This includes using user-defined type instead of **RABERU** long symbol to improve diagnostic -//! , complex checks or provide custom display when using stream insertion of settings. -//! -//! ## Extending RABERU Keywords -//! Let's start again with our unrolling option. This time we want to be able to be sure nobody -//! will use it with a non integral constant value and to display the value in a more informative way. -//! To do so, we can inherits from `rbr::as_keyword`, a CRTP enabled base class: -//! -//! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ c++ -//! struct unrolling : rbr::as_keyword -//! { -//! template -//! constexpr auto operator=(std::integral_constant const&) const noexcept -//! { -//! return rbr::option>{}; -//! } -//! -//! std::ostream& display(std::ostream& os, auto v) const { return os << "Unroll Factor: " << v; } -//! }; -//! -//! template inline constexpr auto unroll = (unrolling{} = std::integral_constant{}); -//! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -//! -//! What if we call `f( unrolling{} = 3.f );` ? Well, we go this error message: -//! -//! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ c++ -//! example.cpp:25:18: error: no viable overloaded '=' -//! f( unrolling{} = 3.f ); -//! ~~~~~~~~~~~ ^ ~~~ -//! :8:18: note: candidate template ignored: could not match 'integral_constant' against 'float' -//! constexpr auto operator=(std::integral_constant const&) const noexcept -//! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -//! -//! ## Custom Keywords Display -//! Let's now improve the output of the option. Currently, the output is like: -//! -//! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ c++ -//! [unrolling] : 8 (std::integral_constant) -//! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -//! -//! A bit verbose especially for end-user. -//! Keyword-like entity can specialize a `display` member function to replace this output by a custom one. -//! -//! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ c++ -//! struct unrolling : rbr::as_keyword -//! { -//! template -//! constexpr auto operator=(std::integral_constant const&) const noexcept -//! { -//! return rbr::option>{}; -//! } -//! -//! std::ostream& display(std::ostream& os, auto v) const { return os << "Unroll Factor: " << v; } -//! }; -//! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -//! -//! The `display` member takes the output stream and the actual value of the option to be displayed. -//! One can then arrange those as they see fit, leading to a better output: -//! -//! @include doc/tutorial05.cpp -//! -//================================================================================================== diff --git a/doc/page10_changelog.md b/doc/page10_changelog.md deleted file mode 100644 index a19da81..0000000 --- a/doc/page10_changelog.md +++ /dev/null @@ -1,37 +0,0 @@ -Change Log {#changelog} -========== - -# Version 2.0 - Past Prologue - -## Bug Fixes -* Moved from `pragma once` to `#ifndef` to allow for multiple raberu files to coexist in multiple projects. -* Fixed a regression in Visual Studio that affected ability to run tests. -* Fix #6 - Compile-time ID are now properly displayed and compared without any issues due to terminal `\0`. - -## New Features -* Fix #4 - Simplify and generalize custom keyword generation - A new CRTP class `rbr::as_keyword` streamlines the definition of compact keyword by users while - supporting the whole range of built-in keywords. Associated documentation has been updated. - -* Fix #2 - Implement direct keyword value access - Keyword can now fetch themselves from a bundles of options. E.g - - ``` c++ - inline constexpr auto coord_ = "coord"_kw; - inline constexpr auto is_modal_ = "is_modal"_fl; - - auto x = coord_(coord_ = "Jane"s, is_modal_); - ``` - -* Fix #5 - Mass extractors for keyword and values - `rbr::keywords` and`rbr::values` can be used to retrieve a tuple-like object containing all the - keywords or values from a bundle of options. - -* `rbr::get_type` is removed and is replaced by `rbr::fetch` and `rbr::result::fetch_t`. - This functions provides an infix syntax for options access. - -# Version 1.0 - Emissary - -## First autonomous public release. - -**RABERU** (ラベル組) is now independent of the OFW repository. diff --git a/doc/page10_licence.md b/doc/page10_licence.md deleted file mode 100644 index 478b52e..0000000 --- a/doc/page10_licence.md +++ /dev/null @@ -1,25 +0,0 @@ -Licence {#licence} -======= - -This library is licensed under the [Boost Software License](https://opensource.org/licenses/BSL-1.0): - -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ none -Copyright : RABERU Project Contributors - -Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the -software and accompanying documentation covered by this license (the "Software") to use, reproduce, -display, distribute, execute, and transmit the Software, and to prepare derivative works of the -Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the -following: - -The copyright notices in the Software and this entire statement, including the above license grant, -this restriction and the following disclaimer, must be included in all copies of the Software, in -whole or in part, and all derivative works of the Software, unless such copies or derivative works -are solely in the form of machine-executable object code generated by a source language processor. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT -NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND -NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE -BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/doc/setup.hpp b/doc/setup.hpp new file mode 100644 index 0000000..f8e8a15 --- /dev/null +++ b/doc/setup.hpp @@ -0,0 +1,102 @@ +#error DO NOT INCLUDE - DOCUMENTATION PURPOSE ONLY + +//================================================================================================== +/** + @page setup Setup + + @tableofcontents + + @section setup-source Install from the source + + Code source of **RABERU** is available on GitHub and can be retrieved via the following command: + + @code + $ git clone https://github.com/jfalcou/raberu.git + @endcode + + Once retrieved, you should have a `raberu` folder which contains the whole source code. + + Create a `build` directory here and enter it. Once in the `build` directory, + you can use **CMake** to generate the build system for **RABERU**. We recommend using + Ninja but any build system is fine. + + @code + $ mkdir build + $ cd build + $ cmake .. -G Ninja + @endcode + + Once **CMake** completes, you can use the `install` target to build and install **RABERU**. + By default, the library will be installed in the `/usr/local` directory, thus requiring + root privileges. + + @code + $ sudo ninja install + @endcode + + You can select an alternative installation path by specifying the `CMAKE_INSTALL_PREFIX` + option at configuration time. + + @code + $ cmake .. -G Ninja -DCMAKE_INSTALL_PREFIX=path/to/install + $ ninja install + @endcode + + Once installed, **RABERU** is usable directly by providing the path to its installed files. + + @section setup-standalone Standalone setup + + You can also use **RABERU** via a single standalone file that can be vendored in your own project without + having to deal with **RABERU** as a dependency. + + Simply use `wget` to fetch the latest version and place it where you want: + + @code + wget https://raw.githubusercontent.com/jfalcou/raberu/main/standalone/raberu/raberu.hpp + @endcode + + Use **RABERU** by just compiling your code with the include path pointing to the location of this single file. + + @section setup-fetchcontent CMake FetchContent + + You can also use CMake FetchContent operation and use the `raberu::raberu` library target that our CMake exports. + + @code{cmake} + ##================================================================================================== + ## Your project setup + ##================================================================================================== + cmake_minimum_required(VERSION 3.22) + project(raberu-fetch LANGUAGES CXX) + + include(FetchContent) + FetchContent_Declare(raberu GIT_REPOSITORY "https://github.com/jfalcou/raberu.git") + FetchContent_MakeAvailable(raberu) + + add_executable(test_raberu ../main.cpp) + target_link_libraries(test_raberu PUBLIC raberu::raberu) + @endcode + + @section setup-cpm Setup with CPM + + The **RABERU** library can be setup using [CPM](https://github.com/cpm-cmake/CPM.cmake): + + @code{cmake} + ##================================================================================================== + ## Your project setup + ##================================================================================================== + cmake_minimum_required(VERSION 3.18) + project(raberu-cpm LANGUAGES CXX) + + # Setup CPM - See https://github.com/cpm-cmake/CPM.cmake#adding-cpm + include(cpm.cmake) + + CPMAddPackage ( NAME raberu + GIT_REPOSITORY "https://github.com/jfalcou/raberu.git" + OPTIONS "RABERU_BUILD_TEST OFF" + ) + + add_executable(test_raberu ../main.cpp) + target_link_libraries(test_raberu PUBLIC raberu::raberu) + @endcode +**/ +//================================================================================================== diff --git a/doc/tutorial.hpp b/doc/tutorial.hpp new file mode 100644 index 0000000..e48b472 --- /dev/null +++ b/doc/tutorial.hpp @@ -0,0 +1,144 @@ +#error DO NOT INCLUDE - DOCUMENTATION PURPOSE ONLY + +//================================================================================================== +/** + \page tutorial RABERU 101 + + @tableofcontents + + The **RABERU** library provides a way to define and use named parameters, *i.e* a list of values assigned to + arbitrary keyword-like identifiers, to functions. + + It does so by providing: + + + a protocol to define such keywords. + + a type to process such aggregate of parameters. + + a `constexpr`-compatible implementation for all of those. + + + \section tutorial_01 Keyword, Options, Settings + + Let's define a small function - `replicate` - that takes a character `c` and an integer `n` as parameters and + return a string containing `c` repeated `n` times. As we want our users to have maximum flexibility, we will + pass those parameters as keyword/value pairs. + + @include doc/tutorial01.cpp + + Let's decompose this code: + + + First, we define the `replicate` function. It takes two parameters which model + rbr::concepts::option, ensuring the parameters are valid **RABERU** key/value pairs. + + Those parameters are then turned into an instance of rbr::settings which will provide the interface to query values from the bundle of parameters. + + We retrieve the value associated to the `"replication"_kw` and `"letter"_kw` keywords. + + In the `main` function, we call `replicate` by passing key/value pairs. Note that the keys are the exact same identifiers than those used inside the function. Their order is irrelevant. + + That's it. The `replicate` function can now takes keywords arguments and as long as the proper keywords are used, it will work as intended. + + \section tutorial_02 Flavor of Keywords + + \subsection tutorial-keywords Regular keywords + + Let's say you want to pass a compile-time unrolling factor to some algorithm. + You can use a regular keyword as seen in the tutorial: + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ c++ + auto x = my_algorithm( "unroll"_kw = std::integral_constant{}); + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + This is working but a bit verbose. Another issue can be that documenting the fact + that your functions awaits a `"unroll"_kw` maybe cumbersome. + + A nicer way to simplify the user experience is to preemptively defines a keyword variable. + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ c++ + inline constexpr auto unroll = "unroll"_kw; + + auto x = my_algorithm( unroll = std::integral_constant{}); + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Slightly terser and far easier to document. + You can also use the rbr::keyword factory that takes an ID and returns a keyword instance + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ c++ + inline constexpr auto unroll = rbr::keyword("unroll"_id); + + auto x = my_algorithm( unroll = std::integral_constant{}); + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + \subsection tutorial-flags Flags + Sometimes, you just want to check if a given parameter has been passed but you don't really care about an associated value. Such keyword parameters are **flags**, carrying information about their sole presence without the need ot be bound to a value. + + They work in a similar way than regular keyword parameters but use the `_fl` user-defined literal + ior the rbr::flag factory. Their value can be retrieved via rbr::settings::operator[]. If present, the value returned is `std::true_type`, otherwise `std::false_type` is returned. + + @include doc/tutorial02.cpp + + \subsection tutorial-checked Checked keywords + Regular keywords accept value of any types. Flag keyword implicitly behaves as boolean parameters. + What if you need to have a keyword accepting values of a specific type ? Or, in more complex + context, what if you need a keyword accepting values which types satisfy an arbitrary set of + constraints ? + + To do so, we'll need to use the rbr::keyword factory function that + accepts an optional template parameter. If this template parameter is a type, + the keyword is setup to only accept value of this exact type. + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ c++ + using namespace rbr::literals; + + // color can only accept unsigned 32 bits integer + auto color = rbr::keyword("color"_id); + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + If this template parameter is a unary template meta-function `F`, the keyword is setup to only + accept value which type satisfy `F::value == true`. + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ c++ + using namespace rbr::literals; + + template struct large_type + { + static constexpr auto value = sizeof(T) >= 4; + }; + + // entropy can only accept types of at least 32 bits + inline constexpr auto entropy = rbr::keyword( "entropy"_id); + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + \section tutorial_03 Settings + + Another important **RABERU** component is rbr::settings. It aggregates key/value pairs in a way their + exploitation is simplified. rbr::settings provides functions for retrieving value from keywords, + inspect the stored keywords and more. + + \subsection tutorial-settings Defining a Settings + rbr::settings can be directly constructed from an arbitrary list of options, ie values bound to + a keyword. Once constructed, its operator[] can be used to fetch the value of a given keyword. + + @include doc/tutorial03.cpp + + \subsection tutorial-stream Stream insertion + rbr::settings can be streamed to display the list of keyword/value pairs it contains + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ c++ + #include + #include + + int main() + { + using namespace rbr::literals; + + auto values = rbr::settings("size"_kw = 75ULL, "transparent"_fl, "value"_kw = 7.7f); + + std::cout << values << "\n"; + } + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + The expected output should be: + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 'size' : 75 (long long unsigned int) + 'transparent' : 1 (std::integral_constant) + 'value' : 7.7 (float) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +**/ +//================================================================================================== diff --git a/test/doc/tutorial05.cpp b/test/doc/tutorial05.cpp index 2653136..0dd8504 100644 --- a/test/doc/tutorial05.cpp +++ b/test/doc/tutorial05.cpp @@ -7,10 +7,6 @@ #include #include -#include -#include -#include - struct unrolling : rbr::as_keyword { template