2 // Open Service Platform
3 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
5 // Licensed under the Apache License, Version 2.0 (the License);
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
9 // http://www.apache.org/licenses/LICENSE-2.0
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
19 * @file FBaseColLinkedList.cpp
20 * @brief This is the implementation for LinkedList class.
24 #include <unique_ptr.h>
25 #include <FBaseColLinkedList.h>
26 #include <FBaseResult.h>
27 #include <FBaseSysLog.h>
30 namespace Tizen { namespace Base { namespace Collection
38 virtual ~_ListNode(void);
43 _ListNode* pNextBlock;
47 _ListNode::_ListNode(void)
55 _ListNode::~_ListNode(void)
59 class _LinkedListEnumerator
60 : public IBidirectionalEnumerator
64 _LinkedListEnumerator(const LinkedList& list, int modCount);
66 virtual ~_LinkedListEnumerator(void);
68 virtual Object* GetCurrent(void) const;
69 virtual result MoveNext(void);
70 virtual result Reset(void);
72 virtual result MovePrevious();
73 virtual result ResetLast();
76 const LinkedList& __list;
82 _LinkedListEnumerator::_LinkedListEnumerator(const LinkedList& list, int modCount)
85 , __modCount(modCount)
89 _LinkedListEnumerator::~_LinkedListEnumerator(void)
94 _LinkedListEnumerator::GetCurrent(void) const
96 SysTryReturn(NID_BASE_COL, __modCount == __list.__modCount, null, E_INVALID_OPERATION, "[%s] The source collection was modified after the creation of this enumerator.", GetErrorMessage(E_INVALID_OPERATION));
97 SysTryReturn(NID_BASE_COL, __pNode != null, null, E_INVALID_OPERATION, "[%s] Current position is before the first element or past the last element.", GetErrorMessage(E_INVALID_OPERATION));
98 SetLastResult(E_SUCCESS);
103 _LinkedListEnumerator::MoveNext(void)
105 SysTryReturnResult(NID_BASE_COL, __modCount == __list.__modCount, E_INVALID_OPERATION, "The source collection was modified after the creation of this enumerator.");
109 __pNode = __list.__pListHead;
112 return E_OUT_OF_RANGE;
117 if (__pNode->pNext != null)
119 __pNode = __pNode->pNext;
123 return E_OUT_OF_RANGE;
131 _LinkedListEnumerator::Reset(void)
133 SysTryReturnResult(NID_BASE_COL, __modCount == __list.__modCount, E_INVALID_OPERATION, "The source collection was modified after the creation of this enumerator.");
140 _LinkedListEnumerator::MovePrevious(void)
142 SysTryReturnResult(NID_BASE_COL, __modCount == __list.__modCount, E_INVALID_OPERATION, "The source collection was modified after the creation of this enumerator.");
146 __pNode = __list.__pListTail;
149 return E_OUT_OF_RANGE;
154 if (__pNode->pPrev != null)
156 __pNode = __pNode->pPrev;
160 return E_OUT_OF_RANGE;
168 _LinkedListEnumerator::ResetLast(void)
173 LinkedList::LinkedList(DeleterFunctionType deleter)
176 , __pAvailableHead(null)
177 , __pAvailableTail(null)
183 , __pLinkedListImpl(null)
187 LinkedList::~LinkedList(void)
194 LinkedList::Add(Object* pObj)
196 SysTryReturnResult(NID_BASE_COL, pObj != null, E_INVALID_ARG, "Invalid argument used. The pObj is null");
198 result r = E_SUCCESS;
201 r = InsertFirst(pObj);
205 r = InsertLast(pObj);
210 SysLogException(NID_BASE_COL, r, "[%s] Propagating.", GetErrorMessage(r));
219 LinkedList::AddItems(const ICollection& collection)
221 result r = InsertItemsFrom(collection, __count);
224 SysLogException(NID_BASE_COL, r, "[%s] Propagating.", GetErrorMessage(r));
231 LinkedList::GetEnumeratorN(void) const
233 return GetBidirectionalEnumeratorN();
236 IBidirectionalEnumerator*
237 LinkedList::GetBidirectionalEnumeratorN() const
239 std::unique_ptr< _LinkedListEnumerator > pEnum(new (std::nothrow) _LinkedListEnumerator(*this, __modCount));
240 SysTryReturn(NID_BASE_COL, pEnum != null, null, E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY));
242 SetLastResult(E_SUCCESS);
243 return pEnum.release();
247 LinkedList::GetAt(int index) const
249 SysTryReturn(NID_BASE_COL, index >= 0 && index < __count, null, E_OUT_OF_RANGE, "[%s] The index(%d) MUST be greater than or equal to 0, and less than the number of elements(%d).", GetErrorMessage(E_OUT_OF_RANGE), index, __count);
251 _ListNode* pNode = GetNode(index);
252 SetLastResult(E_SUCCESS);
257 LinkedList::GetAt(int index)
259 SysTryReturn(NID_BASE_COL, index >= 0 && index < __count, null, E_OUT_OF_RANGE, "[%s] The index(%d) MUST be greater than or equal to 0, and less than the number of elements(%d).", GetErrorMessage(E_OUT_OF_RANGE), index, __count);
261 const Object* pObj = (static_cast< const LinkedList* >(this))->GetAt(index);
262 SetLastResult(E_SUCCESS);
263 return const_cast< Object* >(pObj);
267 LinkedList::GetItemsN(int startIndex, int count) const
269 result r = E_SUCCESS;
271 SysTryReturn(NID_BASE_COL, startIndex >= 0 && count >= 0, null, E_OUT_OF_RANGE, "[%s] Both of the startIndex(%d) and count(%d) MUST be greater than or equal to 0.", GetErrorMessage(E_OUT_OF_RANGE), startIndex, count);
272 SysTryReturn(NID_BASE_COL, startIndex < __count, null, E_OUT_OF_RANGE,
273 "[%s] The startIndex(%d) MUST be less than the number of elements(%d).", GetErrorMessage(E_OUT_OF_RANGE), startIndex, __count);
274 SysTryReturn(NID_BASE_COL, count <= __count && (startIndex + count <= __count), null, E_OUT_OF_RANGE,
275 "[%s] The startIndex(%d) + count(%d) MUST be less than or equal to the number of elements(%d).", GetErrorMessage(E_OUT_OF_RANGE), startIndex, count, __count);
277 _ListNode* pNode = GetNode(startIndex);
279 int linkedListCount = startIndex + count;
280 std::unique_ptr< LinkedList > pList(new (std::nothrow) LinkedList());
281 SysTryReturn(NID_BASE_COL, pList != null, null, E_OUT_OF_MEMORY, "[%s] Memory allocation failed.", GetErrorMessage(E_OUT_OF_MEMORY));
283 for (int i = startIndex; i < linkedListCount; i++)
285 r = pList->Add(pNode->pObj);
286 SysTryReturn(NID_BASE_COL, r == E_SUCCESS, null, r, "[%s] Propagating.", GetErrorMessage(r));
287 pNode = pNode->pNext;
290 return pList.release();
294 LinkedList::IndexOf(const Object& obj, int& index) const
296 return IndexOf(obj, 0, __count, index);
300 LinkedList::IndexOf(const Object& obj, int startIndex, int& index) const
302 SysTryReturn(NID_BASE_COL, (startIndex >= 0 && startIndex < __count), E_OUT_OF_RANGE, E_OUT_OF_RANGE, "[%s] The startIndex(%d) MUST be greater than or equal to 0, and less than the number of elements(%d).", GetErrorMessage(E_OUT_OF_RANGE), startIndex, __count);
303 return IndexOf(obj, startIndex, (__count - startIndex), index);
307 LinkedList::IndexOf(const Object& obj, int startIndex, int count, int& index) const
309 SysTryReturnResult(NID_BASE_COL, __count != 0, E_OBJ_NOT_FOUND, "The linkedlist is empty.");
310 SysTryReturnResult(NID_BASE_COL, startIndex >= 0 && count >= 0, E_OUT_OF_RANGE, "Both of the startIndex(%d) and count(%d) MUST be greater than or equal to 0.", startIndex, count);
311 SysTryReturnResult(NID_BASE_COL, startIndex < __count, E_OUT_OF_RANGE,
312 "The startIndex(%d) MUST be less than the number of elements(%d).", startIndex, __count);
313 SysTryReturnResult(NID_BASE_COL, count <= __count && (startIndex + count <= __count), E_OUT_OF_RANGE,
314 "The startIndex(%d) + count(%d) MUST be less than or equal to the number of elements(%d).", startIndex, count, __count);
316 result r = E_OBJ_NOT_FOUND;
317 _ListNode* pNode = GetNode(startIndex);
319 int linkedListCount = startIndex + count;
320 for (int i = startIndex; i < linkedListCount; i++)
322 if (pNode->pObj->Equals(obj))
328 pNode = pNode->pNext;
335 LinkedList::InsertAt(Object* pObj, int index)
337 SysTryReturnResult(NID_BASE_COL, pObj != null, E_INVALID_ARG, "Invalid argument used. The pObj is null");
338 SysTryReturnResult(NID_BASE_COL, index >= 0 && index <= __count, E_OUT_OF_RANGE, "The index(%d) MUST be greater than or equal to 0, and less than or equal to the number of elements(%d).", index, __count);
340 result r = E_SUCCESS;
343 r = InsertFirst(pObj);
345 else if (index == __count)
347 r = InsertLast(pObj);
351 _ListNode* pNode = GetNode(index - 1);
354 r = InsertNext(pObj, pNode);
360 SysLogException(NID_BASE_COL, r, "[%s] Propagating.", GetErrorMessage(r));
369 LinkedList::InsertItemsFrom(const ICollection& collection, int startIndex)
371 SysTryReturn(NID_BASE_COL, startIndex >= 0 && startIndex <= __count, E_OUT_OF_RANGE, E_OUT_OF_RANGE, "[%s] The startIndex(%d) MUST be greater than or equal to 0, and less than or equal to the number of elements(%d).", GetErrorMessage(E_OUT_OF_RANGE), startIndex, __count);
373 result r = E_SUCCESS;
374 int insertingCount = collection.GetCount();
376 if (insertingCount <= 0)
381 int available = __capacity - __count;
382 if (available < insertingCount)
384 r = AddBlock(insertingCount - available);
385 SysTryReturnResult(NID_BASE_COL, r == E_SUCCESS, r, "[%s] Propagating.", GetErrorMessage(r));
388 std::unique_ptr< IEnumerator > pEnum(collection.GetEnumeratorN());
389 SysTryReturnResult(NID_BASE_COL, pEnum != null, GetLastResult(), "Propagating.");
395 r = pEnum->MoveNext();
396 // enumerator is reached to the end of collection
397 if (E_OUT_OF_RANGE == r)
402 SysTryReturnResult(NID_BASE_COL, r == E_SUCCESS, r, "Propagating.");
404 Object* pObj = pEnum->GetCurrent();
405 SysTryReturnResult(NID_BASE_COL, pObj != null, GetLastResult(), "Propagating.");
407 r = InsertAt(pObj, startIndex++);
408 SysTryReturnResult(NID_BASE_COL, r == E_SUCCESS, r, "Propagating.");
415 LinkedList::LastIndexOf(const Object& obj, int& index) const
417 _ListNode* pNode = __pListTail;
418 for (int i = (__count - 1); i >= 0; i--)
420 if (pNode->pObj->Equals(obj))
425 pNode = pNode->pPrev;
428 SysLogException(NID_BASE_COL, E_OBJ_NOT_FOUND, "The object is not in the list.");
429 return E_OBJ_NOT_FOUND;
433 LinkedList::Remove(const Object& obj)
435 _ListNode* pNode = __pListHead;
436 for (int i = 0; i < __count; i++)
438 if (pNode->pObj->Equals(obj))
445 pNode = pNode->pNext;
448 SysLogException(NID_BASE_COL, E_OBJ_NOT_FOUND, "The object is not in the list.");
449 return E_OBJ_NOT_FOUND;
453 LinkedList::RemoveAt(int index)
455 SysTryReturnResult(NID_BASE_COL, index < __count && index >= 0, E_OUT_OF_RANGE, "The index(%d) MUST be greater than or equal to 0, and less than the number of elements(%d).", index, __count);
458 _ListNode* pNode = GetNode(index);
466 LinkedList::RemoveItems(int startIndex, int count)
468 SysTryReturnResult(NID_BASE_COL, startIndex >= 0 && count >= 0, E_OUT_OF_RANGE, "Both of the startIndex(%d) and count(%d) MUST be greater than or equal to 0.", startIndex, count);
469 SysTryReturnResult(NID_BASE_COL, startIndex < __count, E_OUT_OF_RANGE,
470 "The startIndex(%d) MUST be less than the number of elements(%d).", startIndex, __count);
471 SysTryReturnResult(NID_BASE_COL, count <= __count && (startIndex + count <= __count), E_OUT_OF_RANGE,
472 "The startIndex(%d) + count(%d) MUST be less than or equal to the number of elements(%d).", startIndex, count, __count);
475 _ListNode* pNode = GetNode(startIndex);
477 int linkedListCount = startIndex + count;
478 for (int i = startIndex; i < linkedListCount; i++)
480 _ListNode* pNextNode = pNode->pNext;
490 LinkedList::RemoveItems(const ICollection& collection)
492 result r = E_SUCCESS;
493 std::unique_ptr< IEnumerator > pEnum(collection.GetEnumeratorN());
494 SysTryReturnResult(NID_BASE_COL, pEnum != null, GetLastResult(), "Propagating.");
498 r = pEnum->MoveNext();
499 // enumerator is reached to the end of collection
500 if (E_OUT_OF_RANGE == r)
505 SysTryReturnResult(NID_BASE_COL, r == E_SUCCESS, r, "Propagating.");
507 Object* pTemp = pEnum->GetCurrent();
508 SysTryReturnResult(NID_BASE_COL, pTemp != null, GetLastResult(), "Propagating.");
511 SysTryLog(NID_BASE_COL, !IsFailed(r), "[%s] Propagating.", GetErrorMessage(r));
518 LinkedList::RemoveAll()
522 if (__pListHead == null)
530 for (_ListNode* pNode = __pListHead; pNode != __pListTail; pNode = pNode->pNext)
532 __deleter(pNode->pObj);
536 if (__pListTail != null)
538 __deleter(__pListTail->pObj);
539 __pListTail->pObj = null;
542 if (__pAvailableHead == null)
544 __pAvailableHead = __pListHead;
545 __pAvailableTail = __pListTail;
549 __pAvailableTail->pNext = __pListHead;
550 __pListHead->pPrev = __pAvailableTail;
551 __pAvailableTail = __pListTail;
560 LinkedList::SetAt(Object* pObj, int index)
562 SysTryReturnResult(NID_BASE_COL, pObj != null, E_INVALID_ARG, "Invalid argument used. The pObj is null");
563 SysTryReturnResult(NID_BASE_COL, index >= 0 && index < __count, E_OUT_OF_RANGE, "The index(%d) MUST be greater than or equal to 0, less than the number of elements(%d).", index, __count);
566 _ListNode* pNode = GetNode(index);
568 __deleter(pNode->pObj);
576 LinkedList::Sort(const IComparer& comparer)
584 arrayList.Construct(*this);
586 result r = arrayList.Sort(comparer);
587 SysTryReturnResult(NID_BASE_COL, r == E_SUCCESS, r, "Propagating.");
589 std::unique_ptr< IEnumerator > pEnum(arrayList.GetEnumeratorN());
590 SysTryReturnResult(NID_BASE_COL, pEnum != null, GetLastResult(), "Propagating.");
592 _ListNode* pNode = GetNode(0);
594 while (pEnum->MoveNext() == E_SUCCESS)
596 Object* pItem = pEnum->GetCurrent();
597 SysTryReturnResult(NID_BASE_COL, pItem != null, GetLastResult(), "Propagating.");
600 pNode = pNode->pNext;
601 SysTryReturnResult(NID_BASE_COL, pNode != null, GetLastResult(), "Propagating.");
608 LinkedList::GetCount(void) const
614 LinkedList::Contains(const Object& obj) const
621 _ListNode* pNode = GetNode(0);
623 while (pNode != null)
625 if (pNode->pObj->Equals(obj))
629 pNode = pNode->pNext;
636 LinkedList::ContainsAll(const ICollection& collection) const
638 result r = E_SUCCESS;
641 if (collection.GetCount() == 0)
646 std::unique_ptr< IEnumerator > pEnum(collection.GetEnumeratorN());
647 SysTryReturn(NID_BASE_COL, pEnum != null, false, GetLastResult(), "[%s] Propagating.", GetErrorMessage(GetLastResult()));
649 while ((r = pEnum->MoveNext()) != E_OUT_OF_RANGE)
651 SysTryReturn(NID_BASE_COL, r == E_SUCCESS, false, r, "[%s] Propagating.", GetErrorMessage(r));
653 Object* pTemp = pEnum->GetCurrent();
654 SysTryReturn(NID_BASE_COL, pTemp != null, false, GetLastResult(), "[%s] Propagating.", GetErrorMessage(GetLastResult()));
656 if (!Contains(*pTemp))
666 LinkedList::Equals(const Object& obj) const
673 const LinkedList* pOther = dynamic_cast< const LinkedList* >(&obj);
678 else if (__count != pOther->__count)
684 _ListNode* pNode = __pListHead;
685 _ListNode* pOtherNode = pOther->__pListHead;
686 for (int i = 0; i < __count; i++)
688 if (!(pNode->pObj->Equals(*(pOtherNode->pObj))))
693 pNode = pNode->pNext;
694 pOtherNode = pOtherNode->pNext;
702 LinkedList::GetHashCode(void) const
705 _ListNode* pNode = __pListHead;
706 for (int i = 0; i < __count; i++)
708 hash += pNode->pObj->GetHashCode();
709 pNode = pNode->pNext;
716 LinkedList::GetDeleter(void) const
722 LinkedList::AddBlock(int blockSize)
724 result r = E_SUCCESS;
726 _ListNode* pNode = new (std::nothrow) _ListNode[blockSize];
727 SysTryReturnResult(NID_BASE_COL, pNode != null, E_OUT_OF_MEMORY, "Memory allocation failed.");
730 for (int i = 0; i < blockSize - 1; i++)
732 pNode[i].pNext = &pNode[i + 1];
733 pNode[i + 1].pPrev = &pNode[i];
737 if (__pBlocks == null)
743 _ListNode* pBlock = __pBlocks;
744 while (pBlock->pNextBlock != null)
746 pBlock = pBlock->pNextBlock;
748 pBlock->pNextBlock = pNode;
751 // add to available nodes
752 if (__pAvailableHead == null)
754 __pAvailableHead = pNode;
758 __pAvailableTail->pNext = pNode;
759 pNode->pPrev = __pAvailableTail;
761 __pAvailableTail = &pNode[blockSize - 1];
763 __capacity += blockSize;
769 LinkedList::DeleteBlock(void)
771 while (__pBlocks != null)
773 _ListNode* pNode = __pBlocks->pNextBlock;
780 LinkedList::InsertFirst(Object* pObj)
782 if (__count == __capacity)
784 result r = AddBlock();
785 SysTryReturnResult(NID_BASE_COL, r == E_SUCCESS, r, "Propagating.");
788 _ListNode* pNode = GetNewNode();
792 if (__pListHead == null)
799 pNode->pNext = __pListHead;
800 __pListHead->pPrev = pNode;
809 LinkedList::InsertLast(Object* pObj)
811 if (__count == __capacity)
813 result r = AddBlock();
814 SysTryReturnResult(NID_BASE_COL, r == E_SUCCESS, r, "Propagating.");
817 _ListNode* pNode = GetNewNode();
820 if (__pListHead == null)
827 pNode->pPrev = __pListTail;
828 __pListTail->pNext = pNode;
838 LinkedList::InsertNext(Object* pObj, _ListNode* pPrevNode)
840 SysTryReturnResult(NID_BASE_COL, pPrevNode != null, E_INVALID_ARG, "pPrevNode is null.");
842 if (__count == __capacity)
844 result r = AddBlock();
845 SysTryReturnResult(NID_BASE_COL, r == E_SUCCESS, r, "Propagating.");
848 _ListNode* pNode = GetNewNode();
851 pNode->pPrev = pPrevNode;
852 pNode->pNext = pPrevNode->pNext;
854 pPrevNode->pNext->pPrev = pNode;
855 pPrevNode->pNext = pNode;
863 LinkedList::GetNewNode(void)
865 SysTryReturn(NID_BASE_COL, __pAvailableHead != null, null, E_INVALID_STATE, "[%s] There is no available node.", GetErrorMessage(E_INVALID_STATE));
867 _ListNode* pNode = __pAvailableHead;
869 if (__pAvailableHead == __pAvailableTail)
871 __pAvailableHead = null;
872 __pAvailableTail = null;
876 __pAvailableHead = __pAvailableHead->pNext;
877 __pAvailableHead->pPrev = null;
887 LinkedList::GetNode(int index) const
889 _ListNode* pNode = null;
890 if (index > static_cast< int >(__count / 2))
893 for (int i = __count - 1; i > index; i--)
895 pNode = pNode->pPrev;
901 for (int i = 0; i < index; i++)
903 pNode = pNode->pNext;
911 LinkedList::RemoveNode(_ListNode* pNode)
914 if (pNode == __pListHead)
916 __pListHead = pNode->pNext;
917 if (__pListHead != null)
919 __pListHead->pPrev = null;
926 else if (pNode == __pListTail)
928 __pListTail = pNode->pPrev;
929 __pListTail->pNext = null;
933 pNode->pNext->pPrev = pNode->pPrev;
934 pNode->pPrev->pNext = pNode->pNext;
940 __deleter(pNode->pObj);
943 // add to available list
944 if (__pAvailableHead == null)
946 __pAvailableHead = pNode;
947 __pAvailableTail = pNode;
951 __pAvailableTail->pNext = pNode;
952 pNode->pPrev = __pAvailableTail;
953 __pAvailableTail = pNode;
958 LinkedList::SetDeleter(DeleterFunctionType deleter)
963 } } } // Tizen::Base::Collection