Skip to content

Commit

Permalink
feat(vectors): add formatter support
Browse files Browse the repository at this point in the history
- add ToStringOpts, defFormat(), FORMATTER
- update AVec and GVec impls
  • Loading branch information
postspectacular committed Aug 29, 2021
1 parent d6507ad commit 2bbb54e
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 15 deletions.
26 changes: 26 additions & 0 deletions packages/vectors/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -306,3 +306,29 @@ export const Z4: ReadonlyVec = Object.freeze([0, 0, 1, 0]);
export const W4: ReadonlyVec = Object.freeze([0, 0, 0, 1]);

export type Template = (syms: string[], i?: number) => string;

export interface ToStringOpts {
/**
* Number of fractional digits
*
* @defaultValue 3
*/
prec: number;
/**
* If given, each formatted vector component will be padded to given number
* of characters.
*/
width: number;
/**
* Inter-component delimiter.
*
* @defaultValue ", "
*/
delim: string;
/**
* Prefix/suffix wrapper strings.
*
* @defaultValue "[" and "]"
*/
wrap: ArrayLike<string>;
}
5 changes: 2 additions & 3 deletions packages/vectors/src/gvec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { eqDeltaS } from "./eqdelta";
import { stridedValues } from "./internal/vec-utils";
import { zeroes } from "./setn";
import { setS } from "./sets";
import { FORMATTER } from "./string";

const SYM_B = "buf";
const SYM_L = "length";
Expand Down Expand Up @@ -131,9 +132,7 @@ export const gvec = (
eqDeltaS(buf, o, size, eps, offset, 0, stride, 1);
case SYM_STR:
return () =>
JSON.stringify([
...stridedValues(obj, size, offset, stride),
]);
FORMATTER(stridedValues(obj, size, offset, stride));
default:
const j = parseInt(<string>id);
return !isNaN(j) && j >= 0 && j < size
Expand Down
5 changes: 5 additions & 0 deletions packages/vectors/src/internal/avec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type { NumericArray } from "@thi.ng/api";
import type { StridedVec } from "../api";
import { FORMATTER } from "../string";

export abstract class AVec implements StridedVec {
buf: NumericArray;
Expand All @@ -15,4 +16,8 @@ export abstract class AVec implements StridedVec {
abstract get length(): number;

abstract [Symbol.iterator](): IterableIterator<number>;

toString() {
return FORMATTER(this);
}
}
63 changes: 63 additions & 0 deletions packages/vectors/src/string.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { isFunction } from "@thi.ng/checks";
import { float, floatFixedWidth, Stringer } from "@thi.ng/strings";
import type { ToStringOpts } from "./api";

/**
* Returns a new generic vector formatter for given options (all optional). The
* returned function accepts a single vector(like) value and returns its
* formatted string representation.
*
* @remarks
* See {@link ToStringOpts} for further details. Also see {@link setFormat} to
* set default formatter.
*
* @example
* ```ts
* defFormat()([1, -2, 3])
* // [1.000, -2.000, 3.000]
*
* defFormat({ width: 10, wrap: "||", delim: "|\n|" })([1, -2, 3])
* // | 1.000|
* // | -2.000|
* // | 3.000|
*
* defFormat({ prec: 5, delim: " " })([1, -2, 3])
* // [1.00000 -2.00000 3.00000]
* ```
*
* @param prec
* @param width
*/
export const defFormat = (
opts?: Partial<ToStringOpts>
): Stringer<Iterable<number>> => {
const { prec, width, delim, wrap } = {
prec: 3,
delim: ", ",
wrap: "[]",
...opts,
};
const fmt = width ? floatFixedWidth(width, prec) : float(prec);
return (src) => {
let res: string[] = [];
for (let x of src) res.push(fmt(x));
return `${wrap[0]}${res.join(delim)}${wrap[1]}`;
};
};

/**
* Sets package-wide default vector formatter. See {@link defFormat},
* {@link FORMATTER}.
*
* @param fmt
*/
export const setFormat = (
fmt: Stringer<Iterable<number>> | Partial<ToStringOpts>
) => {
FORMATTER = isFunction(fmt) ? fmt : defFormat(fmt);
};

/**
* Package-wide default vector formatter.
*/
export let FORMATTER: Stringer<Iterable<number>> = defFormat();
4 changes: 0 additions & 4 deletions packages/vectors/src/vec2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,6 @@ export class Vec2 extends AVec implements IHash<number>, IVector<Vec2> {
toJSON() {
return [this.x, this.y];
}

toString() {
return `[${this.x}, ${this.y}]`;
}
}

declareIndices(Vec2.prototype, ["x", "y"]);
Expand Down
4 changes: 0 additions & 4 deletions packages/vectors/src/vec3.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,10 +127,6 @@ export class Vec3 extends AVec implements IHash<number>, IVector<Vec3> {
toJSON() {
return [this.x, this.y, this.z];
}

toString() {
return `[${this.x}, ${this.y}, ${this.z}]`;
}
}

declareIndices(Vec3.prototype, ["x", "y", "z"]);
Expand Down
4 changes: 0 additions & 4 deletions packages/vectors/src/vec4.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,10 +128,6 @@ export class Vec4 extends AVec implements IHash<number>, IVector<Vec4> {
toJSON() {
return [this.x, this.y, this.z, this.w];
}

toString() {
return `[${this.x}, ${this.y}, ${this.z}, ${this.w}]`;
}
}

declareIndices(Vec4.prototype, ["x", "y", "z", "w"]);
Expand Down

0 comments on commit 2bbb54e

Please sign in to comment.