Compare commits

...

4 Commits

Author SHA1 Message Date
Carl Keinath a538f3757e Merge branch 'debian/latest' into 'debian/latest'
new upstream version 0.9.0

See merge request NyxTrail/hyprutils!3
2025-10-06 06:24:38 +00:00
Carl Keinath d947729d68
release 0.10.0 to unstable 2025-10-06 08:22:10 +02:00
Carl Keinath c9d9f5c1de Update upstream source from tag 'upstream/0.10.0'
Update to upstream version '0.10.0'
with Debian dir 65fa022fab
2025-10-06 08:14:28 +02:00
Carl Keinath 91e09ff1e1 New upstream version 0.10.0 2025-10-06 08:14:28 +02:00
13 changed files with 161 additions and 107 deletions

View File

@ -50,7 +50,7 @@ target_include_directories(
PUBLIC "./include"
PRIVATE "./src")
set_target_properties(hyprutils PROPERTIES VERSION ${hyprutils_VERSION}
SOVERSION 8)
SOVERSION 9)
target_link_libraries(hyprutils PkgConfig::deps)
# tests

View File

@ -1 +1 @@
0.9.0
0.10.0

6
debian/changelog vendored
View File

@ -1,10 +1,10 @@
hyprutils (0.9.0-0.1) unstable; urgency=medium
hyprutils (0.10.0-0.1) unstable; urgency=medium
* Non-maintainer upload
* New upstream release (Closes: #1117181)
* Breaking ABI changes: updated soversion to 8
* Breaking ABI changes: updated soversion to 9
-- Carl Keinath <carl.keinath@gmail.com> Sat, 04 Oct 2025 10:58:35 +0200
-- Carl Keinath <carl.keinath@gmail.com> Mon, 06 Oct 2025 08:22:04 +0200
hyprutils (0.8.4-0.1) unstable; urgency=medium

4
debian/control vendored
View File

@ -17,7 +17,7 @@ Section: libdevel
Architecture: any
Multi-Arch: same
Depends:
libhyprutils8 (= ${binary:Version}),
libhyprutils9 (= ${binary:Version}),
${misc:Depends},
Description: Utilities used across the Hyprland ecosystem (development files)
Hyprutils is a small C++ library for utilities used across the Hyprland
@ -25,7 +25,7 @@ Description: Utilities used across the Hyprland ecosystem (development files)
.
This package contains the development files.
Package: libhyprutils8
Package: libhyprutils9
Architecture: any
Multi-Arch: same
Depends:

View File

@ -23,12 +23,11 @@
namespace Hyprutils::Memory {
namespace Atomic_ {
template <typename T>
class impl : public Impl_::impl<T> {
class impl : public Impl_::impl_base {
std::recursive_mutex m_mutex;
public:
impl(T* data, bool lock = true) noexcept : Impl_::impl<T>(data, lock) {
impl(void* data, DeleteFn deleter) noexcept : Impl_::impl_base(data, deleter) {
;
}
@ -55,7 +54,13 @@ namespace Hyprutils::Memory {
using validHierarchy = std::enable_if_t<std::is_assignable_v<CAtomicSharedPointer<T>&, X>, CAtomicSharedPointer&>;
public:
explicit CAtomicSharedPointer(Impl_::impl_base* impl) noexcept : m_ptr(impl) {}
explicit CAtomicSharedPointer(T* object) noexcept : m_ptr(new Atomic_::impl(sc<void*>(object), _delete)) {
;
}
CAtomicSharedPointer(Impl_::impl_base* impl) noexcept : m_ptr(impl) {
;
}
CAtomicSharedPointer(const CAtomicSharedPointer<T>& ref) {
if (!ref.m_ptr.impl_)
@ -141,7 +146,7 @@ namespace Hyprutils::Memory {
// -> must unlock BEFORE reset
// not last ref?
// -> must unlock AFTER reset
auto& mutex = sc<Atomic_::impl<T>*>(m_ptr.impl_)->getMutex();
auto& mutex = sc<Atomic_::impl*>(m_ptr.impl_)->getMutex();
mutex.lock();
if (m_ptr.impl_->ref() > 1) {
@ -152,7 +157,11 @@ namespace Hyprutils::Memory {
if (m_ptr.impl_->wref() == 0) {
mutex.unlock(); // Don't hold the mutex when destroying it
m_ptr.reset();
m_ptr.impl_->destroy();
delete sc<Atomic_::impl*>(m_ptr.impl_);
m_ptr.impl_ = nullptr;
// mutex invalid
return;
} else {
@ -163,12 +172,18 @@ namespace Hyprutils::Memory {
// To avoid this altogether, keep a weak pointer here.
// This guarantees that impl_ is still valid after the reset.
CWeakPointer<T> guard = m_ptr;
m_ptr.reset();
m_ptr.reset(); // destroys the data
// Now we can safely check if guard is the last wref.
if (guard.impl_->wref() == 1) {
mutex.unlock();
return; // ~guard destroys impl_ and mutex
// destroy impl_ (includes the mutex)
delete sc<Atomic_::impl*>(guard.impl_);
guard.impl_ = nullptr;
// mutex invalid
return;
}
guard.reset();
@ -205,8 +220,12 @@ namespace Hyprutils::Memory {
}
private:
static void _delete(void* p) {
std::default_delete<T>{}(sc<T*>(p));
}
std::lock_guard<std::recursive_mutex> implLockGuard() const {
return sc<Atomic_::impl<T>*>(m_ptr.impl_)->lockGuard();
return sc<Atomic_::impl*>(m_ptr.impl_)->lockGuard();
}
CSharedPointer<T> m_ptr;
@ -312,11 +331,13 @@ namespace Hyprutils::Memory {
// -> must unlock BEFORE reset
// not last ref?
// -> must unlock AFTER reset
auto& mutex = sc<Atomic_::impl<T>*>(m_ptr.impl_)->getMutex();
auto& mutex = sc<Atomic_::impl*>(m_ptr.impl_)->getMutex();
mutex.lock();
if (m_ptr.impl_->ref() == 0 && m_ptr.impl_->wref() == 1) {
mutex.unlock();
m_ptr.reset();
delete sc<Atomic_::impl*>(m_ptr.impl_);
m_ptr.impl_ = nullptr;
// mutex invalid
return;
}
@ -375,7 +396,7 @@ namespace Hyprutils::Memory {
private:
std::lock_guard<std::recursive_mutex> implLockGuard() const {
return sc<Atomic_::impl<T>*>(m_ptr.impl_)->lockGuard();
return sc<Atomic_::impl*>(m_ptr.impl_)->lockGuard();
}
CWeakPointer<T> m_ptr;
@ -387,7 +408,7 @@ namespace Hyprutils::Memory {
};
template <typename U, typename... Args>
static CAtomicSharedPointer<U> makeAtomicShared(Args&&... args) {
return CAtomicSharedPointer<U>(new Atomic_::impl<U>(new U(std::forward<Args>(args)...)));
[[nodiscard]] inline CAtomicSharedPointer<U> makeAtomicShared(Args&&... args) {
return CAtomicSharedPointer<U>(new U(std::forward<Args>(args)...));
}
}

View File

@ -8,44 +8,71 @@ namespace Hyprutils {
namespace Impl_ {
class impl_base {
public:
virtual ~impl_base() = default;
using DeleteFn = void (*)(void*);
virtual void inc() noexcept = 0;
virtual void dec() noexcept = 0;
virtual void incWeak() noexcept = 0;
virtual void decWeak() noexcept = 0;
virtual unsigned int ref() noexcept = 0;
virtual unsigned int wref() noexcept = 0;
virtual void destroy() noexcept = 0;
virtual bool destroying() noexcept = 0;
virtual bool dataNonNull() noexcept = 0;
virtual bool lockable() noexcept = 0;
virtual void* getData() noexcept = 0;
};
template <typename T>
class impl : public impl_base {
public:
impl(T* data, bool lock = true) noexcept : _lockable(lock), _data(data) {
impl_base(void* data, DeleteFn deleter, bool lock = true) noexcept : _lockable(lock), _data(data), _deleter(deleter) {
;
}
void inc() noexcept {
_ref++;
}
void dec() noexcept {
_ref--;
}
void incWeak() noexcept {
_weak++;
}
void decWeak() noexcept {
_weak--;
}
unsigned int ref() noexcept {
return _ref;
}
unsigned int wref() noexcept {
return _weak;
}
void destroy() noexcept {
_destroy();
}
bool destroying() noexcept {
return _destroying;
}
bool lockable() noexcept {
return _lockable;
}
bool dataNonNull() noexcept {
return _data != nullptr;
}
void* getData() noexcept {
return _data;
}
~impl_base() {
destroy();
}
private:
/* strong refcount */
unsigned int _ref = 0;
/* weak refcount */
unsigned int _weak = 0;
/* if this is lockable (shared) */
bool _lockable = true;
bool _lockable = true;
T* _data = nullptr;
void* _data = nullptr;
friend void swap(impl*& a, impl*& b) {
impl* tmp = a;
a = b;
b = tmp;
}
/* if the destructor was called,
/* if the destructor was called,
creating shared_ptrs is no longer valid */
bool _destroying = false;
@ -63,56 +90,7 @@ namespace Hyprutils {
_destroying = false;
}
std::default_delete<T> _deleter{};
//
virtual void inc() noexcept {
_ref++;
}
virtual void dec() noexcept {
_ref--;
}
virtual void incWeak() noexcept {
_weak++;
}
virtual void decWeak() noexcept {
_weak--;
}
virtual unsigned int ref() noexcept {
return _ref;
}
virtual unsigned int wref() noexcept {
return _weak;
}
virtual void destroy() noexcept {
_destroy();
}
virtual bool destroying() noexcept {
return _destroying;
}
virtual bool lockable() noexcept {
return _lockable;
}
virtual bool dataNonNull() noexcept {
return _data != nullptr;
}
virtual void* getData() noexcept {
return _data;
}
virtual ~impl() {
destroy();
}
DeleteFn _deleter = nullptr;
};
}
}

View File

@ -28,7 +28,7 @@ namespace Hyprutils {
/* creates a new shared pointer managing a resource
avoid calling. Could duplicate ownership. Prefer makeShared */
explicit CSharedPointer(T* object) noexcept : impl_(new Impl_::impl<T>(object)) {
explicit CSharedPointer(T* object) noexcept : impl_(new Impl_::impl_base(sc<void*>(object), _delete)) {
increment();
}
@ -140,6 +140,10 @@ namespace Hyprutils {
Impl_::impl_base* impl_ = nullptr;
private:
static void _delete(void* p) {
std::default_delete<T>{}(sc<T*>(p));
}
/*
no-op if there is no impl_
may delete the stored object if ref == 0

View File

@ -22,7 +22,7 @@ namespace Hyprutils {
/* creates a new unique pointer managing a resource
avoid calling. Could duplicate ownership. Prefer makeUnique */
explicit CUniquePointer(T* object) noexcept : impl_(new Impl_::impl<T>(object, false)) {
explicit CUniquePointer(T* object) noexcept : impl_(new Impl_::impl_base(sc<void*>(object), [](void* p) { std::default_delete<T>{}(sc<T*>(p)); }, false)) {
increment();
}

View File

@ -145,16 +145,21 @@ CRegion& Hyprutils::Math::CRegion::scale(const Vector2D& scale) {
if (scale == Vector2D{1, 1})
return *this;
int rectsNum = 0;
auto RECTSARR = pixman_region32_rectangles(&m_rRegion, &rectsNum);
int rectsNum = 0;
auto RECTSARR = pixman_region32_rectangles(&m_rRegion, &rectsNum);
std::vector<pixman_box32_t> boxes;
boxes.resize(rectsNum);
for (int i = 0; i < rectsNum; ++i) {
RECTSARR[i].x1 = std::floor(RECTSARR[i].x1 * scale.x);
RECTSARR[i].x2 = std::ceil(RECTSARR[i].x2 * scale.x);
RECTSARR[i].y1 = std::floor(RECTSARR[i].y1 * scale.y);
RECTSARR[i].y2 = std::ceil(RECTSARR[i].y2 * scale.y);
boxes[i].x1 = std::floor(RECTSARR[i].x1 * scale.x);
boxes[i].x2 = std::ceil(RECTSARR[i].x2 * scale.x);
boxes[i].y1 = std::floor(RECTSARR[i].y1 * scale.y);
boxes[i].y2 = std::ceil(RECTSARR[i].y2 * scale.y);
}
pixman_region32_fini(&m_rRegion);
pixman_region32_init_rects(&m_rRegion, boxes.data(), boxes.size());
return *this;
}

View File

@ -104,6 +104,20 @@ int main(int argc, char** argv, char** envp) {
EXPECT(std::abs(expected.getMatrix().at(8) - matrixBox.getMatrix().at(8)) < 0.1, true);
}
// Test Region Scaling
{
CRegion rg(CBox{{20, 20}, {40, 40}});
auto extents = rg.getExtents();
EXPECT_VECTOR2D(extents.pos(), Vector2D(20, 20));
EXPECT_VECTOR2D(extents.size(), Vector2D(40, 40));
rg.scale(2);
extents = rg.getExtents();
EXPECT_VECTOR2D(extents.pos(), Vector2D(40, 40));
EXPECT_VECTOR2D(extents.size(), Vector2D(80, 80));
}
{
Vector2D original(30, 40);
Vector2D monitorSize(100, 200);

View File

@ -92,6 +92,38 @@ static int testAtomicImpl() {
foo->bar = foo;
}
{ // This tests destroying the data when storing the base class of a type
class ITest {
public:
size_t num = 0;
ITest() : num(1234) {};
};
class CA : public ITest {
public:
size_t num2 = 0;
CA() : ITest(), num2(4321) {};
};
class CB : public ITest {
public:
int num2 = 0;
CB() : ITest(), num2(-1) {};
};
ASP<ITest> genericAtomic = nullptr;
SP<ITest> genericNormal = nullptr;
{
auto derivedAtomic = makeAtomicShared<CA>();
auto derivedNormal = makeShared<CA>();
genericAtomic = derivedAtomic;
genericNormal = derivedNormal;
}
EXPECT(!!genericAtomic, true);
EXPECT(!!genericNormal, true);
}
return ret;
}
@ -113,6 +145,7 @@ int main(int argc, char** argv, char** envp) {
EXPECT(intPtr.strongRef(), 1);
EXPECT(*weak, 10);
EXPECT(weak.expired(), false);
EXPECT(!!weak.lock(), true);
EXPECT(*weakUnique, 420);
EXPECT(weakUnique.expired(), false);
EXPECT(intUnique.impl_->wref(), 1);
@ -149,6 +182,5 @@ int main(int argc, char** argv, char** envp) {
EXPECT(*intPtr2, 10);
EXPECT(testAtomicImpl(), 0);
return ret;
}