Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Commit

Permalink
Merge pull request #5910 from matrix-org/travis/tests/array-obj-utils
Browse files Browse the repository at this point in the history
Add unit tests for various collection-based utility functions
  • Loading branch information
turt2live authored Apr 23, 2021
2 parents e088118 + 2c459c4 commit 09af2a8
Show file tree
Hide file tree
Showing 11 changed files with 1,242 additions and 17 deletions.
51 changes: 41 additions & 10 deletions src/utils/arrays.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright 2020 The Matrix.org Foundation C.I.C.
Copyright 2020, 2021 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand All @@ -15,23 +15,47 @@ limitations under the License.
*/

/**
* Quickly resample an array to have less data points. This isn't a perfect representation,
* though this does work best if given a large array to downsample to a much smaller array.
* @param {number[]} input The input array to downsample.
* Quickly resample an array to have less/more data points. If an input which is larger
* than the desired size is provided, it will be downsampled. Similarly, if the input
* is smaller than the desired size then it will be upsampled.
* @param {number[]} input The input array to resample.
* @param {number} points The number of samples to end up with.
* @returns {number[]} The downsampled array.
* @returns {number[]} The resampled array.
*/
export function arrayFastResample(input: number[], points: number): number[] {
// Heavily inpired by matrix-media-repo (used with permission)
if (input.length === points) return input; // short-circuit a complicated call

// Heavily inspired by matrix-media-repo (used with permission)
// https://github.com/turt2live/matrix-media-repo/blob/abe72c87d2e29/util/util_audio/fastsample.go#L10
const everyNth = Math.round(input.length / points);
const samples: number[] = [];
for (let i = 0; i < input.length; i += everyNth) {
samples.push(input[i]);
let samples: number[] = [];
if (input.length > points) {
// Danger: this loop can cause out of memory conditions if the input is too small.
const everyNth = Math.round(input.length / points);
for (let i = 0; i < input.length; i += everyNth) {
samples.push(input[i]);
}
} else {
// Smaller inputs mean we have to spread the values over the desired length. We
// end up overshooting the target length in doing this, so we'll resample down
// before returning. This recursion is risky, but mathematically should not go
// further than 1 level deep.
const spreadFactor = Math.ceil(points / input.length);
for (const val of input) {
samples.push(...arraySeed(val, spreadFactor));
}
samples = arrayFastResample(samples, points);
}

// Sanity fill, just in case
while (samples.length < points) {
samples.push(input[input.length - 1]);
}

// Sanity trim, just in case
if (samples.length > points) {
samples = samples.slice(0, points);
}

return samples;
}

Expand Down Expand Up @@ -178,6 +202,13 @@ export class GroupedArray<K, T> {
constructor(private val: Map<K, T[]>) {
}

/**
* The value of this group, after all applicable alterations.
*/
public get value(): Map<K, T[]> {
return this.val;
}

/**
* Orders the grouping into an array using the provided key order.
* @param keyOrder The key order.
Expand Down
22 changes: 17 additions & 5 deletions src/utils/enums.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright 2020 The Matrix.org Foundation C.I.C.
Copyright 2020, 2021 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand All @@ -19,11 +19,23 @@ limitations under the License.
* @param e The enum.
* @returns The enum values.
*/
export function getEnumValues<T>(e: any): T[] {
export function getEnumValues(e: any): (string | number)[] {
// String-based enums will simply be objects ({Key: "value"}), but number-based
// enums will instead map themselves twice: in one direction for {Key: 12} and
// the reverse for easy lookup, presumably ({12: Key}). In the reverse mapping,
// the key is a string, not a number.
//
// For this reason, we try to determine what kind of enum we're dealing with.

const keys = Object.keys(e);
return keys
.filter(k => ['string', 'number'].includes(typeof(e[k])))
.map(k => e[k]);
const values: (string | number)[] = [];
for (const key of keys) {
const value = e[key];
if (Number.isFinite(value) || e[value.toString()] !== Number(key)) {
values.push(value);
}
}
return values;
}

/**
Expand Down
20 changes: 19 additions & 1 deletion src/utils/objects.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
Copyright 2020 The Matrix.org Foundation C.I.C.
Copyright 2020, 2021 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -141,3 +141,21 @@ export function objectKeyChanges<O extends {}>(a: O, b: O): (keyof O)[] {
export function objectClone<O extends {}>(obj: O): O {
return JSON.parse(JSON.stringify(obj));
}

/**
* Converts a series of entries to an object.
* @param entries The entries to convert.
* @returns The converted object.
*/
// NOTE: Deprecated once we have Object.fromEntries() support.
// @ts-ignore - return type is complaining about non-string keys, but we know better
export function objectFromEntries<K, V>(entries: Iterable<[K, V]>): {[k: K]: V} {
const obj: {
// @ts-ignore - same as return type
[k: K]: V} = {};
for (const e of entries) {
// @ts-ignore - same as return type
obj[e[0]] = e[1];
}
return obj;
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

import {Singleflight} from "../src/utils/Singleflight";
import {Singleflight} from "../../src/utils/Singleflight";

describe('Singleflight', () => {
afterEach(() => {
Expand Down
Loading

0 comments on commit 09af2a8

Please sign in to comment.