util/dbuffer.lua
author Kim Alvefur <zash@zash.se>
Sat, 23 Mar 2024 20:48:19 +0100
changeset 13465 c673ff1075bd
parent 12979 d10957394a3c
permissions -rw-r--r--
mod_posix: Move everything to util.startup This allows greater control over the order of events. Notably, the internal ordering between daemonization, initialization of libunbound and setup of signal handling is sensitive. libunbound starts a separate thread for processing DNS requests. If this thread is started before signal handling has been set up, it will not inherit the signal handlers and instead behave as it would have before signal handlers were set up, i.e. cause the whole process to immediately exit. libunbound is usually initialized on the first DNS request, usually triggered by an outgoing s2s connection attempt. If daemonization happens before signals have been set up, signals may not be processed at all.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
12979
d10957394a3c util: Prefix module imports with prosody namespace
Kim Alvefur <zash@zash.se>
parents: 12767
diff changeset
     1
local queue = require "prosody.util.queue";
11108
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     2
11193
0ff148362a3d util.dbuffer: Optimize :sub() and :byte()
Matthew Wild <mwild1@gmail.com>
parents: 11160
diff changeset
     3
local s_byte, s_sub = string.byte, string.sub;
11108
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     4
local dbuffer_methods = {};
11200
f243836c449a util.dbuffer: Add __name to metatable
Matthew Wild <mwild1@gmail.com>
parents: 11194
diff changeset
     5
