From d76464d4f3fd990c43d20fae7493aa2b79fd4976 Mon Sep 17 00:00:00 2001 From: Riyyi Date: Sun, 6 Apr 2025 21:47:13 +0200 Subject: [PATCH] Finish utility library article --- content/articles/utility-library.md | 121 +++++++++++++++++++++++++++- 1 file changed, 119 insertions(+), 2 deletions(-) diff --git a/content/articles/utility-library.md b/content/articles/utility-library.md index 4574b42..733388a 100644 --- a/content/articles/utility-library.md +++ b/content/articles/utility-library.md @@ -24,11 +24,128 @@ my projects and create one cohesive style. ## Argument parsing -placeholder +This is a simple argument parsing feature, with the attempt of making it simpler +to use than getopt. All you have to do is specify the variables you want to use, +then add the options and arguments on the `ArgParser` object and finally call +the `parse` function. + +```cpp +#include +#include + +#include "ruc/argparser.h" + +int main(int argc, const char* argv[]) +{ + bool verbose = false; + std::vector targets {}; + + ruc::ArgParser argParser; + argParser.addOption(verbose, 'v', "verbose", nullptr, nullptr); + argParser.addArgument(targets, "targets", nullptr, nullptr, ruc::ArgParser::Required::No); + argParser.parse(argc, argv); + + // Do some work here.. + + return 0; +} +``` + +The `nullptr`'s in the above example were going to be used for automatic help +string generation, but that isn't implemented yet. ## Formatting library -placeholder +This is basically a partial copy of the `fmt` library, from before that became +part of the C++20 standard and I didn't want to use an additional dependency in +my projects, because that is less fun! + +The part of `fmt` that is implement is the +"[mini-language](https://fmt.dev/11.1/syntax/#format-specification-mini-language)", +which is a very convenient API. + +```cpp +#include + +#include "ruc/format/format.h" +#include "ruc/format/print.h" + +int main(int argc, const char* argv[]) +{ + std::string fmt = format( + R"( + number {} + string {} + bool {}j + double {} + double {:.2} with 2 precision +)", 123, "this is a string", true, 456.789, 3.14159265359); + print("{}\n", fmt); + + return 0; +} +``` + +Which results the the output. + +``` + number 123 + string this is a string + bool true + double 456.789000 + double 3.14 with 2 precision +``` + +The implementation consists of 2 major parts, the parsing of the format string +and the `format` and `print` functions. The parsing part isn't that complex, so +wont be discussed here. The other secion is interesting, however. + +The functions are implemented with variadic arguments using type erasure, this +improves both compile time and binary size significantly. What it also does, is +allow the library to work on types that are specified by the user and are +therefor not part of the library. + +The formatter implements all the primitives and some of the STL types, it can be +extended by the user. The basic use-case is to specify to just the `format` +function, but the `parser` function can also be overwritten. + +```cpp +// In the header we are extending the existing formatter for vectors, +// so we take advantage of their nice formatting automatically +template<> +struct ruc::format::Formatter : Formatter> { + void format(Builder& builder, glm::vec4 value) const; +}; + +// Then in the implementation, we implement the format functon +void ruc::format::Formatter::format(Builder& builder, glm::vec4 value) const +{ + return Formatter>::format(builder, { value.x, value.y, value.z, value.w }); +} +``` + +Users can even extend formatters based on their own formats. In this example we +are extending the vector (`glm::vec4`) formatter, so we can also print matrices +(`glm::mat4`). + +```cpp +template<> +struct ruc::format::Formatter : Formatter { + void format(Builder& builder, glm::mat4 value) const; +}; + +void ruc::format::Formatter::format(Builder& builder, glm::mat4 value) const +{ + builder.putString("mat4 "); + Formatter::format(builder, value[0]); + builder.putString("\n "); + Formatter::format(builder, value[1]); + builder.putString("\n "); + Formatter::format(builder, value[2]); + builder.putString("\n "); + return Formatter::format(builder, value[3]); +} +``` ## JSON parsing