1 // Copyright 2016 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #pragma once
6 
7 #include <fbl/alloc_checker.h>
8 #include <fbl/macros.h>
9 #include <new>
10 #include <stddef.h>
11 #include <zircon/assert.h>
12 
13 namespace fbl {
14 
15 // Runtime-determined, fixed size arrays that are "inlined" (e.g., on the stack) if the size at most
16 // |max_inline_count| or heap-allocated otherwise. This is typically used like:
17 //
18 //   fbl::AllocChecker ac;
19 //   fbl::InlineArray<zx_handle_t, 4u> handle_values(&ac, num_handles);
20 //   if (!ac.check())
21 //       return ZX_ERR_NO_MEMORY;
22 //
23 // Note: Currently, |max_inline_count| must be at least 1.
24 template <typename T, size_t max_inline_count>
25 class InlineArray {
26 public:
InlineArray(fbl::AllocChecker * ac,size_t count)27     InlineArray(fbl::AllocChecker* ac, size_t count)
28         : count_(count),
29           ptr_(!count_ ? nullptr
30                        : is_inline() ? reinterpret_cast<T*>(inline_storage_) : new (ac) T[count_]) {
31         if (is_inline()) {
32             // Arm the AllocChecker even if we didn't allocate -- the user should check it
33             // regardless!
34             ac->arm(0u, true);
35             for (size_t i = 0; i < count_; i++)
36                 new (&ptr_[i]) T();
37         }
38     }
39 
~InlineArray()40     ~InlineArray() {
41         if (is_inline()) {
42             for (size_t i = 0; i < count_; i++)
43                 ptr_[i].~T();
44         } else {
45             delete[] ptr_;
46         }
47     }
48 
49     InlineArray() = delete;
50     DISALLOW_COPY_ASSIGN_AND_MOVE(InlineArray);
51 
size()52     size_t size() const {
53         return count_;
54     }
55 
get()56     T* get() const { return ptr_; }
57 
58     T& operator[](size_t i) const {
59         ZX_DEBUG_ASSERT(i < count_);
60         return ptr_[i];
61     }
62 
63 private:
is_inline()64     bool is_inline() const { return count_ <= max_inline_count; }
65 
66     const size_t count_;
67     T* const ptr_;
68     alignas(T) char inline_storage_[max_inline_count * sizeof(T)];
69 };
70 
71 } // namespace fbl
72