summaryrefslogtreecommitdiff
path: root/src/utilcode/arraylist.cpp
diff options
context:
space:
mode:
authordotnet-bot <dotnet-bot@microsoft.com>2015-01-30 14:14:42 -0800
committerdotnet-bot <dotnet-bot@microsoft.com>2015-01-30 14:14:42 -0800
commitef1e2ab328087c61a6878c1e84f4fc5d710aebce (patch)
treedee1bbb89e9d722e16b0d1485e3cdd1b6c8e2cfa /src/utilcode/arraylist.cpp
downloadcoreclr-ef1e2ab328087c61a6878c1e84f4fc5d710aebce.tar.gz
coreclr-ef1e2ab328087c61a6878c1e84f4fc5d710aebce.tar.bz2
coreclr-ef1e2ab328087c61a6878c1e84f4fc5d710aebce.zip
Initial commit to populate CoreCLR repo
[tfs-changeset: 1407945]
Diffstat (limited to 'src/utilcode/arraylist.cpp')
-rw-r--r--src/utilcode/arraylist.cpp311
1 files changed, 311 insertions, 0 deletions
diff --git a/src/utilcode/arraylist.cpp b/src/utilcode/arraylist.cpp
new file mode 100644
index 0000000000..801ab98f54
--- /dev/null
+++ b/src/utilcode/arraylist.cpp
@@ -0,0 +1,311 @@
+//
+// Copyright (c) Microsoft. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+//
+
+#include "stdafx.h"
+
+#include "arraylist.h"
+#include "utilcode.h"
+#include "ex.h"
+
+//
+// ArrayList is a simple class which is used to contain a growable
+// list of pointers, stored in chunks. Modification is by appending
+// only currently. Access is by index (efficient if the number of
+// elements stays small) and iteration (efficient in all cases).
+//
+// An important property of an ArrayList is that the list remains
+// coherent while it is being modified (appended to). This means that readers
+// never need to lock when accessing it. (Locking is necessary among multiple
+// writers, however.)
+//
+
+void ArrayListBase::Clear()
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ FORBID_FAULT;
+ }
+ CONTRACTL_END
+
+ ArrayListBlock *block = m_firstBlock.m_next;
+ while (block != NULL)
+ {
+ ArrayListBlock *next = block->m_next;
+ delete [] block;
+ block = next;
+ }
+ m_firstBlock.m_next = 0;
+ m_count = 0;
+}
+
+PTR_VOID * ArrayListBase::GetPtr(DWORD index) const
+{
+ STATIC_CONTRACT_NOTHROW;
+ STATIC_CONTRACT_FORBID_FAULT;
+ STATIC_CONTRACT_SO_TOLERANT;
+ STATIC_CONTRACT_CANNOT_TAKE_LOCK;
+ SUPPORTS_DAC;
+
+ _ASSERTE(index < m_count);
+
+ ArrayListBlock *b = (ArrayListBlock*)&m_firstBlock;
+ while (index >= b->m_blockSize)
+ {
+ PREFIX_ASSUME(b->m_next != NULL);
+ index -= b->m_blockSize;
+ b = b->m_next;
+ }
+
+ return b->m_array + index;
+}
+
+#ifndef DACCESS_COMPILE
+
+HRESULT ArrayListBase::Append(void *element)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ INJECT_FAULT(return E_OUTOFMEMORY;);
+ }
+ CONTRACTL_END
+
+ ArrayListBlock *b = (ArrayListBlock*)&m_firstBlock;
+ DWORD count = m_count;
+
+ while (count >= b->m_blockSize)
+ {
+ count -= b->m_blockSize;
+
+ if (b->m_next == NULL)
+ {
+ _ASSERTE(count == 0);
+
+ DWORD nextSize = b->m_blockSize * 2;
+
+ ArrayListBlock *bNew = (ArrayListBlock *)
+ new (nothrow) BYTE [sizeof(ArrayListBlock) + nextSize * sizeof(void*)];
+
+ if (bNew == NULL)
+ return E_OUTOFMEMORY;
+
+ bNew->m_next = NULL;
+ bNew->m_blockSize = nextSize;
+
+ b->m_next = bNew;
+ }
+
+ b = b->m_next;
+ }
+
+ b->m_array[count] = element;
+
+ m_count++;
+
+ return S_OK;
+}
+
+#endif // #ifndef DACCESS_COMPILE
+
+DWORD ArrayListBase::FindElement(DWORD start, PTR_VOID element) const
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ FORBID_FAULT;
+ }
+ CONTRACTL_END
+
+ DWORD index = start;
+
+ _ASSERTE(index <= m_count);
+
+ ArrayListBlock *b = (ArrayListBlock*)&m_firstBlock;
+
+ //
+ // Skip to the block containing start.
+ // index should be the index of start in the block.
+ //
+
+ while (b != NULL && index >= b->m_blockSize)
+ {
+ index -= b->m_blockSize;
+ b = b->m_next;
+ }
+
+ //
+ // Adjust start to be the index of the start of the block
+ //
+
+ start -= index;
+
+ //
+ // Compute max number of entries from the start of the block
+ //
+
+ DWORD max = m_count - start;
+
+ while (b != NULL)
+ {
+ //
+ // Compute end of search in this block - either end of the block
+ // or end of the array
+ //
+
+ DWORD blockMax;
+ if (max < b->m_blockSize)
+ blockMax = max;
+ else
+ blockMax = b->m_blockSize;
+
+ //
+ // Scan for element, until the end.
+ //
+
+ while (index < blockMax)
+ {
+ if (b->m_array[index] == element)
+ return start + index;
+ index++;
+ }
+
+ //
+ // Otherwise, increment block start index, decrement max count,
+ // reset index, and go to the next block (if any)
+ //
+
+ start += b->m_blockSize;
+ max -= b->m_blockSize;
+ index = 0;
+ b = b->m_next;
+ }
+
+ return (DWORD) NOT_FOUND;
+}
+
+BOOL ArrayListBase::Iterator::Next()
+{
+ LIMITED_METHOD_DAC_CONTRACT;
+
+ ++m_index;
+
+ if (m_index >= m_remaining)
+ return FALSE;
+
+ if (m_index >= m_block->m_blockSize)
+ {
+ m_remaining -= m_block->m_blockSize;
+ m_index -= m_block->m_blockSize;
+ m_total += m_block->m_blockSize;
+ m_block = m_block->m_next;
+ }
+
+ return TRUE;
+}
+
+#ifdef DACCESS_COMPILE
+
+void
+ArrayListBase::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
+{
+ SUPPORTS_DAC;
+
+ // Assume that 'this' is enumerated, either explicitly
+ // or because this class is embedded in another.
+
+ PTR_ArrayListBlock block = m_firstBlock.m_next;
+ while (block.IsValid())
+ {
+ block.EnumMem();
+ block = block->m_next;
+ }
+}
+
+#endif // #ifdef DACCESS_COMPILE
+
+
+void StructArrayListBase::Destruct (FreeProc *pfnFree)
+{
+ WRAPPER_NO_CONTRACT;
+
+ StructArrayListEntryBase *pList = m_pChunkListHead;
+ while (pList)
+ {
+ StructArrayListEntryBase *pTrash = pList;
+ pList = pList->pNext;
+ pfnFree(this, pTrash);
+ }
+}
+
+// Copied from jit.h
+inline
+size_t roundUp(size_t size, size_t mult = sizeof(size_t))
+{
+ assert(mult && ((mult & (mult-1)) == 0)); // power of two test
+
+ return (size + (mult - 1)) & ~(mult - 1);
+}
+
+void StructArrayListBase::CreateNewChunk (SIZE_T InitialChunkLength, SIZE_T ChunkLengthGrowthFactor, SIZE_T cbElement, AllocProc *pfnAlloc, SIZE_T alignment)
+{
+ CONTRACTL {
+ THROWS;
+ PRECONDITION(!m_pChunkListHead || m_nItemsInLastChunk == m_nLastChunkCapacity);
+ } CONTRACTL_END;
+
+ SIZE_T nChunkCapacity;
+ if (!m_pChunkListHead)
+ nChunkCapacity = InitialChunkLength;
+ else
+ nChunkCapacity = m_nLastChunkCapacity * ChunkLengthGrowthFactor;
+
+ S_SIZE_T cbBaseSize = S_SIZE_T(roundUp(sizeof(StructArrayListEntryBase), alignment));
+ S_SIZE_T cbChunk = cbBaseSize +
+ S_SIZE_T(cbElement) * S_SIZE_T(nChunkCapacity);
+ _ASSERTE(!cbChunk.IsOverflow());
+ if(cbChunk.IsOverflow())
+ {
+ ThrowWin32(ERROR_ARITHMETIC_OVERFLOW);
+ }
+
+ StructArrayListEntryBase *pNewChunk = (StructArrayListEntryBase*)pfnAlloc(this, cbChunk.Value());
+
+ if (m_pChunkListTail)
+ {
+ _ASSERTE(m_pChunkListHead);
+ m_pChunkListTail->pNext = pNewChunk;
+ }
+ else
+ {
+ _ASSERTE(!m_pChunkListHead);
+ m_pChunkListHead = pNewChunk;
+ }
+
+ pNewChunk->pNext = NULL;
+ m_pChunkListTail = pNewChunk;
+
+ m_nItemsInLastChunk = 0;
+ m_nLastChunkCapacity = nChunkCapacity;
+}
+
+
+void StructArrayListBase::ArrayIteratorBase::SetCurrentChunk (StructArrayListEntryBase *pChunk, SIZE_T nChunkCapacity)
+{
+ LIMITED_METHOD_CONTRACT;
+
+ m_pCurrentChunk = pChunk;
+
+ if (pChunk)
+ {
+ if (pChunk == m_pArrayList->m_pChunkListTail)
+ m_nItemsInCurrentChunk = m_pArrayList->m_nItemsInLastChunk;
+ else
+ m_nItemsInCurrentChunk = nChunkCapacity;
+
+ m_nCurrentChunkCapacity = nChunkCapacity;
+ }
+}
+