# [`cxx-str`][]
A [C++11][] [`std::string`][] [macro][] library.
If [C++20][] is avaiable, [`std::format`][] and [`std::source_location`][] may
be more appropriate. If [C++23][] is available, [`std::stacktrace`][] may be
more appropriate.
[`cxx-str`]: https://git.rcrnstn.net/rcrnstn/cxx-str
[C++11]: https://en.wikipedia.org/wiki/C++11
[`std::string`]: https://en.cppreference.com/w/cpp/string/basic_string
[macro]: https://en.cppreference.com/w/cpp/preprocessor/replace
[C++20]: https://en.wikipedia.org/wiki/C++20
[`std::format`]: https://en.cppreference.com/w/cpp/utility/format/format
[`std::source_location`]: https://en.cppreference.com/w/cpp/utility/source_location
[C++23]: https://en.wikipedia.org/wiki/C++23
[`std::stacktrace`]: https://en.cppreference.com/w/cpp/utility/basic_stacktrace
## Usage
Note that macros can result in unintuitive behavior.
Looking at the [source][] and [test][] is the best way to understand usage.
Throughout, arguments are only evaluated once. When [lambda][]s are defined and
immediately called behind the scenes, values are implicitly [capture][]d by
reference. The only lambda that implicitly captures by value is
`STR_FUNC(VALUE)`.
Include the header:
```cpp
#include <str.hpp>
```
There are a few different categories of functionality:
- Easy access to [`std::ostringstream`][]'s [`operator<<`][] and [`str()`][].
The `VALUE` expressions below can contain several values joined with `<<`.
`STR(VALUE)` produces a string.
`STR_FUNC(VALUE)` produces a [lambda][], which implicitly [capture][]s by
value, and returns a string. Useful for lazy evaluation of costly string
operations. For good performance, make sure the standard library can
perform Small String Optimization ([SSO][]) (and if used with
[`std::function`][], Small Object Optimization ([SOO][])).
`STR_JOIN(JOIN, ITERATOR, VALUE, ...)` makes the variable name `ITERATOR`
available in the `VALUE` expression, and joins the corresponding non-empty
(as interpreted by `STR(VALUE)`) elements of `...` with `JOIN`.
`STR_JOIN_INIT(JOIN, ITERATOR, VALUE, TYPE, ...)` forwards to
`STR_JOIN(JOIN, ITERATOR, VALUE, ...)`, passing
[`std::initializer_list`][]`<TYPE>`[`__VA_ARGS__`][]`)` as the last
argument. Notice the lack of braces, they have to be supplied manually.
`STR_JOIN_INITSTR(JOIN, ITERATOR, VALUE, ...)` forwards to `STR_JOIN_INIT`
with `std::string` as the `TYPE` argument.
- Easy access to the stringifying and concatenating [`#` and `##`
operators][] to help map constants to strings.
`STR_CASE(CASE)` uses `case` and `return` statements: `case (CASE): return
(#CASE);`.
`STR_COND(VALUE, CASE)` uses the [conditional operator][]: `((VALUE) ==
(CASE)) ? (#CASE) :`.
`STR_INIT(CASE)` uses [list initialization][]: `{(CASE), (#CASE)},`.
`STR_ARGS(ARG)` expands to `ARG, #ARG`.
`STR_ARGS_PREFIX(PREFIX, ARG)` expands to `PREFIX##ARG, #ARG`.
- Easy access to source file and line.
`STR_HERE(VALUE)` joins [`__FILE__` and `__LINE__`][] and [`__func__`][]
with `":"`, and appends `": "` and the given argument to produce a string.
- Easy handling to ([nested][]) [`std::exception`][]s, which contain strings
accessible through the [`what()`][] method.
`STR_EXCEPTION` can be defined to control what exceptions are thrown by the
macros below. If it is not defined, [`std::runtime_error`][] is used.
`STR_THROW(VALUE)` [`throw`][]s a `STR_EXCEPTION` initialized with
`STR(VALUE)`.
`STR_THROW_ERRNO()` calls `STR_THROW` with the argument
`std::generic_category().message(errno) << "."`.
`STR_RETHROW(VALUE)` calls [`std::terminate`][] if called outside a
[`catch`][] block. Otherwise, `STR_THROW`s `VALUE` followed by the
[`what()`][] of the current exception (so it is appropriate to include a
separator manually) if it is a (derives from) [`std::exception`][],
otherwise simply rethrows the current exception.
`STR_NESTED_THROW(VALUE)` calls [`std::throw_with_nested`][] on a
`STR_EXCEPTION` initialized with `STR(VALUE)`.
`STR_NESTED_THROW_ERRNO()` calls `STR_NESTED_THROW` with the argument
`std::generic_category().message(errno) << "."`.
`STR_NESTED_WHAT(JOIN, EXCEPTION)` joins the strings returned by the
(optionally) [nested][] [`std::exception`][]-based `EXCEPTION`'s
[`what()`][] methods with `JOIN`, and returns the resulting string.
[source]: include/str.hpp
[test]: tests/str.cpp
[lambda]: https://en.cppreference.com/w/cpp/language/lambda
[capture]: https://en.cppreference.com/w/cpp/language/lambda#Lambda_capture
[`std::ostringstream`]: https://en.cppreference.com/w/cpp/io/basic_ostringstream
[`operator<<`]: https://en.cppreference.com/w/cpp/io/basic_ostream/operator_ltlt
[`str()`]: https://en.cppreference.com/w/cpp/io/basic_ostringstream/str
[SSO]: https://en.cppreference.com/w/cpp/language/acronyms
[`std::function`]: https://en.cppreference.com/w/cpp/utility/functional/function
[SOO]: https://en.cppreference.com/w/cpp/language/acronyms
[`std::initializer_list`]: https://en.cppreference.com/w/cpp/utility/initializer_list
[`__VA_ARGS__`]: https://en.cppreference.com/w/cpp/preprocessor/replace
[`#` and `##` operators]: https://en.cppreference.com/w/cpp/preprocessor/replace#.23_and_.23.23_operators
[list initialization]: https://en.cppreference.com/w/cpp/language/list_initialization
[conditional operator]: https://en.cppreference.com/w/cpp/language/operator_other#Conditional_operator
[`__FILE__` and `__LINE__`]: https://en.cppreference.com/w/c/preprocessor/line
[`__func__`]: https://en.cppreference.com/w/cpp/language/function#func
[`#ifndef`]: https://en.cppreference.com/w/cpp/preprocessor/conditional
[`NDEBUG`]: https://en.cppreference.com/w/c/error/assert
[nested]: https://en.cppreference.com/w/cpp/error/nested_exception
[`std::exception`]: https://en.cppreference.com/w/cpp/error/exception
[`what()`]: https://en.cppreference.com/w/cpp/error/exception/what
[`std::runtime_error`]: https://en.cppreference.com/w/cpp/error/runtime_error
[`throw`]: https://en.cppreference.com/w/cpp/language/throw
[`std::terminate`]: https://en.cppreference.com/w/cpp/error/terminate
[`catch`]: https://en.cppreference.com/w/cpp/language/try_catch
[`std::throw_with_nested`]: https://en.cppreference.com/w/cpp/error/throw_with_nested
## Test output
The [test][] outputs:
```
0x3
0x3
"first", "", "third"
first, third
first
unknown
third
/path/to/cxx-str/tests/str.cpp:96: Hello from here
Failed to do outer:
Failed to do inner:
Expected this, got that.
```
## Building
See [`BUILDING.md`][].
[`BUILDING.md`]: BUILDING.md
## License
Licensed under the [ISC License][] unless otherwise noted, see the
[`LICENSE`][] file.
[ISC License]: https://choosealicense.com/licenses/isc/
[`LICENSE`]: LICENSE