blob: 3f682af6d3f55f067de44cbb407b2f31299c1ea8 [file] [log] [blame]
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_LIB_ZXDUMP_INCLUDE_LIB_ZXDUMP_BUFFER_H_
#define SRC_LIB_ZXDUMP_INCLUDE_LIB_ZXDUMP_BUFFER_H_
#include <lib/stdcompat/span.h>
#include <cstdint>
#include <memory>
#include <string>
#include <string_view>
#include <type_traits>
namespace zxdump {
// Forward declaration.
class Process;
namespace internal {
// Forward declaration.
class DumpFile;
// This is a private class used in the implementation of the Buffer API, below.
class BufferImpl {
public:
virtual ~BufferImpl() = 0;
};
} // namespace internal
// zxdump::Buffer<T> provides a view over a chunk of memory returned by
// zxdump::Process::read_memory.
//
// This is a move-only object that "owns" the storage viewed, but it's also
// tied to the lifetime of the zxdump::TaskHolder object that owns the
// zxdump::Process object. The data pointers from this object cannot be used
// after either the zxdump::Buffer object or the associated zxdump::TaskHolder
// object has been destroyed.
//
// zxdump::Buffer<T> acts like a smart-pointer type to cpp20::span<const T> (or
// a similar type) in that it has get() and the * and -> operators to access
// that object's standard methods. Unlike other smart-pointer types, a
// zxdump::Buffer has no nullptr-like state (except when default-constructed)
// and is not contextually convertible to bool. A default-constructed
// zxdump::Buffer can be assigned to, but not otherwise used.
//
// All the memory-reading operations that return a zxdump::Buffer return a
// result type that never reflects success with a default-constructed
// zxdump::Buffer object. However, they can return an object whose value
// (View) is in its empty, default-constructed state. This indicates that the
// process memory was valid to access, but was elided (wholly or partially)
// from the dump. In this case, reading a shorter region might succeed if the
// containing segment was truncated rather than elided entirely.
//
// Note that all memory will appear to have been elided if the dump was read in
// by a zxdump::TaskHolder::Insert with read_memory=false.
template <typename T = std::byte, class View = cpp20::span<const T>>
class Buffer {
public:
Buffer() = default;
Buffer(const Buffer&) = delete;
Buffer(Buffer&& other) noexcept
: data_(std::exchange(other.data_, {})), impl_(std::move(other.impl_)) {}
// Converting move construction is allowed if the pointers are convertible.
template <typename OtherT, class OtherView,
typename = std::enable_if_t<std::is_convertible_v<const OtherT*, const T*>>>
Buffer(Buffer<OtherT, OtherView>&& other) noexcept
: data_{reinterpret_cast<const T*>(other->data()), other->size_bytes() / sizeof(T)},
impl_{std::move(other.impl_)} {
other.data_ = {};
}
Buffer& operator=(Buffer&& other) noexcept {
std::swap(data_, other.data_);
std::swap(impl_, other.impl_);
return *this;
}
template <typename OtherT, class OtherView,
typename = std::enable_if_t<std::is_convertible_v<const OtherT*, const T*>>>
Buffer& operator=(Buffer<OtherT, OtherView>&& other) noexcept {
*this = Buffer(std::move(other));
return *this;
}
// An explicit static_cast to another Buffer type is allowed.
template <typename OtherT, class OtherView>
explicit operator Buffer<OtherT, OtherView>() {
Buffer<OtherT, OtherView> other;
other.data_ = {
reinterpret_cast<const OtherT*>(data_.data()),
data_.size_bytes() / sizeof(OtherT),
};
data_ = {};
other.impl_ = std::move(impl_);
return other;
}
~Buffer() = default;
const View& get() const { return data_; }
const View& operator*() const { return data_; }
const View* operator->() const { return &data_; }
private:
template <typename OtherT, class OtherView>
friend class Buffer;
friend Process;
friend internal::DumpFile;
View data_;
std::unique_ptr<internal::BufferImpl> impl_;
};
// This is just zxdump::Buffer using std::string_view and cousins instead of
// cpp20::span to present the data.
template <typename T = char>
using StringBuffer = Buffer<T, std::basic_string_view<T>>;
} // namespace zxdump
#endif // SRC_LIB_ZXDUMP_INCLUDE_LIB_ZXDUMP_BUFFER_H_