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
16namespace webrtc {
17ListItem::ListItem(const void* item)
18    : next_(0),
19      prev_(0),
20      item_ptr_(item),
21      item_(0)
22{
23}
24
25ListItem::ListItem(const unsigned int item)
26    : next_(0),
27      prev_(0),
28      item_ptr_(0),
29      item_(item)
30{
31}
32
33ListItem::~ListItem()
34{
35}
36
37void* ListItem::GetItem() const
38{
39    return const_cast<void*>(item_ptr_);
40}
41
42unsigned int ListItem::GetUnsignedItem() const
43{
44    return item_;
45}
46
47ListWrapper::ListWrapper()
48    : critical_section_(CriticalSectionWrapper::CreateCriticalSection()),
49      first_(0),
50      last_(0),
51      size_(0)
52{
53}
54
55ListWrapper::~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
69bool ListWrapper::Empty() const
70{
71    return !first_ && !last_;
72}
73
74unsigned int ListWrapper::GetSize() const
75{
76    return size_;
77}
78
79int 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
87int 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
95int 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
103int 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
111int ListWrapper::PopFront()
112{
113    return Erase(first_);
114}
115
116int ListWrapper::PopBack()
117{
118    return Erase(last_);
119}
120
121ListItem* ListWrapper::First() const
122{
123    return first_;
124}
125
126ListItem* ListWrapper::Last() const
127{
128    return last_;
129}
130
131ListItem* ListWrapper::Next(ListItem* item) const
132{
133    if(!item)
134    {
135        return 0;
136    }
137    return item->next_;
138}
139
140ListItem* ListWrapper::Previous(ListItem* item) const
141{
142    if (!item)
143    {
144        return 0;
145    }
146    return item->prev_;
147}
148
149int 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
184int 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
221int 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
258void 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
274void 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