diff options
| author | Lexi Winter <lexi@le-fay.org> | 2025-06-29 00:42:31 +0100 |
|---|---|---|
| committer | Lexi Winter <lexi@le-fay.org> | 2025-06-29 00:42:31 +0100 |
| commit | d24315268c11d435bb9accbce87b7f46dda6ed3e (patch) | |
| tree | 66589cb6a15fa74d4b09683105c583e4a5c222b4 /nihil.util | |
| parent | 7741a9698d29f79aca3e47495dcdf87c7a712f42 (diff) | |
| download | nihil-d24315268c11d435bb9accbce87b7f46dda6ed3e.tar.gz nihil-d24315268c11d435bb9accbce87b7f46dda6ed3e.tar.bz2 | |
cli: improve command dispatch a bit
Diffstat (limited to 'nihil.util')
| -rw-r--r-- | nihil.util/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | nihil.util/capture_stream.ccm | 61 | ||||
| -rw-r--r-- | nihil.util/nihil.util.ccm | 1 | ||||
| -rw-r--r-- | nihil.util/test_capture_stream.cc | 44 |
4 files changed, 108 insertions, 0 deletions
diff --git a/nihil.util/CMakeLists.txt b/nihil.util/CMakeLists.txt index b809a68..a07ea7d 100644 --- a/nihil.util/CMakeLists.txt +++ b/nihil.util/CMakeLists.txt @@ -6,6 +6,7 @@ target_sources(nihil.util PUBLIC FILE_SET modules TYPE CXX_MODULES FILES nihil.util.ccm + capture_stream.ccm ctype.ccm parse_size.ccm next_word.ccm @@ -17,6 +18,7 @@ if(NIHIL_TESTS) enable_testing() add_executable(nihil.util.test + test_capture_stream.cc test_ctype.cc test_parse_size.cc test_next_word.cc diff --git a/nihil.util/capture_stream.ccm b/nihil.util/capture_stream.ccm new file mode 100644 index 0000000..3333505 --- /dev/null +++ b/nihil.util/capture_stream.ccm @@ -0,0 +1,61 @@ +/* + * This source code is released into the public domain. + */ + +module; + +#include <iostream> + +export module nihil.util:capture_stream; + +namespace nihil { + +/* + * Capture output written to a stream and redirect it to an internal string + * buffer. Call .str() to get the data written. Call .release() to stop + * capturing (or simply delete the capture_stream object). + */ +export template<typename Char, typename Traits> +struct capture_stream { + capture_stream(std::basic_ostream<Char, Traits> &stream) + : m_stream(&stream) + { + m_old_streambuf = m_stream->rdbuf(); + m_stream->rdbuf(m_buffer.rdbuf()); + } + + ~capture_stream() { + if (m_old_streambuf == nullptr) + return; + release(); + } + + /* + * Release this capture, returning the stream to its previous state. + */ + auto release(this capture_stream &self) -> void + { + if (self.m_old_streambuf == nullptr) + throw std::logic_error( + "release() called on empty capture_stream"); + + self.m_stream->rdbuf(self.m_old_streambuf); + self.m_old_streambuf = nullptr; + } + + /* + * Get the data which has been written to the stream. + */ + [[nodiscard]] auto str(this capture_stream const &self) + -> std::basic_string_view<Char, Traits> + { + return self.m_buffer.view(); + } + +private: + std::basic_ostringstream<Char, Traits> m_buffer; + std::basic_ostream<Char, Traits> *m_stream; + std::streambuf *m_old_streambuf; +}; + +} // namespace nihil diff --git a/nihil.util/nihil.util.ccm b/nihil.util/nihil.util.ccm index afd513a..89510c9 100644 --- a/nihil.util/nihil.util.ccm +++ b/nihil.util/nihil.util.ccm @@ -6,6 +6,7 @@ module; export module nihil.util; +export import :capture_stream; export import :ctype; export import :parse_size; export import :next_word; diff --git a/nihil.util/test_capture_stream.cc b/nihil.util/test_capture_stream.cc new file mode 100644 index 0000000..27c8596 --- /dev/null +++ b/nihil.util/test_capture_stream.cc @@ -0,0 +1,44 @@ +/* + * This source code is released into the public domain. + */ + +#include <iostream> + +#include <catch2/catch_test_macros.hpp> + +import nihil.util; + +TEST_CASE("nihil.util: capture", "[nihil][nihil.util]") +{ + SECTION("std::cout with release()") { + auto cap = nihil::capture_stream(std::cout); + + std::cout << 1 << '+' << 1 << '=' << (1 + 1) << '\n'; + REQUIRE(cap.str() == "1+1=2\n"); + + cap.release(); + REQUIRE(cap.str() == "1+1=2\n"); + } + + SECTION("std::cout with dtor") { + auto cap = nihil::capture_stream(std::cout); + std::cout << 1 << '+' << 1 << '=' << (1 + 1) << '\n'; + REQUIRE(cap.str() == "1+1=2\n"); + } + + SECTION("std::cerr with release()") { + auto cap = nihil::capture_stream(std::cerr); + + std::cerr << 1 << '+' << 1 << '=' << (1 + 1) << '\n'; + REQUIRE(cap.str() == "1+1=2\n"); + + cap.release(); + REQUIRE(cap.str() == "1+1=2\n"); + } + + SECTION("std::cerr with dtor") { + auto cap = nihil::capture_stream(std::cerr); + std::cerr << 1 << '+' << 1 << '=' << (1 + 1) << '\n'; + REQUIRE(cap.str() == "1+1=2\n"); + } +} |
