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