Line data Source code
1 : // Copyright 2024 Accenture. 2 : 3 : #include <estd/forward_list.h> 4 : #include <estd/slice.h> 5 : #include <estd/vector.h> 6 : 7 : #include <gmock/gmock.h> 8 : 9 : namespace 10 : { 11 : // EXAMPLE_START:forward_list 12 : /** 13 : * Wrapper for linked list of integers. 14 : */ 15 : class IntNode : public ::estd::forward_list_node<IntNode> 16 : { 17 : int _i; 18 : 19 : public: 20 1 : explicit IntNode(int const i) : _i(i) {} 21 : 22 2 : int getI() const { return _i; } 23 : }; 24 : 25 1 : void fillAndPrintList() 26 : { 27 : // Create two example nodes. 28 1 : IntNode a(1); 29 1 : IntNode b(2); 30 : 31 : // Create list of IntNodes. 32 1 : estd::forward_list<IntNode> list; 33 : // Add nodes to the list. 34 1 : list.push_front(a); 35 1 : list.push_front(b); 36 : 37 : // Iterate over list and print values. 38 1 : estd::forward_list<IntNode>::const_iterator i; 39 3 : for (i = list.cbegin(); i != list.cend(); ++i) 40 : { 41 2 : printf("Item = %d\n", i->getI()); 42 : } 43 1 : } 44 : 45 : // EXAMPLE_END:forward_list 46 : 47 : // EXAMPLE_START:forward_list_multiple_lists 48 : 49 : /** 50 : * Interface for a timeout. 51 : */ 52 1 : struct ITimeout : ::estd::forward_list_node<ITimeout> 53 : { 54 : /** Function to call, when isExpired() returns true */ 55 : virtual void expired() = 0; 56 : 57 : /** Returns true if a timeout is expired, false otherwise */ 58 : virtual bool isExpired() = 0; 59 : }; 60 : 61 : /** 62 : * Interface for a runnable. 63 : */ 64 1 : struct IRunnable : ::estd::forward_list_node<IRunnable> 65 : { 66 : virtual void run() = 0; 67 : }; 68 : 69 : using Timeouts = ::estd::forward_list<ITimeout>; 70 : 71 1 : void registerTimeout(Timeouts& timeouts, ITimeout& timeout) { timeouts.push_front(timeout); } 72 : 73 : using Runnables = ::estd::forward_list<IRunnable>; 74 : 75 1 : void registerRunnable(Runnables& runnables, IRunnable& runnable) { runnables.push_front(runnable); } 76 : 77 1 : struct MyClass 78 : : ITimeout 79 : , IRunnable 80 : { 81 : void expired() override; 82 : 83 : bool isExpired() override; 84 : 85 : void run() override; 86 : }; 87 : 88 1 : void twoListExample(MyClass& worker, Timeouts& timeouts, Runnables& runnables) 89 : { 90 : // Register worker to two list. 91 1 : registerTimeout(timeouts, worker); 92 1 : registerRunnable(runnables, worker); 93 : } 94 : 95 : // EXAMPLE_END:forward_list_multiple_lists 96 0 : void MyClass::expired() {} 97 : 98 0 : bool MyClass::isExpired() { return true; } 99 : 100 0 : void MyClass::run() {} 101 : 102 : struct ITimeoutMock : ITimeout 103 : { 104 5 : MOCK_METHOD0(expired, void()); 105 6 : MOCK_METHOD0(isExpired, bool()); 106 : }; 107 : 108 : // EXAMPLE_START:forward_list_move_between_lists 109 1 : void callExpiredTimeouts(::estd::forward_list<ITimeout>& timeouts) 110 : { 111 : // List of expired timeouts. 112 1 : ::estd::forward_list<ITimeout> expired{}; 113 : // Maintain two iterators: one pointing to the actual element and one preceding it to be 114 : // used for erasing it from the list. 115 1 : auto itr = timeouts.begin(); 116 1 : auto before = timeouts.before_begin(); 117 : // Iterate over all timeouts in list. 118 4 : while (itr != timeouts.end()) 119 : { 120 : // Check if timeout is expired. 121 3 : if (itr->isExpired()) 122 : { 123 : // Keep reference to expired timeout. 124 2 : ITimeout& t = *itr; 125 : // Erase timeout from list by calling erase_after on before iterator. 126 : // itr points to element after the erased one, before stays as is. 127 2 : itr = timeouts.erase_after(before); 128 : // Move expired timeout to expired list 129 2 : expired.push_front(t); 130 : } 131 : else 132 : { 133 : // Adjust iterators. 134 5 : before = itr++; 135 : } 136 : } 137 : // Notify all expired timeouts. 138 3 : for (auto&& itr : expired) 139 : { 140 2 : itr.expired(); 141 : } 142 1 : } 143 : 144 : // EXAMPLE_END:forward_list_move_between_lists 145 : 146 3 : TEST(ForwardListExample, expired) 147 : { 148 1 : using namespace ::testing; 149 1 : ITimeoutMock t1, t2, t3; 150 2 : EXPECT_CALL(t1, isExpired).WillOnce(Return(true)); 151 2 : EXPECT_CALL(t2, isExpired).WillOnce(Return(false)); 152 2 : EXPECT_CALL(t3, isExpired).WillOnce(Return(true)); 153 2 : EXPECT_CALL(t1, expired).Times(1); 154 2 : EXPECT_CALL(t2, expired).Times(0); 155 2 : EXPECT_CALL(t3, expired).Times(1); 156 1 : ::estd::forward_list<ITimeout> timeouts; 157 1 : timeouts.push_front(t3); 158 1 : timeouts.push_front(t2); 159 1 : timeouts.push_front(t1); 160 1 : callExpiredTimeouts(timeouts); 161 2 : ASSERT_EQ(1, timeouts.size()); 162 1 : ASSERT_FALSE(::estd::is_in_use(t1)); 163 1 : ASSERT_TRUE(::estd::is_in_use(t2)); 164 2 : ASSERT_FALSE(::estd::is_in_use(t3)); 165 1 : } 166 : 167 3 : TEST(forward_list, run_examples) 168 : { 169 1 : MyClass worker; 170 1 : Timeouts timeouts; 171 1 : Runnables runnables; 172 1 : twoListExample(worker, timeouts, runnables); 173 1 : fillAndPrintList(); 174 2 : } 175 : 176 : namespace vector 177 : { 178 : 179 : // EXAMPLE_START:forward_list_vs_vector_1 180 : struct ICanFrameListener 181 : { 182 : virtual void frameReceived(uint32_t id, ::estd::slice<uint8_t> payload) = 0; 183 : }; 184 : 185 : class CanFrameNotifier 186 : { 187 : // Room for at most 10 listeners. 188 : ::estd::declare::vector<ICanFrameListener*, 10> _listeners; 189 : 190 : public: 191 : bool addListener(ICanFrameListener& listener) 192 : { 193 : // Check if listener can be added. 194 : if (_listeners.full()) 195 : { 196 : return false; 197 : } 198 : // Add listener to list. 199 : _listeners.emplace_back().construct(&listener); 200 : return true; 201 : } 202 : }; 203 : 204 : // EXAMPLE_END:forward_list_vs_vector_1 205 : } // namespace vector 206 : 207 : namespace forward_list 208 : { 209 : // EXAMPLE_START:forward_list_vs_vector_2 210 : struct ICanFrameListener : public ::estd::forward_list_node<ICanFrameListener> 211 : { 212 : virtual void frameReceived(uint32_t id, ::estd::slice<uint8_t> payload) = 0; 213 : }; 214 : 215 : class CanFrameNotifier 216 : { 217 : // List of listeners 218 : ::estd::forward_list<ICanFrameListener> _listeners; 219 : 220 : public: 221 : void addListener(ICanFrameListener& listener) 222 : { 223 : // Add listener to list. 224 : _listeners.push_front(listener); 225 : } 226 : }; 227 : 228 : // EXAMPLE_END:forward_list_vs_vector_2 229 : } // namespace forward_list 230 : 231 : } // namespace