//------------------------------------------------------------------------------ // UMFPACK/Source/umf_mem_free_tail_block: free memory in Numeric->Memory //------------------------------------------------------------------------------ // UMFPACK, Copyright (c) 2005-2023, Timothy A. Davis, All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ //------------------------------------------------------------------------------ /* The UMF_mem_* routines manage the Numeric->Memory memory space. */ /* free a block from the tail of Numeric->memory */ #include "umf_internal.h" #include "umf_mem_free_tail_block.h" void UMF_mem_free_tail_block ( NumericType *Numeric, Int i ) { Unit *pprev, *pnext, *p, *pbig ; Int sprev ; ASSERT (Numeric != (NumericType *) NULL) ; ASSERT (Numeric->Memory != (Unit *) NULL) ; if (i == EMPTY || i == 0) return ; /* already deallocated */ /* ---------------------------------------------------------------------- */ /* get the block */ /* ---------------------------------------------------------------------- */ p = Numeric->Memory + i ; p-- ; /* get the corresponding header */ DEBUG2 (("free block: p: "ID, (Int) (p-Numeric->Memory))) ; ASSERT (p >= Numeric->Memory + Numeric->itail) ; ASSERT (p < Numeric->Memory + Numeric->size) ; ASSERT (p->header.size > 0) ; /* block not already free */ ASSERT (p->header.prevsize >= 0) ; Numeric->tail_usage -= p->header.size + 1 ; /* ---------------------------------------------------------------------- */ /* merge with next free block, if any */ /* ---------------------------------------------------------------------- */ pnext = p + 1 + p->header.size ; DEBUG2 (("size: "ID" next: "ID" ", p->header.size, (Int) (pnext-Numeric->Memory))) ; ASSERT (pnext < Numeric->Memory + Numeric->size) ; ASSERT (pnext->header.prevsize == p->header.size) ; ASSERT (pnext->header.size != 0) ; if (pnext->header.size < 0) { /* next block is also free - merge with current block */ p->header.size += (-(pnext->header.size)) + 1 ; DEBUG2 ((" NEXT FREE ")) ; } /* ---------------------------------------------------------------------- */ /* merge with previous free block, if any */ /* ---------------------------------------------------------------------- */ #ifndef NDEBUG if (p == Numeric->Memory + Numeric->itail) { DEBUG2 ((" at top of tail ")) ; ASSERT (p->header.prevsize == 0) ; } #endif if (p > Numeric->Memory + Numeric->itail) { ASSERT (p->header.prevsize > 0) ; pprev = p - 1 - p->header.prevsize ; DEBUG2 ((" prev: "ID" ", (Int) (pprev-Numeric->Memory))) ; ASSERT (pprev >= Numeric->Memory + Numeric->itail) ; sprev = pprev->header.size ; if (sprev < 0) { /* previous block is also free - merge it with current block */ ASSERT (p->header.prevsize == -sprev) ; pprev->header.size = p->header.size + (-sprev) + 1 ; p = pprev ; DEBUG2 ((" PREV FREE ")) ; /* note that p may now point to Numeric->itail */ } #ifndef NDEBUG else { ASSERT (p->header.prevsize == sprev) ; } #endif } /* ---------------------------------------------------------------------- */ /* free the block, p */ /* ---------------------------------------------------------------------- */ pnext = p + 1 + p->header.size ; ASSERT (pnext < Numeric->Memory + Numeric->size) ; if (p == Numeric->Memory + Numeric->itail) { /* top block in list is freed */ Numeric->itail = pnext - Numeric->Memory ; pnext->header.prevsize = 0 ; DEBUG2 ((" NEW TAIL : "ID" ", Numeric->itail)) ; ASSERT (pnext->header.size > 0) ; if (Numeric->ibig != EMPTY && Numeric->ibig <= Numeric->itail) { /* the big free block is now above the tail */ Numeric->ibig = EMPTY ; } } else { /* keep track of the biggest free block seen */ if (Numeric->ibig == EMPTY) { Numeric->ibig = p - Numeric->Memory ; } else { pbig = Numeric->Memory + Numeric->ibig ; if (-(pbig->header.size) < p->header.size) { Numeric->ibig = p - Numeric->Memory ; } } /* flag the block as free, somewhere in the middle of the tail */ pnext->header.prevsize = p->header.size ; p->header.size = -(p->header.size) ; } DEBUG2 (("new p: "ID" freesize: "ID"\n", (Int) (p-Numeric->Memory), -(p->header.size))) ; }