Loading...
Searching...
No Matches
polymorphicsmallobject.hh
Go to the documentation of this file.
// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
// vi: set et ts=4 sw=2 sts=2:
// SPDX-FileCopyrightText: Copyright © DUNE Project contributors, see file AUTHORS.md
// SPDX-License-Identifier: LicenseRef-GPL-2.0-only-with-DUNE-exception OR LGPL-3.0-or-later
#ifndef DUNE_FUNCTIONS_COMMON_POLYMORPHICSMALLOBJECT_HH
#define DUNE_FUNCTIONS_COMMON_POLYMORPHICSMALLOBJECT_HH
#include <cstddef>
#include <utility>
#include <type_traits>
#include <algorithm>
namespace Dune {
namespace Functions {
template<class Base, size_t bufferSize>
class PolymorphicSmallObject
{
// Actual buffer size must be > 0
static constexpr std::size_t actualBufferSize = std::max(sizeof(std::byte), bufferSize);
// Alignment requirement for the buffer. The `Derived` type must have
// an alignment requirement that is a divisor of `bufferAlignment`
static constexpr std::size_t bufferAlignment = alignof(std::max_align_t);
public:
PolymorphicSmallObject() :
p_(nullptr)
{}
template<class Derived,
std::enable_if_t<std::is_base_of_v<Base, std::remove_cv_t<
std::remove_reference_t<Derived>>>, int> = 0>
PolymorphicSmallObject(Derived&& derived)
{
constexpr bool useBuffer = (sizeof(Derived) <= bufferSize)
&& (bufferAlignment % alignof(Derived) == 0);
if constexpr (useBuffer) {
p_ = new (&buffer_) Derived(std::forward<Derived>(derived));
} else {
p_ = new Derived(std::forward<Derived>(derived));
}
}
PolymorphicSmallObject(PolymorphicSmallObject&& other) noexcept
{
moveToWrappedObject(std::move(other));
}
PolymorphicSmallObject(const PolymorphicSmallObject& other)
{
copyToWrappedObject(other);
}
~PolymorphicSmallObject()
{
destroyWrappedObject();
}
PolymorphicSmallObject& operator=(const PolymorphicSmallObject& other)
{
if (&other!=this)
{
destroyWrappedObject();
copyToWrappedObject(other);
}
return *this;
}
PolymorphicSmallObject& operator=(PolymorphicSmallObject&& other) noexcept
{
destroyWrappedObject();
moveToWrappedObject(std::move(other));
return *this;
}
explicit operator bool() const
{
return p_;
}
bool bufferUsed() const
{
return ((void*) (p_) == (void*)(&buffer_));
}
const Base& get() const
{
return *p_;
}
Base& get()
{
return *p_;
}
private:
void destroyWrappedObject() noexcept
{
if (operator bool())
{
if (bufferUsed())
p_->~Base();
else
delete p_;
}
}
void moveToWrappedObject(PolymorphicSmallObject&& other) noexcept
{
if (other.bufferUsed())
p_ = other.p_->move(&buffer_);
else
{
// We don't need to check for &other_!=this, because you can't
// have an rvalue to *this and call it's assignment/constructor
// at the same time. (Despite trying to shoot yourself in the foot
// with std::move explicitly.)
// Take ownership of allocated object
p_ = other.p_;
// Leave pointer in a clean state to avoid double freeing it.
other.p_ = 0;
}
}
void copyToWrappedObject(const PolymorphicSmallObject& other)
{
if (other.bufferUsed())
p_ = other.p_->clone(&buffer_);
else
p_ = other.p_->clone();
}
alignas(bufferAlignment) std::byte buffer_[actualBufferSize];
Base* p_;
};
} // namespace Functions
} // namespace Dune
#endif // DUNE_FUNCTIONS_COMMON_POLYMORPHICSMALLOBJECT_HH
Dune
Definition monomialset.hh:19
Dune::Functions
Definition monomialset.hh:19
Dune::Functions::PolymorphicSmallObject::get
const Base & get() const
Obtain reference to stored object.
Definition polymorphicsmallobject.hh:137
Dune::Functions::PolymorphicSmallObject::bufferUsed
bool bufferUsed() const
Check if object is stored in internal stack buffer.
Definition polymorphicsmallobject.hh:131
Dune::Functions::PolymorphicSmallObject::PolymorphicSmallObject
PolymorphicSmallObject(Derived &&derived)
Construct from object.
Definition polymorphicsmallobject.hh:75
Dune::Functions::PolymorphicSmallObject::PolymorphicSmallObject
PolymorphicSmallObject(PolymorphicSmallObject &&other) noexcept
Move constructor from other PolymorphicSmallObject.
Definition polymorphicsmallobject.hh:88
Dune::Functions::PolymorphicSmallObject::operator=
PolymorphicSmallObject & operator=(const PolymorphicSmallObject &other)
Copy assignment from other PolymorphicSmallObject.
Definition polymorphicsmallobject.hh:106
Dune::Functions::PolymorphicSmallObject::operator=
PolymorphicSmallObject & operator=(PolymorphicSmallObject &&other) noexcept
Move assignment from other PolymorphicSmallObject.
Definition polymorphicsmallobject.hh:117
Dune::Functions::PolymorphicSmallObject::PolymorphicSmallObject
PolymorphicSmallObject(const PolymorphicSmallObject &other)
Copy constructor from other PolymorphicSmallObject.
Definition polymorphicsmallobject.hh:94
Dune::Functions::PolymorphicSmallObject::~PolymorphicSmallObject
~PolymorphicSmallObject()
Destructor.
Definition polymorphicsmallobject.hh:100
Dune::Functions::PolymorphicSmallObject::PolymorphicSmallObject
PolymorphicSmallObject()
Default constructor.
Definition polymorphicsmallobject.hh:62
Dune::Functions::PolymorphicSmallObject::get
Base & get()
Obtain mutable reference to stored object.
Definition polymorphicsmallobject.hh:143