Commit 6433d87f authored by Xavier Thompson's avatar Xavier Thompson

README: Add section on string formatting

parent f77f6db1
...@@ -92,3 +92,28 @@ and ...@@ -92,3 +92,28 @@ and
make client make client
``` ```
## String formatting
In order to (much) more easily compose response messages, I chose to implement string formatting. This provides a way to efficiently pack miscellaneous values into strings without repeated string concatenations. In fact, before this I had no easy way to even convert integer values to strings!
I chose to go with [fmt](https://fmt.dev), a neat C++ string formatting library. I discarded the string formatting solutions from the C standard library like `sprintf` because they (a) do not manage memory alllocation and instead require a buffer of sufficient size be allocated in advance to store the formatted string, and (b) they are not type safe. Since C++20 there is also a string formatting library in the C++ standard library, but I deemed that it would be easier to depend on an external library like `fmt` than to require such a recent version of C++.
To install `fmt` you can follow the explanations in the [usage guide](https://fmt.dev/latest/usage.html). It must be built as a **static library** because we use it in Python extensions; the guide explains how (tldr: `cmake -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE ...`).
Note that since `fmt` makes use of C++ templates and compile-time assertions, Cython will not always be able to catch misuses and the user can be confronted with C++ compilation errors of the underlying compilation step. This is still much better than misuses not being caught at all and resulting in runtime faults as can happen with the C library `sprintf`!
I wrote an adapter for the `fmt::format` method so that our GIL-free strings may be accepted as arguments and be type of the returned value, instead of just `std::string`. This proved rather complicated and I had to come up with several workaround hacks:
1. First, Cython and Cython+ have limited support for C++ templates, so I had to write the adapter directly in C++ using Cython's foreign code interface.
2. But such raw C++ foreign code is inserted before user-defined types such as our GIL-free string class, so I had to use templates that can be instantiated with our string type later in the code.
3. I then overrode the `cname` (the name in the generated C++ code) of my adapter template method to explictly instantiate it with our GIL-free string type.
4. To this end I needed the `cname` of our string type, but in Cython user-defined names are normally mangled, so I had to override its `cname` as well just to know what it would be.
Anyway, it works!
I kept the format string argument as a simple `char *` because the prevailing use case by far is to just pass a string literal.
The formatting syntax is the same as the underlying `fmt` library. It's quite similar to [Python's Format Specification Mini Language](https://docs.python.org/3.8/library/string.html#formatspec), and in fact it's inspired by it.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment