/** @file Auto-resizing array. Copyright (c) 2021, Mike Beaton. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause **/ #include #include #include #include #include #include #define INITIAL_NUM_ITEMS (8) VOID OcFlexArrayFreePointerItem ( IN VOID *Item ) { ASSERT (Item != NULL); if (*(VOID **)Item != NULL) { FreePool (*(VOID **)Item); *(VOID **)Item = NULL; } } OC_FLEX_ARRAY * OcFlexArrayInit ( IN CONST UINTN ItemSize, IN CONST OC_FLEX_ARRAY_FREE_ITEM FreeItem OPTIONAL ) { OC_FLEX_ARRAY *FlexArray; ASSERT (ItemSize > 0); FlexArray = AllocateZeroPool (sizeof (OC_FLEX_ARRAY)); if (FlexArray != NULL) { FlexArray->ItemSize = ItemSize; FlexArray->FreeItem = FreeItem; } DEBUG ((OC_TRACE_FLEX, "FLEX: Init %p %u\n", FlexArray, ItemSize)); return FlexArray; } /** Retrieve the Index-th item in a flex array. @param[in] FlexArray A pointer to the flex array. @param[in] Index The Index-th item to be retrieved in FlexArray. @return The Index-th item in FlexArray. **/ STATIC VOID * InternalFlexArrayItemAt ( IN CONST OC_FLEX_ARRAY *FlexArray, IN CONST UINTN Index ) { VOID *Item; ASSERT (FlexArray != NULL); ASSERT (Index < FlexArray->Count); ASSERT (FlexArray->Items != NULL); Item = ((UINT8 *)FlexArray->Items) + Index * FlexArray->ItemSize; return Item; } /** Add an item in a flex array. @param[in,out] FlexArray A pointer to the flex array. @return The added item. **/ STATIC VOID * InternalFlexArrayAddItem ( IN OUT OC_FLEX_ARRAY *FlexArray ) { VOID *TmpBuffer; UINTN NewSize; VOID *Item; ASSERT (FlexArray != NULL); if (FlexArray->Items == NULL) { FlexArray->AllocatedCount = INITIAL_NUM_ITEMS; if (BaseOverflowMulUN (FlexArray->AllocatedCount, FlexArray->ItemSize, &NewSize)) { return NULL; } FlexArray->Count = 1; FlexArray->Items = AllocatePool (NewSize); if (FlexArray->Items == NULL) { return NULL; } } else { ASSERT (FlexArray->AllocatedCount > 0); ASSERT (FlexArray->Count <= FlexArray->AllocatedCount); ++(FlexArray->Count); if (FlexArray->Count > FlexArray->AllocatedCount) { if (BaseOverflowMulUN (FlexArray->AllocatedCount * FlexArray->ItemSize, 2, &NewSize)) { return NULL; } TmpBuffer = ReallocatePool ( FlexArray->AllocatedCount * FlexArray->ItemSize, NewSize, FlexArray->Items ); if (TmpBuffer == NULL) { return NULL; } FlexArray->Items = TmpBuffer; FlexArray->AllocatedCount = FlexArray->AllocatedCount * 2; } } Item = InternalFlexArrayItemAt (FlexArray, FlexArray->Count - 1); return Item; } VOID * OcFlexArrayAddItem ( IN OUT OC_FLEX_ARRAY *FlexArray ) { VOID *Item; ASSERT (FlexArray != NULL); Item = InternalFlexArrayAddItem (FlexArray); if (Item != NULL) { ZeroMem (Item, FlexArray->ItemSize); } DEBUG ((OC_TRACE_FLEX, "FLEX: Add %p %p\n", FlexArray, Item)); return Item; } VOID * OcFlexArrayInsertItem ( IN OUT OC_FLEX_ARRAY *FlexArray, IN CONST UINTN InsertIndex ) { VOID *Item; VOID *Dest; ASSERT (FlexArray != NULL); ASSERT (InsertIndex <= FlexArray->Count); if (InsertIndex == FlexArray->Count) { return OcFlexArrayAddItem (FlexArray); } Item = InternalFlexArrayAddItem (FlexArray); if (Item == NULL) { return Item; } Item = InternalFlexArrayItemAt (FlexArray, InsertIndex); Dest = InternalFlexArrayItemAt (FlexArray, InsertIndex + 1); CopyMem (Dest, Item, (FlexArray->Count - InsertIndex) * FlexArray->ItemSize); ZeroMem (Item, FlexArray->ItemSize); DEBUG ((OC_TRACE_FLEX, "FLEX: Insert %p %p\n", FlexArray, Item)); return Item; } VOID * OcFlexArrayItemAt ( IN CONST OC_FLEX_ARRAY *FlexArray, IN CONST UINTN Index ) { VOID *Item; // // Repeat these checks here and in internal ItemAt for easier debugging if they fail. // ASSERT (FlexArray != NULL); ASSERT (Index < FlexArray->Count); ASSERT (FlexArray->Items != NULL); Item = InternalFlexArrayItemAt (FlexArray, Index); DEBUG ((OC_TRACE_FLEX, "FLEX: At %p %p\n", FlexArray, Item)); return Item; } VOID OcFlexArrayFree ( IN OC_FLEX_ARRAY **FlexArray ) { UINTN Index; DEBUG ((OC_TRACE_FLEX, "FLEX: Free %p\n", FlexArray)); ASSERT (FlexArray != NULL); if (*FlexArray != NULL) { if ((*FlexArray)->Items != NULL) { if ((*FlexArray)->FreeItem != NULL) { for (Index = 0; Index < (*FlexArray)->Count; Index++) { (*FlexArray)->FreeItem (InternalFlexArrayItemAt (*FlexArray, Index)); } } FreePool ((*FlexArray)->Items); } FreePool (*FlexArray); *FlexArray = NULL; } } VOID OcFlexArrayDiscardItem ( IN OUT OC_FLEX_ARRAY *FlexArray, IN CONST BOOLEAN FreeItem ) { DEBUG ((OC_TRACE_FLEX, "FLEX: Discard %p %u\n", FlexArray, FreeItem)); ASSERT (FlexArray != NULL); ASSERT (FlexArray->Items != NULL); ASSERT (FlexArray->Count > 0); if (FreeItem && (FlexArray->FreeItem != NULL)) { FlexArray->FreeItem (InternalFlexArrayItemAt (FlexArray, FlexArray->Count - 1)); } --FlexArray->Count; } VOID OcFlexArrayFreeContainer ( IN OC_FLEX_ARRAY **FlexArray, IN VOID **Items, IN UINTN *Count ) { DEBUG ((OC_TRACE_FLEX, "FLEX: FreeContainer %p\n", FlexArray)); if ((FlexArray == NULL) || (*FlexArray == NULL)) { ASSERT (FALSE); *Items = NULL; *Count = 0; } else { *Items = (*FlexArray)->Items; *Count = (*FlexArray)->Count; if ((*Count == 0) && (*Items != NULL)) { FreePool (*Items); *Items = NULL; } FreePool (*FlexArray); *FlexArray = NULL; } }