Skip to content

Commit

Permalink
Allows absl::StrCat to accept types that implement AbslStringify()
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 478050535
Change-Id: I8e4a4b01aceb8d712476101633eac0ce8647823a
  • Loading branch information
Abseil Team authored and copybara-github committed Sep 30, 2022
1 parent e8304a5 commit 7f3c0d7
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 0 deletions.
36 changes: 36 additions & 0 deletions absl/strings/str_cat.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,52 @@
#include <assert.h>

#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <string>

#include "absl/strings/ascii.h"
#include "absl/strings/internal/resize_uninitialized.h"
#include "absl/strings/numbers.h"
#include "absl/strings/string_view.h"

namespace absl {
ABSL_NAMESPACE_BEGIN

namespace strings_internal {
void StringifySink::Append(size_t count, char ch) { buffer_.append(count, ch); }

void StringifySink::Append(string_view v) {
buffer_.append(v.data(), v.size());
}

bool StringifySink::PutPaddedString(string_view v, int width, int precision,
bool left) {
size_t space_remaining = 0;

if (width >= 0) space_remaining = static_cast<size_t>(width);

size_t n = v.size();

if (precision >= 0) n = (std::min)(n, static_cast<size_t>(precision));

string_view shown(v.data(), n);

if (shown.size() < space_remaining) {
space_remaining = space_remaining - shown.size();
} else {
space_remaining = 0;
}

if (!left) Append(space_remaining, ' ');
Append(shown);
if (left) Append(space_remaining, ' ');
return true;
}

} // namespace strings_internal

AlphaNum::AlphaNum(Hex hex) {
static_assert(numbers_internal::kFastToBufferSize >= 32,
"This function only works when output buffer >= 32 bytes long");
Expand Down
38 changes: 38 additions & 0 deletions absl/strings/str_cat.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
#include <cstdint>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>

#include "absl/base/port.h"
Expand All @@ -76,6 +77,27 @@ struct AlphaNumBuffer {
size_t size;
};

class StringifySink {
public:
void Append(size_t count, char ch);

void Append(string_view v);

bool PutPaddedString(string_view v, int width, int precision, bool left);

template <typename T>
friend string_view ExtractStringification(StringifySink& sink, const T& v);

private:
std::string buffer_;
};

template <typename T>
string_view ExtractStringification(StringifySink& sink, const T& v) {
AbslStringify(sink, v);
return sink.buffer_;
}

} // namespace strings_internal

// Enum that specifies the number of significant digits to return in a `Hex` or
Expand Down Expand Up @@ -208,6 +230,15 @@ struct Dec {
// `StrAppend()`, providing efficient conversion of numeric, boolean, and
// hexadecimal values (through the `Hex` type) into strings.

template <typename T, typename = void>
struct HasAbslStringify : std::false_type {};

template <typename T>
struct HasAbslStringify<T, std::enable_if_t<std::is_void<decltype(AbslStringify(
std::declval<strings_internal::StringifySink&>(),
std::declval<const T&>()))>::value>>
: std::true_type {};

class AlphaNum {
public:
// No bool ctor -- bools convert to an integral type.
Expand Down Expand Up @@ -255,6 +286,13 @@ class AlphaNum {
: piece_(NullSafeStringView(c_str)) {} // NOLINT(runtime/explicit)
AlphaNum(absl::string_view pc) : piece_(pc) {} // NOLINT(runtime/explicit)

template <typename T, typename = typename std::enable_if<
HasAbslStringify<T>::value>::type>
AlphaNum( // NOLINT(runtime/explicit)
const T& v, // NOLINT(runtime/explicit)
strings_internal::StringifySink&& sink = {}) // NOLINT(runtime/explicit)
: piece_(strings_internal::ExtractStringification(sink, v)) {}

template <typename Allocator>
AlphaNum( // NOLINT(runtime/explicit)
const std::basic_string<char, std::char_traits<char>, Allocator>& str)
Expand Down
20 changes: 20 additions & 0 deletions absl/strings/str_cat_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -612,4 +612,24 @@ TEST(Numbers, TestFunctionsMovedOverFromNumbersMain) {
TestFastPrints();
}

struct PointStringify {
template <typename FormatSink>
friend void AbslStringify(FormatSink& sink, const PointStringify& p) {
sink.Append("(");
sink.Append(absl::StrCat(p.x));
sink.Append(", ");
sink.Append(absl::StrCat(p.y));
sink.Append(")");
}

double x = 10.0;
double y = 20.0;
};

TEST(StrCat, AbslStringifyExample) {
PointStringify p;
EXPECT_EQ(absl::StrCat(p), "(10, 20)");
EXPECT_EQ(absl::StrCat("a ", p, " z"), "a (10, 20) z");
}

} // namespace

0 comments on commit 7f3c0d7

Please sign in to comment.