@ddunigma/node 1.0.11 → 1.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.js +68 -110
- package/dist/cjs/test/{test1.js → test2.js} +4 -4
- package/dist/cjs/test/tester2.js +46 -0
- package/dist/index.d.ts +3 -10
- package/dist/mjs/index.js +70 -122
- package/dist/mjs/test/test2.d.ts +1 -0
- package/dist/mjs/test/{test1.js → test2.js} +4 -4
- package/dist/mjs/test/tester2.d.ts +1 -0
- package/dist/mjs/test/tester2.js +44 -0
- package/package.json +3 -3
- /package/dist/cjs/test/{test1.d.ts → test2.d.ts} +0 -0
- /package/dist/{mjs/test/test1.d.ts → cjs/test/tester2.d.ts} +0 -0
package/dist/cjs/index.js
CHANGED
|
@@ -15,29 +15,18 @@ class Ddu64 {
|
|
|
15
15
|
];
|
|
16
16
|
this.paddingCharKr = "뭐";
|
|
17
17
|
this.defaultEncoding = "utf-8";
|
|
18
|
-
this.dduChar = dduChar || this.dduCharKr;
|
|
19
|
-
this.paddingChar = paddingChar || this.paddingCharKr;
|
|
20
18
|
this.bitLengthMap = new Map();
|
|
21
|
-
this.binaryLookup =
|
|
19
|
+
this.binaryLookup = Array.from({ length: 256 }, (_, i) => i.toString(2).padStart(8, "0"));
|
|
22
20
|
this.dduBinaryLookup = new Map();
|
|
23
21
|
this.dduBinaryLookupKr = new Map();
|
|
24
22
|
this.paddingRegex = new Map();
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
this.
|
|
29
|
-
this.dduBinaryLookup.set(char, index);
|
|
30
|
-
});
|
|
31
|
-
this.dduCharKr.forEach((char, index) => {
|
|
32
|
-
this.dduBinaryLookupKr.set(char, index);
|
|
33
|
-
});
|
|
23
|
+
this.dduChar = dduChar || this.dduCharKr;
|
|
24
|
+
this.paddingChar = paddingChar || this.paddingCharKr;
|
|
25
|
+
this.dduChar.forEach((char, index) => this.dduBinaryLookup.set(char, index));
|
|
26
|
+
this.dduCharKr.forEach((char, index) => this.dduBinaryLookupKr.set(char, index));
|
|
34
27
|
this.paddingRegex.set("default", new RegExp(this.paddingChar, "g"));
|
|
35
28
|
this.paddingRegex.set("KR", new RegExp(this.paddingCharKr, "g"));
|
|
36
29
|
}
|
|
37
|
-
getLargestPowerOfTwo(n) {
|
|
38
|
-
let power = Math.floor(Math.log2(n));
|
|
39
|
-
return Math.pow(2, power);
|
|
40
|
-
}
|
|
41
30
|
getBitLength(setLength) {
|
|
42
31
|
let cached = this.bitLengthMap.get(setLength);
|
|
43
32
|
if (cached === undefined) {
|
|
@@ -46,43 +35,34 @@ class Ddu64 {
|
|
|
46
35
|
}
|
|
47
36
|
return cached;
|
|
48
37
|
}
|
|
38
|
+
getLargestPowerOfTwo(n) {
|
|
39
|
+
return Math.pow(2, Math.floor(Math.log2(n)));
|
|
40
|
+
}
|
|
49
41
|
*splitString(s, length) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
yield s.slice(i, Math.min(i + length, len));
|
|
42
|
+
for (let i = 0; i < s.length; i += length) {
|
|
43
|
+
yield s.slice(i, Math.min(i + length, s.length));
|
|
53
44
|
}
|
|
54
45
|
}
|
|
55
|
-
getSelectedSets(dduSetSymbol) {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
paddingRegExp: this.paddingRegex.get("KR"),
|
|
64
|
-
};
|
|
46
|
+
getSelectedSets(dduSetSymbol, usePowerOfTwo) {
|
|
47
|
+
const isKR = dduSetSymbol === "KR";
|
|
48
|
+
const dduSet = isKR ? this.dduCharKr : this.dduChar;
|
|
49
|
+
const padChar = isKR ? this.paddingCharKr : this.paddingChar;
|
|
50
|
+
let dduLength = dduSet.length;
|
|
51
|
+
if (usePowerOfTwo) {
|
|
52
|
+
const powerOfTwoLength = this.getLargestPowerOfTwo(dduLength);
|
|
53
|
+
dduLength = powerOfTwoLength;
|
|
65
54
|
}
|
|
66
55
|
return {
|
|
67
|
-
dduSet:
|
|
68
|
-
padChar
|
|
69
|
-
dduLength
|
|
70
|
-
bitLength: this.getBitLength(
|
|
71
|
-
lookupTable: this.dduBinaryLookup,
|
|
72
|
-
paddingRegExp: this.paddingRegex.get("default"),
|
|
56
|
+
dduSet: usePowerOfTwo ? dduSet.slice(0, dduLength) : dduSet,
|
|
57
|
+
padChar,
|
|
58
|
+
dduLength,
|
|
59
|
+
bitLength: this.getBitLength(dduLength),
|
|
60
|
+
lookupTable: isKR ? this.dduBinaryLookupKr : this.dduBinaryLookup,
|
|
61
|
+
paddingRegExp: this.paddingRegex.get(isKR ? "KR" : "default"),
|
|
73
62
|
};
|
|
74
63
|
}
|
|
75
|
-
getSelectedSets64(option) {
|
|
76
|
-
const baseSet = this.getSelectedSets(option);
|
|
77
|
-
const powerOfTwoLength = this.getLargestPowerOfTwo(baseSet.dduSet.length);
|
|
78
|
-
return Object.assign(Object.assign({}, baseSet), { dduSet: baseSet.dduSet.slice(0, powerOfTwoLength), dduLength: powerOfTwoLength, bitLength: Math.log2(powerOfTwoLength) });
|
|
79
|
-
}
|
|
80
64
|
bufferToDduBinary(input, bitLength) {
|
|
81
|
-
const
|
|
82
|
-
let encodedBin = "";
|
|
83
|
-
for (let i = 0; i < bufferLength; i++) {
|
|
84
|
-
encodedBin += this.binaryLookup[input[i]];
|
|
85
|
-
}
|
|
65
|
+
const encodedBin = input.reduce((acc, byte) => acc + this.binaryLookup[byte], "");
|
|
86
66
|
const dduBinary = Array.from(this.splitString(encodedBin, bitLength));
|
|
87
67
|
const padding = bitLength - dduBinary[dduBinary.length - 1].length;
|
|
88
68
|
if (padding > 0) {
|
|
@@ -90,86 +70,64 @@ class Ddu64 {
|
|
|
90
70
|
}
|
|
91
71
|
return { dduBinary, padding };
|
|
92
72
|
}
|
|
93
|
-
dduBinaryToBuffer(decodedBin,
|
|
94
|
-
const paddingBits = paddingCount * 2;
|
|
73
|
+
dduBinaryToBuffer(decodedBin, paddingBits) {
|
|
95
74
|
if (paddingBits > 0) {
|
|
96
75
|
decodedBin = decodedBin.slice(0, -paddingBits);
|
|
97
76
|
}
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
const start = i * 8;
|
|
102
|
-
buffer[i] = parseInt(decodedBin.slice(start, start + 8), 2);
|
|
77
|
+
const buffer = [];
|
|
78
|
+
for (let i = 0; i < decodedBin.length; i += 8) {
|
|
79
|
+
buffer.push(parseInt(decodedBin.slice(i, i + 8), 2));
|
|
103
80
|
}
|
|
104
|
-
return buffer;
|
|
81
|
+
return Buffer.from(buffer);
|
|
105
82
|
}
|
|
106
83
|
encode(input, options = {}) {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
const
|
|
110
|
-
const { dduSet, padChar, dduLength, bitLength } = this.getSelectedSets(options.dduSetSymbol);
|
|
111
|
-
const { dduBinary, padding } = this.bufferToDduBinary(bufferInput, bitLength);
|
|
112
|
-
let resultString = "";
|
|
113
|
-
for (const char of dduBinary) {
|
|
114
|
-
const charInt = parseInt(char, 2);
|
|
115
|
-
const quotient = Math.floor(charInt / dduLength);
|
|
116
|
-
const remainder = charInt % dduLength;
|
|
117
|
-
resultString += dduSet[quotient] + dduSet[remainder];
|
|
118
|
-
}
|
|
119
|
-
if (padding > 0) {
|
|
120
|
-
return resultString + padChar.repeat(Math.floor(padding / 2));
|
|
121
|
-
}
|
|
122
|
-
return resultString;
|
|
123
|
-
}
|
|
124
|
-
encode64(input, options = {}) {
|
|
125
|
-
options.dduSetSymbol = options.dduSetSymbol || "default";
|
|
126
|
-
options.encoding = options.encoding || this.defaultEncoding;
|
|
127
|
-
const bufferInput = typeof input === "string" ? Buffer.from(input, options.encoding) : input;
|
|
128
|
-
const { dduSet, padChar, bitLength } = this.getSelectedSets64(options.dduSetSymbol);
|
|
84
|
+
const { dduSetSymbol = "default", encoding = this.defaultEncoding, usePowerOfTwo = false, } = options;
|
|
85
|
+
const bufferInput = typeof input === "string" ? Buffer.from(input, encoding) : input;
|
|
86
|
+
const { dduSet, padChar, dduLength, bitLength } = this.getSelectedSets(dduSetSymbol, usePowerOfTwo);
|
|
129
87
|
const { dduBinary, padding } = this.bufferToDduBinary(bufferInput, bitLength);
|
|
130
88
|
let resultString = "";
|
|
131
|
-
for (const
|
|
132
|
-
const charInt = parseInt(
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
89
|
+
for (const binaryChunk of dduBinary) {
|
|
90
|
+
const charInt = parseInt(binaryChunk, 2);
|
|
91
|
+
if (usePowerOfTwo) {
|
|
92
|
+
resultString += dduSet[charInt];
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
const quotient = Math.floor(charInt / dduLength);
|
|
96
|
+
const remainder = charInt % dduLength;
|
|
97
|
+
resultString += dduSet[quotient] + dduSet[remainder];
|
|
98
|
+
}
|
|
137
99
|
}
|
|
138
|
-
return
|
|
100
|
+
return padding > 0
|
|
101
|
+
? resultString + padChar.repeat(Math.floor(padding / 2))
|
|
102
|
+
: resultString;
|
|
139
103
|
}
|
|
140
104
|
decode(input, options = {}) {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
const { dduSet, dduLength, bitLength, lookupTable, paddingRegExp } = this.getSelectedSets(options.dduSetSymbol);
|
|
144
|
-
const paddingCount = (input.match(paddingRegExp) || []).length;
|
|
145
|
-
input = input.replace(paddingRegExp, "");
|
|
146
|
-
let dduBinary = "";
|
|
147
|
-
for (let i = 0; i < input.length; i += 2) {
|
|
148
|
-
const firstIndex = lookupTable.get(input[i]);
|
|
149
|
-
const secondIndex = lookupTable.get(input[i + 1]);
|
|
150
|
-
if (firstIndex === undefined || secondIndex === undefined)
|
|
151
|
-
continue;
|
|
152
|
-
const value = firstIndex * dduLength + secondIndex;
|
|
153
|
-
dduBinary += value.toString(2).padStart(bitLength, "0");
|
|
154
|
-
}
|
|
155
|
-
const decoded = this.dduBinaryToBuffer(dduBinary, paddingCount);
|
|
156
|
-
return Buffer.from(decoded).toString(options.encoding);
|
|
157
|
-
}
|
|
158
|
-
decode64(input, options = {}) {
|
|
159
|
-
options.dduSetSymbol = options.dduSetSymbol || "default";
|
|
160
|
-
options.encoding = options.encoding || this.defaultEncoding;
|
|
161
|
-
const { dduSet, bitLength, lookupTable, paddingRegExp } = this.getSelectedSets64(options.dduSetSymbol);
|
|
105
|
+
const { dduSetSymbol = "default", encoding = this.defaultEncoding, usePowerOfTwo = false, } = options;
|
|
106
|
+
const { dduSet, dduLength, bitLength, lookupTable, paddingRegExp } = this.getSelectedSets(dduSetSymbol, usePowerOfTwo);
|
|
162
107
|
const paddingCount = (input.match(paddingRegExp) || []).length;
|
|
108
|
+
const paddingBits = paddingCount * 2;
|
|
163
109
|
input = input.replace(paddingRegExp, "");
|
|
164
110
|
let dduBinary = "";
|
|
165
|
-
for (let i = 0; i < input.length; i
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
111
|
+
for (let i = 0; i < input.length; i += usePowerOfTwo ? 1 : 2) {
|
|
112
|
+
const firstChar = input[i];
|
|
113
|
+
const secondChar = input[i + 1];
|
|
114
|
+
if (usePowerOfTwo) {
|
|
115
|
+
const charIndex = lookupTable.get(firstChar);
|
|
116
|
+
if (charIndex === undefined)
|
|
117
|
+
throw new Error(`Invalid character: ${firstChar}`);
|
|
118
|
+
dduBinary += charIndex.toString(2).padStart(bitLength, "0");
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
const firstIndex = lookupTable.get(firstChar);
|
|
122
|
+
const secondIndex = lookupTable.get(secondChar);
|
|
123
|
+
if (firstIndex === undefined || secondIndex === undefined)
|
|
124
|
+
throw new Error(`Invalid character: ${firstChar} or ${secondChar}`);
|
|
125
|
+
const value = firstIndex * dduLength + secondIndex;
|
|
126
|
+
dduBinary += value.toString(2).padStart(bitLength, "0");
|
|
127
|
+
}
|
|
170
128
|
}
|
|
171
|
-
const decoded = this.dduBinaryToBuffer(dduBinary, paddingCount);
|
|
172
|
-
return
|
|
129
|
+
const decoded = this.dduBinaryToBuffer(dduBinary, usePowerOfTwo ? paddingBits : paddingCount * bitLength);
|
|
130
|
+
return decoded.toString(encoding);
|
|
173
131
|
}
|
|
174
132
|
}
|
|
175
133
|
exports.Ddu64 = Ddu64;
|
|
@@ -26,9 +26,9 @@ const koreanChars = [
|
|
|
26
26
|
]; //129
|
|
27
27
|
const ddu64 = new __1.Ddu64(["D", "d", "U", "u", "T", "t", "A", "a"], "응");
|
|
28
28
|
const answer = "안녕 나 안보고싶었어?12";
|
|
29
|
-
const encoded = ddu64.
|
|
29
|
+
const encoded = ddu64.encode(answer, { usePowerOfTwo: true });
|
|
30
30
|
console.log(encoded);
|
|
31
|
-
const decoded = ddu64.
|
|
31
|
+
const decoded = ddu64.decode(encoded, { usePowerOfTwo: true });
|
|
32
32
|
console.log(decoded);
|
|
33
33
|
console.log("=-==");
|
|
34
34
|
const encoded_eng = ddu64.encode(answer, { dduSetSymbol: "KR" });
|
|
@@ -38,7 +38,7 @@ console.log(decoded_eng);
|
|
|
38
38
|
console.log("=-==");
|
|
39
39
|
const ddu64_other = new __1.Ddu64(koreanChars, "즁");
|
|
40
40
|
const answer2 = "안녕나안보고싶었어?스스로칭찬하려니까부담되는걸?하지만기록은완성해야하니까어쩔수없지~엘리시아는상냥하고,친근하고,귀엽고,똑똑하고아름다운소녀야.그녀의초대를거절하거나그녀를냉정하게대할수있는사람은없어.전설속의엘프처럼모든이의마음을사로잡고13명의영웅을이곳에모았으면서첫번째자리를양보하는겸손함까지...영웅들에게엘리시아는가장믿음직스럽고사랑받는동료야.너희도그렇게생각하지?1";
|
|
41
|
-
const encoded2 = ddu64_other.
|
|
41
|
+
const encoded2 = ddu64_other.encode(answer2, { usePowerOfTwo: true });
|
|
42
42
|
console.log(encoded2);
|
|
43
|
-
const decoded2 = ddu64_other.
|
|
43
|
+
const decoded2 = ddu64_other.decode(encoded2, { usePowerOfTwo: true });
|
|
44
44
|
console.log(decoded2);
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const __1 = require("..");
|
|
4
|
+
function measurePerformance(yaho = -1) {
|
|
5
|
+
const encoderDecoder = new __1.Ddu64();
|
|
6
|
+
const testData = `Hello,${yaho} World! Thi${yaho}s is ${yaho}a per${yaho}formance te${yaho}st for e${yaho}ncod${yaho}ing an${yaho}d decod${yaho}ing.`;
|
|
7
|
+
// 메모리 사용량 측정
|
|
8
|
+
const initialMemoryUsage = process.memoryUsage().heapUsed;
|
|
9
|
+
// CPU 사용량 측정
|
|
10
|
+
const initialCpuUsage = process.cpuUsage();
|
|
11
|
+
// 인코딩 성능 테스트
|
|
12
|
+
const encodeStartTime = performance.now();
|
|
13
|
+
const encodedData = encoderDecoder.encode(testData);
|
|
14
|
+
const encodeEndTime = performance.now();
|
|
15
|
+
const encodeTime = encodeEndTime - encodeStartTime;
|
|
16
|
+
// 디코딩 성능 테스트
|
|
17
|
+
const decodeStartTime = performance.now();
|
|
18
|
+
const decodedData = encoderDecoder.decode(encodedData);
|
|
19
|
+
const decodeEndTime = performance.now();
|
|
20
|
+
const decodeTime = decodeEndTime - decodeStartTime;
|
|
21
|
+
// 메모리 사용량 측정
|
|
22
|
+
const finalMemoryUsage = process.memoryUsage().heapUsed;
|
|
23
|
+
const memoryUsage = finalMemoryUsage - initialMemoryUsage;
|
|
24
|
+
const finalCpuUsage = process.cpuUsage(initialCpuUsage);
|
|
25
|
+
const cpuUsage = finalCpuUsage.user + finalCpuUsage.system;
|
|
26
|
+
return { encodeTime, decodeTime, memoryUsage, cpuUsage };
|
|
27
|
+
}
|
|
28
|
+
const result1 = measurePerformance();
|
|
29
|
+
console.log(`Encode Time: ${result1.encodeTime.toFixed(2)} ms`);
|
|
30
|
+
console.log(`Decode Time: ${result1.decodeTime.toFixed(2)} ms`);
|
|
31
|
+
console.log(`Memory Usage: ${result1.memoryUsage} bytes`);
|
|
32
|
+
console.log(`CPU Usage: ${result1.cpuUsage} microseconds\n`);
|
|
33
|
+
const yaho = 10000;
|
|
34
|
+
let yaho2 = yaho;
|
|
35
|
+
console.log(`loop ${yaho}`);
|
|
36
|
+
while (--yaho2 > 0) {
|
|
37
|
+
const result2 = measurePerformance(yaho);
|
|
38
|
+
result1.encodeTime += result2.encodeTime;
|
|
39
|
+
result1.decodeTime += result2.decodeTime;
|
|
40
|
+
result1.memoryUsage += result2.memoryUsage;
|
|
41
|
+
result1.cpuUsage += result2.cpuUsage;
|
|
42
|
+
}
|
|
43
|
+
console.log(`Encode Time: ${(result1.encodeTime / yaho).toFixed(2)} ms`);
|
|
44
|
+
console.log(`Decode Time: ${(result1.decodeTime / yaho).toFixed(2)} ms`);
|
|
45
|
+
console.log(`Memory Usage: ${result1.memoryUsage / yaho} bytes`);
|
|
46
|
+
console.log(`CPU Usage: ${result1.cpuUsage / yaho} microseconds\n`);
|
package/dist/index.d.ts
CHANGED
|
@@ -10,27 +10,20 @@ export declare class Ddu64 {
|
|
|
10
10
|
private readonly dduBinaryLookupKr;
|
|
11
11
|
private readonly paddingRegex;
|
|
12
12
|
constructor(dduChar?: string[], paddingChar?: string);
|
|
13
|
-
private getLargestPowerOfTwo;
|
|
14
13
|
private getBitLength;
|
|
14
|
+
private getLargestPowerOfTwo;
|
|
15
15
|
private splitString;
|
|
16
16
|
private getSelectedSets;
|
|
17
|
-
private getSelectedSets64;
|
|
18
17
|
private bufferToDduBinary;
|
|
19
18
|
private dduBinaryToBuffer;
|
|
20
19
|
encode(input: Buffer | string, options?: {
|
|
21
20
|
dduSetSymbol?: string;
|
|
22
21
|
encoding?: BufferEncoding;
|
|
23
|
-
|
|
24
|
-
encode64(input: Buffer | string, options?: {
|
|
25
|
-
dduSetSymbol?: string;
|
|
26
|
-
encoding?: BufferEncoding;
|
|
22
|
+
usePowerOfTwo?: boolean;
|
|
27
23
|
}): string;
|
|
28
24
|
decode(input: string, options?: {
|
|
29
25
|
dduSetSymbol?: string;
|
|
30
26
|
encoding?: BufferEncoding;
|
|
31
|
-
|
|
32
|
-
decode64(input: string, options?: {
|
|
33
|
-
dduSetSymbol?: string;
|
|
34
|
-
encoding?: BufferEncoding;
|
|
27
|
+
usePowerOfTwo?: boolean;
|
|
35
28
|
}): string;
|
|
36
29
|
}
|
package/dist/mjs/index.js
CHANGED
|
@@ -13,35 +13,19 @@ export class Ddu64 {
|
|
|
13
13
|
];
|
|
14
14
|
paddingCharKr = "뭐";
|
|
15
15
|
defaultEncoding = "utf-8";
|
|
16
|
-
bitLengthMap;
|
|
17
|
-
binaryLookup;
|
|
18
|
-
dduBinaryLookup;
|
|
19
|
-
dduBinaryLookupKr;
|
|
20
|
-
paddingRegex;
|
|
16
|
+
bitLengthMap = new Map();
|
|
17
|
+
binaryLookup = Array.from({ length: 256 }, (_, i) => i.toString(2).padStart(8, "0"));
|
|
18
|
+
dduBinaryLookup = new Map();
|
|
19
|
+
dduBinaryLookupKr = new Map();
|
|
20
|
+
paddingRegex = new Map();
|
|
21
21
|
constructor(dduChar, paddingChar) {
|
|
22
22
|
this.dduChar = dduChar || this.dduCharKr;
|
|
23
23
|
this.paddingChar = paddingChar || this.paddingCharKr;
|
|
24
|
-
this.
|
|
25
|
-
this.
|
|
26
|
-
this.dduBinaryLookup = new Map();
|
|
27
|
-
this.dduBinaryLookupKr = new Map();
|
|
28
|
-
this.paddingRegex = new Map();
|
|
29
|
-
for (let i = 0; i < 256; i++) {
|
|
30
|
-
this.binaryLookup[i] = i.toString(2).padStart(8, "0");
|
|
31
|
-
}
|
|
32
|
-
this.dduChar.forEach((char, index) => {
|
|
33
|
-
this.dduBinaryLookup.set(char, index);
|
|
34
|
-
});
|
|
35
|
-
this.dduCharKr.forEach((char, index) => {
|
|
36
|
-
this.dduBinaryLookupKr.set(char, index);
|
|
37
|
-
});
|
|
24
|
+
this.dduChar.forEach((char, index) => this.dduBinaryLookup.set(char, index));
|
|
25
|
+
this.dduCharKr.forEach((char, index) => this.dduBinaryLookupKr.set(char, index));
|
|
38
26
|
this.paddingRegex.set("default", new RegExp(this.paddingChar, "g"));
|
|
39
27
|
this.paddingRegex.set("KR", new RegExp(this.paddingCharKr, "g"));
|
|
40
28
|
}
|
|
41
|
-
getLargestPowerOfTwo(n) {
|
|
42
|
-
let power = Math.floor(Math.log2(n));
|
|
43
|
-
return 2 ** power;
|
|
44
|
-
}
|
|
45
29
|
getBitLength(setLength) {
|
|
46
30
|
let cached = this.bitLengthMap.get(setLength);
|
|
47
31
|
if (cached === undefined) {
|
|
@@ -50,48 +34,34 @@ export class Ddu64 {
|
|
|
50
34
|
}
|
|
51
35
|
return cached;
|
|
52
36
|
}
|
|
37
|
+
getLargestPowerOfTwo(n) {
|
|
38
|
+
return 2 ** Math.floor(Math.log2(n));
|
|
39
|
+
}
|
|
53
40
|
*splitString(s, length) {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
yield s.slice(i, Math.min(i + length, len));
|
|
41
|
+
for (let i = 0; i < s.length; i += length) {
|
|
42
|
+
yield s.slice(i, Math.min(i + length, s.length));
|
|
57
43
|
}
|
|
58
44
|
}
|
|
59
|
-
getSelectedSets(dduSetSymbol) {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
paddingRegExp: this.paddingRegex.get("KR"),
|
|
68
|
-
};
|
|
45
|
+
getSelectedSets(dduSetSymbol, usePowerOfTwo) {
|
|
46
|
+
const isKR = dduSetSymbol === "KR";
|
|
47
|
+
const dduSet = isKR ? this.dduCharKr : this.dduChar;
|
|
48
|
+
const padChar = isKR ? this.paddingCharKr : this.paddingChar;
|
|
49
|
+
let dduLength = dduSet.length;
|
|
50
|
+
if (usePowerOfTwo) {
|
|
51
|
+
const powerOfTwoLength = this.getLargestPowerOfTwo(dduLength);
|
|
52
|
+
dduLength = powerOfTwoLength;
|
|
69
53
|
}
|
|
70
54
|
return {
|
|
71
|
-
dduSet:
|
|
72
|
-
padChar
|
|
73
|
-
dduLength
|
|
74
|
-
bitLength: this.getBitLength(
|
|
75
|
-
lookupTable: this.dduBinaryLookup,
|
|
76
|
-
paddingRegExp: this.paddingRegex.get("default"),
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
getSelectedSets64(option) {
|
|
80
|
-
const baseSet = this.getSelectedSets(option);
|
|
81
|
-
const powerOfTwoLength = this.getLargestPowerOfTwo(baseSet.dduSet.length);
|
|
82
|
-
return {
|
|
83
|
-
...baseSet,
|
|
84
|
-
dduSet: baseSet.dduSet.slice(0, powerOfTwoLength),
|
|
85
|
-
dduLength: powerOfTwoLength,
|
|
86
|
-
bitLength: Math.log2(powerOfTwoLength),
|
|
55
|
+
dduSet: usePowerOfTwo ? dduSet.slice(0, dduLength) : dduSet,
|
|
56
|
+
padChar,
|
|
57
|
+
dduLength,
|
|
58
|
+
bitLength: this.getBitLength(dduLength),
|
|
59
|
+
lookupTable: isKR ? this.dduBinaryLookupKr : this.dduBinaryLookup,
|
|
60
|
+
paddingRegExp: this.paddingRegex.get(isKR ? "KR" : "default"),
|
|
87
61
|
};
|
|
88
62
|
}
|
|
89
63
|
bufferToDduBinary(input, bitLength) {
|
|
90
|
-
const
|
|
91
|
-
let encodedBin = "";
|
|
92
|
-
for (let i = 0; i < bufferLength; i++) {
|
|
93
|
-
encodedBin += this.binaryLookup[input[i]];
|
|
94
|
-
}
|
|
64
|
+
const encodedBin = input.reduce((acc, byte) => acc + this.binaryLookup[byte], "");
|
|
95
65
|
const dduBinary = Array.from(this.splitString(encodedBin, bitLength));
|
|
96
66
|
const padding = bitLength - dduBinary[dduBinary.length - 1].length;
|
|
97
67
|
if (padding > 0) {
|
|
@@ -99,85 +69,63 @@ export class Ddu64 {
|
|
|
99
69
|
}
|
|
100
70
|
return { dduBinary, padding };
|
|
101
71
|
}
|
|
102
|
-
dduBinaryToBuffer(decodedBin,
|
|
103
|
-
const paddingBits = paddingCount * 2;
|
|
72
|
+
dduBinaryToBuffer(decodedBin, paddingBits) {
|
|
104
73
|
if (paddingBits > 0) {
|
|
105
74
|
decodedBin = decodedBin.slice(0, -paddingBits);
|
|
106
75
|
}
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
const start = i * 8;
|
|
111
|
-
buffer[i] = parseInt(decodedBin.slice(start, start + 8), 2);
|
|
76
|
+
const buffer = [];
|
|
77
|
+
for (let i = 0; i < decodedBin.length; i += 8) {
|
|
78
|
+
buffer.push(parseInt(decodedBin.slice(i, i + 8), 2));
|
|
112
79
|
}
|
|
113
|
-
return buffer;
|
|
80
|
+
return Buffer.from(buffer);
|
|
114
81
|
}
|
|
115
82
|
encode(input, options = {}) {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
const
|
|
119
|
-
const { dduSet, padChar, dduLength, bitLength } = this.getSelectedSets(options.dduSetSymbol);
|
|
120
|
-
const { dduBinary, padding } = this.bufferToDduBinary(bufferInput, bitLength);
|
|
121
|
-
let resultString = "";
|
|
122
|
-
for (const char of dduBinary) {
|
|
123
|
-
const charInt = parseInt(char, 2);
|
|
124
|
-
const quotient = Math.floor(charInt / dduLength);
|
|
125
|
-
const remainder = charInt % dduLength;
|
|
126
|
-
resultString += dduSet[quotient] + dduSet[remainder];
|
|
127
|
-
}
|
|
128
|
-
if (padding > 0) {
|
|
129
|
-
return resultString + padChar.repeat(Math.floor(padding / 2));
|
|
130
|
-
}
|
|
131
|
-
return resultString;
|
|
132
|
-
}
|
|
133
|
-
encode64(input, options = {}) {
|
|
134
|
-
options.dduSetSymbol = options.dduSetSymbol || "default";
|
|
135
|
-
options.encoding = options.encoding || this.defaultEncoding;
|
|
136
|
-
const bufferInput = typeof input === "string" ? Buffer.from(input, options.encoding) : input;
|
|
137
|
-
const { dduSet, padChar, bitLength } = this.getSelectedSets64(options.dduSetSymbol);
|
|
83
|
+
const { dduSetSymbol = "default", encoding = this.defaultEncoding, usePowerOfTwo = false, } = options;
|
|
84
|
+
const bufferInput = typeof input === "string" ? Buffer.from(input, encoding) : input;
|
|
85
|
+
const { dduSet, padChar, dduLength, bitLength } = this.getSelectedSets(dduSetSymbol, usePowerOfTwo);
|
|
138
86
|
const { dduBinary, padding } = this.bufferToDduBinary(bufferInput, bitLength);
|
|
139
87
|
let resultString = "";
|
|
140
|
-
for (const
|
|
141
|
-
const charInt = parseInt(
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
88
|
+
for (const binaryChunk of dduBinary) {
|
|
89
|
+
const charInt = parseInt(binaryChunk, 2);
|
|
90
|
+
if (usePowerOfTwo) {
|
|
91
|
+
resultString += dduSet[charInt];
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
const quotient = Math.floor(charInt / dduLength);
|
|
95
|
+
const remainder = charInt % dduLength;
|
|
96
|
+
resultString += dduSet[quotient] + dduSet[remainder];
|
|
97
|
+
}
|
|
146
98
|
}
|
|
147
|
-
return
|
|
99
|
+
return padding > 0
|
|
100
|
+
? resultString + padChar.repeat(Math.floor(padding / 2))
|
|
101
|
+
: resultString;
|
|
148
102
|
}
|
|
149
103
|
decode(input, options = {}) {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
const { dduSet, dduLength, bitLength, lookupTable, paddingRegExp } = this.getSelectedSets(options.dduSetSymbol);
|
|
153
|
-
const paddingCount = (input.match(paddingRegExp) || []).length;
|
|
154
|
-
input = input.replace(paddingRegExp, "");
|
|
155
|
-
let dduBinary = "";
|
|
156
|
-
for (let i = 0; i < input.length; i += 2) {
|
|
157
|
-
const firstIndex = lookupTable.get(input[i]);
|
|
158
|
-
const secondIndex = lookupTable.get(input[i + 1]);
|
|
159
|
-
if (firstIndex === undefined || secondIndex === undefined)
|
|
160
|
-
continue;
|
|
161
|
-
const value = firstIndex * dduLength + secondIndex;
|
|
162
|
-
dduBinary += value.toString(2).padStart(bitLength, "0");
|
|
163
|
-
}
|
|
164
|
-
const decoded = this.dduBinaryToBuffer(dduBinary, paddingCount);
|
|
165
|
-
return Buffer.from(decoded).toString(options.encoding);
|
|
166
|
-
}
|
|
167
|
-
decode64(input, options = {}) {
|
|
168
|
-
options.dduSetSymbol = options.dduSetSymbol || "default";
|
|
169
|
-
options.encoding = options.encoding || this.defaultEncoding;
|
|
170
|
-
const { dduSet, bitLength, lookupTable, paddingRegExp } = this.getSelectedSets64(options.dduSetSymbol);
|
|
104
|
+
const { dduSetSymbol = "default", encoding = this.defaultEncoding, usePowerOfTwo = false, } = options;
|
|
105
|
+
const { dduSet, dduLength, bitLength, lookupTable, paddingRegExp } = this.getSelectedSets(dduSetSymbol, usePowerOfTwo);
|
|
171
106
|
const paddingCount = (input.match(paddingRegExp) || []).length;
|
|
107
|
+
const paddingBits = paddingCount * 2;
|
|
172
108
|
input = input.replace(paddingRegExp, "");
|
|
173
109
|
let dduBinary = "";
|
|
174
|
-
for (let i = 0; i < input.length; i
|
|
175
|
-
const
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
110
|
+
for (let i = 0; i < input.length; i += usePowerOfTwo ? 1 : 2) {
|
|
111
|
+
const firstChar = input[i];
|
|
112
|
+
const secondChar = input[i + 1];
|
|
113
|
+
if (usePowerOfTwo) {
|
|
114
|
+
const charIndex = lookupTable.get(firstChar);
|
|
115
|
+
if (charIndex === undefined)
|
|
116
|
+
throw new Error(`Invalid character: ${firstChar}`);
|
|
117
|
+
dduBinary += charIndex.toString(2).padStart(bitLength, "0");
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
const firstIndex = lookupTable.get(firstChar);
|
|
121
|
+
const secondIndex = lookupTable.get(secondChar);
|
|
122
|
+
if (firstIndex === undefined || secondIndex === undefined)
|
|
123
|
+
throw new Error(`Invalid character: ${firstChar} or ${secondChar}`);
|
|
124
|
+
const value = firstIndex * dduLength + secondIndex;
|
|
125
|
+
dduBinary += value.toString(2).padStart(bitLength, "0");
|
|
126
|
+
}
|
|
179
127
|
}
|
|
180
|
-
const decoded = this.dduBinaryToBuffer(dduBinary, paddingCount);
|
|
181
|
-
return
|
|
128
|
+
const decoded = this.dduBinaryToBuffer(dduBinary, usePowerOfTwo ? paddingBits : paddingCount * bitLength);
|
|
129
|
+
return decoded.toString(encoding);
|
|
182
130
|
}
|
|
183
131
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -24,9 +24,9 @@ const koreanChars = [
|
|
|
24
24
|
]; //129
|
|
25
25
|
const ddu64 = new Ddu64(["D", "d", "U", "u", "T", "t", "A", "a"], "응");
|
|
26
26
|
const answer = "안녕 나 안보고싶었어?12";
|
|
27
|
-
const encoded = ddu64.
|
|
27
|
+
const encoded = ddu64.encode(answer, { usePowerOfTwo: true });
|
|
28
28
|
console.log(encoded);
|
|
29
|
-
const decoded = ddu64.
|
|
29
|
+
const decoded = ddu64.decode(encoded, { usePowerOfTwo: true });
|
|
30
30
|
console.log(decoded);
|
|
31
31
|
console.log("=-==");
|
|
32
32
|
const encoded_eng = ddu64.encode(answer, { dduSetSymbol: "KR" });
|
|
@@ -36,7 +36,7 @@ console.log(decoded_eng);
|
|
|
36
36
|
console.log("=-==");
|
|
37
37
|
const ddu64_other = new Ddu64(koreanChars, "즁");
|
|
38
38
|
const answer2 = "안녕나안보고싶었어?스스로칭찬하려니까부담되는걸?하지만기록은완성해야하니까어쩔수없지~엘리시아는상냥하고,친근하고,귀엽고,똑똑하고아름다운소녀야.그녀의초대를거절하거나그녀를냉정하게대할수있는사람은없어.전설속의엘프처럼모든이의마음을사로잡고13명의영웅을이곳에모았으면서첫번째자리를양보하는겸손함까지...영웅들에게엘리시아는가장믿음직스럽고사랑받는동료야.너희도그렇게생각하지?1";
|
|
39
|
-
const encoded2 = ddu64_other.
|
|
39
|
+
const encoded2 = ddu64_other.encode(answer2, { usePowerOfTwo: true });
|
|
40
40
|
console.log(encoded2);
|
|
41
|
-
const decoded2 = ddu64_other.
|
|
41
|
+
const decoded2 = ddu64_other.decode(encoded2, { usePowerOfTwo: true });
|
|
42
42
|
console.log(decoded2);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Ddu64 } from "..";
|
|
2
|
+
function measurePerformance(yaho = -1) {
|
|
3
|
+
const encoderDecoder = new Ddu64();
|
|
4
|
+
const testData = `Hello,${yaho} World! Thi${yaho}s is ${yaho}a per${yaho}formance te${yaho}st for e${yaho}ncod${yaho}ing an${yaho}d decod${yaho}ing.`;
|
|
5
|
+
// 메모리 사용량 측정
|
|
6
|
+
const initialMemoryUsage = process.memoryUsage().heapUsed;
|
|
7
|
+
// CPU 사용량 측정
|
|
8
|
+
const initialCpuUsage = process.cpuUsage();
|
|
9
|
+
// 인코딩 성능 테스트
|
|
10
|
+
const encodeStartTime = performance.now();
|
|
11
|
+
const encodedData = encoderDecoder.encode(testData);
|
|
12
|
+
const encodeEndTime = performance.now();
|
|
13
|
+
const encodeTime = encodeEndTime - encodeStartTime;
|
|
14
|
+
// 디코딩 성능 테스트
|
|
15
|
+
const decodeStartTime = performance.now();
|
|
16
|
+
const decodedData = encoderDecoder.decode(encodedData);
|
|
17
|
+
const decodeEndTime = performance.now();
|
|
18
|
+
const decodeTime = decodeEndTime - decodeStartTime;
|
|
19
|
+
// 메모리 사용량 측정
|
|
20
|
+
const finalMemoryUsage = process.memoryUsage().heapUsed;
|
|
21
|
+
const memoryUsage = finalMemoryUsage - initialMemoryUsage;
|
|
22
|
+
const finalCpuUsage = process.cpuUsage(initialCpuUsage);
|
|
23
|
+
const cpuUsage = finalCpuUsage.user + finalCpuUsage.system;
|
|
24
|
+
return { encodeTime, decodeTime, memoryUsage, cpuUsage };
|
|
25
|
+
}
|
|
26
|
+
const result1 = measurePerformance();
|
|
27
|
+
console.log(`Encode Time: ${result1.encodeTime.toFixed(2)} ms`);
|
|
28
|
+
console.log(`Decode Time: ${result1.decodeTime.toFixed(2)} ms`);
|
|
29
|
+
console.log(`Memory Usage: ${result1.memoryUsage} bytes`);
|
|
30
|
+
console.log(`CPU Usage: ${result1.cpuUsage} microseconds\n`);
|
|
31
|
+
const yaho = 10000;
|
|
32
|
+
let yaho2 = yaho;
|
|
33
|
+
console.log(`loop ${yaho}`);
|
|
34
|
+
while (--yaho2 > 0) {
|
|
35
|
+
const result2 = measurePerformance(yaho);
|
|
36
|
+
result1.encodeTime += result2.encodeTime;
|
|
37
|
+
result1.decodeTime += result2.decodeTime;
|
|
38
|
+
result1.memoryUsage += result2.memoryUsage;
|
|
39
|
+
result1.cpuUsage += result2.cpuUsage;
|
|
40
|
+
}
|
|
41
|
+
console.log(`Encode Time: ${(result1.encodeTime / yaho).toFixed(2)} ms`);
|
|
42
|
+
console.log(`Decode Time: ${(result1.decodeTime / yaho).toFixed(2)} ms`);
|
|
43
|
+
console.log(`Memory Usage: ${result1.memoryUsage / yaho} bytes`);
|
|
44
|
+
console.log(`CPU Usage: ${result1.cpuUsage / yaho} microseconds\n`);
|
package/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ddunigma/node",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.12",
|
|
4
4
|
"main": "dist/cjs/index.js",
|
|
5
5
|
"module": "dist/mjs/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"scripts": {
|
|
9
|
-
"test": "tsx ./src/test/test.ts",
|
|
10
9
|
"build": "rm -rf dist/* && tsc -p tsconfig.json && tsc -p tsconfig-cjs.json && sh postProcess.sh",
|
|
11
|
-
"
|
|
10
|
+
"test": "tsx ./src/test/test2.ts",
|
|
11
|
+
"tester": "echo tester2 && tsx ./src/test/tester2.ts && echo tester && tsx ./src/test/tester.ts"
|
|
12
12
|
},
|
|
13
13
|
"exports": {
|
|
14
14
|
".": {
|
|
File without changes
|
|
File without changes
|