File pointers.h¶
File List > endstone > util > pointers.h
Go to the documentation of this file
// Copyright (c) 2024, The Endstone Project. (https://endstone.dev) All Rights Reserved.
//
// 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
#include <cstddef>
#include <functional>
#include <memory>
#include <type_traits>
#include <utility>
#include "endstone/check.h"
namespace endstone {
template <class T>
class Nullable;
template <class T>
class NotNull {
public:
using pointer_type = std::shared_ptr<T>;
using element_type = T;
NotNull() = delete;
NotNull(std::shared_ptr<T> ptr) : ptr_(std::move(ptr))
{
Preconditions::checkArgument(ptr_ != nullptr, "pointer must not be null.");
}
NotNull(const NotNull &other) = default;
NotNull &operator=(const NotNull &other) = default;
template <class U>
requires(!std::is_same_v<U, T>) && std::is_convertible_v<U *, T *>
NotNull(std::shared_ptr<U> ptr) : NotNull(std::shared_ptr<T>(std::move(ptr)))
{
}
template <class U>
requires(!std::is_same_v<U, T>) && std::is_convertible_v<U *, T *>
NotNull(const NotNull<U> &other) : ptr_(other.get())
{
}
const pointer_type &get() const noexcept { return ptr_; }
T *operator->() const noexcept { return ptr_.get(); }
T &operator*() const noexcept { return *get(); }
NotNull(std::nullptr_t) = delete;
NotNull &operator=(std::nullptr_t) = delete;
NotNull &operator++() = delete;
NotNull &operator--() = delete;
NotNull operator++(int) = delete;
NotNull operator--(int) = delete;
NotNull &operator+=(std::ptrdiff_t) = delete;
NotNull &operator-=(std::ptrdiff_t) = delete;
void operator[](std::ptrdiff_t) const = delete;
void swap(NotNull &other) noexcept { std::swap(ptr_, other.ptr_); }
private:
pointer_type ptr_;
};
template <class T>
class Nullable {
public:
using pointer_type = std::shared_ptr<T>;
using element_type = T;
constexpr Nullable() noexcept = default;
constexpr Nullable(std::nullptr_t) noexcept {}
Nullable(std::shared_ptr<T> ptr) : ptr_(std::move(ptr)) {}
Nullable(const NotNull<T> &other) : ptr_(other.get()) {}
template <class U>
requires(!std::is_same_v<U, T>) && std::is_convertible_v<U *, T *>
Nullable(std::shared_ptr<U> ptr) : ptr_(std::move(ptr))
{
}
template <class U>
requires(!std::is_same_v<U, T>) && std::is_convertible_v<U *, T *>
Nullable(const Nullable<U> &other) : ptr_(other.get())
{
}
template <class U>
requires(!std::is_same_v<U, T>) && std::is_convertible_v<U *, T *>
Nullable(const NotNull<U> &other) : ptr_(other.get())
{
}
const pointer_type &get() const noexcept { return ptr_; }
T *operator->() const noexcept { return ptr_.get(); }
T &operator*() const noexcept { return *get(); }
explicit operator bool() const noexcept { return ptr_ != nullptr; }
T &value() const
{
Preconditions::checkState(ptr_ != nullptr, "Nullable holds no value.");
return *ptr_;
}
pointer_type value_or(pointer_type default_value) const { return ptr_ ? ptr_ : std::move(default_value); }
bool operator==(std::nullptr_t) const noexcept { return ptr_ == nullptr; }
private:
std::shared_ptr<T> ptr_;
};
// Handle-to-handle comparisons (pointer identity), provided for both wrappers so they can be used as
// keys in ordered/unordered containers. These delegate to the underlying shared_ptr comparisons.
#define ENDSTONE_DEFINE_PTR_COMPARISONS(Wrapper) \
template <class T, class U> \
bool operator==(const Wrapper<T> &lhs, const Wrapper<U> &rhs) noexcept \
{ \
return lhs.get() == rhs.get(); \
} \
template <class T, class U> \
bool operator!=(const Wrapper<T> &lhs, const Wrapper<U> &rhs) noexcept \
{ \
return lhs.get() != rhs.get(); \
} \
template <class T, class U> \
bool operator<(const Wrapper<T> &lhs, const Wrapper<U> &rhs) noexcept \
{ \
return lhs.get() < rhs.get(); \
} \
template <class T, class U> \
bool operator<=(const Wrapper<T> &lhs, const Wrapper<U> &rhs) noexcept \
{ \
return lhs.get() <= rhs.get(); \
} \
template <class T, class U> \
bool operator>(const Wrapper<T> &lhs, const Wrapper<U> &rhs) noexcept \
{ \
return lhs.get() > rhs.get(); \
} \
template <class T, class U> \
bool operator>=(const Wrapper<T> &lhs, const Wrapper<U> &rhs) noexcept \
{ \
return lhs.get() >= rhs.get(); \
}
ENDSTONE_DEFINE_PTR_COMPARISONS(NotNull)
ENDSTONE_DEFINE_PTR_COMPARISONS(Nullable)
#undef ENDSTONE_DEFINE_PTR_COMPARISONS
} // namespace endstone
template <class T>
struct std::hash<endstone::NotNull<T>> {
std::size_t operator()(const endstone::NotNull<T> &value) const noexcept
{
return std::hash<std::shared_ptr<T>>{}(value.get());
}
};
template <class T>
struct std::hash<endstone::Nullable<T>> {
std::size_t operator()(const endstone::Nullable<T> &value) const noexcept
{
return std::hash<std::shared_ptr<T>>{}(value.get());
}
};