From 76cfc876e2a5a7a42dea1f4e8ab98fb23f0fa7e1 Mon Sep 17 00:00:00 2001 From: jay-tux Date: Tue, 1 Mar 2022 10:52:43 +0100 Subject: [PATCH 1/4] Fortified types by enforcing function signatures (using std::enable_if) --- inc/aggregators.hpp | 14 ++++++++++---- inc/fpgen.hpp | 1 + inc/generator.hpp | 7 ++----- inc/manipulators.hpp | 13 +++++++++---- inc/sources.hpp | 9 ++++++--- inc/type_traits.hpp | 25 +++++++++++++++++++++++++ 6 files changed, 53 insertions(+), 16 deletions(-) create mode 100644 inc/type_traits.hpp diff --git a/inc/aggregators.hpp b/inc/aggregators.hpp index 8f2b4ad..f5afbf0 100644 --- a/inc/aggregators.hpp +++ b/inc/aggregators.hpp @@ -2,6 +2,7 @@ #define _FPGEN_AGGREGATORS #include "generator.hpp" +#include "type_traits.hpp" #include #include #include @@ -102,7 +103,8 @@ template size_t count(generator gen) { * \param[in] folder The folding function. * \returns The final accumulator value. */ -template +template > TOut fold(generator gen, Fun folder) { TOut value = {}; while (gen) { @@ -129,7 +131,8 @@ TOut fold(generator gen, Fun folder) { * \param[in] initial The initial value for the accumulator (is copied). * \returns The final accumulator value. */ -template +template > TOut fold(generator gen, Fun folder, TOut initial) { TOut value(initial); while (gen) { @@ -157,7 +160,8 @@ TOut fold(generator gen, Fun folder, TOut initial) { * \returns A reference to the value which was passed as initial value and is * now the output value. */ -template +template > TOut &fold_ref(generator gen, Fun folder, TOut &initial) { while (gen) { initial = folder(initial, gen()); @@ -196,7 +200,9 @@ template T sum(generator gen) { * \param[in,out] gen The generator to iterate over. * \param[in] func The function to use. */ -template void foreach (generator gen, Fun func) { +template > +void foreach (generator gen, Fun func) { while (gen) { func(gen()); } diff --git a/inc/fpgen.hpp b/inc/fpgen.hpp index f2ba0cf..a39cb81 100644 --- a/inc/fpgen.hpp +++ b/inc/fpgen.hpp @@ -5,5 +5,6 @@ #include "generator.hpp" #include "manipulators.hpp" #include "sources.hpp" +#include "type_traits.hpp" #endif diff --git a/inc/generator.hpp b/inc/generator.hpp index c2f8efe..52a2768 100644 --- a/inc/generator.hpp +++ b/inc/generator.hpp @@ -11,6 +11,7 @@ using namespace experimental; #endif #include "__helpers.hpp" +#include "type_traits.hpp" #include /** @@ -33,11 +34,7 @@ namespace fpgen { */ template class generator { #else -template -using enabler = - typename std::enable_if::value, bool>::type; - -template = true> class generator { +template > class generator { #endif public: /** diff --git a/inc/manipulators.hpp b/inc/manipulators.hpp index 0a6ac60..9afda5f 100644 --- a/inc/manipulators.hpp +++ b/inc/manipulators.hpp @@ -2,6 +2,7 @@ #define _FPGEN_MANIP #include "generator.hpp" +#include "type_traits.hpp" #include #include @@ -18,13 +19,17 @@ namespace fpgen { * * \tparam TIn The type contained in the provided generator. * \tparam Fun The function signature of the mapping function. + * \tparam TOut The output type. This type is deduced from the `Fun` type + * parameter. * \param[in,out] gen The generator to map over. Will be in unusable state * afterwards. * \param[in] func The function to map with. * \returns A new generator whose contained type is the return type of the * mapping function. */ -template +template , + typename _ = type::is_function_to> auto map(generator gen, Fun func) -> generator::type> { while (gen) { @@ -69,7 +74,7 @@ generator> zip(generator gen1, generator gen2) { * \returns A new generator which yields all values in the original generator * except those not matching the predicate. */ -template +template > generator filter(generator gen, Pred p) { while (gen) { T val(gen()); @@ -139,7 +144,7 @@ template generator take(generator gen, size_t count) { * \returns A new generator where the first element is guaranteed to not * satisfy `p`. */ -template +template > generator drop_while(generator gen, Pred p) { while (gen) { T temp = gen(); @@ -172,7 +177,7 @@ generator drop_while(generator gen, Pred p) { * predicate and were generated before any element which didn't satisfy the * predicate. */ -template +template > generator take_while(generator gen, Pred p) { while (gen) { T val = gen(); diff --git a/inc/sources.hpp b/inc/sources.hpp index fa68ba1..8861462 100644 --- a/inc/sources.hpp +++ b/inc/sources.hpp @@ -2,6 +2,7 @@ #define _FPGEN_SOURCES #include "generator.hpp" +#include "type_traits.hpp" #include #include #include @@ -117,14 +118,16 @@ template generator inc(T start) { * * \tparam Fun The type of the function. Should have the signature * (std::istream &) -> T. + * \tparam TOut The output type. This type is deduced from the `Fun` type + * parameter. * \param[in,out] stream The input stream. * \param[in] func The function to extract data from the stream. * \returns A new generator which will iterate over the given stream, each time * applying the given function to retrieve the next value. */ -template -generator::type> -from_stream(std::istream &stream, Fun func) { +template , + typename _ = type::is_function_to> +generator from_stream(std::istream &stream, Fun func) { while (stream.good() && !stream.eof()) { co_yield func(stream); } diff --git a/inc/type_traits.hpp b/inc/type_traits.hpp new file mode 100644 index 0000000..b373048 --- /dev/null +++ b/inc/type_traits.hpp @@ -0,0 +1,25 @@ +#ifndef _FPGEN_TYPE_TRAITS +#define _FPGEN_TYPE_TRAITS + +#include +#include + +namespace fpgen::type { + +template +using is_function_to = typename std::enable_if< + std::is_convertible>::value>::type; + +template +using is_predicate = is_function_to; + +template +using output_type = typename std::invoke_result::type; + +template +using is_generator_type = + typename std::enable_if::value>::type; + +} // namespace fpgen::type + +#endif From 284fc0009b465a6af071fc9e5a7f8c381f40e42e Mon Sep 17 00:00:00 2001 From: jay-tux Date: Tue, 1 Mar 2022 10:57:35 +0100 Subject: [PATCH 2/4] Remove dependency --- inc/__helpers.hpp | 12 ------------ inc/generator.hpp | 5 ----- 2 files changed, 17 deletions(-) delete mode 100644 inc/__helpers.hpp diff --git a/inc/__helpers.hpp b/inc/__helpers.hpp deleted file mode 100644 index 456c7c7..0000000 --- a/inc/__helpers.hpp +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _FPGEN___HELPERS -#define _FPGEN___HELPERS - -#ifdef __clang__ -#include -#define _FPGEN_USE_CONCEPTS 0 -#else -#include -#define _FPGEN_USE_CONCEPTS 1 -#endif - -#endif diff --git a/inc/generator.hpp b/inc/generator.hpp index 52a2768..8167760 100644 --- a/inc/generator.hpp +++ b/inc/generator.hpp @@ -10,7 +10,6 @@ using namespace experimental; #include #endif -#include "__helpers.hpp" #include "type_traits.hpp" #include @@ -18,7 +17,6 @@ using namespace experimental; * \brief The namespace containing all of fpgen's code. */ namespace fpgen { -#if _FPGEN_USE_CONCEPTS /** * \brief The main generator type. * @@ -32,10 +30,7 @@ namespace fpgen { * \tparam T The value type for the generator. This should satisfy * `std::copyable`, or on (older) CLang versions, `std::is_copy_assignable`. */ -template class generator { -#else template > class generator { -#endif public: /** * \brief The promise type for the generator. From 3e87a74dbe3075dc3ef8278aa76cf1f6f37a9c21 Mon Sep 17 00:00:00 2001 From: jay-tux Date: Tue, 1 Mar 2022 11:16:47 +0100 Subject: [PATCH 3/4] Documentation for the type traits --- inc/type_traits.hpp | 52 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/inc/type_traits.hpp b/inc/type_traits.hpp index b373048..af224dc 100644 --- a/inc/type_traits.hpp +++ b/inc/type_traits.hpp @@ -4,18 +4,70 @@ #include #include +/** + * \brief The namespace containing some type helpers for fpgen. + */ namespace fpgen::type { +/** + * \brief Type trait deducing whether a type is a function from the input types + * to the output type. + * + * In short, the function type `TFun` should have the signature `(TIns...) -> + * TOut`. This can include any "free" function (plain C function pointer), any + * lambda function, or any struct/class type supporting `TOut + * operator()(TIns...)`. This is implemented using the type traits + * `std::enable_if` and `std::is_convertible`. Usage: use as an extra template + * type, like so: + * `typename _ = fpgen::type::is_function_to`. + * + * \tparam TFun The function type. + * \tparam TOut The output type for the function. + * \tparam TIns The input type(s) for the function. + */ template using is_function_to = typename std::enable_if< std::is_convertible>::value>::type; +/** + * \brief Type trait deducing whether a type is a predicate. + * + * In short, the function type `TFun` should have the signature `(TIns...) -> + * bool`. This can include any "free" function (plain C function pointer), any + * lambda function, or any struct/class type supporting `bool + * operator()(TIns...)`. This is implemented using fpgen::type::is_function_to. + * Usage: use as an extra template type, like so: + * `typename _ = fpgen::type::is_predicate`; + * this is synonymous to using + * `typename _ = fpgen::type::is_function_to`. + * + * \tparam TFun The predicate function type. + * \tparam TIns The input type(s) for the function. + */ template using is_predicate = is_function_to; +/** + * \brief Type trait deducing the output type of a functional type. + * + * If the type `TFun` is a function type `(TIns...) -> TOut`, this type trait + * will return `TOut`. Thie type trait is implemented using + * `std::invoke_result`. + * + * \tparam TFun The function type. + * \tparam TIns The input type(s) for the function. + */ template using output_type = typename std::invoke_result::type; +/** + * \brief Type trait deducing whether a type is fit as data type for a + * generator. + * + * The type `T` will pass the test if it's copy-assignable. + * + * \tparam T The type to check. + */ template using is_generator_type = typename std::enable_if::value>::type; From 948c8aa435584505284e2bffa8275ef8ad8594ae Mon Sep 17 00:00:00 2001 From: jay-tux Date: Tue, 1 Mar 2022 11:53:24 +0100 Subject: [PATCH 4/4] Modified doxygen style --- .gitignore | 3 + .gitmodules | 3 - Doxyfile.mk | 6 +- docs/doxygen.css | 372 +++++++++++++++++++++++++++++++++++++++ docs/doxygen_footer.html | 7 + docs/doxygen_header.html | 67 +++++++ 6 files changed, 452 insertions(+), 6 deletions(-) delete mode 100644 .gitmodules create mode 100644 docs/doxygen.css create mode 100644 docs/doxygen_footer.html create mode 100644 docs/doxygen_header.html diff --git a/.gitignore b/.gitignore index 496097d..ec576bb 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,9 @@ test/conan/* cov/* !**/.gitkeep +!docs/doxygen.css +!docs/doxygen_footer.html +!docs/doxygen_header.html compile_flags.txt coverage.info diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index e661309..0000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "docs/doxygen-awesome-css"] - path = docs/doxygen-awesome-css - url = git@github.com:jothepro/doxygen-awesome-css diff --git a/Doxyfile.mk b/Doxyfile.mk index edf1ff4..69fe5df 100644 --- a/Doxyfile.mk +++ b/Doxyfile.mk @@ -1221,7 +1221,7 @@ HTML_FILE_EXTENSION = .html # of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_HEADER = +HTML_HEADER = $(OUTDIR)/doxygen_header.html # The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each # generated HTML page. If the tag is left blank doxygen will generate a standard @@ -1231,7 +1231,7 @@ HTML_HEADER = # that doxygen normally uses. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_FOOTER = +HTML_FOOTER = $(OUTDIR)/doxygen_footer.html # The HTML_STYLESHEET tag can be used to specify a user-defined cascading style # sheet that is used by each HTML page. It can be used to fine-tune the look of @@ -1243,7 +1243,7 @@ HTML_FOOTER = # obsolete. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_STYLESHEET = +HTML_STYLESHEET = $(OUTDIR)/doxygen.css # The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined # cascading style sheets that are included after the standard style sheets diff --git a/docs/doxygen.css b/docs/doxygen.css new file mode 100644 index 0000000..10a8395 --- /dev/null +++ b/docs/doxygen.css @@ -0,0 +1,372 @@ +/* From: https://github.com/awalsh128/doxygen-themes/blob/main/themes/primary_dark/doxygen.css */ +:root { + --margin-large: 1rem; + --margin-medium: 0.5rem; + --padding-large: 1rem; + --padding-medium: 0.4rem; + --padding-small: 0.2rem; + --border-radius: 0.4rem; + --header-margin: 0.5rem; +} + +a { + color: var(--bs-info); + text-decoration: none; +} + +body { + background-color: var(--bs-gray-600); +} + +h1 { + background-color: var(--bs-green); + border-radius: var(--border-radius); + font-size: xx-large; + margin-bottom: var(--header-margin); + margin-top: var(--header-margin); + padding: var(--padding-large); +} + +h2 { + background-color: var(--bs-cyan); + border-radius: var(--border-radius); + font-size: x-large; + padding: var(--padding-large); +} + +h3 { + background-color: var(--bs-gray-900); + border-radius: var(--border-radius); + padding: var(--padding-medium); +} + +img { + margin-bottom: var(--margin-large); +} + +p { + padding: 0 var(--padding-medium) 0 var(--padding-medium); +} + +/* Tree View - Hide for now. Doxygen layouts are too unruly. */ +div.ttc { + display: none; +} + +/* Page */ +.header { + background-color: var(--bs-gray-900); + background-image: var(--bs-gradient); + border-style: solid; + border-radius: var(--border-radius); + border-width: 1px; + margin-bottom: var(--margin-large); + margin-top: var(--margin-large); + padding: var(--padding-medium); + text-align: center; +} +.summary { + text-align: center; +} +.summary a { + margin-left: var(--padding-medium); +} +.title { + font-size: x-large; + padding: var(--padding-medium); +} + +.textblock { + background-color: var(--bs-gray-700); + border-style: solid; + border-width: 1px; + border-radius: var(--border-radius); + margin-bottom: var(--margin-medium); + padding: var(--padding-large); +} + +.section { + margin: 0 0 var(--margin-medium) 0; +} +.section dt { + background-color: var(--bs-blue); + border-radius: var(--border-radius) var(--border-radius) 0 0; + padding: var(--padding-medium); +} +.section td { + padding: var(--padding-small); +} +.section dd { + background-color: var(--bs-gray-600); + margin-bottom: 1px; + padding: var(--padding-medium); +} + +.memSeparator { + line-height: 1rem; +} +.separator\: { + line-height: var(--margin-small); +} + +/* Code */ +code { + white-space: pre-wrap; +} +.contents > p > code { + background-color: #000000; + display: inline-block; + padding: 1rem; + width: 100%; +} +.fragment { + background-color: #000000; + border-radius: var(--border-radius); + margin-bottom: var(--margin-medium); + padding: var(--padding-medium); +} +.comment { + color: var(--bs-gray-500); +} +.keyword { + color: var(--bs-pink); +} +.line { + color: var(--bs-cyan); + white-space: pre; +} +span.lineno { + color: var(--bs-teal); + padding-right: 1rem; +} +.preprocessor { + color: var(--bs-blue); +} + +/* Breadcrumbs & Doxygen Header */ +.navpath { + background-color: var(--bs-gray-900); + background-image: var(--bs-gradient); + padding: 0.5rem 0 0.3rem 2rem; + border-radius: 0 0 var(--border-radius) var(--border-radius); +} +.navpath ul { + display: flex; + flex-wrap: wrap; + padding: 0 0; + margin-bottom: 1rem; + list-style: none; +} +.navelem + .navelem { + padding-left: var(--padding-medium); +} +.navelem + .navelem::before { + float: left; + padding-right: var(--padding-medium); + color: #6c757d; + content: var(--bs-breadcrumb-divider, "/"); +} + +/* Class: Types & Public Member Functions */ +.memberdecls { + width: 100%; +} +.memItemLeft { + background-color: var(--bs-gray-800); + padding: var(--padding-medium); + vertical-align: middle; +} +.memItemRight { + background-color: var(--bs-gray-800); + padding: var(--padding-medium); + vertical-align: middle; +} +.mdescLeft { + background-color: var(--bs-gray-700); + padding: var(--padding-medium); + vertical-align: middle; +} +.mdescRight { + background-color: var(--bs-gray-700); + padding: var(--padding-medium); + vertical-align: middle; +} +.inherit_header { + background-color: var(--bs-gray-700); + line-height: 3rem; + padding-left: var(--padding-large); + vertical-align: middle; +} +.memTemplParams { + background-color: var(--bs-gray-700); + padding: var(--padding-medium); + vertical-align: middle; +} +.memTemplItemLeft { + background-color: var(--bs-gray-800); + padding-right: var(--padding-medium); + vertical-align: middle; +} +.memTemplItemRight { + background-color: var(--bs-gray-800); + padding-right: var(--padding-medium); + vertical-align: middle; +} + +/* Class: Member Functions */ +.memtitle { + background-color: var(--bs-orange); + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + border-style: solid solid none solid; + margin-bottom: 0; +} +.memtitle a { + color: var(--bs-yellow); +} +.memtitle a:hover { + color: var(--bs-red); + font-weight: bolder; +} +.memitem { + background-color: var(--bs-gray-700); + border-radius: 0 0 var(--border-radius) var(--border-radius); + border-style: none solid solid solid; + margin-bottom: 1rem; + padding: var(--padding-medium); +} +/* Class: Member Function - Prototype */ +.memproto { + background-color: var(--bs-gray-800); + border-radius: var(--border-radius); + margin-bottom: var(--margin-medium); + padding: var(--padding-medium); +} +.memproto td { + column-fill: auto; +} +/* Class: Member Function - Signature */ +.paramtype { + color: var(--bs-pink); + vertical-align: middle; +} +.paramname { + color: var(--bs-cyan); + vertical-align: middle; + display: inline-flex; +} +.paramname code { + /* Override code from .fragments. */ + margin: 0; + padding: 0; + line-height: 1.6rem; + vertical-align: baseline; +} +/* Class: Member Function - Components */ +.memdoc dl { + margin-bottom: var(--margin-medium); +} +/* Class: Member Function - Template Parameters */ +.tparams dt { + background-color: var(--bs-green); + border-radius: var(--border-radius) var(--border-radius) 0 0; + padding: var(--padding-medium); +} +.tparams td { + padding: var(--padding-small); +} +.tparams dd { + background-color: var(--bs-gray-600); + margin-bottom: 1px; + padding: var(--padding-small); + padding-left: var(--padding-medium); +} +/* Class: Member Function - Parameters */ +.params dt { + background-color: var(--bs-green); + border-radius: var(--border-radius) var(--border-radius) 0 0; + padding: var(--padding-medium); +} +.params td { + padding: var(--padding-small); +} +.params dd { + background-color: var(--bs-gray-600); + padding: var(--padding-small); + padding-left: var(--padding-medium); +} +table.params tr { + margin-bottom: 1px; +} + +/* Class List */ +.levels { + background-color: var(--bs-green); + padding: var(--padding-large); +} +.levels span { + font-weight: bold; + margin-left: var(--padding-medium); + margin-right: var(--padding-medium); +} +.levels span:hover { + color: var(--bs-cyan); + font-weight: bolder; +} +.directory { + background-color: var(--bs-gray-800); + background-image: var(--bs-gradient); + margin-bottom: var(--margin-large); + margin-top: var(--margin-large); +} +table.directory { + width: 100%; +} +.even { + background-color: var(--bs-gray-700); + background-image: var(--bs-gradient); +} +.entry { + padding: 0.5rem; + vertical-align: middle; +} +.arrow:hover { + color: var(--bs-cyan); + font-weight: bolder; +} +.icona { + background-color: var(--bs-green); + border-radius: 0.5rem; + color: var(--bs-black); + margin: 0.2rem 0.5rem 0.2rem 0.5rem; + padding: 0.2rem 0.5rem 0.2rem 0.5rem; +} + +/* Struct */ +.dynheader { + background-color: var(--bs-blue); + border-radius: var(--border-radius) var(--border-radius) 0 0; + font-weight: bolder; + padding: var(--padding-medium); + text-align: center; +} +.dyncontent { + background-color: var(--bs-gray-700); + background-image: var(--bs-gradient); + border-radius: 0 0 var(--border-radius) var(--border-radius); + margin-bottom: var(--margin-medium); + padding: var(--padding-medium); + text-align: center; +} + +#main-nav { + display: none; +} + +#main-menu-state { + display: none; +} + +.main-menu-btn { + display: none; +} diff --git a/docs/doxygen_footer.html b/docs/doxygen_footer.html new file mode 100644 index 0000000..25c8f82 --- /dev/null +++ b/docs/doxygen_footer.html @@ -0,0 +1,7 @@ + + +