From adf17f2b3b2eb119abe324f82dc93cea0a2d0065 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anarthal=20=28Rub=C3=A9n=20P=C3=A9rez=29?= <34971811+anarthal@users.noreply.github.com> Date: Wed, 2 Jul 2025 23:27:33 +0200 Subject: [PATCH] Migrates the documentation to Asciidoc/MrDocs (#276) Fixes some typos close #247 --- .github/workflows/ci.yml | 21 + README.md | 1062 +------- doc/CMakeLists.txt | 26 + doc/DoxygenLayout.xml | 226 -- doc/Jamfile | 92 +- doc/antora.yml | 15 + doc/build_antora.sh | 19 + doc/doxygen-awesome-sidebar-only.css | 145 - doc/doxygen-awesome.css | 2384 ----------------- doc/footer.html | 19 - doc/header.html | 61 - doc/modules/ROOT/nav.adoc | 10 + doc/modules/ROOT/pages/acknowledgements.adoc | 37 + doc/modules/ROOT/pages/benchmarks.adoc | 95 + doc/modules/ROOT/pages/changelog.adoc | 397 +++ doc/modules/ROOT/pages/comparison.adoc | 121 + doc/modules/ROOT/pages/examples.adoc | 27 + doc/modules/ROOT/pages/index.adoc | 143 + doc/modules/ROOT/pages/logging.adoc | 45 + doc/modules/ROOT/pages/reference.adoc | 90 + .../ROOT/pages/requests_responses.adoc | 302 +++ doc/modules/ROOT/pages/serialization.adoc | 26 + doc/mrdocs.cpp | 10 + doc/mrdocs.yml | 31 + doc/package-lock.json | 1955 ++++++++++++++ doc/package.json | 6 + doc/redis-playbook.yml | 45 + include/boost/redis/adapter/adapt.hpp | 48 +- include/boost/redis/adapter/any_adapter.hpp | 6 +- include/boost/redis/adapter/ignore.hpp | 5 +- include/boost/redis/adapter/result.hpp | 13 +- include/boost/redis/config.hpp | 52 +- include/boost/redis/connection.hpp | 360 ++- include/boost/redis/detail/write.hpp | 16 +- include/boost/redis/error.hpp | 12 +- include/boost/redis/ignore.hpp | 10 +- include/boost/redis/logger.hpp | 9 +- include/boost/redis/operation.hpp | 3 +- include/boost/redis/request.hpp | 153 +- include/boost/redis/resp3/node.hpp | 21 +- include/boost/redis/resp3/serialization.hpp | 2 - include/boost/redis/resp3/type.hpp | 28 +- include/boost/redis/response.hpp | 20 +- include/boost/redis/usage.hpp | 9 +- index.html | 2 +- tools/ci.py | 2 +- 46 files changed, 3918 insertions(+), 4263 deletions(-) create mode 100644 doc/CMakeLists.txt delete mode 100644 doc/DoxygenLayout.xml create mode 100644 doc/antora.yml create mode 100755 doc/build_antora.sh delete mode 100644 doc/doxygen-awesome-sidebar-only.css delete mode 100644 doc/doxygen-awesome.css delete mode 100644 doc/footer.html delete mode 100644 doc/header.html create mode 100644 doc/modules/ROOT/nav.adoc create mode 100644 doc/modules/ROOT/pages/acknowledgements.adoc create mode 100644 doc/modules/ROOT/pages/benchmarks.adoc create mode 100644 doc/modules/ROOT/pages/changelog.adoc create mode 100644 doc/modules/ROOT/pages/comparison.adoc create mode 100644 doc/modules/ROOT/pages/examples.adoc create mode 100644 doc/modules/ROOT/pages/index.adoc create mode 100644 doc/modules/ROOT/pages/logging.adoc create mode 100644 doc/modules/ROOT/pages/reference.adoc create mode 100644 doc/modules/ROOT/pages/requests_responses.adoc create mode 100644 doc/modules/ROOT/pages/serialization.adoc create mode 100644 doc/mrdocs.cpp create mode 100644 doc/mrdocs.yml create mode 100644 doc/package-lock.json create mode 100644 doc/package.json create mode 100644 doc/redis-playbook.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e5fe055a..35543ba4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -334,3 +334,24 @@ jobs: --toolset ${{ matrix.toolset }} \ --cxxstd ${{ matrix.cxxstd }} \ --variant debug,release + + # Checks that we don't have any errors in docs + check-docs: + name: Check docs + defaults: + run: + shell: bash + + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Boost + run: ./tools/ci.py setup-boost --source-dir=$(pwd) + + - name: Build docs + run: | + cd ~/boost-root + ./b2 libs/redis/doc + [ -f ~/boost-root/libs/redis/doc/html/index.html ] diff --git a/README.md b/README.md index 026379ad..9b2db656 100644 --- a/README.md +++ b/README.md @@ -1,44 +1,55 @@ # Boost.Redis Boost.Redis is a high-level [Redis](https://redis.io/) client library built on top of -[Boost.Asio](https://www.boost.org/doc/libs/release/doc/html/boost_asio.html) +[Boost.Asio](https://www.boost.org/doc/libs/latest/doc/html/boost_asio.html) that implements the Redis protocol [RESP3](https://github.com/redis/redis-specifications/blob/master/protocol/RESP3.md). -The requirements for using Boost.Redis are -* Boost 1.84 or higher. -* C++17 or higher. +Full documentation is [here](https://www.boost.org/doc/libs/master/libs/redis/index.html). + +## Requirements + +The requirements for using Boost.Redis are: + +* Boost 1.84 or higher. Boost.Redis is included in Boost installations since Boost 1.84. +* C++17 or higher. Supported compilers include gcc 11 and later, clang 11 and later, and Visual Studio 16 (2019) and later. * Redis 6 or higher (must support RESP3). -* GCC (11, 12), Clang (11, 13, 14) and Visual Studio (16 2019, 17 2022). -* Have basic-level knowledge about [Redis](https://redis.io/docs/) - and [Boost.Asio](https://www.boost.org/doc/libs/1_82_0/doc/html/boost_asio/overview.html). +* OpenSSL. -To use the library it is necessary to include +The documentation assumes basic-level knowledge about [Redis](https://redis.io/docs/) and [Boost.Asio](https://www.boost.org/doc/libs/latest/doc/html/boost_asio.html). + +## Building the library + +To use the library it is necessary to include the following: ```cpp #include ``` -in no more than one source file in your applications. To build the -examples and tests with cmake run +in exactly one source file in your applications. Otherwise, the library is header-only. -```cpp -# Linux -$ BOOST_ROOT=/opt/boost_1_84_0 cmake -S -B +Boost.Redis unconditionally requires OpenSSL. Targets using Boost.Redis need to link +to the OpenSSL libraries. -# Windows -$ cmake -G "Visual Studio 17 2022" -A x64 -B bin64 -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake -``` - -For more details see https://github.com/boostorg/cmake. - - -## Connection +## Tutorial The code below uses a short-lived connection to -[ping](https://redis.io/commands/ping/) the Redis server +[ping](https://redis.io/commands/ping/) a Redis server: + ```cpp +#include +#include +#include +#include +#include + +namespace net = boost::asio; +using boost::redis::request; +using boost::redis::response; +using boost::redis::config; +using boost::redis::connection; + auto co_main(config const& cfg) -> net::awaitable { auto conn = std::make_shared(co_await net::this_coro::executor); @@ -59,28 +70,27 @@ auto co_main(config const& cfg) -> net::awaitable } ``` -The roles played by the `async_run` and `async_exec` functions are +The roles played by the `async_run` and `async_exec` functions are: -* `async_exec`: Execute the commands contained in the - request and store the individual responses in the `resp` object. Can +* `connection::async_exec`: executes the commands contained in the + request and stores the individual responses in the response object. Can be called from multiple places in your code concurrently. -* `async_run`: Resolve, connect, ssl-handshake, - resp3-handshake, health-checks, reconnection and coordinate low-level - read and write operations (among other things). +* `connection::async_run`: keeps the connection healthy. It takes care of hostname resolution, session establishment, health-checks, reconnection and coordination of low-level read and write operations. It should be called only once per connection, regardless of the number of requests to execute. -### Server pushes +## Server pushes -Redis servers can also send a variety of pushes to the client, some of -them are +Redis servers can also send a variety of pushes to the client. Some of +them are: -* [Pubsub](https://redis.io/docs/manual/pubsub/) -* [Keyspace notification](https://redis.io/docs/manual/keyspace-notifications/) -* [Client-side caching](https://redis.io/docs/manual/client-side-caching/) +* [Pubsub messages](https://redis.io/docs/manual/pubsub/). +* [Keyspace notifications](https://redis.io/docs/manual/keyspace-notifications/). +* [Client-side caching](https://redis.io/docs/manual/client-side-caching/). The connection class supports server pushes by means of the -`boost::redis::connection::async_receive` function, which can be +`connection::async_receive` function, which can be called in the same connection that is being used to execute commands. -The coroutine below shows how to used it +The coroutine below shows how to use it: + ```cpp auto @@ -112,984 +122,8 @@ receiver(std::shared_ptr conn) -> net::awaitable } } } - ``` - -## Requests - -Redis requests are composed of one or more commands (in the -Redis documentation they are called -[pipelines](https://redis.io/topics/pipelining)). For example - -```cpp -// Some example containers. -std::list list {...}; -std::map map { ...}; - -// The request can contain multiple commands. -request req; - -// Command with variable length of arguments. -req.push("SET", "key", "some value", "EX", "2"); - -// Pushes a list. -req.push_range("SUBSCRIBE", list); - -// Same as above but as an iterator range. -req.push_range("SUBSCRIBE", std::cbegin(list), std::cend(list)); - -// Pushes a map. -req.push_range("HSET", "key", map); -``` - -Sending a request to Redis is performed with `boost::redis::connection::async_exec` as already stated. The -`boost::redis::request::config` object inside the request dictates how -the `boost::redis::connection` the request is handled in some -situations. The reader is advised to read it carefully. - - -## Responses - -Boost.Redis uses the following strategy to deal with Redis responses - -* `boost::redis::request` used for requests whose number of commands are not dynamic. -* `boost::redis::generic_response` used when the size is dynamic. - -For example, the request below has three commands - -```cpp -request req; -req.push("PING"); -req.push("INCR", "key"); -req.push("QUIT"); -``` - -and therefore its response will also contain three elements which can -be read in the following reponse object - -```cpp -response -``` - -The response behaves as a tuple and must -have as many elements as the request has commands (exceptions below). -It is also necessary that each tuple element is capable of storing the -response to the command it refers to, otherwise an error will occur. -To ignore responses to individual commands in the request use the tag -`boost::redis::ignore_t`, for example - -```cpp -// Ignore the second and last responses. -response -``` - -The following table provides the resp3-types returned by some Redis -commands - -Command | RESP3 type | Documentation ----------|-------------------------------------|-------------- -lpush | Number | https://redis.io/commands/lpush -lrange | Array | https://redis.io/commands/lrange -set | Simple-string, null or blob-string | https://redis.io/commands/set -get | Blob-string | https://redis.io/commands/get -smembers | Set | https://redis.io/commands/smembers -hgetall | Map | https://redis.io/commands/hgetall - -To map these RESP3 types into a C++ data structure use the table below - -RESP3 type | Possible C++ type | Type ----------------|--------------------------------------------------------------|------------------ -Simple-string | `std::string` | Simple -Simple-error | `std::string` | Simple -Blob-string | `std::string`, `std::vector` | Simple -Blob-error | `std::string`, `std::vector` | Simple -Number | `long long`, `int`, `std::size_t`, `std::string` | Simple -Double | `double`, `std::string` | Simple -Null | `std::optional` | Simple -Array | `std::vector`, `std::list`, `std::array`, `std::deque` | Aggregate -Map | `std::vector`, `std::map`, `std::unordered_map` | Aggregate -Set | `std::vector`, `std::set`, `std::unordered_set` | Aggregate -Push | `std::vector`, `std::map`, `std::unordered_map` | Aggregate - -For example, the response to the request - -```cpp -request req; -req.push("HELLO", 3); -req.push_range("RPUSH", "key1", vec); -req.push_range("HSET", "key2", map); -req.push("LRANGE", "key3", 0, -1); -req.push("HGETALL", "key4"); -req.push("QUIT"); - -``` - -can be read in the response object below - -```cpp -response< - redis::ignore_t, // hello - int, // rpush - int, // hset - std::vector, // lrange - std::map, // hgetall - std::string // quit -> resp; -``` - -Then, to execute the request and read the response use `async_exec` as -shown below - -```cpp -co_await conn->async_exec(req, resp); -``` - -If the intention is to ignore responses altogether use `ignore` - -```cpp -// Ignores the response -co_await conn->async_exec(req, ignore); -``` - -Responses that contain nested aggregates or heterogeneous data -types will be given special treatment later in [The general case](#the-general-case). As -of this writing, not all RESP3 types are used by the Redis server, -which means in practice users will be concerned with a reduced -subset of the RESP3 specification. - -### Pushes - -Commands that have no response like - -* `"SUBSCRIBE"` -* `"PSUBSCRIBE"` -* `"UNSUBSCRIBE"` - -must **NOT** be included in the response tuple. For example, the request below - -```cpp -request req; -req.push("PING"); -req.push("SUBSCRIBE", "channel"); -req.push("QUIT"); -``` - -must be read in the response object `response`. - -### Null - -It is not uncommon for apps to access keys that do not exist or that -have already expired in the Redis server, to deal with these usecases -wrap the type with an `std::optional` as shown below - -```cpp -response< - std::optional, - std::optional, - ... - > resp; -``` - -Everything else stays the same. - -### Transactions - -To read responses to transactions we must first observe that Redis -will queue the transaction commands and send their individual -responses as elements of an array, the array is itself the response to -the `EXEC` command. For example, to read the response to this request - -```cpp -req.push("MULTI"); -req.push("GET", "key1"); -req.push("LRANGE", "key2", 0, -1); -req.push("HGETALL", "key3"); -req.push("EXEC"); -``` - -use the following response type - -```cpp -using boost::redis::ignore; - - -response< - ignore_t, // multi - ignore_t, // QUEUED - ignore_t, // QUEUED - ignore_t, // QUEUED - response< - std::optional, // get - std::optional>, // lrange - std::optional> // hgetall - > // exec -> resp; -``` - -For a complete example see cpp20_containers.cpp. - - - -### The general case - -There are cases where responses to Redis -commands won't fit in the model presented above, some examples are - -* Commands (like `set`) whose responses don't have a fixed - RESP3 type. Expecting an `int` and receiving a blob-string - results in an error. -* RESP3 aggregates that contain nested aggregates can't be read in STL containers. -* Transactions with a dynamic number of commands can't be read in a `response`. - -To deal with these cases Boost.Redis provides the `boost::redis::resp3::node` type -abstraction, that is the most general form of an element in a -response, be it a simple RESP3 type or the element of an aggregate. It -is defined like this - -```cpp -template -struct basic_node { - // The RESP3 type of the data in this node. - type data_type; - - // The number of elements of an aggregate (or 1 for simple data). - std::size_t aggregate_size; - - // The depth of this node in the response tree. - std::size_t depth; - - // The actual data. For aggregate types this is always empty. - String value; -}; -``` - -Any response to a Redis command can be received in a -`boost::redis::generic_response`. The vector can be seen as a -pre-order view of the response tree. Using it is not different than -using other types - -```cpp -// Receives any RESP3 simple or aggregate data type. -boost::redis::generic_response resp; -co_await conn->async_exec(req, resp); -``` - -For example, suppose we want to retrieve a hash data structure -from Redis with `HGETALL`, some of the options are - -* `boost::redis::generic_response`: Works always. -* `std::vector`: Efficient and flat, all elements as string. -* `std::map`: Efficient if you need the data as a `std::map`. -* `std::map`: Efficient if you are storing serialized data. Avoids temporaries and requires `boost_redis_from_bulk` for `U` and `V`. - -In addition to the above users can also use unordered versions of the -containers. The same reasoning applies to sets e.g. `SMEMBERS` -and other data structures in general. - - -## Serialization - -Boost.Redis supports serialization of user defined types by means of -the following customization points - -```cpp - -// Serialize. -void boost_redis_to_bulk(std::string& to, mystruct const& obj); - -// Deserialize -void boost_redis_from_bulk(mystruct& u, node_view const& node, boost::system::error_code&) -``` - -These functions are accessed over ADL and therefore they must be -imported in the global namespace by the user. In the -[Examples](#examples) section the reader can find examples showing how -to serialize using json and [protobuf](https://protobuf.dev/). - - - -### Logging - -`connection::async_run` is a complex algorithm, with features like built-in reconnection. -This can make configuration problems, like a misconfigured hostname, difficult to debug - -Boost.Redis will keep retrying to connect to the same hostname over and over. -For this reason, Boost.Redis incorporates a lightweight logging solution, and -**will log some status messages to stderr by default**. - -Logging can be customized by passing a `logger` object to the `connection`'s constructor. - -For example, logging can be disabled by writing: - -```cpp -asio::io_context ioc; -redis::connection conn {ioc, redis::logger{redis::logger::level::disabled}}; -``` - -Every message logged by the library is attached a -[syslog-like severity](https://en.wikipedia.org/wiki/Syslog#Severity_level) -tag (a `logger::level`). -You can filter messages by severity by creating a `logger` with a specific level: - -```cpp -asio::io_context ioc; - -// Logs to stderr messages with severity >= level::error. -// This will hide all informational output. -redis::connection conn {ioc, redis::logger{redis::logger::level::error}}; -``` - -`logger`'s constructor accepts a `std::function` -as second argument. If supplied, Boost.Redis will call this function when logging -instead of printing to stderr. This can be used to integrate third-party logging -libraries. See our [spdlog integration example](example/cpp17_spdlog.cpp) for sample code. - - - -## Examples - -The examples below show how to use the features discussed so far - -* cpp20_intro.cpp: Does not use awaitable operators. -* cpp20_intro_tls.cpp: Communicates over TLS. -* cpp20_unix_sockets.cpp: Communicates over UNIX domain sockets. -* cpp20_containers.cpp: Shows how to send and receive STL containers and how to use transactions. -* cpp20_json.cpp: Shows how to serialize types using Boost.Json. -* cpp20_protobuf.cpp: Shows how to serialize types using protobuf. -* cpp20_resolve_with_sentinel.cpp: Shows how to resolve a master address using sentinels. -* cpp20_subscriber.cpp: Shows how to implement pubsub with reconnection re-subscription. -* cpp20_echo_server.cpp: A simple TCP echo server. -* cpp20_chat_room.cpp: A command line chat built on Redis pubsub. -* cpp17_intro.cpp: Uses callbacks and requires C++17. -* cpp17_intro_sync.cpp: Runs `async_run` in a separate thread and performs synchronous calls to `async_exec`. -* cpp17_spdlog.cpp: Shows how to use third-party logging libraries like `spdlog` with Boost.Redis. - -The main function used in some async examples has been factored out in -the main.cpp file. - -## Echo server benchmark - -This document benchmarks the performance of TCP echo servers I -implemented in different languages using different Redis clients. The -main motivations for choosing an echo server are - - * Simple to implement and does not require expertise level in most languages. - * I/O bound: Echo servers have very low CPU consumption in general - and therefore are excellent to measure how a program handles concurrent requests. - * It simulates very well a typical backend in regard to concurrency. - -I also imposed some constraints on the implementations - - * It should be simple enough and not require writing too much code. - * Favor the use standard idioms and avoid optimizations that require expert level. - * Avoid the use of complex things like connection and thread pool. - -To reproduce these results run one of the echo-server programs in one -terminal and the -[echo-server-client](https://github.com/boostorg/redis/blob/42880e788bec6020dd018194075a211ad9f339e8/benchmarks/cpp/asio/echo_server_client.cpp) -in another. - -### Without Redis - -First I tested a pure TCP echo server, i.e. one that sends the messages -directly to the client without interacting with Redis. The result can -be seen below - -![](https://boostorg.github.io/redis/tcp-echo-direct.png) - -The tests were performed with a 1000 concurrent TCP connections on the -localhost where latency is 0.07ms on average on my machine. On higher -latency networks the difference among libraries is expected to -decrease. - - * I expected Libuv to have similar performance to Asio and Tokio. - * I did expect nodejs to come a little behind given it is is - javascript code. Otherwise I did expect it to have similar - performance to libuv since it is the framework behind it. - * Go did surprise me: faster than nodejs and libuv! - -The code used in the benchmarks can be found at - - * [Asio](https://github.com/boostorg/redis/blob/3fb018ccc6138d310ac8b73540391cdd8f2fdad6/benchmarks/cpp/asio/echo_server_direct.cpp): A variation of [this](https://github.com/chriskohlhoff/asio/blob/4915cfd8a1653c157a1480162ae5601318553eb8/asio/src/examples/cpp20/coroutines/echo_server.cpp) Asio example. - * [Libuv](https://github.com/boostorg/redis/tree/835a1decf477b09317f391eddd0727213cdbe12b/benchmarks/c/libuv): Taken from [here](https://github.com/libuv/libuv/blob/06948c6ee502862524f233af4e2c3e4ca876f5f6/docs/code/tcp-echo-server/main.c) Libuv example . - * [Tokio](https://github.com/boostorg/redis/tree/3fb018ccc6138d310ac8b73540391cdd8f2fdad6/benchmarks/rust/echo_server_direct): Taken from [here](https://docs.rs/tokio/latest/tokio/). - * [Nodejs](https://github.com/boostorg/redis/tree/3fb018ccc6138d310ac8b73540391cdd8f2fdad6/benchmarks/nodejs/echo_server_direct) - * [Go](https://github.com/boostorg/redis/blob/3fb018ccc6138d310ac8b73540391cdd8f2fdad6/benchmarks/go/echo_server_direct.go) - -### With Redis - -This is similar to the echo server described above but messages are -echoed by Redis and not by the echo-server itself, which acts -as a proxy between the client and the Redis server. The results -can be seen below - -![](https://boostorg.github.io/redis/tcp-echo-over-redis.png) - -The tests were performed on a network where latency is 35ms on -average, otherwise it uses the same number of TCP connections -as the previous example. - -As the reader can see, the Libuv and the Rust test are not depicted -in the graph, the reasons are - - * [redis-rs](https://github.com/redis-rs/redis-rs): This client - comes so far behind that it can't even be represented together - with the other benchmarks without making them look insignificant. - I don't know for sure why it is so slow, I suppose it has - something to do with its lack of automatic - [pipelining](https://redis.io/docs/manual/pipelining/) support. - In fact, the more TCP connections I launch the worse its - performance gets. - - * Libuv: I left it out because it would require me writing to much - c code. More specifically, I would have to use hiredis and - implement support for pipelines manually. - -The code used in the benchmarks can be found at - - * [Boost.Redis](https://github.com/boostorg/redis): [code](https://github.com/boostorg/redis/blob/3fb018ccc6138d310ac8b73540391cdd8f2fdad6/examples/echo_server.cpp) - * [node-redis](https://github.com/redis/node-redis): [code](https://github.com/boostorg/redis/tree/3fb018ccc6138d310ac8b73540391cdd8f2fdad6/benchmarks/nodejs/echo_server_over_redis) - * [go-redis](https://github.com/go-redis/redis): [code](https://github.com/boostorg/redis/blob/3fb018ccc6138d310ac8b73540391cdd8f2fdad6/benchmarks/go/echo_server_over_redis.go) - -### Conclusion - -Redis clients have to support automatic pipelining to have competitive performance. For updates to this document follow https://github.com/boostorg/redis. - -## Comparison - -The main reason for why I started writing Boost.Redis was to have a client -compatible with the Asio asynchronous model. As I made progresses I could -also address what I considered weaknesses in other libraries. Due to -time constraints I won't be able to give a detailed comparison with -each client listed in the -[official](https://redis.io/docs/clients/#cpp) list, -instead I will focus on the most popular C++ client on github in number of -stars, namely - -* https://github.com/sewenew/redis-plus-plus - -### Boost.Redis vs Redis-plus-plus - -Before we start it is important to mention some of the things -redis-plus-plus does not support - -* The latest version of the communication protocol RESP3. Without that it is impossible to support some important Redis features like client side caching, among other things. -* Coroutines. -* Reading responses directly in user data structures to avoid creating temporaries. -* Error handling with support for error-code. -* Cancellation. - -The remaining points will be addressed individually. Let us first -have a look at what sending a command a pipeline and a transaction -look like - -```cpp -auto redis = Redis("tcp://127.0.0.1:6379"); - -// Send commands -redis.set("key", "val"); -auto val = redis.get("key"); // val is of type OptionalString. -if (val) - std::cout << *val << std::endl; - -// Sending pipelines -auto pipe = redis.pipeline(); -auto pipe_replies = pipe.set("key", "value") - .get("key") - .rename("key", "new-key") - .rpush("list", {"a", "b", "c"}) - .lrange("list", 0, -1) - .exec(); - -// Parse reply with reply type and index. -auto set_cmd_result = pipe_replies.get(0); -// ... - -// Sending a transaction -auto tx = redis.transaction(); -auto tx_replies = tx.incr("num0") - .incr("num1") - .mget({"num0", "num1"}) - .exec(); - -auto incr_result0 = tx_replies.get(0); -// ... -``` - -Some of the problems with this API are - -* Heterogeneous treatment of commands, pipelines and transaction. This makes auto-pipelining impossible. -* Any Api that sends individual commands has a very restricted scope of usability and should be avoided for performance reasons. -* The API imposes exceptions on users, no error-code overload is provided. -* No way to reuse the buffer for new calls to e.g. redis.get in order to avoid further dynamic memory allocations. -* Error handling of resolve and connection not clear. - -According to the documentation, pipelines in redis-plus-plus have -the following characteristics - -> NOTE: By default, creating a Pipeline object is NOT cheap, since -> it creates a new connection. - -This is clearly a downside in the API as pipelines should be the -default way of communicating and not an exception, paying such a -high price for each pipeline imposes a severe cost in performance. -Transactions also suffer from the very same problem. - -> NOTE: Creating a Transaction object is NOT cheap, since it -> creates a new connection. - -In Boost.Redis there is no difference between sending one command, a -pipeline or a transaction because requests are decoupled -from the IO objects. - -> redis-plus-plus also supports async interface, however, async -> support for Transaction and Subscriber is still on the way. -> -> The async interface depends on third-party event library, and so -> far, only libuv is supported. - -Async code in redis-plus-plus looks like the following - -```cpp -auto async_redis = AsyncRedis(opts, pool_opts); - -Future ping_res = async_redis.ping(); - -cout << ping_res.get() << endl; -``` -As the reader can see, the async interface is based on futures -which is also known to have a bad performance. The biggest -problem however with this async design is that it makes it -impossible to write asynchronous programs correctly since it -starts an async operation on every command sent instead of -enqueueing a message and triggering a write when it can be sent. -It is also not clear how are pipelines realised with this design -(if at all). - - -## Reference - -The [High-Level](#high-level-api) page documents all public types. - -## Acknowledgement - -Acknowledgement to people that helped shape Boost.Redis - -* Richard Hodges ([madmongo1](https://github.com/madmongo1)): For very helpful support with Asio, the design of asynchronous programs, etc. -* Vinícius dos Santos Oliveira ([vinipsmaker](https://github.com/vinipsmaker)): For useful discussion about how Boost.Redis consumes buffers in the read operation. -* Petr Dannhofer ([Eddie-cz](https://github.com/Eddie-cz)): For helping me understand how the `AUTH` and `HELLO` command can influence each other. -* Mohammad Nejati ([ashtum](https://github.com/ashtum)): For pointing out scenarios where calls to `async_exec` should fail when the connection is lost. -* Klemens Morgenstern ([klemens-morgenstern](https://github.com/klemens-morgenstern)): For useful discussion about timeouts, cancellation, synchronous interfaces and general help with Asio. -* Vinnie Falco ([vinniefalco](https://github.com/vinniefalco)): For general suggestions about how to improve the code and the documentation. -* Bram Veldhoen ([bveldhoen](https://github.com/bveldhoen)): For contributing a Redis-streams example. - -Also many thanks to all individuals that participated in the Boost -review - -* Zach Laine: https://lists.boost.org/Archives/boost/2023/01/253883.php -* Vinnie Falco: https://lists.boost.org/Archives/boost/2023/01/253886.php -* Christian Mazakas: https://lists.boost.org/Archives/boost/2023/01/253900.php -* Ruben Perez: https://lists.boost.org/Archives/boost/2023/01/253915.php -* Dmitry Arkhipov: https://lists.boost.org/Archives/boost/2023/01/253925.php -* Alan de Freitas: https://lists.boost.org/Archives/boost/2023/01/253927.php -* Mohammad Nejati: https://lists.boost.org/Archives/boost/2023/01/253929.php -* Sam Hartsfield: https://lists.boost.org/Archives/boost/2023/01/253931.php -* Miguel Portilla: https://lists.boost.org/Archives/boost/2023/01/253935.php -* Robert A.H. Leahy: https://lists.boost.org/Archives/boost/2023/01/253928.php - -The Reviews can be found at: -https://lists.boost.org/Archives/boost/2023/01/date.php. The thread -with the ACCEPT from the review manager can be found here: -https://lists.boost.org/Archives/boost/2023/01/253944.php. - -## Changelog - -### Boost 1.88 - -* (Issue [233](https://github.com/boostorg/redis/issues/233)) - To deal with keys that might not exits in the Redis server, the - library supports `std::optional`, for example - `response>>`. In some cases - however, such as the [MGET](https://redis.io/docs/latest/commands/mget/) command, - each element in the vector might be non exiting, now it is possible - to specify a response as `response>>>`. - -* (Issue [225](https://github.com/boostorg/redis/issues/225)) - Use `deferred` as the connection default completion token. - -* (Issue [128](https://github.com/boostorg/redis/issues/128)) - Adds a new `async_exec` overload that allows passing response - adapters. This makes it possible to receive Redis responses directly - in custom data structures thereby avoiding uncessary data copying. - Thanks to Ruben Perez (@anarthal) for implementing this feature. - -* There are also other multiple small improvements in this release, - users can refer to the git history for more details. - -### Boost 1.87 - -* (Issue [205](https://github.com/boostorg/redis/issues/205)) - Improves reaction time to disconnection by using `wait_for_one_error` - instead of `wait_for_all`. The function `connection::async_run` was - also changed to return EOF to the user when that error is received - from the server. That is a breaking change. - -* (Issue [210](https://github.com/boostorg/redis/issues/210)) - Fixes the adapter of empty nested reposponses. - -* (Issues [211](https://github.com/boostorg/redis/issues/211) and [212](https://github.com/boostorg/redis/issues/212)) - Fixes the reconnect loop that would hang under certain conditions, - see the linked issues for more details. - -* (Issue [219](https://github.com/boostorg/redis/issues/219)) - Changes the default log level from `disabled` to `debug`. - -### Boost 1.85 - -* (Issue [170](https://github.com/boostorg/redis/issues/170)) - Under load and on low-latency networks it is possible to start - receiving responses before the write operation completed and while - the request is still marked as staged and not written. This messes - up with the heuristics that classifies responses as unsolicied or - not. - -* (Issue [168](https://github.com/boostorg/redis/issues/168)). - Provides a way of passing a custom SSL context to the connection. - The design here differs from that of Boost.Beast and Boost.MySql - since in Boost.Redis the connection owns the context instead of only - storing a reference to a user provided one. This is ok so because - apps need only one connection for their entire application, which - makes the overhead of one ssl-context per connection negligible. - -* (Issue [181](https://github.com/boostorg/redis/issues/181)). - See a detailed description of this bug in - [this](https://github.com/boostorg/redis/issues/181#issuecomment-1913346983) - comment. - -* (Issue [182](https://github.com/boostorg/redis/issues/182)). - Sets `"default"` as the default value of `config::username`. This - makes it simpler to use the `requirepass` configuration in Redis. - -* (Issue [189](https://github.com/boostorg/redis/issues/189)). - Fixes narrowing conversion by using `std::size_t` instead of - `std::uint64_t` for the sizes of bulks and aggregates. The code - relies now on `std::from_chars` returning an error if a value - greater than 32 is received on platforms on which the size - of `std::size_t` is 32. - - -### Boost 1.84 (First release in Boost) - -* Deprecates the `async_receive` overload that takes a response. Users - should now first call `set_receive_response` to avoid constantly and - unnecessarily setting the same response. - -* Uses `std::function` to type erase the response adapter. This change - should not influence users in any way but allowed important - simplification in the connections internals. This resulted in - massive performance improvement. - -* The connection has a new member `get_usage()` that returns the - connection usage information, such as number of bytes written, - received etc. - -* There are massive performance improvements in the consuming of - server pushes which are now communicated with an `asio::channel` and - therefore can be buffered which avoids blocking the socket read-loop. - Batch reads are also supported by means of `channel.try_send` and - buffered messages can be consumed synchronously with - `connection::receive`. The function `boost::redis::cancel_one` has - been added to simplify processing multiple server pushes contained - in the same `generic_response`. *IMPORTANT*: These changes may - result in more than one push in the response when - `connection::async_receive` resumes. The user must therefore be - careful when calling `resp.clear()`: either ensure that all message - have been processed or just use `consume_one`. - -### v1.4.2 (incorporates changes to conform the boost review and more) - -* Adds `boost::redis::config::database_index` to make it possible to - choose a database before starting running commands e.g. after an - automatic reconnection. - -* Massive performance improvement. One of my tests went from - 140k req/s to 390k/s. This was possible after a parser - simplification that reduced the number of reschedules and buffer - rotations. - -* Adds Redis stream example. - -* Renames the project to Boost.Redis and moves the code into namespace - `boost::redis`. - -* As pointed out in the reviews the `to_bulk` and `from_bulk` names were too - generic for ADL customization points. They gained the prefix `boost_redis_`. - -* Moves `boost::redis::resp3::request` to `boost::redis::request`. - -* Adds new typedef `boost::redis::response` that should be used instead of - `std::tuple`. - -* Adds new typedef `boost::redis::generic_response` that should be used instead - of `std::vector>`. - -* Renames `redis::ignore` to `redis::ignore_t`. - -* Changes `async_exec` to receive a `redis::response` instead of an adapter, - namely, instead of passing `adapt(resp)` users should pass `resp` directly. - -* Introduces `boost::redis::adapter::result` to store responses to commands - including possible resp3 errors without losing the error diagnostic part. To - access values now use `std::get(resp).value()` instead of - `std::get(resp)`. - -* Implements full-duplex communication. Before these changes the connection - would wait for a response to arrive before sending the next one. Now requests - are continuously coalesced and written to the socket. `request::coalesce` - became unnecessary and was removed. I could measure significative performance - gains with these changes. - -* Improves serialization examples using Boost.Describe to serialize to JSON and protobuf. See - cpp20_json.cpp and cpp20_protobuf.cpp for more details. - -* Upgrades to Boost 1.81.0. - -* Fixes build with libc++. - -* Adds high-level functionality to the connection classes. For - example, `boost::redis::connection::async_run` will automatically - resolve, connect, reconnect and perform health checks. - -### v1.4.0-1 - -* Renames `retry_on_connection_lost` to `cancel_if_unresponded`. (v1.4.1) -* Removes dependency on Boost.Hana, `boost::string_view`, Boost.Variant2 and Boost.Spirit. -* Fixes build and setup CI on windows. - -### v1.3.0-1 - -* Upgrades to Boost 1.80.0 - -* Removes automatic sending of the `HELLO` command. This can't be - implemented properly without bloating the connection class. It is - now a user responsibility to send HELLO. Requests that contain it have - priority over other requests and will be moved to the front of the - queue, see `aedis::request::config` - -* Automatic name resolving and connecting have been removed from - `aedis::connection::async_run`. Users have to do this step manually - now. The reason for this change is that having them built-in doesn't - offer enough flexibility that is need for boost users. - -* Removes healthy checks and idle timeout. This functionality must now - be implemented by users, see the examples. This is - part of making Aedis useful to a larger audience and suitable for - the Boost review process. - -* The `aedis::connection` is now using a typeddef to a - `net::ip::tcp::socket` and `aedis::ssl::connection` to - `net::ssl::stream`. Users that need to use - other stream type must now specialize `aedis::basic_connection`. - -* Adds a low level example of async code. - -### v1.2.0 - -* `aedis::adapt` supports now tuples created with `std::tie`. - `aedis::ignore` is now an alias to the type of `std::ignore`. - -* Provides allocator support for the internal queue used in the - `aedis::connection` class. - -* Changes the behaviour of `async_run` to complete with success if - asio::error::eof is received. This makes it easier to write - composed operations with awaitable operators. - -* Adds allocator support in the `aedis::request` (a - contribution from Klemens Morgenstern). - -* Renames `aedis::request::push_range2` to `push_range`. The - suffix 2 was used for disambiguation. Klemens fixed it with SFINAE. - -* Renames `fail_on_connection_lost` to - `aedis::request::config::cancel_on_connection_lost`. Now, it will - only cause connections to be canceled when `async_run` completes. - -* Introduces `aedis::request::config::cancel_if_not_connected` which will - cause a request to be canceled if `async_exec` is called before a - connection has been established. - -* Introduces new request flag `aedis::request::config::retry` that if - set to true will cause the request to not be canceled when it was - sent to Redis but remained unresponded after `async_run` completed. - It provides a way to avoid executing commands twice. - -* Removes the `aedis::connection::async_run` overload that takes - request and adapter as parameters. - -* Changes the way `aedis::adapt()` behaves with - `std::vector>`. Receiving RESP3 simple errors, - blob errors or null won't causes an error but will be treated as - normal response. It is the user responsibility to check the content - in the vector. - -* Fixes a bug in `connection::cancel(operation::exec)`. Now this - call will only cancel non-written requests. - -* Implements per-operation implicit cancellation support for - `aedis::connection::async_exec`. The following call will `co_await (conn.async_exec(...) || timer.async_wait(...))` - will cancel the request as long as it has not been written. - -* Changes `aedis::connection::async_run` completion signature to - `f(error_code)`. This is how is was in the past, the second - parameter was not helpful. - -* Renames `operation::receive_push` to `aedis::operation::receive`. - -### v1.1.0-1 - -* Removes `coalesce_requests` from the `aedis::connection::config`, it - became a request property now, see `aedis::request::config::coalesce`. - -* Removes `max_read_size` from the `aedis::connection::config`. The maximum - read size can be specified now as a parameter of the - `aedis::adapt()` function. - -* Removes `aedis::sync` class, see intro_sync.cpp for how to perform - synchronous and thread safe calls. This is possible in Boost. 1.80 - only as it requires `boost::asio::deferred`. - -* Moves from `boost::optional` to `std::optional`. This is part of - moving to C++17. - -* Changes the behaviour of the second `aedis::connection::async_run` overload - so that it always returns an error when the connection is lost. - -* Adds TLS support, see intro_tls.cpp. - -* Adds an example that shows how to resolve addresses over sentinels, - see subscriber_sentinel.cpp. - -* Adds a `aedis::connection::timeouts::resp3_handshake_timeout`. This is - timeout used to send the `HELLO` command. - -* Adds `aedis::endpoint` where in addition to host and port, users can - optionally provide username, password and the expected server role - (see `aedis::error::unexpected_server_role`). - -* `aedis::connection::async_run` checks whether the server role received in - the hello command is equal to the expected server role specified in - `aedis::endpoint`. To skip this check let the role variable empty. - -* Removes reconnect functionality from `aedis::connection`. It - is possible in simple reconnection strategies but bloats the class - in more complex scenarios, for example, with sentinel, - authentication and TLS. This is trivial to implement in a separate - coroutine. As a result the `enum event` and `async_receive_event` - have been removed from the class too. - -* Fixes a bug in `connection::async_receive_push` that prevented - passing any response adapter other that `adapt(std::vector)`. - -* Changes the behaviour of `aedis::adapt()` that caused RESP3 errors - to be ignored. One consequence of it is that `connection::async_run` - would not exit with failure in servers that required authentication. - -* Changes the behaviour of `connection::async_run` that would cause it - to complete with success when an error in the - `connection::async_exec` occurred. - -* Ports the buildsystem from autotools to CMake. - -### v1.0.0 - -* Adds experimental cmake support for windows users. - -* Adds new class `aedis::sync` that wraps an `aedis::connection` in - a thread-safe and synchronous API. All free functions from the - `sync.hpp` are now member functions of `aedis::sync`. - -* Split `aedis::connection::async_receive_event` in two functions, one - to receive events and another for server side pushes, see - `aedis::connection::async_receive_push`. - -* Removes collision between `aedis::adapter::adapt` and - `aedis::adapt`. - -* Adds `connection::operation` enum to replace `cancel_*` member - functions with a single cancel function that gets the operations - that should be cancelled as argument. - -* Bugfix: a bug on reconnect from a state where the `connection` object - had unsent commands. It could cause `async_exec` to never - complete under certain conditions. - -* Bugfix: Documentation of `adapt()` functions were missing from - Doxygen. - -### v0.3.0 - -* Adds `experimental::exec` and `receive_event` functions to offer a - thread safe and synchronous way of executing requests across - threads. See `intro_sync.cpp` and `subscriber_sync.cpp` for - examples. - -* `connection::async_read_push` was renamed to `async_receive_event`. - -* `connection::async_receive_event` is now being used to communicate - internal events to the user, such as resolve, connect, push etc. For - examples see cpp20_subscriber.cpp and `connection::event`. - -* The `aedis` directory has been moved to `include` to look more - similar to Boost libraries. Users should now replace `-I/aedis-path` - with `-I/aedis-path/include` in the compiler flags. - -* The `AUTH` and `HELLO` commands are now sent automatically. This change was - necessary to implement reconnection. The username and password - used in `AUTH` should be provided by the user on - `connection::config`. - -* Adds support for reconnection. See `connection::enable_reconnect`. - -* Fixes a bug in the `connection::async_run(host, port)` overload - that was causing crashes on reconnection. - -* Fixes the executor usage in the connection class. Before these - changes it was imposing `any_io_executor` on users. - -* `connection::async_receiver_event` is not cancelled anymore when - `connection::async_run` exits. This change makes user code simpler. - -* `connection::async_exec` with host and port overload has been - removed. Use the other `connection::async_run` overload. - -* The host and port parameters from `connection::async_run` have been - move to `connection::config` to better support authentication and - failover. - -* Many simplifications in the `chat_room` example. - -* Fixes build in clang the compilers and makes some improvements in - the documentation. - -### v0.2.0-1 - -* Fixes a bug that happens on very high load. (v0.2.1) -* Major rewrite of the high-level API. There is no more need to use the low-level API anymore. -* No more callbacks: Sending requests follows the ASIO asynchronous model. -* Support for reconnection: Pending requests are not canceled when a connection is lost and are re-sent when a new one is established. -* The library is not sending HELLO-3 on user behalf anymore. This is important to support AUTH properly. - -### v0.1.0-2 - -* Adds reconnect coroutine in the `echo_server` example. (v0.1.2) -* Corrects `client::async_wait_for_data` with `make_parallel_group` to launch operation. (v0.1.2) -* Improvements in the documentation. (v0.1.2) -* Avoids dynamic memory allocation in the client class after reconnection. (v0.1.2) -* Improves the documentation and adds some features to the high-level client. (v.0.1.1) -* Improvements in the design and documentation. - -### v0.0.1 - -* First release to collect design feedback. +## Further reading +Full documentation is [here](https://www.boost.org/doc/libs/master/libs/redis/index.html). \ No newline at end of file diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt new file mode 100644 index 00000000..00388cb7 --- /dev/null +++ b/doc/CMakeLists.txt @@ -0,0 +1,26 @@ +# +# Copyright (c) 2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +# Root CMakeLists.txt so MrDocs knows how to build our code +cmake_minimum_required(VERSION 3.8...3.22) + +# Project +project(boost_redis_mrdocs LANGUAGES CXX) + +# MrDocs forces CMAKE_EXPORT_COMPILE_COMMANDS=ON, incorrectly +# causing all targets to be dumped to the compilation database. +# Disable this setting so we can set EXPORT_COMPILE_COMMANDS +# only to our target of interest +set(CMAKE_EXPORT_COMPILE_COMMANDS OFF) + +# Add Boost +add_subdirectory($ENV{BOOST_SRC_DIR} deps/boost) + +# Add the target for mrdocs to analyze +add_executable(mrdocs mrdocs.cpp) +target_link_libraries(mrdocs PRIVATE Boost::redis) +set_target_properties(mrdocs PROPERTIES EXPORT_COMPILE_COMMANDS ON) diff --git a/doc/DoxygenLayout.xml b/doc/DoxygenLayout.xml deleted file mode 100644 index cb1ee265..00000000 --- a/doc/DoxygenLayout.xml +++ /dev/null @@ -1,226 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/doc/Jamfile b/doc/Jamfile index 81212ec0..fe83de40 100644 --- a/doc/Jamfile +++ b/doc/Jamfile @@ -1,85 +1,17 @@ -project redis/doc ; +# +# Copyright (c) 2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# -import doxygen ; -import path ; -import sequence ; +# Adapted from Boost.Unordered +make html/index.html : build_antora.sh : @run-script ; -# All paths must be absolute to work well with the Doxygen rules. -path-constant this_dir : . ; -path-constant target_dir : html ; -path-constant redis_root_dir : .. ; -path-constant include_dir : ../include ; -path-constant examples_dir : ../example ; -path-constant readme : ../README.md ; -path-constant layout_file : DoxygenLayout.xml ; -path-constant header : header.html ; -path-constant footer : footer.html ; - -local stylesheet_files = [ path.glob $(this_dir) : *.css ] ; -local includes = [ path.glob-tree $(include_dir) : *.hpp *.cpp ] ; -local examples = [ path.glob-tree $(examples_dir) : *.hpp *.cpp ] ; - -# If passed directly, several HTML_EXTRA_STYLESHEET tags are generated, -# which is not correct. -local stylesheet_arg = [ sequence.join "\"$(stylesheet_files)\"" : " " ] ; - -# The doxygen rule requires the target name to end in .html to generate HTML files -doxygen doc.html - : - $(includes) $(examples) $(readme) - : - "PROJECT_NAME=Boost.Redis" - PROJECT_NUMBER="1.84.0" - PROJECT_BRIEF="A redis client library" - "STRIP_FROM_PATH=\"$(redis_root_dir)\"" - "STRIP_FROM_INC_PATH=\"$(include_dir)\"" - BUILTIN_STL_SUPPORT=YES - INLINE_SIMPLE_STRUCTS=YES - HIDE_UNDOC_MEMBERS=YES - HIDE_UNDOC_CLASSES=YES - SHOW_HEADERFILE=YES - SORT_BRIEF_DOCS=YES - SORT_MEMBERS_CTORS_1ST=YES - SHOW_FILES=NO - SHOW_NAMESPACES=NO - "LAYOUT_FILE=\"$(layout_file)\"" - WARN_IF_INCOMPLETE_DOC=YES - FILE_PATTERNS="*.hpp *.cpp" - EXCLUDE_SYMBOLS=std - "USE_MDFILE_AS_MAINPAGE=\"$(readme)\"" - SOURCE_BROWSER=YES - "HTML_HEADER=\"$(header)\"" - "HTML_FOOTER=\"$(footer)\"" - "HTML_EXTRA_STYLESHEET=$(stylesheet_arg)" - HTML_TIMESTAMP=YES - GENERATE_TREEVIEW=YES - FULL_SIDEBAR=YES - DISABLE_INDEX=YES - ENUM_VALUES_PER_LINE=0 - OBFUSCATE_EMAILS=YES - USE_MATHJAX=YES - MATHJAX_VERSION=MathJax_2 - MATHJAX_RELPATH="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/" - MACRO_EXPANSION=YES - HAVE_DOT=NO - CLASS_GRAPH=NO - DIRECTORY_GRAPH=NO - ; - -explicit doc.html ; - -# The doxygen rule only informs b2 about the main HTML file, and not about -# all the doc directory that gets generated. Using the install rule copies -# only a single file, which is incorrect. This is a workaround to copy -# the generated docs to the doc/html directory, where they should be. -make copyhtml.tag : doc.html : @copy_html_dir ; -explicit copyhtml.tag ; -actions copy_html_dir +# Runs the Antora script +actions run-script { - rm -rf $(target_dir) - mkdir -p $(target_dir) - cp -r $(<:D)/html/doc/* $(target_dir)/ - echo "Stamped" > "$(<)" + bash -x $(>) } # These are used to inform the build system of the @@ -88,5 +20,5 @@ actions copy_html_dir alias boostdoc ; explicit boostdoc ; -alias boostrelease : copyhtml.tag ; +alias boostrelease : html/index.html ; explicit boostrelease ; diff --git a/doc/antora.yml b/doc/antora.yml new file mode 100644 index 00000000..07c5d0b9 --- /dev/null +++ b/doc/antora.yml @@ -0,0 +1,15 @@ +# +# Copyright (c) 2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +name: redis +title: Boost.Redis +version: ~ +nav: + - modules/ROOT/nav.adoc +ext: + cpp-reference: + config: doc/mrdocs.yml diff --git a/doc/build_antora.sh b/doc/build_antora.sh new file mode 100755 index 00000000..91646fa7 --- /dev/null +++ b/doc/build_antora.sh @@ -0,0 +1,19 @@ +#!/bin/bash +# +# Copyright (c) 2025 Ruben Perez Hidalgo (rubenperez038 at gmail dot com) +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# + +set -e + +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +cd "$SCRIPT_DIR" + +# Required by our CMake. +# Prevents Antora from cloning Boost again +export BOOST_SRC_DIR=$(realpath $SCRIPT_DIR/../../..) + +npm ci +npx antora --log-format=pretty redis-playbook.yml diff --git a/doc/doxygen-awesome-sidebar-only.css b/doc/doxygen-awesome-sidebar-only.css deleted file mode 100644 index edc5c762..00000000 --- a/doc/doxygen-awesome-sidebar-only.css +++ /dev/null @@ -1,145 +0,0 @@ -/** - -Doxygen Awesome -https://github.com/jothepro/doxygen-awesome-css - -MIT License - -Copyright (c) 2021 jothepro - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - - */ - -html { - /* side nav width. MUST be = `TREEVIEW_WIDTH`. - * Make sure it is wide enough to contain the page title (logo + title + version) - */ - --side-nav-fixed-width: 335px; -} - -#projectname { - white-space: nowrap; -} - -#page-wrapper { - height: calc(100vh - 100px); - display: flex; - flex-direction: column; -} - -#content-wrapper { - display: flex; - flex-direction: row; - min-height: 0; -} - -#doc-content { - overflow-y: scroll; - flex: 1; - height: auto !important; -} - -@media (min-width: 768px) { - html { - --searchbar-background: var(--page-background-color); - } - - #sidebar-wrapper { - display: flex; - flex-direction: column; - min-width: var(--side-nav-fixed-width); - max-width: var(--side-nav-fixed-width); - background-color: var(--side-nav-background); - border-right: 1px solid rgb(222, 222, 222); - } - - #search-box-wrapper { - display: flex; - flex-direction: row; - padding-left: 1em; - padding-right: 1em; - } - - #MSearchBox { - flex: 1; - display: flex; - padding-left: 1em; - padding-right: 1em; - } - - - #MSearchBox .left { - display: flex; - flex: 1; - position: static; - align-items: center; - justify-content: flex-start; - width: auto; - height: auto; - } - - #MSearchBox .right { - display: none; - } - - #MSearchSelect { - padding-left: 0.75em; - left: auto; - background-repeat: no-repeat; - } - - #MSearchField { - flex: 1; - position: static; - width: auto; - height: auto; - } - - #nav-tree { - height: auto !important; - } - - #nav-sync { - display: none; - } - - #top { - display: block; - border-bottom: none; - max-width: var(--side-nav-fixed-width); - background: var(--side-nav-background); - } - - .ui-resizable-handle { - cursor: default; - width: 1px !important; - } - - #MSearchResultsWindow { - left: var(--spacing-medium) !important; - right: auto; - } -} - -@media (max-width: 768px) { - #sidebar-wrapper { - display: none; - } -} diff --git a/doc/doxygen-awesome.css b/doc/doxygen-awesome.css deleted file mode 100644 index 1a51ca84..00000000 --- a/doc/doxygen-awesome.css +++ /dev/null @@ -1,2384 +0,0 @@ -/** - -Doxygen Awesome -https://github.com/jothepro/doxygen-awesome-css - -MIT License - -Copyright (c) 2021 - 2022 jothepro - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -*/ - -html { - /* primary theme color. This will affect the entire websites color scheme: links, arrows, labels, ... */ - --primary-color: #1779c4; - --primary-dark-color: #335c80; - --primary-light-color: #70b1e9; - - /* page base colors */ - --page-background-color: #ffffff; - --page-foreground-color: #2f4153; - --page-secondary-foreground-color: #6f7e8e; - - /* color for all separators on the website: hr, borders, ... */ - --separator-color: #dedede; - - /* border radius for all rounded components. Will affect many components, like dropdowns, memitems, codeblocks, ... */ - --border-radius-large: 8px; - --border-radius-small: 4px; - --border-radius-medium: 6px; - - /* default spacings. Most components reference these values for spacing, to provide uniform spacing on the page. */ - --spacing-small: 5px; - --spacing-medium: 10px; - --spacing-large: 16px; - - /* default box shadow used for raising an element above the normal content. Used in dropdowns, search result, ... */ - --box-shadow: 0 2px 8px 0 rgba(0,0,0,.075); - - --odd-color: rgba(0,0,0,.028); - - /* font-families. will affect all text on the website - * font-family: the normal font for text, headlines, menus - * font-family-monospace: used for preformatted text in memtitle, code, fragments - */ - --font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif; - --font-family-monospace: ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace; - - /* font sizes */ - --page-font-size: 15.6px; - --navigation-font-size: 14.4px; - --toc-font-size: 13.4px; - --code-font-size: 14px; /* affects code, fragment */ - --title-font-size: 22px; - - /* content text properties. These only affect the page content, not the navigation or any other ui elements */ - --content-line-height: 27px; - /* The content is centered and constraint in it's width. To make the content fill the whole page, set the variable to auto.*/ - --content-maxwidth: 1050px; - --table-line-height: 24px; - --toc-sticky-top: var(--spacing-medium); - --toc-width: 200px; - --toc-max-height: calc(100vh - 2 * var(--spacing-medium) - 85px); - - /* colors for various content boxes: @warning, @note, @deprecated @bug */ - --warning-color: #f8d1cc; - --warning-color-dark: #b61825; - --warning-color-darker: #75070f; - --note-color: #faf3d8; - --note-color-dark: #f3a600; - --note-color-darker: #5f4204; - --todo-color: #e4f3ff; - --todo-color-dark: #1879C4; - --todo-color-darker: #274a5c; - --deprecated-color: #ecf0f3; - --deprecated-color-dark: #5b6269; - --deprecated-color-darker: #43454a; - --bug-color: #e4dafd; - --bug-color-dark: #5b2bdd; - --bug-color-darker: #2a0d72; - --invariant-color: #d8f1e3; - --invariant-color-dark: #44b86f; - --invariant-color-darker: #265532; - - /* blockquote colors */ - --blockquote-background: #f8f9fa; - --blockquote-foreground: #636568; - - /* table colors */ - --tablehead-background: #f1f1f1; - --tablehead-foreground: var(--page-foreground-color); - - /* menu-display: block | none - * Visibility of the top navigation on screens >= 768px. On smaller screen the menu is always visible. - * `GENERATE_TREEVIEW` MUST be enabled! - */ - --menu-display: block; - - --menu-focus-foreground: var(--page-background-color); - --menu-focus-background: var(--primary-color); - --menu-selected-background: rgba(0,0,0,.05); - - - --header-background: var(--page-background-color); - --header-foreground: var(--page-foreground-color); - - /* searchbar colors */ - --searchbar-background: var(--side-nav-background); - --searchbar-foreground: var(--page-foreground-color); - - /* searchbar size - * (`searchbar-width` is only applied on screens >= 768px. - * on smaller screens the searchbar will always fill the entire screen width) */ - --searchbar-height: 33px; - --searchbar-width: 210px; - --searchbar-border-radius: var(--searchbar-height); - - /* code block colors */ - --code-background: #f5f5f5; - --code-foreground: var(--page-foreground-color); - - /* fragment colors */ - --fragment-background: #F8F9FA; - --fragment-foreground: #37474F; - --fragment-keyword: #bb6bb2; - --fragment-keywordtype: #8258b3; - --fragment-keywordflow: #d67c3b; - --fragment-token: #438a59; - --fragment-comment: #969696; - --fragment-link: #5383d6; - --fragment-preprocessor: #46aaa5; - --fragment-linenumber-color: #797979; - --fragment-linenumber-background: #f4f4f5; - --fragment-linenumber-border: #e3e5e7; - --fragment-lineheight: 20px; - - /* sidebar navigation (treeview) colors */ - --side-nav-background: #fbfbfb; - --side-nav-foreground: var(--page-foreground-color); - --side-nav-arrow-opacity: 0; - --side-nav-arrow-hover-opacity: 0.9; - - --toc-background: var(--side-nav-background); - --toc-foreground: var(--side-nav-foreground); - - /* height of an item in any tree / collapsable table */ - --tree-item-height: 30px; - - --memname-font-size: var(--code-font-size); - --memtitle-font-size: 18px; - - --webkit-scrollbar-size: 7px; - --webkit-scrollbar-padding: 4px; - --webkit-scrollbar-color: var(--separator-color); -} - -@media screen and (max-width: 767px) { - html { - --page-font-size: 16px; - --navigation-font-size: 16px; - --toc-font-size: 15px; - --code-font-size: 15px; /* affects code, fragment */ - --title-font-size: 22px; - } -} - -@media (prefers-color-scheme: dark) { - html:not(.light-mode) { - color-scheme: dark; - - --primary-color: #1982d2; - --primary-dark-color: #86a9c4; - --primary-light-color: #4779ac; - - --box-shadow: 0 2px 8px 0 rgba(0,0,0,.35); - - --odd-color: rgba(100,100,100,.06); - - --menu-selected-background: rgba(0,0,0,.4); - - --page-background-color: #1C1D1F; - --page-foreground-color: #d2dbde; - --page-secondary-foreground-color: #859399; - --separator-color: #38393b; - --side-nav-background: #252628; - - --code-background: #2a2c2f; - - --tablehead-background: #2a2c2f; - - --blockquote-background: #222325; - --blockquote-foreground: #7e8c92; - - --warning-color: #2e1917; - --warning-color-dark: #ad2617; - --warning-color-darker: #f5b1aa; - --note-color: #3b2e04; - --note-color-dark: #f1b602; - --note-color-darker: #ceb670; - --todo-color: #163750; - --todo-color-dark: #1982D2; - --todo-color-darker: #dcf0fa; - --deprecated-color: #2e323b; - --deprecated-color-dark: #738396; - --deprecated-color-darker: #abb0bd; - --bug-color: #2a2536; - --bug-color-dark: #7661b3; - --bug-color-darker: #ae9ed6; - --invariant-color: #303a35; - --invariant-color-dark: #76ce96; - --invariant-color-darker: #cceed5; - - --fragment-background: #282c34; - --fragment-foreground: #dbe4eb; - --fragment-keyword: #cc99cd; - --fragment-keywordtype: #ab99cd; - --fragment-keywordflow: #e08000; - --fragment-token: #7ec699; - --fragment-comment: #999999; - --fragment-link: #98c0e3; - --fragment-preprocessor: #65cabe; - --fragment-linenumber-color: #cccccc; - --fragment-linenumber-background: #35393c; - --fragment-linenumber-border: #1f1f1f; - } -} - -/* dark mode variables are defined twice, to support both the dark-mode without and with doxygen-awesome-darkmode-toggle.js */ -html.dark-mode { - color-scheme: dark; - - --primary-color: #1982d2; - --primary-dark-color: #86a9c4; - --primary-light-color: #4779ac; - - --box-shadow: 0 2px 8px 0 rgba(0,0,0,.30); - - --odd-color: rgba(100,100,100,.06); - - --menu-selected-background: rgba(0,0,0,.4); - - --page-background-color: #1C1D1F; - --page-foreground-color: #d2dbde; - --page-secondary-foreground-color: #859399; - --separator-color: #38393b; - --side-nav-background: #252628; - - --code-background: #2a2c2f; - - --tablehead-background: #2a2c2f; - - --blockquote-background: #222325; - --blockquote-foreground: #7e8c92; - - --warning-color: #2e1917; - --warning-color-dark: #ad2617; - --warning-color-darker: #f5b1aa; - --note-color: #3b2e04; - --note-color-dark: #f1b602; - --note-color-darker: #ceb670; - --todo-color: #163750; - --todo-color-dark: #1982D2; - --todo-color-darker: #dcf0fa; - --deprecated-color: #2e323b; - --deprecated-color-dark: #738396; - --deprecated-color-darker: #abb0bd; - --bug-color: #2a2536; - --bug-color-dark: #7661b3; - --bug-color-darker: #ae9ed6; - --invariant-color: #303a35; - --invariant-color-dark: #76ce96; - --invariant-color-darker: #cceed5; - - --fragment-background: #282c34; - --fragment-foreground: #dbe4eb; - --fragment-keyword: #cc99cd; - --fragment-keywordtype: #ab99cd; - --fragment-keywordflow: #e08000; - --fragment-token: #7ec699; - --fragment-comment: #999999; - --fragment-link: #98c0e3; - --fragment-preprocessor: #65cabe; - --fragment-linenumber-color: #cccccc; - --fragment-linenumber-background: #35393c; - --fragment-linenumber-border: #1f1f1f; -} - -body { - color: var(--page-foreground-color); - background-color: var(--page-background-color); - font-size: var(--page-font-size); -} - -body, table, div, p, dl, #nav-tree .label, .title, -.sm-dox a, .sm-dox a:hover, .sm-dox a:focus, #projectname, -.SelectItem, #MSearchField, .navpath li.navelem a, -.navpath li.navelem a:hover, p.reference, p.definition { - font-family: var(--font-family); -} - -h1, h2, h3, h4, h5 { - margin-top: .9em; - font-weight: 600; - line-height: initial; -} - -p, div, table, dl, p.reference, p.definition { - font-size: var(--page-font-size); -} - -p.reference, p.definition { - color: var(--page-secondary-foreground-color); -} - -a:link, a:visited, a:hover, a:focus, a:active { - color: var(--primary-color) !important; - font-weight: 500; -} - -a.anchor { - scroll-margin-top: var(--spacing-large); - display: block; -} - -/* - Title and top navigation - */ - -#top { - background: var(--header-background); - border-bottom: 1px solid var(--separator-color); -} - -@media screen and (min-width: 768px) { - #top { - display: flex; - flex-wrap: wrap; - justify-content: space-between; - align-items: center; - } -} - -#main-nav { - flex-grow: 5; - padding: var(--spacing-small) var(--spacing-medium); -} - -#titlearea { - width: auto; - padding: var(--spacing-medium) var(--spacing-large); - background: none; - color: var(--header-foreground); - border-bottom: none; -} - -@media screen and (max-width: 767px) { - #titlearea { - padding-bottom: var(--spacing-small); - } -} - -#titlearea table tbody tr { - height: auto !important; -} - -#projectname { - font-size: var(--title-font-size); - font-weight: 600; -} - -#projectnumber { - font-family: inherit; - font-size: 60%; -} - -#projectbrief { - font-family: inherit; - font-size: 80%; -} - -#projectlogo { - vertical-align: middle; -} - -#projectlogo img { - max-height: calc(var(--title-font-size) * 2); - margin-right: var(--spacing-small); -} - -.sm-dox, .tabs, .tabs2, .tabs3 { - background: none; - padding: 0; -} - -.tabs, .tabs2, .tabs3 { - border-bottom: 1px solid var(--separator-color); - margin-bottom: -1px; -} - -.main-menu-btn-icon, .main-menu-btn-icon:before, .main-menu-btn-icon:after { - background: var(--page-secondary-foreground-color); -} - -@media screen and (max-width: 767px) { - .sm-dox a span.sub-arrow { - background: var(--code-background); - } - - #main-menu a.has-submenu span.sub-arrow { - color: var(--page-secondary-foreground-color); - border-radius: var(--border-radius-medium); - } - - #main-menu a.has-submenu:hover span.sub-arrow { - color: var(--page-foreground-color); - } -} - -@media screen and (min-width: 768px) { - .sm-dox li, .tablist li { - display: var(--menu-display); - } - - .sm-dox a span.sub-arrow { - border-color: var(--header-foreground) transparent transparent transparent; - } - - .sm-dox a:hover span.sub-arrow { - border-color: var(--menu-focus-foreground) transparent transparent transparent; - } - - .sm-dox ul a span.sub-arrow { - border-color: transparent transparent transparent var(--page-foreground-color); - } - - .sm-dox ul a:hover span.sub-arrow { - border-color: transparent transparent transparent var(--menu-focus-foreground); - } -} - -.sm-dox ul { - background: var(--page-background-color); - box-shadow: var(--box-shadow); - border: 1px solid var(--separator-color); - border-radius: var(--border-radius-medium) !important; - padding: var(--spacing-small); - animation: ease-out 150ms slideInMenu; -} - -@keyframes slideInMenu { - from { - opacity: 0; - transform: translate(0px, -2px); - } - - to { - opacity: 1; - transform: translate(0px, 0px); - } -} - -.sm-dox ul a { - color: var(--page-foreground-color) !important; - background: var(--page-background-color); - font-size: var(--navigation-font-size); -} - -.sm-dox>li>ul:after { - border-bottom-color: var(--page-background-color) !important; -} - -.sm-dox>li>ul:before { - border-bottom-color: var(--separator-color) !important; -} - -.sm-dox ul a:hover, .sm-dox ul a:active, .sm-dox ul a:focus { - font-size: var(--navigation-font-size) !important; - color: var(--menu-focus-foreground) !important; - text-shadow: none; - background-color: var(--menu-focus-background); - border-radius: var(--border-radius-small) !important; -} - -.sm-dox a, .sm-dox a:focus, .tablist li, .tablist li a, .tablist li.current a { - text-shadow: none; - background: transparent; - background-image: none !important; - color: var(--header-foreground) !important; - font-weight: normal; - font-size: var(--navigation-font-size); - border-radius: var(--border-radius-small) !important; -} - -.sm-dox a:focus { - outline: auto; -} - -.sm-dox a:hover, .sm-dox a:active, .tablist li a:hover { - text-shadow: none; - font-weight: normal; - background: var(--menu-focus-background); - color: var(--menu-focus-foreground) !important; - border-radius: var(--border-radius-small) !important; - font-size: var(--navigation-font-size); -} - -.tablist li.current { - border-radius: var(--border-radius-small); - background: var(--menu-selected-background); -} - -.tablist li { - margin: var(--spacing-small) 0 var(--spacing-small) var(--spacing-small); -} - -.tablist a { - padding: 0 var(--spacing-large); -} - - -/* - Search box - */ - -#MSearchBox { - height: var(--searchbar-height); - background: var(--searchbar-background); - border-radius: var(--searchbar-border-radius); - border: 1px solid var(--separator-color); - overflow: hidden; - width: var(--searchbar-width); - position: relative; - box-shadow: none; - display: block; - margin-top: 0; -} - -.SelectionMark { - user-select: none; -} - -.tabs .left #MSearchSelect { - padding-left: 0; -} - -.tabs #MSearchBox { - position: absolute; - right: var(--spacing-medium); -} - -@media screen and (max-width: 767px) { - .tabs #MSearchBox { - position: relative; - right: 0; - margin-left: var(--spacing-medium); - margin-top: 0; - } -} - -#MSearchSelectWindow, #MSearchResultsWindow { - z-index: 9999; -} - -#MSearchBox.MSearchBoxActive { - border-color: var(--primary-color); - box-shadow: inset 0 0 0 1px var(--primary-color); -} - -#main-menu > li:last-child { - margin-right: 0; -} - -@media screen and (max-width: 767px) { - #main-menu > li:last-child { - height: 50px; - } -} - -#MSearchField { - font-size: var(--navigation-font-size); - background: transparent; -} - -.MSearchBoxActive #MSearchField { - color: var(--searchbar-foreground); -} - -#MSearchSelect { - top: calc(calc(var(--searchbar-height) / 2) - 11px); -} - -#MSearchBox span.left, #MSearchBox span.right { - background: none; - background-image: none; -} - -#MSearchBox span.right { - padding-top: calc(calc(var(--searchbar-height) / 2) - 12px); - position: absolute; - right: var(--spacing-small); -} - -.tabs #MSearchBox span.right { - top: calc(calc(var(--searchbar-height) / 2) - 12px); -} - -@keyframes slideInSearchResults { - from { - opacity: 0; - transform: translate(0, 15px); - } - - to { - opacity: 1; - transform: translate(0, 20px); - } -} - -#MSearchResultsWindow { - left: auto !important; - right: var(--spacing-medium); - border-radius: var(--border-radius-large); - border: 1px solid var(--separator-color); - transform: translate(0, 20px); - box-shadow: var(--box-shadow); - animation: ease-out 280ms slideInSearchResults; - background: var(--page-background-color); -} - -iframe#MSearchResults { - margin: 4px; -} - -iframe { - color-scheme: normal; -} - -@media (prefers-color-scheme: dark) { - html:not(.light-mode) iframe#MSearchResults { - filter: invert() hue-rotate(180deg); - } -} - -html.dark-mode iframe#MSearchResults { - filter: invert() hue-rotate(180deg); -} - -#MSearchResults .SRPage { - background-color: transparent; -} - -#MSearchResults .SRPage .SREntry { - font-size: 10pt; - padding: var(--spacing-small) var(--spacing-medium); -} - -#MSearchSelectWindow { - border: 1px solid var(--separator-color); - border-radius: var(--border-radius-medium); - box-shadow: var(--box-shadow); - background: var(--page-background-color); - padding-top: var(--spacing-small); - padding-bottom: var(--spacing-small); -} - -#MSearchSelectWindow a.SelectItem { - font-size: var(--navigation-font-size); - line-height: var(--content-line-height); - margin: 0 var(--spacing-small); - border-radius: var(--border-radius-small); - color: var(--page-foreground-color) !important; - font-weight: normal; -} - -#MSearchSelectWindow a.SelectItem:hover { - background: var(--menu-focus-background); - color: var(--menu-focus-foreground) !important; -} - -@media screen and (max-width: 767px) { - #MSearchBox { - margin-top: var(--spacing-medium); - margin-bottom: var(--spacing-medium); - width: calc(100vw - 30px); - } - - #main-menu > li:last-child { - float: none !important; - } - - #MSearchField { - width: calc(100vw - 110px); - } - - @keyframes slideInSearchResultsMobile { - from { - opacity: 0; - transform: translate(0, 15px); - } - - to { - opacity: 1; - transform: translate(0, 20px); - } - } - - #MSearchResultsWindow { - left: var(--spacing-medium) !important; - right: var(--spacing-medium); - overflow: auto; - transform: translate(0, 20px); - animation: ease-out 280ms slideInSearchResultsMobile; - width: auto !important; - } - - /* - * Overwrites for fixing the searchbox on mobile in doxygen 1.9.2 - */ - label.main-menu-btn ~ #searchBoxPos1 { - top: 3px !important; - right: 6px !important; - left: 45px; - display: flex; - } - - label.main-menu-btn ~ #searchBoxPos1 > #MSearchBox { - margin-top: 0; - margin-bottom: 0; - flex-grow: 2; - float: left; - } -} - -/* - Tree view - */ - -#side-nav { - padding: 0 !important; - background: var(--side-nav-background); -} - -@media screen and (max-width: 767px) { - #side-nav { - display: none; - } - - #doc-content { - margin-left: 0 !important; - } -} - -#nav-tree { - background: transparent; -} - -#nav-tree .label { - font-size: var(--navigation-font-size); -} - -#nav-tree .item { - height: var(--tree-item-height); - line-height: var(--tree-item-height); -} - -#nav-sync { - bottom: 12px; - right: 12px; - top: auto !important; - user-select: none; -} - -#nav-tree .selected { - text-shadow: none; - background-image: none; - background-color: transparent; - position: relative; -} - -#nav-tree .selected::after { - content: ""; - position: absolute; - top: 1px; - bottom: 1px; - left: 0; - width: 4px; - border-radius: 0 var(--border-radius-small) var(--border-radius-small) 0; - background: var(--primary-color); -} - - -#nav-tree a { - color: var(--side-nav-foreground) !important; - font-weight: normal; -} - -#nav-tree a:focus { - outline-style: auto; -} - -#nav-tree .arrow { - opacity: var(--side-nav-arrow-opacity); -} - -.arrow { - color: inherit; - cursor: pointer; - font-size: 45%; - vertical-align: middle; - margin-right: 2px; - font-family: serif; - height: auto; - text-align: right; -} - -#nav-tree div.item:hover .arrow, #nav-tree a:focus .arrow { - opacity: var(--side-nav-arrow-hover-opacity); -} - -#nav-tree .selected a { - color: var(--primary-color) !important; - font-weight: bolder; - font-weight: 600; -} - -.ui-resizable-e { - background: var(--separator-color); - width: 1px; -} - -/* - Contents - */ - -div.header { - border-bottom: 1px solid var(--separator-color); - background-color: var(--page-background-color); - background-image: none; -} - -@media screen and (min-width: 1000px) { - #doc-content > div > div.contents, - .PageDoc > div.contents { - display: flex; - flex-direction: row-reverse; - flex-wrap: nowrap; - align-items: flex-start; - } - - div.contents .textblock { - min-width: 200px; - flex-grow: 1; - } -} - -div.contents, div.header .title, div.header .summary { - max-width: var(--content-maxwidth); -} - -div.contents, div.header .title { - line-height: initial; - margin: calc(var(--spacing-medium) + .2em) auto var(--spacing-medium) auto; -} - -div.header .summary { - margin: var(--spacing-medium) auto 0 auto; -} - -div.headertitle { - padding: 0; -} - -div.header .title { - font-weight: 600; - font-size: 225%; - padding: var(--spacing-medium) var(--spacing-large); - word-break: break-word; -} - -div.header .summary { - width: auto; - display: block; - float: none; - padding: 0 var(--spacing-large); -} - -td.memSeparator { - border-color: var(--separator-color); -} - -span.mlabel { - background: var(--primary-color); - border: none; - padding: 4px 9px; - border-radius: 12px; - margin-right: var(--spacing-medium); -} - -span.mlabel:last-of-type { - margin-right: 2px; -} - -div.contents { - padding: 0 var(--spacing-large); -} - -div.contents p, div.contents li { - line-height: var(--content-line-height); -} - -div.contents div.dyncontent { - margin: var(--spacing-medium) 0; -} - -@media (prefers-color-scheme: dark) { - html:not(.light-mode) div.contents div.dyncontent img, - html:not(.light-mode) div.contents center img, - html:not(.light-mode) div.contents > table img, - html:not(.light-mode) div.contents div.dyncontent iframe, - html:not(.light-mode) div.contents center iframe, - html:not(.light-mode) div.contents table iframe { - filter: hue-rotate(180deg) invert(); - } -} - -html.dark-mode div.contents div.dyncontent img, -html.dark-mode div.contents center img, -html.dark-mode div.contents > table img, -html.dark-mode div.contents div.dyncontent iframe, -html.dark-mode div.contents center iframe, -html.dark-mode div.contents table iframe { - filter: hue-rotate(180deg) invert(); -} - -h2.groupheader { - border-bottom: 0px; - color: var(--page-foreground-color); - box-shadow: - 100px 0 var(--page-background-color), - -100px 0 var(--page-background-color), - 100px 0.75px var(--separator-color), - -100px 0.75px var(--separator-color), - 500px 0 var(--page-background-color), - -500px 0 var(--page-background-color), - 500px 0.75px var(--separator-color), - -500px 0.75px var(--separator-color), - 900px 0 var(--page-background-color), - -900px 0 var(--page-background-color), - 900px 0.75px var(--separator-color), - -900px 0.75px var(--separator-color), - 1400px 0 var(--page-background-color), - -1400px 0 var(--page-background-color), - 1400px 0.75px var(--separator-color), - -1400px 0.75px var(--separator-color), - 1900px 0 var(--page-background-color), - -1900px 0 var(--page-background-color), - 1900px 0.75px var(--separator-color), - -1900px 0.75px var(--separator-color); -} - -blockquote { - margin: 0 var(--spacing-medium) 0 var(--spacing-medium); - padding: var(--spacing-small) var(--spacing-large); - background: var(--blockquote-background); - color: var(--blockquote-foreground); - border-left: 0; - overflow: visible; - border-radius: var(--border-radius-medium); - overflow: visible; - position: relative; -} - -blockquote::before, blockquote::after { - font-weight: bold; - font-family: serif; - font-size: 360%; - opacity: .15; - position: absolute; -} - -blockquote::before { - content: "“"; - left: -10px; - top: 4px; -} - -blockquote::after { - content: "”"; - right: -8px; - bottom: -25px; -} - -blockquote p { - margin: var(--spacing-small) 0 var(--spacing-medium) 0; -} -.paramname { - font-weight: 600; - color: var(--primary-dark-color); -} - -.paramname > code { - border: 0; -} - -table.params .paramname { - font-weight: 600; - font-family: var(--font-family-monospace); - font-size: var(--code-font-size); - padding-right: var(--spacing-small); - line-height: var(--table-line-height); -} - -h1.glow, h2.glow, h3.glow, h4.glow, h5.glow, h6.glow { - text-shadow: 0 0 15px var(--primary-light-color); -} - -.alphachar a { - color: var(--page-foreground-color); -} - -/* - Table of Contents - */ - -div.contents .toc { - max-height: var(--toc-max-height); - min-width: var(--toc-width); - border: 0; - border-left: 1px solid var(--separator-color); - border-radius: 0; - background-color: transparent; - box-shadow: none; - position: sticky; - top: var(--toc-sticky-top); - padding: 0 var(--spacing-large); - margin: var(--spacing-small) 0 var(--spacing-large) var(--spacing-large); -} - -div.toc h3 { - color: var(--toc-foreground); - font-size: var(--navigation-font-size); - margin: var(--spacing-large) 0 var(--spacing-medium) 0; -} - -div.toc li { - padding: 0; - background: none; - line-height: var(--toc-font-size); - margin: var(--toc-font-size) 0 0 0; -} - -div.toc li::before { - display: none; -} - -div.toc ul { - margin-top: 0 -} - -div.toc li a { - font-size: var(--toc-font-size); - color: var(--page-foreground-color) !important; - text-decoration: none; -} - -div.toc li a:hover, div.toc li a.active { - color: var(--primary-color) !important; -} - -div.toc li a.aboveActive { - color: var(--page-secondary-foreground-color) !important; -} - - -@media screen and (max-width: 999px) { - div.contents .toc { - max-height: 45vh; - float: none; - width: auto; - margin: 0 0 var(--spacing-medium) 0; - position: relative; - top: 0; - position: relative; - border: 1px solid var(--separator-color); - border-radius: var(--border-radius-medium); - background-color: var(--toc-background); - box-shadow: var(--box-shadow); - } - - div.contents .toc.interactive { - max-height: calc(var(--navigation-font-size) + 2 * var(--spacing-large)); - overflow: hidden; - } - - div.contents .toc > h3 { - -webkit-tap-highlight-color: transparent; - cursor: pointer; - position: sticky; - top: 0; - background-color: var(--toc-background); - margin: 0; - padding: var(--spacing-large) 0; - display: block; - } - - div.contents .toc.interactive > h3::before { - content: ""; - width: 0; - height: 0; - border-left: 4px solid transparent; - border-right: 4px solid transparent; - border-top: 5px solid var(--primary-color); - display: inline-block; - margin-right: var(--spacing-small); - margin-bottom: calc(var(--navigation-font-size) / 4); - transform: rotate(-90deg); - transition: transform 0.25s ease-out; - } - - div.contents .toc.interactive.open > h3::before { - transform: rotate(0deg); - } - - div.contents .toc.interactive.open { - max-height: 45vh; - overflow: auto; - transition: max-height 0.2s ease-in-out; - } - - div.contents .toc a, div.contents .toc a.active { - color: var(--primary-color) !important; - } - - div.contents .toc a:hover { - text-decoration: underline; - } -} - -/* - Code & Fragments - */ - -code, div.fragment, pre.fragment { - border-radius: var(--border-radius-small); - border: 1px solid var(--separator-color); - overflow: hidden; -} - -code { - display: inline; - background: var(--code-background); - color: var(--code-foreground); - padding: 2px 6px; -} - -div.fragment, pre.fragment { - margin: var(--spacing-medium) 0; - padding: calc(var(--spacing-large) - (var(--spacing-large) / 6)) var(--spacing-large); - background: var(--fragment-background); - color: var(--fragment-foreground); - overflow-x: auto; -} - -@media screen and (max-width: 767px) { - div.fragment, pre.fragment { - border-top-right-radius: 0; - border-bottom-right-radius: 0; - border-right: 0; - } - - .contents > div.fragment, - .textblock > div.fragment, - .textblock > pre.fragment, - .contents > .doxygen-awesome-fragment-wrapper > div.fragment, - .textblock > .doxygen-awesome-fragment-wrapper > div.fragment, - .textblock > .doxygen-awesome-fragment-wrapper > pre.fragment { - margin: var(--spacing-medium) calc(0px - var(--spacing-large)); - border-radius: 0; - border-left: 0; - } - - .textblock li > .fragment, - .textblock li > .doxygen-awesome-fragment-wrapper > .fragment { - margin: var(--spacing-medium) calc(0px - var(--spacing-large)); - } - - .memdoc li > .fragment, - .memdoc li > .doxygen-awesome-fragment-wrapper > .fragment { - margin: var(--spacing-medium) calc(0px - var(--spacing-medium)); - } - - .textblock ul, .memdoc ul { - overflow: initial; - } - - .memdoc > div.fragment, - .memdoc > pre.fragment, - dl dd > div.fragment, - dl dd pre.fragment, - .memdoc > .doxygen-awesome-fragment-wrapper > div.fragment, - .memdoc > .doxygen-awesome-fragment-wrapper > pre.fragment, - dl dd > .doxygen-awesome-fragment-wrapper > div.fragment, - dl dd .doxygen-awesome-fragment-wrapper > pre.fragment { - margin: var(--spacing-medium) calc(0px - var(--spacing-medium)); - border-radius: 0; - border-left: 0; - } -} - -code, code a, pre.fragment, div.fragment, div.fragment .line, div.fragment span, div.fragment .line a, div.fragment .line span { - font-family: var(--font-family-monospace); - font-size: var(--code-font-size) !important; -} - -div.line:after { - margin-right: var(--spacing-medium); -} - -div.fragment .line, pre.fragment { - white-space: pre; - word-wrap: initial; - line-height: var(--fragment-lineheight); -} - -div.fragment span.keyword { - color: var(--fragment-keyword); -} - -div.fragment span.keywordtype { - color: var(--fragment-keywordtype); -} - -div.fragment span.keywordflow { - color: var(--fragment-keywordflow); -} - -div.fragment span.stringliteral { - color: var(--fragment-token) -} - -div.fragment span.comment { - color: var(--fragment-comment); -} - -div.fragment a.code { - color: var(--fragment-link) !important; -} - -div.fragment span.preprocessor { - color: var(--fragment-preprocessor); -} - -div.fragment span.lineno { - display: inline-block; - width: 27px; - border-right: none; - background: var(--fragment-linenumber-background); - color: var(--fragment-linenumber-color); -} - -div.fragment span.lineno a { - background: none; - color: var(--fragment-link) !important; -} - -div.fragment .line:first-child .lineno { - box-shadow: -999999px 0px 0 999999px var(--fragment-linenumber-background), -999998px 0px 0 999999px var(--fragment-linenumber-border); -} - -div.line { - border-radius: var(--border-radius-small); -} - -div.line.glow { - background-color: var(--primary-light-color); - box-shadow: none; -} - -/* - dl warning, attention, note, deprecated, bug, ... - */ - -dl.bug dt a, dl.deprecated dt a, dl.todo dt a { - font-weight: bold !important; -} - -dl.warning, dl.attention, dl.note, dl.deprecated, dl.bug, dl.invariant, dl.pre, dl.post, dl.todo, dl.remark { - padding: var(--spacing-medium); - margin: var(--spacing-medium) 0; - color: var(--page-background-color); - overflow: hidden; - margin-left: 0; - border-radius: var(--border-radius-small); -} - -dl.section dd { - margin-bottom: 2px; -} - -dl.warning, dl.attention { - background: var(--warning-color); - border-left: 8px solid var(--warning-color-dark); - color: var(--warning-color-darker); -} - -dl.warning dt, dl.attention dt { - color: var(--warning-color-dark); -} - -dl.note, dl.remark { - background: var(--note-color); - border-left: 8px solid var(--note-color-dark); - color: var(--note-color-darker); -} - -dl.note dt, dl.remark dt { - color: var(--note-color-dark); -} - -dl.todo { - background: var(--todo-color); - border-left: 8px solid var(--todo-color-dark); - color: var(--todo-color-darker); -} - -dl.todo dt { - color: var(--todo-color-dark); -} - -dl.bug dt a { - color: var(--todo-color-dark) !important; -} - -dl.bug { - background: var(--bug-color); - border-left: 8px solid var(--bug-color-dark); - color: var(--bug-color-darker); -} - -dl.bug dt a { - color: var(--bug-color-dark) !important; -} - -dl.deprecated { - background: var(--deprecated-color); - border-left: 8px solid var(--deprecated-color-dark); - color: var(--deprecated-color-darker); -} - -dl.deprecated dt a { - color: var(--deprecated-color-dark) !important; -} - -dl.section dd, dl.bug dd, dl.deprecated dd, dl.todo dd { - margin-inline-start: 0px; -} - -dl.invariant, dl.pre, dl.post { - background: var(--invariant-color); - border-left: 8px solid var(--invariant-color-dark); - color: var(--invariant-color-darker); -} - -dl.invariant dt, dl.pre dt, dl.post dt { - color: var(--invariant-color-dark); -} - -/* - memitem - */ - -div.memdoc, div.memproto, h2.memtitle { - box-shadow: none; - background-image: none; - border: none; -} - -div.memdoc { - padding: 0 var(--spacing-medium); - background: var(--page-background-color); -} - -h2.memtitle, div.memitem { - border: 1px solid var(--separator-color); - box-shadow: var(--box-shadow); -} - -h2.memtitle { - box-shadow: 0px var(--spacing-medium) 0 -1px var(--fragment-background), var(--box-shadow); -} - -div.memitem { - transition: none; -} - -div.memproto, h2.memtitle { - background: var(--fragment-background); -} - -h2.memtitle { - font-weight: 500; - font-size: var(--memtitle-font-size); - font-family: var(--font-family-monospace); - border-bottom: none; - border-top-left-radius: var(--border-radius-medium); - border-top-right-radius: var(--border-radius-medium); - word-break: break-all; - position: relative; -} - -h2.memtitle:after { - content: ""; - display: block; - background: var(--fragment-background); - height: var(--spacing-medium); - bottom: calc(0px - var(--spacing-medium)); - left: 0; - right: -14px; - position: absolute; - border-top-right-radius: var(--border-radius-medium); -} - -h2.memtitle > span.permalink { - font-size: inherit; -} - -h2.memtitle > span.permalink > a { - text-decoration: none; - padding-left: 3px; - margin-right: -4px; - user-select: none; - display: inline-block; - margin-top: -6px; -} - -h2.memtitle > span.permalink > a:hover { - color: var(--primary-dark-color) !important; -} - -a:target + h2.memtitle, a:target + h2.memtitle + div.memitem { - border-color: var(--primary-light-color); -} - -div.memitem { - border-top-right-radius: var(--border-radius-medium); - border-bottom-right-radius: var(--border-radius-medium); - border-bottom-left-radius: var(--border-radius-medium); - overflow: hidden; - display: block !important; -} - -div.memdoc { - border-radius: 0; -} - -div.memproto { - border-radius: 0 var(--border-radius-small) 0 0; - overflow: auto; - border-bottom: 1px solid var(--separator-color); - padding: var(--spacing-medium); - margin-bottom: -1px; -} - -div.memtitle { - border-top-right-radius: var(--border-radius-medium); - border-top-left-radius: var(--border-radius-medium); -} - -div.memproto table.memname { - font-family: var(--font-family-monospace); - color: var(--page-foreground-color); - font-size: var(--memname-font-size); - text-shadow: none; -} - -div.memproto div.memtemplate { - font-family: var(--font-family-monospace); - color: var(--primary-dark-color); - font-size: var(--memname-font-size); - margin-left: 2px; - text-shadow: none; -} - -table.mlabels, table.mlabels > tbody { - display: block; -} - -td.mlabels-left { - width: auto; -} - -td.mlabels-right { - margin-top: 3px; - position: sticky; - left: 0; -} - -table.mlabels > tbody > tr:first-child { - display: flex; - justify-content: space-between; - flex-wrap: wrap; -} - -.memname, .memitem span.mlabels { - margin: 0 -} - -/* - reflist - */ - -dl.reflist { - box-shadow: var(--box-shadow); - border-radius: var(--border-radius-medium); - border: 1px solid var(--separator-color); - overflow: hidden; - padding: 0; -} - - -dl.reflist dt, dl.reflist dd { - box-shadow: none; - text-shadow: none; - background-image: none; - border: none; - padding: 12px; -} - - -dl.reflist dt { - font-weight: 500; - border-radius: 0; - background: var(--code-background); - border-bottom: 1px solid var(--separator-color); - color: var(--page-foreground-color) -} - - -dl.reflist dd { - background: none; -} - -/* - Table - */ - -.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname), -.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody { - display: inline-block; - max-width: 100%; -} - -.contents > table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname):not(.classindex) { - margin-left: calc(0px - var(--spacing-large)); - margin-right: calc(0px - var(--spacing-large)); - max-width: calc(100% + 2 * var(--spacing-large)); -} - -table.fieldtable, -table.markdownTable tbody, -table.doxtable tbody { - border: none; - margin: var(--spacing-medium) 0; - box-shadow: 0 0 0 1px var(--separator-color); - border-radius: var(--border-radius-small); -} - -table.doxtable caption { - display: block; -} - -table.fieldtable { - border-collapse: collapse; - width: 100%; -} - -th.markdownTableHeadLeft, -th.markdownTableHeadRight, -th.markdownTableHeadCenter, -th.markdownTableHeadNone, -table.doxtable th { - background: var(--tablehead-background); - color: var(--tablehead-foreground); - font-weight: 600; - font-size: var(--page-font-size); -} - -th.markdownTableHeadLeft:first-child, -th.markdownTableHeadRight:first-child, -th.markdownTableHeadCenter:first-child, -th.markdownTableHeadNone:first-child, -table.doxtable tr th:first-child { - border-top-left-radius: var(--border-radius-small); -} - -th.markdownTableHeadLeft:last-child, -th.markdownTableHeadRight:last-child, -th.markdownTableHeadCenter:last-child, -th.markdownTableHeadNone:last-child, -table.doxtable tr th:last-child { - border-top-right-radius: var(--border-radius-small); -} - -table.markdownTable td, -table.markdownTable th, -table.fieldtable td, -table.fieldtable th, -table.doxtable td, -table.doxtable th { - border: 1px solid var(--separator-color); - padding: var(--spacing-small) var(--spacing-medium); -} - -table.markdownTable td:last-child, -table.markdownTable th:last-child, -table.fieldtable td:last-child, -table.fieldtable th:last-child, -table.doxtable td:last-child, -table.doxtable th:last-child { - border-right: none; -} - -table.markdownTable td:first-child, -table.markdownTable th:first-child, -table.fieldtable td:first-child, -table.fieldtable th:first-child, -table.doxtable td:first-child, -table.doxtable th:first-child { - border-left: none; -} - -table.markdownTable tr:first-child td, -table.markdownTable tr:first-child th, -table.fieldtable tr:first-child td, -table.fieldtable tr:first-child th, -table.doxtable tr:first-child td, -table.doxtable tr:first-child th { - border-top: none; -} - -table.markdownTable tr:last-child td, -table.markdownTable tr:last-child th, -table.fieldtable tr:last-child td, -table.fieldtable tr:last-child th, -table.doxtable tr:last-child td, -table.doxtable tr:last-child th { - border-bottom: none; -} - -table.markdownTable tr, table.doxtable tr { - border-bottom: 1px solid var(--separator-color); -} - -table.markdownTable tr:last-child, table.doxtable tr:last-child { - border-bottom: none; -} - -table.fieldtable th { - font-size: var(--page-font-size); - font-weight: 600; - background-image: none; - background-color: var(--tablehead-background); - color: var(--tablehead-foreground); -} - -table.fieldtable td.fieldtype, .fieldtable td.fieldname, .fieldtable td.fielddoc, .fieldtable th { - border-bottom: 1px solid var(--separator-color); - border-right: 1px solid var(--separator-color); -} - -table.fieldtable tr:last-child td:first-child { - border-bottom-left-radius: var(--border-radius-small); -} - -table.fieldtable tr:last-child td:last-child { - border-bottom-right-radius: var(--border-radius-small); -} - -.memberdecls td.glow, .fieldtable tr.glow { - background-color: var(--primary-light-color); - box-shadow: none; -} - -table.memberdecls { - display: block; - -webkit-tap-highlight-color: transparent; -} - -table.memberdecls tr[class^='memitem'] { - font-family: var(--font-family-monospace); - font-size: var(--code-font-size); -} - -table.memberdecls tr[class^='memitem'] .memTemplParams { - font-family: var(--font-family-monospace); - font-size: var(--code-font-size); - color: var(--primary-dark-color); - white-space: normal; -} - -table.memberdecls .memItemLeft, -table.memberdecls .memItemRight, -table.memberdecls .memTemplItemLeft, -table.memberdecls .memTemplItemRight, -table.memberdecls .memTemplParams { - transition: none; - padding-top: var(--spacing-small); - padding-bottom: var(--spacing-small); - border-top: 1px solid var(--separator-color); - border-bottom: 1px solid var(--separator-color); - background-color: var(--fragment-background); -} - -table.memberdecls .memTemplItemLeft, -table.memberdecls .memTemplItemRight { - padding-top: 2px; -} - -table.memberdecls .memTemplParams { - border-bottom: 0; - border-left: 1px solid var(--separator-color); - border-right: 1px solid var(--separator-color); - border-radius: var(--border-radius-small) var(--border-radius-small) 0 0; - padding-bottom: var(--spacing-small); -} - -table.memberdecls .memTemplItemLeft { - border-radius: 0 0 0 var(--border-radius-small); - border-left: 1px solid var(--separator-color); - border-top: 0; -} - -table.memberdecls .memTemplItemRight { - border-radius: 0 0 var(--border-radius-small) 0; - border-right: 1px solid var(--separator-color); - padding-left: 0; - border-top: 0; -} - -table.memberdecls .memItemLeft { - border-radius: var(--border-radius-small) 0 0 var(--border-radius-small); - border-left: 1px solid var(--separator-color); - padding-left: var(--spacing-medium); - padding-right: 0; -} - -table.memberdecls .memItemRight { - border-radius: 0 var(--border-radius-small) var(--border-radius-small) 0; - border-right: 1px solid var(--separator-color); - padding-right: var(--spacing-medium); - padding-left: 0; - -} - -table.memberdecls .mdescLeft, table.memberdecls .mdescRight { - background: none; - color: var(--page-foreground-color); - padding: var(--spacing-small) 0; -} - -table.memberdecls .memItemLeft, -table.memberdecls .memTemplItemLeft { - padding-right: var(--spacing-medium); -} - -table.memberdecls .memSeparator { - background: var(--page-background-color); - height: var(--spacing-large); - border: 0; - transition: none; -} - -table.memberdecls .groupheader { - margin-bottom: var(--spacing-large); -} - -table.memberdecls .inherit_header td { - padding: 0 0 var(--spacing-medium) 0; - text-indent: -12px; - color: var(--page-secondary-foreground-color); -} - -table.memberdecls img[src="closed.png"], -table.memberdecls img[src="open.png"], -div.dynheader img[src="open.png"], -div.dynheader img[src="closed.png"] { - width: 0; - height: 0; - border-left: 4px solid transparent; - border-right: 4px solid transparent; - border-top: 5px solid var(--primary-color); - margin-top: 8px; - display: block; - float: left; - margin-left: -10px; - transition: transform 0.25s ease-out; -} - -table.memberdecls img { - margin-right: 10px; -} - -table.memberdecls img[src="closed.png"], -div.dynheader img[src="closed.png"] { - transform: rotate(-90deg); - -} - -.compoundTemplParams { - font-family: var(--font-family-monospace); - color: var(--primary-dark-color); - font-size: var(--code-font-size); -} - -@media screen and (max-width: 767px) { - - table.memberdecls .memItemLeft, - table.memberdecls .memItemRight, - table.memberdecls .mdescLeft, - table.memberdecls .mdescRight, - table.memberdecls .memTemplItemLeft, - table.memberdecls .memTemplItemRight, - table.memberdecls .memTemplParams { - display: block; - text-align: left; - padding-left: var(--spacing-large); - margin: 0 calc(0px - var(--spacing-large)) 0 calc(0px - var(--spacing-large)); - border-right: none; - border-left: none; - border-radius: 0; - white-space: normal; - } - - table.memberdecls .memItemLeft, - table.memberdecls .mdescLeft, - table.memberdecls .memTemplItemLeft { - border-bottom: 0; - padding-bottom: 0; - } - - table.memberdecls .memTemplItemLeft { - padding-top: 0; - } - - table.memberdecls .mdescLeft { - margin-bottom: calc(0px - var(--page-font-size)); - } - - table.memberdecls .memItemRight, - table.memberdecls .mdescRight, - table.memberdecls .memTemplItemRight { - border-top: 0; - padding-top: 0; - padding-right: var(--spacing-large); - overflow-x: auto; - } - - table.memberdecls tr[class^='memitem']:not(.inherit) { - display: block; - width: calc(100vw - 2 * var(--spacing-large)); - } - - table.memberdecls .mdescRight { - color: var(--page-foreground-color); - } - - table.memberdecls tr.inherit { - visibility: hidden; - } - - table.memberdecls tr[style="display: table-row;"] { - display: block !important; - visibility: visible; - width: calc(100vw - 2 * var(--spacing-large)); - animation: fade .5s; - } - - @keyframes fade { - 0% { - opacity: 0; - max-height: 0; - } - - 100% { - opacity: 1; - max-height: 200px; - } - } -} - - -/* - Horizontal Rule - */ - -hr { - margin-top: var(--spacing-large); - margin-bottom: var(--spacing-large); - height: 1px; - background-color: var(--separator-color); - border: 0; -} - -.contents hr { - box-shadow: 100px 0 0 var(--separator-color), - -100px 0 0 var(--separator-color), - 500px 0 0 var(--separator-color), - -500px 0 0 var(--separator-color), - 1500px 0 0 var(--separator-color), - -1500px 0 0 var(--separator-color), - 2000px 0 0 var(--separator-color), - -2000px 0 0 var(--separator-color); -} - -.contents img, .contents .center, .contents center, .contents div.image object { - max-width: 100%; - overflow: auto; -} - -@media screen and (max-width: 767px) { - .contents .dyncontent > .center, .contents > center { - margin-left: calc(0px - var(--spacing-large)); - margin-right: calc(0px - var(--spacing-large)); - max-width: calc(100% + 2 * var(--spacing-large)); - } -} - -/* - Directories - */ -div.directory { - border-top: 1px solid var(--separator-color); - border-bottom: 1px solid var(--separator-color); - width: auto; -} - -table.directory { - font-family: var(--font-family); - font-size: var(--page-font-size); - font-weight: normal; - width: 100%; -} - -table.directory td.entry, table.directory td.desc { - padding: calc(var(--spacing-small) / 2) var(--spacing-small); - line-height: var(--table-line-height); -} - -table.directory tr.even td:last-child { - border-radius: 0 var(--border-radius-small) var(--border-radius-small) 0; -} - -table.directory tr.even td:first-child { - border-radius: var(--border-radius-small) 0 0 var(--border-radius-small); -} - -table.directory tr.even:last-child td:last-child { - border-radius: 0 var(--border-radius-small) 0 0; -} - -table.directory tr.even:last-child td:first-child { - border-radius: var(--border-radius-small) 0 0 0; -} - -table.directory td.desc { - min-width: 250px; -} - -table.directory tr.even { - background-color: var(--odd-color); -} - -table.directory tr.odd { - background-color: transparent; -} - -.icona { - width: auto; - height: auto; - margin: 0 var(--spacing-small); -} - -.icon { - background: var(--primary-color); - border-radius: var(--border-radius-small); - font-size: var(--page-font-size); - padding: calc(var(--page-font-size) / 5); - line-height: var(--page-font-size); - transform: scale(0.8); - height: auto; - width: var(--page-font-size); - user-select: none; -} - -.iconfopen, .icondoc, .iconfclosed { - background-position: center; - margin-bottom: 0; - height: var(--table-line-height); -} - -.icondoc { - filter: saturate(0.2); -} - -@media screen and (max-width: 767px) { - div.directory { - margin-left: calc(0px - var(--spacing-large)); - margin-right: calc(0px - var(--spacing-large)); - } -} - -@media (prefers-color-scheme: dark) { - html:not(.light-mode) .iconfopen, html:not(.light-mode) .iconfclosed { - filter: hue-rotate(180deg) invert(); - } -} - -html.dark-mode .iconfopen, html.dark-mode .iconfclosed { - filter: hue-rotate(180deg) invert(); -} - -/* - Class list - */ - -.classindex dl.odd { - background: var(--odd-color); - border-radius: var(--border-radius-small); -} - -.classindex dl.even { - background-color: transparent; -} - -/* - Class Index Doxygen 1.8 -*/ - -table.classindex { - margin-left: 0; - margin-right: 0; - width: 100%; -} - -table.classindex table div.ah { - background-image: none; - background-color: initial; - border-color: var(--separator-color); - color: var(--page-foreground-color); - box-shadow: var(--box-shadow); - border-radius: var(--border-radius-large); - padding: var(--spacing-small); -} - -div.qindex { - background-color: var(--odd-color); - border-radius: var(--border-radius-small); - border: 1px solid var(--separator-color); - padding: var(--spacing-small) 0; -} - -/* - Footer and nav-path - */ - -#nav-path { - width: 100%; -} - -#nav-path ul { - background-image: none; - background: var(--page-background-color); - border: none; - border-top: 1px solid var(--separator-color); - border-bottom: 1px solid var(--separator-color); - border-bottom: 0; - box-shadow: 0 0.75px 0 var(--separator-color); - font-size: var(--navigation-font-size); -} - -img.footer { - width: 60px; -} - -.navpath li.footer { - color: var(--page-secondary-foreground-color); -} - -address.footer { - color: var(--page-secondary-foreground-color); - margin-bottom: var(--spacing-large); -} - -#nav-path li.navelem { - background-image: none; - display: flex; - align-items: center; -} - -.navpath li.navelem a { - text-shadow: none; - display: inline-block; - color: var(--primary-color) !important; -} - -.navpath li.navelem b { - color: var(--primary-dark-color); - font-weight: 500; -} - -li.navelem { - padding: 0; - margin-left: -8px; -} - -li.navelem:first-child { - margin-left: var(--spacing-large); -} - -li.navelem:first-child:before { - display: none; -} - -#nav-path li.navelem:after { - content: ''; - border: 5px solid var(--page-background-color); - border-bottom-color: transparent; - border-right-color: transparent; - border-top-color: transparent; - transform: translateY(-1px) scaleY(4.2); - z-index: 10; - margin-left: 6px; -} - -#nav-path li.navelem:before { - content: ''; - border: 5px solid var(--separator-color); - border-bottom-color: transparent; - border-right-color: transparent; - border-top-color: transparent; - transform: translateY(-1px) scaleY(3.2); - margin-right: var(--spacing-small); -} - -.navpath li.navelem a:hover { - color: var(--primary-color); -} - -/* - Scrollbars for Webkit -*/ - -#nav-tree::-webkit-scrollbar, -div.fragment::-webkit-scrollbar, -pre.fragment::-webkit-scrollbar, -div.memproto::-webkit-scrollbar, -.contents center::-webkit-scrollbar, -.contents .center::-webkit-scrollbar, -.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody::-webkit-scrollbar, -div.contents .toc::-webkit-scrollbar { - background: transparent; - width: calc(var(--webkit-scrollbar-size) + var(--webkit-scrollbar-padding) + var(--webkit-scrollbar-padding)); - height: calc(var(--webkit-scrollbar-size) + var(--webkit-scrollbar-padding) + var(--webkit-scrollbar-padding)); -} - -#nav-tree::-webkit-scrollbar-thumb, -div.fragment::-webkit-scrollbar-thumb, -pre.fragment::-webkit-scrollbar-thumb, -div.memproto::-webkit-scrollbar-thumb, -.contents center::-webkit-scrollbar-thumb, -.contents .center::-webkit-scrollbar-thumb, -.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody::-webkit-scrollbar-thumb, -div.contents .toc::-webkit-scrollbar-thumb { - background-color: transparent; - border: var(--webkit-scrollbar-padding) solid transparent; - border-radius: calc(var(--webkit-scrollbar-padding) + var(--webkit-scrollbar-padding)); - background-clip: padding-box; -} - -#nav-tree:hover::-webkit-scrollbar-thumb, -div.fragment:hover::-webkit-scrollbar-thumb, -pre.fragment:hover::-webkit-scrollbar-thumb, -div.memproto:hover::-webkit-scrollbar-thumb, -.contents center:hover::-webkit-scrollbar-thumb, -.contents .center:hover::-webkit-scrollbar-thumb, -.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody:hover::-webkit-scrollbar-thumb, -div.contents .toc:hover::-webkit-scrollbar-thumb { - background-color: var(--webkit-scrollbar-color); -} - -#nav-tree::-webkit-scrollbar-track, -div.fragment::-webkit-scrollbar-track, -pre.fragment::-webkit-scrollbar-track, -div.memproto::-webkit-scrollbar-track, -.contents center::-webkit-scrollbar-track, -.contents .center::-webkit-scrollbar-track, -.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody::-webkit-scrollbar-track, -div.contents .toc::-webkit-scrollbar-track { - background: transparent; -} - -#nav-tree::-webkit-scrollbar-corner { - background-color: var(--side-nav-background); -} - -#nav-tree, -div.fragment, -pre.fragment, -div.memproto, -.contents center, -.contents .center, -.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody, -div.contents .toc { - overflow-x: auto; - overflow-x: overlay; -} - -#nav-tree { - overflow-x: auto; - overflow-y: auto; - overflow-y: overlay; -} - -/* - Scrollbars for Firefox -*/ - -#nav-tree, -div.fragment, -pre.fragment, -div.memproto, -.contents center, -.contents .center, -.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody, -div.contents .toc { - scrollbar-width: thin; -} - -/* - Optional Dark mode toggle button -*/ - -doxygen-awesome-dark-mode-toggle { - display: inline-block; - margin: 0 0 0 var(--spacing-small); - padding: 0; - width: var(--searchbar-height); - height: var(--searchbar-height); - background: none; - border: none; - border-radius: var(--searchbar-height); - vertical-align: middle; - text-align: center; - line-height: var(--searchbar-height); - font-size: 22px; - display: flex; - align-items: center; - justify-content: center; - user-select: none; - cursor: pointer; -} - -doxygen-awesome-dark-mode-toggle > svg { - transition: transform .1s ease-in-out; -} - -doxygen-awesome-dark-mode-toggle:active > svg { - transform: scale(.5); -} - -doxygen-awesome-dark-mode-toggle:hover { - background-color: rgba(0,0,0,.03); -} - -html.dark-mode doxygen-awesome-dark-mode-toggle:hover { - background-color: rgba(0,0,0,.18); -} - -/* - Optional fragment copy button -*/ -.doxygen-awesome-fragment-wrapper { - position: relative; -} - -doxygen-awesome-fragment-copy-button { - opacity: 0; - background: var(--fragment-background); - width: 28px; - height: 28px; - position: absolute; - right: calc(var(--spacing-large) - (var(--spacing-large) / 2.5)); - top: calc(var(--spacing-large) - (var(--spacing-large) / 2.5)); - border: 1px solid var(--fragment-foreground); - cursor: pointer; - border-radius: var(--border-radius-small); - display: flex; - justify-content: center; - align-items: center; -} - -.doxygen-awesome-fragment-wrapper:hover doxygen-awesome-fragment-copy-button, doxygen-awesome-fragment-copy-button.success { - opacity: .28; -} - -doxygen-awesome-fragment-copy-button:hover, doxygen-awesome-fragment-copy-button.success { - opacity: 1 !important; -} - -doxygen-awesome-fragment-copy-button:active:not([class~=success]) svg { - transform: scale(.91); -} - -doxygen-awesome-fragment-copy-button svg { - fill: var(--fragment-foreground); - width: 18px; - height: 18px; -} - -doxygen-awesome-fragment-copy-button.success svg { - fill: rgb(14, 168, 14); -} - -doxygen-awesome-fragment-copy-button.success { - border-color: rgb(14, 168, 14); -} - -@media screen and (max-width: 767px) { - .textblock > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button, - .textblock li > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button, - .memdoc li > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button, - .memdoc > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button, - dl dd > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button { - right: 0; - } -} - -/* - Optional paragraph link button -*/ - -a.anchorlink { - font-size: 90%; - margin-left: var(--spacing-small); - color: var(--page-foreground-color) !important; - text-decoration: none; - opacity: .15; - display: none; - transition: opacity .1s ease-in-out, color .1s ease-in-out; -} - -a.anchorlink svg { - fill: var(--page-foreground-color); -} - -h3 a.anchorlink svg, h4 a.anchorlink svg { - margin-bottom: -3px; - margin-top: -4px; -} - -a.anchorlink:hover { - opacity: .45; -} - -h2:hover a.anchorlink, h1:hover a.anchorlink, h3:hover a.anchorlink, h4:hover a.anchorlink { - display: inline-block; -} diff --git a/doc/footer.html b/doc/footer.html deleted file mode 100644 index 499f9e2b..00000000 --- a/doc/footer.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - diff --git a/doc/header.html b/doc/header.html deleted file mode 100644 index 7292889f..00000000 --- a/doc/header.html +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - -$projectname: $title -$title - - - -$treeview -$search -$mathjax - -$extrastylesheet - - -
-
-