Skip to content

Instantly share code, notes, and snippets.

@DrkWithT
Created June 13, 2024 05:59
Show Gist options
  • Save DrkWithT/07768afd56accd456095d4902a8eb83f to your computer and use it in GitHub Desktop.
Save DrkWithT/07768afd56accd456095d4902a8eb83f to your computer and use it in GitHub Desktop.
A toy C++ Any implementation for educational purposes.
#ifndef MY_ANY_HPP
#define MY_ANY_HPP
#include <stdexcept>
#include <type_traits>
#include <utility>
#include <memory>
#include <typeinfo>
/*
GitHub: DrkWithT
Replit: D3rkPlusPlus
A remake of std::any from the standard library of C++17. :)
Inspired by: https://codereview.stackexchange.com/questions/219075/implementation-of-stdany
*/
class Any
{
private:
/* Polymorphic storage classtypes with wrapped value and type info. */
struct IStorage
{
virtual ~IStorage() = default;
virtual const std::type_info& getTypeInfo() const = 0;
virtual std::unique_ptr<IStorage> getClone() = 0;
virtual const void* getRawPtr() const = 0;
};
template <typename ValueType>
struct StorageImpl : public IStorage
{
ValueType value;
constexpr StorageImpl()
: value {} {}
StorageImpl(ValueType& arg)
: value (std::forward<const ValueType&>(arg)) {}
StorageImpl(ValueType&& arg)
: value (std::forward(arg)) {}
const std::type_info& getTypeInfo() const override
{
return typeid(ValueType);
}
std::unique_ptr<IStorage> getClone() override
{
return std::make_unique<StorageImpl>(std::forward<ValueType&>(value));
}
const void* getRawPtr() const override
{
return &value;
}
};
/* Storage smart ptr. does RAII for easy cleanup of whatever value within no matter its type! */
std::unique_ptr<IStorage> storage_ptr;
public:
/* Helper Methods */
[[nodiscard]] bool hasValue() const { return storage_ptr != nullptr; }
template <typename CheckType>
[[nodiscard]] bool hasType() const
{
if (!hasValue())
return false;
return typeid(CheckType) == storage_ptr->getTypeInfo();
}
void swapWith(Any& other) noexcept
{
this->storage_ptr.swap(other.storage_ptr);
}
/* Constructors */
constexpr Any()
: storage_ptr {nullptr} {}
template <typename ArgType>
Any(ArgType& arg)
: storage_ptr (std::make_unique<StorageImpl<ArgType>>(arg)) {}
template <typename ArgType>
Any(ArgType&& arg)
: storage_ptr(std::make_unique<StorageImpl<ArgType>>(std::forward<ArgType>(arg))) {}
Any(const Any& other)
{
if (&other == this)
return;
storage_ptr = (other.hasValue())
? other.storage_ptr->getClone()
: nullptr;
}
Any& operator=(const Any& other)
{
if (&other == this)
return *this;
storage_ptr = (other.hasValue())
? other.storage_ptr->getClone()
: nullptr;
return *this;
}
Any(Any&& x_other) noexcept
: storage_ptr (std::move(x_other.storage_ptr)) {}
Any& operator=(Any&& x_other) noexcept
{
storage_ptr = std::move(x_other.storage_ptr);
return *this;
}
/* Helper Functions */
template <typename ResultType>
friend ResultType unpackAny(const Any& arg)
{
if (arg.hasType<ResultType>())
{
if (arg.hasValue())
{
const ResultType* data_ptr = static_cast<const ResultType*>(arg.storage_ptr->getRawPtr());
return *data_ptr;
}
}
throw std::invalid_argument {"Any: No value or invalid type!"};
}
};
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment