New upstream version 0.2.2

This commit is contained in:
alan (NyxTrail) 2024-09-22 04:28:52 +00:00
parent d322427bc5
commit aa8b6130dd
21 changed files with 385 additions and 55 deletions

10
.gitignore vendored
View File

@ -34,3 +34,13 @@
build/ build/
.vscode/ .vscode/
.cache/ .cache/
.cmake/
CMakeCache.txt
CMakeFiles/
CTestTestfile.cmake
DartConfiguration.tcl
Makefile
cmake_install.cmake
compile_commands.json
hyprutils.pc

View File

@ -1,12 +1,13 @@
cmake_minimum_required(VERSION 3.19) cmake_minimum_required(VERSION 3.19)
set(HYPRUTILS_VERSION "0.1.5") file(READ "${CMAKE_SOURCE_DIR}/VERSION" VER_RAW)
string(STRIP ${VER_RAW} HYPRUTILS_VERSION)
add_compile_definitions(HYPRUTILS_VERSION="${HYPRUTILS_VERSION}") add_compile_definitions(HYPRUTILS_VERSION="${HYPRUTILS_VERSION}")
project(hyprutils project(
VERSION ${HYPRUTILS_VERSION} hyprutils
DESCRIPTION "Small C++ library for utilities used across the Hypr* ecosystem" VERSION ${HYPRUTILS_VERSION}
) DESCRIPTION "Small C++ library for utilities used across the Hypr* ecosystem")
include(CTest) include(CTest)
include(GNUInstallDirs) include(GNUInstallDirs)
@ -20,11 +21,11 @@ configure_file(hyprutils.pc.in hyprutils.pc @ONLY)
set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD 23)
if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG) if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
message(STATUS "Configuring hyprutils in Debug") message(STATUS "Configuring hyprutils in Debug")
add_compile_definitions(HYPRLAND_DEBUG) add_compile_definitions(HYPRLAND_DEBUG)
else() else()
add_compile_options(-O3) add_compile_options(-O3)
message(STATUS "Configuring hyprutils in Release") message(STATUS "Configuring hyprutils in Release")
endif() endif()
file(GLOB_RECURSE SRCFILES CONFIGURE_DEPENDS "src/*.cpp" "include/*.hpp") file(GLOB_RECURSE SRCFILES CONFIGURE_DEPENDS "src/*.cpp" "include/*.hpp")
@ -34,14 +35,12 @@ find_package(PkgConfig REQUIRED)
pkg_check_modules(deps REQUIRED IMPORTED_TARGET pixman-1) pkg_check_modules(deps REQUIRED IMPORTED_TARGET pixman-1)
add_library(hyprutils SHARED ${SRCFILES}) add_library(hyprutils SHARED ${SRCFILES})
target_include_directories( hyprutils target_include_directories(
PUBLIC "./include" hyprutils
PRIVATE "./src" PUBLIC "./include"
) PRIVATE "./src")
set_target_properties(hyprutils PROPERTIES set_target_properties(hyprutils PROPERTIES VERSION ${hyprutils_VERSION}
VERSION ${hyprutils_VERSION} SOVERSION 1)
SOVERSION 0
)
target_link_libraries(hyprutils PkgConfig::deps) target_link_libraries(hyprutils PkgConfig::deps)
# tests # tests
@ -49,25 +48,38 @@ add_custom_target(tests)
add_executable(hyprutils_memory "tests/memory.cpp") add_executable(hyprutils_memory "tests/memory.cpp")
target_link_libraries(hyprutils_memory PRIVATE hyprutils PkgConfig::deps) target_link_libraries(hyprutils_memory PRIVATE hyprutils PkgConfig::deps)
add_test(NAME "Memory" WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tests COMMAND hyprutils_memory "memory") add_test(
NAME "Memory"
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tests
COMMAND hyprutils_memory "memory")
add_dependencies(tests hyprutils_memory) add_dependencies(tests hyprutils_memory)
add_executable(hyprutils_string "tests/string.cpp") add_executable(hyprutils_string "tests/string.cpp")
target_link_libraries(hyprutils_string PRIVATE hyprutils PkgConfig::deps) target_link_libraries(hyprutils_string PRIVATE hyprutils PkgConfig::deps)
add_test(NAME "String" WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tests COMMAND hyprutils_string "string") add_test(
NAME "String"
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tests
COMMAND hyprutils_string "string")
add_dependencies(tests hyprutils_string) add_dependencies(tests hyprutils_string)
add_executable(hyprutils_signal "tests/signal.cpp") add_executable(hyprutils_signal "tests/signal.cpp")
target_link_libraries(hyprutils_signal PRIVATE hyprutils PkgConfig::deps) target_link_libraries(hyprutils_signal PRIVATE hyprutils PkgConfig::deps)
add_test(NAME "Signal" WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tests COMMAND hyprutils_signal "signal") add_test(
NAME "Signal"
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tests
COMMAND hyprutils_signal "signal")
add_dependencies(tests hyprutils_signal) add_dependencies(tests hyprutils_signal)
add_executable(hyprutils_math "tests/math.cpp") add_executable(hyprutils_math "tests/math.cpp")
target_link_libraries(hyprutils_math PRIVATE hyprutils PkgConfig::deps) target_link_libraries(hyprutils_math PRIVATE hyprutils PkgConfig::deps)
add_test(NAME "Math" WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tests COMMAND hyprutils_math "math") add_test(
NAME "Math"
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/tests
COMMAND hyprutils_math "math")
add_dependencies(tests hyprutils_math) add_dependencies(tests hyprutils_math)
# Installation # Installation
install(TARGETS hyprutils) install(TARGETS hyprutils)
install(DIRECTORY "include/hyprutils" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) install(DIRECTORY "include/hyprutils" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
install(FILES ${CMAKE_BINARY_DIR}/hyprutils.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) install(FILES ${CMAKE_BINARY_DIR}/hyprutils.pc
DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)

1
VERSION Normal file
View File

@ -0,0 +1 @@
0.2.2

View File

@ -2,11 +2,11 @@
"nodes": { "nodes": {
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1717602782, "lastModified": 1721138476,
"narHash": "sha256-pL9jeus5QpX5R+9rsp3hhZ+uplVHscNJh8n8VpqscM0=", "narHash": "sha256-+W5eZOhhemLQxelojLxETfbFbc19NWawsXBlapYpqIA=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "e8057b67ebf307f01bdcc8fba94d94f75039d1f6", "rev": "ad0b5eed1b6031efaed382844806550c3dcb4206",
"type": "github" "type": "github"
}, },
"original": { "original": {

View File

@ -23,13 +23,15 @@
(builtins.substring 4 2 longDate) (builtins.substring 4 2 longDate)
(builtins.substring 6 2 longDate) (builtins.substring 6 2 longDate)
]); ]);
version = lib.removeSuffix "\n" (builtins.readFile ./VERSION);
in { in {
overlays = { overlays = {
default = self.overlays.hyprutils; default = self.overlays.hyprutils;
hyprutils = final: prev: { hyprutils = final: prev: {
hyprutils = final.callPackage ./nix/default.nix { hyprutils = final.callPackage ./nix/default.nix {
stdenv = final.gcc13Stdenv; stdenv = final.gcc13Stdenv;
version = "0.pre" + "+date=" + (mkDate (self.lastModifiedDate or "19700101")) + "_" + (self.shortRev or "dirty"); version = version + "+date=" + (mkDate (self.lastModifiedDate or "19700101")) + "_" + (self.shortRev or "dirty");
}; };
hyprutils-with-tests = final.hyprutils.override {doCheck = true;}; hyprutils-with-tests = final.hyprutils.override {doCheck = true;};
}; };

View File

@ -135,6 +135,12 @@ namespace Hyprutils::Math {
*/ */
Vector2D size() const; Vector2D size() const;
/**
* @brief Retrieves the size of the box offset by its position.
* @return Vector2D representing the bottom right extent of the box.
*/
Vector2D extent() const;
/** /**
* @brief Finds the closest point within the box to a given vector. * @brief Finds the closest point within the box to a given vector.
* @param vec Vector from which to find the closest point. * @param vec Vector from which to find the closest point.
@ -179,4 +185,4 @@ namespace Hyprutils::Math {
private: private:
CBox roundInternal(); CBox roundInternal();
}; };
} }

View File

@ -0,0 +1,110 @@
#pragma once
#include <cstdint>
namespace Hyprutils::Math {
/**
* @brief Flag set of box edges
*/
class CEdges {
public:
enum eEdges : uint8_t {
NONE = 0,
TOP = 1,
LEFT = 2,
BOTTOM = 4,
RIGHT = 8,
};
CEdges() = default;
CEdges(eEdges edges) : m_edges(edges) {}
CEdges(uint8_t edges) : m_edges(static_cast<eEdges>(edges)) {}
bool operator==(const CEdges& other) {
return m_edges == other.m_edges;
}
CEdges operator|(const CEdges& other) {
return m_edges | other.m_edges;
}
CEdges operator&(const CEdges& other) {
return m_edges & other.m_edges;
}
CEdges operator^(const CEdges& other) {
return m_edges ^ other.m_edges;
}
void operator|=(const CEdges& other) {
m_edges = (*this | other).m_edges;
}
void operator&=(const CEdges& other) {
m_edges = (*this & other).m_edges;
}
void operator^=(const CEdges& other) {
m_edges = (*this ^ other).m_edges;
}
/**
* @return if the edge set contains the top edge.
*/
bool top() {
return m_edges & TOP;
}
/**
* @return if the edge set contains the left edge.
*/
bool left() {
return m_edges & LEFT;
}
/**
* @return if the edge set contains the bottom edge.
*/
bool bottom() {
return m_edges & BOTTOM;
}
/**
* @return if the edge set contains the right edge.
*/
bool right() {
return m_edges & RIGHT;
}
/**
* @param top The state the top edge should be set to.
*/
void setTop(bool top) {
m_edges = static_cast<eEdges>((m_edges & ~TOP) | (TOP * top));
}
/**
* @param left The state the left edge should be set to.
*/
void setLeft(bool left) {
m_edges = static_cast<eEdges>((m_edges & ~LEFT) | (LEFT * left));
}
/**
* @param bottom The state the bottom edge should be set to.
*/
void setBottom(bool bottom) {
m_edges = static_cast<eEdges>((m_edges & ~BOTTOM) | (BOTTOM * bottom));
}
/**
* @param right The state the right edge should be set to.
*/
void setRight(bool right) {
m_edges = static_cast<eEdges>((m_edges & ~RIGHT) | (RIGHT * right));
}
eEdges m_edges = NONE;
};
}

View File

@ -49,6 +49,7 @@ namespace Hyprutils {
CRegion& invert(const CBox& box); CRegion& invert(const CBox& box);
CRegion& scale(float scale); CRegion& scale(float scale);
CRegion& scale(const Vector2D& scale); CRegion& scale(const Vector2D& scale);
CRegion& expand(double units);
CRegion& rationalize(); CRegion& rationalize();
CBox getExtents(); CBox getExtents();
bool containsPoint(const Vector2D& vec) const; bool containsPoint(const Vector2D& vec) const;

View File

@ -20,7 +20,7 @@ namespace Hyprutils {
namespace CSharedPointer_ { namespace CSharedPointer_ {
class impl_base { class impl_base {
public: public:
virtual ~impl_base(){}; virtual ~impl_base() {};
virtual void inc() noexcept = 0; virtual void inc() noexcept = 0;
virtual void dec() noexcept = 0; virtual void dec() noexcept = 0;
@ -31,6 +31,7 @@ namespace Hyprutils {
virtual void destroy() noexcept = 0; virtual void destroy() noexcept = 0;
virtual bool destroying() noexcept = 0; virtual bool destroying() noexcept = 0;
virtual bool dataNonNull() noexcept = 0; virtual bool dataNonNull() noexcept = 0;
virtual void* getData() noexcept = 0;
}; };
template <typename T> template <typename T>
@ -107,6 +108,10 @@ namespace Hyprutils {
} }
virtual bool dataNonNull() noexcept { virtual bool dataNonNull() noexcept {
return _data != nullptr;
}
virtual void* getData() noexcept {
return _data; return _data;
} }
@ -213,11 +218,11 @@ namespace Hyprutils {
} }
bool operator()(const CSharedPointer& lhs, const CSharedPointer& rhs) const { bool operator()(const CSharedPointer& lhs, const CSharedPointer& rhs) const {
return (uintptr_t)lhs.impl_ < (uintptr_t)rhs.impl_; return reinterpret_cast<uintptr_t>(lhs.impl_) < reinterpret_cast<uintptr_t>(rhs.impl_);
} }
bool operator<(const CSharedPointer& rhs) const { bool operator<(const CSharedPointer& rhs) const {
return (uintptr_t)impl_ < (uintptr_t)rhs.impl_; return reinterpret_cast<uintptr_t>(impl_) < reinterpret_cast<uintptr_t>(rhs.impl_);
} }
T* operator->() const { T* operator->() const {
@ -234,7 +239,7 @@ namespace Hyprutils {
} }
T* get() const { T* get() const {
return (T*)(impl_ ? static_cast<CSharedPointer_::impl<T>*>(impl_)->_data : nullptr); return impl_ ? static_cast<T*>(impl_->getData()) : nullptr;
} }
unsigned int strongRef() const { unsigned int strongRef() const {

View File

@ -80,7 +80,7 @@ namespace Hyprutils {
/* create a weak ptr from a shared ptr with assignment */ /* create a weak ptr from a shared ptr with assignment */
template <typename U> template <typename U>
validHierarchy<const CWeakPointer<U>&> operator=(const CSharedPointer<U>& rhs) { validHierarchy<const CWeakPointer<U>&> operator=(const CSharedPointer<U>& rhs) {
if ((uintptr_t)impl_ == (uintptr_t)rhs.impl_) if (reinterpret_cast<uintptr_t>(impl_) == reinterpret_cast<uintptr_t>(rhs.impl_))
return *this; return *this;
decrementWeak(); decrementWeak();
@ -139,15 +139,15 @@ namespace Hyprutils {
} }
bool operator()(const CWeakPointer& lhs, const CWeakPointer& rhs) const { bool operator()(const CWeakPointer& lhs, const CWeakPointer& rhs) const {
return (uintptr_t)lhs.impl_ < (uintptr_t)rhs.impl_; return reinterpret_cast<uintptr_t>(lhs.impl_) < reinterpret_cast<uintptr_t>(rhs.impl_);
} }
bool operator<(const CWeakPointer& rhs) const { bool operator<(const CWeakPointer& rhs) const {
return (uintptr_t)impl_ < (uintptr_t)rhs.impl_; return reinterpret_cast<uintptr_t>(impl_) < reinterpret_cast<uintptr_t>(rhs.impl_);
} }
T* get() const { T* get() const {
return (T*)(impl_ ? static_cast<CSharedPointer_::impl<T>*>(impl_)->_data : nullptr); return impl_ ? static_cast<T*>(impl_->getData()) : nullptr;
} }
T* operator->() const { T* operator->() const {

View File

@ -0,0 +1,42 @@
#pragma once
#include "../string/VarList.hpp"
#include <string>
#include <optional>
#include <utility>
namespace Hyprutils {
namespace Path {
/** Check whether a config in the form basePath/hypr/programName.conf exists.
@param basePath the path where the config will be searched
@param programName name of the program (and config file) to search for
*/
bool checkConfigExists(const std::string basePath, const std::string programName);
/** Constructs a full config path given the basePath and programName.
@param basePath the path where the config hypr/programName.conf is located
@param programName name of the program (and config file)
*/
std::string fullConfigPath(const std::string basePath, const std::string programName);
/** Retrieves the absolute path of the $HOME env variable.
*/
std::optional<std::string> getHome();
/** Retrieves a CVarList of paths from the $XDG_CONFIG_DIRS env variable.
*/
std::optional<String::CVarList> getXdgConfigDirs();
/** Retrieves the absolute path of the $XDG_CONFIG_HOME env variable.
*/
std::optional<std::string> getXdgConfigHome();
/** Searches for a config according to the XDG Base Directory specification.
Returns a pair of the full path to a config and the base path.
Returns std::nullopt in case of a non-existent value.
@param programName name of the program (and config file)
*/
using T = std::optional<std::string>;
std::pair<T, T> findConfig(const std::string programName);
}
}

View File

@ -12,7 +12,7 @@ namespace Hyprutils {
@param delim if delimiter is 's', use std::isspace @param delim if delimiter is 's', use std::isspace
@param removeEmpty remove empty args from argv @param removeEmpty remove empty args from argv
*/ */
CVarList(const std::string& in, const size_t maxSize = 0, const char delim = ',', const bool removeEmpty = false); CVarList(const std::string& in, const size_t lastArgNo = 0, const char delim = ',', const bool removeEmpty = false);
~CVarList() = default; ~CVarList() = default;

View File

@ -0,0 +1,17 @@
#pragma once
#include <functional>
namespace Hyprutils {
namespace Utils {
// calls a function when it goes out of scope
class CScopeGuard {
public:
CScopeGuard(const std::function<void()>& fn_);
~CScopeGuard();
private:
std::function<void()> fn;
};
};
};

View File

@ -199,23 +199,35 @@ Vector2D Hyprutils::Math::CBox::size() const {
return {w, h}; return {w, h};
} }
Vector2D Hyprutils::Math::CBox::extent() const {
return pos() + size();
}
Vector2D Hyprutils::Math::CBox::closestPoint(const Vector2D& vec) const { Vector2D Hyprutils::Math::CBox::closestPoint(const Vector2D& vec) const {
if (containsPoint(vec)) if (containsPoint(vec))
return vec; return vec;
Vector2D nv = vec; Vector2D nv = vec;
nv.x = std::clamp(nv.x, x, x + w); Vector2D maxPoint = {x + w - EPSILON, y + h - EPSILON};
nv.y = std::clamp(nv.y, y, y + h);
if (x < maxPoint.x)
nv.x = std::clamp(nv.x, x, maxPoint.x);
else
nv.x = x;
if (y < maxPoint.y)
nv.y = std::clamp(nv.y, y, maxPoint.y);
else
nv.y = y;
if (std::fabs(nv.x - x) < EPSILON) if (std::fabs(nv.x - x) < EPSILON)
nv.x = x; nv.x = x;
else if (std::fabs(nv.x - (x + w)) < EPSILON) else if (std::fabs(nv.x - (maxPoint.x)) < EPSILON)
nv.x = x + w; nv.x = maxPoint.x;
if (std::fabs(nv.y - y) < EPSILON) if (std::fabs(nv.y - y) < EPSILON)
nv.y = y; nv.y = y;
else if (std::fabs(nv.y - (y + h)) < EPSILON) else if (std::fabs(nv.y - (maxPoint.y)) < EPSILON)
nv.y = y + h; nv.y = maxPoint.y;
return nv; return nv;
} }

View File

@ -112,6 +112,19 @@ CRegion& Hyprutils::Math::CRegion::transform(const eTransform t, double w, doubl
return *this; return *this;
} }
CRegion& Hyprutils::Math::CRegion::expand(double units) {
auto rects = getRects();
clear();
for (auto& r : rects) {
CBox b{(double)r.x1 - units, (double)r.y1 - units, (double)r.x2 - r.x1 + units * 2, (double)r.y2 - r.y1 + units * 2};
add(b);
}
return *this;
}
CRegion& Hyprutils::Math::CRegion::rationalize() { CRegion& Hyprutils::Math::CRegion::rationalize() {
intersect(CBox{-MAX_REGION_SIDE, -MAX_REGION_SIDE, MAX_REGION_SIDE * 2, MAX_REGION_SIDE * 2}); intersect(CBox{-MAX_REGION_SIDE, -MAX_REGION_SIDE, MAX_REGION_SIDE * 2, MAX_REGION_SIDE * 2});
return *this; return *this;

81
src/path/Path.cpp Normal file
View File

@ -0,0 +1,81 @@
#include <hyprutils/path/Path.hpp>
#include <hyprutils/string/VarList.hpp>
#include <filesystem>
using namespace Hyprutils;
namespace Hyprutils::Path {
std::string fullConfigPath(std::string basePath, std::string programName) {
return basePath + "/hypr/" + programName + ".conf";
}
bool checkConfigExists(std::string basePath, std::string programName) {
return std::filesystem::exists(fullConfigPath(basePath, programName));
}
std::optional<std::string> getHome() {
static const auto homeDir = getenv("HOME");
if (!homeDir || !std::filesystem::path(homeDir).is_absolute())
return std::nullopt;
return std::string(homeDir).append("/.config");
}
std::optional<String::CVarList> getXdgConfigDirs() {
static const auto xdgConfigDirs = getenv("XDG_CONFIG_DIRS");
if (!xdgConfigDirs)
return std::nullopt;
static const auto xdgConfigDirsList = String::CVarList(xdgConfigDirs, 0, ':');
return xdgConfigDirsList;
}
std::optional<std::string> getXdgConfigHome() {
static const auto xdgConfigHome = getenv("XDG_CONFIG_HOME");
if (!xdgConfigHome || !std::filesystem::path(xdgConfigHome).is_absolute())
return std::nullopt;
return xdgConfigHome;
}
using T = std::optional<std::string>;
std::pair<T, T> findConfig(std::string programName) {
bool xdgConfigHomeExists = false;
static const auto xdgConfigHome = getXdgConfigHome();
if (xdgConfigHome.has_value()) {
xdgConfigHomeExists = true;
if (checkConfigExists(xdgConfigHome.value(), programName))
return std::make_pair(fullConfigPath(xdgConfigHome.value(), programName), xdgConfigHome);
}
bool homeExists = false;
static const auto home = getHome();
if (home.has_value()) {
homeExists = true;
if (checkConfigExists(home.value(), programName))
return std::make_pair(fullConfigPath(home.value(), programName), home);
}
static const auto xdgConfigDirs = getXdgConfigDirs();
if (xdgConfigDirs.has_value()) {
for (auto dir : xdgConfigDirs.value()) {
if (checkConfigExists(dir, programName))
return std::make_pair(fullConfigPath(dir, programName), std::nullopt);
}
}
if (checkConfigExists("/etc/xdg", programName))
return std::make_pair(fullConfigPath("/etc/xdg", programName), std::nullopt);
if (xdgConfigHomeExists)
return std::make_pair(std::nullopt, xdgConfigHome);
else if (homeExists)
return std::make_pair(std::nullopt, home);
return std::make_pair(std::nullopt, std::nullopt);
}
}

View File

@ -9,14 +9,10 @@ using namespace Hyprutils::Memory;
#define WP CWeakPointer #define WP CWeakPointer
void Hyprutils::Signal::CSignal::emit(std::any data) { void Hyprutils::Signal::CSignal::emit(std::any data) {
bool dirty = false;
std::vector<SP<CSignalListener>> listeners; std::vector<SP<CSignalListener>> listeners;
for (auto& l : m_vListeners) { for (auto& l : m_vListeners) {
if (l.expired()) { if (l.expired())
dirty = true;
continue; continue;
}
listeners.emplace_back(l.lock()); listeners.emplace_back(l.lock());
} }
@ -29,10 +25,9 @@ void Hyprutils::Signal::CSignal::emit(std::any data) {
for (auto& l : listeners) { for (auto& l : listeners) {
// if there is only one lock, it means the event is only held by the listeners // if there is only one lock, it means the event is only held by the listeners
// vector and was removed during our iteration // vector and was removed during our iteration
if (l.strongRef() == 1) { if (l.strongRef() == 1)
dirty = true;
continue; continue;
}
l->emit(data); l->emit(data);
} }
@ -43,13 +38,17 @@ void Hyprutils::Signal::CSignal::emit(std::any data) {
// release SPs // release SPs
listeners.clear(); listeners.clear();
if (dirty) // we cannot release any expired refs here as one of the listeners could've removed this object and
std::erase_if(m_vListeners, [](const auto& other) { return other.expired(); }); // as such we'd be doing a UAF
} }
CHyprSignalListener Hyprutils::Signal::CSignal::registerListener(std::function<void(std::any)> handler) { CHyprSignalListener Hyprutils::Signal::CSignal::registerListener(std::function<void(std::any)> handler) {
CHyprSignalListener listener = makeShared<CSignalListener>(handler); CHyprSignalListener listener = makeShared<CSignalListener>(handler);
m_vListeners.emplace_back(listener); m_vListeners.emplace_back(listener);
// housekeeping: remove any stale listeners
std::erase_if(m_vListeners, [](const auto& other) { return other.expired(); });
return listener; return listener;
} }

View File

@ -26,6 +26,8 @@ bool Hyprutils::String::isNumber(const std::string& str, bool allowfloat) {
if (str.empty()) if (str.empty())
return false; return false;
bool decimalParsed = false;
for (size_t i = 0; i < str.length(); ++i) { for (size_t i = 0; i < str.length(); ++i) {
const char& c = str.at(i); const char& c = str.at(i);
@ -44,9 +46,11 @@ bool Hyprutils::String::isNumber(const std::string& str, bool allowfloat) {
if (i == 0) if (i == 0)
return false; return false;
if (str.at(0) == '-') if (decimalParsed)
return false; return false;
decimalParsed = true;
continue; continue;
} }
} }

View File

@ -6,7 +6,7 @@
using namespace Hyprutils::String; using namespace Hyprutils::String;
Hyprutils::String::CVarList::CVarList(const std::string& in, const size_t lastArgNo, const char delim, const bool removeEmpty) { Hyprutils::String::CVarList::CVarList(const std::string& in, const size_t lastArgNo, const char delim, const bool removeEmpty) {
if (in.empty()) if (!removeEmpty && in.empty())
m_vArgs.emplace_back(""); m_vArgs.emplace_back("");
std::string args{in}; std::string args{in};

12
src/utils/ScopeGuard.cpp Normal file
View File

@ -0,0 +1,12 @@
#include <hyprutils/utils/ScopeGuard.hpp>
using namespace Hyprutils::Utils;
Hyprutils::Utils::CScopeGuard::CScopeGuard(const std::function<void()>& fn_) : fn(fn_) {
;
}
Hyprutils::Utils::CScopeGuard::~CScopeGuard() {
if (fn)
fn();
}

View File

@ -30,6 +30,9 @@ int main(int argc, char** argv, char** envp) {
EXPECT(isNumber("vvss", true), false); EXPECT(isNumber("vvss", true), false);
EXPECT(isNumber("0.9999s", true), false); EXPECT(isNumber("0.9999s", true), false);
EXPECT(isNumber("s0.9999", true), false); EXPECT(isNumber("s0.9999", true), false);
EXPECT(isNumber("-1.0", true), true);
EXPECT(isNumber("-1..0", true), false);
EXPECT(isNumber("-10.0000000001", true), true);
CVarList list("hello world!", 0, 's', true); CVarList list("hello world!", 0, 's', true);
EXPECT(list[0], "hello"); EXPECT(list[0], "hello");