diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a9d5501718..58eef4eea9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -261,7 +261,6 @@ set(MAIN_SRCS IntSet.cc IP.cc IPAddr.cc - List.cc Reporter.cc NFA.cc Net.cc diff --git a/src/List.cc b/src/List.cc deleted file mode 100644 index 1b8c2fd5e5..0000000000 --- a/src/List.cc +++ /dev/null @@ -1,246 +0,0 @@ -#include "zeek-config.h" - -#include -#include - -#include "List.h" -#include "util.h" - -#define DEFAULT_LIST_SIZE 10 -#define GROWTH_FACTOR 2 - -BaseList::BaseList(int size) - { - num_entries = 0; - - if ( size <= 0 ) - { - max_entries = 0; - entry = 0; - return; - } - - max_entries = size; - - entry = (ent *) safe_malloc(max_entries * sizeof(ent)); - } - - -BaseList::BaseList(const BaseList& b) - { - max_entries = b.max_entries; - num_entries = b.num_entries; - - if ( max_entries ) - entry = (ent *) safe_malloc(max_entries * sizeof(ent)); - else - entry = 0; - - for ( int i = 0; i < num_entries; ++i ) - entry[i] = b.entry[i]; - } - -BaseList::BaseList(BaseList&& b) - { - entry = b.entry; - num_entries = b.num_entries; - max_entries = b.max_entries; - - b.entry = 0; - b.num_entries = b.max_entries = 0; - } - -BaseList::BaseList(const ent* arr, int n) - { - num_entries = max_entries = n; - entry = (ent*) safe_malloc(max_entries * sizeof(ent)); - memcpy(entry, arr, n * sizeof(ent)); - } - -void BaseList::sort(list_cmp_func cmp_func) - { - qsort(entry, num_entries, sizeof(ent), cmp_func); - } - -BaseList& BaseList::operator=(const BaseList& b) - { - if ( this == &b ) - return *this; - - free(entry); - - max_entries = b.max_entries; - num_entries = b.num_entries; - - if ( max_entries ) - entry = (ent *) safe_malloc(max_entries * sizeof(ent)); - else - entry = 0; - - for ( int i = 0; i < num_entries; ++i ) - entry[i] = b.entry[i]; - - return *this; - } - -BaseList& BaseList::operator=(BaseList&& b) - { - if ( this == &b ) - return *this; - - free(entry); - entry = b.entry; - num_entries = b.num_entries; - max_entries = b.max_entries; - - b.entry = 0; - b.num_entries = b.max_entries = 0; - return *this; - } - -void BaseList::insert(ent a) - { - if ( num_entries == max_entries ) - resize(max_entries ? max_entries * GROWTH_FACTOR : DEFAULT_LIST_SIZE); - - for ( int i = num_entries; i > 0; --i ) - entry[i] = entry[i-1]; // move all pointers up one - - ++num_entries; - entry[0] = a; - } - -#include - -void BaseList::sortedinsert(ent a, list_cmp_func cmp_func) - { - // We optimize for the case that the new element is - // larger than most of the current entries. - - // First append element. - if ( num_entries == max_entries ) - resize(max_entries ? max_entries * GROWTH_FACTOR : DEFAULT_LIST_SIZE); - - entry[num_entries++] = a; - - // Then move it to the correct place. - ent tmp; - for ( int i = num_entries - 1; i > 0; --i ) - { - if ( cmp_func(entry[i],entry[i-1]) <= 0 ) - break; - - tmp = entry[i]; - entry[i] = entry[i-1]; - entry[i-1] = tmp; - } - } - -ent BaseList::remove(ent a) - { - int i; - for ( i = 0; i < num_entries && a != entry[i]; ++i ) - ; - - return remove_nth(i); - } - -ent BaseList::remove_nth(int n) - { - if ( n < 0 || n >= num_entries ) - return 0; - - ent old_ent = entry[n]; - --num_entries; - - for ( ; n < num_entries; ++n ) - entry[n] = entry[n+1]; - - entry[n] = 0; // for debugging - return old_ent; - } - -void BaseList::append(ent a) - { - if ( num_entries == max_entries ) - resize(max_entries ? max_entries * GROWTH_FACTOR : DEFAULT_LIST_SIZE); - - entry[num_entries++] = a; - } - -// Get and remove from the end of the list. -ent BaseList::get() - { - if ( num_entries == 0 ) - return 0; - - return entry[--num_entries]; - } - - -void BaseList::clear() - { - free(entry); - entry = 0; - num_entries = max_entries = 0; - } - -ent BaseList::replace(int ent_index, ent new_ent) - { - if ( ent_index < 0 ) - return 0; - - ent old_ent; - - if ( ent_index > num_entries - 1 ) - { // replacement beyond the end of the list - resize(ent_index + 1); - - for ( int i = num_entries; i < max_entries; ++i ) - entry[i] = 0; - num_entries = max_entries; - - old_ent = 0; - } - else - old_ent = entry[ent_index]; - - entry[ent_index] = new_ent; - - return old_ent; - } - -int BaseList::resize(int new_size) - { - if ( new_size < num_entries ) - new_size = num_entries; // do not lose any entries - - if ( new_size != max_entries ) - { - entry = (ent*) safe_realloc((void*) entry, sizeof(ent) * new_size); - if ( entry ) - max_entries = new_size; - else - max_entries = 0; - } - - return max_entries; - } - -ent BaseList::is_member(ent e) const - { - int i; - for ( i = 0; i < length() && e != entry[i]; ++i ) - ; - - return (i == length()) ? 0 : e; - } - -int BaseList::member_pos(ent e) const - { - int i; - for ( i = 0; i < length() && e != entry[i]; ++i ) - ; - - return (i == length()) ? -1 : i; - } diff --git a/src/List.h b/src/List.h index 15e99eb0dd..0540c56354 100644 --- a/src/List.h +++ b/src/List.h @@ -20,67 +20,356 @@ // Entries must be either a pointer to the data or nonzero data with // sizeof(data) <= sizeof(void*). -#include -#include #include +#include +#include +#include #include "util.h" -typedef void* ent; typedef int (*list_cmp_func)(const void* v1, const void* v2); -class BaseList { +template +class ListIterator + { public: - void clear(); // remove all entries - int length() const { return num_entries; } - int max() const { return max_entries; } - int resize(int = 0); // 0 => size to fit current number of entries + ListIterator(T* entries, int offset, int num_entries) : + entries(entries), offset(offset), num_entries(num_entries), endptr() {} + bool operator==(const ListIterator& rhs) { return entries == rhs.entries && offset == rhs.offset; } + bool operator!=(const ListIterator& rhs) { return entries != rhs.entries || offset != rhs.offset; } + ListIterator & operator++() { offset++; return *this; } + ListIterator operator++(int) { auto t = *this; offset++; return t; } + ListIterator & operator--() { offset--; return *this; } + ListIterator operator--(int) { auto t = *this; offset--; return t; } + std::ptrdiff_t operator-(ListIterator const& sibling) const { return offset - sibling.offset; } + ListIterator & operator+=(int amount) { offset += amount; return *this; } + ListIterator & operator-=(int amount) { offset -= amount; return *this; } + bool operator<(ListIterator const&sibling) const { return offset < sibling.offset;} + bool operator<=(ListIterator const&sibling) const { return offset <= sibling.offset; } + bool operator>(ListIterator const&sibling) const { return offset > sibling.offset; } + bool operator>=(ListIterator const&sibling) const { return offset >= sibling.offset; } + T& operator[](int index) + { + if (index < num_entries) + return entries[index]; + else + return endptr; + } + T& operator*() + { + if ( offset < num_entries ) + return entries[offset]; + else + return endptr; + } - void sort(list_cmp_func cmp_func); +private: + T* const entries; + int offset; + int num_entries; + T endptr; // let this get set to some random value on purpose. It's only used + // for the operator[] and operator* cases where you pass something + // off the end of the collection, which is undefined behavior anyways. + }; - int MemoryAllocation() const - { return padded_sizeof(*this) + pad_size(max_entries * sizeof(ent)); } -protected: - ~BaseList() { free(entry); } - explicit BaseList(int = 0); - BaseList(const BaseList&); - BaseList(BaseList&&); - BaseList(const ent* arr, int n); +namespace std { + template + class iterator_traits > + { + 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; + }; +} - BaseList& operator=(const BaseList&); - BaseList& operator=(BaseList&&); - void insert(ent); // add at head of list +template +class List { +public: - // Assumes that the list is sorted and inserts at correct position. - void sortedinsert(ent, list_cmp_func cmp_func); + const int DEFAULT_LIST_SIZE = 10; + const int LIST_GROWTH_FACTOR = 2; - void append(ent); // add to end of list - ent remove(ent); // delete entry from list - ent remove_nth(int); // delete nth entry from list - ent get(); // return and remove ent at end of list - ent last() // return at end of list - { return entry[num_entries-1]; } + ~List() { free(entries); } + explicit List(int size = 0) + { + num_entries = 0; - // Return 0 if ent is not in the list, ent otherwise. - ent is_member(ent) const; + if ( size <= 0 ) + { + max_entries = 0; + entries = nullptr; + return; + } - // Returns -1 if ent is not in the list, otherwise its position. - int member_pos(ent) const; + max_entries = size; - ent replace(int, ent); // replace entry #i with a new value + entries = (T*) safe_malloc(max_entries * sizeof(T)); + } + + List(const List& b) + { + max_entries = b.max_entries; + num_entries = b.num_entries; + + if ( max_entries ) + entries = (T*) safe_malloc(max_entries * sizeof(T)); + else + entries = nullptr; + + for ( int i = 0; i < num_entries; ++i ) + entries[i] = b.entries[i]; + } + + List(List&& b) + { + entries = b.entries; + num_entries = b.num_entries; + max_entries = b.max_entries; + + b.entries = nullptr; + b.num_entries = b.max_entries = 0; + } + + List(const T* arr, int n) + { + num_entries = max_entries = n; + entries = (T*) safe_malloc(max_entries * sizeof(T)); + memcpy(entries, arr, n * sizeof(T)); + } + + List(std::initializer_list il) : List(il.begin(), il.size()) {} + + List& operator=(const List& b) + { + if ( this == &b ) + return *this; + + free(entries); + + max_entries = b.max_entries; + num_entries = b.num_entries; + + if ( max_entries ) + entries = (T *) safe_malloc(max_entries * sizeof(T)); + else + entries = nullptr; + + for ( int i = 0; i < num_entries; ++i ) + entries[i] = b.entries[i]; + + return *this; + } + + List& operator=(List&& b) + { + if ( this == &b ) + return *this; + + free(entries); + entries = b.entries; + num_entries = b.num_entries; + max_entries = b.max_entries; + + b.entries = nullptr; + b.num_entries = b.max_entries = 0; + return *this; + } // Return nth ent of list (do not remove). - ent operator[](int i) const + T& operator[](int i) const { -#ifdef SAFE_LISTS - if ( i < 0 || i > num_entries-1 ) - return 0; - else -#endif - return entry[i]; + return entries[i]; } + void clear() // remove all entries + { + free(entries); + entries = nullptr; + num_entries = max_entries = 0; + } + + int length() const { return num_entries; } + int max() const { return max_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 ) + { + entries = (T*) safe_realloc((void*) entries, sizeof(T) * new_size); + if ( entries ) + max_entries = new_size; + else + max_entries = 0; + } + + return max_entries; + } + + void sort(list_cmp_func cmp_func) + { + qsort(entries, num_entries, sizeof(T), cmp_func); + } + + int MemoryAllocation() const + { return padded_sizeof(*this) + pad_size(max_entries * sizeof(T)); } + + void insert(const T& a) // add at head of list + { + if ( num_entries == max_entries ) + resize(max_entries ? max_entries * LIST_GROWTH_FACTOR : DEFAULT_LIST_SIZE); + + for ( int i = num_entries; i > 0; --i ) + entries[i] = entries[i-1]; // move all pointers up one + + ++num_entries; + entries[0] = a; + } + + // Assumes that the list is sorted and inserts at correct position. + void sortedinsert(const T& a, list_cmp_func cmp_func) + { + // We optimize for the case that the new element is + // larger than most of the current entries. + + // First append element. + if ( num_entries == max_entries ) + resize(max_entries ? max_entries * LIST_GROWTH_FACTOR : DEFAULT_LIST_SIZE); + + entries[num_entries++] = a; + + // Then move it to the correct place. + T tmp; + for ( int i = num_entries - 1; i > 0; --i ) + { + if ( cmp_func(entries[i],entries[i-1]) <= 0 ) + break; + + tmp = entries[i]; + entries[i] = entries[i-1]; + entries[i-1] = tmp; + } + } + + void push_back(const T& a) { append(a); } + void push_front(const T& a) { insert(a); } + void pop_front() { remove_nth(0); } + void pop_back() { remove_nth(num_entries-1); } + + T& front() { return entries[0]; } + T& back() { return entries[num_entries-1]; } + + void append(const T& a) // add to end of list + { + if ( num_entries == max_entries ) + resize(max_entries ? max_entries * LIST_GROWTH_FACTOR : DEFAULT_LIST_SIZE); + + entries[num_entries++] = a; + } + + T remove(const T& a) // delete entry from list + { + int i; + for ( i = 0; i < num_entries && a != entries[i]; ++i ) + ; + + return remove_nth(i); + } + + T remove_nth(int n) // delete nth entry from list + { + assert(n >=0 && n < num_entries); + + T old_ent = entries[n]; + --num_entries; + + for ( ; n < num_entries; ++n ) + entries[n] = entries[n+1]; + + return old_ent; + } + + ZEEK_DEPRECATED("Remove in v3.1: Use back()/pop_back() instead") + T get() // return and remove ent at end of list + { + assert(num_entries > 0); + return entries[--num_entries]; + } + + ZEEK_DEPRECATED("Remove in v3.1: Use back() instead") + T& last() { return back(); } + + // Return 0 if ent is not in the list, ent otherwise. + bool is_member(const T& a) const + { + int pos = member_pos(a); + return pos != -1; + } + + // Returns -1 if ent is not in the list, otherwise its position. + int member_pos(const T& e) const + { + int i; + for ( i = 0; i < length() && e != entries[i]; ++i ) + ; + + return (i == length()) ? -1 : i; + } + + T replace(int ent_index, const T& new_ent) // replace entry #i with a new value + { + if ( ent_index < 0 ) + return 0; + + T old_ent = nullptr; + + if ( ent_index > num_entries - 1 ) + { // replacement beyond the end of the list + resize(ent_index + 1); + + for ( int i = num_entries; i < max_entries; ++i ) + entries[i] = nullptr; + num_entries = max_entries; + } + else + old_ent = entries[ent_index]; + + entries[ent_index] = new_ent; + + return old_ent; + } + + // Type traits needed for some of the std algorithms to work + using value_type = T; + + // Iterator support + using iterator = ListIterator; + using const_iterator = ListIterator; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_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: + // This could essentially be an std::vector if we wanted. Some // reasons to maybe not refactor to use std::vector ? // @@ -105,120 +394,18 @@ protected: // advantage of realloc's ability to contract in-place, it would // allocate-and-copy. - ent* entry; + T* entries; int max_entries; int num_entries; }; -// List.h -- interface for class List -// Use: to get a list of pointers to class foo you should: -// 1) typedef foo* Pfoo; (the macros don't like explicit pointers) -// 2) declare(List,Pfoo); (declare an interest in lists of Pfoo's) -// 3) variables are declared like: -// List(Pfoo) bar; (bar is of type list of Pfoo's) - -// For lists of "type". - -#define List(type) type ## List - -// For lists of pointers to "type" -#define PList(type) type ## PList - -#define Listdeclare(type) \ -struct List(type) : BaseList \ - { \ - explicit List(type)(type ...); \ - List(type)() : BaseList(0) {} \ - explicit List(type)(int sz) : BaseList(sz) {} \ - List(type)(const List(type)& l) : BaseList(l) {} \ - List(type)(List(type)&& l) : BaseList(std::move(l)) {} \ - \ - List(type)& operator=(const List(type)& l) \ - { return (List(type)&) BaseList::operator=(l); } \ - List(type)& operator=(List(type)&& l) \ - { return (List(type)&) BaseList::operator=(std::move(l)); } \ - void insert(type a) { BaseList::insert(ent(a)); } \ - void sortedinsert(type a, list_cmp_func cmp_func) \ - { BaseList::sortedinsert(ent(a), cmp_func); } \ - void append(type a) { BaseList::append(ent(a)); } \ - type remove(type a) \ - { return type(BaseList::remove(ent(a))); } \ - type remove_nth(int n) { return type(BaseList::remove_nth(n)); }\ - type get() { return type(BaseList::get()); } \ - type last() { return type(BaseList::last()); } \ - type replace(int i, type new_type) \ - { return type(BaseList::replace(i,ent(new_type))); } \ - type is_member(type e) const \ - { return type(BaseList::is_member(ent(e))); } \ - int member_pos(type e) const \ - { return BaseList::member_pos(ent(e)); } \ - \ - type operator[](int i) const \ - { return type(BaseList::operator[](i)); } \ - }; \ - -#define Listimplement(type) \ -List(type)::List(type)(type e1 ...) : BaseList() \ - { \ - append(e1); \ - va_list ap; \ - va_start(ap,e1); \ - for ( type e = va_arg(ap,type); e != 0; e = va_arg(ap,type) ) \ - append(e); \ - resize(); \ - } - -#define PListdeclare(type) \ -struct PList(type) : BaseList \ - { \ - explicit PList(type)(type* ...); \ - PList(type)() : BaseList(0) {} \ - explicit PList(type)(int sz) : BaseList(sz) {} \ - PList(type)(const PList(type)& l) : BaseList(l) {} \ - PList(type)(PList(type)&& l) : BaseList(std::move(l)) {} \ - PList(type)(std::initializer_list il) : BaseList((const ent*)il.begin(), il.size()) {} \ - \ - PList(type)& operator=(const PList(type)& l) \ - { return (PList(type)&) BaseList::operator=(l); } \ - PList(type)& operator=(PList(type)&& l) \ - { return (PList(type)&) BaseList::operator=(std::move(l)); } \ - void insert(type* a) { BaseList::insert(ent(a)); } \ - void sortedinsert(type* a, list_cmp_func cmp_func) \ - { BaseList::sortedinsert(ent(a), cmp_func); } \ - void append(type* a) { BaseList::append(ent(a)); } \ - type* remove(type* a) \ - { return (type*)BaseList::remove(ent(a)); } \ - type* remove_nth(int n) { return (type*)(BaseList::remove_nth(n)); }\ - type* get() { return (type*)BaseList::get(); } \ - type* operator[](int i) const \ - { return (type*)(BaseList::operator[](i)); } \ - type* replace(int i, type* new_type) \ - { return (type*)BaseList::replace(i,ent(new_type)); } \ - type* is_member(type* e) \ - { return (type*)BaseList::is_member(ent(e)); } \ - int member_pos(type* e) \ - { return BaseList::member_pos(ent(e)); } \ - }; \ - -#define PListimplement(type) \ -PList(type)::PList(type)(type* ep1 ...) : BaseList() \ - { \ - append(ep1); \ - va_list ap; \ - va_start(ap,ep1); \ - for ( type* ep = va_arg(ap,type*); ep != 0; \ - ep = va_arg(ap,type*) ) \ - append(ep); \ - resize(); \ - } - - -#define declare(metatype,type) metatype ## declare (type) +// Specialization of the List class to store pointers of a type. +template +using PList = List; // Popular type of list: list of strings. -declare(PList,char); -typedef PList(char) name_list; +typedef PList name_list; // Macro to visit each list element in turn. #define loop_over_list(list, iterator) \