local dynamic_buffer_mt = { __name = "dbuffer", __index = dbuffer_methods };
11108
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     6
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     7
function dbuffer_methods:write(data)
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     8
	if self.max_size and #data + self._length > self.max_size then
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
     9
		return nil;
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    10
	end
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    11
	local ok = self.items:push(data);
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    12
	if not ok then
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    13
		self:collapse();
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    14
		ok = self.items:push(data);
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    15
	end
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    16
	if not ok then
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    17
		return nil;
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    18
	end
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    19
	self._length = self._length + #data;
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    20
	return true;
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    21
end
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    22
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    23
function dbuffer_methods:read_chunk(requested_bytes)
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    24
	local chunk, consumed = self.items:peek(), self.front_consumed;
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    25
	if not chunk then return; end
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    26
	local chunk_length = #chunk;
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    27
	local remaining_chunk_length = chunk_length - consumed;
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    28
	if not requested_bytes then
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    29
		requested_bytes = remaining_chunk_length;
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    30
	end
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    31
	if remaining_chunk_length <= requested_bytes then
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    32
		self.front_consumed = 0;
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    33
		self._length = self._length - remaining_chunk_length;
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    34
		self.items:pop();
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    35
		assert(#chunk:sub(consumed + 1, -1) == remaining_chunk_length);
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    36
		return chunk:sub(consumed + 1, -1), remaining_chunk_length;
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    37
	end
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    38
	local end_pos = consumed + requested_bytes;
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    39
	self.front_consumed = end_pos;
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    40
	self._length = self._length - requested_bytes;
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    41
	assert(#chunk:sub(consumed + 1, end_pos) == requested_bytes);
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    42
	return chunk:sub(consumed + 1, end_pos), requested_bytes;
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    43
end
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    44
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    45
function dbuffer_methods:read(requested_bytes)
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    46
	local chunks;
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    47
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    48
	if requested_bytes and requested_bytes > self._length then
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    49
		return nil;
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    50
	end
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    51
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    52
	local chunk, read_bytes = self:read_chunk(requested_bytes);
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    53
	if not requested_bytes then
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    54
		return chunk;
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    55
	elseif chunk then
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    56
		requested_bytes = requested_bytes - read_bytes;
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    57
		if requested_bytes == 0 then -- Already read everything we need
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    58
			return chunk;
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    59
		end
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    60
		chunks = {};
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    61
	else
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    62
		return nil;
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    63
	end
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    64
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    65
	-- Need to keep reading more chunks
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    66
	while chunk do
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    67
		table.insert(chunks, chunk);
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    68
		if requested_bytes > 0 then
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    69
			chunk, read_bytes = self:read_chunk(requested_bytes);
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    70
			requested_bytes = requested_bytes - read_bytes;
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    71
		else
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    72
			break;
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    73
		end
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    74
	end
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    75
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    76
	return table.concat(chunks);
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    77
end
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    78
11640
11e0a0a08da3 util.dbuffer: Add read_until() method
Matthew Wild <mwild1@gmail.com>
parents: 11200
diff changeset
    79
-- Read to, and including, the specified character sequence (return nil if not found)
11e0a0a08da3 util.dbuffer: Add read_until() method
Matthew Wild <mwild1@gmail.com>
parents: 11200
diff changeset
    80
function dbuffer_methods:read_until(char)
11e0a0a08da3 util.dbuffer: Add read_until() method
Matthew Wild <mwild1@gmail.com>
parents: 11200
diff changeset
    81
	local buffer_pos = 0;
11e0a0a08da3 util.dbuffer: Add read_until() method
Matthew Wild <mwild1@gmail.com>
parents: 11200
diff changeset
    82
	for i, chunk in self.items:items() do
11641
19cddf92fcc2 util.dbuffer: Fix bugs, remove multi-char support (more complex than first thought)
Matthew Wild <mwild1@gmail.com>
parents: 11640
diff changeset
    83
		local start = 1 + ((i == 1) and self.front_consumed or 0);
11640
11e0a0a08da3 util.dbuffer: Add read_until() method
Matthew Wild <mwild1@gmail.com>
parents: 11200
diff changeset
    84
		local char_pos = chunk:find(char, start, true);
11e0a0a08da3 util.dbuffer: Add read_until() method
Matthew Wild <mwild1@gmail.com>
parents: 11200
diff changeset
    85
		if char_pos then
11641
19cddf92fcc2 util.dbuffer: Fix bugs, remove multi-char support (more complex than first thought)
Matthew Wild <mwild1@gmail.com>
parents: 11640
diff changeset
    86
			return self:read(1 + buffer_pos + char_pos - start);
11640
11e0a0a08da3 util.dbuffer: Add read_until() method
Matthew Wild <mwild1@gmail.com>
parents: 11200
diff changeset
    87
		end
11641
19cddf92fcc2 util.dbuffer: Fix bugs, remove multi-char support (more complex than first thought)
Matthew Wild <mwild1@gmail.com>
parents: 11640
diff changeset
    88
		buffer_pos = buffer_pos + #chunk - (start - 1);
11640
11e0a0a08da3 util.dbuffer: Add read_until() method
Matthew Wild <mwild1@gmail.com>
parents: 11200
diff changeset
    89
	end
11e0a0a08da3 util.dbuffer: Add read_until() method
Matthew Wild <mwild1@gmail.com>
parents: 11200
diff changeset
    90
	return nil;
11e0a0a08da3 util.dbuffer: Add read_until() method
Matthew Wild <mwild1@gmail.com>
parents: 11200
diff changeset
    91
end
11e0a0a08da3 util.dbuffer: Add read_until() method
Matthew Wild <mwild1@gmail.com>
parents: 11200
diff changeset
    92
11108
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
    93
function dbuffer_methods:discard(requested_bytes)
12767
d26eefe98d09 util.dbuffer: Add efficient shortcuts for discard() in certain cases
Matthew Wild <mwild1@gmail.com>
parents: 12766
diff changeset
    94
	if self._length == 0 then return true; end
d26eefe98d09 util.dbuffer: Add efficient shortcuts for discard() in certain cases
Matthew Wild <mwild1@gmail.com>
parents: 12766
diff changeset
    95
	if not requested_bytes or requested_bytes >= self._length then
d26eefe98d09 util.dbuffer: Add efficient shortcuts for discard() in certain cases
Matthew Wild <mwild1@gmail.com>
parents: 12766
diff changeset
    96
		self.front_consumed = 0;
d26eefe98d09 util.dbuffer: Add efficient shortcuts for discard() in certain cases
Matthew Wild <mwild1@gmail.com>
parents: 12766
diff changeset
    97
		self._length = 0;
d26eefe98d09 util.dbuffer: Add efficient shortcuts for discard() in certain cases
Matthew Wild <mwild1@gmail.com>
parents: 12766
diff changeset
    98
		for _ in self.items:consume() do end
d26eefe98d09 util.dbuffer: Add efficient shortcuts for discard() in certain cases
Matthew Wild <mwild1@gmail.com>
parents: 12766
diff changeset
    99
		return true;
11108
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   100
	end
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   101
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   102
	local chunk, read_bytes = self:read_chunk(requested_bytes);
12766
79b89f382290 util.dbuffer: Remove redundant code (read_chunk() cannot fail at this point)
Matthew Wild <mwild1@gmail.com>
parents: 11641
diff changeset
   103
	requested_bytes = requested_bytes - read_bytes;
79b89f382290 util.dbuffer: Remove redundant code (read_chunk() cannot fail at this point)
Matthew Wild <mwild1@gmail.com>
parents: 11641
diff changeset
   104
	if requested_bytes == 0 then -- Already read everything we need
79b89f382290 util.dbuffer: Remove redundant code (read_chunk() cannot fail at this point)
Matthew Wild <mwild1@gmail.com>
parents: 11641
diff changeset
   105
		return true;
11108
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   106
	end
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   107
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   108
	while chunk do
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   109
		if requested_bytes > 0 then
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   110
			chunk, read_bytes = self:read_chunk(requested_bytes);
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   111
			requested_bytes = requested_bytes - read_bytes;
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   112
		else
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   113
			break;
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   114
		end
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   115
	end
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   116
	return true;
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   117
end
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   118
11193
0ff148362a3d util.dbuffer: Optimize :sub() and :byte()
Matthew Wild <mwild1@gmail.com>
parents: 11160
diff changeset
   119
-- Normalize i, j into absolute offsets within the
0ff148362a3d util.dbuffer: Optimize :sub() and :byte()
Matthew Wild <mwild1@gmail.com>
parents: 11160
diff changeset
   120
-- front chunk (accounting for front_consumed), and
0ff148362a3d util.dbuffer: Optimize :sub() and :byte()
Matthew Wild <mwild1@gmail.com>
parents: 11160
diff changeset
   121
-- ensure there is enough data in the first chunk
0ff148362a3d util.dbuffer: Optimize :sub() and :byte()
Matthew Wild <mwild1@gmail.com>
parents: 11160
diff changeset
   122
-- to cover any subsequent :sub() or :byte() operation
0ff148362a3d util.dbuffer: Optimize :sub() and :byte()
Matthew Wild <mwild1@gmail.com>
parents: 11160
diff changeset
   123
function dbuffer_methods:_prep_sub(i, j)
11108
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   124
	if j == nil then
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   125
		j = -1;
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   126
	end
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   127
	if j < 0 then
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   128
		j = self._length + (j+1);
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   129
	end
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   130
	if i < 0 then
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   131
		i = self._length + (i+1);
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   132
	end
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   133
	if i < 1 then
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   134
		i = 1;
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   135
	end
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   136
	if j > self._length then
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   137
		j = self._length;
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   138
	end
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   139
	if i > j then
11193
0ff148362a3d util.dbuffer: Optimize :sub() and :byte()
Matthew Wild <mwild1@gmail.com>
parents: 11160
diff changeset
   140
		return nil;
11108
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   141
	end
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   142
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   143
	self:collapse(j);
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   144
11193
0ff148362a3d util.dbuffer: Optimize :sub() and :byte()
Matthew Wild <mwild1@gmail.com>
parents: 11160
diff changeset
   145
	if self.front_consumed > 0 then
0ff148362a3d util.dbuffer: Optimize :sub() and :byte()
Matthew Wild <mwild1@gmail.com>
parents: 11160
diff changeset
   146
		i = i + self.front_consumed;
0ff148362a3d util.dbuffer: Optimize :sub() and :byte()
Matthew Wild <mwild1@gmail.com>
parents: 11160
diff changeset
   147
		j = j + self.front_consumed;
0ff148362a3d util.dbuffer: Optimize :sub() and :byte()
Matthew Wild <mwild1@gmail.com>
parents: 11160
diff changeset
   148
	end
0ff148362a3d util.dbuffer: Optimize :sub() and :byte()
Matthew Wild <mwild1@gmail.com>
parents: 11160
diff changeset
   149
0ff148362a3d util.dbuffer: Optimize :sub() and :byte()
Matthew Wild <mwild1@gmail.com>
parents: 11160
diff changeset
   150
	return i, j;
0ff148362a3d util.dbuffer: Optimize :sub() and :byte()
Matthew Wild <mwild1@gmail.com>
parents: 11160
diff changeset
   151
end
0ff148362a3d util.dbuffer: Optimize :sub() and :byte()
Matthew Wild <mwild1@gmail.com>
parents: 11160
diff changeset
   152
0ff148362a3d util.dbuffer: Optimize :sub() and :byte()
Matthew Wild <mwild1@gmail.com>
parents: 11160
diff changeset
   153
function dbuffer_methods:sub(i, j)
0ff148362a3d util.dbuffer: Optimize :sub() and :byte()
Matthew Wild <mwild1@gmail.com>
parents: 11160
diff changeset
   154
	i, j = self:_prep_sub(i, j);
0ff148362a3d util.dbuffer: Optimize :sub() and :byte()
Matthew Wild <mwild1@gmail.com>
parents: 11160
diff changeset
   155
	if not i then
0ff148362a3d util.dbuffer: Optimize :sub() and :byte()
Matthew Wild <mwild1@gmail.com>
parents: 11160
diff changeset
   156
		return "";
0ff148362a3d util.dbuffer: Optimize :sub() and :byte()
Matthew Wild <mwild1@gmail.com>
parents: 11160
diff changeset
   157
	end
0ff148362a3d util.dbuffer: Optimize :sub() and :byte()
Matthew Wild <mwild1@gmail.com>
parents: 11160
diff changeset
   158
	return s_sub(self.items:peek(), i, j);
11108
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   159
end
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   160
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   161
function dbuffer_methods:byte(i, j)
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   162
	i = i or 1;
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   163
	j = j or i;
11193
0ff148362a3d util.dbuffer: Optimize :sub() and :byte()
Matthew Wild <mwild1@gmail.com>
parents: 11160
diff changeset
   164
	i, j = self:_prep_sub(i, j);
0ff148362a3d util.dbuffer: Optimize :sub() and :byte()
Matthew Wild <mwild1@gmail.com>
parents: 11160
diff changeset
   165
	if not i then
0ff148362a3d util.dbuffer: Optimize :sub() and :byte()
Matthew Wild <mwild1@gmail.com>
parents: 11160
diff changeset
   166
		return;
0ff148362a3d util.dbuffer: Optimize :sub() and :byte()
Matthew Wild <mwild1@gmail.com>
parents: 11160
diff changeset
   167
	end
0ff148362a3d util.dbuffer: Optimize :sub() and :byte()
Matthew Wild <mwild1@gmail.com>
parents: 11160
diff changeset
   168
	return s_byte(self.items:peek(), i, j);
11108
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   169
end
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   170
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   171
function dbuffer_methods:length()
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   172
	return self._length;
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   173
end
11160
a8ef69f7fc35 util.dbuffer: Expose length as :len() method, like strings
Kim Alvefur <zash@zash.se>
parents: 11108
diff changeset
   174
dbuffer_methods.len = dbuffer_methods.length; -- strings have :len()
11108
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   175
dynamic_buffer_mt.__len = dbuffer_methods.length; -- support # operator
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   176
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   177
function dbuffer_methods:collapse(bytes)
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   178
	bytes = bytes or self._length;
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   179
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   180
	local front_chunk = self.items:peek();
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   181
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   182
	if not front_chunk or #front_chunk - self.front_consumed >= bytes then
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   183
		return;
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   184
	end
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   185
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   186
	local front_chunks = { front_chunk:sub(self.front_consumed+1) };
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   187
	local front_bytes = #front_chunks[1];
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   188
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   189
	while front_bytes < bytes do
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   190
		self.items:pop();
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   191
		local chunk = self.items:peek();
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   192
		front_bytes = front_bytes + #chunk;
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   193
		table.insert(front_chunks, chunk);
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   194
	end
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   195
	self.items:replace(table.concat(front_chunks));
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   196
	self.front_consumed = 0;
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   197
end
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   198
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   199
local function new(max_size, max_chunks)
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   200
	if max_size and max_size <= 0 then
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   201
		return nil;
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   202
	end
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   203
	return setmetatable({
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   204
		front_consumed = 0;
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   205
		_length = 0;
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   206
		max_size = max_size;
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   207
		items = queue.new(max_chunks or 32);
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   208
	}, dynamic_buffer_mt);
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   209
end
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   210
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   211
return {
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   212
	new = new;
6632acc96cf6 util.dbuffer: Fix :sub() not working with partially-consumed chunks (thanks Zash for test case)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
   213
};