From a2d6944249cdb05734b28fb6147337e385eb58e4 Mon Sep 17 00:00:00 2001 From: King_DuckZ Date: Sat, 23 Aug 2025 12:36:29 +0100 Subject: [PATCH] New PackedPointer class --- include/duckhandy/bitfield_pack.hpp | 2 +- include/duckhandy/packed_pointer.hpp | 194 +++++++++++++++++++++++++++ 2 files changed, 195 insertions(+), 1 deletion(-) create mode 100644 include/duckhandy/packed_pointer.hpp diff --git a/include/duckhandy/bitfield_pack.hpp b/include/duckhandy/bitfield_pack.hpp index 1311571..a140fbe 100644 --- a/include/duckhandy/bitfield_pack.hpp +++ b/include/duckhandy/bitfield_pack.hpp @@ -1,4 +1,4 @@ -/* Copyright 2016-2024 Michele Santullo +/* Copyright 2016-2025 Michele Santullo * This file is part of "duckhandy". * * "duckhandy" is free software: you can redistribute it and/or modify diff --git a/include/duckhandy/packed_pointer.hpp b/include/duckhandy/packed_pointer.hpp new file mode 100644 index 0000000..84aa8de --- /dev/null +++ b/include/duckhandy/packed_pointer.hpp @@ -0,0 +1,194 @@ +/* Copyright 2016-2025 Michele Santullo + * This file is part of "duckhandy". + * + * "duckhandy" 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. + * + * "duckhandy" 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 "duckhandy". If not, see . + */ + +#ifndef id83CE9FAB90684250B98EA584C548E13F +#define id83CE9FAB90684250B98EA584C548E13F + +#include "bitfield_pack.hpp" +#include +#include +#include + +namespace dhandy { +namespace implem { + +//This monster expression is just the one-liner version of this +//implementation of log2: +//unsigned int v; // 32-bit value to find the log2 of +//register unsigned int r; // result of log2(v) will go here +//register unsigned int shift; +// +//r = (v > 0xFFFF) << 4; v >>= r; +//shift = (v > 0xFF ) << 3; v >>= shift; r |= shift; +//shift = (v > 0xF ) << 2; v >>= shift; r |= shift; +//shift = (v > 0x3 ) << 1; v >>= shift; r |= shift; +// r |= (v >> 1); +//see https://graphics.stanford.edu/~seander/bithacks.html#IntegerLog for +//an explanation of that. +//This is a shorter version of it but it only works if the input is a power +//of 2: +//(((((NUM&0xAAAAAAAA)!=0)|((NUM&0xFFFF0000)!=0)<<4)|((NUM&0xFF00FF00)!=0)<< +//3)|((NUM&0xF0F0F0F0)!=0)<<2)|((NUM&0xCCCCCCCC)!=0)<<1 +//Source for that is also available at the page linked above. +template const constexpr std::size_t + pointer_unused_bit_count = + ((((((NUM > 0xFFFF) << 4) | (((NUM >> ((NUM > 0xFFFF) << 4)) > 0xFF) << + 3)) | ((((NUM >> ((NUM > 0xFFFF) << 4)) >> (((NUM >> ((NUM > 0xFFFF) << + 4)) > 0xFF) << 3)) > 0xF) << 2)) | (((((NUM >> ((NUM > 0xFFFF) << 4)) >> + (((NUM >> ((NUM > 0xFFFF) << 4)) > 0xFF) << 3)) >> ((((NUM >> ((NUM > + 0xFFFF) << 4)) >> (((NUM >> ((NUM > 0xFFFF) << 4)) > 0xFF) << 3)) > 0xF) + << 2)) > 0x3) << 1)) | (((((NUM >> ((NUM > 0xFFFF) << 4)) >> (((NUM >> ( + (NUM > 0xFFFF) << 4)) > 0xFF) << 3)) >> ((((NUM >> ((NUM > 0xFFFF) << 4) + ) >> (((NUM >> ((NUM > 0xFFFF) << 4)) > 0xFF) << 3)) > 0xF) << 2)) >> (( + (((NUM >> ((NUM > 0xFFFF) << 4)) >> (((NUM >> ((NUM > 0xFFFF) << 4)) > + 0xFF) << 3)) >> ((((NUM >> ((NUM > 0xFFFF) << 4)) >> (((NUM >> ((NUM > + 0xFFFF) << 4)) > 0xFF) << 3)) > 0xF) << 2)) > 0x3) << 1)) >> 1)) +; + +template +BitfieldPack< + std::uintptr_t, + sizeof(std::uintptr_t) * CHAR_BIT - sizeof...(S), (S+1)/(S+1)... +> +guess_bitfield_type (std::index_sequence); + +template +using BaseBitfieldPackForPackedPointer = decltype( + implem::guess_bitfield_type( + std::make_index_sequence>() + ) +); +} //namespace implem + +template +class PackedPointer : private implem::BaseBitfieldPackForPackedPointer { + static_assert(sizeof(T*) == sizeof(std::uintptr_t), "Mismatching int/pointer size"); + typedef implem::BaseBitfieldPackForPackedPointer parent_type; +public: + static const constexpr std::size_t FlagsCount = parent_type::TotalEntries - 1; + + PackedPointer(); + PackedPointer (T* ptr); + ~PackedPointer() = default; + + operator T*() const; + operator bool() const; + template bool flag () const; + template void set_flag (bool v); + + PackedPointer& operator= (T* ptr); + T* operator->(); + const T* operator->() const; + T& operator*(); + const T& operator*() const; + bool operator== (const PackedPointer& other) const; + bool operator== (T* other) const; + bool operator!= (const PackedPointer& other) const; + bool operator!= (T* other) const; + +private: + //static const constexpr uintptr_t PtrMask = static_cast(-1) << FlagsCount; +}; + +template const constexpr std::size_t PackedPointer::FlagsCount; +//template const constexpr std::uintptr_t PackedPointer::PtrMask; + +template +PackedPointer::PackedPointer() : + PackedPointer(nullptr) +{ +} + +template +PackedPointer::PackedPointer (T* ptr) : + parent_type(0) +{ + (*this) = ptr; +} + +template +PackedPointer::operator T*() const { + return reinterpret_cast(this->get(0) << FlagsCount); +} + +template +PackedPointer::operator bool() const { + return static_cast(*this) != nullptr; +} + +template +template +bool PackedPointer::flag() const { + static_assert(Idx < FlagsCount, "Index out of range"); + return static_cast(this->get(Idx + 1)); +} + +template +template +void PackedPointer::set_flag (bool v) { + static_assert(Idx < FlagsCount, "Index out of range"); + this->set(Idx + 1, (v ? 1 : 0)); +} + +template +PackedPointer& PackedPointer::operator= (T* ptr) { + this->set(0, reinterpret_cast(ptr) >> FlagsCount); + return *this; +} + +template +T* PackedPointer::operator->() { + return static_cast(*this); +} + +template +const T* PackedPointer::operator->() const { + return static_cast(*this); +} + +template +T& PackedPointer::operator*() { + return *static_cast(*this); +} + +template +const T& PackedPointer::operator*() const { + return *static_cast(*this); +} + +template +bool PackedPointer::operator== (const PackedPointer& other) const { + return this == &other or static_cast(*this) == static_cast(other); +} + +template +bool PackedPointer::operator== (T* other) const { + return static_cast(*this) == other; +} + +template +bool PackedPointer::operator!= (const PackedPointer& other) const { + return not this->operator==(other); +} + +template +bool PackedPointer::operator!= (T* other) const { + return not this->operator==(other); +} +} //namepace dhandy + +#endif