mirror of
https://github.com/zeek/zeek.git
synced 2025-10-12 11:38:20 +00:00
Convert BaseQueue/Queue/PQueue into templates, including iterator support
This commit is contained in:
parent
50943a580c
commit
776da8cb9e
3 changed files with 203 additions and 202 deletions
|
@ -272,7 +272,6 @@ set(MAIN_SRCS
|
||||||
PolicyFile.cc
|
PolicyFile.cc
|
||||||
PrefixTable.cc
|
PrefixTable.cc
|
||||||
PriorityQueue.cc
|
PriorityQueue.cc
|
||||||
Queue.cc
|
|
||||||
RandTest.cc
|
RandTest.cc
|
||||||
RE.cc
|
RE.cc
|
||||||
Reassem.cc
|
Reassem.cc
|
||||||
|
|
137
src/Queue.cc
137
src/Queue.cc
|
@ -1,137 +0,0 @@
|
||||||
// See the file "COPYING" in the main distribution directory for copyright.
|
|
||||||
|
|
||||||
#include "zeek-config.h"
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "Queue.h"
|
|
||||||
|
|
||||||
BaseQueue::BaseQueue(int size)
|
|
||||||
{
|
|
||||||
const int DEFAULT_CHUNK_SIZE = 10;
|
|
||||||
|
|
||||||
chunk_size = DEFAULT_CHUNK_SIZE;
|
|
||||||
|
|
||||||
head = tail = num_entries = 0;
|
|
||||||
|
|
||||||
if ( size < 0 )
|
|
||||||
{
|
|
||||||
entry = new ent[1];
|
|
||||||
max_entries = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if ( (entry = new ent[chunk_size+1]) )
|
|
||||||
max_entries = chunk_size;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
entry = new ent[1];
|
|
||||||
max_entries = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void BaseQueue::push_front(ent a)
|
|
||||||
{
|
|
||||||
if ( num_entries == max_entries )
|
|
||||||
{
|
|
||||||
resize(max_entries+chunk_size); // make more room
|
|
||||||
chunk_size *= 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
++num_entries;
|
|
||||||
if ( head )
|
|
||||||
entry[--head] = a;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
head = max_entries;
|
|
||||||
entry[head] = a;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void BaseQueue::push_back(ent a)
|
|
||||||
{
|
|
||||||
if ( num_entries == max_entries )
|
|
||||||
{
|
|
||||||
resize(max_entries+chunk_size); // make more room
|
|
||||||
chunk_size *= 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
++num_entries;
|
|
||||||
if ( tail < max_entries )
|
|
||||||
entry[tail++] = a;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
entry[tail] = a;
|
|
||||||
tail = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ent BaseQueue::pop_front()
|
|
||||||
{
|
|
||||||
if ( ! num_entries )
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
--num_entries;
|
|
||||||
if ( head < max_entries )
|
|
||||||
return entry[head++];
|
|
||||||
else
|
|
||||||
{
|
|
||||||
head = 0;
|
|
||||||
return entry[max_entries];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ent BaseQueue::pop_back()
|
|
||||||
{
|
|
||||||
if ( ! num_entries )
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
--num_entries;
|
|
||||||
if ( tail )
|
|
||||||
return entry[--tail];
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tail = max_entries;
|
|
||||||
return entry[tail];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int BaseQueue::resize(int new_size)
|
|
||||||
{
|
|
||||||
if ( new_size < num_entries )
|
|
||||||
new_size = num_entries; // do not lose any entries
|
|
||||||
|
|
||||||
if ( new_size != max_entries )
|
|
||||||
{
|
|
||||||
// Note, allocate extra space, so that we can always
|
|
||||||
// use the [max_entries] element.
|
|
||||||
// ### Yin, why not use realloc()?
|
|
||||||
ent* new_entry = new ent[new_size+1];
|
|
||||||
|
|
||||||
if ( new_entry )
|
|
||||||
{
|
|
||||||
if ( head <= tail )
|
|
||||||
memcpy( new_entry, entry + head,
|
|
||||||
sizeof(ent) * num_entries );
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int len = num_entries - tail;
|
|
||||||
memcpy( new_entry, entry + head,
|
|
||||||
sizeof(ent) * len );
|
|
||||||
memcpy( new_entry + len, entry,
|
|
||||||
sizeof(ent) * tail );
|
|
||||||
}
|
|
||||||
delete [] entry;
|
|
||||||
entry = new_entry;
|
|
||||||
max_entries = new_size;
|
|
||||||
head = 0;
|
|
||||||
tail = num_entries;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{ // out of memory
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return max_entries;
|
|
||||||
}
|
|
267
src/Queue.h
267
src/Queue.h
|
@ -3,8 +3,8 @@
|
||||||
#ifndef queue_h
|
#ifndef queue_h
|
||||||
#define queue_h
|
#define queue_h
|
||||||
|
|
||||||
// BaseQueue.h --
|
// Queue.h --
|
||||||
// Interface for class BaseQueue, current implementation is as an
|
// Interface for class Queue, current implementation is as an
|
||||||
// array of ent's. This implementation was chosen to optimize
|
// array of ent's. This implementation was chosen to optimize
|
||||||
// getting to the ent's rather than inserting and deleting.
|
// getting to the ent's rather than inserting and deleting.
|
||||||
// Also push's and pop's from the front or the end of the queue
|
// Also push's and pop's from the front or the end of the queue
|
||||||
|
@ -21,35 +21,214 @@
|
||||||
// Entries must be either a pointer to the data or nonzero data with
|
// Entries must be either a pointer to the data or nonzero data with
|
||||||
// sizeof(data) <= sizeof(void*).
|
// sizeof(data) <= sizeof(void*).
|
||||||
|
|
||||||
#include "List.h"
|
template<typename T>
|
||||||
|
class QueueIterator
|
||||||
class BaseQueue {
|
{
|
||||||
|
T* const entries;
|
||||||
|
int offset;
|
||||||
|
int num_entries;
|
||||||
public:
|
public:
|
||||||
~BaseQueue() { delete[] entry; }
|
QueueIterator(T* entries, int offset, int num_entries) :
|
||||||
|
entries(entries), offset(offset), num_entries(num_entries) {}
|
||||||
|
bool operator==(const QueueIterator& rhs) { return entries == rhs.entries && offset == rhs.offset; }
|
||||||
|
bool operator!=(const QueueIterator& rhs) { return entries != rhs.entries || offset != rhs.offset; }
|
||||||
|
QueueIterator & operator++() { offset++; return *this; }
|
||||||
|
QueueIterator operator++(int) { auto t = *this; offset++; return t; }
|
||||||
|
QueueIterator & operator--() { offset--; return *this; }
|
||||||
|
QueueIterator operator--(int) { auto t = *this; offset--; return t; }
|
||||||
|
std::ptrdiff_t operator-(QueueIterator const& sibling) const { return offset - sibling.offset; }
|
||||||
|
QueueIterator & operator+=(int amount) { offset += amount; return *this; }
|
||||||
|
QueueIterator & operator-=(int amount) { offset -= amount; return *this; }
|
||||||
|
bool operator<(QueueIterator const&sibling) const { return offset < sibling.offset;}
|
||||||
|
bool operator<=(QueueIterator const&sibling) const { return offset <= sibling.offset; }
|
||||||
|
bool operator>(QueueIterator const&sibling) const { return offset > sibling.offset; }
|
||||||
|
bool operator>=(QueueIterator const&sibling) const { return offset >= sibling.offset; }
|
||||||
|
T& operator[](int index)
|
||||||
|
{
|
||||||
|
return entries[index];
|
||||||
|
}
|
||||||
|
T& operator*()
|
||||||
|
{
|
||||||
|
return entries[offset];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace std {
|
||||||
|
template<typename T>
|
||||||
|
class iterator_traits<QueueIterator<T> >
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
using size_type = std::size_t;
|
||||||
|
using value_type = T;
|
||||||
|
using pointer = T*;
|
||||||
|
using reference = T&;
|
||||||
|
using iterator_category = std::random_access_iterator_tag;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class Queue {
|
||||||
|
public:
|
||||||
|
explicit Queue(int size = 0)
|
||||||
|
{
|
||||||
|
const int DEFAULT_CHUNK_SIZE = 10;
|
||||||
|
chunk_size = DEFAULT_CHUNK_SIZE;
|
||||||
|
|
||||||
|
head = tail = num_entries = 0;
|
||||||
|
|
||||||
|
if ( size < 0 )
|
||||||
|
{
|
||||||
|
entries = new T[1];
|
||||||
|
max_entries = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( (entries = new T[chunk_size+1]) )
|
||||||
|
max_entries = chunk_size;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
entries = new T[1];
|
||||||
|
max_entries = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~Queue() { delete[] entries; }
|
||||||
|
|
||||||
int length() const { return num_entries; }
|
int length() const { return num_entries; }
|
||||||
int resize(int = 0); // 0 => size to fit current number of entries
|
int resize(int new_size = 0) // 0 => size to fit current number of entries
|
||||||
|
{
|
||||||
|
if ( new_size < num_entries )
|
||||||
|
new_size = num_entries; // do not lose any entries
|
||||||
|
|
||||||
|
if ( new_size != max_entries )
|
||||||
|
{
|
||||||
|
// Note, allocate extra space, so that we can always
|
||||||
|
// use the [max_entries] element.
|
||||||
|
// ### Yin, why not use realloc()?
|
||||||
|
T* new_entries = new T[new_size+1];
|
||||||
|
|
||||||
|
if ( new_entries )
|
||||||
|
{
|
||||||
|
if ( head <= tail )
|
||||||
|
memcpy( new_entries, entries + head,
|
||||||
|
sizeof(T) * num_entries );
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int len = num_entries - tail;
|
||||||
|
memcpy( new_entries, entries + head,
|
||||||
|
sizeof(T) * len );
|
||||||
|
memcpy( new_entries + len, entries,
|
||||||
|
sizeof(T) * tail );
|
||||||
|
}
|
||||||
|
delete [] entries;
|
||||||
|
entries = new_entries;
|
||||||
|
max_entries = new_size;
|
||||||
|
head = 0;
|
||||||
|
tail = num_entries;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ // out of memory
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return max_entries;
|
||||||
|
}
|
||||||
|
|
||||||
// remove all entries without delete[] entry
|
// remove all entries without delete[] entry
|
||||||
void clear() { head = tail = num_entries = 0; }
|
void clear() { head = tail = num_entries = 0; }
|
||||||
|
|
||||||
// helper functions for iterating over queue
|
// helper functions for iterating over queue
|
||||||
int front() const { return head; }
|
T& front() { return entries[head]; }
|
||||||
int back() const { return tail; }
|
T& back() { return entries[tail]; }
|
||||||
void incr(int& index) { index < max_entries ? ++index : index = 0; }
|
const T& front() const { return entries[head]; }
|
||||||
|
const T& back() const { return entries[tail]; }
|
||||||
|
|
||||||
protected:
|
void push_front(const T& a) // add in front of queue
|
||||||
explicit BaseQueue(int = 0);
|
{
|
||||||
|
if ( num_entries == max_entries )
|
||||||
|
{
|
||||||
|
resize(max_entries+chunk_size); // make more room
|
||||||
|
chunk_size *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
void push_front(ent); // add in front of queue
|
++num_entries;
|
||||||
void push_back(ent); // add at end of queue
|
if ( head )
|
||||||
ent pop_front(); // return and remove the front of queue
|
entries[--head] = a;
|
||||||
ent pop_back(); // return and remove the end of queue
|
else
|
||||||
|
{
|
||||||
|
head = max_entries;
|
||||||
|
entries[head] = a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void push_back(const T& a) // add at end of queue
|
||||||
|
{
|
||||||
|
if ( num_entries == max_entries )
|
||||||
|
{
|
||||||
|
resize(max_entries+chunk_size); // make more room
|
||||||
|
chunk_size *= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
++num_entries;
|
||||||
|
if ( tail < max_entries )
|
||||||
|
entries[tail++] = a;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
entries[tail] = a;
|
||||||
|
tail = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void pop_front()
|
||||||
|
{
|
||||||
|
--num_entries;
|
||||||
|
if ( head < max_entries )
|
||||||
|
head++;
|
||||||
|
else
|
||||||
|
head = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pop_back()
|
||||||
|
{
|
||||||
|
--num_entries;
|
||||||
|
if ( tail )
|
||||||
|
--tail;
|
||||||
|
else
|
||||||
|
tail = max_entries;
|
||||||
|
}
|
||||||
|
|
||||||
// return nth *PHYSICAL* entry of queue (do not remove)
|
// return nth *PHYSICAL* entry of queue (do not remove)
|
||||||
ent operator[](int i) const { return entry[i]; }
|
T& operator[](int i) const { return entries[i]; }
|
||||||
|
|
||||||
ent* entry;
|
// Type traits needed for some of the std algorithms to work
|
||||||
|
using value_type = T;
|
||||||
|
|
||||||
|
// Iterator support
|
||||||
|
using iterator = QueueIterator<T>;
|
||||||
|
using const_iterator = QueueIterator<const T>;
|
||||||
|
using reverse_iterator = std::reverse_iterator<iterator>;
|
||||||
|
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
|
||||||
|
|
||||||
|
iterator begin() { return { entries, 0, num_entries }; }
|
||||||
|
iterator end() { return { entries, num_entries, num_entries }; }
|
||||||
|
const_iterator begin() const { return { entries, 0, num_entries }; }
|
||||||
|
const_iterator end() const { return { entries, num_entries, num_entries }; }
|
||||||
|
const_iterator cbegin() const { return { entries, 0, num_entries }; }
|
||||||
|
const_iterator cend() const { return { entries, num_entries, num_entries }; }
|
||||||
|
|
||||||
|
reverse_iterator rbegin() { return reverse_iterator{end()}; }
|
||||||
|
reverse_iterator rend() { return reverse_iterator{begin()}; }
|
||||||
|
const_reverse_iterator rbegin() const { return const_reverse_iterator{end()}; }
|
||||||
|
const_reverse_iterator rend() const { return const_reverse_iterator{begin()}; }
|
||||||
|
const_reverse_iterator crbegin() const { return rbegin(); }
|
||||||
|
const_reverse_iterator crend() const { return rend(); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
T* entries;
|
||||||
int chunk_size; // increase size by this amount when necessary
|
int chunk_size; // increase size by this amount when necessary
|
||||||
int max_entries; // entry's index range: 0 .. max_entries
|
int max_entries; // entry's index range: 0 .. max_entries
|
||||||
int num_entries;
|
int num_entries;
|
||||||
|
@ -57,54 +236,14 @@ protected:
|
||||||
int tail; // just beyond the end of the queue in the ring
|
int tail; // just beyond the end of the queue in the ring
|
||||||
};
|
};
|
||||||
|
|
||||||
// Queue.h -- interface for class Queue
|
|
||||||
// Use: to get a list of pointers to class foo you should:
|
|
||||||
// 1) declare(PQueue,foo); (declare interest in lists of foo*'s)
|
|
||||||
// 2) variables are declared like:
|
|
||||||
// PQueue(foo) bar; (bar is of type list of foo*'s)
|
|
||||||
|
|
||||||
// For queues of "type"
|
template<typename T>
|
||||||
#define Queue(type) type ## Queue
|
using PQueue = Queue<T*>;
|
||||||
|
|
||||||
// For queues of pointers to "type"
|
|
||||||
#define PQueue(type) type ## PQueue
|
|
||||||
|
|
||||||
#define Queuedeclare(type) \
|
|
||||||
struct Queue(type) : BaseQueue \
|
|
||||||
{ \
|
|
||||||
Queue(type)() : BaseQueue(0) {} \
|
|
||||||
explicit Queue(type)(int sz) : BaseQueue(sz) {} \
|
|
||||||
\
|
|
||||||
void push_front(type a) { BaseQueue::push_front(ent(a)); } \
|
|
||||||
void push_back(type a) { BaseQueue::push_back(ent(a)); } \
|
|
||||||
type pop_front() { return type(BaseQueue::pop_front()); }\
|
|
||||||
type pop_back() { return type(BaseQueue::pop_back()); } \
|
|
||||||
\
|
|
||||||
type operator[](int i) const \
|
|
||||||
{ return type(BaseQueue::operator[](i)); } \
|
|
||||||
}; \
|
|
||||||
|
|
||||||
#define PQueuedeclare(type) \
|
|
||||||
struct PQueue(type) : BaseQueue \
|
|
||||||
{ \
|
|
||||||
PQueue(type)() : BaseQueue(0) {} \
|
|
||||||
explicit PQueue(type)(int sz) : BaseQueue(sz) {} \
|
|
||||||
\
|
|
||||||
void push_front(type* a){ BaseQueue::push_front(ent(a)); } \
|
|
||||||
void push_back(type* a) { BaseQueue::push_back(ent(a)); } \
|
|
||||||
type* pop_front() \
|
|
||||||
{ return (type*)BaseQueue::pop_front(); } \
|
|
||||||
type* pop_back() \
|
|
||||||
{ return (type*)BaseQueue::pop_back(); } \
|
|
||||||
\
|
|
||||||
type* operator[](int i) const \
|
|
||||||
{ return (type*)BaseQueue::operator[](i); } \
|
|
||||||
}; \
|
|
||||||
|
|
||||||
// Macro to visit each queue element in turn.
|
// Macro to visit each queue element in turn.
|
||||||
#define loop_over_queue(queue, iterator) \
|
#define loop_over_queue(queue, iterator) \
|
||||||
int iterator; \
|
int iterator; \
|
||||||
for ( iterator = (queue).front(); iterator != (queue).back(); \
|
for ( iterator = (queue).front(); iterator != (queue).back(); \
|
||||||
(queue).incr(iterator) ) \
|
(queue).incr(iterator) )
|
||||||
|
|
||||||
#endif /* queue_h */
|
#endif /* queue_h */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue