blob: e60801378e7c86a675e3be74e85400f4161f88ea [file] [log] [blame]
// Copyright 2016 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 ZIRCON_KERNEL_LIB_FBL_INCLUDE_FBL_INLINE_ARRAY_H_
#define ZIRCON_KERNEL_LIB_FBL_INCLUDE_FBL_INLINE_ARRAY_H_
#include <stddef.h>
#include <zircon/assert.h>
#include <new>
#include <fbl/alloc_checker.h>
#include <fbl/macros.h>
namespace fbl {
// Runtime-determined, fixed size arrays that are "inlined" (e.g., on the stack) if the size at most
// |max_inline_count| or heap-allocated otherwise. This is typically used like:
//
// fbl::AllocChecker ac;
// fbl::InlineArray<zx_handle_t, 4u> handle_values(&ac, num_handles);
// if (!ac.check())
// return ZX_ERR_NO_MEMORY;
//
// Note: Currently, |max_inline_count| must be at least 1.
template <typename T, size_t max_inline_count>
class __OWNER(T) InlineArray {
public:
InlineArray(fbl::AllocChecker* ac, size_t count)
: count_(count),
ptr_(!count_ ? nullptr
: is_inline() ? reinterpret_cast<T*>(inline_storage_) : new (ac) T[count_]) {
if (is_inline()) {
// Arm the AllocChecker even if we didn't allocate -- the user should check it
// regardless!
ac->arm(0u, true);
for (size_t i = 0; i < count_; i++)
new (&ptr_[i]) T();
}
}
~InlineArray() {
if (is_inline()) {
for (size_t i = 0; i < count_; i++)
ptr_[i].~T();
} else {
delete[] ptr_;
}
}
InlineArray() = delete;
DISALLOW_COPY_ASSIGN_AND_MOVE(InlineArray);
size_t size() const { return count_; }
T* get() const { return ptr_; }
T& operator[](size_t i) const {
ZX_DEBUG_ASSERT(i < count_);
return ptr_[i];
}
private:
bool is_inline() const { return count_ <= max_inline_count; }
const size_t count_;
T* const ptr_;
alignas(T) char inline_storage_[max_inline_count * sizeof(T)];
};
} // namespace fbl
#endif // ZIRCON_KERNEL_LIB_FBL_INCLUDE_FBL_INLINE_ARRAY_H_