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