@ddunigma/node 1.0.10 → 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 +84 -109
- package/dist/cjs/test/{test1.js → test2.js} +6 -6
- package/dist/cjs/test/tester2.js +46 -0
- package/dist/index.d.ts +11 -6
- package/dist/mjs/index.js +86 -121
- package/dist/mjs/test/test2.d.ts +1 -0
- package/dist/mjs/test/{test1.js → test2.js} +6 -6
- 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
|
@@ -3,31 +3,29 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.Ddu64 = void 0;
|
|
4
4
|
class Ddu64 {
|
|
5
5
|
constructor(dduChar, paddingChar) {
|
|
6
|
-
this.dduCharKr = [
|
|
6
|
+
this.dduCharKr = [
|
|
7
|
+
"뜌",
|
|
8
|
+
"땨",
|
|
9
|
+
"이",
|
|
10
|
+
"우",
|
|
11
|
+
"야",
|
|
12
|
+
"!",
|
|
13
|
+
"?",
|
|
14
|
+
".",
|
|
15
|
+
];
|
|
7
16
|
this.paddingCharKr = "뭐";
|
|
8
17
|
this.defaultEncoding = "utf-8";
|
|
9
|
-
this.dduChar = dduChar || this.dduCharKr;
|
|
10
|
-
this.paddingChar = paddingChar || this.paddingCharKr;
|
|
11
18
|
this.bitLengthMap = new Map();
|
|
12
|
-
this.binaryLookup =
|
|
19
|
+
this.binaryLookup = Array.from({ length: 256 }, (_, i) => i.toString(2).padStart(8, "0"));
|
|
13
20
|
this.dduBinaryLookup = new Map();
|
|
14
21
|
this.dduBinaryLookupKr = new Map();
|
|
15
22
|
this.paddingRegex = new Map();
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
this.
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
this.dduCharKr.forEach((char, index) => {
|
|
23
|
-
this.dduBinaryLookupKr.set(char, index);
|
|
24
|
-
});
|
|
25
|
-
this.paddingRegex.set('default', new RegExp(this.paddingChar, "g"));
|
|
26
|
-
this.paddingRegex.set('KR', new RegExp(this.paddingCharKr, "g"));
|
|
27
|
-
}
|
|
28
|
-
getLargestPowerOfTwo(n) {
|
|
29
|
-
let power = Math.floor(Math.log2(n));
|
|
30
|
-
return Math.pow(2, power);
|
|
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));
|
|
27
|
+
this.paddingRegex.set("default", new RegExp(this.paddingChar, "g"));
|
|
28
|
+
this.paddingRegex.set("KR", new RegExp(this.paddingCharKr, "g"));
|
|
31
29
|
}
|
|
32
30
|
getBitLength(setLength) {
|
|
33
31
|
let cached = this.bitLengthMap.get(setLength);
|
|
@@ -37,122 +35,99 @@ class Ddu64 {
|
|
|
37
35
|
}
|
|
38
36
|
return cached;
|
|
39
37
|
}
|
|
38
|
+
getLargestPowerOfTwo(n) {
|
|
39
|
+
return Math.pow(2, Math.floor(Math.log2(n)));
|
|
40
|
+
}
|
|
40
41
|
*splitString(s, length) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
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));
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
|
-
getSelectedSets(
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
paddingRegExp: this.paddingRegex.get('KR')
|
|
55
|
-
};
|
|
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;
|
|
56
54
|
}
|
|
57
55
|
return {
|
|
58
|
-
dduSet:
|
|
59
|
-
padChar
|
|
60
|
-
dduLength
|
|
61
|
-
bitLength: this.getBitLength(
|
|
62
|
-
lookupTable: this.dduBinaryLookup,
|
|
63
|
-
paddingRegExp: this.paddingRegex.get(
|
|
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"),
|
|
64
62
|
};
|
|
65
63
|
}
|
|
66
|
-
getSelectedSets64(option) {
|
|
67
|
-
const baseSet = this.getSelectedSets(option);
|
|
68
|
-
const powerOfTwoLength = this.getLargestPowerOfTwo(baseSet.dduSet.length);
|
|
69
|
-
return Object.assign(Object.assign({}, baseSet), { dduSet: baseSet.dduSet.slice(0, powerOfTwoLength), dduLength: powerOfTwoLength, bitLength: Math.log2(powerOfTwoLength) });
|
|
70
|
-
}
|
|
71
64
|
bufferToDduBinary(input, bitLength) {
|
|
72
|
-
const
|
|
73
|
-
let encodedBin = '';
|
|
74
|
-
for (let i = 0; i < bufferLength; i++) {
|
|
75
|
-
encodedBin += this.binaryLookup[input[i]];
|
|
76
|
-
}
|
|
65
|
+
const encodedBin = input.reduce((acc, byte) => acc + this.binaryLookup[byte], "");
|
|
77
66
|
const dduBinary = Array.from(this.splitString(encodedBin, bitLength));
|
|
78
67
|
const padding = bitLength - dduBinary[dduBinary.length - 1].length;
|
|
79
68
|
if (padding > 0) {
|
|
80
|
-
dduBinary[dduBinary.length - 1] +=
|
|
69
|
+
dduBinary[dduBinary.length - 1] += "0".repeat(padding);
|
|
81
70
|
}
|
|
82
71
|
return { dduBinary, padding };
|
|
83
72
|
}
|
|
84
|
-
dduBinaryToBuffer(decodedBin,
|
|
85
|
-
const paddingBits = paddingCount * 2;
|
|
73
|
+
dduBinaryToBuffer(decodedBin, paddingBits) {
|
|
86
74
|
if (paddingBits > 0) {
|
|
87
75
|
decodedBin = decodedBin.slice(0, -paddingBits);
|
|
88
76
|
}
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
const start = i * 8;
|
|
93
|
-
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));
|
|
94
80
|
}
|
|
95
|
-
return buffer;
|
|
81
|
+
return Buffer.from(buffer);
|
|
96
82
|
}
|
|
97
|
-
encode(input,
|
|
98
|
-
const
|
|
99
|
-
const
|
|
83
|
+
encode(input, options = {}) {
|
|
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);
|
|
100
87
|
const { dduBinary, padding } = this.bufferToDduBinary(bufferInput, bitLength);
|
|
101
88
|
let resultString = "";
|
|
102
|
-
for (const
|
|
103
|
-
const charInt = parseInt(
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
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
|
+
}
|
|
107
99
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
return resultString;
|
|
112
|
-
}
|
|
113
|
-
encode64(input, option = "default", encoding = this.defaultEncoding) {
|
|
114
|
-
const bufferInput = typeof input === 'string' ? Buffer.from(input, encoding) : input;
|
|
115
|
-
const { dduSet, padChar, bitLength } = this.getSelectedSets64(option);
|
|
116
|
-
const { dduBinary, padding } = this.bufferToDduBinary(bufferInput, bitLength);
|
|
117
|
-
let resultString = "";
|
|
118
|
-
for (const char of dduBinary) {
|
|
119
|
-
const charInt = parseInt(char, 2);
|
|
120
|
-
resultString += dduSet[charInt];
|
|
121
|
-
}
|
|
122
|
-
if (padding > 0) {
|
|
123
|
-
return resultString + padChar.repeat(Math.floor(padding / 2));
|
|
124
|
-
}
|
|
125
|
-
return resultString;
|
|
100
|
+
return padding > 0
|
|
101
|
+
? resultString + padChar.repeat(Math.floor(padding / 2))
|
|
102
|
+
: resultString;
|
|
126
103
|
}
|
|
127
|
-
decode(input,
|
|
128
|
-
const {
|
|
104
|
+
decode(input, options = {}) {
|
|
105
|
+
const { dduSetSymbol = "default", encoding = this.defaultEncoding, usePowerOfTwo = false, } = options;
|
|
106
|
+
const { dduSet, dduLength, bitLength, lookupTable, paddingRegExp } = this.getSelectedSets(dduSetSymbol, usePowerOfTwo);
|
|
129
107
|
const paddingCount = (input.match(paddingRegExp) || []).length;
|
|
130
|
-
|
|
108
|
+
const paddingBits = paddingCount * 2;
|
|
109
|
+
input = input.replace(paddingRegExp, "");
|
|
131
110
|
let dduBinary = "";
|
|
132
|
-
for (let i = 0; i < input.length; i += 2) {
|
|
133
|
-
const
|
|
134
|
-
const
|
|
135
|
-
if (
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
const charIndex = lookupTable.get(input[i]);
|
|
150
|
-
if (charIndex === undefined)
|
|
151
|
-
continue;
|
|
152
|
-
dduBinary += charIndex.toString(2).padStart(bitLength, '0');
|
|
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
|
+
}
|
|
153
128
|
}
|
|
154
|
-
const decoded = this.dduBinaryToBuffer(dduBinary, paddingCount);
|
|
155
|
-
return
|
|
129
|
+
const decoded = this.dduBinaryToBuffer(dduBinary, usePowerOfTwo ? paddingBits : paddingCount * bitLength);
|
|
130
|
+
return decoded.toString(encoding);
|
|
156
131
|
}
|
|
157
132
|
}
|
|
158
133
|
exports.Ddu64 = Ddu64;
|
|
@@ -26,19 +26,19 @@ 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
|
-
const encoded_eng = ddu64.encode(answer, "KR");
|
|
34
|
+
const encoded_eng = ddu64.encode(answer, { dduSetSymbol: "KR" });
|
|
35
35
|
console.log(encoded_eng);
|
|
36
|
-
const decoded_eng = ddu64.decode(encoded_eng, "KR");
|
|
36
|
+
const decoded_eng = ddu64.decode(encoded_eng, { dduSetSymbol: "KR" });
|
|
37
37
|
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,15 +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
|
-
encode(input: Buffer | string,
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
encode(input: Buffer | string, options?: {
|
|
20
|
+
dduSetSymbol?: string;
|
|
21
|
+
encoding?: BufferEncoding;
|
|
22
|
+
usePowerOfTwo?: boolean;
|
|
23
|
+
}): string;
|
|
24
|
+
decode(input: string, options?: {
|
|
25
|
+
dduSetSymbol?: string;
|
|
26
|
+
encoding?: BufferEncoding;
|
|
27
|
+
usePowerOfTwo?: boolean;
|
|
28
|
+
}): string;
|
|
24
29
|
}
|
package/dist/mjs/index.js
CHANGED
|
@@ -1,37 +1,30 @@
|
|
|
1
1
|
export class Ddu64 {
|
|
2
2
|
dduChar;
|
|
3
3
|
paddingChar;
|
|
4
|
-
dduCharKr = [
|
|
4
|
+
dduCharKr = [
|
|
5
|
+
"뜌",
|
|
6
|
+
"땨",
|
|
7
|
+
"이",
|
|
8
|
+
"우",
|
|
9
|
+
"야",
|
|
10
|
+
"!",
|
|
11
|
+
"?",
|
|
12
|
+
".",
|
|
13
|
+
];
|
|
5
14
|
paddingCharKr = "뭐";
|
|
6
15
|
defaultEncoding = "utf-8";
|
|
7
|
-
bitLengthMap;
|
|
8
|
-
binaryLookup;
|
|
9
|
-
dduBinaryLookup;
|
|
10
|
-
dduBinaryLookupKr;
|
|
11
|
-
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();
|
|
12
21
|
constructor(dduChar, paddingChar) {
|
|
13
22
|
this.dduChar = dduChar || this.dduCharKr;
|
|
14
23
|
this.paddingChar = paddingChar || this.paddingCharKr;
|
|
15
|
-
this.
|
|
16
|
-
this.
|
|
17
|
-
this.
|
|
18
|
-
this.
|
|
19
|
-
this.paddingRegex = new Map();
|
|
20
|
-
for (let i = 0; i < 256; i++) {
|
|
21
|
-
this.binaryLookup[i] = i.toString(2).padStart(8, '0');
|
|
22
|
-
}
|
|
23
|
-
this.dduChar.forEach((char, index) => {
|
|
24
|
-
this.dduBinaryLookup.set(char, index);
|
|
25
|
-
});
|
|
26
|
-
this.dduCharKr.forEach((char, index) => {
|
|
27
|
-
this.dduBinaryLookupKr.set(char, index);
|
|
28
|
-
});
|
|
29
|
-
this.paddingRegex.set('default', new RegExp(this.paddingChar, "g"));
|
|
30
|
-
this.paddingRegex.set('KR', new RegExp(this.paddingCharKr, "g"));
|
|
31
|
-
}
|
|
32
|
-
getLargestPowerOfTwo(n) {
|
|
33
|
-
let power = Math.floor(Math.log2(n));
|
|
34
|
-
return 2 ** power;
|
|
24
|
+
this.dduChar.forEach((char, index) => this.dduBinaryLookup.set(char, index));
|
|
25
|
+
this.dduCharKr.forEach((char, index) => this.dduBinaryLookupKr.set(char, index));
|
|
26
|
+
this.paddingRegex.set("default", new RegExp(this.paddingChar, "g"));
|
|
27
|
+
this.paddingRegex.set("KR", new RegExp(this.paddingCharKr, "g"));
|
|
35
28
|
}
|
|
36
29
|
getBitLength(setLength) {
|
|
37
30
|
let cached = this.bitLengthMap.get(setLength);
|
|
@@ -41,126 +34,98 @@ export class Ddu64 {
|
|
|
41
34
|
}
|
|
42
35
|
return cached;
|
|
43
36
|
}
|
|
37
|
+
getLargestPowerOfTwo(n) {
|
|
38
|
+
return 2 ** Math.floor(Math.log2(n));
|
|
39
|
+
}
|
|
44
40
|
*splitString(s, length) {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
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));
|
|
48
43
|
}
|
|
49
44
|
}
|
|
50
|
-
getSelectedSets(
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
paddingRegExp: this.paddingRegex.get('KR')
|
|
59
|
-
};
|
|
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;
|
|
60
53
|
}
|
|
61
54
|
return {
|
|
62
|
-
dduSet:
|
|
63
|
-
padChar
|
|
64
|
-
dduLength
|
|
65
|
-
bitLength: this.getBitLength(
|
|
66
|
-
lookupTable: this.dduBinaryLookup,
|
|
67
|
-
paddingRegExp: this.paddingRegex.get(
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
getSelectedSets64(option) {
|
|
71
|
-
const baseSet = this.getSelectedSets(option);
|
|
72
|
-
const powerOfTwoLength = this.getLargestPowerOfTwo(baseSet.dduSet.length);
|
|
73
|
-
return {
|
|
74
|
-
...baseSet,
|
|
75
|
-
dduSet: baseSet.dduSet.slice(0, powerOfTwoLength),
|
|
76
|
-
dduLength: powerOfTwoLength,
|
|
77
|
-
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"),
|
|
78
61
|
};
|
|
79
62
|
}
|
|
80
63
|
bufferToDduBinary(input, bitLength) {
|
|
81
|
-
const
|
|
82
|
-
let encodedBin = '';
|
|
83
|
-
for (let i = 0; i < bufferLength; i++) {
|
|
84
|
-
encodedBin += this.binaryLookup[input[i]];
|
|
85
|
-
}
|
|
64
|
+
const encodedBin = input.reduce((acc, byte) => acc + this.binaryLookup[byte], "");
|
|
86
65
|
const dduBinary = Array.from(this.splitString(encodedBin, bitLength));
|
|
87
66
|
const padding = bitLength - dduBinary[dduBinary.length - 1].length;
|
|
88
67
|
if (padding > 0) {
|
|
89
|
-
dduBinary[dduBinary.length - 1] +=
|
|
68
|
+
dduBinary[dduBinary.length - 1] += "0".repeat(padding);
|
|
90
69
|
}
|
|
91
70
|
return { dduBinary, padding };
|
|
92
71
|
}
|
|
93
|
-
dduBinaryToBuffer(decodedBin,
|
|
94
|
-
const paddingBits = paddingCount * 2;
|
|
72
|
+
dduBinaryToBuffer(decodedBin, paddingBits) {
|
|
95
73
|
if (paddingBits > 0) {
|
|
96
74
|
decodedBin = decodedBin.slice(0, -paddingBits);
|
|
97
75
|
}
|
|
98
|
-
const
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
const start = i * 8;
|
|
102
|
-
buffer[i] = parseInt(decodedBin.slice(start, start + 8), 2);
|
|
103
|
-
}
|
|
104
|
-
return buffer;
|
|
105
|
-
}
|
|
106
|
-
encode(input, option = "default", encoding = this.defaultEncoding) {
|
|
107
|
-
const bufferInput = typeof input === 'string' ? Buffer.from(input, encoding) : input;
|
|
108
|
-
const { dduSet, padChar, dduLength, bitLength } = this.getSelectedSets(option);
|
|
109
|
-
const { dduBinary, padding } = this.bufferToDduBinary(bufferInput, bitLength);
|
|
110
|
-
let resultString = "";
|
|
111
|
-
for (const char of dduBinary) {
|
|
112
|
-
const charInt = parseInt(char, 2);
|
|
113
|
-
const quotient = Math.floor(charInt / dduLength);
|
|
114
|
-
const remainder = charInt % dduLength;
|
|
115
|
-
resultString += dduSet[quotient] + dduSet[remainder];
|
|
76
|
+
const buffer = [];
|
|
77
|
+
for (let i = 0; i < decodedBin.length; i += 8) {
|
|
78
|
+
buffer.push(parseInt(decodedBin.slice(i, i + 8), 2));
|
|
116
79
|
}
|
|
117
|
-
|
|
118
|
-
return resultString + padChar.repeat(Math.floor(padding / 2));
|
|
119
|
-
}
|
|
120
|
-
return resultString;
|
|
80
|
+
return Buffer.from(buffer);
|
|
121
81
|
}
|
|
122
|
-
|
|
123
|
-
const
|
|
124
|
-
const
|
|
82
|
+
encode(input, options = {}) {
|
|
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);
|
|
125
86
|
const { dduBinary, padding } = this.bufferToDduBinary(bufferInput, bitLength);
|
|
126
87
|
let resultString = "";
|
|
127
|
-
for (const
|
|
128
|
-
const charInt = parseInt(
|
|
129
|
-
|
|
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
|
+
}
|
|
130
98
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
return resultString;
|
|
99
|
+
return padding > 0
|
|
100
|
+
? resultString + padChar.repeat(Math.floor(padding / 2))
|
|
101
|
+
: resultString;
|
|
135
102
|
}
|
|
136
|
-
decode(input,
|
|
137
|
-
const {
|
|
103
|
+
decode(input, options = {}) {
|
|
104
|
+
const { dduSetSymbol = "default", encoding = this.defaultEncoding, usePowerOfTwo = false, } = options;
|
|
105
|
+
const { dduSet, dduLength, bitLength, lookupTable, paddingRegExp } = this.getSelectedSets(dduSetSymbol, usePowerOfTwo);
|
|
138
106
|
const paddingCount = (input.match(paddingRegExp) || []).length;
|
|
139
|
-
|
|
107
|
+
const paddingBits = paddingCount * 2;
|
|
108
|
+
input = input.replace(paddingRegExp, "");
|
|
140
109
|
let dduBinary = "";
|
|
141
|
-
for (let i = 0; i < input.length; i += 2) {
|
|
142
|
-
const
|
|
143
|
-
const
|
|
144
|
-
if (
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
const charIndex = lookupTable.get(input[i]);
|
|
159
|
-
if (charIndex === undefined)
|
|
160
|
-
continue;
|
|
161
|
-
dduBinary += charIndex.toString(2).padStart(bitLength, '0');
|
|
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
|
+
}
|
|
162
127
|
}
|
|
163
|
-
const decoded = this.dduBinaryToBuffer(dduBinary, paddingCount);
|
|
164
|
-
return
|
|
128
|
+
const decoded = this.dduBinaryToBuffer(dduBinary, usePowerOfTwo ? paddingBits : paddingCount * bitLength);
|
|
129
|
+
return decoded.toString(encoding);
|
|
165
130
|
}
|
|
166
131
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -24,19 +24,19 @@ 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
|
-
const encoded_eng = ddu64.encode(answer, "KR");
|
|
32
|
+
const encoded_eng = ddu64.encode(answer, { dduSetSymbol: "KR" });
|
|
33
33
|
console.log(encoded_eng);
|
|
34
|
-
const decoded_eng = ddu64.decode(encoded_eng, "KR");
|
|
34
|
+
const decoded_eng = ddu64.decode(encoded_eng, { dduSetSymbol: "KR" });
|
|
35
35
|
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
|