Add Base64::EncodedSize to tidy up allocations (flutter/engine#46624)
As a follow-up to #46543, this adds a dedicated function to compute the size of the buffer needed to encode data using Base64 instead of calling the encode function with nullptr. ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide] and the [C++, Objective-C, Java style guides]. - [ ] I listed at least one issue that this PR fixes in the description above. - [x] I added new tests to check the change I am making or feature I am adding, or the PR is [test-exempt]. See [testing the engine] for instructions on writing and running engine tests. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I signed the [CLA]. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/wiki/Tree-hygiene#overview [Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [test-exempt]: https://github.com/flutter/flutter/wiki/Tree-hygiene#tests [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style [testing the engine]: https://github.com/flutter/flutter/wiki/Testing-the-engine [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/wiki/Chat
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
return (length + 2) / 3 * 4;
|
||||
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 EncodedSize(length);
|
||||
}
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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());
|
||||
};
|
||||
@@ -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());
|
||||
};
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user