diff --git a/Src/Base/AMReX_CArena.H b/Src/Base/AMReX_CArena.H index d68285bc878..3962908f1dc 100644 --- a/Src/Base/AMReX_CArena.H +++ b/Src/Base/AMReX_CArena.H @@ -164,15 +164,15 @@ protected: MemStat* m_stat; }; + //! The list of blocks allocated via ::operator new(). + std::vector > m_alloc; + /** * \brief The type of our freelist and blocklist. * We use a set sorted from lo to hi memory addresses. */ using NL = std::set; - //! The list of blocks allocated via ::operator new(). - std::vector > m_alloc; - /** * \brief The free list of allocated but not currently used blocks. * Maintained in lo to hi memory sorted order. diff --git a/Src/Base/AMReX_CArena.cpp b/Src/Base/AMReX_CArena.cpp index 6f7979d4750..76b15a5599e 100644 --- a/Src/Base/AMReX_CArena.cpp +++ b/Src/Base/AMReX_CArena.cpp @@ -203,9 +203,54 @@ CArena::alloc_in_place (void* pt, std::size_t szmin, std::size_t szmax) } void* -CArena::shrink_in_place (void* /*pt*/, std::size_t sz) +CArena::shrink_in_place (void* pt, std::size_t sz) { - return alloc(sz); // xxxxx TODO + if ((pt == nullptr) || (sz == 0)) { return nullptr; } + + sz = Arena::align(sz); + + std::lock_guard lock(carena_mutex); + + auto busy_it = m_busylist.find(Node(pt,nullptr,0)); + if (busy_it == m_busylist.end()) { + amrex::Abort("CArena::shrink_in_place: unknown pointer"); + return nullptr; + } + AMREX_ASSERT(m_freelist.find(*busy_it) == m_freelist.end()); + + if (sz > busy_it->size()) { + amrex::Abort("CArena::shrink_in_place: wrong size. Cannot shrink to a larger size."); + return nullptr; + } else if (sz == busy_it->size()) { + return pt; + } else { + auto leftover_size = busy_it->size() - sz; + + void* pt2 = static_cast(pt) + sz; + Node new_free_node(pt2, busy_it->owner(), leftover_size); + + void* pt_end = static_cast(pt) + busy_it->size(); + auto free_it = m_freelist.find(Node(pt_end,nullptr,0)); + if ((free_it == m_freelist.end()) || + ! new_free_node.coalescable(*free_it)) + { + m_freelist.insert(free_it, new_free_node); + } else { + auto& node = const_cast(*free_it); + auto new_size = leftover_size + node.size(); + // This is safe because the free list is std::set and the + // modification of `block` does not change the order of elements + // in the container, even though Node's opearator< uses block. + node.block(pt2); + node.size(new_size); + } + + const_cast(*busy_it).size(sz); + + m_actually_used -= leftover_size; + + return pt; + } } void