1 /*
2  *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "list_wrapper.h"
12 
13 #include "critical_section_wrapper.h"
14 #include "trace.h"
15 
16 namespace webrtc {
ListItem(const void * item)17 ListItem::ListItem(const void* item)
18     : next_(0),
19       prev_(0),
20       item_ptr_(item),
21       item_(0)
22 {
23 }
24 
ListItem(const unsigned int item)25 ListItem::ListItem(const unsigned int item)
26     : next_(0),
27       prev_(0),
28       item_ptr_(0),
29       item_(item)
30 {
31 }
32 
~ListItem()33 ListItem::~ListItem()
34 {
35 }
36 
GetItem() const37 void* ListItem::GetItem() const
38 {
39     return const_cast<void*>(item_ptr_);
40 }
41 
GetUnsignedItem() const42 unsigned int ListItem::GetUnsignedItem() const
43 {
44     return item_;
45 }
46 
ListWrapper()47 ListWrapper::ListWrapper()
48     : critical_section_(CriticalSectionWrapper::CreateCriticalSection()),
49       first_(0),
50       last_(0),
51       size_(0)
52 {
53 }
54 
~ListWrapper()55 ListWrapper::~ListWrapper()
56 {
57     if (!Empty())
58     {
59         // TODO (hellner) I'm not sure this loggin is useful.
60         WEBRTC_TRACE(kTraceMemory, kTraceUtility, -1,
61                    "Potential memory leak in ListWrapper");
62         // Remove all remaining list items.
63         while (Erase(First()) == 0)
64         {}
65     }
66     delete critical_section_;
67 }
68 
Empty() const69 bool ListWrapper::Empty() const
70 {
71     return !first_ && !last_;
72 }
73 
GetSize() const74 unsigned int ListWrapper::GetSize() const
75 {
76     return size_;
77 }
78 
PushBack(const void * ptr)79 int ListWrapper::PushBack(const void* ptr)
80 {
81     ListItem* item = new ListItem(ptr);
82     CriticalSectionScoped lock(critical_section_);
83     PushBackImpl(item);
84     return 0;
85 }
86 
PushBack(const unsigned int item_id)87 int ListWrapper::PushBack(const unsigned int item_id)
88 {
89     ListItem* item = new ListItem(item_id);
90     CriticalSectionScoped lock(critical_section_);
91     PushBackImpl(item);
92     return 0;
93 }
94 
PushFront(const unsigned int item_id)95 int ListWrapper::PushFront(const unsigned int item_id)
96 {
97     ListItem* item = new ListItem(item_id);
98     CriticalSectionScoped lock(critical_section_);
99     PushFrontImpl(item);
100     return 0;
101 }
102 
PushFront(const void * ptr)103 int ListWrapper::PushFront(const void* ptr)
104 {
105     ListItem* item = new ListItem(ptr);
106     CriticalSectionScoped lock(critical_section_);
107     PushFrontImpl(item);
108     return 0;
109 }
110 
PopFront()111 int ListWrapper::PopFront()
112 {
113     return Erase(first_);
114 }
115 
PopBack()116 int ListWrapper::PopBack()
117 {
118     return Erase(last_);
119 }
120 
First() const121 ListItem* ListWrapper::First() const
122 {
123     return first_;
124 }
125 
Last() const126 ListItem* ListWrapper::Last() const
127 {
128     return last_;
129 }
130 
Next(ListItem * item) const131 ListItem* ListWrapper::Next(ListItem* item) const
132 {
133     if(!item)
134     {
135         return 0;
136     }
137     return item->next_;
138 }
139 
Previous(ListItem * item) const140 ListItem* ListWrapper::Previous(ListItem* item) const
141 {
142     if (!item)
143     {
144         return 0;
145     }
146     return item->prev_;
147 }
148 
Insert(ListItem * existing_previous_item,ListItem * new_item)149 int ListWrapper::Insert(ListItem* existing_previous_item, ListItem* new_item)
150 {
151     if (!new_item)
152     {
153         return -1;
154     }
155     // Allow existing_previous_item to be NULL if the list is empty.
156     // TODO (hellner) why allow this? Keep it as is for now to avoid
157     // breaking API contract.
158     if (!existing_previous_item && !Empty())
159     {
160         return -1;
161     }
162     CriticalSectionScoped lock(critical_section_);
163     if (!existing_previous_item)
164     {
165         PushBackImpl(new_item);
166         return 0;
167     }
168     ListItem* next_item = existing_previous_item->next_;
169     new_item->next_ = existing_previous_item->next_;
170     new_item->prev_ = existing_previous_item;
171     existing_previous_item->next_ = new_item;
172     if (next_item)
173     {
174         next_item->prev_ = new_item;
175     }
176     else
177     {
178         last_ = new_item;
179     }
180     size_++;
181     return 0;
182 }
183 
InsertBefore(ListItem * existing_next_item,ListItem * new_item)184 int ListWrapper::InsertBefore(ListItem* existing_next_item,
185                               ListItem* new_item)
186 {
187     if (!new_item)
188     {
189         return -1;
190     }
191     // Allow existing_next_item to be NULL if the list is empty.
192     // Todo: why allow this? Keep it as is for now to avoid breaking API
193     // contract.
194     if (!existing_next_item && !Empty())
195     {
196         return -1;
197     }
198     CriticalSectionScoped lock(critical_section_);
199     if (!existing_next_item)
200     {
201         PushBackImpl(new_item);
202         return 0;
203     }
204 
205     ListItem* previous_item = existing_next_item->prev_;
206     new_item->next_ = existing_next_item;
207     new_item->prev_ = previous_item;
208     existing_next_item->prev_ = new_item;
209     if (previous_item)
210     {
211         previous_item->next_ = new_item;
212     }
213     else
214     {
215         first_ = new_item;
216     }
217     size_++;
218     return 0;
219 }
220 
Erase(ListItem * item)221 int ListWrapper::Erase(ListItem* item)
222 {
223     if (!item)
224     {
225         return -1;
226     }
227     size_--;
228     ListItem* previous_item = item->prev_;
229     ListItem* next_item = item->next_;
230     if (!previous_item)
231     {
232         if(next_item)
233         {
234             next_item->prev_ = 0;
235         }
236         first_ = next_item;
237     }
238     else
239     {
240         previous_item->next_ = next_item;
241     }
242     if (!next_item)
243     {
244         if(previous_item)
245         {
246             previous_item->next_ = 0;
247         }
248         last_ = previous_item;
249     }
250     else
251     {
252         next_item->prev_ = previous_item;
253     }
254     delete item;
255     return 0;
256 }
257 
PushBackImpl(ListItem * item)258 void ListWrapper::PushBackImpl(ListItem* item)
259 {
260     if (Empty())
261     {
262         first_ = item;
263         last_ = item;
264         size_++;
265         return;
266     }
267 
268     item->prev_ = last_;
269     last_->next_ = item;
270     last_ = item;
271     size_++;
272 }
273 
PushFrontImpl(ListItem * item)274 void ListWrapper::PushFrontImpl(ListItem* item)
275 {
276     if (Empty())
277     {
278         first_ = item;
279         last_ = item;
280         size_++;
281         return;
282     }
283 
284     item->next_ = first_;
285     first_->prev_ = item;
286     first_ = item;
287     size_++;
288 }
289 } //namespace webrtc
290