Program Listing for File shared_ptr.h¶
↰ Return to documentation for file (include/opentelemetry/nostd/shared_ptr.h
)
// Copyright 2020, OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#ifdef HAVE_CPP_STDLIB
# include "opentelemetry/std/shared_ptr.h"
#else
# include <cstdlib>
# include <memory>
# include <utility>
# include "opentelemetry/version.h"
OPENTELEMETRY_BEGIN_NAMESPACE
namespace nostd
{
template <class T>
class shared_ptr
{
public:
using element_type = T;
using pointer = element_type *;
private:
static constexpr size_t kMaxSize = 32;
static constexpr size_t kAlignment = 8;
struct alignas(kAlignment) PlacementBuffer
{
char data[kMaxSize];
};
class shared_ptr_wrapper
{
public:
shared_ptr_wrapper() noexcept = default;
shared_ptr_wrapper(std::shared_ptr<T> &&ptr) noexcept : ptr_{std::move(ptr)} {}
virtual ~shared_ptr_wrapper() {}
virtual void CopyTo(PlacementBuffer &buffer) const noexcept
{
new (buffer.data) shared_ptr_wrapper{*this};
}
virtual void MoveTo(PlacementBuffer &buffer) noexcept
{
new (buffer.data) shared_ptr_wrapper{std::move(this->ptr_)};
}
template <class U,
typename std::enable_if<std::is_convertible<pointer, U *>::value>::type * = nullptr>
void MoveTo(typename shared_ptr<U>::PlacementBuffer &buffer) noexcept
{
new (buffer.data) shared_ptr_wrapper{std::move(this->ptr_)};
}
virtual pointer Get() const noexcept { return ptr_.get(); }
virtual void Reset() noexcept { ptr_.reset(); }
private:
std::shared_ptr<T> ptr_;
};
static_assert(sizeof(shared_ptr_wrapper) <= kMaxSize, "Placement buffer is too small");
static_assert(alignof(shared_ptr_wrapper) <= kAlignment, "Placement buffer not properly aligned");
public:
shared_ptr() noexcept { new (buffer_.data) shared_ptr_wrapper{}; }
explicit shared_ptr(pointer ptr)
{
std::shared_ptr<T> ptr_(ptr);
new (buffer_.data) shared_ptr_wrapper{std::move(ptr_)};
}
shared_ptr(std::shared_ptr<T> ptr) noexcept
{
new (buffer_.data) shared_ptr_wrapper{std::move(ptr)};
}
shared_ptr(shared_ptr &&other) noexcept { other.wrapper().MoveTo(buffer_); }
template <class U,
typename std::enable_if<std::is_convertible<U *, pointer>::value>::type * = nullptr>
shared_ptr(shared_ptr<U> &&other) noexcept
{
other.wrapper().template MoveTo<T>(buffer_);
}
shared_ptr(const shared_ptr &other) noexcept { other.wrapper().CopyTo(buffer_); }
~shared_ptr() { wrapper().~shared_ptr_wrapper(); }
shared_ptr &operator=(shared_ptr &&other) noexcept
{
wrapper().~shared_ptr_wrapper();
other.wrapper().MoveTo(buffer_);
return *this;
}
shared_ptr &operator=(std::nullptr_t) noexcept
{
wrapper().Reset();
return *this;
}
shared_ptr &operator=(const shared_ptr &other) noexcept
{
wrapper().~shared_ptr_wrapper();
other.wrapper().CopyTo(buffer_);
return *this;
}
element_type &operator*() const noexcept { return *wrapper().Get(); }
pointer operator->() const noexcept { return wrapper().Get(); }
operator bool() const noexcept { return wrapper().Get() != nullptr; }
pointer get() const noexcept { return wrapper().Get(); }
void swap(shared_ptr<T> &other) noexcept
{
shared_ptr<T> tmp{std::move(other)};
wrapper().MoveTo(other.buffer_);
tmp.wrapper().MoveTo(buffer_);
}
template <typename U>
friend class shared_ptr;
private:
PlacementBuffer buffer_;
shared_ptr_wrapper &wrapper() noexcept
{
return *reinterpret_cast<shared_ptr_wrapper *>(buffer_.data);
}
const shared_ptr_wrapper &wrapper() const noexcept
{
return *reinterpret_cast<const shared_ptr_wrapper *>(buffer_.data);
}
};
template <class T1, class T2>
bool operator!=(const shared_ptr<T1> &lhs, const shared_ptr<T2> &rhs) noexcept
{
return lhs.get() != rhs.get();
}
template <class T1, class T2>
bool operator==(const shared_ptr<T1> &lhs, const shared_ptr<T2> &rhs) noexcept
{
return lhs.get() == rhs.get();
}
template <class T>
inline bool operator==(const shared_ptr<T> &lhs, std::nullptr_t) noexcept
{
return lhs.get() == nullptr;
}
template <class T>
inline bool operator==(std::nullptr_t, const shared_ptr<T> &rhs) noexcept
{
return nullptr == rhs.get();
}
template <class T>
inline bool operator!=(const shared_ptr<T> &lhs, std::nullptr_t) noexcept
{
return lhs.get() != nullptr;
}
template <class T>
inline bool operator!=(std::nullptr_t, const shared_ptr<T> &rhs) noexcept
{
return nullptr != rhs.get();
}
} // namespace nostd
OPENTELEMETRY_END_NAMESPACE
#endif