Skip to content

Commit fb83c0c

Browse files
authored
refactor(GCS+gRPC): move MakeCord() helpers (#12724)
Move the `MakeCord(std::string)`, and `MakeCord(std::vector<T>)` helpers to their own header. I want to use this outside the `AsyncClient` implementation.
1 parent 929c0f2 commit fb83c0c

File tree

10 files changed

+224
-90
lines changed

10 files changed

+224
-90
lines changed

google/cloud/internal/random.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_INTERNAL_RANDOM_H
1717

1818
#include "google/cloud/version.h"
19+
#include <algorithm>
1920
#include <random>
2021
#include <string>
2122
#include <vector>
@@ -58,6 +59,35 @@ inline DefaultPRNG MakeDefaultPRNG() {
5859
*/
5960
std::string Sample(DefaultPRNG& gen, int n, std::string const& population);
6061

62+
template <typename Collection,
63+
typename std::enable_if<std::is_same<Collection, std::string>::value,
64+
int>::type = 0>
65+
std::string RandomDataToCollection(std::string v) {
66+
// This is not motivated by a desire to optimize this function (though that is
67+
// nice). The issue is that I (coryan@) could not figure out how to write a
68+
// generic version of this function that works with `std::vector<std::byte>`
69+
// and `std::string`.
70+
return v;
71+
}
72+
73+
template <typename Collection,
74+
typename std::enable_if<!std::is_same<Collection, std::string>::value,
75+
int>::type = 0>
76+
Collection RandomDataToCollection(std::string v) {
77+
Collection result(v.size());
78+
std::transform(v.begin(), v.end(), result.begin(), [](auto c) {
79+
return static_cast<typename Collection::value_type>(c);
80+
});
81+
return result;
82+
}
83+
84+
template <typename Collection>
85+
Collection RandomData(DefaultPRNG& generator, std::size_t size) {
86+
auto data = Sample(generator, static_cast<int>(size),
87+
"abcdefghijklmnopqrstuvwxyz0123456789");
88+
return RandomDataToCollection<Collection>(std::move(data));
89+
}
90+
6191
} // namespace internal
6292
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
6393
} // namespace cloud

