/*! @license
* Shaka Player
* Copyright 2016 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
goog.provide('shaka.util.Iterables');
/**
* Recreations of Array-like functions so that they work on any iterable
* type.
* @final
*/
shaka.util.Iterables = class {
/**
* @param {!Iterable.<FROM>} iterable
* @param {function(FROM):TO} mapping
* @return {!Iterable.<TO>}
* @template FROM,TO
*/
static map(iterable, mapping) {
const array = [];
for (const x of iterable) {
array.push(mapping(x));
}
return array;
}
/**
* @param {!Iterable.<T>} iterable
* @param {function(T):boolean} test
* @return {boolean}
* @template T
*/
static every(iterable, test) {
for (const x of iterable) {
if (!test(x)) {
return false;
}
}
return true;
}
/**
* @param {!Iterable.<T>} iterable
* @param {function(T):boolean} test
* @return {boolean}
* @template T
*/
static some(iterable, test) {
for (const x of iterable) {
if (test(x)) {
return true;
}
}
return false;
}
/**
* Iterate over an iterable object and return only the items that |filter|
* returns true for.
*
* @param {!Iterable.<T>} iterable
* @param {function(T):boolean} filter
* @return {!Array.<T>}
* @template T
*/
static filter(iterable, filter) {
const out = [];
for (const x of iterable) {
if (filter(x)) {
out.push(x);
}
}
return out;
}
/**
* Returns an iterable that contains numbers in the range [0, end).
*
* @param {number} end The exclusive end of the list.
* @return {!Iterable.<number>}
*/
static* range(end) {
for (let i = 0; i < end; i++) {
yield i;
}
}
/**
* Iterates over an iterable object and includes additional info about each
* item:
* - The zero-based index of the element.
* - The next item in the list, if it exists.
* - The previous item in the list, if it exists.
*
* @param {!Iterable.<T>} iterable
* @return {!Iterable.<
* {i: number, item: T, prev: (T|undefined), next: (T|undefined)}>}
* @template T
*/
static* enumerate(iterable) {
// Since we want the "next" item, we need to skip the first item and return
// elements one in the past. So as we iterate, we are getting the "next"
// element and yielding the one from the previous iteration.
let i = -1;
let prev = undefined;
let item = undefined;
for (const next of iterable) {
if (i >= 0) {
yield {i, item, prev, next};
}
i++;
prev = item;
item = next;
}
if (i != -1) {
// If it's still -1, there were no items. Otherwise we need to yield
// the last item.
yield {i, prev, item, next: undefined};
}
}
};