Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Possible string length algorithm #348

Open
sno2 opened this issue Aug 11, 2023 · 3 comments
Open

Possible string length algorithm #348

sno2 opened this issue Aug 11, 2023 · 3 comments

Comments

@sno2
Copy link

sno2 commented Aug 11, 2023

I devised a fast logarithmic string length algorithm based on carefully building string type patterns which is surprisingly tedious due to ${string}${string} simplifying to ${string} so we need to add an extra character $ before and after during all of our checks.

Anyways, this string length algorithm supports getting the length of strings up to 10,000 characters long (uses tuples for math). However, you could add an alternate path after the cache gets to 2^13 (8,192) to use your arbitrary math type to support more strings up until a very large size due to beauty of the logarithmic scale.

type TCache = [string, 0[]];

type StringLengthUp<
  T extends string,
  $Acc extends 0[] = [],
  $Cache extends TCache[] = [[`$${string}`, [0]]],
> =
  //
  $Cache extends [infer C extends TCache, ...infer $RestCache extends TCache[]]
    ? (
      `${C[0]}${C[0]}_` extends `$${string}$${infer $After}`
        ? `${C[0]}${$After}` extends `${infer $Before}_` ? $Before : never
        : never
    ) extends infer $DoubleC extends string
      ? `$${T}` extends `${$DoubleC}${infer $Rest}` ? StringLengthUp<
          $Rest,
          [...$Acc, ...C[1], ...C[1]],
          [[$DoubleC, [...C[1], ...C[1]]], ...$Cache]
        >
      : `$${T}` extends `${C[0]}${infer $Rest}`
        ? StringLengthUp<$Rest, [...$Acc, ...C[1]], $Cache>
      : StringLengthDown<T, $Acc, $RestCache>
    : never
    : $Acc["length"];

type StringLengthDown<
  T extends string,
  $Acc extends 0[],
  $Cache extends TCache[],
> = $Cache extends
  [infer C extends TCache, ...infer $RestCache extends TCache[]]
  ? `$${T}` extends `${C[0]}${infer $Rest}`
    ? StringLengthDown<$Rest, [...$Acc, ...C[1]], $Cache>
  : StringLengthDown<T, $Acc, $RestCache>
  : $Acc["length"];

type StringLength<T extends string> = T extends "" ? 0 : StringLengthUp<T>;

type String9999 = "<a 9999 character long string>";
type String9999Length = StringLength<String9999>; // 9999

The code is quite ugly so there still might be some opportunities for simplification.

@unional
Copy link
Owner

unional commented Aug 11, 2023

Thanks, are you suggesting a new type StringLength<T>?

For length, I can think of doing it like this:

type StringLength<T extends string> = T extends { length: infer L extends number } ? L : never

Have not test it but I think that will work.

@sno2
Copy link
Author

sno2 commented Aug 12, 2023

Yeah, sadly that won't work. It currently only makes the "length" property as number. See this TypeScript issue for more information.

@unional
Copy link
Owner

unional commented Aug 12, 2023

At, I see. I actually saw that issue before and 👍 it but forgot. 😀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants