|
| 1 | +/*-------------------------------------------------------------------------- |
| 2 | +
|
| 3 | +ParseBox |
| 4 | +
|
| 5 | +The MIT License (MIT) |
| 6 | +
|
| 7 | +Copyright (c) 2024-2025 Haydn Paterson |
| 8 | +
|
| 9 | +Permission is hereby granted, free of charge, to any person obtaining a copy |
| 10 | +of this software and associated documentation files (the "Software"), to deal |
| 11 | +in the Software without restriction, including without limitation the rights |
| 12 | +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| 13 | +copies of the Software, and to permit persons to whom the Software is |
| 14 | +furnished to do so, subject to the following conditions: |
| 15 | +
|
| 16 | +The above copyright notice and this permission notice shall be included in |
| 17 | +all copies or substantial portions of the Software. |
| 18 | +
|
| 19 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 20 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 21 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| 22 | +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 23 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 24 | +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| 25 | +THE SOFTWARE. |
| 26 | +
|
| 27 | +---------------------------------------------------------------------------*/ |
| 28 | + |
| 29 | +// deno-fmt-ignore-file |
| 30 | + |
| 31 | +// ------------------------------------------------------------------ |
| 32 | +// |
| 33 | +// Future: Binary Numeric Decoding |
| 34 | +// |
| 35 | +// ------------------------------------------------------------------ |
| 36 | + |
| 37 | + |
| 38 | +type D = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' |
| 39 | +type C = '0' | '1' |
| 40 | + |
| 41 | +// ------------------------------------------------------------------ |
| 42 | +// ReverseString |
| 43 | +// ------------------------------------------------------------------ |
| 44 | +type ReverseString<S extends string, R extends string = ''> = S extends `${infer F}${infer Rest}` ? ReverseString<Rest, `${F}${R}`> : R |
| 45 | + |
| 46 | +// ------------------------------------------------------------------ |
| 47 | +// DoubleDigit: Double a single digit with incoming carry -> [carryOut, outDigit] |
| 48 | +// ------------------------------------------------------------------ |
| 49 | +type DoubleDigit<DIG extends D, CarryIn extends C> = CarryIn extends '0' ? DIG extends '0' ? ['0', '0'] |
| 50 | + : DIG extends '1' ? ['0', '2'] |
| 51 | + : DIG extends '2' ? ['0', '4'] |
| 52 | + : DIG extends '3' ? ['0', '6'] |
| 53 | + : DIG extends '4' ? ['0', '8'] |
| 54 | + : DIG extends '5' ? ['1', '0'] |
| 55 | + : DIG extends '6' ? ['1', '2'] |
| 56 | + : DIG extends '7' ? ['1', '4'] |
| 57 | + : DIG extends '8' ? ['1', '6'] |
| 58 | + : ['1', '8'] |
| 59 | + : DIG extends '0' ? ['0', '1'] |
| 60 | + : DIG extends '1' ? ['0', '3'] |
| 61 | + : DIG extends '2' ? ['0', '5'] |
| 62 | + : DIG extends '3' ? ['0', '7'] |
| 63 | + : DIG extends '4' ? ['0', '9'] |
| 64 | + : DIG extends '5' ? ['1', '1'] |
| 65 | + : DIG extends '6' ? ['1', '3'] |
| 66 | + : DIG extends '7' ? ['1', '5'] |
| 67 | + : DIG extends '8' ? ['1', '7'] |
| 68 | + : ['1', '9'] |
| 69 | + |
| 70 | +// ------------------------------------------------------------------ |
| 71 | +// DoubleStringLR |
| 72 | +// ------------------------------------------------------------------ |
| 73 | +type DoubleStringLR<S extends string, CarryIn extends C = '0', R extends string = ''> = S extends `${infer F extends D}${infer Rest}` |
| 74 | + ? DoubleDigit<F, CarryIn> extends [infer CarryOut extends C, infer Out extends D] ? DoubleStringLR<Rest, CarryOut, `${R}${Out}`> |
| 75 | + : never |
| 76 | + : CarryIn extends '1' ? `${R}1` |
| 77 | + : R |
| 78 | + |
| 79 | +// ------------------------------------------------------------------ |
| 80 | +// TrimLeadingZeros |
| 81 | +// ------------------------------------------------------------------ |
| 82 | +type TrimLeadingZeros<S extends string> = S extends '' ? '0' |
| 83 | + : S extends `0${infer R}` ? TrimLeadingZeros<R> |
| 84 | + : S |
| 85 | + |
| 86 | +// ------------------------------------------------------------------ |
| 87 | +// DoubleString |
| 88 | +// ------------------------------------------------------------------ |
| 89 | +export type DoubleString<S extends string> = TrimLeadingZeros<ReverseString<DoubleStringLR<ReverseString<S>>>> |
| 90 | + |
| 91 | +// ------------------------------------------------------------------ |
| 92 | +// DoubleString: Tests |
| 93 | +// ------------------------------------------------------------------ |
| 94 | +type D1 = DoubleString<'0'> // "0" |
| 95 | +type D2 = DoubleString<'1'> // "2" |
| 96 | +type D3 = DoubleString<'9'> // "18" |
| 97 | +type D4 = DoubleString<'10'> // "20" |
| 98 | +type D5 = DoubleString<'99'> // "198" |
| 99 | +type D6 = DoubleString<'123456789'> // "246913578" |
| 100 | +type D7 = DoubleString<'0000'> // "0" |
| 101 | +type D8 = DoubleString<'0001'> // "2" |
| 102 | +type D9 = DoubleString<'500'> // "1000" |
| 103 | + |
| 104 | +// ------------------------------------------------------------------ |
| 105 | +// AddOneLR |
| 106 | +// ------------------------------------------------------------------ |
| 107 | +type AddOneLR<S extends string, Carry extends '1' | '0' = '1', R extends string = ''> = S extends `${infer F extends D}${infer Rest}` ? Carry extends '0' ? `${R}${F}${Rest}` // No carry, append rest as-is |
| 108 | + : F extends '0' ? AddOneLR<Rest, '0', `${R}1`> |
| 109 | + : F extends '1' ? AddOneLR<Rest, '0', `${R}2`> |
| 110 | + : F extends '2' ? AddOneLR<Rest, '0', `${R}3`> |
| 111 | + : F extends '3' ? AddOneLR<Rest, '0', `${R}4`> |
| 112 | + : F extends '4' ? AddOneLR<Rest, '0', `${R}5`> |
| 113 | + : F extends '5' ? AddOneLR<Rest, '0', `${R}6`> |
| 114 | + : F extends '6' ? AddOneLR<Rest, '0', `${R}7`> |
| 115 | + : F extends '7' ? AddOneLR<Rest, '0', `${R}8`> |
| 116 | + : F extends '8' ? AddOneLR<Rest, '0', `${R}9`> |
| 117 | + : /* 9 */ AddOneLR<Rest, '1', `${R}0`> // 9+1 = 10, carry |
| 118 | + : Carry extends '1' ? `${R}1` |
| 119 | + : R |
| 120 | + |
| 121 | +// ------------------------------------------------------------------ |
| 122 | +// AddOne |
| 123 | +// ------------------------------------------------------------------ |
| 124 | +type AddOne<S extends string> = ReverseString<AddOneLR<ReverseString<S>>> |
| 125 | + |
| 126 | +// ------------------------------------------------------------------ |
| 127 | +// AddOne: Tests |
| 128 | +// ------------------------------------------------------------------ |
| 129 | +type A1 = AddOne<'0'> // "1" |
| 130 | +type A2 = AddOne<'1'> // "2" |
| 131 | +type A3 = AddOne<'9'> // "10" |
| 132 | +type A4 = AddOne<'99'> // "100" |
| 133 | +type A5 = AddOne<'123'> // "124" |
| 134 | +type A6 = AddOne<'999'> // "1000" |
| 135 | + |
| 136 | +// ------------------------------------------------------------------ |
| 137 | +// BinaryToDecimal |
| 138 | +// ------------------------------------------------------------------ |
| 139 | +type BinaryToDecimal< |
| 140 | + B extends string, |
| 141 | + Result extends string = '0', |
| 142 | +> = B extends `${infer F extends '0' | '1'}${infer Rest}` |
| 143 | + ? F extends '0' |
| 144 | + ? BinaryToDecimal<Rest, DoubleString<Result>> |
| 145 | + : BinaryToDecimal<Rest, AddOne<DoubleString<Result>>> |
| 146 | + : Result |
| 147 | + |
| 148 | +// ------------------------------------------------------------------ |
| 149 | +// BinaryToDecimal: Test |
| 150 | +// ------------------------------------------------------------------ |
| 151 | +type N0 = BinaryToDecimal<'0'> // "0" |
| 152 | +type N1 = BinaryToDecimal<'1'> // "1" |
| 153 | +type N2 = BinaryToDecimal<'10'> // "2" |
| 154 | +type N3 = BinaryToDecimal<'11'> // "3" |
| 155 | +type N4 = BinaryToDecimal<'1010'> // "10" |
| 156 | +type N5 = BinaryToDecimal<'11111111'> // "255" |
| 157 | +type N6 = BinaryToDecimal<'11111111111111'> // "16383" |
| 158 | + |
0 commit comments