Implemented a nearly generic Queue in scriptland.

This commit is contained in:
Seth Hall 2012-11-19 23:42:19 -05:00
parent 257b460b18
commit 5b81cfe7e2
4 changed files with 224 additions and 0 deletions

View file

@ -12,6 +12,7 @@
@load base/utils/numbers @load base/utils/numbers
@load base/utils/paths @load base/utils/paths
@load base/utils/patterns @load base/utils/patterns
@load base/utils/queue
@load base/utils/strings @load base/utils/strings
@load base/utils/thresholds @load base/utils/thresholds
@load base/utils/urls @load base/utils/urls

View file

@ -0,0 +1,177 @@
##! A FIFO string queue.
module Queue;
export {
## Settings for initializing the queue.
type Settings: record {
## If a maximum length is set for the queue
## it will maintain itself at that
## maximum length automatically.
max_len: count &optional;
};
## The internal data structure for the queue.
type Queue: record {};
## Initialize a queue record structure.
##
## s: A :bro:record:`Settings` record configuring the queue.
##
## Returns: An opaque queue record.
global init: function(s: Settings): Queue;
## Push a string onto the top of a queue.
##
## q: The queue to push the string into.
##
## val: The string to push
global push: function(q: Queue, val: any);
## Pop a string from the bottom of a queue.
##
## q: The queue to pop the string from.
##
## Returns: The string popped from the queue.
global pop: function(q: Queue): any;
## Merge two queue's together. If any settings are applied
## to the queues, the settings from q1 are used for the new
## merged queue.
##
## q1: The first queue. Settings are taken from here.
##
## q2: The second queue.
##
## Returns: A new queue from merging the other two together.
global merge: function(q1: Queue, q2: Queue): Queue;
## Get the number of items in a queue.
##
## q: The queue.
##
## Returns: The length of the queue.
global len: function(q: Queue): count;
## Get the contents of the queue as a string vector.
##
## q: The queue.
##
## Returns: A :bro:type:`vector of string` containing the
## current contents of q.
global get_str_vector: function(q: Queue): vector of string;
## Get the contents of the queue as a count vector. Use care
## with this function. If the data put into the queue wasn't
## integers you will get conversion errors.
##
## q: The queue.
##
## Returns: A :bro:type:`vector of count` containing the
## current contents of q.
global get_cnt_vector: function(q: Queue): vector of count;
}
redef record Queue += {
# Indicator for if the queue was appropriately initialized.
initialized: bool &default=F;
# The values are stored here.
vals: table[count] of any &optional;
# Settings for the queue.
settings: Settings &optional;
# The top value in the vals table.
top: count &default=0;
# The bottom value in the vals table.
bottom: count &default=0;
# The number of bytes in the queue.
size: count &default=0;
};
function init(s: Settings): Queue
{
local q: Queue;
q$vals=table();
q$settings = copy(s);
q$initialized=T;
return q;
}
function push(q: Queue, val: any)
{
if ( q$settings?$max_len && len(q) >= q$settings$max_len )
pop(q);
q$vals[q$top] = val;
++q$top;
}
function pop(q: Queue): any
{
local ret = q$vals[q$bottom];
delete q$vals[q$bottom];
++q$bottom;
return ret;
}
function merge(q1: Queue, q2: Queue): Queue
{
local ret = init(q1$settings);
local i = q1$bottom;
local j = q2$bottom;
for ( ignored_val in q1$vals )
{
if ( i in q1$vals )
push(ret, q1$vals[i]);
if ( j in q2$vals )
push(ret, q2$vals[j]);
++i;
++j;
}
}
function len(q: Queue): count
{
return |q$vals|;
}
function get_str_vector(q: Queue): vector of string
{
local ret: vector of string;
local i = q$bottom;
local j = 0;
# Really dumb hack, this is only to provide
# the iteration for the correct number of
# values in q$vals.
for ( ignored_val in q$vals )
{
if ( i >= q$top )
break;
ret[j] = cat(q$vals[i]);
++j; ++i;
}
return ret;
}
function get_cnt_vector(q: Queue): vector of count
{
local ret: vector of count;
local i = q$bottom;
local j = 0;
# Really dumb hack, this is only to provide
# the iteration for the correct number of
# values in q$vals.
for ( ignored_val in q$vals )
{
if ( i >= q$top )
break;
# TODO: this is terrible and should be replaced by
# a more generic version of the various
# functions to get vectors of values.
# (the way "any" works right now makes this impossible though)
ret[j] = to_count(cat(q$vals[i]));
++j; ++i;
}
return ret;
}

View file

@ -0,0 +1,11 @@
This is a get_cnt_vector test: 3
This is a get_cnt_vector test: 4
This is a get_str_vector test: 3
This is a get_str_vector test: 4
Testing pop: 3
Length after pop: 1
Size of q2: 4
String queue value: test 1
String queue value: test 2
String queue value: test 2
String queue value: test 1

View file

@ -0,0 +1,35 @@
# @TEST-EXEC: bro -b %INPUT > output
# @TEST-EXEC: btest-diff output
# This is loaded by default
@load base/utils/queue
event bro_init()
{
local q = Queue::init([$max_len=2]);
Queue::push(q, 1);
Queue::push(q, 2);
Queue::push(q, 3);
Queue::push(q, 4);
local test1 = Queue::get_cnt_vector(q);
for ( i in test1 )
print fmt("This is a get_cnt_vector test: %d", test1[i]);
local test2 = Queue::get_str_vector(q);
for ( i in test2 )
print fmt("This is a get_str_vector test: %s", test2[i]);
local test_val = Queue::pop(q);
print fmt("Testing pop: %s", test_val);
print fmt("Length after pop: %d", Queue::len(q));
local q2 = Queue::init([]);
Queue::push(q2, "test 1");
Queue::push(q2, "test 2");
Queue::push(q2, "test 2");
Queue::push(q2, "test 1");
print fmt("Size of q2: %d", Queue::len(q2));
local test3: vector of string = Queue::get_str_vector(q2);
for ( i in test3 )
print fmt("String queue value: %s", test3[i]);
}