fmt/test/output-range-test.cc
ThePhD 0743b2fe44
(Non-Appending )Output Ranges in fmt::format_(in)to!
- format_to(some_char_array, ...) will now do the right thing for the most part, and also supports appending to existing ranges (using the same conceptual ideals as as std::ranges::to)
- The API for format_to is a bit complicated since we do appending and also pass/support all the existing iterator-based use cases.
- format_into is a cleaner API that accepts ranges and output iterators, and does not do appending for those ranges that it recognizes (just fills in the `[begin, end)`). This is necessary to avoid strange behaviors on whether or not a container may or may not meet the appending requirements (e.g., more consistent in generic code).
- We lose a lot of compile-time performance with how we're checking things now, so not the best job we could be doing....
- Much of that compile-time performance can be gained back with more rigorous return-style enable_if and such, but that is beyond my work
- Actual performance for the calls themselves are only marginally smaller for pointer-based iterators (fmt is, internally, lacking continguous iterator support. Counterpoint; buffers are the only case that matters! (this is a bit of a lie lmaoo))
2023-12-15 14:27:38 -05:00

193 lines
7.3 KiB
C++

// Formatting library for C++ - std::ostream support tests
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#include "fmt/format.h"
#if FMT_OUTPUT_RANGES
#include "gmock/gmock.h"
#include "gtest-extra.h"
#include "util.h"
#include <vector>
#include <list>
#include <deque>
#include <array>
#include <span>
TEST(output_range_c_array_char_test, format_into) {
char buffer[4];
buffer[3] = 'x';
auto result = fmt::format_into(buffer, "{}", "abc");
EXPECT_EQ(buffer + 3, result.begin());
EXPECT_EQ("abc", fmt::string_view(buffer, 3));
EXPECT_EQ("abcx", fmt::string_view(buffer, 4));
result = fmt::format_into(buffer, "x{}y", "abc");
EXPECT_EQ(buffer + 4, result.begin());
EXPECT_EQ("xabc", fmt::string_view(buffer, 4));
}
TEST(output_range_array_char_test, format_into) {
std::array<char, 4> buffer;
buffer[3] = 'x';
auto result = fmt::format_into(buffer, "{}", "abc");
EXPECT_EQ(buffer.begin() + 3, result.begin());
EXPECT_EQ("abc", fmt::string_view(buffer.data(), 3));
EXPECT_EQ("abcx", fmt::string_view(buffer.data(), 4));
result = fmt::format_into(buffer, "x{}y", "abc");
EXPECT_EQ(buffer.begin() + 4, result.begin());
EXPECT_EQ("xabc", fmt::string_view(buffer.data(), 4));
}
TEST(output_range_span_array_char_test, format_into) {
std::array<char, 4> storage;
std::span<char> buffer(storage);
buffer[3] = 'x';
auto result = fmt::format_into(buffer, "{}", "abc");
EXPECT_EQ(buffer.begin() + 3, result.begin());
EXPECT_EQ("abc", fmt::string_view(buffer.data(), 3));
EXPECT_EQ("abcx", fmt::string_view(buffer.data(), 4));
result = fmt::format_into(buffer, "x{}y", "abc");
EXPECT_EQ(buffer.begin() + 4, result.begin());
EXPECT_EQ("xabc", fmt::string_view(buffer.data(), 4));
}
TEST(output_range_vector_char_test, format_into) {
std::vector<char> buffer(4, '\0');
buffer[3] = 'x';
auto result = fmt::format_into(buffer, "{}", "abc");
EXPECT_EQ(buffer.begin() + 3, result.begin());
EXPECT_EQ("abc", fmt::string_view(buffer.data(), 3));
EXPECT_EQ("abcx", fmt::string_view(buffer.data(), 4));
result = fmt::format_into(buffer, "x{}y", "abc");
EXPECT_EQ(buffer.begin() + 4, result.begin());
EXPECT_EQ("xabc", fmt::string_view(buffer.data(), 4));
}
TEST(output_range_list_char_test, format_into) {
std::list<char> buffer(4, '\0');
using subrng = std::ranges::subrange<typename decltype(buffer)::iterator>;
auto fourth_it = std::ranges::next(buffer.begin(), 3);
auto end = buffer.end();
subrng first3_subrange(buffer.begin(), fourth_it);
*fourth_it = 'x';
auto result = fmt::format_into(buffer, "{}", "abc");
EXPECT_EQ(fourth_it, result.begin());
EXPECT_TRUE(std::ranges::equal(fmt::string_view("abc"), first3_subrange));
EXPECT_TRUE(std::ranges::equal(fmt::string_view("abcx"), buffer));
result = fmt::format_into(buffer, "x{}y", "abc");
EXPECT_EQ(end, result.begin());
EXPECT_TRUE(std::ranges::equal(fmt::string_view("xabc"), buffer));
}
TEST(output_range_deque_char_test, format_into) {
std::deque<char> buffer(4, '\0');
using subrng = std::ranges::subrange<typename decltype(buffer)::iterator>;
auto fourth_it = std::ranges::next(buffer.begin(), 3);
auto end = buffer.end();
subrng first3_subrange(buffer.begin(), fourth_it);
*fourth_it = 'x';
auto result = fmt::format_into(buffer, "{}", "abc");
EXPECT_EQ(fourth_it, result.begin());
EXPECT_TRUE(std::ranges::equal(fmt::string_view("abc"), first3_subrange));
EXPECT_TRUE(std::ranges::equal(fmt::string_view("abcx"), buffer));
result = fmt::format_into(buffer, "x{}y", "abc");
EXPECT_EQ(end, result.begin());
EXPECT_TRUE(std::ranges::equal(fmt::string_view("xabc"), buffer));
}
TEST(output_range_c_array_char_test, format_to) {
char buffer[4];
buffer[3] = 'x';
auto result = fmt::format_to(buffer, "{}", "abc");
EXPECT_EQ(buffer + 3, result.begin());
EXPECT_EQ("abc", fmt::string_view(buffer, 3));
EXPECT_EQ("abcx", fmt::string_view(buffer, 4));
result = fmt::format_to(buffer, "x{}y", "abc");
EXPECT_EQ(buffer + 4, result.begin());
EXPECT_EQ("xabc", fmt::string_view(buffer, 4));
}
TEST(output_range_array_char_test, format_to) {
std::array<char, 4> buffer;
buffer[3] = 'x';
auto result = fmt::format_to(buffer, "{}", "abc");
EXPECT_EQ(buffer.begin() + 3, result.begin());
EXPECT_EQ("abc", fmt::string_view(buffer.data(), 3));
EXPECT_EQ("abcx", fmt::string_view(buffer.data(), 4));
result = fmt::format_to(buffer, "x{}y", "abc");
EXPECT_EQ(buffer.begin() + 4, result.begin());
EXPECT_EQ("xabc", fmt::string_view(buffer.data(), 4));
}
TEST(output_range_span_array_char_test, format_to) {
std::array<char, 4> storage;
std::span<char> buffer(storage);
buffer[3] = 'x';
auto result = fmt::format_to(buffer, "{}", "abc");
EXPECT_EQ(buffer.begin() + 3, result.begin());
EXPECT_EQ("abc", fmt::string_view(buffer.data(), 3));
EXPECT_EQ("abcx", fmt::string_view(buffer.data(), 4));
result = fmt::format_to(buffer, "x{}y", "abc");
EXPECT_EQ(buffer.begin() + 4, result.begin());
EXPECT_EQ("xabc", fmt::string_view(buffer.data(), 4));
}
TEST(output_range_vector_char_test, format_to) {
std::vector<char> buffer{};
auto result = fmt::format_to(buffer, "{}", "abc");
EXPECT_EQ(buffer.begin() + 3, result.begin());
EXPECT_EQ("abc", fmt::string_view(buffer.data(), 3));
result = fmt::format_to(buffer, "x{}y", "abc");
EXPECT_EQ(buffer.begin() + 8, result.begin());
EXPECT_EQ(buffer.begin() + buffer.size(), result.begin());
EXPECT_EQ(buffer.end(), result.begin());
EXPECT_EQ("abcxabcy", fmt::string_view(buffer.data(), 8));
}
TEST(output_range_basic_string_char_test, format_to) {
std::string buffer{};
auto result = fmt::format_to(buffer, "{}", "abc");
EXPECT_EQ(buffer.begin() + 3, result.begin());
EXPECT_EQ("abc", buffer);
result = fmt::format_to(buffer, "x{}y", "abc");
EXPECT_EQ(buffer.begin() + 8, result.begin());
EXPECT_EQ(buffer.begin() + buffer.size(), result.begin());
EXPECT_EQ(buffer.end(), result.begin());
EXPECT_EQ("abcxabcy", buffer);
}
TEST(output_range_list_char_test, format_to) {
std::list<char> buffer{};
auto result = fmt::format_to(buffer, "{}", "abc");
EXPECT_EQ(buffer.end(), result.begin());
EXPECT_EQ(std::ranges::next(buffer.begin(), 3), result.begin());
EXPECT_EQ(std::ranges::next(buffer.begin(), buffer.size()), result.begin());
EXPECT_TRUE(std::ranges::equal(fmt::string_view("abc"), buffer));
result = fmt::format_to(buffer, "x{}y", "abc");
EXPECT_EQ(buffer.end(), result.begin());
EXPECT_EQ(std::ranges::next(buffer.begin(), 8), result.begin());
EXPECT_EQ(std::ranges::next(buffer.begin(), buffer.size()), result.begin());
EXPECT_TRUE(std::ranges::equal(fmt::string_view("abcxabcy"), buffer));
}
TEST(output_range_deque_char_test, format_to) {
std::deque<char> buffer{};
auto result = fmt::format_to(buffer, "{}", "abc");
EXPECT_EQ(buffer.end(), result.begin());
EXPECT_EQ(std::ranges::next(buffer.begin(), 3), result.begin());
EXPECT_EQ(std::ranges::next(buffer.begin(), buffer.size()), result.begin());
EXPECT_TRUE(std::ranges::equal(fmt::string_view("abc"), buffer));
result = fmt::format_to(buffer, "x{}y", "abc");
EXPECT_EQ(buffer.end(), result.begin());
EXPECT_EQ(std::ranges::next(buffer.begin(), 8), result.begin());
EXPECT_EQ(std::ranges::next(buffer.begin(), buffer.size()), result.begin());
EXPECT_TRUE(std::ranges::equal(fmt::string_view("abcxabcy"), buffer));
}
#endif