blob: 76cc9936dc7c7d4dd4c8d051d30613f6b6d367d7 [file]
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RIEGELI_TENSORFLOW_IO_TSTRING_WRITER_H_
#define RIEGELI_TENSORFLOW_IO_TSTRING_WRITER_H_
#include <stddef.h>
#include <type_traits>
#include "riegeli/base/arithmetic.h"
#include "riegeli/base/assert.h"
#include "riegeli/base/dependency.h"
#include "riegeli/base/initializer.h"
#include "riegeli/base/object.h"
#include "riegeli/bytes/resizable_writer.h"
#include "tensorflow/tsl/platform/tstring.h"
namespace riegeli::tensorflow {
namespace tstring_internal {
// `ResizableTraits` for `tsl::tstring`.
struct TStringResizableTraits {
using Resizable = tsl::tstring;
static char* Data(Resizable& dest) { return dest.mdata(); }
static size_t Size(const Resizable& dest) { return dest.size(); }
static constexpr bool kIsStable = false;
static bool Resize(Resizable& dest, size_t new_size, size_t used_size) {
RIEGELI_ASSERT_LE(used_size, dest.size())
<< "Failed precondition of ResizableTraits::Resize(): "
"used size exceeds old size";
RIEGELI_ASSERT_LE(used_size, new_size)
<< "Failed precondition of ResizableTraits::Resize(): "
"used size exceeds new size";
Reserve(dest, new_size, used_size);
dest.resize_uninitialized(new_size);
return true;
}
static void GrowToCapacity(Resizable& dest) {
dest.resize_uninitialized(dest.capacity());
}
static bool Grow(Resizable& dest, size_t new_size, size_t used_size) {
RIEGELI_ASSERT_LE(used_size, dest.size())
<< "Failed precondition of ResizableTraits::Grow(): "
"used size exceeds old size";
RIEGELI_ASSERT_LE(used_size, new_size)
<< "Failed precondition of ResizableTraits::Grow(): "
"used size exceeds new size";
Reserve(dest, new_size, used_size);
GrowToCapacity(dest);
return true;
}
private:
static void Reserve(Resizable& dest, size_t new_size, size_t used_size) {
if (new_size > dest.capacity()) {
dest.resize_uninitialized(used_size);
dest.reserve(
dest.capacity() <= tsl::tstring().capacity()
? new_size
: UnsignedMax(new_size, dest.capacity() + dest.capacity() / 2));
}
}
};
} // namespace tstring_internal
// Template parameter independent part of `TStringWriter`.
using TStringWriterBase = ResizableWriterBase;
// A `Writer` which writes to a `tsl::tstring`. If `Options::append()`
// is `false` (the default), replaces existing contents of the
// `tsl::tstring`, clearing it first. If `Options::append()` is `true`,
// appends to existing contents of the `tsl::tstring`.
//
// It supports `Seek()` and `ReadMode()`.
//
// The `Dest` template parameter specifies the type of the object providing and
// possibly owning the `tsl::tstring` being written to. `Dest` must
// support `Dependency<tsl::tstring*, Dest>`, e.g.
// `tsl::tstring*` (not owned, default), `tsl::tstring` (owned),
// `Any<tsl::tstring*>` (maybe owned).
//
// By relying on CTAD the template argument can be deduced as
// `tsl::tstring` if there are no constructor arguments or the only
// argument is `Options`, otherwise as `TargetT` of the type of the first
// constructor argument, except that CTAD is deleted if the first constructor
// argument is a `tsl::tstring&` or `const tsl::tstring&` (to avoid writing to
// an unintentionally separate copy of an existing object).
//
// The `tsl::tstring` must not be accessed until the `TStringWriter` is
// closed or no longer used, except that it is allowed to read the
// `tsl::tstring` immediately after `Flush()`.
template <typename Dest = tsl::tstring*>
class TStringWriter
: public ResizableWriter<tstring_internal::TStringResizableTraits, Dest> {
public:
using TStringWriter::ResizableWriter::ResizableWriter;
TStringWriter(TStringWriter&& that) = default;
TStringWriter& operator=(TStringWriter&& that) = default;
};
explicit TStringWriter(Closed) -> TStringWriter<DeleteCtad<Closed>>;
template <typename Dest>
explicit TStringWriter(Dest&& dest, TStringWriterBase::Options options =
TStringWriterBase::Options())
-> TStringWriter<std::conditional_t<
std::conjunction_v<std::is_lvalue_reference<Dest>,
std::is_convertible<std::remove_reference_t<Dest>*,
const tsl::tstring*>>,
DeleteCtad<Dest&&>, TargetT<Dest>>>;
explicit TStringWriter(
TStringWriterBase::Options options = TStringWriterBase::Options())
-> TStringWriter<tsl::tstring>;
} // namespace riegeli::tensorflow
#endif // RIEGELI_TENSORFLOW_IO_TSTRING_WRITER_H_