Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Add Base64::EncodedSize to tidy up allocations #46624

Merged
merged 2 commits into from
Oct 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions flow/layers/performance_overlay_layer_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,7 @@ static void TestPerformanceOverlayLayerGold(int refresh_rate) {
wstream.write(snapshot_data->data(), snapshot_data->size());
wstream.flush();

// TODO(kjlubick) We shouldn't need to call Encode once to pre-flight the
// encode length. It should be ceil(4/3 * sksl.value->size()).
size_t b64_size =
Base64::Encode(snapshot_data->data(), snapshot_data->size(), nullptr);
size_t b64_size = Base64::EncodedSize(snapshot_data->size());
sk_sp<SkData> b64_data = SkData::MakeUninitialized(b64_size + 1);
char* b64_char = static_cast<char*>(b64_data->writable_data());
Base64::Encode(snapshot_data->data(), snapshot_data->size(), b64_char);
Expand Down
59 changes: 29 additions & 30 deletions shell/common/base64.cc
Original file line number Diff line number Diff line change
Expand Up @@ -116,42 +116,41 @@ Base64::Error Base64::Decode(const void* srcv,
}

size_t Base64::Encode(const void* srcv, size_t length, void* dstv) {
FML_DCHECK(dstv);
const unsigned char* src = static_cast<const unsigned char*>(srcv);
unsigned char* dst = static_cast<unsigned char*>(dstv);

const char* encode = kDefaultEncode;
if (dst) {
size_t remainder = length % 3;
char unsigned const* const end = &src[length - remainder];
while (src < end) {
unsigned a = *src++;
unsigned b = *src++;
unsigned c = *src++;
int d = c & 0x3F;
c = (c >> 6 | b << 2) & 0x3F;
b = (b >> 4 | a << 4) & 0x3F;
a = a >> 2;
*dst++ = encode[a];
*dst++ = encode[b];
*dst++ = encode[c];
*dst++ = encode[d];
}
if (remainder > 0) {
int k1 = 0;
int k2 = EncodePad;
int a = (uint8_t)*src++;
if (remainder == 2) {
int b = *src++;
k1 = b >> 4;
k2 = (b << 2) & 0x3F;
}
*dst++ = encode[a >> 2];
*dst++ = encode[(k1 | a << 4) & 0x3F];
*dst++ = encode[k2];
*dst++ = encode[EncodePad];
size_t remainder = length % 3;
char unsigned const* const end = &src[length - remainder];
while (src < end) {
unsigned a = *src++;
unsigned b = *src++;
unsigned c = *src++;
int d = c & 0x3F;
c = (c >> 6 | b << 2) & 0x3F;
b = (b >> 4 | a << 4) & 0x3F;
a = a >> 2;
*dst++ = encode[a];
*dst++ = encode[b];
*dst++ = encode[c];
*dst++ = encode[d];
}
if (remainder > 0) {
int k1 = 0;
int k2 = EncodePad;
int a = (uint8_t)*src++;
if (remainder == 2) {
int b = *src++;
k1 = b >> 4;
k2 = (b << 2) & 0x3F;
}
*dst++ = encode[a >> 2];
*dst++ = encode[(k1 | a << 4) & 0x3F];
*dst++ = encode[k2];
*dst++ = encode[EncodePad];
}
return (length + 2) / 3 * 4;
return EncodedSize(length);
}

} // namespace flutter
20 changes: 13 additions & 7 deletions shell/common/base64.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,27 @@ struct Base64 {
/**
Base64 encodes src into dst.

Normally this is called once with 'dst' nullptr to get the required size,
then again with an allocated 'dst' pointer to do the actual encoding.

@param dst nullptr or a pointer to a buffer large enough to receive the
result
@param dst a pointer to a buffer large enough to receive the result.

@return the required length of dst for encoding.
*/
static size_t Encode(const void* src, size_t length, void* dst);

/**
Returns the length of the buffer that needs to be allocated to encode
srcDataLength bytes.
*/
static size_t EncodedSize(size_t srcDataLength) {
// Take the floor of division by 3 to find the number of groups that need to
// be encoded. Each group takes 4 bytes to be represented in base64.
return ((srcDataLength + 2) / 3) * 4;
}

/**
Base64 decodes src into dst.

Normally this is called once with 'dst' nullptr to get the required size,
then again with an allocated 'dst' pointer to do the actual encoding.
This can be called once with 'dst' nullptr to get the required size,
then again with an allocated 'dst' pointer to do the actual decoding.

@param dst nullptr or a pointer to a buffer large enough to receive the
result
Expand Down
2 changes: 2 additions & 0 deletions shell/common/base64_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ TEST(Base64, EncodeStrings) {
char buffer[256];
size_t len = Base64::Encode(input.c_str(), input.length(), &buffer);
FML_CHECK(len <= 256);
ASSERT_EQ(len, Base64::EncodedSize(input.length()));
std::string actual(buffer, len);
ASSERT_STREQ(actual.c_str(), output.c_str());
};
Expand All @@ -34,6 +35,7 @@ TEST(Base64, EncodeBytes) {
char buffer[512];
size_t len = Base64::Encode(input, num, &buffer);
FML_CHECK(len <= 512);
ASSERT_EQ(len, Base64::EncodedSize(num));
std::string actual(buffer, len);
ASSERT_STREQ(actual.c_str(), output.c_str());
};
Expand Down
4 changes: 1 addition & 3 deletions shell/common/rasterizer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -910,9 +910,7 @@ Rasterizer::Screenshot Rasterizer::ScreenshotLastLayerTree(
}

if (base64_encode) {
// TODO(kjlubick) We shouldn't need to call Encode once to pre-flight the
// encode length. It should be ceil(4/3 * sksl.value->size()).
size_t b64_size = Base64::Encode(data->data(), data->size(), nullptr);
size_t b64_size = Base64::EncodedSize(data->size());
auto b64_data = SkData::MakeUninitialized(b64_size);
Base64::Encode(data->data(), data->size(), b64_data->writable_data());
return Rasterizer::Screenshot{b64_data, layer_tree->frame_size(), format};
Expand Down
5 changes: 1 addition & 4 deletions shell/common/shell.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1840,10 +1840,7 @@ bool Shell::OnServiceProtocolGetSkSLs(
PersistentCache* persistent_cache = PersistentCache::GetCacheForProcess();
std::vector<PersistentCache::SkSLCache> sksls = persistent_cache->LoadSkSLs();
for (const auto& sksl : sksls) {
// TODO(kjlubick) We shouldn't need to call Encode once to pre-flight the
// encode length. It should be ceil(4/3 * sksl.value->size()).
size_t b64_size =
Base64::Encode(sksl.value->data(), sksl.value->size(), nullptr);
size_t b64_size = Base64::EncodedSize(sksl.value->size());
sk_sp<SkData> b64_data = SkData::MakeUninitialized(b64_size + 1);
char* b64_char = static_cast<char*>(b64_data->writable_data());
Base64::Encode(sksl.value->data(), sksl.value->size(), b64_char);
Expand Down