Skip to content

Commit

Permalink
bump patch version to 0.7.5
Browse files Browse the repository at this point in the history
- breaking change: renamed everything with "endianess" to "endianness", as the previous spelling was incorrect due to negligence to look it up.
- deprecations: `Array2DShape` has been renamed to `shapeOfArray2D`, and the former will be deprecated later on.
- in `array2d.ts`, add the functions `newArray2D`, `shuffleArray`, and `shuffledDeque`. these are copies from my `layout_engi_ts@v0.1.1` repo (omar-azmi/layout_engi_ts@b90f821).
- add more exports to `builtin_aliases.ts`. "yaaay" - said nobody in response to the bundle size increasing even more than before.
- fix typos in repo
- add `DEBUG` const enum compilation flags to minify the distribution further, when console logging is not essential.
- ready to convert repo to be JSR (http://jsr.io) compatible in the next release.
  • Loading branch information
omar-azmi committed Mar 2, 2024
1 parent 8b01098 commit 129050c
Show file tree
Hide file tree
Showing 23 changed files with 228 additions and 116 deletions.
2 changes: 1 addition & 1 deletion deno.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "kitchensink_ts",
"version": "0.7.4",
"version": "0.7.5",
"description": "a collection of personal utility functions",
"author": "Omar Azmi",
"license": "Lulz plz don't steal yet",
Expand Down
68 changes: 60 additions & 8 deletions src/array2d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
* @module
*/

import { array_isEmpty, math_random } from "./builtin_aliases_deps.ts"
import { max, modulo } from "./numericmethods.ts"
import { isFunction } from "./struct.ts"

/** a 2D array of cell type `T` */
export type Array2D<T> = T[][]
Expand All @@ -15,7 +17,7 @@ export type Array2DRowMajor<T> = Array2D<T>
/** alias for a column-major 2D array */
export type Array2DColMajor<T> = Array2D<T>

type Array2DShape_Signatures = {
type ShapeOfArray2D_Signatures = {
<T>(arr2d: Array2DRowMajor<T>): [rows: number, columns: number]
<T>(arr2d: Array2DColMajor<T>): [columns: number, rows: number]
<T>(arr2d: Array2D<T>): [major_length: number, minor_length: number]
Expand All @@ -29,18 +31,30 @@ type Array2DShape_Signatures = {
* [6 , 7 , 8 , 9 , 10],
* [11, 12, 13, 14, 15],
* ]
* const [rows, cols] = Array2DShape(arr2d)
* const [rows, cols] = shapeOfArray2D(arr2d)
* rows === 3
* cols === 5
* ```
*/
export const Array2DShape: Array2DShape_Signatures = <T>(arr2d: Array2D<T>): [major_length: number, minor_length: number] => {
export const shapeOfArray2D: ShapeOfArray2D_Signatures = <T>(arr2d: Array2D<T>): [major_length: number, minor_length: number] => {
const
major_len = arr2d.length,
minor_len = arr2d[0]?.length ?? 0
return [major_len, minor_len]
}

// TODO: deprecate this later on, as I didn't like the inconsistency in function naming, and the CamelCasing, instead of pascalCasing
/** @deprecated this got renamed to {@link shapeOfArray2D | `shapeOfArray2D`} for naming consistency. */
export const Array2DShape = shapeOfArray2D

/** create a new row-major 2d array, with provided value or fill function. */
export const newArray2D = <T>(rows: number, cols: number, fill_fn?: T | ((value?: undefined, column_index?: number, column_array?: (T | undefined)[]) => T)): Array2DRowMajor<T> => {
const col_map_fn = isFunction(fill_fn) ?
() => Array(cols).fill(undefined).map(fill_fn as () => T) :
() => Array(cols).fill(fill_fn)
return Array(rows).fill(undefined).map(col_map_fn)
}

type TransposeArray2D_Signatures = {
<T>(arr2d: Array2DRowMajor<T>): Array2DColMajor<T>
<T>(arr2d: Array2DColMajor<T>): Array2DRowMajor<T>
Expand Down Expand Up @@ -69,7 +83,7 @@ type TransposeArray2D_Signatures = {
*/
export const transposeArray2D: TransposeArray2D_Signatures = <T>(arr2d: Array2D<T>): Array2D<T> => {
const
[rows, cols] = Array2DShape(arr2d),
[rows, cols] = shapeOfArray2D(arr2d),
arr_transposed: Array2D<T> = []
for (let c = 0; c < cols; c++) { arr_transposed[c] = [] }
for (let r = 0; r < rows; r++) {
Expand Down Expand Up @@ -110,7 +124,7 @@ export const transposeArray2D: TransposeArray2D_Signatures = <T>(arr2d: Array2D<
* ```
*/
export const spliceArray2DMajor = <T>(arr2d: Array2DRowMajor<T>, start: number, delete_count?: number, ...insert_items: Array2DRowMajor<T>): Array2DRowMajor<T> => {
const [rows, cols] = Array2DShape(arr2d)
const [rows, cols] = shapeOfArray2D(arr2d)
delete_count ??= max(rows - start, 0)
return arr2d.splice(start, delete_count, ...insert_items)
}
Expand Down Expand Up @@ -149,7 +163,7 @@ export const spliceArray2DMajor = <T>(arr2d: Array2DRowMajor<T>, start: number,
*/
export const spliceArray2DMinor = <T>(arr2d: Array2DRowMajor<T>, start: number, delete_count?: number, ...insert_items: Array2DColMajor<T>): Array2DColMajor<T> => {
const
[rows, cols] = Array2DShape(arr2d),
[rows, cols] = shapeOfArray2D(arr2d),
insert_items_rowwise: Array2DRowMajor<T> = insert_items.length > 0 ?
transposeArray2D(insert_items) :
Array(rows).fill([])
Expand Down Expand Up @@ -193,7 +207,7 @@ export const spliceArray2DMinor = <T>(arr2d: Array2DRowMajor<T>, start: number,
* ```
*/
export const rotateArray2DMajor = <T>(arr2d: Array2DRowMajor<T>, amount: number): typeof arr2d => {
const [rows, cols] = Array2DShape(arr2d)
const [rows, cols] = shapeOfArray2D(arr2d)
// compute the effective right-rotation amount so that it handles negative values and full rotations
amount = modulo(amount, rows === 0 ? 1 : rows)
// there is nothing to rotate if the effective amount is zero
Expand Down Expand Up @@ -227,7 +241,7 @@ export const rotateArray2DMajor = <T>(arr2d: Array2DRowMajor<T>, amount: number)
* ```
*/
export const rotateArray2DMinor = <T>(arr2d: Array2DRowMajor<T>, amount: number): typeof arr2d => {
const [rows, cols] = Array2DShape(arr2d)
const [rows, cols] = shapeOfArray2D(arr2d)
// compute the effective right-rotation amount so that it handles negative values and full rotations
amount = modulo(amount, cols === 0 ? 1 : cols)
// there is nothing to rotate if the effective amount is zero
Expand Down Expand Up @@ -316,3 +330,41 @@ export const meshMap = <X, Y, Z>(map_fn: (x: X, y: Y) => Z, x_values: Array<X>,
}
return z_values
}

/** shuffle a 1D array via mutation. the ordering of elements will be randomized by the end. */
export const shuffleArray = <T>(arr: Array<T>): Array<T> => {
const
len = arr.length,
rand_int = () => (math_random() * len) | 0,
swap = (i1: number, i2: number) => {
const temp = arr[i1]
arr[i1] = arr[i2]
arr[i2] = temp
}
for (let i = 0; i < len; i++) swap(i, rand_int())
return arr
}

/** a generator that yields random selected non-repeating elements out of a 1D array.
* once the all elements have been yielded, a cycle has been completed.
* after a cycle is completed the iterator resets to a new cycle, yielding randomly selected elements once again.
* the ordering of the randomly yielded elements will also differ from compared to the first time. <br>
* moreover, you can call the iterator with an optional number argument that specifies if you wish to skip ahead a certain number of elements.
* - `1`: go to next element (default behavior)
* - `0`: receive the same element as before
* - `-1`: go to previous next element
* - `+ve number`: skip to next `number` of elements
* - `-ve number`: go back `number` of elements
*
* note that once a cycle is complete, going back won't restore the correct element from the previous cycle, because the info about the previous cycle gets lost.
*/
export const shuffledDeque = function* <T>(arr: Array<T>): Generator<T, void, number | undefined> {
let i = arr.length // this is only temporary. `i` immediately becomes `0` when the while loop begins
while (!array_isEmpty(arr)) {
if (i >= arr.length) {
i = 0
shuffleArray(arr)
}
i = max(i + ((yield arr[i]) ?? 1), 0)
}
}
2 changes: 1 addition & 1 deletion src/browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export const base64BodyToBytes = (data_base64: string): Uint8Array => {
*/
export const bytesToBase64Body = (data_buf: Uint8Array): string => {
// here, we use `String.fromCharCode` to convert numbers to their equivalent binary string encoding. ie: `String.fromCharCode(3, 2, 1) === "\x03\x02\x01"`
// however, most browsers only allow a maximum number of function agument to be around `60000` to `65536`, so we play it safe here by picking around 33000
// however, most browsers only allow a maximum number of function argument to be around `60000` to `65536`, so we play it safe here by picking around 33000
// we must also select a `max_args` such that it is divisible by `6`, because we do not want any trailing "=" or "==" to appear in the middle of our base64
// encoding where we've split the data.
const
Expand Down
10 changes: 5 additions & 5 deletions src/builtin_aliases.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export const {
pow: math_pow,
sqrt: math_sqrt,
// random function
random: math_random,
// random: math_random,
// math constants
E: math_E,
LN10: math_LN10,
Expand All @@ -70,12 +70,12 @@ export const {
// NEGATIVE_INFINITY: number_NEGATIVE_INFINITY,
NaN: number_NaN,
// POSITIVE_INFINITY: number_POSITIVE_INFINITY,
isFinite: number_isFinite,
// isFinite: number_isFinite,
// isInteger: number_isInteger,
isNaN: number_isNaN,
// isNaN: number_isNaN,
isSafeInteger: number_isSafeInteger,
parseFloat: number_parseFloat,
parseInt: number_parseInt,
// parseFloat: number_parseFloat,
// parseInt: number_parseInt,
} = Number

export const {
Expand Down
24 changes: 23 additions & 1 deletion src/builtin_aliases_deps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,20 @@ export const {
} = Array

export const {
isInteger: number_isInteger,
MAX_VALUE: number_MAX_VALUE,
NEGATIVE_INFINITY: number_NEGATIVE_INFINITY,
POSITIVE_INFINITY: number_POSITIVE_INFINITY,
isFinite: number_isFinite,
isInteger: number_isInteger,
isNaN: number_isNaN,
parseFloat: number_parseFloat,
parseInt: number_parseInt,
} = Number

export const {
random: math_random,
} = Math

export const {
assign: object_assign,
defineProperty: object_defineProperty,
Expand All @@ -72,3 +80,17 @@ export const
dom_clearTimeout = clearTimeout,
dom_setInterval = setInterval,
dom_clearInterval = clearInterval

export const {
assert: console_assert,
clear: console_clear,
debug: console_debug,
dir: console_dir,
error: console_error,
log: console_log,
table: console_table,
} = console

export const {
now: performance_now,
} = performance
32 changes: 16 additions & 16 deletions src/collections.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import {
bind_array_clear,
bind_array_pop,
bind_array_push,
bind_array_shift,
bind_array_unshift,
bind_map_delete,
bind_map_entries,
bind_map_forEach,
Expand All @@ -21,7 +19,8 @@ import {
bind_set_has,
bind_stack_seek,
} from "./binder.ts"
import { array_isEmpty, object_assign, symbol_iterator, symbol_toStringTag } from "./builtin_aliases_deps.ts"
import { array_isEmpty, console_log, object_assign, symbol_iterator, symbol_toStringTag } from "./builtin_aliases_deps.ts"
import { DEBUG } from "./deps.ts"
import { modulo } from "./numericmethods.ts"
import { isComplex, monkeyPatchPrototypeOfClass } from "./struct.ts"
import { PrefixProps } from "./typedefs.ts"
Expand All @@ -43,8 +42,8 @@ export class Deque<T> {
}

static {
// we are forced to assign `[Symbol.iterator]` method to the prototype in a static block (on the first class invokation),
// because `esbuild` does not consider Symbol propety method assignment to be side-effect free.
// we are forced to assign `[Symbol.iterator]` method to the prototype in a static block (on the first class invocation),
// because `esbuild` does not consider Symbol property method assignment to be side-effect free.
// which in turn results in this class being included in any bundle that imports anything from `collections.ts`
/*@__PURE__*/
monkeyPatchPrototypeOfClass<Deque<any>>(this, symbol_iterator as typeof Symbol.iterator, function (this: Deque<unknown>) {
Expand Down Expand Up @@ -558,12 +557,12 @@ export class TopologicalScheduler<ID, FROM extends ID = ID, TO extends ID = ID>
visits_get = bind_map_get(visits),
visits_set = bind_map_set(visits)

const recursive_dfs_visiter = (id: FROM) => {
const recursive_dfs_visitor = (id: FROM) => {
for (const to_id of edges_get(id) ?? []) {
const visits = visits_get(to_id)
// if the child node has been visited at least once before (`0 || undefined`), do not dfs revisit it again. just increment its counter
if (visits) { visits_set(to_id, visits + 1) }
else { recursive_dfs_visiter(to_id as unknown as FROM) }
else { recursive_dfs_visitor(to_id as unknown as FROM) }
}
visits_set(id, 1)
}
Expand Down Expand Up @@ -595,7 +594,7 @@ export class TopologicalScheduler<ID, FROM extends ID = ID, TO extends ID = ID>

const fire = (...source_ids: FROM[]) => {
visits.clear()
source_ids.forEach(recursive_dfs_visiter)
source_ids.forEach(recursive_dfs_visitor)
compute_stacks_based_on_visits()
}

Expand Down Expand Up @@ -629,6 +628,7 @@ export class TopologicalScheduler<ID, FROM extends ID = ID, TO extends ID = ID>

export type InvertibleGraphEdges<ID extends PropertyKey, FROM extends ID = ID, TO extends ID = ID> = InvertibleMap<FROM, TO>

// TODO ISSUE: the implementation may be incorrect as this was made during the time when I wrote the incorrect topological scheduler for `tsignal_ts@v0.1.x`
// TODO ISSUE: dependencies/dependants added during a firing cycle AND their some of their dependencies have already been resolved, will lead to forever unresolved newly added depenant
// see `/test/collections.topological_scheduler.test.ts`
export class TopologicalAsyncScheduler<ID extends PropertyKey, FROM extends ID = ID, TO extends ID = ID> {
Expand Down Expand Up @@ -664,7 +664,7 @@ export class TopologicalAsyncScheduler<ID extends PropertyKey, FROM extends ID =
}

const fire = (...source_ids: FROM[]) => {
console.log(source_ids)
DEBUG.LOG && console_log(source_ids)
clear();
(source_ids as unknown[] as TO[]).forEach(pending_add)
}
Expand All @@ -691,7 +691,7 @@ export class TopologicalAsyncScheduler<ID extends PropertyKey, FROM extends ID =
}
}
next_ids.forEach(pending_add)
console.log(next_ids)
DEBUG.LOG && console_log(next_ids)
return next_ids
}

Expand Down Expand Up @@ -761,7 +761,7 @@ export class HybridWeakMap<K, V> implements SimpleMap<K, V> {
}

/** a tree object (constructed by class returned by {@link treeClass_Factory}) with no initialized value will have this symbol set as its default value */
export const TREE_VALUE_UNSET = /*@__PURE__*/ Symbol("represents an unset value for a tree")
export const TREE_VALUE_UNSET = /*@__PURE__*/ Symbol(DEBUG.MINIFY || "represents an unset value for a tree")

// TODO: annotate/document this class, and talk about its similarities with the "Walk" method commonly used in filesystem traversal along with its "create intermediate" option
export const treeClass_Factory = /*@__PURE__*/ (base_map_class: new <KT, VT>(...args: any[]) => SimpleMap<KT, VT>) => {
Expand Down Expand Up @@ -828,16 +828,16 @@ export class StackSet<T> extends Array<T> {
/** peek at the top item of the stack without popping */
top = bind_stack_seek(this)

/** syncronize the ordering of the stack with the underlying {@link $set} object's insertion order (i.e. iteration ordering). <br>
/** synchronize the ordering of the stack with the underlying {@link $set} object's insertion order (i.e. iteration ordering). <br>
* the "f" in "fsync" stands for "forward"
*/
fsync(): number {
super.splice(0)
return super.push(...this.$set)
}

/** syncronize the insertion ordering of the underlying {@link $set} with `this` stack array's ordering. <br>
* this process is more expensive than {@link fsync}, as it has to rebuild the entirity of the underlying set object. <br>
/** synchronize the insertion ordering of the underlying {@link $set} with `this` stack array's ordering. <br>
* this process is more expensive than {@link fsync}, as it has to rebuild the entirety of the underlying set object. <br>
* the "r" in "rsync" stands for "reverse"
*/
rsync(): number {
Expand Down Expand Up @@ -1041,7 +1041,7 @@ export interface ChainedPromiseQueueConfig<T> {
}

/** a collection of promises that can be further chained with a sequence of "then" functions.
* once a certain promise in the collection is completed (i.e. goes throuh all of the chained then functions),
* once a certain promise in the collection is completed (i.e. goes through all of the chained then functions),
* then it gets deleted from this collection.
*
* @example
Expand Down Expand Up @@ -1077,7 +1077,7 @@ export class ChainedPromiseQueue<T> extends Array<Promise<T>> {
]>
] = []

/** an array of promises consisting of all the final "then" calls, after which (when fullfilled) the promise would be shortly deleted since it will no longer be pending.
/** an array of promises consisting of all the final "then" calls, after which (when fulfilled) the promise would be shortly deleted since it will no longer be pending.
* the array indexes of `this.pending` line up with `this`, in the sense that `this.pending[i] = this[i].then(this.chain.at(0))...then(this.chain.at(-1))`.
* once a promise inside of `pending` is fulfilled, it will be shortly deleted (via splicing) from `pending`,
* and its originating `Promise` which was pushed into `this` collection will also get removed. <br>
Expand Down
4 changes: 2 additions & 2 deletions src/crypto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const init_crc32_table = () => {
}

/** the CRC32 hash is quick to compute and used frequently in compression functions and their derivatives <br>
* you do not have to provide the `bytes` array in its entirity all at once, because you can continue
* you do not have to provide the `bytes` array in its entirety all at once, because you can continue
* off with the previous partial byte array's crc-hash using the second argument.
* @example
* ```ts
Expand All @@ -27,7 +27,7 @@ const init_crc32_table = () => {
* crc_c = Crc32(txtenc.encode("hello world")) // == 0x0D4A1185
* console.assert(crc_b === crc_c)
* ```
* @param bytes an array of bytes to compute the hash for. can be any kind of array, so long as all byte numbers conform to being unsinged integers that do not exceed the maximum value of `255` (8-bit max value)
* @param bytes an array of bytes to compute the hash for. can be any kind of array, so long as all byte numbers conform to being unsigned integers that do not exceed the maximum value of `255` (8-bit max value)
* @param crc provide any previous crc hash that you'd like to continue from, or leave it `undefined` to begin from the standard value of `0xFFFFFFFF` by default
*/
export const Crc32 = (bytes: Uint8Array | Array<number>, crc?: number) => {
Expand Down
12 changes: 11 additions & 1 deletion src/deps.ts
Original file line number Diff line number Diff line change
@@ -1 +1,11 @@
/** no external library dependancies yet */
/** no external library dependencies. as it should be. */


/** flags used for minifying (or eliminating) debugging logs and asserts, when an intelligent bundler, such as `esbuild`, is used. */
export const enum DEBUG {
LOG = 0,
ASSERT = 0,
ERROR = 0,
PRODUCTION = 1,
MINIFY = 1,
}
Loading

0 comments on commit 129050c

Please sign in to comment.