Skip to content

Commit

Permalink
Add DigesterHandle::SetWriteSizeHint(), using SetWriteSizeHint()
Browse files Browse the repository at this point in the history
…of the

`Digester` if present.

Let `DigestingWriter` and `DigestFrom()` call `SetWriteSizeHint()`.

PiperOrigin-RevId: 647652531
  • Loading branch information
QrczakMK committed Jun 28, 2024
1 parent 06ba234 commit b49bccc
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 3 deletions.
2 changes: 2 additions & 0 deletions riegeli/digests/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ cc_library(
"@com_google_absl//absl/meta:type_traits",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/strings:cord",
"@com_google_absl//absl/types:optional",
],
)

Expand Down Expand Up @@ -110,6 +111,7 @@ cc_library(
"@com_google_absl//absl/strings",
"@com_google_absl//absl/strings:cord",
"@com_google_absl//absl/types:optional",
"@com_google_absl//absl/utility",
],
)

Expand Down
55 changes: 52 additions & 3 deletions riegeli/digests/digester_handle.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "absl/status/status.h"
#include "absl/strings/cord.h"
#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
#include "absl/types/span.h"
#include "riegeli/base/any.h"
#include "riegeli/base/chain.h"
Expand Down Expand Up @@ -62,6 +63,16 @@ struct IsValidDigesterBaseTarget<
// // All of the following methods returning `bool` return `true` on success.
// // They may also return `void` which is treated as `true`.
//
// // If `write_size_hint` is not `absl::nullopt`, hints that this amount of
// // data will be written from the current position. This may improve
// // performance and memory usage.
// //
// // If the hint turns out to not match reality, nothing breaks. It is better
// // if `write_size_hint` is slightly too large than slightly too small.
// //
// // Optional. If absent, does nothing.
// void SetWriteSizeHint(absl::optional<Position> write_size_hint);
//
// // Called with consecutive fragments of data.
// //
// // Precondition: the digester is open.
Expand Down Expand Up @@ -132,6 +143,16 @@ class DigesterBaseHandle {
// Allow Nullability annotations on `DigesterBaseHandle`.
using absl_nullability_compatible = void;

// If `write_size_hint` is not `absl::nullopt`, hints that this amount of data
// will be written from the current position. This may improve performance and
// memory usage.
//
// If the hint turns out to not match reality, nothing breaks. It is better if
// `write_size_hint` is slightly too large than slightly too small.
void SetWriteSizeHint(absl::optional<Position> write_size_hint) {
methods_->set_write_size_hint(target_, write_size_hint);
}

// Called with consecutive fragments of data.
//
// Precondition: the digester is open.
Expand Down Expand Up @@ -231,6 +252,14 @@ class DigesterBaseHandle {
return true;
}

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

template <typename T>
struct DigesterTargetHasSetWriteSizeHint<
T, absl::void_t<decltype(std::declval<T&>().SetWriteSizeHint(
std::declval<absl::optional<Position>>()))>> : std::true_type {};

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

Expand Down Expand Up @@ -272,6 +301,20 @@ class DigesterBaseHandle {
decltype(std::declval<const T&>().status()), absl::Status>::value>>
: std::true_type {};

template <
typename T,
std::enable_if_t<DigesterTargetHasSetWriteSizeHint<T>::value, int> = 0>
static void SetWriteSizeHintMethod(void* target,
absl::optional<Position> write_size_hint) {
static_cast<T*>(target)->SetWriteSizeHint(write_size_hint);
}
template <
typename T,
std::enable_if_t<!DigesterTargetHasSetWriteSizeHint<T>::value, int> = 0>
static void SetWriteSizeHintMethod(
ABSL_ATTRIBUTE_UNUSED void* target,
ABSL_ATTRIBUTE_UNUSED absl::optional<Position> write_size_hint) {}

template <typename T>
static auto RawWriteMethod(void* target, absl::string_view src) {
return static_cast<T*>(target)->Write(src);
Expand Down Expand Up @@ -364,6 +407,8 @@ class DigesterBaseHandle {

protected:
struct Methods {
void (*set_write_size_hint)(void* target,
absl::optional<Position> write_size_hint);
bool (*write)(void* target, absl::string_view src);
bool (*write_chain)(void* target, const Chain& src);
bool (*write_cord)(void* target, const absl::Cord& src);
Expand All @@ -373,9 +418,13 @@ class DigesterBaseHandle {
};

template <typename T>
static constexpr Methods kMethods = {WriteMethod<T>, WriteChainMethod<T>,
WriteCordMethod<T>, WriteZerosMethod<T>,
CloseMethod<T>, StatusMethod<T>};
static constexpr Methods kMethods = {SetWriteSizeHintMethod<T>,
WriteMethod<T>,
WriteChainMethod<T>,
WriteCordMethod<T>,
WriteZerosMethod<T>,
CloseMethod<T>,
StatusMethod<T>};

template <typename T>
explicit DigesterBaseHandle(const Methods* methods, T* target)
Expand Down
35 changes: 35 additions & 0 deletions riegeli/digests/digesting_writer.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
#include "absl/strings/cord.h"
#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
#include "absl/utility/utility.h"
#include "riegeli/base/arithmetic.h"
#include "riegeli/base/assert.h"
#include "riegeli/base/chain.h"
#include "riegeli/base/dependency.h"
Expand Down Expand Up @@ -348,7 +350,14 @@ void DigestingWriter<Digester, Dest>::SetWriteSizeHintImpl(
if (dest_.IsOwning()) {
if (ABSL_PREDICT_FALSE(!SyncBuffer(*dest_))) return;
dest_->SetWriteSizeHint(write_size_hint);
if (digester_.IsOwning()) digester_.get().SetWriteSizeHint(write_size_hint);
MakeBuffer(*dest_);
} else if (digester_.IsOwning()) {
digester_.get().SetWriteSizeHint(
write_size_hint == absl::nullopt
? absl::nullopt
: absl::make_optional(SaturatingAdd(Position{start_to_cursor()},
*write_size_hint)));
}
}

Expand All @@ -368,6 +377,22 @@ namespace digesting_writer_internal {

ABSL_ATTRIBUTE_COLD absl::Status FailedStatus(DigesterBaseHandle digester);

template <typename DigesterOrWriter, typename... Srcs,
std::enable_if_t<
absl::conjunction<HasStringifiedSize<Srcs>...>::value, int> = 0>
ABSL_ATTRIBUTE_ALWAYS_INLINE inline void SetWriteSizeHint(
DigesterOrWriter&& dest, const Srcs&... srcs) {
std::forward<DigesterOrWriter>(dest).SetWriteSizeHint(
SaturatingAdd<Position>(riegeli::StringifiedSize(srcs)...));
}

template <typename DigesterOrWriter, typename... Srcs,
std::enable_if_t<
!absl::conjunction<HasStringifiedSize<Srcs>...>::value, int> = 0>
ABSL_ATTRIBUTE_ALWAYS_INLINE inline void SetWriteSizeHint(
ABSL_ATTRIBUTE_UNUSED DigesterOrWriter&& dest,
ABSL_ATTRIBUTE_UNUSED const Srcs&... srcs) {}

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

Expand Down Expand Up @@ -400,6 +425,13 @@ inline DesiredDigestType DigestFromImpl(std::tuple<Srcs...> srcs,
Digester&& digester) {
Dependency<DigesterBaseHandle, Digester&&> digester_dep(
std::forward<Digester>(digester));
if (digester_dep.IsOwning()) {
absl::apply(
[&](const Srcs&... srcs) {
SetWriteSizeHint(digester_dep.get(), srcs...);
},
srcs);
}
bool ok = WriteTuple<0>(srcs, digester_dep.get());
if (digester_dep.IsOwning()) {
if (ABSL_PREDICT_FALSE(!digester_dep.get().Close())) ok = false;
Expand All @@ -416,6 +448,9 @@ inline DesiredDigestType DigestFromImpl(std::tuple<Srcs...> srcs,
Digester&& digester) {
DigestingWriter<Digester&&, NullWriter> writer(
riegeli::Maker(), std::forward<Digester>(digester));
absl::apply(
[&](const Srcs&... srcs) { SetWriteSizeHint(writer.get(), srcs...); },
srcs);
writer.WriteTuple(srcs);
RIEGELI_CHECK(writer.Close()) << writer.status();
return writer.template Digest<DesiredDigestType>();
Expand Down
5 changes: 5 additions & 0 deletions riegeli/digests/wrapping_digester.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "absl/meta/type_traits.h"
#include "absl/strings/cord.h"
#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
#include "riegeli/base/chain.h"
#include "riegeli/base/dependency.h"
#include "riegeli/base/maker.h"
Expand Down Expand Up @@ -100,6 +101,10 @@ class WrappingDigester {
base_.Reset(riegeli::Maker(std::forward<Args>(args)...));
}

void SetWriteSizeHint(absl::optional<Position> write_size_hint) {
if (base_.IsOwning()) base_.get().SetWriteSizeHint(write_size_hint);
}

bool Write(absl::string_view src) { return base_.get().Write(src); }
bool Write(const Chain& src) { return base_.get().Write(src); }
bool Write(const absl::Cord& src) { return base_.get().Write(src); }
Expand Down

0 comments on commit b49bccc

Please sign in to comment.