1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2  * vim: set ts=8 sts=2 et sw=2 tw=80:
3  * This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef ds_FixedLengthVector_h
8 #define ds_FixedLengthVector_h
9 
10 #include "mozilla/Assertions.h"             // MOZ_ASSERT
11 #include "mozilla/OperatorNewExtensions.h"  // mozilla::KnownNotNull
12 
13 #include <stddef.h>  // size_t
14 
15 #include "js/Utility.h"    // js_free
16 #include "vm/JSContext.h"  // JSContext
17 
18 namespace js {
19 
20 // A dynamically-allocated fixed-length vector with bounds checking assertions.
21 template <typename T>
22 class FixedLengthVector {
23   // The pointer to the storage.
24   T* data_ = nullptr;
25 
26   // The size of the storage.
27   size_t length_ = 0;
28 
29  public:
30   FixedLengthVector() = default;
31 
32   FixedLengthVector(FixedLengthVector&) = delete;
33   FixedLengthVector(FixedLengthVector&&) = default;
34 
~FixedLengthVector()35   ~FixedLengthVector() {
36     if (initialized()) {
37       js_free(data_);
38     }
39   }
40 
length()41   size_t length() const { return length_; }
42 
initialized()43   bool initialized() const { return !!data_; }
44 
45   // Allocate the storage with the given size, wihtout calling constructor.
46   //
47   // If the allocation fails, this returns false and sets the
48   // pending exception on the given context.
allocateUninitialized(JSContext * cx,size_t length)49   [[nodiscard]] bool allocateUninitialized(JSContext* cx, size_t length) {
50     MOZ_ASSERT(!initialized());
51 
52     length_ = length;
53     data_ = cx->pod_malloc<T>(length);
54     if (MOZ_UNLIKELY(!data_)) {
55       return false;
56     }
57 
58     return true;
59   }
60 
61   // Allocate the storage with the given size and call default constructor.
62   //
63   // If the allocation fails, this returns false and sets the
64   // pending exception on the given context.
allocate(JSContext * cx,size_t length)65   [[nodiscard]] bool allocate(JSContext* cx, size_t length) {
66     if (!allocateUninitialized(cx, length)) {
67       return false;
68     }
69 
70     for (size_t i = 0; i < length; i++) {
71       new (mozilla::KnownNotNull, &data_[i]) T();
72     }
73     return true;
74   }
75 
begin()76   T* begin() {
77     MOZ_ASSERT(initialized());
78     return data_;
79   }
80 
begin()81   const T* begin() const {
82     MOZ_ASSERT(initialized());
83     return data_;
84   }
85 
end()86   T* end() {
87     MOZ_ASSERT(initialized());
88     return data_ + length_;
89   }
90 
end()91   const T* end() const {
92     MOZ_ASSERT(initialized());
93     return data_ + length_;
94   }
95 
96   T& operator[](size_t index) {
97     MOZ_ASSERT(initialized());
98     MOZ_ASSERT(index < length_);
99     return begin()[index];
100   }
101 
102   const T& operator[](size_t index) const {
103     MOZ_ASSERT(initialized());
104     MOZ_ASSERT(index < length_);
105     return begin()[index];
106   }
107 };
108 
109 }  // namespace js
110 
111 #endif  // ds_FixedLengthVector_h
112