Browse Source

Finish utility library article

master
Riyyi 2 weeks ago
parent
commit
d76464d4f3
  1. 121
      content/articles/utility-library.md

121
content/articles/utility-library.md

@ -24,11 +24,128 @@ my projects and create one cohesive style.
## Argument parsing ## 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 <string>
#include <vector>
#include "ruc/argparser.h"
int main(int argc, const char* argv[])
{
bool verbose = false;
std::vector<std::string> 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 ## 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 <string>
#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<glm::vec4> : Formatter<std::vector<float>> {
void format(Builder& builder, glm::vec4 value) const;
};
// Then in the implementation, we implement the format functon
void ruc::format::Formatter<glm::vec4>::format(Builder& builder, glm::vec4 value) const
{
return Formatter<std::vector<float>>::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<glm::mat4> : Formatter<glm::vec4> {
void format(Builder& builder, glm::mat4 value) const;
};
void ruc::format::Formatter<glm::mat4>::format(Builder& builder, glm::mat4 value) const
{
builder.putString("mat4 ");
Formatter<glm::vec4>::format(builder, value[0]);
builder.putString("\n ");
Formatter<glm::vec4>::format(builder, value[1]);
builder.putString("\n ");
Formatter<glm::vec4>::format(builder, value[2]);
builder.putString("\n ");
return Formatter<glm::vec4>::format(builder, value[3]);
}
```
## JSON parsing ## JSON parsing

Loading…
Cancel
Save