blob: 06d16d488e6c6d358ca7d873d52c32b58a9fb749 [file]
// Copyright 2021 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_BYTES_READER_FACTORY_H_
#define RIEGELI_BYTES_READER_FACTORY_H_
#include <memory>
#include <utility>
#include "absl/base/attributes.h"
#include "absl/base/optimization.h"
#include "absl/base/thread_annotations.h"
#include "absl/status/status.h"
#include "absl/synchronization/mutex.h"
#include "riegeli/base/dependency.h"
#include "riegeli/base/initializer.h"
#include "riegeli/base/object.h"
#include "riegeli/base/stable_dependency.h"
#include "riegeli/base/types.h"
#include "riegeli/bytes/buffer_options.h"
#include "riegeli/bytes/reader.h"
namespace riegeli {
// Template parameter independent part of `ReaderFactory`.
class ReaderFactoryBase : public Object {
public:
class Options : public BufferOptionsBase<Options> {};
// Returns the original `Reader`. Unchanged by `Close()`.
virtual Reader* SrcReader() const ABSL_ATTRIBUTE_LIFETIME_BOUND = 0;
// Returns the original position of the original `Reader`.
Position pos() const { return initial_pos_; }
// Returns a `Reader` which reads from the same source as the original
// `Reader`, but has an independent current position, starting from
// `initial_pos`, defaulting to `pos()`.
//
// If the source ends before `initial_pos`, the position of the new `Reader`
// is set to the end. The resulting `Reader` supports `Seek()` and
// `NewReader()`. Calling `NewReader()` on the new `Reader` is equivalent to
// calling it on this `ReaderFactory` again.
//
// The new `Reader` does not own the source, even if the original `Reader`
// does. The original `Reader` must not be accessed until the new `Reader` is
// closed or no longer used.
//
// In contrast to `Reader::NewReader()` and `Reader::NewReaderCurrentPos()`,
// `ReaderFactory::NewReader()` is unconditionally const and thread-safe,
// even with an implicit initial position (concurrency with other operations
// is not applicable because the original `Reader` must not be accessed
// directly). The optimization of sharing the current buffer is applicable
// as long as the initial position is implicit or matches `pos()`.
//
// If `ok()` is `true`, then `NewReader()` does not return `nullptr`.
std::unique_ptr<Reader> NewReader(Position initial_pos) const
ABSL_ATTRIBUTE_LIFETIME_BOUND;
std::unique_ptr<Reader> NewReader() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
return NewReader(pos());
}
protected:
using Object::Object;
ReaderFactoryBase(ReaderFactoryBase&& that) noexcept;
ReaderFactoryBase& operator=(ReaderFactoryBase&& that) noexcept;
void Reset(Closed);
void Reset();
void Initialize(BufferOptions buffer_options, Reader* src);
void Done() override;
ABSL_ATTRIBUTE_COLD absl::Status AnnotateStatusImpl(
absl::Status status) override;
private:
class ConcurrentReader;
struct Shared {
explicit Shared(BufferOptions buffer_options, Reader* reader)
: buffer_options(buffer_options), reader(reader) {}
BufferOptions buffer_options;
absl::Mutex mutex;
Reader* reader ABSL_GUARDED_BY(mutex);
};
Position initial_pos_ = 0;
// If `shared_ == nullptr`, then `!is_open()` or `Reader::NewReader()` is
// used. If `shared_ != nullptr`, then `ConcurrentReader` emulation is used.
std::unique_ptr<Shared> shared_;
};
// `ReaderFactory` exposes `Reader::NewReader()`, or provides its emulation
// for `Reader` classes which do not support `NewReader()`. This allows for
// interleaved or concurrent reading of several regions of the same source.
//
// The original `Reader` must support random access.
//
// The `Src` template parameter specifies the type of the object providing and
// possibly owning the original `Reader`. `Src` must support
// `Dependency<Reader*, Src>`, e.g. `Reader*` (not owned, default),
// `ChainReader<>` (owned), `std::unique_ptr<Reader>` (owned),
// `Any<Reader*>` (maybe owned).
//
// By relying on CTAD the template argument can be deduced as `TargetT` of the
// type of the first constructor argument.
//
// The original `Reader` must not be accessed until the `ReaderFactory` is
// closed or no longer used.
template <typename Src = Reader*>
class ReaderFactory : public ReaderFactoryBase {
public:
// Creates a closed `ReaderFactory`.
explicit ReaderFactory(Closed) noexcept : ReaderFactoryBase(kClosed) {}
// Will read from the original `Reader` provided by `src`.
explicit ReaderFactory(Initializer<Src> src, Options options = Options());
ReaderFactory(ReaderFactory&& that) = default;
ReaderFactory& operator=(ReaderFactory&& that) = default;
// Makes `*this` equivalent to a newly constructed `ReaderFactory`. This
// avoids constructing a temporary `ReaderFactory` and moving from it.
ABSL_ATTRIBUTE_REINITIALIZES void Reset(Closed);
ABSL_ATTRIBUTE_REINITIALIZES void Reset(Initializer<Src> src,
Options options = Options());
// Returns the object providing and possibly owning the original `Reader`.
// Unchanged by `Close()`.
Src& src() ABSL_ATTRIBUTE_LIFETIME_BOUND { return src_.manager(); }
const Src& src() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
return src_.manager();
}
Reader* SrcReader() const ABSL_ATTRIBUTE_LIFETIME_BOUND override {
return src_.get();
}
protected:
void Done() override;
private:
// The object providing and possibly owning the original `Reader`.
StableDependency<Reader*, Src> src_;
};
explicit ReaderFactory(Closed) -> ReaderFactory<DeleteCtad<Closed>>;
template <typename Src>
explicit ReaderFactory(Src&& src, ReaderFactoryBase::Options options =
ReaderFactoryBase::Options())
-> ReaderFactory<TargetT<Src>>;
// Implementation details follow.
inline ReaderFactoryBase::ReaderFactoryBase(ReaderFactoryBase&& that) noexcept
: Object(static_cast<Object&&>(that)),
initial_pos_(that.initial_pos_),
shared_(std::move(that.shared_)) {}
inline ReaderFactoryBase& ReaderFactoryBase::operator=(
ReaderFactoryBase&& that) noexcept {
Object::operator=(static_cast<Object&&>(that));
initial_pos_ = that.initial_pos_;
shared_ = std::move(that.shared_);
return *this;
}
inline void ReaderFactoryBase::Reset(Closed) {
Object::Reset(kClosed);
initial_pos_ = 0;
shared_.reset();
}
inline void ReaderFactoryBase::Reset() {
Object::Reset();
// `initial_pos_` will be set by `Initialize()`.
shared_.reset();
}
template <typename Src>
inline ReaderFactory<Src>::ReaderFactory(Initializer<Src> src, Options options)
: src_(std::move(src)) {
Initialize(options.buffer_options(), src_.get());
}
template <typename Src>
inline void ReaderFactory<Src>::Reset(Closed) {
ReaderFactoryBase::Reset(kClosed);
src_.Reset();
}
template <typename Src>
inline void ReaderFactory<Src>::Reset(Initializer<Src> src, Options options) {
ReaderFactoryBase::Reset();
src_.Reset(std::move(src));
Initialize(options.buffer_options(), src_.get());
}
template <typename Src>
void ReaderFactory<Src>::Done() {
ReaderFactoryBase::Done();
if (src_.IsOwning()) {
if (ABSL_PREDICT_FALSE(!src_->Close())) {
FailWithoutAnnotation(src_->status());
}
}
}
} // namespace riegeli
#endif // RIEGELI_BYTES_READER_FACTORY_H_