<commit_before>/**
 * Call queue for executing callbacks asynchronously.
 *
 * Prevents releasing Zalgo.
 *
 * Copyright (C) 2015 <NAME>
 * License: MIT
 */

"use strict";

// TODO:
// - simpler code

import { assert } from "./util";

// ts-promise uses setImmediate by default, due to problems with
// process.nextTick behaving unreliably in older versions of Node.
// setImmediate is supposed to be available in the global scope, but browserify
// doesn't recognize it. It's also available in the "timers" module, but
// node.d.ts doesn't know that, and it may not be the version that timer-faking
// libs would replace. So, make it available if it isn't, only in these
// browserify'ed environments.
if (typeof setImmediate === "undefined") {
	window.setImmediate = setTimeout;
}

class CallQueue {
	[index: number]: any;

	// Basically twice the number of simultaneously resolving promises
	private _max: number = 1000;

	private _first: number = 0;
	length: number = 0;

	/**
	 * Push a new callback to the queue.
	 * @return true when the queue still has space, false if it's now 'full'
	 */
	push(callback: (arg: any) => void, arg: any): boolean {
		this[this.length++] = callback;
		this[this.length++] = arg;
		return this.length < this._max;
	}

	/**
	 * Flush all callbacks in this queue.
	 * Note that it is 'ok' for callbacks to throw an error;
	 * the next call to flush() will flush the remainder of the queue.
	 * When this function returns, the queue will be 'reset' to its beginning.
	 */
	flush(): void {
		while (this._first < this.length) {
			var callback = this[this._first];
			var arg = this[this._first + 1];
			this[this._first] = this[this._first + 1] = undefined;
			this._first += 2;
			callback(arg);
		}
		this.length = 0;
		this._first = 0;
	}
}

export class Async {
	private _pool: CallQueue[] = [];
	private _ring: CallQueue[] = [new CallQueue()];
	private _current: CallQueue = this._ring[0];
	private _flusher: () => void = (): void => this._scheduledFlush();
	private _flushing = false;
	private _scheduled = false;
	private _scheduler: (callback: () => void) => void = null;

	/**
	 * Configure alternative scheduler to use.
	 * The scheduler function will be called with a flusher, which needs to be
	 * executed to flush the queue. Note: the flusher may throw an
	 * exception, if any of the callbacks on the queue throws one.
	 * This will result in another flush to be scheduled before returning.
	 *
	 * Call with `null` to reset the scheduler to the default (setImmediate).
	 *
	 * Example usage (this is basically the default):
	 *   setScheduler((flusher) => setImmediate(flusher));
	 */
	setScheduler(scheduler: (flusher: () => void) => void): void {
		assert(scheduler === null || typeof scheduler === "function");
		this._scheduler = scheduler;
	}

	enqueue(callback: (arg: any) => void, arg: any): void {
		if (!this._flushing && !this._scheduled) {
			this._schedule();
		}
		if (!this._current) {
			this._current = this._pool.pop();
			if (!this._current) {
				this._current = new CallQueue();
			}
			this._ring.push(this._current);
		}
		if (!this._current.push(callback, arg)) {
			this._current = undefined;
		}
	}

	private _schedule(): void {
		assert(!this._scheduled);
		// Note: we 'fall back' to setImmediate here (instead of e.g.
		// assigning it to the _scheduler property once), to allow
		// setImmediate to be e.g. replaced by a mocked one (e.g. Sinon's
		// useFakeTimers())
		(this._scheduler || setImmediate)(this._flusher);
		this._scheduled = true;
	}

	private _scheduledFlush(): void {
		// Indicate that this 'iteration' of the flush is complete.
		this._scheduled = false;
		this.flush();
	}

