deukpack 1.0.0 → 1.0.1
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/binding.gyp +41 -0
- package/dist/csharp/DeukPack.Protocol.dll +0 -0
- package/dist/csharp/DeukPack.Protocol.pdb +0 -0
- package/native/cpp/include/binary_reader.h +48 -0
- package/native/cpp/include/binary_writer.h +53 -0
- package/native/cpp/include/compact_reader.h +35 -0
- package/native/cpp/include/compact_writer.h +43 -0
- package/native/cpp/include/thrift_engine.h +187 -0
- package/native/cpp/src/binary_reader.cpp +177 -0
- package/native/cpp/src/binary_writer.cpp +211 -0
- package/native/cpp/src/compact_reader.cpp +69 -0
- package/native/cpp/src/compact_writer.cpp +113 -0
- package/native/cpp/src/thrift_engine.cpp +380 -0
- package/package.json +4 -2
package/binding.gyp
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"targets": [
|
|
3
|
+
{
|
|
4
|
+
"target_name": "thrift_fast_engine",
|
|
5
|
+
"sources": [
|
|
6
|
+
"native/cpp/src/thrift_engine.cpp",
|
|
7
|
+
"native/cpp/src/binary_writer.cpp",
|
|
8
|
+
"native/cpp/src/binary_reader.cpp",
|
|
9
|
+
"native/cpp/src/compact_writer.cpp",
|
|
10
|
+
"native/cpp/src/compact_reader.cpp"
|
|
11
|
+
],
|
|
12
|
+
"include_dirs": [
|
|
13
|
+
"<!@(node -p \"require('node-addon-api').include\")",
|
|
14
|
+
"native/cpp/include"
|
|
15
|
+
],
|
|
16
|
+
"defines": [
|
|
17
|
+
"NAPI_DISABLE_CPP_EXCEPTIONS"
|
|
18
|
+
],
|
|
19
|
+
"cflags!": ["-fno-exceptions"],
|
|
20
|
+
"cflags_cc!": ["-fno-exceptions"],
|
|
21
|
+
"xcode_settings": {
|
|
22
|
+
"GCC_ENABLE_CPP_EXCEPTIONS": "YES",
|
|
23
|
+
"CLANG_CXX_LIBRARY": "libc++",
|
|
24
|
+
"MACOSX_DEPLOYMENT_TARGET": "10.7"
|
|
25
|
+
},
|
|
26
|
+
"msvs_settings": {
|
|
27
|
+
"VCCLCompilerTool": {
|
|
28
|
+
"ExceptionHandling": 1
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"conditions": [
|
|
32
|
+
["OS=='win'", {
|
|
33
|
+
"defines": [
|
|
34
|
+
"WIN32_LEAN_AND_MEAN",
|
|
35
|
+
"NOMINMAX"
|
|
36
|
+
]
|
|
37
|
+
}]
|
|
38
|
+
]
|
|
39
|
+
}
|
|
40
|
+
]
|
|
41
|
+
}
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DeukPack Binary Reader Header
|
|
3
|
+
* High-performance binary deserialization
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
#ifndef BINARY_READER_H
|
|
7
|
+
#define BINARY_READER_H
|
|
8
|
+
|
|
9
|
+
#include <vector>
|
|
10
|
+
#include <cstdint>
|
|
11
|
+
#include <string>
|
|
12
|
+
#include "thrift_engine.h"
|
|
13
|
+
|
|
14
|
+
namespace deukpack
|
|
15
|
+
{
|
|
16
|
+
|
|
17
|
+
class BinaryReader
|
|
18
|
+
{
|
|
19
|
+
public:
|
|
20
|
+
explicit BinaryReader(const uint8_t *data, size_t size, Endianness endianness = Endianness::LITTLE_ENDIAN);
|
|
21
|
+
~BinaryReader() = default;
|
|
22
|
+
|
|
23
|
+
// Basic types
|
|
24
|
+
uint8_t ReadByte();
|
|
25
|
+
int16_t ReadI16();
|
|
26
|
+
int32_t ReadI32();
|
|
27
|
+
int64_t ReadI64();
|
|
28
|
+
double ReadDouble();
|
|
29
|
+
|
|
30
|
+
// String and binary
|
|
31
|
+
std::string ReadString();
|
|
32
|
+
std::vector<uint8_t> ReadBinary();
|
|
33
|
+
|
|
34
|
+
// Buffer management
|
|
35
|
+
bool IsAtEnd() const;
|
|
36
|
+
size_t GetPosition() const;
|
|
37
|
+
void SetPosition(size_t position);
|
|
38
|
+
|
|
39
|
+
private:
|
|
40
|
+
const uint8_t *data_;
|
|
41
|
+
size_t size_;
|
|
42
|
+
size_t position_;
|
|
43
|
+
Endianness endianness_;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
} // namespace deukpack
|
|
47
|
+
|
|
48
|
+
#endif // BINARY_READER_H
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DeukPack Binary Writer Header
|
|
3
|
+
* High-performance binary serialization
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
#ifndef BINARY_WRITER_H
|
|
7
|
+
#define BINARY_WRITER_H
|
|
8
|
+
|
|
9
|
+
#include <vector>
|
|
10
|
+
#include <cstdint>
|
|
11
|
+
#include <string>
|
|
12
|
+
#include "thrift_engine.h"
|
|
13
|
+
|
|
14
|
+
namespace deukpack
|
|
15
|
+
{
|
|
16
|
+
|
|
17
|
+
class BinaryWriter
|
|
18
|
+
{
|
|
19
|
+
public:
|
|
20
|
+
explicit BinaryWriter(Endianness endianness = Endianness::LITTLE_ENDIAN, size_t initialSize = 1024);
|
|
21
|
+
~BinaryWriter() = default;
|
|
22
|
+
|
|
23
|
+
// Basic types
|
|
24
|
+
void WriteByte(uint8_t value);
|
|
25
|
+
void WriteI16(int16_t value);
|
|
26
|
+
void WriteI32(int32_t value);
|
|
27
|
+
void WriteI64(int64_t value);
|
|
28
|
+
void WriteDouble(double value);
|
|
29
|
+
|
|
30
|
+
// String and binary
|
|
31
|
+
void WriteString(const std::string &value);
|
|
32
|
+
void WriteBytes(const uint8_t *data, size_t length);
|
|
33
|
+
void WriteBinary(const std::vector<uint8_t> &data);
|
|
34
|
+
|
|
35
|
+
// Buffer management
|
|
36
|
+
std::vector<uint8_t> GetBuffer();
|
|
37
|
+
size_t GetPosition() const;
|
|
38
|
+
void Reset();
|
|
39
|
+
|
|
40
|
+
private:
|
|
41
|
+
void EnsureCapacity(size_t needed);
|
|
42
|
+
void FlushCurrentBuffer();
|
|
43
|
+
void AllocateNewBuffer(size_t size);
|
|
44
|
+
|
|
45
|
+
Endianness endianness_;
|
|
46
|
+
std::vector<uint8_t> currentBuffer_;
|
|
47
|
+
std::vector<std::vector<uint8_t>> buffers_;
|
|
48
|
+
size_t position_;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
} // namespace deukpack
|
|
52
|
+
|
|
53
|
+
#endif // BINARY_WRITER_H
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DeukPack Compact Reader Header
|
|
3
|
+
* High-performance compact protocol deserialization
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
#ifndef COMPACT_READER_H
|
|
7
|
+
#define COMPACT_READER_H
|
|
8
|
+
|
|
9
|
+
#include <cstdint>
|
|
10
|
+
#include <string>
|
|
11
|
+
|
|
12
|
+
namespace deukpack
|
|
13
|
+
{
|
|
14
|
+
|
|
15
|
+
class CompactReader
|
|
16
|
+
{
|
|
17
|
+
public:
|
|
18
|
+
explicit CompactReader(const uint8_t *data, size_t size);
|
|
19
|
+
~CompactReader() = default;
|
|
20
|
+
|
|
21
|
+
uint8_t ReadByte();
|
|
22
|
+
int32_t ReadVarInt();
|
|
23
|
+
std::string ReadString();
|
|
24
|
+
|
|
25
|
+
bool IsAtEnd() const;
|
|
26
|
+
|
|
27
|
+
private:
|
|
28
|
+
const uint8_t *data_;
|
|
29
|
+
size_t size_;
|
|
30
|
+
size_t position_;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
} // namespace deukpack
|
|
34
|
+
|
|
35
|
+
#endif // COMPACT_READER_H
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DeukPack Compact Writer Header
|
|
3
|
+
* High-performance compact protocol serialization
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
#ifndef COMPACT_WRITER_H
|
|
7
|
+
#define COMPACT_WRITER_H
|
|
8
|
+
|
|
9
|
+
#include <vector>
|
|
10
|
+
#include <cstdint>
|
|
11
|
+
#include <string>
|
|
12
|
+
#include <cstring>
|
|
13
|
+
|
|
14
|
+
namespace deukpack
|
|
15
|
+
{
|
|
16
|
+
|
|
17
|
+
class CompactWriter
|
|
18
|
+
{
|
|
19
|
+
public:
|
|
20
|
+
explicit CompactWriter(size_t initialSize = 1024);
|
|
21
|
+
~CompactWriter() = default;
|
|
22
|
+
|
|
23
|
+
void WriteByte(uint8_t value);
|
|
24
|
+
void WriteVarInt(int32_t value);
|
|
25
|
+
void WriteString(const std::string &value);
|
|
26
|
+
void WriteBytes(const uint8_t *data, size_t length);
|
|
27
|
+
|
|
28
|
+
std::vector<uint8_t> GetBuffer();
|
|
29
|
+
void Reset();
|
|
30
|
+
|
|
31
|
+
private:
|
|
32
|
+
void EnsureCapacity(size_t needed);
|
|
33
|
+
void FlushCurrentBuffer();
|
|
34
|
+
void AllocateNewBuffer(size_t size);
|
|
35
|
+
|
|
36
|
+
std::vector<uint8_t> currentBuffer_;
|
|
37
|
+
std::vector<std::vector<uint8_t>> buffers_;
|
|
38
|
+
size_t position_;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
} // namespace deukpack
|
|
42
|
+
|
|
43
|
+
#endif // COMPACT_WRITER_H
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DeukPack Native C++ Header
|
|
3
|
+
* High-performance Thrift engine implementation
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
#ifndef THRIFT_ENGINE_H
|
|
7
|
+
#define THRIFT_ENGINE_H
|
|
8
|
+
|
|
9
|
+
#include <string>
|
|
10
|
+
#include <vector>
|
|
11
|
+
#include <unordered_map>
|
|
12
|
+
#include <memory>
|
|
13
|
+
#include <chrono>
|
|
14
|
+
|
|
15
|
+
namespace deukpack
|
|
16
|
+
{
|
|
17
|
+
|
|
18
|
+
// Forward declarations
|
|
19
|
+
struct ThriftAST;
|
|
20
|
+
struct ThriftStruct;
|
|
21
|
+
struct ThriftEnum;
|
|
22
|
+
struct ThriftService;
|
|
23
|
+
struct ThriftField;
|
|
24
|
+
struct ThriftNamespace;
|
|
25
|
+
struct SerializationOptions;
|
|
26
|
+
|
|
27
|
+
// Thrift types
|
|
28
|
+
enum class ThriftType
|
|
29
|
+
{
|
|
30
|
+
BOOL,
|
|
31
|
+
BYTE,
|
|
32
|
+
I16,
|
|
33
|
+
I32,
|
|
34
|
+
I64,
|
|
35
|
+
DOUBLE,
|
|
36
|
+
STRING,
|
|
37
|
+
BINARY,
|
|
38
|
+
LIST,
|
|
39
|
+
SET,
|
|
40
|
+
MAP,
|
|
41
|
+
STRUCT,
|
|
42
|
+
ENUM
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
enum class Endianness
|
|
46
|
+
{
|
|
47
|
+
LITTLE_ENDIAN,
|
|
48
|
+
BIG_ENDIAN
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
enum class ThriftProtocol
|
|
52
|
+
{
|
|
53
|
+
BINARY,
|
|
54
|
+
COMPACT,
|
|
55
|
+
JSON
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// Thrift field definition
|
|
59
|
+
struct ThriftField
|
|
60
|
+
{
|
|
61
|
+
int32_t id;
|
|
62
|
+
std::string name;
|
|
63
|
+
ThriftType type;
|
|
64
|
+
bool required;
|
|
65
|
+
std::string defaultValue;
|
|
66
|
+
ThriftType elementType;
|
|
67
|
+
ThriftType keyType;
|
|
68
|
+
ThriftType valueType;
|
|
69
|
+
std::string structType;
|
|
70
|
+
std::unordered_map<std::string, int32_t> enumValues;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
// Thrift struct definition
|
|
74
|
+
struct ThriftStruct
|
|
75
|
+
{
|
|
76
|
+
std::string name;
|
|
77
|
+
std::vector<ThriftField> fields;
|
|
78
|
+
std::unordered_map<std::string, std::string> annotations;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
// Thrift enum definition
|
|
82
|
+
struct ThriftEnum
|
|
83
|
+
{
|
|
84
|
+
std::string name;
|
|
85
|
+
std::unordered_map<std::string, int32_t> values;
|
|
86
|
+
std::unordered_map<std::string, std::string> annotations;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
// Thrift method definition
|
|
90
|
+
struct ThriftMethod
|
|
91
|
+
{
|
|
92
|
+
std::string name;
|
|
93
|
+
ThriftType returnType;
|
|
94
|
+
std::vector<ThriftField> parameters;
|
|
95
|
+
bool oneway;
|
|
96
|
+
std::unordered_map<std::string, std::string> annotations;
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
// Thrift service definition
|
|
100
|
+
struct ThriftService
|
|
101
|
+
{
|
|
102
|
+
std::string name;
|
|
103
|
+
std::vector<ThriftMethod> methods;
|
|
104
|
+
std::unordered_map<std::string, std::string> annotations;
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
// Thrift namespace definition
|
|
108
|
+
struct ThriftNamespace
|
|
109
|
+
{
|
|
110
|
+
std::string language;
|
|
111
|
+
std::string name;
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
// Thrift AST
|
|
115
|
+
struct ThriftAST
|
|
116
|
+
{
|
|
117
|
+
std::vector<ThriftNamespace> namespaces;
|
|
118
|
+
std::vector<ThriftStruct> structs;
|
|
119
|
+
std::vector<ThriftEnum> enums;
|
|
120
|
+
std::vector<ThriftService> services;
|
|
121
|
+
std::vector<std::string> includes;
|
|
122
|
+
std::unordered_map<std::string, std::string> annotations;
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
// Serialization options
|
|
126
|
+
struct SerializationOptions
|
|
127
|
+
{
|
|
128
|
+
ThriftProtocol protocol;
|
|
129
|
+
Endianness endianness;
|
|
130
|
+
bool optimizeForSize;
|
|
131
|
+
bool includeDefaultValues;
|
|
132
|
+
bool validateTypes;
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
// Performance metrics
|
|
136
|
+
struct PerformanceMetrics
|
|
137
|
+
{
|
|
138
|
+
double parseTime;
|
|
139
|
+
double generateTime;
|
|
140
|
+
double serializeTime;
|
|
141
|
+
double deserializeTime;
|
|
142
|
+
size_t memoryUsage;
|
|
143
|
+
int32_t fileCount;
|
|
144
|
+
int32_t lineCount;
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
// Main Thrift Engine class
|
|
148
|
+
class ThriftEngine
|
|
149
|
+
{
|
|
150
|
+
public:
|
|
151
|
+
ThriftEngine();
|
|
152
|
+
~ThriftEngine();
|
|
153
|
+
|
|
154
|
+
// Parse Thrift files
|
|
155
|
+
ThriftAST ParseFiles(const std::vector<std::string> &filePaths);
|
|
156
|
+
|
|
157
|
+
// Serialize object
|
|
158
|
+
std::vector<uint8_t> Serialize(const std::unordered_map<std::string, std::string> &data, const SerializationOptions &options);
|
|
159
|
+
|
|
160
|
+
// Deserialize data
|
|
161
|
+
std::unordered_map<std::string, std::string> Deserialize(const std::vector<uint8_t> &data, const SerializationOptions &options);
|
|
162
|
+
|
|
163
|
+
// Get memory usage
|
|
164
|
+
size_t GetMemoryUsage() const;
|
|
165
|
+
|
|
166
|
+
// Get performance metrics
|
|
167
|
+
PerformanceMetrics GetPerformanceMetrics() const;
|
|
168
|
+
|
|
169
|
+
// Reset metrics
|
|
170
|
+
void ResetMetrics();
|
|
171
|
+
|
|
172
|
+
private:
|
|
173
|
+
class Impl;
|
|
174
|
+
std::unique_ptr<Impl> impl_;
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
// Utility functions
|
|
178
|
+
std::string ThriftTypeToString(ThriftType type);
|
|
179
|
+
ThriftType StringToThriftType(const std::string &str);
|
|
180
|
+
std::string EndiannessToString(Endianness endianness);
|
|
181
|
+
Endianness StringToEndianness(const std::string &str);
|
|
182
|
+
std::string ProtocolToString(ThriftProtocol protocol);
|
|
183
|
+
ThriftProtocol StringToProtocol(const std::string &str);
|
|
184
|
+
|
|
185
|
+
} // namespace deukpack
|
|
186
|
+
|
|
187
|
+
#endif // THRIFT_ENGINE_H
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DeukPack Binary Reader
|
|
3
|
+
* High-performance binary deserialization
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
#include "binary_reader.h"
|
|
7
|
+
#include <cstring>
|
|
8
|
+
#include <algorithm>
|
|
9
|
+
|
|
10
|
+
namespace deukpack
|
|
11
|
+
{
|
|
12
|
+
|
|
13
|
+
BinaryReader::BinaryReader(const uint8_t *data, size_t size, Endianness endianness)
|
|
14
|
+
: data_(data), size_(size), position_(0), endianness_(endianness)
|
|
15
|
+
{
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
uint8_t BinaryReader::ReadByte()
|
|
19
|
+
{
|
|
20
|
+
if (position_ >= size_)
|
|
21
|
+
{
|
|
22
|
+
throw std::runtime_error("Buffer overflow");
|
|
23
|
+
}
|
|
24
|
+
return data_[position_++];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
int16_t BinaryReader::ReadI16()
|
|
28
|
+
{
|
|
29
|
+
if (position_ + 2 > size_)
|
|
30
|
+
{
|
|
31
|
+
throw std::runtime_error("Buffer overflow");
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
int16_t value;
|
|
35
|
+
if (endianness_ == Endianness::LITTLE_ENDIAN)
|
|
36
|
+
{
|
|
37
|
+
value = data_[position_] | (data_[position_ + 1] << 8);
|
|
38
|
+
}
|
|
39
|
+
else
|
|
40
|
+
{
|
|
41
|
+
value = (data_[position_] << 8) | data_[position_ + 1];
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
position_ += 2;
|
|
45
|
+
return value;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
int32_t BinaryReader::ReadI32()
|
|
49
|
+
{
|
|
50
|
+
if (position_ + 4 > size_)
|
|
51
|
+
{
|
|
52
|
+
throw std::runtime_error("Buffer overflow");
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
int32_t value;
|
|
56
|
+
if (endianness_ == Endianness::LITTLE_ENDIAN)
|
|
57
|
+
{
|
|
58
|
+
value = data_[position_] |
|
|
59
|
+
(data_[position_ + 1] << 8) |
|
|
60
|
+
(data_[position_ + 2] << 16) |
|
|
61
|
+
(data_[position_ + 3] << 24);
|
|
62
|
+
}
|
|
63
|
+
else
|
|
64
|
+
{
|
|
65
|
+
value = (data_[position_] << 24) |
|
|
66
|
+
(data_[position_ + 1] << 16) |
|
|
67
|
+
(data_[position_ + 2] << 8) |
|
|
68
|
+
data_[position_ + 3];
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
position_ += 4;
|
|
72
|
+
return value;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
int64_t BinaryReader::ReadI64()
|
|
76
|
+
{
|
|
77
|
+
if (position_ + 8 > size_)
|
|
78
|
+
{
|
|
79
|
+
throw std::runtime_error("Buffer overflow");
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
int64_t value = 0;
|
|
83
|
+
if (endianness_ == Endianness::LITTLE_ENDIAN)
|
|
84
|
+
{
|
|
85
|
+
for (int i = 0; i < 8; i++)
|
|
86
|
+
{
|
|
87
|
+
value |= static_cast<int64_t>(data_[position_ + i]) << (i * 8);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
else
|
|
91
|
+
{
|
|
92
|
+
for (int i = 0; i < 8; i++)
|
|
93
|
+
{
|
|
94
|
+
value |= static_cast<int64_t>(data_[position_ + i]) << ((7 - i) * 8);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
position_ += 8;
|
|
99
|
+
return value;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
double BinaryReader::ReadDouble()
|
|
103
|
+
{
|
|
104
|
+
if (position_ + 8 > size_)
|
|
105
|
+
{
|
|
106
|
+
throw std::runtime_error("Buffer overflow");
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
union
|
|
110
|
+
{
|
|
111
|
+
double d;
|
|
112
|
+
uint8_t bytes[8];
|
|
113
|
+
} converter;
|
|
114
|
+
|
|
115
|
+
if (endianness_ == Endianness::LITTLE_ENDIAN)
|
|
116
|
+
{
|
|
117
|
+
std::memcpy(converter.bytes, &data_[position_], 8);
|
|
118
|
+
}
|
|
119
|
+
else
|
|
120
|
+
{
|
|
121
|
+
// Reverse byte order for big endian
|
|
122
|
+
for (int i = 0; i < 8; i++)
|
|
123
|
+
{
|
|
124
|
+
converter.bytes[i] = data_[position_ + 7 - i];
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
position_ += 8;
|
|
129
|
+
return converter.d;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
std::string BinaryReader::ReadString()
|
|
133
|
+
{
|
|
134
|
+
int32_t length = ReadI32();
|
|
135
|
+
if (position_ + length > size_)
|
|
136
|
+
{
|
|
137
|
+
throw std::runtime_error("Buffer overflow");
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
std::string result(reinterpret_cast<const char *>(&data_[position_]), length);
|
|
141
|
+
position_ += length;
|
|
142
|
+
return result;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
std::vector<uint8_t> BinaryReader::ReadBinary()
|
|
146
|
+
{
|
|
147
|
+
int32_t length = ReadI32();
|
|
148
|
+
if (position_ + length > size_)
|
|
149
|
+
{
|
|
150
|
+
throw std::runtime_error("Buffer overflow");
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
std::vector<uint8_t> result(data_ + position_, data_ + position_ + length);
|
|
154
|
+
position_ += length;
|
|
155
|
+
return result;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
bool BinaryReader::IsAtEnd() const
|
|
159
|
+
{
|
|
160
|
+
return position_ >= size_;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
size_t BinaryReader::GetPosition() const
|
|
164
|
+
{
|
|
165
|
+
return position_;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
void BinaryReader::SetPosition(size_t position)
|
|
169
|
+
{
|
|
170
|
+
if (position > size_)
|
|
171
|
+
{
|
|
172
|
+
throw std::runtime_error("Position out of bounds");
|
|
173
|
+
}
|
|
174
|
+
position_ = position;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
} // namespace deukpack
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DeukPack Binary Writer
|
|
3
|
+
* High-performance binary serialization
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
#include "binary_writer.h"
|
|
7
|
+
#include <cstring>
|
|
8
|
+
#include <algorithm>
|
|
9
|
+
|
|
10
|
+
namespace deukpack
|
|
11
|
+
{
|
|
12
|
+
|
|
13
|
+
BinaryWriter::BinaryWriter(Endianness endianness, size_t initialSize)
|
|
14
|
+
: endianness_(endianness), position_(0)
|
|
15
|
+
{
|
|
16
|
+
currentBuffer_.resize(initialSize);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
void BinaryWriter::WriteByte(uint8_t value)
|
|
20
|
+
{
|
|
21
|
+
EnsureCapacity(1);
|
|
22
|
+
currentBuffer_[position_++] = value;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
void BinaryWriter::WriteI16(int16_t value)
|
|
26
|
+
{
|
|
27
|
+
EnsureCapacity(2);
|
|
28
|
+
|
|
29
|
+
if (endianness_ == Endianness::LITTLE_ENDIAN)
|
|
30
|
+
{
|
|
31
|
+
currentBuffer_[position_] = value & 0xFF;
|
|
32
|
+
currentBuffer_[position_ + 1] = (value >> 8) & 0xFF;
|
|
33
|
+
}
|
|
34
|
+
else
|
|
35
|
+
{
|
|
36
|
+
currentBuffer_[position_] = (value >> 8) & 0xFF;
|
|
37
|
+
currentBuffer_[position_ + 1] = value & 0xFF;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
position_ += 2;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
void BinaryWriter::WriteI32(int32_t value)
|
|
44
|
+
{
|
|
45
|
+
EnsureCapacity(4);
|
|
46
|
+
|
|
47
|
+
if (endianness_ == Endianness::LITTLE_ENDIAN)
|
|
48
|
+
{
|
|
49
|
+
currentBuffer_[position_] = value & 0xFF;
|
|
50
|
+
currentBuffer_[position_ + 1] = (value >> 8) & 0xFF;
|
|
51
|
+
currentBuffer_[position_ + 2] = (value >> 16) & 0xFF;
|
|
52
|
+
currentBuffer_[position_ + 3] = (value >> 24) & 0xFF;
|
|
53
|
+
}
|
|
54
|
+
else
|
|
55
|
+
{
|
|
56
|
+
currentBuffer_[position_] = (value >> 24) & 0xFF;
|
|
57
|
+
currentBuffer_[position_ + 1] = (value >> 16) & 0xFF;
|
|
58
|
+
currentBuffer_[position_ + 2] = (value >> 8) & 0xFF;
|
|
59
|
+
currentBuffer_[position_ + 3] = value & 0xFF;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
position_ += 4;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
void BinaryWriter::WriteI64(int64_t value)
|
|
66
|
+
{
|
|
67
|
+
EnsureCapacity(8);
|
|
68
|
+
|
|
69
|
+
if (endianness_ == Endianness::LITTLE_ENDIAN)
|
|
70
|
+
{
|
|
71
|
+
for (int i = 0; i < 8; i++)
|
|
72
|
+
{
|
|
73
|
+
currentBuffer_[position_ + i] = (value >> (i * 8)) & 0xFF;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
else
|
|
77
|
+
{
|
|
78
|
+
for (int i = 0; i < 8; i++)
|
|
79
|
+
{
|
|
80
|
+
currentBuffer_[position_ + i] = (value >> ((7 - i) * 8)) & 0xFF;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
position_ += 8;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
void BinaryWriter::WriteDouble(double value)
|
|
88
|
+
{
|
|
89
|
+
EnsureCapacity(8);
|
|
90
|
+
|
|
91
|
+
// Convert to IEEE 754 representation
|
|
92
|
+
union
|
|
93
|
+
{
|
|
94
|
+
double d;
|
|
95
|
+
uint8_t bytes[8];
|
|
96
|
+
} converter;
|
|
97
|
+
|
|
98
|
+
converter.d = value;
|
|
99
|
+
|
|
100
|
+
if (endianness_ == Endianness::LITTLE_ENDIAN)
|
|
101
|
+
{
|
|
102
|
+
std::memcpy(¤tBuffer_[position_], converter.bytes, 8);
|
|
103
|
+
}
|
|
104
|
+
else
|
|
105
|
+
{
|
|
106
|
+
// Reverse byte order for big endian
|
|
107
|
+
for (int i = 0; i < 8; i++)
|
|
108
|
+
{
|
|
109
|
+
currentBuffer_[position_ + i] = converter.bytes[7 - i];
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
position_ += 8;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
void BinaryWriter::WriteString(const std::string &value)
|
|
117
|
+
{
|
|
118
|
+
WriteI32(static_cast<int32_t>(value.length()));
|
|
119
|
+
WriteBytes(reinterpret_cast<const uint8_t *>(value.c_str()), value.length());
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
void BinaryWriter::WriteBytes(const uint8_t *data, size_t length)
|
|
123
|
+
{
|
|
124
|
+
EnsureCapacity(length);
|
|
125
|
+
std::memcpy(¤tBuffer_[position_], data, length);
|
|
126
|
+
position_ += length;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
void BinaryWriter::WriteBinary(const std::vector<uint8_t> &data)
|
|
130
|
+
{
|
|
131
|
+
WriteI32(static_cast<int32_t>(data.size()));
|
|
132
|
+
WriteBytes(data.data(), data.size());
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
std::vector<uint8_t> BinaryWriter::GetBuffer()
|
|
136
|
+
{
|
|
137
|
+
FlushCurrentBuffer();
|
|
138
|
+
|
|
139
|
+
if (buffers_.empty())
|
|
140
|
+
{
|
|
141
|
+
return std::vector<uint8_t>();
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (buffers_.size() == 1)
|
|
145
|
+
{
|
|
146
|
+
return std::move(buffers_[0]);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Calculate total size
|
|
150
|
+
size_t totalSize = 0;
|
|
151
|
+
for (const auto &buffer : buffers_)
|
|
152
|
+
{
|
|
153
|
+
totalSize += buffer.size();
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Concatenate all buffers
|
|
157
|
+
std::vector<uint8_t> result;
|
|
158
|
+
result.reserve(totalSize);
|
|
159
|
+
|
|
160
|
+
for (const auto &buffer : buffers_)
|
|
161
|
+
{
|
|
162
|
+
result.insert(result.end(), buffer.begin(), buffer.end());
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return result;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
size_t BinaryWriter::GetPosition() const
|
|
169
|
+
{
|
|
170
|
+
size_t totalPosition = 0;
|
|
171
|
+
for (const auto &buffer : buffers_)
|
|
172
|
+
{
|
|
173
|
+
totalPosition += buffer.size();
|
|
174
|
+
}
|
|
175
|
+
return totalPosition + position_;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
void BinaryWriter::Reset()
|
|
179
|
+
{
|
|
180
|
+
buffers_.clear();
|
|
181
|
+
position_ = 0;
|
|
182
|
+
currentBuffer_.resize(1024);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
void BinaryWriter::EnsureCapacity(size_t needed)
|
|
186
|
+
{
|
|
187
|
+
if (position_ + needed > currentBuffer_.size())
|
|
188
|
+
{
|
|
189
|
+
FlushCurrentBuffer();
|
|
190
|
+
AllocateNewBuffer(std::max(needed * 2, static_cast<size_t>(1024)));
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
void BinaryWriter::FlushCurrentBuffer()
|
|
195
|
+
{
|
|
196
|
+
if (position_ > 0)
|
|
197
|
+
{
|
|
198
|
+
std::vector<uint8_t> buffer(position_);
|
|
199
|
+
std::memcpy(buffer.data(), currentBuffer_.data(), position_);
|
|
200
|
+
buffers_.push_back(std::move(buffer));
|
|
201
|
+
position_ = 0;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
void BinaryWriter::AllocateNewBuffer(size_t size)
|
|
206
|
+
{
|
|
207
|
+
currentBuffer_.resize(size);
|
|
208
|
+
position_ = 0;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
} // namespace deukpack
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DeukPack Compact Reader
|
|
3
|
+
* High-performance compact protocol deserialization
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
#include "compact_reader.h"
|
|
7
|
+
#include <stdexcept>
|
|
8
|
+
|
|
9
|
+
namespace deukpack
|
|
10
|
+
{
|
|
11
|
+
|
|
12
|
+
CompactReader::CompactReader(const uint8_t *data, size_t size)
|
|
13
|
+
: data_(data), size_(size), position_(0)
|
|
14
|
+
{
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
uint8_t CompactReader::ReadByte()
|
|
18
|
+
{
|
|
19
|
+
if (position_ >= size_)
|
|
20
|
+
{
|
|
21
|
+
throw std::runtime_error("Buffer overflow");
|
|
22
|
+
}
|
|
23
|
+
return data_[position_++];
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
int32_t CompactReader::ReadVarInt()
|
|
27
|
+
{
|
|
28
|
+
int32_t result = 0;
|
|
29
|
+
int shift = 0;
|
|
30
|
+
|
|
31
|
+
while (position_ < size_)
|
|
32
|
+
{
|
|
33
|
+
uint8_t byte = data_[position_++];
|
|
34
|
+
result |= (byte & 0x7F) << shift;
|
|
35
|
+
|
|
36
|
+
if ((byte & 0x80) == 0)
|
|
37
|
+
{
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
shift += 7;
|
|
42
|
+
if (shift >= 32)
|
|
43
|
+
{
|
|
44
|
+
throw std::runtime_error("VarInt too large");
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
std::string CompactReader::ReadString()
|
|
52
|
+
{
|
|
53
|
+
int32_t length = ReadVarInt();
|
|
54
|
+
if (position_ + length > size_)
|
|
55
|
+
{
|
|
56
|
+
throw std::runtime_error("Buffer overflow");
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
std::string result(reinterpret_cast<const char *>(&data_[position_]), length);
|
|
60
|
+
position_ += length;
|
|
61
|
+
return result;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
bool CompactReader::IsAtEnd() const
|
|
65
|
+
{
|
|
66
|
+
return position_ >= size_;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
} // namespace deukpack
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DeukPack Compact Writer
|
|
3
|
+
* High-performance compact protocol serialization
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
#include "compact_writer.h"
|
|
7
|
+
#include <cstring>
|
|
8
|
+
|
|
9
|
+
namespace deukpack
|
|
10
|
+
{
|
|
11
|
+
|
|
12
|
+
CompactWriter::CompactWriter(size_t initialSize)
|
|
13
|
+
: position_(0)
|
|
14
|
+
{
|
|
15
|
+
currentBuffer_.resize(initialSize);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
void CompactWriter::WriteByte(uint8_t value)
|
|
19
|
+
{
|
|
20
|
+
EnsureCapacity(1);
|
|
21
|
+
currentBuffer_[position_++] = value;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
void CompactWriter::WriteVarInt(int32_t value)
|
|
25
|
+
{
|
|
26
|
+
while (value >= 0x80)
|
|
27
|
+
{
|
|
28
|
+
WriteByte((value & 0x7F) | 0x80);
|
|
29
|
+
value >>= 7;
|
|
30
|
+
}
|
|
31
|
+
WriteByte(value & 0x7F);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
void CompactWriter::WriteString(const std::string &value)
|
|
35
|
+
{
|
|
36
|
+
WriteVarInt(static_cast<int32_t>(value.length()));
|
|
37
|
+
WriteBytes(reinterpret_cast<const uint8_t *>(value.c_str()), value.length());
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
void CompactWriter::WriteBytes(const uint8_t *data, size_t length)
|
|
41
|
+
{
|
|
42
|
+
EnsureCapacity(length);
|
|
43
|
+
std::memcpy(¤tBuffer_[position_], data, length);
|
|
44
|
+
position_ += length;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
std::vector<uint8_t> CompactWriter::GetBuffer()
|
|
48
|
+
{
|
|
49
|
+
FlushCurrentBuffer();
|
|
50
|
+
|
|
51
|
+
if (buffers_.empty())
|
|
52
|
+
{
|
|
53
|
+
return std::vector<uint8_t>();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (buffers_.size() == 1)
|
|
57
|
+
{
|
|
58
|
+
return std::move(buffers_[0]);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Calculate total size
|
|
62
|
+
size_t totalSize = 0;
|
|
63
|
+
for (const auto &buffer : buffers_)
|
|
64
|
+
{
|
|
65
|
+
totalSize += buffer.size();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Concatenate all buffers
|
|
69
|
+
std::vector<uint8_t> result;
|
|
70
|
+
result.reserve(totalSize);
|
|
71
|
+
|
|
72
|
+
for (const auto &buffer : buffers_)
|
|
73
|
+
{
|
|
74
|
+
result.insert(result.end(), buffer.begin(), buffer.end());
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return result;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
void CompactWriter::Reset()
|
|
81
|
+
{
|
|
82
|
+
buffers_.clear();
|
|
83
|
+
position_ = 0;
|
|
84
|
+
currentBuffer_.resize(1024);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
void CompactWriter::EnsureCapacity(size_t needed)
|
|
88
|
+
{
|
|
89
|
+
if (position_ + needed > currentBuffer_.size())
|
|
90
|
+
{
|
|
91
|
+
FlushCurrentBuffer();
|
|
92
|
+
AllocateNewBuffer(std::max(needed * 2, static_cast<size_t>(1024)));
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
void CompactWriter::FlushCurrentBuffer()
|
|
97
|
+
{
|
|
98
|
+
if (position_ > 0)
|
|
99
|
+
{
|
|
100
|
+
std::vector<uint8_t> buffer(position_);
|
|
101
|
+
std::memcpy(buffer.data(), currentBuffer_.data(), position_);
|
|
102
|
+
buffers_.push_back(std::move(buffer));
|
|
103
|
+
position_ = 0;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
void CompactWriter::AllocateNewBuffer(size_t size)
|
|
108
|
+
{
|
|
109
|
+
currentBuffer_.resize(size);
|
|
110
|
+
position_ = 0;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
} // namespace deukpack
|
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DeukPack Native C++ Implementation
|
|
3
|
+
* High-performance Thrift engine
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
#include <napi.h>
|
|
7
|
+
#include <iostream>
|
|
8
|
+
#include <vector>
|
|
9
|
+
#include <string>
|
|
10
|
+
#include <unordered_map>
|
|
11
|
+
#include <memory>
|
|
12
|
+
#include <chrono>
|
|
13
|
+
#include "thrift_engine.h"
|
|
14
|
+
#include "binary_writer.h"
|
|
15
|
+
|
|
16
|
+
using namespace deukpack;
|
|
17
|
+
|
|
18
|
+
// ThriftEngine implementation
|
|
19
|
+
class ThriftEngine::Impl
|
|
20
|
+
{
|
|
21
|
+
public:
|
|
22
|
+
Impl() : memoryUsage_(0) {}
|
|
23
|
+
|
|
24
|
+
ThriftAST ParseFiles(const std::vector<std::string> &filePaths)
|
|
25
|
+
{
|
|
26
|
+
auto start = std::chrono::high_resolution_clock::now();
|
|
27
|
+
|
|
28
|
+
ThriftAST ast;
|
|
29
|
+
// TODO: Implement actual parsing logic
|
|
30
|
+
// For now, return empty AST
|
|
31
|
+
|
|
32
|
+
auto end = std::chrono::high_resolution_clock::now();
|
|
33
|
+
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
|
|
34
|
+
parseTime_ = duration.count();
|
|
35
|
+
|
|
36
|
+
return ast;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
std::vector<uint8_t> Serialize(const std::unordered_map<std::string, std::string> &data,
|
|
40
|
+
const SerializationOptions &options)
|
|
41
|
+
{
|
|
42
|
+
auto start = std::chrono::high_resolution_clock::now();
|
|
43
|
+
|
|
44
|
+
BinaryWriter writer(options.endianness == Endianness::LITTLE_ENDIAN ? Endianness::LITTLE_ENDIAN : Endianness::BIG_ENDIAN);
|
|
45
|
+
|
|
46
|
+
// Simple serialization for demonstration
|
|
47
|
+
writer.WriteI32(static_cast<int32_t>(data.size()));
|
|
48
|
+
for (const auto &pair : data)
|
|
49
|
+
{
|
|
50
|
+
writer.WriteString(pair.first);
|
|
51
|
+
writer.WriteString(pair.second);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
auto result = writer.GetBuffer();
|
|
55
|
+
|
|
56
|
+
auto end = std::chrono::high_resolution_clock::now();
|
|
57
|
+
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
|
|
58
|
+
serializeTime_ = duration.count();
|
|
59
|
+
|
|
60
|
+
return result;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
std::unordered_map<std::string, std::string> Deserialize(const std::vector<uint8_t> &data,
|
|
64
|
+
const SerializationOptions &options)
|
|
65
|
+
{
|
|
66
|
+
auto start = std::chrono::high_resolution_clock::now();
|
|
67
|
+
|
|
68
|
+
std::unordered_map<std::string, std::string> result;
|
|
69
|
+
|
|
70
|
+
// Simple deserialization for demonstration
|
|
71
|
+
if (data.size() >= 4)
|
|
72
|
+
{
|
|
73
|
+
int32_t count = *reinterpret_cast<const int32_t *>(data.data());
|
|
74
|
+
size_t offset = 4;
|
|
75
|
+
|
|
76
|
+
for (int32_t i = 0; i < count && offset < data.size(); i++)
|
|
77
|
+
{
|
|
78
|
+
if (offset + 4 > data.size())
|
|
79
|
+
break;
|
|
80
|
+
|
|
81
|
+
int32_t keyLen = *reinterpret_cast<const int32_t *>(data.data() + offset);
|
|
82
|
+
offset += 4;
|
|
83
|
+
|
|
84
|
+
if (offset + keyLen > data.size())
|
|
85
|
+
break;
|
|
86
|
+
std::string key(data.data() + offset, data.data() + offset + keyLen);
|
|
87
|
+
offset += keyLen;
|
|
88
|
+
|
|
89
|
+
if (offset + 4 > data.size())
|
|
90
|
+
break;
|
|
91
|
+
int32_t valueLen = *reinterpret_cast<const int32_t *>(data.data() + offset);
|
|
92
|
+
offset += 4;
|
|
93
|
+
|
|
94
|
+
if (offset + valueLen > data.size())
|
|
95
|
+
break;
|
|
96
|
+
std::string value(data.data() + offset, data.data() + offset + valueLen);
|
|
97
|
+
offset += valueLen;
|
|
98
|
+
|
|
99
|
+
result[key] = value;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
auto end = std::chrono::high_resolution_clock::now();
|
|
104
|
+
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
|
|
105
|
+
deserializeTime_ = duration.count();
|
|
106
|
+
|
|
107
|
+
return result;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
size_t GetMemoryUsage() const
|
|
111
|
+
{
|
|
112
|
+
return memoryUsage_;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
PerformanceMetrics GetPerformanceMetrics() const
|
|
116
|
+
{
|
|
117
|
+
PerformanceMetrics metrics;
|
|
118
|
+
metrics.parseTime = parseTime_;
|
|
119
|
+
metrics.generateTime = generateTime_;
|
|
120
|
+
metrics.serializeTime = serializeTime_;
|
|
121
|
+
metrics.deserializeTime = deserializeTime_;
|
|
122
|
+
metrics.memoryUsage = memoryUsage_;
|
|
123
|
+
metrics.fileCount = fileCount_;
|
|
124
|
+
metrics.lineCount = lineCount_;
|
|
125
|
+
return metrics;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
void ResetMetrics()
|
|
129
|
+
{
|
|
130
|
+
parseTime_ = 0;
|
|
131
|
+
generateTime_ = 0;
|
|
132
|
+
serializeTime_ = 0;
|
|
133
|
+
deserializeTime_ = 0;
|
|
134
|
+
memoryUsage_ = 0;
|
|
135
|
+
fileCount_ = 0;
|
|
136
|
+
lineCount_ = 0;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
private:
|
|
140
|
+
double parseTime_ = 0;
|
|
141
|
+
double generateTime_ = 0;
|
|
142
|
+
double serializeTime_ = 0;
|
|
143
|
+
double deserializeTime_ = 0;
|
|
144
|
+
size_t memoryUsage_ = 0;
|
|
145
|
+
int32_t fileCount_ = 0;
|
|
146
|
+
int32_t lineCount_ = 0;
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
ThriftEngine::ThriftEngine() : impl_(std::make_unique<Impl>()) {}
|
|
150
|
+
ThriftEngine::~ThriftEngine() = default;
|
|
151
|
+
|
|
152
|
+
ThriftAST ThriftEngine::ParseFiles(const std::vector<std::string> &filePaths)
|
|
153
|
+
{
|
|
154
|
+
return impl_->ParseFiles(filePaths);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
std::vector<uint8_t> ThriftEngine::Serialize(const std::unordered_map<std::string, std::string> &data,
|
|
158
|
+
const SerializationOptions &options)
|
|
159
|
+
{
|
|
160
|
+
return impl_->Serialize(data, options);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
std::unordered_map<std::string, std::string> ThriftEngine::Deserialize(const std::vector<uint8_t> &data,
|
|
164
|
+
const SerializationOptions &options)
|
|
165
|
+
{
|
|
166
|
+
return impl_->Deserialize(data, options);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
size_t ThriftEngine::GetMemoryUsage() const
|
|
170
|
+
{
|
|
171
|
+
return impl_->GetMemoryUsage();
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
PerformanceMetrics ThriftEngine::GetPerformanceMetrics() const
|
|
175
|
+
{
|
|
176
|
+
return impl_->GetPerformanceMetrics();
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
void ThriftEngine::ResetMetrics()
|
|
180
|
+
{
|
|
181
|
+
impl_->ResetMetrics();
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// N-API wrapper functions
|
|
185
|
+
Napi::Value CreateEngine(const Napi::CallbackInfo &info)
|
|
186
|
+
{
|
|
187
|
+
Napi::Env env = info.Env();
|
|
188
|
+
|
|
189
|
+
try
|
|
190
|
+
{
|
|
191
|
+
auto engine = std::make_unique<ThriftEngine>();
|
|
192
|
+
return Napi::External<ThriftEngine>::New(env, engine.release());
|
|
193
|
+
}
|
|
194
|
+
catch (const std::exception &e)
|
|
195
|
+
{
|
|
196
|
+
Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();
|
|
197
|
+
return env.Null();
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
Napi::Value ParseFiles(const Napi::CallbackInfo &info)
|
|
202
|
+
{
|
|
203
|
+
Napi::Env env = info.Env();
|
|
204
|
+
|
|
205
|
+
if (info.Length() < 2 || !info[0].IsExternal() || !info[1].IsArray())
|
|
206
|
+
{
|
|
207
|
+
Napi::TypeError::New(env, "Expected engine and file paths array").ThrowAsJavaScriptException();
|
|
208
|
+
return env.Null();
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
try
|
|
212
|
+
{
|
|
213
|
+
auto engine = info[0].As<Napi::External<ThriftEngine>>().Data();
|
|
214
|
+
auto filePaths = info[1].As<Napi::Array>();
|
|
215
|
+
|
|
216
|
+
std::vector<std::string> paths;
|
|
217
|
+
for (uint32_t i = 0; i < filePaths.Length(); i++)
|
|
218
|
+
{
|
|
219
|
+
if (filePaths.Get(i).IsString())
|
|
220
|
+
{
|
|
221
|
+
paths.push_back(filePaths.Get(i).As<Napi::String>().Utf8Value());
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
auto ast = engine->ParseFiles(paths);
|
|
226
|
+
|
|
227
|
+
// Convert AST to JavaScript object
|
|
228
|
+
auto result = Napi::Object::New(env);
|
|
229
|
+
result.Set("namespaces", Napi::Array::New(env));
|
|
230
|
+
result.Set("structs", Napi::Array::New(env));
|
|
231
|
+
result.Set("enums", Napi::Array::New(env));
|
|
232
|
+
result.Set("services", Napi::Array::New(env));
|
|
233
|
+
result.Set("includes", Napi::Array::New(env));
|
|
234
|
+
|
|
235
|
+
return result;
|
|
236
|
+
}
|
|
237
|
+
catch (const std::exception &e)
|
|
238
|
+
{
|
|
239
|
+
Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();
|
|
240
|
+
return env.Null();
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
Napi::Value Serialize(const Napi::CallbackInfo &info)
|
|
245
|
+
{
|
|
246
|
+
Napi::Env env = info.Env();
|
|
247
|
+
|
|
248
|
+
if (info.Length() < 3 || !info[0].IsExternal() || !info[1].IsObject() || !info[2].IsObject())
|
|
249
|
+
{
|
|
250
|
+
Napi::TypeError::New(env, "Expected engine, data object, and options object").ThrowAsJavaScriptException();
|
|
251
|
+
return env.Null();
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
try
|
|
255
|
+
{
|
|
256
|
+
auto engine = info[0].As<Napi::External<ThriftEngine>>().Data();
|
|
257
|
+
auto dataObj = info[1].As<Napi::Object>();
|
|
258
|
+
auto optionsObj = info[2].As<Napi::Object>();
|
|
259
|
+
|
|
260
|
+
// Convert JavaScript object to map
|
|
261
|
+
std::unordered_map<std::string, std::string> data;
|
|
262
|
+
auto keys = dataObj.GetPropertyNames();
|
|
263
|
+
for (uint32_t i = 0; i < keys.Length(); i++)
|
|
264
|
+
{
|
|
265
|
+
auto key = keys.Get(i).As<Napi::String>().Utf8Value();
|
|
266
|
+
auto value = dataObj.Get(key).As<Napi::String>().Utf8Value();
|
|
267
|
+
data[key] = value;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// Create serialization options
|
|
271
|
+
SerializationOptions options;
|
|
272
|
+
options.protocol = ThriftProtocol::BINARY;
|
|
273
|
+
options.endianness = Endianness::LITTLE_ENDIAN;
|
|
274
|
+
options.optimizeForSize = true;
|
|
275
|
+
options.includeDefaultValues = false;
|
|
276
|
+
options.validateTypes = true;
|
|
277
|
+
|
|
278
|
+
auto result = engine->Serialize(data, options);
|
|
279
|
+
|
|
280
|
+
// Convert to Node.js Buffer
|
|
281
|
+
auto buffer = Napi::Buffer<uint8_t>::Copy(env, result.data(), result.size());
|
|
282
|
+
return buffer;
|
|
283
|
+
}
|
|
284
|
+
catch (const std::exception &e)
|
|
285
|
+
{
|
|
286
|
+
Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();
|
|
287
|
+
return env.Null();
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
Napi::Value Deserialize(const Napi::CallbackInfo &info)
|
|
292
|
+
{
|
|
293
|
+
Napi::Env env = info.Env();
|
|
294
|
+
|
|
295
|
+
if (info.Length() < 3 || !info[0].IsExternal() || !info[1].IsBuffer() || !info[2].IsObject())
|
|
296
|
+
{
|
|
297
|
+
Napi::TypeError::New(env, "Expected engine, buffer, and options object").ThrowAsJavaScriptException();
|
|
298
|
+
return env.Null();
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
try
|
|
302
|
+
{
|
|
303
|
+
auto engine = info[0].As<Napi::External<ThriftEngine>>().Data();
|
|
304
|
+
auto buffer = info[1].As<Napi::Buffer<uint8_t>>();
|
|
305
|
+
auto optionsObj = info[2].As<Napi::Object>();
|
|
306
|
+
|
|
307
|
+
// Convert buffer to vector
|
|
308
|
+
std::vector<uint8_t> data(buffer.Data(), buffer.Data() + buffer.Length());
|
|
309
|
+
|
|
310
|
+
// Create serialization options
|
|
311
|
+
SerializationOptions options;
|
|
312
|
+
options.protocol = ThriftProtocol::BINARY;
|
|
313
|
+
options.endianness = Endianness::LITTLE_ENDIAN;
|
|
314
|
+
options.optimizeForSize = true;
|
|
315
|
+
options.includeDefaultValues = false;
|
|
316
|
+
options.validateTypes = true;
|
|
317
|
+
|
|
318
|
+
auto result = engine->Deserialize(data, options);
|
|
319
|
+
|
|
320
|
+
// Convert map to JavaScript object
|
|
321
|
+
auto resultObj = Napi::Object::New(env);
|
|
322
|
+
for (const auto &pair : result)
|
|
323
|
+
{
|
|
324
|
+
resultObj.Set(pair.first, pair.second);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
return resultObj;
|
|
328
|
+
}
|
|
329
|
+
catch (const std::exception &e)
|
|
330
|
+
{
|
|
331
|
+
Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();
|
|
332
|
+
return env.Null();
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
Napi::Value GetPerformanceMetrics(const Napi::CallbackInfo &info)
|
|
337
|
+
{
|
|
338
|
+
Napi::Env env = info.Env();
|
|
339
|
+
|
|
340
|
+
if (info.Length() < 1 || !info[0].IsExternal())
|
|
341
|
+
{
|
|
342
|
+
Napi::TypeError::New(env, "Expected engine").ThrowAsJavaScriptException();
|
|
343
|
+
return env.Null();
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
try
|
|
347
|
+
{
|
|
348
|
+
auto engine = info[0].As<Napi::External<ThriftEngine>>().Data();
|
|
349
|
+
auto metrics = engine->GetPerformanceMetrics();
|
|
350
|
+
|
|
351
|
+
auto result = Napi::Object::New(env);
|
|
352
|
+
result.Set("parseTime", metrics.parseTime);
|
|
353
|
+
result.Set("generateTime", metrics.generateTime);
|
|
354
|
+
result.Set("serializeTime", metrics.serializeTime);
|
|
355
|
+
result.Set("deserializeTime", metrics.deserializeTime);
|
|
356
|
+
result.Set("memoryUsage", static_cast<double>(metrics.memoryUsage));
|
|
357
|
+
result.Set("fileCount", metrics.fileCount);
|
|
358
|
+
result.Set("lineCount", metrics.lineCount);
|
|
359
|
+
|
|
360
|
+
return result;
|
|
361
|
+
}
|
|
362
|
+
catch (const std::exception &e)
|
|
363
|
+
{
|
|
364
|
+
Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();
|
|
365
|
+
return env.Null();
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
Napi::Object Init(Napi::Env env, Napi::Object exports)
|
|
370
|
+
{
|
|
371
|
+
exports.Set(Napi::String::New(env, "createEngine"), Napi::Function::New(env, CreateEngine));
|
|
372
|
+
exports.Set(Napi::String::New(env, "parseFiles"), Napi::Function::New(env, ParseFiles));
|
|
373
|
+
exports.Set(Napi::String::New(env, "serialize"), Napi::Function::New(env, Serialize));
|
|
374
|
+
exports.Set(Napi::String::New(env, "deserialize"), Napi::Function::New(env, Deserialize));
|
|
375
|
+
exports.Set(Napi::String::New(env, "getPerformanceMetrics"), Napi::Function::New(env, GetPerformanceMetrics));
|
|
376
|
+
|
|
377
|
+
return exports;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
NODE_API_MODULE(thrift_engine_native, Init)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "deukpack",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "DeukPack — multi-format IDL pipeline (.deuk native, Protobuf, OpenAPI, JSON Schema, CSV, Thrift). Protobuf-aligned wire; fast C#/C++/JS codegen, CLI. v1: no Excel/table editor workflow",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"build:native": "node-gyp rebuild",
|
|
14
14
|
"build:all": "npm run build && npm run build:cpp && npm run build:cs",
|
|
15
15
|
"build:cpp": "cd native/cpp && mkdir -p build && cd build && cmake .. && make",
|
|
16
|
-
"build:cs": "cd
|
|
16
|
+
"build:cs": "cd DeukPack.Protocol && dotnet build -c Release",
|
|
17
17
|
"test": "jest",
|
|
18
18
|
"benchmark": "node benchmarks/performance.js",
|
|
19
19
|
"dev": "tsc --watch",
|
|
@@ -65,6 +65,8 @@
|
|
|
65
65
|
"bin",
|
|
66
66
|
"scripts/build_deukpack.js",
|
|
67
67
|
"dist",
|
|
68
|
+
"native/cpp",
|
|
69
|
+
"binding.gyp",
|
|
68
70
|
"LICENSE",
|
|
69
71
|
"NOTICE",
|
|
70
72
|
"README.md",
|