/*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2016-2023 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. OpenFOAM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. OpenFOAM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenFOAM. If not, see . \*---------------------------------------------------------------------------*/ // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // template template inline void Foam::DynamicField::doAssignDynList ( const ListType& list ) { const label len = list.size(); if (capacity_ < len) { // Needs more space for the copy operation List::setAddressableSize(capacity_); // Use entire space List::resize_nocopy(len); capacity_ = List::size(); } // Perform copy into addressable portion List::setAddressableSize(len); List::operator=(list); } template inline void Foam::DynamicField::doCapacity ( const bool nocopy, const label newCapacity ) { if (newCapacity == capacity_) { return; } // Addressable length, possibly truncated by new capacity const label currLen = min(List::size(), newCapacity); // Corner case - see comments in DynamicList doCapacity if (List::size() == newCapacity) { List::setAddressableSize(currLen+1); } if (nocopy) { List::resize_nocopy(newCapacity); } else { List::resize(newCapacity); } capacity_ = List::size(); List::setAddressableSize(currLen); } template inline void Foam::DynamicField::doReserve ( const bool nocopy, const label len ) { if (capacity_ < len) { // Preserve addressed size const label currLen = List::size(); // Increase capacity (doubling) capacity_ = max(SizeMin, max(len, label(2*capacity_))); if (nocopy) { List::resize_nocopy(capacity_); } else { List::resize(capacity_); } List::setAddressableSize(currLen); } } template inline void Foam::DynamicField::doResize ( const bool nocopy, const label len ) { this->doReserve(nocopy, len); List::setAddressableSize(len); } // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // template inline constexpr Foam::DynamicField::DynamicField() noexcept : Field(), capacity_(0) {} template inline Foam::DynamicField::DynamicField(const label initialCapacity) : Field(), capacity_(0) { reserve_nocopy(initialCapacity); } template inline Foam::DynamicField::DynamicField ( const label len, const T& val ) : Field(len, val), capacity_(Field::size()) {} template inline Foam::DynamicField::DynamicField ( const label len, const Foam::zero ) : Field(len, Foam::zero{}), capacity_(Field::size()) {} template inline Foam::DynamicField::DynamicField ( const DynamicField& list ) : Field(list), capacity_(Field::size()) {} template template inline Foam::DynamicField::DynamicField ( const DynamicField& list ) : Field(list), capacity_(Field::size()) {} template inline Foam::DynamicField::DynamicField ( const UList& list ) : Field(list), capacity_(Field::size()) {} template template inline Foam::DynamicField::DynamicField ( const IndirectListBase& list ) : Field(list), capacity_(Field::size()) {} template inline Foam::DynamicField::DynamicField ( List&& content ) : Field(std::move(content)), capacity_(Field::size()) {} template template inline Foam::DynamicField::DynamicField ( DynamicList&& list ) : Field(), capacity_(0) { transfer(list); } template inline Foam::DynamicField::DynamicField ( DynamicField&& content ) : Field(), capacity_(0) { transfer(content); } template template inline Foam::DynamicField::DynamicField ( DynamicField&& content ) : Field(), capacity_(0) { transfer(content); } template inline Foam::DynamicField::DynamicField ( const UList& mapF, const labelUList& mapAddressing ) : Field(mapF, mapAddressing), capacity_(Field::size()) {} template inline Foam::DynamicField::DynamicField ( const UList& mapF, const labelListList& mapAddressing, const scalarListList& weights ) : Field(mapF, mapAddressing, weights), capacity_(Field::size()) {} template inline Foam::DynamicField::DynamicField ( const UList& mapF, const FieldMapper& map ) : Field(mapF, map), capacity_(Field::size()) {} template inline Foam::DynamicField::DynamicField(Istream& is) : Field(is), capacity_(Field::size()) {} template inline Foam::tmp> Foam::DynamicField::clone() const { return tmp>::New(*this); } // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // template inline std::streamsize Foam::DynamicField::capacity_bytes() const noexcept { return std::streamsize(capacity_)*sizeof(T); } template inline void Foam::DynamicField::setCapacity ( const label len ) { this->doCapacity(false, len); // nocopy = false } template inline void Foam::DynamicField::setCapacity_nocopy ( const label len ) { this->doCapacity(true, len); // nocopy = true } template inline void Foam::DynamicField::setCapacity_unsafe ( const label len ) noexcept { capacity_ = len; } template inline void Foam::DynamicField::reserve ( const label len ) { this->doReserve(false, len); // nocopy = false } template inline void Foam::DynamicField::reserve_nocopy ( const label len ) { this->doReserve(true, len); // nocopy = true } template inline void Foam::DynamicField::resize ( const label len ) { this->doResize(false, len); // nocopy = false } template inline void Foam::DynamicField::resize_nocopy ( const label len ) { this->doResize(true, len); // nocopy = true } template inline void Foam::DynamicField::resize ( const label len, const T& val ) { label idx = List::size(); resize(len); // Fill newly exposed with constant value while (idx < len) { this->operator[](idx) = val; ++idx; } } template inline void Foam::DynamicField::clear() noexcept { List::setAddressableSize(0); } template inline void Foam::DynamicField::clearStorage() { List::clear(); capacity_ = 0; } template inline Foam::label Foam::DynamicField::expandStorage() noexcept { const label currLen = List::size(); // Allow addressing into the entire list List::setAddressableSize(capacity_); return currLen; } template inline void Foam::DynamicField::shrinkStorage() { const label currLen = List::size(); if (currLen < capacity_) { // Adjust addressable size to trigger proper resizing List::setAddressableSize(currLen+1); List::resize(currLen); capacity_ = List::size(); } } template inline Foam::DynamicField& Foam::DynamicField::shrink() { this->shrinkStorage(); return *this; } template template inline void Foam::DynamicField::swap ( DynamicField& other ) { if ( static_cast*>(this) == static_cast*>(&other) ) { return; // Self-swap is a no-op } // Swap storage and addressable size UList::swap(other); // Swap capacity std::swap(this->capacity_, other.capacity_); } template template inline void Foam::DynamicField::swap ( DynamicList& other ) { if ( static_cast*>(this) == static_cast*>(&other) ) { return; // Self-swap is a no-op } // Swap storage and addressable size UList::swap(other); // Swap capacity const label oldCap = this->capacity(); const label newCap = other.capacity(); this->setCapacity_unsafe(newCap); other.setCapacity_unsafe(oldCap); } template inline void Foam::DynamicField::transfer(List& list) { // Take over storage, clear addressing for list capacity_ = list.size(); Field::transfer(list); } template template inline void Foam::DynamicField::transfer ( DynamicList& list ) { if ( static_cast*>(this) == static_cast*>(&list) ) { return; // Self-assignment is a no-op } // Take over storage as-is (without shrink, without using SizeMin) // clear addressing and storage for old list. capacity_ = list.capacity(); Field::transfer(static_cast&>(list)); list.clearStorage(); // Ensure capacity=0 } template template inline void Foam::DynamicField::transfer ( DynamicField& list ) { if ( static_cast*>(this) == static_cast*>(&list) ) { return; // Self-assignment is a no-op } // Take over storage as-is (without shrink, without using SizeMin) // clear addressing and storage for old list. capacity_ = list.capacity(); Field::transfer(static_cast&>(list)); list.clearStorage(); // Ensure capacity=0 } template template inline T& Foam::DynamicField::emplace_back(Args&&... args) { // This could/should be better with inplace construction // (as per std::vector), but currently lacking the methods for that // so resize and move assign const label idx = List::size(); resize(idx + 1); // move assign element this->operator[](idx) = T(std::forward(args)...); return this->back(); } template inline void Foam::DynamicField::push_back ( const T& val ) { const label idx = List::size(); resize(idx + 1); this->operator[](idx) = val; // copy element } template inline void Foam::DynamicField::push_back ( T&& val ) { const label idx = List::size(); resize(idx + 1); this->operator[](idx) = std::move(val); // move assign element } template inline void Foam::DynamicField::push_back ( const UList& list ) { if (this == &list) { FatalErrorInFunction << "Attempted push_back to self" << abort(FatalError); } label idx = List::size(); resize(idx + list.size()); for (const T& val : list) { this->operator[](idx++) = val; // copy element } } template inline void Foam::DynamicField::pop_back(label n) { if (n >= this->size()) { this->clear(); } else if (n > 0) { resize(this->size() - n); } } // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * // template inline T& Foam::DynamicField::operator() ( const label i ) { if (i >= List::size()) { resize(i + 1); } return this->operator[](i); } template inline void Foam::DynamicField::operator= ( const T& val ) { UList::operator=(val); } template inline void Foam::DynamicField::operator= ( const Foam::zero ) { UList::operator=(Foam::zero{}); } template inline void Foam::DynamicField::operator= ( const UList& list ) { doAssignDynList(list); } template inline void Foam::DynamicField::operator= ( const DynamicField& list ) { if (this == &list) { return; // Self-assignment is a no-op } doAssignDynList(list); } template template inline void Foam::DynamicField::operator= ( const IndirectListBase& list ) { // NOTE: Self-assignment needs special handling /// if /// ( /// static_cast*>(this) /// == static_cast*>(&list.values()) /// ) doAssignDynList(list); } template inline void Foam::DynamicField::operator= ( List&& list ) { transfer(list); } template inline void Foam::DynamicField::operator= ( DynamicField&& list ) { transfer(list); } template template inline void Foam::DynamicField::operator= ( DynamicField&& list ) { transfer(list); } template template inline void Foam::DynamicField::operator= ( DynamicList&& list ) { transfer(list); } // * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * // template inline Foam::Istream& Foam::DynamicField::readList ( Istream& is ) { // Use DynamicList::readList for reading DynamicField. // The logic should be the same and this avoids duplicate code DynamicList list; (*this).swap(list); list.readList(is); (*this).swap(list); return is; } template inline Foam::Istream& Foam::operator>> ( Istream& is, DynamicField& rhs ) { return rhs.readList(is); } template inline Foam::Ostream& Foam::operator<< ( Ostream& os, const DynamicField& rhs ) { os << static_cast&>(rhs); return os; } // ************************************************************************* //