	flush(): void {
		assert(!this._flushing, "cannot recursively flush");
		this._flushing = true;
		try {
			while (true) {
				// Note: ring is guaranteed to have at least one queue (even though<commit_msg>Revert setImmediate work-around, replace with non-global-polluting version.<commit_after>/**
 * Call queue for executing callbacks asynchronously.
 *
 * Prevents releasing Zalgo.
 *
 * Copyright (C) 2015 <NAME>
 * License: MIT
 */

"use strict";

// TODO:
// - simpler code

import { assert } from "./util";

class CallQueue {
	[index: number]: any;

	// Basically twice the number of simultaneously resolving promises
	private _max: number = 1000;

	private _first: number = 0;
	length: number = 0;

	/**
	 * Push a new callback to the queue.
	 * @return true when the queue still has space, false if it's now 'full'
	 */
	push(callback: (arg: any) => void, arg: any): boolean {
		this[this.length++] = callback;
		this[this.length++] = arg;
		return this.length < this._max;
	}

	/**
	 * Flush all callbacks in this queue.
	 * Note that it is 'ok' for callbacks to throw an error;
	 * the next call to flush() will flush the remainder of the queue.
	 * When this function returns, the queue will be 'reset' to its beginning.
	 */
	flush(): void {
		while (this._first < this.length) {
			var callback = this[this._first];
			var arg = this[this._first + 1];
			this[this._first] = this[this._first + 1] = undefined;
			this._first += 2;
			callback(arg);
		}
		this.length = 0;
		this._first = 0;
	}
}

export class Async {
	private _pool: CallQueue[] = [];
	private _ring: CallQueue[] = [new CallQueue()];
	private _current: CallQueue = this._ring[0];
	private _flusher: () => void = (): void => this._scheduledFlush();
	private _flushing = false;
	private _scheduled = false;
	private _scheduler: (callback: () => void) => void = null;

	/**
	 * Configure alternative scheduler to use.
	 * The scheduler function will be called with a flusher, which needs to be
	 * executed to flush the queue. Note: the flusher may throw an
	 * exception, if any of the callbacks on the queue throws one.
	 * This will result in another flush to be scheduled before returning.
	 *
	 * Call with `null` to reset the scheduler to the default (setImmediate).
	 *
	 * Example usage (this is basically the default):
	 *   setScheduler((flusher) => setImmediate(flusher));
	 */
	setScheduler(scheduler: (flusher: () => void) => void): void {
		assert(scheduler === null || typeof scheduler === "function");
		this._scheduler = scheduler;
	}

	enqueue(callback: (arg: any) => void, arg: any): void {
		if (!this._flushing && !this._scheduled) {
			this._schedule();
		}
		if (!this._current) {
			this._current = this._pool.pop();
			if (!this._current) {
				this._current = new CallQueue();
			}
			this._ring.push(this._current);
		}
		if (!this._current.push(callback, arg)) {
			this._current = undefined;
		}
	}

	private _schedule(): void {
		assert(!this._scheduled);
		// Note: we 'fall back' to setImmediate here (instead of e.g.
		// assigning it to the _scheduler property once), to allow
		// setImmediate to be e.g. replaced by a mocked one (e.g. Sinon's
		// useFakeTimers())
		let scheduler = this._scheduler;
		if (!scheduler) {
			scheduler = typeof setImmediate === "function" ? setImmediate : setTimeout;
		}
		scheduler(this._flusher);
		this._scheduled = true;
	}

	private _scheduledFlush(): void {
		// Indicate that this 'iteration' of the flush is complete.
		this._scheduled = false;
		this.flush();
	}

	flush(): void {
		assert(!this._flushing, "cannot recursively flush");
		this._flushing = true;
		try {
			while (true) {
				// Note: ring is guaranteed to have at least one queue (even though
{'fraction_non_alphanumeric': 0.12955191552727766, 'fraction_numerical': 0.004331934479490998, 'mean_word_length': 3.447922937989163, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '758811', 'n_tokens_mistral': 2503, 'n_tokens_neox': 2283, 'n_words': 821}