forked from lvzixun/sconn_client
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbuffer_queue.lua
More file actions
278 lines (222 loc) · 5.71 KB
/
buffer_queue.lua
File metadata and controls
278 lines (222 loc) · 5.71 KB
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
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
local M = {}
local mt = {}
local function _new_block(v)
local block = {
value = v,
next = false,
prev = false,
}
return block
end
local endian_fmt = {
["little"] = "<",
["big"] = ">",
}
local function pack_data(data, header_len, endian)
local len = #data
local fmt = endian_fmt[endian].."I"..header_len.."c"..(len)
return string.pack(fmt, len, data)
end
local function insert_free_list(self, block)
block.prev = false
block.next = false
local count = self.v_free_list_count
count = count + 1
self.v_free_list_count = count
self.v_free_list[count] = block
end
local function get_block(self)
local count = self.v_free_list_count
if count > 0 then
local block = self.v_free_list[count]
self.v_free_list[count] = nil
self.v_free_list_count = count - 1
return block
else
return _new_block()
end
end
local function free_block(self, block)
local next = block.next
local prev = block.prev
if next then
next.prev = prev
end
if prev then
prev.next = next
end
insert_free_list(self, block)
end
local function init_buffer(self)
local DEF_FREE_BLOCK = 3
for i=1,DEF_FREE_BLOCK do
insert_free_list(self, _new_block())
end
end
local function create()
local raw = {
v_free_list = {},
v_free_list_count = 0,
v_block_head = false,
v_block_tail = false,
v_size = 0,
}
init_buffer(raw)
setmetatable(raw, {__index = mt})
return raw
end
function mt:push(data)
local block = get_block(self)
block.value = data
local size = self.v_size
self.v_size = size + #data
if not self.v_block_head then
assert(self.v_block_tail==false)
self.v_block_head = block
end
local tail = self.v_block_tail
if tail then
tail.next = block
block.prev = tail
block.next = false
end
self.v_block_tail = block
end
local buff = {}
function mt:look(nbytes)
local head = self.v_block_head
local size = self.v_size
if head and nbytes>0 and size>=nbytes then
local count = 0
local index = 0
while head and count ~= nbytes do
local value = head.value
local len = #(value)
if count + len > nbytes then
local sub = nbytes - count
value = string.sub(value, 1, sub)
count = count + sub
else
count = count + len
end
index = index + 1
buff[index] = value
head = head.next
end
return table.concat(buff, "", 1, index)
end
return false
end
function mt:pop(nbytes)
local head = self.v_block_head
nbytes = nbytes or (head and #(head.value))
if head and nbytes>0 and self.v_size>=nbytes then
local count = 0
local index = 0
while head and count ~= nbytes do
local len = #(head.value)
index = index + 1
if count + len > nbytes then
local sub = nbytes - count
local value = head.value
local sub_value = string.sub(value, 1, sub)
buff[index] = sub_value
count = count + sub
head.value = string.sub(value, sub+1)
else
count = count + len
buff[index] = head.value
local next = head.next
free_block(self, head)
head = next
end
end
self.v_block_head = head
self.v_size = self.v_size - count
if not head then
self.v_block_tail=false
end
local ret = table.concat(buff, "", 1, index)
assert(#ret == nbytes)
return ret
end
return false
end
function mt:pop_all(out)
local v = self:pop()
local count = 0
while v do
count = count + 1
out[count] = v
v = self:pop()
end
return count
end
function mt:push_block(data, header_len, endian)
data = pack_data(data, header_len, endian)
self:push(data)
end
function mt:pop_block(header_len, endian)
if self.v_size > header_len then
local header = self:look(header_len)
local fmt = endian_fmt[endian].."I"..header_len
local len = string.unpack(fmt, header)
if self.v_size >= len+header_len then
self:pop(header_len)
return self:pop(len)
end
end
return false
end
function mt:pop_all_block(out, header_len, endian)
local v = self:pop_block(header_len, endian)
local count = 0
while v do
count = count + 1
out[count] = v
v = self:pop_block(header_len, endian)
end
return count
end
function mt:clear()
local head = self.v_block_head
while head do
insert_free_list(self, head)
head = head.next
end
self.v_block_head = false
self.v_block_tail = false
self.v_size = 0
end
function mt:get_head_data()
local head = self.v_block_head
return head and head.value or false
end
---- for test
local function _dump_list(list)
while list do
print(" node = ", list)
for k,v in pairs(list) do
print(" ", k,v)
end
print("----------")
list = list.next
end
end
function mt:dump()
print("==== meta info ====")
for k,v in pairs(self) do
print(k,v)
end
print("===== free list ====", self.v_free_list_count)
local free_list = self.v_free_list
for k,v in pairs(free_list) do
print(k,v)
end
print("===== head list ====")
_dump_list(self.v_block_head)
end
return {
create = create,
pack_data = pack_data,
}