based

Opinionated utility library
git clone git://git.dimitrijedobrota.com/based.git
Log | Files | Refs | README | LICENSE | HACKING | CONTRIBUTING | CODE_OF_CONDUCT | BUILDING

commit ffa7d35ed8baeff0e5db817445a5a55d494718d1
parent e2e839a3bc872c30a3de628a2d3caf72d95660aa
author Dimitrije Dobrota < mail@dimitrijedobrota.com >
date Thu, 12 Jun 2025 20:24:12 +0200

Simple string format utility

Diffstat:
A include/based/string/format.hpp | ++++++++++++++++++++++++++++
M test/CMakeLists.txt | ++ -
A test/source/string/format_test.cpp | ++++++++++++++++++++++++++++++++
A test/source/string/literal_test.cpp | ++++++++++++++++++++++++++++++++++++++
D test/source/string_literal_test.cpp | --------------------------------------

5 files changed, 100 insertions(+), 39 deletions(-)


diff --git a/ include/based/string/format.hpp b/ include/based/string/format.hpp

@@ -0,0 +1,28 @@

#pragma once

#include <string>
#include <string_view>

namespace based
{

constexpr auto string_format(std::string_view format, auto... args)
{
std::string_view::size_type last = 0;
std::string res;

const auto func = [&](std::string_view arg)
{
if (auto pos = format.find("{}", last); pos != std::string_view::npos) {
res += format.substr(last, pos - last);
res += arg;
last = pos + 2;
}
};
(func(args), ...);
res += format.substr(last, std::size(format) - last);

return res;
}

} // namespace based

diff --git a/ test/CMakeLists.txt b/ test/CMakeLists.txt

@@ -84,7 +84,8 @@ add_test(. list_test)


## ----- String -----

add_test(. string_literal_test)
add_test(string literal_test)
add_test(string format_test)

## ----- Char -----

diff --git a/ test/source/string/format_test.cpp b/ test/source/string/format_test.cpp

@@ -0,0 +1,32 @@

#include "based/string/format.hpp"

#include <catch2/catch_test_macros.hpp>

TEST_CASE("format", "[string/format]")
{
const std::string format = "This is a {}! {}";

SECTION("none")
{
const auto res = based::string_format(format);
REQUIRE(res == "This is a {}! {}");
}

SECTION("one")
{
const auto res = based::string_format(format, "test");
REQUIRE(res == "This is a test! {}");
}

SECTION("two")
{
const auto res = based::string_format(format, "test", "hello");
REQUIRE(res == "This is a test! hello");
}

SECTION("three")
{
const auto res = based::string_format(format, "test", "hello", "yo");
REQUIRE(res == "This is a test! hello");
}
}

diff --git a/ test/source/string/literal_test.cpp b/ test/source/string/literal_test.cpp

@@ -0,0 +1,38 @@

#include <catch2/catch_test_macros.hpp>

#include "based/string/literal.hpp"

TEST_CASE("empty", "[string/literal]")
{
const based::string_literal sltr = "";

REQUIRE(sltr.size() == 1);
REQUIRE(std::memcmp(sltr.data(), "", sltr.size()) == 0);
}

TEST_CASE("nonempty", "[string/literal]")
{
const based::string_literal sltr = "nonempty";

REQUIRE(sltr.size() == 9);
REQUIRE(std::memcmp(sltr.data(), "nonempty", sltr.size()) == 0);
}

TEST_CASE("template", "[string/literal]")
{
const auto data = []<based::string_literal l>()
{
return l.data();
};

const auto size = []<based::string_literal l>()
{
return l.size();
};

REQUIRE(size.operator()<"">() == 1);
REQUIRE(size.operator()<"nonempty">() == 9);

REQUIRE(std::memcmp(data.operator()<"">(), "", 1) == 0);
REQUIRE(std::memcmp(data.operator()<"nonempty">(), "nonempty", 9) == 0);
}

diff --git a/ test/source/string_literal_test.cpp b/ test/source/string_literal_test.cpp

@@ -1,38 +0,0 @@

#include <catch2/catch_test_macros.hpp>

#include "based/string/literal.hpp"

TEST_CASE("empty", "[string/string_literal]")
{
const based::string_literal sltr = "";

REQUIRE(sltr.size() == 1);
REQUIRE(std::memcmp(sltr.data(), "", sltr.size()) == 0);
}

TEST_CASE("nonempty", "[string/string_literal]")
{
const based::string_literal sltr = "nonempty";

REQUIRE(sltr.size() == 9);
REQUIRE(std::memcmp(sltr.data(), "nonempty", sltr.size()) == 0);
}

TEST_CASE("template", "[string/string_literal]")
{
const auto data = []<based::string_literal l>()
{
return l.data();
};

const auto size = []<based::string_literal l>()
{
return l.size();
};

REQUIRE(size.operator()<"">() == 1);
REQUIRE(size.operator()<"nonempty">() == 9);

REQUIRE(std::memcmp(data.operator()<"">(), "", 1) == 0);
REQUIRE(std::memcmp(data.operator()<"nonempty">(), "nonempty", 9) == 0);
}