diff options
Diffstat (limited to 'js/src/builtin/streams/QueueWithSizes.cpp')
-rw-r--r-- | js/src/builtin/streams/QueueWithSizes.cpp | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/js/src/builtin/streams/QueueWithSizes.cpp b/js/src/builtin/streams/QueueWithSizes.cpp new file mode 100644 index 0000000000..4b2ce84084 --- /dev/null +++ b/js/src/builtin/streams/QueueWithSizes.cpp @@ -0,0 +1,173 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: + * 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/. */ + +/* Queue-with-sizes operations. */ + +#include "builtin/streams/QueueWithSizes-inl.h" + +#include "mozilla/Assertions.h" // MOZ_ASSERT +#include "mozilla/Attributes.h" // MOZ_MUST_USE +#include "mozilla/FloatingPoint.h" // mozilla::Is{Infinite,NaN} + +#include "jsapi.h" // JS_ReportErrorNumberASCII + +#include "builtin/streams/StreamController.h" // js::StreamController +#include "js/Class.h" // JSClass, JSCLASS_HAS_RESERVED_SLOTS +#include "js/Conversions.h" // JS::ToNumber +#include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_* +#include "js/RootingAPI.h" // JS::Rooted +#include "js/Value.h" // JS::Value, JS::{Number,Object}Value +#include "vm/Compartment.h" // JSCompartment +#include "vm/JSContext.h" // JSContext +#include "vm/List.h" // js::ListObject +#include "vm/NativeObject.h" // js::NativeObject + +#include "vm/Compartment-inl.h" // JSCompartment::wrap +#include "vm/JSContext-inl.h" // JSContext::check +#include "vm/JSObject-inl.h" // js::NewBuiltinClassInstance +#include "vm/List-inl.h" // js::ListObject::*, js::StoreNewListInFixedSlot +#include "vm/Realm-inl.h" // js::AutoRealm + +using JS::Handle; +using JS::MutableHandle; +using JS::NumberValue; +using JS::ObjectValue; +using JS::Rooted; +using JS::ToNumber; +using JS::Value; + +/*** 6.2. Queue-with-sizes operations ***************************************/ + +/** + * Streams spec, 6.2.1. DequeueValue ( container ) nothrow + */ +MOZ_MUST_USE bool js::DequeueValue(JSContext* cx, + Handle<StreamController*> unwrappedContainer, + MutableHandle<Value> chunk) { + // Step 1: Assert: container has [[queue]] and [[queueTotalSize]] internal + // slots (implicit). + // Step 2: Assert: queue is not empty. + Rooted<ListObject*> unwrappedQueue(cx, unwrappedContainer->queue()); + + // Step 3. Let pair be the first element of queue. + double chunkSize = detail::QueueFirstSize(unwrappedQueue); + chunk.set(detail::QueueFirstValue(unwrappedQueue)); + + // Step 4. Remove pair from queue, shifting all other elements downward + // (so that the second becomes the first, and so on). + detail::QueueRemoveFirstValueAndSize(unwrappedQueue, cx); + + // Step 5: Set container.[[queueTotalSize]] to + // container.[[queueTotalSize]] − pair.[[size]]. + // Step 6: If container.[[queueTotalSize]] < 0, set + // container.[[queueTotalSize]] to 0. + // (This can occur due to rounding errors.) + double totalSize = unwrappedContainer->queueTotalSize(); + totalSize -= chunkSize; + if (totalSize < 0) { + totalSize = 0; + } + unwrappedContainer->setQueueTotalSize(totalSize); + + // Step 7: Return pair.[[value]]. + return cx->compartment()->wrap(cx, chunk); +} + +void js::DequeueValue(StreamController* unwrappedContainer, JSContext* cx) { + // Step 1: Assert: container has [[queue]] and [[queueTotalSize]] internal + // slots (implicit). + // Step 2: Assert: queue is not empty. + ListObject* unwrappedQueue = unwrappedContainer->queue(); + + // Step 3. Let pair be the first element of queue. + // (The value is being discarded, so all we must extract is the size.) + double chunkSize = detail::QueueFirstSize(unwrappedQueue); + + // Step 4. Remove pair from queue, shifting all other elements downward + // (so that the second becomes the first, and so on). + detail::QueueRemoveFirstValueAndSize(unwrappedQueue, cx); + + // Step 5: Set container.[[queueTotalSize]] to + // container.[[queueTotalSize]] − pair.[[size]]. + // Step 6: If container.[[queueTotalSize]] < 0, set + // container.[[queueTotalSize]] to 0. + // (This can occur due to rounding errors.) + double totalSize = unwrappedContainer->queueTotalSize(); + totalSize -= chunkSize; + if (totalSize < 0) { + totalSize = 0; + } + unwrappedContainer->setQueueTotalSize(totalSize); + + // Step 7: Return pair.[[value]]. (omitted because not used) +} + +/** + * Streams spec, 6.2.2. EnqueueValueWithSize ( container, value, size ) throws + */ +MOZ_MUST_USE bool js::EnqueueValueWithSize( + JSContext* cx, Handle<StreamController*> unwrappedContainer, + Handle<Value> value, Handle<Value> sizeVal) { + cx->check(value, sizeVal); + + // Step 1: Assert: container has [[queue]] and [[queueTotalSize]] internal + // slots (implicit). + // Step 2: Let size be ? ToNumber(size). + double size; + if (!ToNumber(cx, sizeVal, &size)) { + return false; + } + + // Step 3: If ! IsFiniteNonNegativeNumber(size) is false, throw a RangeError + // exception. + if (size < 0 || mozilla::IsNaN(size) || mozilla::IsInfinite(size)) { + JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, + JSMSG_NUMBER_MUST_BE_FINITE_NON_NEGATIVE, "size"); + return false; + } + + // Step 4: Append Record {[[value]]: value, [[size]]: size} as the last + // element of container.[[queue]]. + { + AutoRealm ar(cx, unwrappedContainer); + Rooted<ListObject*> unwrappedQueue(cx, unwrappedContainer->queue()); + Rooted<Value> wrappedVal(cx, value); + if (!cx->compartment()->wrap(cx, &wrappedVal)) { + return false; + } + + if (!detail::QueueAppendValueAndSize(cx, unwrappedQueue, wrappedVal, + size)) { + return false; + } + } + + // Step 5: Set container.[[queueTotalSize]] to + // container.[[queueTotalSize]] + size. + unwrappedContainer->setQueueTotalSize(unwrappedContainer->queueTotalSize() + + size); + + return true; +} + +/** + * Streams spec, 6.2.4. ResetQueue ( container ) nothrow + */ +MOZ_MUST_USE bool js::ResetQueue(JSContext* cx, + Handle<StreamController*> unwrappedContainer) { + // Step 1: Assert: container has [[queue]] and [[queueTotalSize]] internal + // slots (implicit). + // Step 2: Set container.[[queue]] to a new empty List. + if (!StoreNewListInFixedSlot(cx, unwrappedContainer, + StreamController::Slot_Queue)) { + return false; + } + + // Step 3: Set container.[[queueTotalSize]] to 0. + unwrappedContainer->setQueueTotalSize(0); + + return true; +} |