Skip to content

Commit e83ef27

Browse files
jakecobbcopybara-github
authored andcommitted
Add conversion operator to std::array for StrSplit.
This is similar to the conversion operator to std::pair, but for N elements instead of two. Missing elements are filled with the empty string and extra elements are discarded. PiperOrigin-RevId: 693727220 Change-Id: Icfee16613a4859b019ca043da712f20797386beb
1 parent 4794821 commit e83ef27

File tree

3 files changed

+99
-1
lines changed

3 files changed

+99
-1
lines changed

absl/strings/internal/str_split_internal.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,10 @@ using ShouldUseLifetimeBoundForPair = std::integral_constant<
253253
(std::is_same<First, absl::string_view>::value ||
254254
std::is_same<Second, absl::string_view>::value)>;
255255

256+
template <typename StringType, typename ElementType, std::size_t Size>
257+
using ShouldUseLifetimeBoundForArray = std::integral_constant<
258+
bool, std::is_same<StringType, std::string>::value &&
259+
std::is_same<ElementType, absl::string_view>::value>;
256260

257261
// This class implements the range that is returned by absl::StrSplit(). This
258262
// class has templated conversion operators that allow it to be implicitly
@@ -344,7 +348,38 @@ class Splitter {
344348
return ConvertToPair<First, Second>();
345349
}
346350

351+
// Returns an array with its elements set to the first few strings returned by
352+
// the begin() iterator. If there is not a corresponding value the empty
353+
// string is used.
354+
template <typename ElementType, std::size_t Size,
355+
std::enable_if_t<ShouldUseLifetimeBoundForArray<
356+
StringType, ElementType, Size>::value,
357+
std::nullptr_t> = nullptr>
358+
// NOLINTNEXTLINE(google-explicit-constructor)
359+
operator std::array<ElementType, Size>() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
360+
return ConvertToArray<ElementType, Size>();
361+
}
362+
363+
template <typename ElementType, std::size_t Size,
364+
std::enable_if_t<!ShouldUseLifetimeBoundForArray<
365+
StringType, ElementType, Size>::value,
366+
std::nullptr_t> = nullptr>
367+
// NOLINTNEXTLINE(google-explicit-constructor)
368+
operator std::array<ElementType, Size>() const {
369+
return ConvertToArray<ElementType, Size>();
370+
}
371+
347372
private:
373+
template <typename ElementType, std::size_t Size>
374+
std::array<ElementType, Size> ConvertToArray() const {
375+
std::array<ElementType, Size> a;
376+
auto it = begin();
377+
for (std::size_t i = 0; i < Size && it != end(); ++i, ++it) {
378+
a[i] = ElementType(*it);
379+
}
380+
return a;
381+
}
382+
348383
template <typename First, typename Second>
349384
std::pair<First, Second> ConvertToPair() const {
350385
absl::string_view first, second;

absl/strings/str_split.h

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -444,8 +444,10 @@ using EnableSplitIfString =
444444
// behavior works for:
445445
//
446446
// 1) All standard STL containers including `std::vector`, `std::list`,
447-
// `std::deque`, `std::set`,`std::multiset`, 'std::map`, and `std::multimap`
447+
// `std::deque`, `std::set`,`std::multiset`, 'std::map`, and `std::multimap`.
448448
// 2) `std::pair` (which is not actually a container). See below.
449+
// 3) `std::array`, which is a container but has different behavior due to its
450+
// fixed size. See below.
449451
//
450452
// Example:
451453
//
@@ -487,6 +489,21 @@ using EnableSplitIfString =
487489
// std::pair<std::string, std::string> p = absl::StrSplit("a,b,c", ',');
488490
// // p.first == "a", p.second == "b" // "c" is omitted.
489491
//
492+
//
493+
// Splitting to `std::array` is similar to splitting to `std::pair`, but for
494+
// N elements instead of two; missing elements are filled with the empty string
495+
// and extra elements are discarded.
496+
//
497+
// Examples:
498+
//
499+
// // Stores first two split strings as the elements in a std::array.
500+
// std::array<std::string, 2> a = absl::StrSplit("a,b,c", ',');
501+
// // a[0] == "a", a[1] == "b" // "c" is omitted.
502+
//
503+
// // The second element is empty.
504+
// std::array<std::string, 2> a = absl::StrSplit("a,", ',');
505+
// // a[0] == "a", a[1] == ""
506+
//
490507
// The `StrSplit()` function can be used multiple times to perform more
491508
// complicated splitting logic, such as intelligently parsing key-value pairs.
492509
//

absl/strings/str_split_test.cc

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
#include "absl/strings/str_split.h"
1616

17+
#include <array>
1718
#include <cstddef>
1819
#include <cstdint>
1920
#include <deque>
@@ -397,6 +398,12 @@ void TestPairConversionOperator(const Splitter& splitter) {
397398
EXPECT_EQ(p, (std::pair<FirstType, SecondType>("a", "b")));
398399
}
399400

401+
template <typename StringType, typename Splitter>
402+
void TestArrayConversionOperator(const Splitter& splitter) {
403+
std::array<StringType, 2> a = splitter;
404+
EXPECT_THAT(a, ElementsAre("a", "b"));
405+
}
406+
400407
TEST(Splitter, ConversionOperator) {
401408
auto splitter = absl::StrSplit("a,b,c,d", ',');
402409

@@ -467,6 +474,10 @@ TEST(Splitter, ConversionOperator) {
467474
TestPairConversionOperator<absl::string_view, std::string>(splitter);
468475
TestPairConversionOperator<std::string, absl::string_view>(splitter);
469476
TestPairConversionOperator<std::string, std::string>(splitter);
477+
478+
// Tests conversion to std::array
479+
TestArrayConversionOperator<std::string>(splitter);
480+
TestArrayConversionOperator<absl::string_view>(splitter);
470481
}
471482

472483
// A few additional tests for conversion to std::pair. This conversion is
@@ -511,6 +522,41 @@ TEST(Splitter, ToPair) {
511522
}
512523
}
513524

525+
// std::array tests similar to std::pair tests above, testing fewer, exactly,
526+
// or more elements than the array size.
527+
TEST(Splitter, ToArray) {
528+
{
529+
// Empty string
530+
std::array<std::string, 2> p = absl::StrSplit("", ',');
531+
EXPECT_THAT(p, ElementsAre("", ""));
532+
}
533+
534+
{
535+
// Only first
536+
std::array<std::string, 2> p = absl::StrSplit("a", ',');
537+
EXPECT_THAT(p, ElementsAre("a", ""));
538+
}
539+
540+
{
541+
// Only second
542+
std::array<std::string, 2> p = absl::StrSplit(",b", ',');
543+
EXPECT_THAT(p, ElementsAre("", "b"));
544+
}
545+
546+
{
547+
// First and second.
548+
std::array<std::string, 2> p = absl::StrSplit("a,b", ',');
549+
EXPECT_THAT(p, ElementsAre("a", "b"));
550+
}
551+
552+
{
553+
// First and second and then more stuff that will be ignored.
554+
std::array<std::string, 2> p = absl::StrSplit("a,b,c", ',');
555+
EXPECT_THAT(p, ElementsAre("a", "b"));
556+
// "c" is omitted.
557+
}
558+
}
559+
514560
TEST(Splitter, Predicates) {
515561
static const char kTestChars[] = ",a, ,b,";
516562
using absl::AllowEmpty;

0 commit comments

Comments
 (0)