google/cloud/storage/google_cloud_cpp_storage_grpc.bzl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ google_cloud_cpp_storage_grpc_hdrs = [
4545
"internal/grpc/ctype_cord_workaround.h",
4646
"internal/grpc/hmac_key_metadata_parser.h",
4747
"internal/grpc/hmac_key_request_parser.h",
48+
"internal/grpc/make_cord.h",
4849
"internal/grpc/notification_metadata_parser.h",
4950
"internal/grpc/notification_request_parser.h",
5051
"internal/grpc/object_access_control_parser.h",
@@ -87,6 +88,7 @@ google_cloud_cpp_storage_grpc_srcs = [
8788
"internal/grpc/configure_client_context.cc",
8889
"internal/grpc/hmac_key_metadata_parser.cc",
8990
"internal/grpc/hmac_key_request_parser.cc",
91+
"internal/grpc/make_cord.cc",
9092
"internal/grpc/notification_metadata_parser.cc",
9193
"internal/grpc/notification_request_parser.cc",
9294
"internal/grpc/object_access_control_parser.cc",

google/cloud/storage/google_cloud_cpp_storage_grpc.cmake

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ else ()
8585
internal/grpc/hmac_key_metadata_parser.h
8686
internal/grpc/hmac_key_request_parser.cc
8787
internal/grpc/hmac_key_request_parser.h
88+
internal/grpc/make_cord.cc
89+
internal/grpc/make_cord.h
8890
internal/grpc/notification_metadata_parser.cc
8991
internal/grpc/notification_metadata_parser.h
9092
internal/grpc/notification_request_parser.cc
@@ -285,6 +287,7 @@ if (BUILD_TESTING AND GOOGLE_CLOUD_CPP_STORAGE_ENABLE_GRPC)
285287
internal/grpc/configure_client_context_test.cc
286288
internal/grpc/hmac_key_metadata_parser_test.cc
287289
internal/grpc/hmac_key_request_parser_test.cc
290+
internal/grpc/make_cord_test.cc
288291
internal/grpc/notification_metadata_parser_test.cc
289292
internal/grpc/notification_request_parser_test.cc
290293
internal/grpc/object_access_control_parser_test.cc

google/cloud/storage/internal/async/write_payload_impl.cc

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,6 @@ namespace cloud {
2020
namespace storage_internal {
2121
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN
2222

23-
absl::Cord MakeCord(std::string p) {
24-
// The absl::Cord constructor from `std::string` splits the string into many
25-
// small buffers (and allocates a container for each). We want to avoid copies
26-
// and allocations.
27-
auto holder = std::make_shared<std::string>(std::move(p));
28-
auto contents = absl::string_view(holder->data(), holder->size());
29-
return absl::MakeCordFromExternal(contents,
30-
[b = std::move(holder)]() mutable {});
31-
}
32-
3323
storage_experimental::WritePayload MakeWritePayload(std::string p) {
3424
return WritePayloadImpl::Make(MakeCord(std::move(p)));
3525
}

google/cloud/storage/internal/async/write_payload_impl.h

Lines changed: 2 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,9 @@
1616
#define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_STORAGE_INTERNAL_ASYNC_WRITE_PAYLOAD_IMPL_H
1717

1818
#include "google/cloud/storage/async_object_requests.h"
19+
#include "google/cloud/storage/internal/grpc/make_cord.h"
1920
#include "google/cloud/version.h"
20-
#include "absl/meta/type_traits.h"
21-
#include <algorithm>
22-
#include <cstddef>
23-
#include <cstdint>
21+
#include "absl/strings/cord.h"
2422
#include <numeric>
2523

2624
namespace google {
@@ -39,28 +37,6 @@ struct WritePayloadImpl {
3937
}
4038
};
4139

42-
template <typename T>
43-
using IsPayloadType = absl::disjunction<
44-
#if GOOGLE_CLOUD_CPP_CPP_VERSION >= 201703L
45-
std::is_same<T, std::byte>,
46-
#endif
47-
std::is_same<T, char>, std::is_same<T, signed char>,
48-
std::is_same<T, unsigned char>, std::is_same<T, std::uint8_t>>;
49-
50-
/// Create an `absl::Cord`, without copying the data in @p p.
51-
absl::Cord MakeCord(std::string p);
52-
53-
/// Create an `absl::Cord`, without copying the data in @p p.
54-
template <typename T>
55-
absl::Cord MakeCord(std::vector<T> p) {
56-
static_assert(IsPayloadType<T>::value, "unexpected value type");
57-
auto holder = std::make_shared<std::vector<T>>(std::move(p));
58-
auto contents = absl::string_view(
59-
reinterpret_cast<char const*>(holder->data()), holder->size());
60-
return absl::MakeCordFromExternal(contents,
61-
[b = std::move(holder)]() mutable {});
62-
}
63-
6440
storage_experimental::WritePayload MakeWritePayload(std::string p);
6541
template <typename T,
6642
typename std::enable_if<IsPayloadType<T>::value, int>::type = 0>

google/cloud/storage/internal/async/write_payload_impl_test.cc

Lines changed: 6 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -23,39 +23,9 @@ namespace storage_internal {
2323
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN
2424
namespace {
2525

26-
using ::testing::ElementsAre;
2726
using ::testing::IsEmpty;
2827
using ::testing::Not;
2928

30-
template <typename Collection,
31-
typename std::enable_if<std::is_same<Collection, std::string>::value,
32-
int>::type = 0>
33-
Collection ToCollection(std::string v) {
34-
// This is not motivated by a desire to optimize this test helper function
35-
// (though that is nice). The issue is that I (coryan@) could not figure out
36-
// how to write a generic version of this function that works with
37-
// `std::vector<std::byte>` and `std::string`.
38-
return v;
39-
}
40-
41-
template <typename Collection,
42-
typename std::enable_if<!std::is_same<Collection, std::string>::value,
43-
int>::type = 0>
44-
Collection ToCollection(std::string v) {
45-
Collection result(v.size());
46-
std::transform(v.begin(), v.end(), result.begin(), [](auto c) {
47-
return static_cast<typename Collection::value_type>(c);
48-
});
49-
return result;
50-
}
51-
52-
template <typename Collection>
53-
Collection RandomData(internal::DefaultPRNG& generator, std::size_t size) {
54-
auto data = internal::Sample(generator, static_cast<int>(size),
55-
"abcdefghijklmnopqrstuvwxyz0123456789");
56-
return ToCollection<Collection>(std::move(data));
57-
}
58-
5929
TEST(WritePayloadImpl, Default) {
6030
auto const actual = storage_experimental::WritePayload();
6131
EXPECT_TRUE(actual.empty());
@@ -81,13 +51,6 @@ TEST(WritePayloadImpl, GetImpl) {
8151
EXPECT_EQ(WritePayloadImpl::GetImpl(actual), absl::Cord(expected));
8252
}
8353

84-
TEST(WritePayloadImpl, IsPayloadType) {
85-
EXPECT_TRUE(IsPayloadType<char>::value);
86-
EXPECT_TRUE(IsPayloadType<std::uint8_t>::value);
87-
EXPECT_FALSE(IsPayloadType<std::string>::value);
88-
EXPECT_FALSE(IsPayloadType<std::uint32_t>::value);
89-
}
90-
9154
template <typename T>
9255
class Typed : public ::testing::Test {
9356
public:
@@ -103,26 +66,14 @@ using TestVariations = ::testing::Types<
10366

10467
TYPED_TEST_SUITE(Typed, TestVariations);
10568

106-
TYPED_TEST(Typed, MakeCord) {
107-
using Collection = typename TestFixture::TestType;
108-
static auto generator = internal::MakeDefaultPRNG();
109-
auto constexpr kTestDataSize = 8 * 1024 * 1024L;
110-
auto const buffer = RandomData<Collection>(generator, kTestDataSize);
111-
auto const view = absl::string_view(
112-
reinterpret_cast<char const*>(buffer.data()), buffer.size());
113-
114-
auto const actual = MakeCord(buffer);
115-
auto chunks = actual.Chunks();
116-
EXPECT_THAT(chunks, ElementsAre(view));
117-
}
118-
11969
TYPED_TEST(Typed, MakeWritePayload) {
12070
using Collection = typename TestFixture::TestType;
12171

12272
auto const expected =
12373
std::string{"The quick brown fox jumps over the lazy dog"};
12474

125-
auto const actual = MakeWritePayload(ToCollection<Collection>(expected));
75+
auto const actual =
76+
MakeWritePayload(internal::RandomDataToCollection<Collection>(expected));
12677
EXPECT_FALSE(actual.empty());
12778
EXPECT_EQ(actual.size(), expected.size());
12879
EXPECT_THAT(actual.payload(), Not(IsEmpty()));
@@ -135,11 +86,12 @@ TYPED_TEST(Typed, MakeWritePayloadFromVector) {
13586

13687
static auto generator = internal::MakeDefaultPRNG();
13788
auto constexpr kTestDataSize = 1024;
138-
auto const part = RandomData<std::string>(generator, kTestDataSize);
89+
auto const part = internal::RandomData<std::string>(generator, kTestDataSize);
13990
auto const expected = part + part + part;
14091
auto const actual = MakeWritePayload(std::vector<Collection>{
141-
{ToCollection<Collection>(part), ToCollection<Collection>(part),
142-
ToCollection<Collection>(part)}});
92+
{internal::RandomDataToCollection<Collection>(part),
93+
internal::RandomDataToCollection<Collection>(part),
94+
internal::RandomDataToCollection<Collection>(part)}});
14395
EXPECT_FALSE(actual.empty());
14496
EXPECT_EQ(actual.size(), expected.size());
14597
EXPECT_THAT(actual.payload(), Not(IsEmpty()));
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Copyright 2023 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include "google/cloud/storage/internal/grpc/make_cord.h"
16+
#include <utility>
17+
18+
namespace google {
19+
namespace cloud {
20+
namespace storage_internal {
21+
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN
22+
23+
absl::Cord MakeCord(std::string p) {
24+
// The absl::Cord constructor from `std::string` splits the string into many
25+
// small buffers (and allocates a container for each). We want to avoid copies
26+
// and allocations.
27+
auto holder = std::make_shared<std::string>(std::move(p));
28+
auto contents = absl::string_view(holder->data(), holder->size());
29+
return absl::MakeCordFromExternal(contents,
30+
[b = std::move(holder)]() mutable {});
31+
}
32+
33+
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
34+
} // namespace storage_internal
35+
} // namespace cloud
36+
} // namespace google
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Copyright 2023 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#ifndef GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_STORAGE_INTERNAL_GRPC_MAKE_CORD_H
16+
#define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_STORAGE_INTERNAL_GRPC_MAKE_CORD_H
17+
18+
#include "google/cloud/version.h"
19+
#include "absl/meta/type_traits.h"
20+
#include "absl/strings/cord.h"
21+
#include "absl/strings/string_view.h"
22+
#include <cstddef>
23+
#include <cstdint>
24+
#include <memory>
25+
#include <string>
26+
#include <type_traits>
27+
#include <utility>
28+
#include <vector>
29+
30+
namespace google {
31+
namespace cloud {
32+
namespace storage_internal {
33+
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN
34+
35+
template <typename T>
36+
using IsPayloadType = absl::disjunction<
37+
#if GOOGLE_CLOUD_CPP_CPP_VERSION >= 201703L
38+
std::is_same<T, std::byte>,
39+
#endif
40+
std::is_same<T, char>, std::is_same<T, signed char>,
41+
std::is_same<T, unsigned char>, std::is_same<T, std::uint8_t>>;
42+
43+
/// Create an `absl::Cord`, without copying the data in @p p.
44+
absl::Cord MakeCord(std::string p);
45+
46+
/// Create an `absl::Cord`, without copying the data in @p p.
47+
template <typename T>
48+
absl::Cord MakeCord(std::vector<T> p) {
49+
static_assert(IsPayloadType<T>::value, "unexpected value type");
50+
auto holder = std::make_shared<std::vector<T>>(std::move(p));
51+
auto contents = absl::string_view(
52+
reinterpret_cast<char const*>(holder->data()), holder->size());
53+
return absl::MakeCordFromExternal(contents,
54+
[b = std::move(holder)]() mutable {});
55+
}
56+
57+
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
58+
} // namespace storage_internal
59+
} // namespace cloud
60+
} // namespace google
61+
62+
#endif // GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_STORAGE_INTERNAL_GRPC_MAKE_CORD_H

0 commit comments

Comments
 (0)