ForOfIterator.h (3367B)
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 /* 8 * A convenience class that makes it easy to perform the operations of a for-of 9 * loop. 10 */ 11 12 #ifndef js_ForOfIterator_h 13 #define js_ForOfIterator_h 14 15 #include "mozilla/Attributes.h" // MOZ_STACK_CLASS 16 17 #include <stdint.h> // UINT32_MAX, uint32_t 18 19 #include "jstypes.h" // JS_PUBLIC_API 20 21 #include "js/RootingAPI.h" // JS::{Handle,Rooted} 22 #include "js/Value.h" // JS::Value, JS::{,Mutable}Handle<JS::Value> 23 24 struct JS_PUBLIC_API JSContext; 25 class JS_PUBLIC_API JSObject; 26 27 namespace JS { 28 29 /** 30 * A convenience class for imitating a JS for-of loop. Typical usage: 31 * 32 * JS::ForOfIterator it(cx); 33 * if (!it.init(iterable)) { 34 * return false; 35 * } 36 * JS::Rooted<JS::Value> val(cx); 37 * while (true) { 38 * bool done; 39 * if (!it.next(&val, &done)) { 40 * return false; 41 * } 42 * if (done) { 43 * break; 44 * } 45 * if (!DoStuff(cx, val)) { 46 * return false; 47 * } 48 * } 49 */ 50 class MOZ_STACK_CLASS JS_PUBLIC_API ForOfIterator { 51 protected: 52 JSContext* cx_; 53 54 // Use realm fuses (see `IsArrayWithDefaultIterator` in vm/Iteration.cpp) to 55 // try to optimize iteration across arrays. 56 // 57 // Case 1: Regular Iteration 58 // iterator - pointer to the iterator object. 59 // nextMethod - value of |iterator|.next. 60 // index - fixed to NOT_ARRAY (== UINT32_MAX) 61 // 62 // Case 2: Optimized Array Iteration 63 // iterator - pointer to the array object. 64 // nextMethod - the undefined value. 65 // index - current position in array. 66 // 67 // The cases are distinguished by whether |index == NOT_ARRAY|. 68 Rooted<JSObject*> iterator; 69 Rooted<Value> nextMethod; 70 71 static constexpr uint32_t NOT_ARRAY = UINT32_MAX; 72 73 uint32_t index = NOT_ARRAY; 74 75 ForOfIterator(const ForOfIterator&) = delete; 76 ForOfIterator& operator=(const ForOfIterator&) = delete; 77 78 public: 79 explicit ForOfIterator(JSContext* cx) 80 : cx_(cx), iterator(cx), nextMethod(cx) {} 81 82 enum NonIterableBehavior { ThrowOnNonIterable, AllowNonIterable }; 83 84 /** 85 * Initialize the iterator. If AllowNonIterable is passed then if getting 86 * the @@iterator property from iterable returns undefined init() will just 87 * return true instead of throwing. Callers must then check 88 * valueIsIterable() before continuing with the iteration. 89 */ 90 [[nodiscard]] bool init( 91 Handle<Value> iterable, 92 NonIterableBehavior nonIterableBehavior = ThrowOnNonIterable); 93 94 /** 95 * Get the next value from the iterator. If false *done is true 96 * after this call, do not examine val. 97 */ 98 [[nodiscard]] bool next(MutableHandle<Value> val, bool* done); 99 100 /** 101 * Close the iterator. 102 * For the case that completion type is throw. 103 */ 104 void closeThrow(); 105 106 /** 107 * If initialized with throwOnNonCallable = false, check whether 108 * the value is iterable. 109 */ 110 bool valueIsIterable() const { return iterator; } 111 112 private: 113 inline bool nextFromOptimizedArray(MutableHandle<Value> val, bool* done); 114 }; 115 116 } // namespace JS 117 118 #endif // js_ForOfIterator_h