1 // Copyright 2018 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #pragma once
6 
7 #include <fbl/alloc_checker.h>
8 #include <fbl/intrusive_double_list.h>
9 #include <fbl/string.h>
10 #include <fbl/unique_ptr.h>
11 
12 namespace fuzzing {
13 
14 // |fuzzing::StringList| is a small wrapper class used to make C-style strings easy to store and
15 // manipulate in a |fbl::DoublyLinkedList|.
16 class StringList final {
17 public:
18     StringList();
19     StringList(const char* const* elements, size_t num_elements);
20     ~StringList();
21 
22     // Identical to |fbl::DoublyLinkedList<fbl::unique_ptr<StringElement>>::is_empty|.
23     bool is_empty() const;
24 
25     // Identical to |fbl::DoublyLinkedList<fbl::unique_ptr<StringElement>>::size_slow|.
26     size_t length() const;
27 
28     // These methods are similar to |fbl::DoublyLinkedList|'s, except that take raw C strings and
29     // abstract away the process of wrapping them in the |StringElement| structure defined below.
30     void push_front(const char* str);
31     void push_back(const char* str);
push_front(const fbl::String & str)32     void push_front(const fbl::String& str) { return push_front(str.c_str()); }
push_back(const fbl::String & str)33     void push_back(const fbl::String& str) { return push_back(str.c_str()); }
34 
35     // These methods are similar to |fbl::DoublyLinkedList|'s, except that they apply a simple
36     // substring pattern match instead of taking a functor.  Empty strings match everything, while
37     // null inputs leave the list unchanged.
38 
39     // Keeps elements if they **CONTAIN** |substr|.  Null strings leave the list unchanged.
40     void keep_if(const char* substr);
keep_if(const fbl::String & substr)41     void keep_if(const fbl::String& substr) { return keep_if(substr.c_str()); }
42 
43     // Keeps elements if they contain at least one element of |substrs|.
44     void keep_if_any(StringList* substrs);
45 
46     // Keeps elements if they contain every element of |substrs|.
47     void keep_if_all(StringList* substrs);
48 
49     // Removes elements if they exactly **MATCH** |match|.  Null strings leave the list unchanged.
50     void erase_if(const char* match);
erase_if(const fbl::String & match)51     void erase_if(const fbl::String& match) { return erase_if(match.c_str()); }
52 
53     // In place of iterators, this class provides |first| and |next| methods.  The former resets the
54     // internal iterator to the beginning of the list, while the latter returns successive elements
55     // with each successive call until it reaches the end of the list and returns null.  The list
56     // can be simply iterated by:
57     // for(const char *s = list.first(); s; s = list.next()) { ... }
58     const char* first();
59     const char* next();
60 
61     // Like|fbl::DoublyLinkedList<fbl::unique_ptr<StringElement>>::clear|, but also resets the
62     // internal iterator.
63     void clear();
64 
65 private:
66     DISALLOW_COPY_ASSIGN_AND_MOVE(StringList);
67 
68     // |fuzzing::StringList::StringElement| is an internal intrusive container used to back the
69     // strings in the list.
70     struct StringElement final : public fbl::DoublyLinkedListable<fbl::unique_ptr<StringElement>> {
71         fbl::String str_;
72     };
73 
74     // Implements |push_front| and |push_back| above, depending on the value of |front|.
75     void push(const char* str, bool front);
76 
77     // The actual list elements, and an iterator to return the |next| one.
78     using List = fbl::DoublyLinkedList<fbl::unique_ptr<StringElement>>;
79     List elements_;
80     List::iterator iterator_;
81 };
82 
83 } // namespace fuzzing
84