-
Notifications
You must be signed in to change notification settings - Fork 0
/
gdparser.pyx
225 lines (166 loc) · 5.45 KB
/
gdparser.pyx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
#cython:language_level = 3
#distutils: sources = yyjson/yyjson.c
cimport cython
from cython.parallel cimport prange
from libc.stdlib cimport free
from libc.string cimport memcpy
from cpython.buffer cimport (
Py_buffer,
PyObject_GetBuffer,
PyBuffer_Release,
PyBUF_SIMPLE
)
from cpython.mem cimport PyMem_Free
from cpython.bytes cimport PyBytes_FromStringAndSize
DEF parser_size = 2048
cdef extern from "Python.h":
void *PyMem_Calloc(size_t nelem, size_t elsize)
cdef extern from "b64.h":
struct buffer_s:
size_t len
char* buf
ctypedef buffer_s buffer_t
struct gd_node_s:
size_t pos # The string's current position on the parsing phase...
buffer_t* buf # An arrary of 30 buffers to use
char* raw # the raw robtop string to parse through
ctypedef gd_node_s gd_node_t
int give_memory(buffer_t* buff) nogil
void reset_memory(buffer_t* buffer) nogil
void free_memory(buffer_t* buff) nogil
int parse_next(gd_node_t* node)
bytes from_buffer(buffer_t* buff)
Py_ssize_t fast_atoi(buffer_t * buff)
Py_ssize_t fast_ternary(buffer_t * buff)
bint fast_boolean(buffer_t* buff) with gil
bytes b64decode(buffer_t* buffer)
bytes Write_Json(buffer_t* buff)
# This will do multipurpose decoing on both url-safe and not so it's a win-win
cdef class GDComment:
cdef:
buffer_t* buf
@property
def body(self):
return b64decode(&self.buf[2])
@property
def raw_comment(self):
return from_buffer(&self.buf[2])
@property
def authorPlayerID(self):
return from_buffer(&self.buf[3])
@property
def likes(self):
return fast_atoi(&self.buf[4])
@property
def dislikes(self):
return fast_ternary(&self.buf[5])
@property
def messageID(self):
return from_buffer(&self.buf[6])
@property
def spam(self):
return fast_boolean(&self.buf[7])
@property
def authorAccountID(self):
return from_buffer(&self.buf[29])
@property
def age(self):
return from_buffer(&self.buf[9])
@property
def percent(self):
return fast_ternary(&self.buf[10])
@property
def modBadge(self):
return fast_ternary(&self.buf[11])
@property
def moderatorChatColor(self):
if self.modBadge > 0:
return from_buffer(&self.buf[12])
@property
def author(self):
return from_buffer(&self.buf[14])
@property
def icon(self):
return fast_atoi(&self.buf[22])
@property
def playerColor(self):
return fast_atoi(&self.buf[23])
@property
def playerColor2(self):
return fast_atoi(&self.buf[24])
@property
def icontype(self):
return fast_atoi(&self.buf[27])
@property
def glow(self):
return fast_atoi(&self.buf[28])
# def __dealloc__(self):
# PyMem_Free(self.buf)
@property
def as_json(self):
return Write_Json(self.buf)
cdef class GDParser:
cdef:
Py_buffer py_buf
gd_node_t node
int flag
def __init__(self, object b):
PyObject_GetBuffer(b, &self.py_buf, PyBUF_SIMPLE)
(&self.node).raw = <char*>self.py_buf.buf
self.node.pos = 0
self.node.buf = <buffer_t*>PyMem_Calloc(30, sizeof(buffer_t))
self.give_mem()
self.flag = 0
def __dealloc__(self):
self.free_mem()
PyMem_Free(self.node.buf)
PyBuffer_Release(&self.py_buf)
# used with nogil for quick memeory management
cdef void give_mem(self):
cdef int i , j = 0
cdef gd_node_t node = self.node
for i in prange(30, nogil=True):
j = give_memory(&node.buf[i])
if j == -1:
with gil:
raise MemoryError()
# Set object after use...
self.node = node
# Clean memory before use...
self.reset_mem()
cdef void reset_mem(self):
cdef int i
cdef gd_node_t node = self.node
for i in prange(30, nogil=True):
reset_memory(&node.buf[i])
# Set object after use...
self.node = node
cdef void free_mem(self):
cdef int i
cdef gd_node_t node = self.node
for i in prange(30, nogil=True):
free_memory(&node.buf[i])
# Set object after use...
self.node = node
def parse_comment(self):
if self.flag == -1:
return None
self.flag = parse_next(&self.node)
cdef GDComment comment = GDComment.__new__(GDComment)
comment.buf = self.node.buf
return comment
def debug_position(self):
return "Debug pos: <%i>" % self.node.pos
def __iter__(self):
cdef GDComment comment
while self.flag != -1:
self.flag = parse_next(&self.node)
comment = <GDComment>GDComment.__new__(GDComment)
comment.buf = self.node.buf
yield comment
def range(self,Py_ssize_t i):
for _ in range(i):
self.flag = parse_next(&self.node)
comment = <GDComment>GDComment.__new__(GDComment)
comment.buf = self.node.buf
yield comment