blob: 92556d6cb2c9eb817ca0bff802ed319b2e65e304 [file] [log] [blame]
// Copyright 2017 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 LIB_FIDL_CPP_WIRE_VECTOR_VIEW_H_
#define LIB_FIDL_CPP_WIRE_VECTOR_VIEW_H_
#include <lib/fidl/cpp/wire/arena.h>
#include <lib/stdcompat/span.h>
#include <zircon/fidl.h>
#include <algorithm>
#include <iterator>
#include <type_traits>
namespace {
class LayoutChecker;
} // namespace
namespace fidl {
// VectorView is the representation of a FIDL vector in wire domain objects.
//
// VectorViews provide limited functionality to access and set fields of the
// vector and other methods like fidl::Arena, std::array, or std::vector must be
// used to construct it.
//
// VectorView's layout and data format must match fidl_vector_t as it will be
// reinterpret_casted into/from fidl_vector_t during encoding and decoding.
//
// Example:
//
// uint32_t arr[5] = { 1, 2, 3 };
// fuchsia_some_lib::wire::SomeFidlObject obj;
// // Sets the field to a vector view borrowing from |arr|.
// obj.set_vec_field(fidl::VectorView<uint32_t>::FromExternal(arr));
//
template <typename T>
class VectorView {
private:
template <typename>
friend class VectorView;
public:
using elem_type = T;
VectorView() = default;
// Allocates a vector using an arena. |T| is default constructed.
VectorView(AnyArena& allocator, size_t count)
: count_(count), data_(allocator.AllocateVector<T>(count)) {}
VectorView(AnyArena& allocator, size_t initial_count, size_t capacity)
: count_(initial_count), data_(allocator.AllocateVector<T>(capacity)) {
ZX_DEBUG_ASSERT(initial_count <= capacity);
}
VectorView(std::nullptr_t data, size_t count) {}
// Allocates a vector using an arena and copies the data from the supplied iterators.
// The iterator must satisfy the random_access_iterator concept.
//
// Example:
//
// fidl::Arena arena;
// std::vector<int32_t> vec(...);
// // Copy contents of |vec| into |arena|, and return a view of the copies content.
// fidl::VectorView<int32_t> vv(arena, vec.begin(), vec.end());
//
template <typename InputIterator>
VectorView(AnyArena& arena, InputIterator first, InputIterator last)
: count_(last - first), data_(arena.AllocateVector<T>(count_)) {
using Traits = std::iterator_traits<InputIterator>;
constexpr bool kIsIterator = has_difference_type<Traits>::value;
static_assert(
kIsIterator,
"|InputIterator| is not an iterator. "
"Ensure that the last two arguments to this constructor are random access iterators.");
std::copy(first, last, data_);
}
// Allocates a vector using an arena and copies the data from the supplied |span|.
VectorView(AnyArena& arena, cpp20::span<const T> span)
: VectorView(arena, span.begin(), span.end()) {}
// Allocates a vector using an arena and copies the data from the supplied |std::vector|.
VectorView(AnyArena& arena, const std::vector<T>& vector)
: VectorView(arena, cpp20::span(vector)) {}
template <typename U>
VectorView(VectorView<U>&& other) {
static_assert(
std::is_same<T, U>::value || std::is_same<T, std::add_const_t<U>>::value,
"VectorView<T> can only be move-constructed from VectorView<T> or VectorView<const T>");
count_ = other.count_;
data_ = other.data_;
}
// Constructs a fidl::VectorView by unsafely borrowing other sequences.
//
// |FromExternal| methods are the only way to reference data which is not
// managed by an arena. Their usage is discouraged. The lifetime of the
// referenced vector must be longer than the lifetime of the created
// |VectorView|.
//
// For example:
//
// std::vector<int32_t> my_vector = { 1, 2, 3 };
// auto my_view =
// fidl::VectorView<int32_t>::FromExternal(my_vector);
//
static VectorView<T> FromExternal(std::vector<T>& from) { return VectorView<T>(from); }
template <size_t size>
static VectorView<T> FromExternal(std::array<T, size>& from) {
return VectorView<T>(from.data(), size);
}
template <size_t size>
static VectorView<T> FromExternal(T (&data)[size]) {
return VectorView<T>(data, size);
}
static VectorView<T> FromExternal(T* data, size_t count) { return VectorView<T>(data, count); }
template <typename U>
VectorView& operator=(VectorView<U>&& other) {
static_assert(std::is_same<T, U>::value || std::is_same<T, std::add_const_t<U>>::value,
"VectorView<T> can only be assigned from VectorView<T> or VectorView<const T>");
count_ = other.count_;
data_ = other.data_;
return *this;
}
cpp20::span<T> get() const { return {data(), count()}; }
size_t count() const { return count_; }
void set_count(size_t count) { count_ = count; }
T* data() const { return data_; }
// Returns if the vector view is empty.
bool empty() const { return count() == 0; }
// TODO(https://fxbug.dev/42061094): |is_null| is used to check if an optional view type
// is absent. This can be removed if optional view types switch to
// |fidl::WireOptional|.
bool is_null() const { return data() == nullptr; }
T& at(size_t offset) const { return data()[offset]; }
T& operator[](size_t offset) const { return at(offset); }
T* begin() const { return data(); }
const T* cbegin() const { return data(); }
T* end() const { return data() + count(); }
const T* cend() const { return data() + count(); }
// Allocates |count| items of |T| from the |arena|, forgetting any values
// currently held by the vector view. |T| is default constructed.
void Allocate(AnyArena& arena, size_t count) {
count_ = count;
data_ = arena.AllocateVector<T>(count);
}
protected:
explicit VectorView(std::vector<T>& from) : count_(from.size()), data_(from.data()) {}
VectorView(T* data, size_t count) : count_(count), data_(data) {}
private:
template <class I>
struct has_difference_type {
template <class U>
static std::false_type test(...);
template <class U>
static std::true_type test(std::void_t<typename U::difference_type>* = 0);
static const bool value = decltype(test<I>(0))::value;
};
friend ::LayoutChecker;
size_t count_ = 0;
T* data_ = nullptr;
};
template <typename T>
VectorView(fidl::AnyArena&, cpp20::span<T>) -> VectorView<T>;
} // namespace fidl
namespace {
class LayoutChecker {
static_assert(sizeof(fidl::VectorView<uint8_t>) == sizeof(fidl_vector_t),
"VectorView size should match fidl_vector_t");
static_assert(offsetof(fidl::VectorView<uint8_t>, count_) == offsetof(fidl_vector_t, count),
"VectorView count offset should match fidl_vector_t");
static_assert(sizeof(fidl::VectorView<uint8_t>::count_) == sizeof(fidl_vector_t::count),
"VectorView count size should match fidl_vector_t");
static_assert(offsetof(fidl::VectorView<uint8_t>, data_) == offsetof(fidl_vector_t, data),
"VectorView data offset should match fidl_vector_t");
static_assert(sizeof(fidl::VectorView<uint8_t>::data_) == sizeof(fidl_vector_t::data),
"VectorView data size should match fidl_vector_t");
};
} // namespace
#endif // LIB_FIDL_CPP_WIRE_VECTOR_VIEW_H_