/*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2017 OpenFOAM Foundation Copyright (C) 2018-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 . \*---------------------------------------------------------------------------*/ #include "error.H" #include // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * // template inline Foam::word Foam::tmp::typeName() { return Foam::word("tmp<" + std::string(typeid(T).name()) + '>', false); } // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // template inline void Foam::tmp::checkUseCount() const { if (ptr_ && ptr_->refCount::use_count() > 1) { FatalErrorInFunction << "Attempt to create more than " << (ptr_->refCount::use_count() + 1) << " tmp's referring to the same object of type tmp<" << typeid(T).name() << '>' << abort(FatalError); } } // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // template inline constexpr Foam::tmp::tmp() noexcept : ptr_(nullptr), type_(PTR) {} template inline constexpr Foam::tmp::tmp(std::nullptr_t) noexcept : ptr_(nullptr), type_(PTR) {} template inline Foam::tmp::tmp(T* p) : ptr_(p), type_(PTR) { if (ptr_ && !ptr_->refCount::unique()) { FatalErrorInFunction << "Attempted construction of a " << this->typeName() << " from non-unique pointer" << abort(FatalError); } } template inline constexpr Foam::tmp::tmp(const T& obj) noexcept : ptr_(const_cast(&obj)), type_(CREF) {} template inline Foam::tmp::tmp(tmp&& rhs) noexcept : ptr_(rhs.ptr_), type_(rhs.type_) { rhs.ptr_ = nullptr; rhs.type_ = PTR; } template inline Foam::tmp::tmp(const tmp&& rhs) noexcept : ptr_(rhs.ptr_), type_(rhs.type_) { rhs.ptr_ = nullptr; rhs.type_ = PTR; } template inline Foam::tmp::tmp(const tmp& rhs) : ptr_(rhs.ptr_), type_(rhs.type_) { if (is_pointer()) { if (ptr_) { ptr_->refCount::operator++(); this->checkUseCount(); } else { FatalErrorInFunction << "Attempted copy/move of a deallocated " << this->typeName() << abort(FatalError); } } } template inline Foam::tmp::tmp(const tmp& rhs, bool reuse) : ptr_(rhs.ptr_), type_(rhs.type_) { if (is_pointer()) { if (ptr_) { if (reuse) { rhs.ptr_ = nullptr; rhs.type_ = PTR; } else { ptr_->refCount::operator++(); this->checkUseCount(); } } else { FatalErrorInFunction << "Attempted copy/move of a deallocated " << this->typeName() << abort(FatalError); } } } template inline Foam::tmp::tmp(autoPtr&& rhs) noexcept : tmp(rhs.release()) {} // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // template inline Foam::tmp::~tmp() noexcept { clear(); } // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // template inline bool Foam::tmp::is_const() const noexcept { return (type_ == CREF); } template inline bool Foam::tmp::is_pointer() const noexcept { //OR: return (type_ == PTR || type_ == CACHE_PTR); return (type_ < REF_Types); } template inline bool Foam::tmp::is_reference() const noexcept { //OR: return (type_ == CREF || type_ == REF); return (type_ > REF_Types); } template inline bool Foam::tmp::movable() const noexcept { return (ptr_ && type_ == PTR && ptr_->refCount::unique()); } template inline const T& Foam::tmp::cref() const { if (!ptr_ && is_pointer()) { FatalErrorInFunction << this->typeName() << " deallocated" << abort(FatalError); } return *ptr_; // const reference } template inline T& Foam::tmp::ref() const { if (is_const()) { FatalErrorInFunction << "Attempted non-const reference to const object: " << this->typeName() << abort(FatalError); } else if (!ptr_ && is_pointer()) { FatalErrorInFunction << this->typeName() << " deallocated" << abort(FatalError); } return *ptr_; // non-const reference } template inline T* Foam::tmp::ptr() const { if (!ptr_) { FatalErrorInFunction << this->typeName() << " deallocated" << abort(FatalError); } if (type_ == PTR) { if (!ptr_->refCount::unique()) { FatalErrorInFunction << "Attempt to acquire pointer to object referred to" << " by multiple temporaries of type " << this->typeName() << abort(FatalError); } // Release pointer T* p = ptr_; ptr_ = nullptr; return p; } // CACHE_PTR (immovable) is cloned, as per a reference return ptr_->clone().ptr(); } template inline void Foam::tmp::clear() const noexcept { if (ptr_ && is_pointer()) { if (ptr_->refCount::unique()) { delete ptr_; } else { ptr_->refCount::operator--(); } ptr_ = nullptr; } } template inline void Foam::tmp::protect(bool on) noexcept { if (on) { // ON: from PTR -> CACHE_PTR, but not nullptr if (ptr_ && type_ == PTR) { type_ = CACHE_PTR; } } else { // OFF: from CACHE_PTR -> PTR if (type_ == CACHE_PTR) { type_ = PTR; } } } template inline void Foam::tmp::reset(T* p) noexcept { clear(); ptr_ = p; type_ = PTR; } template inline void Foam::tmp::reset(tmp&& other) noexcept { // Could also make Fatal with FULLDEBUG if (&other == this) { return; // No self-assignment } clear(); ptr_ = other.ptr_; type_ = other.type_; other.ptr_ = nullptr; other.type_ = PTR; } template template inline T& Foam::tmp::emplace(Args&&... args) { clear(); // delete old entry ptr_ = new T(std::forward(args)...); type_ = PTR; return *ptr_; } template inline void Foam::tmp::cref(const tmp& other) noexcept { // Could also make Fatal with FULLDEBUG if (&other == this) { return; // No self-assignment } clear(); ptr_ = other.ptr_; type_ = (ptr_ ? CREF : PTR); } template inline void Foam::tmp::cref(const T& obj) noexcept { clear(); ptr_ = const_cast(&obj); type_ = CREF; } template inline void Foam::tmp::cref(const T* p) noexcept { clear(); ptr_ = const_cast(p); type_ = (ptr_ ? CREF : PTR); } template inline void Foam::tmp::ref(T& obj) noexcept { clear(); ptr_ = &obj; type_ = REF; } template inline void Foam::tmp::ref(T* p) noexcept { clear(); ptr_ = p; type_ = (ptr_ ? REF : PTR); } template inline void Foam::tmp::swap(tmp& other) noexcept { // Swap is just copy/assign for pointer and enum types // Self-swap is effectively ignored T* p = ptr_; ptr_ = other.ptr_; other.ptr_ = p; refType t = type_; type_ = other.type_; other.type_ = t; } // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * // template inline const T* Foam::tmp::operator->() const { if (!ptr_ && is_pointer()) { FatalErrorInFunction << this->typeName() << " deallocated" << abort(FatalError); } return ptr_; } template inline T* Foam::tmp::operator->() { if (is_const()) { FatalErrorInFunction << "Attempt to cast const object to non-const: " << this->typeName() << abort(FatalError); } else if (!ptr_ && is_pointer()) { FatalErrorInFunction << this->typeName() << " deallocated" << abort(FatalError); } return ptr_; } template inline void Foam::tmp::operator=(const tmp& other) { // Could also make Fatal with FULLDEBUG if (&other == this) { return; // No self-assignment } clear(); if (other.is_pointer()) { ptr_ = other.ptr_; type_ = other.type_; other.ptr_ = nullptr; other.type_ = PTR; if (!ptr_) { FatalErrorInFunction << "Attempted assignment of a deallocated " << this->typeName() << abort(FatalError); } } else { FatalErrorInFunction << "Attempted assignment of an object reference of type " << typeid(T).name() << abort(FatalError); } } template inline void Foam::tmp::operator=(tmp&& other) noexcept { // Could also make Fatal with FULLDEBUG if (&other == this) { return; // No self-assignment } clear(); ptr_ = other.ptr_; type_ = other.type_; other.ptr_ = nullptr; other.type_ = PTR; } template inline void Foam::tmp::operator=(T* p) { if (!p) { FatalErrorInFunction << "Attempted copy of a deallocated " << this->typeName() << abort(FatalError); } else if (!p->refCount::unique()) { FatalErrorInFunction << "Attempted assignment of a " << this->typeName() << " to non-unique pointer" << abort(FatalError); } reset(p); } // ************************************************************************* //