diff --git a/include/xo/object2/DString.hpp b/include/xo/object2/DString.hpp index accdd96..b7be708 100644 --- a/include/xo/object2/DString.hpp +++ b/include/xo/object2/DString.hpp @@ -11,6 +11,7 @@ #include #include #include +#include namespace xo { namespace scm { @@ -119,6 +120,25 @@ namespace xo { /** replace contents with @p other, or prefix of up to @p capacity - 1 chars **/ DString & assign(const DString & other); + ///@} + /** @defgroup dstring-general general methods **/ + ///@{ + + /** format string into this DString using printf-style formatting. + * Truncates if result exceeds capacity. + * @return number of characters written (excluding null terminator) + **/ + template + size_type sprintf(const char * fmt, Args&&... args) { + int n = std::snprintf(chars_, capacity_, fmt, std::forward(args)...); + if (n < 0) { + size_ = 0; + chars_[0] = '\0'; + } else { + size_ = (n < static_cast(capacity_)) ? n : capacity_ - 1; + } + return size_; + } // TODO - behave like std::string, to the extent feasible // insert diff --git a/utest/DString.test.cpp b/utest/DString.test.cpp index b5f70f1..213f502 100644 --- a/utest/DString.test.cpp +++ b/utest/DString.test.cpp @@ -260,6 +260,38 @@ namespace xo { REQUIRE(copy->capacity() == src->capacity()); REQUIRE(std::strcmp(copy->chars(), src->chars()) == 0); } + + TEST_CASE("DString-sprintf", "[object2][DString]") + { + ArenaConfig cfg { .name_ = "testarena", + .size_ = 4*1024 }; + DArena arena = DArena::map(cfg); + auto alloc = with_facet::mkobj(&arena); + + DString * s = DString::empty(alloc, 32); + + auto n = s->sprintf("hello %s %d", "world", 42); + + REQUIRE(n == 14); + REQUIRE(s->size() == 14); + REQUIRE(std::strcmp(s->chars(), "hello world 42") == 0); + } + + TEST_CASE("DString-sprintf-truncate", "[object2][DString]") + { + ArenaConfig cfg { .name_ = "testarena", + .size_ = 4*1024 }; + DArena arena = DArena::map(cfg); + auto alloc = with_facet::mkobj(&arena); + + DString * s = DString::empty(alloc, 8); + + auto n = s->sprintf("hello world"); + + REQUIRE(n == 7); + REQUIRE(s->size() == 7); + REQUIRE(std::strcmp(s->chars(), "hello w") == 0); + } } /*namespace ut*/ } /*namespace xo*/