1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_QueueWithSizes_h
#define mozilla_dom_QueueWithSizes_h
#include <cmath>
#include "js/TypeDecls.h"
#include "js/Value.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/UniquePtr.h"
#include "nsTArray.h"
namespace mozilla::dom {
// Note: Consumers of QueueWithSize need to ensure it is traced. See
// ReadableStreamDefaultController.cpp for an example.
struct ValueWithSize : LinkedListElement<ValueWithSize> {
ValueWithSize(JS::Handle<JS::Value> aValue, double aSize)
: mValue(aValue), mSize(aSize) {};
JS::Heap<JS::Value> mValue;
double mSize = 0.0f;
};
// This type is a little tricky lifetime wise: Despite the fact that we're
// talking about linked list of VaueWithSize, what is actually stored in the
// list are dynamically allocated ValueWithSize*. As a result, these have to be
// deleted. There are two ways this lifetime is managed:
//
// 1. In DequeueValue we pop the first element into a UniquePtr, so that it is
// correctly cleaned up at destruction time.
// 2. We use an AutoCleanLinkedList which will delete elements when destroyed
// or `clear`ed.
using QueueWithSizes = AutoCleanLinkedList<ValueWithSize>;
// https://streams.spec.whatwg.org/#is-non-negative-number
inline bool IsNonNegativeNumber(double v) {
// Step 1. Implicit.
// Step 2.
if (std::isnan(v)) {
return false;
}
// Step 3.
return !(v < 0);
}
// https://streams.spec.whatwg.org/#enqueue-value-with-size
template <class QueueContainingClass>
inline void EnqueueValueWithSize(QueueContainingClass aContainer,
JS::Handle<JS::Value> aValue, double aSize,
ErrorResult& aRv) {
// Step 1. Assert: container has [[queue]] and [[queueTotalSize]] internal
// slots. (Implicit by template instantiation.)
// Step 2. If ! IsNonNegativeNumber(size) is false, throw a RangeError
// exception.
if (!IsNonNegativeNumber(aSize)) {
aRv.ThrowRangeError("invalid size");
return;
}
// Step 3. If size is +∞, throw a RangeError exception.
if (std::isinf(aSize)) {
aRv.ThrowRangeError("Infinite queue size");
return;
}
// Step 4. Append a new value-with-size with value value and size size to
// container.[[queue]].
// (See the comment on QueueWithSizes for the lifetime reasoning around this
// allocation.)
ValueWithSize* valueWithSize = new ValueWithSize(aValue, aSize);
aContainer->Queue().insertBack(valueWithSize);
// Step 5. Set container.[[queueTotalSize]] to container.[[queueTotalSize]] +
// size.
aContainer->SetQueueTotalSize(aContainer->QueueTotalSize() + aSize);
}
// https://streams.spec.whatwg.org/#dequeue-value
template <class QueueContainingClass>
inline void DequeueValue(QueueContainingClass aContainer,
JS::MutableHandle<JS::Value> aResultValue) {
// Step 1. Implicit via template instantiation.
// Step 2.
MOZ_ASSERT(!aContainer->Queue().isEmpty());
// Step 3+4
// UniquePtr to ensure memory is freed.
UniquePtr<ValueWithSize> valueWithSize(aContainer->Queue().popFirst());
// Step 5.
aContainer->SetQueueTotalSize(aContainer->QueueTotalSize() -
valueWithSize->mSize);
// Step 6.
if (aContainer->QueueTotalSize() < 0) {
aContainer->SetQueueTotalSize(0);
}
// Step 7.
aResultValue.set(valueWithSize->mValue);
}
// https://streams.spec.whatwg.org/#peek-queue-value
template <class QueueContainingClass>
inline void PeekQueueValue(QueueContainingClass aContainer,
JS::MutableHandle<JS::Value> aResultValue) {
// Step 1. Assert: container has [[queue]] and [[queueTotalSize]] internal
// slots.
// Step 2. Assert: container.[[queue]] is not empty.
MOZ_ASSERT(!aContainer->Queue().isEmpty());
// Step 3. Let valueWithSize be container.[[queue]][0].
ValueWithSize* valueWithSize = aContainer->Queue().getFirst();
// Step 4. Return valueWithSize’s value.
aResultValue.set(valueWithSize->mValue);
}
// https://streams.spec.whatwg.org/#reset-queue
template <class QueueContainingClass>
inline void ResetQueue(QueueContainingClass aContainer) {
// Step 1. Assert: container has [[queue]] and [[queueTotalSize]] internal
// slots. (implicit)
// Step 2. Set container.[[queue]] to a new empty list.
aContainer->Queue().clear();
// Step 3. Set container.[[queueTotalSize]] to 0.
aContainer->SetQueueTotalSize(0.0);
}
} // namespace mozilla::dom
#endif
|