EdgeAIG's picture
download
raw
13 kB
/**
* Transactional priority queues whose state is stored in a `TxRef`. Elements
* are kept in the order defined by the `Order` supplied at construction time,
* and dequeue operations return the first element according to that ordering.
*
* Use `TxPriorityQueue` when multiple fibers coordinate through a shared queue
* and queue operations need to compose with other transactional state changes.
* The retrying `peek` and `take` operations wait transactionally when the queue
* is empty, so they can be combined with other transactional reads and writes in
* one atomic workflow.
*
* @since 4.0.0
*/
import * as C from "./Chunk.js";
import * as Effect from "./Effect.js";
import { dual } from "./Function.js";
import { NodeInspectSymbol, toJson } from "./Inspectable.js";
import * as O from "./Option.js";
import { pipeArguments } from "./Pipeable.js";
import { hasProperty } from "./Predicate.js";
import * as TxRef from "./TxRef.js";
const TypeId = "~effect/transactions/TxPriorityQueue";
const TxPriorityQueueProto = {
[NodeInspectSymbol]() {
return toJson(this);
},
toJSON() {
return {
_id: "TxPriorityQueue"
};
},
pipe() {
return pipeArguments(this, arguments);
}
};
const makeTxPriorityQueue = (ref, ord) => {
const self = Object.create(TxPriorityQueueProto);
self[TypeId] = TypeId;
self.ref = ref;
self.ord = ord;
return self;
};
const insertSorted = (chunk, value, ord) => {
const arr = C.toArray(chunk);
let lo = 0;
let hi = arr.length;
while (lo < hi) {
const mid = lo + hi >>> 1;
if (ord(arr[mid], value) <= 0) {
lo = mid + 1;
} else {
hi = mid;
}
}
const out = Array(arr.length + 1);
for (let i = 0; i < lo; i++) out[i] = arr[i];
out[lo] = value;
for (let i = lo; i < arr.length; i++) out[i + 1] = arr[i];
return C.fromIterable(out);
};
/**
* Creates an empty `TxPriorityQueue` with the given ordering.
*
* **Example** (Creating an empty priority queue)
*
* ```ts
* import { Effect, Order, TxPriorityQueue } from "effect"
*
* const program = Effect.gen(function*() {
* const pq = yield* TxPriorityQueue.empty<number>(Order.Number)
* const empty = yield* TxPriorityQueue.isEmpty(pq)
* console.log(empty) // true
* })
* ```
*
* @category constructors
* @since 2.0.0
*/
export const empty = order => Effect.map(TxRef.make(C.empty()), ref => makeTxPriorityQueue(ref, order));
/**
* Creates a `TxPriorityQueue` from an iterable of elements.
*
* **Example** (Creating a priority queue from an iterable)
*
* ```ts
* import { Effect, Order, TxPriorityQueue } from "effect"
*
* const program = Effect.gen(function*() {
* const pq = yield* TxPriorityQueue.fromIterable(Order.Number, [3, 1, 2])
* const first = yield* TxPriorityQueue.take(pq)
* console.log(first) // 1
* })
* ```
*
* @category constructors
* @since 2.0.0
*/
export const fromIterable = /*#__PURE__*/dual(2, (order, iterable) => {
const arr = Array.from(iterable).sort((a, b) => order(a, b));
return Effect.map(TxRef.make(C.fromIterable(arr)), ref => makeTxPriorityQueue(ref, order));
});
/**
* Creates a `TxPriorityQueue` from variadic elements.
*
* **Example** (Creating a priority queue from variadic values)
*
* ```ts
* import { Effect, Order, TxPriorityQueue } from "effect"
*
* const program = Effect.gen(function*() {
* const pq = yield* TxPriorityQueue.make(Order.Number)(3, 1, 2)
* const first = yield* TxPriorityQueue.take(pq)
* console.log(first) // 1
* })
* ```
*
* @category constructors
* @since 2.0.0
*/
export const make = order => (...elements) => fromIterable(order, elements);
/**
* Returns the number of elements in the queue.
*
* **Example** (Getting the queue size)
*
* ```ts
* import { Effect, Order, TxPriorityQueue } from "effect"
*
* const program = Effect.gen(function*() {
* const pq = yield* TxPriorityQueue.fromIterable(Order.Number, [1, 2, 3])
* const s = yield* TxPriorityQueue.size(pq)
* console.log(s) // 3
* })
* ```
*
* @category getters
* @since 2.0.0
*/
export const size = self => Effect.map(TxRef.get(self.ref), C.size);
/**
* Returns `true` if the queue is empty.
*
* **Example** (Checking whether a queue is empty)
*
* ```ts
* import { Effect, Order, TxPriorityQueue } from "effect"
*
* const program = Effect.gen(function*() {
* const pq = yield* TxPriorityQueue.empty<number>(Order.Number)
* const empty = yield* TxPriorityQueue.isEmpty(pq)
* console.log(empty) // true
* })
* ```
*
* @category getters
* @since 2.0.0
*/
export const isEmpty = self => Effect.map(size(self), n => n === 0);
/**
* Returns `true` if the queue has at least one element.
*
* **Example** (Checking whether a queue has elements)
*
* ```ts
* import { Effect, Order, TxPriorityQueue } from "effect"
*
* const program = Effect.gen(function*() {
* const pq = yield* TxPriorityQueue.fromIterable(Order.Number, [1])
* const nonEmpty = yield* TxPriorityQueue.isNonEmpty(pq)
* console.log(nonEmpty) // true
* })
* ```
*
* @category getters
* @since 2.0.0
*/
export const isNonEmpty = self => Effect.map(size(self), n => n > 0);
/**
* Observes the smallest element without removing it.
*
* **When to use**
*
* Use to inspect the next prioritized value and retry transactionally while
* the queue is empty.
*
* **Example** (Peeking at the next value)
*
* ```ts
* import { Effect, Order, TxPriorityQueue } from "effect"
*
* const program = Effect.gen(function*() {
* const pq = yield* TxPriorityQueue.fromIterable(Order.Number, [3, 1, 2])
* const top = yield* TxPriorityQueue.peek(pq)
* console.log(top) // 1
* })
* ```
*
* @category getters
* @since 2.0.0
*/
export const peek = self => Effect.gen(function* () {
const chunk = yield* TxRef.get(self.ref);
const head = C.head(chunk);
if (O.isNone(head)) {
return yield* Effect.txRetry;
}
return head.value;
}).pipe(Effect.tx);
/**
* Observes the smallest element without removing it, returning `None` when the
* queue is empty.
*
* **When to use**
*
* Use to inspect the next prioritized value without retrying on an empty queue.
*
* **Example** (Peeking without retrying)
*
* ```ts
* import { Effect, Option, Order, TxPriorityQueue } from "effect"
*
* const program = Effect.gen(function*() {
* const pq = yield* TxPriorityQueue.empty<number>(Order.Number)
* const result = yield* TxPriorityQueue.peekOption(pq)
* console.log(Option.isNone(result)) // true
* })
* ```
*
* @category getters
* @since 2.0.0
*/
export const peekOption = self => Effect.map(TxRef.get(self.ref), C.head);
/**
* Inserts an element into the queue in sorted position.
*
* **Example** (Offering a value)
*
* ```ts
* import { Effect, Order, TxPriorityQueue } from "effect"
*
* const program = Effect.gen(function*() {
* const pq = yield* TxPriorityQueue.empty<number>(Order.Number)
* yield* TxPriorityQueue.offer(pq, 2)
* yield* TxPriorityQueue.offer(pq, 1)
* const first = yield* TxPriorityQueue.take(pq)
* console.log(first) // 1
* })
* ```
*
* @category mutations
* @since 2.0.0
*/
export const offer = /*#__PURE__*/dual(2, (self, value) => TxRef.update(self.ref, chunk => insertSorted(chunk, value, self.ord)));
/**
* Inserts all elements from an iterable into the queue.
*
* **Example** (Offering multiple values)
*
* ```ts
* import { Effect, Order, TxPriorityQueue } from "effect"
*
* const program = Effect.gen(function*() {
* const pq = yield* TxPriorityQueue.empty<number>(Order.Number)
* yield* TxPriorityQueue.offerAll(pq, [3, 1, 2])
* const first = yield* TxPriorityQueue.take(pq)
* console.log(first) // 1
* })
* ```
*
* @category mutations
* @since 2.0.0
*/
export const offerAll = /*#__PURE__*/dual(2, (self, values) => TxRef.update(self.ref, chunk => {
const arr = [...C.toArray(chunk), ...values].sort((a, b) => self.ord(a, b));
return C.fromIterable(arr);
}));
/**
* Takes the smallest element from the queue. Retries if the queue is empty.
*
* **Example** (Taking the next value)
*
* ```ts
* import { Effect, Order, TxPriorityQueue } from "effect"
*
* const program = Effect.gen(function*() {
* const pq = yield* TxPriorityQueue.fromIterable(Order.Number, [3, 1, 2])
* const first = yield* TxPriorityQueue.take(pq)
* console.log(first) // 1
* })
* ```
*
* @category mutations
* @since 2.0.0
*/
export const take = self => Effect.gen(function* () {
const chunk = yield* TxRef.get(self.ref);
const head = C.head(chunk);
if (O.isNone(head)) {
return yield* Effect.txRetry;
}
yield* TxRef.set(self.ref, C.drop(chunk, 1));
return head.value;
}).pipe(Effect.tx);
/**
* Takes all elements from the queue, returning them in priority order.
*
* **Example** (Taking all values in priority order)
*
* ```ts
* import { Effect, Order, TxPriorityQueue } from "effect"
*
* const program = Effect.gen(function*() {
* const pq = yield* TxPriorityQueue.fromIterable(Order.Number, [3, 1, 2])
* const all = yield* TxPriorityQueue.takeAll(pq)
* console.log(all) // [1, 2, 3]
* })
* ```
*
* @category mutations
* @since 2.0.0
*/
export const takeAll = self => Effect.map(TxRef.modify(self.ref, chunk => [chunk, C.empty()]), C.toArray);
/**
* Tries to take the smallest element. Returns `None` if the queue is empty.
*
* **Example** (Taking without retrying)
*
* ```ts
* import { Effect, Option, Order, TxPriorityQueue } from "effect"
*
* const program = Effect.gen(function*() {
* const pq = yield* TxPriorityQueue.empty<number>(Order.Number)
* const result = yield* TxPriorityQueue.takeOption(pq)
* console.log(Option.isNone(result)) // true
* })
* ```
*
* @category mutations
* @since 2.0.0
*/
export const takeOption = self => TxRef.modify(self.ref, chunk => {
const head = C.head(chunk);
if (O.isNone(head)) {
return [O.none(), chunk];
}
return [O.some(head.value), C.drop(chunk, 1)];
});
/**
* Takes up to `n` elements from the queue in priority order.
*
* **Example** (Taking up to a limit)
*
* ```ts
* import { Effect, Order, TxPriorityQueue } from "effect"
*
* const program = Effect.gen(function*() {
* const pq = yield* TxPriorityQueue.fromIterable(Order.Number, [5, 3, 1, 4, 2])
* const top2 = yield* TxPriorityQueue.takeUpTo(pq, 2)
* console.log(top2) // [1, 2]
* })
* ```
*
* @category mutations
* @since 2.0.0
*/
export const takeUpTo = /*#__PURE__*/dual(2, (self, n) => Effect.map(TxRef.modify(self.ref, chunk => {
const taken = C.take(chunk, n);
const rest = C.drop(chunk, n);
return [taken, rest];
}), C.toArray));
/**
* Removes elements matching the predicate.
*
* **Example** (Removing matching values)
*
* ```ts
* import { Effect, Order, TxPriorityQueue } from "effect"
*
* const program = Effect.gen(function*() {
* const pq = yield* TxPriorityQueue.fromIterable(Order.Number, [1, 2, 3, 4, 5])
* yield* TxPriorityQueue.removeIf(pq, (n) => n % 2 === 0)
* const all = yield* TxPriorityQueue.takeAll(pq)
* console.log(all) // [1, 3, 5]
* })
* ```
*
* @category filtering
* @since 2.0.0
*/
export const removeIf = /*#__PURE__*/dual(2, (self, predicate) => TxRef.update(self.ref, chunk => C.filter(chunk, a => !predicate(a))));
/**
* Keeps only elements matching the predicate.
*
* **Example** (Retaining matching values)
*
* ```ts
* import { Effect, Order, TxPriorityQueue } from "effect"
*
* const program = Effect.gen(function*() {
* const pq = yield* TxPriorityQueue.fromIterable(Order.Number, [1, 2, 3, 4, 5])
* yield* TxPriorityQueue.retainIf(pq, (n) => n % 2 === 0)
* const all = yield* TxPriorityQueue.takeAll(pq)
* console.log(all) // [2, 4]
* })
* ```
*
* @category filtering
* @since 2.0.0
*/
export const retainIf = /*#__PURE__*/dual(2, (self, predicate) => TxRef.update(self.ref, chunk => C.filter(chunk, predicate)));
/**
* Returns all elements in priority order without removing them.
*
* **Example** (Reading values in priority order)
*
* ```ts
* import { Effect, Order, TxPriorityQueue } from "effect"
*
* const program = Effect.gen(function*() {
* const pq = yield* TxPriorityQueue.fromIterable(Order.Number, [3, 1, 2])
* const all = yield* TxPriorityQueue.toArray(pq)
* console.log(all) // [1, 2, 3]
* })
* ```
*
* @category converting
* @since 2.0.0
*/
export const toArray = self => Effect.map(TxRef.get(self.ref), C.toArray);
/**
* Determines if the provided value is a `TxPriorityQueue`.
*
* **Example** (Checking for a TxPriorityQueue)
*
* ```ts
* import { Effect, Order, TxPriorityQueue } from "effect"
*
* const program = Effect.gen(function*() {
* const pq = yield* TxPriorityQueue.empty<number>(Order.Number)
* console.log(TxPriorityQueue.isTxPriorityQueue(pq)) // true
* console.log(TxPriorityQueue.isTxPriorityQueue("nope")) // false
* })
* ```
*
* @category guards
* @since 4.0.0
*/
export const isTxPriorityQueue = u => hasProperty(u, TypeId);
//# sourceMappingURL=TxPriorityQueue.js.map

Xet Storage Details

Size:
13 kB
·
Xet hash:
d56ce2fe84ef8f2fa3dd0f8437e20134a635b49ae854c3e557bc8ac54f833dad

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.