diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b8dc001c..982c265f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,7 +1,7 @@ fail_fast: false repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.6.0 + rev: v6.0.0 hooks: - id: trailing-whitespace - id: check-yaml diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 1f274967..9a90fd32 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -7,4 +7,4 @@ "danielpinto8zz6.c-cpp-compile-run", "usernamehw.errorlens" ] -} \ No newline at end of file +} diff --git a/CMakePresets.json b/CMakePresets.json index 32073840..f073259a 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -286,4 +286,4 @@ } } ] -} \ No newline at end of file +} diff --git a/atom/CMakeLists.txt b/atom/CMakeLists.txt index 4f854b19..50c2543a 100644 --- a/atom/CMakeLists.txt +++ b/atom/CMakeLists.txt @@ -281,20 +281,20 @@ option(ATOM_BUILD_UNIFIED_LIBRARY "Build a unified Atom library containing all m if(ATOM_BUILD_UNIFIED_LIBRARY) # Get all targets that are atom modules get_property(ATOM_MODULE_TARGETS GLOBAL PROPERTY ATOM_MODULE_TARGETS) - + if(ATOM_MODULE_TARGETS) message(STATUS "Creating unified Atom library with modules: ${ATOM_MODULE_TARGETS}") - + # Create unified target add_library(atom-unified INTERFACE) - + # Link all module targets target_link_libraries(atom-unified INTERFACE ${ATOM_MODULE_TARGETS}) - + # Create an alias 'atom' that points to 'atom-unified' # This allows examples and other components to link against 'atom' add_library(atom ALIAS atom-unified) - + # Install unified target install(TARGETS atom-unified EXPORT atom-unified-targets @@ -305,4 +305,4 @@ if(ATOM_BUILD_UNIFIED_LIBRARY) endif() endif() -message(STATUS "Atom modules configuration completed successfully") \ No newline at end of file +message(STATUS "Atom modules configuration completed successfully") diff --git a/atom/algorithm/algorithm.cpp b/atom/algorithm/algorithm.cpp index fea8bbd5..66230465 100644 --- a/atom/algorithm/algorithm.cpp +++ b/atom/algorithm/algorithm.cpp @@ -694,4 +694,4 @@ void BoyerMoore::computeGoodSuffixShift() noexcept { spdlog::info("Good suffix shift table computed."); } -} // namespace atom::algorithm \ No newline at end of file +} // namespace atom::algorithm diff --git a/atom/algorithm/algorithm.hpp b/atom/algorithm/algorithm.hpp index 21df539b..f0297984 100644 --- a/atom/algorithm/algorithm.hpp +++ b/atom/algorithm/algorithm.hpp @@ -337,4 +337,4 @@ auto BloomFilter::elementCount() const noexcept } // namespace atom::algorithm -#endif \ No newline at end of file +#endif diff --git a/atom/algorithm/base.cpp b/atom/algorithm/base.cpp index 0bcc51b8..82454ffe 100644 --- a/atom/algorithm/base.cpp +++ b/atom/algorithm/base.cpp @@ -644,4 +644,4 @@ auto decodeBase32(std::string_view encoded_sv) noexcept } } -} // namespace atom::algorithm \ No newline at end of file +} // namespace atom::algorithm diff --git a/atom/algorithm/base.hpp b/atom/algorithm/base.hpp index fc6bff95..82606d4f 100644 --- a/atom/algorithm/base.hpp +++ b/atom/algorithm/base.hpp @@ -341,4 +341,4 @@ void parallelExecute(std::span data, size_t threadCount, } // namespace atom::algorithm -#endif \ No newline at end of file +#endif diff --git a/atom/algorithm/bignumber.cpp b/atom/algorithm/bignumber.cpp index c9c5d164..5264ddea 100644 --- a/atom/algorithm/bignumber.cpp +++ b/atom/algorithm/bignumber.cpp @@ -607,4 +607,4 @@ void BigNumber::validate() const { } } -} // namespace atom::algorithm \ No newline at end of file +} // namespace atom::algorithm diff --git a/atom/algorithm/bignumber.hpp b/atom/algorithm/bignumber.hpp index c68479ad..cad7218e 100644 --- a/atom/algorithm/bignumber.hpp +++ b/atom/algorithm/bignumber.hpp @@ -284,4 +284,4 @@ constexpr auto BigNumber::at(size_t index) const -> uint8_t { } // namespace atom::algorithm -#endif // ATOM_ALGORITHM_BIGNUMBER_HPP \ No newline at end of file +#endif // ATOM_ALGORITHM_BIGNUMBER_HPP diff --git a/atom/algorithm/blowfish.cpp b/atom/algorithm/blowfish.cpp index 49a4c482..8c771c3a 100644 --- a/atom/algorithm/blowfish.cpp +++ b/atom/algorithm/blowfish.cpp @@ -533,4 +533,4 @@ template void Blowfish::decrypt_data(std::span, usize&); template void Blowfish::decrypt_data(std::span, usize&); -} // namespace atom::algorithm \ No newline at end of file +} // namespace atom::algorithm diff --git a/atom/algorithm/blowfish.hpp b/atom/algorithm/blowfish.hpp index 685a9d52..79152766 100644 --- a/atom/algorithm/blowfish.hpp +++ b/atom/algorithm/blowfish.hpp @@ -132,4 +132,4 @@ class Blowfish { } // namespace atom::algorithm -#endif // ATOM_ALGORITHM_BLOWFISH_HPP \ No newline at end of file +#endif // ATOM_ALGORITHM_BLOWFISH_HPP diff --git a/atom/algorithm/convolve.cpp b/atom/algorithm/convolve.cpp index cf596b71..a508bb34 100644 --- a/atom/algorithm/convolve.cpp +++ b/atom/algorithm/convolve.cpp @@ -430,10 +430,10 @@ __kernel void convolve2D(__global const float* input, for (int j = -halfKernelCols; j <= halfKernelCols; ++j) { int x = clamp(row + i, 0, inputRows - 1); int y = clamp(col + j, 0, inputCols - 1); - + int kernelIdx = (i + halfKernelRows) * kernelCols + (j + halfKernelCols); int inputIdx = x * inputCols + y; - + sum += input[inputIdx] * kernel[kernelIdx]; } } @@ -1257,4 +1257,4 @@ auto applyGaussianFilter(const std::vector>& image, #ifdef _MSC_VER #pragma warning(pop) -#endif \ No newline at end of file +#endif diff --git a/atom/algorithm/flood.cpp b/atom/algorithm/flood.cpp index f7e95a20..c82f7592 100644 --- a/atom/algorithm/flood.cpp +++ b/atom/algorithm/flood.cpp @@ -373,4 +373,4 @@ usize FloodFill::processBlock( return filled_count; } -} // namespace atom::algorithm \ No newline at end of file +} // namespace atom::algorithm diff --git a/atom/algorithm/flood.hpp b/atom/algorithm/flood.hpp index aeea4ee2..8c3f20a6 100644 --- a/atom/algorithm/flood.hpp +++ b/atom/algorithm/flood.hpp @@ -694,4 +694,4 @@ usize FloodFill::fillParallel( } // namespace atom::algorithm -#endif // ATOM_ALGORITHM_FLOOD_GPP \ No newline at end of file +#endif // ATOM_ALGORITHM_FLOOD_GPP diff --git a/atom/algorithm/fnmatch.cpp b/atom/algorithm/fnmatch.cpp index 71c64044..5931f937 100644 --- a/atom/algorithm/fnmatch.cpp +++ b/atom/algorithm/fnmatch.cpp @@ -512,4 +512,4 @@ atom::algorithm::filter, std::vector>( const std::vector&, const std::vector&, int, bool); -} // namespace atom::algorithm \ No newline at end of file +} // namespace atom::algorithm diff --git a/atom/algorithm/fnmatch.hpp b/atom/algorithm/fnmatch.hpp index 45211e6f..196980a4 100644 --- a/atom/algorithm/fnmatch.hpp +++ b/atom/algorithm/fnmatch.hpp @@ -145,4 +145,4 @@ template } // namespace atom::algorithm -#endif // ATOM_SYSTEM_FNMATCH_HPP \ No newline at end of file +#endif // ATOM_SYSTEM_FNMATCH_HPP diff --git a/atom/algorithm/fraction.cpp b/atom/algorithm/fraction.cpp index 233e965a..4377b87d 100644 --- a/atom/algorithm/fraction.cpp +++ b/atom/algorithm/fraction.cpp @@ -450,4 +450,4 @@ auto makeFraction(double value, int max_denominator) -> Fraction { return Fraction(sign * h2, k2); } -} // namespace atom::algorithm \ No newline at end of file +} // namespace atom::algorithm diff --git a/atom/algorithm/fraction.hpp b/atom/algorithm/fraction.hpp index 8606d53f..4fcd1e4c 100644 --- a/atom/algorithm/fraction.hpp +++ b/atom/algorithm/fraction.hpp @@ -451,4 +451,4 @@ class Fraction { } // namespace atom::algorithm -#endif // ATOM_ALGORITHM_FRACTION_HPP \ No newline at end of file +#endif // ATOM_ALGORITHM_FRACTION_HPP diff --git a/atom/algorithm/huffman.hpp b/atom/algorithm/huffman.hpp index d626249d..9eb568f6 100644 --- a/atom/algorithm/huffman.hpp +++ b/atom/algorithm/huffman.hpp @@ -252,4 +252,4 @@ std::vector decompressParallel( } // namespace huffman_optimized -#endif // ATOM_ALGORITHM_HUFFMAN_HPP \ No newline at end of file +#endif // ATOM_ALGORITHM_HUFFMAN_HPP diff --git a/atom/algorithm/matrix_compress.cpp b/atom/algorithm/matrix_compress.cpp index 00f90b43..134fadf7 100644 --- a/atom/algorithm/matrix_compress.cpp +++ b/atom/algorithm/matrix_compress.cpp @@ -603,4 +603,4 @@ void performanceTest(i32 rows, i32 cols, bool runParallel) { } #endif -} // namespace atom::algorithm \ No newline at end of file +} // namespace atom::algorithm diff --git a/atom/algorithm/mhash.cpp b/atom/algorithm/mhash.cpp index 00d17996..dfd561b0 100644 --- a/atom/algorithm/mhash.cpp +++ b/atom/algorithm/mhash.cpp @@ -74,12 +74,12 @@ namespace { // Using template string to simplify OpenCL kernel code constexpr const char *minhashKernelSource = R"CLC( __kernel void minhash_kernel( - __global const size_t* hashes, - __global size_t* signature, - __global const size_t* a_values, - __global const size_t* b_values, - const size_t p, - const size_t num_hashes, + __global const size_t* hashes, + __global size_t* signature, + __global const size_t* a_values, + __global const size_t* b_values, + const size_t p, + const size_t num_hashes, const size_t num_elements ) { int gid = get_global_id(0); @@ -87,13 +87,13 @@ __kernel void minhash_kernel( size_t min_hash = SIZE_MAX; size_t a = a_values[gid]; size_t b = b_values[gid]; - + // Batch processing to leverage locality for (size_t i = 0; i < num_elements; ++i) { size_t h = (a * hashes[i] + b) % p; min_hash = (h < min_hash) ? h : min_hash; } - + signature[gid] = min_hash; } } @@ -628,4 +628,4 @@ auto keccak256(std::span input) -> std::array { thread_local std::vector tls_buffer_{}; -} // namespace atom::algorithm \ No newline at end of file +} // namespace atom::algorithm diff --git a/atom/algorithm/pathfinding.cpp b/atom/algorithm/pathfinding.cpp index e93d4b79..3fdb3bcf 100644 --- a/atom/algorithm/pathfinding.cpp +++ b/atom/algorithm/pathfinding.cpp @@ -652,4 +652,4 @@ std::vector PathFinder::funnelAlgorithm(const std::vector& path, return result; } -} // namespace atom::algorithm \ No newline at end of file +} // namespace atom::algorithm diff --git a/atom/algorithm/pathfinding.hpp b/atom/algorithm/pathfinding.hpp index 224a6406..65926501 100644 --- a/atom/algorithm/pathfinding.hpp +++ b/atom/algorithm/pathfinding.hpp @@ -523,4 +523,4 @@ struct hash { (hash()(p.y) << 1); } }; -} // namespace std \ No newline at end of file +} // namespace std diff --git a/atom/algorithm/perlin.hpp b/atom/algorithm/perlin.hpp index 3cd0f72f..bcc444bf 100644 --- a/atom/algorithm/perlin.hpp +++ b/atom/algorithm/perlin.hpp @@ -419,4 +419,4 @@ class PerlinNoise { }; } // namespace atom::algorithm -#endif // ATOM_ALGORITHM_PERLIN_HPP \ No newline at end of file +#endif // ATOM_ALGORITHM_PERLIN_HPP diff --git a/atom/algorithm/sha1.cpp b/atom/algorithm/sha1.cpp index a9e624e1..14d299dd 100644 --- a/atom/algorithm/sha1.cpp +++ b/atom/algorithm/sha1.cpp @@ -387,4 +387,4 @@ auto computeHashesInParallel(const Containers&... containers) return results; } -} // namespace atom::algorithm \ No newline at end of file +} // namespace atom::algorithm diff --git a/atom/algorithm/sha1.hpp b/atom/algorithm/sha1.hpp index 8a3208a0..25eccae2 100644 --- a/atom/algorithm/sha1.hpp +++ b/atom/algorithm/sha1.hpp @@ -265,4 +265,4 @@ template } // namespace atom::algorithm -#endif // ATOM_ALGORITHM_SHA1_HPP \ No newline at end of file +#endif // ATOM_ALGORITHM_SHA1_HPP diff --git a/atom/algorithm/snowflake.hpp b/atom/algorithm/snowflake.hpp index bd4f30a5..49b0cdd5 100644 --- a/atom/algorithm/snowflake.hpp +++ b/atom/algorithm/snowflake.hpp @@ -668,4 +668,4 @@ class Snowflake { } // namespace atom::algorithm -#endif // ATOM_ALGORITHM_SNOWFLAKE_HPP \ No newline at end of file +#endif // ATOM_ALGORITHM_SNOWFLAKE_HPP diff --git a/atom/algorithm/tea.cpp b/atom/algorithm/tea.cpp index a7abd41f..d1c8ea5c 100644 --- a/atom/algorithm/tea.cpp +++ b/atom/algorithm/tea.cpp @@ -421,4 +421,4 @@ template auto toUint32Vector>(const std::vector& data) template auto toByteArray>(const std::vector& data) -> std::vector; -} // namespace atom::algorithm \ No newline at end of file +} // namespace atom::algorithm diff --git a/atom/algorithm/tea.hpp b/atom/algorithm/tea.hpp index 44f2e78c..75c9b162 100644 --- a/atom/algorithm/tea.hpp +++ b/atom/algorithm/tea.hpp @@ -396,4 +396,4 @@ auto toByteArray(const Container &data) -> std::vector { } // namespace atom::algorithm -#endif \ No newline at end of file +#endif diff --git a/atom/algorithm/weight.hpp b/atom/algorithm/weight.hpp index e1744d96..e165819f 100644 --- a/atom/algorithm/weight.hpp +++ b/atom/algorithm/weight.hpp @@ -1147,4 +1147,4 @@ class WeightSelector { } // namespace atom::algorithm -#endif // ATOM_ALGORITHM_WEIGHT_HPP \ No newline at end of file +#endif // ATOM_ALGORITHM_WEIGHT_HPP diff --git a/atom/algorithm/xmake.lua b/atom/algorithm/xmake.lua index 8b88edbb..2f1f54e2 100644 --- a/atom/algorithm/xmake.lua +++ b/atom/algorithm/xmake.lua @@ -21,46 +21,46 @@ add_requires("openssl", "tbb", "loguru") target("atom-algorithm") -- Set target kind set_kind("static") - + -- Add source files (automatically collect .cpp files) add_files("*.cpp") - - -- Add header files (automatically collect .hpp files) + + -- Add header files (automatically collect .hpp files) add_headerfiles("*.hpp") - + -- Add include directories add_includedirs(".", {public = true}) - + -- Add packages add_packages("openssl", "tbb", "loguru") - + -- Add system libraries add_syslinks("pthread") - + -- Add dependencies (assuming they are other xmake targets or libraries) for _, dep in ipairs(atom_algorithm_depends) do add_deps(dep) end - + -- Set properties set_targetdir("$(buildir)/lib") set_objectdir("$(buildir)/obj") - + -- Enable position independent code for static library add_cxflags("-fPIC", {tools = {"gcc", "clang"}}) add_cflags("-fPIC", {tools = {"gcc", "clang"}}) - + -- Set version info set_version("1.0.0") - + -- Add compile features set_policy("build.optimization.lto", true) - + -- Installation rules after_build(function (target) -- Custom post-build actions if needed end) - + -- Install target on_install(function (target) local installdir = target:installdir() or "$(prefix)" @@ -80,7 +80,7 @@ if has_config("enable-deps-check") then -- Convert atom-error to ATOM_BUILD_ERROR format local dep_var = dep:upper():gsub("ATOM%-", "ATOM_BUILD_") if not has_config(dep_var:lower()) then - print("Warning: Module atom-algorithm depends on " .. dep .. + print("Warning: Module atom-algorithm depends on " .. dep .. ", but that module is not enabled for building") end end diff --git a/atom/async/async.hpp b/atom/async/async.hpp index 70915bc3..1c0e20b8 100644 --- a/atom/async/async.hpp +++ b/atom/async/async.hpp @@ -1541,4 +1541,4 @@ size_t AsyncWorkerManager::pruneCompletedWorkers() noexcept { } } } // namespace atom::async -#endif \ No newline at end of file +#endif diff --git a/atom/async/async_executor.cpp b/atom/async/async_executor.cpp index b836c53a..6d79d544 100644 --- a/atom/async/async_executor.cpp +++ b/atom/async/async_executor.cpp @@ -385,4 +385,4 @@ void AsyncExecutor::statsLoop(std::stop_token stoken) { } } -} // namespace atom::async \ No newline at end of file +} // namespace atom::async diff --git a/atom/async/eventstack.hpp b/atom/async/eventstack.hpp index 5bfd3b96..d84b672c 100644 --- a/atom/async/eventstack.hpp +++ b/atom/async/eventstack.hpp @@ -937,7 +937,7 @@ void EventStack::transformEvents(Func&& transformFunc) { Parallel::for_each(events_.begin(), events_.end(), std::forward(transformFunc)); */ - + } #endif } catch (const std::exception& e) { diff --git a/atom/async/lock.cpp b/atom/async/lock.cpp index 773bfe49..fff0eaf3 100644 --- a/atom/async/lock.cpp +++ b/atom/async/lock.cpp @@ -44,13 +44,13 @@ void Spinlock::lock() { // Slow path - exponential backoff uint32_t backoff_count = 1; constexpr uint32_t MAX_BACKOFF = 1024; - + while (true) { - // Perform exponential backoff + // Perform exponential backoff for (uint32_t i = 0; i < backoff_count; ++i) { cpu_relax(); } - + // Try to acquire the lock if (!flag_.test_and_set(std::memory_order_acquire)) { #ifdef ATOM_DEBUG @@ -58,10 +58,10 @@ void Spinlock::lock() { #endif return; } - + // Increase backoff time (capped at maximum) backoff_count = std::min(backoff_count * 2, MAX_BACKOFF); - + // Yield to scheduler if we've been spinning for a while if (backoff_count >= MAX_BACKOFF / 2) { std::this_thread::yield(); @@ -71,13 +71,13 @@ void Spinlock::lock() { auto Spinlock::tryLock() noexcept -> bool { bool success = !flag_.test_and_set(std::memory_order_acquire); - + #ifdef ATOM_DEBUG if (success) { owner_.store(std::this_thread::get_id(), std::memory_order_relaxed); } #endif - + return success; } @@ -90,9 +90,9 @@ void Spinlock::unlock() noexcept { } owner_.store(std::thread::id(), std::memory_order_relaxed); #endif - + flag_.clear(std::memory_order_release); - + #if defined(__cpp_lib_atomic_flag_test) // Use C++20's notify to wake waiting threads flag_.notify_one(); @@ -102,12 +102,12 @@ void Spinlock::unlock() noexcept { auto TicketSpinlock::lock() noexcept -> uint64_t { const auto ticket = ticket_.fetch_add(1, std::memory_order_acq_rel); auto current_serving = serving_.load(std::memory_order_acquire); - + // Fast path - check if we're next if (current_serving == ticket) { return ticket; } - + // Slow path with adaptive waiting strategy uint32_t spin_count = 0; while (true) { @@ -115,7 +115,7 @@ auto TicketSpinlock::lock() noexcept -> uint64_t { if (current_serving == ticket) { return ticket; } - + if (spin_count < MAX_SPIN_COUNT) { // Use CPU pause instruction for short spins cpu_relax(); @@ -137,7 +137,7 @@ void TicketSpinlock::unlock(uint64_t ticket) { throw std::invalid_argument("Incorrect ticket provided to unlock"); } #endif - + serving_.store(ticket + 1, std::memory_order_release); } @@ -146,23 +146,23 @@ void UnfairSpinlock::lock() noexcept { if (!flag_.test_and_set(std::memory_order_acquire)) { return; } - + // Slow path with backoff uint32_t backoff_count = 1; constexpr uint32_t MAX_BACKOFF = 1024; - + while (true) { for (uint32_t i = 0; i < backoff_count; ++i) { cpu_relax(); } - + if (!flag_.test_and_set(std::memory_order_acquire)) { return; } - + // Increase backoff time (capped at maximum) backoff_count = std::min(backoff_count * 2, MAX_BACKOFF); - + // Yield to scheduler if we've been spinning for a while if (backoff_count >= MAX_BACKOFF / 2) { std::this_thread::yield(); @@ -172,7 +172,7 @@ void UnfairSpinlock::lock() noexcept { void UnfairSpinlock::unlock() noexcept { flag_.clear(std::memory_order_release); - + #if defined(__cpp_lib_atomic_flag_test) // Wake any waiting threads (C++20 feature) flag_.notify_one(); @@ -202,7 +202,7 @@ void BoostSpinlock::lock() noexcept { // Slow path - exponential backoff uint32_t backoff_count = 1; constexpr uint32_t MAX_BACKOFF = 1024; - + // Wait until we acquire the lock while (true) { // First check if lock is free without doing an exchange @@ -215,15 +215,15 @@ void BoostSpinlock::lock() noexcept { return; } } - - // Perform exponential backoff + + // Perform exponential backoff for (uint32_t i = 0; i < backoff_count; ++i) { cpu_relax(); } - + // Increase backoff time (capped at maximum) backoff_count = std::min(backoff_count * 2, MAX_BACKOFF); - + // Yield to scheduler if we've been spinning for a while if (backoff_count >= MAX_BACKOFF / 2) { std::this_thread::yield(); @@ -233,16 +233,16 @@ void BoostSpinlock::lock() noexcept { auto BoostSpinlock::tryLock() noexcept -> bool { bool expected = false; - bool success = flag_.compare_exchange_strong(expected, true, + bool success = flag_.compare_exchange_strong(expected, true, boost::memory_order_acquire, boost::memory_order_relaxed); - + #ifdef ATOM_DEBUG if (success) { owner_.store(std::this_thread::get_id(), boost::memory_order_relaxed); } #endif - + return success; } @@ -255,7 +255,7 @@ void BoostSpinlock::unlock() noexcept { } owner_.store(std::thread::id(), boost::memory_order_relaxed); #endif - + flag_.store(false, boost::memory_order_release); } #endif diff --git a/atom/async/lodash.hpp b/atom/async/lodash.hpp index b4098e4b..983eb260 100644 --- a/atom/async/lodash.hpp +++ b/atom/async/lodash.hpp @@ -550,4 +550,4 @@ auto Throttle::callCount() const noexcept -> size_t { } } // namespace atom::async -#endif \ No newline at end of file +#endif diff --git a/atom/async/message_bus.hpp b/atom/async/message_bus.hpp index c50a6325..3fee523d 100644 --- a/atom/async/message_bus.hpp +++ b/atom/async/message_bus.hpp @@ -694,7 +694,7 @@ class MessageBus : public std::enable_shared_from_this { // Optimization: if 'once' subscribers are common, breaking here might be too early // if a token could somehow be associated with multiple names (not current design). // For now, assume a token is unique across all names for a given type. - // break; + // break; } } @@ -956,7 +956,7 @@ class MessageBus : public std::enable_shared_from_this { for (auto& subscriber : subscribersList) { // Iterate by reference to allow modification if needed (though not directly here) try { // Ensure message is converted to std::any for filter and handler - std::any msg_any = message; + std::any msg_any = message; if (subscriber.filter(msg_any) && calledSubscribers.insert(subscriber.token).second) { auto handler_task = [handlerFunc = subscriber.handler, message_for_handler = msg_any, token = subscriber.token]() { // Capture message_any by value try { @@ -998,7 +998,7 @@ class MessageBus : public std::enable_shared_from_this { subscribersList.end()); if (subscribersList.empty()) { // If list becomes empty, remove 'name' entry from typeIter->second - typeIter->second.erase(nameIterator); + typeIter->second.erase(nameIterator); if (typeIter->second.empty()) { // If type map becomes empty, remove type_index entry from subscribers_ subscribers_.erase(typeIter); diff --git a/atom/async/message_queue.hpp b/atom/async/message_queue.hpp index 2b41840a..0deade78 100644 --- a/atom/async/message_queue.hpp +++ b/atom/async/message_queue.hpp @@ -1114,4 +1114,4 @@ size_t MessageQueue::clearAllMessages() noexcept { } // namespace atom::async -#endif // ATOM_ASYNC_MESSAGE_QUEUE_HPP \ No newline at end of file +#endif // ATOM_ASYNC_MESSAGE_QUEUE_HPP diff --git a/atom/async/parallel.hpp b/atom/async/parallel.hpp index f0345b82..1b73f820 100644 --- a/atom/async/parallel.hpp +++ b/atom/async/parallel.hpp @@ -1432,4 +1432,4 @@ class SimdOps { } // namespace atom::async -#endif // ATOM_ASYNC_PARALLEL_HPP \ No newline at end of file +#endif // ATOM_ASYNC_PARALLEL_HPP diff --git a/atom/async/pool.hpp b/atom/async/pool.hpp index 5c566877..f6ef465e 100644 --- a/atom/async/pool.hpp +++ b/atom/async/pool.hpp @@ -1721,4 +1721,4 @@ auto asyncAsio(F&& f, Args&&... args) { } // namespace atom::async -#endif // ATOM_ASYNC_THREADPOOL_HPP \ No newline at end of file +#endif // ATOM_ASYNC_THREADPOOL_HPP diff --git a/atom/async/queue.hpp b/atom/async/queue.hpp index 1b8cc2a3..a3df0d63 100644 --- a/atom/async/queue.hpp +++ b/atom/async/queue.hpp @@ -1329,4 +1329,4 @@ class QueueBenchmark { } // namespace atom::async #endif // ATOM_QUEUE_BENCHMARK -#endif // ATOM_ASYNC_QUEUE_HPP \ No newline at end of file +#endif // ATOM_ASYNC_QUEUE_HPP diff --git a/atom/async/timer.hpp b/atom/async/timer.hpp index 570ea84d..4c04e3c5 100644 --- a/atom/async/timer.hpp +++ b/atom/async/timer.hpp @@ -466,4 +466,4 @@ void Timer::setCallback(Function &&func) noexcept(false) { } // namespace atom::async -#endif \ No newline at end of file +#endif diff --git a/atom/async/xmake.lua b/atom/async/xmake.lua index 47691dd3..c9bd4457 100644 --- a/atom/async/xmake.lua +++ b/atom/async/xmake.lua @@ -18,19 +18,19 @@ add_requires("loguru") target("atom-async") -- Set target kind set_kind("static") - + -- Add source files (explicitly specified) add_files("limiter.cpp", "lock.cpp", "timer.cpp") - + -- Add header files (explicitly specified) add_headerfiles( "async.hpp", - "daemon.hpp", + "daemon.hpp", "eventstack.hpp", "limiter.hpp", "lock.hpp", "message_bus.hpp", - "message_queue.hpp", + "message_queue.hpp", "pool.hpp", "queue.hpp", "safetype.hpp", @@ -38,33 +38,33 @@ target("atom-async") "timer.hpp", "trigger.hpp" ) - + -- Add include directories add_includedirs(".", {public = true}) - + -- Add packages add_packages("loguru") - + -- Add dependencies (assuming atom-utils is another xmake target) add_deps("atom-utils") - + -- Add system libraries add_syslinks("pthread") - + -- Enable position independent code for static library add_cxflags("-fPIC", {tools = {"gcc", "clang"}}) add_cflags("-fPIC", {tools = {"gcc", "clang"}}) - + -- Set target directory set_targetdir("$(buildir)/lib") set_objectdir("$(buildir)/obj") - + -- Set version info set_version("1.0.0") - + -- Set output name (equivalent to OUTPUT_NAME) set_basename("atom-async") - + -- Installation rules on_install(function (target) local installdir = target:installdir() or "$(prefix)" @@ -77,10 +77,10 @@ target("atom-async") -- Optional: Create an object library equivalent (if needed elsewhere) target("atom-async-object") set_kind("object") - + -- Add the same source files add_files("limiter.cpp", "lock.cpp", "timer.cpp") add_headerfiles( "async.hpp", - "daemon.hpp", - "eventstack.hpp", \ No newline at end of file + "daemon.hpp", + "eventstack.hpp", diff --git a/atom/components/CMakeLists.txt b/atom/components/CMakeLists.txt index 8663d60e..4a27a8ef 100644 --- a/atom/components/CMakeLists.txt +++ b/atom/components/CMakeLists.txt @@ -55,4 +55,4 @@ set_target_properties(${PROJECT_NAME} PROPERTIES # Install rules install(TARGETS ${PROJECT_NAME} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} -) \ No newline at end of file +) diff --git a/atom/components/dispatch.cpp b/atom/components/dispatch.cpp index 309befab..5684a669 100644 --- a/atom/components/dispatch.cpp +++ b/atom/components/dispatch.cpp @@ -709,4 +709,4 @@ auto CommandDispatcher::dispatchHelper(const std::string& name, THROW_INVALID_ARGUMENT( "No matching overload for command '{}' with the given arguments.", name); -} \ No newline at end of file +} diff --git a/atom/components/dispatch.hpp b/atom/components/dispatch.hpp index b3a56a65..58cfc568 100644 --- a/atom/components/dispatch.hpp +++ b/atom/components/dispatch.hpp @@ -635,4 +635,4 @@ auto CommandDispatcher::completeArgs(const Command& cmd, const ArgsType& args) return fullArgs; } -#endif \ No newline at end of file +#endif diff --git a/atom/components/xmake.lua b/atom/components/xmake.lua index 5d128da9..6675173e 100644 --- a/atom/components/xmake.lua +++ b/atom/components/xmake.lua @@ -27,7 +27,7 @@ add_requires("loguru") -- Define sources and headers local sources = { "component.cpp", - "dispatch.cpp", + "dispatch.cpp", "registry.cpp", "var.cpp" } @@ -43,38 +43,38 @@ local headers = { target("atom-component") -- Set target kind to shared library set_kind("shared") - + -- Add source files add_files(sources) - + -- Add header files add_headerfiles(headers) - + -- Add include directories add_includedirs(".", {public = true}) - + -- Add packages add_packages("loguru") - + -- Add dependencies (assuming these are other xmake targets) add_deps("atom-error", "atom-utils") - + -- Add system libraries add_syslinks("pthread") - + -- Enable position independent code (automatic for shared libraries) set_policy("build.optimization.lto", true) - + -- Set version info set_version("1.0.0") - + -- Set output name set_basename("atom-component") - + -- Set target and object directories set_targetdir("$(buildir)/lib") set_objectdir("$(buildir)/obj") - + -- Installation rules after_install(function (target) local installdir = target:installdir() or "$(prefix)" @@ -91,17 +91,17 @@ target("atom-component") -- Optional: Create object library target (equivalent to CMake's object library) target("atom-component-object") set_kind("object") - + -- Add the same source files add_files(sources) add_headerfiles(headers) - + -- Configuration add_includedirs(".") add_packages("loguru") add_deps("atom-error", "atom-utils") add_syslinks("pthread") - + -- Enable position independent code add_cxflags("-fPIC", {tools = {"gcc", "clang"}}) add_cflags("-fPIC", {tools = {"gcc", "clang"}}) diff --git a/atom/connection/async_sockethub.hpp b/atom/connection/async_sockethub.hpp index d6b2960e..7c74bc7b 100644 --- a/atom/connection/async_sockethub.hpp +++ b/atom/connection/async_sockethub.hpp @@ -143,4 +143,4 @@ class SocketHub { } // namespace atom::async::connection -#endif // ATOM_CONNECTION_ASYNC_SOCKETHUB_HPP \ No newline at end of file +#endif // ATOM_CONNECTION_ASYNC_SOCKETHUB_HPP diff --git a/atom/connection/async_tcpclient.cpp b/atom/connection/async_tcpclient.cpp index 9c20810e..34fc27f8 100644 --- a/atom/connection/async_tcpclient.cpp +++ b/atom/connection/async_tcpclient.cpp @@ -1189,4 +1189,4 @@ void TcpClient::setOnHeartbeatCallback(const OnHeartbeatCallback& callback) { impl_->setOnHeartbeatCallback(callback); } -} // namespace atom::async::connection \ No newline at end of file +} // namespace atom::async::connection diff --git a/atom/connection/async_tcpclient.hpp b/atom/connection/async_tcpclient.hpp index 7511f191..bf901d4b 100644 --- a/atom/connection/async_tcpclient.hpp +++ b/atom/connection/async_tcpclient.hpp @@ -318,4 +318,4 @@ class TcpClient { } // namespace atom::async::connection -#endif // ATOM_CONNECTION_ASYNC_TCPCLIENT_HPP \ No newline at end of file +#endif // ATOM_CONNECTION_ASYNC_TCPCLIENT_HPP diff --git a/atom/connection/async_udpclient.cpp b/atom/connection/async_udpclient.cpp index cb221746..bdb2dcef 100644 --- a/atom/connection/async_udpclient.cpp +++ b/atom/connection/async_udpclient.cpp @@ -807,4 +807,4 @@ UdpClient::Statistics UdpClient::getStatistics() const { void UdpClient::resetStatistics() { impl_->resetStatistics(); } -} // namespace atom::async::connection \ No newline at end of file +} // namespace atom::async::connection diff --git a/atom/connection/async_udpserver.cpp b/atom/connection/async_udpserver.cpp index 16bd3c0c..4371f537 100644 --- a/atom/connection/async_udpserver.cpp +++ b/atom/connection/async_udpserver.cpp @@ -799,4 +799,4 @@ template bool UdpSocketHub::setSocketOption(SocketOption option, template bool UdpSocketHub::setSocketOption( SocketOption option, const unsigned int& value); -} // namespace atom::async::connection \ No newline at end of file +} // namespace atom::async::connection diff --git a/atom/connection/async_udpserver.hpp b/atom/connection/async_udpserver.hpp index 87735735..32b0f989 100644 --- a/atom/connection/async_udpserver.hpp +++ b/atom/connection/async_udpserver.hpp @@ -226,4 +226,4 @@ class UdpSocketHub { } // namespace atom::async::connection -#endif \ No newline at end of file +#endif diff --git a/atom/connection/fifoclient.hpp b/atom/connection/fifoclient.hpp index d1cf71c4..a339318f 100644 --- a/atom/connection/fifoclient.hpp +++ b/atom/connection/fifoclient.hpp @@ -376,4 +376,4 @@ auto FifoClient::write(const T& data, } // namespace atom::connection -#endif // ATOM_CONNECTION_FIFOCLIENT_HPP \ No newline at end of file +#endif // ATOM_CONNECTION_FIFOCLIENT_HPP diff --git a/atom/connection/fifoserver.cpp b/atom/connection/fifoserver.cpp index 606fbe85..fb1ea7ad 100644 --- a/atom/connection/fifoserver.cpp +++ b/atom/connection/fifoserver.cpp @@ -953,4 +953,4 @@ void FIFOServer::setLogLevel(LogLevel level) { impl_->setLogLevel(level); } size_t FIFOServer::getQueueSize() const { return impl_->getQueueSize(); } -} // namespace atom::connection \ No newline at end of file +} // namespace atom::connection diff --git a/atom/connection/fifoserver.hpp b/atom/connection/fifoserver.hpp index c25cbb41..d4cdd7ac 100644 --- a/atom/connection/fifoserver.hpp +++ b/atom/connection/fifoserver.hpp @@ -326,4 +326,4 @@ class FIFOServer { } // namespace atom::connection -#endif // ATOM_CONNECTION_FIFOSERVER_HPP \ No newline at end of file +#endif // ATOM_CONNECTION_FIFOSERVER_HPP diff --git a/atom/connection/sockethub.cpp b/atom/connection/sockethub.cpp index 62c7141d..b2288ea2 100644 --- a/atom/connection/sockethub.cpp +++ b/atom/connection/sockethub.cpp @@ -850,4 +850,4 @@ void SocketHub::setClientTimeout(std::chrono::seconds timeout) { int SocketHub::getPort() const noexcept { return impl_->getPort(); } -} // namespace atom::connection \ No newline at end of file +} // namespace atom::connection diff --git a/atom/connection/sockethub.hpp b/atom/connection/sockethub.hpp index 40aa05ed..37f1c0bb 100644 --- a/atom/connection/sockethub.hpp +++ b/atom/connection/sockethub.hpp @@ -157,4 +157,4 @@ class SocketHub { } // namespace atom::connection -#endif // ATOM_CONNECTION_SOCKETHUB_HPP \ No newline at end of file +#endif // ATOM_CONNECTION_SOCKETHUB_HPP diff --git a/atom/connection/sshserver.cpp b/atom/connection/sshserver.cpp index 603afeaf..dabb9593 100644 --- a/atom/connection/sshserver.cpp +++ b/atom/connection/sshserver.cpp @@ -1364,4 +1364,4 @@ void SshServer::setServerVersion(const std::string& version) { impl_->setServerVersion(version); } -} // namespace atom::connection \ No newline at end of file +} // namespace atom::connection diff --git a/atom/connection/sshserver.hpp b/atom/connection/sshserver.hpp index 594b324d..f62dab19 100644 --- a/atom/connection/sshserver.hpp +++ b/atom/connection/sshserver.hpp @@ -533,4 +533,4 @@ class SshServer : public NonCopyable { } // namespace atom::connection -#endif // ATOM_CONNECTION_SSHSERVER_HPP \ No newline at end of file +#endif // ATOM_CONNECTION_SSHSERVER_HPP diff --git a/atom/connection/tcpclient.cpp b/atom/connection/tcpclient.cpp index e7e4d01f..63a0aefc 100644 --- a/atom/connection/tcpclient.cpp +++ b/atom/connection/tcpclient.cpp @@ -112,27 +112,27 @@ class TcpClient::Impl { cleanupResources(); } - type::expected connect(std::string_view host, + type::expected connect(std::string_view host, uint16_t port, std::chrono::milliseconds timeout) { try { if (port == 0) { return type::unexpected(std::system_error( - std::make_error_code(std::errc::invalid_argument), + std::make_error_code(std::errc::invalid_argument), "Invalid port number")); } // Resolve hostname struct addrinfo hints = {}; struct addrinfo* result = nullptr; - + hints.ai_family = options_.ipv6_enabled ? AF_UNSPEC : AF_INET; hints.ai_socktype = SOCK_STREAM; - + int status = getaddrinfo(std::string(host).c_str(), std::to_string(port).c_str(), &hints, &result); if (status != 0) { return type::unexpected(std::system_error( - std::make_error_code(std::errc::host_unreachable), + std::make_error_code(std::errc::host_unreachable), "Failed to resolve hostname: " + std::string(gai_strerror(status)))); } @@ -156,7 +156,7 @@ class TcpClient::Impl { // Attempt connection status = ::connect(socket_, rp->ai_addr, rp->ai_addrlen); - + #ifdef _WIN32 if (status == SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK) { continue; // Try next address @@ -175,11 +175,11 @@ class TcpClient::Impl { // Verify connection success int error = 0; socklen_t len = sizeof(error); - if (getsockopt(socket_, SOL_SOCKET, SO_ERROR, + if (getsockopt(socket_, SOL_SOCKET, SO_ERROR, #ifdef _WIN32 reinterpret_cast(&error), #else - &error, + &error, #endif &len) < 0 || error != 0) { continue; // Try next address @@ -187,10 +187,10 @@ class TcpClient::Impl { // Restore blocking mode setNonBlocking(socket_, false); - + // Connection successful connected_ = true; - + #if defined(__linux__) // Add socket to epoll struct epoll_event event = {}; @@ -212,24 +212,24 @@ class TcpClient::Impl { if (onConnectedCallback_) { onConnectedCallback_(); } - + return {}; // Success } // If we got here, all connection attempts failed return type::unexpected(std::system_error( - std::make_error_code(std::errc::connection_refused), + std::make_error_code(std::errc::connection_refused), "Failed to connect to any resolved address")); } catch (const std::exception& e) { auto error = std::system_error( - std::make_error_code(std::errc::io_error), + std::make_error_code(std::errc::io_error), "Connection failed: " + std::string(e.what())); last_error_ = error; return type::unexpected(error); } } - Task> connect_async(std::string_view host, + Task> connect_async(std::string_view host, uint16_t port, std::chrono::milliseconds timeout) { auto result = connect(host, port, timeout); @@ -238,23 +238,23 @@ class TcpClient::Impl { void disconnect() { std::lock_guard lock(mutex_); - + if (connected_) { stopReceiving(); - + #ifdef _WIN32 closesocket(socket_); #else close(socket_); #endif connected_ = false; - + // Recreate socket for reuse socket_ = socket(options_.ipv6_enabled ? AF_INET6 : AF_INET, SOCK_STREAM, IPPROTO_TCP); if (socket_ >= 0) { configureSocket(); } - + // Invoke disconnection callback if (onDisconnectedCallback_) { onDisconnectedCallback_(); @@ -264,10 +264,10 @@ class TcpClient::Impl { type::expected send(std::span data) { std::lock_guard lock(mutex_); - + if (!connected_) { auto error = std::system_error( - std::make_error_code(std::errc::not_connected), + std::make_error_code(std::errc::not_connected), "Not connected"); last_error_ = error; return type::unexpected(error); @@ -281,21 +281,21 @@ class TcpClient::Impl { // Handle large data by sending in chunks size_t total_sent = 0; size_t remaining = data.size(); - + while (remaining > 0) { // Calculate chunk size (limited by SO_SNDBUF) size_t chunk_size = std::min(remaining, options_.send_buffer_size); - - ssize_t bytes_sent = ::send(socket_, - data.data() + total_sent, - chunk_size, + + ssize_t bytes_sent = ::send(socket_, + data.data() + total_sent, + chunk_size, #ifdef _WIN32 0 #else MSG_NOSIGNAL // Prevent SIGPIPE #endif ); - + if (bytes_sent < 0) { #ifdef _WIN32 if (WSAGetLastError() == WSAEWOULDBLOCK) { @@ -318,38 +318,38 @@ class TcpClient::Impl { continue; // Retry send } #endif - + auto error = createSystemError("Send failed"); last_error_ = error; return type::unexpected(error); } - + total_sent += bytes_sent; remaining -= bytes_sent; } - + return total_sent; } catch (const std::exception& e) { auto error = std::system_error( - std::make_error_code(std::errc::io_error), + std::make_error_code(std::errc::io_error), "Send operation failed: " + std::string(e.what())); last_error_ = error; return type::unexpected(error); } } - + Task> send_async(std::span data) { auto result = send(data); co_return result; } - type::expected, std::system_error> receive(size_t max_size, + type::expected, std::system_error> receive(size_t max_size, std::chrono::milliseconds timeout) { std::lock_guard lock(mutex_); - + if (!connected_) { auto error = std::system_error( - std::make_error_code(std::errc::not_connected), + std::make_error_code(std::errc::not_connected), "Not connected"); last_error_ = error; return type::unexpected(error); @@ -368,7 +368,7 @@ class TcpClient::Impl { // Wait until data is available or timeout if (!waitForReceiveReady(timeout)) { auto error = std::system_error( - std::make_error_code(std::errc::timed_out), + std::make_error_code(std::errc::timed_out), "Receive operation timed out"); last_error_ = error; return type::unexpected(error); @@ -377,10 +377,10 @@ class TcpClient::Impl { // Create buffer limited by max_size and receive buffer size size_t buffer_size = std::min(max_size, options_.receive_buffer_size); std::vector buffer(buffer_size); - + // Perform the receive ssize_t bytes_read = ::recv(socket_, buffer.data(), buffer_size, 0); - + if (bytes_read < 0) { auto error = createSystemError("Receive failed"); last_error_ = error; @@ -388,31 +388,31 @@ class TcpClient::Impl { } else if (bytes_read == 0) { // Connection closed by peer connected_ = false; - + if (onDisconnectedCallback_) { onDisconnectedCallback_(); } - + auto error = std::system_error( - std::make_error_code(std::errc::connection_reset), + std::make_error_code(std::errc::connection_reset), "Connection closed by peer"); last_error_ = error; return type::unexpected(error); } - + // Resize buffer to actual bytes read buffer.resize(bytes_read); return buffer; - + } catch (const std::exception& e) { auto error = std::system_error( - std::make_error_code(std::errc::io_error), + std::make_error_code(std::errc::io_error), "Receive operation failed: " + std::string(e.what())); last_error_ = error; return type::unexpected(error); } } - + Task, std::system_error>> receive_async( size_t max_size, std::chrono::milliseconds timeout) { auto result = receive(max_size, timeout); @@ -441,17 +441,17 @@ class TcpClient::Impl { void startReceiving(size_t buffer_size) { std::lock_guard lock(mutex_); - + if (!connected_) { return; } stopReceiving(); - + // Use at least the minimum buffer size size_t actual_buffer_size = std::max(buffer_size, options_.receive_buffer_size); receiving_stopped_.store(false); - + // Launch the receiving thread receiving_thread_ = std::jthread([this, actual_buffer_size](std::stop_token stop_token) { receiveLoop(actual_buffer_size, stop_token); @@ -460,7 +460,7 @@ class TcpClient::Impl { void stopReceiving() { receiving_stopped_.store(true); - + if (receiving_thread_.joinable()) { receiving_thread_.request_stop(); receiving_thread_.join(); @@ -475,25 +475,25 @@ class TcpClient::Impl { void configureSocket() { // Set socket options int opt = 1; - + // TCP keep-alive if (options_.keep_alive) { - setsockopt(socket_, SOL_SOCKET, SO_KEEPALIVE, + setsockopt(socket_, SOL_SOCKET, SO_KEEPALIVE, #ifdef _WIN32 reinterpret_cast(&opt), #else - &opt, + &opt, #endif sizeof(opt)); } - + // Disable Nagle's algorithm (TCP_NODELAY) if (options_.no_delay) { - setsockopt(socket_, IPPROTO_TCP, TCP_NODELAY, + setsockopt(socket_, IPPROTO_TCP, TCP_NODELAY, #ifdef _WIN32 reinterpret_cast(&opt), #else - &opt, + &opt, #endif sizeof(opt)); } @@ -501,20 +501,20 @@ class TcpClient::Impl { // Configure send and receive buffer sizes int recv_size = static_cast(options_.receive_buffer_size); int send_size = static_cast(options_.send_buffer_size); - - setsockopt(socket_, SOL_SOCKET, SO_RCVBUF, + + setsockopt(socket_, SOL_SOCKET, SO_RCVBUF, #ifdef _WIN32 reinterpret_cast(&recv_size), #else - &recv_size, + &recv_size, #endif sizeof(recv_size)); - setsockopt(socket_, SOL_SOCKET, SO_SNDBUF, + setsockopt(socket_, SOL_SOCKET, SO_SNDBUF, #ifdef _WIN32 reinterpret_cast(&send_size), #else - &send_size, + &send_size, #endif sizeof(send_size)); } @@ -539,7 +539,7 @@ class TcpClient::Impl { fd_set write_fds, error_fds; FD_ZERO(&write_fds); FD_ZERO(&error_fds); - + #ifdef _WIN32 FD_SET(socket_, &write_fds); FD_SET(socket_, &error_fds); @@ -547,79 +547,79 @@ class TcpClient::Impl { FD_SET(socket_, &write_fds); FD_SET(socket_, &error_fds); #endif - + struct timeval tv; tv.tv_sec = timeout.count() / 1000; tv.tv_usec = (timeout.count() % 1000) * 1000; - - int result = select(socket_ + 1, nullptr, &write_fds, &error_fds, + + int result = select(socket_ + 1, nullptr, &write_fds, &error_fds, timeout > std::chrono::milliseconds::zero() ? &tv : nullptr); - + return result > 0 && FD_ISSET(socket_, &write_fds); } bool waitForSendReady(std::chrono::milliseconds timeout) { fd_set write_fds; FD_ZERO(&write_fds); - + #ifdef _WIN32 FD_SET(socket_, &write_fds); #else FD_SET(socket_, &write_fds); #endif - + struct timeval tv; tv.tv_sec = timeout.count() / 1000; tv.tv_usec = (timeout.count() % 1000) * 1000; - + int result = select(socket_ + 1, nullptr, &write_fds, nullptr, timeout > std::chrono::milliseconds::zero() ? &tv : nullptr); - + return result > 0 && FD_ISSET(socket_, &write_fds); } bool waitForReceiveReady(std::chrono::milliseconds timeout) { fd_set read_fds; FD_ZERO(&read_fds); - + #ifdef _WIN32 FD_SET(socket_, &read_fds); #else FD_SET(socket_, &read_fds); #endif - + struct timeval tv; tv.tv_sec = timeout.count() / 1000; tv.tv_usec = (timeout.count() % 1000) * 1000; - + int result = select(socket_ + 1, &read_fds, nullptr, nullptr, timeout > std::chrono::milliseconds::zero() ? &tv : nullptr); - + return result > 0 && FD_ISSET(socket_, &read_fds); } void receiveLoop(size_t buffer_size, const std::stop_token& stop_token) { std::vector buffer(buffer_size); - + while (!receiving_stopped_.load() && !stop_token.stop_requested()) { try { #if defined(__linux__) // Use epoll for efficient I/O waiting on Linux struct epoll_event events[10]; int num_events = epoll_wait(epoll_fd_, events, 10, 100); - + if (num_events < 0) { if (errno == EINTR) continue; // Interrupted throw createSystemError("epoll_wait failed"); } - + bool has_data = false; for (int i = 0; i < num_events; i++) { if (events[i].events & EPOLLIN) { has_data = true; break; } - + if (events[i].events & (EPOLLERR | EPOLLHUP)) { // Socket error or hangup connected_ = false; @@ -629,23 +629,23 @@ class TcpClient::Impl { return; } } - + if (!has_data) { continue; // No data available } - + #elif defined(__APPLE__) // Use kqueue for efficient I/O waiting on macOS struct kevent events[10]; struct timespec timeout = {0, 100000000}; // 100ms - + int num_events = kevent(kqueue_fd_, nullptr, 0, events, 10, &timeout); - + if (num_events < 0) { if (errno == EINTR) continue; // Interrupted throw createSystemError("kevent failed"); } - + bool has_data = false; for (int i = 0; i < num_events; i++) { if (events[i].filter == EVFILT_READ) { @@ -653,11 +653,11 @@ class TcpClient::Impl { break; } } - + if (!has_data) { continue; // No data available } - + #else // Use select for other platforms if (!waitForReceiveReady(std::chrono::milliseconds(100))) { @@ -667,13 +667,13 @@ class TcpClient::Impl { // Lock for the recv operation std::unique_lock lock(mutex_); - + if (!connected_) { break; } - + ssize_t bytes_read = ::recv(socket_, buffer.data(), buffer.size(), 0); - + if (bytes_read < 0) { #ifdef _WIN32 if (WSAGetLastError() == WSAEWOULDBLOCK) { @@ -689,37 +689,37 @@ class TcpClient::Impl { // Connection closed connected_ = false; lock.unlock(); // Unlock before callback - + if (onDisconnectedCallback_) { onDisconnectedCallback_(); } break; } - + // Create a data view of valid size std::span data_view(buffer.data(), bytes_read); lock.unlock(); // Unlock before callback - + if (onDataReceivedCallback_) { onDataReceivedCallback_(data_view); } - + } catch (const std::system_error& e) { last_error_ = e; if (onErrorCallback_) { onErrorCallback_(e); } - + // If the error is fatal, break the loop if (e.code().value() != EINTR) { break; } } catch (const std::exception& e) { auto error = std::system_error( - std::make_error_code(std::errc::io_error), + std::make_error_code(std::errc::io_error), "Receive thread error: " + std::string(e.what())); last_error_ = error; - + if (onErrorCallback_) { onErrorCallback_(error); } @@ -730,7 +730,7 @@ class TcpClient::Impl { void cleanupResources() { stopReceiving(); - + if (socket_ >= 0) { #ifdef _WIN32 closesocket(socket_); @@ -773,18 +773,18 @@ class TcpClient::Impl { // Flags and options Options options_; std::atomic connected_{false}; - + // Threading support std::mutex mutex_; std::jthread receiving_thread_; std::atomic receiving_stopped_{false}; - + // Callbacks std::function onConnectedCallback_; std::function onDisconnectedCallback_; std::function)> onDataReceivedCallback_; std::function onErrorCallback_; - + // Error tracking std::system_error last_error_{std::error_code(), ""}; }; @@ -793,7 +793,7 @@ TcpClient::TcpClient(Options options) : impl_(std::make_unique(options)) { TcpClient::~TcpClient() = default; -type::expected TcpClient::connect(std::string_view host, +type::expected TcpClient::connect(std::string_view host, uint16_t port, std::chrono::milliseconds timeout) { auto result = impl_->connect(host, port, timeout); @@ -803,7 +803,7 @@ type::expected TcpClient::connect(std::string_view host return result; } -Task> TcpClient::connect_async(std::string_view host, +Task> TcpClient::connect_async(std::string_view host, uint16_t port, std::chrono::milliseconds timeout) { auto result = co_await impl_->connect_async(host, port, timeout); @@ -828,7 +828,7 @@ Task> TcpClient::send_async(std::span< co_return co_await impl_->send_async(data); } -type::expected, std::system_error> TcpClient::receive(size_t max_size, +type::expected, std::system_error> TcpClient::receive(size_t max_size, std::chrono::milliseconds timeout) { return impl_->receive(max_size, timeout); } @@ -858,4 +858,4 @@ const std::system_error& TcpClient::getLastError() const { return impl_->getLastError(); } -} // namespace atom::connection \ No newline at end of file +} // namespace atom::connection diff --git a/atom/connection/tcpclient.hpp b/atom/connection/tcpclient.hpp index 71b43d0a..eaa5f195 100644 --- a/atom/connection/tcpclient.hpp +++ b/atom/connection/tcpclient.hpp @@ -299,4 +299,4 @@ class TcpClient : public NonCopyable { } // namespace atom::connection -#endif // ATOM_CONNECTION_TCPCLIENT_HPP \ No newline at end of file +#endif // ATOM_CONNECTION_TCPCLIENT_HPP diff --git a/atom/connection/ttybase.hpp b/atom/connection/ttybase.hpp index ac51c2b0..9ec3c65c 100644 --- a/atom/connection/ttybase.hpp +++ b/atom/connection/ttybase.hpp @@ -203,4 +203,4 @@ auto makeByteSpan(Container& container) { std::ranges::size(container) * sizeof(value_type)); } -#endif // ATOM_CONNECTION_TTYBASE_HPP \ No newline at end of file +#endif // ATOM_CONNECTION_TTYBASE_HPP diff --git a/atom/connection/udpclient.cpp b/atom/connection/udpclient.cpp index e112c8eb..a4e2005f 100644 --- a/atom/connection/udpclient.cpp +++ b/atom/connection/udpclient.cpp @@ -1041,4 +1041,4 @@ bool UdpClient::isIPv6Supported() noexcept { return true; } -} // namespace atom::connection \ No newline at end of file +} // namespace atom::connection diff --git a/atom/connection/udpclient.hpp b/atom/connection/udpclient.hpp index 2cffe407..e25ee837 100644 --- a/atom/connection/udpclient.hpp +++ b/atom/connection/udpclient.hpp @@ -397,4 +397,4 @@ class UdpClient { }; } // namespace atom::connection -#endif // ATOM_CONNECTION_UDPCLIENT_HPP \ No newline at end of file +#endif // ATOM_CONNECTION_UDPCLIENT_HPP diff --git a/atom/connection/udpserver.cpp b/atom/connection/udpserver.cpp index 6f732849..b260023d 100644 --- a/atom/connection/udpserver.cpp +++ b/atom/connection/udpserver.cpp @@ -423,4 +423,4 @@ void UdpSocketHub::setBufferSize(std::size_t size) noexcept { impl_->setBufferSize(size); } -} // namespace atom::connection \ No newline at end of file +} // namespace atom::connection diff --git a/atom/connection/udpserver.hpp b/atom/connection/udpserver.hpp index 984c82e5..4f4b08f6 100644 --- a/atom/connection/udpserver.hpp +++ b/atom/connection/udpserver.hpp @@ -132,4 +132,4 @@ class UdpSocketHub { } // namespace atom::connection -#endif \ No newline at end of file +#endif diff --git a/atom/connection/xmake.lua b/atom/connection/xmake.lua index 41b85b52..4af10d5f 100644 --- a/atom/connection/xmake.lua +++ b/atom/connection/xmake.lua @@ -44,7 +44,7 @@ option_end() -- Define base sources and headers local base_sources = { "async_fifoclient.cpp", - "async_fifoserver.cpp", + "async_fifoserver.cpp", "async_sockethub.cpp", "async_tcpclient.cpp", "async_udpclient.cpp", @@ -53,14 +53,14 @@ local base_sources = { "fifoserver.cpp", "sockethub.cpp", "tcpclient.cpp", - "udpclient.cpp", + "udpclient.cpp", "udpserver.cpp" } local base_headers = { "async_fifoclient.hpp", "async_fifoserver.hpp", - "async_sockethub.hpp", + "async_sockethub.hpp", "async_tcpclient.hpp", "async_udpclient.hpp", "async_udpserver.hpp", @@ -79,7 +79,7 @@ local ssh_sources = { } local ssh_headers = { - "sshclient.hpp", + "sshclient.hpp", "sshserver.hpp" } @@ -87,65 +87,65 @@ local ssh_headers = { target("atom-connection") -- Set target kind set_kind("static") - + -- Add base source files add_files(base_sources) add_headerfiles(base_headers) - + -- Add SSH files conditionally if has_config("enable-libssh") then add_files(ssh_sources) add_headerfiles(ssh_headers) end - + -- Add include directories add_includedirs(".", {public = true}) - + -- Add packages add_packages("loguru", "openssl") - + -- Add SSH package conditionally if has_config("enable-ssh") then add_packages("libssh") end - + -- Add system libraries add_syslinks("pthread") - + -- Windows-specific libraries if is_plat("windows") then add_syslinks("ws2_32", "mswsock") end - + -- Enable position independent code add_cxflags("-fPIC", {tools = {"gcc", "clang"}}) add_cflags("-fPIC", {tools = {"gcc", "clang"}}) - + -- Set version info set_version("1.0.0") - + -- Set output name set_basename("atom-connection") - + -- Set directories set_targetdir("$(buildir)/lib") set_objectdir("$(buildir)/obj") - + -- Installation rules after_install(function (target) local installdir = target:installdir() or "$(prefix)" -- Install static library os.cp(target:targetfile(), path.join(installdir, "lib")) - + -- Install headers local headerdir = path.join(installdir, "include", "atom-connection") os.mkdir(headerdir) - + -- Install base headers for _, header in ipairs(base_headers) do os.cp(header, headerdir) end - + -- Install SSH headers conditionally if has_config("enable-libssh") then for _, header in ipairs(ssh_headers) do @@ -157,31 +157,31 @@ target("atom-connection") -- Optional: Create object library target target("atom-connection-object") set_kind("object") - + -- Add base files add_files(base_sources) add_headerfiles(base_headers) - + -- Add SSH files conditionally if has_config("enable-libssh") then add_files(ssh_sources) add_headerfiles(ssh_headers) end - + -- Configuration add_includedirs(".") add_packages("loguru", "openssl") - + if has_config("enable-ssh") then add_packages("libssh") end - + add_syslinks("pthread") - + if is_plat("windows") then add_syslinks("ws2_32", "mswsock") end - + -- Enable PIC add_cxflags("-fPIC", {tools = {"gcc", "clang"}}) add_cflags("-fPIC", {tools = {"gcc", "clang"}}) diff --git a/atom/containers/boost_containers.hpp b/atom/containers/boost_containers.hpp index 5eea0f8b..2b01631a 100644 --- a/atom/containers/boost_containers.hpp +++ b/atom/containers/boost_containers.hpp @@ -126,4 +126,4 @@ using flat_map = boost::container::flat_map< } // namespace containers } // namespace atom -#endif // defined(ATOM_HAS_BOOST_CONTAINER) \ No newline at end of file +#endif // defined(ATOM_HAS_BOOST_CONTAINER) diff --git a/atom/containers/graph.hpp b/atom/containers/graph.hpp index bafa14ce..e0f0afd1 100644 --- a/atom/containers/graph.hpp +++ b/atom/containers/graph.hpp @@ -549,4 +549,4 @@ Graph create_graph( } // namespace containers } // namespace atom -#endif // defined(ATOM_HAS_BOOST_GRAPH) \ No newline at end of file +#endif // defined(ATOM_HAS_BOOST_GRAPH) diff --git a/atom/containers/high_performance.hpp b/atom/containers/high_performance.hpp index dc761e4a..6bb7fbd8 100644 --- a/atom/containers/high_performance.hpp +++ b/atom/containers/high_performance.hpp @@ -507,4 +507,4 @@ using String = std::string; #endif // ATOM_OPTIMIZE_FOR_SPEED -} // namespace atom::containers \ No newline at end of file +} // namespace atom::containers diff --git a/atom/containers/intrusive.hpp b/atom/containers/intrusive.hpp index eda77e6b..2bb3869e 100644 --- a/atom/containers/intrusive.hpp +++ b/atom/containers/intrusive.hpp @@ -38,17 +38,17 @@ using slist_base_hook = boost::intrusive::slist_base_hook<>; /** * @brief 侵入式链表 - * + * * 侵入式链表要求元素类型内包含钩子(hook),避免了额外的内存分配。 * 非常适合管理大量对象,减少内存碎片和提高缓存性能。 - * + * * 使用示例: * class MyClass : public atom::containers::intrusive::list_base_hook { * // 类成员和方法 * }; - * + * * atom::containers::intrusive::list my_list; - * + * * @tparam T 必须继承自list_base_hook的元素类型 */ template @@ -56,9 +56,9 @@ using list = boost::intrusive::list; /** * @brief 侵入式单向链表 - * + * * 比双向链表更轻量,但只支持单向遍历 - * + * * @tparam T 必须继承自slist_base_hook的元素类型 */ template @@ -66,9 +66,9 @@ using slist = boost::intrusive::slist; /** * @brief 侵入式有序集合 - * + * * 元素按键排序,提供快速查找,同时避免了内存分配开销 - * + * * @tparam T 必须继承自set_base_hook的元素类型 * @tparam Compare 比较元素的函数对象类型 */ @@ -77,14 +77,14 @@ using set = boost::intrusive::set>; /** * @brief 侵入式无序集合 - * + * * 通过哈希实现快速查找,避免了标准无序容器的节点分配开销 - * + * * @tparam T 必须继承自unordered_set_base_hook的元素类型 * @tparam Hash 哈希函数对象类型 * @tparam Equal 判断元素相等的函数对象类型 */ -template , typename Equal = std::equal_to> class unordered_set { @@ -93,80 +93,80 @@ class unordered_set { static constexpr std::size_t NumBuckets = 128; using bucket_type = boost::intrusive::unordered_set::bucket_type; bucket_type buckets_[NumBuckets]; - + using unordered_set_type = boost::intrusive::unordered_set< T, boost::intrusive::hash, boost::intrusive::equal, boost::intrusive::constant_time_size >; - + unordered_set_type set_; - + public: using iterator = typename unordered_set_type::iterator; using const_iterator = typename unordered_set_type::const_iterator; - + unordered_set() : set_(boost::intrusive::bucket_traits(buckets_, NumBuckets)) {} - + /** * @brief 插入元素到无序集合 - * + * * @param value 要插入的元素 * @return std::pair 包含指向插入元素的迭代器和是否成功插入的标志 */ std::pair insert(T& value) { return set_.insert(value); } - + /** * @brief 从无序集合中移除元素 - * + * * @param value 要移除的元素 * @return bool 如果元素被移除则返回true */ bool remove(T& value) { return set_.erase(value) > 0; } - + /** * @brief 查找元素 - * + * * @param value 要查找的元素 * @return iterator 指向找到的元素,如果未找到则返回end() */ iterator find(const T& value) { return set_.find(value); } - + /** * @brief 返回起始迭代器 */ iterator begin() { return set_.begin(); } - + /** * @brief 返回终止迭代器 */ iterator end() { return set_.end(); } - + /** * @brief 检查容器是否为空 */ bool empty() const { return set_.empty(); } - + /** * @brief 返回容器中元素的数量 */ std::size_t size() const { return set_.size(); } - + /** * @brief 清空容器 */ @@ -177,7 +177,7 @@ class unordered_set { /** * @brief 提供可链接类型的助手基类 - * + * * 这个类简化了创建支持多种侵入式容器的对象。 * 如果需要一个对象同时可以放入list、set和unordered_set, * 可以继承这个类。 @@ -191,14 +191,14 @@ class intrusive_base : protected: // 保护构造函数防止直接实例化 intrusive_base() = default; - + // 允许派生类销毁 virtual ~intrusive_base() = default; - + // 禁止复制 intrusive_base(const intrusive_base&) = delete; intrusive_base& operator=(const intrusive_base&) = delete; - + // 允许移动 intrusive_base(intrusive_base&&) = default; intrusive_base& operator=(intrusive_base&&) = default; @@ -208,4 +208,4 @@ class intrusive_base : } // namespace containers } // namespace atom -#endif // defined(ATOM_HAS_BOOST_INTRUSIVE) \ No newline at end of file +#endif // defined(ATOM_HAS_BOOST_INTRUSIVE) diff --git a/atom/containers/lockfree.hpp b/atom/containers/lockfree.hpp index b0b6127c..fbe29449 100644 --- a/atom/containers/lockfree.hpp +++ b/atom/containers/lockfree.hpp @@ -33,7 +33,7 @@ namespace lockfree { * * 这个队列允许多个线程并发地入队和出队,无需互斥锁。 * 适用于高性能并发系统和并行计算。 - * + * * @tparam T 元素类型 * @tparam Capacity 队列容量 */ @@ -47,7 +47,7 @@ class queue { /** * @brief 将元素推入队列 - * + * * @param item 要入队的元素 * @return bool 如果成功返回true,如果队列已满则返回false */ @@ -57,7 +57,7 @@ class queue { /** * @brief 从队列弹出元素 - * + * * @param item 接收弹出元素的引用 * @return bool 如果成功返回true,如果队列为空则返回false */ @@ -67,9 +67,9 @@ class queue { /** * @brief 检查队列是否为空 - * + * * 注意:在多线程环境中,此操作结果可能立即过期 - * + * * @return bool 如果队列为空返回true */ bool empty() const { @@ -79,10 +79,10 @@ class queue { /** * @brief 单生产者单消费者无锁队列 - * + * * 这个高度优化的队列适用于只有一个线程生产数据和一个线程消费数据的场景。 * 比多生产者多消费者版本有更低的开销。 - * + * * @tparam T 元素类型 * @tparam Capacity 队列容量 */ @@ -96,7 +96,7 @@ class spsc_queue { /** * @brief 将元素推入队列 - * + * * @param item 要入队的元素 * @return bool 如果成功返回true,如果队列已满则返回false */ @@ -106,7 +106,7 @@ class spsc_queue { /** * @brief 从队列弹出元素 - * + * * @param item 接收弹出元素的引用 * @return bool 如果成功返回true,如果队列为空则返回false */ @@ -116,7 +116,7 @@ class spsc_queue { /** * @brief 检查队列是否为空 - * + * * @return bool 如果队列为空返回true */ bool empty() const { @@ -126,9 +126,9 @@ class spsc_queue { /** * @brief 无锁栈 - * + * * 线程安全的LIFO数据结构,允许多个线程并发地压入和弹出元素,无需互斥锁。 - * + * * @tparam T 元素类型 * @tparam Capacity 栈容量 */ @@ -142,7 +142,7 @@ class stack { /** * @brief 将元素压入栈 - * + * * @param item 要压入的元素 * @return bool 如果成功返回true,如果栈已满则返回false */ @@ -152,7 +152,7 @@ class stack { /** * @brief 从栈弹出元素 - * + * * @param item 接收弹出元素的引用 * @return bool 如果成功返回true,如果栈为空则返回false */ @@ -162,9 +162,9 @@ class stack { /** * @brief 检查栈是否为空 - * + * * 注意:在多线程环境中,此操作结果可能立即过期 - * + * * @return bool 如果栈为空返回true */ bool empty() const { @@ -176,4 +176,4 @@ class stack { } // namespace containers } // namespace atom -#endif // defined(ATOM_HAS_BOOST_LOCKFREE) \ No newline at end of file +#endif // defined(ATOM_HAS_BOOST_LOCKFREE) diff --git a/atom/error/CMakeLists.txt b/atom/error/CMakeLists.txt index 3999892b..9f3a86a7 100644 --- a/atom/error/CMakeLists.txt +++ b/atom/error/CMakeLists.txt @@ -50,4 +50,4 @@ set_target_properties(${PROJECT_NAME} PROPERTIES # Install rules install(TARGETS ${PROJECT_NAME} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} -) \ No newline at end of file +) diff --git a/atom/error/stacktrace.cpp b/atom/error/stacktrace.cpp index 996d4faa..41a5b130 100644 --- a/atom/error/stacktrace.cpp +++ b/atom/error/stacktrace.cpp @@ -304,4 +304,4 @@ void StackTrace::capture() { #endif } -} // namespace atom::error \ No newline at end of file +} // namespace atom::error diff --git a/atom/error/stacktrace.hpp b/atom/error/stacktrace.hpp index 0bd3d90c..6beceac7 100644 --- a/atom/error/stacktrace.hpp +++ b/atom/error/stacktrace.hpp @@ -64,4 +64,4 @@ class StackTrace { } // namespace atom::error -#endif \ No newline at end of file +#endif diff --git a/atom/error/xmake.lua b/atom/error/xmake.lua index e82bdc7a..9292f8be 100644 --- a/atom/error/xmake.lua +++ b/atom/error/xmake.lua @@ -38,37 +38,37 @@ local headers = { target("atom-error") -- Set target kind to shared library set_kind("shared") - + -- Add source files add_files(sources) - + -- Add header files add_headerfiles(headers) - + -- Add include directories add_includedirs(".", {public = true}) - + -- Add packages add_packages("loguru") - + -- Add platform-specific libraries if is_plat("linux") then add_syslinks("dl") end - + -- Enable position independent code (automatic for shared libraries) set_policy("build.optimization.lto", true) - + -- Set version info set_version("1.0.0") - + -- Set output name set_basename("atom-error") - + -- Set target and object directories set_targetdir("$(buildir)/lib") set_objectdir("$(buildir)/obj") - + -- Installation rules after_install(function (target) local installdir = target:installdir() or "$(prefix)" @@ -85,20 +85,20 @@ target("atom-error") -- Optional: Create object library target (equivalent to CMake's object library) target("atom-error-object") set_kind("object") - + -- Add the same source files add_files(sources) add_headerfiles(headers) - + -- Configuration add_includedirs(".") add_packages("loguru") - + -- Platform-specific libraries if is_plat("linux") then add_syslinks("dl") end - + -- Enable position independent code add_cxflags("-fPIC", {tools = {"gcc", "clang"}}) add_cflags("-fPIC", {tools = {"gcc", "clang"}}) diff --git a/atom/extra/asio/asio_compatibility.hpp b/atom/extra/asio/asio_compatibility.hpp index 160fafef..dfdb3a56 100644 --- a/atom/extra/asio/asio_compatibility.hpp +++ b/atom/extra/asio/asio_compatibility.hpp @@ -65,4 +65,4 @@ template auto as_tuple_awaitable(AsyncOperation&& op) { return std::forward(op)( net::experimental::as_tuple(use_awaitable)); -} \ No newline at end of file +} diff --git a/atom/extra/asio/mqtt/client.cpp b/atom/extra/asio/mqtt/client.cpp index 3505cb7b..7ebd95d0 100644 --- a/atom/extra/asio/mqtt/client.cpp +++ b/atom/extra/asio/mqtt/client.cpp @@ -781,4 +781,4 @@ void Client::handle_transport_error(ErrorCode error) { } } -} // namespace mqtt \ No newline at end of file +} // namespace mqtt diff --git a/atom/extra/asio/mqtt/client.hpp b/atom/extra/asio/mqtt/client.hpp index 3908b183..58edb6da 100644 --- a/atom/extra/asio/mqtt/client.hpp +++ b/atom/extra/asio/mqtt/client.hpp @@ -557,4 +557,4 @@ class Client { /** @} */ }; -} // namespace mqtt \ No newline at end of file +} // namespace mqtt diff --git a/atom/extra/asio/mqtt/packet.cpp b/atom/extra/asio/mqtt/packet.cpp index 1ce3c6a3..a4e58600 100644 --- a/atom/extra/asio/mqtt/packet.cpp +++ b/atom/extra/asio/mqtt/packet.cpp @@ -417,4 +417,4 @@ Result> PacketCodec::parse_unsuback( return parse_suback(data); // Same format as SUBACK } -} // namespace mqtt \ No newline at end of file +} // namespace mqtt diff --git a/atom/extra/asio/mqtt/packet.hpp b/atom/extra/asio/mqtt/packet.hpp index aa5f4c6a..0b1a64e9 100644 --- a/atom/extra/asio/mqtt/packet.hpp +++ b/atom/extra/asio/mqtt/packet.hpp @@ -407,4 +407,4 @@ class PacketCodec { ProtocolVersion version); }; -} // namespace mqtt \ No newline at end of file +} // namespace mqtt diff --git a/atom/extra/asio/mqtt/protocol.hpp b/atom/extra/asio/mqtt/protocol.hpp index ac9b57d4..9f4da386 100644 --- a/atom/extra/asio/mqtt/protocol.hpp +++ b/atom/extra/asio/mqtt/protocol.hpp @@ -316,4 +316,4 @@ inline bool TLSTransport::is_open() const { return ssl_socket_.lowest_layer().is_open(); } -} // namespace mqtt \ No newline at end of file +} // namespace mqtt diff --git a/atom/extra/asio/mqtt/test_client.hpp b/atom/extra/asio/mqtt/test_client.hpp index d3790a99..ff1981fb 100644 --- a/atom/extra/asio/mqtt/test_client.hpp +++ b/atom/extra/asio/mqtt/test_client.hpp @@ -468,4 +468,4 @@ TEST_F(ClientTest, StatsAfterOperations) { // verifies no crashes auto after_stats = client_->get_stats(); EXPECT_GE(after_stats.messages_sent, initial_stats.messages_sent); -} \ No newline at end of file +} diff --git a/atom/extra/asio/mqtt/test_packet.hpp b/atom/extra/asio/mqtt/test_packet.hpp index 3cd035f8..fd2971d5 100644 --- a/atom/extra/asio/mqtt/test_packet.hpp +++ b/atom/extra/asio/mqtt/test_packet.hpp @@ -249,4 +249,4 @@ TEST(BinaryBufferTest, ReadMalformedPacket) { auto result = buf.read(); EXPECT_FALSE(result.has_value()); EXPECT_EQ(result.error(), ErrorCode::MALFORMED_PACKET); -} \ No newline at end of file +} diff --git a/atom/extra/asio/mqtt/test_protocol.hpp b/atom/extra/asio/mqtt/test_protocol.hpp index 7db44066..f6fd4485 100644 --- a/atom/extra/asio/mqtt/test_protocol.hpp +++ b/atom/extra/asio/mqtt/test_protocol.hpp @@ -195,4 +195,4 @@ TEST(TLSTransportTest, AsyncWriteAndReadError) { transport.close(); EXPECT_FALSE(transport.is_open()); -} \ No newline at end of file +} diff --git a/atom/extra/asio/mqtt/test_types.hpp b/atom/extra/asio/mqtt/test_types.hpp index cd0097cf..b2391ba9 100644 --- a/atom/extra/asio/mqtt/test_types.hpp +++ b/atom/extra/asio/mqtt/test_types.hpp @@ -225,4 +225,4 @@ TEST(CallbackTypesTest, DisconnectionHandler) { }; handler(ErrorCode::SERVER_UNAVAILABLE); EXPECT_TRUE(called); -} \ No newline at end of file +} diff --git a/atom/extra/asio/mqtt/types.hpp b/atom/extra/asio/mqtt/types.hpp index e62eafa4..aa4011a8 100644 --- a/atom/extra/asio/mqtt/types.hpp +++ b/atom/extra/asio/mqtt/types.hpp @@ -174,4 +174,4 @@ using ConnectionHandler = std::function; */ using DisconnectionHandler = std::function; -} // namespace mqtt \ No newline at end of file +} // namespace mqtt diff --git a/atom/extra/asio/sse/client/client.cpp b/atom/extra/asio/sse/client/client.cpp index 6d2f5719..96a7ce45 100644 --- a/atom/extra/asio/sse/client/client.cpp +++ b/atom/extra/asio/sse/client/client.cpp @@ -435,4 +435,4 @@ bool Client::is_connected() const { return pimpl_->is_connected(); } const ClientConfig& Client::config() const { return pimpl_->config(); } -} // namespace atom::extra::asio::sse \ No newline at end of file +} // namespace atom::extra::asio::sse diff --git a/atom/extra/asio/sse/client/client.hpp b/atom/extra/asio/sse/client/client.hpp index c4804e1f..de8533e8 100644 --- a/atom/extra/asio/sse/client/client.hpp +++ b/atom/extra/asio/sse/client/client.hpp @@ -116,4 +116,4 @@ class Client { std::unique_ptr pimpl_; ///< Pointer to implementation. }; -} // namespace atom::extra::asio::sse \ No newline at end of file +} // namespace atom::extra::asio::sse diff --git a/atom/extra/asio/sse/client/client_config.cpp b/atom/extra/asio/sse/client/client_config.cpp index f74e1f54..e9507ecf 100644 --- a/atom/extra/asio/sse/client/client_config.cpp +++ b/atom/extra/asio/sse/client/client_config.cpp @@ -102,4 +102,4 @@ void ClientConfig::save_to_file(const std::string& filename) const { } } -} // namespace sse \ No newline at end of file +} // namespace sse diff --git a/atom/extra/asio/sse/client/client_config.hpp b/atom/extra/asio/sse/client/client_config.hpp index c1fcfe8f..59ad2ac6 100644 --- a/atom/extra/asio/sse/client/client_config.hpp +++ b/atom/extra/asio/sse/client/client_config.hpp @@ -68,4 +68,4 @@ struct ClientConfig { void save_to_file(const std::string& filename) const; }; -} // namespace atom::extra::asio::sse \ No newline at end of file +} // namespace atom::extra::asio::sse diff --git a/atom/extra/asio/sse/event.cpp b/atom/extra/asio/sse/event.cpp index e4de5fb2..9f7ee13a 100644 --- a/atom/extra/asio/sse/event.cpp +++ b/atom/extra/asio/sse/event.cpp @@ -308,4 +308,4 @@ HeartbeatEvent::HeartbeatEvent() .count()), std::string("heartbeat"), std::string("ping")) {} -} // namespace atom::extra::asio::sse \ No newline at end of file +} // namespace atom::extra::asio::sse diff --git a/atom/extra/asio/sse/event.hpp b/atom/extra/asio/sse/event.hpp index a91fc478..e164fcb1 100644 --- a/atom/extra/asio/sse/event.hpp +++ b/atom/extra/asio/sse/event.hpp @@ -250,4 +250,4 @@ class HeartbeatEvent final : public Event { } // namespace atom::extra::asio::sse -#endif // ATOM_EXTRA_ASIO_SSE_EVENT_HPP \ No newline at end of file +#endif // ATOM_EXTRA_ASIO_SSE_EVENT_HPP diff --git a/atom/extra/asio/sse/event_store.cpp b/atom/extra/asio/sse/event_store.cpp index 6fef1be8..560ab912 100644 --- a/atom/extra/asio/sse/event_store.cpp +++ b/atom/extra/asio/sse/event_store.cpp @@ -115,4 +115,4 @@ void EventStore::load_existing_events() { } } -} // namespace atom::extra::asio::sse \ No newline at end of file +} // namespace atom::extra::asio::sse diff --git a/atom/extra/asio/sse/event_store.hpp b/atom/extra/asio/sse/event_store.hpp index d3fbdb8e..a47a4d22 100644 --- a/atom/extra/asio/sse/event_store.hpp +++ b/atom/extra/asio/sse/event_store.hpp @@ -83,4 +83,4 @@ class EventStore { } // namespace atom::extra::asio::sse -#endif // ATOM_EXTRA_ASIO_SSE_EVENT_STORE_HPP \ No newline at end of file +#endif // ATOM_EXTRA_ASIO_SSE_EVENT_STORE_HPP diff --git a/atom/extra/asio/sse/server/auth_service.cpp b/atom/extra/asio/sse/server/auth_service.cpp index b55fe971..974a968a 100644 --- a/atom/extra/asio/sse/server/auth_service.cpp +++ b/atom/extra/asio/sse/server/auth_service.cpp @@ -95,4 +95,4 @@ void AuthService::save_auth_data() { } } -} // namespace atom::extra::asio::sse \ No newline at end of file +} // namespace atom::extra::asio::sse diff --git a/atom/extra/asio/sse/server/auth_service.hpp b/atom/extra/asio/sse/server/auth_service.hpp index 61bf268e..f10605d0 100644 --- a/atom/extra/asio/sse/server/auth_service.hpp +++ b/atom/extra/asio/sse/server/auth_service.hpp @@ -105,4 +105,4 @@ class AuthService { void save_auth_data(); }; -} // namespace atom::extra::asio::sse \ No newline at end of file +} // namespace atom::extra::asio::sse diff --git a/atom/extra/asio/sse/server/connection.cpp b/atom/extra/asio/sse/server/connection.cpp index f58119c9..4391650e 100644 --- a/atom/extra/asio/sse/server/connection.cpp +++ b/atom/extra/asio/sse/server/connection.cpp @@ -470,4 +470,4 @@ net::awaitable SSEConnection::send_event(const Event& event) { client_id_); } -} // namespace atom::extra::asio::sse \ No newline at end of file +} // namespace atom::extra::asio::sse diff --git a/atom/extra/asio/sse/server/connection.hpp b/atom/extra/asio/sse/server/connection.hpp index 0602c832..bba02f15 100644 --- a/atom/extra/asio/sse/server/connection.hpp +++ b/atom/extra/asio/sse/server/connection.hpp @@ -91,4 +91,4 @@ class SSEConnection : public std::enable_shared_from_this { bool authenticate_client(const HttpRequest& request); }; -} // namespace atom::extra::asio::sse \ No newline at end of file +} // namespace atom::extra::asio::sse diff --git a/atom/extra/asio/sse/server/event_queue.cpp b/atom/extra/asio/sse/server/event_queue.cpp index 0c1ce2e1..d87f17ff 100644 --- a/atom/extra/asio/sse/server/event_queue.cpp +++ b/atom/extra/asio/sse/server/event_queue.cpp @@ -30,4 +30,4 @@ std::optional EventQueue::pop_event() { return event; } -} // namespace atom::extra::asio::sse \ No newline at end of file +} // namespace atom::extra::asio::sse diff --git a/atom/extra/asio/sse/server/event_queue.hpp b/atom/extra/asio/sse/server/event_queue.hpp index 8bcd4b9e..6cdc0611 100644 --- a/atom/extra/asio/sse/server/event_queue.hpp +++ b/atom/extra/asio/sse/server/event_queue.hpp @@ -33,4 +33,4 @@ class EventQueue { bool persist_events_; }; -} // namespace sse_server \ No newline at end of file +} // namespace sse_server diff --git a/atom/extra/asio/sse/server/event_store.cpp b/atom/extra/asio/sse/server/event_store.cpp index 2911d582..0a5d7ec3 100644 --- a/atom/extra/asio/sse/server/event_store.cpp +++ b/atom/extra/asio/sse/server/event_store.cpp @@ -147,4 +147,4 @@ void EventStore::persist_event(const Event& event) { } } -} // namespace atom::extra::asio::sse \ No newline at end of file +} // namespace atom::extra::asio::sse diff --git a/atom/extra/asio/sse/server/event_store.hpp b/atom/extra/asio/sse/server/event_store.hpp index ad65fb68..c93b97b7 100644 --- a/atom/extra/asio/sse/server/event_store.hpp +++ b/atom/extra/asio/sse/server/event_store.hpp @@ -117,4 +117,4 @@ class EventStore { void persist_event(const Event& event); }; -} // namespace atom::extra::asio::sse \ No newline at end of file +} // namespace atom::extra::asio::sse diff --git a/atom/extra/asio/sse/server/http_request.cpp b/atom/extra/asio/sse/server/http_request.cpp index 6aa9de53..8a4589cb 100644 --- a/atom/extra/asio/sse/server/http_request.cpp +++ b/atom/extra/asio/sse/server/http_request.cpp @@ -51,4 +51,4 @@ std::optional HttpRequest::get_last_event_id() const { return std::nullopt; } -} // namespace atom::extra::asio::sse \ No newline at end of file +} // namespace atom::extra::asio::sse diff --git a/atom/extra/asio/sse/server/http_request.hpp b/atom/extra/asio/sse/server/http_request.hpp index 8274e9cc..3ab2ef33 100644 --- a/atom/extra/asio/sse/server/http_request.hpp +++ b/atom/extra/asio/sse/server/http_request.hpp @@ -79,4 +79,4 @@ struct HttpRequest { std::optional get_last_event_id() const; }; -} // namespace atom::extra::asio::sse \ No newline at end of file +} // namespace atom::extra::asio::sse diff --git a/atom/extra/asio/sse/server/metrics.cpp b/atom/extra/asio/sse/server/metrics.cpp index d2f482eb..f76ca897 100644 --- a/atom/extra/asio/sse/server/metrics.cpp +++ b/atom/extra/asio/sse/server/metrics.cpp @@ -50,4 +50,4 @@ void ServerMetrics::update_max_concurrent() { } } -} // namespace atom::extra::asio::sse \ No newline at end of file +} // namespace atom::extra::asio::sse diff --git a/atom/extra/asio/sse/server/metrics.hpp b/atom/extra/asio/sse/server/metrics.hpp index 82b97883..818335a4 100644 --- a/atom/extra/asio/sse/server/metrics.hpp +++ b/atom/extra/asio/sse/server/metrics.hpp @@ -125,4 +125,4 @@ class ServerMetrics { void update_max_concurrent(); }; -} // namespace atom::extra::asio::sse \ No newline at end of file +} // namespace atom::extra::asio::sse diff --git a/atom/extra/asio/sse/server/server.cpp b/atom/extra/asio/sse/server/server.cpp index 4ac88947..47698e22 100644 --- a/atom/extra/asio/sse/server/server.cpp +++ b/atom/extra/asio/sse/server/server.cpp @@ -178,4 +178,4 @@ std::string generate_id() { return std::to_string(counter++); } -} // namespace atom::extra::asio::sse \ No newline at end of file +} // namespace atom::extra::asio::sse diff --git a/atom/extra/asio/sse/server/server.hpp b/atom/extra/asio/sse/server/server.hpp index fdb23a14..23ac5644 100644 --- a/atom/extra/asio/sse/server/server.hpp +++ b/atom/extra/asio/sse/server/server.hpp @@ -182,4 +182,4 @@ class SSEServer { */ std::string generate_id(); -} // namespace atom::extra::asio::sse \ No newline at end of file +} // namespace atom::extra::asio::sse diff --git a/atom/extra/asio/sse/server/server_config.cpp b/atom/extra/asio/sse/server/server_config.cpp index 4357018a..61665594 100644 --- a/atom/extra/asio/sse/server/server_config.cpp +++ b/atom/extra/asio/sse/server/server_config.cpp @@ -69,4 +69,4 @@ void ServerConfig::save_to_file(const std::string& filename) const { } } -} // namespace atom::extra::asio::sse \ No newline at end of file +} // namespace atom::extra::asio::sse diff --git a/atom/extra/asio/sse/server/server_config.hpp b/atom/extra/asio/sse/server/server_config.hpp index c38aa984..7148c8cc 100644 --- a/atom/extra/asio/sse/server/server_config.hpp +++ b/atom/extra/asio/sse/server/server_config.hpp @@ -125,4 +125,4 @@ struct ServerConfig { void save_to_file(const std::string& filename) const; }; -} // namespace atom::extra::asio::sse \ No newline at end of file +} // namespace atom::extra::asio::sse diff --git a/atom/extra/asio/sse/sse.hpp b/atom/extra/asio/sse/sse.hpp index 2fed7d6f..0868efe0 100644 --- a/atom/extra/asio/sse/sse.hpp +++ b/atom/extra/asio/sse/sse.hpp @@ -10,4 +10,4 @@ #include "client_config.hpp" #include "event_store.hpp" #include "client.hpp" -#include "logger.hpp" \ No newline at end of file +#include "logger.hpp" diff --git a/atom/extra/beast/ws.cpp b/atom/extra/beast/ws.cpp index fc094f4c..435b78b1 100644 --- a/atom/extra/beast/ws.cpp +++ b/atom/extra/beast/ws.cpp @@ -269,4 +269,4 @@ void WSClient::startPing() { } })); })); -} \ No newline at end of file +} diff --git a/atom/extra/beast/ws.hpp b/atom/extra/beast/ws.hpp index caf335a8..d3fa77c1 100644 --- a/atom/extra/beast/ws.hpp +++ b/atom/extra/beast/ws.hpp @@ -436,4 +436,4 @@ void WSClient::handleConnectError(beast::error_code ec, } } -#endif // ATOM_EXTRA_BEAST_WS_HPP \ No newline at end of file +#endif // ATOM_EXTRA_BEAST_WS_HPP diff --git a/atom/extra/curl/cache.hpp b/atom/extra/curl/cache.hpp index efd7ee64..ee476344 100644 --- a/atom/extra/curl/cache.hpp +++ b/atom/extra/curl/cache.hpp @@ -111,4 +111,4 @@ class Cache { }; } // namespace atom::extra::curl -#endif // ATOM_EXTRA_CURL_CACHE_HPP \ No newline at end of file +#endif // ATOM_EXTRA_CURL_CACHE_HPP diff --git a/atom/extra/curl/connection_pool.hpp b/atom/extra/curl/connection_pool.hpp index 16e473cf..a0971658 100644 --- a/atom/extra/curl/connection_pool.hpp +++ b/atom/extra/curl/connection_pool.hpp @@ -20,4 +20,4 @@ class ConnectionPool { }; } // namespace atom::extra::curl -#endif \ No newline at end of file +#endif diff --git a/atom/extra/curl/cookie.hpp b/atom/extra/curl/cookie.hpp index 576e6cb1..0796d8ed 100644 --- a/atom/extra/curl/cookie.hpp +++ b/atom/extra/curl/cookie.hpp @@ -208,4 +208,4 @@ class CookieJar { }; } // namespace atom::extra::curl -#endif // ATOM_EXTRA_CURL_COOKIE_HPP \ No newline at end of file +#endif // ATOM_EXTRA_CURL_COOKIE_HPP diff --git a/atom/extra/curl/error.cpp b/atom/extra/curl/error.cpp index c519245b..97ac9c07 100644 --- a/atom/extra/curl/error.cpp +++ b/atom/extra/curl/error.cpp @@ -16,4 +16,4 @@ std::optional Error::multi_code() const noexcept { return multi_code_; } -} // namespace atom::extra::curl \ No newline at end of file +} // namespace atom::extra::curl diff --git a/atom/extra/curl/error.hpp b/atom/extra/curl/error.hpp index 588f69e6..fb0ef777 100644 --- a/atom/extra/curl/error.hpp +++ b/atom/extra/curl/error.hpp @@ -55,4 +55,4 @@ class Error : public std::runtime_error { } // namespace atom::extra::curl -#endif // ATOM_EXTRA_CURL_ERROR_HPP \ No newline at end of file +#endif // ATOM_EXTRA_CURL_ERROR_HPP diff --git a/atom/extra/curl/interceptor.hpp b/atom/extra/curl/interceptor.hpp index 685ad02b..e28d6f34 100644 --- a/atom/extra/curl/interceptor.hpp +++ b/atom/extra/curl/interceptor.hpp @@ -60,4 +60,4 @@ class Interceptor { }; } // namespace atom::extra::curl -#endif // ATOM_EXTRA_CURL_INTERCEPTOR_HPP \ No newline at end of file +#endif // ATOM_EXTRA_CURL_INTERCEPTOR_HPP diff --git a/atom/extra/curl/multi_session.cpp b/atom/extra/curl/multi_session.cpp index b61aa69e..a7ab72b8 100644 --- a/atom/extra/curl/multi_session.cpp +++ b/atom/extra/curl/multi_session.cpp @@ -268,4 +268,4 @@ size_t MultiSession::header_callback(char* buffer, size_t size, size_t nitems, return realsize; } -} // namespace atom::extra::curl \ No newline at end of file +} // namespace atom::extra::curl diff --git a/atom/extra/curl/multi_session.hpp b/atom/extra/curl/multi_session.hpp index 127149bf..786fe66e 100644 --- a/atom/extra/curl/multi_session.hpp +++ b/atom/extra/curl/multi_session.hpp @@ -131,4 +131,4 @@ class MultiSession { }; } // namespace atom::extra::curl -#endif // ATOM_EXTRA_CURL_MULTI_SESSION_HPP \ No newline at end of file +#endif // ATOM_EXTRA_CURL_MULTI_SESSION_HPP diff --git a/atom/extra/curl/multipart.cpp b/atom/extra/curl/multipart.cpp index dde3d3ef..444c34e1 100644 --- a/atom/extra/curl/multipart.cpp +++ b/atom/extra/curl/multipart.cpp @@ -87,4 +87,4 @@ void MultipartForm::initialize() { form_ = curl_mime_init(curl); curl_easy_cleanup(curl); } -} // namespace atom::extra::curl \ No newline at end of file +} // namespace atom::extra::curl diff --git a/atom/extra/curl/multipart.hpp b/atom/extra/curl/multipart.hpp index 8a65e01b..2d23dbb9 100644 --- a/atom/extra/curl/multipart.hpp +++ b/atom/extra/curl/multipart.hpp @@ -115,4 +115,4 @@ class MultipartForm { }; } // namespace atom::extra::curl -#endif // ATOM_EXTRA_CURL_MULTIPART_HPP \ No newline at end of file +#endif // ATOM_EXTRA_CURL_MULTIPART_HPP diff --git a/atom/extra/curl/rate_limiter.hpp b/atom/extra/curl/rate_limiter.hpp index 1798bfef..51595165 100644 --- a/atom/extra/curl/rate_limiter.hpp +++ b/atom/extra/curl/rate_limiter.hpp @@ -51,4 +51,4 @@ class RateLimiter { } // namespace atom::extra::curl -#endif // ATOM_EXTRA_CURL_RATE_LIMITER_HPP \ No newline at end of file +#endif // ATOM_EXTRA_CURL_RATE_LIMITER_HPP diff --git a/atom/extra/curl/request.hpp b/atom/extra/curl/request.hpp index 8df00706..3fb6c08f 100644 --- a/atom/extra/curl/request.hpp +++ b/atom/extra/curl/request.hpp @@ -631,4 +631,4 @@ class Request { }; } // namespace atom::extra::curl -#endif // ATOM_EXTRA_CURL_REQUEST_HPP \ No newline at end of file +#endif // ATOM_EXTRA_CURL_REQUEST_HPP diff --git a/atom/extra/curl/response.hpp b/atom/extra/curl/response.hpp index 3a8a1701..7268bf71 100644 --- a/atom/extra/curl/response.hpp +++ b/atom/extra/curl/response.hpp @@ -139,4 +139,4 @@ class Response { }; } // namespace atom::extra::curl -#endif // ATOM_EXTRA_CURL_RESPONSE_HPP \ No newline at end of file +#endif // ATOM_EXTRA_CURL_RESPONSE_HPP diff --git a/atom/extra/curl/rest_client.hpp b/atom/extra/curl/rest_client.hpp index acd1f53e..71a3db3d 100644 --- a/atom/extra/curl/rest_client.hpp +++ b/atom/extra/curl/rest_client.hpp @@ -509,4 +509,4 @@ class RestClient { }; } // namespace atom::extra::curl -#endif // ATOM_EXTRA_CURL_REST_CLIENT_HPP \ No newline at end of file +#endif // ATOM_EXTRA_CURL_REST_CLIENT_HPP diff --git a/atom/extra/curl/session.hpp b/atom/extra/curl/session.hpp index 0f5fa0eb..00a73745 100644 --- a/atom/extra/curl/session.hpp +++ b/atom/extra/curl/session.hpp @@ -378,4 +378,4 @@ class Session { }; } // namespace atom::extra::curl -#endif // ATOM_EXTRA_CURL_SESSION_HPP \ No newline at end of file +#endif // ATOM_EXTRA_CURL_SESSION_HPP diff --git a/atom/extra/curl/session_pool.cpp b/atom/extra/curl/session_pool.cpp index dab709f7..59efee70 100644 --- a/atom/extra/curl/session_pool.cpp +++ b/atom/extra/curl/session_pool.cpp @@ -33,4 +33,4 @@ void SessionPool::release(std::shared_ptr session) { } // 如果池已满,session 会自动析构 } -} // namespace atom::extra::curl \ No newline at end of file +} // namespace atom::extra::curl diff --git a/atom/extra/curl/session_pool.hpp b/atom/extra/curl/session_pool.hpp index 01747940..3b2e5243 100644 --- a/atom/extra/curl/session_pool.hpp +++ b/atom/extra/curl/session_pool.hpp @@ -66,4 +66,4 @@ class SessionPool { }; } // namespace atom::extra::curl -#endif // ATOM_EXTRA_CURL_SESSION_POOL_HPP \ No newline at end of file +#endif // ATOM_EXTRA_CURL_SESSION_POOL_HPP diff --git a/atom/extra/curl/websocket.hpp b/atom/extra/curl/websocket.hpp index 581498f4..ddb3be7e 100644 --- a/atom/extra/curl/websocket.hpp +++ b/atom/extra/curl/websocket.hpp @@ -166,4 +166,4 @@ class WebSocket { }; } // namespace atom::extra::curl -#endif // ATOM_EXTRA_CURL_WEBSOCKET_HPP \ No newline at end of file +#endif // ATOM_EXTRA_CURL_WEBSOCKET_HPP diff --git a/atom/extra/dotenv/CMakeLists.txt b/atom/extra/dotenv/CMakeLists.txt index ba220d02..cecc7c9f 100644 --- a/atom/extra/dotenv/CMakeLists.txt +++ b/atom/extra/dotenv/CMakeLists.txt @@ -72,4 +72,4 @@ install(FILES ${HEADERS} DESTINATION include/dotenv) install(EXPORT dotenv-cpp-targets FILE dotenv-cpp-config.cmake DESTINATION lib/cmake/dotenv-cpp -) \ No newline at end of file +) diff --git a/atom/extra/dotenv/dotenv.cpp b/atom/extra/dotenv/dotenv.cpp index 4e64d9e1..735528d7 100644 --- a/atom/extra/dotenv/dotenv.cpp +++ b/atom/extra/dotenv/dotenv.cpp @@ -272,4 +272,4 @@ void Dotenv::config(const std::filesystem::path& filepath, } } -} // namespace dotenv \ No newline at end of file +} // namespace dotenv diff --git a/atom/extra/dotenv/dotenv.hpp b/atom/extra/dotenv/dotenv.hpp index 4a489da2..c145b328 100644 --- a/atom/extra/dotenv/dotenv.hpp +++ b/atom/extra/dotenv/dotenv.hpp @@ -258,4 +258,4 @@ class Dotenv { const std::vector& source_files = {}); }; -} // namespace dotenv \ No newline at end of file +} // namespace dotenv diff --git a/atom/extra/dotenv/exceptions.hpp b/atom/extra/dotenv/exceptions.hpp index 22b88589..6fe41867 100644 --- a/atom/extra/dotenv/exceptions.hpp +++ b/atom/extra/dotenv/exceptions.hpp @@ -42,4 +42,4 @@ class ValidationException : public DotenvException { : DotenvException("Validation Error: " + message) {} }; -} // namespace dotenv \ No newline at end of file +} // namespace dotenv diff --git a/atom/extra/dotenv/loader.cpp b/atom/extra/dotenv/loader.cpp index a1d3ae3b..62bd4cc3 100644 --- a/atom/extra/dotenv/loader.cpp +++ b/atom/extra/dotenv/loader.cpp @@ -268,4 +268,4 @@ std::string FileLoader::convertEncoding(const std::string& content, return content; } -} // namespace dotenv \ No newline at end of file +} // namespace dotenv diff --git a/atom/extra/dotenv/loader.hpp b/atom/extra/dotenv/loader.hpp index 86d0a06a..de0e9ef0 100644 --- a/atom/extra/dotenv/loader.hpp +++ b/atom/extra/dotenv/loader.hpp @@ -158,4 +158,4 @@ class FileLoader { const std::string& from_encoding); }; -} // namespace dotenv \ No newline at end of file +} // namespace dotenv diff --git a/atom/extra/dotenv/parser.cpp b/atom/extra/dotenv/parser.cpp index 87767b09..2e448543 100644 --- a/atom/extra/dotenv/parser.cpp +++ b/atom/extra/dotenv/parser.cpp @@ -235,4 +235,4 @@ void Parser::setVariableExpander(VariableExpander expander) { variable_expander_ = std::move(expander); } -} // namespace dotenv \ No newline at end of file +} // namespace dotenv diff --git a/atom/extra/dotenv/parser.hpp b/atom/extra/dotenv/parser.hpp index afc7a4a6..d730dd5f 100644 --- a/atom/extra/dotenv/parser.hpp +++ b/atom/extra/dotenv/parser.hpp @@ -82,4 +82,4 @@ class Parser { bool isEmpty(const std::string& line); }; -} // namespace dotenv \ No newline at end of file +} // namespace dotenv diff --git a/atom/extra/dotenv/test_dotenv.hpp b/atom/extra/dotenv/test_dotenv.hpp index e34a8db7..eda3c2de 100644 --- a/atom/extra/dotenv/test_dotenv.hpp +++ b/atom/extra/dotenv/test_dotenv.hpp @@ -259,4 +259,4 @@ TEST_F(DotenvTest, StaticConfigSuccess) { TEST_F(DotenvTest, StaticConfigFailureThrows) { auto file = dir / "bad.env"; EXPECT_THROW(Dotenv::config(file, true), DotenvException); -} \ No newline at end of file +} diff --git a/atom/extra/dotenv/test_validator.hpp b/atom/extra/dotenv/test_validator.hpp index c2dd990f..e4ee7cff 100644 --- a/atom/extra/dotenv/test_validator.hpp +++ b/atom/extra/dotenv/test_validator.hpp @@ -196,4 +196,4 @@ TEST_F(ValidatorTest, ValidatorValidateNoRules) { auto result = validator.validate(env, schema); EXPECT_TRUE(result.is_valid); EXPECT_TRUE(result.errors.empty()); -} \ No newline at end of file +} diff --git a/atom/extra/dotenv/validator.cpp b/atom/extra/dotenv/validator.cpp index 4671e366..59d5c610 100644 --- a/atom/extra/dotenv/validator.cpp +++ b/atom/extra/dotenv/validator.cpp @@ -225,4 +225,4 @@ std::shared_ptr custom(ValidationRule::Validator validator, } // namespace rules -} // namespace dotenv \ No newline at end of file +} // namespace dotenv diff --git a/atom/extra/dotenv/validator.hpp b/atom/extra/dotenv/validator.hpp index 862f7470..8447f381 100644 --- a/atom/extra/dotenv/validator.hpp +++ b/atom/extra/dotenv/validator.hpp @@ -152,4 +152,4 @@ class Validator { ValidationResult& result); }; -} // namespace dotenv \ No newline at end of file +} // namespace dotenv diff --git a/atom/extra/iconv/test_iconv_cpp.cpp b/atom/extra/iconv/test_iconv_cpp.cpp index b60eb5b9..6dc4f54f 100644 --- a/atom/extra/iconv/test_iconv_cpp.cpp +++ b/atom/extra/iconv/test_iconv_cpp.cpp @@ -21,12 +21,12 @@ class IconvCppTest : public ::testing::Test { temp_input = fs::temp_directory_path() / "iconv_test_input.txt"; temp_output = fs::temp_directory_path() / "iconv_test_output.txt"; temp_output2 = fs::temp_directory_path() / "iconv_test_output2.txt"; - + // Create test file with UTF-8 content including multibyte characters std::ofstream ofs(temp_input, std::ios::binary); ofs << "Hello, 世界! 🌍\nTest file with UTF-8 content.\n"; ofs.close(); - + // Create ASCII test file temp_ascii = fs::temp_directory_path() / "iconv_test_ascii.txt"; std::ofstream ascii_ofs(temp_ascii, std::ios::binary); @@ -60,12 +60,12 @@ TEST_F(IconvCppTest, ConverterMoveSemantics) { Converter conv1("UTF-8", "UTF-8"); std::string test = "move test"; auto result1 = conv1.convert_string(test); - + // Move constructor Converter conv2 = std::move(conv1); auto result2 = conv2.convert_string(test); EXPECT_EQ(result1, result2); - + // Move assignment Converter conv3("UTF-8", "UTF-16LE"); conv3 = std::move(conv2); @@ -84,10 +84,10 @@ TEST_F(IconvCppTest, UTF8ToUTF16RoundTrip) { std::string utf8 = "Hello, 世界! 🌍"; UTF8ToUTF16Converter to16; UTF16ToUTF8Converter to8; - + auto utf16 = to16.convert_u16string(utf8); EXPECT_GT(utf16.size(), 0); - + std::string roundtrip = to8.convert_u16string(utf16); EXPECT_EQ(utf8, roundtrip); } @@ -96,10 +96,10 @@ TEST_F(IconvCppTest, UTF8ToUTF32RoundTrip) { std::string utf8 = "Test 🌍 emoji"; UTF8ToUTF32Converter to32; UTF32ToUTF8Converter to8; - + auto utf32 = to32.convert_u32string(utf8); EXPECT_GT(utf32.size(), 0); - + std::string roundtrip = to8.convert_u32string(utf32); EXPECT_EQ(utf8, roundtrip); } @@ -116,7 +116,7 @@ TEST_F(IconvCppTest, ErrorHandlingReplace) { ConversionOptions opts; opts.error_policy = ErrorHandlingPolicy::Replace; opts.replacement_char = '?'; - + Converter conv("UTF-8", "UTF-8", opts); std::string result = conv.convert_string(invalid_utf8); EXPECT_TRUE(result.find('?') != std::string::npos); @@ -127,7 +127,7 @@ TEST_F(IconvCppTest, ErrorHandlingSkip) { std::string invalid_utf8 = "abc\xFF\\xFEdef"; ConversionOptions opts; opts.error_policy = ErrorHandlingPolicy::Skip; - + Converter conv("UTF-8", "UTF-8", opts); std::string result = conv.convert_string(invalid_utf8); EXPECT_TRUE(result.find("abc") != std::string::npos); @@ -139,7 +139,7 @@ TEST_F(IconvCppTest, ErrorHandlingIgnore) { std::string invalid_utf8 = "abc\xFF\xFE"; ConversionOptions opts; opts.error_policy = ErrorHandlingPolicy::Ignore; - + Converter conv("UTF-8", "UTF-8", opts); std::string result = conv.convert_string(invalid_utf8); EXPECT_TRUE(result.find("abc") != std::string::npos); @@ -175,15 +175,15 @@ TEST_F(IconvCppTest, FileConversion) { TEST_F(IconvCppTest, FileConversionWithProgress) { bool progress_called = false; size_t last_processed = 0; - + auto progress_cb = [&](size_t processed, size_t total) { progress_called = true; EXPECT_LE(processed, total); EXPECT_GE(processed, last_processed); last_processed = processed; }; - - EXPECT_TRUE(convert_file("UTF-8", "UTF-8", temp_input, temp_output, + + EXPECT_TRUE(convert_file("UTF-8", "UTF-8", temp_input, temp_output, ConversionOptions(), progress_cb)); EXPECT_TRUE(progress_called); } @@ -246,7 +246,7 @@ TEST_F(IconvCppTest, BomAddition) { std::vector data = {'H', 'e', 'l', 'l', 'o'}; auto with_bom = BomHandler::add_bom("UTF-8", data); EXPECT_GT(with_bom.size(), data.size()); - + auto [detected_enc, bom_size] = BomHandler::detect_bom(with_bom); EXPECT_EQ(detected_enc, "UTF-8"); EXPECT_EQ(bom_size, 3); @@ -299,7 +299,7 @@ TEST_F(IconvCppTest, EncodingDetectionMaxResults) { TEST_F(IconvCppTest, FileEncodingDetection) { auto encoding = detect_file_encoding(temp_ascii); EXPECT_TRUE(encoding == "ASCII" || encoding == "UTF-8"); - + encoding = detect_file_encoding(temp_input); EXPECT_TRUE(encoding == "UTF-8" || encoding == "ASCII"); } @@ -320,7 +320,7 @@ TEST_F(IconvCppTest, EncodingRegistryListEncodings) { auto encodings = registry.list_all_encodings(); EXPECT_FALSE(encodings.empty()); EXPECT_GT(encodings.size(), 10); - + // Check for common encodings bool found_utf8 = false, found_ascii = false; for (const auto& enc : encodings) { @@ -346,7 +346,7 @@ TEST_F(IconvCppTest, EncodingRegistryInfo) { EXPECT_TRUE(info->is_ascii_compatible); EXPECT_EQ(info->min_char_size, 1); EXPECT_EQ(info->max_char_size, 4); - + auto invalid_info = registry.get_encoding_info("INVALID-ENCODING"); EXPECT_FALSE(invalid_info.has_value()); } @@ -355,7 +355,7 @@ TEST_F(IconvCppTest, EncodingRegistryInfo) { TEST_F(IconvCppTest, BufferManagerCreate) { auto buffer = BufferManager::create_resizable_buffer(1024); EXPECT_EQ(buffer.size(), 1024); - + auto default_buffer = BufferManager::create_resizable_buffer(); EXPECT_EQ(default_buffer.size(), 4096); } @@ -363,7 +363,7 @@ TEST_F(IconvCppTest, BufferManagerCreate) { TEST_F(IconvCppTest, BufferManagerEnsureCapacity) { auto buffer = BufferManager::create_resizable_buffer(10); EXPECT_EQ(buffer.size(), 10); - + BufferManager::ensure_buffer_capacity(buffer, 50); EXPECT_GE(buffer.size(), 50); } @@ -371,7 +371,7 @@ TEST_F(IconvCppTest, BufferManagerEnsureCapacity) { TEST_F(IconvCppTest, BufferManagerEstimateSize) { size_t estimate = BufferManager::estimate_output_size(100, "UTF-8", "UTF-16LE"); EXPECT_GT(estimate, 100); - + size_t unknown_estimate = BufferManager::estimate_output_size(100, "UNKNOWN", "UNKNOWN"); EXPECT_EQ(unknown_estimate, 400); // 4x fallback } @@ -381,16 +381,16 @@ TEST_F(IconvCppTest, ProgressCallbackCalled) { std::string large_input(10000, 'a'); bool callback_called = false; size_t max_processed = 0; - + auto progress_cb = [&](size_t processed, size_t total) { callback_called = true; EXPECT_LE(processed, total); max_processed = std::max(max_processed, processed); }; - + Converter conv("UTF-8", "UTF-8"); auto result = conv.convert_with_progress({large_input.data(), large_input.size()}, progress_cb); - + EXPECT_TRUE(callback_called); EXPECT_EQ(max_processed, large_input.size()); EXPECT_EQ(result.size(), large_input.size()); @@ -400,17 +400,17 @@ TEST_F(IconvCppTest, ProgressCallbackCalled) { TEST_F(IconvCppTest, StatefulConversion) { ConversionState state; Converter conv("UTF-8", "UTF-8"); - + std::string part1 = "First part "; std::string part2 = "Second part"; - + auto out1 = conv.convert_with_state({part1.data(), part1.size()}, state); EXPECT_GT(state.processed_input_bytes, 0); EXPECT_GT(state.processed_output_bytes, 0); - + auto out2 = conv.convert_with_state({part2.data(), part2.size()}, state); EXPECT_EQ(state.processed_input_bytes, part1.size() + part2.size()); - + std::string combined(out1.begin(), out1.end()); combined.append(out2.begin(), out2.end()); EXPECT_EQ(combined, part1 + part2); @@ -422,7 +422,7 @@ TEST_F(IconvCppTest, ConversionStateReset) { state.processed_output_bytes = 50; state.is_complete = true; state.state_data = {'a', 'b', 'c'}; - + state.reset(); EXPECT_EQ(state.processed_input_bytes, 0); EXPECT_EQ(state.processed_output_bytes, 0); @@ -435,30 +435,30 @@ TEST_F(IconvCppTest, StreamConverter) { std::string input = "Stream conversion test with 中文"; std::istringstream iss(input); std::ostringstream oss; - + StreamConverter sc("UTF-8", "UTF-8"); sc.convert(iss, oss); - + EXPECT_EQ(oss.str(), input); } TEST_F(IconvCppTest, StreamConverterToString) { std::string input = "Convert to string test"; std::istringstream iss(input); - + StreamConverter sc("UTF-8", "UTF-8"); std::string result = sc.convert_to_string(iss); - + EXPECT_EQ(result, input); } TEST_F(IconvCppTest, StreamConverterFromString) { std::string input = "Convert from string test"; std::ostringstream oss; - + StreamConverter sc("UTF-8", "UTF-8"); sc.convert_from_string(input, oss); - + EXPECT_EQ(oss.str(), input); } @@ -467,15 +467,15 @@ TEST_F(IconvCppTest, StreamConverterWithProgress) { std::istringstream iss(input); std::ostringstream oss; bool progress_called = false; - + auto progress_cb = [&](size_t processed, size_t total) { progress_called = true; EXPECT_LE(processed, total); }; - + StreamConverter sc("UTF-8", "UTF-8"); sc.convert(iss, oss, progress_cb); - + EXPECT_EQ(oss.str(), input); // Note: Progress may not be called for small inputs } @@ -484,7 +484,7 @@ TEST_F(IconvCppTest, StreamConverterWithProgress) { TEST_F(IconvCppTest, BatchConverterStrings) { BatchConverter batch("UTF-8", "UTF-8"); std::vector inputs = {"first", "second", "third 中文"}; - + auto outputs = batch.convert_strings(inputs); EXPECT_EQ(outputs.size(), inputs.size()); EXPECT_EQ(outputs, inputs); @@ -494,7 +494,7 @@ TEST_F(IconvCppTest, BatchConverterFiles) { BatchConverter batch("UTF-8", "UTF-8"); std::vector input_paths = {temp_input}; std::vector output_paths = {temp_output}; - + auto results = batch.convert_files(input_paths, output_paths); EXPECT_EQ(results.size(), 1); EXPECT_TRUE(results[0]); @@ -505,7 +505,7 @@ TEST_F(IconvCppTest, BatchConverterFilesMismatch) { BatchConverter batch("UTF-8", "UTF-8"); std::vector input_paths = {temp_input, temp_ascii}; std::vector output_paths = {temp_output}; // Size mismatch - + EXPECT_THROW(batch.convert_files(input_paths, output_paths), IconvError); } @@ -513,7 +513,7 @@ TEST_F(IconvCppTest, BatchConverterParallel) { BatchConverter batch("UTF-8", "UTF-8"); std::vector input_paths = {temp_input, temp_ascii}; std::vector output_paths = {temp_output, temp_output2}; - + auto results = batch.convert_files_parallel(input_paths, output_paths, 2); EXPECT_EQ(results.size(), 2); EXPECT_TRUE(results[0]); @@ -526,19 +526,19 @@ TEST_F(IconvCppTest, BatchConverterParallel) { TEST_F(IconvCppTest, ChineseEncodingConverter) { ChineseEncodingConverter conv; std::string utf8 = "你好世界"; - + // Test GB18030 conversion std::string gb18030 = conv.utf8_to_gb18030_string(utf8); EXPECT_NE(gb18030, utf8); std::string utf8_back = conv.gb18030_to_utf8_string(gb18030); EXPECT_EQ(utf8_back, utf8); - + // Test GBK conversion std::string gbk = conv.utf8_to_gbk_string(utf8); EXPECT_NE(gbk, utf8); utf8_back = conv.gbk_to_utf8_string(gbk); EXPECT_EQ(utf8_back, utf8); - + // Test Big5 conversion std::string big5 = conv.utf8_to_big5_string(utf8); EXPECT_NE(big5, utf8); @@ -549,13 +549,13 @@ TEST_F(IconvCppTest, ChineseEncodingConverter) { TEST_F(IconvCppTest, JapaneseEncodingConverter) { JapaneseEncodingConverter conv; std::string utf8 = "こんにちは"; - + // Test Shift-JIS conversion std::string sjis = conv.utf8_to_shift_jis_string(utf8); EXPECT_NE(sjis, utf8); std::string utf8_back = conv.shift_jis_to_utf8_string(sjis); EXPECT_EQ(utf8_back, utf8); - + // Test EUC-JP conversion std::string euc_jp = conv.utf8_to_euc_jp_string(utf8); EXPECT_NE(euc_jp, utf8); @@ -566,7 +566,7 @@ TEST_F(IconvCppTest, JapaneseEncodingConverter) { TEST_F(IconvCppTest, KoreanEncodingConverter) { KoreanEncodingConverter conv; std::string utf8 = "안녕하세요"; - + // Test EUC-KR conversion std::string euc_kr = conv.utf8_to_euc_kr_string(utf8); EXPECT_NE(euc_kr, utf8); @@ -592,12 +592,12 @@ TEST_F(IconvCppTest, ConvertFunction) { TEST_F(IconvCppTest, ThreadSafety) { std::string input = "Thread safety test 线程安全测试"; Converter conv("UTF-8", "UTF-8"); - + const int num_threads = 4; const int iterations = 100; std::vector threads; std::vector results(num_threads, true); - + for (int t = 0; t < num_threads; ++t) { threads.emplace_back([&conv, &input, &results, t, iterations]() { try { @@ -613,11 +613,11 @@ TEST_F(IconvCppTest, ThreadSafety) { } }); } - + for (auto& thread : threads) { thread.join(); } - + for (bool result : results) { EXPECT_TRUE(result); } @@ -633,7 +633,7 @@ TEST_F(IconvCppTest, ConverterReset) { Converter conv("UTF-8", "UTF-8"); std::string test = "Reset test"; auto result1 = conv.convert_string(test); - + conv.reset(); // Should not affect subsequent conversions auto result2 = conv.convert_string(test); EXPECT_EQ(result1, result2); @@ -643,15 +643,15 @@ TEST_F(IconvCppTest, ConverterReset) { TEST_F(IconvCppTest, LargeInputPerformance) { const size_t large_size = 1024 * 1024; // 1MB std::string large_input(large_size, 'A'); - + auto start = std::chrono::high_resolution_clock::now(); - + Converter conv("UTF-8", "UTF-8"); auto result = conv.convert_string(large_input); - + auto end = std::chrono::high_resolution_clock::now(); auto duration = std::chrono::duration_cast(end - start); - + EXPECT_EQ(result.size(), large_size); // Performance assertion - should complete within reasonable time EXPECT_LT(duration.count(), 1000); // Less than 1 second @@ -692,4 +692,4 @@ TEST_F(IconvCppTest, MixedContentConversion) { std::string mixed = "ASCII 中文 123 🌍 test"; auto result = convert_string("UTF-8", "UTF-8", mixed); EXPECT_EQ(result, mixed); -} \ No newline at end of file +} diff --git a/atom/extra/inicpp/event_listener.hpp b/atom/extra/inicpp/event_listener.hpp index 1bd6f1fc..a11e9420 100644 --- a/atom/extra/inicpp/event_listener.hpp +++ b/atom/extra/inicpp/event_listener.hpp @@ -260,4 +260,4 @@ class EventManager { #endif // INICPP_CONFIG_EVENT_LISTENERS -#endif // ATOM_EXTRA_INICPP_EVENT_LISTENER_HPP \ No newline at end of file +#endif // ATOM_EXTRA_INICPP_EVENT_LISTENER_HPP diff --git a/atom/extra/inicpp/field.hpp b/atom/extra/inicpp/field.hpp index 9ed54235..a6d8ea1f 100644 --- a/atom/extra/inicpp/field.hpp +++ b/atom/extra/inicpp/field.hpp @@ -168,7 +168,7 @@ class IniField { class IniFieldPool { private: static boost::object_pool pool_; - + public: /** * @brief Allocate a new IniField from the pool. @@ -177,7 +177,7 @@ class IniFieldPool { static IniField* allocate() { return pool_.construct(); } - + /** * @brief Allocate a new IniField from the pool with an initial value. * @param value The initial value. @@ -188,7 +188,7 @@ class IniFieldPool { static IniField* allocate(StringType value) { return pool_.construct(value); } - + /** * @brief Free an IniField back to the pool. * @param field The field to free. diff --git a/atom/extra/inicpp/format_converter.hpp b/atom/extra/inicpp/format_converter.hpp index c9320f35..7fe3a717 100644 --- a/atom/extra/inicpp/format_converter.hpp +++ b/atom/extra/inicpp/format_converter.hpp @@ -341,4 +341,4 @@ inline IniFile FormatConverter::importFrom(const std::string& content, #endif // INICPP_CONFIG_FORMAT_CONVERSION -#endif // ATOM_EXTRA_INICPP_FORMAT_CONVERTER_HPP \ No newline at end of file +#endif // ATOM_EXTRA_INICPP_FORMAT_CONVERTER_HPP diff --git a/atom/extra/inicpp/inicpp.hpp b/atom/extra/inicpp/inicpp.hpp index a1f35966..d95cd49b 100644 --- a/atom/extra/inicpp/inicpp.hpp +++ b/atom/extra/inicpp/inicpp.hpp @@ -22,14 +22,14 @@ /** * @namespace inicpp * @brief 提供高性能、类型安全的INI配置文件解析功能 - * + * * 该库具有以下特点: * 1. 类型安全 - 通过模板获取强类型字段值 * 2. 线程安全 - 使用共享锁实现并发读写 * 3. 高性能 - 支持并行处理、内存池和Boost容器 * 4. 可扩展 - 支持自定义分隔符、转义字符和注释前缀 * 5. 丰富功能 - 支持嵌套段落、事件监听、路径查询、格式转换等 - * + * * 可通过宏控制功能开关: * - INICPP_CONFIG_USE_BOOST: 是否使用Boost库 * - INICPP_CONFIG_USE_BOOST_CONTAINERS: 是否使用Boost容器 diff --git a/atom/extra/inicpp/path_query.hpp b/atom/extra/inicpp/path_query.hpp index 162babfd..697c04df 100644 --- a/atom/extra/inicpp/path_query.hpp +++ b/atom/extra/inicpp/path_query.hpp @@ -162,4 +162,4 @@ class PathQuery { } // namespace inicpp -#endif // ATOM_EXTRA_INICPP_PATH_QUERY_HPP \ No newline at end of file +#endif // ATOM_EXTRA_INICPP_PATH_QUERY_HPP diff --git a/atom/extra/inicpp/section.hpp b/atom/extra/inicpp/section.hpp index d9f56566..65c12f2a 100644 --- a/atom/extra/inicpp/section.hpp +++ b/atom/extra/inicpp/section.hpp @@ -282,7 +282,7 @@ class IniSectionBase : public map_type { // 检查字段是否已存在 auto it = this->find(key); bool fieldExists = (it != this->end()); - + // 如果启用了事件监听,准备事件数据 #if INICPP_CONFIG_EVENT_LISTENERS std::string oldValue; @@ -293,7 +293,7 @@ class IniSectionBase : public map_type { // 设置或更新字段值 (*this)[key] = value; - + // 如果启用了事件监听,触发事件 #if INICPP_CONFIG_EVENT_LISTENERS // 准备事件数据 @@ -301,18 +301,18 @@ class IniSectionBase : public map_type { eventData.sectionName = sectionName_; eventData.fieldName = key; eventData.newValue = (*this)[key].template as(); - + if (fieldExists) { eventData.oldValue = oldValue; eventData.eventType = SectionEventType::FIELD_MODIFIED; } else { eventData.eventType = SectionEventType::FIELD_ADDED; } - + // 通知监听器 notifyListeners(eventData); #endif - + } catch (const std::exception& ex) { throw std::invalid_argument("Failed to set field '" + key + "': " + ex.what()); @@ -329,7 +329,7 @@ class IniSectionBase : public map_type { if (it == this->end()) { return false; } - + #if INICPP_CONFIG_EVENT_LISTENERS // 准备事件数据 SectionEventData eventData; @@ -338,15 +338,15 @@ class IniSectionBase : public map_type { eventData.oldValue = it->second.template as(); eventData.eventType = SectionEventType::FIELD_REMOVED; #endif - + // 删除字段 this->erase(it); - + #if INICPP_CONFIG_EVENT_LISTENERS // 通知监听器 notifyListeners(eventData); #endif - + return true; } @@ -369,10 +369,10 @@ class IniSectionBase : public map_type { eventData.sectionName = sectionName_; eventData.eventType = SectionEventType::SECTION_CLEARED; #endif - + // 清空所有字段 this->clear(); - + #if INICPP_CONFIG_EVENT_LISTENERS // 通知监听器 notifyListeners(eventData); diff --git a/atom/extra/pugixml/xml_builder.hpp b/atom/extra/pugixml/xml_builder.hpp index 16b78e3a..b3053d35 100644 --- a/atom/extra/pugixml/xml_builder.hpp +++ b/atom/extra/pugixml/xml_builder.hpp @@ -177,4 +177,4 @@ namespace literals { } // namespace literals -} // namespace atom::extra::pugixml \ No newline at end of file +} // namespace atom::extra::pugixml diff --git a/atom/extra/pugixml/xml_document.hpp b/atom/extra/pugixml/xml_document.hpp index 6f0da212..5f01bda3 100644 --- a/atom/extra/pugixml/xml_document.hpp +++ b/atom/extra/pugixml/xml_document.hpp @@ -232,4 +232,4 @@ class Document { } }; -} // namespace atom::extra::pugixml \ No newline at end of file +} // namespace atom::extra::pugixml diff --git a/atom/extra/pugixml/xml_node_wrapper.hpp b/atom/extra/pugixml/xml_node_wrapper.hpp index 7f2717c9..8bc36321 100644 --- a/atom/extra/pugixml/xml_node_wrapper.hpp +++ b/atom/extra/pugixml/xml_node_wrapper.hpp @@ -471,4 +471,4 @@ struct std::hash { size_t operator()(const atom::extra::pugixml::Node& node) const noexcept { return node.hash(); } -}; \ No newline at end of file +}; diff --git a/atom/extra/pugixml/xml_query.hpp b/atom/extra/pugixml/xml_query.hpp index 93016525..9b28c53d 100644 --- a/atom/extra/pugixml/xml_query.hpp +++ b/atom/extra/pugixml/xml_query.hpp @@ -219,4 +219,4 @@ void sort_children(Node& node, Compare&& comp) { } // namespace transform -} // namespace atom::extra::pugixml \ No newline at end of file +} // namespace atom::extra::pugixml diff --git a/atom/extra/spdlog/CMakeLists.txt b/atom/extra/spdlog/CMakeLists.txt index 9272bdfa..0a90245d 100644 --- a/atom/extra/spdlog/CMakeLists.txt +++ b/atom/extra/spdlog/CMakeLists.txt @@ -71,4 +71,4 @@ install(EXPORT modern_log_targets FILE modern_log_targets.cmake NAMESPACE modern_log:: DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/modern_log -) \ No newline at end of file +) diff --git a/atom/extra/spdlog/core/concepts.h b/atom/extra/spdlog/core/concepts.h index fb69ea58..69baa2be 100644 --- a/atom/extra/spdlog/core/concepts.h +++ b/atom/extra/spdlog/core/concepts.h @@ -75,4 +75,4 @@ template concept Range = std::ranges::range && Formattable>; -} // namespace modern_log \ No newline at end of file +} // namespace modern_log diff --git a/atom/extra/spdlog/core/context.cpp b/atom/extra/spdlog/core/context.cpp index e89f8701..8cf445d0 100644 --- a/atom/extra/spdlog/core/context.cpp +++ b/atom/extra/spdlog/core/context.cpp @@ -78,4 +78,4 @@ bool LogContext::empty() const { request_id_.empty() && custom_fields_.empty(); } -} // namespace modern_log \ No newline at end of file +} // namespace modern_log diff --git a/atom/extra/spdlog/core/context.h b/atom/extra/spdlog/core/context.h index 97c89e96..ecb6800e 100644 --- a/atom/extra/spdlog/core/context.h +++ b/atom/extra/spdlog/core/context.h @@ -151,4 +151,4 @@ class LogContext { bool empty() const; }; -} // namespace modern_log \ No newline at end of file +} // namespace modern_log diff --git a/atom/extra/spdlog/core/error.h b/atom/extra/spdlog/core/error.h index e55bca31..0d0e7927 100644 --- a/atom/extra/spdlog/core/error.h +++ b/atom/extra/spdlog/core/error.h @@ -127,4 +127,4 @@ using Result = std::expected; namespace std { template <> struct is_error_code_enum : true_type {}; -} // namespace std \ No newline at end of file +} // namespace std diff --git a/atom/extra/spdlog/core/test_context.h b/atom/extra/spdlog/core/test_context.h index 44dcf1bd..6768bc17 100644 --- a/atom/extra/spdlog/core/test_context.h +++ b/atom/extra/spdlog/core/test_context.h @@ -125,4 +125,4 @@ TEST(LogContextTest, EmptyReturnsTrueOnlyIfAllFieldsAreEmpty) { EXPECT_FALSE(ctx.empty()); ctx.clear(); EXPECT_TRUE(ctx.empty()); -} \ No newline at end of file +} diff --git a/atom/extra/spdlog/core/test_error.h b/atom/extra/spdlog/core/test_error.h index d00c02ee..bfaf3fd2 100644 --- a/atom/extra/spdlog/core/test_error.h +++ b/atom/extra/spdlog/core/test_error.h @@ -70,4 +70,4 @@ TEST(LogErrorTest, ErrorCodeEnumTrait) { // This test ensures LogError is recognized as an error_code_enum bool is_enum = std::is_error_code_enum::value; EXPECT_TRUE(is_enum); -} \ No newline at end of file +} diff --git a/atom/extra/spdlog/core/test_types.h b/atom/extra/spdlog/core/test_types.h index 58651e70..a814c6f7 100644 --- a/atom/extra/spdlog/core/test_types.h +++ b/atom/extra/spdlog/core/test_types.h @@ -139,4 +139,4 @@ TEST(LogConfigTest, AsyncConfig) { EXPECT_TRUE(config.async); EXPECT_EQ(config.async_queue_size, 4096u); EXPECT_EQ(config.async_thread_count, 4u); -} \ No newline at end of file +} diff --git a/atom/extra/spdlog/core/types.h b/atom/extra/spdlog/core/types.h index a130ad15..af1fac1f 100644 --- a/atom/extra/spdlog/core/types.h +++ b/atom/extra/spdlog/core/types.h @@ -147,4 +147,4 @@ struct LogStats { } }; -} // namespace modern_log \ No newline at end of file +} // namespace modern_log diff --git a/atom/extra/spdlog/events/event_system.cpp b/atom/extra/spdlog/events/event_system.cpp index 55f20eaf..08a74a5b 100644 --- a/atom/extra/spdlog/events/event_system.cpp +++ b/atom/extra/spdlog/events/event_system.cpp @@ -59,4 +59,4 @@ void LogEventSystem::clear_all_subscriptions() { callbacks_.clear(); } -} // namespace modern_log \ No newline at end of file +} // namespace modern_log diff --git a/atom/extra/spdlog/events/event_system.h b/atom/extra/spdlog/events/event_system.h index 8f7a59d2..1d5dff94 100644 --- a/atom/extra/spdlog/events/event_system.h +++ b/atom/extra/spdlog/events/event_system.h @@ -98,4 +98,4 @@ class LogEventSystem { void clear_all_subscriptions(); }; -} // namespace modern_log \ No newline at end of file +} // namespace modern_log diff --git a/atom/extra/spdlog/events/test_event_system.cpp b/atom/extra/spdlog/events/test_event_system.cpp index 9fd23173..4cdd4e51 100644 --- a/atom/extra/spdlog/events/test_event_system.cpp +++ b/atom/extra/spdlog/events/test_event_system.cpp @@ -122,4 +122,4 @@ TEST(LogEventSystemTest, SubscribeDifferentEventsAreIndependent) { sys.emit(LogEvent::logger_destroyed); EXPECT_EQ(called1, 1); EXPECT_EQ(called2, 1); -} \ No newline at end of file +} diff --git a/atom/extra/spdlog/filters/builtin_filters.cpp b/atom/extra/spdlog/filters/builtin_filters.cpp index e58d0994..92a5a24c 100644 --- a/atom/extra/spdlog/filters/builtin_filters.cpp +++ b/atom/extra/spdlog/filters/builtin_filters.cpp @@ -113,4 +113,4 @@ LogFilter::FilterFunc BuiltinFilters::duplicate_filter( }; } -} // namespace modern_log \ No newline at end of file +} // namespace modern_log diff --git a/atom/extra/spdlog/filters/builtin_filters.h b/atom/extra/spdlog/filters/builtin_filters.h index 8d749633..1f349ea4 100644 --- a/atom/extra/spdlog/filters/builtin_filters.h +++ b/atom/extra/spdlog/filters/builtin_filters.h @@ -106,4 +106,4 @@ class BuiltinFilters { std::chrono::seconds window = std::chrono::seconds(60)); }; -} // namespace modern_log \ No newline at end of file +} // namespace modern_log diff --git a/atom/extra/spdlog/filters/filter.cpp b/atom/extra/spdlog/filters/filter.cpp index aceafe90..c32f8095 100644 --- a/atom/extra/spdlog/filters/filter.cpp +++ b/atom/extra/spdlog/filters/filter.cpp @@ -28,4 +28,4 @@ size_t LogFilter::filter_count() const { return filters_.size(); } -} // namespace modern_log \ No newline at end of file +} // namespace modern_log diff --git a/atom/extra/spdlog/filters/filter.h b/atom/extra/spdlog/filters/filter.h index 769e0599..8f10ce4b 100644 --- a/atom/extra/spdlog/filters/filter.h +++ b/atom/extra/spdlog/filters/filter.h @@ -68,4 +68,4 @@ class LogFilter { size_t filter_count() const; }; -} // namespace modern_log \ No newline at end of file +} // namespace modern_log diff --git a/atom/extra/spdlog/filters/test_builtin_filters.cpp b/atom/extra/spdlog/filters/test_builtin_filters.cpp index d0264253..34612542 100644 --- a/atom/extra/spdlog/filters/test_builtin_filters.cpp +++ b/atom/extra/spdlog/filters/test_builtin_filters.cpp @@ -419,4 +419,4 @@ TEST(BuiltinFiltersTest, DuplicateFilterSuppressesDuplicatesWithinWindow) { std::this_thread::sleep_for(std::chrono::seconds(2)); EXPECT_TRUE(filter("msg1", Level::info, LogContext{})); EXPECT_TRUE(filter("msg2", Level::info, LogContext{})); -} \ No newline at end of file +} diff --git a/atom/extra/spdlog/logger/logger.cpp b/atom/extra/spdlog/logger/logger.cpp index 29158865..9faf7c42 100644 --- a/atom/extra/spdlog/logger/logger.cpp +++ b/atom/extra/spdlog/logger/logger.cpp @@ -116,4 +116,4 @@ void Logger::emit_event(LogEvent event, const std::any& data) { } } -} // namespace modern_log \ No newline at end of file +} // namespace modern_log diff --git a/atom/extra/spdlog/logger/logger.h b/atom/extra/spdlog/logger/logger.h index 7fc82be4..005ad600 100644 --- a/atom/extra/spdlog/logger/logger.h +++ b/atom/extra/spdlog/logger/logger.h @@ -346,4 +346,4 @@ class Logger { void emit_event(LogEvent event, const std::any& data = {}); }; -} // namespace modern_log \ No newline at end of file +} // namespace modern_log diff --git a/atom/extra/spdlog/logger/manager.cpp b/atom/extra/spdlog/logger/manager.cpp index 6996be04..e24cdf17 100644 --- a/atom/extra/spdlog/logger/manager.cpp +++ b/atom/extra/spdlog/logger/manager.cpp @@ -244,4 +244,4 @@ void LogManager::setup_async_logging(const LogConfig& config) { } } -} // namespace modern_log \ No newline at end of file +} // namespace modern_log diff --git a/atom/extra/spdlog/logger/manager.h b/atom/extra/spdlog/logger/manager.h index a48b936c..67e2b2ce 100644 --- a/atom/extra/spdlog/logger/manager.h +++ b/atom/extra/spdlog/logger/manager.h @@ -216,4 +216,4 @@ class LogManager { void setup_async_logging(const LogConfig& config); }; -} // namespace modern_log \ No newline at end of file +} // namespace modern_log diff --git a/atom/extra/spdlog/logger/test_logger.cpp b/atom/extra/spdlog/logger/test_logger.cpp index 626c0d16..f15202b1 100644 --- a/atom/extra/spdlog/logger/test_logger.cpp +++ b/atom/extra/spdlog/logger/test_logger.cpp @@ -51,7 +51,7 @@ class LoggerTest : public ::testing::Test { auto sink = std::make_shared(*log_stream); spdlog_logger = std::make_shared("test_logger", sink); spdlog_logger->set_level(spdlog::level::trace); - + mock_event_system = std::make_unique>(); event_system_ptr = mock_event_system.get(); } @@ -73,9 +73,9 @@ class LoggerTest : public ::testing::Test { TEST_F(LoggerTest, ConstructorInitializesComponents) { EXPECT_CALL(*mock_event_system, emit(LogEvent::logger_created, _)); - + Logger logger(spdlog_logger, event_system_ptr); - + EXPECT_EQ(logger.get_spdlog_logger(), spdlog_logger); EXPECT_EQ(logger.get_log_type(), LogType::general); EXPECT_TRUE(logger.get_context().empty()); @@ -83,14 +83,14 @@ TEST_F(LoggerTest, ConstructorInitializesComponents) { TEST_F(LoggerTest, BasicLoggingAtAllLevels) { Logger logger(spdlog_logger); - + logger.trace("trace message"); logger.debug("debug message"); logger.info("info message"); logger.warn("warn message"); logger.error("error message"); logger.critical("critical message"); - + std::string output = getLogOutput(); EXPECT_NE(output.find("trace message"), std::string::npos); EXPECT_NE(output.find("debug message"), std::string::npos); @@ -154,14 +154,14 @@ TEST_F(LoggerTest, ContextClearing) { TEST_F(LoggerTest, StructuredLogging) { Logger logger(spdlog_logger); - + StructuredData data; data.add("key1", "value1"); data.add("key2", 42); data.add("key3", true); - + logger.log_structured(Level::info, data); - + std::string output = getLogOutput(); EXPECT_NE(output.find("STRUCTURED:"), std::string::npos); EXPECT_NE(output.find("key1"), std::string::npos); @@ -172,10 +172,10 @@ TEST_F(LoggerTest, StructuredLogging) { TEST_F(LoggerTest, ExceptionLogging) { Logger logger(spdlog_logger); - + std::runtime_error ex("test exception"); logger.log_exception(Level::error, ex, "test context"); - + std::string output = getLogOutput(); EXPECT_NE(output.find("Exception: test exception"), std::string::npos); EXPECT_NE(output.find("Context: test context"), std::string::npos); @@ -184,10 +184,10 @@ TEST_F(LoggerTest, ExceptionLogging) { TEST_F(LoggerTest, ConditionalLogging) { Logger logger(spdlog_logger); - + logger.log_if(true, Level::info, "should log"); logger.log_if(false, Level::info, "should not log"); - + std::string output = getLogOutput(); EXPECT_NE(output.find("should log"), std::string::npos); EXPECT_EQ(output.find("should not log"), std::string::npos); @@ -195,12 +195,12 @@ TEST_F(LoggerTest, ConditionalLogging) { TEST_F(LoggerTest, ScopedTiming) { Logger logger(spdlog_logger); - + { auto timer = logger.time_scope("test_operation"); std::this_thread::sleep_for(std::chrono::milliseconds(1)); } - + std::string output = getLogOutput(); EXPECT_NE(output.find("test_operation took"), std::string::npos); EXPECT_NE(output.find("μs"), std::string::npos); @@ -208,9 +208,9 @@ TEST_F(LoggerTest, ScopedTiming) { TEST_F(LoggerTest, BatchLogging) { Logger logger(spdlog_logger); - + logger.log_batch(Level::info, "message1", "message2", "message3"); - + std::string output = getLogOutput(); EXPECT_NE(output.find("message1"), std::string::npos); EXPECT_NE(output.find("message2"), std::string::npos); @@ -219,10 +219,10 @@ TEST_F(LoggerTest, BatchLogging) { TEST_F(LoggerTest, RangeLogging) { Logger logger(spdlog_logger); - + std::vector numbers = {1, 2, 3, 4, 5}; logger.log_range(Level::info, "numbers", numbers); - + std::string output = getLogOutput(); EXPECT_NE(output.find("numbers"), std::string::npos); EXPECT_NE(output.find("1"), std::string::npos); @@ -232,12 +232,12 @@ TEST_F(LoggerTest, RangeLogging) { TEST_F(LoggerTest, LogLevelFiltering) { Logger logger(spdlog_logger); logger.set_level(Level::warn); - + logger.debug("debug message"); logger.info("info message"); logger.warn("warn message"); logger.error("error message"); - + std::string output = getLogOutput(); EXPECT_EQ(output.find("debug message"), std::string::npos); EXPECT_EQ(output.find("info message"), std::string::npos); @@ -247,9 +247,9 @@ TEST_F(LoggerTest, LogLevelFiltering) { TEST_F(LoggerTest, ShouldLogChecking) { Logger logger(spdlog_logger); - + logger.set_level(Level::warn); - + EXPECT_FALSE(logger.should_log(Level::trace)); EXPECT_FALSE(logger.should_log(Level::debug)); EXPECT_FALSE(logger.should_log(Level::info)); @@ -260,11 +260,11 @@ TEST_F(LoggerTest, ShouldLogChecking) { TEST_F(LoggerTest, StatisticsTracking) { Logger logger(spdlog_logger); - + logger.info("message1"); logger.warn("message2"); logger.error("message3"); - + const auto& stats = logger.get_stats(); EXPECT_EQ(stats.total_logs.load(), 3u); EXPECT_EQ(stats.failed_logs.load(), 0u); @@ -272,20 +272,20 @@ TEST_F(LoggerTest, StatisticsTracking) { TEST_F(LoggerTest, StatisticsReset) { Logger logger(spdlog_logger); - + logger.info("message"); EXPECT_GT(logger.get_stats().total_logs.load(), 0u); - + logger.reset_stats(); EXPECT_EQ(logger.get_stats().total_logs.load(), 0u); } TEST_F(LoggerTest, FlushOperation) { Logger logger(spdlog_logger); - + logger.info("test message"); logger.flush(); - + // Verify message is in output after flush std::string output = getLogOutput(); EXPECT_NE(output.find("test message"), std::string::npos); @@ -293,21 +293,21 @@ TEST_F(LoggerTest, FlushOperation) { TEST_F(LoggerTest, LogTypeManagement) { Logger logger(spdlog_logger); - + EXPECT_EQ(logger.get_log_type(), LogType::general); - + logger.set_log_type(LogType::security); EXPECT_EQ(logger.get_log_type(), LogType::security); - + logger.set_log_type(LogType::performance); EXPECT_EQ(logger.get_log_type(), LogType::performance); } TEST_F(LoggerTest, EventSystemIntegration) { EXPECT_CALL(*mock_event_system, emit(LogEvent::logger_created, _)); - + Logger logger(spdlog_logger, event_system_ptr); - + // Verify constructor emitted logger_created event ::testing::Mock::VerifyAndClearExpectations(mock_event_system.get()); } @@ -374,13 +374,13 @@ TEST_F(LoggerTest, ContextualLogging) { TEST_F(LoggerTest, SetFlushLevel) { Logger logger(spdlog_logger); - + logger.set_flush_level(Level::warn); - + // This test mainly verifies the function doesn't crash logger.info("info message"); logger.warn("warn message"); - + std::string output = getLogOutput(); EXPECT_NE(output.find("info message"), std::string::npos); EXPECT_NE(output.find("warn message"), std::string::npos); @@ -388,19 +388,19 @@ TEST_F(LoggerTest, SetFlushLevel) { TEST_F(LoggerTest, FilteringIntegration) { Logger logger(spdlog_logger); - + // Add a filter that blocks messages containing "secret" logger.add_filter([](const std::string& msg, Level, const LogContext&) { return msg.find("secret") == std::string::npos; }); - + logger.info("normal message"); logger.info("secret message"); - + std::string output = getLogOutput(); EXPECT_NE(output.find("normal message"), std::string::npos); EXPECT_EQ(output.find("secret message"), std::string::npos); - + // Verify filtered message is counted in stats const auto& stats = logger.get_stats(); EXPECT_EQ(stats.filtered_logs.load(), 1u); @@ -408,16 +408,16 @@ TEST_F(LoggerTest, FilteringIntegration) { TEST_F(LoggerTest, SamplingIntegration) { Logger logger(spdlog_logger); - + // Set sampling to 0% (drop everything) logger.set_sampling(SamplingStrategy::uniform, 0.0); - + logger.info("sampled message 1"); logger.info("sampled message 2"); - + std::string output = getLogOutput(); EXPECT_EQ(output.find("sampled message"), std::string::npos); - + // Verify sampled messages are counted in stats const auto& stats = logger.get_stats(); EXPECT_EQ(stats.sampled_logs.load(), 2u); @@ -427,11 +427,11 @@ TEST_F(LoggerTest, ErrorHandlingInLogInternal) { // Create a logger with a bad sink to simulate errors auto bad_sink = std::make_shared(std::cout); auto bad_logger = std::make_shared("bad_logger", bad_sink); - + Logger logger(bad_logger); - + // This should not crash even if the underlying logger fails logger.info("test message"); - + // The test mainly verifies no exceptions are thrown -} \ No newline at end of file +} diff --git a/atom/extra/spdlog/logger/test_manager.cpp b/atom/extra/spdlog/logger/test_manager.cpp index 37002285..78d7ea34 100644 --- a/atom/extra/spdlog/logger/test_manager.cpp +++ b/atom/extra/spdlog/logger/test_manager.cpp @@ -466,4 +466,4 @@ TEST_F(LogManagerTest, LoggerCreationPerformance) { // Should create 100 loggers reasonably quickly (adjust threshold as needed) EXPECT_LT(duration.count(), 1000); // Less than 1 second -} \ No newline at end of file +} diff --git a/atom/extra/spdlog/modern_log.h b/atom/extra/spdlog/modern_log.h index e6b0bfca..476a9137 100644 --- a/atom/extra/spdlog/modern_log.h +++ b/atom/extra/spdlog/modern_log.h @@ -25,4 +25,4 @@ #define LOG_TIME_SCOPE(name) auto _timer = modern_log::LogManager::default_logger().time_scope(name) -#define LOG_WITH_CONTEXT(ctx) modern_log::LogManager::default_logger().with_context(ctx) \ No newline at end of file +#define LOG_WITH_CONTEXT(ctx) modern_log::LogManager::default_logger().with_context(ctx) diff --git a/atom/extra/spdlog/sampling/sampler.cpp b/atom/extra/spdlog/sampling/sampler.cpp index 09309531..149ed2aa 100644 --- a/atom/extra/spdlog/sampling/sampler.cpp +++ b/atom/extra/spdlog/sampling/sampler.cpp @@ -116,4 +116,4 @@ double LogSampler::get_system_load() const { return dis(gen) * 0.5; } -} // namespace modern_log \ No newline at end of file +} // namespace modern_log diff --git a/atom/extra/spdlog/sampling/sampler.h b/atom/extra/spdlog/sampling/sampler.h index c6ad05c1..caa70328 100644 --- a/atom/extra/spdlog/sampling/sampler.h +++ b/atom/extra/spdlog/sampling/sampler.h @@ -97,4 +97,4 @@ class LogSampler { double get_system_load() const; }; -} // namespace modern_log \ No newline at end of file +} // namespace modern_log diff --git a/atom/extra/spdlog/sampling/test_sampler.cpp b/atom/extra/spdlog/sampling/test_sampler.cpp index 88dd7f92..754f4c4b 100644 --- a/atom/extra/spdlog/sampling/test_sampler.cpp +++ b/atom/extra/spdlog/sampling/test_sampler.cpp @@ -146,4 +146,4 @@ TEST(LogSamplerTest, ThreadSafety) { EXPECT_NEAR(kept, 200, 20); EXPECT_NEAR(dropped, 200, 20); EXPECT_EQ(sampler.get_dropped_count(), dropped); -} \ No newline at end of file +} diff --git a/atom/extra/spdlog/utils/archiver.cpp b/atom/extra/spdlog/utils/archiver.cpp index d5be26c9..5828b43f 100644 --- a/atom/extra/spdlog/utils/archiver.cpp +++ b/atom/extra/spdlog/utils/archiver.cpp @@ -173,4 +173,4 @@ std::string LogArchiver::generate_archive_name( return pattern; } -} // namespace modern_log \ No newline at end of file +} // namespace modern_log diff --git a/atom/extra/spdlog/utils/archiver.h b/atom/extra/spdlog/utils/archiver.h index 17bd1047..5084c2fc 100644 --- a/atom/extra/spdlog/utils/archiver.h +++ b/atom/extra/spdlog/utils/archiver.h @@ -162,4 +162,4 @@ class LogArchiver { const std::filesystem::path& original) const; }; -} // namespace modern_log \ No newline at end of file +} // namespace modern_log diff --git a/atom/extra/spdlog/utils/structured_data.cpp b/atom/extra/spdlog/utils/structured_data.cpp index 95c03b40..1216cb1d 100644 --- a/atom/extra/spdlog/utils/structured_data.cpp +++ b/atom/extra/spdlog/utils/structured_data.cpp @@ -102,4 +102,4 @@ std::string StructuredData::any_to_string(const std::any& value) const { return "null"; } -} // namespace modern_log \ No newline at end of file +} // namespace modern_log diff --git a/atom/extra/spdlog/utils/structured_data.h b/atom/extra/spdlog/utils/structured_data.h index 763a9412..ca515dc3 100644 --- a/atom/extra/spdlog/utils/structured_data.h +++ b/atom/extra/spdlog/utils/structured_data.h @@ -145,4 +145,4 @@ class StructuredData { std::string any_to_string(const std::any& value) const; }; -} // namespace modern_log \ No newline at end of file +} // namespace modern_log diff --git a/atom/extra/spdlog/utils/test_archiver.cpp b/atom/extra/spdlog/utils/test_archiver.cpp index 14a3cffa..0f2688ed 100644 --- a/atom/extra/spdlog/utils/test_archiver.cpp +++ b/atom/extra/spdlog/utils/test_archiver.cpp @@ -146,4 +146,4 @@ TEST_F(LogArchiverTest, CompressFileHandlesNonexistentFileGracefully) { TEST_F(LogArchiverTest, DecompressFileHandlesNonexistentFileGracefully) { LogArchiver archiver(temp_dir); EXPECT_FALSE(archiver.decompress_file(temp_dir / "no_such_file.gz")); -} \ No newline at end of file +} diff --git a/atom/extra/spdlog/utils/test_timer.cpp b/atom/extra/spdlog/utils/test_timer.cpp index bd1001b1..57352b5a 100644 --- a/atom/extra/spdlog/utils/test_timer.cpp +++ b/atom/extra/spdlog/utils/test_timer.cpp @@ -121,4 +121,4 @@ TEST(BenchmarkTest, ReportDoesNothingIfLoggerNullOrEmpty) { auto logger = std::make_shared(); bench.report(logger.get()); EXPECT_TRUE(logger->entries.empty()); -} \ No newline at end of file +} diff --git a/atom/extra/spdlog/utils/timer.cpp b/atom/extra/spdlog/utils/timer.cpp index 80a0c493..14bd080d 100644 --- a/atom/extra/spdlog/utils/timer.cpp +++ b/atom/extra/spdlog/utils/timer.cpp @@ -99,4 +99,4 @@ void Benchmark::report(Logger* logger) const { std::format(" Std Dev: {:.2f}μs", stats.std_dev)); } -} // namespace modern_log \ No newline at end of file +} // namespace modern_log diff --git a/atom/extra/spdlog/utils/timer.h b/atom/extra/spdlog/utils/timer.h index f2d1b1ab..86336b0c 100644 --- a/atom/extra/spdlog/utils/timer.h +++ b/atom/extra/spdlog/utils/timer.h @@ -143,4 +143,4 @@ class Benchmark { void report(Logger* logger) const; }; -} // namespace modern_log \ No newline at end of file +} // namespace modern_log diff --git a/atom/extra/uv/coro.hpp b/atom/extra/uv/coro.hpp index 5a6b40ad..9607f061 100644 --- a/atom/extra/uv/coro.hpp +++ b/atom/extra/uv/coro.hpp @@ -1040,4 +1040,4 @@ inline FileSystem make_file_system() { } } // namespace uv_coro -#endif // ATOM_EXTRA_UV_CORO_HPP \ No newline at end of file +#endif // ATOM_EXTRA_UV_CORO_HPP diff --git a/atom/extra/uv/message_bus.cpp b/atom/extra/uv/message_bus.cpp index c2674a67..737174b4 100644 --- a/atom/extra/uv/message_bus.cpp +++ b/atom/extra/uv/message_bus.cpp @@ -373,4 +373,4 @@ Result> MessageAwaiter::await_resume() { return future.get(); } -} // namespace msgbus \ No newline at end of file +} // namespace msgbus diff --git a/atom/extra/uv/message_bus.hpp b/atom/extra/uv/message_bus.hpp index 4b8f0520..5c4c5e47 100644 --- a/atom/extra/uv/message_bus.hpp +++ b/atom/extra/uv/message_bus.hpp @@ -117,4 +117,4 @@ struct MessageAwaiter { std::shared_ptr>>> promise_; }; -} // namespace msgbus \ No newline at end of file +} // namespace msgbus diff --git a/atom/extra/uv/subprocess.cpp b/atom/extra/uv/subprocess.cpp index a3b39f37..50a3099a 100644 --- a/atom/extra/uv/subprocess.cpp +++ b/atom/extra/uv/subprocess.cpp @@ -701,4 +701,4 @@ void UvProcess::reset() { void UvProcess::setErrorCallback(ErrorCallback error_callback) { std::lock_guard lock(mutex_); error_callback_ = std::move(error_callback); -} \ No newline at end of file +} diff --git a/atom/extra/uv/subprocess.hpp b/atom/extra/uv/subprocess.hpp index 4cfc340f..8d18f096 100644 --- a/atom/extra/uv/subprocess.hpp +++ b/atom/extra/uv/subprocess.hpp @@ -256,4 +256,4 @@ class UvProcess { ErrorCallback error_callback_; }; -#endif // ATOM_EXTRA_UV_SUBPROCESS_HPP \ No newline at end of file +#endif // ATOM_EXTRA_UV_SUBPROCESS_HPP diff --git a/atom/image/fits_data.hpp b/atom/image/fits_data.hpp index a70c8630..e43ee00e 100644 --- a/atom/image/fits_data.hpp +++ b/atom/image/fits_data.hpp @@ -42,10 +42,10 @@ class FITSDataException : public std::system_error { public: explicit FITSDataException(FITSDataErrorCode code, const std::string& message = "") : std::system_error(make_error_code(code), message) {} - + explicit FITSDataException(const std::string& message) : std::system_error(make_error_code(FITSDataErrorCode::InternalError), message) {} - + [[nodiscard]] FITSDataErrorCode errorCode() const noexcept { return static_cast(code().value()); } @@ -96,7 +96,7 @@ class FITSData { * @param chunkSize The size of each chunk to read (default 1MB). * @throws FITSDataException If there is an error reading data */ - virtual void readDataChunked(std::ifstream& file, int64_t dataSize, + virtual void readDataChunked(std::ifstream& file, int64_t dataSize, size_t chunkSize = 1024 * 1024) = 0; /** @@ -178,7 +178,7 @@ class FITSData { protected: DataProgressCallback progressCallback; ///< Callback for progress reporting - + /** * @brief Reports progress to the registered callback, if any. * @param progress Progress value (0.0 to 1.0). @@ -240,7 +240,7 @@ class TypedFITSData : public FITSData { * @param chunkSize The size of each chunk to read (default 1MB). * @throws FITSDataException If there is an error reading data */ - void readDataChunked(std::ifstream& file, int64_t dataSize, + void readDataChunked(std::ifstream& file, int64_t dataSize, size_t chunkSize = 1024 * 1024) override; /** diff --git a/atom/image/fits_file.hpp b/atom/image/fits_file.hpp index 8673db89..79217988 100644 --- a/atom/image/fits_file.hpp +++ b/atom/image/fits_file.hpp @@ -52,10 +52,10 @@ class FITSFileException : public std::system_error { public: explicit FITSFileException(FITSErrorCode code, const std::string& message = "") : std::system_error(make_error_code(code), message) {} - + explicit FITSFileException(const std::string& message) : std::system_error(make_error_code(FITSErrorCode::InternalError), message) {} - + [[nodiscard]] FITSErrorCode errorCode() const noexcept { return static_cast(code().value()); } @@ -214,7 +214,7 @@ class FITSFile { * @param callback The callback function to set. */ void setProgressCallback(ProgressCallback callback) noexcept; - + /** * @brief Reads a FITS file from the specified filename with options. * @param filename The name of the file to read. @@ -222,7 +222,7 @@ class FITSFile { * @param validateData Whether to validate data after reading. * @throws FITSFileException if file cannot be opened or read */ - void readFITS(const std::string& filename, bool useMmap = false, + void readFITS(const std::string& filename, bool useMmap = false, bool validateData = true); /** @@ -232,7 +232,7 @@ class FITSFile { * @param validateData Whether to validate data after reading. * @return A future that can be waited on for completion. */ - [[nodiscard]] std::future readFITSAsync(const std::string& filename, + [[nodiscard]] std::future readFITSAsync(const std::string& filename, bool useMmap = false, bool validateData = true); @@ -240,14 +240,14 @@ class FITSFile { std::vector> hdus; ///< Vector of unique pointers to HDUs. ProgressCallback progressCallback; ///< Callback for progress reporting. - + /** * @brief Reports progress to the registered callback, if any. * @param progress Progress value (0.0 to 1.0). * @param status Status message. */ void reportProgress(float progress, const std::string& status) const; - + /** * @brief Reads a FITS file using memory-mapped I/O. * @param filename The name of the file to read. diff --git a/atom/image/fits_header.cpp b/atom/image/fits_header.cpp index 202b462b..fdc5e73b 100644 --- a/atom/image/fits_header.cpp +++ b/atom/image/fits_header.cpp @@ -339,4 +339,4 @@ std::vector FITSHeader::getAllKeywords() const { } return keywords; -} \ No newline at end of file +} diff --git a/atom/image/fits_header.hpp b/atom/image/fits_header.hpp index d5f6b996..fbbf21db 100644 --- a/atom/image/fits_header.hpp +++ b/atom/image/fits_header.hpp @@ -251,21 +251,21 @@ class FITSHeader { /** * @brief Removes all comments from the header - * + * * @return The number of comments removed */ size_t clearComments() noexcept; /** * @brief Get the number of records in the header - * + * * @return The number of keyword records */ [[nodiscard]] size_t size() const noexcept { return records.size(); } /** * @brief Check if the header is empty - * + * * @return true if there are no records, false otherwise */ [[nodiscard]] bool empty() const noexcept { return records.empty(); } @@ -286,11 +286,11 @@ class FITSHeader { /** * @brief Finds a keyword in the records - * + * * @param keyword The keyword to find * @return The index of the keyword record, or std::string::npos if not found */ [[nodiscard]] size_t findKeywordIndex(std::string_view keyword) const noexcept; }; -#endif // ATOM_IMAGE_FITS_HEADER_HPP \ No newline at end of file +#endif // ATOM_IMAGE_FITS_HEADER_HPP diff --git a/atom/image/fits_utils.cpp b/atom/image/fits_utils.cpp index 1a3e5e52..4a1084ce 100644 --- a/atom/image/fits_utils.cpp +++ b/atom/image/fits_utils.cpp @@ -1331,4 +1331,4 @@ int processFitsDirectory(const std::string& inputDir, #endif // ATOM_ENABLE_OPENCV } // namespace image -} // namespace atom \ No newline at end of file +} // namespace atom diff --git a/atom/image/fits_utils.hpp b/atom/image/fits_utils.hpp index 3826d20f..2a47e468 100644 --- a/atom/image/fits_utils.hpp +++ b/atom/image/fits_utils.hpp @@ -412,4 +412,4 @@ std::optional> getFitsImageInfo( } // namespace image } // namespace atom -#endif // ATOM_IMAGE_FITS_UTILS_HPP \ No newline at end of file +#endif // ATOM_IMAGE_FITS_UTILS_HPP diff --git a/atom/image/ocr/install_ocr_dependencies.sh b/atom/image/ocr/install_ocr_dependencies.sh index 9c9082fe..9ac5ec92 100644 --- a/atom/image/ocr/install_ocr_dependencies.sh +++ b/atom/image/ocr/install_ocr_dependencies.sh @@ -61,7 +61,7 @@ detect_os() { else OS="unknown" fi - + log "Detected operating system: $OS" } @@ -75,10 +75,10 @@ create_directories() { # Download models download_models() { log "Downloading OCR models and resources..." - + # Create models directory if it doesn't exist mkdir -p "$MODELS_DIR" - + # Download EAST text detection model log "Downloading EAST text detection model..." if command -v wget &> /dev/null; then @@ -100,7 +100,7 @@ download_models() { error "Download URL: https://github.com/oyyd/frozen_east_text_detection.pb/raw/master/frozen_east_text_detection.pb" error "Save to: $MODELS_DIR/east_text_detection.pb" fi - + # Download super resolution model log "Downloading ESPCN super resolution model..." if command -v wget &> /dev/null; then @@ -122,7 +122,7 @@ download_models() { error "Download URL: https://github.com/fannymonori/TF-ESPCN/raw/master/export/ESPCN_x4.pb" error "Save to: $MODELS_DIR/ESPCN_x4.pb" fi - + # Download English dictionary for spell checking log "Downloading English dictionary for spell checking..." if command -v wget &> /dev/null; then @@ -144,7 +144,7 @@ download_models() { error "Download URL: https://raw.githubusercontent.com/dwyl/english-words/master/words.txt" error "Save to: $DICT_DIR/english.txt" fi - + # Check if files were downloaded successfully if [ -f "$MODELS_DIR/east_text_detection.pb" ] && [ -f "$MODELS_DIR/ESPCN_x4.pb" ]; then success "Models downloaded successfully" @@ -156,13 +156,13 @@ download_models() { # Install dependencies on Debian/Ubuntu install_debian() { log "Installing dependencies on Debian/Ubuntu..." - + # Update package lists sudo apt-get update - + # Install build tools and basic dependencies sudo apt-get install -y build-essential cmake git pkg-config wget curl - + # Install OpenCV dependencies sudo apt-get install -y \ libopencv-dev \ @@ -180,7 +180,7 @@ install_debian() { gfortran \ openexr \ libatlas-base-dev - + # Install Tesseract OCR and language data sudo apt-get install -y \ tesseract-ocr \ @@ -188,26 +188,26 @@ install_debian() { libleptonica-dev \ tesseract-ocr-eng \ tesseract-ocr-osd - + # Optional: Install additional language packs sudo apt-get install -y \ tesseract-ocr-fra \ tesseract-ocr-deu \ tesseract-ocr-spa - + success "Dependencies installed successfully on Debian/Ubuntu" } # Install dependencies on Fedora install_fedora() { log "Installing dependencies on Fedora..." - + # Update package lists sudo dnf update -y - + # Install build tools and basic dependencies sudo dnf install -y gcc-c++ cmake git pkgconfig wget curl - + # Install OpenCV and its dependencies sudo dnf install -y \ opencv \ @@ -222,42 +222,42 @@ install_fedora() { lapack-devel \ atlas-devel \ openexr-devel - + # Install Tesseract OCR and language data sudo dnf install -y \ tesseract \ tesseract-devel \ tesseract-langpack-eng \ leptonica-devel - + # Optional: Install additional language packs sudo dnf install -y \ tesseract-langpack-fra \ tesseract-langpack-deu \ tesseract-langpack-spa - + success "Dependencies installed successfully on Fedora" } # Install dependencies on RHEL/CentOS install_rhel() { log "Installing dependencies on RHEL/CentOS..." - + # Enable EPEL repository sudo yum install -y epel-release - + # Update package lists sudo yum update -y - + # Install build tools and basic dependencies sudo yum groupinstall -y "Development Tools" sudo yum install -y cmake3 git pkgconfig wget curl - + # Create link for cmake if needed if ! command -v cmake &> /dev/null && command -v cmake3 &> /dev/null; then sudo ln -s /usr/bin/cmake3 /usr/bin/cmake fi - + # Install OpenCV dependencies sudo yum install -y \ opencv \ @@ -270,34 +270,34 @@ install_rhel() { libtiff-devel \ atlas-devel \ openexr-devel - + # Install Tesseract OCR and language data sudo yum install -y \ tesseract \ tesseract-devel \ leptonica-devel - + # Download and install English language data if [ ! -d "/usr/share/tesseract/tessdata" ]; then sudo mkdir -p /usr/share/tesseract/tessdata fi - + wget -O /tmp/eng.traineddata https://github.com/tesseract-ocr/tessdata/raw/4.0.0/eng.traineddata sudo mv /tmp/eng.traineddata /usr/share/tesseract/tessdata/ - + success "Dependencies installed successfully on RHEL/CentOS" } # Install dependencies on Arch Linux install_arch() { log "Installing dependencies on Arch Linux..." - + # Update package database sudo pacman -Syu --noconfirm - + # Install build tools and basic dependencies sudo pacman -S --noconfirm base-devel cmake git pkgconf wget curl - + # Install OpenCV and its dependencies sudo pacman -S --noconfirm \ opencv \ @@ -310,33 +310,33 @@ install_arch() { openblas \ lapack \ openexr - + # Install Tesseract OCR and language data sudo pacman -S --noconfirm \ tesseract \ tesseract-data-eng \ leptonica - + # Optional: Install additional language data sudo pacman -S --noconfirm \ tesseract-data-fra \ tesseract-data-deu \ tesseract-data-spa - + success "Dependencies installed successfully on Arch Linux" } # Install dependencies on openSUSE install_suse() { log "Installing dependencies on openSUSE..." - + # Update package database sudo zypper refresh - + # Install build tools and basic dependencies sudo zypper install -y -t pattern devel_basis sudo zypper install -y cmake git pkgconfig wget curl - + # Install OpenCV and its dependencies sudo zypper install -y \ opencv \ @@ -350,27 +350,27 @@ install_suse() { blas-devel \ lapack-devel \ OpenEXR-devel - + # Install Tesseract OCR and language data sudo zypper install -y \ tesseract-ocr \ tesseract-ocr-devel \ tesseract-ocr-traineddata-english \ leptonica-devel - + # Optional: Install additional language data sudo zypper install -y \ tesseract-ocr-traineddata-french \ tesseract-ocr-traineddata-german \ tesseract-ocr-traineddata-spanish - + success "Dependencies installed successfully on openSUSE" } # Install dependencies on macOS using Homebrew install_macos() { log "Installing dependencies on macOS..." - + # Check if Homebrew is installed, install if not if ! command -v brew &> /dev/null; then log "Installing Homebrew..." @@ -379,26 +379,26 @@ install_macos() { log "Homebrew already installed, updating..." brew update fi - + # Install build tools and basic dependencies brew install cmake git wget curl - + # Install OpenCV and its dependencies brew install opencv - + # Install Tesseract OCR and language data brew install tesseract - + # Optional: Install additional language data brew install tesseract-lang - + success "Dependencies installed successfully on macOS" } # Install dependencies on Windows using Chocolatey and vcpkg create_windows_script() { log "Creating Windows installation script..." - + cat > Install-OCRDependencies.ps1 << 'EOF' # Enhanced OCR System - Windows Dependency Installer # Run this script with administrator privileges @@ -413,31 +413,31 @@ $VCPKG_DIR = "C:\vcpkg" # Create directories function Create-Directories { Write-Host "Creating necessary directories..." - + if (-not (Test-Path $MODELS_DIR)) { New-Item -ItemType Directory -Force -Path $MODELS_DIR | Out-Null } if (-not (Test-Path $CACHE_DIR)) { New-Item -ItemType Directory -Force -Path $CACHE_DIR | Out-Null } if (-not (Test-Path $LOG_DIR)) { New-Item -ItemType Directory -Force -Path $LOG_DIR | Out-Null } if (-not (Test-Path $DICT_DIR)) { New-Item -ItemType Directory -Force -Path $DICT_DIR | Out-Null } - + Write-Host "Directories created successfully" -ForegroundColor Green } # Download models function Download-Models { Write-Host "Downloading OCR models and resources..." - + # Download EAST text detection model Write-Host "Downloading EAST text detection model..." Invoke-WebRequest -Uri "https://github.com/oyyd/frozen_east_text_detection.pb/raw/master/frozen_east_text_detection.pb" -OutFile "$MODELS_DIR\east_text_detection.pb" - + # Download super resolution model Write-Host "Downloading ESPCN super resolution model..." Invoke-WebRequest -Uri "https://github.com/fannymonori/TF-ESPCN/raw/master/export/ESPCN_x4.pb" -OutFile "$MODELS_DIR\ESPCN_x4.pb" - + # Download English dictionary for spell checking Write-Host "Downloading English dictionary for spell checking..." Invoke-WebRequest -Uri "https://raw.githubusercontent.com/dwyl/english-words/master/words.txt" -OutFile "$DICT_DIR\english.txt" - + if ((Test-Path "$MODELS_DIR\east_text_detection.pb") -and (Test-Path "$MODELS_DIR\ESPCN_x4.pb")) { Write-Host "Models downloaded successfully" -ForegroundColor Green } else { @@ -461,22 +461,22 @@ function Install-Chocolatey { function Install-Vcpkg { if (-not (Test-Path $VCPKG_DIR)) { Write-Host "Installing vcpkg..." - + # Clone vcpkg repository git clone https://github.com/Microsoft/vcpkg.git $VCPKG_DIR - + # Run bootstrap script & "$VCPKG_DIR\bootstrap-vcpkg.bat" -disableMetrics - + # Add vcpkg to PATH $env:Path += ";$VCPKG_DIR" [Environment]::SetEnvironmentVariable("Path", $env:Path, [EnvironmentVariableTarget]::User) - + # Integrate vcpkg with Visual Studio & "$VCPKG_DIR\vcpkg" integrate install } else { Write-Host "vcpkg is already installed" - + # Update vcpkg Push-Location $VCPKG_DIR git pull @@ -499,40 +499,40 @@ function Install-BuildTools { # Install dependencies using vcpkg function Install-Dependencies { Write-Host "Installing dependencies using vcpkg..." - + # Install OpenCV & "$VCPKG_DIR\vcpkg" install opencv:x64-windows - + # Install Tesseract OCR & "$VCPKG_DIR\vcpkg" install tesseract:x64-windows - + # Install additional dependencies & "$VCPKG_DIR\vcpkg" install leptonica:x64-windows - + Write-Host "Dependencies installed successfully" -ForegroundColor Green } # Install additional tools function Install-AdditionalTools { Write-Host "Installing additional tools..." - + # Install Git if not already installed if (-not (Get-Command git -ErrorAction SilentlyContinue)) { choco install git -y } - + # Install CMake if not already installed if (-not (Get-Command cmake -ErrorAction SilentlyContinue)) { choco install cmake --installargs 'ADD_CMAKE_TO_PATH=System' -y } - + Write-Host "Additional tools installed successfully" -ForegroundColor Green } # Configure environment function Configure-Environment { Write-Host "Configuring environment..." - + # Create a sample config file $configJson = @" { @@ -574,16 +574,16 @@ function Configure-Environment { } } "@ - + Set-Content -Path "ocr_config.json" -Value $configJson - + Write-Host "Environment configured successfully" -ForegroundColor Green } # Create example compilation script function Create-CompilationScript { Write-Host "Creating compilation script..." - + $compileBat = @" @echo off REM Compile Enhanced OCR system @@ -605,49 +605,49 @@ cd .. echo Build completed. Check the 'build' directory for output. "@ - + Set-Content -Path "compile.bat" -Value $compileBat - + Write-Host "Compilation script created successfully" -ForegroundColor Green } # Main function function Main { Write-Host "Starting OCR dependencies installation for Windows..." -ForegroundColor Cyan - + # Create directories Create-Directories - + # Check if only downloading models if ($args[0] -eq "--models-only") { Download-Models return } - + # Install Chocolatey Install-Chocolatey - + # Install additional tools Install-AdditionalTools - + # Install Visual Studio Build Tools Install-BuildTools - + # Install vcpkg Install-Vcpkg - + # Install dependencies Install-Dependencies - + # Download models Download-Models - + # Configure environment Configure-Environment - + # Create compilation script Create-CompilationScript - + Write-Host "Installation completed successfully!" -ForegroundColor Green Write-Host "You can now build the Enhanced OCR system using the generated compile.bat script." } @@ -661,7 +661,7 @@ if (-not ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdenti # Run main function with passed arguments Main $args EOF - + success "Windows installation script created: Install-OCRDependencies.ps1" log "Please run this script on Windows with administrator privileges." } @@ -669,20 +669,20 @@ EOF # Main function main() { log "Starting OCR dependencies installation..." - + # Create directories create_directories - + # Check if only downloading models if [[ "$1" == "--models-only" ]]; then download_models success "Models downloaded successfully. Exiting." exit 0 fi - + # Detect OS detect_os - + # Install dependencies based on OS case $OS in debian) @@ -726,10 +726,10 @@ EOF exit 1 ;; esac - + # Download models download_models - + # Create sample config file log "Creating sample configuration file..." cat > ocr_config.json << EOF @@ -772,7 +772,7 @@ EOF } } EOF - + # Create CMakeLists.txt file log "Creating CMakeLists.txt file..." cat > CMakeLists.txt << EOF @@ -829,7 +829,7 @@ file(MAKE_DIRECTORY \${CMAKE_BINARY_DIR}/.ocr_cache) # Create logs directory in build directory file(MAKE_DIRECTORY \${CMAKE_BINARY_DIR}/logs) EOF - + # Create compilation script log "Creating compilation script..." cat > compile.sh << EOF @@ -854,10 +854,10 @@ cd .. echo "Build completed. Check the 'build' directory for output." EOF chmod +x compile.sh - + success "Installation completed successfully!" log "You can now build the Enhanced OCR system using the generated compile.sh script." } # Run main function with all arguments -main "$@" \ No newline at end of file +main "$@" diff --git a/atom/image/ocr/ocr.cpp b/atom/image/ocr/ocr.cpp index 532e053b..c6edda61 100644 --- a/atom/image/ocr/ocr.cpp +++ b/atom/image/ocr/ocr.cpp @@ -1504,4 +1504,4 @@ class EnhancedOCRProcessor { } } }; -}; \ No newline at end of file +}; diff --git a/atom/image/ocr/ocr.hpp b/atom/image/ocr/ocr.hpp index be39758a..9f410502 100644 --- a/atom/image/ocr/ocr.hpp +++ b/atom/image/ocr/ocr.hpp @@ -482,4 +482,4 @@ class EnhancedOCRProcessor { * @brief Clean up resources */ void cleanup(); -}; \ No newline at end of file +}; diff --git a/atom/image/ser/exception.h b/atom/image/ser/exception.h index b6c99efb..c4874924 100644 --- a/atom/image/ser/exception.h +++ b/atom/image/ser/exception.h @@ -75,4 +75,4 @@ class ResourceException : public SERException { : SERException(message, location) {} }; -} // namespace serastro \ No newline at end of file +} // namespace serastro diff --git a/atom/image/ser/frame_processor.cpp b/atom/image/ser/frame_processor.cpp index 28d0b352..6e907139 100644 --- a/atom/image/ser/frame_processor.cpp +++ b/atom/image/ser/frame_processor.cpp @@ -9,23 +9,23 @@ std::vector FrameProcessor::process(const std::vector& frames, const ProgressCallback& progress) { std::vector results; results.reserve(frames.size()); - + cancelRequested = false; - + for (size_t i = 0; i < frames.size(); ++i) { if (cancelRequested) { break; } - + results.push_back(process(frames[i])); - + if (progress) { double progressValue = static_cast(i + 1) / frames.size(); - progress(progressValue, std::format("{}: Processing frame {}/{}", + progress(progressValue, std::format("{}: Processing frame {}/{}", getName(), i + 1, frames.size())); } } - + return results; } @@ -84,37 +84,37 @@ ProcessingPipeline::ProcessingPipeline() = default; cv::Mat ProcessingPipeline::process(const cv::Mat& frame) { cv::Mat result = frame.clone(); - + for (auto& processor : processors) { if (cancelRequested) { break; } - + result = processor->process(result); } - + return result; } std::vector ProcessingPipeline::process(const std::vector& frames, const ProgressCallback& progress) { std::vector results = frames; - + cancelRequested = false; - + for (size_t i = 0; i < processors.size(); ++i) { if (cancelRequested) { break; } - + auto& processor = processors[i]; - + if (progress) { progress(static_cast(i) / processors.size(), - std::format("Running processor {}/{}: {}", + std::format("Running processor {}/{}: {}", i + 1, processors.size(), processor->getName())); } - + // Create a wrapper progress function that scales appropriately ProgressCallback processorProgress = nullptr; if (progress) { @@ -124,14 +124,14 @@ std::vector ProcessingPipeline::process(const std::vector& fra progress(overallProgress, message); }; } - + results = processor->process(results, processorProgress); - + if (processor->isCancelled()) { cancelRequested = true; } } - + return results; } @@ -161,4 +161,4 @@ void ProcessingPipeline::clear() { processors.clear(); } -} // namespace serastro \ No newline at end of file +} // namespace serastro diff --git a/atom/image/ser/frame_processor.h b/atom/image/ser/frame_processor.h index a4194e12..6dc1ef9e 100644 --- a/atom/image/ser/frame_processor.h +++ b/atom/image/ser/frame_processor.h @@ -20,17 +20,17 @@ using ProgressCallback = std::function process(const std::vector& frames, const ProgressCallback& progress = nullptr); - + // Get processor name virtual std::string getName() const = 0; - + // Allow cancellation of multi-frame processing void requestCancel() { cancelRequested = true; } bool isCancelled() const { return cancelRequested; } @@ -45,19 +45,19 @@ class CustomizableProcessor : public FrameProcessor { public: // Set parameter by name virtual void setParameter(const std::string& name, double value) = 0; - + // Get parameter value virtual double getParameter(const std::string& name) const = 0; - + // Get all parameter names virtual std::vector getParameterNames() const = 0; - + // Check if parameter exists virtual bool hasParameter(const std::string& name) const = 0; - + // Set multiple parameters virtual void setParameters(const std::unordered_map& params); - + // Get all parameters as a map virtual std::unordered_map getParameters() const; }; @@ -69,10 +69,10 @@ class BaseCustomizableProcessor : public CustomizableProcessor { double getParameter(const std::string& name) const override; std::vector getParameterNames() const override; bool hasParameter(const std::string& name) const override; - + protected: std::unordered_map parameters; - + // Register a parameter with initial value void registerParameter(const std::string& name, double initialValue); }; @@ -81,21 +81,21 @@ class BaseCustomizableProcessor : public CustomizableProcessor { class ProcessingPipeline : public FrameProcessor { public: ProcessingPipeline(); - + cv::Mat process(const cv::Mat& frame) override; std::vector process(const std::vector& frames, const ProgressCallback& progress = nullptr) override; std::string getName() const override; - + // Add processor to the pipeline void addProcessor(std::shared_ptr processor); - + // Remove processor by index void removeProcessor(size_t index); - + // Get all processors std::vector> getProcessors() const; - + // Clear all processors void clear(); @@ -103,4 +103,4 @@ class ProcessingPipeline : public FrameProcessor { std::vector> processors; }; -} // namespace serastro \ No newline at end of file +} // namespace serastro diff --git a/atom/image/ser/quality.cpp b/atom/image/ser/quality.cpp index 39675595..f7c2df18 100644 --- a/atom/image/ser/quality.cpp +++ b/atom/image/ser/quality.cpp @@ -37,27 +37,27 @@ double QualityAssessor::assessQuality(const cv::Mat& frame) const { std::vector QualityAssessor::getQualityScores(const std::vector& frames) const { std::vector scores; scores.reserve(frames.size()); - + for (const auto& frame : frames) { scores.push_back(assessQuality(frame)); } - + return scores; } std::vector QualityAssessor::sortFramesByQuality(const std::vector& frames) const { // Calculate quality scores std::vector scores = getQualityScores(frames); - + // Create index vector std::vector indices(frames.size()); std::iota(indices.begin(), indices.end(), 0); - + // Sort indices by scores (descending order) std::sort(indices.begin(), indices.end(), [&scores](size_t a, size_t b) { return scores[a] > scores[b]; }); - + return indices; } @@ -65,31 +65,31 @@ std::vector QualityAssessor::selectBestFrames(const std::vector bestFrames; bestFrames.reserve(count); - + for (size_t i = 0; i < count; ++i) { bestFrames.push_back(frames[sortedIndices[i]]); } - + return bestFrames; } -void QualityAssessor::addCustomMetric(const std::string& name, +void QualityAssessor::addCustomMetric(const std::string& name, QualityMetricFunction metricFunction, double weight) { if (weight <= 0.0) { throw InvalidParameterException("Metric weight must be greater than zero"); } - + customMetrics[name] = std::make_pair(std::move(metricFunction), weight); } @@ -134,20 +134,20 @@ double QualityAssessor::getCustomMetricValue(const cv::Mat& frame, const std::st if (it == customMetrics.end()) { throw InvalidParameterException(std::format("Unknown custom metric: {}", metricName)); } - + return it->second.first(frame); } std::vector QualityAssessor::getDetailedMetrics(const cv::Mat& frame) const { std::vector details; - + // Add standard metrics struct StdMetric { QualityMetric metric; std::string name; double weight; }; - + std::vector stdMetrics = { {QualityMetric::Sharpness, "Sharpness", parameters.metricWeights[0]}, {QualityMetric::SNR, "SNR", parameters.metricWeights[1]}, @@ -156,17 +156,17 @@ std::vector QualityAssessor::getDetailedMetrics( {QualityMetric::Contrast, "Contrast", parameters.metricWeights[4]}, {QualityMetric::StarCount, "StarCount", parameters.metricWeights[5]} }; - + // Calculate raw values std::vector rawValues; rawValues.reserve(stdMetrics.size() + customMetrics.size()); - + for (const auto& metric : stdMetrics) { double value = getMetricValue(frame, metric.metric); rawValues.push_back(value); details.push_back({metric.name, value, 0.0, metric.weight}); } - + // Add custom metrics for (const auto& [name, metricPair] : customMetrics) { const auto& [metricFunc, weight] = metricPair; @@ -174,7 +174,7 @@ std::vector QualityAssessor::getDetailedMetrics( rawValues.push_back(value); details.push_back({name, value, 0.0, weight}); } - + // Normalize if requested if (parameters.normalizeMetrics) { // Find min and max for each metric @@ -190,7 +190,7 @@ std::vector QualityAssessor::getDetailedMetrics( details[i].normalizedValue = details[i].rawValue; } } - + return details; } @@ -198,10 +198,10 @@ cv::Rect QualityAssessor::calculateROI(const cv::Mat& frame) const { // Calculate ROI based on selected method int width = frame.cols; int height = frame.rows; - + int roiWidth = static_cast(width * parameters.roiSize); int roiHeight = static_cast(height * parameters.roiSize); - + if (parameters.roiSelector == "centered") { // Centered ROI int x = (width - roiWidth) / 2; @@ -211,13 +211,13 @@ cv::Rect QualityAssessor::calculateROI(const cv::Mat& frame) const { // Find brightest region (simplified) cv::Mat blurred; cv::GaussianBlur(frame, blurred, cv::Size(21, 21), 5); - + cv::Point maxLoc; cv::minMaxLoc(blurred, nullptr, nullptr, nullptr, &maxLoc); - + int x = std::clamp(maxLoc.x - roiWidth/2, 0, width - roiWidth); int y = std::clamp(maxLoc.y - roiHeight/2, 0, height - roiHeight); - + return cv::Rect(x, y, roiWidth, roiHeight); } else { // Default to full frame @@ -233,7 +233,7 @@ double QualityAssessor::calculateSharpness(const cv::Mat& frame) const { } else { gray = frame; } - + // Convert to float if needed cv::Mat floatImg; if (gray.depth() != CV_32F) { @@ -241,21 +241,21 @@ double QualityAssessor::calculateSharpness(const cv::Mat& frame) const { } else { floatImg = gray; } - + // Calculate ROI cv::Rect roi = calculateROI(floatImg); cv::Mat roiImg = floatImg(roi); - + // Apply Laplacian cv::Mat laplacian; cv::Laplacian(roiImg, laplacian, CV_32F, 3); - + // Calculate variance of Laplacian (measure of sharpness) cv::Scalar mean, stddev; cv::meanStdDev(laplacian, mean, stddev); - + double variance = stddev[0] * stddev[0]; - + // Normalize to a reasonable range (empirical) return std::min(variance / 100.0, 1.0); } @@ -268,30 +268,30 @@ double QualityAssessor::calculateSNR(const cv::Mat& frame) const { } else { gray = frame; } - + // Convert to float cv::Mat floatImg; gray.convertTo(floatImg, CV_32F); - + // Calculate ROI cv::Rect roi = calculateROI(floatImg); cv::Mat roiImg = floatImg(roi); - + // Apply Gaussian blur to estimate signal cv::Mat blurred; cv::GaussianBlur(roiImg, blurred, cv::Size(0, 0), 3); - + // Estimate noise as difference between original and blurred cv::Mat noise = roiImg - blurred; - + // Calculate statistics cv::Scalar signalMean, signalStdDev, noiseStdDev; cv::meanStdDev(blurred, signalMean, signalStdDev); cv::meanStdDev(noise, cv::Scalar(), noiseStdDev); - + // SNR = signal / noise double snr = signalMean[0] / (noiseStdDev[0] + 1e-6); - + // Normalize to a reasonable range (empirical) return std::min(snr / 20.0, 1.0); } @@ -304,7 +304,7 @@ double QualityAssessor::calculateEntropy(const cv::Mat& frame) const { } else { gray = frame; } - + // Ensure 8-bit for histogram cv::Mat img8bit; if (gray.depth() != CV_8U) { @@ -312,22 +312,22 @@ double QualityAssessor::calculateEntropy(const cv::Mat& frame) const { } else { img8bit = gray; } - + // Calculate ROI cv::Rect roi = calculateROI(img8bit); cv::Mat roiImg = img8bit(roi); - + // Calculate histogram cv::Mat hist; int histSize = 256; float range[] = {0, 256}; const float* histRange = {range}; cv::calcHist(&roiImg, 1, 0, cv::Mat(), hist, 1, &histSize, &histRange); - + // Normalize histogram double pixelCount = roiImg.total(); hist /= pixelCount; - + // Calculate entropy double entropy = 0.0; for (int i = 0; i < histSize; i++) { @@ -336,7 +336,7 @@ double QualityAssessor::calculateEntropy(const cv::Mat& frame) const { entropy -= binVal * std::log2(binVal); } } - + // Normalize to 0-1 range (max entropy for 8-bit is 8) return std::min(entropy / 8.0, 1.0); } @@ -349,14 +349,14 @@ double QualityAssessor::calculateBrightness(const cv::Mat& frame) const { } else { gray = frame; } - + // Calculate ROI cv::Rect roi = calculateROI(gray); cv::Mat roiImg = gray(roi); - + // Calculate mean brightness cv::Scalar meanVal = cv::mean(roiImg); - + // Normalize based on bit depth double normFactor = 1.0; if (gray.depth() == CV_8U) { @@ -364,7 +364,7 @@ double QualityAssessor::calculateBrightness(const cv::Mat& frame) const { } else if (gray.depth() == CV_16U) { normFactor = 65535.0; } - + return meanVal[0] / normFactor; } @@ -376,19 +376,19 @@ double QualityAssessor::calculateContrast(const cv::Mat& frame) const { } else { gray = frame; } - + // Convert to float cv::Mat floatImg; gray.convertTo(floatImg, CV_32F); - + // Calculate ROI cv::Rect roi = calculateROI(floatImg); cv::Mat roiImg = floatImg(roi); - + // Calculate standard deviation (measure of contrast) cv::Scalar mean, stddev; cv::meanStdDev(roiImg, mean, stddev); - + // Normalize by maximum possible standard deviation double maxStdDev = 0.5; // For normalized [0,1] image if (gray.depth() == CV_8U) { @@ -396,7 +396,7 @@ double QualityAssessor::calculateContrast(const cv::Mat& frame) const { } else if (gray.depth() == CV_16U) { maxStdDev = 32767.5; } - + return std::min(stddev[0] / maxStdDev, 1.0); } @@ -408,7 +408,7 @@ double QualityAssessor::calculateStarCount(const cv::Mat& frame) const { } else { gray = frame; } - + // Ensure 8-bit for blob detection cv::Mat img8bit; if (gray.depth() != CV_8U) { @@ -416,37 +416,37 @@ double QualityAssessor::calculateStarCount(const cv::Mat& frame) const { } else { img8bit = gray; } - + // Calculate ROI cv::Rect roi = calculateROI(img8bit); cv::Mat roiImg = img8bit(roi); - + // Threshold the image to find bright points cv::Mat thresholded; double thresh = parameters.starDetectionThreshold * 255.0; cv::threshold(roiImg, thresholded, thresh, 255, cv::THRESH_BINARY); - + // Find contours std::vector> contours; cv::findContours(thresholded, contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE); - + // Filter contours by size and shape to find star-like objects int starCount = 0; for (const auto& contour : contours) { double area = cv::contourArea(contour); - + // Stars are typically small and roughly circular if (area > 3 && area < 100) { // Check circularity double perimeter = cv::arcLength(contour, true); double circularity = 4 * M_PI * area / (perimeter * perimeter); - + if (circularity > 0.7) { // More circular than not starCount++; } } } - + // Normalize star count to 0-1 (assuming max ~100 stars in frame) return std::min(static_cast(starCount) / 100.0, 1.0); } @@ -459,11 +459,11 @@ double QualityAssessor::calculateCompositeScore(const cv::Mat& frame) const { double brightness = calculateBrightness(frame); double contrast = calculateContrast(frame); double starCount = calculateStarCount(frame); - + // Calculate weighted sum double weightSum = 0; double score = 0; - + // Standard metrics const std::vector values = {sharpness, snr, entropy, brightness, contrast, starCount}; for (size_t i = 0; i < values.size(); ++i) { @@ -472,7 +472,7 @@ double QualityAssessor::calculateCompositeScore(const cv::Mat& frame) const { weightSum += parameters.metricWeights[i]; } } - + // Add custom metrics for (const auto& [name, metricPair] : customMetrics) { const auto& [metricFunc, weight] = metricPair; @@ -480,13 +480,13 @@ double QualityAssessor::calculateCompositeScore(const cv::Mat& frame) const { score += value * weight; weightSum += weight; } - + // Normalize by sum of weights if (weightSum > 0) { score /= weightSum; } - + return score; } -} // namespace serastro \ No newline at end of file +} // namespace serastro diff --git a/atom/image/ser/quality.h b/atom/image/ser/quality.h index e49cb7ae..f7e4a7b0 100644 --- a/atom/image/ser/quality.h +++ b/atom/image/ser/quality.h @@ -42,35 +42,35 @@ class QualityAssessor { public: QualityAssessor(); explicit QualityAssessor(const QualityParameters& params); - + // Assess quality of a single frame double assessQuality(const cv::Mat& frame) const; - + // Get quality scores as vector std::vector getQualityScores(const std::vector& frames) const; - + // Sort frames by quality (returns indices of frames in descending order) std::vector sortFramesByQuality(const std::vector& frames) const; - + // Select best N frames std::vector selectBestFrames(const std::vector& frames, size_t count) const; - + // Add custom quality metric - void addCustomMetric(const std::string& name, + void addCustomMetric(const std::string& name, QualityMetricFunction metricFunction, double weight = 1.0); - + // Remove custom metric void removeCustomMetric(const std::string& name); - + // Get/set parameters void setParameters(const QualityParameters& params); const QualityParameters& getParameters() const; - + // Get value of specific metric double getMetricValue(const cv::Mat& frame, QualityMetric metric) const; double getCustomMetricValue(const cv::Mat& frame, const std::string& metricName) const; - + // Get details of all metrics for a frame struct MetricDetails { std::string name; @@ -78,16 +78,16 @@ class QualityAssessor { double normalizedValue; double weight; }; - + std::vector getDetailedMetrics(const cv::Mat& frame) const; private: QualityParameters parameters; std::unordered_map> customMetrics; - + // Calculate ROI for quality assessment cv::Rect calculateROI(const cv::Mat& frame) const; - + // Internal implementations for standard metrics double calculateSharpness(const cv::Mat& frame) const; double calculateSNR(const cv::Mat& frame) const; @@ -98,4 +98,4 @@ class QualityAssessor { double calculateCompositeScore(const cv::Mat& frame) const; }; -} // namespace serastro \ No newline at end of file +} // namespace serastro diff --git a/atom/image/ser/registration.h b/atom/image/ser/registration.h index f131c075..f098aa29 100644 --- a/atom/image/ser/registration.h +++ b/atom/image/ser/registration.h @@ -49,14 +49,14 @@ struct FrameTransformation { Perspective, // Perspective transform Polynomial // Higher-order polynomial transform }; - + Type type = Type::Translation; cv::Mat transform; // Transformation matrix double confidence = 0.0; // Confidence score (0-1) - + // Apply transformation to a point cv::Point2f apply(const cv::Point2f& pt) const; - + // Apply transformation to a frame cv::Mat applyToFrame(const cv::Mat& frame, const cv::Size& outputSize = cv::Size()) const; }; @@ -66,32 +66,32 @@ class FrameRegistrar : public CustomizableProcessor { public: FrameRegistrar(); explicit FrameRegistrar(const RegistrationParameters& params); - + // Calculate transformation between frames FrameTransformation calculateTransformation(const cv::Mat& frame) const; - + // Register frame and return transformation std::pair registerFrame(const cv::Mat& frame) const; - + // Register and apply in one step cv::Mat registerAndApply(const cv::Mat& frame); - + // Set reference frame void setReferenceFrame(const cv::Mat& referenceFrame); - + // Auto-select reference frame from a set of frames void autoSelectReferenceFrame(const std::vector& frames); - + // Get reference frame cv::Mat getReferenceFrame() const; - + // Check if reference frame is set bool hasReferenceFrame() const; - + // Register multiple frames std::vector registerFrames(const std::vector& frames, const ProgressCallback& progress = nullptr); - + // CustomizableProcessor interface implementation cv::Mat process(const cv::Mat& frame) override; std::string getName() const override; @@ -99,11 +99,11 @@ class FrameRegistrar : public CustomizableProcessor { double getParameter(const std::string& name) const override; std::vector getParameterNames() const override; bool hasParameter(const std::string& name) const override; - + // Set/get registration parameters void setRegistrationParameters(const RegistrationParameters& params); const RegistrationParameters& getRegistrationParameters() const; - + // Set quality assessor for reference frame selection void setQualityAssessor(std::shared_ptr assessor); std::shared_ptr getQualityAssessor() const; @@ -113,18 +113,18 @@ class FrameRegistrar : public CustomizableProcessor { cv::Mat referenceFrame; bool hasReference = false; std::shared_ptr qualityAssessor; - + // Transformation methods FrameTransformation calculatePhaseCorrelation(const cv::Mat& frame) const; FrameTransformation calculateFeatureMatching(const cv::Mat& frame) const; FrameTransformation calculateOpticalFlow(const cv::Mat& frame) const; FrameTransformation calculateECC(const cv::Mat& frame) const; FrameTransformation calculateTemplateMatching(const cv::Mat& frame) const; - + // Helper methods cv::Mat prepareFrameForRegistration(const cv::Mat& frame) const; cv::Rect calculateCommonArea(const std::vector& transforms, const cv::Size& frameSize) const; }; -} // namespace serastro \ No newline at end of file +} // namespace serastro diff --git a/atom/image/ser/ser.hpp b/atom/image/ser/ser.hpp index e4cd1726..5bf28379 100644 --- a/atom/image/ser/ser.hpp +++ b/atom/image/ser/ser.hpp @@ -40,4 +40,4 @@ struct LibraryInfo { } }; -} // namespace serastro \ No newline at end of file +} // namespace serastro diff --git a/atom/image/ser/ser_format.h b/atom/image/ser/ser_format.h index 63a465bd..fae19218 100644 --- a/atom/image/ser/ser_format.h +++ b/atom/image/ser/ser_format.h @@ -192,4 +192,4 @@ struct SERHeader { } }; -} // namespace serastro \ No newline at end of file +} // namespace serastro diff --git a/atom/image/ser/ser_reader.cpp b/atom/image/ser/ser_reader.cpp index 1e9dcc7b..1ac18b31 100644 --- a/atom/image/ser/ser_reader.cpp +++ b/atom/image/ser/ser_reader.cpp @@ -407,4 +407,4 @@ void SERReader::clearCache() const { pImpl->currentCacheSize = 0; } -} // namespace serastro \ No newline at end of file +} // namespace serastro diff --git a/atom/image/ser/ser_reader.h b/atom/image/ser/ser_reader.h index 2e2d30a4..7472461f 100644 --- a/atom/image/ser/ser_reader.h +++ b/atom/image/ser/ser_reader.h @@ -105,4 +105,4 @@ class SERReader { std::unique_ptr pImpl; }; -} // namespace serastro \ No newline at end of file +} // namespace serastro diff --git a/atom/image/ser/ser_writer.cpp b/atom/image/ser/ser_writer.cpp index f9af304f..92710136 100644 --- a/atom/image/ser/ser_writer.cpp +++ b/atom/image/ser/ser_writer.cpp @@ -245,4 +245,4 @@ void SERWriter::finalize() { // Get current number of frames written size_t SERWriter::getFrameCount() const { return pImpl->currentFrameCount; } -} // namespace serastro \ No newline at end of file +} // namespace serastro diff --git a/atom/image/ser/ser_writer.h b/atom/image/ser/ser_writer.h index 0970d744..0cef1980 100644 --- a/atom/image/ser/ser_writer.h +++ b/atom/image/ser/ser_writer.h @@ -25,26 +25,26 @@ class SERWriter { public: // Create a new SER file explicit SERWriter(const std::filesystem::path& filePath, const SERHeader& header); - + // Destructor ~SERWriter(); - + // Write a frame to the file void writeFrame(const cv::Mat& frame, const WriteOptions& options = {}); - + // Write a frame with a timestamp void writeFrameWithTimestamp(const cv::Mat& frame, uint64_t timestamp, const WriteOptions& options = {}); - + // Write multiple frames void writeFrames(const std::vector& frames, const WriteOptions& options = {}); - + // Finalize the file (updates header with frame count) void finalize(); - + // Get current number of frames written size_t getFrameCount() const; - + // Write custom raw frame data (advanced) void writeRawFrame(const std::vector& frameData); @@ -53,4 +53,4 @@ class SERWriter { std::unique_ptr pImpl; }; -} // namespace serastro \ No newline at end of file +} // namespace serastro diff --git a/atom/image/ser/stacking.h b/atom/image/ser/stacking.h index a35517a2..88bf0473 100644 --- a/atom/image/ser/stacking.h +++ b/atom/image/ser/stacking.h @@ -29,10 +29,10 @@ enum class StackingMethod { class FrameWeightCalculator { public: virtual ~FrameWeightCalculator() = default; - + // Calculate weight for a single frame virtual double calculateWeight(const cv::Mat& frame) = 0; - + // Calculate weights for multiple frames virtual std::vector calculateWeights(const std::vector& frames); }; @@ -41,10 +41,10 @@ class FrameWeightCalculator { class QualityWeightCalculator : public FrameWeightCalculator { public: explicit QualityWeightCalculator(std::shared_ptr assessor = nullptr); - + double calculateWeight(const cv::Mat& frame) override; std::vector calculateWeights(const std::vector& frames) override; - + void setQualityAssessor(std::shared_ptr assessor); std::shared_ptr getQualityAssessor() const; @@ -72,14 +72,14 @@ class FrameStacker : public CustomizableProcessor { public: FrameStacker(); explicit FrameStacker(const StackingParameters& params); - + // Stack multiple frames cv::Mat stackFrames(const std::vector& frames); - + // Stack with explicit weights - cv::Mat stackFramesWithWeights(const std::vector& frames, + cv::Mat stackFramesWithWeights(const std::vector& frames, const std::vector& weights); - + // CustomizableProcessor interface implementation cv::Mat process(const cv::Mat& frame) override; std::string getName() const override; @@ -87,15 +87,15 @@ class FrameStacker : public CustomizableProcessor { double getParameter(const std::string& name) const override; std::vector getParameterNames() const override; bool hasParameter(const std::string& name) const override; - + // Set/get stacking parameters void setStackingParameters(const StackingParameters& params); const StackingParameters& getStackingParameters() const; - + // Set/get weight calculator void setWeightCalculator(std::shared_ptr calculator); std::shared_ptr getWeightCalculator() const; - + // Buffer management void addFrameToBuffer(const cv::Mat& frame); void clearBuffer(); @@ -107,7 +107,7 @@ class FrameStacker : public CustomizableProcessor { StackingParameters parameters; std::vector frameBuffer; size_t maxBufferSize = 100; - + // Implementation methods for different stacking algorithms cv::Mat stackMean(const std::vector& frames) const; cv::Mat stackMedian(const std::vector& frames) const; @@ -116,12 +116,12 @@ class FrameStacker : public CustomizableProcessor { cv::Mat stackSigmaClipping(const std::vector& frames) const; cv::Mat stackWeightedAverage(const std::vector& frames, const std::vector& weights) const; - + // Prepare frames for stacking (convert to float, normalize, etc.) std::vector prepareFrames(const std::vector& frames) const; - + // Normalize result after stacking cv::Mat normalizeResult(const cv::Mat& stacked) const; }; -} // namespace serastro \ No newline at end of file +} // namespace serastro diff --git a/atom/image/ser/utils.cpp b/atom/image/ser/utils.cpp index 33ad02fd..4ef112a3 100644 --- a/atom/image/ser/utils.cpp +++ b/atom/image/ser/utils.cpp @@ -651,4 +651,4 @@ std::string getLibraryVersion() { std::string getOpenCVVersion() { return CV_VERSION; } } // namespace utils -} // namespace serastro \ No newline at end of file +} // namespace serastro diff --git a/atom/image/ser/utils.h b/atom/image/ser/utils.h index b4b96a19..8682534b 100644 --- a/atom/image/ser/utils.h +++ b/atom/image/ser/utils.h @@ -25,11 +25,11 @@ cv::Mat convertToRGB(const cv::Mat& src); // Normalization cv::Mat normalize(const cv::Mat& src, double alpha = 0.0, double beta = 1.0); cv::Mat normalizeMinMax(const cv::Mat& src); -cv::Mat normalizePercentile(const cv::Mat& src, double lowPercentile = 0.5, +cv::Mat normalizePercentile(const cv::Mat& src, double lowPercentile = 0.5, double highPercentile = 99.5); // File utilities -std::vector findSerFiles(const std::filesystem::path& directory, +std::vector findSerFiles(const std::filesystem::path& directory, bool recursive = false); std::optional estimateFrameCount(const std::filesystem::path& serFile); bool isValidSerFile(const std::filesystem::path& serFile); @@ -62,7 +62,7 @@ std::vector detectHotPixels(const cv::Mat& image, double threshold = std::vector detectColdPixels(const cv::Mat& image, double threshold = 0.05); // Create bad pixel map -cv::Mat createBadPixelMask(const cv::Mat& image, double hotThreshold = 0.95, +cv::Mat createBadPixelMask(const cv::Mat& image, double hotThreshold = 0.95, double coldThreshold = 0.05); // Fix bad pixels @@ -76,4 +76,4 @@ std::string getLibraryVersion(); std::string getOpenCVVersion(); } // namespace utils -} // namespace serastro \ No newline at end of file +} // namespace serastro diff --git a/atom/image/xmake.lua b/atom/image/xmake.lua index ea84f10f..605802c3 100644 --- a/atom/image/xmake.lua +++ b/atom/image/xmake.lua @@ -38,24 +38,24 @@ add_requires("cfitsio", {optional = true}) -- Object Library target("atom-image-object") set_kind("object") - + -- Add files add_files(table.unpack(source_files)) add_headerfiles(table.unpack(header_files)) - + -- Add dependencies add_packages("loguru") - + -- Add optional dependency on cfitsio if available if has_package("cfitsio") then add_packages("cfitsio") add_defines("HAS_CFITSIO") end - + -- Add include directories add_includedirs(".", {public = true}) add_includedirs("..", {public = true}) - + -- Set C++ standard set_languages("c++20") target_end() @@ -64,20 +64,20 @@ target_end() target("atom-image") -- Set library type based on parent project option set_kind(has_config("shared_libs") and "shared" or "static") - + -- Add dependencies add_deps("atom-image-object") add_packages("loguru") - + -- Add optional dependency on cfitsio if available if has_package("cfitsio") then add_packages("cfitsio") end - + -- Set output directories set_targetdir("$(buildir)/lib") set_objectdir("$(buildir)/obj") - + -- Install configuration on_install(function (target) os.cp(target:targetfile(), path.join(target:installdir(), "lib")) diff --git a/atom/io/compress.cpp b/atom/io/compress.cpp index fca62cc4..ef9c1ad6 100644 --- a/atom/io/compress.cpp +++ b/atom/io/compress.cpp @@ -82,7 +82,7 @@ class ZStreamGuard { // Initialize for compression bool initDeflate(int level, int windowBits = 7) { - int ret = deflateInit2(&stream_, level, Z_DEFLATED, windowBits, + int ret = deflateInit2(&stream_, level, Z_DEFLATED, windowBits, 8, Z_DEFAULT_STRATEGY); if (ret == Z_OK) { initialized_ = true; @@ -2064,27 +2064,27 @@ std::pair> compressData( zs.next_in = const_cast(reinterpret_cast(data_ptr)); zs.avail_out = static_cast(compressed_bound); zs.next_out = reinterpret_cast(compressed_data.data()); - + // Initialize deflate with window_bits from options - int ret = deflateInit2(&zs, options.level, Z_DEFLATED, options.window_bits, + int ret = deflateInit2(&zs, options.level, Z_DEFLATED, options.window_bits, 8, Z_DEFAULT_STRATEGY); if (ret != Z_OK) { compression_result.error_message = getZlibErrorMessage(ret); return result_pair; } - + // Use RAII for zstream cleanup std::unique_ptr deflate_guard(&zs, deflateEnd); - + // Perform compression in one step ret = deflate(&zs, Z_FINISH); - + if (ret != Z_STREAM_END) { - compression_result.error_message = + compression_result.error_message = String("Compression failed: ") + getZlibErrorMessage(ret); return result_pair; } - + // Use actual bytes written uLongf actual_compressed_size = zs.total_out; @@ -2156,7 +2156,7 @@ std::pair> decompressData( // Try to detect compression type from header bytes for better buffer estimation if (compressed_data_size >= 2) { const unsigned char* header = reinterpret_cast(compressed_data_ptr); - + // Check for gzip magic signature (0x1F, 0x8B) if (header[0] == 0x1F && header[1] == 0x8B) { // Gzip typically has 2:1 to 10:1 compression ratio @@ -2176,12 +2176,12 @@ std::pair> decompressData( buffer_size = 4096; } } - + // Ensure minimum buffer size if (buffer_size < 1024) { buffer_size = 1024; } - + decompressed_data.resize(buffer_size); // Use z_stream for more control, especially for potential resizing @@ -2199,7 +2199,7 @@ std::pair> decompressData( // For gzip/zlib auto-detection, add 32 (15+32) // For raw deflate with no header, use negative value (-15) int windowBits = options.window_bits; - + // Auto-detect based on header bytes if possible if (compressed_data_size >= 2) { const unsigned char* header = reinterpret_cast(compressed_data_ptr); @@ -2215,7 +2215,7 @@ std::pair> decompressData( } // If not recognized, use as-is (for raw deflate) } - + int ret = inflateInit2(&zs, windowBits); if (ret != Z_OK) { compression_result.error_message = getZlibErrorMessage(ret); @@ -2236,7 +2236,7 @@ std::pair> decompressData( if (zs.avail_out == 0) { // Buffer is full, resize it with an optimized growth strategy size_t old_size = decompressed_data.size(); - + // Smart growth strategy: // - For small buffers (<64KB): double the size // - For medium buffers (64KB-1MB): grow by 50% @@ -2250,14 +2250,14 @@ std::pair> decompressData( size_t increment = std::max(old_size / 4, size_t(1048576)); new_size = old_size + increment; } - + // Check for overflow if (new_size <= old_size) { compression_result.error_message = "Decompression buffer size overflow"; return result_pair; // inflate_guard handles cleanup } - + // Allocate new buffer try { decompressed_data.resize(new_size); @@ -2266,7 +2266,7 @@ std::pair> decompressData( "Memory allocation failed during decompression"; return result_pair; } - + // Update stream pointers after resize zs.avail_out = static_cast(decompressed_data.size() - zs.total_out); diff --git a/atom/io/file_permission.cpp b/atom/io/file_permission.cpp index 182d0e6f..84e9c5e9 100644 --- a/atom/io/file_permission.cpp +++ b/atom/io/file_permission.cpp @@ -425,4 +425,4 @@ void changeFilePermissions(const fs::path& filePath, } } -} // namespace atom::io \ No newline at end of file +} // namespace atom::io diff --git a/atom/io/file_permission.hpp b/atom/io/file_permission.hpp index 92aecdb4..06afb457 100644 --- a/atom/io/file_permission.hpp +++ b/atom/io/file_permission.hpp @@ -77,4 +77,4 @@ std::string getSelfPermissions() noexcept; void changeFilePermissions(const std::filesystem::path &filePath, const atom::containers::String &permissions); -} // namespace atom::io \ No newline at end of file +} // namespace atom::io diff --git a/atom/io/xmake.lua b/atom/io/xmake.lua index cf529e5c..1421de04 100644 --- a/atom/io/xmake.lua +++ b/atom/io/xmake.lua @@ -49,41 +49,41 @@ local headers = { target("atom-io") -- Set target kind to static library set_kind("static") - + -- Add source files add_files(sources) - + -- Add header files add_headerfiles(headers) - + -- Add include directories add_includedirs(".", {public = true}) - + -- Add packages add_packages("loguru", "minizip", "zlib", "tbb") - + -- Add system libraries add_syslinks("pthread") - + -- Windows-specific libraries if is_plat("windows") then add_syslinks("ws2_32", "wsock32") end - + -- Enable position independent code add_cxflags("-fPIC", {tools = {"gcc", "clang"}}) add_cflags("-fPIC", {tools = {"gcc", "clang"}}) - + -- Set version info set_version("1.0.0") - + -- Set output name set_basename("atom-io") - + -- Set target and object directories set_targetdir("$(buildir)/lib") set_objectdir("$(buildir)/obj") - + -- Installation rules after_install(function (target) local installdir = target:installdir() or "$(prefix)" @@ -100,21 +100,21 @@ target("atom-io") -- Optional: Create object library target (equivalent to CMake's object library) target("atom-io-object") set_kind("object") - + -- Add the same source files add_files(sources) add_headerfiles(headers) - + -- Configuration add_includedirs(".") add_packages("loguru", "minizip", "zlib", "tbb") add_syslinks("pthread") - + -- Windows-specific libraries if is_plat("windows") then add_syslinks("ws2_32", "wsock32") end - + -- Enable position independent code add_cxflags("-fPIC", {tools = {"gcc", "clang"}}) add_cflags("-fPIC", {tools = {"gcc", "clang"}}) diff --git a/atom/log/async_logger.cpp b/atom/log/async_logger.cpp index f610117c..5c60d059 100644 --- a/atom/log/async_logger.cpp +++ b/atom/log/async_logger.cpp @@ -854,4 +854,4 @@ Task AsyncLogger::logAsync(LogLevel level, std::string msg, co_return; } -} // namespace atom::log \ No newline at end of file +} // namespace atom::log diff --git a/atom/log/async_logger.hpp b/atom/log/async_logger.hpp index eaeaa14c..e49c6960 100644 --- a/atom/log/async_logger.hpp +++ b/atom/log/async_logger.hpp @@ -464,4 +464,4 @@ class AsyncLogger { } // namespace atom::log -#endif // ATOM_LOG_ASYNC_LOGGER_HPP \ No newline at end of file +#endif // ATOM_LOG_ASYNC_LOGGER_HPP diff --git a/atom/log/atomlog.cpp b/atom/log/atomlog.cpp index eb03637e..a14dd610 100644 --- a/atom/log/atomlog.cpp +++ b/atom/log/atomlog.cpp @@ -912,4 +912,4 @@ std::shared_ptr Logger::create(const fs::path& file_name) { return std::make_shared(file_name); } -} // namespace atom::log \ No newline at end of file +} // namespace atom::log diff --git a/atom/log/atomlog.hpp b/atom/log/atomlog.hpp index 111a3c00..452bc622 100644 --- a/atom/log/atomlog.hpp +++ b/atom/log/atomlog.hpp @@ -443,4 +443,4 @@ class Logger { } // namespace atom::log -#endif // ATOM_LOG_ATOMLOG_HPP \ No newline at end of file +#endif // ATOM_LOG_ATOMLOG_HPP diff --git a/atom/log/log_manager.cpp b/atom/log/log_manager.cpp index eec3d1a9..a42b2c9a 100644 --- a/atom/log/log_manager.cpp +++ b/atom/log/log_manager.cpp @@ -322,4 +322,4 @@ void LogManager::flushAll() { } } -} // namespace atom::log \ No newline at end of file +} // namespace atom::log diff --git a/atom/log/log_manager.hpp b/atom/log/log_manager.hpp index 5ee53d3c..0eb3db2a 100644 --- a/atom/log/log_manager.hpp +++ b/atom/log/log_manager.hpp @@ -255,4 +255,4 @@ inline std::optional> getMmapLogger( } // namespace atom::log -#endif // ATOM_LOG_LOG_MANAGER_HPP \ No newline at end of file +#endif // ATOM_LOG_LOG_MANAGER_HPP diff --git a/atom/log/mmap_logger.cpp b/atom/log/mmap_logger.cpp index d9278529..1c177515 100644 --- a/atom/log/mmap_logger.cpp +++ b/atom/log/mmap_logger.cpp @@ -1169,4 +1169,4 @@ void MmapLogger::log(LogLevel level, Category category, std::string_view msg, impl_->log(level, category, msg, location); } -} // namespace atom::log \ No newline at end of file +} // namespace atom::log diff --git a/atom/log/mmap_logger.hpp b/atom/log/mmap_logger.hpp index 47566d24..f92ac830 100644 --- a/atom/log/mmap_logger.hpp +++ b/atom/log/mmap_logger.hpp @@ -356,4 +356,4 @@ using LoggerConfig = MmapLogger::Config; } // namespace atom::log -#endif // ATOM_LOG_MMAP_LOGGER_HPP \ No newline at end of file +#endif // ATOM_LOG_MMAP_LOGGER_HPP diff --git a/atom/log/xmake.lua b/atom/log/xmake.lua index 1e3733b3..913b3e49 100644 --- a/atom/log/xmake.lua +++ b/atom/log/xmake.lua @@ -26,28 +26,28 @@ local headers = { -- Object Library target("atom-log-object") set_kind("object") - + -- Add files add_files(table.unpack(sources)) add_headerfiles(table.unpack(headers)) - + -- Add dependencies add_packages("loguru") - + -- Add include directories add_includedirs(".", {public = true}) add_includedirs("..", {public = true}) - + -- Set C++ standard set_languages("c++20") - + -- Configure loguru options if is_plat("windows") then add_defines("LOGURU_STACKTRACES=1", {public = true}) else add_defines("LOGURU_STACKTRACES=1", {public = true}) end - + add_defines("LOGURU_WITH_STREAMS=1", {public = true}) add_defines("LOGURU_RTTI=1", {public = true}) target_end() @@ -56,11 +56,11 @@ target_end() target("atom-log") -- Set library type based on parent project option set_kind(has_config("shared_libs") and "shared" or "static") - + -- Add dependencies add_deps("atom-log-object") add_packages("loguru") - + -- Platform-specific settings if is_plat("windows") then add_packages("dlfcn-win32") @@ -68,11 +68,11 @@ target("atom-log") else add_syslinks("dl", "pthread") end - + -- Set output directories set_targetdir("$(buildir)/lib") set_objectdir("$(buildir)/obj") - + -- Install configuration on_install(function (target) os.cp(target:targetfile(), path.join(target:installdir(), "lib")) diff --git a/atom/memory/memory_pool.hpp b/atom/memory/memory_pool.hpp index eebafca6..11e3d3ed 100644 --- a/atom/memory/memory_pool.hpp +++ b/atom/memory/memory_pool.hpp @@ -345,4 +345,4 @@ template } } // namespace memory -} // namespace atom \ No newline at end of file +} // namespace atom diff --git a/atom/memory/object.hpp b/atom/memory/object.hpp index abc50beb..30469a72 100644 --- a/atom/memory/object.hpp +++ b/atom/memory/object.hpp @@ -820,4 +820,4 @@ class ObjectPool { } // namespace atom::memory -#endif // ATOM_MEMORY_OBJECT_POOL_HPP \ No newline at end of file +#endif // ATOM_MEMORY_OBJECT_POOL_HPP diff --git a/atom/memory/ring.hpp b/atom/memory/ring.hpp index c44c6d3c..9823e67c 100644 --- a/atom/memory/ring.hpp +++ b/atom/memory/ring.hpp @@ -470,4 +470,4 @@ class RingBuffer { } // namespace atom::memory -#endif // ATOM_ALGORITHM_RING_HPP \ No newline at end of file +#endif // ATOM_ALGORITHM_RING_HPP diff --git a/atom/memory/shared.hpp b/atom/memory/shared.hpp index eb88087d..0a18e848 100644 --- a/atom/memory/shared.hpp +++ b/atom/memory/shared.hpp @@ -1206,4 +1206,4 @@ auto SharedMemory::getNativeHandle() const -> void* { } // namespace atom::connection -#endif // ATOM_CONNECTION_SHARED_MEMORY_HPP \ No newline at end of file +#endif // ATOM_CONNECTION_SHARED_MEMORY_HPP diff --git a/atom/memory/tracker.hpp b/atom/memory/tracker.hpp index a699033f..78135432 100644 --- a/atom/memory/tracker.hpp +++ b/atom/memory/tracker.hpp @@ -544,4 +544,4 @@ void operator delete[](void* ptr, const std::nothrow_t&) noexcept { #endif // ATOM_MEMORY_TRACKING_ENABLED -#endif // ATOM_MEMORY_TRACKER_HPP \ No newline at end of file +#endif // ATOM_MEMORY_TRACKER_HPP diff --git a/atom/memory/utils.hpp b/atom/memory/utils.hpp index 97e8f750..d376357c 100644 --- a/atom/memory/utils.hpp +++ b/atom/memory/utils.hpp @@ -167,4 +167,4 @@ std::shared_ptr lockWeakOrCreate(std::weak_ptr& weak, Args&&... args) { } // namespace atom::memory -#endif // ATOM_MEMORY_UTILS_HPP \ No newline at end of file +#endif // ATOM_MEMORY_UTILS_HPP diff --git a/atom/memory/xmake.lua b/atom/memory/xmake.lua index bf601d04..1faa66f3 100644 --- a/atom/memory/xmake.lua +++ b/atom/memory/xmake.lua @@ -42,61 +42,61 @@ end target(lib_name) local sources = get_sources() local headers = get_headers() - + if #sources > 0 then -- Create library with source files set_kind("static") add_files(sources) add_headerfiles(headers) - + -- Add dependencies add_deps("atom-error") - + -- Set include directories add_includedirs(".", {public = true}) - + -- Enable position independent code add_cxflags("-fPIC", {tools = {"gcc", "clang"}}) add_cflags("-fPIC", {tools = {"gcc", "clang"}}) - + else -- Create header-only library set_kind("headeronly") add_headerfiles(headers) - + -- Add dependencies for header-only library add_deps("atom-error") - + -- Set include directories add_includedirs(".", {public = true}) end - + -- Set version set_version("1.0.0") - + -- Set output name set_basename(lib_name) - + -- Installation rules after_install(function (target) local installdir = target:installdir() or "$(prefix)" local kind = target:kind() - + if kind ~= "headeronly" then -- Install library file os.cp(target:targetfile(), path.join(installdir, "lib")) end - + -- Install headers local headerdir = path.join(installdir, "include", "atom", "memory") os.mkdir(headerdir) - + local headers = get_headers() for _, header in ipairs(headers) do os.cp(header, headerdir) end end) - + -- Add to global module list (equivalent to CMake's global property) after_build(function (target) -- Store module information for potential use by parent build system diff --git a/atom/meta/CMakeLists.txt b/atom/meta/CMakeLists.txt index 615a5c04..b3d1ff65 100644 --- a/atom/meta/CMakeLists.txt +++ b/atom/meta/CMakeLists.txt @@ -43,4 +43,4 @@ set_target_properties(${PROJECT_NAME} PROPERTIES # Install rules install(TARGETS ${PROJECT_NAME} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} -) \ No newline at end of file +) diff --git a/atom/meta/container_traits.hpp b/atom/meta/container_traits.hpp index fa20c087..5693ca04 100644 --- a/atom/meta/container_traits.hpp +++ b/atom/meta/container_traits.hpp @@ -845,4 +845,4 @@ auto make_container_pipe(Container&& container) { } // namespace atom::meta -#endif // ATOM_META_CONTAINER_TRAITS_HPP \ No newline at end of file +#endif // ATOM_META_CONTAINER_TRAITS_HPP diff --git a/atom/meta/facade.hpp b/atom/meta/facade.hpp index 5997ecb7..3d538b94 100644 --- a/atom/meta/facade.hpp +++ b/atom/meta/facade.hpp @@ -1088,4 +1088,4 @@ std::ostream& operator<<(std::ostream& os, const proxy& p) { return os; } -} // namespace atom::meta \ No newline at end of file +} // namespace atom::meta diff --git a/atom/meta/facade_any.hpp b/atom/meta/facade_any.hpp index 0c41da3f..a08e95c3 100644 --- a/atom/meta/facade_any.hpp +++ b/atom/meta/facade_any.hpp @@ -796,4 +796,4 @@ auto enhancedVarWithDesc(T&& value, std::string_view description) } // namespace atom::meta -#endif // ATOM_META_FACADE_ANY_HPP \ No newline at end of file +#endif // ATOM_META_FACADE_ANY_HPP diff --git a/atom/meta/facade_proxy.hpp b/atom/meta/facade_proxy.hpp index a5de1853..63f5a933 100644 --- a/atom/meta/facade_proxy.hpp +++ b/atom/meta/facade_proxy.hpp @@ -525,4 +525,4 @@ auto makeEnhancedProxy(Func&& func, std::string_view name) { } // namespace atom::meta -#endif // ATOM_META_FACADE_PROXY_HPP \ No newline at end of file +#endif // ATOM_META_FACADE_PROXY_HPP diff --git a/atom/meta/field_count.hpp b/atom/meta/field_count.hpp index 506f21a6..0e061b07 100644 --- a/atom/meta/field_count.hpp +++ b/atom/meta/field_count.hpp @@ -255,4 +255,4 @@ consteval auto fieldCountOf() -> std::size_t { } // namespace atom::meta -#endif // ATOM_META_FIELD_COUNT_HPP \ No newline at end of file +#endif // ATOM_META_FIELD_COUNT_HPP diff --git a/atom/meta/global_ptr.cpp b/atom/meta/global_ptr.cpp index 4e0adb75..64774f5a 100644 --- a/atom/meta/global_ptr.cpp +++ b/atom/meta/global_ptr.cpp @@ -183,4 +183,4 @@ void GlobalSharedPtrManager::updateMetadata(std::string_view key, // Ignore type errors in ref counting } } -} \ No newline at end of file +} diff --git a/atom/meta/god.hpp b/atom/meta/god.hpp index da4c537c..b8a416d9 100644 --- a/atom/meta/god.hpp +++ b/atom/meta/god.hpp @@ -791,4 +791,4 @@ T& singleton() { } // namespace atom::meta -#endif // ATOM_META_GOD_HPP \ No newline at end of file +#endif // ATOM_META_GOD_HPP diff --git a/atom/meta/invoke.hpp b/atom/meta/invoke.hpp index e11cdfe4..a3458b42 100644 --- a/atom/meta/invoke.hpp +++ b/atom/meta/invoke.hpp @@ -855,4 +855,4 @@ template } // namespace atom::meta -#endif // ATOM_META_INVOKE_HPP \ No newline at end of file +#endif // ATOM_META_INVOKE_HPP diff --git a/atom/meta/proxy.hpp b/atom/meta/proxy.hpp index 62ff9b6d..bb0d1b11 100644 --- a/atom/meta/proxy.hpp +++ b/atom/meta/proxy.hpp @@ -862,4 +862,4 @@ auto composeProxy(Func1&& f1, Func2&& f2) { } // namespace atom::meta -#endif \ No newline at end of file +#endif diff --git a/atom/meta/stepper.hpp b/atom/meta/stepper.hpp index 68ca4bde..81cfde73 100644 --- a/atom/meta/stepper.hpp +++ b/atom/meta/stepper.hpp @@ -971,4 +971,4 @@ class FunctionSequence { } // namespace atom::meta -#endif // ATOM_META_STEPPER_HPP \ No newline at end of file +#endif // ATOM_META_STEPPER_HPP diff --git a/atom/meta/type_info.hpp b/atom/meta/type_info.hpp index c05851f7..ab117547 100644 --- a/atom/meta/type_info.hpp +++ b/atom/meta/type_info.hpp @@ -697,4 +697,4 @@ struct hash { }; } // namespace std -#endif \ No newline at end of file +#endif diff --git a/atom/meta/xmake.lua b/atom/meta/xmake.lua index 098060be..1078b694 100644 --- a/atom/meta/xmake.lua +++ b/atom/meta/xmake.lua @@ -24,15 +24,15 @@ local header_files = { -- Object Library target("atom-meta-object") set_kind("object") - + -- Add files add_files(table.unpack(source_files)) add_headerfiles(table.unpack(header_files)) - + -- Add include directories add_includedirs(".", {public = true}) add_includedirs("..", {public = true}) - + -- Set C++ standard set_languages("c++20") target_end() @@ -41,17 +41,17 @@ target_end() target("atom-meta") -- Set library type based on parent project option set_kind(has_config("shared_libs") and "shared" or "static") - + -- Add dependencies add_deps("atom-meta-object") - + -- Set output directories set_targetdir("$(buildir)/lib") set_objectdir("$(buildir)/obj") - + -- Set version with build timestamp set_version("1.0.0", {build = "%Y%m%d%H%M"}) - + -- Install configuration on_install(function (target) os.cp(target:targetfile(), path.join(target:installdir(), "lib")) diff --git a/atom/search/lru.hpp b/atom/search/lru.hpp index 1019897a..2a6aa912 100644 --- a/atom/search/lru.hpp +++ b/atom/search/lru.hpp @@ -1282,4 +1282,4 @@ auto ThreadSafeLRUCache::acquireWriteLock( } // namespace atom::search -#endif // THREADSAFE_LRU_CACHE_H \ No newline at end of file +#endif // THREADSAFE_LRU_CACHE_H diff --git a/atom/search/mysql.cpp b/atom/search/mysql.cpp index da3e2b5b..bb639f7d 100644 --- a/atom/search/mysql.cpp +++ b/atom/search/mysql.cpp @@ -969,4 +969,4 @@ bool MysqlDB::setConnectionTimeout(unsigned int timeout) { } } // namespace database -} // namespace atom \ No newline at end of file +} // namespace atom diff --git a/atom/search/mysql.hpp b/atom/search/mysql.hpp index 994b1f45..72ed6c20 100644 --- a/atom/search/mysql.hpp +++ b/atom/search/mysql.hpp @@ -29,7 +29,7 @@ namespace database { /** * @brief Custom exception class for MySQL-related errors - * + * * This exception is thrown when MySQL operations fail or encounter errors. * It provides detailed error messages to help with debugging. */ @@ -37,7 +37,7 @@ class MySQLException : public std::runtime_error { public: /** * @brief Construct a new MySQL Exception object - * + * * @param message Error message describing the exception */ explicit MySQLException(const std::string& message) @@ -46,7 +46,7 @@ class MySQLException : public std::runtime_error { /** * @brief Structure to hold database connection parameters - * + * * This structure encapsulates all the necessary parameters needed * to establish a connection to a MySQL/MariaDB database. */ @@ -67,7 +67,7 @@ struct ConnectionParams { /** * @brief Enum for transaction isolation levels - * + * * Defines the different isolation levels available for database transactions, * controlling how transactions interact with each other. */ @@ -80,7 +80,7 @@ enum class TransactionIsolation { /** * @brief Class representing a database row - * + * * This class provides methods to access field values in different data types * from a single row of a MySQL result set. */ @@ -88,7 +88,7 @@ class Row { public: /** * @brief Construct a new Row object - * + * * @param row MySQL row data * @param lengths Array of field lengths * @param numFields Number of fields in the row @@ -97,7 +97,7 @@ class Row { /** * @brief Get a string value from the specified field - * + * * @param index Field index (0-based) * @return std::string Field value as string, empty if null or invalid index */ @@ -105,7 +105,7 @@ class Row { /** * @brief Get an integer value from the specified field - * + * * @param index Field index (0-based) * @return int Field value as integer, 0 if null or invalid index */ @@ -113,7 +113,7 @@ class Row { /** * @brief Get a 64-bit integer value from the specified field - * + * * @param index Field index (0-based) * @return int64_t Field value as 64-bit integer, 0 if null or invalid index */ @@ -121,7 +121,7 @@ class Row { /** * @brief Get a double value from the specified field - * + * * @param index Field index (0-based) * @return double Field value as double, 0.0 if null or invalid index */ @@ -129,7 +129,7 @@ class Row { /** * @brief Get a boolean value from the specified field - * + * * @param index Field index (0-based) * @return bool Field value as boolean, false if null or invalid index */ @@ -137,7 +137,7 @@ class Row { /** * @brief Check if the specified field is null - * + * * @param index Field index (0-based) * @return true if field is null, false otherwise */ @@ -145,7 +145,7 @@ class Row { /** * @brief Get the number of fields in this row - * + * * @return unsigned int Number of fields */ unsigned int getFieldCount() const { return numFields; } @@ -159,7 +159,7 @@ class Row { /** * @class ResultSet * @brief Represents the result of a MySQL query - * + * * This class wraps the MYSQL_RES structure and provides methods to navigate * through the result set, retrieve field values, field names, count rows and * columns. It implements iterator support for modern C++ iteration patterns. @@ -172,14 +172,14 @@ class ResultSet { public: /** * @brief Construct a new ResultSet object - * + * * @param result MySQL result set pointer */ explicit ResultSet(MYSQL_RES* result); /** * @brief Destroy the ResultSet object - * + * * Automatically frees the MySQL result set. */ ~ResultSet(); @@ -189,14 +189,14 @@ class ResultSet { /** * @brief Move constructor - * + * * @param other Source ResultSet to move from */ ResultSet(ResultSet&& other) noexcept; /** * @brief Move assignment operator - * + * * @param other Source ResultSet to move from * @return ResultSet& Reference to this object */ @@ -204,14 +204,14 @@ class ResultSet { /** * @brief Move to the next row in the result set - * + * * @return true if there is a next row, false if end of result set */ bool next(); /** * @brief Get the current row - * + * * @return Row Current row object * @throws std::runtime_error if no current row */ @@ -219,14 +219,14 @@ class ResultSet { /** * @brief Get the number of fields in the result set - * + * * @return unsigned int Number of fields */ unsigned int getFieldCount() const; /** * @brief Get the name of a field by index - * + * * @param index Field index (0-based) * @return std::string Field name, empty if invalid index */ @@ -234,14 +234,14 @@ class ResultSet { /** * @brief Get the total number of rows in the result set - * + * * @return unsigned long long Number of rows */ unsigned long long getRowCount() const; /** * @brief Reset the result set to the beginning - * + * * @return true if successful, false otherwise */ bool reset(); @@ -274,7 +274,7 @@ class ResultSet { /** * @brief Get iterator to the beginning of the result set - * + * * @return iterator Iterator to the first row */ iterator begin() { @@ -289,7 +289,7 @@ class ResultSet { /** * @brief Get iterator to the end of the result set - * + * * @return iterator Iterator representing end */ iterator end() { return iterator(this, true); } @@ -304,7 +304,7 @@ class ResultSet { /** * @brief Class for prepared statements - * + * * This class provides a safe way to execute SQL statements with parameters, * preventing SQL injection attacks and improving performance for repeated * queries. @@ -313,7 +313,7 @@ class PreparedStatement { public: /** * @brief Construct a new PreparedStatement object - * + * * @param connection MySQL connection handle * @param query SQL query with parameter placeholders (?) * @throws MySQLException if statement preparation fails @@ -322,7 +322,7 @@ class PreparedStatement { /** * @brief Destroy the PreparedStatement object - * + * * Automatically closes the MySQL statement. */ ~PreparedStatement(); @@ -332,14 +332,14 @@ class PreparedStatement { /** * @brief Move constructor - * + * * @param other Source PreparedStatement to move from */ PreparedStatement(PreparedStatement&& other) noexcept; /** * @brief Move assignment operator - * + * * @param other Source PreparedStatement to move from * @return PreparedStatement& Reference to this object */ @@ -347,7 +347,7 @@ class PreparedStatement { /** * @brief Bind a string parameter - * + * * @param index Parameter index (0-based) * @param value String value to bind * @return PreparedStatement& Reference to this object for method chaining @@ -356,7 +356,7 @@ class PreparedStatement { /** * @brief Bind an integer parameter - * + * * @param index Parameter index (0-based) * @param value Integer value to bind * @return PreparedStatement& Reference to this object for method chaining @@ -365,7 +365,7 @@ class PreparedStatement { /** * @brief Bind a 64-bit integer parameter - * + * * @param index Parameter index (0-based) * @param value 64-bit integer value to bind * @return PreparedStatement& Reference to this object for method chaining @@ -374,7 +374,7 @@ class PreparedStatement { /** * @brief Bind a double parameter - * + * * @param index Parameter index (0-based) * @param value Double value to bind * @return PreparedStatement& Reference to this object for method chaining @@ -383,7 +383,7 @@ class PreparedStatement { /** * @brief Bind a boolean parameter - * + * * @param index Parameter index (0-based) * @param value Boolean value to bind * @return PreparedStatement& Reference to this object for method chaining @@ -392,7 +392,7 @@ class PreparedStatement { /** * @brief Bind a null parameter - * + * * @param index Parameter index (0-based) * @return PreparedStatement& Reference to this object for method chaining */ @@ -400,14 +400,14 @@ class PreparedStatement { /** * @brief Execute the prepared statement - * + * * @return true if execution was successful, false otherwise */ bool execute(); /** * @brief Execute the prepared statement and return results - * + * * @return std::unique_ptr Result set containing query results * @throws MySQLException if execution fails */ @@ -415,7 +415,7 @@ class PreparedStatement { /** * @brief Execute an update/insert/delete statement - * + * * @return int Number of affected rows * @throws MySQLException if execution fails */ @@ -423,7 +423,7 @@ class PreparedStatement { /** * @brief Reset the statement for reuse - * + * * @throws MySQLException if reset fails */ void reset(); @@ -435,7 +435,7 @@ class PreparedStatement { /** * @brief Get the number of parameters in the statement - * + * * @return unsigned int Number of parameters */ unsigned int getParameterCount() const; @@ -451,7 +451,7 @@ class PreparedStatement { /** * @class MysqlDB * @brief Enhanced class for interacting with a MySQL/MariaDB database - * + * * This class provides a comprehensive interface for MySQL database operations * including connection management, query execution, transaction handling, * prepared statements, and error management. It is thread-safe and supports @@ -461,7 +461,7 @@ class MysqlDB { public: /** * @brief Constructor with connection parameters structure - * + * * @param params Connection parameters * @throws MySQLException if connection fails */ @@ -469,7 +469,7 @@ class MysqlDB { /** * @brief Constructor with individual connection parameters - * + * * @param host Database server hostname or IP * @param user Database username * @param password Database password @@ -494,14 +494,14 @@ class MysqlDB { /** * @brief Move constructor - * + * * @param other Source MysqlDB to move from */ MysqlDB(MysqlDB&& other) noexcept; /** * @brief Move assignment operator - * + * * @param other Source MysqlDB to move from * @return MysqlDB& Reference to this object */ @@ -509,14 +509,14 @@ class MysqlDB { /** * @brief Connect to the database with stored parameters - * + * * @return true if connection successful, false otherwise */ bool connect(); /** * @brief Reconnect to the database if connection was lost - * + * * @return true if reconnection successful, false otherwise */ bool reconnect(); @@ -528,14 +528,14 @@ class MysqlDB { /** * @brief Check if the connection is alive - * + * * @return true if connected, false otherwise */ bool isConnected(); /** * @brief Execute a SQL query without returning results - * + * * @param query SQL query string * @return true if execution successful, false otherwise */ @@ -543,7 +543,7 @@ class MysqlDB { /** * @brief Execute a query and return results - * + * * @param query SQL SELECT query string * @return std::unique_ptr Result set containing query results * @throws MySQLException if execution fails @@ -552,7 +552,7 @@ class MysqlDB { /** * @brief Execute a data modification query and return affected rows - * + * * @param query SQL INSERT/UPDATE/DELETE query * @return int Number of affected rows, -1 if error * @throws MySQLException if execution fails @@ -561,7 +561,7 @@ class MysqlDB { /** * @brief Get a single integer value from a query - * + * * @param query SQL query that returns a single integer * @return std::optional Integer value if successful, nullopt otherwise */ @@ -569,7 +569,7 @@ class MysqlDB { /** * @brief Get a single double value from a query - * + * * @param query SQL query that returns a single double * @return std::optional Double value if successful, nullopt otherwise */ @@ -577,7 +577,7 @@ class MysqlDB { /** * @brief Get a single string value from a query - * + * * @param query SQL query that returns a single string * @return std::optional String value if successful, nullopt otherwise */ @@ -585,7 +585,7 @@ class MysqlDB { /** * @brief Search for data matching criteria - * + * * @param query Base SQL query * @param column Column name to search in * @param searchTerm Term to search for @@ -596,7 +596,7 @@ class MysqlDB { /** * @brief Create a prepared statement for safe query execution - * + * * @param query SQL query with parameter placeholders (?) * @return std::unique_ptr Prepared statement object * @throws MySQLException if preparation fails @@ -605,28 +605,28 @@ class MysqlDB { /** * @brief Begin a database transaction - * + * * @return true if transaction started successfully, false otherwise */ bool beginTransaction(); /** * @brief Commit the current transaction - * + * * @return true if transaction committed successfully, false otherwise */ bool commitTransaction(); /** * @brief Rollback the current transaction - * + * * @return true if transaction rolled back successfully, false otherwise */ bool rollbackTransaction(); /** * @brief Set a savepoint within a transaction - * + * * @param savepointName Name of the savepoint * @return true if savepoint created successfully, false otherwise */ @@ -634,7 +634,7 @@ class MysqlDB { /** * @brief Rollback to a specific savepoint - * + * * @param savepointName Name of the savepoint * @return true if rollback successful, false otherwise */ @@ -642,7 +642,7 @@ class MysqlDB { /** * @brief Set transaction isolation level - * + * * @param level Isolation level to set * @return true if isolation level set successfully, false otherwise */ @@ -650,7 +650,7 @@ class MysqlDB { /** * @brief Execute multiple queries in sequence - * + * * @param queries Vector of SQL queries to execute * @return true if all queries executed successfully, false otherwise */ @@ -658,7 +658,7 @@ class MysqlDB { /** * @brief Execute multiple queries within a transaction - * + * * @param queries Vector of SQL queries to execute * @return true if all queries executed successfully, false if any failed (transaction rolled back) */ @@ -666,7 +666,7 @@ class MysqlDB { /** * @brief Execute operations within a transaction with automatic rollback - * + * * @param operations Function containing database operations to execute * @throws Re-throws any exceptions from operations after rollback */ @@ -674,7 +674,7 @@ class MysqlDB { /** * @brief Call a stored procedure - * + * * @param procedureName Name of the stored procedure * @param params Vector of parameters for the procedure * @return std::unique_ptr Result set if procedure returns data @@ -685,7 +685,7 @@ class MysqlDB { /** * @brief Get list of databases on the server - * + * * @return std::vector Vector of database names * @throws MySQLException if query fails */ @@ -693,7 +693,7 @@ class MysqlDB { /** * @brief Get list of tables in the current database - * + * * @return std::vector Vector of table names * @throws MySQLException if query fails */ @@ -701,7 +701,7 @@ class MysqlDB { /** * @brief Get list of columns for a specific table - * + * * @param tableName Name of the table * @return std::vector Vector of column names * @throws MySQLException if query fails @@ -710,7 +710,7 @@ class MysqlDB { /** * @brief Check if a table exists in the database - * + * * @param tableName Name of the table to check * @return true if table exists, false otherwise */ @@ -718,21 +718,21 @@ class MysqlDB { /** * @brief Get the last error message - * + * * @return std::string Error message */ std::string getLastError() const; /** * @brief Get the last error code - * + * * @return unsigned int Error code */ unsigned int getLastErrorCode() const; /** * @brief Set a custom error callback function - * + * * @param callback Function to call when errors occur */ void setErrorCallback( @@ -740,7 +740,7 @@ class MysqlDB { /** * @brief Escape a string for safe use in SQL queries - * + * * @param str String to escape * @return std::string Escaped string * @throws MySQLException if not connected @@ -749,21 +749,21 @@ class MysqlDB { /** * @brief Get the ID of the last inserted row - * + * * @return unsigned long long Last insert ID */ unsigned long long getLastInsertId() const; /** * @brief Get the number of rows affected by the last statement - * + * * @return unsigned long long Number of affected rows */ unsigned long long getAffectedRows() const; /** * @brief Execute a query with pagination - * + * * @param query Base SQL SELECT query * @param limit Maximum number of rows to return * @param offset Number of rows to skip @@ -775,28 +775,28 @@ class MysqlDB { /** * @brief Get database server version - * + * * @return std::string Server version string */ std::string getServerVersion() const; /** * @brief Get client library version - * + * * @return std::string Client library version string */ std::string getClientVersion() const; /** * @brief Ping the server to check connection - * + * * @return true if connection is alive, false otherwise */ bool ping(); /** * @brief Set connection timeout - * + * * @param timeout Timeout in seconds * @return true if timeout set successfully, false otherwise */ @@ -811,7 +811,7 @@ class MysqlDB { /** * @brief Handle database errors - * + * * @param operation Description of the operation that failed * @param throwOnError Whether to throw exception on error * @return true if error occurred, false otherwise @@ -827,4 +827,4 @@ class MysqlDB { } // namespace database } // namespace atom -#endif // ATOM_SEARCH_MYSQL_HPP \ No newline at end of file +#endif // ATOM_SEARCH_MYSQL_HPP diff --git a/atom/search/search.cpp b/atom/search/search.cpp index a8b09afe..18a2d6b6 100644 --- a/atom/search/search.cpp +++ b/atom/search/search.cpp @@ -1177,4 +1177,4 @@ std::vector> SearchEngine::getRankedResults( return results; } -} // namespace atom::search \ No newline at end of file +} // namespace atom::search diff --git a/atom/search/sqlite.cpp b/atom/search/sqlite.cpp index f5ccd179..882bc1da 100644 --- a/atom/search/sqlite.cpp +++ b/atom/search/sqlite.cpp @@ -859,4 +859,4 @@ bool SqliteDB::analyze() { template std::optional SqliteDB::getSingleValue( std::string_view query, int (*columnFunc)(sqlite3_stmt*, int)); template std::optional SqliteDB::getSingleValue( - std::string_view query, double (*columnFunc)(sqlite3_stmt*, int)); \ No newline at end of file + std::string_view query, double (*columnFunc)(sqlite3_stmt*, int)); diff --git a/atom/search/sqlite.hpp b/atom/search/sqlite.hpp index 108d4a84..6ede9857 100644 --- a/atom/search/sqlite.hpp +++ b/atom/search/sqlite.hpp @@ -24,7 +24,7 @@ using atom::containers::Vector; /** * @brief Custom exception class for SQLite operations - * + * * This exception is thrown when SQLite operations fail or encounter errors. * It provides detailed error messages to help with debugging. */ @@ -35,14 +35,14 @@ class SQLiteException : public std::exception { public: /** * @brief Construct a new SQLite Exception object - * + * * @param msg Error message describing the exception */ explicit SQLiteException(std::string_view msg) : message(msg) {} - + /** * @brief Get the exception message - * + * * @return const char* Null-terminated error message string */ [[nodiscard]] const char* what() const noexcept override { @@ -53,7 +53,7 @@ class SQLiteException : public std::exception { /** * @class SqliteDB * @brief A thread-safe SQLite database wrapper with advanced features - * + * * This class provides a high-level interface for SQLite database operations * including prepared statement caching, transaction management, and thread safety. * It uses the Pimpl design pattern for implementation hiding and better @@ -73,7 +73,7 @@ class SqliteDB { /** * @brief Construct a new SqliteDB object - * + * * @param dbPath Path to the SQLite database file * @throws SQLiteException if the database cannot be opened */ @@ -81,7 +81,7 @@ class SqliteDB { /** * @brief Destroy the SqliteDB object - * + * * Automatically closes the database connection and cleans up resources. */ ~SqliteDB(); @@ -91,14 +91,14 @@ class SqliteDB { /** * @brief Move constructor - * + * * @param other Source object to move from */ SqliteDB(SqliteDB&& other) noexcept; /** * @brief Move assignment operator - * + * * @param other Source object to move from * @return SqliteDB& Reference to this object */ @@ -106,7 +106,7 @@ class SqliteDB { /** * @brief Execute a simple SQL query without parameters - * + * * @param query SQL query string to execute * @return true if execution was successful * @throws SQLiteException on execution error @@ -115,10 +115,10 @@ class SqliteDB { /** * @brief Execute a parameterized SQL query with bound values - * + * * This method uses prepared statements for security and performance. * Parameters are automatically bound based on their types. - * + * * @tparam Args Parameter types to bind * @param query SQL query with placeholders (?) * @param params Parameters to bind to the query @@ -131,7 +131,7 @@ class SqliteDB { /** * @brief Execute a SELECT query and return all results - * + * * @param query SQL SELECT query string * @return ResultSet containing all rows from the query * @throws SQLiteException on query error @@ -140,7 +140,7 @@ class SqliteDB { /** * @brief Execute a parameterized SELECT query and return results - * + * * @tparam Args Parameter types to bind * @param query SQL SELECT query with placeholders * @param params Parameters to bind to the query @@ -153,7 +153,7 @@ class SqliteDB { /** * @brief Helper function to retrieve a single value of any type - * + * * @tparam T Type of value to retrieve * @param query SQL query that returns a single value * @param columnFunc Function to extract value from SQLite column @@ -165,7 +165,7 @@ class SqliteDB { /** * @brief Retrieve a single integer value from a query - * + * * @param query SQL query that returns a single integer * @return Optional integer value */ @@ -173,7 +173,7 @@ class SqliteDB { /** * @brief Retrieve a single floating-point value from a query - * + * * @param query SQL query that returns a single double * @return Optional double value */ @@ -181,7 +181,7 @@ class SqliteDB { /** * @brief Retrieve a single text value from a query - * + * * @param query SQL query that returns a single text value * @return Optional String value */ @@ -189,7 +189,7 @@ class SqliteDB { /** * @brief Search for data matching a specific term - * + * * @param query SQL query with a single parameter placeholder * @param searchTerm Term to search for * @return true if matching data was found @@ -199,7 +199,7 @@ class SqliteDB { /** * @brief Execute an UPDATE statement and return affected row count - * + * * @param query SQL UPDATE statement * @return Number of rows affected by the update * @throws SQLiteException on update error @@ -208,7 +208,7 @@ class SqliteDB { /** * @brief Execute a DELETE statement and return affected row count - * + * * @param query SQL DELETE statement * @return Number of rows affected by the delete * @throws SQLiteException on delete error @@ -217,23 +217,23 @@ class SqliteDB { /** * @brief Begin a database transaction - * + * * Uses IMMEDIATE transaction mode for better concurrency control. - * + * * @throws SQLiteException if transaction cannot be started */ void beginTransaction(); /** * @brief Commit the current transaction - * + * * @throws SQLiteException if transaction cannot be committed */ void commitTransaction(); /** * @brief Rollback the current transaction - * + * * This method does not throw exceptions to ensure it can be safely * called from destructors and error handlers. */ @@ -241,10 +241,10 @@ class SqliteDB { /** * @brief Execute operations within a transaction with automatic rollback - * + * * Automatically begins a transaction, executes the provided operations, * and commits. If any exception occurs, the transaction is rolled back. - * + * * @param operations Function containing database operations to execute * @throws Re-throws any exceptions from operations after rollback */ @@ -252,10 +252,10 @@ class SqliteDB { /** * @brief Validate data using a validation query - * + * * Executes the main query, then runs a validation query to check * if the operation was successful. - * + * * @param query Main SQL query to execute * @param validationQuery Query that should return non-zero for success * @return true if validation passes @@ -265,7 +265,7 @@ class SqliteDB { /** * @brief Execute a SELECT query with pagination - * + * * @param query Base SQL SELECT query (without LIMIT/OFFSET) * @param limit Maximum number of rows to return * @param offset Number of rows to skip @@ -277,7 +277,7 @@ class SqliteDB { /** * @brief Set a custom error message callback - * + * * @param errorCallback Function to call when errors occur */ void setErrorMessageCallback( @@ -285,14 +285,14 @@ class SqliteDB { /** * @brief Check if the database connection is active - * + * * @return true if connected to a database */ [[nodiscard]] bool isConnected() const noexcept; /** * @brief Get the rowid of the last inserted row - * + * * @return Row ID of the last insert operation * @throws SQLiteException if not connected */ @@ -300,7 +300,7 @@ class SqliteDB { /** * @brief Get the number of rows modified by the last statement - * + * * @return Number of rows affected by the last INSERT/UPDATE/DELETE * @throws SQLiteException if not connected */ @@ -308,7 +308,7 @@ class SqliteDB { /** * @brief Get the total number of rows modified since database opened - * + * * @return Total number of rows modified * @throws SQLiteException if not connected */ @@ -316,7 +316,7 @@ class SqliteDB { /** * @brief Check if a table exists in the database - * + * * @param tableName Name of the table to check * @return true if the table exists */ @@ -324,7 +324,7 @@ class SqliteDB { /** * @brief Get the schema information for a table - * + * * @param tableName Name of the table * @return ResultSet containing column information */ @@ -332,14 +332,14 @@ class SqliteDB { /** * @brief Execute VACUUM command to optimize database - * + * * @return true if VACUUM was successful */ [[nodiscard]] bool vacuum(); /** * @brief Execute ANALYZE command to update query planner statistics - * + * * @return true if ANALYZE was successful */ [[nodiscard]] bool analyze(); @@ -351,7 +351,7 @@ class SqliteDB { /** * @brief Validate query string for basic security checks - * + * * @param query Query string to validate * @throws SQLiteException if query is invalid */ @@ -359,14 +359,14 @@ class SqliteDB { /** * @brief Check database connection before operations - * + * * @throws SQLiteException if database is not connected */ void checkConnection() const; /** * @brief Helper for update/delete operations - * + * * @param query SQL statement to execute * @return Number of rows affected * @throws SQLiteException on error @@ -378,4 +378,4 @@ class SqliteDB { #endif }; -#endif // ATOM_SEARCH_SQLITE_HPP \ No newline at end of file +#endif // ATOM_SEARCH_SQLITE_HPP diff --git a/atom/search/ttl.hpp b/atom/search/ttl.hpp index cbfa6bfa..22a1c931 100644 --- a/atom/search/ttl.hpp +++ b/atom/search/ttl.hpp @@ -41,25 +41,25 @@ namespace atom::search { #if defined(ATOM_USE_BOOST_THREAD) template using SharedMutex = boost::shared_mutex; - + template using SharedLock = boost::shared_lock; - + template using UniqueLock = boost::unique_lock; - + using CondVarAny = boost::condition_variable_any; using Thread = boost::thread; #else template using SharedMutex = std::shared_mutex; - + template using SharedLock = std::shared_lock; - + template using UniqueLock = std::unique_lock; - + using CondVarAny = std::condition_variable_any; using Thread = std::thread; #endif @@ -119,7 +119,7 @@ struct CacheConfig { * @tparam Hash The hash function type for keys (defaults to std::hash). * @tparam KeyEqual The key equality comparison type (defaults to std::equal_to). */ -template , typename KeyEqual = std::equal_to> class TTLCache { @@ -142,7 +142,7 @@ class TTLCache { * @param eviction_callback Optional callback for eviction events. * @throws TTLCacheException if ttl <= 0 or max_capacity == 0 */ - explicit TTLCache(Duration ttl, + explicit TTLCache(Duration ttl, size_t max_capacity, std::optional cleanup_interval = std::nullopt, CacheConfig config = CacheConfig{}, @@ -175,7 +175,7 @@ class TTLCache { * @throws std::bad_alloc if memory allocation fails * @throws TTLCacheException for other internal errors */ - void put(const Key& key, const Value& value, + void put(const Key& key, const Value& value, std::optional custom_ttl = std::nullopt); /** @@ -239,7 +239,7 @@ class TTLCache { * @param update_access_time Whether to update access times (default: true). * @return Vector of optional values corresponding to the keys. */ - [[nodiscard]] ValueContainer batch_get(const KeyContainer& keys, + [[nodiscard]] ValueContainer batch_get(const KeyContainer& keys, bool update_access_time = true); /** @@ -410,7 +410,7 @@ class TTLCache { ValuePtr value; TimePoint expiry_time; TimePoint access_time; - + CacheItem(const Key& k, const Value& v, const TimePoint& expiry, const TimePoint& access); CacheItem(const Key& k, Value&& v, const TimePoint& expiry, const TimePoint& access); template @@ -430,7 +430,7 @@ class TTLCache { CacheMap cache_map_; mutable SharedMutex mutex_; - + Atomic hit_count_{0}; Atomic miss_count_{0}; Atomic eviction_count_{0}; @@ -459,7 +459,7 @@ TTLCache::TTLCache( max_capacity_(max_capacity), config_(std::move(config)), eviction_callback_(std::move(eviction_callback)) { - + if (ttl <= Duration::zero()) { throw TTLCacheException("TTL must be greater than zero"); } @@ -499,7 +499,7 @@ TTLCache::TTLCache(TTLCache&& other) noexcept miss_count_(other.miss_count_.load()), eviction_count_(other.eviction_count_.load()), expiration_count_(other.expiration_count_.load()) { - + UniqueLock lock(other.mutex_); cache_list_ = std::move(other.cache_list_); cache_map_ = std::move(other.cache_map_); @@ -517,7 +517,7 @@ TTLCache::TTLCache(TTLCache&& other) noexcept } template -TTLCache& +TTLCache& TTLCache::operator=(TTLCache&& other) noexcept { if (this != &other) { stop_flag_ = true; @@ -559,7 +559,7 @@ TTLCache::operator=(TTLCache&& other) noexcept { template void TTLCache::put( const Key& key, const Value& value, std::optional custom_ttl) { - + try { UniqueLock lock(mutex_); auto now = Clock::now(); @@ -587,7 +587,7 @@ void TTLCache::put( template void TTLCache::put( const Key& key, Value&& value, std::optional custom_ttl) { - + try { UniqueLock lock(mutex_); auto now = Clock::now(); @@ -616,7 +616,7 @@ template template void TTLCache::emplace( const Key& key, std::optional custom_ttl, Args&&... args) { - + try { UniqueLock lock(mutex_); auto now = Clock::now(); @@ -645,7 +645,7 @@ template void TTLCache::batch_put( const std::vector>& items, std::optional custom_ttl) { - + if (items.empty()) return; try { @@ -657,7 +657,7 @@ void TTLCache::batch_put( for (const auto& [key, value] : items) { auto expiry = now + ttl_to_use; - + auto it = cache_map_.find(key); if (it != cache_map_.end()) { notify_eviction(it->second->key, *(it->second->value), false); @@ -680,7 +680,7 @@ void TTLCache::batch_put( template std::optional TTLCache::get( const Key& key, bool update_access_time) { - + try { if (config_.thread_safe) { SharedLock lock(mutex_); @@ -698,9 +698,9 @@ std::optional TTLCache::get( } template -typename TTLCache::ValuePtr +typename TTLCache::ValuePtr TTLCache::get_shared(const Key& key, bool update_access_time) { - + try { if (config_.thread_safe) { SharedLock lock(mutex_); @@ -721,7 +721,7 @@ template typename TTLCache::ValueContainer TTLCache::batch_get( const KeyContainer& keys, bool update_access_time) { - + if (keys.empty()) return {}; ValueContainer results; @@ -735,12 +735,12 @@ TTLCache::batch_get( auto it = cache_map_.find(key); if (it != cache_map_.end() && !is_expired(it->second->expiry_time)) { if (config_.enable_statistics) hit_count_++; - + if (update_access_time) { it->second->access_time = now; move_to_front(it->second); } - + results.emplace_back(*(it->second->value)); } else { if (config_.enable_statistics) miss_count_++; @@ -761,7 +761,7 @@ template template Value TTLCache::get_or_compute( const Key& key, Factory&& factory, std::optional custom_ttl) { - + auto cached_value = get_shared(key); if (cached_value) { return *cached_value; @@ -880,7 +880,7 @@ CacheStatistics TTLCache::get_statistics() const noe stats.expirations = expiration_count_.load(); stats.current_size = cache_map_.size(); stats.max_capacity = max_capacity_; - + size_t total = stats.hits + stats.misses; stats.hit_rate = total > 0 ? static_cast(stats.hits) / total : 0.0; } catch (...) { @@ -901,7 +901,7 @@ void TTLCache::reset_statistics() noexcept { template double TTLCache::hit_rate() const noexcept { if (!config_.enable_statistics) return 0.0; - + size_t hits = hit_count_.load(); size_t misses = miss_count_.load(); size_t total = hits + misses; @@ -931,7 +931,7 @@ TTLCache::get_keys() const { SharedLock lock(mutex_); auto now = Clock::now(); keys.reserve(cache_map_.size()); - + for (const auto& [key, iter] : cache_map_) { if (!is_expired(iter->expiry_time)) { keys.push_back(key); @@ -946,16 +946,16 @@ template void TTLCache::clear() noexcept { try { UniqueLock lock(mutex_); - + if (eviction_callback_) { for (const auto& item : cache_list_) { notify_eviction(item.key, *(item.value), false); } } - + cache_list_.clear(); cache_map_.clear(); - + if (config_.enable_statistics) { hit_count_ = 0; miss_count_ = 0; @@ -1038,7 +1038,7 @@ template template TTLCache::CacheItem::CacheItem( const Key& k, const TimePoint& expiry, const TimePoint& access, Args&&... args) - : key(k), value(std::make_shared(std::forward(args)...)), + : key(k), value(std::make_shared(std::forward(args)...)), expiry_time(expiry), access_time(access) {} template @@ -1062,7 +1062,7 @@ void TTLCache::cleaner_task() noexcept { template void TTLCache::evict_items( UniqueLock& lock, size_t count) noexcept { - + try { auto now = Clock::now(); size_t expired_removed = 0; @@ -1080,7 +1080,7 @@ void TTLCache::evict_items( cache_map_.erase(key); --count; ++expired_removed; - + if (config_.enable_statistics) { expiration_count_++; } @@ -1095,7 +1095,7 @@ void TTLCache::evict_items( cache_map_.erase(last.key); cache_list_.pop_back(); --count; - + if (config_.enable_statistics) { eviction_count_++; } @@ -1130,11 +1130,11 @@ inline bool TTLCache::is_expired(const TimePoint& ex template void TTLCache::cleanup_expired_items( UniqueLock& lock) noexcept { - + try { auto now = Clock::now(); size_t batch_count = 0; - + auto it = cache_list_.begin(); while (it != cache_list_.end() && batch_count < config_.cleanup_batch_size) { if (is_expired(it->expiry_time)) { @@ -1142,10 +1142,10 @@ void TTLCache::cleanup_expired_items( auto value = it->value; it = cache_list_.erase(it); cache_map_.erase(key); - + notify_eviction(key, *value, true); ++batch_count; - + if (config_.enable_statistics) { expiration_count_++; } @@ -1159,4 +1159,4 @@ void TTLCache::cleanup_expired_items( } // namespace atom::search -#endif // ATOM_SEARCH_TTL_CACHE_HPP \ No newline at end of file +#endif // ATOM_SEARCH_TTL_CACHE_HPP diff --git a/atom/search/xmake.lua b/atom/search/xmake.lua index c3a39f3c..e9a7d55b 100644 --- a/atom/search/xmake.lua +++ b/atom/search/xmake.lua @@ -15,25 +15,25 @@ set_license("GPL3") -- Object Library target("atom-search-object") set_kind("object") - + -- Add source files add_files("*.cpp") - + -- Add header files add_headerfiles("*.hpp") - + -- Add dependencies add_packages("loguru") - + -- Add include directories add_includedirs(".", {public = true}) add_includedirs("..", {public = true}) - + -- Platform-specific settings if is_plat("linux") then add_syslinks("pthread") end - + -- Set C++ standard set_languages("c++20") target_end() @@ -42,20 +42,20 @@ target_end() target("atom-search") -- Set library type based on parent project option set_kind(has_config("shared_libs") and "shared" or "static") - + -- Add dependencies add_deps("atom-search-object") add_packages("loguru") - + -- Platform-specific settings if is_plat("linux") then add_syslinks("pthread") end - + -- Set output directories set_targetdir("$(buildir)/lib") set_objectdir("$(buildir)/obj") - + -- Install configuration on_install(function (target) os.cp(target:targetfile(), path.join(target:installdir(), "lib")) diff --git a/atom/secret/CMakeLists.txt b/atom/secret/CMakeLists.txt index e11ab9c7..d09b95a7 100644 --- a/atom/secret/CMakeLists.txt +++ b/atom/secret/CMakeLists.txt @@ -59,4 +59,4 @@ install(TARGETS ${PROJECT_NAME} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} PUBLIC_HEADER DESTINATION include/${PROJECT_NAME} -) \ No newline at end of file +) diff --git a/atom/secret/common.hpp b/atom/secret/common.hpp index 88a830f6..bca06b35 100644 --- a/atom/secret/common.hpp +++ b/atom/secret/common.hpp @@ -71,4 +71,4 @@ struct PreviousPassword { } // namespace atom::secret -#endif // ATOM_SECRET_COMMON_HPP \ No newline at end of file +#endif // ATOM_SECRET_COMMON_HPP diff --git a/atom/secret/encryption.cpp b/atom/secret/encryption.cpp index 4693fc9b..859852ee 100644 --- a/atom/secret/encryption.cpp +++ b/atom/secret/encryption.cpp @@ -37,4 +37,4 @@ SslCipherContext& SslCipherContext::operator=( return *this; } -} // namespace atom::secret \ No newline at end of file +} // namespace atom::secret diff --git a/atom/secret/encryption.hpp b/atom/secret/encryption.hpp index 166b16dd..93d1dfde 100644 --- a/atom/secret/encryption.hpp +++ b/atom/secret/encryption.hpp @@ -51,4 +51,4 @@ class SslCipherContext { } // namespace atom::secret -#endif // ATOM_SECRET_ENCRYPTION_HPP \ No newline at end of file +#endif // ATOM_SECRET_ENCRYPTION_HPP diff --git a/atom/secret/password_entry.hpp b/atom/secret/password_entry.hpp index 0ab685ad..0134b859 100644 --- a/atom/secret/password_entry.hpp +++ b/atom/secret/password_entry.hpp @@ -47,4 +47,4 @@ namespace atom::secret { } // namespace atom::secret -#endif // ATOM_SECRET_PASSWORD_ENTRY_HPP \ No newline at end of file +#endif // ATOM_SECRET_PASSWORD_ENTRY_HPP diff --git a/atom/secret/result.hpp b/atom/secret/result.hpp index cc79700b..92e6a4b7 100644 --- a/atom/secret/result.hpp +++ b/atom/secret/result.hpp @@ -91,4 +91,4 @@ class Result { } // namespace atom::secret -#endif // ATOM_SECRET_RESULT_HPP \ No newline at end of file +#endif // ATOM_SECRET_RESULT_HPP diff --git a/atom/secret/storage.cpp b/atom/secret/storage.cpp index 8934223a..1837e260 100644 --- a/atom/secret/storage.cpp +++ b/atom/secret/storage.cpp @@ -893,4 +893,4 @@ std::unique_ptr SecureStorage::create(std::string_view appName) { #endif } -} // namespace atom::secret \ No newline at end of file +} // namespace atom::secret diff --git a/atom/secret/storage.hpp b/atom/secret/storage.hpp index 3a628e55..9cbae8e4 100644 --- a/atom/secret/storage.hpp +++ b/atom/secret/storage.hpp @@ -54,4 +54,4 @@ class SecureStorage { } // namespace atom::secret -#endif // ATOM_SECRET_STORAGE_HPP \ No newline at end of file +#endif // ATOM_SECRET_STORAGE_HPP diff --git a/atom/secret/xmake.lua b/atom/secret/xmake.lua index 8402c633..c78603a0 100644 --- a/atom/secret/xmake.lua +++ b/atom/secret/xmake.lua @@ -29,19 +29,19 @@ local header_files = { -- Object Library target("atom-secret-object") set_kind("object") - + -- Add files add_files(table.unpack(source_files)) add_headerfiles(table.unpack(header_files)) - + -- Add dependencies add_packages("loguru") add_deps("atom-utils") - + -- Add include directories add_includedirs(".", {public = true}) add_includedirs("..", {public = true}) - + -- Platform-specific settings if is_plat("windows") then add_syslinks("crypt32", "advapi32") @@ -50,7 +50,7 @@ target("atom-secret-object") elseif is_plat("macosx") then add_frameworks("Security") end - + -- Set C++ standard set_languages("c++20") target_end() @@ -59,11 +59,11 @@ target_end() target("atom-secret") -- Set library type based on parent project option set_kind(has_config("shared_libs") and "shared" or "static") - + -- Add dependencies add_deps("atom-secret-object", "atom-utils") add_packages("loguru") - + -- Platform-specific settings if is_plat("windows") then add_syslinks("crypt32", "advapi32") @@ -72,11 +72,11 @@ target("atom-secret") elseif is_plat("macosx") then add_frameworks("Security") end - + -- Set output directories set_targetdir("$(buildir)/lib") set_objectdir("$(buildir)/obj") - + -- Install configuration on_install(function (target) os.cp(target:targetfile(), path.join(target:installdir(), "lib")) diff --git a/atom/serial/CMakeLists.txt b/atom/serial/CMakeLists.txt index d63f6913..4060bffb 100644 --- a/atom/serial/CMakeLists.txt +++ b/atom/serial/CMakeLists.txt @@ -27,7 +27,7 @@ target_include_directories(${LIB_NAME} PUBLIC # Set platform-specific dependencies if(WIN32) - target_link_libraries(${LIB_NAME} + target_link_libraries(${LIB_NAME} PUBLIC atom-error atom-log @@ -37,7 +37,7 @@ if(WIN32) elseif(APPLE) find_library(IOKIT_FRAMEWORK IOKit REQUIRED) find_library(FOUNDATION_FRAMEWORK Foundation REQUIRED) - target_link_libraries(${LIB_NAME} + target_link_libraries(${LIB_NAME} PUBLIC atom-error atom-log @@ -48,13 +48,13 @@ else() # Linux/Unix find_package(PkgConfig REQUIRED) pkg_check_modules(UDEV REQUIRED libudev) pkg_check_modules(LIBUSB REQUIRED libusb-1.0) - + target_include_directories(${LIB_NAME} PUBLIC ${UDEV_INCLUDE_DIRS} ${LIBUSB_INCLUDE_DIRS} ) - - target_link_libraries(${LIB_NAME} + + target_link_libraries(${LIB_NAME} PUBLIC atom-error atom-log diff --git a/atom/serial/bluetooth_serial.cpp b/atom/serial/bluetooth_serial.cpp index 2349c1df..10c1a07d 100644 --- a/atom/serial/bluetooth_serial.cpp +++ b/atom/serial/bluetooth_serial.cpp @@ -117,4 +117,4 @@ BluetoothSerial::Statistics BluetoothSerial::getStatistics() const { return impl_->getStatistics(); } -} // namespace serial \ No newline at end of file +} // namespace serial diff --git a/atom/serial/bluetooth_serial.hpp b/atom/serial/bluetooth_serial.hpp index f7a01b4d..2c4b29c7 100644 --- a/atom/serial/bluetooth_serial.hpp +++ b/atom/serial/bluetooth_serial.hpp @@ -324,4 +324,4 @@ class BluetoothSerial { impl_; // PIMPL pattern for platform implementation }; -} // namespace serial \ No newline at end of file +} // namespace serial diff --git a/atom/serial/bluetooth_serial_mac.hpp b/atom/serial/bluetooth_serial_mac.hpp index 0bf46288..ee1b4731 100644 --- a/atom/serial/bluetooth_serial_mac.hpp +++ b/atom/serial/bluetooth_serial_mac.hpp @@ -257,4 +257,4 @@ class BluetoothSerialImpl { } // namespace serial -#endif // __APPLE__ \ No newline at end of file +#endif // __APPLE__ diff --git a/atom/serial/bluetooth_serial_mac.mm b/atom/serial/bluetooth_serial_mac.mm index 445ce9be..49e89c81 100644 --- a/atom/serial/bluetooth_serial_mac.mm +++ b/atom/serial/bluetooth_serial_mac.mm @@ -487,4 +487,4 @@ void stopAsyncWorker() { } // namespace serial -#endif // __APPLE__ \ No newline at end of file +#endif // __APPLE__ diff --git a/atom/serial/bluetooth_serial_unix.hpp b/atom/serial/bluetooth_serial_unix.hpp index 54d2a29f..97533b4b 100644 --- a/atom/serial/bluetooth_serial_unix.hpp +++ b/atom/serial/bluetooth_serial_unix.hpp @@ -882,4 +882,4 @@ class BluetoothSerialImpl { } // namespace serial -#endif // defined(__linux__) \ No newline at end of file +#endif // defined(__linux__) diff --git a/atom/serial/bluetooth_serial_win.hpp b/atom/serial/bluetooth_serial_win.hpp index 2a10aeb8..3d25ded7 100644 --- a/atom/serial/bluetooth_serial_win.hpp +++ b/atom/serial/bluetooth_serial_win.hpp @@ -638,4 +638,4 @@ class BluetoothSerialImpl { } // namespace serial -#endif // _WIN32 \ No newline at end of file +#endif // _WIN32 diff --git a/atom/serial/scanner.cpp b/atom/serial/scanner.cpp index 26e816f9..67193d6f 100644 --- a/atom/serial/scanner.cpp +++ b/atom/serial/scanner.cpp @@ -1269,7 +1269,7 @@ SerialPortScanner::get_port_details_linux(std::string_view port_name) { } catch (const std::exception& e) { if (config_.enable_debug_logging) { - spdlog::warn("Failed to get Linux port details for {}: {}", + spdlog::warn("Failed to get Linux port details for {}: {}", port_name, e.what()); } } diff --git a/atom/serial/serial_port.cpp b/atom/serial/serial_port.cpp index 925cd582..81004772 100644 --- a/atom/serial/serial_port.cpp +++ b/atom/serial/serial_port.cpp @@ -31,12 +31,12 @@ void SerialPort::open(std::string_view portName, const SerialConfig& config) { impl_->open(portName, config); } -void SerialPort::close() { - impl_->close(); +void SerialPort::close() { + impl_->close(); } -bool SerialPort::isOpen() const { - return impl_->isOpen(); +bool SerialPort::isOpen() const { + return impl_->isOpen(); } std::vector SerialPort::read(size_t maxBytes) { @@ -54,14 +54,14 @@ std::string SerialPort::readUntil(char terminator, std::chrono::milliseconds tim while (true) { const auto now = std::chrono::steady_clock::now(); const auto elapsed = std::chrono::duration_cast(now - startTime); - + if (elapsed >= timeout) { throw SerialTimeoutException("Waiting for terminator timed out"); } const auto remainingTime = timeout - elapsed; auto buffer = impl_->readExactly(1, remainingTime); - + if (buffer.empty()) { continue; } @@ -93,14 +93,14 @@ std::vector SerialPort::readUntilSequence(std::span sequ while (true) { const auto now = std::chrono::steady_clock::now(); const auto elapsed = std::chrono::duration_cast(now - startTime); - + if (elapsed >= timeout) { throw SerialTimeoutException("Waiting for termination sequence timed out"); } const auto remainingTime = timeout - elapsed; auto chunk = impl_->readExactly(1, remainingTime); - + if (chunk.empty()) { continue; } @@ -113,7 +113,7 @@ std::vector SerialPort::readUntilSequence(std::span sequ buffer.erase(buffer.begin()); } - if (buffer.size() == sequence.size() && + if (buffer.size() == sequence.size() && std::equal(buffer.begin(), buffer.end(), sequence.begin())) { if (!includeSequence) { result.erase(result.end() - static_cast(sequence.size()), result.end()); @@ -165,52 +165,52 @@ std::future SerialPort::asyncWrite(std::string_view data) { }); } -void SerialPort::flush() { - impl_->flush(); +void SerialPort::flush() { + impl_->flush(); } -void SerialPort::drain() { - impl_->drain(); +void SerialPort::drain() { + impl_->drain(); } -size_t SerialPort::available() const { - return impl_->available(); +size_t SerialPort::available() const { + return impl_->available(); } void SerialPort::setConfig(const SerialConfig& config) { impl_->setConfig(config); } -SerialConfig SerialPort::getConfig() const { - return impl_->getConfig(); +SerialConfig SerialPort::getConfig() const { + return impl_->getConfig(); } -void SerialPort::setDTR(bool value) { - impl_->setDTR(value); +void SerialPort::setDTR(bool value) { + impl_->setDTR(value); } -void SerialPort::setRTS(bool value) { - impl_->setRTS(value); +void SerialPort::setRTS(bool value) { + impl_->setRTS(value); } -bool SerialPort::getCTS() const { - return impl_->getCTS(); +bool SerialPort::getCTS() const { + return impl_->getCTS(); } -bool SerialPort::getDSR() const { - return impl_->getDSR(); +bool SerialPort::getDSR() const { + return impl_->getDSR(); } -bool SerialPort::getRI() const { - return impl_->getRI(); +bool SerialPort::getRI() const { + return impl_->getRI(); } -bool SerialPort::getCD() const { - return impl_->getCD(); +bool SerialPort::getCD() const { + return impl_->getCD(); } -std::string SerialPort::getPortName() const { - return impl_->getPortName(); +std::string SerialPort::getPortName() const { + return impl_->getPortName(); } std::vector SerialPort::getAvailablePorts() { @@ -226,4 +226,4 @@ std::optional SerialPort::tryOpen(std::string_view portName, const } } -} // namespace serial \ No newline at end of file +} // namespace serial diff --git a/atom/serial/serial_port.hpp b/atom/serial/serial_port.hpp index 3aa49055..ff28c69f 100644 --- a/atom/serial/serial_port.hpp +++ b/atom/serial/serial_port.hpp @@ -364,4 +364,4 @@ class SerialPort { std::unique_ptr impl_; }; -} // namespace serial \ No newline at end of file +} // namespace serial diff --git a/atom/serial/serial_port_unix.hpp b/atom/serial/serial_port_unix.hpp index d66f1478..e6568186 100644 --- a/atom/serial/serial_port_unix.hpp +++ b/atom/serial/serial_port_unix.hpp @@ -730,4 +730,4 @@ class SerialPortImpl { } // namespace serial -#endif // defined(__unix__) || defined(__APPLE__) \ No newline at end of file +#endif // defined(__unix__) || defined(__APPLE__) diff --git a/atom/serial/serial_port_win.hpp b/atom/serial/serial_port_win.hpp index 2bdd725f..b09e4d43 100644 --- a/atom/serial/serial_port_win.hpp +++ b/atom/serial/serial_port_win.hpp @@ -782,4 +782,4 @@ class SerialPortImpl { } // namespace serial -#endif // _WIN32 \ No newline at end of file +#endif // _WIN32 diff --git a/atom/serial/usb.hpp b/atom/serial/usb.hpp index e30cf7b6..399b4302 100644 --- a/atom/serial/usb.hpp +++ b/atom/serial/usb.hpp @@ -417,4 +417,4 @@ class UsbDevice { } // namespace atom::serial -#endif // ATOM_SERIAL_USB_HPP \ No newline at end of file +#endif // ATOM_SERIAL_USB_HPP diff --git a/atom/serial/xmake.lua b/atom/serial/xmake.lua index 895203a8..1e9fc253 100644 --- a/atom/serial/xmake.lua +++ b/atom/serial/xmake.lua @@ -35,18 +35,18 @@ local header_files = { -- Object Library target("atom-serial-object") set_kind("object") - + -- Add files add_files(table.unpack(source_files)) add_headerfiles(table.unpack(header_files)) - + -- Add dependencies add_packages("loguru") - + -- Add include directories add_includedirs(".", {public = true}) add_includedirs("..", {public = true}) - + -- Platform-specific settings if is_plat("windows") then add_defines("WIN32_LEAN_AND_MEAN") @@ -56,7 +56,7 @@ target("atom-serial-object") elseif is_plat("macosx") then add_frameworks("IOKit", "CoreFoundation") end - + -- Set C++ standard set_languages("c++20") target_end() @@ -65,11 +65,11 @@ target_end() target("atom-serial") -- Set library type based on parent project option set_kind(has_config("shared_libs") and "shared" or "static") - + -- Add dependencies add_deps("atom-serial-object") add_packages("loguru") - + -- Platform-specific settings if is_plat("windows") then add_syslinks("setupapi") @@ -78,11 +78,11 @@ target("atom-serial") elseif is_plat("macosx") then add_frameworks("IOKit", "CoreFoundation") end - + -- Set output directories set_targetdir("$(buildir)/lib") set_objectdir("$(buildir)/obj") - + -- Install configuration on_install(function (target) os.cp(target:targetfile(), path.join(target:installdir(), "lib")) diff --git a/atom/sysinfo/CMakeLists.txt b/atom/sysinfo/CMakeLists.txt index 3c1e687c..c85be2a3 100644 --- a/atom/sysinfo/CMakeLists.txt +++ b/atom/sysinfo/CMakeLists.txt @@ -84,4 +84,4 @@ install(TARGETS ${PROJECT_NAME} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} PUBLIC_HEADER DESTINATION include/${PROJECT_NAME} -) \ No newline at end of file +) diff --git a/atom/sysinfo/cpu.hpp b/atom/sysinfo/cpu.hpp index f17aa844..3172ffae 100644 --- a/atom/sysinfo/cpu.hpp +++ b/atom/sysinfo/cpu.hpp @@ -127,4 +127,4 @@ void refreshCpuInfo(); } // namespace atom::system -#endif // ATOM_SYSTEM_MODULE_CPU_HPP \ No newline at end of file +#endif // ATOM_SYSTEM_MODULE_CPU_HPP diff --git a/atom/sysinfo/cpu/freebsd.cpp b/atom/sysinfo/cpu/freebsd.cpp index a89290ef..4e557d56 100644 --- a/atom/sysinfo/cpu/freebsd.cpp +++ b/atom/sysinfo/cpu/freebsd.cpp @@ -28,197 +28,197 @@ auto getCPUModel_FreeBSD() -> std::string; auto getCurrentCpuUsage_FreeBSD() -> float { LOG_F(INFO, "Starting getCurrentCpuUsage function on FreeBSD"); - + static std::mutex mutex; static long lastTotal = 0, lastIdle = 0; - + std::unique_lock lock(mutex); - + float cpuUsage = 0.0f; - + long cp_time[CPUSTATES]; size_t len = sizeof(cp_time); - + if (sysctlbyname("kern.cp_time", &cp_time, &len, NULL, 0) != -1) { long total = cp_time[CP_USER] + cp_time[CP_NICE] + cp_time[CP_SYS] + cp_time[CP_IDLE] + cp_time[CP_INTR]; long idle = cp_time[CP_IDLE]; - + if (lastTotal > 0 && lastIdle > 0) { long totalDiff = total - lastTotal; long idleDiff = idle - lastIdle; - + if (totalDiff > 0) { cpuUsage = 100.0f * (1.0f - (static_cast(idleDiff) / totalDiff)); } } - + lastTotal = total; lastIdle = idle; } - + // Clamp to 0-100 range cpuUsage = std::max(0.0f, std::min(100.0f, cpuUsage)); - + LOG_F(INFO, "FreeBSD CPU Usage: {}%", cpuUsage); return cpuUsage; } auto getPerCoreCpuUsage() -> std::vector { LOG_F(INFO, "Starting getPerCoreCpuUsage function on FreeBSD"); - + static std::mutex mutex; static std::vector lastTotals; static std::vector lastIdles; - + std::unique_lock lock(mutex); - + int numCpus = getNumberOfLogicalCores(); std::vector coreUsages(numCpus, 0.0f); - + // Resize previous vectors if needed if (lastTotals.size() < static_cast(numCpus)) { lastTotals.resize(numCpus, 0); lastIdles.resize(numCpus, 0); } - + // Get per-CPU statistics for (int i = 0; i < numCpus; i++) { long cp_time[CPUSTATES]; size_t len = sizeof(cp_time); - + std::string sysctlName = "kern.cp_times"; if (sysctlbyname(sysctlName.c_str(), NULL, &len, NULL, 0) != -1) { std::vector times(len / sizeof(long)); if (sysctlbyname(sysctlName.c_str(), times.data(), &len, NULL, 0) != -1) { // Each CPU has CPUSTATES values int j = i * CPUSTATES; - long total = times[j + CP_USER] + times[j + CP_NICE] + times[j + CP_SYS] + + long total = times[j + CP_USER] + times[j + CP_NICE] + times[j + CP_SYS] + times[j + CP_IDLE] + times[j + CP_INTR]; long idle = times[j + CP_IDLE]; - + if (lastTotals[i] > 0 && lastIdles[i] > 0) { long totalDiff = total - lastTotals[i]; long idleDiff = idle - lastIdles[i]; - + if (totalDiff > 0) { coreUsages[i] = 100.0f * (1.0f - (static_cast(idleDiff) / totalDiff)); coreUsages[i] = std::max(0.0f, std::min(100.0f, coreUsages[i])); } } - + lastTotals[i] = total; lastIdles[i] = idle; } } } - + LOG_F(INFO, "FreeBSD Per-Core CPU Usage collected for {} cores", numCpus); return coreUsages; } auto getCurrentCpuTemperature() -> float { LOG_F(INFO, "Starting getCurrentCpuTemperature function on FreeBSD"); - + float temperature = 0.0f; - + // FreeBSD typically uses ACPI or hardware-specific drivers for temperature // This would require access to /dev/acpi or similar // This is a placeholder implementation - + LOG_F(INFO, "FreeBSD CPU Temperature: {}°C (placeholder)", temperature); return temperature; } auto getPerCoreCpuTemperature() -> std::vector { LOG_F(INFO, "Starting getPerCoreCpuTemperature function on FreeBSD"); - + int numCores = getNumberOfLogicalCores(); std::vector temperatures(numCores, 0.0f); - + // FreeBSD doesn't have a standard way to get per-core temperatures // This is a placeholder implementation - + LOG_F(INFO, "FreeBSD Per-Core CPU Temperature: placeholder values for {} cores", numCores); return temperatures; } auto getCPUModel() -> std::string { LOG_F(INFO, "Starting getCPUModel function on FreeBSD"); - + if (!needsCacheRefresh() && !g_cpuInfoCache.model.empty()) { return g_cpuInfoCache.model; } - + std::string cpuModel = "Unknown"; - + // Try to get model from sysctl char buffer[1024]; size_t len = sizeof(buffer); - + if (sysctlbyname("hw.model", buffer, &len, NULL, 0) != -1) { cpuModel = buffer; } - + LOG_F(INFO, "FreeBSD CPU Model: {}", cpuModel); return cpuModel; } auto getProcessorIdentifier() -> std::string { LOG_F(INFO, "Starting getProcessorIdentifier function on FreeBSD"); - + if (!needsCacheRefresh() && !g_cpuInfoCache.identifier.empty()) { return g_cpuInfoCache.identifier; } - + std::string identifier; - + // Combine hw.model with some additional CPU information char model[256]; size_t len = sizeof(model); - + if (sysctlbyname("hw.model", model, &len, NULL, 0) != -1) { identifier = model; - + // Try to get additional CPU information (family, level, etc.) int family = 0; len = sizeof(family); - + if (sysctlbyname("hw.cpu.family", &family, &len, NULL, 0) != -1) { identifier += " Family " + std::to_string(family); } - + int model_id = 0; len = sizeof(model_id); - + if (sysctlbyname("hw.cpu.model", &model_id, &len, NULL, 0) != -1) { identifier += " Model " + std::to_string(model_id); } - + int stepping = 0; len = sizeof(stepping); - + if (sysctlbyname("hw.cpu.stepping", &stepping, &len, NULL, 0) != -1) { identifier += " Stepping " + std::to_string(stepping); } } - + if (identifier.empty()) { identifier = "FreeBSD CPU"; } - + LOG_F(INFO, "FreeBSD CPU Identifier: {}", identifier); return identifier; } auto getProcessorFrequency() -> double { LOG_F(INFO, "Starting getProcessorFrequency function on FreeBSD"); - + double frequency = 0.0; - + // Try to get CPU frequency int freq = 0; size_t len = sizeof(freq); - + if (sysctlbyname("dev.cpu.0.freq", &freq, &len, NULL, 0) != -1) { // dev.cpu.0.freq returns frequency in MHz frequency = static_cast(freq) / 1000.0; // Convert MHz to GHz @@ -228,26 +228,26 @@ auto getProcessorFrequency() -> double { frequency = static_cast(freq) / 1000.0; // Convert MHz to GHz } } - + LOG_F(INFO, "FreeBSD CPU Frequency: {} GHz", frequency); return frequency; } auto getMinProcessorFrequency() -> double { LOG_F(INFO, "Starting getMinProcessorFrequency function on FreeBSD"); - + double minFreq = 0.0; - + // Check if CPU frequency scaling is available int freq = 0; size_t len = sizeof(freq); - + // Some FreeBSD systems expose this information if (sysctlbyname("dev.cpu.0.freq_levels", NULL, &len, NULL, 0) != -1) { std::vector freqLevels(len); if (sysctlbyname("dev.cpu.0.freq_levels", freqLevels.data(), &len, NULL, 0) != -1) { std::string levels(freqLevels.begin(), freqLevels.end()); - + // Format is typically "frequency/power frequency/power ..." // We want the lowest frequency size_t pos = levels.find_last_of(" \t"); @@ -264,7 +264,7 @@ auto getMinProcessorFrequency() -> double { } } } - + // Ensure we have a reasonable minimum value if (minFreq <= 0.0) { // As a fallback, estimate min as a fraction of current @@ -276,26 +276,26 @@ auto getMinProcessorFrequency() -> double { minFreq = 1.0; // Default fallback } } - + LOG_F(INFO, "FreeBSD CPU Min Frequency: {} GHz", minFreq); return minFreq; } auto getMaxProcessorFrequency() -> double { LOG_F(INFO, "Starting getMaxProcessorFrequency function on FreeBSD"); - + double maxFreq = 0.0; - + // Check if CPU frequency scaling is available int freq = 0; size_t len = sizeof(freq); - + // Some FreeBSD systems expose this information if (sysctlbyname("dev.cpu.0.freq_levels", NULL, &len, NULL, 0) != -1) { std::vector freqLevels(len); if (sysctlbyname("dev.cpu.0.freq_levels", freqLevels.data(), &len, NULL, 0) != -1) { std::string levels(freqLevels.begin(), freqLevels.end()); - + // Format is typically "frequency/power frequency/power ..." // We want the highest frequency (first one) size_t pos = levels.find('/'); @@ -308,30 +308,30 @@ auto getMaxProcessorFrequency() -> double { } } } - + // If we couldn't find a max frequency, use current as fallback if (maxFreq <= 0.0) { maxFreq = getProcessorFrequency(); LOG_F(INFO, "Using current CPU frequency as max: {} GHz", maxFreq); } - + LOG_F(INFO, "FreeBSD CPU Max Frequency: {} GHz", maxFreq); return maxFreq; } auto getPerCoreFrequencies() -> std::vector { LOG_F(INFO, "Starting getPerCoreFrequencies function on FreeBSD"); - + int numCores = getNumberOfLogicalCores(); std::vector frequencies(numCores, 0.0); - + // Try to get per-core frequencies for (int i = 0; i < numCores; i++) { std::string sysctlName = "dev.cpu." + std::to_string(i) + ".freq"; - + int freq = 0; size_t len = sizeof(freq); - + if (sysctlbyname(sysctlName.c_str(), &freq, &len, NULL, 0) != -1) { // dev.cpu.N.freq returns frequency in MHz frequencies[i] = static_cast(freq) / 1000.0; // Convert MHz to GHz @@ -344,248 +344,248 @@ auto getPerCoreFrequencies() -> std::vector { } } } - + LOG_F(INFO, "FreeBSD Per-Core CPU Frequencies collected for {} cores", numCores); return frequencies; } auto getNumberOfPhysicalPackages() -> int { LOG_F(INFO, "Starting getNumberOfPhysicalPackages function on FreeBSD"); - + if (!needsCacheRefresh() && g_cpuInfoCache.numPhysicalPackages > 0) { return g_cpuInfoCache.numPhysicalPackages; } - + // FreeBSD doesn't provide a direct way to get physical packages // Most systems have a single physical package int numberOfPackages = 1; - + // Check hw.packages if available int packages = 0; size_t len = sizeof(packages); - + if (sysctlbyname("hw.packages", &packages, &len, NULL, 0) != -1 && packages > 0) { numberOfPackages = packages; } - + LOG_F(INFO, "FreeBSD Physical CPU Packages: {}", numberOfPackages); return numberOfPackages; } auto getNumberOfPhysicalCores() -> int { LOG_F(INFO, "Starting getNumberOfPhysicalCores function on FreeBSD"); - + if (!needsCacheRefresh() && g_cpuInfoCache.numPhysicalCores > 0) { return g_cpuInfoCache.numPhysicalCores; } - + int numberOfCores = 0; - + // Try to get physical cores int physCores = 0; size_t len = sizeof(physCores); - + // Check hw.ncpu for physical cores if (sysctlbyname("hw.ncpu", &physCores, &len, NULL, 0) != -1) { numberOfCores = physCores; - + // Check if hyperthreading is enabled int hyperThreading = 0; len = sizeof(hyperThreading); - + if (sysctlbyname("hw.cpu_hyperthreading", &hyperThreading, &len, NULL, 0) != -1 && hyperThreading) { numberOfCores /= 2; // If hyperthreading is enabled, logical cores = 2 * physical cores } } - + // Ensure at least one core if (numberOfCores <= 0) { numberOfCores = 1; } - + LOG_F(INFO, "FreeBSD Physical CPU Cores: {}", numberOfCores); return numberOfCores; } auto getNumberOfLogicalCores() -> int { LOG_F(INFO, "Starting getNumberOfLogicalCores function on FreeBSD"); - + if (!needsCacheRefresh() && g_cpuInfoCache.numLogicalCores > 0) { return g_cpuInfoCache.numLogicalCores; } - + int numberOfCores = 0; - + // Get logical cores using hw.ncpu int ncpu = 0; size_t len = sizeof(ncpu); - + if (sysctlbyname("hw.ncpu", &ncpu, &len, NULL, 0) != -1) { numberOfCores = ncpu; } else { // Fall back to sysconf numberOfCores = static_cast(sysconf(_SC_NPROCESSORS_ONLN)); } - + // Ensure at least one core if (numberOfCores <= 0) { numberOfCores = 1; } - + LOG_F(INFO, "FreeBSD Logical CPU Cores: {}", numberOfCores); return numberOfCores; } auto getCacheSizes() -> CacheSizes { LOG_F(INFO, "Starting getCacheSizes function on FreeBSD"); - + if (!needsCacheRefresh() && (g_cpuInfoCache.caches.l1d > 0 || g_cpuInfoCache.caches.l2 > 0 || g_cpuInfoCache.caches.l3 > 0)) { return g_cpuInfoCache.caches; } - + CacheSizes cacheSizes{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - + // Try to read cache sizes int cachesize = 0; size_t len = sizeof(cachesize); - + // L1 Data Cache if (sysctlbyname("hw.l1dcachesize", &cachesize, &len, NULL, 0) != -1) { cacheSizes.l1d = static_cast(cachesize); } - + // L1 Instruction Cache if (sysctlbyname("hw.l1icachesize", &cachesize, &len, NULL, 0) != -1) { cacheSizes.l1i = static_cast(cachesize); } - + // L2 Cache if (sysctlbyname("hw.l2cachesize", &cachesize, &len, NULL, 0) != -1) { cacheSizes.l2 = static_cast(cachesize); } - + // L3 Cache if (sysctlbyname("hw.l3cachesize", &cachesize, &len, NULL, 0) != -1) { cacheSizes.l3 = static_cast(cachesize); } - + // Cache line sizes int lineSize = 0; - + if (sysctlbyname("hw.cacheline", &lineSize, &len, NULL, 0) != -1) { cacheSizes.l1d_line_size = lineSize; cacheSizes.l1i_line_size = lineSize; cacheSizes.l2_line_size = lineSize; cacheSizes.l3_line_size = lineSize; } - + LOG_F(INFO, "FreeBSD Cache Sizes: L1d={}KB, L1i={}KB, L2={}KB, L3={}KB", cacheSizes.l1d / 1024, cacheSizes.l1i / 1024, cacheSizes.l2 / 1024, cacheSizes.l3 / 1024); - + return cacheSizes; } auto getCpuLoadAverage() -> LoadAverage { LOG_F(INFO, "Starting getCpuLoadAverage function on FreeBSD"); - + LoadAverage loadAvg{0.0, 0.0, 0.0}; - + double avg[3]; if (getloadavg(avg, 3) == 3) { loadAvg.oneMinute = avg[0]; loadAvg.fiveMinutes = avg[1]; loadAvg.fifteenMinutes = avg[2]; } - + LOG_F(INFO, "FreeBSD Load Average: {}, {}, {}", loadAvg.oneMinute, loadAvg.fiveMinutes, loadAvg.fifteenMinutes); - + return loadAvg; } auto getCpuPowerInfo() -> CpuPowerInfo { LOG_F(INFO, "Starting getCpuPowerInfo function on FreeBSD"); - + CpuPowerInfo powerInfo{0.0, 0.0, 0.0}; - + // FreeBSD doesn't provide CPU power information through a simple API - + LOG_F(INFO, "FreeBSD CPU Power Info: Not implemented"); return powerInfo; } auto getCpuFeatureFlags() -> std::vector { LOG_F(INFO, "Starting getCpuFeatureFlags function on FreeBSD"); - + if (!needsCacheRefresh() && !g_cpuInfoCache.flags.empty()) { return g_cpuInfoCache.flags; } - + std::vector flags; - + // Get CPU feature flags char buffer[1024]; size_t len = sizeof(buffer); - + if (sysctlbyname("hw.cpu.features", buffer, &len, NULL, 0) != -1) { std::string flagsStr(buffer); std::istringstream ss(flagsStr); std::string flag; - + while (ss >> flag) { flags.push_back(flag); } } - + // Additional features for newer CPUs if (sysctlbyname("hw.cpu.features.ext", buffer, &len, NULL, 0) != -1) { std::string flagsStr(buffer); std::istringstream ss(flagsStr); std::string flag; - + while (ss >> flag) { flags.push_back(flag); } } - + // Even more features if (sysctlbyname("hw.cpu.features.amd", buffer, &len, NULL, 0) != -1) { std::string flagsStr(buffer); std::istringstream ss(flagsStr); std::string flag; - + while (ss >> flag) { flags.push_back(flag); } } - + // Remove duplicates std::sort(flags.begin(), flags.end()); flags.erase(std::unique(flags.begin(), flags.end()), flags.end()); - + LOG_F(INFO, "FreeBSD CPU Flags: {} features collected", flags.size()); return flags; } auto getCpuArchitecture() -> CpuArchitecture { LOG_F(INFO, "Starting getCpuArchitecture function on FreeBSD"); - + if (!needsCacheRefresh()) { std::lock_guard lock(g_cacheMutex); if (g_cacheInitialized && g_cpuInfoCache.architecture != CpuArchitecture::UNKNOWN) { return g_cpuInfoCache.architecture; } } - + CpuArchitecture arch = CpuArchitecture::UNKNOWN; - + // Get architecture using uname struct utsname sysInfo; if (uname(&sysInfo) == 0) { std::string machine = sysInfo.machine; - + if (machine == "amd64") { arch = CpuArchitecture::X86_64; } else if (machine == "i386") { @@ -602,57 +602,57 @@ auto getCpuArchitecture() -> CpuArchitecture { arch = CpuArchitecture::RISC_V; } } - + LOG_F(INFO, "FreeBSD CPU Architecture: {}", cpuArchitectureToString(arch)); return arch; } auto getCpuVendor() -> CpuVendor { LOG_F(INFO, "Starting getCpuVendor function on FreeBSD"); - + if (!needsCacheRefresh()) { std::lock_guard lock(g_cacheMutex); if (g_cacheInitialized && g_cpuInfoCache.vendor != CpuVendor::UNKNOWN) { return g_cpuInfoCache.vendor; } } - + CpuVendor vendor = CpuVendor::UNKNOWN; std::string vendorString; - + char buffer[64]; size_t len = sizeof(buffer); - + if (sysctlbyname("hw.cpu.vendor", buffer, &len, NULL, 0) != -1) { vendorString = buffer; } - + vendor = getVendorFromString(vendorString); - + LOG_F(INFO, "FreeBSD CPU Vendor: {} ({})", vendorString, cpuVendorToString(vendor)); return vendor; } auto getCpuSocketType() -> std::string { LOG_F(INFO, "Starting getCpuSocketType function on FreeBSD"); - + if (!needsCacheRefresh() && !g_cpuInfoCache.socketType.empty()) { return g_cpuInfoCache.socketType; } - + std::string socketType = "Unknown"; - + // FreeBSD doesn't provide socket type directly - + LOG_F(INFO, "FreeBSD CPU Socket Type: {} (placeholder)", socketType); return socketType; } auto getCpuScalingGovernor() -> std::string { LOG_F(INFO, "Starting getCpuScalingGovernor function on FreeBSD"); - + std::string governor = "Unknown"; - + // Check if powerd is running FILE* pipe = popen("service powerd status", "r"); if (pipe) { @@ -664,12 +664,12 @@ auto getCpuScalingGovernor() -> std::string { } pclose(pipe); } - + // Check the current governor setting if (governor == "powerd") { int economy = 0, performance = 0; size_t len = sizeof(economy); - + if (sysctlbyname("hw.acpi.cpu.px_dom0.select", &economy, &len, NULL, 0) != -1) { if (economy == 0) { governor = "performance"; @@ -678,24 +678,24 @@ auto getCpuScalingGovernor() -> std::string { } } } - + LOG_F(INFO, "FreeBSD CPU Scaling Governor: {}", governor); return governor; } auto getPerCoreScalingGovernors() -> std::vector { LOG_F(INFO, "Starting getPerCoreScalingGovernors function on FreeBSD"); - + int numCores = getNumberOfLogicalCores(); std::vector governors(numCores); - + // FreeBSD typically uses the same governor for all cores std::string governor = getCpuScalingGovernor(); - + for (int i = 0; i < numCores; ++i) { governors[i] = governor; } - + LOG_F(INFO, "FreeBSD Per-Core Scaling Governors: {} (same for all cores)", governor); return governors; } diff --git a/atom/sysinfo/cpu/macos.cpp b/atom/sysinfo/cpu/macos.cpp index 78cbf9a2..11d363e6 100644 --- a/atom/sysinfo/cpu/macos.cpp +++ b/atom/sysinfo/cpu/macos.cpp @@ -28,118 +28,118 @@ auto getCPUModel_MacOS() -> std::string; auto getCurrentCpuUsage_MacOS() -> float { LOG_F(INFO, "Starting getCurrentCpuUsage function on macOS"); - + processor_cpu_load_info_t cpuInfo; mach_msg_type_number_t count; - + float cpuUsage = 0.0F; - - if (host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &count, + + if (host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &count, reinterpret_cast(&cpuInfo), &count) == KERN_SUCCESS) { - + static unsigned long long previousUser = 0, previousSystem = 0, previousIdle = 0; - + unsigned long long user = 0, system = 0, idle = 0; - + // Sum usage across all CPUs for (unsigned i = 0; i < count / CPU_STATE_MAX; i++) { user += cpuInfo[i].cpu_ticks[CPU_STATE_USER] + cpuInfo[i].cpu_ticks[CPU_STATE_NICE]; system += cpuInfo[i].cpu_ticks[CPU_STATE_SYSTEM]; idle += cpuInfo[i].cpu_ticks[CPU_STATE_IDLE]; } - + if (previousUser > 0 || previousSystem > 0 || previousIdle > 0) { unsigned long long userDiff = user - previousUser; unsigned long long systemDiff = system - previousSystem; unsigned long long idleDiff = idle - previousIdle; - + unsigned long long totalTicks = userDiff + systemDiff + idleDiff; - + if (totalTicks > 0) { cpuUsage = 100.0F * (static_cast(userDiff + systemDiff) / totalTicks); } } - + previousUser = user; previousSystem = system; previousIdle = idle; - + // Free the allocated memory vm_deallocate(mach_task_self(), reinterpret_cast(cpuInfo), count); } - + // Clamp to 0-100 range cpuUsage = std::max(0.0F, std::min(100.0F, cpuUsage)); - + LOG_F(INFO, "macOS CPU Usage: {}%", cpuUsage); return cpuUsage; } auto getPerCoreCpuUsage() -> std::vector { LOG_F(INFO, "Starting getPerCoreCpuUsage function on macOS"); - + processor_cpu_load_info_t cpuInfo; mach_msg_type_number_t count; - + std::vector coreUsages; - - if (host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &count, + + if (host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &count, reinterpret_cast(&cpuInfo), &count) == KERN_SUCCESS) { - + static std::vector previousUser, previousSystem, previousIdle; - + int numCores = count / CPU_STATE_MAX; coreUsages.resize(numCores, 0.0F); - + // Resize previous vectors if needed if (previousUser.size() < static_cast(numCores)) { previousUser.resize(numCores, 0); previousSystem.resize(numCores, 0); previousIdle.resize(numCores, 0); } - + for (int i = 0; i < numCores; i++) { unsigned long long user = cpuInfo[i].cpu_ticks[CPU_STATE_USER] + cpuInfo[i].cpu_ticks[CPU_STATE_NICE]; unsigned long long system = cpuInfo[i].cpu_ticks[CPU_STATE_SYSTEM]; unsigned long long idle = cpuInfo[i].cpu_ticks[CPU_STATE_IDLE]; - + if (previousUser[i] > 0 || previousSystem[i] > 0 || previousIdle[i] > 0) { unsigned long long userDiff = user - previousUser[i]; unsigned long long systemDiff = system - previousSystem[i]; unsigned long long idleDiff = idle - previousIdle[i]; - + unsigned long long totalTicks = userDiff + systemDiff + idleDiff; - + if (totalTicks > 0) { coreUsages[i] = 100.0F * (static_cast(userDiff + systemDiff) / totalTicks); coreUsages[i] = std::max(0.0F, std::min(100.0F, coreUsages[i])); } } - + previousUser[i] = user; previousSystem[i] = system; previousIdle[i] = idle; } - + // Free the allocated memory vm_deallocate(mach_task_self(), reinterpret_cast(cpuInfo), count); } - + LOG_F(INFO, "macOS Per-Core CPU Usage collected for {} cores", coreUsages.size()); return coreUsages; } auto getCurrentCpuTemperature() -> float { LOG_F(INFO, "Starting getCurrentCpuTemperature function on macOS"); - + // macOS doesn't provide a direct API for CPU temperature // This would require SMC (System Management Controller) access // through a third-party library like SMCKit - + float temperature = 0.0F; - + // This is a placeholder implementation LOG_F(INFO, "macOS CPU Temperature: {}°C (not implemented)", temperature); return temperature; @@ -147,41 +147,41 @@ auto getCurrentCpuTemperature() -> float { auto getPerCoreCpuTemperature() -> std::vector { LOG_F(INFO, "Starting getPerCoreCpuTemperature function on macOS"); - + int numCores = getNumberOfLogicalCores(); std::vector temperatures(numCores, 0.0F); - + // macOS doesn't provide per-core temperatures through a public API // This is a placeholder implementation - + LOG_F(INFO, "macOS Per-Core CPU Temperature: not implemented, returning zeros for {} cores", numCores); return temperatures; } auto getCPUModel() -> std::string { LOG_F(INFO, "Starting getCPUModel function on macOS"); - + if (!needsCacheRefresh() && !g_cpuInfoCache.model.empty()) { return g_cpuInfoCache.model; } - + std::string cpuModel = "Unknown"; - + // Use sysctl to get CPU model char buffer[1024]; size_t bufferSize = sizeof(buffer); - + if (sysctlbyname("machdep.cpu.brand_string", buffer, &bufferSize, NULL, 0) == 0) { cpuModel = buffer; } else { // For Apple Silicon, get chip name if (sysctlbyname("machdep.cpu.brand", buffer, &bufferSize, NULL, 0) == 0) { cpuModel = buffer; - + // Try to get more information for Apple Silicon char modelBuffer[256]; size_t modelBufferSize = sizeof(modelBuffer); - + if (sysctlbyname("hw.model", modelBuffer, &modelBufferSize, NULL, 0) == 0) { if (std::string(modelBuffer).find("Mac") != std::string::npos) { cpuModel += " " + std::string(modelBuffer); @@ -189,35 +189,35 @@ auto getCPUModel() -> std::string { } } } - + LOG_F(INFO, "macOS CPU Model: {}", cpuModel); return cpuModel; } auto getProcessorIdentifier() -> std::string { LOG_F(INFO, "Starting getProcessorIdentifier function on macOS"); - + if (!needsCacheRefresh() && !g_cpuInfoCache.identifier.empty()) { return g_cpuInfoCache.identifier; } - + std::string identifier = "Unknown"; - + // Get CPU vendor, family, model, and stepping char vendor[64]; int family = 0, model = 0, stepping = 0; size_t size = sizeof(vendor); - + if (sysctlbyname("machdep.cpu.vendor", vendor, &size, NULL, 0) == 0) { size = sizeof(family); sysctlbyname("machdep.cpu.family", &family, &size, NULL, 0); - + size = sizeof(model); sysctlbyname("machdep.cpu.model", &model, &size, NULL, 0); - + size = sizeof(stepping); sysctlbyname("machdep.cpu.stepping", &stepping, &size, NULL, 0); - + identifier = std::string(vendor) + " Family " + std::to_string(family) + " Model " + std::to_string(model) + " Stepping " + std::to_string(stepping); @@ -225,24 +225,24 @@ auto getProcessorIdentifier() -> std::string { // For Apple Silicon, use what we can get char buffer[256]; size = sizeof(buffer); - + if (sysctlbyname("machdep.cpu.brand", buffer, &size, NULL, 0) == 0) { identifier = buffer; } } - + LOG_F(INFO, "macOS CPU Identifier: {}", identifier); return identifier; } auto getProcessorFrequency() -> double { LOG_F(INFO, "Starting getProcessorFrequency function on macOS"); - + double frequency = 0.0; - + uint64_t freq = 0; size_t size = sizeof(freq); - + // Try to get the CPU frequency if (sysctlbyname("hw.cpufrequency", &freq, &size, NULL, 0) == 0) { frequency = static_cast(freq) / 1000000000.0; // Convert Hz to GHz @@ -250,31 +250,31 @@ auto getProcessorFrequency() -> double { // Try CPU frequency in MHz (some older Macs) unsigned int freqMHz = 0; size = sizeof(freqMHz); - + if (sysctlbyname("hw.cpufrequency_max", &freq, &size, NULL, 0) == 0) { frequency = static_cast(freq) / 1000000000.0; // Convert Hz to GHz } else if (sysctlbyname("hw.cpufrequency_max", &freqMHz, &size, NULL, 0) == 0) { frequency = static_cast(freqMHz) / 1000.0; // Convert MHz to GHz } } - + LOG_F(INFO, "macOS CPU Frequency: {} GHz", frequency); return frequency; } auto getMinProcessorFrequency() -> double { LOG_F(INFO, "Starting getMinProcessorFrequency function on macOS"); - + double minFreq = 0.0; - + // Try to get the minimum CPU frequency uint64_t freq = 0; size_t size = sizeof(freq); - + if (sysctlbyname("hw.cpufrequency_min", &freq, &size, NULL, 0) == 0) { minFreq = static_cast(freq) / 1000000000.0; // Convert Hz to GHz } - + // Ensure we have a reasonable minimum value if (minFreq <= 0.0) { // As a fallback, estimate min as a fraction of current @@ -286,20 +286,20 @@ auto getMinProcessorFrequency() -> double { minFreq = 1.0; // Default fallback } } - + LOG_F(INFO, "macOS CPU Min Frequency: {} GHz", minFreq); return minFreq; } auto getMaxProcessorFrequency() -> double { LOG_F(INFO, "Starting getMaxProcessorFrequency function on macOS"); - + double maxFreq = 0.0; - + // Try to get the maximum CPU frequency uint64_t freq = 0; size_t size = sizeof(freq); - + if (sysctlbyname("hw.cpufrequency_max", &freq, &size, NULL, 0) == 0) { maxFreq = static_cast(freq) / 1000000000.0; // Convert Hz to GHz } else { @@ -308,91 +308,91 @@ auto getMaxProcessorFrequency() -> double { maxFreq = static_cast(freq) / 1000000000.0; // Convert Hz to GHz } } - + // If still no valid max frequency, use current as fallback if (maxFreq <= 0.0) { maxFreq = getProcessorFrequency(); LOG_F(INFO, "Using current CPU frequency as max: {} GHz", maxFreq); } - + LOG_F(INFO, "macOS CPU Max Frequency: {} GHz", maxFreq); return maxFreq; } auto getPerCoreFrequencies() -> std::vector { LOG_F(INFO, "Starting getPerCoreFrequencies function on macOS"); - + int numCores = getNumberOfLogicalCores(); std::vector frequencies(numCores, 0.0); - + // macOS doesn't provide per-core frequencies through a simple API // Use the overall CPU frequency for all cores double frequency = getProcessorFrequency(); - + for (int i = 0; i < numCores; i++) { frequencies[i] = frequency; } - + LOG_F(INFO, "macOS Per-Core CPU Frequencies: {} GHz (all cores)", frequency); return frequencies; } auto getNumberOfPhysicalPackages() -> int { LOG_F(INFO, "Starting getNumberOfPhysicalPackages function on macOS"); - + if (!needsCacheRefresh() && g_cpuInfoCache.numPhysicalPackages > 0) { return g_cpuInfoCache.numPhysicalPackages; } - + // Most Macs have a single physical CPU package int numberOfPackages = 1; - + LOG_F(INFO, "macOS Physical CPU Packages: {}", numberOfPackages); return numberOfPackages; } auto getNumberOfPhysicalCores() -> int { LOG_F(INFO, "Starting getNumberOfPhysicalCores function on macOS"); - + if (!needsCacheRefresh() && g_cpuInfoCache.numPhysicalCores > 0) { return g_cpuInfoCache.numPhysicalCores; } - + int numberOfCores = 0; - + // Get physical cores int physCores = 0; size_t size = sizeof(physCores); - + if (sysctlbyname("hw.physicalcpu", &physCores, &size, NULL, 0) == 0) { numberOfCores = physCores; } else { // Fall back to logical cores and account for hyperthreading numberOfCores = getNumberOfLogicalCores() / 2; } - + // Ensure at least one core if (numberOfCores <= 0) { numberOfCores = 1; } - + LOG_F(INFO, "macOS Physical CPU Cores: {}", numberOfCores); return numberOfCores; } auto getNumberOfLogicalCores() -> int { LOG_F(INFO, "Starting getNumberOfLogicalCores function on macOS"); - + if (!needsCacheRefresh() && g_cpuInfoCache.numLogicalCores > 0) { return g_cpuInfoCache.numLogicalCores; } - + int numberOfCores = 0; - + // Get logical cores int logicalCores = 0; size_t size = sizeof(logicalCores); - + if (sysctlbyname("hw.logicalcpu", &logicalCores, &size, NULL, 0) == 0) { numberOfCores = logicalCores; } else { @@ -404,117 +404,117 @@ auto getNumberOfLogicalCores() -> int { numberOfCores = static_cast(sysconf(_SC_NPROCESSORS_ONLN)); } } - + // Ensure at least one core if (numberOfCores <= 0) { numberOfCores = 1; } - + LOG_F(INFO, "macOS Logical CPU Cores: {}", numberOfCores); return numberOfCores; } auto getCacheSizes() -> CacheSizes { LOG_F(INFO, "Starting getCacheSizes function on macOS"); - + if (!needsCacheRefresh() && (g_cpuInfoCache.caches.l1d > 0 || g_cpuInfoCache.caches.l2 > 0 || g_cpuInfoCache.caches.l3 > 0)) { return g_cpuInfoCache.caches; } - + CacheSizes cacheSizes{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - + // Read cache sizes from sysctl uint64_t cacheSize = 0; size_t size = sizeof(cacheSize); - + // L1 Data Cache if (sysctlbyname("hw.l1dcachesize", &cacheSize, &size, NULL, 0) == 0) { cacheSizes.l1d = static_cast(cacheSize); } - + // L1 Instruction Cache if (sysctlbyname("hw.l1icachesize", &cacheSize, &size, NULL, 0) == 0) { cacheSizes.l1i = static_cast(cacheSize); } - + // L2 Cache if (sysctlbyname("hw.l2cachesize", &cacheSize, &size, NULL, 0) == 0) { cacheSizes.l2 = static_cast(cacheSize); } - + // L3 Cache if (sysctlbyname("hw.l3cachesize", &cacheSize, &size, NULL, 0) == 0) { cacheSizes.l3 = static_cast(cacheSize); } - + // Get line sizes and associativity if available int lineSize = 0; size = sizeof(lineSize); - + if (sysctlbyname("hw.cachelinesize", &lineSize, &size, NULL, 0) == 0) { cacheSizes.l1d_line_size = lineSize; cacheSizes.l1i_line_size = lineSize; cacheSizes.l2_line_size = lineSize; cacheSizes.l3_line_size = lineSize; } - + int l2associativity = 0; size = sizeof(l2associativity); if (sysctlbyname("machdep.cpu.cache.L2_associativity", &l2associativity, &size, NULL, 0) == 0) { cacheSizes.l2_associativity = l2associativity; } - + LOG_F(INFO, "macOS Cache Sizes: L1d={}KB, L1i={}KB, L2={}KB, L3={}KB", cacheSizes.l1d / 1024, cacheSizes.l1i / 1024, cacheSizes.l2 / 1024, cacheSizes.l3 / 1024); - + return cacheSizes; } auto getCpuLoadAverage() -> LoadAverage { LOG_F(INFO, "Starting getCpuLoadAverage function on macOS"); - + LoadAverage loadAvg{0.0, 0.0, 0.0}; - + double avg[3]; if (getloadavg(avg, 3) == 3) { loadAvg.oneMinute = avg[0]; loadAvg.fiveMinutes = avg[1]; loadAvg.fifteenMinutes = avg[2]; } - + LOG_F(INFO, "macOS Load Average: {}, {}, {}", loadAvg.oneMinute, loadAvg.fiveMinutes, loadAvg.fifteenMinutes); - + return loadAvg; } auto getCpuPowerInfo() -> CpuPowerInfo { LOG_F(INFO, "Starting getCpuPowerInfo function on macOS"); - + CpuPowerInfo powerInfo{0.0, 0.0, 0.0}; - + // macOS doesn't provide this information through a public API - + LOG_F(INFO, "macOS CPU Power Info: Not implemented"); return powerInfo; } auto getCpuFeatureFlags() -> std::vector { LOG_F(INFO, "Starting getCpuFeatureFlags function on macOS"); - + if (!needsCacheRefresh() && !g_cpuInfoCache.flags.empty()) { return g_cpuInfoCache.flags; } - + std::vector flags; - + // Check for common flags using sysctlbyname auto checkFeature = [&flags](const char* name) { int supported = 0; size_t size = sizeof(supported); - + if (sysctlbyname(name, &supported, &size, NULL, 0) == 0 && supported) { // Extract feature name from sysctl name std::string featureName = name; @@ -524,7 +524,7 @@ auto getCpuFeatureFlags() -> std::vector { } } }; - + // Intel CPU features checkFeature("hw.optional.floatingpoint"); checkFeature("hw.optional.mmx"); @@ -549,7 +549,7 @@ auto getCpuFeatureFlags() -> std::vector { checkFeature("hw.optional.avx512vl"); checkFeature("hw.optional.avx512ifma"); checkFeature("hw.optional.avx512vbmi"); - + // ARM features checkFeature("hw.optional.neon"); checkFeature("hw.optional.armv8_1_atomics"); @@ -558,23 +558,23 @@ auto getCpuFeatureFlags() -> std::vector { checkFeature("hw.optional.armv8_2_sha3"); checkFeature("hw.optional.amx_version"); checkFeature("hw.optional.ucnormal_mem"); - + LOG_F(INFO, "macOS CPU Flags: {} features collected", flags.size()); return flags; } auto getCpuArchitecture() -> CpuArchitecture { LOG_F(INFO, "Starting getCpuArchitecture function on macOS"); - + if (!needsCacheRefresh()) { std::lock_guard lock(g_cacheMutex); if (g_cacheInitialized && g_cpuInfoCache.architecture != CpuArchitecture::UNKNOWN) { return g_cpuInfoCache.architecture; } } - + CpuArchitecture arch = CpuArchitecture::UNKNOWN; - + #ifdef __x86_64__ arch = CpuArchitecture::X86_64; #elif defined(__i386__) @@ -588,7 +588,7 @@ auto getCpuArchitecture() -> CpuArchitecture { struct utsname sysInfo; if (uname(&sysInfo) == 0) { std::string machine = sysInfo.machine; - + if (machine == "x86_64") { arch = CpuArchitecture::X86_64; } else if (machine == "i386") { @@ -600,27 +600,27 @@ auto getCpuArchitecture() -> CpuArchitecture { } } #endif - + LOG_F(INFO, "macOS CPU Architecture: {}", cpuArchitectureToString(arch)); return arch; } auto getCpuVendor() -> CpuVendor { LOG_F(INFO, "Starting getCpuVendor function on macOS"); - + if (!needsCacheRefresh()) { std::lock_guard lock(g_cacheMutex); if (g_cacheInitialized && g_cpuInfoCache.vendor != CpuVendor::UNKNOWN) { return g_cpuInfoCache.vendor; } } - + CpuVendor vendor = CpuVendor::UNKNOWN; std::string vendorString = "Unknown"; - + char buffer[64]; size_t size = sizeof(buffer); - + if (sysctlbyname("machdep.cpu.vendor", buffer, &size, NULL, 0) == 0) { vendorString = buffer; } else { @@ -630,48 +630,48 @@ auto getCpuVendor() -> CpuVendor { vendorString = "Apple"; } } - + vendor = getVendorFromString(vendorString); - + LOG_F(INFO, "macOS CPU Vendor: {} ({})", vendorString, cpuVendorToString(vendor)); return vendor; } auto getCpuSocketType() -> std::string { LOG_F(INFO, "Starting getCpuSocketType function on macOS"); - + if (!needsCacheRefresh() && !g_cpuInfoCache.socketType.empty()) { return g_cpuInfoCache.socketType; } - + std::string socketType = "Unknown"; - + // Check architecture to determine socket type CpuArchitecture arch = getCpuArchitecture(); - + if (arch == CpuArchitecture::ARM64 || arch == CpuArchitecture::ARM) { socketType = "Apple SoC"; } else { // For Intel Macs, socket type is generally not available through public APIs socketType = "Intel Mac"; } - + LOG_F(INFO, "macOS CPU Socket Type: {}", socketType); return socketType; } auto getCpuScalingGovernor() -> std::string { LOG_F(INFO, "Starting getCpuScalingGovernor function on macOS"); - + std::string governor = "Unknown"; - + // Get power management mode // This is a simplified approach - macOS uses more sophisticated power management - + // Check if we can get power management information int perfMode = 0; size_t size = sizeof(perfMode); - + if (sysctlbyname("hw.perflevel0.frequency", &perfMode, &size, NULL, 0) == 0) { governor = "perflevel"; } else { @@ -679,37 +679,37 @@ auto getCpuScalingGovernor() -> std::string { CFTypeRef powerSourceInfo = IOPSCopyPowerSourcesInfo(); if (powerSourceInfo) { CFArrayRef powerSources = IOPSCopyPowerSourcesList(powerSourceInfo); - + if (powerSources && CFArrayGetCount(powerSources) > 0) { CFDictionaryRef powerSource = (CFDictionaryRef)CFArrayGetValueAtIndex(powerSources, 0); CFStringRef powerSourceState = (CFStringRef)CFDictionaryGetValue(powerSource, CFSTR(kIOPSPowerSourceStateKey)); - + if (powerSourceState) { bool onBattery = CFStringCompare(powerSourceState, CFSTR(kIOPSBatteryPowerValue), 0) == kCFCompareEqualTo; governor = onBattery ? "Battery Power" : "AC Power"; } } - + if (powerSources) { CFRelease(powerSources); } CFRelease(powerSourceInfo); } } - + LOG_F(INFO, "macOS CPU Power Mode: {}", governor); return governor; } auto getPerCoreScalingGovernors() -> std::vector { LOG_F(INFO, "Starting getPerCoreScalingGovernors function on macOS"); - + int numCores = getNumberOfLogicalCores(); std::string governor = getCpuScalingGovernor(); - + // macOS uses a system-wide power management policy std::vector governors(numCores, governor); - + LOG_F(INFO, "macOS Per-Core Power Modes: {} (same for all cores)", governor); return governors; } diff --git a/atom/sysinfo/disk.hpp b/atom/sysinfo/disk.hpp index d1998e76..d750b6c2 100644 --- a/atom/sysinfo/disk.hpp +++ b/atom/sysinfo/disk.hpp @@ -17,7 +17,7 @@ Description: System Information Module - Disk /** * @brief Disk module for system information - * + * * This module provides functionality for retrieving disk information, * monitoring disk events, and managing disk security. */ @@ -30,4 +30,4 @@ Description: System Information Module - Disk #include "atom/sysinfo/disk/disk_security.hpp" #include "atom/sysinfo/disk/disk_monitor.hpp" -#endif // ATOM_SYSTEM_MODULE_DISK_HPP \ No newline at end of file +#endif // ATOM_SYSTEM_MODULE_DISK_HPP diff --git a/atom/sysinfo/disk/disk_monitor.cpp b/atom/sysinfo/disk/disk_monitor.cpp index 59a50ada..de8293ad 100644 --- a/atom/sysinfo/disk/disk_monitor.cpp +++ b/atom/sysinfo/disk/disk_monitor.cpp @@ -197,11 +197,11 @@ std::future startDeviceMonitoring(std::function:windows.hpp> diff --git a/atom/sysinfo/memory/windows.cpp b/atom/sysinfo/memory/windows.cpp index 214316a9..3f7345bd 100644 --- a/atom/sysinfo/memory/windows.cpp +++ b/atom/sysinfo/memory/windows.cpp @@ -34,21 +34,21 @@ constexpr int MEMORY_TEST_SIZE = 1024 * 1024; static MEMORYSTATUSEX getMemoryStatus() { MEMORYSTATUSEX status{}; status.dwLength = sizeof(status); - + if (!GlobalMemoryStatusEx(&status)) { spdlog::error("Failed to get memory status: {}", GetLastError()); } - + return status; } static PROCESS_MEMORY_COUNTERS getProcessMemoryCounters() { PROCESS_MEMORY_COUNTERS pmc{}; - + if (!GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc))) { spdlog::error("Failed to get process memory info: {}", GetLastError()); } - + return pmc; } } @@ -78,7 +78,7 @@ auto getTotalMemorySize() -> unsigned long long { if (status.ullTotalPhys > 0) { spdlog::debug("Total memory size: {} bytes", status.ullTotalPhys); } - + return status.ullTotalPhys; } @@ -89,7 +89,7 @@ auto getAvailableMemorySize() -> unsigned long long { if (status.ullAvailPhys > 0) { spdlog::debug("Available memory size: {} bytes", status.ullAvailPhys); } - + return status.ullAvailPhys; } @@ -98,7 +98,7 @@ auto getPhysicalMemoryInfo() -> MemoryInfo::MemorySlot { MemoryInfo::MemorySlot slot; const auto status = getMemoryStatus(); - + if (status.ullTotalPhys > 0) { slot.capacity = std::to_string(status.ullTotalPhys / (1024 * 1024)); slot.type = "DDR"; @@ -116,7 +116,7 @@ auto getVirtualMemoryMax() -> unsigned long long { if (status.ullTotalVirtual > 0) { spdlog::debug("Maximum virtual memory: {} bytes", status.ullTotalVirtual); } - + return status.ullTotalVirtual; } @@ -129,7 +129,7 @@ auto getVirtualMemoryUsed() -> unsigned long long { spdlog::debug("Used virtual memory: {} bytes", usedVirtual); return usedVirtual; } - + return 0; } @@ -140,7 +140,7 @@ auto getSwapMemoryTotal() -> unsigned long long { if (status.ullTotalPageFile > 0) { spdlog::debug("Total swap memory: {} bytes", status.ullTotalPageFile); } - + return status.ullTotalPageFile; } @@ -153,7 +153,7 @@ auto getSwapMemoryUsed() -> unsigned long long { spdlog::debug("Used swap memory: {} bytes", usedSwap); return usedSwap; } - + return 0; } @@ -166,7 +166,7 @@ auto getCommittedMemory() -> size_t { spdlog::debug("Committed memory: {} bytes", committed); return static_cast(committed); } - + return 0; } @@ -178,7 +178,7 @@ auto getUncommittedMemory() -> size_t { spdlog::debug("Uncommitted memory: {} bytes", status.ullAvailPhys); return static_cast(status.ullAvailPhys); } - + return 0; } @@ -187,7 +187,7 @@ auto getDetailedMemoryStats() -> MemoryInfo { MemoryInfo info{}; const auto memStatus = getMemoryStatus(); - + if (memStatus.ullTotalPhys > 0) { info.memoryLoadPercentage = memStatus.dwMemoryLoad; info.totalPhysicalMemory = memStatus.ullTotalPhys; @@ -226,7 +226,7 @@ auto getPeakWorkingSetSize() -> size_t { if (pmc.PeakWorkingSetSize > 0) { spdlog::debug("Peak working set size: {} bytes", pmc.PeakWorkingSetSize); } - + return pmc.PeakWorkingSetSize; } @@ -237,7 +237,7 @@ auto getCurrentWorkingSetSize() -> size_t { if (pmc.WorkingSetSize > 0) { spdlog::debug("Current working set size: {} bytes", pmc.WorkingSetSize); } - + return pmc.WorkingSetSize; } @@ -246,7 +246,7 @@ auto getPageFaultCount() -> size_t { const auto pmc = getProcessMemoryCounters(); spdlog::debug("Page fault count: {}", pmc.PageFaultCount); - + return pmc.PageFaultCount; } @@ -255,11 +255,11 @@ auto getMemoryLoadPercentage() -> double { const auto status = getMemoryStatus(); const auto memoryLoad = static_cast(status.dwMemoryLoad); - + if (status.ullTotalPhys > 0) { spdlog::debug("Memory load: {}%", memoryLoad); } - + return memoryLoad; } @@ -275,7 +275,7 @@ auto getMemoryPerformance() -> MemoryPerformance { if (PdhOpenQuery(nullptr, 0, &query) == ERROR_SUCCESS) { const auto addCounterResult1 = PdhAddCounterW(query, L"\\Memory\\Pages/sec", 0, &readCounter); const auto addCounterResult2 = PdhAddCounterW(query, L"\\Memory\\Page Writes/sec", 0, &writeCounter); - + if (addCounterResult1 == ERROR_SUCCESS && addCounterResult2 == ERROR_SUCCESS) { PdhCollectQueryData(query); std::this_thread::sleep_for(std::chrono::seconds(1)); @@ -283,10 +283,10 @@ auto getMemoryPerformance() -> MemoryPerformance { PDH_FMT_COUNTERVALUE readValue{}; PDH_FMT_COUNTERVALUE writeValue{}; - + const auto getValueResult1 = PdhGetFormattedCounterValue(readCounter, PDH_FMT_DOUBLE, nullptr, &readValue); const auto getValueResult2 = PdhGetFormattedCounterValue(writeCounter, PDH_FMT_DOUBLE, nullptr, &writeValue); - + if (getValueResult1 == ERROR_SUCCESS && getValueResult2 == ERROR_SUCCESS) { perf.readSpeed = readValue.doubleValue * PAGE_SIZE_KB * KB_TO_MB; perf.writeSpeed = writeValue.doubleValue * PAGE_SIZE_KB * KB_TO_MB; @@ -306,13 +306,13 @@ auto getMemoryPerformance() -> MemoryPerformance { std::vector testData; testData.reserve(MEMORY_TEST_SIZE); - + const auto start = std::chrono::high_resolution_clock::now(); for (int i = 0; i < MEMORY_TEST_SIZE; ++i) { testData.push_back(i); } const auto end = std::chrono::high_resolution_clock::now(); - + perf.latency = std::chrono::duration_cast(end - start).count() / static_cast(MEMORY_TEST_SIZE); spdlog::debug("Memory performance - Read: {:.2f} MB/s, Write: {:.2f} MB/s, Bandwidth: {:.1f}%, Latency: {:.2f} ns", diff --git a/atom/sysinfo/os.hpp b/atom/sysinfo/os.hpp index e72674aa..6f3c4730 100644 --- a/atom/sysinfo/os.hpp +++ b/atom/sysinfo/os.hpp @@ -1,10 +1,10 @@ /** * @file os.hpp * @brief Operating System Information Module - * + * * This file contains definitions for retrieving comprehensive operating system * information across different platforms including Windows, Linux, and macOS. - * + * * @copyright Copyright (C) 2023-2024 Max Qian */ @@ -22,7 +22,7 @@ namespace atom::system { /** * @struct OperatingSystemInfo * @brief Comprehensive information about the operating system - * + * * Contains detailed information about the operating system including * version details, architecture, boot time, and system configuration. */ @@ -64,96 +64,96 @@ struct OperatingSystemInfo { /** * @brief Retrieves comprehensive information about the operating system - * + * * Queries the operating system for detailed information including name, * version, kernel details, architecture, and other system properties. - * + * * @return OperatingSystemInfo struct containing the operating system information */ OperatingSystemInfo getOperatingSystemInfo(); /** * @brief Checks if the operating system is running in a Windows Subsystem for Linux (WSL) environment - * + * * Detects whether the current environment is running under WSL by examining * system files and environment indicators. - * + * * @return true if the operating system is running in a WSL environment, false otherwise */ auto isWsl() -> bool; /** * @brief Retrieves the system uptime - * + * * Calculates the duration since the system was last booted. - * + * * @return The system uptime as a duration in seconds */ auto getSystemUptime() -> std::chrono::seconds; /** * @brief Retrieves the last boot time of the system - * + * * Determines when the system was last started by calculating the boot time * based on current time and uptime. - * + * * @return The last boot time as a formatted string */ auto getLastBootTime() -> std::string; /** * @brief Retrieves the system timezone - * + * * Gets the current timezone configuration of the system. - * + * * @return The system timezone as a string */ auto getSystemTimeZone() -> std::string; /** * @brief Retrieves the list of installed updates - * + * * Queries the system for a list of installed updates, patches, or packages * depending on the operating system. - * + * * @return A vector containing the names of installed updates */ auto getInstalledUpdates() -> std::vector; /** * @brief Checks for available updates - * + * * Queries the system or update repositories for available updates * that can be installed. - * + * * @return A vector containing the names of available updates */ auto checkForUpdates() -> std::vector; /** * @brief Retrieves the system language - * + * * Gets the primary language configured for the system. - * + * * @return The system language as a string */ auto getSystemLanguage() -> std::string; /** * @brief Retrieves the system encoding - * + * * Gets the character encoding used by the system. - * + * * @return The system encoding as a string */ auto getSystemEncoding() -> std::string; /** * @brief Checks if the operating system is a server edition - * + * * Determines whether the current OS installation is a server variant * or desktop/workstation variant. - * + * * @return true if the operating system is a server edition, false otherwise */ auto isServerEdition() -> bool; diff --git a/atom/sysinfo/sysinfo_printer.cpp b/atom/sysinfo/sysinfo_printer.cpp index 6214c223..5dfec90a 100644 --- a/atom/sysinfo/sysinfo_printer.cpp +++ b/atom/sysinfo/sysinfo_printer.cpp @@ -113,18 +113,18 @@ auto SystemInfoPrinter::formatBiosInfo(const BiosInfoData& info) -> std::string auto SystemInfoPrinter::formatDiskInfo(const std::vector& disks) -> std::string { std::stringstream ss; ss << createTableHeader("Disk Information"); - + for (size_t i = 0; i < disks.size(); ++i) { const auto& disk = disks[i]; ss << createTableRow("Disk " + std::to_string(i + 1) + " Model", disk.model); - ss << createTableRow("Disk " + std::to_string(i + 1) + " Type", + ss << createTableRow("Disk " + std::to_string(i + 1) + " Type", diskTypeToString(disk.fsType)); - ss << createTableRow("Disk " + std::to_string(i + 1) + " Size", + ss << createTableRow("Disk " + std::to_string(i + 1) + " Size", std::format("{:.2f} GB", disk.totalSpace / (1024.0 * 1024 * 1024))); - ss << createTableRow("Disk " + std::to_string(i + 1) + " Free Space", + ss << createTableRow("Disk " + std::to_string(i + 1) + " Free Space", std::format("{:.2f} GB", disk.freeSpace / (1024.0 * 1024 * 1024))); } - + ss << createTableFooter(); return ss.str(); } @@ -255,13 +255,13 @@ auto SystemInfoPrinter::generateSimpleReport() -> std::string { auto memInfo = getDetailedMemoryStats(); ss << "OS: " << osInfo.osName << " " << osInfo.osVersion << "\n"; - ss << "CPU: " << cpuInfo.model << " (" << cpuInfo.numPhysicalCores + ss << "CPU: " << cpuInfo.model << " (" << cpuInfo.numPhysicalCores << " cores, " << cpuInfo.numLogicalCores << " threads)\n"; - ss << "Memory: " << std::format("{:.2f} GB / {:.2f} GB ({:.1f}% used)\n", + ss << "Memory: " << std::format("{:.2f} GB / {:.2f} GB ({:.1f}% used)\n", (memInfo.totalPhysicalMemory - memInfo.availablePhysicalMemory) / (1024.0 * 1024 * 1024), memInfo.totalPhysicalMemory / (1024.0 * 1024 * 1024), memInfo.memoryLoadPercentage); - + auto batteryResult = getDetailedBatteryInfo(); if (std::holds_alternative(batteryResult)) { const auto& batteryInfo = std::get(batteryResult); @@ -394,8 +394,8 @@ bool SystemInfoPrinter::exportToHTML(const std::string& filename) {

System Information Report

-

Generated at: )" + - std::format("{:%Y-%m-%d %H:%M:%S}", std::chrono::system_clock::now()) + +

Generated at: )" + + std::format("{:%Y-%m-%d %H:%M:%S}", std::chrono::system_clock::now()) + R"(

)"; @@ -403,7 +403,7 @@ R"(

std::string currentLine; std::istringstream reportStream(report); bool inTable = false; - + while (std::getline(reportStream, currentLine)) { if (currentLine.find("===") != std::string::npos) { html += "

" + currentLine + "

\n"; @@ -421,18 +421,18 @@ R"(

if (middlePipe != std::string::npos) { std::string param = currentLine.substr(1, middlePipe - 1); std::string value = currentLine.substr(middlePipe + 1); - + // Remove trailing pipe and trim if (!value.empty() && value.back() == '|') { value.pop_back(); } - + // Trim spaces param.erase(0, param.find_first_not_of(" ")); param.erase(param.find_last_not_of(" ") + 1); value.erase(0, value.find_first_not_of(" ")); value.erase(value.find_last_not_of(" ") + 1); - + html += "" + param + "" + value + "\n"; } } @@ -444,7 +444,7 @@ R"(

html += "

" + currentLine + "

\n"; } } - + if (inTable) { html += "\n"; } @@ -469,9 +469,9 @@ bool SystemInfoPrinter::exportToJSON(const std::string& filename) { // Create a JSON structure with system information file << "{\n"; - file << " \"timestamp\": \"" << + file << " \"timestamp\": \"" << std::format("{:%Y-%m-%d %H:%M:%S}", std::chrono::system_clock::now()) << "\",\n"; - + // OS information try { auto osInfo = getOperatingSystemInfo(); @@ -492,7 +492,7 @@ bool SystemInfoPrinter::exportToJSON(const std::string& filename) { spdlog::error("Error getting OS info for JSON export: {}", e.what()); file << " \"os\": { \"error\": \"" << e.what() << "\" },\n"; } - + // CPU information try { auto cpuInfo = getCpuInfo(); @@ -510,7 +510,7 @@ bool SystemInfoPrinter::exportToJSON(const std::string& filename) { spdlog::error("Error getting CPU info for JSON export: {}", e.what()); file << " \"cpu\": { \"error\": \"" << e.what() << "\" },\n"; } - + // Memory information try { auto memInfo = getDetailedMemoryStats(); @@ -524,7 +524,7 @@ bool SystemInfoPrinter::exportToJSON(const std::string& filename) { spdlog::error("Error getting memory info for JSON export: {}", e.what()); file << " \"memory\": { \"error\": \"" << e.what() << "\" }\n"; } - + file << "}\n"; return true; } catch (const std::exception& e) { @@ -543,7 +543,7 @@ bool SystemInfoPrinter::exportToMarkdown(const std::string& filename) { } file << "# System Information Report\n\n"; - file << "Generated at: " << + file << "Generated at: " << std::format("{:%Y-%m-%d %H:%M:%S}", std::chrono::system_clock::now()) << "\n\n"; // Operating system information @@ -567,9 +567,9 @@ bool SystemInfoPrinter::exportToMarkdown(const std::string& filename) { spdlog::error("Error getting OS info for Markdown export: {}", e.what()); file << "Error retrieving operating system information: " << e.what() << "\n\n"; } - + // Add additional sections for CPU, memory, etc. - + return true; } catch (const std::exception& e) { spdlog::error("Error exporting to Markdown: {}", e.what()); @@ -577,4 +577,4 @@ bool SystemInfoPrinter::exportToMarkdown(const std::string& filename) { } } -} // namespace atom::system \ No newline at end of file +} // namespace atom::system diff --git a/atom/sysinfo/sysinfo_printer.hpp b/atom/sysinfo/sysinfo_printer.hpp index 69d2fa19..0d80fa6c 100644 --- a/atom/sysinfo/sysinfo_printer.hpp +++ b/atom/sysinfo/sysinfo_printer.hpp @@ -11,10 +11,10 @@ #ifndef ATOM_SYSINFO_PRINTER_HPP #define ATOM_SYSINFO_PRINTER_HPP - + #include #include - + #include "battery.hpp" #include "bios.hpp" #include "cpu.hpp" @@ -23,9 +23,9 @@ #include "memory.hpp" #include "os.hpp" #include "wm.hpp" - + namespace atom::system { - + /** * @class SystemInfoPrinter * @brief Formats and presents system information in human-readable formats @@ -42,21 +42,21 @@ * @return A formatted string containing battery details */ static auto formatBatteryInfo(const BatteryInfo& info) -> std::string; - + /** * @brief Format BIOS information as a string * @param info The BIOS information to format * @return A formatted string containing BIOS details */ static auto formatBiosInfo(const BiosInfoData& info) -> std::string; - + /** * @brief Format CPU information as a string * @param info The CPU information to format * @return A formatted string containing CPU details */ static auto formatCpuInfo(const CpuInfo& info) -> std::string; - + /** * @brief Format disk information as a string * @param info Vector of disk information objects to format @@ -64,114 +64,114 @@ */ static auto formatDiskInfo(const std::vector& info) -> std::string; - + /** * @brief Format GPU information as a string * @return A formatted string containing GPU details */ static auto formatGpuInfo() -> std::string; - + /** * @brief Format locale information as a string * @param info The locale information to format * @return A formatted string containing locale settings */ static auto formatLocaleInfo(const LocaleInfo& info) -> std::string; - + /** * @brief Format memory information as a string * @param info The memory information to format * @return A formatted string containing memory details */ static auto formatMemoryInfo(const MemoryInfo& info) -> std::string; - + /** * @brief Format operating system information as a string * @param info The OS information to format * @return A formatted string containing OS details */ static auto formatOsInfo(const OperatingSystemInfo& info) -> std::string; - + /** * @brief Format comprehensive system information as a string * @param info The system information structure to format * @return A formatted string containing system details */ static auto formatSystemInfo(const SystemInfo& info) -> std::string; - + /** * @brief Generate a comprehensive report of all system components - * + * * Creates a detailed report including information about all hardware and * software components of the system. - * + * * @return A string containing the full system report */ static auto generateFullReport() -> std::string; - + /** * @brief Generate a simplified overview of key system information - * + * * Creates a concise report with the most important system details * suitable for quick reference. - * + * * @return A string containing the simplified system report */ static auto generateSimpleReport() -> std::string; - + /** * @brief Generate a report focused on system performance metrics - * + * * Creates a report with emphasis on performance-related information * like CPU speed, memory usage, disk speeds, etc. - * + * * @return A string containing the performance-focused report */ static auto generatePerformanceReport() -> std::string; - + /** * @brief Generate a report focused on system security features - * + * * Creates a report highlighting security-related information such as * OS security features, firmware versions, and potential vulnerabilities. - * + * * @return A string containing the security-focused report */ static auto generateSecurityReport() -> std::string; - + /** * @brief Export system information to HTML format - * + * * Generates a complete system information report and saves it as an * HTML file at the specified location. - * + * * @param filename The path where the HTML file will be saved * @return true if export was successful, false otherwise */ static bool exportToHTML(const std::string& filename); - + /** * @brief Export system information to JSON format - * + * * Generates a complete system information report and saves it as a * structured JSON file at the specified location. - * + * * @param filename The path where the JSON file will be saved * @return true if export was successful, false otherwise */ static bool exportToJSON(const std::string& filename); - + /** * @brief Export system information to Markdown format - * + * * Generates a complete system information report and saves it as a * Markdown file at the specified location. - * + * * @param filename The path where the Markdown file will be saved * @return true if export was successful, false otherwise */ static bool exportToMarkdown(const std::string& filename); - + private: /** * @brief Helper method to create a formatted table row @@ -181,21 +181,21 @@ */ static auto createTableRow(const std::string& label, const std::string& value) -> std::string; - + /** * @brief Helper method to create a formatted table header * @param title The title of the table * @return A formatted string representing a table header */ static auto createTableHeader(const std::string& title) -> std::string; - + /** * @brief Helper method to create a formatted table footer * @return A formatted string representing a table footer */ static auto createTableFooter() -> std::string; }; - + } // namespace atom::system - - #endif // ATOM_SYSINFO_PRINTER_HPP \ No newline at end of file + + #endif // ATOM_SYSINFO_PRINTER_HPP diff --git a/atom/sysinfo/virtual.hpp b/atom/sysinfo/virtual.hpp index e7b6cceb..fcf4514d 100644 --- a/atom/sysinfo/virtual.hpp +++ b/atom/sysinfo/virtual.hpp @@ -185,4 +185,4 @@ auto getContainerType() -> std::string; } // namespace atom::system -#endif // ATOM_SYSINFO_VIRTUAL_HPP \ No newline at end of file +#endif // ATOM_SYSINFO_VIRTUAL_HPP diff --git a/atom/sysinfo/wifi/wifi.cpp b/atom/sysinfo/wifi/wifi.cpp index 39e8ddd6..b09e9794 100644 --- a/atom/sysinfo/wifi/wifi.cpp +++ b/atom/sysinfo/wifi/wifi.cpp @@ -102,7 +102,7 @@ auto getIPAddresses(int addressFamily) -> std::vector { if (ua->Address.lpSockaddr->sa_family == addressFamily) { char ipStr[INET6_ADDRSTRLEN] = {0}; void* addr = nullptr; - + if (addressFamily == AF_INET) { struct sockaddr_in* ipv4 = reinterpret_cast(ua->Address.lpSockaddr); addr = &(ipv4->sin_addr); @@ -134,7 +134,7 @@ auto getIPAddresses(int addressFamily) -> std::vector { if (ifa->ifa_addr && ifa->ifa_addr->sa_family == addressFamily) { char ipStr[INET6_ADDRSTRLEN] = {0}; void* addr = nullptr; - + if (addressFamily == AF_INET) { struct sockaddr_in* ipv4 = reinterpret_cast(ifa->ifa_addr); addr = &(ipv4->sin_addr); @@ -142,7 +142,7 @@ auto getIPAddresses(int addressFamily) -> std::vector { struct sockaddr_in6* ipv6 = reinterpret_cast(ifa->ifa_addr); addr = &(ipv6->sin6_addr); } - + inet_ntop(addressFamily, addr, ipStr, sizeof(ipStr)); addresses.emplace_back(ipStr); LOG_F(INFO, "Found IP address: {}", ipStr); diff --git a/atom/sysinfo/xmake.lua b/atom/sysinfo/xmake.lua index 3f67ae62..6e70f20d 100644 --- a/atom/sysinfo/xmake.lua +++ b/atom/sysinfo/xmake.lua @@ -36,25 +36,25 @@ local header_files = { -- Object Library target("atom-sysinfo-object") set_kind("object") - + -- Add files add_files(table.unpack(source_files)) add_headerfiles(table.unpack(header_files)) - + -- Add dependencies add_packages("loguru") - + -- Add include directories add_includedirs(".", {public = true}) add_includedirs("..", {public = true}) - + -- Platform-specific settings if is_plat("linux") then add_syslinks("pthread") elseif is_plat("windows") then add_syslinks("pdh", "wlanapi") end - + -- Set C++ standard set_languages("c++20") target_end() @@ -63,25 +63,25 @@ target_end() target("atom-sysinfo") -- Set library type based on parent project option set_kind(has_config("shared_libs") and "shared" or "static") - + -- Add dependencies add_deps("atom-sysinfo-object") add_packages("loguru") - + -- Platform-specific settings if is_plat("linux") then add_syslinks("pthread") elseif is_plat("windows") then add_syslinks("pdh", "wlanapi") end - + -- Set output directories set_targetdir("$(buildir)/lib") set_objectdir("$(buildir)/obj") - + -- Set version with build timestamp set_version("1.0.0", {build = "%Y%m%d%H%M"}) - + -- Install configuration on_install(function (target) os.cp(target:targetfile(), path.join(target:installdir(), "lib")) diff --git a/atom/system/CMakeLists.txt b/atom/system/CMakeLists.txt index f683dfe9..74aab780 100644 --- a/atom/system/CMakeLists.txt +++ b/atom/system/CMakeLists.txt @@ -94,4 +94,4 @@ install(TARGETS ${PROJECT_NAME} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} PUBLIC_HEADER DESTINATION include/${PROJECT_NAME} -) \ No newline at end of file +) diff --git a/atom/system/clipboard.ipp b/atom/system/clipboard.ipp index bcc2f069..10b29c86 100644 --- a/atom/system/clipboard.ipp +++ b/atom/system/clipboard.ipp @@ -14,7 +14,7 @@ public: // ============================================================================ // Core Operations // ============================================================================ - + virtual bool open() = 0; virtual void close() noexcept = 0; virtual bool clear() = 0; @@ -22,14 +22,14 @@ public: // ============================================================================ // Text Operations // ============================================================================ - + virtual bool setText(std::string_view text) = 0; virtual std::optional getText() = 0; // ============================================================================ // Binary Data Operations // ============================================================================ - + virtual bool setData(ClipboardFormat format, std::span data) = 0; virtual std::optional> getData(ClipboardFormat format) = 0; virtual bool containsFormat(ClipboardFormat format) = 0; @@ -37,7 +37,7 @@ public: // ============================================================================ // Image Operations // ============================================================================ - + #ifdef CLIPBOARD_SUPPORT_OPENCV virtual bool setImage(const cv::Mat& image) = 0; virtual std::optional getImageAsMat() = 0; @@ -51,7 +51,7 @@ public: // ============================================================================ // Query Operations // ============================================================================ - + virtual bool hasText() = 0; virtual bool hasImage() = 0; virtual std::vector getAvailableFormats() = 0; @@ -60,16 +60,16 @@ public: // ============================================================================ // Change Monitoring // ============================================================================ - + virtual bool hasChanged() const { return false; } virtual void updateChangeCount() {} // ============================================================================ // Static Factory Methods // ============================================================================ - + static std::unique_ptr create(); static ClipboardFormat registerFormat(std::string_view formatName); }; -} // namespace clip \ No newline at end of file +} // namespace clip diff --git a/atom/system/clipboard_error.hpp b/atom/system/clipboard_error.hpp index ac03c9a9..6eaac335 100644 --- a/atom/system/clipboard_error.hpp +++ b/atom/system/clipboard_error.hpp @@ -224,4 +224,4 @@ template return ScopeGuard>(std::forward(f)); } -} // namespace clip \ No newline at end of file +} // namespace clip diff --git a/atom/system/clipboard_macos.cpp b/atom/system/clipboard_macos.cpp index c263fabb..97144fe1 100644 --- a/atom/system/clipboard_macos.cpp +++ b/atom/system/clipboard_macos.cpp @@ -19,20 +19,20 @@ namespace { class CFStringWrapper { public: explicit CFStringWrapper(CFStringRef str) : m_string(str) {} - + ~CFStringWrapper() { if (m_string) { CFRelease(m_string); } } - + CFStringWrapper(const CFStringWrapper&) = delete; CFStringWrapper& operator=(const CFStringWrapper&) = delete; - + CFStringWrapper(CFStringWrapper&& other) noexcept : m_string(other.m_string) { other.m_string = nullptr; } - + CFStringWrapper& operator=(CFStringWrapper&& other) noexcept { if (this != &other) { if (m_string) { @@ -43,14 +43,14 @@ namespace { } return *this; } - + CFStringRef get() const noexcept { return m_string; } operator bool() const noexcept { return m_string != nullptr; } - + private: CFStringRef m_string; }; - + // Helper function to create CFString from std::string CFStringWrapper createCFString(std::string_view text) { CFStringRef str = CFStringCreateWithBytes( @@ -62,19 +62,19 @@ namespace { ); return CFStringWrapper(str); } - + // Helper function to convert CFString to std::string std::string cfStringToString(CFStringRef cfStr) { if (!cfStr) { return {}; } - + CFIndex length = CFStringGetLength(cfStr); CFIndex maxSize = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8); - + std::string result(maxSize, '\0'); CFIndex actualSize = 0; - + Boolean success = CFStringGetBytes( cfStr, CFRangeMake(0, length), @@ -85,15 +85,15 @@ namespace { maxSize, &actualSize ); - + if (success) { result.resize(actualSize); return result; } - + return {}; } - + // Convert error to ClipboardErrorCode ClipboardErrorCode osStatusToErrorCode(OSStatus status) { switch (status) { @@ -140,7 +140,7 @@ class MacOSClipboard : public Clipboard::Impl { if (!m_pasteboard) { return false; } - + [m_pasteboard clearContents]; m_changeCount = [m_pasteboard changeCount]; return true; @@ -152,27 +152,27 @@ class MacOSClipboard : public Clipboard::Impl { if (!m_pasteboard) { return false; } - + try { - NSString* nsString = [[NSString alloc] - initWithBytes:text.data() - length:text.size() + NSString* nsString = [[NSString alloc] + initWithBytes:text.data() + length:text.size() encoding:NSUTF8StringEncoding]; - + if (!nsString) { throw ClipboardFormatException("Failed to create NSString from text"); } - + auto guard = make_scope_guard([nsString] { [nsString release]; }); - + [m_pasteboard clearContents]; BOOL success = [m_pasteboard setString:nsString forType:NSPasteboardTypeString]; - + if (success) { m_changeCount = [m_pasteboard changeCount]; return true; } - + return false; } catch (const std::exception&) { return false; @@ -185,18 +185,18 @@ class MacOSClipboard : public Clipboard::Impl { if (!m_pasteboard) { return std::nullopt; } - + try { NSString* string = [m_pasteboard stringForType:NSPasteboardTypeString]; if (!string) { return std::nullopt; } - + const char* cString = [string UTF8String]; if (!cString) { return std::nullopt; } - + return std::string(cString); } catch (const std::exception&) { return std::nullopt; @@ -209,27 +209,27 @@ class MacOSClipboard : public Clipboard::Impl { if (!m_pasteboard) { return false; } - + try { // Convert format to pasteboard type NSString* pasteboardType = formatToPasteboardType(format); if (!pasteboardType) { return false; } - + NSData* nsData = [NSData dataWithBytes:data.data() length:data.size()]; if (!nsData) { return false; } - + [m_pasteboard clearContents]; BOOL success = [m_pasteboard setData:nsData forType:pasteboardType]; - + if (success) { m_changeCount = [m_pasteboard changeCount]; return true; } - + return false; } catch (const std::exception&) { return false; @@ -242,21 +242,21 @@ class MacOSClipboard : public Clipboard::Impl { if (!m_pasteboard) { return std::nullopt; } - + try { NSString* pasteboardType = formatToPasteboardType(format); if (!pasteboardType) { return std::nullopt; } - + NSData* data = [m_pasteboard dataForType:pasteboardType]; if (!data) { return std::nullopt; } - + std::vector result(data.length); std::memcpy(result.data(), data.bytes, data.length); - + return result; } catch (const std::exception&) { return std::nullopt; @@ -269,12 +269,12 @@ class MacOSClipboard : public Clipboard::Impl { if (!m_pasteboard) { return false; } - + NSString* pasteboardType = formatToPasteboardType(format); if (!pasteboardType) { return false; } - + NSArray* types = [m_pasteboard types]; return [types containsObject:pasteboardType]; } @@ -286,7 +286,7 @@ class MacOSClipboard : public Clipboard::Impl { if (!m_pasteboard || image.empty()) { return false; } - + try { // Convert cv::Mat to NSImage cv::Mat rgbImage; @@ -297,7 +297,7 @@ class MacOSClipboard : public Clipboard::Impl { } else { rgbImage = image.clone(); } - + NSBitmapImageRep* imageRep = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:nil pixelsWide:rgbImage.cols @@ -309,28 +309,28 @@ class MacOSClipboard : public Clipboard::Impl { colorSpaceName:NSCalibratedRGBColorSpace bytesPerRow:rgbImage.step bitsPerPixel:rgbImage.channels() * 8]; - + if (!imageRep) { return false; } - + auto guard = make_scope_guard([imageRep] { [imageRep release]; }); - + std::memcpy([imageRep bitmapData], rgbImage.data, rgbImage.total() * rgbImage.elemSize()); - + NSImage* nsImage = [[NSImage alloc] init]; [nsImage addRepresentation:imageRep]; - + auto imageGuard = make_scope_guard([nsImage] { [nsImage release]; }); - + [m_pasteboard clearContents]; BOOL success = [m_pasteboard writeObjects:@[nsImage]]; - + if (success) { m_changeCount = [m_pasteboard changeCount]; return true; } - + return false; } catch (const std::exception&) { return false; @@ -343,18 +343,18 @@ class MacOSClipboard : public Clipboard::Impl { if (!m_pasteboard) { return std::nullopt; } - + try { NSArray* images = [m_pasteboard readObjectsForClasses:@[[NSImage class]] options:nil]; if (!images || images.count == 0) { return std::nullopt; } - + NSImage* image = [images firstObject]; if (!image) { return std::nullopt; } - + NSBitmapImageRep* imageRep = nil; for (NSImageRep* rep in [image representations]) { if ([rep isKindOfClass:[NSBitmapImageRep class]]) { @@ -362,31 +362,31 @@ class MacOSClipboard : public Clipboard::Impl { break; } } - + if (!imageRep) { // Convert to bitmap representation NSSize imageSize = [image size]; [image lockFocus]; imageRep = [[NSBitmapImageRep alloc] initWithFocusedViewRect:NSMakeRect(0, 0, imageSize.width, imageSize.height)]; [image unlockFocus]; - + if (!imageRep) { return std::nullopt; } } - + auto guard = make_scope_guard([imageRep] { [imageRep release]; }); - + int width = (int)[imageRep pixelsWide]; int height = (int)[imageRep pixelsHigh]; int channels = (int)[imageRep samplesPerPixel]; - + cv::Mat result(height, width, CV_8UC(channels)); - + unsigned char* imageData = [imageRep bitmapData]; if (imageData) { std::memcpy(result.data, imageData, result.total() * result.elemSize()); - + // Convert from RGB to BGR for OpenCV if (channels == 3) { cv::cvtColor(result, result, cv::COLOR_RGB2BGR); @@ -394,7 +394,7 @@ class MacOSClipboard : public Clipboard::Impl { cv::cvtColor(result, result, cv::COLOR_RGBA2BGRA); } } - + return result; } catch (const std::exception&) { return std::nullopt; @@ -408,7 +408,7 @@ class MacOSClipboard : public Clipboard::Impl { // Convert CImg to cv::Mat and use OpenCV implementation #ifdef CLIPBOARD_SUPPORT_OPENCV cv::Mat mat(image.height(), image.width(), CV_8UC(image.spectrum())); - + if (image.spectrum() == 1) { // Grayscale std::memcpy(mat.data, image.data(), image.size()); @@ -422,7 +422,7 @@ class MacOSClipboard : public Clipboard::Impl { } } } - + return setImage(mat); #else return false; @@ -435,9 +435,9 @@ class MacOSClipboard : public Clipboard::Impl { if (!mat) { return std::nullopt; } - + cimg_library::CImg result(mat->cols, mat->rows, 1, mat->channels()); - + if (mat->channels() == 1) { std::memcpy(result.data(), mat->data, mat->total()); } else if (mat->channels() == 3) { @@ -450,7 +450,7 @@ class MacOSClipboard : public Clipboard::Impl { } } } - + return result; #else return std::nullopt; @@ -463,7 +463,7 @@ class MacOSClipboard : public Clipboard::Impl { if (!m_pasteboard) { return false; } - + NSArray* types = [m_pasteboard types]; return [types containsObject:NSPasteboardTypeString]; } @@ -474,7 +474,7 @@ class MacOSClipboard : public Clipboard::Impl { if (!m_pasteboard) { return false; } - + NSArray* types = [m_pasteboard types]; return [types containsObject:NSPasteboardTypeTIFF] || [types containsObject:NSPasteboardTypePNG]; @@ -484,11 +484,11 @@ class MacOSClipboard : public Clipboard::Impl { std::vector getAvailableFormats() override { @autoreleasepool { std::vector formats; - + if (!m_pasteboard) { return formats; } - + NSArray* types = [m_pasteboard types]; for (NSString* type in types) { unsigned int format = pasteboardTypeToFormat(type); @@ -496,7 +496,7 @@ class MacOSClipboard : public Clipboard::Impl { formats.push_back(format); } } - + return formats; } } @@ -515,7 +515,7 @@ class MacOSClipboard : public Clipboard::Impl { if (!m_pasteboard) { return false; } - + NSInteger currentChangeCount = [m_pasteboard changeCount]; return currentChangeCount != m_changeCount; } @@ -532,7 +532,7 @@ class MacOSClipboard : public Clipboard::Impl { private: NSPasteboard* m_pasteboard = nullptr; NSInteger m_changeCount = 0; - + // Format conversion mappings std::unordered_map m_formatToType = { {1, NSPasteboardTypeString}, @@ -541,14 +541,14 @@ class MacOSClipboard : public Clipboard::Impl { {4, NSPasteboardTypePNG}, {5, NSPasteboardTypeRTF} }; - + std::unordered_map m_typeToFormat; - + NSString* formatToPasteboardType(unsigned int format) { auto it = m_formatToType.find(format); return (it != m_formatToType.end()) ? it->second : nil; } - + unsigned int pasteboardTypeToFormat(NSString* type) { if (m_typeToFormat.empty()) { // Initialize reverse mapping @@ -556,7 +556,7 @@ class MacOSClipboard : public Clipboard::Impl { m_typeToFormat[pair.second] = pair.first; } } - + auto it = m_typeToFormat.find(type); return (it != m_typeToFormat.end()) ? it->second : 0; } @@ -570,17 +570,17 @@ std::unique_ptr Clipboard::Impl::create() { // Static format registration method unsigned int Clipboard::Impl::registerFormat(std::string_view formatName) { @autoreleasepool { - NSString* nsFormatName = [[NSString alloc] - initWithBytes:formatName.data() - length:formatName.size() + NSString* nsFormatName = [[NSString alloc] + initWithBytes:formatName.data() + length:formatName.size() encoding:NSUTF8StringEncoding]; - + if (!nsFormatName) { return 0; } - + auto guard = make_scope_guard([nsFormatName] { [nsFormatName release]; }); - + // In macOS, we use the string directly as the pasteboard type // Return a hash of the format name as the format ID std::hash hasher; diff --git a/atom/system/clipboard_windows.cpp b/atom/system/clipboard_windows.cpp index ea97c7c2..9ba92d4b 100644 --- a/atom/system/clipboard_windows.cpp +++ b/atom/system/clipboard_windows.cpp @@ -661,9 +661,9 @@ class WindowsClipboard : public Clipboard::Impl { // ============================================================================ // Change Monitoring Implementation // ============================================================================ - + bool hasChanged() const override { - // Windows doesn't provide built-in change detection, + // Windows doesn't provide built-in change detection, // so we'll use a simple sequence number approach DWORD currentSequence = GetClipboardSequenceNumber(); if (currentSequence != m_lastSequenceNumber) { @@ -672,7 +672,7 @@ class WindowsClipboard : public Clipboard::Impl { } return false; } - + void updateChangeCount() override { m_lastSequenceNumber = GetClipboardSequenceNumber(); }std::vector getAvailableFormats() override { @@ -766,4 +766,4 @@ ClipboardFormat Clipboard::Impl::registerFormat(std::string_view formatName) { } // namespace clip -#endif // _WIN32 \ No newline at end of file +#endif // _WIN32 diff --git a/atom/system/crontab.cpp b/atom/system/crontab.cpp index a90313df..d3e5ab65 100644 --- a/atom/system/crontab.cpp +++ b/atom/system/crontab.cpp @@ -853,4 +853,4 @@ auto CronManager::getJobsByPriority() -> std::vector { }); return sortedJobs; -} \ No newline at end of file +} diff --git a/atom/system/crontab.hpp b/atom/system/crontab.hpp index 0a3d7a77..eb8db1ed 100644 --- a/atom/system/crontab.hpp +++ b/atom/system/crontab.hpp @@ -366,4 +366,4 @@ class CronManager { auto handleJobFailure(const std::string& id) -> bool; }; -#endif // CRONJOB_H \ No newline at end of file +#endif // CRONJOB_H diff --git a/atom/system/gpio.hpp b/atom/system/gpio.hpp index c6f60f05..e33896de 100644 --- a/atom/system/gpio.hpp +++ b/atom/system/gpio.hpp @@ -362,4 +362,4 @@ std::string edgeToString(GPIO::Edge edge); } // namespace atom::system -#endif // ATOM_SYSTEM_GPIO_HPP \ No newline at end of file +#endif // ATOM_SYSTEM_GPIO_HPP diff --git a/atom/system/lregistry.cpp b/atom/system/lregistry.cpp index b1a0ae54..76103a51 100644 --- a/atom/system/lregistry.cpp +++ b/atom/system/lregistry.cpp @@ -1435,4 +1435,4 @@ bool Registry::RegistryImpl::matchesPattern(const std::string& text, } } -} // namespace atom::system \ No newline at end of file +} // namespace atom::system diff --git a/atom/system/lregistry.hpp b/atom/system/lregistry.hpp index f3976e73..1d669715 100644 --- a/atom/system/lregistry.hpp +++ b/atom/system/lregistry.hpp @@ -322,4 +322,4 @@ class Registry { } // namespace atom::system -#endif \ No newline at end of file +#endif diff --git a/atom/system/network_manager.hpp b/atom/system/network_manager.hpp index 76f1756f..9dbdcc82 100644 --- a/atom/system/network_manager.hpp +++ b/atom/system/network_manager.hpp @@ -186,4 +186,4 @@ auto getNetworkConnections(int pid) -> std::vector; } // namespace atom::system -#endif // ATOM_SYSTEM_NETWORK_MANAGER_HPP \ No newline at end of file +#endif // ATOM_SYSTEM_NETWORK_MANAGER_HPP diff --git a/atom/system/nodebugger.cpp b/atom/system/nodebugger.cpp index f4495b0d..92baa86e 100644 --- a/atom/system/nodebugger.cpp +++ b/atom/system/nodebugger.cpp @@ -362,4 +362,4 @@ void stopAntiDebugMonitoring() { g_monitoringThread.join(); } } -} // namespace atom::system \ No newline at end of file +} // namespace atom::system diff --git a/atom/system/nodebugger.hpp b/atom/system/nodebugger.hpp index 681b616c..bf4cfa1b 100644 --- a/atom/system/nodebugger.hpp +++ b/atom/system/nodebugger.hpp @@ -56,4 +56,4 @@ void enableSelfModifyingCode(void* codeAddress, size_t codeSize); } // namespace atom::system -#endif // ATOM_SYSTEM_NODEBUGGER_HPP \ No newline at end of file +#endif // ATOM_SYSTEM_NODEBUGGER_HPP diff --git a/atom/system/pidwatcher.cpp b/atom/system/pidwatcher.cpp index 437b0ef1..d279a556 100644 --- a/atom/system/pidwatcher.cpp +++ b/atom/system/pidwatcher.cpp @@ -2462,4 +2462,4 @@ void PidWatcher::watchdogThread() { spdlog::info("Watchdog thread exited"); } -} // namespace atom::system \ No newline at end of file +} // namespace atom::system diff --git a/atom/system/pidwatcher.hpp b/atom/system/pidwatcher.hpp index 6e862102..4d3e074f 100644 --- a/atom/system/pidwatcher.hpp +++ b/atom/system/pidwatcher.hpp @@ -467,4 +467,4 @@ class PidWatcher { } // namespace atom::system -#endif \ No newline at end of file +#endif diff --git a/atom/system/shortcut/CMakeLists.txt b/atom/system/shortcut/CMakeLists.txt index 438d71ca..52f591ab 100644 --- a/atom/system/shortcut/CMakeLists.txt +++ b/atom/system/shortcut/CMakeLists.txt @@ -26,7 +26,7 @@ add_library(shortcut_detector SHARED # Set include directories target_include_directories(shortcut_detector - PUBLIC + PUBLIC $ $ PRIVATE @@ -50,7 +50,7 @@ add_library(shortcut_detector_static STATIC ) target_include_directories(shortcut_detector_static - PUBLIC + PUBLIC $ $ PRIVATE @@ -101,7 +101,7 @@ install( ) install( - FILES + FILES include/detector.h include/shortcut.h include/factory.h @@ -113,4 +113,4 @@ install( EXPORT shortcut_detector-config NAMESPACE shortcut_detector:: DESTINATION lib/cmake/shortcut_detector -) \ No newline at end of file +) diff --git a/atom/system/shortcut/detector.hpp b/atom/system/shortcut/detector.hpp index caede697..b4e9d37f 100644 --- a/atom/system/shortcut/detector.hpp +++ b/atom/system/shortcut/detector.hpp @@ -60,4 +60,4 @@ class ShortcutDetector { std::unique_ptr pImpl; }; -} // namespace shortcut_detector \ No newline at end of file +} // namespace shortcut_detector diff --git a/atom/system/shortcut/detector_impl.cpp b/atom/system/shortcut/detector_impl.cpp index 6f2045ed..3d00c897 100644 --- a/atom/system/shortcut/detector_impl.cpp +++ b/atom/system/shortcut/detector_impl.cpp @@ -44,13 +44,13 @@ ShortcutCheckResult ShortcutDetectorImpl::isShortcutCaptured( if (!canRegister) { const auto capturingApp = findCapturingApplication(shortcut); if (capturingApp.empty()) { - spdlog::debug("Shortcut {} is captured by unknown system component", + spdlog::debug("Shortcut {} is captured by unknown system component", shortcut.toString()); return {ShortcutStatus::CapturedBySystem, "Unknown System Component", "The shortcut is captured by the system"}; } else { - spdlog::debug("Shortcut {} is captured by application: {}", + spdlog::debug("Shortcut {} is captured by application: {}", shortcut.toString(), capturingApp); return {ShortcutStatus::CapturedByApp, capturingApp, "The shortcut is registered by another application"}; @@ -59,7 +59,7 @@ ShortcutCheckResult ShortcutDetectorImpl::isShortcutCaptured( if (hasInterceptingKeyboardHook(shortcut)) { const auto hookOwner = findKeyboardHookOwner(); - spdlog::debug("Shortcut {} may be intercepted by keyboard hook owned by: {}", + spdlog::debug("Shortcut {} may be intercepted by keyboard hook owned by: {}", shortcut.toString(), hookOwner); return {ShortcutStatus::CapturedByApp, hookOwner, "A keyboard hook may intercept this shortcut"}; @@ -138,4 +138,4 @@ std::string ShortcutDetectorImpl::findKeyboardHookOwner() { return processes[0]; } -} // namespace shortcut_detector \ No newline at end of file +} // namespace shortcut_detector diff --git a/atom/system/shortcut/detector_impl.h b/atom/system/shortcut/detector_impl.h index 9433bb97..fe529541 100644 --- a/atom/system/shortcut/detector_impl.h +++ b/atom/system/shortcut/detector_impl.h @@ -11,7 +11,7 @@ namespace shortcut_detector { /** * @brief Implementation class for ShortcutDetector using PIMPL idiom - * + * * This class provides the actual implementation for keyboard shortcut detection * on Windows systems. It checks for system-reserved shortcuts, attempts hotkey * registration, and detects keyboard hooks. @@ -23,23 +23,23 @@ class ShortcutDetectorImpl { /** * @brief Check if a keyboard shortcut is captured by system or applications - * + * * @param shortcut The shortcut to check * @return ShortcutCheckResult Result containing status and details */ ShortcutCheckResult isShortcutCaptured(const Shortcut& shortcut); - + /** * @brief Check if any keyboard hook is currently installed - * + * * @return true If keyboard hooks are detected * @return false If no keyboard hooks are detected */ bool hasKeyboardHookInstalled(); - + /** * @brief Get list of processes that have keyboard hooks installed - * + * * @return std::vector Process names with keyboard hooks */ std::vector getProcessesWithKeyboardHooks(); @@ -58,4 +58,4 @@ class ShortcutDetectorImpl { systemReservedShortcuts; }; -} // namespace shortcut_detector \ No newline at end of file +} // namespace shortcut_detector diff --git a/atom/system/shortcut/factory.cpp b/atom/system/shortcut/factory.cpp index 1170f60e..c25212a8 100644 --- a/atom/system/shortcut/factory.cpp +++ b/atom/system/shortcut/factory.cpp @@ -87,4 +87,4 @@ Shortcut ShortcutFactory::fromString(const std::string& description) { return Shortcut(vkCode, ctrl, alt, shift, win); } -} // namespace shortcut_detector \ No newline at end of file +} // namespace shortcut_detector diff --git a/atom/system/shortcut/factory.h b/atom/system/shortcut/factory.h index 1df53a70..23038853 100644 --- a/atom/system/shortcut/factory.h +++ b/atom/system/shortcut/factory.h @@ -61,4 +61,4 @@ class ShortcutFactory { } // VK_F4 = 0x73 }; -} // namespace shortcut_detector \ No newline at end of file +} // namespace shortcut_detector diff --git a/atom/system/shortcut/shortcut.cpp b/atom/system/shortcut/shortcut.cpp index 041c4a95..e1a6d891 100644 --- a/atom/system/shortcut/shortcut.cpp +++ b/atom/system/shortcut/shortcut.cpp @@ -97,4 +97,4 @@ bool Shortcut::operator==(const Shortcut& other) const { shift == other.shift && win == other.win; } -} // namespace shortcut_detector \ No newline at end of file +} // namespace shortcut_detector diff --git a/atom/system/shortcut/shortcut.h b/atom/system/shortcut/shortcut.h index 074bb196..e9a5c124 100644 --- a/atom/system/shortcut/shortcut.h +++ b/atom/system/shortcut/shortcut.h @@ -60,4 +60,4 @@ struct hash { return s.hash(); } }; -} // namespace std \ No newline at end of file +} // namespace std diff --git a/atom/system/shortcut/status.h b/atom/system/shortcut/status.h index c233831d..6bf9c9df 100644 --- a/atom/system/shortcut/status.h +++ b/atom/system/shortcut/status.h @@ -24,4 +24,4 @@ struct ShortcutCheckResult { std::string details; // Additional details }; -} // namespace shortcut_detector \ No newline at end of file +} // namespace shortcut_detector diff --git a/atom/system/shortcut/test_shortcut_detector.cpp b/atom/system/shortcut/test_shortcut_detector.cpp index 94c07ba3..e9dec597 100644 --- a/atom/system/shortcut/test_shortcut_detector.cpp +++ b/atom/system/shortcut/test_shortcut_detector.cpp @@ -14,7 +14,7 @@ int main() { try { // Create detector instance shortcut_detector::ShortcutDetector detector; - + // Test various shortcuts std::vector> testShortcuts = { {"Ctrl+C", shortcut_detector::ShortcutFactory::create('C', true, false, false, false)}, @@ -28,12 +28,12 @@ int main() { for (const auto& [name, shortcut] : testShortcuts) { spdlog::info("Testing shortcut: {} ({})", name, shortcut.toString()); - + const auto result = detector.isShortcutCaptured(shortcut); - + std::cout << "Shortcut: " << name << " (" << shortcut.toString() << ")\n"; std::cout << " Status: "; - + switch (result.status) { case shortcut_detector::ShortcutStatus::Available: std::cout << "Available"; @@ -48,7 +48,7 @@ int main() { std::cout << "Reserved by Windows"; break; } - + std::cout << "\n Details: " << result.details << "\n\n"; } diff --git a/atom/system/shortcut/win32_utils.cpp b/atom/system/shortcut/win32_utils.cpp index e9523220..9e4a4513 100644 --- a/atom/system/shortcut/win32_utils.cpp +++ b/atom/system/shortcut/win32_utils.cpp @@ -19,9 +19,9 @@ namespace win32_utils { * @brief Known keyboard hook DLL modules commonly used by applications */ static const std::unordered_set knownHookDlls = { - "HOOK.DLL", "KBDHOOK.DLL", "KEYHOOK.DLL", - "INPUTHOOK.DLL", "WINHOOK.DLL", "LLKEYBOARD.DLL", - "KEYMAGIC.DLL", "HOOKSPY.DLL", "KEYBOARDHOOK.DLL", + "HOOK.DLL", "KBDHOOK.DLL", "KEYHOOK.DLL", + "INPUTHOOK.DLL", "WINHOOK.DLL", "LLKEYBOARD.DLL", + "KEYMAGIC.DLL", "HOOKSPY.DLL", "KEYBOARDHOOK.DLL", "INPUTMANAGERHOOK.DLL", "UIHOOK.DLL"}; std::vector getProcessesWithKeyboardHooks() { @@ -125,4 +125,4 @@ bool isHookingModule(const std::string& moduleName) { } } // namespace win32_utils -} // namespace shortcut_detector \ No newline at end of file +} // namespace shortcut_detector diff --git a/atom/system/shortcut/win32_utils.h b/atom/system/shortcut/win32_utils.h index 7c268df1..543cf4ec 100644 --- a/atom/system/shortcut/win32_utils.h +++ b/atom/system/shortcut/win32_utils.h @@ -39,4 +39,4 @@ std::string getProcessName(DWORD processId); bool isHookingModule(const std::string& moduleName); } // namespace win32_utils -} // namespace shortcut_detector \ No newline at end of file +} // namespace shortcut_detector diff --git a/atom/system/software.hpp b/atom/system/software.hpp index d295b526..2c45df3f 100644 --- a/atom/system/software.hpp +++ b/atom/system/software.hpp @@ -94,4 +94,4 @@ auto checkSoftwareUpdates(const std::string& software_name, } // namespace atom::system -#endif \ No newline at end of file +#endif diff --git a/atom/system/stat.cpp b/atom/system/stat.cpp index 2302bba2..39074a5d 100644 --- a/atom/system/stat.cpp +++ b/atom/system/stat.cpp @@ -799,4 +799,4 @@ std::string Stat::formatTime(std::time_t time, const std::string& format) { return oss.str(); } -} // namespace atom::system \ No newline at end of file +} // namespace atom::system diff --git a/atom/system/stat.hpp b/atom/system/stat.hpp index fd6efa1f..c29f2c86 100644 --- a/atom/system/stat.hpp +++ b/atom/system/stat.hpp @@ -307,4 +307,4 @@ class Stat { } // namespace atom::system -#endif // ATOM_SYSTEM_STAT_HPP \ No newline at end of file +#endif // ATOM_SYSTEM_STAT_HPP diff --git a/atom/system/storage.hpp b/atom/system/storage.hpp index 7d7a6f19..4c81e720 100644 --- a/atom/system/storage.hpp +++ b/atom/system/storage.hpp @@ -197,4 +197,4 @@ void monitorUdisk(StorageMonitor& monitor); } // namespace atom::system -#endif \ No newline at end of file +#endif diff --git a/atom/system/user.cpp b/atom/system/user.cpp index 238d33bc..07bc0b3f 100644 --- a/atom/system/user.cpp +++ b/atom/system/user.cpp @@ -92,7 +92,7 @@ auto getUserGroups() -> std::vector { spdlog::error("Failed to open process token for group enumeration"); return groups; } - + DWORD bufferSize = 0; GetTokenInformation(hToken, TokenGroups, nullptr, 0, &bufferSize); if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { @@ -501,7 +501,7 @@ auto getLoggedInUsers() -> std::vector { WTSUserName, &buffer, &bytesReturned)) { if (buffer && bytesReturned > 1) { std::string username(buffer); - if (!username.empty() && + if (!username.empty() && std::find(users.begin(), users.end(), username) == users.end()) { users.push_back(username); spdlog::debug("Found logged-in user: {}", username); @@ -522,7 +522,7 @@ auto getLoggedInUsers() -> std::vector { while ((entry = getutent()) != nullptr) { if (entry->ut_type == USER_PROCESS) { std::string username(entry->ut_user); - if (!username.empty() && + if (!username.empty() && std::find(users.begin(), users.end(), username) == users.end()) { users.push_back(username); spdlog::debug("Found logged-in user: {}", username); diff --git a/atom/system/user.hpp b/atom/system/user.hpp index 0062cbad..7c8e29fe 100644 --- a/atom/system/user.hpp +++ b/atom/system/user.hpp @@ -132,4 +132,4 @@ ATOM_NODISCARD auto getLoggedInUsers() -> std::vector; ATOM_NODISCARD auto userExists(const std::string& username) -> bool; } // namespace atom::system -#endif \ No newline at end of file +#endif diff --git a/atom/system/virtual_network.cpp b/atom/system/virtual_network.cpp index cb1a127c..1dc2fa87 100644 --- a/atom/system/virtual_network.cpp +++ b/atom/system/virtual_network.cpp @@ -763,4 +763,4 @@ bool VirtualNetworkAdapter::ConfigureDNS(const std::wstring& adapterName, std::wstring VirtualNetworkAdapter::GetLastErrorMessage() const { return pImpl->GetLastErrorMessage(); -} \ No newline at end of file +} diff --git a/atom/system/virtual_network.hpp b/atom/system/virtual_network.hpp index f803117e..36ccf272 100644 --- a/atom/system/virtual_network.hpp +++ b/atom/system/virtual_network.hpp @@ -89,4 +89,4 @@ class VirtualNetworkAdapter { std::unique_ptr pImpl; }; -#endif // VIRTUAL_NETWORK_ADAPTER_H \ No newline at end of file +#endif // VIRTUAL_NETWORK_ADAPTER_H diff --git a/atom/system/voltage.cpp b/atom/system/voltage.cpp index 00f41a47..75cd3a22 100644 --- a/atom/system/voltage.cpp +++ b/atom/system/voltage.cpp @@ -63,4 +63,4 @@ std::unique_ptr VoltageMonitor::create() { #endif } -} // namespace atom::system \ No newline at end of file +} // namespace atom::system diff --git a/atom/system/voltage.hpp b/atom/system/voltage.hpp index 2fa65612..244beb5e 100644 --- a/atom/system/voltage.hpp +++ b/atom/system/voltage.hpp @@ -145,4 +145,4 @@ std::string powerSourceTypeToString(PowerSourceType type); } // namespace atom::system -#endif // ATOM_SYSTEM_VOLTAGE_HPP \ No newline at end of file +#endif // ATOM_SYSTEM_VOLTAGE_HPP diff --git a/atom/system/voltage_linux.cpp b/atom/system/voltage_linux.cpp index b00f32b8..282e98c1 100644 --- a/atom/system/voltage_linux.cpp +++ b/atom/system/voltage_linux.cpp @@ -167,4 +167,4 @@ inline std::unique_ptr VoltageMonitor::create() { } // namespace atom::system -#endif // __linux__ \ No newline at end of file +#endif // __linux__ diff --git a/atom/system/voltage_linux.hpp b/atom/system/voltage_linux.hpp index b88c6dd4..7656eb7e 100644 --- a/atom/system/voltage_linux.hpp +++ b/atom/system/voltage_linux.hpp @@ -92,4 +92,4 @@ class LinuxVoltageMonitor : public VoltageMonitor { } // namespace atom::system -#endif // __linux__ \ No newline at end of file +#endif // __linux__ diff --git a/atom/system/voltage_windows.cpp b/atom/system/voltage_windows.cpp index e4091217..71be662b 100644 --- a/atom/system/voltage_windows.cpp +++ b/atom/system/voltage_windows.cpp @@ -344,4 +344,4 @@ std::vector WindowsVoltageMonitor::getWMIPowerInfo() const { } // namespace atom::system -#endif // _WIN32 \ No newline at end of file +#endif // _WIN32 diff --git a/atom/system/voltage_windows.hpp b/atom/system/voltage_windows.hpp index a1ba3de2..ffe69c00 100644 --- a/atom/system/voltage_windows.hpp +++ b/atom/system/voltage_windows.hpp @@ -91,4 +91,4 @@ class WindowsVoltageMonitor : public VoltageMonitor { } // namespace atom::system -#endif // _WIN32 \ No newline at end of file +#endif // _WIN32 diff --git a/atom/system/xmake.lua b/atom/system/xmake.lua index 8c4fab24..8200e5fe 100644 --- a/atom/system/xmake.lua +++ b/atom/system/xmake.lua @@ -15,29 +15,29 @@ set_license("GPL3") -- Object Library target("atom-system-object") set_kind("object") - + -- Add source files add_files("*.cpp") add_files("module/*.cpp") - + -- Add header files add_headerfiles("*.hpp") add_headerfiles("module/*.hpp") - + -- Add dependencies add_packages("loguru") - + -- Add include directories add_includedirs(".", {public = true}) add_includedirs("..", {public = true}) - + -- Platform-specific settings if is_plat("linux") then add_syslinks("pthread") elseif is_plat("windows") then add_syslinks("pdh", "wlanapi") end - + -- Set C++ standard set_languages("c++20") target_end() @@ -46,22 +46,22 @@ target_end() target("atom-system") -- Set library type based on parent project option set_kind(has_config("shared_libs") and "shared" or "static") - + -- Add dependencies add_deps("atom-system-object") add_packages("loguru") - + -- Platform-specific settings if is_plat("linux") then add_syslinks("pthread") elseif is_plat("windows") then add_syslinks("pdh", "wlanapi") end - + -- Set output directories set_targetdir("$(buildir)/lib") set_objectdir("$(buildir)/obj") - + -- Install configuration on_install(function (target) os.cp(target:targetfile(), path.join(target:installdir(), "lib")) diff --git a/atom/tests/CMakeLists.txt b/atom/tests/CMakeLists.txt index 2449b5eb..105df2a3 100644 --- a/atom/tests/CMakeLists.txt +++ b/atom/tests/CMakeLists.txt @@ -60,4 +60,4 @@ install(TARGETS ${PROJECT_NAME} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} PUBLIC_HEADER DESTINATION include/${PROJECT_NAME} -) \ No newline at end of file +) diff --git a/atom/tests/benchmark.hpp b/atom/tests/benchmark.hpp index b7c718a7..68b500d9 100644 --- a/atom/tests/benchmark.hpp +++ b/atom/tests/benchmark.hpp @@ -93,13 +93,13 @@ class Benchmark { size_t peakUsage = 0; ///< Peak memory usage. MemoryStats() noexcept = default; - + /** * @brief Constructor with explicit initialization values * @param current Current memory usage * @param peak Peak memory usage */ - MemoryStats(size_t current, size_t peak) noexcept + MemoryStats(size_t current, size_t peak) noexcept : currentUsage(current), peakUsage(peak) {} /** diff --git a/atom/tests/charts.py b/atom/tests/charts.py index 312de3f2..e2c38a72 100644 --- a/atom/tests/charts.py +++ b/atom/tests/charts.py @@ -376,7 +376,7 @@ def generate_report(data, metrics, out_dir, style='default', dark_mode=False):

Performance Test Results

Generated on: {now}

- +

Statistics

""" @@ -416,17 +416,17 @@ def generate_report(data, metrics, out_dir, style='default', dark_mode=False):

{metric} - Bar Chart

{metric} Bar Chart
- +

{metric} - Line Chart

{metric} Line Chart
- +

{metric} - Pie Chart

{metric} Pie Chart
- +

{metric} - Histogram

{metric} Histogram diff --git a/atom/tests/perf.cpp b/atom/tests/perf.cpp index 7f82e181..9c8f8c8e 100644 --- a/atom/tests/perf.cpp +++ b/atom/tests/perf.cpp @@ -615,4 +615,4 @@ void Perf::finalize() { } spdlog::apply_all([](std::shared_ptr l) { l->flush(); }); -} \ No newline at end of file +} diff --git a/atom/tests/perf.hpp b/atom/tests/perf.hpp index ee1616e0..f46985c7 100644 --- a/atom/tests/perf.hpp +++ b/atom/tests/perf.hpp @@ -306,4 +306,4 @@ template auto measureWithTag(const char* tag, Func&& func, Args&&... args) { Perf p({__func__, __FILE__, __LINE__, tag}); return std::invoke(std::forward(func), std::forward(args)...); -} \ No newline at end of file +} diff --git a/atom/tests/test_cli.hpp b/atom/tests/test_cli.hpp index 6724dab5..4c46dd0c 100644 --- a/atom/tests/test_cli.hpp +++ b/atom/tests/test_cli.hpp @@ -481,4 +481,4 @@ class CommandLineParser { } // namespace atom::test -#endif // ATOM_TEST_CLI_HPP \ No newline at end of file +#endif // ATOM_TEST_CLI_HPP diff --git a/atom/tests/test_registry.hpp b/atom/tests/test_registry.hpp index 2870152d..1e97a1f7 100644 --- a/atom/tests/test_registry.hpp +++ b/atom/tests/test_registry.hpp @@ -310,4 +310,4 @@ inline void clearAllTests() { TestRegistry::instance().clear(); } } // namespace atom::test -#endif // ATOM_TEST_REGISTRY_HPP \ No newline at end of file +#endif // ATOM_TEST_REGISTRY_HPP diff --git a/atom/tests/test_reporter.hpp b/atom/tests/test_reporter.hpp index 051c85fa..4b5a3bdd 100644 --- a/atom/tests/test_reporter.hpp +++ b/atom/tests/test_reporter.hpp @@ -490,4 +490,4 @@ class HtmlReporter : public TestReporter { } // namespace atom::test -#endif // ATOM_TEST_REPORTER_HPP \ No newline at end of file +#endif // ATOM_TEST_REPORTER_HPP diff --git a/atom/tests/test_reporter_charts.hpp b/atom/tests/test_reporter_charts.hpp index 65aeaea2..6d8e69e6 100644 --- a/atom/tests/test_reporter_charts.hpp +++ b/atom/tests/test_reporter_charts.hpp @@ -423,4 +423,4 @@ class ChartReporter : public TestReporter { #endif // ATOM_USE_PYBIND11 -#endif // ATOM_TEST_REPORTER_CHARTS_HPP \ No newline at end of file +#endif // ATOM_TEST_REPORTER_CHARTS_HPP diff --git a/atom/tests/test_runner.hpp b/atom/tests/test_runner.hpp index 303079a6..6d5c08a2 100644 --- a/atom/tests/test_runner.hpp +++ b/atom/tests/test_runner.hpp @@ -755,4 +755,4 @@ class TestRunner { } // namespace atom::test -#endif // ATOM_TEST_RUNNER_HPP \ No newline at end of file +#endif // ATOM_TEST_RUNNER_HPP diff --git a/atom/type/args.hpp b/atom/type/args.hpp index 8a1f8b69..7f98109b 100644 --- a/atom/type/args.hpp +++ b/atom/type/args.hpp @@ -507,4 +507,4 @@ class Args { } // namespace atom -#endif // ATOM_TYPE_ARG_HPP \ No newline at end of file +#endif // ATOM_TYPE_ARG_HPP diff --git a/atom/type/argsview.hpp b/atom/type/argsview.hpp index bdb91c8a..89166d6f 100644 --- a/atom/type/argsview.hpp +++ b/atom/type/argsview.hpp @@ -573,4 +573,4 @@ void print(Args&&... args) { } // namespace atom #endif -#endif // ATOM_TYPE_ARGSVIEW_HPP \ No newline at end of file +#endif // ATOM_TYPE_ARGSVIEW_HPP diff --git a/atom/type/auto_table.hpp b/atom/type/auto_table.hpp index 903adfa4..87e81b18 100644 --- a/atom/type/auto_table.hpp +++ b/atom/type/auto_table.hpp @@ -515,4 +515,4 @@ void CountingHashTable::deserializeFromJson(const json& j) { } // namespace atom::type -#endif // ATOM_TYPE_COUNTING_HASH_TABLE_HPP \ No newline at end of file +#endif // ATOM_TYPE_COUNTING_HASH_TABLE_HPP diff --git a/atom/type/concurrent_map.hpp b/atom/type/concurrent_map.hpp index 7cf309fb..b92954a1 100644 --- a/atom/type/concurrent_map.hpp +++ b/atom/type/concurrent_map.hpp @@ -910,4 +910,4 @@ class concurrent_map { } // namespace atom::type -#endif // ATOM_TYPE_CONCURRENT_MAP_HPP \ No newline at end of file +#endif // ATOM_TYPE_CONCURRENT_MAP_HPP diff --git a/atom/type/concurrent_set.hpp b/atom/type/concurrent_set.hpp index 3649f502..4d1b174a 100644 --- a/atom/type/concurrent_set.hpp +++ b/atom/type/concurrent_set.hpp @@ -1461,4 +1461,4 @@ class concurrent_set { } // namespace atom::type -#endif // ATOM_TYPE_CONCURRENT_SET_HPP \ No newline at end of file +#endif // ATOM_TYPE_CONCURRENT_SET_HPP diff --git a/atom/type/expected.hpp b/atom/type/expected.hpp index 21d0c57f..94edfcda 100644 --- a/atom/type/expected.hpp +++ b/atom/type/expected.hpp @@ -133,7 +133,7 @@ class unexpected { std::is_nothrow_constructible_v) : error_(std::forward(error)) {} - + /** * @brief Gets a const reference to the error value. diff --git a/atom/type/json-schema.hpp b/atom/type/json-schema.hpp index 215bf9cd..2aebfd3e 100644 --- a/atom/type/json-schema.hpp +++ b/atom/type/json-schema.hpp @@ -1762,4 +1762,4 @@ class SchemaManager : public std::enable_shared_from_this { } // namespace atom::type -#endif // ATOM_TYPE_JSON_SCHEMA_HPP \ No newline at end of file +#endif // ATOM_TYPE_JSON_SCHEMA_HPP diff --git a/atom/type/json.hpp b/atom/type/json.hpp index 04944366..14de2792 100644 --- a/atom/type/json.hpp +++ b/atom/type/json.hpp @@ -24789,4 +24789,4 @@ inline void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL& j1, nlohmann::NLOHMANN_BASIC -#endif // INCLUDE_NLOHMANN_JSON_HPP_ \ No newline at end of file +#endif // INCLUDE_NLOHMANN_JSON_HPP_ diff --git a/atom/type/json_fwd.hpp b/atom/type/json_fwd.hpp index 8fec46df..29a6036d 100644 --- a/atom/type/json_fwd.hpp +++ b/atom/type/json_fwd.hpp @@ -173,4 +173,4 @@ using ordered_json = basic_json; NLOHMANN_JSON_NAMESPACE_END -#endif // INCLUDE_NLOHMANN_JSON_FWD_HPP_ \ No newline at end of file +#endif // INCLUDE_NLOHMANN_JSON_FWD_HPP_ diff --git a/atom/type/noncopyable.hpp b/atom/type/noncopyable.hpp index 21b94328..72e0f251 100644 --- a/atom/type/noncopyable.hpp +++ b/atom/type/noncopyable.hpp @@ -48,4 +48,4 @@ class NonCopyable #endif }; -#endif // ATOM_TYPE_NONCOPYABLE_HPP \ No newline at end of file +#endif // ATOM_TYPE_NONCOPYABLE_HPP diff --git a/atom/type/pod_vector.hpp b/atom/type/pod_vector.hpp index 05c3e354..a3e68328 100644 --- a/atom/type/pod_vector.hpp +++ b/atom/type/pod_vector.hpp @@ -693,4 +693,4 @@ class PodVector { } // namespace atom::type -#endif // ATOM_TYPE_POD_VECTOR_HPP \ No newline at end of file +#endif // ATOM_TYPE_POD_VECTOR_HPP diff --git a/atom/type/qvariant.hpp b/atom/type/qvariant.hpp index 657810bd..c8598786 100644 --- a/atom/type/qvariant.hpp +++ b/atom/type/qvariant.hpp @@ -549,4 +549,4 @@ auto operator<<(std::ostream& outputStream, } // namespace atom::type -#endif \ No newline at end of file +#endif diff --git a/atom/type/robin_hood.hpp b/atom/type/robin_hood.hpp index d163e299..7bc7f129 100644 --- a/atom/type/robin_hood.hpp +++ b/atom/type/robin_hood.hpp @@ -515,4 +515,4 @@ class unordered_flat_map { } // namespace atom::utils -#endif \ No newline at end of file +#endif diff --git a/atom/type/ryaml.cpp b/atom/type/ryaml.cpp index 3d7bc185..90d04ad4 100644 --- a/atom/type/ryaml.cpp +++ b/atom/type/ryaml.cpp @@ -1558,4 +1558,4 @@ bool YamlParser::is_first_identifier_char(char c) { return std::isalpha(c) || c == '_'; } -} // namespace atom::type \ No newline at end of file +} // namespace atom::type diff --git a/atom/type/string.hpp b/atom/type/string.hpp index cc560c63..acccade1 100644 --- a/atom/type/string.hpp +++ b/atom/type/string.hpp @@ -1143,4 +1143,4 @@ struct hash { */ inline void swap(String& lhs, String& rhs) noexcept { lhs.swap(rhs); } -#endif // ATOM_TYPE_STRING_HPP \ No newline at end of file +#endif // ATOM_TYPE_STRING_HPP diff --git a/atom/type/trackable.hpp b/atom/type/trackable.hpp index 50b115b6..c826c47e 100644 --- a/atom/type/trackable.hpp +++ b/atom/type/trackable.hpp @@ -325,4 +325,4 @@ class Trackable { } }; -#endif // ATOM_TYPE_TRACKABLE_HPP \ No newline at end of file +#endif // ATOM_TYPE_TRACKABLE_HPP diff --git a/atom/type/uint.hpp b/atom/type/uint.hpp index e2152624..cb070a2f 100644 --- a/atom/type/uint.hpp +++ b/atom/type/uint.hpp @@ -74,4 +74,4 @@ constexpr auto operator""_u64(unsigned long long value) -> uint64_t { return static_cast(value); } -#endif // ATOM_TYPE_UINT_HPP \ No newline at end of file +#endif // ATOM_TYPE_UINT_HPP diff --git a/atom/type/weak_ptr.hpp b/atom/type/weak_ptr.hpp index 07c3b8f4..40b71764 100644 --- a/atom/type/weak_ptr.hpp +++ b/atom/type/weak_ptr.hpp @@ -811,4 +811,4 @@ template } // namespace atom::type -#endif // ATOM_TYPE_WEAK_PTR_HPP \ No newline at end of file +#endif // ATOM_TYPE_WEAK_PTR_HPP diff --git a/atom/type/xmake.lua b/atom/type/xmake.lua index fee077ee..709669f0 100644 --- a/atom/type/xmake.lua +++ b/atom/type/xmake.lua @@ -36,15 +36,15 @@ local headers = { -- Object Library target("atom-type-object") set_kind("object") - + -- Add files add_headerfiles(table.unpack(headers)) add_files(table.unpack(sources)) - + -- Add include directories add_includedirs(".", {public = true}) add_includedirs("..", {public = true}) - + -- Set C++ standard set_languages("c++20") target_end() @@ -53,17 +53,17 @@ target_end() target("atom-type") -- Set library type based on parent project option set_kind(has_config("shared_libs") and "shared" or "static") - + -- Add dependencies add_deps("atom-type-object", "atom-utils") - + -- Set include directories add_includedirs(".", {public = true}) - + -- Set output directories set_targetdir("$(buildir)/lib") set_objectdir("$(buildir)/obj") - + -- Install configuration on_install(function (target) os.cp(target:targetfile(), path.join(target:installdir(), "lib")) diff --git a/atom/utils/CMakeLists.txt b/atom/utils/CMakeLists.txt index 47927836..52182821 100644 --- a/atom/utils/CMakeLists.txt +++ b/atom/utils/CMakeLists.txt @@ -93,4 +93,4 @@ set_target_properties(${PROJECT_NAME} PROPERTIES # Installation install(TARGETS ${PROJECT_NAME} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} -) \ No newline at end of file +) diff --git a/atom/utils/aligned.hpp b/atom/utils/aligned.hpp index ada8f658..a8f767f8 100644 --- a/atom/utils/aligned.hpp +++ b/atom/utils/aligned.hpp @@ -61,4 +61,4 @@ class ValidateAlignedStorage { } // namespace atom::utils -#endif // ATOM_UTILS_ALIGNED_HPP \ No newline at end of file +#endif // ATOM_UTILS_ALIGNED_HPP diff --git a/atom/utils/bit.hpp b/atom/utils/bit.hpp index 20e109a3..33c0e108 100644 --- a/atom/utils/bit.hpp +++ b/atom/utils/bit.hpp @@ -498,4 +498,4 @@ auto parallelBitOp(std::span input, Op op) -> std::vector { } // namespace atom::utils -#endif // ATOM_UTILS_BIT_HPP \ No newline at end of file +#endif // ATOM_UTILS_BIT_HPP diff --git a/atom/utils/color_print.hpp b/atom/utils/color_print.hpp index 8bd9ddca..5b122843 100644 --- a/atom/utils/color_print.hpp +++ b/atom/utils/color_print.hpp @@ -195,4 +195,4 @@ using TextStyle = atom::utils::TextStyle; using ColorPrinter = atom::utils::ColorPrinter; } // namespace atom::test -#endif // ATOM_UTILS_COLOR_PRINT_HPP \ No newline at end of file +#endif // ATOM_UTILS_COLOR_PRINT_HPP diff --git a/atom/utils/convert.cpp b/atom/utils/convert.cpp index 23e033dc..2b507223 100644 --- a/atom/utils/convert.cpp +++ b/atom/utils/convert.cpp @@ -307,4 +307,4 @@ std::wstring LPCWSTRToWString(LPCWSTR lpcwstr) { } // namespace atom::utils -#endif \ No newline at end of file +#endif diff --git a/atom/utils/convert.hpp b/atom/utils/convert.hpp index 849188c6..b180e4a3 100644 --- a/atom/utils/convert.hpp +++ b/atom/utils/convert.hpp @@ -87,4 +87,4 @@ namespace atom::utils { } // namespace atom::utils #endif -#endif \ No newline at end of file +#endif diff --git a/atom/utils/lcg.cpp b/atom/utils/lcg.cpp index 799b3731..f7a4edb5 100644 --- a/atom/utils/lcg.cpp +++ b/atom/utils/lcg.cpp @@ -511,4 +511,4 @@ auto LCG::nextMultinomial(int trials, std::span probabilities) return counts; } -} // namespace atom::utils \ No newline at end of file +} // namespace atom::utils diff --git a/atom/utils/qprocess.cpp b/atom/utils/qprocess.cpp index 84c32d7a..b0b1771c 100644 --- a/atom/utils/qprocess.cpp +++ b/atom/utils/qprocess.cpp @@ -868,7 +868,7 @@ void QProcess::Impl::startAsyncReaders() { #else pollfd pfd = {childStdout_, POLLIN, 0}; int poll_result = poll(&pfd, 1, 100); - + if (poll_result > 0 && (pfd.revents & POLLIN)) { ssize_t bytesRead = ::read(childStdout_, buffer.data(), buffer.size()); if (bytesRead > 0) { @@ -907,7 +907,7 @@ void QProcess::Impl::startAsyncReaders() { #else pollfd pfd = {childStderr_, POLLIN, 0}; int poll_result = poll(&pfd, 1, 100); - + if (poll_result > 0 && (pfd.revents & POLLIN)) { ssize_t bytesRead = ::read(childStderr_, buffer.data(), buffer.size()); if (bytesRead > 0) { diff --git a/atom/utils/qtimer.cpp b/atom/utils/qtimer.cpp index 080aaf4c..0bc60646 100644 --- a/atom/utils/qtimer.cpp +++ b/atom/utils/qtimer.cpp @@ -338,4 +338,4 @@ void Timer::timerLoop() { } } -} // namespace atom::utils \ No newline at end of file +} // namespace atom::utils diff --git a/atom/utils/random.cpp b/atom/utils/random.cpp index b673d19b..bb8762b2 100644 --- a/atom/utils/random.cpp +++ b/atom/utils/random.cpp @@ -53,7 +53,7 @@ auto generateRandomString(int length, const std::string& charset, bool secure) - } } else { std::uniform_int_distribution dist(0, chars.size() - 1); - + for (int i = 0; i < length; ++i) { result.push_back(chars[dist(thread_engine)]); } diff --git a/atom/utils/simd_wrapper.hpp b/atom/utils/simd_wrapper.hpp index a64d997a..ae5a1742 100644 --- a/atom/utils/simd_wrapper.hpp +++ b/atom/utils/simd_wrapper.hpp @@ -643,4 +643,4 @@ using uint64x2_t = Vec; // 128位64位无符号整数向量 } // namespace simd -#endif // SIMD_WRAPPER_HPP \ No newline at end of file +#endif // SIMD_WRAPPER_HPP diff --git a/atom/utils/span.hpp b/atom/utils/span.hpp index 953bf7ca..233daf10 100644 --- a/atom/utils/span.hpp +++ b/atom/utils/span.hpp @@ -567,4 +567,4 @@ template } // namespace atom::utils -#endif // ATOM_UTILS_SPAN_HPP \ No newline at end of file +#endif // ATOM_UTILS_SPAN_HPP diff --git a/atom/utils/stopwatcher.cpp b/atom/utils/stopwatcher.cpp index dd135bdd..3668438f 100644 --- a/atom/utils/stopwatcher.cpp +++ b/atom/utils/stopwatcher.cpp @@ -710,4 +710,4 @@ auto StopWatcher::fromJson(std::string_view json) } } -} // namespace atom::utils \ No newline at end of file +} // namespace atom::utils diff --git a/atom/utils/stopwatcher.hpp b/atom/utils/stopwatcher.hpp index 05ee142a..f6d5cf07 100644 --- a/atom/utils/stopwatcher.hpp +++ b/atom/utils/stopwatcher.hpp @@ -309,4 +309,4 @@ class ScopedStopWatch { }; } // namespace atom::utils -#endif \ No newline at end of file +#endif diff --git a/atom/utils/switch.hpp b/atom/utils/switch.hpp index e468c94a..04c31e36 100644 --- a/atom/utils/switch.hpp +++ b/atom/utils/switch.hpp @@ -651,4 +651,4 @@ StringSwitch( } // namespace atom::utils -#endif // ATOM_UTILS_SWITCH_HPP \ No newline at end of file +#endif // ATOM_UTILS_SWITCH_HPP diff --git a/atom/utils/time.cpp b/atom/utils/time.cpp index 845ba4a0..86cd329a 100644 --- a/atom/utils/time.cpp +++ b/atom/utils/time.cpp @@ -426,4 +426,4 @@ auto timestampToTime(long long timestamp) -> std::optional { } } -} // namespace atom::utils \ No newline at end of file +} // namespace atom::utils diff --git a/atom/utils/to_byte.hpp b/atom/utils/to_byte.hpp index a12e4ce7..dfdb7dc3 100644 --- a/atom/utils/to_byte.hpp +++ b/atom/utils/to_byte.hpp @@ -783,4 +783,4 @@ inline auto loadFromFile(const std::string& filename) -> std::vector { } // namespace atom::utils -#endif // ATOM_UTILS_TO_BYTE_HPP \ No newline at end of file +#endif // ATOM_UTILS_TO_BYTE_HPP diff --git a/atom/utils/to_string.hpp b/atom/utils/to_string.hpp index 07ae59c5..a23afaee 100644 --- a/atom/utils/to_string.hpp +++ b/atom/utils/to_string.hpp @@ -201,7 +201,7 @@ template auto toString(const T& ptr) -> std::string { try { if (ptr) { - return std::format("SmartPointer({}, {})", + return std::format("SmartPointer({}, {})", static_cast(ptr.get()), toString(*ptr)); } return "nullptr"; @@ -287,7 +287,7 @@ auto toString(const T& container) -> std::string { * @throws ToStringException if conversion fails */ template - requires(!StringType && !Container && !PointerType && + requires(!StringType && !Container && !PointerType && !EnumType && !SmartPointer) auto toString(const T& value) -> std::string { try { @@ -323,11 +323,11 @@ auto joinCommandLine(const Args&... args) -> std::string { try { std::string result; result.reserve(sizeof...(args) * 32); - + bool first = true; - ((first ? (result += toString(args), first = false) + ((first ? (result += toString(args), first = false) : (result += " " + toString(args))), ...); - + return result; } catch (const std::exception& e) { throw ToStringException(std::format("Command line joining failed: {}", e.what())); @@ -432,7 +432,7 @@ auto toString(const std::array& array) -> std::string { * @throws ToStringException if conversion fails */ template -auto tupleToStringImpl(const Tuple& tpl, std::index_sequence, +auto tupleToStringImpl(const Tuple& tpl, std::index_sequence, std::string_view separator) -> std::string { try { std::string result = "("; diff --git a/atom/utils/valid_string.cpp b/atom/utils/valid_string.cpp index 85d6406a..8fe1704a 100644 --- a/atom/utils/valid_string.cpp +++ b/atom/utils/valid_string.cpp @@ -511,4 +511,4 @@ template auto validateImpl(const char*&&, const ValidationOptions&) template auto validateImpl(char*&&, const ValidationOptions&) -> std::expected; -} // namespace atom::utils \ No newline at end of file +} // namespace atom::utils diff --git a/atom/utils/xmake.lua b/atom/utils/xmake.lua index 5efa9807..6446b495 100644 --- a/atom/utils/xmake.lua +++ b/atom/utils/xmake.lua @@ -42,18 +42,18 @@ local headers = { -- Object Library target("atom-utils-object") set_kind("object") - + -- Add files add_headerfiles(table.unpack(headers)) add_files(table.unpack(sources)) - + -- Add dependencies add_packages("loguru", "tinyxml2") - + -- Add include directories add_includedirs(".", {public = true}) add_includedirs("..", {public = true}) - + -- Set C++ standard set_languages("c++20") target_end() @@ -62,18 +62,18 @@ target_end() target("atom-utils") -- Set library type based on parent project option set_kind(has_config("shared_libs") and "shared" or "static") - + -- Add dependencies add_deps("atom-utils-object") add_packages("loguru", "tinyxml2") - + -- Add include directories add_includedirs(".", {public = true}) - + -- Set output directories set_targetdir("$(buildir)/lib") set_objectdir("$(buildir)/obj") - + -- Install configuration on_install(function (target) os.cp(target:targetfile(), path.join(target:installdir(), "lib")) diff --git a/atom/utils/xml.cpp b/atom/utils/xml.cpp index cbc3855c..89dae3fc 100644 --- a/atom/utils/xml.cpp +++ b/atom/utils/xml.cpp @@ -355,4 +355,4 @@ auto XMLReader::isValidPath(std::string_view path) -> bool { return !path.empty(); // Placeholder } -} // namespace atom::utils \ No newline at end of file +} // namespace atom::utils diff --git a/atom/web/CMakeLists.txt b/atom/web/CMakeLists.txt index d4a67043..a4a0d8ea 100644 --- a/atom/web/CMakeLists.txt +++ b/atom/web/CMakeLists.txt @@ -70,7 +70,7 @@ set_property(TARGET ${PROJECT_NAME}_object PROPERTY POSITION_INDEPENDENT_CODE 1) target_link_libraries(${PROJECT_NAME}_object PRIVATE ${LIBS} atom-web-time) # Build Static Library -add_library(${PROJECT_NAME} STATIC +add_library(${PROJECT_NAME} STATIC $ $ $ @@ -88,4 +88,4 @@ set_target_properties(${PROJECT_NAME} PROPERTIES # Installation install(TARGETS ${PROJECT_NAME} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} -) \ No newline at end of file +) diff --git a/atom/web/address/CMakeLists.txt b/atom/web/address/CMakeLists.txt index 6be08dbc..69922e4a 100644 --- a/atom/web/address/CMakeLists.txt +++ b/atom/web/address/CMakeLists.txt @@ -44,4 +44,4 @@ target_include_directories(atom-web-address PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/. install(FILES ${ADDRESS_HEADERS} DESTINATION include/atom/web/address COMPONENT Development -) \ No newline at end of file +) diff --git a/atom/web/address/main.hpp b/atom/web/address/main.hpp index bf876b21..7de56e49 100644 --- a/atom/web/address/main.hpp +++ b/atom/web/address/main.hpp @@ -5,14 +5,14 @@ // 统一引入所有地址类型和相关功能 #include "address.hpp" -#include "ipv4.hpp" +#include "ipv4.hpp" #include "ipv6.hpp" #include "unix_domain.hpp" /** * @namespace atom::web * @brief 用于网络相关功能的命名空间 - * + * * 这个命名空间包含了各种网络地址类型和相关操作: * - IPv4 地址处理 * - IPv6 地址处理 @@ -26,7 +26,7 @@ namespace atom::web { * @brief 创建一个合适类型的地址对象 * @param addressString 地址字符串 (可以是IPv4, IPv6或Unix域套接字路径) * @return std::unique_ptr
指向创建的地址对象的智能指针 - * + * * 这是一个便捷函数,它会自动检测地址类型并创建相应的对象。 * 如果地址类型无法识别,将返回nullptr。 */ diff --git a/atom/web/curl.hpp b/atom/web/curl.hpp index aad627eb..6a381b9e 100644 --- a/atom/web/curl.hpp +++ b/atom/web/curl.hpp @@ -150,4 +150,4 @@ class CurlWrapper { } // namespace atom::web -#endif // ATOM_WEB_CURL_HPP \ No newline at end of file +#endif // ATOM_WEB_CURL_HPP diff --git a/atom/web/downloader.hpp b/atom/web/downloader.hpp index 53854faa..f18c7954 100644 --- a/atom/web/downloader.hpp +++ b/atom/web/downloader.hpp @@ -156,4 +156,4 @@ class DownloadManager { std::unique_ptr impl_; }; -} // namespace atom::web \ No newline at end of file +} // namespace atom::web diff --git a/atom/web/minetype.hpp b/atom/web/minetype.hpp index a104ae86..78a874d4 100644 --- a/atom/web/minetype.hpp +++ b/atom/web/minetype.hpp @@ -188,4 +188,4 @@ class MimeTypes { std::unique_ptr pImpl; }; -#endif // ATOM_WEB_MIMETYPE_HPP \ No newline at end of file +#endif // ATOM_WEB_MIMETYPE_HPP diff --git a/atom/web/time/xmake.lua b/atom/web/time/xmake.lua index d17f5694..ece385f8 100644 --- a/atom/web/time/xmake.lua +++ b/atom/web/time/xmake.lua @@ -21,22 +21,22 @@ local time_headers = { -- Build Object Library target("atom-web-time-object") set_kind("object") - + -- Add files add_headerfiles(table.unpack(time_headers)) add_files(table.unpack(time_sources)) - + -- Add dependencies add_packages("loguru") - + -- Add include directories add_includedirs("$(projectdir)/atom", {public = true}) - + -- Platform-specific settings if is_plat("windows") then add_syslinks("wsock32", "ws2_32") end - + -- Set C++ standard set_languages("c++20") target_end() diff --git a/atom/web/utils/dns.hpp b/atom/web/utils/dns.hpp index 1563273a..80a723b5 100644 --- a/atom/web/utils/dns.hpp +++ b/atom/web/utils/dns.hpp @@ -23,7 +23,7 @@ namespace atom::web { /** * @brief Set the Time-To-Live for DNS cache entries - * + * * @param ttlSeconds The TTL in seconds */ void setDNSCacheTTL(std::chrono::seconds ttlSeconds); diff --git a/atom/web/xmake.lua b/atom/web/xmake.lua index 506d6097..465763c3 100644 --- a/atom/web/xmake.lua +++ b/atom/web/xmake.lua @@ -59,18 +59,18 @@ end -- Object Library target("atom-web-object") set_kind("object") - + -- Add files add_headerfiles(table.unpack(headers)) add_files(table.unpack(sources)) - + -- Add dependencies add_packages("loguru") - + -- Add include directories add_includedirs(".", {public = true}) add_includedirs("..", {public = true}) - + -- Set C++ standard set_languages("c++20") target_end() @@ -79,23 +79,23 @@ target_end() target("atom-web") -- Set library type based on parent project option set_kind(has_config("shared_libs") and "shared" or "static") - + -- Add dependencies add_deps("atom-web-object") add_packages("loguru", "cpp-httplib") - + -- Add include directories add_includedirs(".", {public = true}) - + -- Platform-specific settings if is_plat("windows") then add_syslinks("wsock32", "ws2_32") end - + -- Set output directories set_targetdir("$(buildir)/lib") set_objectdir("$(buildir)/obj") - + -- Install configuration on_install(function (target) os.cp(target:targetfile(), path.join(target:installdir(), "lib")) diff --git a/atom/xmake.lua b/atom/xmake.lua index ea242dd1..81e0eae6 100644 --- a/atom/xmake.lua +++ b/atom/xmake.lua @@ -33,8 +33,8 @@ option_end() -- Module build options local modules = { - "algorithm", "async", "components", "connection", "containers", - "error", "io", "log", "memory", "meta", "search", "secret", + "algorithm", "async", "components", "connection", "containers", + "error", "io", "log", "memory", "meta", "search", "secret", "serial", "sysinfo", "system", "type", "utils", "web" } @@ -66,7 +66,7 @@ option_end() if has_config("python") then add_requires("python3", "pybind11") - + after_load(function () local python = find_tool("python3") if python then @@ -94,7 +94,7 @@ end function check_module_directory(name, dir_name) local module_path = path.join(".", dir_name) local xmake_file = path.join(module_path, "xmake.lua") - + if os.isdir(module_path) and os.isfile(xmake_file) then return true else @@ -161,16 +161,16 @@ end if has_config("unified") and #_G.ATOM_MODULES > 0 then target("atom-unified") set_kind("phony") - + -- Add all module dependencies for _, module in ipairs(_G.ATOM_MODULES) do add_deps(module) end - + after_build(function (target) print("Created unified Atom library with modules: " .. table.concat(_G.ATOM_MODULES, ", ")) end) - + -- Create atom alias target target("atom") set_kind("phony") @@ -187,7 +187,7 @@ task("install-all") usage = "xmake install-all", description = "Install all Atom modules" } - + on_run(function () for _, module in ipairs(_G.ATOM_MODULES) do os.exec("xmake install " .. module) diff --git a/build.bat b/build.bat index 18176962..6d3d5590 100644 --- a/build.bat +++ b/build.bat @@ -135,7 +135,7 @@ if "%CLEAN_BUILD%"=="y" ( REM Build using the selected system if "%BUILD_SYSTEM%"=="xmake" ( echo Building with XMake... - + REM Configure XMake options set XMAKE_ARGS= if "%BUILD_TYPE%"=="debug" set XMAKE_ARGS=%XMAKE_ARGS% -m debug @@ -145,7 +145,7 @@ if "%BUILD_SYSTEM%"=="xmake" ( if "%BUILD_TESTS%"=="y" set XMAKE_ARGS=%XMAKE_ARGS% --tests=y if "%BUILD_CFITSIO%"=="y" set XMAKE_ARGS=%XMAKE_ARGS% --cfitsio=y if "%BUILD_SSH%"=="y" set XMAKE_ARGS=%XMAKE_ARGS% --ssh=y - + REM Run XMake echo Configuring XMake project... xmake f %XMAKE_ARGS% @@ -153,7 +153,7 @@ if "%BUILD_SYSTEM%"=="xmake" ( echo Error: XMake configuration failed exit /b 1 ) - + echo Building project... xmake if %ERRORLEVEL% NEQ 0 ( @@ -162,7 +162,7 @@ if "%BUILD_SYSTEM%"=="xmake" ( ) ) else ( echo Building with CMake... - + REM Configure CMake options set CMAKE_ARGS=-B build if "%BUILD_TYPE%"=="debug" set CMAKE_ARGS=%CMAKE_ARGS% -DCMAKE_BUILD_TYPE=Debug @@ -173,7 +173,7 @@ if "%BUILD_SYSTEM%"=="xmake" ( if "%BUILD_TESTS%"=="y" set CMAKE_ARGS=%CMAKE_ARGS% -DATOM_BUILD_TESTS=ON if "%BUILD_CFITSIO%"=="y" set CMAKE_ARGS=%CMAKE_ARGS% -DATOM_USE_CFITSIO=ON if "%BUILD_SSH%"=="y" set CMAKE_ARGS=%CMAKE_ARGS% -DATOM_USE_SSH=ON - + REM Run CMake echo Configuring CMake project... cmake %CMAKE_ARGS% . @@ -181,7 +181,7 @@ if "%BUILD_SYSTEM%"=="xmake" ( echo Error: CMake configuration failed exit /b 1 ) - + echo Building project... cmake --build build --config %BUILD_TYPE% if %ERRORLEVEL% NEQ 0 ( diff --git a/build.sh b/build.sh index 4ade7a83..532d7e45 100644 --- a/build.sh +++ b/build.sh @@ -130,7 +130,7 @@ fi # Build using the selected system if [[ "$BUILD_SYSTEM" == "xmake" ]]; then echo "Building with XMake..." - + # Configure XMake options XMAKE_ARGS="" if [[ "$BUILD_TYPE" == "debug" ]]; then XMAKE_ARGS="$XMAKE_ARGS -m debug"; fi @@ -140,7 +140,7 @@ if [[ "$BUILD_SYSTEM" == "xmake" ]]; then if [[ "$BUILD_TESTS" == "y" ]]; then XMAKE_ARGS="$XMAKE_ARGS --tests=y"; fi if [[ "$BUILD_CFITSIO" == "y" ]]; then XMAKE_ARGS="$XMAKE_ARGS --cfitsio=y"; fi if [[ "$BUILD_SSH" == "y" ]]; then XMAKE_ARGS="$XMAKE_ARGS --ssh=y"; fi - + # Run XMake echo "Configuring XMake project..." xmake f $XMAKE_ARGS @@ -148,7 +148,7 @@ if [[ "$BUILD_SYSTEM" == "xmake" ]]; then echo "Error: XMake configuration failed" exit 1 fi - + echo "Building project..." xmake if [ $? -ne 0 ]; then @@ -157,7 +157,7 @@ if [[ "$BUILD_SYSTEM" == "xmake" ]]; then fi else echo "Building with CMake..." - + # Configure CMake options CMAKE_ARGS="-B build" if [[ "$BUILD_TYPE" == "debug" ]]; then CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_BUILD_TYPE=Debug"; fi @@ -168,7 +168,7 @@ else if [[ "$BUILD_TESTS" == "y" ]]; then CMAKE_ARGS="$CMAKE_ARGS -DATOM_BUILD_TESTS=ON"; fi if [[ "$BUILD_CFITSIO" == "y" ]]; then CMAKE_ARGS="$CMAKE_ARGS -DATOM_USE_CFITSIO=ON"; fi if [[ "$BUILD_SSH" == "y" ]]; then CMAKE_ARGS="$CMAKE_ARGS -DATOM_USE_SSH=ON"; fi - + # Run CMake echo "Configuring CMake project..." cmake $CMAKE_ARGS . @@ -176,7 +176,7 @@ else echo "Error: CMake configuration failed" exit 1 fi - + # Determine number of CPU cores for parallel build if command -v nproc &> /dev/null; then CORES=$(nproc) @@ -185,7 +185,7 @@ else else CORES=4 # Default to 4 cores if we can't determine fi - + echo "Building project using $CORES cores..." cmake --build build --config $BUILD_TYPE --parallel $CORES if [ $? -ne 0 ]; then diff --git a/cmake/ExamplesBuildOptions.cmake b/cmake/ExamplesBuildOptions.cmake index db32f4cb..1472712c 100644 --- a/cmake/ExamplesBuildOptions.cmake +++ b/cmake/ExamplesBuildOptions.cmake @@ -1,7 +1,7 @@ # ExamplesBuildOptions.cmake # # This file contains all options for controlling the build of Atom examples -# +# # Author: Max Qian # License: GPL3 diff --git a/cmake/FindAsio.cmake b/cmake/FindAsio.cmake index 6aa02f2a..951b9b84 100644 --- a/cmake/FindAsio.cmake +++ b/cmake/FindAsio.cmake @@ -4,14 +4,14 @@ if(ASIO_INCLUDE_DIR) set(Asio_FOUND TRUE) set(ASIO_STANDALONE TRUE) set(ASIO_INCLUDE_DIRS ${ASIO_INCLUDE_DIR}) - + if(NOT TARGET Asio::Asio) add_library(Asio::Asio INTERFACE IMPORTED) set_target_properties(Asio::Asio PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${ASIO_INCLUDE_DIRS}" INTERFACE_COMPILE_DEFINITIONS "ASIO_STANDALONE") endif() - + mark_as_advanced(ASIO_INCLUDE_DIR) else() find_package(Boost QUIET COMPONENTS system) @@ -21,7 +21,7 @@ else() set(Asio_FOUND TRUE) set(ASIO_STANDALONE FALSE) set(ASIO_INCLUDE_DIRS ${Boost_INCLUDE_DIRS}) - + if(NOT TARGET Asio::Asio) add_library(Asio::Asio INTERFACE IMPORTED) set_target_properties(Asio::Asio PROPERTIES diff --git a/cmake/FindReadline.cmake b/cmake/FindReadline.cmake index 87a9e977..a2ced20d 100644 --- a/cmake/FindReadline.cmake +++ b/cmake/FindReadline.cmake @@ -12,11 +12,11 @@ endif() # **Windows specific search paths** if(WIN32) # Native Windows paths - list(APPEND CMAKE_PREFIX_PATH + list(APPEND CMAKE_PREFIX_PATH "C:/Program Files/readline" "C:/readline" ) - + # **MSYS2 environment paths** # First, try to get MSYS2 paths from the PATH environment variable set(_msys_prefixes_from_env_path "") @@ -24,7 +24,7 @@ if(WIN32) set(_path_list "$ENV{PATH}") string(REPLACE ";" "\\;" _path_list "${_path_list}") string(REPLACE "\\" "/" _path_list "${_path_list}") - + if(WIN32) string(REPLACE ";" "\\\\;" _path_list_escaped "${_path_list}") string(REPLACE "\\\\;" ";" _path_list_escaped "${_path_list_escaped}") @@ -33,10 +33,10 @@ if(WIN32) else() string(REPLACE ":" ";" _path_list_cmake "${_path_list}") endif() - + foreach(_path_entry IN LISTS _path_list_cmake) string(REPLACE "\\" "/" _path_entry "${_path_entry}") - + if(_path_entry MATCHES ".*/mingw64/bin$") get_filename_component(_prefix_mingw64 "${_path_entry}" DIRECTORY) list(APPEND _msys_prefixes_from_env_path "${_prefix_mingw64}") @@ -71,7 +71,7 @@ if(WIN32) endif() endif() endforeach() - + if(_msys_prefixes_from_env_path) list(REMOVE_DUPLICATES _msys_prefixes_from_env_path) list(APPEND CMAKE_PREFIX_PATH ${_msys_prefixes_from_env_path}) @@ -93,7 +93,7 @@ if(WIN32) endif() else() # Finally, check common MSYS2 installation paths - list(APPEND CMAKE_PREFIX_PATH + list(APPEND CMAKE_PREFIX_PATH "D:/msys64/mingw64" "D:/msys64/mingw32" "D:/msys64/usr" @@ -114,9 +114,9 @@ endif() # Find include directory find_path(Readline_INCLUDE_DIR NAMES readline/readline.h - PATHS + PATHS ${READLINE_ROOT}/include - /usr/include + /usr/include /usr/local/include /opt/local/include /sw/include @@ -127,30 +127,30 @@ find_path(Readline_INCLUDE_DIR if(WIN32) find_library(Readline_LIBRARY NAMES readline libreadline readline.lib - PATHS + PATHS ${READLINE_ROOT}/lib - /usr/lib + /usr/lib /usr/local/lib /opt/local/lib /sw/lib ) - + # **On Windows/MSYS2, Readline often depends on ncurses or termcap** find_library(Readline_NCURSES_LIBRARY NAMES ncurses libncurses ncursesw libncursesw pdcurses - PATHS + PATHS ${READLINE_ROOT}/lib - /usr/lib + /usr/lib /usr/local/lib /opt/local/lib /sw/lib ) - + find_library(Readline_TERMCAP_LIBRARY NAMES termcap libtermcap - PATHS + PATHS ${READLINE_ROOT}/lib - /usr/lib + /usr/lib /usr/local/lib /opt/local/lib /sw/lib @@ -158,9 +158,9 @@ if(WIN32) else() find_library(Readline_LIBRARY NAMES readline - PATHS + PATHS ${READLINE_ROOT}/lib - /usr/lib + /usr/lib /usr/local/lib /opt/local/lib /sw/lib @@ -188,7 +188,7 @@ if(Readline_FOUND) endif() mark_as_advanced( - Readline_INCLUDE_DIR + Readline_INCLUDE_DIR Readline_LIBRARY Readline_NCURSES_LIBRARY Readline_TERMCAP_LIBRARY diff --git a/cmake/FindYamlCpp.cmake b/cmake/FindYamlCpp.cmake index f7170cfb..888b4594 100644 --- a/cmake/FindYamlCpp.cmake +++ b/cmake/FindYamlCpp.cmake @@ -39,7 +39,7 @@ if(WIN32) if(MSVC) set(_YAMLCPP_MSVC_SUFFIX "md" CACHE STRING "基于运行时库选择的 yaml-cpp 库后缀") if(CMAKE_BUILD_TYPE STREQUAL "Debug") - set(_YAMLCPP_LIB_NAMES + set(_YAMLCPP_LIB_NAMES yaml-cppd libyaml-cppd yaml-cpp${_YAMLCPP_MSVC_SUFFIX}d @@ -47,7 +47,7 @@ if(WIN32) yaml-cpp libyaml-cpp) else() - set(_YAMLCPP_LIB_NAMES + set(_YAMLCPP_LIB_NAMES yaml-cpp libyaml-cpp yaml-cpp${_YAMLCPP_MSVC_SUFFIX} @@ -76,11 +76,11 @@ endif() # 尝试查找包含目录 find_path(YAMLCPP_INCLUDE_DIR NAMES yaml-cpp/yaml.h - HINTS + HINTS ${PC_YAMLCPP_INCLUDEDIR} ${PC_YAMLCPP_INCLUDE_DIRS} ${_YAMLCPP_POSSIBLE_ROOT_DIRS} - PATH_SUFFIXES + PATH_SUFFIXES include yaml-cpp/include ) @@ -88,11 +88,11 @@ find_path(YAMLCPP_INCLUDE_DIR # 尝试查找库文件 find_library(YAMLCPP_LIBRARY NAMES ${_YAMLCPP_LIB_NAMES} - HINTS + HINTS ${PC_YAMLCPP_LIBDIR} ${PC_YAMLCPP_LIBRARY_DIRS} ${_YAMLCPP_POSSIBLE_ROOT_DIRS} - PATH_SUFFIXES + PATH_SUFFIXES lib lib64 lib/${CMAKE_LIBRARY_ARCHITECTURE} @@ -107,12 +107,12 @@ if(YAMLCPP_INCLUDE_DIR AND NOT YAMLCPP_VERSION) string(REGEX MATCH "#define YAML_CPP_VERSION_MAJOR ([0-9]+)" _YAMLCPP_MAJOR_VERSION_MATCH "${_YAMLCPP_VERSION_HEADER}") string(REGEX MATCH "#define YAML_CPP_VERSION_MINOR ([0-9]+)" _YAMLCPP_MINOR_VERSION_MATCH "${_YAMLCPP_VERSION_HEADER}") string(REGEX MATCH "#define YAML_CPP_VERSION_PATCH ([0-9]+)" _YAMLCPP_PATCH_VERSION_MATCH "${_YAMLCPP_VERSION_HEADER}") - + if(_YAMLCPP_MAJOR_VERSION_MATCH AND _YAMLCPP_MINOR_VERSION_MATCH AND _YAMLCPP_PATCH_VERSION_MATCH) string(REGEX REPLACE "#define YAML_CPP_VERSION_MAJOR ([0-9]+)" "\\1" _YAMLCPP_MAJOR_VERSION "${_YAMLCPP_MAJOR_VERSION_MATCH}") string(REGEX REPLACE "#define YAML_CPP_VERSION_MINOR ([0-9]+)" "\\1" _YAMLCPP_MINOR_VERSION "${_YAMLCPP_MINOR_VERSION_MATCH}") string(REGEX REPLACE "#define YAML_CPP_VERSION_PATCH ([0-9]+)" "\\1" _YAMLCPP_PATCH_VERSION "${_YAMLCPP_PATCH_VERSION_MATCH}") - + set(YAMLCPP_VERSION "${_YAMLCPP_MAJOR_VERSION}.${_YAMLCPP_MINOR_VERSION}.${_YAMLCPP_PATCH_VERSION}") endif() endif() diff --git a/cmake/GitVersion.cmake b/cmake/GitVersion.cmake index e355a8b9..b538ac49 100644 --- a/cmake/GitVersion.cmake +++ b/cmake/GitVersion.cmake @@ -10,15 +10,15 @@ function(configure_version_from_git) if(NOT DEFINED ARG_OUTPUT_HEADER) set(ARG_OUTPUT_HEADER "${CMAKE_CURRENT_BINARY_DIR}/version.h") endif() - + if(NOT DEFINED ARG_VERSION_VARIABLE) set(ARG_VERSION_VARIABLE PROJECT_VERSION) endif() - + if(NOT DEFINED ARG_PREFIX) set(ARG_PREFIX "${PROJECT_NAME}") endif() - + # Get Git information find_package(Git QUIET) if(GIT_FOUND) @@ -30,7 +30,7 @@ function(configure_version_from_git) OUTPUT_QUIET ERROR_QUIET ) - + if(GIT_REPO_CHECK EQUAL 0) # Get the most recent tag execute_process( @@ -41,7 +41,7 @@ function(configure_version_from_git) ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE ) - + # Get the current commit short hash execute_process( COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD @@ -51,7 +51,7 @@ function(configure_version_from_git) ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE ) - + # Get the number of commits since the most recent tag execute_process( COMMAND ${GIT_EXECUTABLE} rev-list --count ${GIT_TAG}..HEAD @@ -61,20 +61,20 @@ function(configure_version_from_git) ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE ) - + # Check if the working directory is clean execute_process( COMMAND ${GIT_EXECUTABLE} diff --quiet HEAD WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} RESULT_VARIABLE GIT_DIRTY_RESULT ) - + if(NOT GIT_DIRTY_RESULT EQUAL 0) set(GIT_DIRTY "-dirty") else() set(GIT_DIRTY "") endif() - + # Build version string if(GIT_TAG_RESULT EQUAL 0) # Parse tag version number (assuming format vX.Y.Z or X.Y.Z) @@ -83,12 +83,12 @@ function(configure_version_from_git) set(VERSION_MAJOR ${CMAKE_MATCH_1}) set(VERSION_MINOR ${CMAKE_MATCH_2}) set(VERSION_PATCH ${CMAKE_MATCH_3}) - + # If there are additional commits, increment the patch version if(GIT_COUNT GREATER 0) math(EXPR VERSION_PATCH "${VERSION_PATCH}+${GIT_COUNT}") endif() - + set(VERSION_STRING "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}${GIT_DIRTY}") else() set(VERSION_STRING "${GIT_TAG}-${GIT_HASH}${GIT_DIRTY}") @@ -103,7 +103,7 @@ function(configure_version_from_git) set(VERSION_MINOR 0) set(VERSION_PATCH 0) endif() - + # Set variables in parent scope set(${ARG_VERSION_VARIABLE} "${VERSION_STRING}" PARENT_SCOPE) set(PROJECT_VERSION_MAJOR ${VERSION_MAJOR} PARENT_SCOPE) @@ -111,10 +111,10 @@ function(configure_version_from_git) set(PROJECT_VERSION_PATCH ${VERSION_PATCH} PARENT_SCOPE) set(GIT_HASH ${GIT_HASH} PARENT_SCOPE) set(GIT_DIRTY_RESULT ${GIT_DIRTY_RESULT} PARENT_SCOPE) - + # Generate version header file string(TOUPPER "${ARG_PREFIX}" PREFIX_UPPER) - + # Configure using the existing version.h.in template set(VERSION_TEMPLATE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/version_info.h.in") if(EXISTS "${VERSION_TEMPLATE_PATH}") @@ -126,7 +126,7 @@ function(configure_version_from_git) message(STATUS "Generated version header file from template: ${VERSION_TEMPLATE_PATH} -> ${ARG_OUTPUT_HEADER}") else() message(WARNING "Version template file not found: ${VERSION_TEMPLATE_PATH}") - + # Fall back to built-in template message(STATUS "Creating a default version header file at: ${ARG_OUTPUT_HEADER}") configure_file( @@ -135,7 +135,7 @@ function(configure_version_from_git) @ONLY ) endif() - + message(STATUS "Git version: ${VERSION_STRING} (Major: ${VERSION_MAJOR}, Minor: ${VERSION_MINOR}, Patch: ${VERSION_PATCH}, Hash: ${GIT_HASH})") else() message(WARNING "Current directory is not a Git repository, using default version") @@ -171,17 +171,17 @@ function(configure_atom_version) VERSION_VARIABLE ${ARG_VERSION_VARIABLE} PREFIX "ATOM" ) - + # Now generate the user-friendly version info header if(${ARG_VERSION_VARIABLE}) set(PROJECT_VERSION ${${ARG_VERSION_VARIABLE}}) endif() - + configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/cmake/version_info.h.in" "${CMAKE_CURRENT_BINARY_DIR}/atom_version_info.h" @ONLY ) - + message(STATUS "Generated atom_version_info.h with version ${PROJECT_VERSION}") -endfunction() \ No newline at end of file +endfunction() diff --git a/cmake/PlatformSpecifics.cmake b/cmake/PlatformSpecifics.cmake index 0a4e77a3..ec24ee86 100644 --- a/cmake/PlatformSpecifics.cmake +++ b/cmake/PlatformSpecifics.cmake @@ -117,4 +117,4 @@ if(UNIX AND NOT APPLE) else() message(WARNING "ccache not found: compiler cache support disabled.\nRecommendation: On Linux, you can install ccache via package manager, e.g.: sudo apt install ccache or sudo yum install ccache") endif() -endif() \ No newline at end of file +endif() diff --git a/cmake/ScanModule.cmake b/cmake/ScanModule.cmake index 627c00ad..c74bc87a 100644 --- a/cmake/ScanModule.cmake +++ b/cmake/ScanModule.cmake @@ -5,24 +5,24 @@ function(scan_and_generate_modules source_dir return_var) set(modules_name_r "") file(GLOB_RECURSE CPP_FILES "${source_dir}/*.cpp") - + foreach(cpp_file ${CPP_FILES}) file(READ ${cpp_file} file_content) string(REGEX MATCH "ATOM_MODULE\\(([a-zA-Z0-9_]+)," match ${file_content}) - + if(match) string(REGEX REPLACE "ATOM_MODULE\\(([a-zA-Z0-9_]+),.*" "\\1" module_name ${match}) - + if(NOT module_name) message(WARNING "Found ATOM_MODULE macro in ${cpp_file} but could not extract module name.") continue() endif() - + set(modules_name_r ${module_name}) message(VERBOSE "Found module '${module_name}' in ${cpp_file}") endif() endforeach() - + set(${return_var} "${modules_name_r}" PARENT_SCOPE) endfunction() @@ -34,38 +34,38 @@ endfunction() function(scan_module_dependencies) # Find all enabled modules set(enabled_modules) - + # Map build options to module names if(ATOM_BUILD_ERROR) list(APPEND enabled_modules "atom-error") message(STATUS "Module 'atom-error' is enabled") endif() - + if(ATOM_BUILD_LOG) list(APPEND enabled_modules "atom-log") message(STATUS "Module 'atom-log' is enabled") endif() - + if(ATOM_BUILD_ALGORITHM) list(APPEND enabled_modules "atom-algorithm") message(STATUS "Module 'atom-algorithm' is enabled") endif() - + if(ATOM_BUILD_ASYNC) list(APPEND enabled_modules "atom-async") message(STATUS "Module 'atom-async' is enabled") endif() - + if(ATOM_BUILD_COMPONENTS) list(APPEND enabled_modules "atom-components") message(STATUS "Module 'atom-components' is enabled") endif() - + if(ATOM_BUILD_CONNECTION) list(APPEND enabled_modules "atom-connection") message(STATUS "Module 'atom-connection' is enabled") endif() - + if(ATOM_BUILD_CONTAINERS) list(APPEND enabled_modules "atom-containers") message(STATUS "Module 'atom-containers' is enabled") @@ -75,52 +75,52 @@ function(scan_module_dependencies) list(APPEND enabled_modules "atom-io") message(STATUS "Module 'atom-io' is enabled") endif() - + if(ATOM_BUILD_META) list(APPEND enabled_modules "atom-meta") message(STATUS "Module 'atom-meta' is enabled") endif() - + if(ATOM_BUILD_MEMORY) list(APPEND enabled_modules "atom-memory") message(STATUS "Module 'atom-memory' is enabled") endif() - + if(ATOM_BUILD_SEARCH) list(APPEND enabled_modules "atom-search") message(STATUS "Module 'atom-search' is enabled") endif() - + if(ATOM_BUILD_SECRET) list(APPEND enabled_modules "atom-secret") message(STATUS "Module 'atom-secret' is enabled") endif() - + if(ATOM_BUILD_SERIAL) list(APPEND enabled_modules "atom-serial") message(STATUS "Module 'atom-serial' is enabled") endif() - + if(ATOM_BUILD_SYSINFO) list(APPEND enabled_modules "atom-sysinfo") message(STATUS "Module 'atom-sysinfo' is enabled") endif() - + if(ATOM_BUILD_SYSTEM) list(APPEND enabled_modules "atom-system") message(STATUS "Module 'atom-system' is enabled") endif() - + if(ATOM_BUILD_TYPE) list(APPEND enabled_modules "atom-type") message(STATUS "Module 'atom-type' is enabled") endif() - + if(ATOM_BUILD_UTILS) list(APPEND enabled_modules "atom-utils") message(STATUS "Module 'atom-utils' is enabled") endif() - + if(ATOM_BUILD_WEB) list(APPEND enabled_modules "atom-web") message(STATUS "Module 'atom-web' is enabled") @@ -135,7 +135,7 @@ endfunction() function(module_exists module_name result_var) # Convert module name (e.g., "atom-error") to directory name (e.g., "error") string(REPLACE "atom-" "" dir_name "${module_name}") - + # Check if directory exists and has a CMakeLists.txt file set(module_path "${CMAKE_CURRENT_SOURCE_DIR}/../atom/${dir_name}") if(EXISTS "${module_path}" AND EXISTS "${module_path}/CMakeLists.txt") @@ -149,10 +149,10 @@ endfunction() function(process_module_dependencies) # Get list of initially enabled modules get_property(enabled_modules GLOBAL PROPERTY ATOM_ENABLED_MODULES) - + # Create a copy of the initial list set(initial_modules ${enabled_modules}) - + # Validate initial modules - remove any that don't exist set(validated_modules "") foreach(module ${enabled_modules}) @@ -167,32 +167,32 @@ function(process_module_dependencies) set(ATOM_BUILD_${module_upper} OFF CACHE BOOL "Build ${module} module" FORCE) endif() endforeach() - + # Update the enabled modules list with only valid ones set(enabled_modules ${validated_modules}) set_property(GLOBAL PROPERTY ATOM_ENABLED_MODULES "${enabled_modules}") - + # Process dependencies until no new modules are added set(process_again TRUE) set(iteration 0) set(max_iterations 10) # Prevent infinite loops - + while(process_again AND iteration LESS max_iterations) set(process_again FALSE) set(new_modules "") - + # For each enabled module, check its dependencies foreach(module ${enabled_modules}) # Convert module name to uppercase for variable lookup string(TOUPPER "${module}" module_upper) string(REPLACE "-" "_" module_var "${module_upper}") - + # Get dependencies for this module if(DEFINED ATOM_${module_var}_DEPENDS) foreach(dep ${ATOM_${module_var}_DEPENDS}) # Check if dependency exists before adding it module_exists(${dep} DEP_EXISTS) - + # If the dependency is not already in the enabled list and it exists, add it if(NOT "${dep}" IN_LIST enabled_modules AND DEP_EXISTS) list(APPEND new_modules ${dep}) @@ -206,21 +206,21 @@ function(process_module_dependencies) endforeach() endif() endforeach() - + # Add newly discovered dependencies to the enabled list if(new_modules) list(APPEND enabled_modules ${new_modules}) list(REMOVE_DUPLICATES enabled_modules) endif() - + math(EXPR iteration "${iteration} + 1") endwhile() - + # Check if we reached max iterations if(iteration EQUAL max_iterations) message(WARNING "Reached maximum dependency resolution iterations. There may be circular dependencies.") endif() - + # Find any new modules that were added because of dependencies set(added_modules "") foreach(module ${enabled_modules}) @@ -228,24 +228,24 @@ function(process_module_dependencies) list(APPEND added_modules ${module}) endif() endforeach() - + if(added_modules) message(STATUS "Additional modules enabled due to dependencies: ${added_modules}") endif() - + # Update the global property with the full list of modules to build set_property(GLOBAL PROPERTY ATOM_ENABLED_MODULES "${enabled_modules}") message(STATUS "Final list of enabled modules: ${enabled_modules}") - + # Create a property to hold all module targets set_property(GLOBAL PROPERTY ATOM_MODULE_TARGETS "") - + # Enable the build for each required module foreach(module ${enabled_modules}) # Convert module name to CMake variable format string(REPLACE "atom-" "" module_name "${module}") string(TOUPPER "${module_name}" module_upper) - + # Set the corresponding build option to ON set(ATOM_BUILD_${module_upper} ON CACHE BOOL "Build ${module} module" FORCE) endforeach() diff --git a/cmake/TestsBuildOptions.cmake b/cmake/TestsBuildOptions.cmake index 4880990b..9b89a780 100644 --- a/cmake/TestsBuildOptions.cmake +++ b/cmake/TestsBuildOptions.cmake @@ -1,7 +1,7 @@ # TestsBuildOptions.cmake # # This file contains all options for controlling the build of Atom tests -# +# # Author: Max Qian # License: GPL3 diff --git a/cmake/VcpkgSetup.cmake b/cmake/VcpkgSetup.cmake index cf5e1107..2b4b452e 100644 --- a/cmake/VcpkgSetup.cmake +++ b/cmake/VcpkgSetup.cmake @@ -85,4 +85,4 @@ elseif(DEFINED ENV{VCPKG_ROOT} AND EXISTS "$ENV{VCPKG_ROOT}") else() message(FATAL_ERROR "Vcpkg root directory (ATOM_VCPKG_ROOT) could not be determined. " "Ensure VCPKG_ROOT is set or vcpkg is in a standard location, or CMAKE_TOOLCHAIN_FILE points to vcpkg.") -endif() \ No newline at end of file +endif() diff --git a/cmake/VersionConfig.cmake b/cmake/VersionConfig.cmake index dac3e09e..5cb71fe6 100644 --- a/cmake/VersionConfig.cmake +++ b/cmake/VersionConfig.cmake @@ -36,4 +36,4 @@ else() message(WARNING "cmake/version_info.h.in not found. Skipping generation of atom_version_info.h.") endif() -message(STATUS "Atom project version configured to: ${PROJECT_VERSION}") \ No newline at end of file +message(STATUS "Atom project version configured to: ${PROJECT_VERSION}") diff --git a/cmake/WSLDetection.cmake b/cmake/WSLDetection.cmake index 2af8f9f4..e802ca16 100644 --- a/cmake/WSLDetection.cmake +++ b/cmake/WSLDetection.cmake @@ -44,7 +44,7 @@ function(detect_wsl RESULT_VAR) set(${RESULT_VAR} TRUE PARENT_SCOPE) return() endif() - + # Default to not WSL set(${RESULT_VAR} FALSE PARENT_SCOPE) -endfunction() \ No newline at end of file +endfunction() diff --git a/cmake/compiler_options.cmake b/cmake/compiler_options.cmake index 2a2c5c14..e2437bc0 100644 --- a/cmake/compiler_options.cmake +++ b/cmake/compiler_options.cmake @@ -24,30 +24,30 @@ function(check_compiler_requirements) set(options "") set(oneValueArgs CXX_STANDARD MIN_GCC_VERSION MIN_CLANG_VERSION MIN_MSVC_VERSION) set(multiValueArgs "") - + cmake_parse_arguments(CHECK "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - + # Set default values if(NOT DEFINED CHECK_CXX_STANDARD) set(CHECK_CXX_STANDARD 23) endif() - + if(NOT DEFINED CHECK_MIN_GCC_VERSION) set(CHECK_MIN_GCC_VERSION 10.0) endif() - + if(NOT DEFINED CHECK_MIN_CLANG_VERSION) set(CHECK_MIN_CLANG_VERSION 10.0) endif() - + if(NOT DEFINED CHECK_MIN_MSVC_VERSION) set(CHECK_MIN_MSVC_VERSION 19.28) endif() - + # Check C++ standard support check_cxx_compiler_flag(-std=c++20 HAS_CXX20_FLAG) check_cxx_compiler_flag(-std=c++23 HAS_CXX23_FLAG) - + if(CHECK_CXX_STANDARD EQUAL 23) if(NOT HAS_CXX23_FLAG) message(FATAL_ERROR "C++23 standard support is required!") @@ -61,11 +61,11 @@ function(check_compiler_requirements) else() set(CMAKE_CXX_STANDARD ${CHECK_CXX_STANDARD} PARENT_SCOPE) endif() - + set(CMAKE_CXX_STANDARD_REQUIRED ON PARENT_SCOPE) set(CMAKE_CXX_EXTENSIONS OFF PARENT_SCOPE) set(CMAKE_C_STANDARD 17 PARENT_SCOPE) - + # Check compiler version if(CMAKE_CXX_COMPILER_ID MATCHES "GNU") execute_process( @@ -95,7 +95,7 @@ function(check_compiler_requirements) message(STATUS "Using MSVC version ${CMAKE_CXX_COMPILER_VERSION}") endif() message(STATUS "Using C++${CMAKE_CXX_STANDARD}") - + # Set special flags for Apple platforms if(APPLE) check_cxx_compiler_flag(-stdlib=libc++ HAS_LIBCXX_FLAG) @@ -103,7 +103,7 @@ function(check_compiler_requirements) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++" PARENT_SCOPE) endif() endif() - + # Set build architecture for non-Apple platforms if(NOT APPLE) set(CMAKE_OSX_ARCHITECTURES x86_64 CACHE STRING "Build architecture for non-Apple platforms" FORCE) @@ -113,22 +113,22 @@ endfunction() # Configure compiler options function function(configure_compiler_options) # Parse arguments - set(options - ENABLE_WARNINGS TREAT_WARNINGS_AS_ERRORS + set(options + ENABLE_WARNINGS TREAT_WARNINGS_AS_ERRORS ENABLE_OPTIMIZATIONS ENABLE_DEBUG_INFO ENABLE_UTF8 ENABLE_EXCEPTION_HANDLING ENABLE_LTO ) set(oneValueArgs WARNING_LEVEL OPTIMIZATION_LEVEL) set(multiValueArgs ADDITIONAL_OPTIONS) - + cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - + # Set default values if(NOT DEFINED ARGS_WARNING_LEVEL) set(ARGS_WARNING_LEVEL "normal") endif() - + if(NOT DEFINED ARGS_OPTIMIZATION_LEVEL) if(CMAKE_BUILD_TYPE STREQUAL "Debug") set(ARGS_OPTIMIZATION_LEVEL "none") @@ -136,17 +136,17 @@ function(configure_compiler_options) set(ARGS_OPTIMIZATION_LEVEL "speed") endif() endif() - + set(compiler_options "") set(linker_options "") - + # MSVC compiler options if(MSVC) # Basic options list(APPEND compiler_options /nologo # Suppress copyright message ) - + # UTF-8 support if(ARGS_ENABLE_UTF8) list(APPEND compiler_options @@ -154,12 +154,12 @@ function(configure_compiler_options) /execution-charset:UTF-8 # Specify execution character set as UTF-8 ) endif() - + # Exception handling if(ARGS_ENABLE_EXCEPTION_HANDLING) list(APPEND compiler_options /EHsc) endif() - + # Warning level if(ARGS_ENABLE_WARNINGS) if(ARGS_WARNING_LEVEL STREQUAL "high") @@ -169,12 +169,12 @@ function(configure_compiler_options) else() list(APPEND compiler_options /W3) endif() - + if(ARGS_TREAT_WARNINGS_AS_ERRORS) list(APPEND compiler_options /WX) endif() endif() - + # Optimization level if(ARGS_ENABLE_OPTIMIZATIONS) if(ARGS_OPTIMIZATION_LEVEL STREQUAL "speed") @@ -187,30 +187,30 @@ function(configure_compiler_options) else() list(APPEND compiler_options /Od) endif() - + # Debug information if(ARGS_ENABLE_DEBUG_INFO) list(APPEND compiler_options /Zi) endif() - + # Link Time Optimization if(ARGS_ENABLE_LTO) list(APPEND compiler_options /GL) list(APPEND linker_options /LTCG) endif() - + # GCC/Clang compiler options elseif(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") # UTF-8 support if(ARGS_ENABLE_UTF8) list(APPEND compiler_options -fexec-charset=UTF-8) endif() - + # Exception handling if(ARGS_ENABLE_EXCEPTION_HANDLING) list(APPEND compiler_options -fexceptions) endif() - + # Warning level if(ARGS_ENABLE_WARNINGS) if(ARGS_WARNING_LEVEL STREQUAL "high") @@ -220,12 +220,12 @@ function(configure_compiler_options) else() list(APPEND compiler_options -Wall) endif() - + if(ARGS_TREAT_WARNINGS_AS_ERRORS) list(APPEND compiler_options -Werror) endif() endif() - + # Optimization level if(ARGS_ENABLE_OPTIMIZATIONS) if(ARGS_OPTIMIZATION_LEVEL STREQUAL "speed") @@ -238,34 +238,34 @@ function(configure_compiler_options) else() list(APPEND compiler_options -O0) endif() - + # Debug information if(ARGS_ENABLE_DEBUG_INFO) list(APPEND compiler_options -g) endif() - + # Link Time Optimization if(ARGS_ENABLE_LTO) list(APPEND compiler_options -flto) list(APPEND linker_options -flto) endif() endif() - + # Add user-provided additional options if(ARGS_ADDITIONAL_OPTIONS) list(APPEND compiler_options ${ARGS_ADDITIONAL_OPTIONS}) endif() - + # Apply compiler options add_compile_options(${compiler_options}) - + # Apply linker options if(linker_options) string(REPLACE ";" " " linker_flags_str "${linker_options}") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${linker_flags_str}" PARENT_SCOPE) set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${linker_flags_str}" PARENT_SCOPE) endif() - + # Print information message(STATUS "Configured compiler options: ${compiler_options}") if(linker_options) @@ -284,7 +284,7 @@ function(apply_build_preset PRESET_NAME) ENABLE_DEBUG_INFO ) add_definitions(-DDEBUG -D_DEBUG) - + elseif(PRESET_NAME STREQUAL "RELEASE") configure_compiler_options( ENABLE_UTF8 @@ -296,7 +296,7 @@ function(apply_build_preset PRESET_NAME) ENABLE_LTO ) add_definitions(-DNDEBUG) - + elseif(PRESET_NAME STREQUAL "MINSIZEREL") configure_compiler_options( ENABLE_UTF8 @@ -306,7 +306,7 @@ function(apply_build_preset PRESET_NAME) ENABLE_LTO ) add_definitions(-DNDEBUG) - + elseif(PRESET_NAME STREQUAL "RELWITHDEBINFO") configure_compiler_options( ENABLE_UTF8 @@ -315,7 +315,7 @@ function(apply_build_preset PRESET_NAME) ENABLE_DEBUG_INFO ) add_definitions(-DNDEBUG) - + elseif(PRESET_NAME STREQUAL "SANITIZE") # Enable code analysis and checking tools if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") @@ -346,7 +346,7 @@ function(configure_platform_options) elseif(UNIX AND NOT APPLE) add_definitions(-DPLATFORM_LINUX) endif() - + # Check architecture if(CMAKE_SIZEOF_VOID_P EQUAL 8) add_definitions(-DARCH_X64) @@ -361,9 +361,9 @@ macro(setup_project_defaults) set(options STATIC_RUNTIME ENABLE_PCH) set(oneValueArgs BUILD_PRESET CXX_STANDARD MIN_GCC_VERSION MIN_CLANG_VERSION MIN_MSVC_VERSION) set(multiValueArgs PCH_HEADERS) - + cmake_parse_arguments(SETUP "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - + # Check compiler requirements check_compiler_requirements( CXX_STANDARD ${SETUP_CXX_STANDARD} @@ -371,7 +371,7 @@ macro(setup_project_defaults) MIN_CLANG_VERSION ${SETUP_MIN_CLANG_VERSION} MIN_MSVC_VERSION ${SETUP_MIN_MSVC_VERSION} ) - + # Configure static runtime library if(SETUP_STATIC_RUNTIME AND MSVC) set(variables @@ -390,10 +390,10 @@ macro(setup_project_defaults) endif() endforeach() endif() - + # Apply platform options configure_platform_options() - + # Apply build preset if(DEFINED SETUP_BUILD_PRESET) apply_build_preset(${SETUP_BUILD_PRESET}) @@ -412,7 +412,7 @@ macro(setup_project_defaults) apply_build_preset("RELEASE") endif() endif() - + # Configure precompiled headers if(SETUP_ENABLE_PCH AND DEFINED SETUP_PCH_HEADERS) if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.16) @@ -426,4 +426,4 @@ macro(setup_project_defaults) message(WARNING "Precompiled header functionality requested, but CMake version does not support it (3.16+ required)") endif() endif() -endmacro() \ No newline at end of file +endmacro() diff --git a/cmake/module_dependencies.cmake b/cmake/module_dependencies.cmake index cb6e3d1e..37444cbe 100644 --- a/cmake/module_dependencies.cmake +++ b/cmake/module_dependencies.cmake @@ -66,4 +66,4 @@ set(ATOM_MODULE_BUILD_ORDER atom-search atom-secret atom-web -) \ No newline at end of file +) diff --git a/cmake/version_info.h.in b/cmake/version_info.h.in index 843d2998..c4a8b5a7 100644 --- a/cmake/version_info.h.in +++ b/cmake/version_info.h.in @@ -1,7 +1,7 @@ /** * @file atom_version_info.h * @brief Auto-generated Atom version information header file - * + * * This file is automatically generated by CMake, do not modify manually */ @@ -57,4 +57,4 @@ static inline int atom_check_version(int major, int minor, int patch) { } #endif -#endif /* ATOM_VERSION_INFO_H */ \ No newline at end of file +#endif /* ATOM_VERSION_INFO_H */ diff --git a/example/algorithm/CMakeLists.txt b/example/algorithm/CMakeLists.txt index d756f796..a650db84 100644 --- a/example/algorithm/CMakeLists.txt +++ b/example/algorithm/CMakeLists.txt @@ -14,20 +14,20 @@ file(GLOB CPP_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) foreach(CPP_FILE ${CPP_FILES}) # 获取不带扩展名的文件名 get_filename_component(EXAMPLE_NAME ${CPP_FILE} NAME_WE) - + # 构造可执行文件名称(子目录名_文件名) set(EXECUTABLE_NAME ${SUBDIR_NAME}_${EXAMPLE_NAME}) - + # 配置选项,允许单独控制每个示例的构建 string(TOUPPER ${EXAMPLE_NAME} EXAMPLE_NAME_UPPER) option(ATOM_EXAMPLE_ALGORITHM_${EXAMPLE_NAME_UPPER} "Build algorithm example: ${EXAMPLE_NAME}" ${ATOM_EXAMPLE_ALGORITHM_BUILD_ALL}) - + # 有条件地添加可执行文件 if(ATOM_EXAMPLE_ALGORITHM_${EXAMPLE_NAME_UPPER}) add_executable(${EXECUTABLE_NAME} ${CPP_FILE}) target_link_libraries(${EXECUTABLE_NAME} atom) - - + + # 设置IDE文件夹分组 set_property(TARGET ${EXECUTABLE_NAME} PROPERTY FOLDER "Examples/Algorithm") endif() diff --git a/example/algorithm/algorithm.cpp b/example/algorithm/algorithm.cpp index 86678cee..ee088348 100644 --- a/example/algorithm/algorithm.cpp +++ b/example/algorithm/algorithm.cpp @@ -154,4 +154,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/example/algorithm/annealing.cpp b/example/algorithm/annealing.cpp index 3d70c13d..b88baf52 100644 --- a/example/algorithm/annealing.cpp +++ b/example/algorithm/annealing.cpp @@ -109,4 +109,4 @@ int main() { << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/algorithm/base.cpp b/example/algorithm/base.cpp index 3212baa8..c0ae5ccc 100644 --- a/example/algorithm/base.cpp +++ b/example/algorithm/base.cpp @@ -132,4 +132,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/example/algorithm/bignumber.cpp b/example/algorithm/bignumber.cpp index 934c6fac..f9af2b5e 100644 --- a/example/algorithm/bignumber.cpp +++ b/example/algorithm/bignumber.cpp @@ -203,4 +203,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/example/algorithm/convolve.cpp b/example/algorithm/convolve.cpp index 21bed8c5..3613dd61 100644 --- a/example/algorithm/convolve.cpp +++ b/example/algorithm/convolve.cpp @@ -358,4 +358,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/example/algorithm/error_calibration.cpp b/example/algorithm/error_calibration.cpp index 3cbb4171..dbb12f77 100644 --- a/example/algorithm/error_calibration.cpp +++ b/example/algorithm/error_calibration.cpp @@ -56,4 +56,4 @@ int main() { calibrator.crossValidation(measured, actual, 5); return 0; -} \ No newline at end of file +} diff --git a/example/algorithm/flood.cpp b/example/algorithm/flood.cpp index 8b3d4b7a..a06e24cc 100644 --- a/example/algorithm/flood.cpp +++ b/example/algorithm/flood.cpp @@ -318,4 +318,4 @@ int main() { std::cout << "- Performance comparison between algorithms" << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/algorithm/fnmatch.cpp b/example/algorithm/fnmatch.cpp index 351d982c..e998b524 100644 --- a/example/algorithm/fnmatch.cpp +++ b/example/algorithm/fnmatch.cpp @@ -68,4 +68,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/example/algorithm/fraction.cpp b/example/algorithm/fraction.cpp index 7be37035..1b1b098c 100644 --- a/example/algorithm/fraction.cpp +++ b/example/algorithm/fraction.cpp @@ -86,4 +86,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/example/algorithm/hash.cpp b/example/algorithm/hash.cpp index 93bb4268..550d2d1b 100644 --- a/example/algorithm/hash.cpp +++ b/example/algorithm/hash.cpp @@ -96,4 +96,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/example/algorithm/huffman.cpp b/example/algorithm/huffman.cpp index 6415f839..75ab021e 100644 --- a/example/algorithm/huffman.cpp +++ b/example/algorithm/huffman.cpp @@ -66,4 +66,4 @@ int main() { atom::algorithm::visualizeHuffmanTree(huffmanTreeRoot.get()); return 0; -} \ No newline at end of file +} diff --git a/example/algorithm/math.cpp b/example/algorithm/math.cpp index ebc86f51..794b0964 100644 --- a/example/algorithm/math.cpp +++ b/example/algorithm/math.cpp @@ -123,4 +123,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/example/algorithm/matrix.cpp b/example/algorithm/matrix.cpp index 8ec60471..cf25accd 100644 --- a/example/algorithm/matrix.cpp +++ b/example/algorithm/matrix.cpp @@ -106,4 +106,4 @@ int main() { randomMatrix.print(); return 0; -} \ No newline at end of file +} diff --git a/example/algorithm/matrix_compress.cpp b/example/algorithm/matrix_compress.cpp index ef8e0792..a232ca98 100644 --- a/example/algorithm/matrix_compress.cpp +++ b/example/algorithm/matrix_compress.cpp @@ -132,4 +132,4 @@ int main() { #endif return 0; -} \ No newline at end of file +} diff --git a/example/algorithm/md5.cpp b/example/algorithm/md5.cpp index c723a874..ac9440e6 100644 --- a/example/algorithm/md5.cpp +++ b/example/algorithm/md5.cpp @@ -14,4 +14,4 @@ int main() { std::cout << "MD5 Hash: " << hash << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/algorithm/mhash.cpp b/example/algorithm/mhash.cpp index 21c0eea1..47c66691 100644 --- a/example/algorithm/mhash.cpp +++ b/example/algorithm/mhash.cpp @@ -63,4 +63,4 @@ int main() { std::cout << std::dec << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/algorithm/perlin.cpp b/example/algorithm/perlin.cpp index 59e0a23b..4a942312 100644 --- a/example/algorithm/perlin.cpp +++ b/example/algorithm/perlin.cpp @@ -42,4 +42,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/example/algorithm/rust_numeric.cpp b/example/algorithm/rust_numeric.cpp index dd96c4a7..b56c3654 100644 --- a/example/algorithm/rust_numeric.cpp +++ b/example/algorithm/rust_numeric.cpp @@ -339,4 +339,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/example/algorithm/sha1.cpp b/example/algorithm/sha1.cpp index 1df4d806..7c57b059 100644 --- a/example/algorithm/sha1.cpp +++ b/example/algorithm/sha1.cpp @@ -43,4 +43,4 @@ int main() { << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/algorithm/snowflake.cpp b/example/algorithm/snowflake.cpp index 0e2af7d7..88da73ff 100644 --- a/example/algorithm/snowflake.cpp +++ b/example/algorithm/snowflake.cpp @@ -39,4 +39,4 @@ int main() { std::cout << "Current Datacenter ID: " << currentDatacenterId << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/algorithm/tea.cpp b/example/algorithm/tea.cpp index eb6bcea3..ba9ae10b 100644 --- a/example/algorithm/tea.cpp +++ b/example/algorithm/tea.cpp @@ -83,4 +83,4 @@ int main() { std::cout << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/algorithm/weight.cpp b/example/algorithm/weight.cpp index 7125a014..c9ed2a76 100644 --- a/example/algorithm/weight.cpp +++ b/example/algorithm/weight.cpp @@ -115,4 +115,4 @@ int main() { std::cout << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/async/CMakeLists.txt b/example/async/CMakeLists.txt index 2cc215e7..e4995c49 100644 --- a/example/async/CMakeLists.txt +++ b/example/async/CMakeLists.txt @@ -14,20 +14,20 @@ file(GLOB CPP_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) foreach(CPP_FILE ${CPP_FILES}) # 获取不带扩展名的文件名 get_filename_component(EXAMPLE_NAME ${CPP_FILE} NAME_WE) - + # 构造可执行文件名称(子目录名_文件名) set(EXECUTABLE_NAME ${SUBDIR_NAME}_${EXAMPLE_NAME}) - + # 配置选项,允许单独控制每个示例的构建 string(TOUPPER ${EXAMPLE_NAME} EXAMPLE_NAME_UPPER) option(ATOM_EXAMPLE_ASYNC_${EXAMPLE_NAME_UPPER} "Build async example: ${EXAMPLE_NAME}" ${ATOM_EXAMPLE_ASYNC_BUILD_ALL}) - + # 有条件地添加可执行文件 if(ATOM_EXAMPLE_ASYNC_${EXAMPLE_NAME_UPPER}) add_executable(${EXECUTABLE_NAME} ${CPP_FILE}) target_link_libraries(${EXECUTABLE_NAME} atom) - - + + # 设置IDE文件夹分组 set_property(TARGET ${EXECUTABLE_NAME} PROPERTY FOLDER "Examples/Async") endif() diff --git a/example/async/async.cpp b/example/async/async.cpp index 57619703..747f9120 100644 --- a/example/async/async.cpp +++ b/example/async/async.cpp @@ -438,4 +438,4 @@ int main(int argc, char* argv[]) { } return 0; -} \ No newline at end of file +} diff --git a/example/async/async_executor.cpp b/example/async/async_executor.cpp index 3be79b31..ebdba358 100644 --- a/example/async/async_executor.cpp +++ b/example/async/async_executor.cpp @@ -562,4 +562,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/example/async/daemon.cpp b/example/async/daemon.cpp index 745e8f7e..72a47f4b 100644 --- a/example/async/daemon.cpp +++ b/example/async/daemon.cpp @@ -16,16 +16,16 @@ namespace examples { int simpleTask(int argc, char** argv) { std::cout << "简单任务开始执行" << std::endl; std::cout << "参数数量: " << argc << std::endl; - + for (int i = 0; i < argc; ++i) { std::cout << "参数[" << i << "]: " << (argv[i] ? argv[i] : "nullptr") << std::endl; } - + // 模拟工作 std::cout << "任务正在执行..." << std::endl; std::this_thread::sleep_for(std::chrono::seconds(2)); std::cout << "简单任务执行完成" << std::endl; - + return 0; } @@ -48,17 +48,17 @@ namespace examples { int simpleTask(int argc, char** argv) { std::cout << "简单任务开始执行" << std::endl; std::cout << "参数数量: " << argc << std::endl; - + for (int i = 0; i < argc; ++i) { std::cout << "参数[" << i << "]: " << (argv[i] ? argv[i] : "nullptr") << std::endl; } - + // 模拟工作 std::cout << "任务正在执行..." << std::endl; std::this_thread::sleep_for(std::chrono::seconds(2)); std::cout << "简单任务执行完成" << std::endl; - + return 0; } -// 简单的任务回调函数 - 现代方式 (使用 std::span \ No newline at end of file +// 简单的任务回调函数 - 现代方式 (使用 std::span diff --git a/example/async/eventstack.cpp b/example/async/eventstack.cpp index 6e867e50..32f4e012 100644 --- a/example/async/eventstack.cpp +++ b/example/async/eventstack.cpp @@ -352,4 +352,4 @@ int main() { std::cout << "\n所有测试完成!\n"; return 0; -} \ No newline at end of file +} diff --git a/example/async/future.cpp b/example/async/future.cpp index 2d021a69..b087a73e 100644 --- a/example/async/future.cpp +++ b/example/async/future.cpp @@ -346,4 +346,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/example/async/generator.cpp b/example/async/generator.cpp index 8681b421..85b64255 100644 --- a/example/async/generator.cpp +++ b/example/async/generator.cpp @@ -494,4 +494,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/example/async/limiter.cpp b/example/async/limiter.cpp index d9af1da9..f9f05469 100644 --- a/example/async/limiter.cpp +++ b/example/async/limiter.cpp @@ -613,4 +613,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/example/async/lock.cpp b/example/async/lock.cpp index f7978a9a..e494de56 100644 --- a/example/async/lock.cpp +++ b/example/async/lock.cpp @@ -603,4 +603,4 @@ int main() { std::cout << "\n========= 示例完成 =========\n"; return 0; -} \ No newline at end of file +} diff --git a/example/async/message_bus.cpp b/example/async/message_bus.cpp index 499f62f3..e09fe795 100644 --- a/example/async/message_bus.cpp +++ b/example/async/message_bus.cpp @@ -61,4 +61,4 @@ int main() { ioThread.join(); return 0; -} \ No newline at end of file +} diff --git a/example/async/message_queue.cpp b/example/async/message_queue.cpp index d770fea3..1be823fa 100644 --- a/example/async/message_queue.cpp +++ b/example/async/message_queue.cpp @@ -71,4 +71,4 @@ int main() { processingThread.join(); return 0; -} \ No newline at end of file +} diff --git a/example/async/packaged_task.cpp b/example/async/packaged_task.cpp index 8c6204cb..2a58867e 100644 --- a/example/async/packaged_task.cpp +++ b/example/async/packaged_task.cpp @@ -744,4 +744,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/example/async/parallel.cpp b/example/async/parallel.cpp index 4ed811cc..b6cdddc9 100644 --- a/example/async/parallel.cpp +++ b/example/async/parallel.cpp @@ -386,7 +386,7 @@ void cpp20_features_example() { { Timer t("使用 span 进行映射操作"); std::span data_view(data); - + // 创建结果向量 std::vector results(data_view.size()); for (size_t i = 0; i < data_view.size(); ++i) { @@ -406,10 +406,10 @@ void cpp20_features_example() { struct Person { std::string name; int age; - + // 移除局部类中的友元函数定义 }; - + // 定义非成员操作符重载 std::ostream& operator<<(std::ostream& os, const Person& p) { return os << p.name << "(" << p.age << ")"; @@ -422,14 +422,14 @@ void cpp20_features_example() { // 使用标准库过滤数据 { Timer t("使用标准库过滤成年人"); - + std::vector adults; for (const auto& p : people) { if (p.age >= 18) { adults.push_back(p); } } - + // 注释掉有问题的调用 // auto adults = atom::async::Parallel::filter_range( // people, [](const Person& p) { return p.age >= 18; }); @@ -441,9 +441,9 @@ void cpp20_features_example() { // 7. 协程任务示例 - 使用标准库替代 void coroutine_task_example() { std::cout << "\n===== 协程任务示例 =====\n"; - + std::cout << "注意:协程示例需要使用 atom::async::Task,已被注释" << std::endl; - + // 简化协程示例,使用标准线程代替 auto simple_task = []() -> int { std::cout << "执行简单任务..." << std::endl; @@ -522,7 +522,7 @@ void simd_operations_example() { for (size_t i = 0; i < size; ++i) { result[i] = a[i] + b[i]; } - + // 注释掉有问题的调用 // atom::async::SimdOps::add(a.data(), b.data(), result.data(), size); @@ -553,7 +553,7 @@ void simd_operations_example() { for (size_t i = 0; i < size; ++i) { result[i] = a[i] * b[i]; } - + // 注释掉有问题的调用 // atom::async::SimdOps::multiply(a.data(), b.data(), result.data(), size); @@ -585,7 +585,7 @@ void simd_operations_example() { for (size_t i = 0; i < size; ++i) { dot_result += a[i] * b[i]; } - + // 注释掉有问题的调用 // float dot_result = atom::async::SimdOps::dotProduct(a.data(), b.data(), size); @@ -622,7 +622,7 @@ void simd_operations_example() { for (size_t i = 0; i < span_a.size(); ++i) { dot_result += span_a[i] * span_b[i]; } - + // 注释掉有问题的调用 // float dot_result = atom::async::SimdOps::dotProduct(span_a, span_b); std::cout << "使用 span 的点积结果: " << dot_result @@ -647,11 +647,11 @@ void edge_cases_and_error_handling() { try { // 使用标准库代替 std::for_each(empty_data.begin(), empty_data.end(), [](int& x) { x *= 2; }); - + // 注释掉有问题的调用 // atom::async::Parallel::for_each( // empty_data.begin(), empty_data.end(), [](int& x) { x *= 2; }); - + std::cout << "空数据集的 for_each 成功完成" << std::endl; } catch (const std::exception& e) { std::cout << "空数据集的 for_each 发生错误: " << e.what() @@ -666,12 +666,12 @@ void edge_cases_and_error_handling() { for (int x : empty_data) { result.push_back(x * 2); } - + // 注释掉有问题的调用 // auto result = // atom::async::Parallel::map(empty_data.begin(), empty_data.end(), // [](int x) { return x * 2; }); - + std::cout << "空数据集的 map 成功完成,结果大小: " << result.size() << std::endl; } catch (const std::exception& e) { @@ -688,12 +688,12 @@ void edge_cases_and_error_handling() { try { // 使用标准库代替 int result = std::accumulate(single_data.begin(), single_data.end(), 10); - + // 注释掉有问题的调用 // int result = atom::async::Parallel::reduce( // single_data.begin(), single_data.end(), 10, // [](int a, int b) { return a + b; }); - + std::cout << "单元素数据集的 reduce 结果: " << result << std::endl; } catch (const std::exception& e) { std::cout << "单元素数据集的 reduce 发生错误: " << e.what() @@ -704,10 +704,10 @@ void edge_cases_and_error_handling() { try { // 使用标准库代替 std::sort(single_data.begin(), single_data.end()); - + // 注释掉有问题的调用 // atom::async::Parallel::sort(single_data.begin(), single_data.end()); - + std::cout << "单元素数据集的 sort 成功完成,结果: " << single_data[0] << std::endl; } catch (const std::exception& e) { @@ -730,12 +730,12 @@ void edge_cases_and_error_handling() { if (b.data() == nullptr || result.data() == nullptr) { throw std::invalid_argument("输入指针不能为空"); } - + // 模拟正常操作 for (size_t i = 0; i < 2; ++i) { result[i] = 0 + b[i]; // 模拟 a 为空 } - + // 注释掉有问题的调用 // atom::async::SimdOps::add(nullptr, b.data(), result.data(), 2); std::cout << "不应该看到这行输出!" << std::endl; @@ -753,7 +753,7 @@ void edge_cases_and_error_handling() { if (span_a.size() != span_c.size()) { throw std::invalid_argument("向量大小不匹配"); } - + // 注释掉有问题的调用 // float result = atom::async::SimdOps::dotProduct(span_a, span_c); std::cout << "不应该看到这行输出!" << std::endl; @@ -798,13 +798,13 @@ void jthread_example() { // 使用标准库代替 jthread 实现的 for_each { Timer t("使用 std::for_each 的处理"); - + // 使用标准库代替 std::for_each(data.begin(), data.end(), [&counter](int& val) { val *= 2; // 乘以2 counter++; }); - + // 注释掉有问题的调用 // atom::async::Parallel::for_each_jthread(data.begin(), data.end(), // [&counter](int& val) { @@ -823,13 +823,13 @@ void jthread_example() { // 使用标准库代替 jthread 实现的 for_each { Timer t("使用 std::for_each 的处理 (模拟4个线程)"); - + // 使用标准库代替 std::for_each(data.begin(), data.end(), [&counter](int& val) { val *= 2; // 乘以2 counter++; }); - + // 注释掉有问题的调用 // atom::async::Parallel::for_each_jthread( // data.begin(), data.end(), @@ -862,4 +862,4 @@ int main() { std::cout << "\n========== 示例完成 ==========\n"; return 0; -} \ No newline at end of file +} diff --git a/example/async/pool.cpp b/example/async/pool.cpp index b432f83b..1f1475da 100644 --- a/example/async/pool.cpp +++ b/example/async/pool.cpp @@ -476,4 +476,4 @@ int main() { std::cout << "\n所有示例已完成\n" << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/async/promise.cpp b/example/async/promise.cpp index 88dea53d..6b04c094 100644 --- a/example/async/promise.cpp +++ b/example/async/promise.cpp @@ -728,4 +728,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/example/async/queue.cpp b/example/async/queue.cpp index 2b681674..a5398e2b 100644 --- a/example/async/queue.cpp +++ b/example/async/queue.cpp @@ -630,4 +630,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/example/async/safetype.cpp b/example/async/safetype.cpp index da3411ef..3ee5b08e 100644 --- a/example/async/safetype.cpp +++ b/example/async/safetype.cpp @@ -616,4 +616,4 @@ int main() { std::cout << "\n所有示例已成功完成!" << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/async/slot.cpp b/example/async/slot.cpp index a017faf9..0823dce1 100644 --- a/example/async/slot.cpp +++ b/example/async/slot.cpp @@ -389,4 +389,4 @@ int main() { std::cout << "\n所有示例已完成!" << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/async/thread_wrapper.cpp b/example/async/thread_wrapper.cpp index 1b53244b..fd05b0a5 100644 --- a/example/async/thread_wrapper.cpp +++ b/example/async/thread_wrapper.cpp @@ -620,4 +620,4 @@ int main() { print_safe("\nAll examples completed"); return 0; -} \ No newline at end of file +} diff --git a/example/async/threadlocal.cpp b/example/async/threadlocal.cpp index 901e587f..3aa8534c 100644 --- a/example/async/threadlocal.cpp +++ b/example/async/threadlocal.cpp @@ -526,4 +526,4 @@ int main() { std::cout << "\n===== 示例完成 =====\n"; return 0; -} \ No newline at end of file +} diff --git a/example/async/timer.cpp b/example/async/timer.cpp index eb5e2c1d..7c772a5b 100644 --- a/example/async/timer.cpp +++ b/example/async/timer.cpp @@ -484,4 +484,4 @@ int main() { std::cout << "\n===== 示例完成 =====\n"; return 0; -} \ No newline at end of file +} diff --git a/example/async/trigger.cpp b/example/async/trigger.cpp index d4301a5d..b5b5e4b2 100644 --- a/example/async/trigger.cpp +++ b/example/async/trigger.cpp @@ -489,4 +489,4 @@ int main() { std::cout << "\n===== Examples Complete =====\n"; return 0; -} \ No newline at end of file +} diff --git a/example/components/CMakeLists.txt b/example/components/CMakeLists.txt index 13ce9567..f6faa642 100644 --- a/example/components/CMakeLists.txt +++ b/example/components/CMakeLists.txt @@ -14,20 +14,20 @@ file(GLOB CPP_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) foreach(CPP_FILE ${CPP_FILES}) # 获取不带扩展名的文件名 get_filename_component(EXAMPLE_NAME ${CPP_FILE} NAME_WE) - + # 构造可执行文件名称(子目录名_文件名) set(EXECUTABLE_NAME ${SUBDIR_NAME}_${EXAMPLE_NAME}) - + # 配置选项,允许单独控制每个示例的构建 string(TOUPPER ${EXAMPLE_NAME} EXAMPLE_NAME_UPPER) option(ATOM_EXAMPLE_COMPONENTS_${EXAMPLE_NAME_UPPER} "Build components example: ${EXAMPLE_NAME}" ${ATOM_EXAMPLE_COMPONENTS_BUILD_ALL}) - + # 有条件地添加可执行文件 if(ATOM_EXAMPLE_COMPONENTS_${EXAMPLE_NAME_UPPER}) add_executable(${EXECUTABLE_NAME} ${CPP_FILE}) target_link_libraries(${EXECUTABLE_NAME} atom) - - + + # 设置IDE文件夹分组 set_property(TARGET ${EXECUTABLE_NAME} PROPERTY FOLDER "Examples/Components") endif() diff --git a/example/connection/CMakeLists.txt b/example/connection/CMakeLists.txt index bd20d10c..cfc5e631 100644 --- a/example/connection/CMakeLists.txt +++ b/example/connection/CMakeLists.txt @@ -14,20 +14,20 @@ file(GLOB CPP_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) foreach(CPP_FILE ${CPP_FILES}) # 获取不带扩展名的文件名 get_filename_component(EXAMPLE_NAME ${CPP_FILE} NAME_WE) - + # 构造可执行文件名称(子目录名_文件名) set(EXECUTABLE_NAME ${SUBDIR_NAME}_${EXAMPLE_NAME}) - + # 配置选项,允许单独控制每个示例的构建 string(TOUPPER ${EXAMPLE_NAME} EXAMPLE_NAME_UPPER) option(ATOM_EXAMPLE_CONNECTION_${EXAMPLE_NAME_UPPER} "Build connection example: ${EXAMPLE_NAME}" ${ATOM_EXAMPLE_CONNECTION_BUILD_ALL}) - + # 有条件地添加可执行文件 if(ATOM_EXAMPLE_CONNECTION_${EXAMPLE_NAME_UPPER}) add_executable(${EXECUTABLE_NAME} ${CPP_FILE}) target_link_libraries(${EXECUTABLE_NAME} atom) - - + + # 设置IDE文件夹分组 set_property(TARGET ${EXECUTABLE_NAME} PROPERTY FOLDER "Examples/Connection") endif() diff --git a/example/connection/async_fifoclient.cpp b/example/connection/async_fifoclient.cpp index 627d29b0..f7dc9d95 100644 --- a/example/connection/async_fifoclient.cpp +++ b/example/connection/async_fifoclient.cpp @@ -134,4 +134,4 @@ int main() { std::cout << "\nFifoClient example completed successfully" << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/connection/async_fifoserver.cpp b/example/connection/async_fifoserver.cpp index bbfffe60..c8912387 100644 --- a/example/connection/async_fifoserver.cpp +++ b/example/connection/async_fifoserver.cpp @@ -163,4 +163,4 @@ int main() { std::cerr << "Fatal error: " << e.what() << std::endl; return 1; } -} \ No newline at end of file +} diff --git a/example/connection/async_sockethub.cpp b/example/connection/async_sockethub.cpp index 5379411d..c38d29e3 100644 --- a/example/connection/async_sockethub.cpp +++ b/example/connection/async_sockethub.cpp @@ -295,4 +295,4 @@ int main() { Logger::log("Main", std::string("Fatal error: ") + e.what()); return 1; } -} \ No newline at end of file +} diff --git a/example/connection/async_tcpclient.cpp b/example/connection/async_tcpclient.cpp index aed34da1..1b0ba2f4 100644 --- a/example/connection/async_tcpclient.cpp +++ b/example/connection/async_tcpclient.cpp @@ -399,4 +399,4 @@ int main() { std::string("Fatal error: ") + e.what()); return 1; } -} \ No newline at end of file +} diff --git a/example/connection/async_udpclient.cpp b/example/connection/async_udpclient.cpp index 9d04dfa1..090c5a1b 100644 --- a/example/connection/async_udpclient.cpp +++ b/example/connection/async_udpclient.cpp @@ -69,4 +69,4 @@ int main() { std::cout << "Stopped receiving data" << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/connection/async_udpserver.cpp b/example/connection/async_udpserver.cpp index dd849580..37699546 100644 --- a/example/connection/async_udpserver.cpp +++ b/example/connection/async_udpserver.cpp @@ -50,4 +50,4 @@ int main() { std::cout << "Server stopped" << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/error/CMakeLists.txt b/example/error/CMakeLists.txt index e17057a3..06a85992 100644 --- a/example/error/CMakeLists.txt +++ b/example/error/CMakeLists.txt @@ -14,20 +14,20 @@ file(GLOB CPP_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) foreach(CPP_FILE ${CPP_FILES}) # 获取不带扩展名的文件名 get_filename_component(EXAMPLE_NAME ${CPP_FILE} NAME_WE) - + # 构造可执行文件名称(子目录名_文件名) set(EXECUTABLE_NAME ${SUBDIR_NAME}_${EXAMPLE_NAME}) - + # 配置选项,允许单独控制每个示例的构建 string(TOUPPER ${EXAMPLE_NAME} EXAMPLE_NAME_UPPER) option(ATOM_EXAMPLE_ERROR_${EXAMPLE_NAME_UPPER} "Build error example: ${EXAMPLE_NAME}" ${ATOM_EXAMPLE_ERROR_BUILD_ALL}) - + # 有条件地添加可执行文件 if(ATOM_EXAMPLE_ERROR_${EXAMPLE_NAME_UPPER}) add_executable(${EXECUTABLE_NAME} ${CPP_FILE}) target_link_libraries(${EXECUTABLE_NAME} atom) - - + + # 设置IDE文件夹分组 set_property(TARGET ${EXECUTABLE_NAME} PROPERTY FOLDER "Examples/Error") endif() diff --git a/example/error/exception.cpp b/example/error/exception.cpp index 197fd5e2..2fe23f28 100644 --- a/example/error/exception.cpp +++ b/example/error/exception.cpp @@ -312,4 +312,4 @@ void testException() { int main() { testException(); return 0; -} \ No newline at end of file +} diff --git a/example/error/stacktrace.cpp b/example/error/stacktrace.cpp index d1ca59e3..a4e61044 100644 --- a/example/error/stacktrace.cpp +++ b/example/error/stacktrace.cpp @@ -28,4 +28,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/example/extra/CMakeLists.txt b/example/extra/CMakeLists.txt index 014dcfa8..04247bd9 100644 --- a/example/extra/CMakeLists.txt +++ b/example/extra/CMakeLists.txt @@ -14,20 +14,20 @@ file(GLOB CPP_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) foreach(CPP_FILE ${CPP_FILES}) # 获取不带扩展名的文件名 get_filename_component(EXAMPLE_NAME ${CPP_FILE} NAME_WE) - + # 构造可执行文件名称(子目录名_文件名) set(EXECUTABLE_NAME ${SUBDIR_NAME}_${EXAMPLE_NAME}) - + # 配置选项,允许单独控制每个示例的构建 string(TOUPPER ${EXAMPLE_NAME} EXAMPLE_NAME_UPPER) option(ATOM_EXAMPLE_EXTRA_${EXAMPLE_NAME_UPPER} "Build extra example: ${EXAMPLE_NAME}" ${ATOM_EXAMPLE_EXTRA_BUILD_ALL}) - + # 有条件地添加可执行文件 if(ATOM_EXAMPLE_EXTRA_${EXAMPLE_NAME_UPPER}) add_executable(${EXECUTABLE_NAME} ${CPP_FILE}) target_link_libraries(${EXECUTABLE_NAME} atom) - - + + # 设置IDE文件夹分组 set_property(TARGET ${EXECUTABLE_NAME} PROPERTY FOLDER "Examples/Extra") endif() diff --git a/example/extra/beast/http.cpp b/example/extra/beast/http.cpp index 5c5b6ab9..afe3bbe2 100644 --- a/example/extra/beast/http.cpp +++ b/example/extra/beast/http.cpp @@ -140,4 +140,4 @@ int main() { ioc.run(); return 0; -} \ No newline at end of file +} diff --git a/example/extra/beast/ws.cpp b/example/extra/beast/ws.cpp index bf7b7fdf..b70e447d 100644 --- a/example/extra/beast/ws.cpp +++ b/example/extra/beast/ws.cpp @@ -114,4 +114,4 @@ int main() { ioc.run(); return 0; -} \ No newline at end of file +} diff --git a/example/extra/boost/charconv.cpp b/example/extra/boost/charconv.cpp index 1e5c2ce8..cc412a5d 100644 --- a/example/extra/boost/charconv.cpp +++ b/example/extra/boost/charconv.cpp @@ -94,4 +94,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/example/extra/boost/locale.cpp b/example/extra/boost/locale.cpp index 08e1823b..ee3c1990 100644 --- a/example/extra/boost/locale.cpp +++ b/example/extra/boost/locale.cpp @@ -87,4 +87,4 @@ int main() { std::cout << "Formatted string: " << formattedStr << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/extra/boost/math.cpp b/example/extra/boost/math.cpp index 3aab81ee..40319d48 100644 --- a/example/extra/boost/math.cpp +++ b/example/extra/boost/math.cpp @@ -157,4 +157,4 @@ int main() { << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/extra/boost/regex.cpp b/example/extra/boost/regex.cpp index b2a246ec..67023eec 100644 --- a/example/extra/boost/regex.cpp +++ b/example/extra/boost/regex.cpp @@ -112,4 +112,4 @@ int main() { << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/extra/boost/system.cpp b/example/extra/boost/system.cpp index ed428992..e8ef9911 100644 --- a/example/extra/boost/system.cpp +++ b/example/extra/boost/system.cpp @@ -103,4 +103,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/example/extra/boost/uuid.cpp b/example/extra/boost/uuid.cpp index 33f61f50..f712081c 100644 --- a/example/extra/boost/uuid.cpp +++ b/example/extra/boost/uuid.cpp @@ -115,4 +115,4 @@ int main() { std::cout << "UUID hash value: " << hashValue << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/extra/uv/subprocess.cpp b/example/extra/uv/subprocess.cpp index d2e20ef6..f27e1d58 100644 --- a/example/extra/uv/subprocess.cpp +++ b/example/extra/uv/subprocess.cpp @@ -450,4 +450,4 @@ int main() { std::cerr << "\n\nSome examples failed!" << std::endl; return 1; } -} \ No newline at end of file +} diff --git a/example/image/CMakeLists.txt b/example/image/CMakeLists.txt index 098cd118..d0089f2d 100644 --- a/example/image/CMakeLists.txt +++ b/example/image/CMakeLists.txt @@ -14,20 +14,20 @@ file(GLOB CPP_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) foreach(CPP_FILE ${CPP_FILES}) # 获取不带扩展名的文件名 get_filename_component(EXAMPLE_NAME ${CPP_FILE} NAME_WE) - + # 构造可执行文件名称(子目录名_文件名) set(EXECUTABLE_NAME ${SUBDIR_NAME}_${EXAMPLE_NAME}) - + # 配置选项,允许单独控制每个示例的构建 string(TOUPPER ${EXAMPLE_NAME} EXAMPLE_NAME_UPPER) option(ATOM_EXAMPLE_IMAGE_${EXAMPLE_NAME_UPPER} "Build image example: ${EXAMPLE_NAME}" ${ATOM_EXAMPLE_IMAGE_BUILD_ALL}) - + # 有条件地添加可执行文件 if(ATOM_EXAMPLE_IMAGE_${EXAMPLE_NAME_UPPER}) add_executable(${EXECUTABLE_NAME} ${CPP_FILE}) target_link_libraries(${EXECUTABLE_NAME} atom) - - + + # 设置IDE文件夹分组 set_property(TARGET ${EXECUTABLE_NAME} PROPERTY FOLDER "Examples/Image") endif() diff --git a/example/io/CMakeLists.txt b/example/io/CMakeLists.txt index 8866c8a6..db4b9192 100644 --- a/example/io/CMakeLists.txt +++ b/example/io/CMakeLists.txt @@ -14,20 +14,20 @@ file(GLOB CPP_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) foreach(CPP_FILE ${CPP_FILES}) # 获取不带扩展名的文件名 get_filename_component(EXAMPLE_NAME ${CPP_FILE} NAME_WE) - + # 构造可执行文件名称(子目录名_文件名) set(EXECUTABLE_NAME ${SUBDIR_NAME}_${EXAMPLE_NAME}) - + # 配置选项,允许单独控制每个示例的构建 string(TOUPPER ${EXAMPLE_NAME} EXAMPLE_NAME_UPPER) option(ATOM_EXAMPLE_IO_${EXAMPLE_NAME_UPPER} "Build io example: ${EXAMPLE_NAME}" ${ATOM_EXAMPLE_IO_BUILD_ALL}) - + # 有条件地添加可执行文件 if(ATOM_EXAMPLE_IO_${EXAMPLE_NAME_UPPER}) add_executable(${EXECUTABLE_NAME} ${CPP_FILE}) target_link_libraries(${EXECUTABLE_NAME} atom) - - + + # 设置IDE文件夹分组 set_property(TARGET ${EXECUTABLE_NAME} PROPERTY FOLDER "Examples/Io") endif() diff --git a/example/log/CMakeLists.txt b/example/log/CMakeLists.txt index b4bb314b..add90c10 100644 --- a/example/log/CMakeLists.txt +++ b/example/log/CMakeLists.txt @@ -14,20 +14,20 @@ file(GLOB CPP_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) foreach(CPP_FILE ${CPP_FILES}) # 获取不带扩展名的文件名 get_filename_component(EXAMPLE_NAME ${CPP_FILE} NAME_WE) - + # 构造可执行文件名称(子目录名_文件名) set(EXECUTABLE_NAME ${SUBDIR_NAME}_${EXAMPLE_NAME}) - + # 配置选项,允许单独控制每个示例的构建 string(TOUPPER ${EXAMPLE_NAME} EXAMPLE_NAME_UPPER) option(ATOM_EXAMPLE_LOG_${EXAMPLE_NAME_UPPER} "Build log example: ${EXAMPLE_NAME}" ${ATOM_EXAMPLE_LOG_BUILD_ALL}) - + # 有条件地添加可执行文件 if(ATOM_EXAMPLE_LOG_${EXAMPLE_NAME_UPPER}) add_executable(${EXECUTABLE_NAME} ${CPP_FILE}) target_link_libraries(${EXECUTABLE_NAME} atom) - - + + # 设置IDE文件夹分组 set_property(TARGET ${EXECUTABLE_NAME} PROPERTY FOLDER "Examples/Log") endif() diff --git a/example/log/async_logger.cpp b/example/log/async_logger.cpp index 1fb00554..f64e3d62 100644 --- a/example/log/async_logger.cpp +++ b/example/log/async_logger.cpp @@ -211,4 +211,4 @@ int main() { std::cout << "\nAll examples completed.\nCheck the logs/ directory for " "output files.\n"; return 0; -} \ No newline at end of file +} diff --git a/example/log/atomlog.cpp b/example/log/atomlog.cpp index d46e5a2f..d023da76 100644 --- a/example/log/atomlog.cpp +++ b/example/log/atomlog.cpp @@ -44,4 +44,4 @@ int main() { logger.clearSinks(); return 0; -} \ No newline at end of file +} diff --git a/example/log/logger.cpp b/example/log/logger.cpp index f4f19f99..38b2dfda 100644 --- a/example/log/logger.cpp +++ b/example/log/logger.cpp @@ -36,4 +36,4 @@ int main() { loggerManager.analyzeLogs(); return 0; -} \ No newline at end of file +} diff --git a/example/memory/CMakeLists.txt b/example/memory/CMakeLists.txt index 0b4981a1..dbc13194 100644 --- a/example/memory/CMakeLists.txt +++ b/example/memory/CMakeLists.txt @@ -14,20 +14,20 @@ file(GLOB CPP_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) foreach(CPP_FILE ${CPP_FILES}) # 获取不带扩展名的文件名 get_filename_component(EXAMPLE_NAME ${CPP_FILE} NAME_WE) - + # 构造可执行文件名称(子目录名_文件名) set(EXECUTABLE_NAME ${SUBDIR_NAME}_${EXAMPLE_NAME}) - + # 配置选项,允许单独控制每个示例的构建 string(TOUPPER ${EXAMPLE_NAME} EXAMPLE_NAME_UPPER) option(ATOM_EXAMPLE_MEMORY_${EXAMPLE_NAME_UPPER} "Build memory example: ${EXAMPLE_NAME}" ${ATOM_EXAMPLE_MEMORY_BUILD_ALL}) - + # 有条件地添加可执行文件 if(ATOM_EXAMPLE_MEMORY_${EXAMPLE_NAME_UPPER}) add_executable(${EXECUTABLE_NAME} ${CPP_FILE}) target_link_libraries(${EXECUTABLE_NAME} atom) - - + + # 设置IDE文件夹分组 set_property(TARGET ${EXECUTABLE_NAME} PROPERTY FOLDER "Examples/Memory") endif() diff --git a/example/memory/memory.cpp b/example/memory/memory.cpp index bde7ad6c..9d074e4d 100644 --- a/example/memory/memory.cpp +++ b/example/memory/memory.cpp @@ -595,4 +595,4 @@ int main() { std::cout << "\nAll Memory Pool examples completed successfully!\n"; return 0; -} \ No newline at end of file +} diff --git a/example/memory/object.cpp b/example/memory/object.cpp index 3b7d692d..f2d9f5d5 100644 --- a/example/memory/object.cpp +++ b/example/memory/object.cpp @@ -696,4 +696,4 @@ int main() { std::cout << "\nAll ObjectPool examples completed successfully!\n"; return 0; -} \ No newline at end of file +} diff --git a/example/memory/ring.cpp b/example/memory/ring.cpp index 0a92260c..830781be 100644 --- a/example/memory/ring.cpp +++ b/example/memory/ring.cpp @@ -674,4 +674,4 @@ int main() { std::cout << "\nAll RingBuffer examples completed successfully!\n"; return 0; -} \ No newline at end of file +} diff --git a/example/memory/shared.cpp b/example/memory/shared.cpp index 9ea5e0e3..76c7823a 100644 --- a/example/memory/shared.cpp +++ b/example/memory/shared.cpp @@ -907,4 +907,4 @@ int main() { // The destructors for the SharedMemory objects will handle resource cleanup return 0; -} \ No newline at end of file +} diff --git a/example/memory/short_alloc.cpp b/example/memory/short_alloc.cpp index 13ac75b8..a8338f51 100644 --- a/example/memory/short_alloc.cpp +++ b/example/memory/short_alloc.cpp @@ -1033,4 +1033,4 @@ int main() { << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/memory/tracker.cpp b/example/memory/tracker.cpp index b8cfb753..bb483e94 100644 --- a/example/memory/tracker.cpp +++ b/example/memory/tracker.cpp @@ -541,4 +541,4 @@ int main() { << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/memory/utils.cpp b/example/memory/utils.cpp index 44c7c4d5..59cad253 100644 --- a/example/memory/utils.cpp +++ b/example/memory/utils.cpp @@ -538,4 +538,4 @@ int main() { std::cout << " 8. Combined usage of multiple utilities" << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/meta/CMakeLists.txt b/example/meta/CMakeLists.txt index a280ac9f..2ef618d3 100644 --- a/example/meta/CMakeLists.txt +++ b/example/meta/CMakeLists.txt @@ -14,20 +14,20 @@ file(GLOB CPP_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) foreach(CPP_FILE ${CPP_FILES}) # 获取不带扩展名的文件名 get_filename_component(EXAMPLE_NAME ${CPP_FILE} NAME_WE) - + # 构造可执行文件名称(子目录名_文件名) set(EXECUTABLE_NAME ${SUBDIR_NAME}_${EXAMPLE_NAME}) - + # 配置选项,允许单独控制每个示例的构建 string(TOUPPER ${EXAMPLE_NAME} EXAMPLE_NAME_UPPER) option(ATOM_EXAMPLE_META_${EXAMPLE_NAME_UPPER} "Build meta example: ${EXAMPLE_NAME}" ${ATOM_EXAMPLE_META_BUILD_ALL}) - + # 有条件地添加可执行文件 if(ATOM_EXAMPLE_META_${EXAMPLE_NAME_UPPER}) add_executable(${EXECUTABLE_NAME} ${CPP_FILE}) target_link_libraries(${EXECUTABLE_NAME} atom) - - + + # 设置IDE文件夹分组 set_property(TARGET ${EXECUTABLE_NAME} PROPERTY FOLDER "Examples/Meta") endif() diff --git a/example/meta/abi.cpp b/example/meta/abi.cpp index 3efee2ad..29ff09a5 100644 --- a/example/meta/abi.cpp +++ b/example/meta/abi.cpp @@ -380,4 +380,4 @@ int main() { std::cout << "End of ABI Parsing Tool Library Example\n" << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/meta/any.cpp b/example/meta/any.cpp index f5dd9402..6c1c366a 100644 --- a/example/meta/any.cpp +++ b/example/meta/any.cpp @@ -469,4 +469,4 @@ int main() { << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/meta/anymeta.cpp b/example/meta/anymeta.cpp index fea5344a..074bcf58 100644 --- a/example/meta/anymeta.cpp +++ b/example/meta/anymeta.cpp @@ -900,4 +900,4 @@ int main() { std::cout << "Cleanup complete." << std::endl; std::cout << "=========================================" << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/meta/bind_first.cpp b/example/meta/bind_first.cpp index 84c89265..cebd5082 100644 --- a/example/meta/bind_first.cpp +++ b/example/meta/bind_first.cpp @@ -951,4 +951,4 @@ int main() { } }; -} \ No newline at end of file +} diff --git a/example/meta/concept.cpp b/example/meta/concept.cpp index cbc6d702..638a93bb 100644 --- a/example/meta/concept.cpp +++ b/example/meta/concept.cpp @@ -747,4 +747,4 @@ int main() { std::cout << "All examples completed successfully!" << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/meta/constructor.cpp b/example/meta/constructor.cpp index b398fee5..964a359f 100644 --- a/example/meta/constructor.cpp +++ b/example/meta/constructor.cpp @@ -605,4 +605,4 @@ int main() { std::cout << "\nAll examples completed successfully!" << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/meta/conversion.cpp b/example/meta/conversion.cpp index 6e08e464..41cbedbd 100644 --- a/example/meta/conversion.cpp +++ b/example/meta/conversion.cpp @@ -828,4 +828,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/example/meta/decorate.cpp b/example/meta/decorate.cpp index 31d30b1a..963e014b 100644 --- a/example/meta/decorate.cpp +++ b/example/meta/decorate.cpp @@ -564,4 +564,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/example/meta/enum.cpp b/example/meta/enum.cpp index 302aa442..0cf4b587 100644 --- a/example/meta/enum.cpp +++ b/example/meta/enum.cpp @@ -466,4 +466,4 @@ int main() { filePerms = checkAndUpdatePermissions(filePerms, false); // Remove execute return 0; -} \ No newline at end of file +} diff --git a/example/meta/ffi.cpp b/example/meta/ffi.cpp index 4f1a93d1..551a8ae5 100644 --- a/example/meta/ffi.cpp +++ b/example/meta/ffi.cpp @@ -360,7 +360,7 @@ int main() { std::cout << R"( DynamicLibrary myLibrary("path/to/library.so", {}); auto mockObjectResult = myLibrary.createObject("createMockLibrary"); - + if (mockObjectResult) { MockLibraryInterface& mockObj = *mockObjectResult.value(); int sum = mockObj.add(10, 20); @@ -554,4 +554,4 @@ int main() { std::cout << "10. Low-level FFI wrapper for direct control" << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/meta/field_count.cpp b/example/meta/field_count.cpp index 057f00ac..3b99354e 100644 --- a/example/meta/field_count.cpp +++ b/example/meta/field_count.cpp @@ -369,4 +369,4 @@ int main() { << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/meta/func_traits.cpp b/example/meta/func_traits.cpp index ec37a224..885c4cc5 100644 --- a/example/meta/func_traits.cpp +++ b/example/meta/func_traits.cpp @@ -553,4 +553,4 @@ int main() { executeFunction("add", "wrong", "types"); // Intentional type mismatch return 0; -} \ No newline at end of file +} diff --git a/example/meta/global_ptr.cpp b/example/meta/global_ptr.cpp index 260547a1..ea25b127 100644 --- a/example/meta/global_ptr.cpp +++ b/example/meta/global_ptr.cpp @@ -598,4 +598,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/example/meta/god.cpp b/example/meta/god.cpp index de66817d..35dc16a1 100644 --- a/example/meta/god.cpp +++ b/example/meta/god.cpp @@ -870,4 +870,4 @@ void demonstrateResourceManagement() { std::cout << std::endl; } -} \ No newline at end of file +} diff --git a/example/meta/invoke.cpp b/example/meta/invoke.cpp index d83faf0c..c1575128 100644 --- a/example/meta/invoke.cpp +++ b/example/meta/invoke.cpp @@ -822,4 +822,4 @@ void demo_instrumentation() { std::cout << " Instrumentation report for divide_function:\n"; std::cout << " - Would show 4 calls, 2 exceptions\n"; } -} \ No newline at end of file +} diff --git a/example/meta/member.cpp b/example/meta/member.cpp index a1f7b863..9516d169 100644 --- a/example/meta/member.cpp +++ b/example/meta/member.cpp @@ -393,4 +393,4 @@ int main() { std::cout << "\n"; return 0; -} \ No newline at end of file +} diff --git a/example/meta/overload.cpp b/example/meta/overload.cpp index 4ba37aa5..f25395fe 100644 --- a/example/meta/overload.cpp +++ b/example/meta/overload.cpp @@ -270,4 +270,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/example/meta/property.cpp b/example/meta/property.cpp index 798c6cf0..2aeb9a03 100644 --- a/example/meta/property.cpp +++ b/example/meta/property.cpp @@ -396,4 +396,4 @@ int main() { << "°C = " << fahrenheit << "°F" << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/meta/proxy.cpp b/example/meta/proxy.cpp index cdda1659..212dd42b 100644 --- a/example/meta/proxy.cpp +++ b/example/meta/proxy.cpp @@ -479,4 +479,4 @@ int main() { << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/meta/proxy_params.cpp b/example/meta/proxy_params.cpp index 14c01b52..596f7917 100644 --- a/example/meta/proxy_params.cpp +++ b/example/meta/proxy_params.cpp @@ -478,4 +478,4 @@ int main() { printJson(complexJson); return 0; -} \ No newline at end of file +} diff --git a/example/meta/raw_name.cpp b/example/meta/raw_name.cpp index 568c7d53..3feb3b6a 100644 --- a/example/meta/raw_name.cpp +++ b/example/meta/raw_name.cpp @@ -311,4 +311,4 @@ int main() { "test"); // Should not match (std::string vs const char*) return 0; -} \ No newline at end of file +} diff --git a/example/meta/signature.cpp b/example/meta/signature.cpp index b3585afe..3818f471 100644 --- a/example/meta/signature.cpp +++ b/example/meta/signature.cpp @@ -356,4 +356,4 @@ int main() { "Matrix, parallelism: int = 4) -> Matrix noexcept"); return 0; -} \ No newline at end of file +} diff --git a/example/meta/stepper.cpp b/example/meta/stepper.cpp index d0d2cbbf..3460979d 100644 --- a/example/meta/stepper.cpp +++ b/example/meta/stepper.cpp @@ -579,4 +579,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/example/meta/template_traits.cpp b/example/meta/template_traits.cpp index b16d56cf..67fb1c62 100644 --- a/example/meta/template_traits.cpp +++ b/example/meta/template_traits.cpp @@ -495,4 +495,4 @@ int main() { showTemplateInfo(var); return 0; -} \ No newline at end of file +} diff --git a/example/meta/type_caster.cpp b/example/meta/type_caster.cpp index 872cff8c..4d38f3ac 100644 --- a/example/meta/type_caster.cpp +++ b/example/meta/type_caster.cpp @@ -550,4 +550,4 @@ int main() { std::cout << "\nAll TypeCaster examples completed successfully!\n"; return 0; -} \ No newline at end of file +} diff --git a/example/meta/type_info.cpp b/example/meta/type_info.cpp index 7d57ea3d..6977587c 100644 --- a/example/meta/type_info.cpp +++ b/example/meta/type_info.cpp @@ -563,4 +563,4 @@ int main() { std::cout << "\nAll TypeInfo examples completed successfully!\n"; return 0; -} \ No newline at end of file +} diff --git a/example/meta/vany.cpp b/example/meta/vany.cpp index 106670bd..4e1585ad 100644 --- a/example/meta/vany.cpp +++ b/example/meta/vany.cpp @@ -560,4 +560,4 @@ int main() { std::cout << "\nAll Any examples completed successfully!\n"; return 0; -} \ No newline at end of file +} diff --git a/example/search/CMakeLists.txt b/example/search/CMakeLists.txt index d54f820a..ad38a495 100644 --- a/example/search/CMakeLists.txt +++ b/example/search/CMakeLists.txt @@ -14,20 +14,20 @@ file(GLOB CPP_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) foreach(CPP_FILE ${CPP_FILES}) # 获取不带扩展名的文件名 get_filename_component(EXAMPLE_NAME ${CPP_FILE} NAME_WE) - + # 构造可执行文件名称(子目录名_文件名) set(EXECUTABLE_NAME ${SUBDIR_NAME}_${EXAMPLE_NAME}) - + # 配置选项,允许单独控制每个示例的构建 string(TOUPPER ${EXAMPLE_NAME} EXAMPLE_NAME_UPPER) option(ATOM_EXAMPLE_SEARCH_${EXAMPLE_NAME_UPPER} "Build search example: ${EXAMPLE_NAME}" ${ATOM_EXAMPLE_SEARCH_BUILD_ALL}) - + # 有条件地添加可执行文件 if(ATOM_EXAMPLE_SEARCH_${EXAMPLE_NAME_UPPER}) add_executable(${EXECUTABLE_NAME} ${CPP_FILE}) target_link_libraries(${EXECUTABLE_NAME} atom) - - + + # 设置IDE文件夹分组 set_property(TARGET ${EXECUTABLE_NAME} PROPERTY FOLDER "Examples/Search") endif() diff --git a/example/search/cache.cpp b/example/search/cache.cpp index 4db22626..d6ea85b7 100644 --- a/example/search/cache.cpp +++ b/example/search/cache.cpp @@ -650,4 +650,4 @@ int main() { std::cout << "Example completed successfully!" << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/search/lru.cpp b/example/search/lru.cpp index 35635234..fd6887ac 100644 --- a/example/search/lru.cpp +++ b/example/search/lru.cpp @@ -669,4 +669,4 @@ int main() { std::cout << " 10. Error handling and edge cases" << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/search/search.cpp b/example/search/search.cpp index e4bd46de..8f8d579e 100644 --- a/example/search/search.cpp +++ b/example/search/search.cpp @@ -617,4 +617,4 @@ int main() { std::cout << " 8. Multithreaded search operations" << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/search/sqlite.cpp b/example/search/sqlite.cpp index c6c9523d..331bc1aa 100644 --- a/example/search/sqlite.cpp +++ b/example/search/sqlite.cpp @@ -313,4 +313,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/example/search/ttl.cpp b/example/search/ttl.cpp index 148c4526..47f6d510 100644 --- a/example/search/ttl.cpp +++ b/example/search/ttl.cpp @@ -265,4 +265,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/example/serial/CMakeLists.txt b/example/serial/CMakeLists.txt index acbe9f52..a20ac4d3 100644 --- a/example/serial/CMakeLists.txt +++ b/example/serial/CMakeLists.txt @@ -14,20 +14,20 @@ file(GLOB CPP_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) foreach(CPP_FILE ${CPP_FILES}) # 获取不带扩展名的文件名 get_filename_component(EXAMPLE_NAME ${CPP_FILE} NAME_WE) - + # 构造可执行文件名称(子目录名_文件名) set(EXECUTABLE_NAME ${SUBDIR_NAME}_${EXAMPLE_NAME}) - + # 配置选项,允许单独控制每个示例的构建 string(TOUPPER ${EXAMPLE_NAME} EXAMPLE_NAME_UPPER) option(ATOM_EXAMPLE_SERIAL_${EXAMPLE_NAME_UPPER} "Build serial example: ${EXAMPLE_NAME}" ${ATOM_EXAMPLE_SERIAL_BUILD_ALL}) - + # 有条件地添加可执行文件 if(ATOM_EXAMPLE_SERIAL_${EXAMPLE_NAME_UPPER}) add_executable(${EXECUTABLE_NAME} ${CPP_FILE}) target_link_libraries(${EXECUTABLE_NAME} atom) - - + + # 设置IDE文件夹分组 set_property(TARGET ${EXECUTABLE_NAME} PROPERTY FOLDER "Examples/Serial") endif() diff --git a/example/serial/scanner.cpp b/example/serial/scanner.cpp index dc126026..bd9f82f0 100644 --- a/example/serial/scanner.cpp +++ b/example/serial/scanner.cpp @@ -9,7 +9,7 @@ using namespace atom::serial; /** * 展示如何使用 SerialPortScanner 类的基本功能 - * + * * 本示例展示: * 1. 异步列出可用端口 * 2. 获取特定端口的详细信息 @@ -26,41 +26,41 @@ int main() { config.detect_ch340 = true; config.include_virtual_ports = false; config.timeout = std::chrono::milliseconds(2000); - + SerialPortScanner scanner(config); - + // 注册一个自定义设备检测器 scanner.register_device_detector( - "FTDI", + "FTDI", [](uint16_t vid, uint16_t pid, std::string_view description) -> std::pair { // 检测是否为FTDI设备 if (vid == 0x0403) { return {true, "FTDI Device"}; } - + // 检查描述 std::string lower_desc; lower_desc.resize(description.size()); std::transform(description.begin(), description.end(), lower_desc.begin(), [](unsigned char c) { return std::tolower(c); }); - + if (lower_desc.find("ftdi") != std::string::npos) { return {true, "FTDI (Detected by Description)"}; } - + return {false, ""}; } ); - + // 异步列出可用端口 std::cout << "正在异步列出可用端口...\n"; std::atomic done = false; - + scanner.list_available_ports_async( [&done](SerialPortScanner::Result> result) { if (std::holds_alternative>(result)) { const auto& ports = std::get>(result); - + std::cout << "找到 " << ports.size() << " 个串口:\n"; for (const auto& port : ports) { std::cout << " - " << port.device << ": " << port.description; @@ -71,36 +71,36 @@ int main() { } } else { const auto& error = std::get(result); - std::cerr << "错误: " << error.message + std::cerr << "错误: " << error.message << " (代码: " << error.error_code << ")\n"; } - + done = true; } ); - + // 等待异步操作完成 while (!done) { std::cout << "等待扫描完成...\n"; std::this_thread::sleep_for(std::chrono::milliseconds(500)); } - + std::cout << "\n正在同步列出可用端口...\n"; auto sync_result = scanner.list_available_ports(); - + if (std::holds_alternative>(sync_result)) { const auto& ports = std::get>(sync_result); - + // 如果找到端口,获取第一个端口的详细信息 if (!ports.empty()) { std::string first_port = ports.front().device; std::cout << "\n获取 " << first_port << " 的详细信息:\n"; - + auto details_result = scanner.get_port_details(first_port); - + if (std::holds_alternative>(details_result)) { const auto& maybe_details = std::get>(details_result); - + if (maybe_details) { const auto& details = *maybe_details; std::cout << " 设备名称: " << details.device_name << "\n"; @@ -108,22 +108,22 @@ int main() { std::cout << " 硬件 ID: " << details.hardware_id << "\n"; std::cout << " VID: " << details.vid << "\n"; std::cout << " PID: " << details.pid << "\n"; - + if (!details.serial_number.empty()) std::cout << " 序列号: " << details.serial_number << "\n"; - + if (!details.manufacturer.empty()) std::cout << " 制造商: " << details.manufacturer << "\n"; - + if (!details.product.empty()) std::cout << " 产品: " << details.product << "\n"; - + if (!details.location.empty()) std::cout << " 位置: " << details.location << "\n"; - + if (!details.interface.empty()) std::cout << " 接口: " << details.interface << "\n"; - + if (details.is_ch340) { std::cout << " CH340 设备: " << details.ch340_model << "\n"; std::cout << " 推荐波特率: " << details.recommended_baud_rates << "\n"; @@ -134,16 +134,16 @@ int main() { } } else { const auto& error = std::get(details_result); - std::cerr << "获取详细信息时出错: " << error.message + std::cerr << "获取详细信息时出错: " << error.message << " (代码: " << error.error_code << ")\n"; } } } - + } catch (const std::exception& e) { std::cerr << "异常: " << e.what() << "\n"; return 1; } - + return 0; -} \ No newline at end of file +} diff --git a/example/system/CMakeLists.txt b/example/system/CMakeLists.txt index ed517df5..304f8021 100644 --- a/example/system/CMakeLists.txt +++ b/example/system/CMakeLists.txt @@ -14,20 +14,20 @@ file(GLOB CPP_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) foreach(CPP_FILE ${CPP_FILES}) # 获取不带扩展名的文件名 get_filename_component(EXAMPLE_NAME ${CPP_FILE} NAME_WE) - + # 构造可执行文件名称(子目录名_文件名) set(EXECUTABLE_NAME ${SUBDIR_NAME}_${EXAMPLE_NAME}) - + # 配置选项,允许单独控制每个示例的构建 string(TOUPPER ${EXAMPLE_NAME} EXAMPLE_NAME_UPPER) option(ATOM_EXAMPLE_SYSTEM_${EXAMPLE_NAME_UPPER} "Build system example: ${EXAMPLE_NAME}" ${ATOM_EXAMPLE_SYSTEM_BUILD_ALL}) - + # 有条件地添加可执行文件 if(ATOM_EXAMPLE_SYSTEM_${EXAMPLE_NAME_UPPER}) add_executable(${EXECUTABLE_NAME} ${CPP_FILE}) target_link_libraries(${EXECUTABLE_NAME} atom) - - + + # 设置IDE文件夹分组 set_property(TARGET ${EXECUTABLE_NAME} PROPERTY FOLDER "Examples/System") endif() diff --git a/example/system/command.cpp b/example/system/command.cpp index c1b9ba46..100bbad5 100644 --- a/example/system/command.cpp +++ b/example/system/command.cpp @@ -236,4 +236,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/example/system/crash_quotes.cpp b/example/system/crash_quotes.cpp index ca3c8470..47f1ec8a 100644 --- a/example/system/crash_quotes.cpp +++ b/example/system/crash_quotes.cpp @@ -58,4 +58,4 @@ int main() { manager.saveQuotesToJson("saved_quotes.json"); return 0; -} \ No newline at end of file +} diff --git a/example/system/crontab.cpp b/example/system/crontab.cpp index f68382f4..4ef9e116 100644 --- a/example/system/crontab.cpp +++ b/example/system/crontab.cpp @@ -56,4 +56,4 @@ int main() { std::cout << "Cron job statistics: " << stats << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/system/env.cpp b/example/system/env.cpp index bd5f905a..b606b694 100644 --- a/example/system/env.cpp +++ b/example/system/env.cpp @@ -62,4 +62,4 @@ int main(int argc, char** argv) { std::cout << "Added SHARED_VAR=789 to shared Env" << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/system/gpio.cpp b/example/system/gpio.cpp index 59574f4c..793e6854 100644 --- a/example/system/gpio.cpp +++ b/example/system/gpio.cpp @@ -27,4 +27,4 @@ int main() { }); return 0; -} \ No newline at end of file +} diff --git a/example/system/lregistry.cpp b/example/system/lregistry.cpp index ea1fe761..a0f16e7a 100644 --- a/example/system/lregistry.cpp +++ b/example/system/lregistry.cpp @@ -58,4 +58,4 @@ int main() { std::cout << "Registry data restored from backup file" << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/system/network_manager.cpp b/example/system/network_manager.cpp index 7f9d935b..ea3fb7ef 100644 --- a/example/system/network_manager.cpp +++ b/example/system/network_manager.cpp @@ -74,4 +74,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/example/system/pidwatcher.cpp b/example/system/pidwatcher.cpp index b8e1cff0..f204c7db 100644 --- a/example/system/pidwatcher.cpp +++ b/example/system/pidwatcher.cpp @@ -43,4 +43,4 @@ int main() { std::cout << "Monitoring stopped." << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/system/priority.cpp b/example/system/priority.cpp index f09f11e5..b4a87e07 100644 --- a/example/system/priority.cpp +++ b/example/system/priority.cpp @@ -57,4 +57,4 @@ int main() { std::this_thread::sleep_for(std::chrono::seconds(5)); return 0; -} \ No newline at end of file +} diff --git a/example/system/process.cpp b/example/system/process.cpp index f09d6084..0046ab8e 100644 --- a/example/system/process.cpp +++ b/example/system/process.cpp @@ -62,4 +62,4 @@ int main() { #endif return 0; -} \ No newline at end of file +} diff --git a/example/system/process_manager.cpp b/example/system/process_manager.cpp index 5b27c739..dcb5ef4d 100644 --- a/example/system/process_manager.cpp +++ b/example/system/process_manager.cpp @@ -105,4 +105,4 @@ int main() { #endif return 0; -} \ No newline at end of file +} diff --git a/example/system/signal.cpp b/example/system/signal.cpp index 6fcb6bf9..1152b18a 100644 --- a/example/system/signal.cpp +++ b/example/system/signal.cpp @@ -58,4 +58,4 @@ int main() { std::this_thread::sleep_for(std::chrono::seconds(1)); return 0; -} \ No newline at end of file +} diff --git a/example/system/software.cpp b/example/system/software.cpp index b2745cb5..5b21d72b 100644 --- a/example/system/software.cpp +++ b/example/system/software.cpp @@ -28,4 +28,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/example/system/stat.cpp b/example/system/stat.cpp index 661f9728..85310a9f 100644 --- a/example/system/stat.cpp +++ b/example/system/stat.cpp @@ -58,4 +58,4 @@ int main() { std::cout << "File path: " << filePathRetrieved << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/system/storage.cpp b/example/system/storage.cpp index 022a7cee..d4038a4a 100644 --- a/example/system/storage.cpp +++ b/example/system/storage.cpp @@ -60,4 +60,4 @@ int main() { std::cout << "Stopped monitoring" << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/system/user.cpp b/example/system/user.cpp index 08a44a28..7e798dd7 100644 --- a/example/system/user.cpp +++ b/example/system/user.cpp @@ -57,4 +57,4 @@ int main() { std::cout << "Is root user: " << std::boolalpha << isRootUser << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/system/wregistry.cpp b/example/system/wregistry.cpp index 433c2c09..24154c70 100644 --- a/example/system/wregistry.cpp +++ b/example/system/wregistry.cpp @@ -69,4 +69,4 @@ int main() { #endif return 0; -} \ No newline at end of file +} diff --git a/example/type/CMakeLists.txt b/example/type/CMakeLists.txt index 7de8c56d..5c1c4897 100644 --- a/example/type/CMakeLists.txt +++ b/example/type/CMakeLists.txt @@ -14,20 +14,20 @@ file(GLOB CPP_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) foreach(CPP_FILE ${CPP_FILES}) # 获取不带扩展名的文件名 get_filename_component(EXAMPLE_NAME ${CPP_FILE} NAME_WE) - + # 构造可执行文件名称(子目录名_文件名) set(EXECUTABLE_NAME ${SUBDIR_NAME}_${EXAMPLE_NAME}) - + # 配置选项,允许单独控制每个示例的构建 string(TOUPPER ${EXAMPLE_NAME} EXAMPLE_NAME_UPPER) option(ATOM_EXAMPLE_TYPE_${EXAMPLE_NAME_UPPER} "Build type example: ${EXAMPLE_NAME}" ${ATOM_EXAMPLE_TYPE_BUILD_ALL}) - + # 有条件地添加可执行文件 if(ATOM_EXAMPLE_TYPE_${EXAMPLE_NAME_UPPER}) add_executable(${EXECUTABLE_NAME} ${CPP_FILE}) target_link_libraries(${EXECUTABLE_NAME} atom) - - + + # 设置IDE文件夹分组 set_property(TARGET ${EXECUTABLE_NAME} PROPERTY FOLDER "Examples/Type") endif() diff --git a/example/type/args.cpp b/example/type/args.cpp index d6de0e00..b5c85d57 100644 --- a/example/type/args.cpp +++ b/example/type/args.cpp @@ -899,4 +899,4 @@ int main() { << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/type/argsview.cpp b/example/type/argsview.cpp index f1f441d4..db10c03e 100644 --- a/example/type/argsview.cpp +++ b/example/type/argsview.cpp @@ -366,4 +366,4 @@ int main() { std::cout << "\nAll examples completed successfully!" << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/type/auto_table.cpp b/example/type/auto_table.cpp index 3d8c4e13..c9e72bc2 100644 --- a/example/type/auto_table.cpp +++ b/example/type/auto_table.cpp @@ -391,4 +391,4 @@ int main() { std::cout << "\nAll examples completed successfully!" << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/type/concurrent_map.cpp b/example/type/concurrent_map.cpp index 9460d03a..f454b42f 100644 --- a/example/type/concurrent_map.cpp +++ b/example/type/concurrent_map.cpp @@ -311,4 +311,4 @@ int main() { std::cout << "\nAll examples completed successfully!" << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/type/concurrent_set.cpp b/example/type/concurrent_set.cpp index 44cd5a3f..b12cad8f 100644 --- a/example/type/concurrent_set.cpp +++ b/example/type/concurrent_set.cpp @@ -791,4 +791,4 @@ int main() { std::cout << "\nExample completed successfully!" << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/type/concurrent_vector.cpp b/example/type/concurrent_vector.cpp index b8dcde8e..362fb60b 100644 --- a/example/type/concurrent_vector.cpp +++ b/example/type/concurrent_vector.cpp @@ -667,4 +667,4 @@ int main() { << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/type/cstream.cpp b/example/type/cstream.cpp index e62e5a28..3258f235 100644 --- a/example/type/cstream.cpp +++ b/example/type/cstream.cpp @@ -598,4 +598,4 @@ int main() { << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/type/expected.cpp b/example/type/expected.cpp index d3fe08f4..b412927a 100644 --- a/example/type/expected.cpp +++ b/example/type/expected.cpp @@ -725,4 +725,4 @@ int main() { << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/type/flatmap.cpp b/example/type/flatmap.cpp index 8578413a..e422eeb4 100644 --- a/example/type/flatmap.cpp +++ b/example/type/flatmap.cpp @@ -354,4 +354,4 @@ int main() { sorted_vector_example(); return 0; -} \ No newline at end of file +} diff --git a/example/type/flatset.cpp b/example/type/flatset.cpp index a60ef2a2..b8c1a0c0 100644 --- a/example/type/flatset.cpp +++ b/example/type/flatset.cpp @@ -565,4 +565,4 @@ int main() { error_handling(); return 0; -} \ No newline at end of file +} diff --git a/example/type/indestructible.cpp b/example/type/indestructible.cpp index adb41c51..fdbc7440 100644 --- a/example/type/indestructible.cpp +++ b/example/type/indestructible.cpp @@ -450,4 +450,4 @@ int main() { std::cout << "\nAll examples completed!\n"; return 0; -} \ No newline at end of file +} diff --git a/example/type/iter.cpp b/example/type/iter.cpp index 72e99684..802e6b61 100644 --- a/example/type/iter.cpp +++ b/example/type/iter.cpp @@ -29,34 +29,34 @@ void print_key_value_container(const Container& container, const std::string& na // Example 1: PointerIterator void pointer_iterator_example() { std::cout << "\n=== Example 1: PointerIterator ===\n"; - + // Create a sample container std::vector numbers = {10, 20, 30, 40, 50}; print_container(numbers, "Original vector"); - + // Create pointer iterators auto [begin_ptr, end_ptr] = makePointerRange(numbers.begin(), numbers.end()); - + // Print addresses of original elements std::cout << "Addresses of elements:\n"; for (auto it = begin_ptr; it != end_ptr; ++it) { int* ptr = *it; // Get a pointer to the element std::cout << "Value: " << *ptr << ", Address: " << ptr << std::endl; } - + // Modify elements via pointers std::cout << "\nModifying elements via pointers...\n"; for (auto it = begin_ptr; it != end_ptr; ++it) { int* ptr = *it; *ptr *= 2; // Double each value } - + print_container(numbers, "Modified vector"); - + // Example of processContainer function std::list chars = {'a', 'b', 'c', 'd', 'e'}; print_container(chars, "Original list of chars"); - + std::cout << "Calling processContainer to remove middle elements...\n"; processContainer(chars); print_container(chars, "Resulting list of chars"); @@ -65,30 +65,30 @@ void pointer_iterator_example() { // Example 2: EarlyIncIterator void early_inc_iterator_example() { std::cout << "\n=== Example 2: EarlyIncIterator ===\n"; - + std::vector numbers = {1, 2, 3, 4, 5}; print_container(numbers, "Original vector"); - + // Create early increment iterators auto begin_early = makeEarlyIncIterator(numbers.begin()); auto end_early = makeEarlyIncIterator(numbers.end()); - + std::cout << "Using EarlyIncIterator to traverse the vector:\n"; for (auto it = begin_early; it != end_early; ++it) { std::cout << *it << " "; } std::cout << std::endl; - + // Demonstrate the early increment behavior std::cout << "\nDemonstrating early increment behavior:\n"; auto it = makeEarlyIncIterator(numbers.begin()); std::cout << "Initial value: " << *it << std::endl; - + // Post increment returns iterator before increment auto copy = it++; std::cout << "After post-increment, original iterator: " << *it << std::endl; std::cout << "Returned copy: " << *copy << std::endl; - + // Pre increment returns reference to incremented iterator auto& ref = ++it; std::cout << "After pre-increment: " << *it << std::endl; @@ -98,37 +98,37 @@ void early_inc_iterator_example() { // Example 3: TransformIterator void transform_iterator_example() { std::cout << "\n=== Example 3: TransformIterator ===\n"; - + std::vector numbers = {1, 2, 3, 4, 5}; print_container(numbers, "Original vector"); - + // Square function auto square = [](int n) { return n * n; }; - + // Create transform iterators that will square each element auto begin_transform = makeTransformIterator(numbers.begin(), square); auto end_transform = makeTransformIterator(numbers.end(), square); - + std::cout << "Squared values using TransformIterator: "; for (auto it = begin_transform; it != end_transform; ++it) { std::cout << *it << " "; // Will print squared values } std::cout << std::endl; - + // Transform strings to their lengths std::vector strings = {"hello", "world", "custom", "iterators", "example"}; print_container(strings, "Original strings"); - + auto string_length = [](const std::string& s) { return s.length(); }; auto begin_length = makeTransformIterator(strings.begin(), string_length); auto end_length = makeTransformIterator(strings.end(), string_length); - + std::cout << "String lengths using TransformIterator: "; for (auto it = begin_length; it != end_length; ++it) { std::cout << *it << " "; // Will print string lengths } std::cout << std::endl; - + // Using transform iterator with structured bindings std::map scores = { {"Alice", 95}, @@ -138,15 +138,15 @@ void transform_iterator_example() { {"Eve", 89} }; print_key_value_container(scores, "Original scores"); - + // Transform to formatted strings auto format_score = [](const std::pair& p) -> std::string { return p.first + ": " + std::to_string(p.second) + " points"; }; - + auto begin_format = makeTransformIterator(scores.begin(), format_score); auto end_format = makeTransformIterator(scores.end(), format_score); - + std::cout << "Formatted scores using TransformIterator:\n"; for (auto it = begin_format; it != end_format; ++it) { std::cout << " " << *it << std::endl; @@ -156,46 +156,46 @@ void transform_iterator_example() { // Example 4: FilterIterator void filter_iterator_example() { std::cout << "\n=== Example 4: FilterIterator ===\n"; - + std::vector numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; print_container(numbers, "Original vector"); - + // Filter for even numbers auto is_even = [](int n) { return n % 2 == 0; }; auto begin_even = makeFilterIterator(numbers.begin(), numbers.end(), is_even); auto end_even = makeFilterIterator(numbers.end(), numbers.end(), is_even); - + std::cout << "Even numbers using FilterIterator: "; for (auto it = begin_even; it != end_even; ++it) { std::cout << *it << " "; } std::cout << std::endl; - + // Filter for numbers greater than 5 auto greater_than_5 = [](int n) { return n > 5; }; auto begin_gt5 = makeFilterIterator(numbers.begin(), numbers.end(), greater_than_5); auto end_gt5 = makeFilterIterator(numbers.end(), numbers.end(), greater_than_5); - + std::cout << "Numbers > 5 using FilterIterator: "; for (auto it = begin_gt5; it != end_gt5; ++it) { std::cout << *it << " "; } std::cout << std::endl; - + // Filter strings by length std::vector strings = {"hi", "hello", "a", "world", "cpp", "custom", "iterators"}; print_container(strings, "Original strings"); - + auto length_greater_than_3 = [](const std::string& s) { return s.length() > 3; }; auto begin_str = makeFilterIterator(strings.begin(), strings.end(), length_greater_than_3); auto end_str = makeFilterIterator(strings.end(), strings.end(), length_greater_than_3); - + std::cout << "Strings longer than 3 characters using FilterIterator: "; for (auto it = begin_str; it != end_str; ++it) { std::cout << *it << " "; } std::cout << std::endl; - + // Filter on a map - only show scores above 90 std::map scores = { {"Alice", 95}, @@ -204,11 +204,11 @@ void filter_iterator_example() { {"David", 78}, {"Eve", 89} }; - + auto high_score = [](const std::pair& p) { return p.second >= 90; }; auto begin_high = makeFilterIterator(scores.begin(), scores.end(), high_score); auto end_high = makeFilterIterator(scores.end(), scores.end(), high_score); - + std::cout << "High scorers (>= 90) using FilterIterator: "; for (auto it = begin_high; it != end_high; ++it) { std::cout << it->first << "(" << it->second << ") "; @@ -219,40 +219,40 @@ void filter_iterator_example() { // Example 5: ReverseIterator void reverse_iterator_example() { std::cout << "\n=== Example 5: ReverseIterator ===\n"; - + std::vector numbers = {1, 2, 3, 4, 5}; print_container(numbers, "Original vector"); - + // Create reverse iterators ReverseIterator::iterator> rbegin(numbers.end()); ReverseIterator::iterator> rend(numbers.begin()); - + std::cout << "Vector traversed in reverse using ReverseIterator: "; for (auto it = rbegin; it != rend; ++it) { std::cout << *it << " "; } std::cout << std::endl; - + // Compare with STL reverse iterator std::cout << "Vector traversed with STL reverse_iterator: "; for (auto it = numbers.rbegin(); it != numbers.rend(); ++it) { std::cout << *it << " "; } std::cout << std::endl; - + // Modify elements using the custom reverse iterator std::cout << "Modifying elements using ReverseIterator...\n"; for (auto it = rbegin; it != rend; ++it) { *it += 10; } print_container(numbers, "Modified vector"); - + // Get underlying iterator using base() std::cout << "Using base() to get the original iterator:\n"; auto rev_it = rbegin; ++rev_it; // Move to the second element from the end auto base_it = rev_it.base(); // Get the forward iterator - + std::cout << "Reverse iterator points to: " << *rev_it << std::endl; std::cout << "Base iterator points to: " << *(base_it - 1) << std::endl; } @@ -260,57 +260,57 @@ void reverse_iterator_example() { // Example 6: ZipIterator void zip_iterator_example() { std::cout << "\n=== Example 6: ZipIterator ===\n"; - + std::vector numbers = {1, 2, 3, 4, 5}; std::vector names = {"one", "two", "three", "four", "five"}; std::vector letters = {'a', 'b', 'c', 'd', 'e'}; - + print_container(numbers, "Numbers"); print_container(names, "Names"); print_container(letters, "Letters"); - + // Create zip iterators for two containers auto begin_zip2 = makeZipIterator(numbers.begin(), names.begin()); auto end_zip2 = makeZipIterator(numbers.end(), names.end()); - + std::cout << "\nZipping numbers and names:\n"; for (auto it = begin_zip2; it != end_zip2; ++it) { auto [num, name] = *it; // Unpack the tuple std::cout << num << ": " << name << std::endl; } - + // Create zip iterators for three containers auto begin_zip3 = makeZipIterator(numbers.begin(), names.begin(), letters.begin()); auto end_zip3 = makeZipIterator(numbers.end(), names.end(), letters.end()); - + std::cout << "\nZipping numbers, names, and letters:\n"; for (auto it = begin_zip3; it != end_zip3; ++it) { auto [num, name, letter] = *it; // Unpack the tuple std::cout << num << ": " << name << " (" << letter << ")" << std::endl; } - + // Use zip iterator to modify elements std::vector vec1 = {1, 2, 3, 4}; std::vector vec2 = {10, 20, 30, 40}; - + std::cout << "\nBefore modification:\n"; print_container(vec1, "Vector 1"); print_container(vec2, "Vector 2"); - + auto begin_mod = makeZipIterator(vec1.begin(), vec2.begin()); auto end_mod = makeZipIterator(vec1.end(), vec2.end()); - + // Sum corresponding elements from vec2 into vec1 for (auto it = begin_mod; it != end_mod; ++it) { const auto& [v1, v2] = *it; // Now correctly bound with const reference // This is just to demonstrate the concept } - + // The correct way to modify elements is to manually unpack and modify for (size_t i = 0; i < vec1.size(); ++i) { vec1[i] += vec2[i]; } - + std::cout << "\nAfter modification (vec1 += vec2):\n"; print_container(vec1, "Vector 1"); print_container(vec2, "Vector 2"); @@ -319,51 +319,51 @@ void zip_iterator_example() { // Example 7: Combining different iterators void combined_iterators_example() { std::cout << "\n=== Example 7: Combining Different Iterators ===\n"; - + std::vector numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; print_container(numbers, "Original vector"); - + // 1. Filter for even numbers, then transform to squares auto is_even = [](int n) { return n % 2 == 0; }; auto square = [](int n) { return n * n; }; - + auto begin_filter = makeFilterIterator(numbers.begin(), numbers.end(), is_even); auto end_filter = makeFilterIterator(numbers.end(), numbers.end(), is_even); - + auto begin_combined = makeTransformIterator(begin_filter, square); auto end_combined = makeTransformIterator(end_filter, square); - + std::cout << "Squares of even numbers: "; for (auto it = begin_combined; it != end_combined; ++it) { std::cout << *it << " "; // Should print 4, 16, 36, 64, 100 } std::cout << std::endl; - + // 2. Create pointers to the elements, then filter by value std::cout << "\nPointing to elements greater than 5:\n"; - + auto [begin_ptr, end_ptr] = makePointerRange(numbers.begin(), numbers.end()); - + auto value_gt_5 = [](int* ptr) { return *ptr > 5; }; auto begin_ptr_filter = makeFilterIterator(begin_ptr, end_ptr, value_gt_5); auto end_ptr_filter = makeFilterIterator(end_ptr, end_ptr, value_gt_5); - + for (auto it = begin_ptr_filter; it != end_ptr_filter; ++it) { int* ptr = *it; std::cout << "Value: " << *ptr << ", Address: " << ptr << std::endl; } - + // 3. Combine transform and zip std::vector names = {"Alice", "Bob", "Charlie", "David", "Eve"}; std::vector ages = {25, 30, 35, 40, 45}; - + auto name_to_length = [](const std::string& s) { return s.length(); }; auto begin_name_len = makeTransformIterator(names.begin(), name_to_length); auto end_name_len = makeTransformIterator(names.end(), name_to_length); - + auto begin_combined_zip = makeZipIterator(begin_name_len, ages.begin()); auto end_combined_zip = makeZipIterator(end_name_len, ages.end()); - + std::cout << "\nName lengths paired with ages:\n"; for (auto it = begin_combined_zip; it != end_combined_zip; ++it) { auto [length, age] = *it; @@ -373,7 +373,7 @@ void combined_iterators_example() { int main() { std::cout << "===== Custom Iterator Examples =====\n"; - + pointer_iterator_example(); early_inc_iterator_example(); transform_iterator_example(); @@ -381,6 +381,6 @@ int main() { reverse_iterator_example(); zip_iterator_example(); combined_iterators_example(); - + return 0; -} \ No newline at end of file +} diff --git a/example/type/json-schema.cpp b/example/type/json-schema.cpp index 128bb6da..45b33a87 100644 --- a/example/type/json-schema.cpp +++ b/example/type/json-schema.cpp @@ -52,4 +52,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/example/type/no_offset_ptr.cpp b/example/type/no_offset_ptr.cpp index bdc9030f..ae4a1b8f 100644 --- a/example/type/no_offset_ptr.cpp +++ b/example/type/no_offset_ptr.cpp @@ -466,4 +466,4 @@ int main() { std::cout << "\nAll examples completed successfully!\n"; return 0; -} \ No newline at end of file +} diff --git a/example/type/optional.cpp b/example/type/optional.cpp index d1d7e40b..d145df74 100644 --- a/example/type/optional.cpp +++ b/example/type/optional.cpp @@ -647,4 +647,4 @@ int main() { advancedUsageExample(); return 0; -} \ No newline at end of file +} diff --git a/example/type/pod_vector.cpp b/example/type/pod_vector.cpp index 7b9c996e..078bb659 100644 --- a/example/type/pod_vector.cpp +++ b/example/type/pod_vector.cpp @@ -529,4 +529,4 @@ int main() { advancedUsageExample(); return 0; -} \ No newline at end of file +} diff --git a/example/type/pointer.cpp b/example/type/pointer.cpp index 7220a2eb..22ae6af1 100644 --- a/example/type/pointer.cpp +++ b/example/type/pointer.cpp @@ -700,4 +700,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/example/type/qvariant.cpp b/example/type/qvariant.cpp index 7ec2c5af..057ac627 100644 --- a/example/type/qvariant.cpp +++ b/example/type/qvariant.cpp @@ -799,4 +799,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/example/type/rtype.cpp b/example/type/rtype.cpp index 4b2d5bc1..6f97c154 100644 --- a/example/type/rtype.cpp +++ b/example/type/rtype.cpp @@ -98,4 +98,4 @@ int main() { std::cout << "Person YAML: " << newPersonYaml.dump() << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/type/small_list.cpp b/example/type/small_list.cpp index 4187a4d1..4f38e627 100644 --- a/example/type/small_list.cpp +++ b/example/type/small_list.cpp @@ -766,4 +766,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/example/type/small_vector.cpp b/example/type/small_vector.cpp index de59e965..d5fba399 100644 --- a/example/type/small_vector.cpp +++ b/example/type/small_vector.cpp @@ -841,4 +841,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/example/type/static_string.cpp b/example/type/static_string.cpp index 8530b394..7f74c06b 100644 --- a/example/type/static_string.cpp +++ b/example/type/static_string.cpp @@ -663,4 +663,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/example/type/static_vector.cpp b/example/type/static_vector.cpp index e3e706d6..b4b2df18 100644 --- a/example/type/static_vector.cpp +++ b/example/type/static_vector.cpp @@ -831,4 +831,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/example/type/string.cpp b/example/type/string.cpp index 77dcb54a..3e88e179 100644 --- a/example/type/string.cpp +++ b/example/type/string.cpp @@ -753,4 +753,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/example/type/trackable.cpp b/example/type/trackable.cpp index aecbf2fa..a145dedd 100644 --- a/example/type/trackable.cpp +++ b/example/type/trackable.cpp @@ -658,4 +658,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/example/type/uint.cpp b/example/type/uint.cpp index 8a999ffc..8beddbb3 100644 --- a/example/type/uint.cpp +++ b/example/type/uint.cpp @@ -35,4 +35,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/example/type/weak_ptr.cpp b/example/type/weak_ptr.cpp index 45300523..c76425be 100644 --- a/example/type/weak_ptr.cpp +++ b/example/type/weak_ptr.cpp @@ -25,30 +25,30 @@ class TestObject { TestObject(int id, std::string name) : id_(id), name_(std::move(name)) { std::cout << "TestObject #" << id_ << " (" << name_ << ") constructed" << std::endl; } - + ~TestObject() { std::cout << "TestObject #" << id_ << " (" << name_ << ") destroyed" << std::endl; } - - int getId() const { + + int getId() const { access_count_++; - return id_; + return id_; } - - std::string getName() const { + + std::string getName() const { access_count_++; - return name_; + return name_; } - + void setName(const std::string& name) { access_count_++; name_ = name; } - + int getAccessCount() const { return access_count_.load(); } - + void performOperation() const { access_count_++; std::cout << "Operation performed on TestObject #" << id_ << " (" << name_ << ")" << std::endl; @@ -61,19 +61,19 @@ class DerivedObject : public TestObject { double extra_data_; public: - DerivedObject(int id, std::string name, double extra_data) + DerivedObject(int id, std::string name, double extra_data) : TestObject(id, std::move(name)), extra_data_(extra_data) { std::cout << "DerivedObject with extra_data=" << extra_data_ << " constructed" << std::endl; } - + ~DerivedObject() { std::cout << "DerivedObject with extra_data=" << extra_data_ << " destroyed" << std::endl; } - + double getExtraData() const { return extra_data_; } - + void setExtraData(double value) { extra_data_ = value; } @@ -95,17 +95,17 @@ void basicUsageExample() { // Create a shared_ptr to a TestObject auto shared = std::make_shared(1, "Basic Test"); - + printSubSection("Construction and State Checking"); // Create an EnhancedWeakPtr from the shared_ptr EnhancedWeakPtr weak(shared); - + // Check if the weak pointer is expired std::cout << "Is weak pointer expired? " << (weak.expired() ? "Yes" : "No") << std::endl; - + // Get the use count std::cout << "Use count: " << weak.useCount() << std::endl; - + printSubSection("Locking the Weak Pointer"); // Lock the weak pointer to get a shared_ptr if (auto locked = weak.lock()) { @@ -114,81 +114,81 @@ void basicUsageExample() { } else { std::cout << "Failed to lock weak pointer" << std::endl; } - + printSubSection("Handling Expiration"); // Make the weak pointer expire by resetting the original shared_ptr std::cout << "Resetting original shared_ptr..." << std::endl; shared.reset(); - + // Check if the weak pointer is now expired std::cout << "Is weak pointer expired? " << (weak.expired() ? "Yes" : "No") << std::endl; - + // Try to lock an expired weak pointer if (auto locked = weak.lock()) { std::cout << "Successfully locked weak pointer (shouldn't happen)" << std::endl; } else { std::cout << "Failed to lock expired weak pointer (expected)" << std::endl; } - + printSubSection("Manual Reset"); // Create a new shared_ptr and weak_ptr shared = std::make_shared(2, "Reset Test"); EnhancedWeakPtr resetWeak(shared); - + // Reset the weak pointer manually std::cout << "Manually resetting weak pointer..." << std::endl; resetWeak.reset(); - + // Verify it's expired even though the shared_ptr is still valid std::cout << "Is weak pointer expired after reset? " << (resetWeak.expired() ? "Yes" : "No") << std::endl; std::cout << "Original shared_ptr use count: " << shared.use_count() << std::endl; - + printSubSection("Getting Lock Attempts"); EnhancedWeakPtr lockCounter(shared); - + // Perform several lock attempts for (int i = 0; i < 5; i++) { auto locked = lockCounter.lock(); } - + std::cout << "Number of lock attempts: " << lockCounter.getLockAttempts() << std::endl; } // Example 2: Advanced Locking Techniques void advancedLockingExample() { printSection("Advanced Locking Techniques"); - + // Create a shared_ptr to a TestObject auto shared = std::make_shared(3, "Advanced Lock Test"); - + // Create an EnhancedWeakPtr from the shared_ptr EnhancedWeakPtr weak(shared); - + printSubSection("Using withLock for Safe Access"); // Use withLock to safely access the object auto result = weak.withLock([](TestObject& obj) { std::cout << "Accessing object with ID: " << obj.getId() << std::endl; return obj.getName(); }); - + if (result) { std::cout << "withLock returned: " << *result << std::endl; } else { std::cout << "withLock failed to access the object" << std::endl; } - + // Use withLock with a void return type bool success = weak.withLock([](TestObject& obj) { std::cout << "Performing void operation on object: " << obj.getName() << std::endl; obj.setName("Updated Name"); }); - + std::cout << "Void operation success: " << (success ? "Yes" : "No") << std::endl; - + // Verify the name was updated std::string name = weak.withLock([](TestObject& obj) { return obj.getName(); }).value_or("Unknown"); std::cout << "Updated name: " << name << std::endl; - + printSubSection("tryLockOrElse Method"); // Use tryLockOrElse to handle both success and failure cases auto nameOrDefault = weak.tryLockOrElse( @@ -201,27 +201,27 @@ void advancedLockingExample() { return "Object not available"; } ); - + std::cout << "tryLockOrElse result: " << nameOrDefault << std::endl; - + printSubSection("Periodic Lock Attempts"); // Use tryLockPeriodic to attempt locking periodically std::cout << "Attempting periodic locks (should succeed immediately)..." << std::endl; auto periodicLock = weak.tryLockPeriodic(100ms, 5); - + if (periodicLock) { std::cout << "Successfully obtained lock periodically for: " << periodicLock->getName() << std::endl; } else { std::cout << "Failed to obtain lock after periodic attempts" << std::endl; } - + // Make the object expire shared.reset(); - + // Try periodic locking on an expired pointer std::cout << "Attempting periodic locks on expired pointer..." << std::endl; auto failedLock = weak.tryLockPeriodic(50ms, 3); - + if (failedLock) { std::cout << "Unexpectedly obtained lock" << std::endl; } else { @@ -232,22 +232,22 @@ void advancedLockingExample() { // Example 3: Asynchronous Operations void asynchronousOperationsExample() { printSection("Asynchronous Operations"); - + // Create a shared_ptr to a TestObject auto shared = std::make_shared(4, "Async Test"); - + // Create an EnhancedWeakPtr from the shared_ptr EnhancedWeakPtr weak(shared); - + printSubSection("Async Lock"); // Perform an asynchronous lock std::cout << "Starting async lock operation..." << std::endl; auto future = weak.asyncLock(); - + // Do some other work std::cout << "Doing other work while lock is in progress..." << std::endl; std::this_thread::sleep_for(100ms); - + // Get the result of the async lock auto asyncLocked = future.get(); if (asyncLocked) { @@ -255,31 +255,31 @@ void asynchronousOperationsExample() { } else { std::cout << "Async lock failed" << std::endl; } - + printSubSection("Waiting with Timeout"); // Set up a condition to wait for std::atomic condition{false}; - + // Start a thread that will set the condition after a delay std::thread conditionThread([&]() { std::this_thread::sleep_for(300ms); std::cout << "Setting condition to true" << std::endl; condition.store(true); }); - + // Wait for the object with timeout bool waitResult = weak.waitFor(500ms); std::cout << "waitFor result: " << (waitResult ? "Object available" : "Timeout or object expired") << std::endl; - + // Wait until the condition is true bool predResult = weak.waitUntil([&]() { return condition.load(); }); std::cout << "waitUntil result: " << (predResult ? "Condition met and object available" : "Object expired") << std::endl; - + // Cleanup if (conditionThread.joinable()) { conditionThread.join(); } - + printSubSection("Notification Mechanism"); // Create a thread that waits for notification std::atomic notified{false}; @@ -289,36 +289,36 @@ void asynchronousOperationsExample() { notified.store(true); std::cout << "Thread received notification or timed out" << std::endl; }); - + // Sleep briefly to ensure the thread starts waiting std::this_thread::sleep_for(100ms); - + // Send notification std::cout << "Sending notification to waiting threads..." << std::endl; weak.notifyAll(); - + // Join the thread if (waitingThread.joinable()) { waitingThread.join(); } - + std::cout << "Was thread notified? " << (notified.load() ? "Yes" : "No") << std::endl; } // Example 4: Type Casting and Special Operations void typeCastingExample() { printSection("Type Casting and Special Operations"); - + // Create a shared_ptr to a DerivedObject auto derivedShared = std::make_shared(5, "Derived Test", 3.14159); - + // Create an EnhancedWeakPtr to the base type EnhancedWeakPtr baseWeak(derivedShared); - + printSubSection("Type Casting"); // Cast the weak pointer to the derived type auto derivedWeak = baseWeak.cast(); - + // Test if the cast worked auto result = derivedWeak.withLock([](DerivedObject& obj) { std::cout << "Successfully cast to derived type" << std::endl; @@ -326,18 +326,18 @@ void typeCastingExample() { std::cout << "Derived property - Extra data: " << obj.getExtraData() << std::endl; return obj.getExtraData(); }); - + if (result) { std::cout << "Cast and lock succeeded, extra data value: " << *result << std::endl; } else { std::cout << "Cast or lock failed" << std::endl; } - + printSubSection("Weak Pointer to Shared Pointer"); // Get the underlying weak_ptr std::weak_ptr stdWeakPtr = baseWeak.getWeakPtr(); std::cout << "Standard weak_ptr use count: " << stdWeakPtr.use_count() << std::endl; - + // Create a shared_ptr from the weak_ptr auto createdShared = baseWeak.createShared(); if (createdShared) { @@ -346,35 +346,35 @@ void typeCastingExample() { } else { std::cout << "Failed to create shared_ptr (object expired)" << std::endl; } - + printSubSection("Total Instances Tracking"); // Get the total number of EnhancedWeakPtr instances size_t beforeCount = EnhancedWeakPtr::getTotalInstances(); std::cout << "Total EnhancedWeakPtr instances before: " << beforeCount << std::endl; - + // Create more instances { EnhancedWeakPtr temp1(derivedShared); EnhancedWeakPtr temp2(derivedShared); - + size_t duringCount = EnhancedWeakPtr::getTotalInstances(); std::cout << "Total EnhancedWeakPtr instances during: " << duringCount << std::endl; assert(duringCount > beforeCount); } - + size_t afterCount = EnhancedWeakPtr::getTotalInstances(); std::cout << "Total EnhancedWeakPtr instances after: " << afterCount << std::endl; assert(afterCount == beforeCount); - + printSubSection("Equality Comparison"); // Create two weak pointers to the same object EnhancedWeakPtr weak1(derivedShared); EnhancedWeakPtr weak2(derivedShared); - + // Create a weak pointer to a different object auto differentShared = std::make_shared(6, "Different Test"); EnhancedWeakPtr weak3(differentShared); - + // Compare weak pointers std::cout << "weak1 == weak2: " << (weak1 == weak2 ? "true" : "false") << std::endl; std::cout << "weak1 == weak3: " << (weak1 == weak3 ? "true" : "false") << std::endl; @@ -383,47 +383,47 @@ void typeCastingExample() { // Example 5: Void Specialization void voidSpecializationExample() { printSection("Void Specialization"); - + // Create a shared_ptr from a concrete type auto original = std::make_shared(7, "Void Test"); std::shared_ptr voidShared = original; - + // Create an EnhancedWeakPtr from the shared_ptr EnhancedWeakPtr voidWeak(voidShared); - + printSubSection("Basic Operations with void Type"); // Check if the weak pointer is expired std::cout << "Is void weak pointer expired? " << (voidWeak.expired() ? "Yes" : "No") << std::endl; - + // Get the use count std::cout << "Use count: " << voidWeak.useCount() << std::endl; - + // Lock the void weak pointer if (auto locked = voidWeak.lock()) { std::cout << "Successfully locked void weak pointer" << std::endl; } else { std::cout << "Failed to lock void weak pointer" << std::endl; } - + printSubSection("withLock for void Type"); // Use withLock with void return type bool success = voidWeak.withLock([]() { std::cout << "Performing void operation on void pointer" << std::endl; }); - + std::cout << "Void operation success: " << (success ? "Yes" : "No") << std::endl; - + // Use withLock with non-void return type auto result = voidWeak.withLock([]() { return std::string("Data from void pointer operation"); }); - + if (result) { std::cout << "withLock on void pointer returned: " << *result << std::endl; } else { std::cout << "withLock on void pointer failed" << std::endl; } - + printSubSection("tryLockOrElse with void Type"); // Use tryLockOrElse with void pointer auto resultOrDefault = voidWeak.tryLockOrElse( @@ -436,27 +436,27 @@ void voidSpecializationExample() { return "Failed to access void pointer"; } ); - + std::cout << "tryLockOrElse result: " << resultOrDefault << std::endl; - + printSubSection("Casting from void Type"); // Cast the void weak pointer back to the original type auto castBack = voidWeak.cast(); - + // Use withLock on the cast pointer auto name = castBack.withLock([](TestObject& obj) { return obj.getName(); }); - + if (name) { std::cout << "Successfully cast back from void to TestObject: " << *name << std::endl; } else { std::cout << "Failed to cast back from void to TestObject" << std::endl; } - + // Clean up original.reset(); - + // Verify both weak pointers are now expired std::cout << "Original weak ptr expired: " << (voidWeak.expired() ? "Yes" : "No") << std::endl; std::cout << "Cast weak ptr expired: " << (castBack.expired() ? "Yes" : "No") << std::endl; @@ -465,19 +465,19 @@ void voidSpecializationExample() { // Example 6: Group Operations void groupOperationsExample() { printSection("Group Operations"); - + // Create a vector of shared pointers std::vector> sharedPtrs; for (int i = 0; i < 5; ++i) { sharedPtrs.push_back(std::make_shared( 100 + i, "Group-" + std::to_string(i))); } - + printSubSection("Creating Weak Pointer Group"); // Create a group of weak pointers auto weakPtrGroup = createWeakPtrGroup(sharedPtrs); std::cout << "Created weak pointer group with " << weakPtrGroup.size() << " elements" << std::endl; - + printSubSection("Batch Operations"); // Perform a batch operation on the group std::cout << "Performing batch operation on the group..." << std::endl; @@ -485,136 +485,136 @@ void groupOperationsExample() { std::cout << "Batch operation on object #" << obj.getId() << " - " << obj.getName() << std::endl; obj.performOperation(); }); - + printSubSection("Individual Access After Batch"); // Access individual elements after batch operation for (size_t i = 0; i < weakPtrGroup.size(); ++i) { weakPtrGroup[i].withLock([i](TestObject& obj) { - std::cout << "Element " << i << " - ID: " << obj.getId() - << ", Name: " << obj.getName() + std::cout << "Element " << i << " - ID: " << obj.getId() + << ", Name: " << obj.getName() << ", Access count: " << obj.getAccessCount() << std::endl; }); } - + printSubSection("Handling Expired Group Members"); // Make some of the shared pointers expire std::cout << "Expiring elements 1 and 3..." << std::endl; sharedPtrs[1].reset(); sharedPtrs[3].reset(); - + // Try to access all elements including expired ones std::cout << "Trying to access all elements after expiration:" << std::endl; for (size_t i = 0; i < weakPtrGroup.size(); ++i) { bool accessed = weakPtrGroup[i].withLock([i](TestObject& obj) { - std::cout << "Element " << i << " - Successfully accessed object #" + std::cout << "Element " << i << " - Successfully accessed object #" << obj.getId() << std::endl; }); - + if (!accessed) { std::cout << "Element " << i << " - Failed to access (expired)" << std::endl; } } - + printSubSection("Batch Operation with Expiry Handling"); // Perform another batch operation with explicit handling std::cout << "Performing batch operation with expiry checks:" << std::endl; - + size_t successCount = 0; for (const auto& weakPtr : weakPtrGroup) { bool success = weakPtr.withLock([](TestObject& obj) { std::cout << "Processing object #" << obj.getId() << std::endl; obj.performOperation(); }); - + if (success) { successCount++; } } - - std::cout << "Successfully processed " << successCount << " out of " + + std::cout << "Successfully processed " << successCount << " out of " << weakPtrGroup.size() << " objects" << std::endl; } // Example 7: Multi-threading Scenarios void multiThreadingExample() { printSection("Multi-threading Scenarios"); - + // Create a shared pointer that will be accessed from multiple threads auto shared = std::make_shared(200, "Thread-Test"); EnhancedWeakPtr weak(shared); - + printSubSection("Concurrent Access"); // Set up a flag for coordination std::atomic shouldContinue{true}; - + // Track the total operations performed std::atomic totalOperations{0}; - + // Start multiple reader threads std::vector threads; for (int i = 0; i < 5; ++i) { threads.emplace_back([&weak, &shouldContinue, &totalOperations, i]() { std::cout << "Thread " << i << " started" << std::endl; int localCount = 0; - + while (shouldContinue.load()) { // Try to access the object weak.withLock([i, &localCount](TestObject& obj) { localCount++; - std::cout << "Thread " << i << " accessing object #" + std::cout << "Thread " << i << " accessing object #" << obj.getId() << ", local count: " << localCount << std::endl; - + // Simulate some work std::this_thread::sleep_for(50ms); }); - + // Small delay between attempts std::this_thread::sleep_for(20ms); } - + // Update the total count totalOperations.fetch_add(localCount); std::cout << "Thread " << i << " finished, local operations: " << localCount << std::endl; }); } - + // Let the threads run for a while std::this_thread::sleep_for(500ms); - + printSubSection("Object Expiration During Thread Execution"); // Reset the shared pointer while threads are running std::cout << "Resetting shared pointer while threads are accessing it..." << std::endl; shared.reset(); - + // Let the threads continue for a bit after expiration std::this_thread::sleep_for(300ms); - + // Signal threads to stop std::cout << "Signaling threads to stop..." << std::endl; shouldContinue.store(false); - + // Wait for all threads to complete for (auto& t : threads) { if (t.joinable()) { t.join(); } } - + std::cout << "All threads completed. Total operations: " << totalOperations.load() << std::endl; std::cout << "Lock attempts recorded: " << weak.getLockAttempts() << std::endl; - + printSubSection("Coordination with Condition Variables"); // Create a new shared pointer shared = std::make_shared(201, "CV-Test"); EnhancedWeakPtr cvWeak(shared); - + // Create a waiter thread std::thread waiterThread([&cvWeak]() { std::cout << "Waiter thread waiting for object to become available..." << std::endl; bool success = cvWeak.waitFor(2s); std::cout << "Waiter thread done. Object available: " << (success ? "Yes" : "No") << std::endl; }); - + // Create a notifier thread std::thread notifierThread([&cvWeak]() { std::cout << "Notifier thread sleeping before notification..." << std::endl; @@ -622,7 +622,7 @@ void multiThreadingExample() { std::cout << "Notifier thread sending notification..." << std::endl; cvWeak.notifyAll(); }); - + // Wait for threads to complete if (waiterThread.joinable()) waiterThread.join(); if (notifierThread.joinable()) notifierThread.join(); @@ -631,25 +631,25 @@ void multiThreadingExample() { // Example 8: Error Handling and Edge Cases void errorHandlingExample() { printSection("Error Handling and Edge Cases"); - + printSubSection("Construction and Assignment"); // Default construction EnhancedWeakPtr defaultWeak; std::cout << "Default constructed weak ptr expired: " << (defaultWeak.expired() ? "Yes" : "No") << std::endl; - + // Construction from nullptr or empty shared_ptr std::shared_ptr nullShared; EnhancedWeakPtr nullWeak(nullShared); std::cout << "Null constructed weak ptr expired: " << (nullWeak.expired() ? "Yes" : "No") << std::endl; - + // Copy construction EnhancedWeakPtr copyWeak = nullWeak; std::cout << "Copy constructed weak ptr expired: " << (copyWeak.expired() ? "Yes" : "No") << std::endl; - + // Move construction EnhancedWeakPtr moveWeak = std::move(copyWeak); std::cout << "Move constructed weak ptr expired: " << (moveWeak.expired() ? "Yes" : "No") << std::endl; - + printSubSection("Edge Cases in Locking"); // Create temporary object then let it expire EnhancedWeakPtr tempWeak; @@ -659,23 +659,23 @@ void errorHandlingExample() { std::cout << "Temporary weak ptr expired (inside scope): " << (tempWeak.expired() ? "Yes" : "No") << std::endl; } std::cout << "Temporary weak ptr expired (outside scope): " << (tempWeak.expired() ? "Yes" : "No") << std::endl; - + // Try to lock expired pointer auto locked = tempWeak.lock(); std::cout << "Lock result on expired pointer: " << (locked ? "Succeeded (unexpected)" : "Failed (expected)") << std::endl; - + // Try to use withLock on expired pointer bool success = tempWeak.withLock([](TestObject& obj) { std::cout << "This should not print" << std::endl; }); std::cout << "withLock on expired pointer: " << (success ? "Succeeded (unexpected)" : "Failed (expected)") << std::endl; - + printSubSection("Validation in Boost Mode"); #ifdef ATOM_USE_BOOST // Create a valid pointer auto validShared = std::make_shared(301, "Valid"); EnhancedWeakPtr validWeak(validShared); - + try { std::cout << "Validating valid pointer..." << std::endl; validWeak.validate(); @@ -683,10 +683,10 @@ void errorHandlingExample() { } catch (const EnhancedWeakPtrException& e) { std::cout << "Unexpected exception: " << e.what() << std::endl; } - + // Make it expire validShared.reset(); - + try { std::cout << "Validating expired pointer..." << std::endl; validWeak.validate(); @@ -702,32 +702,32 @@ void errorHandlingExample() { // Create an object that will be contested auto contestedShared = std::make_shared(302, "Contested"); EnhancedWeakPtr contestedWeak(contestedShared); - + // Create multiple threads that will race to access and possibly reset std::vector racingThreads; std::atomic successfulAccesses{0}; std::atomic failedAccesses{0}; - + // This will be set by one of the threads std::atomic hasReset{false}; - + for (int i = 0; i < 10; ++i) { racingThreads.emplace_back([&contestedWeak, &successfulAccesses, &failedAccesses, &hasReset, i]() { // Random delay to increase chance of race conditions std::this_thread::sleep_for(std::chrono::milliseconds(rand() % 50)); - + // Thread 5 will reset the pointer if (i == 5 && !hasReset.load()) { hasReset.store(true); std::cout << "Thread " << i << " resetting weak pointer" << std::endl; contestedWeak.reset(); } - + // All threads try to access bool success = contestedWeak.withLock([i](TestObject& obj) { std::cout << "Thread " << i << " successfully accessed object #" << obj.getId() << std::endl; }); - + if (success) { successfulAccesses++; } else { @@ -736,14 +736,14 @@ void errorHandlingExample() { } }); } - + // Wait for all threads to complete for (auto& t : racingThreads) { if (t.joinable()) { t.join(); } } - + std::cout << "Race condition test completed." << std::endl; std::cout << "Successful accesses: " << successfulAccesses.load() << std::endl; std::cout << "Failed accesses: " << failedAccesses.load() << std::endl; @@ -753,7 +753,7 @@ int main() { std::cout << "===============================================" << std::endl; std::cout << " EnhancedWeakPtr Comprehensive Examples " << std::endl; std::cout << "===============================================" << std::endl; - + // Run all examples try { basicUsageExample(); @@ -764,12 +764,12 @@ int main() { groupOperationsExample(); multiThreadingExample(); errorHandlingExample(); - + std::cout << "\nAll examples completed successfully!" << std::endl; } catch (const std::exception& e) { std::cerr << "An unexpected error occurred: " << e.what() << std::endl; return 1; } - + return 0; -} \ No newline at end of file +} diff --git a/example/utils/CMakeLists.txt b/example/utils/CMakeLists.txt index 8002b1cc..a576e571 100644 --- a/example/utils/CMakeLists.txt +++ b/example/utils/CMakeLists.txt @@ -14,20 +14,20 @@ file(GLOB CPP_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) foreach(CPP_FILE ${CPP_FILES}) # 获取不带扩展名的文件名 get_filename_component(EXAMPLE_NAME ${CPP_FILE} NAME_WE) - + # 构造可执行文件名称(子目录名_文件名) set(EXECUTABLE_NAME ${SUBDIR_NAME}_${EXAMPLE_NAME}) - + # 配置选项,允许单独控制每个示例的构建 string(TOUPPER ${EXAMPLE_NAME} EXAMPLE_NAME_UPPER) option(ATOM_EXAMPLE_UTILS_${EXAMPLE_NAME_UPPER} "Build utils example: ${EXAMPLE_NAME}" ${ATOM_EXAMPLE_UTILS_BUILD_ALL}) - + # 有条件地添加可执行文件 if(ATOM_EXAMPLE_UTILS_${EXAMPLE_NAME_UPPER}) add_executable(${EXECUTABLE_NAME} ${CPP_FILE}) target_link_libraries(${EXECUTABLE_NAME} atom) - - + + # 设置IDE文件夹分组 set_property(TARGET ${EXECUTABLE_NAME} PROPERTY FOLDER "Examples/Utils") endif() diff --git a/example/utils/aes.cpp b/example/utils/aes.cpp index bd212a17..379b41bd 100644 --- a/example/utils/aes.cpp +++ b/example/utils/aes.cpp @@ -533,4 +533,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/example/utils/aligned.cpp b/example/utils/aligned.cpp index 06e209af..b2dede70 100644 --- a/example/utils/aligned.cpp +++ b/example/utils/aligned.cpp @@ -427,4 +427,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/example/utils/anyutils.cpp b/example/utils/anyutils.cpp index a22112b6..ba13c17b 100644 --- a/example/utils/anyutils.cpp +++ b/example/utils/anyutils.cpp @@ -586,4 +586,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/example/utils/argsview.cpp b/example/utils/argsview.cpp index 350b6180..b9b82e8c 100644 --- a/example/utils/argsview.cpp +++ b/example/utils/argsview.cpp @@ -577,4 +577,4 @@ int main(int argc, char* argv[]) { } return 0; -} \ No newline at end of file +} diff --git a/example/utils/bit.cpp b/example/utils/bit.cpp index e15f3b3c..c3cb43cd 100644 --- a/example/utils/bit.cpp +++ b/example/utils/bit.cpp @@ -430,4 +430,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/example/utils/container.cpp b/example/utils/container.cpp index a241405a..f1d265e6 100644 --- a/example/utils/container.cpp +++ b/example/utils/container.cpp @@ -21,14 +21,14 @@ #include #include #include - + // Helper function to print section headers void printSection(const std::string& title) { std::cout << "\n===============================================" << std::endl; std::cout << " " << title << std::endl; std::cout << "===============================================" << std::endl; } - + // Helper function to print containers template void printContainer(const std::string& label, const Container& container) { @@ -41,7 +41,7 @@ } std::cout << "]" << std::endl; } - + // Helper function to print pairs template void printPairs(const std::string& label, const std::vector>& pairs) { @@ -54,7 +54,7 @@ } std::cout << "]" << std::endl; } - + // Helper function to print maps template void printMap(const std::string& label, const std::map& map) { @@ -67,34 +67,34 @@ } std::cout << "}" << std::endl; } - + // Sample class to demonstrate member function handling class Person { public: Person(std::string name, int age, std::string city) : name_(std::move(name)), age_(age), city_(std::move(city)) {} - + std::string getName() const { return name_; } int getAge() const { return age_; } std::string getCity() const { return city_; } - + // For printing Person objects friend std::ostream& operator<<(std::ostream& os, const Person& person) { os << person.name_ << "(" << person.age_ << ")"; return os; } - + // For making Person objects hashable bool operator==(const Person& other) const { return name_ == other.name_ && age_ == other.age_ && city_ == other.city_; } - + private: std::string name_; int age_; std::string city_; }; - + // Make Person hashable for std::unordered_set namespace std { template<> @@ -104,30 +104,30 @@ } }; } - + int main() { try { std::cout << "Container Utilities Demonstration" << std::endl; - + // =================================================== // Example 1: Basic Container Operations and Subset Checking // =================================================== printSection("1. Basic Container Operations and Subset Checking"); - + // Create different container types std::vector vec1 = {1, 2, 3, 4, 5}; std::list list1 = {2, 3, 4}; std::set set1 = {3, 4, 5, 6, 7}; - + printContainer("Vector", vec1); printContainer("List", list1); printContainer("Set", set1); - + // Test contains function std::cout << "\nContains function demonstration:" << std::endl; std::cout << "Vector contains 3: " << (atom::utils::contains(vec1, 3) ? "Yes" : "No") << std::endl; std::cout << "Vector contains 8: " << (atom::utils::contains(vec1, 8) ? "Yes" : "No") << std::endl; - + // Test conversion to unordered_set std::cout << "\nToUnorderedSet demonstration:" << std::endl; auto vec1AsSet = atom::utils::toUnorderedSet(vec1); @@ -135,73 +135,73 @@ std::cout << "Checking membership in unordered_set:" << std::endl; std::cout << "Contains 3: " << (vec1AsSet.contains(3) ? "Yes" : "No") << std::endl; std::cout << "Contains 8: " << (vec1AsSet.contains(8) ? "Yes" : "No") << std::endl; - + // Test subset operations with different algorithms std::cout << "\nSubset checking demonstration:" << std::endl; - std::cout << "Is list a subset of vector (isSubset): " + std::cout << "Is list a subset of vector (isSubset): " << (atom::utils::isSubset(list1, vec1) ? "Yes" : "No") << std::endl; - std::cout << "Is list a subset of vector (linearSearch): " + std::cout << "Is list a subset of vector (linearSearch): " << (atom::utils::isSubsetLinearSearch(list1, vec1) ? "Yes" : "No") << std::endl; - std::cout << "Is list a subset of vector (hashSet): " + std::cout << "Is list a subset of vector (hashSet): " << (atom::utils::isSubsetWithHashSet(list1, vec1) ? "Yes" : "No") << std::endl; - + // Test negative subset case std::list list2 = {2, 3, 8}; printContainer("List 2", list2); - std::cout << "Is list2 a subset of vector: " + std::cout << "Is list2 a subset of vector: " << (atom::utils::isSubset(list2, vec1) ? "Yes" : "No") << std::endl; - + // =================================================== // Example 2: Set Operations // =================================================== printSection("2. Set Operations"); - + // Create test containers std::vector setA = {1, 2, 3, 4, 5}; std::list setB = {4, 5, 6, 7}; - + printContainer("Set A", setA); printContainer("Set B", setB); - + // Test intersection auto intersect = atom::utils::intersection(setA, setB); printContainer("Intersection (A ∩ B)", intersect); - + // Test union auto unionSet = atom::utils::unionSet(setA, setB); printContainer("Union (A ∪ B)", unionSet); - + // Test difference auto diff1 = atom::utils::difference(setA, setB); printContainer("Difference (A - B)", diff1); - + auto diff2 = atom::utils::difference(setB, setA); printContainer("Difference (B - A)", diff2); - + // Test symmetric difference auto symDiff = atom::utils::symmetricDifference(setA, setB); printContainer("Symmetric Difference", symDiff); - + // Test container equality std::vector vecEqual1 = {1, 2, 3}; std::list listEqual1 = {1, 2, 3}; std::set setEqual1 = {3, 2, 1}; // Different order but same elements - + printContainer("Vector for equality", vecEqual1); printContainer("List for equality", listEqual1); printContainer("Set for equality", setEqual1); - + std::cout << "\nEquality checking demonstration:" << std::endl; - std::cout << "Vector equals List: " + std::cout << "Vector equals List: " << (atom::utils::isEqual(vecEqual1, listEqual1) ? "Yes" : "No") << std::endl; - std::cout << "Vector equals Set: " + std::cout << "Vector equals Set: " << (atom::utils::isEqual(vecEqual1, setEqual1) ? "Yes" : "No") << std::endl; - + // =================================================== // Example 3: Container Transformations // =================================================== printSection("3. Container Transformations"); - + // Create a vector of Person objects std::vector people = { Person("Alice", 30, "New York"), @@ -209,40 +209,40 @@ Person("Charlie", 35, "Los Angeles"), Person("David", 28, "Boston") }; - + std::cout << "People collection:" << std::endl; for (const auto& person : people) { - std::cout << " " << person.getName() << ", Age: " << person.getAge() + std::cout << " " << person.getName() << ", Age: " << person.getAge() << ", City: " << person.getCity() << std::endl; } - + // Transform container using member functions std::cout << "\nTransforming containers using member functions:" << std::endl; - + auto names = atom::utils::transformToVector(people, &Person::getName); printContainer("Names", names); - + auto ages = atom::utils::transformToVector(people, &Person::getAge); printContainer("Ages", ages); - + auto cities = atom::utils::transformToVector(people, &Person::getCity); printContainer("Cities", cities); - + // Test applyAndStore (alternative transformation function) std::cout << "\nUsing applyAndStore function:" << std::endl; auto namesByApply = atom::utils::applyAndStore(people, &Person::getName); printContainer("Names by applyAndStore", namesByApply); - + // =================================================== // Example 4: Handling Duplicates // =================================================== printSection("4. Handling Duplicates"); - + // Create containers with duplicates std::vector duplicateInts = {1, 2, 2, 3, 4, 4, 5, 5, 5}; std::vector duplicateStrings = {"apple", "banana", "apple", "cherry", "banana", "date"}; std::map duplicateMap = {{"a", 1}, {"b", 2}, {"a", 3}, {"c", 4}}; - + printContainer("Duplicate Integers", duplicateInts); printContainer("Duplicate Strings", duplicateStrings); std::cout << "Duplicate Map entries: "; @@ -250,12 +250,12 @@ std::cout << key << ":" << value << " "; } std::cout << std::endl; - + // Remove duplicates auto uniqueInts = atom::utils::unique(duplicateInts); auto uniqueStrings = atom::utils::unique(duplicateStrings); auto uniqueMap = atom::utils::unique(duplicateMap); - + printContainer("Unique Integers", uniqueInts); printContainer("Unique Strings", uniqueStrings); std::cout << "Unique Map entries: "; @@ -263,173 +263,173 @@ std::cout << key << ":" << value << " "; } std::cout << std::endl; - + // =================================================== // Example 5: Container Flattening // =================================================== printSection("5. Container Flattening"); - + // Create nested containers std::vector> nestedInts = { {1, 2, 3}, {4, 5}, {6, 7, 8, 9} }; - + std::cout << "Nested integers:" << std::endl; for (const auto& innerVec : nestedInts) { printContainer(" Inner vector", innerVec); } - + // Flatten the nested containers auto flattenedInts = atom::utils::flatten(nestedInts); printContainer("Flattened integers", flattenedInts); - + // More complex example - nested lists std::vector> nestedLists = { {"red", "green", "blue"}, {"apple", "banana"}, {"one", "two", "three"} }; - + std::cout << "\nNested lists:" << std::endl; for (const auto& innerList : nestedLists) { printContainer(" Inner list", innerList); } - + // Flatten the nested lists auto flattenedStrings = atom::utils::flatten(nestedLists); printContainer("Flattened strings", flattenedStrings); - + // =================================================== // Example 6: Container Combining Operations // =================================================== printSection("6. Container Combining Operations"); - + // Create containers to combine std::vector letters = {'A', 'B', 'C'}; std::list numbers = {1, 2, 3, 4, 5}; // Longer than letters - + printContainer("Letters", letters); printContainer("Numbers", numbers); - + // Zip containers std::cout << "\nZip operation (combines corresponding elements):" << std::endl; auto zipped = atom::utils::zip(letters, numbers); printPairs("Zipped pairs", zipped); std::cout << "Note: Zip stops at the end of the shortest container" << std::endl; - + // Cartesian product std::cout << "\nCartesian product (all possible combinations):" << std::endl; auto product = atom::utils::cartesianProduct(letters, std::vector{1, 2}); printPairs("Cartesian product", product); - + // =================================================== // Example 7: Filtering and Partitioning // =================================================== printSection("7. Filtering and Partitioning"); - + // Create a container to filter std::vector mixedNumbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; printContainer("Mixed Numbers", mixedNumbers); - + // Define predicates auto isEven = [](int n) { return n % 2 == 0; }; auto isGreaterThan5 = [](int n) { return n > 5; }; - + // Filter elements std::cout << "\nFiltering demonstration:" << std::endl; auto evenNumbers = atom::utils::filter(mixedNumbers, isEven); printContainer("Even numbers", evenNumbers); - + auto largeNumbers = atom::utils::filter(mixedNumbers, isGreaterThan5); printContainer("Numbers > 5", largeNumbers); - + // Partition elements std::cout << "\nPartitioning demonstration:" << std::endl; auto [even, odd] = atom::utils::partition(mixedNumbers, isEven); printContainer("Even partition", even); printContainer("Odd partition", odd); - + auto [large, small] = atom::utils::partition(mixedNumbers, isGreaterThan5); printContainer("Large partition (>5)", large); printContainer("Small partition (≤5)", small); - + // =================================================== // Example 8: Finding Elements // =================================================== printSection("8. Finding Elements"); - + std::vector employees = { Person("John", 42, "Seattle"), Person("Sarah", 38, "Portland"), Person("Michael", 29, "San Francisco"), Person("Emma", 45, "Seattle") }; - + std::cout << "Employee collection:" << std::endl; for (const auto& employee : employees) { - std::cout << " " << employee.getName() << ", Age: " << employee.getAge() + std::cout << " " << employee.getName() << ", Age: " << employee.getAge() << ", City: " << employee.getCity() << std::endl; } - + // Find first element that satisfies predicate std::cout << "\nFinding elements demonstration:" << std::endl; - - auto youngEmployee = atom::utils::findIf(employees, [](const Person& p) { - return p.getAge() < 30; + + auto youngEmployee = atom::utils::findIf(employees, [](const Person& p) { + return p.getAge() < 30; }); - + if (youngEmployee) { - std::cout << "Found young employee: " << youngEmployee->getName() + std::cout << "Found young employee: " << youngEmployee->getName() << ", Age: " << youngEmployee->getAge() << std::endl; } else { std::cout << "No young employee found" << std::endl; } - - auto seattleEmployee = atom::utils::findIf(employees, [](const Person& p) { - return p.getCity() == "Seattle"; + + auto seattleEmployee = atom::utils::findIf(employees, [](const Person& p) { + return p.getCity() == "Seattle"; }); - + if (seattleEmployee) { - std::cout << "Found Seattle employee: " << seattleEmployee->getName() + std::cout << "Found Seattle employee: " << seattleEmployee->getName() << ", Age: " << seattleEmployee->getAge() << std::endl; } else { std::cout << "No Seattle employee found" << std::endl; } - - auto oldEmployee = atom::utils::findIf(employees, [](const Person& p) { - return p.getAge() > 50; + + auto oldEmployee = atom::utils::findIf(employees, [](const Person& p) { + return p.getAge() > 50; }); - + if (oldEmployee) { - std::cout << "Found employee over 50: " << oldEmployee->getName() + std::cout << "Found employee over 50: " << oldEmployee->getName() << ", Age: " << oldEmployee->getAge() << std::endl; } else { std::cout << "No employee over 50 found" << std::endl; } - + // =================================================== // Example 9: String Literal to Vector // =================================================== printSection("9. String Literal to Vector"); - + // Use the custom string literal operator auto fruits = "apple, banana, cherry, date"_vec; printContainer("Fruits from string literal", fruits); - + auto colors = "red,green,blue,yellow"_vec; printContainer("Colors from string literal", colors); - + auto mixedSpacing = " item1 ,item2, item3,item4 "_vec; printContainer("Mixed spacing from string literal", mixedSpacing); - + std::cout << "\nAll examples completed successfully!" << std::endl; - + } catch (const std::exception& e) { std::cerr << "ERROR: " << e.what() << std::endl; return 1; } - + return 0; - } \ No newline at end of file + } diff --git a/example/utils/convert.cpp b/example/utils/convert.cpp index 0d0089fd..669a1ac9 100644 --- a/example/utils/convert.cpp +++ b/example/utils/convert.cpp @@ -67,4 +67,4 @@ int main() { return 0; } -#endif \ No newline at end of file +#endif diff --git a/example/utils/cstring.cpp b/example/utils/cstring.cpp index 9a17edf0..e696219a 100644 --- a/example/utils/cstring.cpp +++ b/example/utils/cstring.cpp @@ -450,4 +450,4 @@ int main() { std::cout << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/utils/difflib.cpp b/example/utils/difflib.cpp index 4fef1131..775389e9 100644 --- a/example/utils/difflib.cpp +++ b/example/utils/difflib.cpp @@ -1,7 +1,7 @@ /** * @file difflib_example.cpp * @brief Comprehensive examples demonstrating difflib utilities - * + * * This example demonstrates all functions available in atom::utils::difflib.hpp: * - SequenceMatcher for comparing sequences * - Differ for generating text differences @@ -17,48 +17,48 @@ #include #include #include - + // Helper function to print section headers void printSection(const std::string& title) { std::cout << "\n===============================================" << std::endl; std::cout << " " << title << std::endl; std::cout << "===============================================" << std::endl; } - + // Helper function to print sequences void printSequences(const std::vector& seq1, const std::vector& seq2) { std::cout << "Sequence 1:" << std::endl; for (const auto& item : seq1) { std::cout << " " << item << std::endl; } - + std::cout << "\nSequence 2:" << std::endl; for (const auto& item : seq2) { std::cout << " " << item << std::endl; } std::cout << std::endl; } - + // Helper function to print the matching blocks void printMatchingBlocks(const std::vector>& blocks) { std::cout << "Matching blocks:" << std::endl; for (const auto& [a, b, size] : blocks) { - std::cout << " a[" << a << ":" << (a + size) << "] == b[" << b << ":" + std::cout << " a[" << a << ":" << (a + size) << "] == b[" << b << ":" << (b + size) << "] (size: " << size << ")" << std::endl; } std::cout << std::endl; } - + // Helper function to print the opcodes void printOpcodes(const std::vector>& opcodes) { std::cout << "Opcodes:" << std::endl; for (const auto& [tag, i1, i2, j1, j2] : opcodes) { - std::cout << " " << std::left << std::setw(8) << tag + std::cout << " " << std::left << std::setw(8) << tag << " a[" << i1 << ":" << i2 << "] b[" << j1 << ":" << j2 << "]" << std::endl; } std::cout << std::endl; } - + // Helper function to save a string to a file bool saveToFile(const std::string& filename, const std::string& content) { std::ofstream file(filename); @@ -66,76 +66,76 @@ std::cerr << "Failed to open file for writing: " << filename << std::endl; return false; } - + file << content; file.close(); return true; } - + int main() { try { std::cout << "Difflib Utilities Demonstration" << std::endl; - + // =================================================== // Example 1: Basic String Comparison with SequenceMatcher // =================================================== printSection("1. Basic String Comparison with SequenceMatcher"); - + // Compare two simple strings std::string str1 = "This is the first test string."; std::string str2 = "This is the second test string."; - + std::cout << "String 1: \"" << str1 << "\"" << std::endl; std::cout << "String 2: \"" << str2 << "\"" << std::endl; - + // Create a SequenceMatcher atom::utils::SequenceMatcher matcher(str1, str2); - + // Calculate similarity ratio double similarity = matcher.ratio(); - std::cout << "Similarity ratio: " << similarity << " (" + std::cout << "Similarity ratio: " << similarity << " (" << static_cast(similarity * 100) << "%)" << std::endl; - + // Get matching blocks auto blocks = matcher.getMatchingBlocks(); printMatchingBlocks(blocks); - + // Get opcodes auto opcodes = matcher.getOpcodes(); printOpcodes(opcodes); - + // =================================================== // Example 2: Comparing Different Strings // =================================================== printSection("2. Comparing Different Strings"); - + // Compare two more different strings std::string text1 = "The quick brown fox jumps over the lazy dog."; std::string text2 = "A quick brown dog jumps over the lazy fox."; - + std::cout << "Text 1: \"" << text1 << "\"" << std::endl; std::cout << "Text 2: \"" << text2 << "\"" << std::endl; - + // Set new sequences to compare matcher.setSeqs(text1, text2); - + // Calculate similarity ratio similarity = matcher.ratio(); - std::cout << "Similarity ratio: " << similarity << " (" + std::cout << "Similarity ratio: " << similarity << " (" << static_cast(similarity * 100) << "%)" << std::endl; - + // Get matching blocks and opcodes blocks = matcher.getMatchingBlocks(); printMatchingBlocks(blocks); - + opcodes = matcher.getOpcodes(); printOpcodes(opcodes); - + // =================================================== // Example 3: Comparing Line Sequences with Differ // =================================================== printSection("3. Comparing Line Sequences with Differ"); - + // Create two sequences of lines std::vector lines1 = { "Line 1: This is a test.", @@ -144,7 +144,7 @@ "Line 4: This line will be removed.", "Line 5: The end." }; - + std::vector lines2 = { "Line 1: This is a test.", "Line 2: The quick brown fox jumps over the lazy cat.", // Changed dog -> cat @@ -152,58 +152,58 @@ "Line 5: The end.", // Line 4 removed "Line 6: An additional line." // New line added }; - + // Print the original sequences printSequences(lines1, lines2); - + // Generate differences using Differ std::cout << "Differences (Differ::compare):" << std::endl; auto diffs = atom::utils::Differ::compare(lines1, lines2); - + for (const auto& line : diffs) { std::cout << line << std::endl; } - + // =================================================== // Example 4: Unified Diff Format // =================================================== printSection("4. Unified Diff Format"); - + // Generate unified diff with default parameters std::cout << "Unified diff (default context=3):" << std::endl; auto unified_diff = atom::utils::Differ::unifiedDiff(lines1, lines2); - + for (const auto& line : unified_diff) { std::cout << line << std::endl; } - + // Generate unified diff with custom parameters std::cout << "\nUnified diff (custom labels, context=1):" << std::endl; auto custom_diff = atom::utils::Differ::unifiedDiff( lines1, lines2, "original.txt", "modified.txt", 1); - + for (const auto& line : custom_diff) { std::cout << line << std::endl; } - + // =================================================== // Example 5: HTML Diff Visualization // =================================================== printSection("5. HTML Diff Visualization"); - + // Generate HTML diff table std::cout << "Generating HTML diff table..." << std::endl; auto html_table_result = atom::utils::HtmlDiff::makeTable( lines1, lines2, "Original Text", "Modified Text"); - + if (html_table_result) { std::cout << "HTML table generated successfully." << std::endl; std::cout << "HTML table size: " << html_table_result->size() << " bytes" << std::endl; - + // Show first 200 characters std::cout << "Preview:" << std::endl; std::cout << html_table_result->substr(0, 200) << "..." << std::endl; - + // Save to file if (saveToFile("diff_table.html", *html_table_result)) { std::cout << "Saved to diff_table.html" << std::endl; @@ -211,16 +211,16 @@ } else { std::cerr << "Failed to generate HTML table: " << html_table_result.error() << std::endl; } - + // Generate complete HTML file std::cout << "\nGenerating complete HTML diff file..." << std::endl; auto html_file_result = atom::utils::HtmlDiff::makeFile( lines1, lines2, "Original Text", "Modified Text"); - + if (html_file_result) { std::cout << "HTML file generated successfully." << std::endl; std::cout << "HTML file size: " << html_file_result->size() << " bytes" << std::endl; - + // Save to file if (saveToFile("diff_complete.html", *html_file_result)) { std::cout << "Saved to diff_complete.html" << std::endl; @@ -228,12 +228,12 @@ } else { std::cerr << "Failed to generate HTML file: " << html_file_result.error() << std::endl; } - + // =================================================== // Example 6: Finding Close Matches // =================================================== printSection("6. Finding Close Matches"); - + // Define a list of words std::vector words = { "apple", "banana", "cherry", "date", "elderberry", @@ -241,7 +241,7 @@ "kiwi", "lemon", "mango", "nectarine", "orange", "papaya", "quince", "raspberry", "strawberry", "tangerine" }; - + std::cout << "List of words:" << std::endl; for (size_t i = 0; i < words.size(); ++i) { std::cout << words[i]; @@ -253,15 +253,15 @@ } } std::cout << std::endl; - + // Find close matches for slightly misspelled words std::vector test_words = { "aple", "strberry", "lemen", "banna", "grap" }; - + for (const auto& test_word : test_words) { std::cout << "Finding close matches for \"" << test_word << "\":" << std::endl; - + // Test with default parameters auto matches = atom::utils::getCloseMatches(test_word, words); std::cout << " Default (n=3, cutoff=0.6): "; @@ -272,7 +272,7 @@ } } std::cout << std::endl; - + // Test with different parameters auto matches2 = atom::utils::getCloseMatches(test_word, words, 1, 0.7); std::cout << " Custom (n=1, cutoff=0.7): "; @@ -280,7 +280,7 @@ std::cout << match; } std::cout << std::endl; - + // Test with very low cutoff auto matches3 = atom::utils::getCloseMatches(test_word, words, 5, 0.4); std::cout << " Custom (n=5, cutoff=0.4): "; @@ -292,22 +292,22 @@ } std::cout << std::endl; } - + // =================================================== // Example 7: Performance Testing with Larger Texts // =================================================== printSection("7. Performance Testing with Larger Texts"); - + // Generate larger text samples std::vector large_text1; std::vector large_text2; - + // Add some repeated content with variations for (int i = 0; i < 100; ++i) { std::ostringstream line1, line2; line1 << "Line " << i << ": This is test line number " << i << " in the first document."; large_text1.push_back(line1.str()); - + // Make some differences in the second document if (i % 10 == 0) { // Skip this line in text2 (deletion) @@ -329,102 +329,102 @@ large_text2.push_back(line2.str()); } } - + std::cout << "Created large text samples:" << std::endl; std::cout << " Text 1: " << large_text1.size() << " lines" << std::endl; std::cout << " Text 2: " << large_text2.size() << " lines" << std::endl; - + // Measure performance of different operations - + // 1. SequenceMatcher std::cout << "\nTesting SequenceMatcher performance..." << std::endl; auto start_time = std::chrono::high_resolution_clock::now(); - + std::string joined_text1; std::string joined_text2; - + for (const auto& line : large_text1) { joined_text1 += line + "\n"; } - + for (const auto& line : large_text2) { joined_text2 += line + "\n"; } - + atom::utils::SequenceMatcher large_matcher(joined_text1, joined_text2); double large_similarity = large_matcher.ratio(); - + auto end_time = std::chrono::high_resolution_clock::now(); auto duration = std::chrono::duration_cast(end_time - start_time).count(); - + std::cout << " Similarity ratio: " << large_similarity << std::endl; std::cout << " Time taken: " << duration << " ms" << std::endl; - + // 2. Differ::compare std::cout << "\nTesting Differ::compare performance..." << std::endl; start_time = std::chrono::high_resolution_clock::now(); - + auto large_diffs = atom::utils::Differ::compare(large_text1, large_text2); - + end_time = std::chrono::high_resolution_clock::now(); duration = std::chrono::duration_cast(end_time - start_time).count(); - + std::cout << " Generated diff with " << large_diffs.size() << " lines" << std::endl; std::cout << " Time taken: " << duration << " ms" << std::endl; - + // 3. HtmlDiff::makeTable std::cout << "\nTesting HtmlDiff::makeTable performance..." << std::endl; start_time = std::chrono::high_resolution_clock::now(); - + auto large_html_table = atom::utils::HtmlDiff::makeTable(large_text1, large_text2); - + end_time = std::chrono::high_resolution_clock::now(); duration = std::chrono::duration_cast(end_time - start_time).count(); - + if (large_html_table) { std::cout << " Generated HTML table with " << large_html_table->size() << " bytes" << std::endl; } else { std::cout << " Failed to generate HTML table: " << large_html_table.error() << std::endl; } std::cout << " Time taken: " << duration << " ms" << std::endl; - + // =================================================== // Example 8: Edge Cases and Special Scenarios // =================================================== printSection("8. Edge Cases and Special Scenarios"); - + // Case 1: Empty strings std::cout << "Comparing empty strings:" << std::endl; atom::utils::SequenceMatcher empty_matcher("", ""); std::cout << " Similarity ratio: " << empty_matcher.ratio() << std::endl; - + // Case 2: Empty vs non-empty std::cout << "\nComparing empty vs non-empty string:" << std::endl; atom::utils::SequenceMatcher mixed_matcher("", "Hello world"); std::cout << " Similarity ratio: " << mixed_matcher.ratio() << std::endl; - + // Case 3: Identical strings std::cout << "\nComparing identical strings:" << std::endl; std::string identical = "This string is exactly the same in both cases."; atom::utils::SequenceMatcher identical_matcher(identical, identical); std::cout << " Similarity ratio: " << identical_matcher.ratio() << std::endl; - + // Case 4: Finding close matches with empty string std::cout << "\nFinding close matches for empty string:" << std::endl; auto empty_matches = atom::utils::getCloseMatches("", words); std::cout << " Found " << empty_matches.size() << " matches" << std::endl; - + // Case 5: Finding close matches in empty list std::cout << "\nFinding close matches in empty list:" << std::endl; std::vector empty_list; auto no_matches = atom::utils::getCloseMatches("apple", empty_list); std::cout << " Found " << no_matches.size() << " matches" << std::endl; - + // =================================================== // Example 9: Practical Application - Spell Checker // =================================================== printSection("9. Practical Application - Simple Spell Checker"); - + // Define a dictionary of correctly spelled words std::vector dictionary = { "algorithm", "application", "binary", "compiler", "computer", @@ -433,17 +433,17 @@ "network", "operating", "processor", "programming", "recursive", "software", "storage", "structure", "system", "variable" }; - + // Define some misspelled words to check std::vector misspelled_words = { "algorthm", "aplicasion", "compiller", "developmint", "recursve" }; - + std::cout << "Simple spell checker:" << std::endl; for (const auto& word : misspelled_words) { std::cout << "Checking \"" << word << "\":" << std::endl; auto suggestions = atom::utils::getCloseMatches(word, dictionary, 3, 0.6); - + std::cout << " Did you mean: "; if (suggestions.empty()) { std::cout << "No suggestions found."; @@ -457,13 +457,13 @@ } std::cout << std::endl; } - + std::cout << "\nAll examples completed successfully!" << std::endl; - + } catch (const std::exception& e) { std::cerr << "ERROR: " << e.what() << std::endl; return 1; } - + return 0; - } \ No newline at end of file + } diff --git a/example/utils/event_stack.cpp b/example/utils/event_stack.cpp index 6d24f365..d0b6d615 100644 --- a/example/utils/event_stack.cpp +++ b/example/utils/event_stack.cpp @@ -40,4 +40,4 @@ int main() { std::cout << "Compressed errors: " << compressedErrors << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/utils/lcg.cpp b/example/utils/lcg.cpp index 791d82cd..bf7a7d37 100644 --- a/example/utils/lcg.cpp +++ b/example/utils/lcg.cpp @@ -287,4 +287,4 @@ int main() { } spdlog::info("\nAll LCG examples completed successfully!"); return 0; -} \ No newline at end of file +} diff --git a/example/utils/leak.cpp b/example/utils/leak.cpp index 31867b0c..4e609142 100644 --- a/example/utils/leak.cpp +++ b/example/utils/leak.cpp @@ -15,46 +15,46 @@ #include #include #include - + // Include leak detection header first to ensure proper initialization #include "atom/utils/leak.hpp" - + // Additional headers #include "atom/log/loguru.hpp" - + // A class with deliberate memory leak for demonstration class LeakyClass { private: int* data; char* buffer; std::vector* vector_data; - + public: LeakyClass(int size) { // Allocate memory without proper cleanup in some paths data = new int[size]; std::cout << "Allocated int array with " << size << " elements at " << data << std::endl; - + buffer = new char[1024]; std::cout << "Allocated char buffer of 1024 bytes at " << static_cast(buffer) << std::endl; - + vector_data = new std::vector(size, 0.0); std::cout << "Allocated vector with " << size << " elements at " << vector_data << std::endl; } - + // Proper cleanup path void cleanupProperly() { std::cout << "Properly cleaning up all allocations" << std::endl; delete[] data; delete[] buffer; delete vector_data; - + // Set to nullptr to prevent double-free data = nullptr; buffer = nullptr; vector_data = nullptr; } - + // Incomplete cleanup - will cause leak void cleanupIncomplete() { std::cout << "Performing incomplete cleanup (will cause leaks)" << std::endl; @@ -62,104 +62,104 @@ delete[] data; data = nullptr; } - + // No cleanup - will cause all resources to leak void noCleanup() { std::cout << "No cleanup performed (will cause all resources to leak)" << std::endl; // Intentionally do nothing } - + ~LeakyClass() { // In real code, we should clean up here // But for the example, we'll leave it empty to demonstrate leaks std::cout << "~LeakyClass destructor called (without proper cleanup)" << std::endl; } }; - + // Function that demonstrates a memory leak void demonstrateSimpleLeak() { std::cout << "\n=== Demonstrating Simple Memory Leak ===" << std::endl; - + // Allocate memory without freeing it int* leakedArray = new int[100]; for (int i = 0; i < 100; i++) { leakedArray[i] = i; } - + std::cout << "Allocated array at " << leakedArray << " but didn't free it" << std::endl; - + // Note: Deliberately not deleting leakedArray to demonstrate leak detection } - + // Function that demonstrates proper memory management void demonstrateProperMemoryManagement() { std::cout << "\n=== Demonstrating Proper Memory Management ===" << std::endl; - + // Allocate memory and properly free it int* properArray = new int[100]; for (int i = 0; i < 100; i++) { properArray[i] = i; } - + std::cout << "Allocated array at " << properArray << std::endl; - + // Proper cleanup delete[] properArray; std::cout << "Properly freed the array" << std::endl; } - + // Function that demonstrates smart pointers to prevent leaks void demonstrateSmartPointers() { std::cout << "\n=== Demonstrating Smart Pointers ===" << std::endl; - + // Using unique_ptr for automatic cleanup { std::unique_ptr uniqueArray = std::make_unique(100); std::cout << "Created array with unique_ptr at " << uniqueArray.get() << std::endl; - + // Fill with data for (int i = 0; i < 100; i++) { uniqueArray[i] = i; } - + std::cout << "unique_ptr will automatically free memory when going out of scope" << std::endl; } // uniqueArray is automatically deleted here - + // Using shared_ptr for shared ownership { auto sharedVector = std::make_shared>(1000, 0.5); std::cout << "Created vector with shared_ptr at " << sharedVector.get() << std::endl; - + // Create another shared pointer to the same data std::shared_ptr> anotherReference = sharedVector; std::cout << "Created second reference, use count: " << sharedVector.use_count() << std::endl; - + // The data will be freed when all references are gone } // Both shared pointers are automatically deleted here } - + // Function to demonstrate complex leaking scenario across threads void demonstrateThreadedLeaks() { std::cout << "\n=== Demonstrating Threaded Memory Leaks ===" << std::endl; - + // Create a vector to store thread objects std::vector threads; - + // Launch multiple threads that may leak memory for (int i = 0; i < 3; i++) { threads.emplace_back([i]() { std::cout << "Thread " << i << " starting" << std::endl; - + // Allocate memory in thread char* threadBuffer = new char[512 * (i + 1)]; std::memset(threadBuffer, 'A' + i, 512 * (i + 1)); - - std::cout << "Thread " << i << " allocated " << 512 * (i + 1) + + std::cout << "Thread " << i << " allocated " << 512 * (i + 1) << " bytes at " << static_cast(threadBuffer) << std::endl; - + // Sleep to simulate work std::this_thread::sleep_for(std::chrono::milliseconds(100)); - + // Even threads leak differently if (i % 2 == 0) { // Even-numbered threads free their memory @@ -169,33 +169,33 @@ // Odd-numbered threads leak their memory std::cout << "Thread " << i << " is leaking its memory" << std::endl; } - + std::cout << "Thread " << i << " ending" << std::endl; }); } - + // Join all threads for (auto& thread : threads) { thread.join(); } - + std::cout << "All threads completed" << std::endl; } - + // Function to demonstrate leak detection with container classes void demonstrateContainerLeaks() { std::cout << "\n=== Demonstrating Container Leaks ===" << std::endl; - + // Create a vector of raw pointers (not recommended in real code) std::vector pointerVector; - + // Add multiple allocations for (int i = 0; i < 5; i++) { int* ptr = new int(i * 100); pointerVector.push_back(ptr); std::cout << "Added pointer to value " << *ptr << " at " << ptr << std::endl; } - + // Only delete some of them (creating leaks) for (size_t i = 0; i < pointerVector.size(); i++) { if (i % 2 == 0) { @@ -205,87 +205,87 @@ std::cout << "Leaking pointer at index " << i << std::endl; } } - + // Clear the vector (but the odd-indexed pointers are still leaked) pointerVector.clear(); std::cout << "Vector cleared, but some pointers were leaked" << std::endl; } - + // Class to demonstrate RAII pattern to prevent leaks class RAIIExample { private: int* resource; - + public: RAIIExample(int size) : resource(new int[size]) { std::cout << "RAII class allocated resource at " << resource << std::endl; } - + ~RAIIExample() { std::cout << "RAII class automatically freeing resource at " << resource << std::endl; delete[] resource; } }; - + // Function to demonstrate proper RAII usage void demonstrateRAII() { std::cout << "\n=== Demonstrating RAII (Resource Acquisition Is Initialization) ===" << std::endl; - + // Create an instance of the RAII class { RAIIExample raii(200); std::cout << "Using RAII object..." << std::endl; - + // No need to manually call cleanup methods } // Resource is automatically freed here - + std::cout << "RAII object went out of scope, resource was freed" << std::endl; } - + int main() { // Initialize loguru loguru::g_stderr_verbosity = 1; loguru::init(0, nullptr); - + std::cout << "===============================================" << std::endl; std::cout << "Memory Leak Detection Example" << std::endl; std::cout << "===============================================" << std::endl; std::cout << "This example demonstrates how to use the leak detection utility" << std::endl; std::cout << "Note: Visual Leak Detector will report leaks at program exit" << std::endl; std::cout << "===============================================\n" << std::endl; - + // Demonstrate memory leaks with different scenarios demonstrateSimpleLeak(); - + demonstrateProperMemoryManagement(); - + demonstrateSmartPointers(); - + // Create leaky class instances with different cleanup approaches { std::cout << "\n=== Demonstrating Different Cleanup Strategies ===" << std::endl; - + LeakyClass* properCleanup = new LeakyClass(50); LeakyClass* incompleteCleanup = new LeakyClass(100); LeakyClass* noCleanup = new LeakyClass(150); - + // Demonstrate different cleanup strategies properCleanup->cleanupProperly(); incompleteCleanup->cleanupIncomplete(); noCleanup->noCleanup(); - + // Free the class instances delete properCleanup; delete incompleteCleanup; delete noCleanup; } - + demonstrateThreadedLeaks(); - + demonstrateContainerLeaks(); - + demonstrateRAII(); - + std::cout << "\n=== Additional Memory Leak Detection Tips ===" << std::endl; std::cout << "1. Always use smart pointers (std::unique_ptr, std::shared_ptr) when possible" << std::endl; std::cout << "2. Implement RAII pattern in your classes" << std::endl; @@ -293,10 +293,10 @@ std::cout << "4. Use containers and algorithms from the standard library" << std::endl; std::cout << "5. Set clear ownership rules for resources" << std::endl; std::cout << "6. Run with memory leak detection tools regularly" << std::endl; - + std::cout << "\n===============================================" << std::endl; std::cout << "Program completed. Check leak detector output." << std::endl; std::cout << "===============================================" << std::endl; - + return 0; - } \ No newline at end of file + } diff --git a/example/utils/linq.cpp b/example/utils/linq.cpp index b77f0cbe..7e42ade0 100644 --- a/example/utils/linq.cpp +++ b/example/utils/linq.cpp @@ -520,4 +520,4 @@ int main() { << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/utils/print.cpp b/example/utils/print.cpp index 337bbd8f..877e5cbf 100644 --- a/example/utils/print.cpp +++ b/example/utils/print.cpp @@ -425,4 +425,4 @@ int main() { << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/utils/qdatetime.cpp b/example/utils/qdatetime.cpp index b8350089..4daabf37 100644 --- a/example/utils/qdatetime.cpp +++ b/example/utils/qdatetime.cpp @@ -357,4 +357,4 @@ int main() { std::cout << "===============================================" << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/utils/qprocess.cpp b/example/utils/qprocess.cpp index 2ba7ac4f..ba79400f 100644 --- a/example/utils/qprocess.cpp +++ b/example/utils/qprocess.cpp @@ -511,4 +511,4 @@ int main(int argc, char* argv[]) { spdlog::info("======================================================="); return 0; -} \ No newline at end of file +} diff --git a/example/utils/qtimer.cpp b/example/utils/qtimer.cpp index 80788251..46a27188 100644 --- a/example/utils/qtimer.cpp +++ b/example/utils/qtimer.cpp @@ -554,4 +554,4 @@ int main() { << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/utils/qtimezone.cpp b/example/utils/qtimezone.cpp index 8037ddf6..eb582352 100644 --- a/example/utils/qtimezone.cpp +++ b/example/utils/qtimezone.cpp @@ -442,4 +442,4 @@ int main(int argc, char* argv[]) { std::cout << "QTimeZone Example Completed" << std::endl; std::cout << "==================================================" << std::endl; // filepath: examples/qtimezone_example.cpp -} \ No newline at end of file +} diff --git a/example/utils/random.cpp b/example/utils/random.cpp index dfef60df..e8acda9f 100644 --- a/example/utils/random.cpp +++ b/example/utils/random.cpp @@ -201,4 +201,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/example/utils/ranges.cpp b/example/utils/ranges.cpp index bc1036f5..3742412b 100644 --- a/example/utils/ranges.cpp +++ b/example/utils/ranges.cpp @@ -298,4 +298,4 @@ int main() { std::cout << "\n\n"; return 0; -} \ No newline at end of file +} diff --git a/example/utils/span.cpp b/example/utils/span.cpp index 6cf6cba5..7919fa25 100644 --- a/example/utils/span.cpp +++ b/example/utils/span.cpp @@ -261,4 +261,4 @@ int main() { << atom::utils::standardDeviation(changesSpan) << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/utils/stopwatcher.cpp b/example/utils/stopwatcher.cpp index 4dc3aeb5..df499f08 100644 --- a/example/utils/stopwatcher.cpp +++ b/example/utils/stopwatcher.cpp @@ -342,4 +342,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/example/utils/string.cpp b/example/utils/string.cpp index beb9c9bc..de299d59 100644 --- a/example/utils/string.cpp +++ b/example/utils/string.cpp @@ -312,4 +312,4 @@ int main() { printCollection(arr, "Array from split"); return 0; -} \ No newline at end of file +} diff --git a/example/utils/switch.cpp b/example/utils/switch.cpp index c2fba1d5..e58b617d 100644 --- a/example/utils/switch.cpp +++ b/example/utils/switch.cpp @@ -464,4 +464,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/example/utils/time.cpp b/example/utils/time.cpp index 3c34735b..f531320b 100644 --- a/example/utils/time.cpp +++ b/example/utils/time.cpp @@ -48,4 +48,4 @@ int main() { << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/utils/to_any.cpp b/example/utils/to_any.cpp index 64762cfa..3f0404ee 100644 --- a/example/utils/to_any.cpp +++ b/example/utils/to_any.cpp @@ -405,4 +405,4 @@ int main(int argc, char** argv) { } return 0; -} \ No newline at end of file +} diff --git a/example/utils/to_byte.cpp b/example/utils/to_byte.cpp index 6e0353e2..fbad998b 100644 --- a/example/utils/to_byte.cpp +++ b/example/utils/to_byte.cpp @@ -646,4 +646,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/example/utils/utf.cpp b/example/utils/utf.cpp index 4769ed54..4cee1bd4 100644 --- a/example/utils/utf.cpp +++ b/example/utils/utf.cpp @@ -60,4 +60,4 @@ int main() { std::cout << "Is valid UTF-8: " << std::boolalpha << isValid << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/utils/uuid.cpp b/example/utils/uuid.cpp index 97029e4f..1caa3246 100644 --- a/example/utils/uuid.cpp +++ b/example/utils/uuid.cpp @@ -222,4 +222,4 @@ int main() { #endif return 0; -} \ No newline at end of file +} diff --git a/example/utils/valid_string.cpp b/example/utils/valid_string.cpp index 66690ddd..9ee2fc83 100644 --- a/example/utils/valid_string.cpp +++ b/example/utils/valid_string.cpp @@ -321,4 +321,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/example/utils/xml.cpp b/example/utils/xml.cpp index ac00b88a..5c9f3a01 100644 --- a/example/utils/xml.cpp +++ b/example/utils/xml.cpp @@ -321,4 +321,4 @@ int main() { std::cout << "Example completed successfully!" << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/web/CMakeLists.txt b/example/web/CMakeLists.txt index 5eb9a2dc..b8e49989 100644 --- a/example/web/CMakeLists.txt +++ b/example/web/CMakeLists.txt @@ -14,20 +14,20 @@ file(GLOB CPP_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp) foreach(CPP_FILE ${CPP_FILES}) # 获取不带扩展名的文件名 get_filename_component(EXAMPLE_NAME ${CPP_FILE} NAME_WE) - + # 构造可执行文件名称(子目录名_文件名) set(EXECUTABLE_NAME ${SUBDIR_NAME}_${EXAMPLE_NAME}) - + # 配置选项,允许单独控制每个示例的构建 string(TOUPPER ${EXAMPLE_NAME} EXAMPLE_NAME_UPPER) option(ATOM_EXAMPLE_WEB_${EXAMPLE_NAME_UPPER} "Build web example: ${EXAMPLE_NAME}" ${ATOM_EXAMPLE_WEB_BUILD_ALL}) - + # 有条件地添加可执行文件 if(ATOM_EXAMPLE_WEB_${EXAMPLE_NAME_UPPER}) add_executable(${EXECUTABLE_NAME} ${CPP_FILE}) target_link_libraries(${EXECUTABLE_NAME} atom) - - + + # 设置IDE文件夹分组 set_property(TARGET ${EXECUTABLE_NAME} PROPERTY FOLDER "Examples/Web") endif() diff --git a/example/web/address.cpp b/example/web/address.cpp index 45b0ff48..a6938ca7 100644 --- a/example/web/address.cpp +++ b/example/web/address.cpp @@ -469,4 +469,4 @@ int main() { comprehensiveExample(); return 0; -} \ No newline at end of file +} diff --git a/example/web/curl.cpp b/example/web/curl.cpp index eafcfcdd..6f8754fb 100644 --- a/example/web/curl.cpp +++ b/example/web/curl.cpp @@ -59,4 +59,4 @@ int main() { curl.setMaxDownloadSpeed(1024 * 1024); // 1 MB/s return 0; -} \ No newline at end of file +} diff --git a/example/web/httpparser.cpp b/example/web/httpparser.cpp index 82b59dfb..52c3b0b0 100644 --- a/example/web/httpparser.cpp +++ b/example/web/httpparser.cpp @@ -61,4 +61,4 @@ int main() { std::cout << "Headers cleared." << std::endl; return 0; -} \ No newline at end of file +} diff --git a/example/web/minetype.cpp b/example/web/minetype.cpp index 3d16c9b1..9c3b0459 100644 --- a/example/web/minetype.cpp +++ b/example/web/minetype.cpp @@ -55,4 +55,4 @@ int main() { } return 0; -} \ No newline at end of file +} diff --git a/example/web/time.cpp b/example/web/time.cpp index 02a5e97d..4d9adf18 100644 --- a/example/web/time.cpp +++ b/example/web/time.cpp @@ -164,4 +164,4 @@ int main(int argc, char** argv) { } return 0; -} \ No newline at end of file +} diff --git a/example/web/utils.cpp b/example/web/utils.cpp index 9e13a8fb..eab295b8 100644 --- a/example/web/utils.cpp +++ b/example/web/utils.cpp @@ -274,4 +274,4 @@ int main(int argc, char** argv) { LOG_F(INFO, "Network Utils Example Application Completed Successfully"); return 0; -} \ No newline at end of file +} diff --git a/example/xmake.lua b/example/xmake.lua index a44051df..97503b99 100644 --- a/example/xmake.lua +++ b/example/xmake.lua @@ -38,24 +38,24 @@ local example_dirs = { -- Function to build examples from a directory function build_examples_from_dir(dir) local files = os.files(dir .. "/*.cpp") - + for _, file in ipairs(files) do local name = path.basename(file) local example_name = "example_" .. dir:gsub("/", "_") .. "_" .. name - + target(example_name) -- Set target kind to executable set_kind("binary") - + -- Add source file add_files(file) - + -- Add dependencies on atom libraries add_deps("atom") - + -- Add packages add_packages("loguru") - + -- Set output directory set_targetdir("$(buildir)/examples/" .. dir) target_end() diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index 1aaf4e53..2da0f1b3 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -101,7 +101,7 @@ foreach(type ${MODULE_TYPES}) # Set include directories target_include_directories( atom_${type} PRIVATE ${CMAKE_SOURCE_DIR}/.. # Atom root directory - ) + ) if(TARGET atom-${type}) target_link_libraries(atom_${type} PRIVATE atom-${type}) endif() # 对web模块特殊处理,确保链接到address组件和utils库 @@ -110,7 +110,7 @@ foreach(type ${MODULE_TYPES}) target_link_libraries(atom_${type} PRIVATE atom-web-address) message(STATUS "Linking atom_web to atom-web-address") endif() - + if(TARGET atom-utils) target_link_libraries(atom_${type} PRIVATE atom-utils) message(STATUS "Linking atom_web to atom-utils") @@ -122,7 +122,7 @@ foreach(type ${MODULE_TYPES}) target_link_libraries(atom_${type} PRIVATE mswsock) message(STATUS "Linking atom_connection to mswsock on Windows") endif() - + # 对algorithm模块特殊处理,确保链接必要的库 if("${type}" STREQUAL "algorithm") if(TARGET atom-type) @@ -130,7 +130,7 @@ foreach(type ${MODULE_TYPES}) message(STATUS "Linking atom_algorithm to atom-type") endif() endif() - + target_link_libraries(atom_${type} PRIVATE loguru atom-error) # Set output name diff --git a/python/algorithm/__init__.py b/python/algorithm/__init__.py index 83c7202c..70578fcd 100644 --- a/python/algorithm/__init__.py +++ b/python/algorithm/__init__.py @@ -1 +1 @@ -# Auto-generated __init__.py for algorithm module \ No newline at end of file +# Auto-generated __init__.py for algorithm module diff --git a/python/algorithm/annealing.cpp b/python/algorithm/annealing.cpp index d8585a58..379a6fc2 100644 --- a/python/algorithm/annealing.cpp +++ b/python/algorithm/annealing.cpp @@ -273,8 +273,8 @@ PYBIND11_MODULE(annealing, m) { R"pbdoc( Calculate a cooling rate for exponential cooling. - This function computes a cooling rate that will reduce the acceptance - probability from an initial value to a final value over the specified + This function computes a cooling rate that will reduce the acceptance + probability from an initial value to a final value over the specified number of iterations. Args: @@ -437,14 +437,14 @@ PYBIND11_MODULE(annealing, m) { py::arg("num_cities") = 20, py::arg("num_runs") = 5, R"pbdoc( Benchmark different cooling strategies for TSP. - + This function runs the simulated annealing algorithm with different cooling strategies and reports the average tour length and execution time. - + Args: num_cities: Number of cities in the random TSP instance (default: 20) num_runs: Number of runs per strategy (default: 5) - + Returns: List of (strategy_name, avg_tour_length, execution_time) tuples )pbdoc"); @@ -489,13 +489,13 @@ PYBIND11_MODULE(annealing, m) { py::arg("cities"), py::arg("tour"), R"pbdoc( Visualize a TSP tour using matplotlib. - + This function plots the cities and the tour path connecting them. - + Args: cities: List of (x,y) coordinates for each city tour: List of city indices representing the tour - + Note: This function requires matplotlib to be installed )pbdoc"); @@ -523,14 +523,14 @@ PYBIND11_MODULE(annealing, m) { py::arg("cities"), py::arg("tour"), R"pbdoc( Compute the total length of a TSP tour. - + This is a convenience function to calculate the total distance of a tour without creating a TSP instance. - + Args: cities: List of (x,y) coordinates for each city tour: List of city indices representing the tour - + Returns: The total distance of the tour )pbdoc"); @@ -580,13 +580,13 @@ PYBIND11_MODULE(annealing, m) { py::arg("cities"), py::arg("start_city") = 0, R"pbdoc( Generate a TSP tour using a greedy nearest neighbor heuristic. - + This function builds a tour by always choosing the closest unvisited city. - + Args: cities: List of (x,y) coordinates for each city start_city: Index of the starting city (default: 0) - + Returns: A tour constructed using the nearest neighbor heuristic )pbdoc"); @@ -640,15 +640,15 @@ PYBIND11_MODULE(annealing, m) { py::arg("cities"), py::arg("tour"), py::arg("max_iterations") = 1000, R"pbdoc( Improve a TSP tour using the 2-opt local search heuristic. - + This algorithm iteratively removes two edges and reconnects the tour in the other possible way, keeping the change if it improves the tour length. - + Args: cities: List of (x,y) coordinates for each city tour: Initial tour to improve max_iterations: Maximum number of improvement iterations - + Returns: An improved tour )pbdoc"); @@ -667,11 +667,11 @@ class CustomProblem: Example custom problem implementation compatible with the C++ AnnealingProblem concept. Replace with your own problem definition. """ - + def __init__(self, problem_data: Any): """Initialize your problem with specific data""" self.problem_data = problem_data - + def energy(self, solution: Any) -> float: """ Calculate the objective function value (energy) of a solution. @@ -679,17 +679,17 @@ class CustomProblem: """ # Replace with your actual objective function return 0.0 - + def neighbor(self, solution: Any) -> Any: """Generate a slightly modified neighboring solution""" # Replace with your neighbor generation logic return solution - + def random_solution(self) -> Any: """Generate a random initial solution""" # Replace with code to generate a valid random solution return None - + def validate(self, solution: Any) -> bool: """Check if a solution is valid""" # Replace with your validation logic @@ -698,29 +698,29 @@ class CustomProblem: # Example usage with the atom.algorithm.annealing module: def solve_custom_problem(): from atom.algorithm.annealing import SimulatedAnnealing, AnnealingStrategy - + # Create your problem instance problem = CustomProblem(your_problem_data) - + # Set up the annealing solver annealing = SimulatedAnnealing(problem) annealing.set_max_iterations(10000) annealing.set_initial_temperature(100.0) annealing.set_cooling_strategy(AnnealingStrategy.EXPONENTIAL) - + # Run the optimization best_solution = annealing.optimize() - + return best_solution )code"; }, R"pbdoc( Provides a Python template for creating custom problem types. - + This function returns a string containing Python code that shows how to create a custom problem compatible with the simulated annealing algorithm interface. - + Returns: Python code template as a string )pbdoc"); diff --git a/python/algorithm/base.cpp b/python/algorithm/base.cpp index b33a0542..213f7c1c 100644 --- a/python/algorithm/base.cpp +++ b/python/algorithm/base.cpp @@ -10,12 +10,12 @@ PYBIND11_MODULE(base, m) { m.doc() = R"pbdoc( Base Encoding/Decoding Algorithms --------------------------------- - + This module provides functions for encoding and decoding data in various formats: - Base32 encoding and decoding - Base64 encoding and decoding - XOR encryption and decryption - + Examples: >>> import atom.algorithm.base as base >>> base.base64_encode("Hello, world!") @@ -56,16 +56,16 @@ PYBIND11_MODULE(base, m) { }, py::arg("data"), R"pbdoc( Encode binary data using Base32. - + Args: data (bytes): The binary data to encode. - + Returns: str: The Base32 encoded string. - + Raises: ValueError: If encoding fails. - + Example: >>> encode_base32(b'hello') 'NBSWY3DP' @@ -85,16 +85,16 @@ PYBIND11_MODULE(base, m) { }, py::arg("encoded"), R"pbdoc( Decode a Base32 encoded string back to binary data. - + Args: encoded (str): The Base32 encoded string. - + Returns: bytes: The decoded binary data. - + Raises: ValueError: If decoding fails. - + Example: >>> decode_base32('NBSWY3DP') b'hello' @@ -113,17 +113,17 @@ PYBIND11_MODULE(base, m) { }, py::arg("input"), py::arg("padding") = true, R"pbdoc( Encode a string using Base64. - + Args: input (str): The string to encode. padding (bool, optional): Whether to add padding characters. Defaults to True. - + Returns: str: The Base64 encoded string. - + Raises: ValueError: If encoding fails. - + Example: >>> base64_encode("hello") 'aGVsbG8=' @@ -143,16 +143,16 @@ PYBIND11_MODULE(base, m) { }, py::arg("input"), R"pbdoc( Decode a Base64 encoded string. - + Args: input (str): The Base64 encoded string. - + Returns: str: The decoded string. - + Raises: ValueError: If decoding fails. - + Example: >>> base64_decode('aGVsbG8=') 'hello' @@ -163,14 +163,14 @@ PYBIND11_MODULE(base, m) { py::arg("key"), R"pbdoc( Encrypt a string using XOR algorithm. - + Args: plaintext (str): The string to encrypt. key (int): The encryption key (0-255). - + Returns: str: The encrypted string. - + Example: >>> encrypted = xor_encrypt("hello", 42) >>> # Result is binary data @@ -180,14 +180,14 @@ PYBIND11_MODULE(base, m) { py::arg("key"), R"pbdoc( Decrypt a string using XOR algorithm. - + Args: ciphertext (str): The encrypted string. key (int): The decryption key (0-255). - + Returns: str: The decrypted string. - + Example: >>> encrypted = xor_encrypt("hello", 42) >>> xor_decrypt(encrypted, 42) @@ -198,13 +198,13 @@ PYBIND11_MODULE(base, m) { m.def("is_base64", &atom::algorithm::isBase64, py::arg("str"), R"pbdoc( Check if a string is a valid Base64 encoded string. - + Args: str (str): The string to validate. - + Returns: bool: True if the string is valid Base64, False otherwise. - + Example: >>> is_base64('aGVsbG8=') True @@ -227,14 +227,14 @@ PYBIND11_MODULE(base, m) { }, py::arg("input"), py::arg("padding") = true, R"pbdoc( Encode binary data using Base64. - + Args: input (bytes): The binary data to encode. padding (bool, optional): Whether to add padding characters. Defaults to True. - + Returns: str: The Base64 encoded string. - + Example: >>> base64_encode_binary(b'\x00\x01\x02\x03') 'AAECAw==' @@ -252,13 +252,13 @@ PYBIND11_MODULE(base, m) { }, py::arg("input"), R"pbdoc( Decode a Base64 encoded string to binary data. - + Args: input (str): The Base64 encoded string. - + Returns: bytes: The decoded binary data. - + Example: >>> base64_decode_binary('AAECAw==') b'\x00\x01\x02\x03' @@ -279,13 +279,13 @@ PYBIND11_MODULE(base, m) { }, py::arg("input"), py::arg("padding") = true, R"pbdoc( Encode binary data using Base64 (returns bytes). - + This function matches the API of Python's `base64.b64encode`. - + Args: input (bytes): The binary data to encode. padding (bool, optional): Whether to add padding characters. Defaults to True. - + Returns: bytes: The Base64 encoded data as bytes. )pbdoc"); @@ -304,12 +304,12 @@ PYBIND11_MODULE(base, m) { }, py::arg("input"), R"pbdoc( Decode Base64 encoded data (accepts bytes). - + This function matches the API of Python's `base64.b64decode`. - + Args: input (bytes): The Base64 encoded data. - + Returns: bytes: The decoded binary data. )pbdoc"); @@ -338,11 +338,11 @@ PYBIND11_MODULE(base, m) { }, py::arg("plaintext"), py::arg("key"), R"pbdoc( Encrypt binary data using XOR algorithm. - + Args: plaintext (bytes): The binary data to encrypt. key (int): The encryption key (0-255). - + Returns: bytes: The encrypted data. )pbdoc"); @@ -357,11 +357,11 @@ PYBIND11_MODULE(base, m) { }, py::arg("ciphertext"), py::arg("key"), R"pbdoc( Decrypt binary data using XOR algorithm. - + Args: ciphertext (bytes): The encrypted data. key (int): The decryption key (0-255). - + Returns: bytes: The decrypted data. )pbdoc"); @@ -411,20 +411,20 @@ PYBIND11_MODULE(base, m) { }, py::arg("data"), py::arg("thread_count") = 0, py::arg("func"), R"pbdoc( Process binary data in parallel across multiple threads. - + Args: data (bytes): The binary data to process. thread_count (int, optional): Number of threads to use. Default is 0 (auto). func (callable): Function that processes a chunk of data. Should accept and return bytes objects of the same size. - + Returns: bytes: The processed data. - + Example: >>> def process_chunk(chunk): ... return bytes(b ^ 42 for b in chunk) >>> parallel_process(b'hello world', 2, process_chunk) b'*\x0f\x16\x16\x17K\x04\x17\x03\x16\x0e' )pbdoc"); -} \ No newline at end of file +} diff --git a/python/algorithm/blowfish.cpp b/python/algorithm/blowfish.cpp index 11b99208..7fae3ced 100644 --- a/python/algorithm/blowfish.cpp +++ b/python/algorithm/blowfish.cpp @@ -8,10 +8,10 @@ PYBIND11_MODULE(blowfish, m) { m.doc() = R"pbdoc( Blowfish Encryption Algorithm ---------------------------- - + This module provides a Python interface to the Blowfish encryption algorithm. Blowfish is a symmetric-key block cipher designed by Bruce Schneier in 1993. - + Example: >>> import atom.algorithm.blowfish as bf >>> # Generate a random key @@ -47,10 +47,10 @@ PYBIND11_MODULE(blowfish, m) { // Blowfish class py::class_(m, "Blowfish", R"pbdoc( Blowfish cipher implementation. - + The Blowfish class implements the Blowfish encryption algorithm, a symmetric key block cipher that can be used for encrypting data. - + Args: key (bytes): The encryption key (4-56 bytes) )pbdoc") @@ -94,13 +94,13 @@ PYBIND11_MODULE(blowfish, m) { }, py::arg("block"), R"pbdoc( Encrypt a single 8-byte block. - + Args: block (bytes): The 8-byte block to encrypt - + Returns: bytes: The encrypted 8-byte block - + Raises: ValueError: If the block is not exactly 8 bytes )pbdoc") @@ -127,13 +127,13 @@ PYBIND11_MODULE(blowfish, m) { }, py::arg("block"), R"pbdoc( Decrypt a single 8-byte block. - + Args: block (bytes): The 8-byte block to decrypt - + Returns: bytes: The decrypted 8-byte block - + Raises: ValueError: If the block is not exactly 8 bytes )pbdoc") @@ -156,16 +156,16 @@ PYBIND11_MODULE(blowfish, m) { }, py::arg("data"), R"pbdoc( Encrypt arbitrary data. - + This method encrypts arbitrary data using the Blowfish cipher. PKCS7 padding is automatically applied. - + Args: data (bytes): The data to encrypt - + Returns: bytes: The encrypted data - + Raises: ValueError: If the data is empty )pbdoc") @@ -200,16 +200,16 @@ PYBIND11_MODULE(blowfish, m) { }, py::arg("data"), R"pbdoc( Decrypt data. - + This method decrypts data that was encrypted with the encrypt_data method. PKCS7 padding is automatically removed. - + Args: data (bytes): The encrypted data - + Returns: bytes: The decrypted data - + Raises: ValueError: If the data is empty or not a multiple of 8 bytes )pbdoc") @@ -217,14 +217,14 @@ PYBIND11_MODULE(blowfish, m) { py::arg("input_file"), py::arg("output_file"), R"pbdoc( Encrypt a file. - + This method reads a file, encrypts its contents, and writes the encrypted data to another file. - + Args: input_file (str): Path to the input file output_file (str): Path to the output file - + Raises: RuntimeError: If file operations fail )pbdoc") @@ -232,14 +232,14 @@ PYBIND11_MODULE(blowfish, m) { py::arg("input_file"), py::arg("output_file"), R"pbdoc( Decrypt a file. - + This method reads an encrypted file, decrypts its contents, and writes the decrypted data to another file. - + Args: input_file (str): Path to the encrypted file output_file (str): Path to the output file - + Raises: RuntimeError: If file operations fail )pbdoc"); @@ -260,14 +260,14 @@ PYBIND11_MODULE(blowfish, m) { }, py::arg("length") = 16, R"pbdoc( Generate a cryptographically secure random key. - + Args: length (int, optional): The key length in bytes. Default is 16. Must be between 4 and 56 bytes. - + Returns: bytes: A random key of the specified length - + Raises: ValueError: If the length is not between 4 and 56 bytes )pbdoc"); @@ -288,11 +288,11 @@ PYBIND11_MODULE(blowfish, m) { }, py::arg("cipher"), py::arg("text"), R"pbdoc( Encrypt a string using a Blowfish cipher. - + Args: cipher (Blowfish): The Blowfish cipher instance text (str): The string to encrypt - + Returns: bytes: The encrypted data )pbdoc"); @@ -326,14 +326,14 @@ PYBIND11_MODULE(blowfish, m) { }, py::arg("cipher"), py::arg("data"), R"pbdoc( Decrypt data to a string using a Blowfish cipher. - + Args: cipher (Blowfish): The Blowfish cipher instance data (bytes): The encrypted data - + Returns: str: The decrypted string - + Raises: ValueError: If the data is empty or not a multiple of 8 bytes UnicodeDecodeError: If the decrypted data is not valid UTF-8 @@ -379,17 +379,17 @@ PYBIND11_MODULE(blowfish, m) { }, py::arg("password"), py::arg("data"), R"pbdoc( Encrypt data using a password. - + WARNING: This is a convenience function with a simple key derivation. For secure applications, use a proper key derivation function. - + Args: password (str): The password data (bytes): The data to encrypt - + Returns: bytes: The encrypted data - + Raises: ValueError: If the password is empty or data is empty )pbdoc"); @@ -439,18 +439,18 @@ PYBIND11_MODULE(blowfish, m) { }, py::arg("password"), py::arg("data"), R"pbdoc( Decrypt data using a password. - + WARNING: This is a convenience function with a simple key derivation. For secure applications, use a proper key derivation function. - + Args: password (str): The password data (bytes): The encrypted data - + Returns: bytes: The decrypted data - + Raises: ValueError: If the password is empty, data is empty, or data is not a multiple of 8 bytes )pbdoc"); -} \ No newline at end of file +} diff --git a/python/algorithm/error_calibration.cpp b/python/algorithm/error_calibration.cpp index bfd9a86f..7b77ba1a 100644 --- a/python/algorithm/error_calibration.cpp +++ b/python/algorithm/error_calibration.cpp @@ -29,24 +29,24 @@ PYBIND11_MODULE(error_calibration, m) { This module provides tools for error calibration of measurement data. It includes methods for linear, polynomial, exponential, logarithmic, and power law calibration, as well as tools for statistical analysis. - + Examples: >>> import numpy as np >>> from atom.algorithm.error_calibration import ErrorCalibration - >>> + >>> >>> # Sample data >>> measured = [1.0, 2.0, 3.0, 4.0, 5.0] >>> actual = [0.9, 2.1, 2.8, 4.2, 4.9] - >>> + >>> >>> # Create calibrator and perform linear calibration >>> calibrator = ErrorCalibration() >>> calibrator.linear_calibrate(measured, actual) - >>> + >>> >>> # Print calibration parameters >>> print(f"Slope: {calibrator.get_slope()}") >>> print(f"Intercept: {calibrator.get_intercept()}") >>> print(f"R-squared: {calibrator.get_r_squared()}") - >>> + >>> >>> # Apply calibration to new measurements >>> new_measurement = 3.5 >>> calibrated_value = calibrator.apply(new_measurement) @@ -79,7 +79,7 @@ PYBIND11_MODULE(error_calibration, m) { py::class_>(m, "ErrorCalibration", R"pbdoc( Error calibration class for measurement data. - + This class provides methods for calibrating measurements and analyzing errors using various calibration techniques, including linear, polynomial, exponential, logarithmic, and power law models. @@ -90,11 +90,11 @@ PYBIND11_MODULE(error_calibration, m) { py::arg("measured"), py::arg("actual"), R"pbdoc( Perform linear calibration using the least squares method. - + Args: measured: List of measured values actual: List of actual values - + Raises: ValueError: If input vectors are empty or of unequal size )pbdoc") @@ -103,12 +103,12 @@ PYBIND11_MODULE(error_calibration, m) { py::arg("measured"), py::arg("actual"), py::arg("degree"), R"pbdoc( Perform polynomial calibration using the least squares method. - + Args: measured: List of measured values actual: List of actual values degree: Degree of the polynomial - + Raises: ValueError: If input vectors are empty, of unequal size, or if degree is invalid )pbdoc") @@ -117,11 +117,11 @@ PYBIND11_MODULE(error_calibration, m) { py::arg("measured"), py::arg("actual"), R"pbdoc( Perform exponential calibration using the least squares method. - + Args: measured: List of measured values actual: List of actual values - + Raises: ValueError: If input vectors are empty, of unequal size, or if actual values are not positive )pbdoc") @@ -130,11 +130,11 @@ PYBIND11_MODULE(error_calibration, m) { py::arg("measured"), py::arg("actual"), R"pbdoc( Perform logarithmic calibration using the least squares method. - + Args: measured: List of measured values actual: List of actual values - + Raises: ValueError: If input vectors are empty, of unequal size, or if measured values are not positive )pbdoc") @@ -143,11 +143,11 @@ PYBIND11_MODULE(error_calibration, m) { py::arg("measured"), py::arg("actual"), R"pbdoc( Perform power law calibration using the least squares method. - + Args: measured: List of measured values actual: List of actual values - + Raises: ValueError: If input vectors are empty, of unequal size, or if values are not positive )pbdoc") @@ -164,10 +164,10 @@ PYBIND11_MODULE(error_calibration, m) { py::arg("filename"), R"pbdoc( Save residuals to a CSV file for plotting. - + Args: filename: Path to the output file - + Raises: IOError: If the file cannot be opened )pbdoc") @@ -178,16 +178,16 @@ PYBIND11_MODULE(error_calibration, m) { py::arg("n_iterations") = 1000, py::arg("confidence_level") = 0.95, R"pbdoc( Calculate bootstrap confidence interval for the slope. - + Args: measured: List of measured values actual: List of actual values n_iterations: Number of bootstrap iterations (default: 1000) confidence_level: Confidence level (default: 0.95) - + Returns: Tuple of lower and upper bounds of the confidence interval - + Raises: ValueError: If input parameters are invalid )pbdoc") @@ -196,15 +196,15 @@ PYBIND11_MODULE(error_calibration, m) { py::arg("measured"), py::arg("actual"), py::arg("threshold") = 2.0, R"pbdoc( Detect outliers using the residuals of the calibration. - + Args: measured: List of measured values actual: List of actual values threshold: Z-score threshold for outlier detection (default: 2.0) - + Returns: Tuple of mean residual, standard deviation, and threshold - + Raises: RuntimeError: If metrics have not been calculated yet )pbdoc") @@ -213,12 +213,12 @@ PYBIND11_MODULE(error_calibration, m) { py::arg("measured"), py::arg("actual"), py::arg("k") = 5, R"pbdoc( Perform k-fold cross-validation of the calibration. - + Args: measured: List of measured values actual: List of actual values k: Number of folds (default: 5) - + Raises: ValueError: If input vectors are invalid RuntimeError: If all cross-validation folds fail @@ -249,7 +249,7 @@ PYBIND11_MODULE(error_calibration, m) { py::class_>( m, "ErrorCalibrationFloat", R"pbdoc( Error calibration class with single precision (float). - + This class is identical to ErrorCalibration but uses single precision floating point calculations, which may be faster but less accurate. )pbdoc") @@ -317,17 +317,17 @@ PYBIND11_MODULE(error_calibration, m) { py::arg("measured"), py::arg("actual"), R"pbdoc( Perform asynchronous linear calibration. - + This function starts a calibration in a background thread and returns the calibrator once the calibration is complete. - + Args: measured: List of measured values actual: List of actual values - + Returns: ErrorCalibration object with the calibration results - + Raises: ValueError: If the calibration fails )pbdoc"); @@ -406,17 +406,17 @@ PYBIND11_MODULE(error_calibration, m) { py::arg("measured"), py::arg("actual"), R"pbdoc( Find the best calibration method for the given data. - + This function tries different calibration methods and returns the name of the method with the lowest Mean Squared Error (MSE). - + Args: measured: List of measured values actual: List of actual values - + Returns: String with the name of the best calibration method - + Raises: ValueError: If all calibration methods fail )pbdoc"); @@ -439,11 +439,11 @@ PYBIND11_MODULE(error_calibration, m) { py::arg("measured_array"), py::arg("calibrator"), R"pbdoc( Apply calibration to a numpy array of measurements. - + Args: measured_array: Numpy array of measured values calibrator: ErrorCalibration object - + Returns: Numpy array of calibrated values )pbdoc"); @@ -502,18 +502,18 @@ PYBIND11_MODULE(error_calibration, m) { py::arg("measured"), py::arg("actual"), py::arg("calibrator"), R"pbdoc( Plot calibration results using matplotlib. - + This function creates a scatter plot of measured vs actual values, as well as the calibrated values and the calibration line. - + Args: measured: List of measured values actual: List of actual values calibrator: ErrorCalibration object - + Returns: True if the plot was created successfully, False otherwise - + Note: This function requires matplotlib to be installed. )pbdoc"); @@ -656,21 +656,21 @@ PYBIND11_MODULE(error_calibration, m) { py::arg("calibrator"), py::arg("measured"), py::arg("actual"), R"pbdoc( Analyze residuals with comprehensive plots and statistics. - + This function creates a set of diagnostic plots for analyzing residuals: 1. Residuals vs measured values 2. Histogram of residuals 3. Q-Q plot for normality check 4. Calibration curve - + Args: calibrator: ErrorCalibration object measured: List of measured values actual: List of actual values - + Returns: Dictionary with residual statistics (mean, std_dev, mse, mae, r_squared, slope, intercept) - + Note: This function requires matplotlib and scipy to be installed. )pbdoc"); diff --git a/python/algorithm/flood.cpp b/python/algorithm/flood.cpp index 481e07b1..3d0bd837 100644 --- a/python/algorithm/flood.cpp +++ b/python/algorithm/flood.cpp @@ -53,7 +53,7 @@ PYBIND11_MODULE(flood_fill, m) { -------------------- This module provides various flood fill algorithms for 2D grids: - + - **fill_bfs**: Flood fill using Breadth-First Search - **fill_dfs**: Flood fill using Depth-First Search - **fill_parallel**: Flood fill using multiple threads @@ -61,14 +61,14 @@ PYBIND11_MODULE(flood_fill, m) { Example: >>> import numpy as np >>> from atom.algorithm.flood_fill import fill_bfs, Connectivity - >>> + >>> >>> # Create a grid >>> grid = np.zeros((10, 10), dtype=np.int32) >>> grid[3:7, 3:7] = 1 # Create a square - >>> + >>> >>> # Fill the square >>> filled_grid = fill_bfs(grid, 5, 5, 1, 2, Connectivity.FOUR) - >>> + >>> >>> # Check result >>> assert np.all(filled_grid[3:7, 3:7] == 2) )pbdoc"; @@ -518,4 +518,4 @@ PYBIND11_MODULE(flood_fill, m) { Raises: RuntimeError: If image is not 3D or doesn't have 3 channels )pbdoc"); -} \ No newline at end of file +} diff --git a/python/algorithm/fnmatch.cpp b/python/algorithm/fnmatch.cpp index bb21d26d..9e3178f9 100644 --- a/python/algorithm/fnmatch.cpp +++ b/python/algorithm/fnmatch.cpp @@ -13,24 +13,24 @@ PYBIND11_MODULE(fnmatch, m) { This module provides pattern matching functionality similar to Python's fnmatch, but with additional features and optimizations: - + - Case-insensitive matching - Path-aware matching - SIMD-accelerated matching (when available) - Support for multiple patterns - Parallel processing options - + Example: >>> from atom.algorithm import fnmatch - >>> + >>> >>> # Simple pattern matching >>> fnmatch.fnmatch("example.txt", "*.txt") True - + >>> # Case-insensitive matching >>> fnmatch.fnmatch("Example.TXT", "*.txt", fnmatch.CASEFOLD) True - + >>> # Filter a list of filenames >>> names = ["file1.txt", "file2.jpg", "file3.txt", "file4.png"] >>> fnmatch.filter(names, "*.txt") @@ -61,16 +61,16 @@ PYBIND11_MODULE(fnmatch, m) { py::arg("pattern"), py::arg("string"), py::arg("flags") = 0, R"pbdoc( Matches a string against a specified pattern. - + Args: pattern: The pattern to match against string: The string to match flags: Optional flags to modify matching behavior (default: 0) Can be NOESCAPE, PATHNAME, PERIOD, CASEFOLD or combined with bitwise OR - + Returns: bool: True if the string matches the pattern, False otherwise - + Raises: FnmatchException: If there is an error in the pattern )pbdoc"); @@ -81,12 +81,12 @@ PYBIND11_MODULE(fnmatch, m) { py::arg("pattern"), py::arg("string"), py::arg("flags") = 0, R"pbdoc( Matches a string against a specified pattern without throwing exceptions. - + Args: pattern: The pattern to match against string: The string to match flags: Optional flags to modify matching behavior (default: 0) - + Returns: Expected object containing bool result or FnmatchError )pbdoc"); @@ -106,12 +106,12 @@ PYBIND11_MODULE(fnmatch, m) { py::arg("names"), py::arg("pattern"), py::arg("flags") = 0, R"pbdoc( Check if any string in the list matches the pattern. - + Args: names: List of strings to filter pattern: Pattern to filter with flags: Optional flags to modify filtering behavior (default: 0) - + Returns: bool: True if any element matches the pattern )pbdoc"); @@ -147,13 +147,13 @@ PYBIND11_MODULE(fnmatch, m) { py::arg("use_parallel") = true, R"pbdoc( Filter a list of strings with multiple patterns. - + Args: names: List of strings to filter patterns: List of patterns to filter with flags: Optional flags to modify filtering behavior (default: 0) use_parallel: Whether to use parallel execution (default: True) - + Returns: list: Strings from names that match any pattern in patterns )pbdoc"); @@ -163,15 +163,15 @@ PYBIND11_MODULE(fnmatch, m) { py::arg("pattern"), py::arg("flags") = 0, R"pbdoc( Translate a pattern into a regular expression string. - + Args: pattern: The pattern to translate flags: Optional flags to modify translation behavior (default: 0) - + Returns: Expected object containing regex string or FnmatchError )pbdoc"); // Add version information m.attr("__version__") = "1.0.0"; -} \ No newline at end of file +} diff --git a/python/algorithm/fraction.cpp b/python/algorithm/fraction.cpp index df8b1a13..d5f79954 100644 --- a/python/algorithm/fraction.cpp +++ b/python/algorithm/fraction.cpp @@ -13,22 +13,22 @@ PYBIND11_MODULE(fraction, m) { ----------------------------- This module provides a robust fraction class for exact rational arithmetic. - + The Fraction class represents rational numbers as a numerator and denominator, always keeping the fraction in reduced form. It supports all standard arithmetic operations, comparison, conversion to various types, and additional utilities. Example: >>> from atom.algorithm import fraction - >>> + >>> >>> # Create fractions >>> a = fraction.Fraction(1, 2) # 1/2 >>> b = fraction.Fraction(3, 4) # 3/4 - >>> + >>> >>> # Arithmetic operations >>> c = a + b # 5/4 >>> print(c) # "5/4" - >>> + >>> >>> # Converting from floats >>> d = fraction.make_fraction(0.333333) # Approximate as a fraction >>> print(d) # "1/3" or a close approximation @@ -67,18 +67,18 @@ various arithmetic operations, comparisons, and conversions. Examples: >>> from atom.algorithm.fraction import Fraction - >>> + >>> >>> # Create a fraction >>> f1 = Fraction(1, 2) # 1/2 >>> f2 = Fraction(3, 4) # 3/4 - >>> + >>> >>> # Basic arithmetic >>> f3 = f1 + f2 # 5/4 >>> f4 = f1 * f2 # 3/8 - >>> + >>> >>> # Comparisons >>> f1 < f2 # True - >>> + >>> >>> # Conversion >>> float(f1) # 0.5 )") @@ -283,4 +283,4 @@ various arithmetic operations, comparisons, and conversions. >>> lcm(4, 6) # Returns 12 >>> lcm(15, 25) # Returns 75 )"); -} \ No newline at end of file +} diff --git a/python/algorithm/hash.cpp b/python/algorithm/hash.cpp index 12655051..9dc84d81 100644 --- a/python/algorithm/hash.cpp +++ b/python/algorithm/hash.cpp @@ -13,29 +13,29 @@ PYBIND11_MODULE(hash, m) { This module provides a collection of optimized hash functions with thread-safe caching, parallel processing capability, and support for various data types. - + The module includes: - Standard hash functions optimized with SIMD instructions - Support for various hash algorithms (STD, FNV1A, etc.) - Utilities for combining and verifying hash values - Thread-safe hash caching - Hash computation for complex data structures - + Example: >>> from atom.algorithm import hash - >>> + >>> >>> # Compute hash of a string >>> h1 = hash.compute_hash("Hello, world!") >>> print(h1) - + >>> # Compute hash with a specific algorithm >>> h2 = hash.compute_hash("Hello, world!", hash.HashAlgorithm.FNV1A) >>> print(h2) - + >>> # Hash a list of values >>> h3 = hash.compute_hash([1, 2, 3, 4, 5]) >>> print(h3) - + >>> # Verify if two hashes match >>> hash.verify_hash(h1, h2) # False >>> hash.verify_hash(h1, h1) # True @@ -66,11 +66,11 @@ PYBIND11_MODULE(hash, m) { py::arg("algorithm") = atom::algorithm::HashAlgorithm::STD, R"pbdoc( Compute the hash value of a string. - + Args: value: The string value to hash algorithm: The hash algorithm to use (default: STD) - + Returns: The computed hash value )pbdoc"); @@ -85,11 +85,11 @@ PYBIND11_MODULE(hash, m) { py::arg("algorithm") = atom::algorithm::HashAlgorithm::STD, R"pbdoc( Compute the hash value of an integer. - + Args: value: The integer value to hash algorithm: The hash algorithm to use (default: STD) - + Returns: The computed hash value )pbdoc"); @@ -104,11 +104,11 @@ PYBIND11_MODULE(hash, m) { py::arg("algorithm") = atom::algorithm::HashAlgorithm::STD, R"pbdoc( Compute the hash value of a float. - + Args: value: The float value to hash algorithm: The hash algorithm to use (default: STD) - + Returns: The computed hash value )pbdoc"); @@ -123,11 +123,11 @@ PYBIND11_MODULE(hash, m) { py::arg("algorithm") = atom::algorithm::HashAlgorithm::STD, R"pbdoc( Compute the hash value of a boolean. - + Args: value: The boolean value to hash algorithm: The hash algorithm to use (default: STD) - + Returns: The computed hash value )pbdoc"); @@ -143,11 +143,11 @@ PYBIND11_MODULE(hash, m) { py::arg("algorithm") = atom::algorithm::HashAlgorithm::STD, R"pbdoc( Compute the hash value of a bytes object. - + Args: value: The bytes object to hash algorithm: The hash algorithm to use (default: STD) - + Returns: The computed hash value )pbdoc"); @@ -168,10 +168,10 @@ PYBIND11_MODULE(hash, m) { py::arg("value"), R"pbdoc( Compute the hash value of a tuple. - + Args: value: The tuple to hash - + Returns: The computed hash value )pbdoc"); @@ -210,11 +210,11 @@ PYBIND11_MODULE(hash, m) { py::arg("value"), py::arg("parallel") = false, R"pbdoc( Compute the hash value of a list. - + Args: value: The list to hash parallel: Whether to use parallel processing for large lists (default: False) - + Returns: The computed hash value )pbdoc"); @@ -245,10 +245,10 @@ PYBIND11_MODULE(hash, m) { py::arg("value"), R"pbdoc( Compute the hash value of a dictionary. - + Args: value: The dictionary to hash - + Returns: The computed hash value )pbdoc"); @@ -275,10 +275,10 @@ PYBIND11_MODULE(hash, m) { py::arg("value"), R"pbdoc( Compute the hash value of a set. - + Args: value: The set to hash - + Returns: The computed hash value )pbdoc"); @@ -289,10 +289,10 @@ PYBIND11_MODULE(hash, m) { py::arg("value"), R"pbdoc( Compute the hash value of None. - + Args: value: None - + Returns: The hash value of None (0) )pbdoc"); @@ -306,11 +306,11 @@ PYBIND11_MODULE(hash, m) { py::arg("value"), py::arg("basis") = 2166136261u, R"pbdoc( Compute the FNV-1a hash of a string. - + Args: value: The string to hash basis: The initial basis value (default: 2166136261) - + Returns: The computed FNV-1a hash value )pbdoc"); @@ -320,13 +320,13 @@ PYBIND11_MODULE(hash, m) { py::arg("hash"), R"pbdoc( Combine two hash values into one. - + This function is useful for creating hash values for composite objects. - + Args: seed: The initial hash value hash: The hash value to combine with the seed - + Returns: The combined hash value )pbdoc"); @@ -336,12 +336,12 @@ PYBIND11_MODULE(hash, m) { py::arg("hash2"), py::arg("tolerance") = 0, R"pbdoc( Verify if two hash values match. - + Args: hash1: The first hash value hash2: The second hash value tolerance: Allowed difference for fuzzy matching (default: 0) - + Returns: True if the hashes match within the tolerance, False otherwise )pbdoc"); @@ -355,12 +355,12 @@ PYBIND11_MODULE(hash, m) { py::arg("str"), R"pbdoc( Compute the hash value of a string using the FNV-1a algorithm. - + This is equivalent to the _hash string literal operator in C++. - + Args: str: The string to hash - + Returns: The computed hash value )pbdoc"); @@ -396,12 +396,12 @@ PYBIND11_MODULE(hash, m) { py::arg("filename"), R"pbdoc( Generate a fast hash for a filename. - + This is useful for creating unique identifiers for files. - + Args: filename: The filename to hash - + Returns: The computed hash value )pbdoc"); @@ -438,11 +438,11 @@ PYBIND11_MODULE(hash, m) { py::arg("value"), py::arg("iterations") = 100000, R"pbdoc( Benchmark different hash algorithms. - + Args: value: The string to hash iterations: Number of iterations to run (default: 100000) - + Returns: A dictionary with algorithm names as keys and tuples (time, hash_value) as values )pbdoc"); @@ -498,15 +498,15 @@ PYBIND11_MODULE(hash, m) { py::arg("algorithm") = atom::algorithm::HashAlgorithm::STD, R"pbdoc( Analyze the distribution of hash values for a list of inputs. - + Args: values: The list of values to hash algorithm: The hash algorithm to use (default: STD) - + Returns: A dictionary with distribution metrics )pbdoc"); // Add version information m.attr("__version__") = "1.0.0"; -} \ No newline at end of file +} diff --git a/python/algorithm/huffman.cpp b/python/algorithm/huffman.cpp index d312bc40..9461b581 100644 --- a/python/algorithm/huffman.cpp +++ b/python/algorithm/huffman.cpp @@ -9,39 +9,39 @@ PYBIND11_MODULE(huffman, m) { m.doc() = R"pbdoc( Huffman Encoding and Compression ------------------------------- - + This module provides functions for compressing and decompressing data using Huffman encoding, an efficient variable-length prefix coding algorithm. - + **Basic Usage:** - + ```python from atom.algorithm.huffman import compress, decompress - + # Compress some data data = b"This is an example string with repeating characters" compressed_data, serialized_tree = compress(data) - + # Print compression statistics print(f"Original size: {len(data)} bytes") print(f"Compressed size: {len(compressed_data) // 8} bytes") print(f"Compression ratio: {len(compressed_data) / (len(data) * 8):.2%}") - + # Decompress the data decompressed_data = decompress(compressed_data, serialized_tree) - + # Verify the data matches assert data == decompressed_data ``` - + **Convenience Functions:** - + For simpler usage with built-in serialization: - + ```python from atom.algorithm.huffman import encode, decode - + compressed = encode(b"Hello, world!") original = decode(compressed) ``` @@ -95,13 +95,13 @@ PYBIND11_MODULE(huffman, m) { py::arg("frequencies"), R"pbdoc( Create a Huffman tree from a frequency map. - + Args: frequencies: A dictionary mapping bytes to their frequencies - + Returns: The root node of the Huffman tree - + Raises: RuntimeError: If the frequency map is empty )pbdoc"); @@ -116,13 +116,13 @@ PYBIND11_MODULE(huffman, m) { py::arg("root"), R"pbdoc( Generate a mapping of bytes to their Huffman codes. - + Args: root: The root node of the Huffman tree - + Returns: A dictionary mapping bytes to their Huffman codes (as strings of '0's and '1's) - + Raises: RuntimeError: If the root node is null )pbdoc"); @@ -131,14 +131,14 @@ PYBIND11_MODULE(huffman, m) { py::arg("huffman_codes"), R"pbdoc( Compress data using Huffman codes. - + Args: data: The data to compress as a bytes-like object huffman_codes: A dictionary mapping bytes to Huffman codes - + Returns: A string of '0's and '1's representing the compressed data - + Raises: RuntimeError: If a byte in the data doesn't have a corresponding Huffman code )pbdoc"); @@ -147,14 +147,14 @@ PYBIND11_MODULE(huffman, m) { py::arg("compressed_data"), py::arg("root"), R"pbdoc( Decompress Huffman-encoded data. - + Args: compressed_data: The compressed data as a string of '0's and '1's root: The root node of the Huffman tree - + Returns: The decompressed data as bytes - + Raises: RuntimeError: If the compressed data is invalid or the tree is null )pbdoc"); @@ -162,10 +162,10 @@ PYBIND11_MODULE(huffman, m) { m.def("serialize_tree", &atom::algorithm::serializeTree, py::arg("root"), R"pbdoc( Serialize a Huffman tree to a binary string. - + Args: root: The root node of the Huffman tree - + Returns: A string of '0's and '1's representing the serialized tree )pbdoc"); @@ -179,13 +179,13 @@ PYBIND11_MODULE(huffman, m) { py::arg("serialized_tree"), R"pbdoc( Deserialize a binary string back into a Huffman tree. - + Args: serialized_tree: The serialized tree as a string of '0's and '1's - + Returns: The root node of the reconstructed Huffman tree - + Raises: RuntimeError: If the serialized tree format is invalid )pbdoc"); @@ -194,11 +194,11 @@ PYBIND11_MODULE(huffman, m) { py::arg("root"), py::arg("indent") = "", R"pbdoc( Print a visualization of a Huffman tree. - + Args: root: The root node of the Huffman tree indent: The indentation to use (mostly for internal recursion) - + Note: This function prints to standard output and doesn't return anything. )pbdoc"); @@ -238,15 +238,15 @@ PYBIND11_MODULE(huffman, m) { py::arg("data"), R"pbdoc( Compress data using Huffman encoding. - + Args: data: The data to compress as a bytes-like object - + Returns: A tuple of (compressed_data, serialized_tree) where: - compressed_data: A string of '0's and '1's representing the compressed data - serialized_tree: A string of '0's and '1's representing the serialized Huffman tree - + Raises: RuntimeError: If compression fails )pbdoc"); @@ -271,14 +271,14 @@ PYBIND11_MODULE(huffman, m) { py::arg("compressed_data"), py::arg("serialized_tree"), R"pbdoc( Decompress Huffman-encoded data. - + Args: compressed_data: The compressed data as a string of '0's and '1's serialized_tree: The serialized Huffman tree as a string of '0's and '1's - + Returns: The decompressed data as bytes - + Raises: RuntimeError: If decompression fails )pbdoc"); @@ -348,13 +348,13 @@ PYBIND11_MODULE(huffman, m) { py::arg("data"), R"pbdoc( Compress data using Huffman encoding and pack everything into a single binary format. - + Args: data: The data to compress as a bytes-like object - + Returns: A bytes object containing the compressed data and Huffman tree - + Raises: RuntimeError: If compression fails )pbdoc"); @@ -427,13 +427,13 @@ PYBIND11_MODULE(huffman, m) { py::arg("encoded_data"), R"pbdoc( Decompress data that was compressed with the encode() function. - + Args: encoded_data: The encoded data as returned by encode() - + Returns: The original decompressed data as bytes - + Raises: ValueError: If the encoded data format is invalid RuntimeError: If decompression fails @@ -453,10 +453,10 @@ PYBIND11_MODULE(huffman, m) { py::arg("data"), R"pbdoc( Calculate the frequency of each byte in the data. - + Args: data: The data as a bytes-like object - + Returns: A dictionary mapping bytes to their frequencies )pbdoc"); @@ -473,11 +473,11 @@ PYBIND11_MODULE(huffman, m) { py::arg("original_data"), py::arg("compressed_bit_string"), R"pbdoc( Calculate the compression ratio (compressed size / original size). - + Args: original_data: The original uncompressed data compressed_bit_string: The compressed data as a string of '0's and '1's - + Returns: The compression ratio as a float (smaller is better) )pbdoc"); @@ -500,10 +500,10 @@ PYBIND11_MODULE(huffman, m) { py::arg("bit_string"), R"pbdoc( Convert a string of '0's and '1's to bytes. - + Args: bit_string: A string of '0's and '1's - + Returns: The packed bytes )pbdoc"); @@ -527,11 +527,11 @@ PYBIND11_MODULE(huffman, m) { py::arg("data"), py::arg("bit_count"), R"pbdoc( Convert bytes to a string of '0's and '1's. - + Args: data: The bytes to convert bit_count: The number of bits to extract - + Returns: A string of '0's and '1's )pbdoc"); @@ -577,11 +577,11 @@ PYBIND11_MODULE(huffman, m) { py::arg("codes"), R"pbdoc( Analyze the properties of a set of Huffman codes. - + Args: codes: A dictionary mapping bytes to Huffman codes - + Returns: A dictionary containing statistics about the codes )pbdoc"); -} \ No newline at end of file +} diff --git a/python/algorithm/md5.cpp b/python/algorithm/md5.cpp index 6eba9941..f881baf9 100644 --- a/python/algorithm/md5.cpp +++ b/python/algorithm/md5.cpp @@ -14,19 +14,19 @@ PYBIND11_MODULE(md5, m) { This module provides a modern, optimized implementation of the MD5 hashing algorithm with additional utility functions and binary data support. - + Example: >>> from atom.algorithm import md5 - >>> + >>> >>> # Compute MD5 hash of a string >>> hash_value = md5.encrypt("Hello, world!") >>> print(hash_value) '6cd3556deb0da54bca060b4c39479839' - + >>> # Verify a hash >>> md5.verify("Hello, world!", hash_value) True - + >>> # Compute hash of binary data >>> import os >>> binary_data = os.urandom(1024) @@ -42,13 +42,13 @@ PYBIND11_MODULE(md5, m) { py::arg("input"), R"pbdoc( Encrypts a string using the MD5 algorithm. - + Args: input: The input string to hash - + Returns: The MD5 hash as a lowercase hex string - + Raises: MD5Exception: If encryption fails )pbdoc"); @@ -57,11 +57,11 @@ PYBIND11_MODULE(md5, m) { py::arg("input"), py::arg("hash"), R"pbdoc( Verifies if a string matches a given MD5 hash. - + Args: input: The input string to check hash: The expected MD5 hash - + Returns: True if the hash of input matches the expected hash, False otherwise )pbdoc"); @@ -83,17 +83,17 @@ PYBIND11_MODULE(md5, m) { py::arg("data"), R"pbdoc( Computes MD5 hash for binary data. - + Args: data: Binary data (bytes, bytearray, or any buffer-like object) - + Returns: The MD5 hash as a lowercase hex string - + Raises: ValueError: If encryption fails )pbdoc"); // Add version information m.attr("__version__") = "1.0.0"; -} \ No newline at end of file +} diff --git a/python/algorithm/mhash.cpp b/python/algorithm/mhash.cpp index 21f40ba6..fe08b65e 100644 --- a/python/algorithm/mhash.cpp +++ b/python/algorithm/mhash.cpp @@ -25,21 +25,21 @@ PYBIND11_MODULE(mhash, m) { Optimized Hashing Algorithms --------------------------- - This module provides implementation of MinHash for similarity estimation + This module provides implementation of MinHash for similarity estimation and Keccak-256 cryptographic hash functions. - + The module includes: - MinHash implementation for estimating Jaccard similarity between sets - Keccak-256 cryptographic hash function (compatible with Ethereum's keccak256) - Utility functions for hex string conversion - + Example: >>> from atom.algorithm import mhash - >>> + >>> >>> # Computing Keccak-256 hash >>> h = mhash.keccak256("Hello, world!") >>> print(mhash.hash_to_hex(h)) - + >>> # Using MinHash for similarity estimation >>> minhash = mhash.MinHash(100) # 100 hash functions >>> sig1 = minhash.compute_signature(["a", "b", "c", "d"]) @@ -238,4 +238,4 @@ Jaccard index (similarity) between sets based on these signatures. // Constants m.attr("HASH_SIZE") = atom::algorithm::K_HASH_SIZE; -} \ No newline at end of file +} diff --git a/python/algorithm/pathfinding.cpp b/python/algorithm/pathfinding.cpp index 437754ed..e70f21a4 100644 --- a/python/algorithm/pathfinding.cpp +++ b/python/algorithm/pathfinding.cpp @@ -292,4 +292,4 @@ This combines Manhattan distance with diagonal shortcuts. ... ] >>> path = find_path_with_obstacles(obstacles, Point(0, 0), Point(4, 4)) )"); -} \ No newline at end of file +} diff --git a/python/algorithm/perlin.cpp b/python/algorithm/perlin.cpp index e1362f7f..d6fd0d7d 100644 --- a/python/algorithm/perlin.cpp +++ b/python/algorithm/perlin.cpp @@ -14,22 +14,22 @@ PYBIND11_MODULE(perlin, m) { This module provides a high-performance implementation of Perlin noise, with support for multiple octaves, persistence, and GPU acceleration. - + Features: - 1D, 2D, and 3D noise generation - Octave noise for more natural patterns - Noise map generation for terrain or texture creation - OpenCL acceleration when available - + Example: >>> from atom.algorithm.perlin import PerlinNoise - >>> + >>> >>> # Create a noise generator with a specific seed >>> noise = PerlinNoise(seed=42) - >>> + >>> >>> # Generate a single noise value >>> value = noise.noise(1.0, 2.0, 0.5) - >>> + >>> >>> # Generate a 2D noise map (e.g., for terrain) >>> noise_map = noise.generate_noise_map(256, 256, scale=25.0, octaves=4, persistence=0.5) )pbdoc"; @@ -52,14 +52,14 @@ PYBIND11_MODULE(perlin, m) { py::class_(m, "PerlinNoise", R"pbdoc( Perlin noise generator class. - + This class implements the improved Perlin noise algorithm for generating coherent noise in 1D, 2D, or 3D space. It can be used for procedural generation of terrain, textures, animations, etc. - + Constructor Args: seed: Optional random seed for noise generation (default: system random) - + Examples: >>> noise = PerlinNoise(seed=42) >>> value = noise.noise(x=1.0, y=2.0, z=3.0) @@ -75,15 +75,15 @@ PYBIND11_MODULE(perlin, m) { py::arg("x"), py::arg("y"), py::arg("z"), R"pbdoc( Generate a 3D Perlin noise value. - + Args: x: X-coordinate in noise space y: Y-coordinate in noise space z: Z-coordinate in noise space - + Returns: Noise value in range [0.0, 1.0] - + Example: >>> noise = PerlinNoise(seed=42) >>> value = noise.noise(0.5, 1.2, 0.8) @@ -97,14 +97,14 @@ PYBIND11_MODULE(perlin, m) { py::arg("x"), py::arg("y"), R"pbdoc( Generate a 2D Perlin noise value. - + Args: x: X-coordinate in noise space y: Y-coordinate in noise space - + Returns: Noise value in range [0.0, 1.0] - + Example: >>> noise = PerlinNoise(seed=42) >>> value = noise.noise_2d(0.5, 1.2) @@ -118,13 +118,13 @@ PYBIND11_MODULE(perlin, m) { py::arg("x"), R"pbdoc( Generate a 1D Perlin noise value. - + Args: x: X-coordinate in noise space - + Returns: Noise value in range [0.0, 1.0] - + Example: >>> noise = PerlinNoise(seed=42) >>> value = noise.noise_1d(0.5) @@ -139,17 +139,17 @@ PYBIND11_MODULE(perlin, m) { py::arg("persistence"), R"pbdoc( Generate fractal noise by summing multiple octaves of Perlin noise. - + Args: x: X-coordinate in noise space y: Y-coordinate in noise space z: Z-coordinate in noise space octaves: Number of noise layers to sum persistence: Amplitude multiplier for each octave (0.0-1.0) - + Returns: Octave noise value in range [0.0, 1.0] - + Example: >>> noise = PerlinNoise(seed=42) >>> value = noise.octave_noise(0.5, 1.2, 0.8, octaves=4, persistence=0.5) @@ -164,13 +164,13 @@ PYBIND11_MODULE(perlin, m) { py::arg("persistence"), R"pbdoc( Generate 2D fractal noise by summing multiple octaves of Perlin noise. - + Args: x: X-coordinate in noise space y: Y-coordinate in noise space octaves: Number of noise layers to sum persistence: Amplitude multiplier for each octave (0.0-1.0) - + Returns: Octave noise value in range [0.0, 1.0] )pbdoc") @@ -202,9 +202,9 @@ PYBIND11_MODULE(perlin, m) { py::arg("seed") = std::default_random_engine::default_seed, R"pbdoc( Generate a 2D noise map. - + This is useful for terrain generation, textures, or other 2D applications. - + Args: width: Width of the noise map height: Height of the noise map @@ -213,17 +213,17 @@ PYBIND11_MODULE(perlin, m) { persistence: Amplitude reduction per octave (0.0-1.0) lacunarity: Frequency multiplier per octave (default: 2.0) seed: Random seed for noise map generation (default: uses object's seed) - + Returns: 2D numpy array of noise values in range [0.0, 1.0] - + Example: >>> noise = PerlinNoise(seed=42) >>> terrain = noise.generate_noise_map( - ... width=256, height=256, + ... width=256, height=256, ... scale=50.0, octaves=4, persistence=0.5 ... ) - >>> + >>> >>> # You can visualize it with matplotlib: >>> import matplotlib.pyplot as plt >>> plt.imshow(terrain, cmap='terrain') @@ -245,7 +245,7 @@ PYBIND11_MODULE(perlin, m) { py::arg("seed") = std::default_random_engine::default_seed, R"pbdoc( Convenience function to create a fractal noise map in one call. - + Args: width: Width of the noise map height: Height of the noise map @@ -254,7 +254,7 @@ PYBIND11_MODULE(perlin, m) { persistence: Amplitude reduction per octave (0.0-1.0) lacunarity: Frequency multiplier per octave (default: 2.0) seed: Random seed for noise map generation - + Returns: 2D numpy array of noise values in range [0.0, 1.0] )pbdoc"); @@ -268,4 +268,4 @@ PYBIND11_MODULE(perlin, m) { // Add version information m.attr("__version__") = "1.0.0"; -} \ No newline at end of file +} diff --git a/python/algorithm/rust_numeric.cpp b/python/algorithm/rust_numeric.cpp index 4bf9db46..b89317a8 100644 --- a/python/algorithm/rust_numeric.cpp +++ b/python/algorithm/rust_numeric.cpp @@ -357,7 +357,7 @@ PYBIND11_MODULE(rust_numeric, m) { m.attr("__doc__") = R"( Rust-like numeric types and utilities for Python - This module provides Rust-inspired numeric types and operations with + This module provides Rust-inspired numeric types and operations with controlled overflow behavior, checked arithmetic, and error handling patterns. Examples: @@ -369,7 +369,7 @@ PYBIND11_MODULE(rust_numeric, m) { >>> else: >>> print(result.unwrap_err()) 123 - + >>> # Check for overflow when adding >>> option = I32.checked_add(2147483647, 1) # MAX_INT32 + 1 >>> if option.is_some(): @@ -377,12 +377,12 @@ PYBIND11_MODULE(rust_numeric, m) { >>> else: >>> print("Overflow occurred") Overflow occurred - + >>> # Saturating operations (clamping to min/max) >>> saturated = I32.saturating_add(2147483647, 1000) >>> print(saturated) 2147483647 - + >>> # Working with ranges >>> from atom.algorithm.rust_numeric import range, range_inclusive >>> r = range(1, 5) # 1, 2, 3, 4 @@ -393,4 +393,4 @@ PYBIND11_MODULE(rust_numeric, m) { 3 4 )"; -} \ No newline at end of file +} diff --git a/python/algorithm/sha1.cpp b/python/algorithm/sha1.cpp index 0c813939..2fd3f8a6 100644 --- a/python/algorithm/sha1.cpp +++ b/python/algorithm/sha1.cpp @@ -19,31 +19,31 @@ PYBIND11_MODULE(sha1, m) { -------------------------------------- This module provides a SHA-1 hash implementation conforming to FIPS PUB 180-4. - + The SHA1 class allows incremental updates to compute the hash of large data, and supports both raw byte arrays and higher-level containers as input. - + Note: While SHA-1 is no longer considered secure for cryptographic purposes, it remains useful for non-security applications like data integrity checks. Example: >>> from atom.algorithm import sha1 - >>> + >>> >>> # Create a new SHA1 hash object >>> hasher = sha1.SHA1() - >>> + >>> >>> # Update with data >>> hasher.update(b"Hello") >>> hasher.update(b", World!") - >>> + >>> >>> # Get digest as bytes >>> digest_bytes = hasher.digest_bytes() >>> print(digest_bytes.hex()) - >>> + >>> >>> # Or as a hex string >>> digest_str = hasher.digest_string() >>> print(digest_str) - >>> + >>> >>> # One-step hashing convenience function >>> hash_value = sha1.compute_hash("Hello, World!") )pbdoc"; @@ -72,18 +72,18 @@ It supports incremental updates, allowing the hash of large data to be computed Examples: >>> from atom.algorithm.sha1 import SHA1 - >>> + >>> >>> # Create a new hash object >>> hasher = SHA1() - >>> + >>> >>> # Update with data incrementally >>> hasher.update(b"Hello") >>> hasher.update(b", World!") - >>> + >>> >>> # Get the digest as a hexadecimal string >>> digest = hasher.digest_string() >>> print(digest) - >>> + >>> >>> # Reset and start a new hash >>> hasher.reset() >>> hasher.update(b"New data") @@ -369,4 +369,4 @@ for hashing new data. >>> # Print the hash of the first item >>> print(bytes_to_hex(hashes[0])) )"); -} \ No newline at end of file +} diff --git a/python/algorithm/snowflake.cpp b/python/algorithm/snowflake.cpp index cc453462..d6aad236 100644 --- a/python/algorithm/snowflake.cpp +++ b/python/algorithm/snowflake.cpp @@ -25,32 +25,32 @@ PYBIND11_MODULE(snowflake, m) { ----------------------- This module provides a distributed ID generator based on Twitter's Snowflake algorithm. - + The Snowflake algorithm generates 64-bit unique IDs that are: - Time-based (roughly sortable by generation time) - Distributed (different workers/datacenter IDs produce different ranges) - High-performance (can generate thousands of IDs per second per node) - + The generated IDs are composed of: - Timestamp (milliseconds since a custom epoch) - Datacenter ID (5 bits) - Worker ID (5 bits) - Sequence number (12 bits, for multiple IDs in the same millisecond) - + Example: >>> from atom.algorithm import snowflake - >>> + >>> >>> # Create a generator with worker_id=1, datacenter_id=2 >>> generator = snowflake.SnowflakeGenerator(1, 2) - >>> + >>> >>> # Generate a single ID >>> id = generator.next_id() >>> print(id) - + >>> # Generate multiple IDs at once >>> ids = generator.next_ids(5) # Generate 5 IDs >>> print(ids) - + >>> # Extract timestamp from an ID >>> timestamp = generator.extract_timestamp(id) >>> print(timestamp) @@ -304,4 +304,4 @@ The Snowflake algorithm generates 64-bit IDs composed of: atom::algorithm::Snowflake::SEQUENCE_BITS; m.attr("TWEPOCH") = atom::algorithm::Snowflake::TWEPOCH; -} \ No newline at end of file +} diff --git a/python/algorithm/tea.cpp b/python/algorithm/tea.cpp index 8462b42c..5de706e6 100644 --- a/python/algorithm/tea.cpp +++ b/python/algorithm/tea.cpp @@ -469,4 +469,4 @@ This is a convenience function that handles conversion between byte data and 32- >>> print(key) >>> encrypted = encrypt_bytes(b"Secret message", key) )"); -} \ No newline at end of file +} diff --git a/python/algorithm/weight.cpp b/python/algorithm/weight.cpp index 6fb97f95..1ad131fa 100644 --- a/python/algorithm/weight.cpp +++ b/python/algorithm/weight.cpp @@ -80,15 +80,15 @@ This class provides methods for weighted random selection with different probabi Examples: >>> from atom.algorithm.weight import WeightSelectorFloat, SelectionStrategyFloat - >>> + >>> >>> # Create a selector with default strategy >>> selector = WeightSelectorFloat([1.0, 2.0, 3.0, 4.0]) - >>> + >>> >>> # Select an index based on weights >>> selected_index = selector.select() >>> >>> # Use bottom-heavy distribution (favors lower weights) - >>> selector2 = WeightSelectorFloat([1.0, 2.0, 3.0, 4.0], + >>> selector2 = WeightSelectorFloat([1.0, 2.0, 3.0, 4.0], >>> strategy=SelectionStrategyFloat.BOTTOM_HEAVY) >>> >>> # Multiple selections without replacement @@ -192,7 +192,7 @@ This class provides methods for weighted random selection with different probabi Raises: ValueError: If resulting weights are negative - + Examples: >>> # Double all weights >>> selector.apply_function_to_weights(lambda w: w * 2) @@ -372,15 +372,15 @@ This class provides methods for weighted random sampling with or without replace Args: seed: Optional random seed for reproducible sampling - + Examples: >>> from atom.algorithm.weight import WeightedRandomSamplerFloat - >>> + >>> >>> sampler = WeightedRandomSamplerFloat(seed=42) - >>> + >>> >>> # Sample 3 indices with replacement >>> indices1 = sampler.sample([1.0, 2.0, 3.0, 4.0], 3) - >>> + >>> >>> # Sample 2 unique indices (no replacement) >>> indices2 = sampler.sample_unique([1.0, 2.0, 3.0, 4.0], 2) )") @@ -395,7 +395,7 @@ This class provides methods for weighted random sampling with or without replace Returns: List of sampled indices - + Raises: ValueError: If weights is empty )") @@ -410,7 +410,7 @@ This class provides methods for weighted random sampling with or without replace Returns: List of sampled indices - + Raises: ValueError: If n is greater than the number of weights or if weights is empty )"); @@ -444,32 +444,32 @@ PYBIND11_MODULE(weight, m) { Weighted Random Selection Algorithms ----------------------------------- - This module provides flexible weighted random selection algorithms with + This module provides flexible weighted random selection algorithms with multiple probability distributions and thread-safe operations. - + The module includes: - Various selection strategies (uniform, bottom-heavy, top-heavy, etc.) - Methods for selecting with and without replacement - Thread-safe weight updates and manipulations - Utilities for normalizing and transforming weights - Detailed statistics and weight information - + Example: >>> from atom.algorithm import weight - >>> + >>> >>> # Create a selector with weights >>> selector = weight.WeightSelectorFloat([1.0, 2.0, 3.0, 4.0]) - >>> + >>> >>> # Select an index based on weights >>> selected_idx = selector.select() >>> print(selected_idx) - + >>> # Select using a bottom-heavy distribution >>> selector2 = weight.WeightSelectorFloat( - >>> [1.0, 2.0, 3.0, 4.0], + >>> [1.0, 2.0, 3.0, 4.0], >>> strategy=weight.SelectionStrategyFloat.BOTTOM_HEAVY >>> ) - >>> + >>> >>> # Select multiple unique indices >>> indices = selector.select_unique_multiple(2) )pbdoc"; @@ -551,7 +551,7 @@ The function automatically selects the WeightSelector type based on the input we Examples: >>> # Create a selector with integer weights >>> int_selector = weight.create_selector([1, 2, 3, 4]) - >>> + >>> >>> # Create a selector with float weights and power law distribution >>> float_selector = weight.create_selector( >>> [1.0, 2.0, 3.0, 4.0], @@ -559,4 +559,4 @@ The function automatically selects the WeightSelector type based on the input we >>> exponent=1.5 >>> ) )"); -} \ No newline at end of file +} diff --git a/python/async/__init__.py b/python/async/__init__.py index 879c3789..ce38ef10 100644 --- a/python/async/__init__.py +++ b/python/async/__init__.py @@ -1 +1 @@ -# Auto-generated __init__.py for async module \ No newline at end of file +# Auto-generated __init__.py for async module diff --git a/python/async/async.cpp b/python/async/async.cpp index 2af85e5a..c469b9f6 100644 --- a/python/async/async.cpp +++ b/python/async/async.cpp @@ -297,10 +297,10 @@ void declare_async_retry(py::module& m, const std::string& suffix) { callback: Callback function called on success (default: no-op) exception_handler: Handler called when exceptions occur (default: no-op) complete_handler: Handler called when all attempts complete (default: no-op) - + Returns: A future with the result of the async operation - + Raises: ValueError: If invalid parameters are provided )pbdoc"); @@ -311,36 +311,36 @@ PYBIND11_MODULE(async, m) { Asynchronous Task Processing Module ---------------------------------- - This module provides tools for executing tasks asynchronously with + This module provides tools for executing tasks asynchronously with features like timeouts, callbacks, and task management. - + Key components: - AsyncWorker: Manages a single asynchronous task - AsyncWorkerManager: Coordinates multiple async workers - Task/Future wrappers: Enhanced futures with additional capabilities - Retry mechanisms: Automatic retry with configurable backoff strategies - + Example: >>> from atom.async import AsyncWorkerInt, AsyncWorkerManagerInt - >>> + >>> >>> # Create a worker and start a task >>> worker = AsyncWorkerInt() >>> worker.start_async(lambda: 42) - >>> + >>> >>> # Get the result (with optional timeout) >>> result = worker.get_result(timeout=5000) # 5 seconds timeout >>> print(result) # Output: 42 - >>> + >>> >>> # Create a worker manager for multiple tasks >>> manager = AsyncWorkerManagerInt() >>> workers = [ - >>> manager.create_worker(lambda: i * 10) + >>> manager.create_worker(lambda: i * 10) >>> for i in range(5) >>> ] - >>> + >>> >>> # Wait for all tasks to complete >>> manager.wait_for_all() - >>> + >>> >>> # Collect results >>> results = [w.get_result() for w in workers] >>> print(results) # Output: [0, 10, 20, 30, 40] @@ -417,14 +417,14 @@ PYBIND11_MODULE(async, m) { py::arg("future"), py::arg("timeout"), R"pbdoc( Gets the result of a future with a timeout. - + Args: future: The future to get the result from timeout: The timeout in seconds - + Returns: The result of the future - + Raises: TimeoutException: If the timeout is reached )pbdoc"); @@ -438,4 +438,4 @@ PYBIND11_MODULE(async, m) { // Add version information m.attr("__version__") = "1.0.0"; -} \ No newline at end of file +} diff --git a/python/async/async_executor.cpp b/python/async/async_executor.cpp index c346fd79..86f785eb 100644 --- a/python/async/async_executor.cpp +++ b/python/async/async_executor.cpp @@ -11,30 +11,30 @@ PYBIND11_MODULE(async_executor, m) { Advanced Async Task Executor --------------------------- - This module provides a high-performance asynchronous task executor with + This module provides a high-performance asynchronous task executor with thread pooling, priority-based scheduling, and multiple execution strategies. - + The module includes: - Thread pool with dynamic resizing - Priority-based task scheduling (LOW, NORMAL, HIGH, CRITICAL) - Various execution strategies (IMMEDIATE, DEFERRED, SCHEDULED) - Task cancellation support - Wait for completion functionality - + Example: >>> from atom.async.async_executor import AsyncExecutor, ExecutionStrategy, TaskPriority - >>> + >>> >>> # Create an executor with 4 threads >>> executor = AsyncExecutor(4) - >>> + >>> >>> # Schedule a task for immediate execution with normal priority >>> future = executor.schedule( - >>> ExecutionStrategy.IMMEDIATE, + >>> ExecutionStrategy.IMMEDIATE, >>> TaskPriority.NORMAL, - >>> lambda x: x * 2, + >>> lambda x: x * 2, >>> 10 >>> ) - >>> + >>> >>> # Get the result when ready >>> result = future.result() >>> print(result) # Outputs: 20 @@ -110,12 +110,12 @@ with different execution strategies and priorities. Examples: >>> executor = AsyncExecutor(4) # Create an executor with 4 threads - >>> + >>> >>> # Schedule an immediate task >>> future = executor.schedule( - >>> ExecutionStrategy.IMMEDIATE, + >>> ExecutionStrategy.IMMEDIATE, >>> TaskPriority.NORMAL, - >>> lambda x: x * 2, + >>> lambda x: x * 2, >>> 10 >>> ) >>> @@ -205,4 +205,4 @@ with different execution strategies and priorities. // Add version information m.attr("__version__") = "1.0.0"; -} \ No newline at end of file +} diff --git a/python/async/daemon.cpp b/python/async/daemon.cpp index bfcd8b05..bfccccfe 100644 --- a/python/async/daemon.cpp +++ b/python/async/daemon.cpp @@ -15,27 +15,27 @@ PYBIND11_MODULE(daemon, m) { This module provides tools for creating and managing daemon processes on both Unix-like systems and Windows. - + Features: - Create daemon processes that run in the background - Monitor and control daemon processes - Handle daemon restarts and failure recovery - Manage daemon PID files - + Example: >>> from atom.async.daemon import DaemonGuard, check_pid_file, write_pid_file - >>> + >>> >>> # Check if daemon is already running >>> if not check_pid_file("my-daemon"): >>> # Create a daemon process >>> daemon = DaemonGuard() - >>> + >>> >>> # Define the main process function >>> def main_process(argc, argv): >>> # Your daemon code here >>> write_pid_file("my-daemon") >>> return 0 - >>> + >>> >>> # Start the daemon >>> daemon.start_daemon(0, [], main_process, True) )pbdoc"; @@ -65,18 +65,18 @@ PYBIND11_MODULE(daemon, m) { py::class_(m, "DaemonGuard", R"pbdoc( Class for managing daemon processes. - + This class provides methods to start, monitor and control daemon processes on both Unix-like systems and Windows. - + Examples: >>> daemon = DaemonGuard() - >>> + >>> >>> # Define the main process function >>> def main_process(argc, argv): >>> # Your daemon code here >>> return 0 - >>> + >>> >>> # Start a daemon process >>> daemon.start_daemon(0, [], main_process, True) )pbdoc") @@ -112,15 +112,15 @@ PYBIND11_MODULE(daemon, m) { py::arg("argc"), py::arg("argv"), py::arg("main_cb"), R"pbdoc( Starts a child process to execute the actual task. - + Args: argc: The number of command line arguments argv: A list of command line arguments main_cb: The main callback function to be executed in the child process - + Returns: The return value of the main callback function - + Raises: DaemonException: If process creation fails )pbdoc") @@ -151,15 +151,15 @@ PYBIND11_MODULE(daemon, m) { py::arg("argc"), py::arg("argv"), py::arg("main_cb"), R"pbdoc( Starts a child process as a daemon to execute the actual task. - + Args: argc: The number of command line arguments argv: A list of command line arguments main_cb: The main callback function to be executed in the daemon process - + Returns: The return value of the main callback function - + Raises: DaemonException: If daemon process creation fails )pbdoc") @@ -192,18 +192,18 @@ PYBIND11_MODULE(daemon, m) { py::arg("argc"), py::arg("argv"), py::arg("main_cb"), py::arg("is_daemon"), R"pbdoc( - Starts the process. If a daemon process needs to be created, + Starts the process. If a daemon process needs to be created, it will create the daemon process first. - + Args: argc: The number of command line arguments argv: A list of command line arguments main_cb: The main callback function to be executed is_daemon: Determines if a daemon process should be created - + Returns: The return value of the main callback function - + Raises: DaemonException: If process creation fails )pbdoc") @@ -224,10 +224,10 @@ PYBIND11_MODULE(daemon, m) { py::arg("file_path") = "lithium-daemon", R"pbdoc( Writes the process ID to a file. - + Args: file_path: Path to write the PID file (default: "lithium-daemon") - + Raises: OSError: If file operation fails )pbdoc"); @@ -240,10 +240,10 @@ PYBIND11_MODULE(daemon, m) { py::arg("file_path") = "lithium-daemon", R"pbdoc( Checks if the process ID file exists and the process is running. - + Args: file_path: Path to the PID file (default: "lithium-daemon") - + Returns: True if the PID file exists and the process is running, False otherwise )pbdoc"); @@ -252,10 +252,10 @@ PYBIND11_MODULE(daemon, m) { py::arg("seconds"), R"pbdoc( Sets the restart interval for daemon processes. - + Args: seconds: Interval in seconds - + Raises: ValueError: If seconds is less than or equal to zero )pbdoc"); @@ -272,4 +272,4 @@ PYBIND11_MODULE(daemon, m) { // Add version information m.attr("__version__") = "1.0.0"; -} \ No newline at end of file +} diff --git a/python/async/eventstack.cpp b/python/async/eventstack.cpp index acc48a05..857189ff 100644 --- a/python/async/eventstack.cpp +++ b/python/async/eventstack.cpp @@ -24,26 +24,26 @@ void declare_event_stack(py::module& m, const std::string& type_name) { Args: None (default constructor) - + Examples: >>> from atom.async.eventstack import EventStackInt - >>> + >>> >>> # Create an event stack >>> stack = EventStackInt() - >>> + >>> >>> # Add some events >>> stack.push_event(42) >>> stack.push_event(100) >>> stack.push_event(7) - >>> + >>> >>> # Access the top event without removing it >>> top = stack.peek_top_event() >>> print(top) # Output: 7 - >>> + >>> >>> # Pop an event >>> event = stack.pop_event() >>> print(event) # Output: 7 - >>> + >>> >>> # Check size >>> print(len(stack)) # Output: 2 )pbdoc") @@ -55,35 +55,35 @@ void declare_event_stack(py::module& m, const std::string& type_name) { /* .def(py::init(), py::arg("other"), "Move constructor - creates a new stack by taking ownership of " - "another stack") + "another stack") */ - + // Core stack operations .def("push_event", &EventStackType::pushEvent, py::arg("event"), R"pbdoc( Pushes an event onto the stack. - + Args: event: The event to push onto the stack - + Raises: RuntimeError: If memory allocation fails )pbdoc") .def("pop_event", &EventStackType::popEvent, R"pbdoc( Pops an event from the stack. - + Returns: The popped event, or None if the stack is empty )pbdoc") .def("peek_top_event", &EventStackType::peekTopEvent, R"pbdoc( Returns the top event in the stack without removing it. - + Returns: The top event, or None if the stack is empty - + Raises: RuntimeError: If the stack is empty and exceptions are enabled )pbdoc") @@ -110,11 +110,11 @@ void declare_event_stack(py::module& m, const std::string& type_name) { py::arg("predicate"), R"pbdoc( Filters events based on a custom filter function. - + Args: predicate: A function that takes an event and returns a boolean. Events are kept if the function returns True. - + Examples: >>> # Keep only events greater than 50 >>> stack.filter_events(lambda event: event > 50) @@ -130,13 +130,13 @@ void declare_event_stack(py::module& m, const std::string& type_name) { py::arg("predicate"), R"pbdoc( Finds the first event that satisfies a predicate. - + Args: predicate: A function that takes an event and returns a boolean - + Returns: The first event satisfying the predicate, or None if not found - + Examples: >>> # Find first event divisible by 10 >>> event = stack.find_event(lambda e: e % 10 == 0) @@ -154,13 +154,13 @@ void declare_event_stack(py::module& m, const std::string& type_name) { py::arg("predicate"), R"pbdoc( Counts the number of events that satisfy a predicate. - + Args: predicate: A function that takes an event and returns a boolean - + Returns: The count of events satisfying the predicate - + Examples: >>> # Count events less than 100 >>> count = stack.count_events(lambda e: e < 100) @@ -176,10 +176,10 @@ void declare_event_stack(py::module& m, const std::string& type_name) { py::arg("predicate"), R"pbdoc( Checks if any event in the stack satisfies a predicate. - + Args: predicate: A function that takes an event and returns a boolean - + Returns: True if any event satisfies the predicate, False otherwise )pbdoc") @@ -194,10 +194,10 @@ void declare_event_stack(py::module& m, const std::string& type_name) { py::arg("predicate"), R"pbdoc( Checks if all events in the stack satisfy a predicate. - + Args: predicate: A function that takes an event and returns a boolean - + Returns: True if all events satisfy the predicate, False otherwise )pbdoc") @@ -217,10 +217,10 @@ void declare_event_stack(py::module& m, const std::string& type_name) { py::arg("transform_func"), R"pbdoc( Transforms events using the provided function. - + Args: transform_func: A function that takes an event and returns a new event or None - + Examples: >>> # Double all event values >>> stack.transform_events(lambda e: e * 2) @@ -236,11 +236,11 @@ void declare_event_stack(py::module& m, const std::string& type_name) { py::arg("compare_func"), R"pbdoc( Sorts the events in the stack based on a custom comparison function. - + Args: compare_func: A function that takes two events and returns a boolean. Returns true if the first argument should be placed before the second. - + Examples: >>> # Sort in descending order >>> stack.sort_events(lambda a, b: a > b) @@ -260,10 +260,10 @@ void declare_event_stack(py::module& m, const std::string& type_name) { py::arg("func"), R"pbdoc( Applies a function to each event in the stack. - + Args: func: A function to apply to each event - + Examples: >>> # Print each event >>> stack.for_each(lambda e: print(e)) @@ -293,7 +293,7 @@ PYBIND11_MODULE(eventstack, m) { This module provides a thread-safe stack data structure for managing events with support for various filtering, transformation, and querying operations. - + Features: - Thread-safe event storage with LIFO (Last In, First Out) semantics - Atomic operations for push, pop, and peek @@ -301,32 +301,32 @@ PYBIND11_MODULE(eventstack, m) { - Search functionality - Statistical queries - Support for various data types - + The module includes implementations for common data types: - EventStackInt: For integer events - - EventStackFloat: For floating-point events + - EventStackFloat: For floating-point events - EventStackString: For string events - EventStackBool: For boolean events - + Example: >>> from atom.async.eventstack import EventStackInt - >>> + >>> >>> # Create an event stack >>> stack = EventStackInt() - >>> + >>> >>> # Add events >>> for i in range(10): >>> stack.push_event(i) - >>> + >>> >>> # Check if any event satisfies a condition >>> has_even = stack.any_event(lambda e: e % 2 == 0) >>> print(f"Has even numbers: {has_even}") - >>> + >>> >>> # Find an event >>> five = stack.find_event(lambda e: e == 5) >>> if five is not None: >>> print(f"Found: {five}") - >>> + >>> >>> # Filter events >>> stack.filter_events(lambda e: e > 5) >>> print(f"Events after filtering: {stack.size()}") @@ -386,22 +386,22 @@ PYBIND11_MODULE(eventstack, m) { py::arg("sample_event"), R"pbdoc( Factory function to create an appropriate EventStack based on the input type. - + Args: sample_event: An example event of the type you want to store (used only to determine the type) - + Returns: A new EventStack of the appropriate type - + Raises: TypeError: If the event type is not supported - + Examples: >>> # Create an integer event stack >>> int_stack = create_event_stack(42) - >>> - >>> # Create a string event stack + >>> + >>> # Create a string event stack >>> str_stack = create_event_stack("hello") )pbdoc"); @@ -414,4 +414,4 @@ PYBIND11_MODULE(eventstack, m) { #else m.attr("PARALLEL_EXECUTION_SUPPORTED") = false; #endif -} \ No newline at end of file +} diff --git a/python/async/future.cpp b/python/async/future.cpp index c002a638..9054056e 100644 --- a/python/async/future.cpp +++ b/python/async/future.cpp @@ -19,25 +19,25 @@ void declare_enhanced_future(py::module& m, const std::string& type_name) { py::class_(m, class_name.c_str(), R"pbdoc( Enhanced future class with additional functionality beyond standard futures. - - This class extends std::future with features like chaining operations, + + This class extends std::future with features like chaining operations, callbacks, timeouts, cancellation, and more. - + Args: future: A shared_future to wrap (typically created by makeEnhancedFuture) - + Examples: >>> from atom.async.future import makeEnhancedFuture - >>> + >>> >>> # Create an enhanced future >>> future = makeEnhancedFuture(lambda: 42) - >>> + >>> >>> # Chain operations >>> result_future = future.then(lambda x: x * 2) - >>> + >>> >>> # Add completion callback >>> future.on_complete(lambda x: print(f"Result: {x}")) - >>> + >>> >>> # Get result with timeout >>> result = future.wait_for(5000) # 5 seconds timeout )pbdoc") @@ -48,10 +48,10 @@ void declare_enhanced_future(py::module& m, const std::string& type_name) { .def("wait", &EnhancedFutureT::wait, R"pbdoc( Waits synchronously for the future to complete. - + Returns: The value of the future. - + Raises: RuntimeError: If the future is cancelled or throws an exception. )pbdoc") @@ -64,10 +64,10 @@ void declare_enhanced_future(py::module& m, const std::string& type_name) { py::arg("timeout"), R"pbdoc( Waits for the future with a timeout and auto-cancels if not ready. - + Args: timeout: The timeout duration in milliseconds - + Returns: The value if ready, or None if timed out )pbdoc") @@ -77,10 +77,10 @@ void declare_enhanced_future(py::module& m, const std::string& type_name) { .def("get", &EnhancedFutureT::get, R"pbdoc( Gets the result of the future. - + Returns: The value of the future. - + Raises: RuntimeError: If the future is cancelled or throws an exception. )pbdoc") @@ -107,13 +107,13 @@ void declare_enhanced_future(py::module& m, const std::string& type_name) { py::arg("func"), R"pbdoc( Chains another operation to be called after the future is done. - + Args: func: The function to call when the future is done - + Returns: A new EnhancedFuture for the result of the function - + Examples: >>> future = makeEnhancedFuture(lambda: 10) >>> future2 = future.then(lambda x: x * 2) @@ -137,17 +137,17 @@ void declare_enhanced_future(py::module& m, const std::string& type_name) { py::arg("func"), R"pbdoc( Provides exception handling for the future. - + Args: func: The function to call when an exception occurs - + Returns: A new EnhancedFuture that will handle exceptions - + Examples: >>> def might_fail(): >>> raise ValueError("Something went wrong") - >>> + >>> >>> future = makeEnhancedFuture(might_fail) >>> safe_future = future.catching(lambda err: f"Error: {err}") >>> result = safe_future.get() # Will be "Error: Something went wrong" @@ -168,15 +168,15 @@ void declare_enhanced_future(py::module& m, const std::string& type_name) { py::arg("backoff_ms") = py::none(), R"pbdoc( Retries the operation associated with the future. - + Args: func: The function to call when retrying max_retries: The maximum number of retries backoff_ms: Optional backoff time between retries in milliseconds - + Returns: A new EnhancedFuture for the retry operation - + Examples: >>> future = makeEnhancedFuture(lambda: 10) >>> retry_future = future.retry(lambda x: x * 2, 3, 100) @@ -193,10 +193,10 @@ void declare_enhanced_future(py::module& m, const std::string& type_name) { py::arg("callback"), R"pbdoc( Sets a completion callback to be called when the future is done. - + Args: callback: The callback function to add - + Examples: >>> future = makeEnhancedFuture(lambda: 42) >>> future.on_complete(lambda x: print(f"Result: {x}")) @@ -211,22 +211,22 @@ void declare_enhanced_future_void(py::module& m) { py::class_(m, "EnhancedFutureVoid", R"pbdoc( Enhanced future class for void operations. - - This class extends std::future with features like chaining operations, + + This class extends std::future with features like chaining operations, callbacks, timeouts, cancellation, and more. - + Args: future: A shared_future to wrap (typically created by makeEnhancedFuture) - + Examples: >>> from atom.async.future import makeEnhancedFuture - >>> + >>> >>> # Create a void enhanced future >>> future = makeEnhancedFuture(lambda: None) - >>> + >>> >>> # Chain operations >>> result_future = future.then(lambda: "Operation completed") - >>> + >>> >>> # Add completion callback >>> future.on_complete(lambda: print("Done!")) )pbdoc") @@ -237,7 +237,7 @@ void declare_enhanced_future_void(py::module& m) { .def("wait", &EnhancedFutureVoid::wait, R"pbdoc( Waits synchronously for the future to complete. - + Raises: RuntimeError: If the future is cancelled or throws an exception. )pbdoc") @@ -247,10 +247,10 @@ void declare_enhanced_future_void(py::module& m) { py::arg("timeout"), R"pbdoc( Waits for the future with a timeout and auto-cancels if not ready. - + Args: timeout: The timeout duration in milliseconds - + Returns: True if completed successfully, False if timed out )pbdoc") @@ -259,7 +259,7 @@ void declare_enhanced_future_void(py::module& m) { .def("get", &EnhancedFutureVoid::get, R"pbdoc( Waits for the future to complete. - + Raises: RuntimeError: If the future is cancelled or throws an exception. )pbdoc") @@ -286,13 +286,13 @@ void declare_enhanced_future_void(py::module& m) { py::arg("func"), R"pbdoc( Chains another operation to be called after the future is done. - + Args: func: The function to call when the future is done - + Returns: A new EnhancedFuture for the result of the function - + Examples: >>> future = makeEnhancedFuture(lambda: None) >>> future2 = future.then(lambda: "Done!") @@ -310,10 +310,10 @@ void declare_enhanced_future_void(py::module& m) { py::arg("callback"), R"pbdoc( Sets a completion callback to be called when the future is done. - + Args: callback: The callback function to add - + Examples: >>> future = makeEnhancedFuture(lambda: None) >>> future.on_complete(lambda: print("Task completed!")) @@ -328,27 +328,27 @@ PYBIND11_MODULE(future, m) { This module provides enhanced future classes with additional functionality beyond standard futures, including chaining operations, callbacks, timeouts, cancellation support, and more. - + Key components: - EnhancedFuture: Extended future with additional functionality - makeEnhancedFuture: Factory function to create enhanced futures - whenAll: Synchronization for multiple futures - parallelProcess: Utility for parallel data processing - + Example: >>> from atom.async.future import makeEnhancedFuture, whenAll - >>> + >>> >>> # Create enhanced futures >>> future1 = makeEnhancedFuture(lambda: 10) >>> future2 = makeEnhancedFuture(lambda: 20) - >>> + >>> >>> # Chain operations >>> future3 = future1.then(lambda x: x * 2) - >>> + >>> >>> # Synchronize multiple futures >>> all_futures = whenAll(future1, future2, future3) >>> results = all_futures.get() # [10, 20, 20] - >>> + >>> >>> # With timeout and callbacks >>> future = makeEnhancedFuture(lambda: compute_something()) >>> future.on_complete(lambda x: print(f"Result: {x}")) @@ -398,13 +398,13 @@ PYBIND11_MODULE(future, m) { py::arg("func"), R"pbdoc( Creates an EnhancedFuture from a function. - + Args: func: The function to execute asynchronously - + Returns: An EnhancedFuture for the result of the function - + Examples: >>> future = makeEnhancedFuture(lambda: 42) >>> result = future.get() # 42 @@ -508,14 +508,14 @@ PYBIND11_MODULE(future, m) { py::arg("futures"), py::arg("timeout") = py::none(), R"pbdoc( Waits for all futures to complete and returns their results. - + Args: futures: List of futures to wait for timeout: Optional timeout in milliseconds - + Returns: List of results from all futures - + Examples: >>> future1 = makeEnhancedFuture(lambda: 10) >>> future2 = makeEnhancedFuture(lambda: 20) @@ -562,15 +562,15 @@ PYBIND11_MODULE(future, m) { py::arg("items"), py::arg("func"), py::arg("chunk_size") = 0, R"pbdoc( Processes items in parallel using multiple threads. - + Args: items: List of items to process func: Function to apply to each item chunk_size: Size of chunks to process together (0 = auto) - + Returns: List of futures containing the results - + Examples: >>> items = list(range(100)) >>> futures = parallelProcess(items, lambda x: x * x) @@ -604,14 +604,14 @@ PYBIND11_MODULE(future, m) { py::arg("future"), py::arg("timeout"), R"pbdoc( Gets the result of a future with a timeout. - + Args: future: The future to get the result from timeout: The timeout in seconds - + Returns: The result of the future - + Raises: InvalidFutureException: If the timeout is reached )pbdoc"); @@ -625,4 +625,4 @@ PYBIND11_MODULE(future, m) { // Add version information m.attr("__version__") = "1.0.0"; -} \ No newline at end of file +} diff --git a/python/async/generator.cpp b/python/async/generator.cpp index 76c8cf54..631b8775 100644 --- a/python/async/generator.cpp +++ b/python/async/generator.cpp @@ -20,10 +20,10 @@ yield values, similar to Python generators. Examples: >>> from atom.async import generator - >>> + >>> >>> # Create a generator from a range >>> g = generator.range_int(0, 5) - >>> + >>> >>> # Iterate through the generator >>> for value in g: >>> print(value) @@ -61,14 +61,14 @@ yields values and can also receive values from the caller. Examples: >>> from atom.async import generator - >>> + >>> >>> # Create a two-way generator >>> g = generator.create_echo_generator_int() - >>> + >>> >>> # Send values and get responses >>> value = g.next(42) # Send 42, get 42 back >>> print(value) - >>> + >>> >>> # Check if generator is done >>> print(g.done()) )") @@ -103,10 +103,10 @@ This generator yields values to the caller but doesn't receive input. Examples: >>> from atom.async import generator - >>> + >>> >>> # Create a one-way generator >>> g = generator.create_counter_generator_int(10) - >>> + >>> >>> # Get values >>> for i in range(5): >>> value = g.next() @@ -169,26 +169,26 @@ PYBIND11_MODULE(generator, m) { This module provides Python bindings for C++20 coroutine-based generators, allowing for efficient, lazy evaluation of sequences and bi-directional communication with coroutines. - + The module includes: - Standard generators that yield values in a sequence - Two-way generators that can both yield and receive values - Utility functions to create generators from ranges, sequences, etc. - Support for infinite generators with safe iteration - + Example: >>> from atom.async import generator - >>> + >>> >>> # Create a range generator >>> g = generator.range_int(0, 5) - >>> + >>> >>> # Iterate through all values >>> for i in g: >>> print(i) # Prints 0, 1, 2, 3, 4 - >>> + >>> >>> # Create an infinite generator (use with caution!) >>> inf_gen = generator.infinite_range_int(1, 2) - >>> + >>> >>> # Take only the first few values from infinite generator >>> for i, value in enumerate(inf_gen): >>> print(value) @@ -270,7 +270,7 @@ PYBIND11_MODULE(generator, m) { Examples: >>> g = range_int(0, 5) >>> list(g) # [0, 1, 2, 3, 4] - + >>> g = range_int(0, 10, 2) >>> list(g) # [0, 2, 4, 6, 8] )"); @@ -346,4 +346,4 @@ PYBIND11_MODULE(generator, m) { // Add version information m.attr("__version__") = "1.0.0"; -} \ No newline at end of file +} diff --git a/python/async/limiter.cpp b/python/async/limiter.cpp index 7da96bbf..b15f8a6b 100644 --- a/python/async/limiter.cpp +++ b/python/async/limiter.cpp @@ -30,25 +30,25 @@ PYBIND11_MODULE(limiter, m) { This module provides tools for controlling call rates, including rate limiting, debouncing, and throttling functions. - + The module includes: - RateLimiter for controlling call frequency with configurable limits - Debounce for delaying function execution after multiple calls - Throttle for limiting function execution to specific intervals - + Example: >>> from atom.async import limiter - >>> + >>> >>> # Create a rate limiter >>> rate_limiter = limiter.RateLimiter() - >>> + >>> >>> # Set limit for a specific function (5 calls per second) >>> rate_limiter.set_function_limit("my_api_call", 5, 1) - >>> + >>> >>> # Create a debounced function (waits 500ms after last call) >>> debounced_fn = limiter.create_debounce(lambda: print("Debounced!"), 500) >>> debounced_fn() # Will wait 500ms before executing - >>> + >>> >>> # Create a throttled function (executes at most once every 1000ms) >>> throttled_fn = limiter.create_throttle(lambda: print("Throttled!"), 1000) >>> throttled_fn() # Executes immediately @@ -101,7 +101,7 @@ This class manages rate limiting for different functions based on configurable s Examples: >>> limiter = RateLimiter() >>> limiter.set_function_limit("api_call", 10, 60) # 10 calls per minute - >>> + >>> >>> # In an async function: >>> async def call_api(): >>> await limiter.acquire("api_call") @@ -184,7 +184,7 @@ since the last time it was invoked. >>> debounced = create_debounce(lambda: print("Called!"), 500) >>> debounced() # Will wait 500ms before printing >>> debounced() # Resets the timer - >>> + >>> >>> # Leading execution (immediate first call) >>> debounced2 = create_debounce(lambda: print("Called!"), 500, leading=True) >>> debounced2() # Executes immediately, then waits for subsequent calls @@ -235,7 +235,7 @@ ignoring additional calls during that interval. >>> throttled = create_throttle(lambda: print("Called!"), 1000) >>> throttled() # Executes immediately >>> throttled() # Ignored until 1000ms have passed - >>> + >>> >>> # Force immediate execution on first call >>> throttled2 = create_throttle(lambda: print("Called!"), 1000, leading=True) >>> throttled2() # Executes immediately @@ -312,4 +312,4 @@ This method is intended to be used with Python's 'await' keyword. // 添加版本信息 m.attr("__version__") = "1.0.0"; -} \ No newline at end of file +} diff --git a/python/async/message_bus.cpp b/python/async/message_bus.cpp index c20bd924..73b8ddb4 100644 --- a/python/async/message_bus.cpp +++ b/python/async/message_bus.cpp @@ -108,10 +108,10 @@ void declare_message_type(py::module& m, const std::string& type_name) { Examples: >>> def handler(message): >>> print(f"Received: {message}") - >>> + >>> >>> # Subscribe to string messages >>> token = subscribe_string(bus, "notifications.system", handler) - >>> + >>> >>> # Unsubscribe later >>> unsubscribe_string(bus, token) )"); @@ -170,7 +170,7 @@ void declare_message_type(py::module& m, const std::string& type_name) { Examples: >>> # Publish a string message >>> publish_string(bus, "notifications.system", "System is shutting down") - >>> + >>> >>> # Publish with delay >>> publish_string(bus, "notifications.system", "Delayed message", 5000) )"); @@ -271,10 +271,10 @@ PYBIND11_MODULE(message_bus, m) { This module provides an event-driven communication system with hierarchical routing, filtering, and asynchronous message handling. - + The message bus allows components to communicate without direct coupling, enabling a modular, extensible architecture. - + Features: - Hierarchical message routing with namespace support - Type-safe message passing @@ -282,27 +282,27 @@ PYBIND11_MODULE(message_bus, m) { - Message filtering - Message history tracking - Delayed message publishing - + Example: >>> from atom.async.message_bus import PyIOContext, MessageBus >>> from atom.async.message_bus import publish_string, subscribe_string - >>> + >>> >>> # Create an IO context for async operations >>> io_context = PyIOContext() - >>> + >>> >>> # Create a message bus >>> bus = MessageBus.create_shared(io_context) - >>> + >>> >>> # Define a message handler >>> def message_handler(message): >>> print(f"Received: {message}") - >>> + >>> >>> # Subscribe to a message type >>> token = subscribe_string(bus, "system.notifications", message_handler) - >>> + >>> >>> # Publish a message >>> publish_string(bus, "system.notifications", "Hello from the message bus!") - >>> + >>> >>> # Publish with delay (5 seconds) >>> publish_string(bus, "system.notifications", "Delayed message", 5000) )pbdoc"; @@ -329,13 +329,13 @@ PYBIND11_MODULE(message_bus, m) { // Define the IO context wrapper py::class_(m, "PyIOContext", R"( Python-friendly wrapper for asio::io_context. - + This class manages a thread that processes asynchronous operations for the message bus. - + The IO context is automatically started on creation and stopped when the object is garbage collected. - + Examples: >>> io_context = PyIOContext() >>> bus = MessageBus.create_shared(io_context) @@ -346,10 +346,10 @@ PYBIND11_MODULE(message_bus, m) { py::class_>(m, "MessageBus", R"( A message bus for asynchronous event-driven communication. - + The MessageBus provides a way for components to communicate without direct coupling, using a publish-subscribe pattern with hierarchical routing. - + Examples: >>> io_context = PyIOContext() >>> bus = MessageBus.create_shared(io_context) @@ -393,4 +393,4 @@ PYBIND11_MODULE(message_bus, m) { m.attr("MAX_HISTORY_SIZE") = atom::async::MessageBus::K_MAX_HISTORY_SIZE; m.attr("MAX_SUBSCRIBERS_PER_MESSAGE") = atom::async::MessageBus::K_MAX_SUBSCRIBERS_PER_MESSAGE; -} \ No newline at end of file +} diff --git a/python/async/message_queue.cpp b/python/async/message_queue.cpp index 9b15def3..338e0112 100644 --- a/python/async/message_queue.cpp +++ b/python/async/message_queue.cpp @@ -96,23 +96,23 @@ and support for both synchronous and asynchronous message processing. Examples: >>> from atom.async.message_queue import PyIOContext, MessageQueueString - >>> + >>> >>> # Create an IO context for async operations >>> io_context = PyIOContext() - >>> + >>> >>> # Create a message queue >>> queue = MessageQueueString(io_context) - >>> + >>> >>> # Define a message handler >>> def message_handler(message): >>> print(f"Received: {message}") - >>> + >>> >>> # Subscribe to messages >>> queue.subscribe(message_handler, "my_subscriber") - >>> + >>> >>> # Start processing messages >>> queue.start_processing() - >>> + >>> >>> # Publish messages >>> queue.publish("Hello, world!") >>> queue.publish("Another message", 10) # Higher priority @@ -169,19 +169,19 @@ and support for both synchronous and asynchronous message processing. Examples: >>> # Basic subscription >>> queue.subscribe(lambda msg: print(msg), "basic_subscriber") - >>> + >>> >>> # Priority subscription - >>> queue.subscribe(lambda msg: print(f"High priority: {msg}"), + >>> queue.subscribe(lambda msg: print(f"High priority: {msg}"), >>> "high_priority", 10) - >>> + >>> >>> # With filter - >>> queue.subscribe(lambda msg: print(f"Filtered: {msg}"), - >>> "filtered", 0, + >>> queue.subscribe(lambda msg: print(f"Filtered: {msg}"), + >>> "filtered", 0, >>> lambda msg: "important" in msg) - >>> + >>> >>> # With timeout - >>> queue.subscribe(lambda msg: process_message(msg), - >>> "timeout_protected", 0, None, + >>> queue.subscribe(lambda msg: process_message(msg), + >>> "timeout_protected", 0, None, >>> timeout=5000) # 5 seconds )") @@ -206,10 +206,10 @@ and support for both synchronous and asynchronous message processing. >>> # Define a handler >>> def my_handler(msg): >>> print(msg) - >>> + >>> >>> # Subscribe >>> queue.subscribe(my_handler, "my_subscriber") - >>> + >>> >>> # Later, unsubscribe >>> queue.unsubscribe(my_handler) )") @@ -225,7 +225,7 @@ and support for both synchronous and asynchronous message processing. Examples: >>> # Publish a basic message >>> queue.publish("Hello, world!") - >>> + >>> >>> # Publish a high-priority message >>> queue.publish("Urgent message", 10) )") @@ -369,7 +369,7 @@ This method stops the background thread that processes messages. >>> # Wait for a message >>> msg = await queue.await_message() >>> print(f"Received: {msg}") - >>> + >>> >>> # Wait for a filtered message >>> important_msg = await queue.await_message( >>> lambda m: "important" in m) @@ -388,11 +388,11 @@ PYBIND11_MODULE(message_queue, m) { This module provides a priority-based message queue with filtering, timeouts, and support for both synchronous and asynchronous message processing. - + The message queue allows components to communicate through a publish-subscribe - pattern with priority handling, ensuring that high-priority messages are + pattern with priority handling, ensuring that high-priority messages are processed before lower-priority ones. - + Features: - Priority-based message processing - Message filtering @@ -400,30 +400,30 @@ PYBIND11_MODULE(message_queue, m) { - Asynchronous message processing - Python async/await support - Cancellation of pending messages - + Example: >>> from atom.async.message_queue import PyIOContext, MessageQueueString - >>> + >>> >>> # Create an IO context for async operations >>> io_context = PyIOContext() - >>> + >>> >>> # Create a message queue >>> queue = MessageQueueString(io_context) - >>> + >>> >>> # Define a message handler >>> def message_handler(message): >>> print(f"Received: {message}") - >>> + >>> >>> # Subscribe to messages >>> queue.subscribe(message_handler, "my_subscriber") - >>> + >>> >>> # Start processing messages >>> queue.start_processing() - >>> + >>> >>> # Publish messages >>> queue.publish("Hello, world!") >>> queue.publish("Another message", 10) # Higher priority - >>> + >>> >>> # Using async/await >>> async def process_messages(): >>> message = await queue.await_message() @@ -461,13 +461,13 @@ PYBIND11_MODULE(message_queue, m) { // Define the IO context wrapper py::class_(m, "PyIOContext", R"( Python-friendly wrapper for asio::io_context. - + This class manages a thread that processes asynchronous operations for the message queue. - + The IO context is automatically started on creation and stopped when the object is garbage collected. - + Examples: >>> io_context = PyIOContext() >>> queue = MessageQueueString(io_context) @@ -486,4 +486,4 @@ PYBIND11_MODULE(message_queue, m) { // Add version information m.attr("__version__") = "1.0.0"; -} \ No newline at end of file +} diff --git a/python/async/packaged_task.cpp b/python/async/packaged_task.cpp index 8ef89862..82bbacfe 100644 --- a/python/async/packaged_task.cpp +++ b/python/async/packaged_task.cpp @@ -53,7 +53,7 @@ PYBIND11_MODULE(packaged_task, m) { m, "PackagedTask", R"(Enhanced packaged task for executing deferred operations. -This class wraps a callable object and provides mechanisms to execute it +This class wraps a callable object and provides mechanisms to execute it asynchronously, returning its result through a future. Examples: @@ -124,7 +124,7 @@ asynchronously, returning its result through a future. m, "VoidPackagedTask", R"(Enhanced packaged task for executing deferred operations without return values. -This class wraps a callable object and provides mechanisms to execute it +This class wraps a callable object and provides mechanisms to execute it asynchronously, signaling completion through a future. Examples: @@ -277,7 +277,7 @@ asynchronously, signaling completion through a future. py::arg("task"), R"(Run a callable as a packaged task and return its future. -This is a convenience function that creates a packaged task, +This is a convenience function that creates a packaged task, executes it in a background thread, and returns a future. Args: @@ -292,4 +292,4 @@ executes it in a background thread, and returns a future. >>> result = future.result() >>> print(result) # Output: 42 )"); -} \ No newline at end of file +} diff --git a/python/async/parallel.cpp b/python/async/parallel.cpp index a2ea7442..8c9b2529 100644 --- a/python/async/parallel.cpp +++ b/python/async/parallel.cpp @@ -382,4 +382,4 @@ instructions for common vector operations like addition, multiplication and dot py::arg("b")) .def_static("dot_product", &simd_dot_product, py::arg("a"), py::arg("b")); -} \ No newline at end of file +} diff --git a/python/async/pool.cpp b/python/async/pool.cpp index 604a3f76..fac0e098 100644 --- a/python/async/pool.cpp +++ b/python/async/pool.cpp @@ -79,7 +79,7 @@ PYBIND11_MODULE(pool, m) { m, "ThreadSafeQueue", R"(A thread-safe queue implementation for storing Python objects. -This queue provides thread-safe operations for adding, removing, and +This queue provides thread-safe operations for adding, removing, and manipulating elements in a multi-threaded environment. Examples: @@ -347,4 +347,4 @@ Keyword Args: "hardware_concurrency", []() { return std::thread::hardware_concurrency(); }, "Returns the number of concurrent threads supported by the hardware."); -} \ No newline at end of file +} diff --git a/python/async/promise.cpp b/python/async/promise.cpp index 6fa66f00..ccead125 100644 --- a/python/async/promise.cpp +++ b/python/async/promise.cpp @@ -348,7 +348,7 @@ resolution and rejection mechanisms similar to JavaScript Promises. A new Promise that is resolved/rejected with the return value of the called handler. Examples: - >>> promise.then(lambda value: print(f"Success: {value}"), + >>> promise.then(lambda value: print(f"Success: {value}"), ... lambda reason: print(f"Failed: {reason}")) )") .def( @@ -519,4 +519,4 @@ resolution and rejection mechanisms similar to JavaScript Promises. >>> race_promise.wait() 'p2 done' )"); -} \ No newline at end of file +} diff --git a/python/async/queue.cpp b/python/async/queue.cpp index 147c4990..b93fa42a 100644 --- a/python/async/queue.cpp +++ b/python/async/queue.cpp @@ -373,4 +373,4 @@ A list of extracted elements. >>> queue.size() 3 )"); -} \ No newline at end of file +} diff --git a/python/async/safetype.cpp b/python/async/safetype.cpp index 1e7f6869..bfe851ae 100644 --- a/python/async/safetype.cpp +++ b/python/async/safetype.cpp @@ -587,4 +587,4 @@ simultaneously without explicit locking mechanisms. 3 >>> lst.front() # Should be item3 )"); -} \ No newline at end of file +} diff --git a/python/async/slot.cpp b/python/async/slot.cpp index af94869a..f7608226 100644 --- a/python/async/slot.cpp +++ b/python/async/slot.cpp @@ -130,7 +130,7 @@ This class provides a mechanism for implementing the observer pattern where func R"(A signal class that allows asynchronous slot execution. This class provides a mechanism for implementing the observer pattern where functions -(slots) can be connected to a signal and will be called asynchronously when the +(slots) can be connected to a signal and will be called asynchronously when the signal is emitted. Examples: @@ -254,7 +254,7 @@ uniquely identifiable connections that can be easily disconnected by ID. m, "ChainedSignal", R"(A signal class that allows chaining of signals. -This class provides a mechanism for implementing signal chains where emitting +This class provides a mechanism for implementing signal chains where emitting one signal will trigger others connected in a chain. Examples: @@ -687,4 +687,4 @@ automatic cleanup of slots when they are no longer referenced. >>> from atom.async import create_scoped_signal >>> signal = create_scoped_signal() )"); -} \ No newline at end of file +} diff --git a/python/async/thread_wrapper.cpp b/python/async/thread_wrapper.cpp index ed51b560..26aa6565 100644 --- a/python/async/thread_wrapper.cpp +++ b/python/async/thread_wrapper.cpp @@ -477,4 +477,4 @@ The callable can optionally accept a `StopToken` as its first argument. }, py::arg("func"), R"(Runs a function in the thread pool and returns a future for the result.)"); -} \ No newline at end of file +} diff --git a/python/async/threadlocal.cpp b/python/async/threadlocal.cpp index f093fbcd..fa13032e 100644 --- a/python/async/threadlocal.cpp +++ b/python/async/threadlocal.cpp @@ -410,4 +410,4 @@ Equivalent to calling .get(). }, "Support for boolean evaluation (True if current thread has a " "value)."); -} \ No newline at end of file +} diff --git a/python/async/timer.cpp b/python/async/timer.cpp index 38d24204..42d0c719 100644 --- a/python/async/timer.cpp +++ b/python/async/timer.cpp @@ -76,7 +76,7 @@ options for repetition and priority settings. m, "Timer", R"(Represents a timer for scheduling and executing tasks. -This class provides methods to schedule one-time or recurring tasks with +This class provides methods to schedule one-time or recurring tasks with precise timing control and priority settings. Examples: @@ -308,4 +308,4 @@ precise timing control and priority settings. ... print(f"Alert: {message}") >>> timer, future = schedule_timeout(alert, 2000, "Time's up!") )"); -} \ No newline at end of file +} diff --git a/python/async/trigger.cpp b/python/async/trigger.cpp index b883c5bd..c2976a39 100644 --- a/python/async/trigger.cpp +++ b/python/async/trigger.cpp @@ -97,7 +97,7 @@ for different events with support for priorities and delayed execution. TriggerException: If the event name is empty or the callback is invalid. Examples: - >>> callback_id = trigger.register_callback("data_received", + >>> callback_id = trigger.register_callback("data_received", ... lambda data: print(f"Got: {data}"), ... CallbackPriority.HIGH) )") @@ -282,4 +282,4 @@ for different events with support for priorities and delayed execution. >>> from atom.async import create_trigger >>> trigger = create_trigger() )"); -} \ No newline at end of file +} diff --git a/python/connection/__init__.py b/python/connection/__init__.py index 59191b7a..d1d39489 100644 --- a/python/connection/__init__.py +++ b/python/connection/__init__.py @@ -1 +1 @@ -# Auto-generated __init__.py for connection module \ No newline at end of file +# Auto-generated __init__.py for connection module diff --git a/python/connection/fifo.cpp b/python/connection/fifo.cpp index 748e3877..2b455087 100644 --- a/python/connection/fifo.cpp +++ b/python/connection/fifo.cpp @@ -116,4 +116,4 @@ This will release any resources associated with the FIFO. >>> from atom.connection.fifo import create_fifo_client >>> client = create_fifo_client("/tmp/my_fifo") )"); -} \ No newline at end of file +} diff --git a/python/connection/fifoserver.cpp b/python/connection/fifoserver.cpp index bc7d152c..476c4d89 100644 --- a/python/connection/fifoserver.cpp +++ b/python/connection/fifoserver.cpp @@ -97,4 +97,4 @@ This method stops the server, closes the FIFO, and joins any background threads. >>> server = create_fifo_server("/tmp/my_fifo") >>> server.start() )"); -} \ No newline at end of file +} diff --git a/python/connection/sockethub.cpp b/python/connection/sockethub.cpp index 949ffb23..55aabdcd 100644 --- a/python/connection/sockethub.cpp +++ b/python/connection/sockethub.cpp @@ -186,22 +186,22 @@ manage client groups, and process messages with customizable handlers. Examples: >>> from atom.connection.sockethub import SocketHub, Message, SocketHubConfig - >>> + >>> >>> # Create and configure the hub >>> config = SocketHubConfig() >>> config.connection_timeout = 60 >>> hub = SocketHub(config) - >>> + >>> >>> # Set up handlers >>> def on_message(message, client_id): ... print(f"Received: {message.as_string()} from client {client_id}") ... hub.broadcast_message(Message.create_text("Echo: " + message.as_string())) - >>> + >>> >>> hub.add_message_handler(on_message) - >>> + >>> >>> # Start the server >>> hub.start(8080) - >>> + >>> >>> # Keep the server running until manually stopped >>> try: ... # Your application logic here @@ -240,7 +240,7 @@ This method will disconnect all clients and release resources. Examples: >>> def message_handler(message, client_id): ... print(f"Message from {client_id}: {message.as_string()}") - ... + ... >>> hub.add_message_handler(message_handler) )") .def("add_connect_handler", @@ -254,7 +254,7 @@ This method will disconnect all clients and release resources. Examples: >>> def connect_handler(client_id, ip): ... print(f"Client {client_id} connected from {ip}") - ... + ... >>> hub.add_connect_handler(connect_handler) )") .def("add_disconnect_handler", @@ -268,7 +268,7 @@ This method will disconnect all clients and release resources. Examples: >>> def disconnect_handler(client_id, reason): ... print(f"Client {client_id} disconnected: {reason}") - ... + ... >>> hub.add_disconnect_handler(disconnect_handler) )") .def("add_error_handler", @@ -282,7 +282,7 @@ This method will disconnect all clients and release resources. Examples: >>> def error_handler(error, client_id): ... print(f"Error for client {client_id}: {error}") - ... + ... >>> hub.add_error_handler(error_handler) )") .def("broadcast_message", @@ -357,7 +357,7 @@ This method will disconnect all clients and release resources. >>> def authenticate(username, password): ... # Check credentials against a database, etc. ... return username == "admin" and password == "secret" - ... + ... >>> hub.set_authenticator(authenticate) )") .def("require_authentication", @@ -419,7 +419,7 @@ This method will disconnect all clients and release resources. >>> def log_handler(level, message): ... levels = ["DEBUG", "INFO", "WARNING", "ERROR", "FATAL"] ... print(f"[{levels[int(level)]}] {message}") - ... + ... >>> hub.set_log_handler(log_handler) )") .def("is_running", &atom::async::connection::SocketHub::isRunning, @@ -553,4 +553,4 @@ then starts it on the specified port. >>> msg = create_binary_message(bytearray([0x01, 0x02, 0x03])) >>> hub.broadcast_message(msg) )"); -} \ No newline at end of file +} diff --git a/python/connection/tcpclient.cpp b/python/connection/tcpclient.cpp index 97db2d9f..76e5ee6d 100644 --- a/python/connection/tcpclient.cpp +++ b/python/connection/tcpclient.cpp @@ -203,11 +203,11 @@ automatic reconnection, heartbeats, and configurable timeouts. >>> config = ConnectionConfig() >>> config.keep_alive = True >>> config.connect_timeout = 5000 # 5 seconds - >>> + >>> >>> client = TcpClient(config) >>> client.connect("example.com", 80) >>> client.send_string("GET / HTTP/1.1\r\nHost: example.com\r\n\r\n") - >>> + >>> >>> # Asynchronous receive >>> future = client.receive_until('\n', 1000) >>> response = future.result() @@ -487,7 +487,7 @@ This method zeroes all counters in the statistics object. Examples: >>> def on_connecting(): ... print("Connecting to server...") - ... + ... >>> client.set_on_connecting_callback(on_connecting) )") .def("set_on_connected_callback", @@ -501,7 +501,7 @@ This method zeroes all counters in the statistics object. Examples: >>> def on_connected(): ... print("Successfully connected to server") - ... + ... >>> client.set_on_connected_callback(on_connected) )") .def("set_on_disconnected_callback", @@ -515,7 +515,7 @@ This method zeroes all counters in the statistics object. Examples: >>> def on_disconnected(): ... print("Disconnected from server") - ... + ... >>> client.set_on_disconnected_callback(on_disconnected) )") .def("set_on_data_received_callback", @@ -529,7 +529,7 @@ This method zeroes all counters in the statistics object. Examples: >>> def on_data_received(data): ... print(f"Received {len(data)} bytes") - ... + ... >>> client.set_on_data_received_callback(on_data_received) )") .def("set_on_error_callback", @@ -543,7 +543,7 @@ This method zeroes all counters in the statistics object. Examples: >>> def on_error(error_msg): ... print(f"Error: {error_msg}") - ... + ... >>> client.set_on_error_callback(on_error) )") .def("set_on_state_changed_callback", @@ -557,7 +557,7 @@ This method zeroes all counters in the statistics object. Examples: >>> def on_state_changed(new_state, old_state): ... print(f"State changed from {old_state} to {new_state}") - ... + ... >>> client.set_on_state_changed_callback(on_state_changed) )") .def("set_on_heartbeat_callback", @@ -571,7 +571,7 @@ This method zeroes all counters in the statistics object. Examples: >>> def on_heartbeat(): ... print("Heartbeat sent") - ... + ... >>> client.set_on_heartbeat_callback(on_heartbeat) )") .def( @@ -666,4 +666,4 @@ This method zeroes all counters in the statistics object. ... except RuntimeError as e: ... print(f"Secure connection failed: {e}") )"); -} \ No newline at end of file +} diff --git a/python/connection/udp.cpp b/python/connection/udp.cpp index 62b8a172..65ad25c8 100644 --- a/python/connection/udp.cpp +++ b/python/connection/udp.cpp @@ -132,7 +132,7 @@ PYBIND11_MODULE(udp, m) { m, "UdpClient", R"(A modern UDP client for sending and receiving datagrams. -This class provides methods for UDP socket communication, including sending +This class provides methods for UDP socket communication, including sending and receiving datagrams, multicast support, broadcast support, and asynchronous operations. Examples: @@ -569,4 +569,4 @@ and receiving datagrams, multicast support, broadcast support, and asynchronous Returns: True if IPv6 is supported, False otherwise )"); -} \ No newline at end of file +} diff --git a/python/connection/udpserver.cpp b/python/connection/udpserver.cpp index e9aa2d52..e22ba8ee 100644 --- a/python/connection/udpserver.cpp +++ b/python/connection/udpserver.cpp @@ -92,12 +92,12 @@ asynchronous operations, multicast, broadcast, and more. Examples: >>> from atom.connection.udpserver import UdpSocketHub >>> server = UdpSocketHub() - >>> + >>> >>> # Set up message handler >>> def on_message(message, addr, port): ... print(f"Received from {addr}:{port}: {message}") ... return "Response: " + message - >>> + >>> >>> server.add_message_handler(on_message) >>> server.start(8080) # Start listening on port 8080 )") @@ -144,7 +144,7 @@ This method stops the server, closes the socket, and joins any worker threads. Examples: >>> def message_handler(message, ip, port): ... print(f"Received message from {ip}:{port}: {message}") - ... + ... >>> server.add_message_handler(message_handler) )") .def("remove_message_handler", @@ -167,7 +167,7 @@ This method stops the server, closes the socket, and joins any worker threads. Examples: >>> def error_handler(message, error_code): ... print(f"Error {error_code}: {message}") - ... + ... >>> server.add_error_handler(error_handler) )") .def("remove_error_handler", @@ -371,4 +371,4 @@ This function creates a UdpSocketHub, starts it, and joins a multicast group. >>> from atom.connection.udpserver import create_multicast_server >>> server = create_multicast_server(5000, "224.0.0.1") )"); -} \ No newline at end of file +} diff --git a/python/error/__init__.py b/python/error/__init__.py index ac8b725d..248ed704 100644 --- a/python/error/__init__.py +++ b/python/error/__init__.py @@ -1 +1 @@ -# Auto-generated __init__.py for error module \ No newline at end of file +# Auto-generated __init__.py for error module diff --git a/python/error/stacktrace.cpp b/python/error/stacktrace.cpp index 30038163..a83a416d 100644 --- a/python/error/stacktrace.cpp +++ b/python/error/stacktrace.cpp @@ -27,8 +27,8 @@ PYBIND11_MODULE(stacktrace, m) { m, "StackTrace", R"(Class for capturing and representing a stack trace with enhanced details. -This class captures the stack trace of the current execution context and represents -it as a string, including file names, line numbers, function names, module +This class captures the stack trace of the current execution context and represents +it as a string, including file names, line numbers, function names, module information, and memory addresses when available. Examples: @@ -129,7 +129,7 @@ enhanced error reporting. ... print(error_report) Exception: ValueError Message: Invalid input - + Native Stack Trace: [0] format_exception_with_traceback at ... [1] __main__ at ... @@ -192,4 +192,4 @@ the native stack trace and include it in the error message. ... # Some code that might raise a C++ exception ... pass )"); -} \ No newline at end of file +} diff --git a/python/extra/beast/http.cpp b/python/extra/beast/http.cpp index 2777fd41..d3c116f2 100644 --- a/python/extra/beast/http.cpp +++ b/python/extra/beast/http.cpp @@ -59,14 +59,14 @@ handling, file uploads and downloads, and more. Examples: >>> from atom.http import HttpClient, HttpVerb >>> import asyncio - >>> + >>> >>> # Synchronous request >>> client = HttpClient() >>> response = client.request(HttpVerb.GET, "example.com", "80", "/") >>> print(response.body()) - >>> + >>> >>> # JSON request - >>> json_response = client.json_request(HttpVerb.POST, "api.example.com", + >>> json_response = client.json_request(HttpVerb.POST, "api.example.com", >>> "443", "/data", {"key": "value"}) >>> print(json_response) )") @@ -443,4 +443,4 @@ headers, and body content. return headers; }, "Gets all headers as a dictionary."); -} \ No newline at end of file +} diff --git a/python/extra/beast/http_utils.cpp b/python/extra/beast/http_utils.cpp index 67125d60..f642bef8 100644 --- a/python/extra/beast/http_utils.cpp +++ b/python/extra/beast/http_utils.cpp @@ -131,7 +131,7 @@ Keys and values are URL-encoded. params: A dictionary where keys are parameter names and values are parameter values. Returns: - The formatted query string (e.g., "key1=value1&key2=value2"). + The formatted query string (e.g., "key1=value1&key2=value2"). Does not include the leading '?'. Examples: @@ -237,4 +237,4 @@ add_cookies_to_request for accurate cookie selection. The cookie value if found matching the host and name (considering domain matching), otherwise an empty string. Returns the first match found. )"); -} \ No newline at end of file +} diff --git a/python/extra/beast/ws.cpp b/python/extra/beast/ws.cpp index 039eab20..b3098bd2 100644 --- a/python/extra/beast/ws.cpp +++ b/python/extra/beast/ws.cpp @@ -41,16 +41,16 @@ messages, and manage connection settings like timeouts and reconnection. Examples: >>> from atom.ws import WSClient >>> import asyncio - >>> + >>> >>> # Create a WebSocket client >>> client = WSClient() - >>> + >>> >>> # Connect to a WebSocket server >>> client.connect("echo.websocket.org", "80") - >>> + >>> >>> # Send a message >>> client.send("Hello, WebSocket!") - >>> + >>> >>> # Receive a message >>> response = client.receive() >>> print(response) @@ -266,4 +266,4 @@ messages, and manage connection settings like timeouts and reconnection. Raises: RuntimeError: If not connected. )"); -} \ No newline at end of file +} diff --git a/python/extra/boost/charconv.cpp b/python/extra/boost/charconv.cpp index ec0d16d9..3aa8724e 100644 --- a/python/extra/boost/charconv.cpp +++ b/python/extra/boost/charconv.cpp @@ -304,4 +304,4 @@ with precise format control. m.def("string_to_float", &atom::extra::boost::BoostCharConv::stringToFloat, py::arg("str"), "Shorthand for BoostCharConv.string_to_float"); -} \ No newline at end of file +} diff --git a/python/extra/boost/locale.cpp b/python/extra/boost/locale.cpp index bc128d17..381028a8 100644 --- a/python/extra/boost/locale.cpp +++ b/python/extra/boost/locale.cpp @@ -368,4 +368,4 @@ number formatting, currency formatting, and regex replacement using Boost.Locale // Create a default instance m.attr("default_wrapper") = py::cast(atom::extra::boost::LocaleWrapper()); -} \ No newline at end of file +} diff --git a/python/extra/boost/math.cpp b/python/extra/boost/math.cpp index 4e662ca5..4db72c1c 100644 --- a/python/extra/boost/math.cpp +++ b/python/extra/boost/math.cpp @@ -19,7 +19,7 @@ void declare_math_classes(py::module& m, const std::string& type_suffix) { m, class_name.c_str(), R"(Wrapper class for special mathematical functions. -This class provides various special mathematical functions like beta, gamma, +This class provides various special mathematical functions like beta, gamma, digamma, error function, Bessel functions, and Legendre polynomials. Examples: @@ -496,7 +496,7 @@ This class provides optimization methods like golden section search and Newton-R py::class_(m, class_name.c_str(), R"(Wrapper class for linear algebra operations. -This class provides linear algebra operations such as solving linear systems, +This class provides linear algebra operations such as solving linear systems, computing determinants, matrix multiplication, and transpose. Examples: @@ -601,7 +601,7 @@ This class provides methods for solving ODEs such as the 4th order Runge-Kutta m m, class_name.c_str(), R"(Wrapper class for financial mathematics functions. -This class provides financial math functions such as Black-Scholes option pricing, +This class provides financial math functions such as Black-Scholes option pricing, bond pricing, and implied volatility calculation. Examples: @@ -739,4 +739,4 @@ PYBIND11_MODULE(math, m) { // Add version info m.attr("__version__") = "1.0.0"; -} \ No newline at end of file +} diff --git a/python/extra/boost/regex.cpp b/python/extra/boost/regex.cpp index dfc9c0d7..1f6b98d6 100644 --- a/python/extra/boost/regex.cpp +++ b/python/extra/boost/regex.cpp @@ -539,4 +539,4 @@ using the Boost.Regex library. // Add version info m.attr("__version__") = "1.0.0"; -} \ No newline at end of file +} diff --git a/python/extra/boost/system.cpp b/python/extra/boost/system.cpp index e9070c94..e0bbea3e 100644 --- a/python/extra/boost/system.cpp +++ b/python/extra/boost/system.cpp @@ -153,7 +153,7 @@ If the function throws an exception, it's caught and converted to an Error. >>> result = system.make_result(success_func) >>> print(result.value()) Success! - + >>> def error_func(): ... raise ValueError("Something went wrong") >>> result = system.make_result(error_func) @@ -208,7 +208,7 @@ This specialization is used for functions that don't return a value but might fa >>> result = system.ResultVoid() >>> print(result.has_value()) True - + >>> # Creating a failed void result >>> error_result = system.ResultVoid(system.Error(1, system.generic_category())) >>> print(error_result.has_value()) @@ -239,7 +239,7 @@ This class either contains a value of the specified type or an error. >>> result = system.ResultInt(42) >>> print(result.value()) 42 - + >>> # Creating a failed result >>> error_result = system.ResultInt(system.Error(1, system.generic_category())) >>> print(error_result.has_value()) @@ -333,4 +333,4 @@ This class either contains a value of the specified type or an error. }); */ } -} \ No newline at end of file +} diff --git a/python/extra/boost/uuid.cpp b/python/extra/boost/uuid.cpp index 9519110c..a302f991 100644 --- a/python/extra/boost/uuid.cpp +++ b/python/extra/boost/uuid.cpp @@ -42,7 +42,7 @@ in various formats. >>> id1 = uuid.UUID() >>> print(id1.to_string()) 550e8400-e29b-41d4-a716-446655440000 - + >>> # Create UUID from string >>> id2 = uuid.UUID("550e8400-e29b-41d4-a716-446655440000") >>> print(id2.format()) @@ -230,4 +230,4 @@ in various formats. // Add version info m.attr("__version__") = "1.0.0"; -} \ No newline at end of file +} diff --git a/python/io/__init__.py b/python/io/__init__.py index 0e05c922..27570b4c 100644 --- a/python/io/__init__.py +++ b/python/io/__init__.py @@ -1 +1 @@ -# Auto-generated __init__.py for io module \ No newline at end of file +# Auto-generated __init__.py for io module diff --git a/python/io/asyncio.cpp b/python/io/asyncio.cpp index 0e521a82..da11c270 100644 --- a/python/io/asyncio.cpp +++ b/python/io/asyncio.cpp @@ -246,16 +246,16 @@ This class provides methods for reading, writing, and manipulating files asynchr Examples: >>> import asio >>> from atom.io.asyncio import AsyncFile - >>> + >>> >>> io_context = asio.io_context() >>> async_file = AsyncFile(io_context) - >>> + >>> >>> def on_read(result): ... if result.success: ... print(f"Read {len(result.value)} bytes") ... else: ... print(f"Error: {result.error_message}") - >>> + >>> >>> async_file.async_read("example.txt", on_read) >>> io_context.run() )") @@ -286,7 +286,7 @@ This class provides methods for reading, writing, and manipulating files asynchr ... print(f"Content: {result.value[:50]}...") ... else: ... print(f"Error: {result.error_message}") - >>> + >>> >>> async_file.async_read("example.txt", on_read) )") .def( @@ -316,7 +316,7 @@ This class provides methods for reading, writing, and manipulating files asynchr ... print("Write successful") ... else: ... print(f"Error: {result.error_message}") - >>> + >>> >>> async_file.async_write("example.txt", "Hello, World!", on_write) )") .def( @@ -343,7 +343,7 @@ This class provides methods for reading, writing, and manipulating files asynchr ... print("Delete successful") ... else: ... print(f"Error: {result.error_message}") - >>> + >>> >>> async_file.async_delete("temporary.txt", on_delete) )") .def( @@ -371,7 +371,7 @@ This class provides methods for reading, writing, and manipulating files asynchr ... print("Copy successful") ... else: ... print(f"Error: {result.error_message}") - >>> + >>> >>> async_file.async_copy("original.txt", "backup.txt", on_copy) )") .def( @@ -400,7 +400,7 @@ This class provides methods for reading, writing, and manipulating files asynchr ... print(f"Read successful: {len(result.value }) bytes") ... else: ... print(f"Error: {result.error_message}") - >>> + >>> >>> async_file.async_read_with_timeout("example.txt", 1000, on_read) # 1 second timeout )") .def( @@ -431,7 +431,7 @@ This class provides methods for reading, writing, and manipulating files asynchr ... print(f"File {i+1}: {len(content)} bytes") ... else: ... print(f"Error: {result.error_message}") - >>> + >>> >>> async_file.async_batch_read(["file1.txt", "file2.txt"], on_batch_read) )") .def( @@ -462,7 +462,7 @@ This class provides methods for reading, writing, and manipulating files asynchr ... print("It's a regular file") ... else: ... print(f"Error: {result.error_message}") - >>> + >>> >>> async_file.async_stat("example.txt", on_stat) )") .def( @@ -490,7 +490,7 @@ This class provides methods for reading, writing, and manipulating files asynchr ... print("Move successful") ... else: ... print(f"Error: {result.error_message}") - >>> + >>> >>> async_file.async_move("old_path.txt", "new_path.txt", on_move) )") .def( @@ -516,13 +516,13 @@ This class provides methods for reading, writing, and manipulating files asynchr >>> import stat >>> from pathlib import Path >>> perms = stat.S_IRUSR | stat.S_IWUSR # Read & write for owner only - >>> + >>> >>> def on_chmod(result): ... if result.success: ... print("Changed permissions successfully") ... else: ... print(f"Error: {result.error_message}") - >>> + >>> >>> async_file.async_change_permissions("example.txt", perms, on_chmod) )") .def( @@ -549,7 +549,7 @@ This class provides methods for reading, writing, and manipulating files asynchr ... print("Directory created successfully") ... else: ... print(f"Error: {result.error_message}") - >>> + >>> >>> async_file.async_create_directory("new_directory", on_create_dir) )") .def( @@ -579,7 +579,7 @@ This class provides methods for reading, writing, and manipulating files asynchr ... print("File does not exist") ... else: ... print(f"Error: {result.error_message}") - >>> + >>> >>> async_file.async_exists("example.txt", on_exists) )") .def( @@ -679,10 +679,10 @@ This class provides methods for creating, removing, and listing directories asyn Examples: >>> import asio >>> from atom.io.asyncio import AsyncDirectory - >>> + >>> >>> io_context = asio.io_context() >>> async_dir = AsyncDirectory(io_context) - >>> + >>> >>> def on_list(result): ... if result.success: ... print(f"Found {len(result.value)} entries:") @@ -690,7 +690,7 @@ This class provides methods for creating, removing, and listing directories asyn ... print(f" - {path}") ... else: ... print(f"Error: {result.error_message}") - >>> + >>> >>> async_dir.async_list_contents(".", on_list) >>> io_context.run() )") @@ -721,7 +721,7 @@ This class provides methods for creating, removing, and listing directories asyn ... print("Directory created successfully") ... else: ... print(f"Error: {result.error_message}") - >>> + >>> >>> async_dir.async_create("new_directory", on_create) )") .def( @@ -748,7 +748,7 @@ This class provides methods for creating, removing, and listing directories asyn ... print("Directory removed successfully") ... else: ... print(f"Error: {result.error_message}") - >>> + >>> >>> async_dir.async_remove("old_directory", on_remove) )") .def( @@ -778,7 +778,7 @@ This class provides methods for creating, removing, and listing directories asyn ... print(f" - {path}") ... else: ... print(f"Error: {result.error_message}") - >>> + >>> >>> async_dir.async_list_contents(".", on_list) )") .def( @@ -808,7 +808,7 @@ This class provides methods for creating, removing, and listing directories asyn ... print("Directory does not exist") ... else: ... print(f"Error: {result.error_message}") - >>> + >>> >>> async_dir.async_exists("my_directory", on_exists) )") .def( @@ -960,4 +960,4 @@ This class provides methods for creating, removing, and listing directories asyn ... else: ... print(f"Error: {result.error_message}") )"); -} \ No newline at end of file +} diff --git a/python/io/compress.cpp b/python/io/compress.cpp index c002a384..02fab6e0 100644 --- a/python/io/compress.cpp +++ b/python/io/compress.cpp @@ -514,4 +514,4 @@ This class calculates the total size of a ZIP archive. >>> io_context.run() >>> print(f"File removed successfully: {success}") )"); -} \ No newline at end of file +} diff --git a/python/io/dirstack.cpp b/python/io/dirstack.cpp index 84913509..57264807 100644 --- a/python/io/dirstack.cpp +++ b/python/io/dirstack.cpp @@ -146,17 +146,17 @@ allowing you to maintain a directory stack for easy navigation. Examples: >>> import asio >>> from atom.io.dirstack import DirectoryStack - >>> + >>> >>> io_context = asio.io_context() >>> dirstack = DirectoryStack(io_context) - >>> + >>> >>> # Push current directory and change to a new one >>> def on_push(error): ... if not error: ... print("Successfully changed directory") ... else: ... print(f"Error: {error.message()}") - >>> + >>> >>> dirstack.async_pushd("/tmp", on_push) >>> io_context.run() )") @@ -185,7 +185,7 @@ allowing you to maintain a directory stack for easy navigation. ... print("Successfully changed directory") ... else: ... print(f"Error: {error.message()}") - >>> + >>> >>> dirstack.async_pushd("/tmp", on_push) )") .def( @@ -203,11 +203,11 @@ This method returns a coroutine-compatible Task object. Examples: >>> import asyncio - >>> + >>> >>> async def change_dir(): ... await dirstack.pushd("/tmp").__await__() ... print("Directory changed") - >>> + >>> >>> asyncio.run(change_dir()) )") .def( @@ -230,7 +230,7 @@ This method returns a coroutine-compatible Task object. ... print("Successfully changed back to previous directory") ... else: ... print(f"Error: {error.message()}") - >>> + >>> >>> dirstack.async_popd(on_pop) )") .def("popd", &atom::io::DirectoryStack::popd, @@ -243,11 +243,11 @@ This method returns a coroutine-compatible Task object. Examples: >>> import asyncio - >>> + >>> >>> async def pop_dir(): ... await dirstack.popd().__await__() ... print("Returned to previous directory") - >>> + >>> >>> asyncio.run(pop_dir()) )") .def("peek", &atom::io::DirectoryStack::peek, @@ -322,7 +322,7 @@ This method returns a coroutine-compatible Task object. ... print("Changed to directory at index") ... else: ... print(f"Error: {error.message()}") - >>> + >>> >>> dirstack.async_goto_index(2, on_goto) # Change to the directory at index 2 )") .def("goto_index", &atom::io::DirectoryStack::gotoIndex, @@ -339,11 +339,11 @@ This method returns a coroutine-compatible Task object. Examples: >>> import asyncio - >>> + >>> >>> async def goto_dir(): ... await dirstack.goto_index(2).__await__() ... print("Changed to directory at index 2") - >>> + >>> >>> asyncio.run(goto_dir()) )") .def( @@ -369,7 +369,7 @@ This method returns a coroutine-compatible Task object. ... print("Stack saved to file") ... else: ... print(f"Error saving stack: {error.message()}") - >>> + >>> >>> dirstack.async_save_stack_to_file("dirstack.txt", on_save) )") .def("save_stack_to_file", &atom::io::DirectoryStack::saveStackToFile, @@ -386,11 +386,11 @@ This method returns a coroutine-compatible Task object. Examples: >>> import asyncio - >>> + >>> >>> async def save_stack(): ... await dirstack.save_stack_to_file("dirstack.txt").__await__() ... print("Stack saved to file") - >>> + >>> >>> asyncio.run(save_stack()) )") .def( @@ -416,7 +416,7 @@ This method returns a coroutine-compatible Task object. ... print("Stack loaded from file") ... else: ... print(f"Error loading stack: {error.message()}") - >>> + >>> >>> dirstack.async_load_stack_from_file("dirstack.txt", on_load) )") .def("load_stack_from_file", @@ -433,11 +433,11 @@ This method returns a coroutine-compatible Task object. Examples: >>> import asyncio - >>> + >>> >>> async def load_stack(): ... await dirstack.load_stack_from_file("dirstack.txt").__await__() ... print("Stack loaded from file") - >>> + >>> >>> asyncio.run(load_stack()) )") .def("size", &atom::io::DirectoryStack::size, @@ -485,7 +485,7 @@ This method returns a coroutine-compatible Task object. Examples: >>> def on_get_dir(path): ... print(f"Current directory: {path}") - >>> + >>> >>> dirstack.async_get_current_directory(on_get_dir) )") .def("get_current_directory", @@ -499,11 +499,11 @@ This method returns a coroutine-compatible Task object. Examples: >>> import asyncio - >>> + >>> >>> async def print_current_dir(): ... path = await dirstack.get_current_directory().__await__() ... print(f"Current directory: {path}") - >>> + >>> >>> asyncio.run(print_current_dir()) )") .def("__len__", &atom::io::DirectoryStack::size, @@ -533,7 +533,7 @@ This method returns a coroutine-compatible Task object. Examples: >>> import asio >>> from atom.io.dirstack import create_directory_stack - >>> + >>> >>> io_context = asio.io_context() >>> dirstack = create_directory_stack(io_context) )"); @@ -579,4 +579,4 @@ This method returns a coroutine-compatible Task object. ... else: ... print("Failed to change directory") )"); -} \ No newline at end of file +} diff --git a/python/io/glob.cpp b/python/io/glob.cpp index 1771c6b8..e91ce9ba 100644 --- a/python/io/glob.cpp +++ b/python/io/glob.cpp @@ -46,19 +46,19 @@ supporting both synchronous and asynchronous operations. Examples: >>> import asio >>> from atom.io.glob import AsyncGlob - >>> + >>> >>> # Create an io_context and glob object >>> io_context = asio.io_context() >>> glob = AsyncGlob(io_context) - >>> + >>> >>> # Example of synchronous usage >>> matches = glob.glob_sync("*.txt") >>> print(f"Found {len(matches)} text files") - >>> + >>> >>> # Example of asynchronous usage with callback >>> def on_files_found(files): ... print(f"Found {len(files)} files") - >>> + >>> >>> glob.glob("*.py", on_files_found, recursive=True) >>> io_context.run() )") @@ -92,7 +92,7 @@ supporting both synchronous and asynchronous operations. ... print(f"Matched {len(files)} files") ... for file in files: ... print(f" - {file}") - >>> + >>> >>> glob.glob("*.py", print_matches) >>> io_context.run() # Run the ASIO io_context )") @@ -259,4 +259,4 @@ This is a convenience function that works like Python's glob.glob() with recursi >>> escape("file[1].txt") # Escapes the brackets 'file\\[1\\].txt' )"); -} \ No newline at end of file +} diff --git a/python/pybind11_json.hpp b/python/pybind11_json.hpp index 71ff1c60..9ff0242c 100644 --- a/python/pybind11_json.hpp +++ b/python/pybind11_json.hpp @@ -206,4 +206,4 @@ struct type_caster { } // namespace detail } // namespace pybind11 -#endif \ No newline at end of file +#endif diff --git a/python/search/__init__.py b/python/search/__init__.py index 9d600c45..1c0d8148 100644 --- a/python/search/__init__.py +++ b/python/search/__init__.py @@ -1 +1 @@ -# Auto-generated __init__.py for search module \ No newline at end of file +# Auto-generated __init__.py for search module diff --git a/python/search/cache.cpp b/python/search/cache.cpp index 23e97b86..25299432 100644 --- a/python/search/cache.cpp +++ b/python/search/cache.cpp @@ -355,4 +355,4 @@ This class provides methods to insert, retrieve, and manage cached string resour Returns: A FloatCache object. )"); -} \ No newline at end of file +} diff --git a/python/search/lru.cpp b/python/search/lru.cpp index 8558ea9f..f8d18605 100644 --- a/python/search/lru.cpp +++ b/python/search/lru.cpp @@ -633,4 +633,4 @@ Thread-safe LRU cache implementation optimized for floating-point values. Returns: A new FloatCache instance )"); -} \ No newline at end of file +} diff --git a/python/search/mysql.cpp b/python/search/mysql.cpp index 43408482..785c27c4 100644 --- a/python/search/mysql.cpp +++ b/python/search/mysql.cpp @@ -463,4 +463,4 @@ Provides connection management and various query execution methods. Returns: ResultSet object with paginated results )"); -} \ No newline at end of file +} diff --git a/python/search/search.cpp b/python/search/search.cpp index f50014ec..711e3efd 100644 --- a/python/search/search.cpp +++ b/python/search/search.cpp @@ -211,4 +211,4 @@ Supports operators AND, OR, NOT, and parentheses. Raises: IOError: If the file cannot be read )"); -} \ No newline at end of file +} diff --git a/python/search/sqlite.cpp b/python/search/sqlite.cpp index ff6d2f88..f1565a19 100644 --- a/python/search/sqlite.cpp +++ b/python/search/sqlite.cpp @@ -255,4 +255,4 @@ from SQLite databases. Returns: The number of rows modified )"); -} \ No newline at end of file +} diff --git a/python/search/ttl.cpp b/python/search/ttl.cpp index 56433b0a..817ef28f 100644 --- a/python/search/ttl.cpp +++ b/python/search/ttl.cpp @@ -91,7 +91,7 @@ PYBIND11_MODULE(ttl, m) { m, "StringCache", R"(A Time-to-Live (TTL) Cache with string keys and string values. -This class implements a TTL cache with an LRU eviction policy. Items in the cache +This class implements a TTL cache with an LRU eviction policy. Items in the cache expire after a specified duration and are evicted when the cache exceeds its maximum capacity. Args: @@ -201,4 +201,4 @@ This cache implements an LRU eviction policy with automatic expiration of items. Returns: A new FloatCache instance )"); -} \ No newline at end of file +} diff --git a/python/sysinfo/__init__.py b/python/sysinfo/__init__.py index 51240b02..dfd68b92 100644 --- a/python/sysinfo/__init__.py +++ b/python/sysinfo/__init__.py @@ -1 +1 @@ -# Auto-generated __init__.py for sysinfo module \ No newline at end of file +# Auto-generated __init__.py for sysinfo module diff --git a/python/sysinfo/battery.cpp b/python/sysinfo/battery.cpp index 5571e330..41d254f5 100644 --- a/python/sysinfo/battery.cpp +++ b/python/sysinfo/battery.cpp @@ -76,14 +76,14 @@ voltage, current, and other properties. "Battery serial number") .def("get_battery_health", &BatteryInfo::getBatteryHealth, R"(Calculate battery health (0-100%). - + Returns: Battery health percentage. )") .def("get_estimated_time_remaining", &BatteryInfo::getEstimatedTimeRemaining, R"(Estimate remaining usage time. - + Returns: Estimated time remaining in hours. )") @@ -235,18 +235,18 @@ This class provides static methods to start and stop battery monitoring. Examples: >>> from atom.sysinfo import battery >>> import time - >>> + >>> >>> # Define callback function for battery updates >>> def on_battery_update(info): ... print(f"Battery level: {info.battery_life_percent}%") ... print(f"Charging: {info.is_charging}") - ... + ... >>> # Start monitoring with 2 second interval >>> battery.BatteryMonitor.start_monitoring(on_battery_update, 2000) - >>> + >>> >>> # Let it run for a while >>> time.sleep(10) - >>> + >>> >>> # Stop monitoring >>> battery.BatteryMonitor.stop_monitoring() )") @@ -276,7 +276,7 @@ This class provides static methods to start and stop battery monitoring. >>> # Define a callback function >>> def on_battery_update(info): ... print(f"Battery update - Level: {info.battery_life_percent}%") - ... + ... >>> # Start monitoring with 1 second intervals >>> battery.BatteryMonitor.start_monitoring(on_battery_update) )") @@ -301,14 +301,14 @@ and alert functionality. >>> from atom.sysinfo import battery >>> # Get the singleton instance >>> manager = battery.BatteryManager.get_instance() - >>> + >>> >>> # Set up alert callback >>> def on_battery_alert(alert_msg, info): ... print(f"Battery alert: {alert_msg}") ... print(f"Current level: {info.battery_life_percent}%") - ... + ... >>> manager.set_alert_callback(on_battery_alert) - >>> + >>> >>> # Start monitoring >>> manager.start_monitoring(5000) # Check every 5 seconds )") @@ -364,17 +364,17 @@ and alert functionality. Args: callback: Function to call when a battery alert is triggered. - The callback receives two arguments: alert message (str) + The callback receives two arguments: alert message (str) and battery info (BatteryInfo). Examples: >>> from atom.sysinfo import battery >>> mgr = battery.BatteryManager.get_instance() - >>> + >>> >>> def alert_handler(alert_msg, info): ... print(f"Alert: {alert_msg}") ... print(f"Battery level: {info.battery_life_percent}%") - ... + ... >>> mgr.set_alert_callback(alert_handler) )") .def("set_alert_settings", &BatteryManager::setAlertSettings, @@ -390,7 +390,7 @@ and alert functionality. >>> settings = battery.BatteryAlertSettings() >>> settings.low_battery_threshold = 25.0 >>> settings.high_temp_threshold = 42.0 - >>> + >>> >>> # Apply settings >>> mgr = battery.BatteryManager.get_instance() >>> mgr.set_alert_settings(settings) @@ -465,11 +465,11 @@ and alert functionality. Examples: >>> from atom.sysinfo import battery >>> import datetime - >>> + >>> >>> mgr = battery.BatteryManager.get_instance() >>> # Get the last 10 history entries >>> history = mgr.get_history(10) - >>> + >>> >>> for timestamp, info in history: ... # Convert timestamp to readable format ... time_str = datetime.datetime.fromtimestamp( @@ -490,7 +490,7 @@ This class provides static methods to get and set the current power plan. >>> # Get current power plan >>> current_plan = battery.PowerPlanManager.get_current_power_plan() >>> print(f"Current power plan: {current_plan}") - >>> + >>> >>> # Switch to power saver >>> success = battery.PowerPlanManager.set_power_plan(battery.PowerPlan.POWER_SAVER) >>> if success: @@ -724,15 +724,15 @@ provided callback and cleans up when the context is exited. Examples: >>> from atom.sysinfo import battery >>> import time - >>> + >>> >>> def process_battery_info(info): ... print(f"Battery level: {info.battery_life_percent}%") - ... + ... >>> # Use as a context manager >>> with battery.monitor_battery(process_battery_info, 2000): ... print("Monitoring battery for 10 seconds...") ... time.sleep(10) - ... + ... >>> print("Monitoring stopped") )"); @@ -815,4 +815,4 @@ provided callback and cleans up when the context is exited. >>> time_str = battery.format_time_remaining() >>> print(f"Time remaining: {time_str}") )"); -} \ No newline at end of file +} diff --git a/python/sysinfo/bios.cpp b/python/sysinfo/bios.cpp index 829a2e29..20883840 100644 --- a/python/sysinfo/bios.cpp +++ b/python/sysinfo/bios.cpp @@ -145,7 +145,7 @@ look for updates, and perform BIOS-related operations. >>> from atom.sysinfo import bios >>> # Get the singleton instance >>> bios_mgr = bios.BiosInfo.get_instance() - >>> + >>> >>> # Get basic BIOS information >>> info = bios_mgr.get_bios_info() >>> print(f"BIOS version: {info.version}") @@ -182,7 +182,7 @@ look for updates, and perform BIOS-related operations. >>> # Get cached BIOS info >>> info = bios.BiosInfo.get_instance().get_bios_info() >>> print(f"BIOS version: {info.version}") - >>> + >>> >>> # Force update and get fresh info >>> info = bios.BiosInfo.get_instance().get_bios_info(True) )", @@ -518,13 +518,13 @@ look for updates, and perform BIOS-related operations. >>> print(f"BIOS version: {summary['version']}") >>> print(f"Manufacturer: {summary['manufacturer']}") >>> print(f"Age: {summary['age_in_days']} days") - >>> + >>> >>> if summary['update_available']: ... print(f"Update available: {summary['latest_version']}") - >>> + >>> >>> if summary['warnings']: ... print("Warnings:") ... for warning in summary['warnings']: ... print(f"- {warning}") )"); -} \ No newline at end of file +} diff --git a/python/sysinfo/cpu.cpp b/python/sysinfo/cpu.cpp index 0bd29c4e..3dd01a4e 100644 --- a/python/sysinfo/cpu.cpp +++ b/python/sysinfo/cpu.cpp @@ -105,7 +105,7 @@ its frequency, temperature, and utilization. py::class_(m, "CacheSizes", R"(CPU cache size information. -This class provides information about the sizes and characteristics of the +This class provides information about the sizes and characteristics of the various CPU caches. Examples: @@ -804,7 +804,7 @@ usage, temperature, and frequency and calls the provided callback with this data Args: interval_sec: How often to check CPU status, in seconds (default: 1.0). callback: Function to call with CPU data. The callback receives six arguments: - usage (float), temperature (float), frequency (float), + usage (float), temperature (float), frequency (float), core_usage (list), core_temperatures (list), core_frequencies (list). Returns: @@ -813,16 +813,16 @@ usage, temperature, and frequency and calls the provided callback with this data Examples: >>> from atom.sysinfo import cpu >>> import time - >>> + >>> >>> # Define a callback function >>> def cpu_callback(usage, temp, freq, core_usage, core_temps, core_freqs): ... print(f"CPU Usage: {usage:.1f}%, Temp: {temp:.1f}°C, Freq: {freq:.2f} GHz") - ... + ... >>> # Use as a context manager >>> with cpu.monitor_cpu(0.5, cpu_callback): ... print("Monitoring CPU for 5 seconds...") ... time.sleep(5) - ... + ... >>> print("Monitoring stopped") )"); @@ -963,4 +963,4 @@ usage, temperature, and frequency and calls the provided callback with this data >>> print(f"AVX support: {avx_support}") >>> print(f"AVX2 support: {avx2_support}") )"); -} \ No newline at end of file +} diff --git a/python/sysinfo/disk.cpp b/python/sysinfo/disk.cpp index e716b2d9..396b34b9 100644 --- a/python/sysinfo/disk.cpp +++ b/python/sysinfo/disk.cpp @@ -145,7 +145,7 @@ and device model information. >>> all_disks = disk.get_disk_info() >>> for d in all_disks: ... print(f"{d.path}: {d.usage_percent:.1f}% used") - >>> + >>> >>> # Get only fixed disks (exclude removable) >>> fixed_disks = disk.get_disk_info(include_removable=False) )"); @@ -201,7 +201,7 @@ and usage. For more detailed information, use get_disk_info() instead. >>> devices = disk.get_storage_devices() >>> for device in devices: ... print(f"{device.model} ({device.size_bytes / (1024**3):.1f} GB) - >>> + >>> >>> # Get only fixed storage devices (exclude removable) >>> fixed_devices = disk.get_storage_devices(include_removable=False) )"); @@ -235,7 +235,7 @@ and usage. For more detailed information, use get_disk_info() instead. >>> # Get all available drives >>> drives = disk.get_available_drives() >>> print(f"Available drives: {', '.join(drives)}") - >>> + >>> >>> # Get only fixed drives >>> fixed_drives = disk.get_available_drives(include_removable=False) )"); @@ -395,19 +395,19 @@ and usage. For more detailed information, use get_disk_info() instead. Examples: >>> from atom.sysinfo import disk >>> import time - >>> + >>> >>> # Define callback function >>> def on_device_inserted(device): ... print(f"New device detected: {device.model}") ... print(f"Path: {device.device_path}") ... print(f"Size: {device.size_bytes / (1024**3):.1f} GB") - ... + ... >>> # Start monitoring with read-only policy >>> future = disk.start_device_monitoring( - ... on_device_inserted, + ... on_device_inserted, ... disk.SecurityPolicy.READ_ONLY ... ) - >>> + >>> >>> # Let it run for a while >>> try: ... print("Monitoring for devices. Insert a USB drive...") @@ -551,11 +551,11 @@ and calls the provided callback when a device is inserted. Examples: >>> from atom.sysinfo import disk >>> import time - >>> + >>> >>> # Define a callback function >>> def on_device_inserted(device): - ... print(f"New device: {device.model} ({device.size_bytes / (1024**3):.1f} GB) - >>> # Use as a context manager + ... print(f"New device: {device.model} ({device.size_bytes / (1024**3):.1f} GB) + >>> # Use as a context manager >>> with disk.monitor_devices(on_device_inserted, disk.SecurityPolicy.READ_ONLY): ... print("Monitoring for devices. Insert a USB drive...") @@ -563,7 +563,7 @@ and calls the provided callback when a device is inserted. ... time.sleep(30) # Monitor for 30 seconds ... except KeyboardInterrupt: ... print("Monitoring stopped by user") - ... + ... >>> print("Monitoring stopped") )"); @@ -770,4 +770,4 @@ and calls the provided callback when a device is inserted. >>> if most_free: ... print(f"Most free space: {most_free.path} ({most_free.free_space / (1024**3):.1f} GB free) )"); -} \ No newline at end of file +} diff --git a/python/sysinfo/memory.cpp b/python/sysinfo/memory.cpp index 94524871..ada42bd9 100644 --- a/python/sysinfo/memory.cpp +++ b/python/sysinfo/memory.cpp @@ -411,18 +411,18 @@ with updated memory information. Examples: >>> from atom.sysinfo import memory >>> import time - >>> + >>> >>> # Define a callback function >>> def on_memory_update(info): ... print(f"Memory usage: {info.memory_load_percentage:.1f}%") ... print(f"Available: {info.available_physical_memory / (1024**3):.2f} GB") - ... + ... >>> # Start monitoring >>> memory.start_memory_monitoring(on_memory_update) - >>> + >>> >>> # Let it run for a while >>> time.sleep(10) - >>> + >>> >>> # Stop monitoring >>> memory.stop_memory_monitoring() )"); @@ -452,11 +452,11 @@ Retrieves a timeline of memory statistics over a specified duration. Examples: >>> from atom.sysinfo import memory >>> import datetime - >>> + >>> >>> # Get memory timeline for 1 minute >>> timeline = memory.get_memory_timeline(datetime.timedelta(minutes=1)) >>> print(f"Collected {len(timeline)} memory snapshots") - >>> + >>> >>> # Analyze the data >>> for i, snapshot in enumerate(timeline): ... print(f"Snapshot {i}: {snapshot.memory_load_percentage:.1f}% used") @@ -590,17 +590,17 @@ the provided callback with memory information updates. Examples: >>> from atom.sysinfo import memory >>> import time - >>> + >>> >>> # Define a callback function >>> def on_memory_update(info): ... print(f"Memory usage: {info.memory_load_percentage:.1f}%") ... print(f"Available: {info.available_physical_memory / (1024**3):.2f} GB") - ... + ... >>> # Use as a context manager >>> with memory.monitor_memory(on_memory_update): ... print("Monitoring memory for 5 seconds...") ... time.sleep(5) - ... + ... >>> print("Monitoring stopped") )"); @@ -749,4 +749,4 @@ the provided callback with memory information updates. >>> for i, usage in enumerate(history): ... print(f"Sample {i+1}: {usage:.1f}%") )"); -} \ No newline at end of file +} diff --git a/python/sysinfo/os.cpp b/python/sysinfo/os.cpp index fb408051..44b61974 100644 --- a/python/sysinfo/os.cpp +++ b/python/sysinfo/os.cpp @@ -496,4 +496,4 @@ name, version, kernel version, architecture, and more. >>> bits = os.get_architecture_bits() >>> print(f"Running on a {bits}-bit architecture") )"); -} \ No newline at end of file +} diff --git a/python/sysinfo/sysinfo_printer.cpp b/python/sysinfo/sysinfo_printer.cpp index d9f547a8..4fc8e380 100644 --- a/python/sysinfo/sysinfo_printer.cpp +++ b/python/sysinfo/sysinfo_printer.cpp @@ -33,7 +33,7 @@ PYBIND11_MODULE(sysinfo_printer, m) { R"(Formats and presents system information in human-readable formats. This class provides methods to format different types of system information -into readable text, generate comprehensive system reports, and export this +into readable text, generate comprehensive system reports, and export this information to various file formats like HTML, JSON, and Markdown. Examples: @@ -43,7 +43,7 @@ information to various file formats like HTML, JSON, and Markdown. >>> # Format it as readable text >>> formatted = sysinfo_printer.SystemInfoPrinter.format_cpu_info(cpu_info) >>> print(formatted) - >>> + >>> >>> # Generate a comprehensive system report >>> full_report = sysinfo_printer.SystemInfoPrinter.generate_full_report() >>> print(full_report) @@ -202,7 +202,7 @@ software components of the system. >>> # Generate a full system report >>> report = sysinfo_printer.SystemInfoPrinter.generate_full_report() >>> print(report) - >>> + >>> >>> # Optionally, save to a file >>> with open('system_report.txt', 'w') as f: ... f.write(report) @@ -650,11 +650,11 @@ Markdown file at the specified location. ... formats=["html", "markdown"], ... report_types=["performance", "security"] ... ) - >>> + >>> >>> # Check results >>> for report_type, formats in results.items(): ... print(f"{report_type} report:") ... for format_name, result in formats.items(): ... print(f" {format_name}: {result}") )"); -} \ No newline at end of file +} diff --git a/python/sysinfo/wifi.cpp b/python/sysinfo/wifi.cpp index 476b4387..bf5dae2a 100644 --- a/python/sysinfo/wifi.cpp +++ b/python/sysinfo/wifi.cpp @@ -584,27 +584,27 @@ including download/upload speeds, latency, packet loss, and signal strength. Examples: >>> from atom.sysinfo import wifi >>> import time - >>> + >>> >>> # Simple automatic monitoring for 20 seconds >>> with wifi.monitor_network(20, 2) as monitor: ... while monitor.is_active: ... print(f"Monitoring... {monitor.elapsed_time:.1f}s elapsed, " ... f"{monitor.remaining_time:.1f}s remaining") ... monitor.update() # This will sleep for the interval - ... + ... >>> # Get results after monitoring completes >>> avg_stats = monitor.average_stats >>> print(f"Average download: {avg_stats.download_speed:.2f} MB/s") >>> print(f"Average upload: {avg_stats.upload_speed:.2f} MB/s") >>> print(f"Average latency: {avg_stats.latency:.2f} ms") - >>> + >>> >>> # Manual updating >>> with wifi.monitor_network(30, 5) as monitor: ... # Do other things and manually update periodically ... for i in range(6): ... print(f"Taking measurement {i+1}") ... monitor.update() - ... + ... >>> print(f"Collected {len(monitor.stats_history)} measurements") )"); @@ -703,17 +703,17 @@ This is a simplified ping implementation for network diagnostics. >>> from atom.sysinfo import wifi >>> # Ping a host 5 times >>> results, summary = wifi.ping("www.example.com", 5) - >>> + >>> >>> # Print summary >>> print(f"Host: {summary['host']}") >>> print(f"Packets: {summary['packets_received']}/{summary['packets_sent']}") >>> print(f"Packet loss: {summary['packet_loss']:.1f}%") - >>> + >>> >>> if summary['packets_received'] > 0: ... print(f"Latency: min={summary['min_latency']:.1f}ms, " ... f"avg={summary['avg_latency']:.1f}ms, " ... f"max={summary['max_latency']:.1f}ms") - >>> + >>> >>> # Individual results >>> for i, result in enumerate(results): ... if result['success']: @@ -721,4 +721,4 @@ This is a simplified ping implementation for network diagnostics. ... else: ... print(f"Ping {i+1}: {result['error']} ") )"); -} \ No newline at end of file +} diff --git a/python/system/__init__.py b/python/system/__init__.py index 5e0221f1..06a59dcd 100644 --- a/python/system/__init__.py +++ b/python/system/__init__.py @@ -1 +1 @@ -# Auto-generated __init__.py for system module \ No newline at end of file +# Auto-generated __init__.py for system module diff --git a/python/system/command.cpp b/python/system/command.cpp index 265a37ec..1fa1062c 100644 --- a/python/system/command.cpp +++ b/python/system/command.cpp @@ -353,7 +353,7 @@ PYBIND11_MODULE(command, m) { Examples: >>> from atom.system import command >>> results = command.execute_commands_with_common_env( - ... ["echo %HOME%", "echo %PATH%"], + ... ["echo %HOME%", "echo %PATH%"], ... {"HOME": "/home/user", "PATH": "/usr/bin"} ... ) >>> for output, status in results: @@ -471,4 +471,4 @@ This class provides methods to store, retrieve, and search for commands that hav >>> history = command.create_command_history(100) >>> history.add_command("echo Hello World", 0) )"); -} \ No newline at end of file +} diff --git a/python/system/crash_quotes.cpp b/python/system/crash_quotes.cpp index 3b955b16..09121138 100644 --- a/python/system/crash_quotes.cpp +++ b/python/system/crash_quotes.cpp @@ -261,4 +261,4 @@ It can load quotes from and save them to JSON files. return !self.empty(); }, "Support for boolean evaluation."); -} \ No newline at end of file +} diff --git a/python/system/crontab.cpp b/python/system/crontab.cpp index edff07ff..c892ddce 100644 --- a/python/system/crontab.cpp +++ b/python/system/crontab.cpp @@ -364,22 +364,22 @@ This module provides classes for managing cron jobs in both memory and the syste Examples: >>> from atom.system.crontab import CronManager, CronJob - >>> + >>> >>> # Create a new cron manager >>> manager = CronManager() - >>> + >>> >>> # Create a job that runs every day at midnight >>> job = CronJob("0 0 * * *", "backup.sh", True, "backups", "Daily backup") - >>> + >>> >>> # Add the job to the manager >>> manager.create_cron_job(job) - >>> + >>> >>> # Validate a cron expression >>> result = CronManager.validate_cron_expression("0 0 * * *") >>> if result.valid: ... print("Valid cron expression") - >>> + >>> >>> # Export jobs to system crontab >>> manager.export_to_crontab() )"; -} \ No newline at end of file +} diff --git a/python/system/env.cpp b/python/system/env.cpp index fa3138e7..3c29740d 100644 --- a/python/system/env.cpp +++ b/python/system/env.cpp @@ -87,7 +87,7 @@ PYBIND11_MODULE(env, m) { std::shared_ptr>( m, "ScopedEnv", R"(Temporary environment variable scope. - + When this object is created, it sets the specified environment variable. When the object is destroyed, the original value is restored.)") .def(py::init(), @@ -792,4 +792,4 @@ and command-line arguments. >>> print(f"System: {info['system']} ({info['arch']}) ") >>> print(f"User: {info['user']} on {info['host']}") )"); -} \ No newline at end of file +} diff --git a/python/system/gpio.cpp b/python/system/gpio.cpp index 8344cab7..5ff60b1a 100644 --- a/python/system/gpio.cpp +++ b/python/system/gpio.cpp @@ -290,4 +290,4 @@ making it easier to work with related pins. Returns: The corresponding edge as a string. )"); -} \ No newline at end of file +} diff --git a/python/system/pidwatcher.cpp b/python/system/pidwatcher.cpp index ffd98b0f..dfd7ac59 100644 --- a/python/system/pidwatcher.cpp +++ b/python/system/pidwatcher.cpp @@ -849,4 +849,4 @@ process, stop monitoring, and switch the target process. >>> for proc in high_mem: ... print(f"{proc.name}: {proc.memory_usage/1024:.1f} MB") )"); -} \ No newline at end of file +} diff --git a/python/system/power.cpp b/python/system/power.cpp index 2c03c5c1..dc774066 100644 --- a/python/system/power.cpp +++ b/python/system/power.cpp @@ -154,4 +154,4 @@ This function ensures the brightness level is clamped between 0 and 100. >>> # Values outside the range are clamped to 0-100 >>> power.set_screen_brightness_safely(150) # Will set to 100 )"); -} \ No newline at end of file +} diff --git a/python/system/priority.cpp b/python/system/priority.cpp index e6a368f8..9221007f 100644 --- a/python/system/priority.cpp +++ b/python/system/priority.cpp @@ -136,14 +136,14 @@ Different policies provide different behaviors for thread execution. >>> import threading >>> # Set current thread to high priority >>> priority.set_thread_priority(priority.PriorityLevel.HIGHEST) - >>> + >>> >>> # Create thread and set its priority (using native handle) >>> def worker(): ... # Get native handle and set priority (platform-specific code) ... thread_handle = threading.get_native_id() # This is simplified ... priority.set_thread_priority(priority.PriorityLevel.ABOVE_NORMAL, thread_handle) ... # Thread work... - ... + ... >>> t = threading.Thread(target=worker) >>> t.start() )"); @@ -232,14 +232,14 @@ Different policies provide different behaviors for thread execution. Examples: >>> from atom.system import priority >>> import time - >>> + >>> >>> # Callback function for priority changes >>> def on_priority_change(level): ... print(f"Process priority changed to: {level}") - ... + ... >>> # Monitor process 1234 for priority changes >>> priority.start_priority_monitor(1234, on_priority_change) - >>> + >>> >>> # Keep the program running to receive callbacks >>> try: ... while True: @@ -312,7 +312,7 @@ Different policies provide different behaviors for thread execution. >>> from atom.system import priority >>> cpu_count = priority.get_available_cpu_count() >>> print(f"This system has {cpu_count} CPU cores") - >>> + >>> >>> # Pin process to first half of available cores >>> first_half = list(range(cpu_count // 2)) >>> priority.set_process_affinity(first_half) @@ -400,7 +400,7 @@ priority and restores it when the context is exited. Examples: >>> from atom.system import priority >>> import time - >>> + >>> >>> # Temporarily run with high priority >>> with priority.thread_priority(priority.PriorityLevel.HIGHEST): ... # This code runs with high priority @@ -463,7 +463,7 @@ priority and restores it when the context is exited. Examples: >>> from atom.system import priority >>> import time - >>> + >>> >>> # Temporarily run with high priority >>> with priority.process_priority(priority.PriorityLevel.HIGHEST): ... # This code runs with high priority @@ -506,16 +506,16 @@ priority and restores it when the context is exited. Examples: >>> from atom.system import priority - >>> + >>> >>> def compute_something(): ... result = 0 ... for i in range(10000000): ... result += i ... return result - ... + ... >>> # Run with high priority >>> result = priority.run_with_priority( - ... priority.PriorityLevel.HIGHEST, + ... priority.PriorityLevel.HIGHEST, ... compute_something ... ) >>> print(f"Result: {result}") @@ -581,21 +581,21 @@ priority and restores it when the context is exited. Examples: >>> from atom.system import priority >>> import threading - >>> + >>> >>> def worker(cpu_id): ... # Pin this thread to the specified CPU ... priority.pin_thread_to_cpus([cpu_id]) ... # Now this thread will only run on the specified CPU ... for i in range(10): ... print(f"Thread on CPU {cpu_id}: {i}") - ... + ... >>> # Create threads and pin each to a different CPU >>> threads = [] >>> for i in range(4): # Create 4 threads ... t = threading.Thread(target=worker, args=(i,)) ... threads.append(t) ... t.start() - ... + ... >>> # Wait for all threads to complete >>> for t in threads: ... t.join() @@ -646,4 +646,4 @@ priority and restores it when the context is exited. >>> cpu_ids = priority.get_thread_affinity() >>> print(f"Current thread can run on these CPUs: {cpu_ids}") )"); -} \ No newline at end of file +} diff --git a/python/system/process.cpp b/python/system/process.cpp index eaeee478..27bc1d29 100644 --- a/python/system/process.cpp +++ b/python/system/process.cpp @@ -1190,4 +1190,4 @@ with the specified command. This function is only available on Windows. ... time.sleep(10) # Wait for events ... # Monitoring stops automatically when leaving the block )"); -} \ No newline at end of file +} diff --git a/python/system/process_info.cpp b/python/system/process_info.cpp index 5a7b2ddc..5337163e 100644 --- a/python/system/process_info.cpp +++ b/python/system/process_info.cpp @@ -154,7 +154,7 @@ including protocol, local and remote addresses, ports, and connection status. }); // FileDescriptor struct binding - py::class_(m, "FileDescriptor", + py::class_(m, "FileDescriptor", R"(Represents a file descriptor or handle used by a process. This structure contains information about file descriptors opened by a process, @@ -171,13 +171,13 @@ including file descriptor ID, file path, type, and access mode. >>> print(f"FD {fd.fd}: {fd.path} ({fd.type}, {fd.mode}) ") )") .def(py::init<>()) - .def_readwrite("fd", &atom::system::FileDescriptor::fd, + .def_readwrite("fd", &atom::system::FileDescriptor::fd, "File descriptor/handle ID") - .def_readwrite("path", &atom::system::FileDescriptor::path, + .def_readwrite("path", &atom::system::FileDescriptor::path, "File path") - .def_readwrite("type", &atom::system::FileDescriptor::type, + .def_readwrite("type", &atom::system::FileDescriptor::type, "File type (regular, socket, pipe, etc.)") - .def_readwrite("mode", &atom::system::FileDescriptor::mode, + .def_readwrite("mode", &atom::system::FileDescriptor::mode, "Access mode (r, w, rw, etc.)") .def("__repr__", [](const atom::system::FileDescriptor& fd) { return ">> print(f"Sample process: {sample.name} (PID: {sample.pid}) ") >>> print(f"CPU: {sample.resources.cpu_usage}%, Memory: {sample.resources.mem_usage / 1024 / 1024} MB") )"); -} \ No newline at end of file +} diff --git a/python/system/process_manager.cpp b/python/system/process_manager.cpp index f931cf9d..16739ba8 100644 --- a/python/system/process_manager.cpp +++ b/python/system/process_manager.cpp @@ -484,4 +484,4 @@ This function returns a context manager that automatically handles process creat } throw py::key_error("Invalid key: " + name); }); -} \ No newline at end of file +} diff --git a/python/system/registry.cpp b/python/system/registry.cpp index ae0aab71..565139bd 100644 --- a/python/system/registry.cpp +++ b/python/system/registry.cpp @@ -434,4 +434,4 @@ and event callbacks. >>> if registry.is_success(result): ... print("Registry initialized successfully") )"); -} \ No newline at end of file +} diff --git a/python/system/signal.cpp b/python/system/signal.cpp index 11ac43b1..e1fb17d2 100644 --- a/python/system/signal.cpp +++ b/python/system/signal.cpp @@ -67,13 +67,13 @@ PYBIND11_MODULE(signal, m) { m, "SignalHandlerRegistry", R"(Singleton class to manage signal handlers and dispatch signals. -This class handles registering and dispatching signal handlers with priorities. +This class handles registering and dispatching signal handlers with priorities. It also provides a mechanism to set up default crash signal handlers. Examples: >>> from atom.system import signal >>> registry = signal.SignalHandlerRegistry.get_instance() - >>> + >>> >>> # Define a simple handler >>> def handle_interrupt(sig_id): ... print(f"Received interrupt signal: {sig_id}") @@ -90,7 +90,7 @@ It also provides a mechanism to set up default crash signal handlers. Reference to the singleton SignalHandlerRegistry instance. )") */ - + .def( "set_signal_handler", &SignalHandlerRegistry::setSignalHandler, py::arg("signal"), py::arg("handler"), py::arg("priority") = 0, @@ -257,7 +257,7 @@ in a separate thread to ensure thread safety and avoid blocking signal handling. Examples: >>> from atom.system import signal >>> manager = signal.SafeSignalManager.get_instance() - >>> + >>> >>> # Define a signal handler function >>> def handle_signal(sig_id): ... print(f"Handled signal {sig_id} safely in separate thread") @@ -294,7 +294,7 @@ in a separate thread to ensure thread safety and avoid blocking signal handling. Examples: >>> def safe_handler(sig_id): ... print(f"Safe handling of signal {sig_id}") - ... + ... >>> handler_id = manager.add_safe_signal_handler(15, safe_handler) )") .def("remove_safe_signal_handler_by_id", @@ -518,4 +518,4 @@ in a separate thread to ensure thread safety and avoid blocking signal handling. >>> registry = signal.SignalHandlerRegistry.get_instance() >>> registry.set_signal_handler(signal.SIGTERM, handler) )"); -} \ No newline at end of file +} diff --git a/python/system/signal_monitor.cpp b/python/system/signal_monitor.cpp index e7d76b5f..9a630ae4 100644 --- a/python/system/signal_monitor.cpp +++ b/python/system/signal_monitor.cpp @@ -127,21 +127,21 @@ and register callbacks for various signal events. Examples: >>> from atom.system import signal_monitor >>> import time - >>> + >>> >>> # Get the singleton instance >>> monitor = signal_monitor.get_instance() - >>> + >>> >>> # Start monitoring all signals >>> monitor.start() - >>> + >>> >>> # Wait a bit to collect stats >>> time.sleep(5) - >>> + >>> >>> # Get a snapshot of signal statistics >>> stats = monitor.get_stat_snapshot() >>> for signal_id, signal_stats in stats.items(): ... print(f"Signal {signal_id}: Received {signal_stats.received}") - >>> + >>> >>> # Stop monitoring >>> monitor.stop() )") @@ -165,7 +165,7 @@ and register callbacks for various signal events. >>> # Start monitoring all signals, checking every 500ms >>> monitor = signal_monitor.get_instance() >>> monitor.start(500) - >>> + >>> >>> # Or monitor specific signals >>> import signal >>> monitor.start(1000, [signal.SIGINT, signal.SIGTERM]) @@ -219,12 +219,12 @@ and register callbacks for various signal events. Examples: >>> from atom.system import signal_monitor >>> import signal - >>> + >>> >>> # Define a callback function >>> def on_signal_threshold(signal_id, stats): ... print(f"Signal {signal_id} threshold exceeded!") ... print(f"Received: {stats.received}, Errors: {stats.handler_errors}") - ... + ... >>> # Register callback for SIGINT - triggered after 5 occurrences >>> monitor = signal_monitor.get_instance() >>> callback_id = monitor.add_threshold_callback( @@ -267,12 +267,12 @@ and register callbacks for various signal events. >>> from atom.system import signal_monitor >>> import signal >>> import time - >>> + >>> >>> # Define a callback function >>> def on_signal_inactivity(signal_id, stats): ... print(f"Signal {signal_id} has been inactive for too long!") ... print(f"Last received: {stats.last_received}") - ... + ... >>> # Register callback for SIGTERM - triggered after 30 seconds of inactivity >>> monitor = signal_monitor.get_instance() >>> callback_id = monitor.add_inactivity_callback( @@ -293,15 +293,15 @@ and register callbacks for various signal events. Examples: >>> from atom.system import signal_monitor >>> monitor = signal_monitor.get_instance() - >>> + >>> >>> # Add a callback >>> def callback(signal_id, stats): ... print(f"Signal {signal_id} event") - ... + ... >>> callback_id = monitor.add_threshold_callback( ... signal.SIGINT, 5, 0, callback ... ) - >>> + >>> >>> # Later, remove the callback >>> success = monitor.remove_callback(callback_id) >>> print(f"Callback removed: {success}") @@ -315,7 +315,7 @@ and register callbacks for various signal events. Examples: >>> from atom.system import signal_monitor >>> monitor = signal_monitor.get_instance() - >>> + >>> >>> # Get stats for all monitored signals >>> stats = monitor.get_stat_snapshot() >>> for signal_id, signal_stats in stats.items(): @@ -333,7 +333,7 @@ and register callbacks for various signal events. Examples: >>> from atom.system import signal_monitor >>> monitor = signal_monitor.get_instance() - >>> + >>> >>> # Get list of monitored signals >>> signals = monitor.get_monitored_signals() >>> print(f"Monitoring {len(signals)} signals: {signals}") @@ -344,7 +344,7 @@ and register callbacks for various signal events. Examples: >>> from atom.system import signal_monitor >>> monitor = signal_monitor.get_instance() - >>> + >>> >>> # Reset all stats to zero >>> monitor.reset_all_stats() >>> print("All signal statistics have been reset") @@ -390,7 +390,7 @@ This is a convenience function to get the SignalMonitor instance and start it. >>> from atom.system import signal_monitor >>> # Start monitoring all signals >>> signal_monitor.start_monitoring() - >>> + >>> >>> # Or monitor specific signals with custom interval >>> import signal >>> signal_monitor.start_monitoring(500, [signal.SIGINT, signal.SIGTERM]) @@ -519,17 +519,17 @@ and removes the monitoring when the context is exited. Examples: >>> from atom.system import signal_monitor >>> import signal - >>> + >>> >>> def on_signal_event(signal_id, stats): ... print(f"Signal {signal_id} event detected!") - ... + ... >>> # Use as a context manager to monitor signals >>> with signal_monitor.monitor_signals( ... [signal.SIGINT, signal.SIGTERM], on_signal_event, 500 ... ): ... print("Monitoring signals in this block...") ... # Your code here - ... + ... >>> print("Signal monitoring stopped") )"); @@ -602,19 +602,19 @@ and removes the monitoring when the context is exited. >>> import threading >>> import os >>> import time - >>> + >>> >>> # Set up a thread to send a signal after 1 second >>> def send_test_signal(pid, sig_to_send): ... time.sleep(1) ... os.kill(pid, sig_to_send) - ... + ... >>> # Note: SIGUSR1 might not be available on Windows without specific setup. >>> # Using SIGINT for a more portable example, though be careful with terminal interruption. >>> # For a real test, use a signal like SIGUSR1 if available and handled. >>> test_signal = signal.SIGUSR1 if hasattr(signal, "SIGUSR1") else signal.SIGINT >>> pid = os.getpid() >>> threading.Thread(target=send_test_signal, args=(pid, test_signal)).start() - >>> + >>> >>> # Wait for the signal with 2 second timeout >>> print(f"Waiting for signal {test_signal}...") >>> if signal_monitor.wait_for_signal(test_signal, 2000): @@ -779,11 +779,11 @@ context is entered until get_rate() is called. >>> import signal >>> import time >>> import os - >>> + >>> >>> # Note: SIGUSR1 might not be available on Windows. >>> test_signal = signal.SIGUSR1 if hasattr(signal, "SIGUSR1") else signal.SIGINT >>> pid = os.getpid() - >>> + >>> >>> # Use as a context manager to track signal rate >>> with signal_monitor.track_signal_rate(test_signal) as tracker: ... # Generate some signals @@ -800,9 +800,9 @@ context is entered until get_rate() is called. ... sig_thread.start() ... time.sleep(0.6) // Allow signals to be sent and processed ... sig_thread.join() - ... + ... ... // Get the rate ... rate = tracker.get_rate() ... print(f"Signal rate for {test_signal}: {rate:.2f} signals per second") )"); -} \ No newline at end of file +} diff --git a/python/system/signal_utils.cpp b/python/system/signal_utils.cpp index 1bcfd8d6..a3cbf300 100644 --- a/python/system/signal_utils.cpp +++ b/python/system/signal_utils.cpp @@ -70,7 +70,7 @@ they're properly cleaned up when the object goes out of scope. >>> def handle_sigint(signal_id): ... print(f"Caught signal {signal_utils.get_signal_name(signal_id)}") ... return True # Continue handling - ... + ... >>> # Create a scoped handler for SIGINT >>> handler = signal_utils.ScopedSignalHandler(signal_utils.SIGINT, handle_sigint) >>> # The handler will be automatically removed when it goes out of scope @@ -96,19 +96,19 @@ When the group is destroyed, all its handlers are automatically removed. >>> from atom.system import signal_utils >>> # Create a signal group >>> group = signal_utils.SignalGroup("app_signals") - >>> + >>> >>> def handle_int(signal_id): ... print("Handling SIGINT") ... return True - ... + ... >>> def handle_term(signal_id): ... print("Handling SIGTERM") ... return True - ... + ... >>> # Add handlers to the group >>> group.add_handler(signal_utils.SIGINT, handle_int) >>> group.add_handler(signal_utils.SIGTERM, handle_term) - >>> + >>> >>> # All handlers will be removed when group is destroyed )") .def(py::init(), py::arg("group_name") = "", @@ -144,11 +144,11 @@ When the group is destroyed, all its handlers are automatically removed. Examples: >>> from atom.system import signal_utils >>> group = signal_utils.SignalGroup("app_signals") - >>> + >>> >>> def handle_signal(signal_id): ... print(f"Handling signal {signal_id}") ... return True - ... + ... >>> handler_id = group.add_handler(signal_utils.SIGINT, handle_signal) >>> print(f"Registered handler with ID: {handler_id}") )") @@ -165,11 +165,11 @@ When the group is destroyed, all its handlers are automatically removed. Examples: >>> from atom.system import signal_utils >>> group = signal_utils.SignalGroup() - >>> + >>> >>> def handle_signal(signal_id): ... print(f"Handling signal {signal_id}") ... return True - ... + ... >>> handler_id = group.add_handler(signal_utils.SIGINT, handle_signal) >>> # Later, when we want to remove just this handler: >>> success = group.remove_handler(handler_id) @@ -188,11 +188,11 @@ When the group is destroyed, all its handlers are automatically removed. Examples: >>> from atom.system import signal_utils >>> group = signal_utils.SignalGroup() - >>> + >>> >>> # Add multiple handlers for SIGINT >>> group.add_handler(signal_utils.SIGINT, lambda sig: True) >>> group.add_handler(signal_utils.SIGINT, lambda sig: True) - >>> + >>> >>> # Remove all SIGINT handlers >>> removed = group.remove_signal_handlers(signal_utils.SIGINT) >>> print(f"Removed {removed} handlers") @@ -206,11 +206,11 @@ When the group is destroyed, all its handlers are automatically removed. Examples: >>> from atom.system import signal_utils >>> group = signal_utils.SignalGroup() - >>> + >>> >>> # Add handlers for different signals >>> group.add_handler(signal_utils.SIGINT, lambda sig: True) >>> group.add_handler(signal_utils.SIGTERM, lambda sig: True) - >>> + >>> >>> # Later, remove all handlers >>> removed = group.remove_all() >>> print(f"Removed {removed} handlers") @@ -224,10 +224,10 @@ When the group is destroyed, all its handlers are automatically removed. Examples: >>> from atom.system import signal_utils >>> group = signal_utils.SignalGroup() - >>> + >>> >>> group.add_handler(signal_utils.SIGINT, lambda sig: True) >>> group.add_handler(signal_utils.SIGTERM, lambda sig: True) - >>> + >>> >>> handler_ids = group.get_handler_ids() >>> for signal, ids in handler_ids.items(): ... signal_name = signal_utils.get_signal_name(signal) @@ -262,11 +262,11 @@ When the group is destroyed, all its handlers are automatically removed. >>> from atom.system import signal_utils >>> # Create a signal group >>> group = signal_utils.make_signal_group("app_signals") - >>> + >>> >>> def handle_signal(signal_id): ... print(f"Handling signal {signal_id}") ... return True - ... + ... >>> group.add_handler(signal_utils.SIGINT, handle_signal) >>> # The group will be automatically cleaned up when the reference is lost )", @@ -308,12 +308,12 @@ When the group is destroyed, all its handlers are automatically removed. Examples: >>> from atom.system import signal_utils >>> import time - >>> + >>> >>> def critical_section(): ... print("Starting critical section (SIGINT blocked) ") ... time.sleep(2) # During this time, SIGINT is blocked ... print("Ending critical section") - ... + ... >>> # SIGINT will be blocked during the execution of critical_section >>> signal_utils.with_blocked_signal(signal_utils.SIGINT, critical_section) )"); @@ -383,16 +383,16 @@ When the group is destroyed, all its handlers are automatically removed. Examples: >>> from atom.system import signal_utils >>> import time - >>> + >>> >>> def handle_int(signal_id): ... print("Got SIGINT, but continuing execution") ... return True - ... + ... >>> # Use as a context manager >>> with signal_utils.handle_signal(signal_utils.SIGINT, handle_int): ... print("SIGINT will be handled specially in this block") ... time.sleep(5) # Try pressing Ctrl+C during this time - ... + ... >>> print("Back to normal signal handling") )"); @@ -469,13 +469,13 @@ When the group is destroyed, all its handlers are automatically removed. Examples: >>> from atom.system import signal_utils >>> import time - >>> + >>> >>> # Use as a context manager to block SIGINT >>> with signal_utils.block_signal(signal_utils.SIGINT): ... print("SIGINT is blocked in this block") ... print("Try pressing Ctrl+C, it won't interrupt until after the block") ... time.sleep(5) - ... + ... >>> print("SIGINT is now unblocked") )"); @@ -548,15 +548,15 @@ When the group is destroyed, all its handlers are automatically removed. Examples: >>> from atom.system import signal_utils - >>> + >>> >>> def handle_signal(signal_id): ... signal_name = signal_utils.get_signal_name(signal_id) ... print(f"Handling {signal_name}") ... return True - ... + ... >>> # Single signal handler >>> int_handler = signal_utils.create_handler(signal_utils.SIGINT, handler=handle_signal) - >>> + >>> >>> # Multiple signal handler group >>> termination_handlers = signal_utils.create_handler( ... [signal_utils.SIGTERM, signal_utils.SIGINT, signal_utils.SIGQUIT], @@ -628,10 +628,10 @@ When the group is destroyed, all its handlers are automatically removed. Examples: >>> from atom.system import signal_utils >>> import threading, time, os - >>> + >>> >>> # Ensure SIGUSR1 is available for the example >>> sig_to_test = signal_utils.SIGUSR1 if hasattr(signal_utils, "SIGUSR1") else signal_utils.SIGINT - >>> + >>> >>> def send_signal_thread_func(pid, sig): ... time.sleep(0.5) # Give capture_next_signal time to set up ... try: @@ -639,10 +639,10 @@ When the group is destroyed, all its handlers are automatically removed. ... print(f"Test thread: Sent signal {sig}") ... except Exception as e: ... print(f"Test thread: Error sending signal: {e}") - ... + ... >>> t = threading.Thread(target=send_signal_thread_func, args=(os.getpid(), sig_to_test)) >>> t.start() - >>> + >>> >>> print(f"Main thread: Waiting for signal {sig_to_test}...") >>> success, sig = signal_utils.capture_next_signal(sig_to_test, 2.0) >>> if success and sig is not None: @@ -765,4 +765,4 @@ When the group is destroyed, all its handlers are automatically removed. >>> for sig_id in available_sigs: ... print(signal_utils.get_signal_name(sig_id)) )"); -} \ No newline at end of file +} diff --git a/python/system/stat.cpp b/python/system/stat.cpp index d8fe6cd3..15e58885 100644 --- a/python/system/stat.cpp +++ b/python/system/stat.cpp @@ -414,7 +414,7 @@ constructor. >>> # Format the modification time >>> formatted_time = stat.Stat.format_time(s.mtime()) >>> print(f"Last modified: {formatted_time}") - >>> + >>> >>> # Custom time format >>> custom_format = stat.Stat.format_time(s.mtime(), "%H:%M:%S %d-%m-%Y") >>> print(f"Last modified: {custom_format}") @@ -769,4 +769,4 @@ to work with Stat objects. ... print(f"File size: {s.size()} bytes") ... print(f"Last modified: {stat.Stat.format_time(s.mtime())}") )"); -} \ No newline at end of file +} diff --git a/python/system/storage.cpp b/python/system/storage.cpp index d75dafb6..7f0f32e5 100644 --- a/python/system/storage.cpp +++ b/python/system/storage.cpp @@ -36,14 +36,14 @@ trigger registered callback functions when storage space changes. >>> from atom.system import storage >>> # Create a storage monitor >>> monitor = storage.StorageMonitor() - >>> + >>> >>> # Define a callback function >>> def on_storage_change(path): ... print(f"Storage change detected at: {path}") - ... + ... >>> # Register the callback >>> monitor.register_callback(on_storage_change) - >>> + >>> >>> # Start monitoring >>> monitor.start_monitoring() )") @@ -296,12 +296,12 @@ and then waits for the specified interval before returning. >>> from atom.system import storage >>> # Create a polling callback factory with 2-second interval >>> polling = storage.with_polling_callback(2.0) - >>> + >>> >>> # Use it to decorate our actual callback >>> @polling ... def my_callback(path): ... print(f"Storage changed: {path}") - ... + ... >>> # Register the decorated callback >>> monitor = storage.StorageMonitor() >>> monitor.register_callback(my_callback) @@ -363,7 +363,7 @@ the context and stops it when exiting. >>> from atom.system import storage >>> def notify_change(path): ... print(f"Storage changed: {path}") - ... + ... >>> # Use as a context manager >>> with storage.monitor_storage(notify_change): ... print("Monitoring storage...") @@ -372,4 +372,4 @@ the context and stops it when exiting. ... time.sleep(10) ... # Monitoring automatically stops when exiting the context )"); -} \ No newline at end of file +} diff --git a/python/system/user.cpp b/python/system/user.cpp index a32e3654..aa812e1f 100644 --- a/python/system/user.cpp +++ b/python/system/user.cpp @@ -427,4 +427,4 @@ current process. ... assert debug == "1" >>> # Original environment is restored after the with block )"); -} \ No newline at end of file +} diff --git a/python/system/voltage.cpp b/python/system/voltage.cpp index 8b692023..38096ef3 100644 --- a/python/system/voltage.cpp +++ b/python/system/voltage.cpp @@ -554,7 +554,7 @@ and power source information and calls the provided callback when changes are de Examples: >>> from atom.system import voltage >>> import time - >>> + >>> >>> # Define a callback function >>> def on_voltage_change(input_v, battery_v, sources): ... print(f"Voltage change detected!") @@ -564,12 +564,12 @@ and power source information and calls the provided callback when changes are de ... print(f"Battery voltage: {battery_v} V") ... for source in sources: ... print(f"Source: {source.name}, Type: {source.type}") - ... + ... >>> # Use as a context manager >>> with voltage.monitor_voltage_changes(0.5, on_voltage_change): ... print("Monitoring voltage changes for 10 seconds...") ... time.sleep(10) - ... + ... >>> print("Monitoring stopped") )"); -} \ No newline at end of file +} diff --git a/python/system/wregistry.cpp b/python/system/wregistry.cpp index ecf58b6c..8926a8b1 100644 --- a/python/system/wregistry.cpp +++ b/python/system/wregistry.cpp @@ -108,7 +108,7 @@ PYBIND11_MODULE(wregistry, m) { >>> from atom.system import wregistry >>> # Get values from HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run >>> values = wregistry.get_registry_values( - ... wregistry.HKEY_CURRENT_USER, + ... wregistry.HKEY_CURRENT_USER, ... "Software\\Microsoft\\Windows\\CurrentVersion\\Run" ... ) >>> for name, value in values.items(): @@ -863,4 +863,4 @@ This function prints all matching values to standard output. ... except ValueError as e: ... print(f"Error: {e}") )"); -} \ No newline at end of file +} diff --git a/python/type/__init__.py b/python/type/__init__.py index c9d5c5d5..d1f72b61 100644 --- a/python/type/__init__.py +++ b/python/type/__init__.py @@ -1 +1 @@ -# Auto-generated __init__.py for type module \ No newline at end of file +# Auto-generated __init__.py for type module diff --git a/python/type/expected.cpp b/python/type/expected.cpp index 4ce49c92..f979e89d 100644 --- a/python/type/expected.cpp +++ b/python/type/expected.cpp @@ -508,4 +508,4 @@ PYBIND11_MODULE(expected, m) { >>> exp.error() 'Something went wrong' )"); -} \ No newline at end of file +} diff --git a/python/type/json_schema.cpp b/python/type/json_schema.cpp index 504daf11..855b3128 100644 --- a/python/type/json_schema.cpp +++ b/python/type/json_schema.cpp @@ -30,7 +30,7 @@ PYBIND11_MODULE(json_schema, m) { // Bind SchemaVersion enum py::enum_(m, "SchemaVersion", R"( JSON Schema specification versions. - + Enum values: DRAFT4: JSON Schema draft 4 DRAFT6: JSON Schema draft 6 @@ -50,7 +50,7 @@ PYBIND11_MODULE(json_schema, m) { // Bind ValidationError struct py::class_(m, "ValidationError", R"( Structure representing a JSON Schema validation error. - + Attributes: message (str): Error message describing the validation failure path (str): JSON path to the location where validation failed @@ -78,7 +78,7 @@ PYBIND11_MODULE(json_schema, m) { // Bind ValidationOptions struct py::class_(m, "ValidationOptions", R"( Configuration options for JSON Schema validation. - + Attributes: fail_fast (bool): Stop on first error validate_schema (bool): Validate schema against meta-schema @@ -107,10 +107,10 @@ PYBIND11_MODULE(json_schema, m) { // Bind the JsonValidator class py::class_(m, "JsonValidator", R"( Enhanced JSON Schema validator with full JSON Schema draft support. - + This class provides methods for validating JSON instances against JSON Schemas following various draft versions of the specification. - + Args: options: Validation options @@ -163,7 +163,7 @@ PYBIND11_MODULE(json_schema, m) { Args: format_name: Name of the format - validator: Function that validates strings against this format. + validator: Function that validates strings against this format. Should take a string and return a boolean. )") .def("set_schema_manager", &JsonValidator::setSchemaManager, @@ -180,9 +180,9 @@ PYBIND11_MODULE(json_schema, m) { py::class_>( m, "SchemaManager", R"( Schema Manager for handling multiple schemas and references. - + This class manages multiple JSON schemas and resolves references between them. - + Args: options: Validation options to use for schemas @@ -338,4 +338,4 @@ PYBIND11_MODULE(json_schema, m) { ... } >>> manager = create_schema_manager(schemas) )"); -} \ No newline at end of file +} diff --git a/python/type/robin_hood.cpp b/python/type/robin_hood.cpp index 172c0246..fa3d9174 100644 --- a/python/type/robin_hood.cpp +++ b/python/type/robin_hood.cpp @@ -211,4 +211,4 @@ PYBIND11_MODULE(robin_hood, m) { >>> map["key"] 'value' )"); -} \ No newline at end of file +} diff --git a/python/type/trackable.cpp b/python/type/trackable.cpp index 401260da..32d32269 100644 --- a/python/type/trackable.cpp +++ b/python/type/trackable.cpp @@ -235,11 +235,11 @@ PYBIND11_MODULE(trackable, m) { >>> t.value += 10 >>> print(t.value) 52 - >>> + >>> >>> # With change callback >>> def on_change(old, new): ... print(f"Value changed from {old} to {new}") - ... + ... >>> t.subscribe(on_change) >>> t.value = 100 # This will trigger the callback )", @@ -286,4 +286,4 @@ PYBIND11_MODULE(trackable, m) { >>> supports_operation(t_int, "+") # Returns True >>> supports_operation(t_str, "*") # Returns False )"); -} \ No newline at end of file +} diff --git a/python/utils/__init__.py b/python/utils/__init__.py index 58ef7aff..8f304395 100644 --- a/python/utils/__init__.py +++ b/python/utils/__init__.py @@ -1 +1 @@ -# Auto-generated __init__.py for utils module \ No newline at end of file +# Auto-generated __init__.py for utils module diff --git a/python/utils/aes.cpp b/python/utils/aes.cpp index 3a1693eb..ce2896ea 100644 --- a/python/utils/aes.cpp +++ b/python/utils/aes.cpp @@ -193,4 +193,4 @@ PYBIND11_MODULE(aes, m) { >>> from atom.utils import aes >>> hash_value = aes.calculate_sha512("hello world") )"); -} \ No newline at end of file +} diff --git a/python/utils/bit.cpp b/python/utils/bit.cpp index f7416a7f..a796bd2c 100644 --- a/python/utils/bit.cpp +++ b/python/utils/bit.cpp @@ -364,4 +364,4 @@ PYBIND11_MODULE(bit, m) { >>> data = array.array('B', [0xFF, 0x0F, 0xF0, 0x00]) >>> result = bit.parallel_bit_operation(data, "count") )"); -} \ No newline at end of file +} diff --git a/python/utils/difflib.cpp b/python/utils/difflib.cpp index 9f59b8d1..82444dbf 100644 --- a/python/utils/difflib.cpp +++ b/python/utils/difflib.cpp @@ -250,4 +250,4 @@ and 1 means identical sequences. >>> difflib.get_close_matches("appel", ["ape", "apple", "peach", "puppy"]) ['apple', 'ape'] )"); -} \ No newline at end of file +} diff --git a/python/utils/error_stack.cpp b/python/utils/error_stack.cpp index 89fa0a41..2c00c2d6 100644 --- a/python/utils/error_stack.cpp +++ b/python/utils/error_stack.cpp @@ -227,23 +227,23 @@ filtering errors by module or severity, and exporting error data. Examples: >>> from atom.utils import error_stack >>> from atom.utils.error_stack import ErrorLevel, ErrorCategory - >>> + >>> >>> # Create an error stack >>> stack = error_stack.ErrorStack() - >>> + >>> >>> # Insert a simple error >>> stack.insert_error("File not found", "IO", "readFile", 42, "file_io.cpp") - >>> + >>> >>> # Insert an error with additional information >>> stack.insert_error_with_level( ... "Connection timeout", "Network", "connect", 123, "network.cpp", ... ErrorLevel.ERROR, ErrorCategory.NETWORK, 408) - >>> + >>> >>> # Get the latest error >>> latest = stack.get_latest_error() >>> if latest: ... print(f"Latest error: {latest.error_message} in {latest.module_name}") - >>> + >>> >>> # Export errors to JSON >>> json_data = stack.export_to_json() )") @@ -392,4 +392,4 @@ filtering errors by module or severity, and exporting error data. // Version information m.attr("__version__") = "1.0.0"; -} \ No newline at end of file +} diff --git a/python/utils/lcg.cpp b/python/utils/lcg.cpp index 424a0526..dbea2998 100644 --- a/python/utils/lcg.cpp +++ b/python/utils/lcg.cpp @@ -55,7 +55,7 @@ random numbers following different distributions. Args: filename: The name of the file to save the state to. - + Raises: RuntimeError: If the file cannot be opened. )") @@ -64,7 +64,7 @@ random numbers following different distributions. Args: filename: The name of the file to load the state from. - + Raises: RuntimeError: If the file cannot be opened or is corrupt. )") @@ -75,10 +75,10 @@ random numbers following different distributions. Args: min: The minimum value (inclusive). Defaults to 0. max: The maximum value (inclusive). Defaults to the maximum value of int. - + Returns: A random integer within the specified range. - + Raises: ValueError: If min > max. )") @@ -89,10 +89,10 @@ random numbers following different distributions. Args: min: The minimum value (inclusive). Defaults to 0.0. max: The maximum value (exclusive). Defaults to 1.0. - + Returns: A random double within the specified range. - + Raises: ValueError: If min >= max. )") @@ -103,10 +103,10 @@ random numbers following different distributions. Args: probability: The probability of returning true. Defaults to 0.5. - + Returns: A random boolean value. - + Raises: ValueError: If probability is not in [0,1]. )") @@ -118,10 +118,10 @@ random numbers following different distributions. Args: mean: The mean of the distribution. Defaults to 0.0. stddev: The standard deviation of the distribution. Defaults to 1.0. - + Returns: A random number following a Gaussian distribution. - + Raises: ValueError: If stddev <= 0. )") @@ -131,10 +131,10 @@ random numbers following different distributions. Args: lambda: The rate parameter (lambda) of the distribution. Defaults to 1.0. - + Returns: A random number following a Poisson distribution. - + Raises: ValueError: If lambda <= 0. )") @@ -145,10 +145,10 @@ random numbers following different distributions. Args: lambda: The rate parameter (lambda) of the distribution. Defaults to 1.0. - + Returns: A random number following an Exponential distribution. - + Raises: ValueError: If lambda <= 0. )") @@ -158,10 +158,10 @@ random numbers following different distributions. Args: probability: The probability of success in each trial. Defaults to 0.5. - + Returns: A random number following a Geometric distribution. - + Raises: ValueError: If probability not in (0,1). )") @@ -172,10 +172,10 @@ random numbers following different distributions. Args: shape: The shape parameter of the distribution. scale: The scale parameter of the distribution. Defaults to 1.0. - + Returns: A random number following a Gamma distribution. - + Raises: ValueError: If shape or scale <= 0. )") @@ -186,10 +186,10 @@ random numbers following different distributions. Args: alpha: The alpha parameter of the distribution. beta: The beta parameter of the distribution. - + Returns: A random number following a Beta distribution. - + Raises: ValueError: If alpha or beta <= 0. )") @@ -199,10 +199,10 @@ random numbers following different distributions. Args: degrees_of_freedom: The degrees of freedom of the distribution. - + Returns: A random number following a Chi-Squared distribution. - + Raises: ValueError: If degrees_of_freedom <= 0. )") @@ -215,10 +215,10 @@ random numbers following different distributions. total: The total number of items. success: The number of successful items. draws: The number of draws. - + Returns: A random number following a Hypergeometric distribution. - + Raises: ValueError: If parameters are invalid. )") @@ -230,10 +230,10 @@ random numbers following different distributions. Args: weights: The weights of the discrete distribution. - + Returns: A random index based on the weights. - + Raises: ValueError: If weights is empty or contains negative values. )") @@ -246,10 +246,10 @@ random numbers following different distributions. Args: trials: The number of trials. probabilities: The probabilities of each outcome. - + Returns: A vector of counts for each outcome. - + Raises: ValueError: If probabilities is invalid. )") @@ -277,7 +277,7 @@ random numbers following different distributions. Args: data: The list of data to shuffle. - + Returns: A new shuffled list. )") @@ -311,10 +311,10 @@ random numbers following different distributions. Args: data: The list of data to sample from. sample_size: The number of elements to sample. - + Returns: A list containing the sampled elements. - + Raises: ValueError: If sample_size > len(data). )"); @@ -326,4 +326,4 @@ random numbers following different distributions. m.attr("LCG").attr("random_int") = m.attr("LCG").attr("next_int"); m.attr("LCG").attr("randint") = m.attr("LCG").attr("next_int"); m.attr("LCG").attr("choice") = m.attr("LCG").attr("next_discrete"); -} \ No newline at end of file +} diff --git a/python/utils/linq.cpp b/python/utils/linq.cpp index 0d1b7094..666d2878 100644 --- a/python/utils/linq.cpp +++ b/python/utils/linq.cpp @@ -974,4 +974,4 @@ PYBIND11_MODULE(linq, m) { >>> from atom.utils import flatten >>> flatten([[1, 2], [3, 4], [5, 6]]) # [1, 2, 3, 4, 5, 6] )"); -} \ No newline at end of file +} diff --git a/python/utils/qdatetime.cpp b/python/utils/qdatetime.cpp index 4cd98f78..a6d993ad 100644 --- a/python/utils/qdatetime.cpp +++ b/python/utils/qdatetime.cpp @@ -164,4 +164,4 @@ arithmetic operations, and timezone conversions. "set_time", "set_time_zone", "time_zone", "to_local_time", "to_string", "to_time_t", "to_utc"}; }); -} \ No newline at end of file +} diff --git a/python/utils/qprocess.cpp b/python/utils/qprocess.cpp index 4232a18f..0942763d 100644 --- a/python/utils/qprocess.cpp +++ b/python/utils/qprocess.cpp @@ -73,7 +73,7 @@ PYBIND11_MODULE(process, m) { m, "Process", R"(A class to manage and interact with external processes. -This class provides methods to start and control external processes. +This class provides methods to start and control external processes. It allows setting working directories, managing environment variables, and reading from or writing to the process's standard output and error streams. @@ -129,7 +129,7 @@ and reading from or writing to the process's standard output and error streams. Returns: bool: True if the process was started successfully, False otherwise. -In detached mode, the process will run independently of the parent process +In detached mode, the process will run independently of the parent process and will not be terminated when the parent process exits. )") .def( @@ -235,4 +235,4 @@ and will not be terminated when the parent process exits. } return false; // Don't suppress exceptions }); -} \ No newline at end of file +} diff --git a/python/utils/qtimer.cpp b/python/utils/qtimer.cpp index 2e71d08b..40dcaad0 100644 --- a/python/utils/qtimer.cpp +++ b/python/utils/qtimer.cpp @@ -123,7 +123,7 @@ This class provides functionality to measure elapsed time in various units py::class_>( m, "Timer", R"(Modern C++ timer class inspired by Qt's QTimer. - + This class provides timer functionality with callbacks, single-shot mode, and customizable precision. @@ -171,7 +171,7 @@ and customizable precision. py::arg("milliseconds"), py::arg("callback"), py::arg("mode") = atom::utils::Timer::PrecisionMode::PRECISE, R"(Creates a single-shot timer that calls the provided callback after the specified interval. - + Args: milliseconds: Interval in milliseconds callback: Function to call when timer expires @@ -186,4 +186,4 @@ and customizable precision. ... print("Single shot timer fired!") >>> timer = Timer.single_shot(1000, callback) )"); -} \ No newline at end of file +} diff --git a/python/utils/qtimezone.cpp b/python/utils/qtimezone.cpp index 26907742..c790acbb 100644 --- a/python/utils/qtimezone.cpp +++ b/python/utils/qtimezone.cpp @@ -129,4 +129,4 @@ about daylight saving time. Raises: RuntimeError: If the time conversion fails. )"); -} \ No newline at end of file +} diff --git a/python/utils/stopwatcher.cpp b/python/utils/stopwatcher.cpp index 0f0a0170..b0133ff1 100644 --- a/python/utils/stopwatcher.cpp +++ b/python/utils/stopwatcher.cpp @@ -254,10 +254,10 @@ When exiting a context started with 'with StopWatcher() as sw:', the stopwatch s Args: function: Function to execute and time. - + Returns: tuple: A tuple containing (function_result, elapsed_time_ms). - + Examples: >>> from atom.utils import timed_execution >>> def my_func(): @@ -289,12 +289,12 @@ When exiting a context started with 'with StopWatcher() as sw:', the stopwatch s Args: milliseconds: Time in milliseconds. - + Returns: str: Formatted time string. - + Examples: >>> from atom.utils import format_time >>> formatted = format_time(65432) # "00:01:05.432" )"); -} \ No newline at end of file +} diff --git a/python/utils/time.cpp b/python/utils/time.cpp index 89c755c4..e23c57f6 100644 --- a/python/utils/time.cpp +++ b/python/utils/time.cpp @@ -58,7 +58,7 @@ pattern "%Y-%m-%d %H:%M:%S". Returns: str: The current timestamp formatted as "%Y-%m-%d %H:%M:%S" - + Raises: TimeConvertException: If time conversion fails @@ -81,7 +81,7 @@ the same format. Returns: str: The corresponding time in China Standard Time, formatted as "%Y-%m-%d %H:%M:%S" - + Raises: TimeConvertException: If the input format is invalid or conversion fails @@ -100,7 +100,7 @@ formatted as a string with the pattern "%Y-%m-%d %H:%M:%S". Returns: str: The current China Standard Time formatted as "%Y-%m-%d %H:%M:%S" - + Raises: TimeConvertException: If time conversion fails @@ -123,7 +123,7 @@ converts it to a string representation. Returns: str: The string representation of the timestamp - + Raises: TimeConvertException: If the timestamp is invalid or conversion fails @@ -152,7 +152,7 @@ converts it to a formatted string according to the specified format. Returns: str: The formatted time string based on the tm structure and format - + Raises: TimeConvertException: If formatting fails @@ -172,7 +172,7 @@ pattern "%Y-%m-%d %H:%M:%S". Returns: str: The current UTC time formatted as "%Y-%m-%d %H:%M:%S" - + Raises: TimeConvertException: If time conversion fails @@ -193,7 +193,7 @@ converts it to a tm structure, which represents a calendar date and time. timestamp: The timestamp to be converted, in seconds since the Unix epoch Returns: - Optional[tm]: The corresponding tm structure representing the timestamp, + Optional[tm]: The corresponding tm structure representing the timestamp, or None if conversion fails Examples: @@ -231,7 +231,7 @@ converts it to a tm structure, which represents a calendar date and time. Returns: int: Elapsed time in milliseconds - + Raises: TypeError: If the input is not a valid time point @@ -319,7 +319,7 @@ converts it to a tm structure, which represents a calendar date and time. Returns: tm: The parsed time as a tm structure - + Raises: ValueError: If parsing fails @@ -369,7 +369,7 @@ converts it to a tm structure, which represents a calendar date and time. Returns: float: The difference in seconds (time2 - time1) - + Raises: ValueError: If parsing or conversion fails @@ -379,4 +379,4 @@ converts it to a tm structure, which represents a calendar date and time. >>> diff 30.0 )"); -} \ No newline at end of file +} diff --git a/python/utils/uuid.cpp b/python/utils/uuid.cpp index aaf78dc4..d8086fa9 100644 --- a/python/utils/uuid.cpp +++ b/python/utils/uuid.cpp @@ -444,4 +444,4 @@ when available on the platform. m.attr("NAMESPACE_X500") = atom::utils::UUID::fromString("6ba7b814-9dad-11d1-80b4-00c04fd430c8") .value(); -} \ No newline at end of file +} diff --git a/python/web/__init__.py b/python/web/__init__.py index cb4210bd..4a1b1238 100644 --- a/python/web/__init__.py +++ b/python/web/__init__.py @@ -1 +1 @@ -# Auto-generated __init__.py for web module \ No newline at end of file +# Auto-generated __init__.py for web module diff --git a/python/web/address.cpp b/python/web/address.cpp index b95fd1af..029ac2f3 100644 --- a/python/web/address.cpp +++ b/python/web/address.cpp @@ -339,4 +339,4 @@ and path validation. >>> is_valid_address("not-an-address") False )"); -} \ No newline at end of file +} diff --git a/python/web/downloader.cpp b/python/web/downloader.cpp index 898ba7af..f279673f 100644 --- a/python/web/downloader.cpp +++ b/python/web/downloader.cpp @@ -259,4 +259,4 @@ It supports multi-threaded downloads, download speed control, and progress callb >>> download_files(files, 4) # Download with 4 threads 2 )"); -} \ No newline at end of file +} diff --git a/python/web/httpparser.cpp b/python/web/httpparser.cpp index d7f0638b..e77a25a5 100644 --- a/python/web/httpparser.cpp +++ b/python/web/httpparser.cpp @@ -551,7 +551,7 @@ requests, and responses. Examples: >>> from atom.web.httpparser import create_request, HttpMethod, HttpVersion - >>> parser = create_request(HttpMethod.POST, "/api/data", HttpVersion.HTTP_1_1, + >>> parser = create_request(HttpMethod.POST, "/api/data", HttpVersion.HTTP_1_1, ... {"Content-Type": ["application/json"]}, '{"key": "value"}') >>> parser.build_request() 'POST /api/data HTTP/1.1\r\nContent-Type: application/json\r\n\r\n{"key": "value"}' @@ -587,9 +587,9 @@ requests, and responses. Examples: >>> from atom.web.httpparser import create_response, HttpStatus, HttpVersion - >>> parser = create_response(HttpStatus.OK(), HttpVersion.HTTP_1_1, + >>> parser = create_response(HttpStatus.OK(), HttpVersion.HTTP_1_1, ... {"Content-Type": ["text/html"]}, 'Hello') >>> parser.build_response() 'HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\nHello' )"); -} \ No newline at end of file +} diff --git a/python/web/mimetype.cpp b/python/web/mimetype.cpp index 1fae971f..62702aec 100644 --- a/python/web/mimetype.cpp +++ b/python/web/mimetype.cpp @@ -296,4 +296,4 @@ or when you plan to load data later. >>> print(mime_type) text/plain )"); -} \ No newline at end of file +} diff --git a/python/web/utils.cpp b/python/web/utils.cpp index 58f38ff2..e517667f 100644 --- a/python/web/utils.cpp +++ b/python/web/utils.cpp @@ -440,4 +440,4 @@ checking if a host is reachable. >>> hostname_to_ip("example.com") ['93.184.216.34', '2606:2800:220:1:248:1893:25c8:1946'] )"); -} \ No newline at end of file +} diff --git a/scripts/setup_vcpkg.bat b/scripts/setup_vcpkg.bat index 00ac6641..beb64a57 100644 --- a/scripts/setup_vcpkg.bat +++ b/scripts/setup_vcpkg.bat @@ -48,14 +48,14 @@ echo %YELLOW%vcpkg not found. Do you want to install it? (Y/N)%RESET% set /p INSTALL_CHOICE="> " if /i "%INSTALL_CHOICE%"=="Y" ( echo %GREEN%Installing vcpkg...%RESET% - + REM Determine installation path echo %YELLOW%Please select vcpkg installation location:%RESET% echo 1. User home directory (%USERPROFILE%\vcpkg) echo 2. C drive root (C:\vcpkg) echo 3. Current directory (%cd%\vcpkg) set /p INSTALL_LOCATION="> " - + if "%INSTALL_LOCATION%"=="1" ( set "VCPKG_PATH=%USERPROFILE%\vcpkg" ) else if "%INSTALL_LOCATION%"=="2" ( @@ -66,28 +66,28 @@ if /i "%INSTALL_CHOICE%"=="Y" ( echo %RED%Invalid choice. Using default location (%USERPROFILE%\vcpkg)%RESET% set "VCPKG_PATH=%USERPROFILE%\vcpkg" ) - + REM Clone and bootstrap vcpkg if exist "%VCPKG_PATH%" ( echo %YELLOW%Directory %VCPKG_PATH% already exists. Continue? (Y/N)%RESET% set /p CONTINUE_CHOICE="> " if /i not "%CONTINUE_CHOICE%"=="Y" goto :eof ) - + echo %GREEN%Cloning vcpkg to %VCPKG_PATH%...%RESET% git clone https://github.com/microsoft/vcpkg.git "%VCPKG_PATH%" if %ERRORLEVEL% neq 0 ( echo %RED%Failed to clone vcpkg%RESET% goto :eof ) - + echo %GREEN%Bootstrapping vcpkg...%RESET% call "%VCPKG_PATH%\bootstrap-vcpkg.bat" -disableMetrics if %ERRORLEVEL% neq 0 ( echo %RED%Failed to bootstrap vcpkg%RESET% goto :eof ) - + REM Set VCPKG_ROOT environment variable echo %GREEN%Setting VCPKG_ROOT environment variable...%RESET% setx VCPKG_ROOT "%VCPKG_PATH%" @@ -123,18 +123,18 @@ set "TRIPLET=%ARCH%-windows" if %IS_MSYS2% equ 1 ( set "TRIPLET=%ARCH%-mingw-dynamic" echo %GREEN%MSYS2: Using triplet %TRIPLET%%RESET% - + REM Check if MinGW triplet needs to be created if not exist "%VCPKG_PATH%\triplets\community\%TRIPLET%.cmake" ( echo %YELLOW%Need to create MinGW triplet file: %TRIPLET%%RESET% - + mkdir "%VCPKG_PATH%\triplets\community" 2>nul - + echo set(VCPKG_TARGET_ARCHITECTURE %ARCH%) > "%VCPKG_PATH%\triplets\community\%TRIPLET%.cmake" echo set(VCPKG_CRT_LINKAGE dynamic) >> "%VCPKG_PATH%\triplets\community\%TRIPLET%.cmake" echo set(VCPKG_LIBRARY_LINKAGE dynamic) >> "%VCPKG_PATH%\triplets\community\%TRIPLET%.cmake" echo set(VCPKG_CMAKE_SYSTEM_NAME MinGW) >> "%VCPKG_PATH%\triplets\community\%TRIPLET%.cmake" - + echo %GREEN%Triplet file created: %TRIPLET%%RESET% fi ) @@ -158,7 +158,7 @@ if /i "%OPTIONAL_DEPS%"=="Y" ( if %ERRORLEVEL% neq 0 ( echo %YELLOW%Warning: Failed to install optional Boost components%RESET% ) - + echo %GREEN%Installing test components...%RESET% "%VCPKG_PATH%\vcpkg.exe" install gtest --triplet=%TRIPLET% if %ERRORLEVEL% neq 0 ( @@ -192,7 +192,7 @@ if /i "%CONFIG_NOW%"=="Y" ( echo %RED%Project configuration failed%RESET% ) else { echo %GREEN%Project configured successfully!%RESET% - + echo %YELLOW%Start build now? (Y/N)%RESET% set /p BUILD_NOW="> " if /i "%BUILD_NOW%"=="Y" ( @@ -207,4 +207,4 @@ if /i "%CONFIG_NOW%"=="Y" ( } ) -pause \ No newline at end of file +pause diff --git a/scripts/setup_vcpkg.ps1 b/scripts/setup_vcpkg.ps1 index c88018eb..c54bce9d 100644 --- a/scripts/setup_vcpkg.ps1 +++ b/scripts/setup_vcpkg.ps1 @@ -34,17 +34,17 @@ else { # vcpkg not found, prompt to install Write-Yellow "vcpkg not found. Do you want to install it? (Y/N)" $installChoice = Read-Host "> " - + if ($installChoice -eq "Y" -or $installChoice -eq "y") { Write-Green "Installing vcpkg..." - + # Determine installation path Write-Yellow "Please select vcpkg installation location:" Write-Host "1. User home directory ($env:USERPROFILE\vcpkg)" Write-Host "2. C drive root (C:\vcpkg)" Write-Host "3. Current directory ($(Get-Location)\vcpkg)" $installLocation = Read-Host "> " - + switch ($installLocation) { "1" { $VcpkgPath = "$env:USERPROFILE\vcpkg" } "2" { $VcpkgPath = "C:\vcpkg" } @@ -54,7 +54,7 @@ else { $VcpkgPath = "$env:USERPROFILE\vcpkg" } } - + # Clone and bootstrap vcpkg if (Test-Path $VcpkgPath) { Write-Yellow "Directory $VcpkgPath already exists. Continue? (Y/N)" @@ -63,21 +63,21 @@ else { exit } } - + Write-Green "Cloning vcpkg to $VcpkgPath..." git clone https://github.com/microsoft/vcpkg.git $VcpkgPath if ($LASTEXITCODE -ne 0) { Write-Red "Failed to clone vcpkg" exit } - + Write-Green "Bootstrapping vcpkg..." & "$VcpkgPath\bootstrap-vcpkg.bat" -disableMetrics if ($LASTEXITCODE -ne 0) { Write-Red "Failed to bootstrap vcpkg" exit } - + # Set VCPKG_ROOT environment variable Write-Green "Setting VCPKG_ROOT environment variable..." try { @@ -114,18 +114,18 @@ $Triplet = "$Arch-windows" if ($IsMsys2) { $Triplet = "$Arch-mingw-dynamic" Write-Green "MSYS2: Using triplet $Triplet" - + # Check if MinGW triplet needs to be created $TripletFile = "$VcpkgPath\triplets\community\$Triplet.cmake" if (-not (Test-Path $TripletFile)) { Write-Yellow "Need to create MinGW triplet file: $Triplet" - + # Create directory if it doesn't exist $TripletDir = "$VcpkgPath\triplets\community" if (-not (Test-Path $TripletDir)) { New-Item -Path $TripletDir -ItemType Directory -Force | Out-Null } - + # Create the triplet file @" set(VCPKG_TARGET_ARCHITECTURE $Arch) @@ -133,7 +133,7 @@ set(VCPKG_CRT_LINKAGE dynamic) set(VCPKG_LIBRARY_LINKAGE dynamic) set(VCPKG_CMAKE_SYSTEM_NAME MinGW) "@ | Set-Content -Path $TripletFile - + Write-Green "Triplet file created: $Triplet" } } @@ -157,7 +157,7 @@ if ($optionalDeps -eq "Y" -or $optionalDeps -eq "y") { if ($LASTEXITCODE -ne 0) { Write-Yellow "Warning: Failed to install optional Boost components" } - + Write-Green "Installing test components..." & "$VcpkgPath\vcpkg.exe" install gtest --triplet=$Triplet if ($LASTEXITCODE -ne 0) { @@ -187,19 +187,19 @@ $configNow = Read-Host "> " if ($configNow -eq "Y" -or $configNow -eq "y") { Write-Green "Configuring project..." & cmake -B build -G "Ninja" -DCMAKE_TOOLCHAIN_FILE="$VcpkgPath/scripts/buildsystems/vcpkg.cmake" -DVCPKG_TARGET_TRIPLET=$Triplet - + if ($LASTEXITCODE -ne 0) { Write-Red "Project configuration failed" } else { Write-Green "Project configured successfully!" - + Write-Yellow "Start build now? (Y/N)" $buildNow = Read-Host "> " if ($buildNow -eq "Y" -or $buildNow -eq "y") { Write-Green "Building project..." & cmake --build build - + if ($LASTEXITCODE -ne 0) { Write-Red "Project build failed" } @@ -211,4 +211,4 @@ if ($configNow -eq "Y" -or $configNow -eq "y") { } Write-Host "Press any key to continue..." -$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") \ No newline at end of file +$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") diff --git a/tests/algorithm/test_blowfish.cpp b/tests/algorithm/test_blowfish.cpp index 48ed2c63..dcfb9973 100644 --- a/tests/algorithm/test_blowfish.cpp +++ b/tests/algorithm/test_blowfish.cpp @@ -492,4 +492,4 @@ int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); spdlog::set_level(spdlog::level::off); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/tests/algorithm/test_fraction.cpp b/tests/algorithm/test_fraction.cpp index 16284e21..9b8d8071 100644 --- a/tests/algorithm/test_fraction.cpp +++ b/tests/algorithm/test_fraction.cpp @@ -440,4 +440,4 @@ TEST_F(FractionTest, ChainedOperations) { // 1/2 + 1/3 = 5/6 // 5/6 - 1/20 = 100/120 - 6/120 = 94/120 = 47/60 EXPECT_EQ(result.toString(), "47/60"); -} \ No newline at end of file +} diff --git a/tests/algorithm/test_math.cpp b/tests/algorithm/test_math.cpp index 8612d52d..0b1282fb 100644 --- a/tests/algorithm/test_math.cpp +++ b/tests/algorithm/test_math.cpp @@ -208,4 +208,4 @@ TEST(MathTest, ModPow) { int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/tests/algorithm/test_mhash.cpp b/tests/algorithm/test_mhash.cpp index a9d7b369..1ece3d3f 100644 --- a/tests/algorithm/test_mhash.cpp +++ b/tests/algorithm/test_mhash.cpp @@ -270,4 +270,4 @@ TEST_F(MHashTest, ThreadSafety) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/tests/algorithm/test_sha1.cpp b/tests/algorithm/test_sha1.cpp index 960604d6..4b99898b 100644 --- a/tests/algorithm/test_sha1.cpp +++ b/tests/algorithm/test_sha1.cpp @@ -455,4 +455,4 @@ TEST_F(SHA1Test, BinaryData) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/tests/algorithm/test_tea.cpp b/tests/algorithm/test_tea.cpp index b3986e04..91ae8339 100644 --- a/tests/algorithm/test_tea.cpp +++ b/tests/algorithm/test_tea.cpp @@ -486,4 +486,4 @@ TEST_F(TEATest, RandomData) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/tests/extra/beast/test_http.cpp b/tests/extra/beast/test_http.cpp index 70be67a0..89899be6 100644 --- a/tests/extra/beast/test_http.cpp +++ b/tests/extra/beast/test_http.cpp @@ -323,4 +323,4 @@ TEST_F(HttpClientTest, InvalidValues) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/tests/extra/beast/test_ws.cpp b/tests/extra/beast/test_ws.cpp index ba9827c4..b9b2e8d7 100644 --- a/tests/extra/beast/test_ws.cpp +++ b/tests/extra/beast/test_ws.cpp @@ -481,4 +481,4 @@ TEST_F(WSClientTest, DestructorBehavior) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/tests/extra/boost/test_charconv.hpp b/tests/extra/boost/test_charconv.hpp index 439213f9..720aaa26 100644 --- a/tests/extra/boost/test_charconv.hpp +++ b/tests/extra/boost/test_charconv.hpp @@ -310,4 +310,4 @@ TEST_F(BoostCharConvTest, ExtremeValues) { } // namespace atom::extra::boost::test -#endif // ATOM_EXTRA_BOOST_TEST_CHARCONV_HPP \ No newline at end of file +#endif // ATOM_EXTRA_BOOST_TEST_CHARCONV_HPP diff --git a/tests/extra/boost/test_locale.hpp b/tests/extra/boost/test_locale.hpp index 18e6fc3b..3a195bcf 100644 --- a/tests/extra/boost/test_locale.hpp +++ b/tests/extra/boost/test_locale.hpp @@ -541,4 +541,4 @@ TEST_F(LocaleWrapperTest, EdgeCases) { } // namespace atom::extra::boost::test -#endif // ATOM_EXTRA_BOOST_TEST_LOCALE_HPP \ No newline at end of file +#endif // ATOM_EXTRA_BOOST_TEST_LOCALE_HPP diff --git a/tests/extra/boost/test_math.hpp b/tests/extra/boost/test_math.hpp index 05125d52..7c6017cc 100644 --- a/tests/extra/boost/test_math.hpp +++ b/tests/extra/boost/test_math.hpp @@ -638,4 +638,4 @@ TEST_F(FinancialMathTest, ImpliedVolatility) { } // namespace atom::extra::boost::test -#endif // ATOM_EXTRA_BOOST_TEST_MATH_HPP \ No newline at end of file +#endif // ATOM_EXTRA_BOOST_TEST_MATH_HPP diff --git a/tests/extra/boost/test_regex.hpp b/tests/extra/boost/test_regex.hpp index 1cef74c5..b54cac62 100644 --- a/tests/extra/boost/test_regex.hpp +++ b/tests/extra/boost/test_regex.hpp @@ -549,4 +549,4 @@ TEST_F(RegexWrapperTest, EdgeCases) { } // namespace atom::extra::boost::test -#endif // ATOM_EXTRA_BOOST_TEST_REGEX_HPP \ No newline at end of file +#endif // ATOM_EXTRA_BOOST_TEST_REGEX_HPP diff --git a/tests/extra/boost/test_system.hpp b/tests/extra/boost/test_system.hpp index 407e0983..2815defb 100644 --- a/tests/extra/boost/test_system.hpp +++ b/tests/extra/boost/test_system.hpp @@ -593,4 +593,4 @@ TEST_F(IntegrationTest, ResultMapping) { } // namespace atom::extra::boost::test -#endif // ATOM_EXTRA_BOOST_TEST_SYSTEM_HPP \ No newline at end of file +#endif // ATOM_EXTRA_BOOST_TEST_SYSTEM_HPP diff --git a/tests/extra/boost/test_uuid.hpp b/tests/extra/boost/test_uuid.hpp index cbce88b3..f59c4cfe 100644 --- a/tests/extra/boost/test_uuid.hpp +++ b/tests/extra/boost/test_uuid.hpp @@ -35,17 +35,17 @@ class UUIDTest : public ::testing::Test { void SetUp() override { // Create a nil UUID nilUUID = std::make_unique(::boost::uuids::nil_uuid()); - + // Create a UUID from a fixed string for consistent testing const std::string testUUIDString = "123e4567-e89b-12d3-a456-426614174000"; fixedUUID = std::make_unique(testUUIDString); - + // Static predefined namespace UUIDs dnsNamespaceUUID = std::make_unique(UUID::namespaceDNS()); urlNamespaceUUID = std::make_unique(UUID::namespaceURL()); oidNamespaceUUID = std::make_unique(UUID::namespaceOID()); } - + void TearDown() override { nilUUID.reset(); fixedUUID.reset(); @@ -53,22 +53,22 @@ class UUIDTest : public ::testing::Test { urlNamespaceUUID.reset(); oidNamespaceUUID.reset(); } - + // Helper functions for testing static bool isValidUUIDString(const std::string& str) { std::regex uuidRegex( - "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", + "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", std::regex::icase ); return std::regex_match(str, uuidRegex); } - + static bool isValidBase64String(const std::string& str) { // Base64 consists of alphanumeric chars, '+', and '/' std::regex base64Regex("^[A-Za-z0-9+/]+={0,2}$"); return std::regex_match(str, base64Regex); } - + std::unique_ptr nilUUID; std::unique_ptr fixedUUID; std::unique_ptr dnsNamespaceUUID; @@ -82,17 +82,17 @@ TEST_F(UUIDTest, Constructors) { UUID randomUUID; EXPECT_FALSE(randomUUID.isNil()); EXPECT_TRUE(isValidUUIDString(randomUUID.toString())); - + // Test constructor with string std::string uuidStr = "123e4567-e89b-12d3-a456-426614174000"; UUID fromString(uuidStr); EXPECT_EQ(fromString.toString(), uuidStr); - + // Test constructor with Boost UUID ::boost::uuids::uuid boostUUID = ::boost::uuids::nil_uuid(); UUID fromBoostUUID(boostUUID); EXPECT_TRUE(fromBoostUUID.isNil()); - + // Test constructor with invalid string (should throw) EXPECT_THROW(UUID("not-a-uuid"), std::runtime_error); } @@ -103,10 +103,10 @@ TEST_F(UUIDTest, ToString) { std::string nilString = nilUUID->toString(); EXPECT_TRUE(isValidUUIDString(nilString)); EXPECT_EQ(nilString, "00000000-0000-0000-0000-000000000000"); - + // Fixed UUID should match its string representation EXPECT_EQ(fixedUUID->toString(), "123e4567-e89b-12d3-a456-426614174000"); - + // Random UUID should have a valid string representation UUID randomUUID; EXPECT_TRUE(isValidUUIDString(randomUUID.toString())); @@ -116,10 +116,10 @@ TEST_F(UUIDTest, ToString) { TEST_F(UUIDTest, IsNil) { // Nil UUID should be nil EXPECT_TRUE(nilUUID->isNil()); - + // Fixed UUID should not be nil EXPECT_FALSE(fixedUUID->isNil()); - + // Random UUID should not be nil UUID randomUUID; EXPECT_FALSE(randomUUID.isNil()); @@ -130,21 +130,21 @@ TEST_F(UUIDTest, ComparisonOperators) { // Create copies of UUIDs UUID nilCopy(*nilUUID); UUID fixedCopy(*fixedUUID); - + // Test equality EXPECT_TRUE(*nilUUID == nilCopy); EXPECT_TRUE(*fixedUUID == fixedCopy); EXPECT_FALSE(*nilUUID == *fixedUUID); - + // Test inequality EXPECT_FALSE(*nilUUID != nilCopy); EXPECT_FALSE(*fixedUUID != fixedCopy); EXPECT_TRUE(*nilUUID != *fixedUUID); - + // Test spaceship operator EXPECT_TRUE((*nilUUID <=> nilCopy) == std::strong_ordering::equal); EXPECT_TRUE((*fixedUUID <=> fixedCopy) == std::strong_ordering::equal); - + // The actual comparison depends on the underlying bytes, so we can't easily // predict less/greater, but we can check it's consistent auto compResult = *nilUUID <=> *fixedUUID; @@ -160,11 +160,11 @@ TEST_F(UUIDTest, Format) { // Nil UUID format std::string nilFormat = nilUUID->format(); EXPECT_EQ(nilFormat, "{00000000-0000-0000-0000-000000000000}"); - + // Fixed UUID format std::string fixedFormat = fixedUUID->format(); EXPECT_EQ(fixedFormat, "{123e4567-e89b-12d3-a456-426614174000}"); - + // Random UUID format UUID randomUUID; std::string randomFormat = randomUUID.format(); @@ -179,22 +179,22 @@ TEST_F(UUIDTest, ByteConversion) { std::vector nilBytes = nilUUID->toBytes(); EXPECT_EQ(nilBytes.size(), atom::extra::boost::UUID_SIZE); EXPECT_TRUE(std::all_of(nilBytes.begin(), nilBytes.end(), [](uint8_t b) { return b == 0; })); - + std::vector fixedBytes = fixedUUID->toBytes(); EXPECT_EQ(fixedBytes.size(), atom::extra::boost::UUID_SIZE); - + // Test fromBytes with valid input UUID reconstructedNil = UUID::fromBytes(std::span(nilBytes)); EXPECT_TRUE(reconstructedNil.isNil()); EXPECT_EQ(reconstructedNil, *nilUUID); - + UUID reconstructedFixed = UUID::fromBytes(std::span(fixedBytes)); EXPECT_EQ(reconstructedFixed, *fixedUUID); - + // Test fromBytes with invalid input std::vector tooShort(15, 0); EXPECT_THROW(UUID::fromBytes(std::span(tooShort)), std::invalid_argument); - + std::vector tooLong(17, 0); EXPECT_THROW(UUID::fromBytes(std::span(tooLong)), std::invalid_argument); } @@ -203,11 +203,11 @@ TEST_F(UUIDTest, ByteConversion) { TEST_F(UUIDTest, ToUint64) { // Nil UUID should convert to 0 EXPECT_EQ(nilUUID->toUint64(), 0); - + // Fixed UUID conversion should be deterministic uint64_t fixedValue = fixedUUID->toUint64(); EXPECT_NE(fixedValue, 0); - + // Creating a new UUID with the same string should give the same uint64 UUID fixedCopy("123e4567-e89b-12d3-a456-426614174000"); EXPECT_EQ(fixedCopy.toUint64(), fixedValue); @@ -218,11 +218,11 @@ TEST_F(UUIDTest, NamespaceUUIDs) { // Test DNS namespace UUID EXPECT_FALSE(dnsNamespaceUUID->isNil()); EXPECT_EQ(dnsNamespaceUUID->toString(), "6ba7b810-9dad-11d1-80b4-00c04fd430c8"); - + // Test URL namespace UUID EXPECT_FALSE(urlNamespaceUUID->isNil()); EXPECT_EQ(urlNamespaceUUID->toString(), "6ba7b811-9dad-11d1-80b4-00c04fd430c8"); - + // Test OID namespace UUID EXPECT_FALSE(oidNamespaceUUID->isNil()); EXPECT_EQ(oidNamespaceUUID->toString(), "6ba7b812-9dad-11d1-80b4-00c04fd430c8"); @@ -233,16 +233,16 @@ TEST_F(UUIDTest, V3UUID) { // Generate v3 UUIDs with the same namespace and name UUID v3_1 = UUID::v3(*dnsNamespaceUUID, "example.com"); UUID v3_2 = UUID::v3(*dnsNamespaceUUID, "example.com"); - + // They should be the same EXPECT_EQ(v3_1, v3_2); EXPECT_EQ(v3_1.version(), 3); - + // Generate v3 UUIDs with different names UUID v3_3 = UUID::v3(*dnsNamespaceUUID, "example.org"); EXPECT_NE(v3_1, v3_3); EXPECT_EQ(v3_3.version(), 3); - + // Generate v3 UUIDs with different namespaces UUID v3_4 = UUID::v3(*urlNamespaceUUID, "example.com"); EXPECT_NE(v3_1, v3_4); @@ -254,21 +254,21 @@ TEST_F(UUIDTest, V5UUID) { // Generate v5 UUIDs with the same namespace and name UUID v5_1 = UUID::v5(*dnsNamespaceUUID, "example.com"); UUID v5_2 = UUID::v5(*dnsNamespaceUUID, "example.com"); - + // They should be the same EXPECT_EQ(v5_1, v5_2); EXPECT_EQ(v5_1.version(), 5); - + // Generate v5 UUIDs with different names UUID v5_3 = UUID::v5(*dnsNamespaceUUID, "example.org"); EXPECT_NE(v5_1, v5_3); EXPECT_EQ(v5_3.version(), 5); - + // Generate v5 UUIDs with different namespaces UUID v5_4 = UUID::v5(*urlNamespaceUUID, "example.com"); EXPECT_NE(v5_1, v5_4); EXPECT_EQ(v5_4.version(), 5); - + // v3 and v5 UUIDs for the same name should be different UUID v3 = UUID::v3(*dnsNamespaceUUID, "example.com"); UUID v5 = UUID::v5(*dnsNamespaceUUID, "example.com"); @@ -279,31 +279,31 @@ TEST_F(UUIDTest, V5UUID) { TEST_F(UUIDTest, VersionAndVariant) { // Nil UUID should have version 0 EXPECT_EQ(nilUUID->version(), 0); - + // Random UUID (v4) should have version 4 UUID v4UUID = UUID::v4(); EXPECT_EQ(v4UUID.version(), 4); - + // v3 UUID should have version 3 UUID v3UUID = UUID::v3(*dnsNamespaceUUID, "example.com"); EXPECT_EQ(v3UUID.version(), 3); - + // v5 UUID should have version 5 UUID v5UUID = UUID::v5(*dnsNamespaceUUID, "example.com"); EXPECT_EQ(v5UUID.version(), 5); - + // v1 UUID should have version 1 UUID v1UUID = UUID::v1(); // Note: Test this if v1() actually generates v1 UUIDs if (v1UUID.version() == 1) { EXPECT_EQ(v1UUID.version(), 1); } - + // Variant should be correct for all UUIDs (DCE 1.1 variant) EXPECT_EQ(v4UUID.variant(), 1); EXPECT_EQ(v3UUID.variant(), 1); EXPECT_EQ(v5UUID.variant(), 1); - + // Nil UUID variant might be 0 // This is implementation-defined, so we don't make strict assertions } @@ -313,19 +313,19 @@ TEST_F(UUIDTest, V1AndV4UUID) { // Generate multiple v1 UUIDs UUID v1_1 = UUID::v1(); UUID v1_2 = UUID::v1(); - + // They should be different EXPECT_NE(v1_1, v1_2); - + // Generate multiple v4 UUIDs UUID v4_1 = UUID::v4(); UUID v4_2 = UUID::v4(); - + // They should be different EXPECT_NE(v4_1, v4_2); EXPECT_EQ(v4_1.version(), 4); EXPECT_EQ(v4_2.version(), 4); - + // v1 and v4 UUIDs should be different EXPECT_NE(v1_1, v4_1); } @@ -335,21 +335,21 @@ TEST_F(UUIDTest, ToBase64) { // Test nil UUID base64 std::string nilBase64 = nilUUID->toBase64(); EXPECT_EQ(nilBase64.size(), atom::extra::boost::BASE64_RESERVE_SIZE); - + // Test fixed UUID base64 std::string fixedBase64 = fixedUUID->toBase64(); EXPECT_EQ(fixedBase64.size(), atom::extra::boost::BASE64_RESERVE_SIZE); EXPECT_TRUE(isValidBase64String(fixedBase64)); - + // Random UUID base64 UUID randomUUID; std::string randomBase64 = randomUUID.toBase64(); EXPECT_EQ(randomBase64.size(), atom::extra::boost::BASE64_RESERVE_SIZE); EXPECT_TRUE(isValidBase64String(randomBase64)); - + // Converting the same UUID twice should give the same base64 EXPECT_EQ(fixedUUID->toBase64(), fixedBase64); - + // Different UUIDs should give different base64 strings EXPECT_NE(nilUUID->toBase64(), fixedUUID->toBase64()); } @@ -358,28 +358,28 @@ TEST_F(UUIDTest, ToBase64) { TEST_F(UUIDTest, GetTimestamp) { // Create a v1 UUID UUID v1UUID = UUID::v1(); - + // If it's actually a v1 UUID, test getTimestamp if (v1UUID.version() == 1) { // Getting timestamp should not throw for v1 UUID EXPECT_NO_THROW({ auto timestamp = v1UUID.getTimestamp(); }); - + // Timestamp should be recent auto timestamp = v1UUID.getTimestamp(); auto now = std::chrono::system_clock::now(); - + // It should be within a reasonable time range from now // Note: This is approximate and may fail if time zones are involved auto timeDiff = std::chrono::duration_cast(now - timestamp).count(); EXPECT_LE(std::abs(timeDiff), 366); // Within a year (generous margin) } - + // Getting timestamp from non-v1 UUID should throw UUID v4UUID = UUID::v4(); EXPECT_THROW(v4UUID.getTimestamp(), std::runtime_error); - + EXPECT_THROW(nilUUID->getTimestamp(), std::runtime_error); } @@ -389,32 +389,32 @@ TEST_F(UUIDTest, HashFunction) { UUID u1 = UUID::v4(); UUID u2 = UUID::v4(); UUID u1Copy = UUID(u1.toString()); - + // Create hash function std::hash hasher; - + // Same UUIDs should have same hash EXPECT_EQ(hasher(u1), hasher(u1Copy)); - + // Different UUIDs should (probably) have different hashes // This is not guaranteed but highly likely EXPECT_NE(hasher(u1), hasher(u2)); - + // Test in hash containers std::unordered_set uuidSet; uuidSet.insert(u1); uuidSet.insert(u2); uuidSet.insert(u1Copy); // Should not increase the size since u1 is already there - + EXPECT_EQ(uuidSet.size(), 2); EXPECT_TRUE(uuidSet.contains(u1)); EXPECT_TRUE(uuidSet.contains(u2)); - + std::unordered_map uuidMap; uuidMap[u1] = 1; uuidMap[u2] = 2; uuidMap[u1Copy] = 3; // Should update the value for u1 - + EXPECT_EQ(uuidMap.size(), 2); EXPECT_EQ(uuidMap[u1], 3); EXPECT_EQ(uuidMap[u2], 2); @@ -424,10 +424,10 @@ TEST_F(UUIDTest, HashFunction) { TEST_F(UUIDTest, GetUUID) { // Get the underlying Boost UUID const auto& boostUUID = nilUUID->getUUID(); - + // Verify it's the correct type and value EXPECT_TRUE(boostUUID.is_nil()); - + // Create a new UUID from the Boost UUID UUID newUUID(boostUUID); EXPECT_EQ(newUUID, *nilUUID); @@ -437,14 +437,14 @@ TEST_F(UUIDTest, GetUUID) { TEST_F(UUIDTest, Uniqueness) { constexpr int NUM_UUIDS = 1000; std::set uuidStrings; - + // Generate a bunch of UUIDs and ensure they're all unique for (int i = 0; i < NUM_UUIDS; ++i) { UUID uuid = UUID::v4(); std::string uuidStr = uuid.toString(); EXPECT_TRUE(uuidStrings.insert(uuidStr).second) << "UUID collision detected: " << uuidStr; } - + EXPECT_EQ(uuidStrings.size(), NUM_UUIDS); } @@ -454,17 +454,17 @@ TEST_F(UUIDTest, EdgeCases) { EXPECT_THROW(UUID("not-a-uuid"), std::runtime_error); EXPECT_THROW(UUID("123456789"), std::runtime_error); EXPECT_THROW(UUID("123e4567-e89b-12d3-a456-4266141740"), std::runtime_error); // Too short - + // Empty string for UUID constructor EXPECT_THROW(UUID(""), std::runtime_error); - + // Invalid bytes for fromBytes std::vector tooShort(15, 0); EXPECT_THROW(UUID::fromBytes(std::span(tooShort)), std::invalid_argument); - + std::vector tooLong(17, 0); EXPECT_THROW(UUID::fromBytes(std::span(tooLong)), std::invalid_argument); - + // Empty bytes should throw std::vector empty; EXPECT_THROW(UUID::fromBytes(std::span(empty)), std::invalid_argument); @@ -473,16 +473,16 @@ TEST_F(UUIDTest, EdgeCases) { // Verify that UUIDs can be sorted (for use in ordered containers) TEST_F(UUIDTest, SortingBehavior) { std::vector uuids; - + // Add some UUIDs uuids.push_back(*nilUUID); uuids.push_back(*fixedUUID); uuids.push_back(UUID::v4()); uuids.push_back(UUID::v4()); - + // Should be able to sort without errors EXPECT_NO_THROW(std::sort(uuids.begin(), uuids.end())); - + // Verify the sort is stable (sorting again gives the same result) std::vector uuidsCopy = uuids; std::sort(uuidsCopy.begin(), uuidsCopy.end()); @@ -491,4 +491,4 @@ TEST_F(UUIDTest, SortingBehavior) { } // namespace atom::extra::boost::test -#endif // ATOM_EXTRA_BOOST_TEST_UUID_HPP \ No newline at end of file +#endif // ATOM_EXTRA_BOOST_TEST_UUID_HPP diff --git a/tests/extra/curl/test_rest_client.hpp b/tests/extra/curl/test_rest_client.hpp index 5be75b2c..c547bc98 100644 --- a/tests/extra/curl/test_rest_client.hpp +++ b/tests/extra/curl/test_rest_client.hpp @@ -365,4 +365,4 @@ TEST_F(RestClientTest, ErrorHandlerConcept) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/tests/extra/inicpp/file.cpp b/tests/extra/inicpp/file.cpp index a61534fa..ea51173b 100644 --- a/tests/extra/inicpp/file.cpp +++ b/tests/extra/inicpp/file.cpp @@ -146,4 +146,4 @@ TEST(IniFileBaseTest, Save) { int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/tests/extra/pugixml/test_xml_builder.hpp b/tests/extra/pugixml/test_xml_builder.hpp index ee16f0a1..6ec06bc6 100644 --- a/tests/extra/pugixml/test_xml_builder.hpp +++ b/tests/extra/pugixml/test_xml_builder.hpp @@ -516,4 +516,4 @@ TEST_F(XmlBuilderTest, ChainedOperations) { EXPECT_EQ(second->attribute("id")->value(), "2"); } -} // namespace atom::extra::pugixml::test \ No newline at end of file +} // namespace atom::extra::pugixml::test diff --git a/tests/extra/pugixml/test_xml_document.hpp b/tests/extra/pugixml/test_xml_document.hpp index 6b9cff17..53d38448 100644 --- a/tests/extra/pugixml/test_xml_document.hpp +++ b/tests/extra/pugixml/test_xml_document.hpp @@ -438,4 +438,4 @@ TEST_F(XmlDocumentTest, MixedLoadSaveOptions) { EXPECT_THAT(result, ::testing::HasSubstr("")); } -} // namespace atom::extra::pugixml::test \ No newline at end of file +} // namespace atom::extra::pugixml::test diff --git a/tests/extra/pugixml/test_xml_node_wrapper.hpp b/tests/extra/pugixml/test_xml_node_wrapper.hpp index 600727ea..b102403e 100644 --- a/tests/extra/pugixml/test_xml_node_wrapper.hpp +++ b/tests/extra/pugixml/test_xml_node_wrapper.hpp @@ -419,4 +419,4 @@ TEST_F(XmlNodeWrapperTest, CompileTimeStrings) { EXPECT_EQ(view.size(), 4); } -} // namespace atom::extra::pugixml::test \ No newline at end of file +} // namespace atom::extra::pugixml::test diff --git a/tests/extra/pugixml/test_xml_query.hpp b/tests/extra/pugixml/test_xml_query.hpp index 62d68f9e..fe8040bd 100644 --- a/tests/extra/pugixml/test_xml_query.hpp +++ b/tests/extra/pugixml/test_xml_query.hpp @@ -533,4 +533,4 @@ TEST_F(XmlQueryTest, CombinedOperations) { EXPECT_EQ(title->text(), "The Lord of the Rings"); } -} // namespace atom::extra::pugixml::test \ No newline at end of file +} // namespace atom::extra::pugixml::test diff --git a/tests/extra/uv/test_coro.hpp b/tests/extra/uv/test_coro.hpp index a485b87b..92eaf594 100644 --- a/tests/extra/uv/test_coro.hpp +++ b/tests/extra/uv/test_coro.hpp @@ -861,4 +861,4 @@ TEST_F(UvCoroTest, SchedulerTest) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/tests/extra/uv/test_message_bus.hpp b/tests/extra/uv/test_message_bus.hpp index d6c160e1..4371e064 100644 --- a/tests/extra/uv/test_message_bus.hpp +++ b/tests/extra/uv/test_message_bus.hpp @@ -343,4 +343,4 @@ TEST_F(MessageBusTest, MessageEnvelopeMetadataTest) { EXPECT_EQ(envelope.metadata.find("source"), envelope.metadata.end()); } -} // namespace msgbus::test \ No newline at end of file +} // namespace msgbus::test diff --git a/tests/extra/uv/test_subprocess.hpp b/tests/extra/uv/test_subprocess.hpp index 47d0650c..5ba7cadb 100644 --- a/tests/extra/uv/test_subprocess.hpp +++ b/tests/extra/uv/test_subprocess.hpp @@ -601,4 +601,4 @@ TEST_F(UvProcessTest, DetachedProcess) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/tests/image/test_fits_header.hpp b/tests/image/test_fits_header.hpp index d4473239..52b420af 100644 --- a/tests/image/test_fits_header.hpp +++ b/tests/image/test_fits_header.hpp @@ -37,15 +37,15 @@ TEST_F(FITSHeaderTest, AddAndGetKeyword) { EXPECT_EQ(header.getKeywordValue("SIMPLE"), "T"); EXPECT_EQ(header.getKeywordValue("BITPIX"), "16"); EXPECT_EQ(header.getKeywordValue("NAXIS"), "2"); - + // Add a new keyword header.addKeyword("OBJECT", "M31"); EXPECT_EQ(header.getKeywordValue("OBJECT"), "M31"); - + // Update an existing keyword header.addKeyword("BITPIX", "32"); EXPECT_EQ(header.getKeywordValue("BITPIX"), "32"); - + // Add a keyword with a longer value std::string long_value = "This is a longer value with spaces and special chars: !@#$%^&*()"; header.addKeyword("COMMENT", long_value); @@ -57,7 +57,7 @@ TEST_F(FITSHeaderTest, HasKeyword) { EXPECT_TRUE(header.hasKeyword("SIMPLE")); EXPECT_TRUE(header.hasKeyword("BITPIX")); EXPECT_FALSE(header.hasKeyword("NONEXIST")); - + // Check case sensitivity EXPECT_FALSE(header.hasKeyword("simple")); // FITS keywords should be case-sensitive } @@ -67,7 +67,7 @@ TEST_F(FITSHeaderTest, RemoveKeyword) { EXPECT_TRUE(header.hasKeyword("BITPIX")); header.removeKeyword("BITPIX"); EXPECT_FALSE(header.hasKeyword("BITPIX")); - + // Removing non-existent keyword should not throw EXPECT_NO_THROW(header.removeKeyword("NONEXIST")); } @@ -75,17 +75,17 @@ TEST_F(FITSHeaderTest, RemoveKeyword) { // Test getting all keywords TEST_F(FITSHeaderTest, GetAllKeywords) { auto keywords = header.getAllKeywords(); - + // Check that expected keywords are present EXPECT_THAT(keywords, ::testing::Contains("SIMPLE")); EXPECT_THAT(keywords, ::testing::Contains("BITPIX")); EXPECT_THAT(keywords, ::testing::Contains("NAXIS")); EXPECT_THAT(keywords, ::testing::Contains("NAXIS1")); EXPECT_THAT(keywords, ::testing::Contains("NAXIS2")); - + // Check that non-existent keywords are not present EXPECT_THAT(keywords, ::testing::Not(::testing::Contains("NONEXIST"))); - + // Check the total count EXPECT_EQ(keywords.size(), 5); } @@ -94,7 +94,7 @@ TEST_F(FITSHeaderTest, GetAllKeywords) { TEST_F(FITSHeaderTest, AddAndGetComments) { header.addComment("This is a test comment"); header.addComment("Another comment"); - + auto comments = header.getComments(); EXPECT_EQ(comments.size(), 2); EXPECT_THAT(comments, ::testing::Contains("This is a test comment")); @@ -105,9 +105,9 @@ TEST_F(FITSHeaderTest, AddAndGetComments) { TEST_F(FITSHeaderTest, ClearComments) { header.addComment("Comment 1"); header.addComment("Comment 2"); - + EXPECT_EQ(header.getComments().size(), 2); - + header.clearComments(); EXPECT_EQ(header.getComments().size(), 0); } @@ -120,15 +120,15 @@ TEST_F(FITSHeaderTest, GetKeywordValueError) { // Test serialization TEST_F(FITSHeaderTest, Serialization) { std::vector data = header.serialize(); - + // Check size is a multiple of FITS_HEADER_UNIT_SIZE EXPECT_EQ(data.size() % FITSHeader::FITS_HEADER_UNIT_SIZE, 0); - + // Check for expected patterns in the serialized data EXPECT_TRUE(containsPattern(data, "SIMPLE = T")); EXPECT_TRUE(containsPattern(data, "BITPIX = 16")); EXPECT_TRUE(containsPattern(data, "NAXIS = 2")); - + // Check for END keyword at the end std::string end_pattern = "END "; bool has_end = false; @@ -145,18 +145,18 @@ TEST_F(FITSHeaderTest, Serialization) { TEST_F(FITSHeaderTest, Deserialization) { // Serialize the current header std::vector data = header.serialize(); - + // Create a new header and deserialize into it FITSHeader new_header; new_header.deserialize(data); - + // Check that deserialized header has the same keywords EXPECT_TRUE(new_header.hasKeyword("SIMPLE")); EXPECT_TRUE(new_header.hasKeyword("BITPIX")); EXPECT_TRUE(new_header.hasKeyword("NAXIS")); EXPECT_TRUE(new_header.hasKeyword("NAXIS1")); EXPECT_TRUE(new_header.hasKeyword("NAXIS2")); - + // Check that values match EXPECT_EQ(new_header.getKeywordValue("SIMPLE"), "T"); EXPECT_EQ(new_header.getKeywordValue("BITPIX"), "16"); @@ -168,11 +168,11 @@ TEST_F(FITSHeaderTest, DeserializationErrors) { // Test with empty data std::vector empty_data; EXPECT_THROW(header.deserialize(empty_data), FITSHeaderException); - + // Test with data that's not a multiple of FITS_HEADER_CARD_SIZE std::vector invalid_size_data(FITSHeader::FITS_HEADER_CARD_SIZE - 1, ' '); EXPECT_THROW(header.deserialize(invalid_size_data), FITSHeaderException); - + // Test with data that doesn't contain an END keyword std::vector no_end_data(FITSHeader::FITS_HEADER_UNIT_SIZE, ' '); EXPECT_THROW(header.deserialize(no_end_data), FITSHeaderException); @@ -185,7 +185,7 @@ TEST_F(FITSHeaderTest, LongKeywordsAndValues) { header.addKeyword(long_keyword, "value"); EXPECT_FALSE(header.hasKeyword(long_keyword)); EXPECT_TRUE(header.hasKeyword(long_keyword.substr(0, 8))); - + // Value longer than 72 chars should be truncated std::string long_value(100, 'X'); // 100 X characters header.addKeyword("LONGVAL", long_value); @@ -197,15 +197,15 @@ TEST_F(FITSHeaderTest, SpecialKeywordFormats) { // Test HIERARCH convention for long keywords header.addKeyword("HIERARCH ESO DET CHIP TEMP", "-120.0"); EXPECT_TRUE(header.hasKeyword("HIERARCH")); - + // Test with string value (should be quoted) header.addKeyword("TELESCOP", "'JWST'"); EXPECT_EQ(header.getKeywordValue("TELESCOP"), "'JWST'"); - + // Test with boolean value header.addKeyword("FLAG", "T"); EXPECT_EQ(header.getKeywordValue("FLAG"), "T"); - + // Test with numeric value header.addKeyword("EXPTIME", "1200.5"); EXPECT_EQ(header.getKeywordValue("EXPTIME"), "1200.5"); @@ -214,11 +214,11 @@ TEST_F(FITSHeaderTest, SpecialKeywordFormats) { // Test KeywordRecord constructor TEST_F(FITSHeaderTest, KeywordRecordConstructor) { FITSHeader::KeywordRecord record("TEST", "value"); - + // Check keyword is stored correctly std::array expected_keyword{'T', 'E', 'S', 'T', 0, 0, 0, 0}; EXPECT_EQ(record.keyword, expected_keyword); - + // Check value is stored correctly std::array expected_value{}; std::fill(expected_value.begin(), expected_value.end(), 0); @@ -230,24 +230,24 @@ TEST_F(FITSHeaderTest, KeywordRecordConstructor) { TEST_F(FITSHeaderTest, ExtensiveFITSHeader) { // Create a header with many keywords to test scaling behavior FITSHeader large_header; - + // Add 100 keywords for (int i = 0; i < 100; i++) { std::string keyword = "KEY" + std::to_string(i); std::string value = "value" + std::to_string(i); large_header.addKeyword(keyword.substr(0, 8), value); } - + // Check all keywords exist for (int i = 0; i < 100; i++) { std::string keyword = "KEY" + std::to_string(i); EXPECT_TRUE(large_header.hasKeyword(keyword.substr(0, 8))); } - + // Check serialization size std::vector data = large_header.serialize(); - int expected_size = ((100 + 1) * FITSHeader::FITS_HEADER_CARD_SIZE + FITSHeader::FITS_HEADER_UNIT_SIZE - 1) - / FITSHeader::FITS_HEADER_UNIT_SIZE + int expected_size = ((100 + 1) * FITSHeader::FITS_HEADER_CARD_SIZE + FITSHeader::FITS_HEADER_UNIT_SIZE - 1) + / FITSHeader::FITS_HEADER_UNIT_SIZE * FITSHeader::FITS_HEADER_UNIT_SIZE; EXPECT_EQ(data.size(), expected_size); } @@ -259,19 +259,19 @@ TEST_F(FITSHeaderTest, RequiredFITSKeywords) { minimal_header.addKeyword("SIMPLE", "T"); minimal_header.addKeyword("BITPIX", "16"); minimal_header.addKeyword("NAXIS", "0"); - + // Serialize and check std::vector data = minimal_header.serialize(); EXPECT_TRUE(containsPattern(data, "SIMPLE = T")); EXPECT_TRUE(containsPattern(data, "BITPIX = 16")); EXPECT_TRUE(containsPattern(data, "NAXIS = 0")); - + // Required keywords should be in the correct order std::string data_str(data.begin(), data.end()); size_t simple_pos = data_str.find("SIMPLE"); size_t bitpix_pos = data_str.find("BITPIX"); size_t naxis_pos = data_str.find("NAXIS"); - + EXPECT_LT(simple_pos, bitpix_pos); EXPECT_LT(bitpix_pos, naxis_pos); } @@ -280,10 +280,10 @@ TEST_F(FITSHeaderTest, RequiredFITSKeywords) { TEST_F(FITSHeaderTest, ContinueKeyword) { // Create a header with a long string that requires CONTINUE FITSHeader header_with_continue; - + std::string long_string(150, 'A'); // 150 'A' characters header_with_continue.addKeyword("HISTORY", long_string); - + // Serialize and check for CONTINUE std::vector data = header_with_continue.serialize(); EXPECT_TRUE(containsPattern(data, "HISTORY ")); @@ -294,12 +294,12 @@ TEST_F(FITSHeaderTest, ContinueKeyword) { TEST_F(FITSHeaderTest, CommentVsHistory) { header.addComment("This is a comment"); header.addKeyword("HISTORY", "This is a history entry"); - + // Serialize and check both are present std::vector data = header.serialize(); EXPECT_TRUE(containsPattern(data, "COMMENT This is a comment")); EXPECT_TRUE(containsPattern(data, "HISTORY This is a history entry")); - + // COMMENT should not appear in normal getAllKeywords list auto keywords = header.getAllKeywords(); EXPECT_THAT(keywords, ::testing::Contains("HISTORY")); @@ -309,7 +309,7 @@ TEST_F(FITSHeaderTest, CommentVsHistory) { TEST_F(FITSHeaderTest, EmptyValues) { header.addKeyword("EMPTY", ""); EXPECT_EQ(header.getKeywordValue("EMPTY"), ""); - + // Serialize and check std::vector data = header.serialize(); EXPECT_TRUE(containsPattern(data, "EMPTY =")); @@ -318,7 +318,7 @@ TEST_F(FITSHeaderTest, EmptyValues) { // Test round-trip with all kinds of values TEST_F(FITSHeaderTest, RoundTripValues) { FITSHeader test_header; - + // Add various types of values test_header.addKeyword("BOOLEAN", "T"); test_header.addKeyword("INTEGER", "42"); @@ -327,12 +327,12 @@ TEST_F(FITSHeaderTest, RoundTripValues) { test_header.addKeyword("DATE", "'2023-01-01T12:00:00'"); test_header.addKeyword("EMPTY", ""); test_header.addComment("Test comment"); - + // Serialize and deserialize std::vector data = test_header.serialize(); FITSHeader deserialized; deserialized.deserialize(data); - + // Check all values survived round-trip EXPECT_EQ(deserialized.getKeywordValue("BOOLEAN"), "T"); EXPECT_EQ(deserialized.getKeywordValue("INTEGER"), "42"); @@ -346,26 +346,26 @@ TEST_F(FITSHeaderTest, RoundTripValues) { // Test with multi-line serialization TEST_F(FITSHeaderTest, MultilineComment) { header.addComment("Line 1\nLine 2\nLine 3"); - + auto comments = header.getComments(); EXPECT_EQ(comments.size(), 1); EXPECT_EQ(comments[0], "Line 1\nLine 2\nLine 3"); - + // Serialize and check - should be flattened or split into multiple COMMENT lines std::vector data = header.serialize(); - + // Either approach is valid, just make sure the data is preserved FITSHeader deserialized; deserialized.deserialize(data); auto deserialized_comments = deserialized.getComments(); - + std::string original = comments[0]; std::string reconstructed; for (const auto& c : deserialized_comments) { if (!reconstructed.empty()) reconstructed += "\n"; reconstructed += c; } - + // Check that content is preserved, even if format changes EXPECT_TRUE(reconstructed.find("Line 1") != std::string::npos); EXPECT_TRUE(reconstructed.find("Line 2") != std::string::npos); @@ -377,4 +377,4 @@ TEST_F(FITSHeaderTest, MultilineComment) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/tests/image/test_hdu.hpp b/tests/image/test_hdu.hpp index d886541d..57d0f208 100644 --- a/tests/image/test_hdu.hpp +++ b/tests/image/test_hdu.hpp @@ -21,12 +21,12 @@ namespace fs = std::filesystem; // Helper function to create a temporary FITS file for testing inline std::string createTempFitsFile(int width = 10, int height = 10, int channels = 1) { // Create a temporary file - std::string tempFilePath = (fs::temp_directory_path() / + std::string tempFilePath = (fs::temp_directory_path() / fs::path("test_hdu_temp_" + std::to_string(std::random_device{}()) + ".fits")).string(); - + // Create a simple FITS file with basic header std::ofstream outFile(tempFilePath, std::ios::binary); - + // Write FITS header outFile << "SIMPLE = T / Standard FITS format" << std::string(80-44, ' ') << std::endl; outFile << "BITPIX = 32 / Bits per pixel" << std::string(80-42, ' ') << std::endl; @@ -37,22 +37,22 @@ inline std::string createTempFitsFile(int width = 10, int height = 10, int chann outFile << "NAXIS3 = " << std::setw(2) << channels << " / Channels" << std::string(80-41, ' ') << std::endl; } outFile << "END" << std::string(80-3, ' ') << std::endl; - + // Pad header to multiple of 2880 bytes int headerBlocks = 1; // Start with one for the header we've already written int bytesWritten = headerBlocks * 2880; int paddingRequired = bytesWritten - (7 * 80); // 7 header cards written so far outFile << std::string(paddingRequired, ' '); - + // Write simple data (all zeros) int dataSize = width * height * channels * sizeof(int32_t); std::vector dummyData(width * height * channels, 0); outFile.write(reinterpret_cast(dummyData.data()), dataSize); - + // Pad data to multiple of 2880 bytes int dataPaddingRequired = (2880 - (dataSize % 2880)) % 2880; outFile << std::string(dataPaddingRequired, '\0'); - + outFile.close(); return tempFilePath; } @@ -65,19 +65,19 @@ class ImageHDUTest : public ::testing::Test { tempFilePaths.push_back(createTempFitsFile(10, 10, 3)); // RGB image tempFilePaths.push_back(createTempFitsFile(100, 100, 1)); // Larger image } - + void TearDown() override { // Clean up all created temp files for (const auto& path : tempFilePaths) { std::remove(path.c_str()); } } - + // Fill an ImageHDU with test data template void fillTestData(ImageHDU& hdu, int width, int height, int channels) { hdu.setImageSize(width, height, channels); - + // Fill with test pattern for (int y = 0; y < height; ++y) { for (int x = 0; x < width; ++x) { @@ -88,7 +88,7 @@ class ImageHDUTest : public ::testing::Test { } } } - + // Create an ImageHDU with test pattern and specific data type template std::unique_ptr createTestImageHDU(int width, int height, int channels = 1) { @@ -96,7 +96,7 @@ class ImageHDUTest : public ::testing::Test { fillTestData(*hdu, width, height, channels); return hdu; } - + std::vector tempFilePaths; }; @@ -104,9 +104,9 @@ class ImageHDUTest : public ::testing::Test { TEST_F(ImageHDUTest, ReadHDUFromFile) { ImageHDU hdu; std::ifstream file(tempFilePaths[0], std::ios::binary); - + ASSERT_NO_THROW(hdu.readHDU(file)); - + auto [width, height, channels] = hdu.getImageSize(); EXPECT_EQ(width, 10); EXPECT_EQ(height, 10); @@ -117,9 +117,9 @@ TEST_F(ImageHDUTest, ReadHDUFromFile) { TEST_F(ImageHDUTest, ReadMultiChannelHDU) { ImageHDU hdu; std::ifstream file(tempFilePaths[1], std::ios::binary); - + ASSERT_NO_THROW(hdu.readHDU(file)); - + auto [width, height, channels] = hdu.getImageSize(); EXPECT_EQ(width, 10); EXPECT_EQ(height, 10); @@ -131,24 +131,24 @@ TEST_F(ImageHDUTest, ReadMultiChannelHDU) { TEST_F(ImageHDUTest, WriteHDUToFile) { // Create a test HDU with data auto hdu = createTestImageHDU(20, 15, 1); - + // Write to a new file std::string outputPath = (fs::temp_directory_path() / "test_hdu_write.fits").string(); std::ofstream outputFile(outputPath, std::ios::binary); - + ASSERT_NO_THROW(hdu->writeHDU(outputFile)); outputFile.close(); - + // Read it back to verify ImageHDU readHdu; std::ifstream inputFile(outputPath, std::ios::binary); ASSERT_NO_THROW(readHdu.readHDU(inputFile)); - + auto [width, height, channels] = readHdu.getImageSize(); EXPECT_EQ(width, 20); EXPECT_EQ(height, 15); EXPECT_EQ(channels, 1); - + // Clean up std::remove(outputPath.c_str()); } @@ -158,11 +158,11 @@ TEST_F(ImageHDUTest, HeaderKeywords) { ImageHDU hdu; std::ifstream file(tempFilePaths[0], std::ios::binary); hdu.readHDU(file); - + // Set and get a keyword hdu.setHeaderKeyword("OBSERVER", "Test User"); EXPECT_EQ(hdu.getHeaderKeyword("OBSERVER"), "Test User"); - + // Should have standard FITS keywords EXPECT_EQ(hdu.getHeaderKeyword("SIMPLE"), "T"); EXPECT_EQ(hdu.getHeaderKeyword("BITPIX"), "32"); @@ -172,16 +172,16 @@ TEST_F(ImageHDUTest, HeaderKeywords) { // Test setting and getting image dimensions TEST_F(ImageHDUTest, ImageDimensions) { ImageHDU hdu; - + ASSERT_NO_THROW(hdu.setImageSize(30, 40, 2)); - + auto [width, height, channels] = hdu.getImageSize(); EXPECT_EQ(width, 30); EXPECT_EQ(height, 40); EXPECT_EQ(channels, 2); EXPECT_TRUE(hdu.isColor()); EXPECT_EQ(hdu.getChannelCount(), 2); - + // Test invalid dimensions EXPECT_THROW(hdu.setImageSize(-5, 40), std::invalid_argument); EXPECT_THROW(hdu.setImageSize(30, 0), std::invalid_argument); @@ -191,16 +191,16 @@ TEST_F(ImageHDUTest, ImageDimensions) { // Test pixel access operations for different data types TEST_F(ImageHDUTest, PixelAccess_Int32) { auto hdu = createTestImageHDU(15, 10); - + // Check a few pixels EXPECT_EQ(hdu->getPixel(5, 5), (5 + 5 * 2) % 255); EXPECT_EQ(hdu->getPixel(0, 0), 0); EXPECT_EQ(hdu->getPixel(9, 9), (9 + 9 * 2) % 255); - + // Modify a pixel hdu->setPixel(5, 5, 123); EXPECT_EQ(hdu->getPixel(5, 5), 123); - + // Out of bounds access EXPECT_THROW(hdu->getPixel(15, 5), std::out_of_range); EXPECT_THROW(hdu->getPixel(5, 15), std::out_of_range); @@ -209,32 +209,32 @@ TEST_F(ImageHDUTest, PixelAccess_Int32) { TEST_F(ImageHDUTest, PixelAccess_Float) { auto hdu = createTestImageHDU(15, 10); - + // Check a few pixels EXPECT_FLOAT_EQ(hdu->getPixel(5, 5), static_cast((5 + 5 * 2) % 255)); EXPECT_FLOAT_EQ(hdu->getPixel(0, 0), 0.0f); - + // Modify a pixel hdu->setPixel(5, 5, 123.45f); EXPECT_FLOAT_EQ(hdu->getPixel(5, 5), 123.45f); - + // Invalid channel access EXPECT_THROW(hdu->getPixel(5, 5, 1), std::out_of_range); } TEST_F(ImageHDUTest, PixelAccess_Double) { auto hdu = createTestImageHDU(15, 10, 3); - + // Check multi-channel access for (int c = 0; c < 3; ++c) { EXPECT_DOUBLE_EQ(hdu->getPixel(5, 5, c), static_cast((5 + 5 * 2) % 255)); } - + // Modify different channels hdu->setPixel(5, 5, 100.5, 0); hdu->setPixel(5, 5, 200.5, 1); hdu->setPixel(5, 5, 300.5, 2); - + EXPECT_DOUBLE_EQ(hdu->getPixel(5, 5, 0), 100.5); EXPECT_DOUBLE_EQ(hdu->getPixel(5, 5, 1), 200.5); EXPECT_DOUBLE_EQ(hdu->getPixel(5, 5, 2), 300.5); @@ -243,15 +243,15 @@ TEST_F(ImageHDUTest, PixelAccess_Double) { // Test image statistics computation TEST_F(ImageHDUTest, ComputeImageStats_Int) { auto hdu = createTestImageHDU(20, 10); - + auto stats = hdu->computeImageStats(); - + // Check basic stats properties EXPECT_LE(stats.min, stats.max); EXPECT_GE(stats.mean, static_cast(stats.min)); EXPECT_LE(stats.mean, static_cast(stats.max)); EXPECT_GE(stats.stddev, 0.0); - + // For our pattern, we know some properties EXPECT_EQ(stats.min, 0); EXPECT_EQ(stats.max, 57); // (19 + 19*2) % 255 = 57 @@ -259,17 +259,17 @@ TEST_F(ImageHDUTest, ComputeImageStats_Int) { TEST_F(ImageHDUTest, ComputeImageStats_Float) { auto hdu = createTestImageHDU(20, 10, 2); - + // Check stats for each channel for (int channel = 0; channel < 2; ++channel) { auto stats = hdu->computeImageStats(channel); - + EXPECT_FLOAT_EQ(stats.min, 0.0f); EXPECT_FLOAT_EQ(stats.max, 57.0f); // (19 + 19*2) % 255 = 57 EXPECT_GT(stats.mean, 0.0); EXPECT_GT(stats.stddev, 0.0); } - + // Invalid channel EXPECT_THROW(hdu->computeImageStats(2), std::out_of_range); } @@ -277,25 +277,25 @@ TEST_F(ImageHDUTest, ComputeImageStats_Float) { // Test convolution filtering TEST_F(ImageHDUTest, ApplyFilter) { auto hdu = createTestImageHDU(20, 10); - + // Create a simple box blur kernel (3x3) std::vector kernelData = { 1.0/9.0, 1.0/9.0, 1.0/9.0, 1.0/9.0, 1.0/9.0, 1.0/9.0, 1.0/9.0, 1.0/9.0, 1.0/9.0 }; - + std::vector> kernel; for (int i = 0; i < 3; ++i) { kernel.push_back(std::span(&kernelData[i*3], 3)); } - + // Store original value for comparison float originalValue = hdu->getPixel(5, 5); - + // Apply filter ASSERT_NO_THROW(hdu->applyFilter(kernel)); - + // After box blur, center pixels should be the average of their neighborhood // But exact equality can be affected by boundary conditions, so we just verify it changed EXPECT_NE(hdu->getPixel(5, 5), originalValue); @@ -304,19 +304,19 @@ TEST_F(ImageHDUTest, ApplyFilter) { // Test parallel filtering TEST_F(ImageHDUTest, ApplyFilterParallel) { auto hdu = createTestImageHDU(50, 50); // Larger image for parallel processing - + // Create a simple box blur kernel (3x3) std::vector kernelData = { 1.0/9.0, 1.0/9.0, 1.0/9.0, 1.0/9.0, 1.0/9.0, 1.0/9.0, 1.0/9.0, 1.0/9.0, 1.0/9.0 }; - + std::vector> kernel; for (int i = 0; i < 3; ++i) { kernel.push_back(std::span(&kernelData[i*3], 3)); } - + // Store original values at several positions std::vector originalValues; for (int y = 10; y < 40; y += 10) { @@ -324,10 +324,10 @@ TEST_F(ImageHDUTest, ApplyFilterParallel) { originalValues.push_back(hdu->getPixel(x, y)); } } - + // Apply parallel filter ASSERT_NO_THROW(hdu->applyFilterParallel(kernel)); - + // Check that values have changed int idx = 0; for (int y = 10; y < 40; y += 10) { @@ -340,21 +340,21 @@ TEST_F(ImageHDUTest, ApplyFilterParallel) { // Test image resizing TEST_F(ImageHDUTest, Resize) { auto hdu = createTestImageHDU(20, 10); - + // Resize to larger dimensions ASSERT_NO_THROW(hdu->resize(40, 20)); - + auto [width, height, channels] = hdu->getImageSize(); EXPECT_EQ(width, 40); EXPECT_EQ(height, 20); - + // Resize to smaller dimensions ASSERT_NO_THROW(hdu->resize(10, 5)); - + std::tie(width, height, channels) = hdu->getImageSize(); EXPECT_EQ(width, 10); EXPECT_EQ(height, 5); - + // Invalid dimensions EXPECT_THROW(hdu->resize(0, 20), std::invalid_argument); EXPECT_THROW(hdu->resize(10, -5), std::invalid_argument); @@ -363,17 +363,17 @@ TEST_F(ImageHDUTest, Resize) { // Test thumbnail creation TEST_F(ImageHDUTest, CreateThumbnail) { auto hdu = createTestImageHDU(100, 50); - + // Create a thumbnail with max size 20 auto thumbnail = hdu->createThumbnail(20); ASSERT_NE(thumbnail, nullptr); - + auto [width, height, channels] = thumbnail->getImageSize(); - + // The width should be 20 and height should be proportionally scaled EXPECT_EQ(width, 20); EXPECT_EQ(height, 10); // 50/100 * 20 = 10 - + // Test with invalid size EXPECT_THROW(hdu->createThumbnail(0), std::invalid_argument); } @@ -381,23 +381,23 @@ TEST_F(ImageHDUTest, CreateThumbnail) { // Test ROI extraction TEST_F(ImageHDUTest, ExtractROI) { auto hdu = createTestImageHDU(30, 20); - + // Extract a region auto roi = hdu->extractROI(5, 5, 10, 8); ASSERT_NE(roi, nullptr); - + auto [width, height, channels] = roi->getImageSize(); EXPECT_EQ(width, 10); EXPECT_EQ(height, 8); - + // Check that the ROI data matches the original in that region for (int y = 0; y < 8; ++y) { for (int x = 0; x < 10; ++x) { - EXPECT_EQ(roi->getPixel(x, y), + EXPECT_EQ(roi->getPixel(x, y), hdu->getPixel(x + 5, y + 5)); } } - + // Test invalid ROI parameters EXPECT_THROW(hdu->extractROI(-1, 5, 10, 8), std::out_of_range); EXPECT_THROW(hdu->extractROI(5, 5, 50, 8), std::out_of_range); @@ -407,13 +407,13 @@ TEST_F(ImageHDUTest, ExtractROI) { // Test async statistics computation TEST_F(ImageHDUTest, ComputeImageStatsAsync) { auto hdu = createTestImageHDU(100, 100); // Larger image for async test - + // Compute stats asynchronously auto statsTask = hdu->computeImageStatsAsync(); - + // Get the result auto stats = statsTask.get_result(); - + // Check basic stats properties EXPECT_LE(stats.min, stats.max); EXPECT_GE(stats.mean, static_cast(stats.min)); @@ -425,26 +425,26 @@ TEST_F(ImageHDUTest, ComputeImageStatsAsync) { TEST_F(ImageHDUTest, BlendImage) { auto hdu1 = createTestImageHDU(20, 10); auto hdu2 = createTestImageHDU(20, 10); - + // Modify hdu2 to have different values for (int y = 0; y < 10; ++y) { for (int x = 0; x < 20; ++x) { hdu2->setPixel(x, y, 200.0f); } } - + // Blend with 50% of each ASSERT_NO_THROW(hdu1->blendImage(*hdu2, 0.5)); - + // Check a sample point - should be halfway between original and 200 float originalValue = static_cast((5 + 5 * 2) % 255); float expectedValue = originalValue * 0.5f + 200.0f * 0.5f; EXPECT_FLOAT_EQ(hdu1->getPixel(5, 5), expectedValue); - + // Test invalid alpha EXPECT_THROW(hdu1->blendImage(*hdu2, -0.1), std::invalid_argument); EXPECT_THROW(hdu1->blendImage(*hdu2, 1.5), std::invalid_argument); - + // Test incompatible images auto hdu3 = createTestImageHDU(30, 10); EXPECT_THROW(hdu1->blendImage(*hdu3, 0.5), ImageProcessingException); @@ -453,19 +453,19 @@ TEST_F(ImageHDUTest, BlendImage) { // Test mathematical operations TEST_F(ImageHDUTest, ApplyMathOperation) { auto hdu = createTestImageHDU(20, 10); - + // Apply a multiply-by-2 operation ASSERT_NO_THROW(hdu->applyMathOperation([](float val) { return val * 2.0f; })); - + // Check a sample point float originalValue = static_cast((5 + 5 * 2) % 255); EXPECT_FLOAT_EQ(hdu->getPixel(5, 5), originalValue * 2.0f); - + // Apply a complex operation - ASSERT_NO_THROW(hdu->applyMathOperation([](float val) { - return std::sin(val) * 100.0f; + ASSERT_NO_THROW(hdu->applyMathOperation([](float val) { + return std::sin(val) * 100.0f; })); - + // Check the result is changed EXPECT_NE(hdu->getPixel(5, 5), originalValue * 2.0f); } @@ -473,13 +473,13 @@ TEST_F(ImageHDUTest, ApplyMathOperation) { // Test histogram computation TEST_F(ImageHDUTest, ComputeHistogram) { auto hdu = createTestImageHDU(50, 50); - + // Compute a histogram with 10 bins auto histogram = hdu->computeHistogram(10); - + // Check basic properties EXPECT_EQ(histogram.size(), 10); - + // The sum of all bins should equal the number of pixels double sum = 0.0; for (double binCount : histogram) { @@ -487,7 +487,7 @@ TEST_F(ImageHDUTest, ComputeHistogram) { EXPECT_GE(binCount, 0.0); // Bin counts should be non-negative } EXPECT_EQ(sum, 50 * 50); - + // Test invalid bin count EXPECT_THROW(hdu->computeHistogram(0), std::invalid_argument); } @@ -495,16 +495,16 @@ TEST_F(ImageHDUTest, ComputeHistogram) { // Test histogram equalization TEST_F(ImageHDUTest, EqualizeHistogram) { auto hdu = createTestImageHDU(50, 50); - + // Calculate histogram before equalization auto histBefore = hdu->computeHistogram(256); - + // Perform equalization ASSERT_NO_THROW(hdu->equalizeHistogram()); - + // Calculate histogram after equalization auto histAfter = hdu->computeHistogram(256); - + // Histograms should be different after equalization bool histogramChanged = false; for (size_t i = 0; i < histBefore.size(); ++i) { @@ -519,16 +519,16 @@ TEST_F(ImageHDUTest, EqualizeHistogram) { // Test edge detection TEST_F(ImageHDUTest, DetectEdges) { auto hdu = createTestImageHDU(50, 50); - + // Store original value float originalValue = hdu->getPixel(25, 25); - + // Apply Sobel edge detection ASSERT_NO_THROW(hdu->detectEdges("sobel")); - + // Values should change after edge detection EXPECT_NE(hdu->getPixel(25, 25), originalValue); - + // Test invalid method EXPECT_THROW(hdu->detectEdges("invalid_method"), std::invalid_argument); } @@ -536,7 +536,7 @@ TEST_F(ImageHDUTest, DetectEdges) { // Test compression functions TEST_F(ImageHDUTest, CompressionDecompression) { auto hdu = createTestImageHDU(50, 50); - + // Store original data std::vector originalData; for (int y = 0; y < 50; ++y) { @@ -544,17 +544,17 @@ TEST_F(ImageHDUTest, CompressionDecompression) { originalData.push_back(hdu->getPixel(x, y)); } } - + // Compress with RLE ASSERT_NO_THROW(hdu->compressData("rle")); - + // Check compression ratio double ratio = hdu->computeCompressionRatio(); EXPECT_GT(ratio, 1.0); // Should achieve some compression - + // Decompress ASSERT_NO_THROW(hdu->decompressData()); - + // Verify data is preserved int idx = 0; for (int y = 0; y < 50; ++y) { @@ -562,7 +562,7 @@ TEST_F(ImageHDUTest, CompressionDecompression) { EXPECT_FLOAT_EQ(hdu->getPixel(x, y), originalData[idx++]); } } - + // Test invalid algorithm EXPECT_THROW(hdu->compressData("invalid_algorithm"), std::invalid_argument); } @@ -570,7 +570,7 @@ TEST_F(ImageHDUTest, CompressionDecompression) { // Test noise addition and removal TEST_F(ImageHDUTest, NoiseAdditionAndRemoval) { auto hdu = createTestImageHDU(30, 30); - + // Store original data std::vector originalData; for (int y = 0; y < 30; ++y) { @@ -578,10 +578,10 @@ TEST_F(ImageHDUTest, NoiseAdditionAndRemoval) { originalData.push_back(hdu->getPixel(x, y)); } } - + // Add Gaussian noise ASSERT_NO_THROW(hdu->addNoise("gaussian", 10.0)); - + // Verify data changed bool dataChanged = false; int idx = 0; @@ -593,10 +593,10 @@ TEST_F(ImageHDUTest, NoiseAdditionAndRemoval) { } } EXPECT_TRUE(dataChanged); - + // Remove noise with median filter ASSERT_NO_THROW(hdu->removeNoise("median", 3)); - + // Test invalid parameters EXPECT_THROW(hdu->addNoise("invalid_noise", 10.0), std::invalid_argument); EXPECT_THROW(hdu->removeNoise("median", 0), std::invalid_argument); @@ -605,16 +605,16 @@ TEST_F(ImageHDUTest, NoiseAdditionAndRemoval) { // Test Fourier transform and filtering TEST_F(ImageHDUTest, FourierTransformAndFiltering) { auto hdu = createTestImageHDU(32, 32); // Power of 2 size for FFT - + // Apply forward FFT ASSERT_NO_THROW(hdu->applyFourierTransform(false)); - + // Apply lowpass filter in frequency domain ASSERT_NO_THROW(hdu->applyFrequencyFilter("lowpass", 0.5)); - + // Apply inverse FFT to get back to spatial domain ASSERT_NO_THROW(hdu->applyFourierTransform(true)); - + // Test invalid parameters EXPECT_THROW(hdu->applyFrequencyFilter("invalid_filter", 0.5), std::invalid_argument); } @@ -622,10 +622,10 @@ TEST_F(ImageHDUTest, FourierTransformAndFiltering) { // Test auto-levels adjustment TEST_F(ImageHDUTest, AutoLevels) { auto hdu = createTestImageHDU(50, 50); - + // Apply auto-levels with custom black and white points ASSERT_NO_THROW(hdu->autoLevels(0.1, 0.9)); - + // Test invalid parameters EXPECT_THROW(hdu->autoLevels(-0.1, 0.9), std::invalid_argument); EXPECT_THROW(hdu->autoLevels(0.1, 1.1), std::invalid_argument); @@ -635,13 +635,13 @@ TEST_F(ImageHDUTest, AutoLevels) { // Test morphological operations TEST_F(ImageHDUTest, ApplyMorphology) { auto hdu = createTestImageHDU(50, 50); - + // Apply dilation ASSERT_NO_THROW(hdu->applyMorphology("dilate", 3)); - + // Apply erosion ASSERT_NO_THROW(hdu->applyMorphology("erode", 3)); - + // Test invalid parameters EXPECT_THROW(hdu->applyMorphology("invalid_op", 3), std::invalid_argument); EXPECT_THROW(hdu->applyMorphology("dilate", 4), std::invalid_argument); // Kernel size should be odd @@ -650,4 +650,4 @@ TEST_F(ImageHDUTest, ApplyMorphology) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/tests/image/test_image_blob.hpp b/tests/image/test_image_blob.hpp index abd1fabe..3badb00f 100644 --- a/tests/image/test_image_blob.hpp +++ b/tests/image/test_image_blob.hpp @@ -50,7 +50,7 @@ TEST_F(BlobTest, DefaultConstructor) { TEST_F(BlobTest, ConstructorWithRawData) { blob b(test_data.data(), test_data.size()); EXPECT_EQ(b.size(), test_data.size()); - + // Check that data was copied correctly for (size_t i = 0; i < test_data.size(); ++i) { EXPECT_EQ(b[i], test_data[i]); @@ -77,7 +77,7 @@ TEST_F(BlobTest, CopyConstructor) { EXPECT_EQ(copy.getCols(), original.getCols()); EXPECT_EQ(copy.getChannels(), original.getChannels()); EXPECT_EQ(copy.getDepth(), original.getDepth()); - + // Check that data was copied correctly for (size_t i = 0; i < original.size(); ++i) { EXPECT_EQ(copy[i], original[i]); @@ -103,9 +103,9 @@ TEST_F(BlobTest, MoveConstructor) { TEST_F(BlobTest, ConstConversionConstructor) { blob mutable_blob(test_data.data(), test_data.size()); cblob const_blob(mutable_blob); - + EXPECT_EQ(const_blob.size(), mutable_blob.size()); - + // Check that data was copied correctly for (size_t i = 0; i < mutable_blob.size(); ++i) { EXPECT_EQ(const_blob[i], mutable_blob[i]); @@ -116,9 +116,9 @@ TEST_F(BlobTest, ConstConversionConstructor) { TEST_F(BlobTest, FastModeBlob) { std::vector data(test_data); fast_blob fb(data.data(), data.size()); - + EXPECT_EQ(fb.size(), data.size()); - + // Modify original data and check that fast_blob reflects the changes data[0] = std::byte{255}; EXPECT_EQ(fb[0], std::byte{255}); @@ -130,19 +130,19 @@ TEST_F(BlobTest, Slice) { b.rows_ = 2; b.cols_ = 6; // 2 pixels per row, 3 channels per pixel b.channels_ = 3; - + // Slice first row blob first_row = b.slice(0, 6); EXPECT_EQ(first_row.size(), 6); EXPECT_EQ(first_row[0], std::byte{10}); EXPECT_EQ(first_row[5], std::byte{60}); - + // Slice second row blob second_row = b.slice(6, 6); EXPECT_EQ(second_row.size(), 6); EXPECT_EQ(second_row[0], std::byte{70}); EXPECT_EQ(second_row[5], std::byte{120}); - + // Test out of bounds slice EXPECT_THROW(b.slice(10, 10), std::out_of_range); } @@ -152,18 +152,18 @@ TEST_F(BlobTest, EqualityOperator) { blob b1(test_data.data(), test_data.size()); blob b2(test_data.data(), test_data.size()); blob b3(test_data.data(), test_data.size() - 1); // Different size - + EXPECT_EQ(b1, b2); EXPECT_NE(b1, b3); - + // Modify b2 and check inequality b2[0] = std::byte{255}; EXPECT_NE(b1, b2); - + // Set b2 back to equal b1 b2[0] = b1[0]; EXPECT_EQ(b1, b2); - + // Change other properties and check inequality b2.rows_ = 3; EXPECT_NE(b1, b2); @@ -173,7 +173,7 @@ TEST_F(BlobTest, EqualityOperator) { TEST_F(BlobTest, Fill) { blob b(test_data.data(), test_data.size()); b.fill(std::byte{42}); - + for (size_t i = 0; i < b.size(); ++i) { EXPECT_EQ(b[i], std::byte{42}); } @@ -183,17 +183,17 @@ TEST_F(BlobTest, Fill) { TEST_F(BlobTest, AppendBlob) { blob b1(test_data.data(), 6); // First row blob b2(test_data.data() + 6, 6); // Second row - + b1.rows_ = 1; b1.cols_ = 6; b1.channels_ = 1; - + b2.rows_ = 1; b2.cols_ = 6; b2.channels_ = 1; - + b1.append(b2); - + EXPECT_EQ(b1.size(), 12); EXPECT_EQ(b1.getRows(), 2); EXPECT_EQ(b1[6], std::byte{70}); @@ -206,9 +206,9 @@ TEST_F(BlobTest, AppendRawData) { b.rows_ = 1; b.cols_ = 6; b.channels_ = 1; - + b.append(test_data.data() + 6, 6); // Append second row - + EXPECT_EQ(b.size(), 12); EXPECT_EQ(b.getRows(), 2); EXPECT_EQ(b[6], std::byte{70}); @@ -220,7 +220,7 @@ TEST_F(BlobTest, AllocateAndDeallocate) { blob b; b.allocate(10); EXPECT_EQ(b.size(), 10); - + b.deallocate(); EXPECT_EQ(b.size(), 0); } @@ -229,17 +229,17 @@ TEST_F(BlobTest, AllocateAndDeallocate) { TEST_F(BlobTest, XorOperation) { blob b1(test_data.data(), test_data.size()); blob b2(test_data.data(), test_data.size()); - + // Fill b2 with a constant value b2.fill(std::byte{255}); - + b1.xorWith(b2); - + // Check that each byte is now the XOR of the original and 255 for (size_t i = 0; i < test_data.size(); ++i) { EXPECT_EQ(b1[i], std::byte{static_cast(test_data[i]) ^ 255}); } - + // Test with different sized blobs blob b3(test_data.data(), test_data.size() - 1); EXPECT_THROW(b1.xorWith(b3), std::runtime_error); @@ -250,10 +250,10 @@ TEST_F(BlobTest, CompressionAndDecompression) { // Create a blob with repeated values that should compress well std::vector compressible_data(100, std::byte{42}); blob original(compressible_data.data(), compressible_data.size()); - + blob compressed = original.compress(); EXPECT_LT(compressed.size(), original.size()); - + blob decompressed = compressed.decompress(); EXPECT_EQ(decompressed.size(), original.size()); EXPECT_EQ(decompressed, original); @@ -265,17 +265,17 @@ TEST_F(BlobTest, SerializationAndDeserialization) { original.rows_ = 2; original.cols_ = 2; original.channels_ = 3; - + std::vector serialized = original.serialize(); blob deserialized = blob::deserialize(serialized); - + EXPECT_EQ(deserialized.size(), original.size()); - + // Check data equality for (size_t i = 0; i < original.size(); ++i) { EXPECT_EQ(deserialized[i], original[i]); } - + // Test with invalid data std::vector invalid_data(2, std::byte{0}); EXPECT_THROW(blob::deserialize(invalid_data), std::runtime_error); @@ -284,14 +284,14 @@ TEST_F(BlobTest, SerializationAndDeserialization) { // Test iteration methods TEST_F(BlobTest, Iteration) { blob b(test_data.data(), test_data.size()); - + // Test begin/end interface size_t i = 0; for (auto byte : b) { EXPECT_EQ(byte, test_data[i++]); } EXPECT_EQ(i, test_data.size()); - + // Test const begin/end interface const blob& const_b = b; i = 0; @@ -306,7 +306,7 @@ TEST_F(BlobTest, Iteration) { TEST_F(BlobTest, OpenCVIntegration) { // Create a test matrix cv::Mat mat(2, 2, CV_8UC3); - + // Fill with test data for (int i = 0; i < 2; ++i) { for (int j = 0; j < 2; ++j) { @@ -315,21 +315,21 @@ TEST_F(BlobTest, OpenCVIntegration) { } } } - + // Create blob from matrix blob b(mat); - + EXPECT_EQ(b.getRows(), 2); EXPECT_EQ(b.getCols(), 2); EXPECT_EQ(b.getChannels(), 3); EXPECT_EQ(b.size(), 12); - + // Convert back to matrix cv::Mat reconstructed = b.to_mat(); - + // Verify matrix equality EXPECT_TRUE(cv::countNonZero(mat != reconstructed) == 0); - + // Test image operations blob resized = b; resized.resize(4, 4); @@ -337,32 +337,32 @@ TEST_F(BlobTest, OpenCVIntegration) { EXPECT_EQ(resized.getCols(), 4); EXPECT_EQ(resized.getChannels(), 3); EXPECT_EQ(resized.size(), 48); - + // Test channel splitting and merging std::vector channels = b.split_channels(); EXPECT_EQ(channels.size(), 3); EXPECT_EQ(channels[0].getChannels(), 1); EXPECT_EQ(channels[0].size(), 4); - + blob merged = blob::merge_channels(channels); EXPECT_EQ(merged.getChannels(), 3); EXPECT_EQ(merged.size(), 12); EXPECT_EQ(merged, b); - + // Test filtering cv::Mat kernel = (cv::Mat_(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0); blob filtered = b; filtered.apply_filter(kernel); - + // Test rotation and flipping blob rotated = b; rotated.rotate(90); EXPECT_NE(rotated, b); - + blob flipped = b; flipped.flip(1); // Horizontal flip EXPECT_NE(flipped, b); - + // Test color conversion if (b.getChannels() == 3) { blob gray = b; @@ -375,7 +375,7 @@ TEST_F(BlobTest, OpenCVIntegration) { TEST_F(BlobTest, OpenCVImageIO) { // Create a test matrix cv::Mat mat(2, 2, CV_8UC3); - + // Fill with test data for (int i = 0; i < 2; ++i) { for (int j = 0; j < 2; ++j) { @@ -384,21 +384,21 @@ TEST_F(BlobTest, OpenCVImageIO) { } } } - + // Create blob from matrix blob b(mat); - + // Save to file b.save(test_image_path); - + // Load from file blob loaded = blob::load(test_image_path); - + // Size and channels should be the same EXPECT_EQ(loaded.getRows(), b.getRows()); EXPECT_EQ(loaded.getCols(), b.getCols()); EXPECT_EQ(loaded.getChannels(), b.getChannels()); - + // Test loading non-existent file EXPECT_THROW(blob::load("non_existent_file.png"), std::runtime_error); } @@ -409,7 +409,7 @@ TEST_F(BlobTest, OpenCVImageIO) { TEST_F(BlobTest, CImgIntegration) { // Create a CImg cimg_library::CImg img(2, 2, 1, 3); - + // Fill with test data for (int y = 0; y < 2; ++y) { for (int x = 0; x < 2; ++x) { @@ -418,18 +418,18 @@ TEST_F(BlobTest, CImgIntegration) { } } } - + // Create blob from CImg blob b(img); - + EXPECT_EQ(b.getRows(), 2); EXPECT_EQ(b.getCols(), 2); EXPECT_EQ(b.getChannels(), 3); EXPECT_EQ(b.size(), 12); - + // Convert back to CImg cimg_library::CImg reconstructed = b.to_cimg(); - + // Verify image equality for (int y = 0; y < 2; ++y) { for (int x = 0; x < 2; ++x) { @@ -438,14 +438,14 @@ TEST_F(BlobTest, CImgIntegration) { } } } - + // Test filter application cimg_library::CImg kernel(3, 3, 1, 1, 0); kernel(1, 1) = 1.0f; // Identity filter - + blob filtered = b; filtered.apply_cimg_filter(kernel); - + // Should be similar to original after applying identity filter EXPECT_EQ(filtered.getRows(), b.getRows()); EXPECT_EQ(filtered.getCols(), b.getCols()); @@ -490,7 +490,7 @@ TEST_F(BlobTest, StbImageIntegration) { 0x00, 0x00, 0x00, 0x00 // Important colors }; fwrite(bmp_header, sizeof(bmp_header), 1, f); - + // Write test data (BGR order for BMP) for (int i = 0; i < test_data.size(); i += 3) { unsigned char bgr[3] = { @@ -503,27 +503,27 @@ TEST_F(BlobTest, StbImageIntegration) { fclose(f); } #endif - + // Load with stb_image blob b(test_image_path); - + // Basic checks EXPECT_EQ(b.getCols(), 2); EXPECT_EQ(b.getRows(), 2); EXPECT_EQ(b.getChannels(), 3); - + // Save with different formats b.save_as(test_image_path + ".png", "png"); b.save_as(test_image_path + ".bmp", "bmp"); b.save_as(test_image_path + ".jpg", "jpg"); b.save_as(test_image_path + ".tga", "tga"); - + // Clean up std::remove((test_image_path + ".png").c_str()); std::remove((test_image_path + ".bmp").c_str()); std::remove((test_image_path + ".jpg").c_str()); std::remove((test_image_path + ".tga").c_str()); - + // Test invalid format EXPECT_THROW(b.save_as(test_image_path + ".invalid", "invalid"), std::runtime_error); } @@ -534,24 +534,24 @@ TEST_F(BlobTest, FastModeLimitations) { // Create a fast blob std::vector data(test_data); fast_blob fb(data.data(), data.size()); - + // These operations should throw in FAST mode EXPECT_THROW(fb.append(fb), std::runtime_error); EXPECT_THROW(fb.append(data.data(), data.size()), std::runtime_error); EXPECT_THROW(fb.allocate(20), std::runtime_error); EXPECT_THROW(fb.deallocate(), std::runtime_error); - + #if __has_include() // CImg operations should throw in FAST mode cimg_library::CImg kernel(3, 3); EXPECT_THROW(fb.apply_cimg_filter(kernel), std::runtime_error); EXPECT_THROW(fb.to_cimg(), std::runtime_error); #endif - + #if __has_include() // stb_image operations should throw in FAST mode EXPECT_THROW(fb.save_as(test_image_path, "png"), std::runtime_error); - + // Fast mode constructor from stb_image should throw EXPECT_THROW(fast_blob bad_fb(test_image_path), std::runtime_error); #endif @@ -562,4 +562,4 @@ TEST_F(BlobTest, FastModeLimitations) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/tests/io/test_async_compress.cpp b/tests/io/test_async_compress.cpp index 81aafdc2..bb8911b2 100644 --- a/tests/io/test_async_compress.cpp +++ b/tests/io/test_async_compress.cpp @@ -25,82 +25,82 @@ class AsyncCompressTest : public ::testing::Test { test_dir_ = fs::temp_directory_path() / "atom_compress_test"; input_dir_ = test_dir_ / "input"; output_dir_ = test_dir_ / "output"; - + // Clean up any existing test directories if (fs::exists(test_dir_)) { fs::remove_all(test_dir_); } - + // Create fresh directories fs::create_directories(input_dir_); fs::create_directories(output_dir_); - + // Create test files with content createTestFile(input_dir_ / "test1.txt", "This is test file 1 content."); createTestFile(input_dir_ / "test2.txt", "This is test file 2 with different content."); createTestFile(input_dir_ / "test3.txt", std::string(50000, 'x')); // Larger file - + // Create a subdirectory with files fs::create_directories(input_dir_ / "subdir"); createTestFile(input_dir_ / "subdir" / "subfile1.txt", "Subdirectory file content."); - + // Set up io_context and work guard to keep io_context running work_guard_ = std::make_unique>( io_context_.get_executor()); - + // Start io_context in a separate thread io_thread_ = std::thread([this]() { io_context_.run(); }); } - + void TearDown() override { // Allow io_context to finish and join thread work_guard_.reset(); if (io_thread_.joinable()) { io_thread_.join(); } - + // Clean up test directory if (fs::exists(test_dir_)) { fs::remove_all(test_dir_); } } - + void createTestFile(const fs::path& path, const std::string& content) { std::ofstream file(path); file << content; file.close(); ASSERT_TRUE(fs::exists(path)) << "Failed to create test file: " << path; } - + bool fileContentsEqual(const fs::path& file1, const fs::path& file2) { std::ifstream f1(file1, std::ios::binary); std::ifstream f2(file2, std::ios::binary); - + if (!f1.is_open() || !f2.is_open()) { return false; } - + constexpr size_t BUFFER_SIZE = 4096; std::array buffer1, buffer2; - + while (f1 && f2) { f1.read(buffer1.data(), buffer1.size()); f2.read(buffer2.data(), buffer2.size()); - + if (f1.gcount() != f2.gcount()) { return false; } - + if (std::memcmp(buffer1.data(), buffer2.data(), f1.gcount()) != 0) { return false; } } - + return f1.eof() && f2.eof(); } - + // Wait for an operation to complete void waitForCompletion(std::chrono::milliseconds timeout = std::chrono::seconds(5)) { std::unique_lock lock(completion_mutex_); @@ -108,7 +108,7 @@ class AsyncCompressTest : public ::testing::Test { << "Operation timed out"; operation_completed_ = false; } - + void signalCompletion() { { std::lock_guard lock(completion_mutex_); @@ -116,15 +116,15 @@ class AsyncCompressTest : public ::testing::Test { } completion_cv_.notify_one(); } - + asio::io_context io_context_; std::unique_ptr> work_guard_; std::thread io_thread_; - + fs::path test_dir_; fs::path input_dir_; fs::path output_dir_; - + std::mutex completion_mutex_; std::condition_variable completion_cv_; bool operation_completed_ = false; @@ -134,23 +134,23 @@ class AsyncCompressTest : public ::testing::Test { TEST_F(AsyncCompressTest, SingleFileCompressorBasicOperation) { fs::path input_file = input_dir_ / "test1.txt"; fs::path output_file = output_dir_ / "test1.txt.gz"; - + // Create a completion handler auto handler = [this](const asio::error_code& ec, std::size_t bytes_transferred) { EXPECT_FALSE(ec) << "Error in async operation: " << ec.message(); signalCompletion(); }; - + // Create and start the compressor auto compressor = std::make_shared( io_context_, input_file, output_file); - + // Hook into the completion using a lambda that captures our handler compressor->start(); - + // Wait for operation to complete waitForCompletion(); - + // Verify output file exists and is not empty ASSERT_TRUE(fs::exists(output_file)) << "Output file was not created"; EXPECT_GT(fs::file_size(output_file), 0) << "Output file is empty"; @@ -159,23 +159,23 @@ TEST_F(AsyncCompressTest, SingleFileCompressorBasicOperation) { // Test DirectoryCompressor functionality TEST_F(AsyncCompressTest, DirectoryCompressorBasicOperation) { fs::path output_file = output_dir_ / "all_files.gz"; - + // Create a completion handler auto handler = [this](const asio::error_code& ec, std::size_t bytes_transferred) { EXPECT_FALSE(ec) << "Error in async operation: " << ec.message(); signalCompletion(); }; - + // Create and start the compressor auto compressor = std::make_shared( io_context_, input_dir_, output_file); - + // Start compression compressor->start(); - + // Wait for operation to complete waitForCompletion(); - + // Verify output file exists and is not empty ASSERT_TRUE(fs::exists(output_file)) << "Output file was not created"; EXPECT_GT(fs::file_size(output_file), 0) << "Output file is empty"; @@ -186,30 +186,30 @@ TEST_F(AsyncCompressTest, SingleFileDecompressorBasicOperation) { // First compress a file fs::path input_file = input_dir_ / "test1.txt"; fs::path compressed_file = output_dir_ / "test1.txt.gz"; - + { auto compressor = std::make_shared( io_context_, input_file, compressed_file); compressor->start(); waitForCompletion(); } - + // Now decompress it fs::path decompressed_file = output_dir_ / "decompressed_test1.txt"; - + auto decompressor = std::make_shared( io_context_, compressed_file, output_dir_); - + // Start decompression decompressor->start(); - + // Wait for operation to complete waitForCompletion(); - + // Verify decompressed file exists and content matches original - ASSERT_TRUE(fs::exists(output_dir_ / "test1.txt")) + ASSERT_TRUE(fs::exists(output_dir_ / "test1.txt")) << "Decompressed file was not created"; - + EXPECT_TRUE(fileContentsEqual(input_file, output_dir_ / "test1.txt")) << "Decompressed content does not match original"; } @@ -218,28 +218,28 @@ TEST_F(AsyncCompressTest, SingleFileDecompressorBasicOperation) { TEST_F(AsyncCompressTest, DirectoryDecompressorBasicOperation) { // First compress the directory fs::path compressed_file = output_dir_ / "all_files.gz"; - + { auto compressor = std::make_shared( io_context_, input_dir_, compressed_file); compressor->start(); waitForCompletion(); } - + // Create a new output directory for decompressed files fs::path decompressed_dir = output_dir_ / "decompressed"; fs::create_directories(decompressed_dir); - + // Now decompress it auto decompressor = std::make_shared( io_context_, output_dir_, decompressed_dir); - + // Start decompression decompressor->start(); - + // Wait for operation to complete waitForCompletion(); - + // Verify at least one decompressed file exists bool found_decompressed_file = false; for (const auto& entry : fs::directory_iterator(decompressed_dir)) { @@ -248,7 +248,7 @@ TEST_F(AsyncCompressTest, DirectoryDecompressorBasicOperation) { break; } } - + EXPECT_TRUE(found_decompressed_file) << "No decompressed files were created"; } @@ -256,7 +256,7 @@ TEST_F(AsyncCompressTest, DirectoryDecompressorBasicOperation) { TEST_F(AsyncCompressTest, CompressorErrorHandlingNonExistentFile) { fs::path non_existent_file = input_dir_ / "does_not_exist.txt"; fs::path output_file = output_dir_ / "error_output.gz"; - + // Expect an exception when trying to compress a non-existent file EXPECT_THROW({ auto compressor = std::make_shared( @@ -269,7 +269,7 @@ TEST_F(AsyncCompressTest, CompressorErrorHandlingNonExistentFile) { TEST_F(AsyncCompressTest, CompressorErrorHandlingInvalidOutputPath) { fs::path input_file = input_dir_ / "test1.txt"; fs::path invalid_output_file = fs::path("/non_existent_dir") / "output.gz"; - + // Expect an exception when trying to write to an invalid path EXPECT_THROW({ auto compressor = std::make_shared( @@ -282,86 +282,86 @@ TEST_F(AsyncCompressTest, CompressorErrorHandlingInvalidOutputPath) { TEST_F(AsyncCompressTest, ZipOperations) { // Create a test ZIP file fs::path zip_file = output_dir_ / "test.zip"; - + // We need to check if zip is available bool zip_available = atom::system::checkSoftwareInstalled("zip"); if (!zip_available) { GTEST_SKIP() << "Skipping test as 'zip' command is not available"; } - + // Create a ZIP file for testing using system commands - std::string cmd = "zip -j " + zip_file.string() + " " + + std::string cmd = "zip -j " + zip_file.string() + " " + (input_dir_ / "test1.txt").string() + " " + (input_dir_ / "test2.txt").string(); int result = std::system(cmd.c_str()); ASSERT_EQ(result, 0) << "Failed to create test ZIP file"; - + // Test ListFilesInZip { auto list_files = std::make_shared(io_context_, zip_file.string()); list_files->start(); - + // Wait for io operations to complete std::this_thread::sleep_for(std::chrono::milliseconds(500)); - + auto file_list = list_files->getFileList(); EXPECT_EQ(file_list.size(), 2); EXPECT_THAT(file_list, Contains(HasSubstr("test1.txt"))); EXPECT_THAT(file_list, Contains(HasSubstr("test2.txt"))); } - + // Test FileExistsInZip { auto file_exists = std::make_shared( io_context_, zip_file.string(), "test1.txt"); file_exists->start(); - + // Wait for io operations to complete std::this_thread::sleep_for(std::chrono::milliseconds(500)); - + EXPECT_TRUE(file_exists->found()); - + auto file_not_exists = std::make_shared( io_context_, zip_file.string(), "non_existent.txt"); file_not_exists->start(); - + // Wait for io operations to complete std::this_thread::sleep_for(std::chrono::milliseconds(500)); - + EXPECT_FALSE(file_not_exists->found()); } - + // Test GetZipFileSize { auto get_size = std::make_shared(io_context_, zip_file.string()); get_size->start(); - + // Wait for io operations to complete std::this_thread::sleep_for(std::chrono::milliseconds(500)); - + EXPECT_GT(get_size->getSizeValue(), 0); } - + // Test RemoveFileFromZip { auto remove_file = std::make_shared( io_context_, zip_file.string(), "test1.txt"); remove_file->start(); - + // Wait for io operations to complete std::this_thread::sleep_for(std::chrono::milliseconds(500)); - + // Check if removal was successful EXPECT_TRUE(remove_file->isSuccessful()); - + // Verify the file is no longer in the ZIP auto file_exists = std::make_shared( io_context_, zip_file.string(), "test1.txt"); file_exists->start(); - + // Wait for io operations to complete std::this_thread::sleep_for(std::chrono::milliseconds(500)); - + EXPECT_FALSE(file_exists->found()); } } @@ -372,11 +372,11 @@ TEST_F(AsyncCompressTest, ConcurrentCompression) { fs::path input_file1 = input_dir_ / "test1.txt"; fs::path input_file2 = input_dir_ / "test2.txt"; fs::path input_file3 = input_dir_ / "test3.txt"; - + fs::path output_file1 = output_dir_ / "test1.txt.gz"; fs::path output_file2 = output_dir_ / "test2.txt.gz"; fs::path output_file3 = output_dir_ / "test3.txt.gz"; - + // Create compressors auto compressor1 = std::make_shared( io_context_, input_file1, output_file1); @@ -384,20 +384,20 @@ TEST_F(AsyncCompressTest, ConcurrentCompression) { io_context_, input_file2, output_file2); auto compressor3 = std::make_shared( io_context_, input_file3, output_file3); - + // Start compressions concurrently compressor1->start(); compressor2->start(); compressor3->start(); - + // Wait for a reasonable amount of time for all operations to complete std::this_thread::sleep_for(std::chrono::seconds(3)); - + // Verify all output files exist EXPECT_TRUE(fs::exists(output_file1)) << "Output file 1 was not created"; EXPECT_TRUE(fs::exists(output_file2)) << "Output file 2 was not created"; EXPECT_TRUE(fs::exists(output_file3)) << "Output file 3 was not created"; - + // Verify all output files are not empty EXPECT_GT(fs::file_size(output_file1), 0) << "Output file 1 is empty"; EXPECT_GT(fs::file_size(output_file2), 0) << "Output file 2 is empty"; @@ -412,13 +412,13 @@ TEST_F(AsyncCompressTest, CompressDecompressRoundTrip) { input_dir_ / "test2.txt", input_dir_ / "test3.txt" }; - + // Create separate output directories for each file for (size_t i = 0; i < input_files.size(); ++i) { fs::path compressed_file = output_dir_ / (std::to_string(i) + ".gz"); fs::path decomp_dir = output_dir_ / ("decomp_" + std::to_string(i)); fs::create_directories(decomp_dir); - + // Compress { auto compressor = std::make_shared( @@ -426,7 +426,7 @@ TEST_F(AsyncCompressTest, CompressDecompressRoundTrip) { compressor->start(); std::this_thread::sleep_for(std::chrono::milliseconds(500)); } - + // Decompress { auto decompressor = std::make_shared( @@ -434,13 +434,13 @@ TEST_F(AsyncCompressTest, CompressDecompressRoundTrip) { decompressor->start(); std::this_thread::sleep_for(std::chrono::milliseconds(500)); } - + // Get the original filename fs::path original_name = input_files[i].filename(); - + // Verify content matches EXPECT_TRUE(fileContentsEqual( - input_files[i], + input_files[i], decomp_dir / original_name )) << "Round-trip content does not match for file " << i; } @@ -450,7 +450,7 @@ TEST_F(AsyncCompressTest, CompressDecompressRoundTrip) { TEST_F(AsyncCompressTest, CompressionPerformance) { // This test would typically measure and compare compression times and ratios // For different files or compression settings - + // Create a large test file fs::path large_file = input_dir_ / "large_file.txt"; { @@ -460,36 +460,36 @@ TEST_F(AsyncCompressTest, CompressionPerformance) { file << std::string(1024, 'a' + (i % 26)); } } - + fs::path output_file = output_dir_ / "large_file.gz"; - + // Record start time auto start_time = std::chrono::high_resolution_clock::now(); - + // Compress the file auto compressor = std::make_shared( io_context_, large_file, output_file); compressor->start(); - + // Wait for completion waitForCompletion(); - + // Record end time auto end_time = std::chrono::high_resolution_clock::now(); auto duration = std::chrono::duration_cast( end_time - start_time).count(); - + // Calculate compression ratio double original_size = static_cast(fs::file_size(large_file)); double compressed_size = static_cast(fs::file_size(output_file)); double compression_ratio = original_size / compressed_size; - + // Log performance metrics std::cout << "Compression time: " << duration << "ms\n"; std::cout << "Original size: " << original_size << " bytes\n"; std::cout << "Compressed size: " << compressed_size << " bytes\n"; std::cout << "Compression ratio: " << compression_ratio << ":1\n"; - + // Expect reasonable compression ratio for our test data EXPECT_GT(compression_ratio, 2.0) << "Compression ratio is lower than expected"; } @@ -497,4 +497,4 @@ TEST_F(AsyncCompressTest, CompressionPerformance) { int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/tests/io/test_async_glob.cpp b/tests/io/test_async_glob.cpp index 90f87dae..bae73989 100644 --- a/tests/io/test_async_glob.cpp +++ b/tests/io/test_async_glob.cpp @@ -25,12 +25,12 @@ class AsyncGlobTest : public ::testing::Test { void SetUp() override { // Create a temporary test directory structure testDir = fs::temp_directory_path() / "async_glob_test"; - + // Clean up any existing test directory if (fs::exists(testDir)) { fs::remove_all(testDir); } - + fs::create_directory(testDir); fs::create_directory(testDir / "dir1"); fs::create_directory(testDir / "dir2"); @@ -38,7 +38,7 @@ class AsyncGlobTest : public ::testing::Test { fs::create_directory(testDir / "dir1" / "subdir2"); fs::create_directory(testDir / "dir2" / "subdir1"); fs::create_directory(testDir / ".hidden_dir"); - + // Create some test files createFile(testDir / "file1.txt", "Test file 1"); createFile(testDir / "file2.txt", "Test file 2"); @@ -48,33 +48,33 @@ class AsyncGlobTest : public ::testing::Test { createFile(testDir / "dir2" / "file1.log", "Test file in dir2"); createFile(testDir / "dir1" / "subdir1" / "nested.txt", "Nested file"); createFile(testDir / ".hidden_file.txt", "Hidden file"); - + // Initialize IO context io_context = std::make_unique(); } - + void TearDown() override { // Clean up the test directory if (fs::exists(testDir)) { fs::remove_all(testDir); } - + // Make sure IO context is stopped io_context->stop(); } - + void createFile(const fs::path& path, const std::string& content) { std::ofstream file(path); file << content; file.close(); } - + // Helper to run the io_context void runContext() { io_context->run_for(std::chrono::milliseconds(100)); io_context->restart(); } - + fs::path testDir; std::unique_ptr io_context; }; @@ -87,9 +87,9 @@ TEST_F(AsyncGlobTest, Constructor) { // Test glob_sync with simple pattern TEST_F(AsyncGlobTest, GlobSyncSimplePattern) { AsyncGlob glob(*io_context); - + auto result = glob.glob_sync((testDir / "*.txt").string()); - + ASSERT_EQ(result.size(), 2); EXPECT_THAT(result, Contains(testDir / "file1.txt")); EXPECT_THAT(result, Contains(testDir / "file2.txt")); @@ -98,9 +98,9 @@ TEST_F(AsyncGlobTest, GlobSyncSimplePattern) { // Test glob_sync with directory pattern TEST_F(AsyncGlobTest, GlobSyncDirectoryPattern) { AsyncGlob glob(*io_context); - + auto result = glob.glob_sync((testDir / "dir*").string(), false, true); - + ASSERT_EQ(result.size(), 2); EXPECT_THAT(result, Contains(testDir / "dir1")); EXPECT_THAT(result, Contains(testDir / "dir2")); @@ -109,9 +109,9 @@ TEST_F(AsyncGlobTest, GlobSyncDirectoryPattern) { // Test glob_sync with recursive search TEST_F(AsyncGlobTest, GlobSyncRecursive) { AsyncGlob glob(*io_context); - + auto result = glob.glob_sync((testDir).string(), true, false); - + // Should find all non-hidden files and directories EXPECT_GT(result.size(), 10); EXPECT_THAT(result, Contains(testDir / "file1.txt")); @@ -124,19 +124,19 @@ TEST_F(AsyncGlobTest, GlobWithCallback) { std::vector callbackResult; std::promise callbackPromise; auto callbackFuture = callbackPromise.get_future(); - - glob.glob((testDir / "*.txt").string(), + + glob.glob((testDir / "*.txt").string(), [&callbackResult, &callbackPromise](std::vector result) { callbackResult = std::move(result); callbackPromise.set_value(); }); - + runContext(); - + // Wait for the callback to be called - ASSERT_EQ(callbackFuture.wait_for(std::chrono::seconds(1)), + ASSERT_EQ(callbackFuture.wait_for(std::chrono::seconds(1)), std::future_status::ready); - + ASSERT_EQ(callbackResult.size(), 2); EXPECT_THAT(callbackResult, Contains(testDir / "file1.txt")); EXPECT_THAT(callbackResult, Contains(testDir / "file2.txt")); @@ -145,12 +145,12 @@ TEST_F(AsyncGlobTest, GlobWithCallback) { // Test glob_async with coroutine TEST_F(AsyncGlobTest, GlobAsync) { AsyncGlob glob(*io_context); - + auto task = glob.glob_async((testDir / "*.txt").string()); auto result = task.get_result(); - + runContext(); - + ASSERT_EQ(result.size(), 2); EXPECT_THAT(result, Contains(testDir / "file1.txt")); EXPECT_THAT(result, Contains(testDir / "file2.txt")); @@ -159,9 +159,9 @@ TEST_F(AsyncGlobTest, GlobAsync) { // Test with complex pattern TEST_F(AsyncGlobTest, ComplexPattern) { AsyncGlob glob(*io_context); - + auto result = glob.glob_sync((testDir / "dir1" / "*" / "*.txt").string()); - + ASSERT_EQ(result.size(), 1); EXPECT_THAT(result, Contains(testDir / "dir1" / "subdir1" / "nested.txt")); } @@ -169,9 +169,9 @@ TEST_F(AsyncGlobTest, ComplexPattern) { // Test with question mark wildcard TEST_F(AsyncGlobTest, QuestionMarkWildcard) { AsyncGlob glob(*io_context); - + auto result = glob.glob_sync((testDir / "file?.txt").string()); - + ASSERT_EQ(result.size(), 2); EXPECT_THAT(result, Contains(testDir / "file1.txt")); EXPECT_THAT(result, Contains(testDir / "file2.txt")); @@ -180,9 +180,9 @@ TEST_F(AsyncGlobTest, QuestionMarkWildcard) { // Test with character class wildcard TEST_F(AsyncGlobTest, CharacterClassWildcard) { AsyncGlob glob(*io_context); - + auto result = glob.glob_sync((testDir / "file[1-2].txt").string()); - + ASSERT_EQ(result.size(), 2); EXPECT_THAT(result, Contains(testDir / "file1.txt")); EXPECT_THAT(result, Contains(testDir / "file2.txt")); @@ -191,9 +191,9 @@ TEST_F(AsyncGlobTest, CharacterClassWildcard) { // Test with negated character class TEST_F(AsyncGlobTest, NegatedCharacterClass) { AsyncGlob glob(*io_context); - + auto result = glob.glob_sync((testDir / "file[!3].txt").string()); - + ASSERT_EQ(result.size(), 2); EXPECT_THAT(result, Contains(testDir / "file1.txt")); EXPECT_THAT(result, Contains(testDir / "file2.txt")); @@ -202,9 +202,9 @@ TEST_F(AsyncGlobTest, NegatedCharacterClass) { // Test with recursive pattern TEST_F(AsyncGlobTest, RecursivePattern) { AsyncGlob glob(*io_context); - + auto result = glob.glob_sync((testDir / "**" / "*.txt").string()); - + EXPECT_GT(result.size(), 3); EXPECT_THAT(result, Contains(testDir / "file1.txt")); EXPECT_THAT(result, Contains(testDir / "file2.txt")); @@ -215,9 +215,9 @@ TEST_F(AsyncGlobTest, RecursivePattern) { // Test with non-existent directory TEST_F(AsyncGlobTest, NonExistentDirectory) { AsyncGlob glob(*io_context); - + auto result = glob.glob_sync((testDir / "non_existent_dir" / "*.txt").string()); - + EXPECT_TRUE(result.empty()); } @@ -225,20 +225,20 @@ TEST_F(AsyncGlobTest, NonExistentDirectory) { TEST_F(AsyncGlobTest, EmptyDirectory) { // Create an empty directory fs::create_directory(testDir / "empty_dir"); - + AsyncGlob glob(*io_context); - + auto result = glob.glob_sync((testDir / "empty_dir" / "*.txt").string()); - + EXPECT_TRUE(result.empty()); } // Test with dir-only flag TEST_F(AsyncGlobTest, DirOnlyFlag) { AsyncGlob glob(*io_context); - + auto result = glob.glob_sync((testDir / "*").string(), false, true); - + // Should only match directories, not files for (const auto& path : result) { EXPECT_TRUE(fs::is_directory(path)); @@ -250,9 +250,9 @@ TEST_F(AsyncGlobTest, DirOnlyFlag) { // Test with hidden files TEST_F(AsyncGlobTest, HiddenFiles) { AsyncGlob glob(*io_context); - + auto result = glob.glob_sync((testDir / ".*").string()); - + // Should find hidden files/directories EXPECT_THAT(result, Contains(testDir / ".hidden_file.txt")); EXPECT_THAT(result, Contains(testDir / ".hidden_dir")); @@ -262,7 +262,7 @@ TEST_F(AsyncGlobTest, HiddenFiles) { TEST_F(AsyncGlobTest, TildeExpansion) { // This test is platform-dependent, so we'll make a conditional test AsyncGlob glob(*io_context); - + // Just verify it doesn't throw - actual expansion is platform-dependent EXPECT_NO_THROW(glob.glob_sync("~/test_pattern")); } @@ -271,14 +271,14 @@ TEST_F(AsyncGlobTest, TildeExpansion) { TEST_F(AsyncGlobTest, ParallelGlob) { AsyncGlob glob(*io_context); std::vector>> futures; - + // Start multiple glob operations in parallel for (int i = 0; i < 5; i++) { futures.push_back(std::async(std::launch::async, [&glob, this]() { return glob.glob_sync((testDir / "*.txt").string()); })); } - + // Check results from all operations for (auto& future : futures) { auto result = future.get(); @@ -291,10 +291,10 @@ TEST_F(AsyncGlobTest, ParallelGlob) { // Test error handling with invalid pattern TEST_F(AsyncGlobTest, InvalidPattern) { AsyncGlob glob(*io_context); - + // Unbalanced bracket should be handled gracefully auto result = glob.glob_sync((testDir / "file[1.txt").string()); - + // Should either be empty or return a valid subset of files if (!result.empty()) { for (const auto& path : result) { @@ -306,9 +306,9 @@ TEST_F(AsyncGlobTest, InvalidPattern) { // Test with pattern ending in directory separator TEST_F(AsyncGlobTest, PatternEndingInSeparator) { AsyncGlob glob(*io_context); - + auto result = glob.glob_sync((testDir / "dir1/").string(), false, true); - + // Should match the directory ASSERT_EQ(result.size(), 1); EXPECT_THAT(result, Contains(testDir / "dir1")); @@ -317,24 +317,24 @@ TEST_F(AsyncGlobTest, PatternEndingInSeparator) { // Test with absolute and relative paths TEST_F(AsyncGlobTest, AbsoluteVsRelativePaths) { AsyncGlob glob(*io_context); - + // Change to the test directory auto originalPath = fs::current_path(); fs::current_path(testDir); - + // Do a relative path glob auto relativeResult = glob.glob_sync("*.txt"); - + // Change back to original directory fs::current_path(originalPath); - + // Do an absolute path glob auto absoluteResult = glob.glob_sync((testDir / "*.txt").string()); - + // The number of results should be the same ASSERT_EQ(relativeResult.size(), absoluteResult.size()); ASSERT_EQ(relativeResult.size(), 2); - + // But the paths will be different (relative vs absolute) EXPECT_THAT(relativeResult, Contains(fs::path("file1.txt"))); EXPECT_THAT(relativeResult, Contains(fs::path("file2.txt"))); @@ -347,21 +347,21 @@ TEST_F(AsyncGlobTest, DeepDirectoryStructure) { // Create a deep directory structure fs::path deepDir = testDir / "deep"; fs::create_directory(deepDir); - + fs::path currentPath = deepDir; for (int i = 0; i < 20; i++) { currentPath = currentPath / ("level" + std::to_string(i)); fs::create_directory(currentPath); } - + // Create a file at the deepest level createFile(currentPath / "deep_file.txt", "Deep file"); - + AsyncGlob glob(*io_context); - + // Test recursive glob on deep structure auto result = glob.glob_sync((deepDir / "**" / "*.txt").string()); - + ASSERT_EQ(result.size(), 1); EXPECT_THAT(result, Contains(currentPath / "deep_file.txt")); } @@ -371,26 +371,26 @@ TEST_F(AsyncGlobTest, PerformanceWithManyFiles) { // Create directory with many files fs::path manyFilesDir = testDir / "many_files"; fs::create_directory(manyFilesDir); - + const int numFiles = 100; // Can increase for more thorough testing for (int i = 0; i < numFiles; i++) { - createFile(manyFilesDir / ("file" + std::to_string(i) + ".txt"), + createFile(manyFilesDir / ("file" + std::to_string(i) + ".txt"), "Content " + std::to_string(i)); } - + AsyncGlob glob(*io_context); - + auto start = std::chrono::high_resolution_clock::now(); auto result = glob.glob_sync((manyFilesDir / "*.txt").string()); auto end = std::chrono::high_resolution_clock::now(); - + auto duration = std::chrono::duration_cast(end - start).count(); - + ASSERT_EQ(result.size(), numFiles); - + // Performance check - should be reasonably fast std::cout << "Time to glob " << numFiles << " files: " << duration << "ms" << std::endl; - + // This is not a strict test as timing depends on the system, // but we can output the timing for information } @@ -400,39 +400,39 @@ TEST_F(AsyncGlobTest, ConcurrentModification) { // Create a directory for the test fs::path concurrentDir = testDir / "concurrent"; fs::create_directory(concurrentDir); - + // Add some initial files createFile(concurrentDir / "file1.txt", "Initial file 1"); createFile(concurrentDir / "file2.txt", "Initial file 2"); - + AsyncGlob glob(*io_context); - + // Start a glob operation in a separate thread std::promise> resultPromise; auto resultFuture = resultPromise.get_future(); - + std::thread globThread([&glob, &concurrentDir, &resultPromise]() { // Simulate a slow glob operation auto result = glob.glob_sync((concurrentDir / "*.txt").string()); std::this_thread::sleep_for(std::chrono::milliseconds(50)); resultPromise.set_value(result); }); - + // Modify the directory while the glob is running std::this_thread::sleep_for(std::chrono::milliseconds(10)); createFile(concurrentDir / "file3.txt", "Added during glob"); fs::remove(concurrentDir / "file1.txt"); - + // Wait for the glob to complete auto result = resultFuture.get(); globThread.join(); - + // We can't make strict assertions about what should be returned, as it depends // on timing, but we can verify it didn't crash and returned something reasonable for (const auto& path : result) { std::cout << "Found in concurrent test: " << path << std::endl; } - + // Verify the final state auto finalResult = glob.glob_sync((concurrentDir / "*.txt").string()); ASSERT_EQ(finalResult.size(), 2); @@ -448,19 +448,19 @@ TEST_F(AsyncGlobTest, SpecialCharacters) { createFile(testDir / "file-with-dashes.txt", "Dash file"); createFile(testDir / "file+with+plus.txt", "Plus file"); createFile(testDir / "file.with.dots.txt", "Dot file"); - + AsyncGlob glob(*io_context); - + // Test glob with space in pattern auto spaceResult = glob.glob_sync((testDir / "file with*.txt").string()); ASSERT_EQ(spaceResult.size(), 1); EXPECT_THAT(spaceResult, Contains(testDir / "file with spaces.txt")); - + // Test glob with bracket in pattern (requires escaping) auto bracketResult = glob.glob_sync((testDir / "file_with_\\[*").string()); ASSERT_EQ(bracketResult.size(), 1); EXPECT_THAT(bracketResult, Contains(testDir / "file_with_[brackets].txt")); - + // Test glob with various special characters auto mixedResult = glob.glob_sync((testDir / "file*").string()); ASSERT_EQ(mixedResult.size(), 8); // Includes the original files @@ -472,4 +472,4 @@ TEST_F(AsyncGlobTest, SpecialCharacters) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/tests/io/test_async_io.cpp b/tests/io/test_async_io.cpp index 558baa18..69ad181d 100644 --- a/tests/io/test_async_io.cpp +++ b/tests/io/test_async_io.cpp @@ -22,71 +22,71 @@ class AsyncIOTest : public ::testing::Test { void SetUp() override { // Create a temporary test directory structure testDir = fs::temp_directory_path() / "async_io_test"; - + // Clean up any existing test directory if (fs::exists(testDir)) { fs::remove_all(testDir); } - + fs::create_directory(testDir); - + // Create test files createFile(testDir / "file1.txt", "Test file 1 content"); createFile(testDir / "file2.txt", "Test file 2 content\nwith multiple lines"); createFile(testDir / "file3.dat", "Binary file content\0with null bytes", 35); - + // Create subdirectories fs::create_directory(testDir / "subdir1"); fs::create_directory(testDir / "subdir2"); - + createFile(testDir / "subdir1" / "nested_file.txt", "Nested file content"); - + // Initialize IO context and start thread to run it io_context_ptr = std::make_unique(); - + // Start the io_context in a separate thread io_thread = std::thread([this]() { asio::io_context::work work(*io_context_ptr); io_context_ptr->run(); }); - + // Create the async file instance async_file = std::make_unique(*io_context_ptr); async_dir = std::make_unique(*io_context_ptr); } - + void TearDown() override { // Stop the io_context and join the thread io_context_ptr->stop(); if (io_thread.joinable()) { io_thread.join(); } - + // Clean up the test directory if (fs::exists(testDir)) { fs::remove_all(testDir); } } - + void createFile(const fs::path& path, const std::string& content) { std::ofstream file(path); file << content; file.close(); } - + void createFile(const fs::path& path, const char* content, size_t size) { std::ofstream file(path, std::ios::binary); file.write(content, size); file.close(); } - + // Helper for waiting on futures with timeout template bool waitForFuture(std::future& future, int timeoutMs = 1000) { - return future.wait_for(std::chrono::milliseconds(timeoutMs)) == + return future.wait_for(std::chrono::milliseconds(timeoutMs)) == std::future_status::ready; } - + fs::path testDir; std::unique_ptr io_context_ptr; std::thread io_thread; @@ -108,15 +108,15 @@ TEST_F(AsyncIOTest, AsyncDirectoryConstructor) { TEST_F(AsyncIOTest, AsyncFileReadExistingFile) { std::promise> promise; auto future = promise.get_future(); - - async_file->asyncRead(testDir / "file1.txt", + + async_file->asyncRead(testDir / "file1.txt", [&promise](AsyncResult result) { promise.set_value(std::move(result)); }); - + ASSERT_TRUE(waitForFuture(future)); auto result = future.get(); - + EXPECT_TRUE(result.success); EXPECT_EQ(result.value, "Test file 1 content"); EXPECT_TRUE(result.error_message.empty()); @@ -126,15 +126,15 @@ TEST_F(AsyncIOTest, AsyncFileReadExistingFile) { TEST_F(AsyncIOTest, AsyncFileReadNonExistentFile) { std::promise> promise; auto future = promise.get_future(); - - async_file->asyncRead(testDir / "non_existent.txt", + + async_file->asyncRead(testDir / "non_existent.txt", [&promise](AsyncResult result) { promise.set_value(std::move(result)); }); - + ASSERT_TRUE(waitForFuture(future)); auto result = future.get(); - + EXPECT_FALSE(result.success); EXPECT_THAT(result.error_message, HasSubstr("does not exist")); } @@ -143,25 +143,25 @@ TEST_F(AsyncIOTest, AsyncFileReadNonExistentFile) { TEST_F(AsyncIOTest, AsyncFileWriteNewFile) { std::promise> promise; auto future = promise.get_future(); - + std::string content = "New file content"; fs::path newFilePath = testDir / "new_file.txt"; - - async_file->asyncWrite(newFilePath, std::span(content.data(), content.size()), + + async_file->asyncWrite(newFilePath, std::span(content.data(), content.size()), [&promise](AsyncResult result) { promise.set_value(std::move(result)); }); - + ASSERT_TRUE(waitForFuture(future)); auto result = future.get(); - + EXPECT_TRUE(result.success); EXPECT_TRUE(result.error_message.empty()); - + // Verify file was created with correct content EXPECT_TRUE(fs::exists(newFilePath)); std::ifstream file(newFilePath); - std::string fileContent((std::istreambuf_iterator(file)), + std::string fileContent((std::istreambuf_iterator(file)), std::istreambuf_iterator()); EXPECT_EQ(fileContent, content); } @@ -170,24 +170,24 @@ TEST_F(AsyncIOTest, AsyncFileWriteNewFile) { TEST_F(AsyncIOTest, AsyncFileWriteExistingFile) { std::promise> promise; auto future = promise.get_future(); - + std::string content = "Updated content"; fs::path filePath = testDir / "file1.txt"; - - async_file->asyncWrite(filePath, std::span(content.data(), content.size()), + + async_file->asyncWrite(filePath, std::span(content.data(), content.size()), [&promise](AsyncResult result) { promise.set_value(std::move(result)); }); - + ASSERT_TRUE(waitForFuture(future)); auto result = future.get(); - + EXPECT_TRUE(result.success); EXPECT_TRUE(result.error_message.empty()); - + // Verify file was updated with correct content std::ifstream file(filePath); - std::string fileContent((std::istreambuf_iterator(file)), + std::string fileContent((std::istreambuf_iterator(file)), std::istreambuf_iterator()); EXPECT_EQ(fileContent, content); } @@ -196,21 +196,21 @@ TEST_F(AsyncIOTest, AsyncFileWriteExistingFile) { TEST_F(AsyncIOTest, AsyncFileDeleteExistingFile) { std::promise> promise; auto future = promise.get_future(); - + fs::path filePath = testDir / "file2.txt"; ASSERT_TRUE(fs::exists(filePath)); // Ensure file exists before test - - async_file->asyncDelete(filePath, + + async_file->asyncDelete(filePath, [&promise](AsyncResult result) { promise.set_value(std::move(result)); }); - + ASSERT_TRUE(waitForFuture(future)); auto result = future.get(); - + EXPECT_TRUE(result.success); EXPECT_TRUE(result.error_message.empty()); - + // Verify file was deleted EXPECT_FALSE(fs::exists(filePath)); } @@ -219,17 +219,17 @@ TEST_F(AsyncIOTest, AsyncFileDeleteExistingFile) { TEST_F(AsyncIOTest, AsyncFileDeleteNonExistentFile) { std::promise> promise; auto future = promise.get_future(); - + fs::path filePath = testDir / "non_existent.txt"; - - async_file->asyncDelete(filePath, + + async_file->asyncDelete(filePath, [&promise](AsyncResult result) { promise.set_value(std::move(result)); }); - + ASSERT_TRUE(waitForFuture(future)); auto result = future.get(); - + EXPECT_FALSE(result.success); EXPECT_THAT(result.error_message, HasSubstr("does not exist")); } @@ -238,33 +238,33 @@ TEST_F(AsyncIOTest, AsyncFileDeleteNonExistentFile) { TEST_F(AsyncIOTest, AsyncFileCopyExistingFile) { std::promise> promise; auto future = promise.get_future(); - + fs::path srcPath = testDir / "file1.txt"; fs::path destPath = testDir / "file1_copy.txt"; - - async_file->asyncCopy(srcPath, destPath, + + async_file->asyncCopy(srcPath, destPath, [&promise](AsyncResult result) { promise.set_value(std::move(result)); }); - + ASSERT_TRUE(waitForFuture(future)); auto result = future.get(); - + EXPECT_TRUE(result.success); EXPECT_TRUE(result.error_message.empty()); - + // Verify file was copied EXPECT_TRUE(fs::exists(destPath)); - + // Verify content is the same std::ifstream srcFile(srcPath); - std::string srcContent((std::istreambuf_iterator(srcFile)), + std::string srcContent((std::istreambuf_iterator(srcFile)), std::istreambuf_iterator()); - + std::ifstream destFile(destPath); - std::string destContent((std::istreambuf_iterator(destFile)), + std::string destContent((std::istreambuf_iterator(destFile)), std::istreambuf_iterator()); - + EXPECT_EQ(srcContent, destContent); } @@ -272,21 +272,21 @@ TEST_F(AsyncIOTest, AsyncFileCopyExistingFile) { TEST_F(AsyncIOTest, AsyncFileCopyNonExistentSource) { std::promise> promise; auto future = promise.get_future(); - + fs::path srcPath = testDir / "non_existent.txt"; fs::path destPath = testDir / "copy_fail.txt"; - - async_file->asyncCopy(srcPath, destPath, + + async_file->asyncCopy(srcPath, destPath, [&promise](AsyncResult result) { promise.set_value(std::move(result)); }); - + ASSERT_TRUE(waitForFuture(future)); auto result = future.get(); - + EXPECT_FALSE(result.success); EXPECT_THAT(result.error_message, HasSubstr("does not exist")); - + // Verify destination was not created EXPECT_FALSE(fs::exists(destPath)); } @@ -295,35 +295,35 @@ TEST_F(AsyncIOTest, AsyncFileCopyNonExistentSource) { TEST_F(AsyncIOTest, AsyncFileReadWithTimeoutSuccess) { std::promise> promise; auto future = promise.get_future(); - - async_file->asyncReadWithTimeout(testDir / "file1.txt", std::chrono::milliseconds(500), + + async_file->asyncReadWithTimeout(testDir / "file1.txt", std::chrono::milliseconds(500), [&promise](AsyncResult result) { promise.set_value(std::move(result)); }); - + ASSERT_TRUE(waitForFuture(future, 1000)); auto result = future.get(); - + EXPECT_TRUE(result.success); EXPECT_EQ(result.value, "Test file 1 content"); EXPECT_TRUE(result.error_message.empty()); } -// Test AsyncFile::asyncReadWithTimeout that times out +// Test AsyncFile::asyncReadWithTimeout that times out // (this test may be flaky depending on implementation details) TEST_F(AsyncIOTest, AsyncFileReadWithTimeoutExpires) { std::promise> promise; auto future = promise.get_future(); - + // Assuming implementation adds artificial delay, set very short timeout - async_file->asyncReadWithTimeout(testDir / "file1.txt", std::chrono::milliseconds(1), + async_file->asyncReadWithTimeout(testDir / "file1.txt", std::chrono::milliseconds(1), [&promise](AsyncResult result) { promise.set_value(std::move(result)); }); - + ASSERT_TRUE(waitForFuture(future, 200)); auto result = future.get(); - + // If the operation timed out, result.success should be false if (!result.success) { EXPECT_THAT(result.error_message, HasSubstr("timeout")); @@ -337,20 +337,20 @@ TEST_F(AsyncIOTest, AsyncFileReadWithTimeoutExpires) { TEST_F(AsyncIOTest, AsyncFileBatchReadExistingFiles) { std::promise>> promise; auto future = promise.get_future(); - + std::vector filePaths = { (testDir / "file1.txt").string(), (testDir / "file2.txt").string() }; - - async_file->asyncBatchRead(filePaths, + + async_file->asyncBatchRead(filePaths, [&promise](AsyncResult> result) { promise.set_value(std::move(result)); }); - + ASSERT_TRUE(waitForFuture(future)); auto result = future.get(); - + EXPECT_TRUE(result.success); EXPECT_TRUE(result.error_message.empty()); ASSERT_EQ(result.value.size(), 2); @@ -362,20 +362,20 @@ TEST_F(AsyncIOTest, AsyncFileBatchReadExistingFiles) { TEST_F(AsyncIOTest, AsyncFileBatchReadMixedFiles) { std::promise>> promise; auto future = promise.get_future(); - + std::vector filePaths = { (testDir / "file1.txt").string(), (testDir / "non_existent.txt").string() }; - - async_file->asyncBatchRead(filePaths, + + async_file->asyncBatchRead(filePaths, [&promise](AsyncResult> result) { promise.set_value(std::move(result)); }); - + ASSERT_TRUE(waitForFuture(future)); auto result = future.get(); - + EXPECT_FALSE(result.success); EXPECT_THAT(result.error_message, HasSubstr("non_existent.txt")); } @@ -384,15 +384,15 @@ TEST_F(AsyncIOTest, AsyncFileBatchReadMixedFiles) { TEST_F(AsyncIOTest, AsyncFileStatExistingFile) { std::promise> promise; auto future = promise.get_future(); - - async_file->asyncStat(testDir / "file1.txt", + + async_file->asyncStat(testDir / "file1.txt", [&promise](AsyncResult result) { promise.set_value(std::move(result)); }); - + ASSERT_TRUE(waitForFuture(future)); auto result = future.get(); - + EXPECT_TRUE(result.success); EXPECT_TRUE(result.error_message.empty()); EXPECT_EQ(fs::is_regular_file(result.value), true); @@ -402,15 +402,15 @@ TEST_F(AsyncIOTest, AsyncFileStatExistingFile) { TEST_F(AsyncIOTest, AsyncFileStatNonExistentFile) { std::promise> promise; auto future = promise.get_future(); - - async_file->asyncStat(testDir / "non_existent.txt", + + async_file->asyncStat(testDir / "non_existent.txt", [&promise](AsyncResult result) { promise.set_value(std::move(result)); }); - + ASSERT_TRUE(waitForFuture(future)); auto result = future.get(); - + EXPECT_FALSE(result.success); EXPECT_THAT(result.error_message, HasSubstr("does not exist")); } @@ -419,21 +419,21 @@ TEST_F(AsyncIOTest, AsyncFileStatNonExistentFile) { TEST_F(AsyncIOTest, AsyncFileMoveExistingFile) { std::promise> promise; auto future = promise.get_future(); - + fs::path srcPath = testDir / "file1.txt"; fs::path destPath = testDir / "file1_moved.txt"; - - async_file->asyncMove(srcPath, destPath, + + async_file->asyncMove(srcPath, destPath, [&promise](AsyncResult result) { promise.set_value(std::move(result)); }); - + ASSERT_TRUE(waitForFuture(future)); auto result = future.get(); - + EXPECT_TRUE(result.success); EXPECT_TRUE(result.error_message.empty()); - + // Verify file was moved EXPECT_FALSE(fs::exists(srcPath)); EXPECT_TRUE(fs::exists(destPath)); @@ -443,21 +443,21 @@ TEST_F(AsyncIOTest, AsyncFileMoveExistingFile) { TEST_F(AsyncIOTest, AsyncFileMoveNonExistentSource) { std::promise> promise; auto future = promise.get_future(); - + fs::path srcPath = testDir / "non_existent.txt"; fs::path destPath = testDir / "move_fail.txt"; - - async_file->asyncMove(srcPath, destPath, + + async_file->asyncMove(srcPath, destPath, [&promise](AsyncResult result) { promise.set_value(std::move(result)); }); - + ASSERT_TRUE(waitForFuture(future)); auto result = future.get(); - + EXPECT_FALSE(result.success); EXPECT_THAT(result.error_message, HasSubstr("does not exist")); - + // Verify destination was not created EXPECT_FALSE(fs::exists(destPath)); } @@ -466,20 +466,20 @@ TEST_F(AsyncIOTest, AsyncFileMoveNonExistentSource) { TEST_F(AsyncIOTest, AsyncFileChangePermissionsExistingFile) { std::promise> promise; auto future = promise.get_future(); - + fs::path filePath = testDir / "file1.txt"; - - async_file->asyncChangePermissions(filePath, fs::perms::owner_read | fs::perms::owner_write, + + async_file->asyncChangePermissions(filePath, fs::perms::owner_read | fs::perms::owner_write, [&promise](AsyncResult result) { promise.set_value(std::move(result)); }); - + ASSERT_TRUE(waitForFuture(future)); auto result = future.get(); - + EXPECT_TRUE(result.success); EXPECT_TRUE(result.error_message.empty()); - + // Verify permissions were changed (implementation-dependent) // This might be system-dependent, so we're not checking the actual permissions } @@ -488,20 +488,20 @@ TEST_F(AsyncIOTest, AsyncFileChangePermissionsExistingFile) { TEST_F(AsyncIOTest, AsyncFileCreateDirectoryNew) { std::promise> promise; auto future = promise.get_future(); - + fs::path dirPath = testDir / "new_dir"; - - async_file->asyncCreateDirectory(dirPath, + + async_file->asyncCreateDirectory(dirPath, [&promise](AsyncResult result) { promise.set_value(std::move(result)); }); - + ASSERT_TRUE(waitForFuture(future)); auto result = future.get(); - + EXPECT_TRUE(result.success); EXPECT_TRUE(result.error_message.empty()); - + // Verify directory was created EXPECT_TRUE(fs::exists(dirPath)); EXPECT_TRUE(fs::is_directory(dirPath)); @@ -511,17 +511,17 @@ TEST_F(AsyncIOTest, AsyncFileCreateDirectoryNew) { TEST_F(AsyncIOTest, AsyncFileCreateDirectoryExisting) { std::promise> promise; auto future = promise.get_future(); - + fs::path dirPath = testDir / "subdir1"; - - async_file->asyncCreateDirectory(dirPath, + + async_file->asyncCreateDirectory(dirPath, [&promise](AsyncResult result) { promise.set_value(std::move(result)); }); - + ASSERT_TRUE(waitForFuture(future)); auto result = future.get(); - + EXPECT_FALSE(result.success); EXPECT_THAT(result.error_message, HasSubstr("already exists")); } @@ -530,15 +530,15 @@ TEST_F(AsyncIOTest, AsyncFileCreateDirectoryExisting) { TEST_F(AsyncIOTest, AsyncFileExistsExistingFile) { std::promise> promise; auto future = promise.get_future(); - - async_file->asyncExists(testDir / "file1.txt", + + async_file->asyncExists(testDir / "file1.txt", [&promise](AsyncResult result) { promise.set_value(std::move(result)); }); - + ASSERT_TRUE(waitForFuture(future)); auto result = future.get(); - + EXPECT_TRUE(result.success); EXPECT_TRUE(result.error_message.empty()); EXPECT_TRUE(result.value); @@ -548,15 +548,15 @@ TEST_F(AsyncIOTest, AsyncFileExistsExistingFile) { TEST_F(AsyncIOTest, AsyncFileExistsNonExistentFile) { std::promise> promise; auto future = promise.get_future(); - - async_file->asyncExists(testDir / "non_existent.txt", + + async_file->asyncExists(testDir / "non_existent.txt", [&promise](AsyncResult result) { promise.set_value(std::move(result)); }); - + ASSERT_TRUE(waitForFuture(future)); auto result = future.get(); - + EXPECT_TRUE(result.success); EXPECT_TRUE(result.error_message.empty()); EXPECT_FALSE(result.value); @@ -566,7 +566,7 @@ TEST_F(AsyncIOTest, AsyncFileExistsNonExistentFile) { TEST_F(AsyncIOTest, AsyncFileReadFileCoroutine) { auto fileTask = async_file->readFile(testDir / "file1.txt"); auto result = fileTask.get(); - + EXPECT_TRUE(result.success); EXPECT_EQ(result.value, "Test file 1 content"); EXPECT_TRUE(result.error_message.empty()); @@ -576,18 +576,18 @@ TEST_F(AsyncIOTest, AsyncFileReadFileCoroutine) { TEST_F(AsyncIOTest, AsyncFileWriteFileCoroutine) { std::string content = "Coroutine written content"; fs::path filePath = testDir / "coroutine_written.txt"; - - auto writeTask = async_file->writeFile(filePath, + + auto writeTask = async_file->writeFile(filePath, std::span(content.data(), content.size())); auto result = writeTask.get(); - + EXPECT_TRUE(result.success); EXPECT_TRUE(result.error_message.empty()); - + // Verify file was created with correct content EXPECT_TRUE(fs::exists(filePath)); std::ifstream file(filePath); - std::string fileContent((std::istreambuf_iterator(file)), + std::string fileContent((std::istreambuf_iterator(file)), std::istreambuf_iterator()); EXPECT_EQ(fileContent, content); } @@ -596,20 +596,20 @@ TEST_F(AsyncIOTest, AsyncFileWriteFileCoroutine) { TEST_F(AsyncIOTest, AsyncDirectoryCreateNew) { std::promise> promise; auto future = promise.get_future(); - + fs::path dirPath = testDir / "async_dir_new"; - - async_dir->asyncCreate(dirPath, + + async_dir->asyncCreate(dirPath, [&promise](AsyncResult result) { promise.set_value(std::move(result)); }); - + ASSERT_TRUE(waitForFuture(future)); auto result = future.get(); - + EXPECT_TRUE(result.success); EXPECT_TRUE(result.error_message.empty()); - + // Verify directory was created EXPECT_TRUE(fs::exists(dirPath)); EXPECT_TRUE(fs::is_directory(dirPath)); @@ -619,20 +619,20 @@ TEST_F(AsyncIOTest, AsyncDirectoryCreateNew) { TEST_F(AsyncIOTest, AsyncDirectoryRemoveExisting) { std::promise> promise; auto future = promise.get_future(); - + fs::path dirPath = testDir / "subdir2"; - - async_dir->asyncRemove(dirPath, + + async_dir->asyncRemove(dirPath, [&promise](AsyncResult result) { promise.set_value(std::move(result)); }); - + ASSERT_TRUE(waitForFuture(future)); auto result = future.get(); - + EXPECT_TRUE(result.success); EXPECT_TRUE(result.error_message.empty()); - + // Verify directory was removed EXPECT_FALSE(fs::exists(dirPath)); } @@ -641,30 +641,30 @@ TEST_F(AsyncIOTest, AsyncDirectoryRemoveExisting) { TEST_F(AsyncIOTest, AsyncDirectoryListContentsExisting) { std::promise>> promise; auto future = promise.get_future(); - - async_dir->asyncListContents(testDir, + + async_dir->asyncListContents(testDir, [&promise](AsyncResult> result) { promise.set_value(std::move(result)); }); - + ASSERT_TRUE(waitForFuture(future)); auto result = future.get(); - + EXPECT_TRUE(result.success); EXPECT_TRUE(result.error_message.empty()); - + // Verify we have the expected number of entries EXPECT_GE(result.value.size(), 5); // At least 5 entries (files and dirs) - + // Check for known files and directories bool foundFile1 = false; bool foundSubdir1 = false; - + for (const auto& entry : result.value) { if (entry.filename() == "file1.txt") foundFile1 = true; if (entry.filename() == "subdir1") foundSubdir1 = true; } - + EXPECT_TRUE(foundFile1); EXPECT_TRUE(foundSubdir1); } @@ -673,15 +673,15 @@ TEST_F(AsyncIOTest, AsyncDirectoryListContentsExisting) { TEST_F(AsyncIOTest, AsyncDirectoryListContentsNonExistent) { std::promise>> promise; auto future = promise.get_future(); - - async_dir->asyncListContents(testDir / "non_existent_dir", + + async_dir->asyncListContents(testDir / "non_existent_dir", [&promise](AsyncResult> result) { promise.set_value(std::move(result)); }); - + ASSERT_TRUE(waitForFuture(future)); auto result = future.get(); - + EXPECT_FALSE(result.success); EXPECT_THAT(result.error_message, HasSubstr("does not exist")); } @@ -690,15 +690,15 @@ TEST_F(AsyncIOTest, AsyncDirectoryListContentsNonExistent) { TEST_F(AsyncIOTest, AsyncDirectoryExistsExisting) { std::promise> promise; auto future = promise.get_future(); - - async_dir->asyncExists(testDir / "subdir1", + + async_dir->asyncExists(testDir / "subdir1", [&promise](AsyncResult result) { promise.set_value(std::move(result)); }); - + ASSERT_TRUE(waitForFuture(future)); auto result = future.get(); - + EXPECT_TRUE(result.success); EXPECT_TRUE(result.error_message.empty()); EXPECT_TRUE(result.value); @@ -708,15 +708,15 @@ TEST_F(AsyncIOTest, AsyncDirectoryExistsExisting) { TEST_F(AsyncIOTest, AsyncDirectoryExistsNonExistent) { std::promise> promise; auto future = promise.get_future(); - - async_dir->asyncExists(testDir / "non_existent_dir", + + async_dir->asyncExists(testDir / "non_existent_dir", [&promise](AsyncResult result) { promise.set_value(std::move(result)); }); - + ASSERT_TRUE(waitForFuture(future)); auto result = future.get(); - + EXPECT_TRUE(result.success); EXPECT_TRUE(result.error_message.empty()); EXPECT_FALSE(result.value); @@ -726,22 +726,22 @@ TEST_F(AsyncIOTest, AsyncDirectoryExistsNonExistent) { TEST_F(AsyncIOTest, AsyncDirectoryListContentsCoroutine) { auto listTask = async_dir->listContents(testDir); auto result = listTask.get(); - + EXPECT_TRUE(result.success); EXPECT_TRUE(result.error_message.empty()); - + // Verify we have the expected number of entries EXPECT_GE(result.value.size(), 5); // At least 5 entries (files and dirs) - + // Check for known files and directories bool foundFile1 = false; bool foundSubdir1 = false; - + for (const auto& entry : result.value) { if (entry.filename() == "file1.txt") foundFile1 = true; if (entry.filename() == "subdir1") foundSubdir1 = true; } - + EXPECT_TRUE(foundFile1); EXPECT_TRUE(foundSubdir1); } @@ -750,16 +750,16 @@ TEST_F(AsyncIOTest, AsyncDirectoryListContentsCoroutine) { TEST_F(AsyncIOTest, InvalidInputHandling) { std::promise> readPromise; auto readFuture = readPromise.get_future(); - + // Empty filename - async_file->asyncRead("", + async_file->asyncRead("", [&readPromise](AsyncResult result) { readPromise.set_value(std::move(result)); }); - + ASSERT_TRUE(waitForFuture(readFuture)); auto readResult = readFuture.get(); - + EXPECT_FALSE(readResult.success); EXPECT_THAT(readResult.error_message, HasSubstr("Invalid")); } @@ -769,24 +769,24 @@ TEST_F(AsyncIOTest, ConcurrentOperations) { constexpr int numConcurrentOps = 10; std::vector>> promises(numConcurrentOps); std::vector>> futures; - + for (int i = 0; i < numConcurrentOps; i++) { futures.push_back(promises[i].get_future()); } - + // Start multiple reads concurrently for (int i = 0; i < numConcurrentOps; i++) { - async_file->asyncRead(testDir / "file1.txt", + async_file->asyncRead(testDir / "file1.txt", [&promises, i](AsyncResult result) { promises[i].set_value(std::move(result)); }); } - + // Wait for all operations to complete for (int i = 0; i < numConcurrentOps; i++) { ASSERT_TRUE(waitForFuture(futures[i])); auto result = futures[i].get(); - + EXPECT_TRUE(result.success); EXPECT_EQ(result.value, "Test file 1 content"); } @@ -797,19 +797,19 @@ TEST_F(AsyncIOTest, TaskFunctionality) { // Create a task manually std::promise> promise; auto future = promise.get_future(); - + Task> task(std::move(future)); - + // Set a value to the promise AsyncResult expectedResult; expectedResult.success = true; expectedResult.value = "Task test value"; - + promise.set_value(expectedResult); - + // Check if task is ready EXPECT_TRUE(task.is_ready()); - + // Get the result auto result = task.get(); EXPECT_TRUE(result.success); @@ -819,4 +819,4 @@ TEST_F(AsyncIOTest, TaskFunctionality) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/tests/io/test_compress.cpp b/tests/io/test_compress.cpp index e3ecb246..fbf11f29 100644 --- a/tests/io/test_compress.cpp +++ b/tests/io/test_compress.cpp @@ -924,4 +924,4 @@ TEST_F(FolderCompressionTest, DISABLED_CompressionPerformance) { double size_ratio = static_cast(par_size) / seq_size; EXPECT_NEAR(size_ratio, 1.0, 0.05); // Allow 5% difference -} \ No newline at end of file +} diff --git a/tests/io/test_file_permission.cpp b/tests/io/test_file_permission.cpp index a88f4fc7..c8ef75cf 100644 --- a/tests/io/test_file_permission.cpp +++ b/tests/io/test_file_permission.cpp @@ -319,4 +319,4 @@ TEST_F(FilePermissionTest, ThreadSafety) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/tests/io/test_glob.cpp b/tests/io/test_glob.cpp index 390082ba..28e282d1 100644 --- a/tests/io/test_glob.cpp +++ b/tests/io/test_glob.cpp @@ -328,4 +328,4 @@ TEST_F(GlobTest, DirectoryIteration) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/tests/io/test_pushd.cpp b/tests/io/test_pushd.cpp index 9c8aa0b8..d8b91876 100644 --- a/tests/io/test_pushd.cpp +++ b/tests/io/test_pushd.cpp @@ -571,4 +571,4 @@ TEST_F(DirectoryStackTest, MoveOperations) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/tests/memory/test_memory.cpp b/tests/memory/test_memory.cpp index abc12240..6c1b1ca9 100644 --- a/tests/memory/test_memory.cpp +++ b/tests/memory/test_memory.cpp @@ -441,4 +441,4 @@ TEST_F(MemoryPoolTest, MemoryLeakCheck) { // No way to directly verify cleanup after destruction, but we can // at least verify the test ran without memory errors -} \ No newline at end of file +} diff --git a/tests/memory/test_object.cpp b/tests/memory/test_object.cpp index c89286c6..0e23a381 100644 --- a/tests/memory/test_object.cpp +++ b/tests/memory/test_object.cpp @@ -596,4 +596,4 @@ TEST_F(ObjectPoolTest, PerformanceComparison) { // Pool should generally be faster after warmup, but we don't assert this // as performance can vary by platform -} \ No newline at end of file +} diff --git a/tests/memory/test_ring.cpp b/tests/memory/test_ring.cpp index f5ca6aea..e6ab75d4 100644 --- a/tests/memory/test_ring.cpp +++ b/tests/memory/test_ring.cpp @@ -687,4 +687,4 @@ TEST_F(RingBufferTest, EmptyIterator) { EXPECT_EQ(*it, 42); } EXPECT_EQ(count, 1); -} \ No newline at end of file +} diff --git a/tests/memory/test_shared.cpp b/tests/memory/test_shared.cpp index bd5cb1a8..5c4251d8 100644 --- a/tests/memory/test_shared.cpp +++ b/tests/memory/test_shared.cpp @@ -736,4 +736,4 @@ TEST_F(SharedMemoryTest, InitializationFailures) { << "'"; } } -} \ No newline at end of file +} diff --git a/tests/memory/test_short_alloc.cpp b/tests/memory/test_short_alloc.cpp index 1c347bac..2001c6bc 100644 --- a/tests/memory/test_short_alloc.cpp +++ b/tests/memory/test_short_alloc.cpp @@ -624,4 +624,4 @@ TEST(UtilsTest, MemoryFill) { for (int i = 0; i < 1024; i++) { EXPECT_EQ(static_cast(buffer[i]), utils::getFreedPattern()); } -} \ No newline at end of file +} diff --git a/tests/memory/test_utils.cpp b/tests/memory/test_utils.cpp index 767008a8..4029c3f1 100644 --- a/tests/memory/test_utils.cpp +++ b/tests/memory/test_utils.cpp @@ -296,4 +296,4 @@ TEST(MemoryUtilsTest, Config) { #else EXPECT_FALSE(Config::EnableMemoryTracking); #endif -} \ No newline at end of file +} diff --git a/tests/meta/test_bind_first.hpp b/tests/meta/test_bind_first.hpp index 169374a7..a3f03216 100644 --- a/tests/meta/test_bind_first.hpp +++ b/tests/meta/test_bind_first.hpp @@ -350,4 +350,4 @@ TEST_F(BindFirstTest, AwaitableCreation) { } // namespace atom::test -#endif // ATOM_TEST_BIND_FIRST_HPP \ No newline at end of file +#endif // ATOM_TEST_BIND_FIRST_HPP diff --git a/tests/meta/test_container_traits.hpp b/tests/meta/test_container_traits.hpp index 21f59c52..3dd4ac1d 100644 --- a/tests/meta/test_container_traits.hpp +++ b/tests/meta/test_container_traits.hpp @@ -39,20 +39,20 @@ class ContainerTraitsTest : public ::testing::Test { // Test std::vector traits TEST_F(ContainerTraitsTest, VectorTraits) { using VectorTraits = atom::meta::ContainerTraits>; - + // Container category EXPECT_TRUE(VectorTraits::is_sequence_container); EXPECT_FALSE(VectorTraits::is_associative_container); EXPECT_FALSE(VectorTraits::is_unordered_associative_container); EXPECT_FALSE(VectorTraits::is_container_adapter); - + // Iterator capabilities EXPECT_TRUE(VectorTraits::has_random_access); EXPECT_TRUE(VectorTraits::has_bidirectional_access); EXPECT_FALSE(VectorTraits::has_forward_access); EXPECT_TRUE(VectorTraits::has_begin_end); EXPECT_TRUE(VectorTraits::has_rbegin_rend); - + // Container operations EXPECT_TRUE(VectorTraits::has_size); EXPECT_TRUE(VectorTraits::has_empty); @@ -68,25 +68,25 @@ TEST_F(ContainerTraitsTest, VectorTraits) { EXPECT_TRUE(VectorTraits::has_emplace); EXPECT_FALSE(VectorTraits::has_emplace_front); EXPECT_TRUE(VectorTraits::has_emplace_back); - + // Memory management EXPECT_TRUE(VectorTraits::has_reserve); EXPECT_TRUE(VectorTraits::has_capacity); EXPECT_TRUE(VectorTraits::has_shrink_to_fit); - + // Access operations EXPECT_TRUE(VectorTraits::has_subscript); EXPECT_TRUE(VectorTraits::has_at); EXPECT_FALSE(VectorTraits::has_find); EXPECT_FALSE(VectorTraits::has_count); - + // Container properties EXPECT_FALSE(VectorTraits::has_key_type); EXPECT_FALSE(VectorTraits::has_mapped_type); EXPECT_FALSE(VectorTraits::is_sorted); EXPECT_FALSE(VectorTraits::is_unique); EXPECT_FALSE(VectorTraits::is_fixed_size); - + // Type checks static_assert(std::is_same_v); static_assert(std::is_same_v>); @@ -95,15 +95,15 @@ TEST_F(ContainerTraitsTest, VectorTraits) { // Test std::deque traits TEST_F(ContainerTraitsTest, DequeTraits) { using DequeTraits = atom::meta::ContainerTraits>; - + // Container category EXPECT_TRUE(DequeTraits::is_sequence_container); EXPECT_FALSE(DequeTraits::is_associative_container); - + // Iterator capabilities EXPECT_TRUE(DequeTraits::has_random_access); EXPECT_TRUE(DequeTraits::has_bidirectional_access); - + // Container operations - deque supports both front and back operations EXPECT_TRUE(DequeTraits::has_front); EXPECT_TRUE(DequeTraits::has_back); @@ -113,16 +113,16 @@ TEST_F(ContainerTraitsTest, DequeTraits) { EXPECT_TRUE(DequeTraits::has_pop_back); EXPECT_TRUE(DequeTraits::has_emplace_front); EXPECT_TRUE(DequeTraits::has_emplace_back); - + // Access operations EXPECT_TRUE(DequeTraits::has_subscript); EXPECT_TRUE(DequeTraits::has_at); - + // Memory management - deque doesn't have reserve/capacity EXPECT_FALSE(DequeTraits::has_reserve); EXPECT_FALSE(DequeTraits::has_capacity); EXPECT_TRUE(DequeTraits::has_shrink_to_fit); - + // Container properties EXPECT_FALSE(DequeTraits::is_fixed_size); } @@ -130,15 +130,15 @@ TEST_F(ContainerTraitsTest, DequeTraits) { // Test std::list traits TEST_F(ContainerTraitsTest, ListTraits) { using ListTraits = atom::meta::ContainerTraits>; - + // Container category EXPECT_TRUE(ListTraits::is_sequence_container); - + // Iterator capabilities - list has bidirectional but not random access EXPECT_FALSE(ListTraits::has_random_access); EXPECT_TRUE(ListTraits::has_bidirectional_access); EXPECT_FALSE(ListTraits::has_forward_access); - + // Container operations EXPECT_TRUE(ListTraits::has_front); EXPECT_TRUE(ListTraits::has_back); @@ -148,11 +148,11 @@ TEST_F(ContainerTraitsTest, ListTraits) { EXPECT_TRUE(ListTraits::has_pop_back); EXPECT_TRUE(ListTraits::has_emplace_front); EXPECT_TRUE(ListTraits::has_emplace_back); - + // Access operations - list doesn't support random access EXPECT_FALSE(ListTraits::has_subscript); EXPECT_FALSE(ListTraits::has_at); - + // Memory management - list doesn't have reserve/capacity EXPECT_FALSE(ListTraits::has_reserve); EXPECT_FALSE(ListTraits::has_capacity); @@ -162,16 +162,16 @@ TEST_F(ContainerTraitsTest, ListTraits) { // Test std::forward_list traits TEST_F(ContainerTraitsTest, ForwardListTraits) { using ForwardListTraits = atom::meta::ContainerTraits>; - + // Container category EXPECT_TRUE(ForwardListTraits::is_sequence_container); - + // Iterator capabilities - forward_list only has forward iterators EXPECT_FALSE(ForwardListTraits::has_random_access); EXPECT_FALSE(ForwardListTraits::has_bidirectional_access); EXPECT_TRUE(ForwardListTraits::has_forward_access); EXPECT_FALSE(ForwardListTraits::has_rbegin_rend); - + // Container operations - forward_list only supports front operations EXPECT_TRUE(ForwardListTraits::has_front); EXPECT_FALSE(ForwardListTraits::has_back); @@ -181,10 +181,10 @@ TEST_F(ContainerTraitsTest, ForwardListTraits) { EXPECT_FALSE(ForwardListTraits::has_pop_back); EXPECT_TRUE(ForwardListTraits::has_emplace_front); EXPECT_FALSE(ForwardListTraits::has_emplace_back); - + // Special property - forward_list doesn't have size() EXPECT_FALSE(ForwardListTraits::has_size); - + // Access operations EXPECT_FALSE(ForwardListTraits::has_subscript); EXPECT_FALSE(ForwardListTraits::has_at); @@ -193,14 +193,14 @@ TEST_F(ContainerTraitsTest, ForwardListTraits) { // Test std::array traits TEST_F(ContainerTraitsTest, ArrayTraits) { using ArrayTraits = atom::meta::ContainerTraits>; - + // Container category EXPECT_TRUE(ArrayTraits::is_sequence_container); - + // Iterator capabilities EXPECT_TRUE(ArrayTraits::has_random_access); EXPECT_TRUE(ArrayTraits::has_bidirectional_access); - + // Container operations EXPECT_TRUE(ArrayTraits::has_front); EXPECT_TRUE(ArrayTraits::has_back); @@ -210,16 +210,16 @@ TEST_F(ContainerTraitsTest, ArrayTraits) { EXPECT_FALSE(ArrayTraits::has_pop_back); EXPECT_FALSE(ArrayTraits::has_insert); EXPECT_FALSE(ArrayTraits::has_erase); - + // Access operations EXPECT_TRUE(ArrayTraits::has_subscript); EXPECT_TRUE(ArrayTraits::has_at); - + // Special properties - array is fixed size and cannot be cleared EXPECT_TRUE(ArrayTraits::is_fixed_size); EXPECT_FALSE(ArrayTraits::has_clear); EXPECT_EQ(ArrayTraits::array_size, 5); - + // Memory management - arrays don't have these operations EXPECT_FALSE(ArrayTraits::has_reserve); EXPECT_FALSE(ArrayTraits::has_capacity); @@ -229,14 +229,14 @@ TEST_F(ContainerTraitsTest, ArrayTraits) { // Test std::string traits TEST_F(ContainerTraitsTest, StringTraits) { using StringTraits = atom::meta::ContainerTraits; - + // Container category EXPECT_TRUE(StringTraits::is_sequence_container); - + // Iterator capabilities EXPECT_TRUE(StringTraits::has_random_access); EXPECT_TRUE(StringTraits::has_bidirectional_access); - + // Container operations EXPECT_TRUE(StringTraits::has_front); EXPECT_TRUE(StringTraits::has_back); @@ -244,17 +244,17 @@ TEST_F(ContainerTraitsTest, StringTraits) { EXPECT_TRUE(StringTraits::has_push_back); EXPECT_FALSE(StringTraits::has_pop_front); EXPECT_TRUE(StringTraits::has_pop_back); - + // Access operations EXPECT_TRUE(StringTraits::has_subscript); EXPECT_TRUE(StringTraits::has_at); EXPECT_TRUE(StringTraits::has_find); // string has find method - + // Memory management EXPECT_TRUE(StringTraits::has_reserve); EXPECT_TRUE(StringTraits::has_capacity); EXPECT_TRUE(StringTraits::has_shrink_to_fit); - + // Container properties EXPECT_FALSE(StringTraits::is_fixed_size); } @@ -264,41 +264,41 @@ TEST_F(ContainerTraitsTest, StringTraits) { // Test std::map traits TEST_F(ContainerTraitsTest, MapTraits) { using MapTraits = atom::meta::ContainerTraits>; - + // Container category EXPECT_FALSE(MapTraits::is_sequence_container); EXPECT_TRUE(MapTraits::is_associative_container); EXPECT_FALSE(MapTraits::is_unordered_associative_container); EXPECT_FALSE(MapTraits::is_container_adapter); - + // Iterator capabilities EXPECT_FALSE(MapTraits::has_random_access); EXPECT_TRUE(MapTraits::has_bidirectional_access); EXPECT_FALSE(MapTraits::has_forward_access); - + // Container operations EXPECT_TRUE(MapTraits::has_insert); EXPECT_TRUE(MapTraits::has_erase); EXPECT_TRUE(MapTraits::has_emplace); EXPECT_TRUE(MapTraits::has_find); EXPECT_TRUE(MapTraits::has_count); - + // Access operations - map has operator[] EXPECT_TRUE(MapTraits::has_subscript); EXPECT_FALSE(MapTraits::has_at); // This might be incorrect, map does have at() - + // Key-value properties EXPECT_TRUE(MapTraits::has_key_type); EXPECT_TRUE(MapTraits::has_mapped_type); EXPECT_TRUE(MapTraits::is_sorted); EXPECT_TRUE(MapTraits::is_unique); - + // Front/back operations not supported EXPECT_FALSE(MapTraits::has_front); EXPECT_FALSE(MapTraits::has_back); EXPECT_FALSE(MapTraits::has_push_front); EXPECT_FALSE(MapTraits::has_push_back); - + // Type checks static_assert(std::is_same_v); static_assert(std::is_same_v); @@ -308,19 +308,19 @@ TEST_F(ContainerTraitsTest, MapTraits) { // Test std::multimap traits TEST_F(ContainerTraitsTest, MultimapTraits) { using MultimapTraits = atom::meta::ContainerTraits>; - + // Container category EXPECT_TRUE(MultimapTraits::is_associative_container); - + // Key-value properties - multimap allows duplicate keys EXPECT_TRUE(MultimapTraits::has_key_type); EXPECT_TRUE(MultimapTraits::has_mapped_type); EXPECT_TRUE(MultimapTraits::is_sorted); EXPECT_FALSE(MultimapTraits::is_unique); // multimap allows duplicates - + // Access operations - multimap doesn't have operator[] EXPECT_FALSE(MultimapTraits::has_subscript); - + // Other operations EXPECT_TRUE(MultimapTraits::has_find); EXPECT_TRUE(MultimapTraits::has_count); @@ -329,29 +329,29 @@ TEST_F(ContainerTraitsTest, MultimapTraits) { // Test std::set traits TEST_F(ContainerTraitsTest, SetTraits) { using SetTraits = atom::meta::ContainerTraits>; - + // Container category EXPECT_TRUE(SetTraits::is_associative_container); - + // Iterator capabilities EXPECT_TRUE(SetTraits::has_bidirectional_access); - + // Key properties EXPECT_TRUE(SetTraits::has_key_type); EXPECT_FALSE(SetTraits::has_mapped_type); // set doesn't have mapped_type EXPECT_TRUE(SetTraits::is_sorted); EXPECT_TRUE(SetTraits::is_unique); - + // Operations EXPECT_TRUE(SetTraits::has_insert); EXPECT_TRUE(SetTraits::has_erase); EXPECT_TRUE(SetTraits::has_find); EXPECT_TRUE(SetTraits::has_count); - + // Access operations - set doesn't have subscript or at EXPECT_FALSE(SetTraits::has_subscript); EXPECT_FALSE(SetTraits::has_at); - + // Type checks static_assert(std::is_same_v); static_assert(std::is_same_v); @@ -360,10 +360,10 @@ TEST_F(ContainerTraitsTest, SetTraits) { // Test std::multiset traits TEST_F(ContainerTraitsTest, MultisetTraits) { using MultisetTraits = atom::meta::ContainerTraits>; - + // Container category EXPECT_TRUE(MultisetTraits::is_associative_container); - + // Key properties - multiset allows duplicates EXPECT_TRUE(MultisetTraits::has_key_type); EXPECT_FALSE(MultisetTraits::has_mapped_type); @@ -376,18 +376,18 @@ TEST_F(ContainerTraitsTest, MultisetTraits) { // Test std::unordered_map traits TEST_F(ContainerTraitsTest, UnorderedMapTraits) { using UnorderedMapTraits = atom::meta::ContainerTraits>; - + // Container category EXPECT_FALSE(UnorderedMapTraits::is_sequence_container); EXPECT_FALSE(UnorderedMapTraits::is_associative_container); EXPECT_TRUE(UnorderedMapTraits::is_unordered_associative_container); EXPECT_FALSE(UnorderedMapTraits::is_container_adapter); - + // Iterator capabilities - unordered containers have forward iterators EXPECT_FALSE(UnorderedMapTraits::has_random_access); EXPECT_FALSE(UnorderedMapTraits::has_bidirectional_access); EXPECT_TRUE(UnorderedMapTraits::has_forward_access); - + // Container operations EXPECT_TRUE(UnorderedMapTraits::has_insert); EXPECT_TRUE(UnorderedMapTraits::has_erase); @@ -395,16 +395,16 @@ TEST_F(ContainerTraitsTest, UnorderedMapTraits) { EXPECT_TRUE(UnorderedMapTraits::has_find); EXPECT_TRUE(UnorderedMapTraits::has_count); EXPECT_TRUE(UnorderedMapTraits::has_reserve); - + // Access operations EXPECT_TRUE(UnorderedMapTraits::has_subscript); - + // Key-value properties EXPECT_TRUE(UnorderedMapTraits::has_key_type); EXPECT_TRUE(UnorderedMapTraits::has_mapped_type); EXPECT_FALSE(UnorderedMapTraits::is_sorted); // unordered containers are not sorted EXPECT_TRUE(UnorderedMapTraits::is_unique); - + // Type checks static_assert(std::is_same_v); static_assert(std::is_same_v); @@ -413,16 +413,16 @@ TEST_F(ContainerTraitsTest, UnorderedMapTraits) { // Test std::unordered_multimap traits TEST_F(ContainerTraitsTest, UnorderedMultimapTraits) { using UnorderedMultimapTraits = atom::meta::ContainerTraits>; - + // Container category EXPECT_TRUE(UnorderedMultimapTraits::is_unordered_associative_container); - + // Key-value properties EXPECT_TRUE(UnorderedMultimapTraits::has_key_type); EXPECT_TRUE(UnorderedMultimapTraits::has_mapped_type); EXPECT_FALSE(UnorderedMultimapTraits::is_sorted); EXPECT_FALSE(UnorderedMultimapTraits::is_unique); // multimap allows duplicates - + // Access operations - unordered_multimap doesn't have operator[] EXPECT_FALSE(UnorderedMultimapTraits::has_subscript); } @@ -430,19 +430,19 @@ TEST_F(ContainerTraitsTest, UnorderedMultimapTraits) { // Test std::unordered_set traits TEST_F(ContainerTraitsTest, UnorderedSetTraits) { using UnorderedSetTraits = atom::meta::ContainerTraits>; - + // Container category EXPECT_TRUE(UnorderedSetTraits::is_unordered_associative_container); - + // Iterator capabilities EXPECT_TRUE(UnorderedSetTraits::has_forward_access); - + // Key properties EXPECT_TRUE(UnorderedSetTraits::has_key_type); EXPECT_FALSE(UnorderedSetTraits::has_mapped_type); EXPECT_FALSE(UnorderedSetTraits::is_sorted); EXPECT_TRUE(UnorderedSetTraits::is_unique); - + // Operations EXPECT_TRUE(UnorderedSetTraits::has_reserve); EXPECT_TRUE(UnorderedSetTraits::has_find); @@ -452,10 +452,10 @@ TEST_F(ContainerTraitsTest, UnorderedSetTraits) { // Test std::unordered_multiset traits TEST_F(ContainerTraitsTest, UnorderedMultisetTraits) { using UnorderedMultisetTraits = atom::meta::ContainerTraits>; - + // Container category EXPECT_TRUE(UnorderedMultisetTraits::is_unordered_associative_container); - + // Key properties EXPECT_TRUE(UnorderedMultisetTraits::has_key_type); EXPECT_FALSE(UnorderedMultisetTraits::has_mapped_type); @@ -468,17 +468,17 @@ TEST_F(ContainerTraitsTest, UnorderedMultisetTraits) { // Test std::stack traits TEST_F(ContainerTraitsTest, StackTraits) { using StackTraits = atom::meta::ContainerTraits>; - + // Container category EXPECT_FALSE(StackTraits::is_sequence_container); EXPECT_FALSE(StackTraits::is_associative_container); EXPECT_FALSE(StackTraits::is_unordered_associative_container); EXPECT_TRUE(StackTraits::is_container_adapter); - + // Iterator capabilities - adapters don't have iterators EXPECT_FALSE(StackTraits::has_begin_end); EXPECT_FALSE(StackTraits::has_rbegin_rend); - + // Container operations - stack only supports top, push, pop EXPECT_FALSE(StackTraits::has_front); EXPECT_TRUE(StackTraits::has_back); // top() is considered back @@ -486,16 +486,16 @@ TEST_F(ContainerTraitsTest, StackTraits) { EXPECT_TRUE(StackTraits::has_push_back); // push() is considered push_back EXPECT_FALSE(StackTraits::has_pop_front); EXPECT_TRUE(StackTraits::has_pop_back); // pop() is considered pop_back - + // Operations not supported by adapters EXPECT_FALSE(StackTraits::has_clear); EXPECT_FALSE(StackTraits::has_insert); EXPECT_FALSE(StackTraits::has_erase); - + // Access operations EXPECT_FALSE(StackTraits::has_subscript); EXPECT_FALSE(StackTraits::has_at); - + // Type checks static_assert(std::is_same_v); } @@ -503,10 +503,10 @@ TEST_F(ContainerTraitsTest, StackTraits) { // Test std::queue traits TEST_F(ContainerTraitsTest, QueueTraits) { using QueueTraits = atom::meta::ContainerTraits>; - + // Container category EXPECT_TRUE(QueueTraits::is_container_adapter); - + // Container operations - queue supports front, back, push, pop EXPECT_TRUE(QueueTraits::has_front); EXPECT_TRUE(QueueTraits::has_back); @@ -514,7 +514,7 @@ TEST_F(ContainerTraitsTest, QueueTraits) { EXPECT_TRUE(QueueTraits::has_push_back); // push() is considered push_back EXPECT_TRUE(QueueTraits::has_pop_front); // pop() is considered pop_front EXPECT_FALSE(QueueTraits::has_pop_back); - + // Iterator capabilities EXPECT_FALSE(QueueTraits::has_begin_end); } @@ -522,19 +522,19 @@ TEST_F(ContainerTraitsTest, QueueTraits) { // Test std::priority_queue traits TEST_F(ContainerTraitsTest, PriorityQueueTraits) { using PriorityQueueTraits = atom::meta::ContainerTraits>; - + // Container category EXPECT_TRUE(PriorityQueueTraits::is_container_adapter); - + // Container operations - priority_queue only supports top, push, pop EXPECT_FALSE(PriorityQueueTraits::has_front); EXPECT_TRUE(PriorityQueueTraits::has_back); // top() is considered back EXPECT_TRUE(PriorityQueueTraits::has_push_back); // push() EXPECT_TRUE(PriorityQueueTraits::has_pop_back); // pop() - + // Special property - priority_queue maintains heap order EXPECT_TRUE(PriorityQueueTraits::is_sorted); - + // Iterator capabilities EXPECT_FALSE(PriorityQueueTraits::has_begin_end); } @@ -545,7 +545,7 @@ TEST_F(ContainerTraitsTest, PriorityQueueTraits) { TEST_F(ContainerTraitsTest, ConstContainerTraits) { using ConstVectorTraits = atom::meta::ContainerTraits>; using VectorTraits = atom::meta::ContainerTraits>; - + // Const containers should have the same traits as non-const EXPECT_EQ(ConstVectorTraits::is_sequence_container, VectorTraits::is_sequence_container); EXPECT_EQ(ConstVectorTraits::has_random_access, VectorTraits::has_random_access); @@ -557,11 +557,11 @@ TEST_F(ContainerTraitsTest, ReferenceContainerTraits) { using VectorRefTraits = atom::meta::ContainerTraits&>; using VectorRValueRefTraits = atom::meta::ContainerTraits&&>; using VectorTraits = atom::meta::ContainerTraits>; - + // Reference containers should have the same traits as non-reference EXPECT_EQ(VectorRefTraits::is_sequence_container, VectorTraits::is_sequence_container); EXPECT_EQ(VectorRefTraits::has_random_access, VectorTraits::has_random_access); - + EXPECT_EQ(VectorRValueRefTraits::is_sequence_container, VectorTraits::is_sequence_container); EXPECT_EQ(VectorRValueRefTraits::has_random_access, VectorTraits::has_random_access); } @@ -573,55 +573,55 @@ TEST_F(ContainerTraitsTest, VariableTemplates) { // Sequence container checks EXPECT_TRUE(atom::meta::is_sequence_container_v>); EXPECT_FALSE(atom::meta::is_sequence_container_v>); - + // Associative container checks EXPECT_TRUE(atom::meta::is_associative_container_v>); EXPECT_FALSE(atom::meta::is_associative_container_v>); - + // Unordered associative container checks EXPECT_TRUE(atom::meta::is_unordered_associative_container_v>); EXPECT_FALSE(atom::meta::is_unordered_associative_container_v>); - + // Container adapter checks EXPECT_TRUE(atom::meta::is_container_adapter_v>); EXPECT_FALSE(atom::meta::is_container_adapter_v>); - + // Iterator capability checks EXPECT_TRUE(atom::meta::has_random_access_v>); EXPECT_FALSE(atom::meta::has_random_access_v>); - + EXPECT_TRUE(atom::meta::has_bidirectional_access_v>); EXPECT_FALSE(atom::meta::has_bidirectional_access_v>); - + EXPECT_TRUE(atom::meta::has_forward_access_v>); EXPECT_FALSE(atom::meta::has_forward_access_v>); - + // Operation capability checks EXPECT_TRUE(atom::meta::has_subscript_v>); EXPECT_FALSE(atom::meta::has_subscript_v>); - + EXPECT_TRUE(atom::meta::has_reserve_v>); EXPECT_FALSE(atom::meta::has_reserve_v>); - + EXPECT_TRUE(atom::meta::has_capacity_v>); EXPECT_FALSE(atom::meta::has_capacity_v>); - + EXPECT_TRUE(atom::meta::has_push_back_v>); EXPECT_FALSE(atom::meta::has_push_back_v>); - + EXPECT_TRUE(atom::meta::has_push_front_v>); EXPECT_FALSE(atom::meta::has_push_front_v>); - + EXPECT_TRUE(atom::meta::has_insert_v>); EXPECT_FALSE(atom::meta::has_insert_v>); - + // Container property checks EXPECT_TRUE(atom::meta::is_fixed_size_v>); EXPECT_FALSE(atom::meta::is_fixed_size_v>); - + EXPECT_TRUE(atom::meta::is_sorted_v>); EXPECT_FALSE(atom::meta::is_sorted_v>); - + EXPECT_TRUE(atom::meta::is_unique_v>); EXPECT_FALSE(atom::meta::is_unique_v>); } @@ -633,24 +633,24 @@ TEST_F(ContainerTraitsTest, GetIteratorCategory) { // Random access containers auto vectorCategory = atom::meta::get_iterator_category>(); static_assert(std::is_same_v); - + auto arrayCategory = atom::meta::get_iterator_category>(); static_assert(std::is_same_v); - + // Bidirectional containers auto listCategory = atom::meta::get_iterator_category>(); static_assert(std::is_same_v); - + auto mapCategory = atom::meta::get_iterator_category>(); static_assert(std::is_same_v); - + // Forward containers auto forwardListCategory = atom::meta::get_iterator_category>(); static_assert(std::is_same_v); - + auto unorderedMapCategory = atom::meta::get_iterator_category>(); static_assert(std::is_same_v); - + // Container adapters (input iterator as fallback) auto stackCategory = atom::meta::get_iterator_category>(); static_assert(std::is_same_v); @@ -663,14 +663,14 @@ TEST_F(ContainerTraitsTest, UtilityFunctions) { EXPECT_TRUE(atom::meta::supports_efficient_random_access>()); EXPECT_FALSE(atom::meta::supports_efficient_random_access>()); EXPECT_FALSE(atom::meta::supports_efficient_random_access>()); - + // Test can_grow_dynamically EXPECT_TRUE(atom::meta::can_grow_dynamically>()); EXPECT_TRUE(atom::meta::can_grow_dynamically>()); EXPECT_TRUE(atom::meta::can_grow_dynamically>()); EXPECT_FALSE(atom::meta::can_grow_dynamically>()); EXPECT_FALSE(atom::meta::can_grow_dynamically>()); // Adapters don't directly support growth - + // Test supports_key_lookup EXPECT_TRUE(atom::meta::supports_key_lookup>()); EXPECT_TRUE(atom::meta::supports_key_lookup>()); @@ -685,29 +685,29 @@ TEST_F(ContainerTraitsTest, UtilityFunctions) { TEST_F(ContainerTraitsTest, ContainerPipe) { // Create a test vector std::vector numbers = {1, 2, 3, 4, 5}; - + // Test transform operation auto pipe = atom::meta::make_container_pipe(numbers); auto doubled = pipe.transform([](int x) { return x * 2; }); auto result = doubled.get(); - + std::vector expected = {2, 4, 6, 8, 10}; EXPECT_EQ(result, expected); - + // Test filter operation auto filtered = atom::meta::make_container_pipe(numbers) .filter([](int x) { return x % 2 == 0; }); auto filteredResult = filtered.get(); - + std::vector expectedFiltered = {2, 4}; EXPECT_EQ(filteredResult, expectedFiltered); - + // Test chaining operations auto chained = atom::meta::make_container_pipe(numbers) .filter([](int x) { return x > 2; }) .transform([](int x) { return x * 3; }); auto chainedResult = chained.get(); - + std::vector expectedChained = {9, 12, 15}; // (3, 4, 5) * 3 EXPECT_EQ(chainedResult, expectedChained); } @@ -716,19 +716,19 @@ TEST_F(ContainerTraitsTest, ContainerPipe) { TEST_F(ContainerTraitsTest, ContainerPipeWithDifferentTypes) { // Test with list std::list words = {"hello", "world", "test"}; - + auto lengthPipe = atom::meta::make_container_pipe(words) .transform([](const std::string& s) { return s.length(); }); auto lengths = lengthPipe.get(); - + std::vector expectedLengths = {5, 5, 4}; EXPECT_EQ(lengths, expectedLengths); - + // Test filter with strings auto longWords = atom::meta::make_container_pipe(words) .filter([](const std::string& s) { return s.length() > 4; }); auto longWordsResult = longWords.get(); - + std::list expectedLongWords = {"hello", "world"}; EXPECT_EQ(longWordsResult, expectedLongWords); } @@ -739,11 +739,11 @@ TEST_F(ContainerTraitsTest, ContainerPipeWithDifferentTypes) { TEST_F(ContainerTraitsTest, EmptyContainerTests) { std::vector emptyVector; auto emptyPipe = atom::meta::make_container_pipe(emptyVector); - + // Transform on empty container should return empty container auto transformedEmpty = emptyPipe.transform([](int x) { return x * 2; }); EXPECT_TRUE(transformedEmpty.get().empty()); - + // Filter on empty container should return empty container auto filteredEmpty = emptyPipe.filter([](int x) { return x > 0; }); EXPECT_TRUE(filteredEmpty.get().empty()); @@ -752,16 +752,16 @@ TEST_F(ContainerTraitsTest, EmptyContainerTests) { // Test with single element containers TEST_F(ContainerTraitsTest, SingleElementContainerTests) { std::vector singleElement = {42}; - + auto transformed = atom::meta::make_container_pipe(singleElement) .transform([](int x) { return x / 2; }); std::vector expected = {21}; EXPECT_EQ(transformed.get(), expected); - + auto filtered = atom::meta::make_container_pipe(singleElement) .filter([](int x) { return x > 50; }); EXPECT_TRUE(filtered.get().empty()); - + auto notFiltered = atom::meta::make_container_pipe(singleElement) .filter([](int x) { return x > 10; }); EXPECT_EQ(notFiltered.get(), singleElement); @@ -771,11 +771,11 @@ TEST_F(ContainerTraitsTest, SingleElementContainerTests) { TEST_F(ContainerTraitsTest, ComplexTypeTests) { using ComplexMap = std::map>; using ComplexMapTraits = atom::meta::ContainerTraits; - + EXPECT_TRUE(ComplexMapTraits::is_associative_container); EXPECT_TRUE(ComplexMapTraits::has_key_type); EXPECT_TRUE(ComplexMapTraits::has_mapped_type); - + static_assert(std::is_same_v); static_assert(std::is_same_v>); } @@ -784,9 +784,9 @@ TEST_F(ContainerTraitsTest, ComplexTypeTests) { TEST_F(ContainerTraitsTest, OperationDetection) { // Test container_supports_operation (basic test since it's a SFINAE helper) using VectorSupportsOp = atom::meta::container_supports_operation< - std::vector, + std::vector, void(typename atom::meta::ContainerTraits>::value_type)>; - + // This tests the SFINAE mechanism - exact test depends on the specific operation signature // The test mainly ensures the template compiles correctly static_assert(std::is_same_v); @@ -794,4 +794,4 @@ TEST_F(ContainerTraitsTest, OperationDetection) { } // namespace atom::test -#endif // ATOM_TEST_CONTAINER_TRAITS_HPP \ No newline at end of file +#endif // ATOM_TEST_CONTAINER_TRAITS_HPP diff --git a/tests/meta/test_conversion.hpp b/tests/meta/test_conversion.hpp index ad830565..0c6f4851 100644 --- a/tests/meta/test_conversion.hpp +++ b/tests/meta/test_conversion.hpp @@ -441,4 +441,4 @@ TEST_F(ConversionTest, ReferenceConversions) { } // namespace atom::test -#endif // ATOM_TEST_CONVERSION_HPP \ No newline at end of file +#endif // ATOM_TEST_CONVERSION_HPP diff --git a/tests/meta/test_decorate.cpp b/tests/meta/test_decorate.cpp index f78d555f..5903b39a 100644 --- a/tests/meta/test_decorate.cpp +++ b/tests/meta/test_decorate.cpp @@ -557,4 +557,4 @@ TEST_F(DecorateTest, ConceptsAndTypeTraits) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/tests/meta/test_enum.hpp b/tests/meta/test_enum.hpp index 372675bc..83d7f12f 100644 --- a/tests/meta/test_enum.hpp +++ b/tests/meta/test_enum.hpp @@ -71,21 +71,21 @@ struct EnumTraits { } }; -// Complete EnumTraits specialization for Permissions (as flag enum) +// Complete EnumTraits specialization for Permissions (as flag enum) template <> struct EnumTraits { using enum_type = test::Permissions; using underlying_type = std::underlying_type_t; static constexpr std::array values = { - test::Permissions::None, test::Permissions::Read, test::Permissions::Write, + test::Permissions::None, test::Permissions::Read, test::Permissions::Write, test::Permissions::Execute, test::Permissions::All}; static constexpr std::array names = { "None", "Read", "Write", "Execute", "All"}; static constexpr std::array descriptions = { - "No permissions", "Read permission", "Write permission", + "No permissions", "Read permission", "Write permission", "Execute permission", "All permissions"}; static constexpr std::array aliases = { @@ -409,10 +409,10 @@ TEST_F(EnumTest, FlagEnumFunctions) { // Test get_set_flags function TEST_F(EnumTest, GetSetFlags) { Permissions readWrite = Permissions::Read | Permissions::Write; - + auto setFlags = atom::meta::get_set_flags(readWrite); EXPECT_EQ(setFlags.size(), 2); - + // Flags should be in the order they appear in the enum values array bool foundRead = false, foundWrite = false; for (const auto& flag : setFlags) { @@ -441,7 +441,7 @@ TEST_F(EnumTest, FlagSerialization) { // Test serializing combined flags Permissions readWrite = Permissions::Read | Permissions::Write; std::string readWriteStr = atom::meta::serialize_flags(readWrite); - + // Should contain both flag names separated by | EXPECT_TRUE(readWriteStr.find("Read") != std::string::npos); EXPECT_TRUE(readWriteStr.find("Write") != std::string::npos); @@ -495,8 +495,8 @@ TEST_F(EnumTest, FlagDeserialization) { TEST_F(EnumTest, EnumValidator) { // Create validator that only allows primary colors atom::meta::EnumValidator primaryColorValidator( - [](Color c) { - return c == Color::Red || c == Color::Green || c == Color::Blue; + [](Color c) { + return c == Color::Red || c == Color::Green || c == Color::Blue; }, "Only primary colors allowed" ); @@ -546,7 +546,7 @@ TEST_F(EnumTest, EnumIteratorAndRange) { for (auto color : atom::meta::enum_range()) { colors.push_back(color); } - + EXPECT_EQ(colors.size(), 4); EXPECT_EQ(colors[0], Color::Red); EXPECT_EQ(colors[1], Color::Green); @@ -683,4 +683,4 @@ TEST_F(EnumTest, IntegerInEnumRange) { } // namespace atom::test -#endif // ATOM_TEST_ENUM_HPP \ No newline at end of file +#endif // ATOM_TEST_ENUM_HPP diff --git a/tests/meta/test_func_traits.hpp b/tests/meta/test_func_traits.hpp index d531f69a..9e00dad7 100644 --- a/tests/meta/test_func_traits.hpp +++ b/tests/meta/test_func_traits.hpp @@ -396,4 +396,4 @@ TEST_F(FunctionTraitsTest, HasConstMethodDetection) { } // namespace atom::test -#endif // ATOM_TEST_FUNC_TRAITS_HPP \ No newline at end of file +#endif // ATOM_TEST_FUNC_TRAITS_HPP diff --git a/tests/meta/test_global_ptr.hpp b/tests/meta/test_global_ptr.hpp index 33589abf..fb2fb4e6 100644 --- a/tests/meta/test_global_ptr.hpp +++ b/tests/meta/test_global_ptr.hpp @@ -577,4 +577,4 @@ TEST_F(GlobalPtrTest, GetWeakPtrMacroSimulated) { } // namespace atom::test -#endif // ATOM_TEST_GLOBAL_PTR_HPP \ No newline at end of file +#endif // ATOM_TEST_GLOBAL_PTR_HPP diff --git a/tests/meta/test_god.hpp b/tests/meta/test_god.hpp index 0b8e807d..cdde3ecc 100644 --- a/tests/meta/test_god.hpp +++ b/tests/meta/test_god.hpp @@ -710,4 +710,4 @@ TEST_F(GodTest, AtomicThreadSafetyTest) { EXPECT_EQ(counter.load(), kNumThreads * kIterationsPerThread); } -} // namespace atom::meta::test \ No newline at end of file +} // namespace atom::meta::test diff --git a/tests/meta/test_invoke.hpp b/tests/meta/test_invoke.hpp index d35e141c..82e667d1 100644 --- a/tests/meta/test_invoke.hpp +++ b/tests/meta/test_invoke.hpp @@ -613,4 +613,4 @@ TEST(FunctionCallInfoTest, BasicFunctionality) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/tests/meta/test_member.cpp b/tests/meta/test_member.cpp index 2562ceaf..cdcd290f 100644 --- a/tests/meta/test_member.cpp +++ b/tests/meta/test_member.cpp @@ -449,4 +449,4 @@ TEST_F(MemberTest, ErrorHandling) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/tests/meta/test_overload.hpp b/tests/meta/test_overload.hpp index ed55e7a5..3cbdcc99 100644 --- a/tests/meta/test_overload.hpp +++ b/tests/meta/test_overload.hpp @@ -388,4 +388,4 @@ TEST_F(OverloadTest, EdgeCases) { } // namespace atom::meta::test -#endif // ATOM_META_TEST_OVERLOAD_HPP \ No newline at end of file +#endif // ATOM_META_TEST_OVERLOAD_HPP diff --git a/tests/meta/test_property.hpp b/tests/meta/test_property.hpp index 662c0a5c..2a4b75d0 100644 --- a/tests/meta/test_property.hpp +++ b/tests/meta/test_property.hpp @@ -534,4 +534,4 @@ int main(int argc, char** argv) { return RUN_ALL_TESTS(); } -#endif // ATOM_META_TEST_PROPERTY_HPP \ No newline at end of file +#endif // ATOM_META_TEST_PROPERTY_HPP diff --git a/tests/meta/test_proxy.hpp b/tests/meta/test_proxy.hpp index 3b0a3c75..5c8a4572 100644 --- a/tests/meta/test_proxy.hpp +++ b/tests/meta/test_proxy.hpp @@ -648,4 +648,4 @@ TEST(FactoryFunctionTest, ProxyFactoryFunctions) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/tests/meta/test_proxy_params.hpp b/tests/meta/test_proxy_params.hpp index 2654ef6f..fda83605 100644 --- a/tests/meta/test_proxy_params.hpp +++ b/tests/meta/test_proxy_params.hpp @@ -638,4 +638,4 @@ TEST_F(FunctionParamsTest, ComplexUsageScenarios) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/tests/meta/test_raw_name.hpp b/tests/meta/test_raw_name.hpp index d0e1add6..8f7f7350 100644 --- a/tests/meta/test_raw_name.hpp +++ b/tests/meta/test_raw_name.hpp @@ -276,4 +276,4 @@ int main(int argc, char** argv) { return RUN_ALL_TESTS(); } -#endif // ATOM_META_TEST_RAW_NAME_HPP \ No newline at end of file +#endif // ATOM_META_TEST_RAW_NAME_HPP diff --git a/tests/meta/test_signature.cpp b/tests/meta/test_signature.cpp index 3c99bff7..2799ed71 100644 --- a/tests/meta/test_signature.cpp +++ b/tests/meta/test_signature.cpp @@ -460,4 +460,4 @@ TEST_F(SignatureTest, ParameterComparison) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/tests/meta/test_stepper.hpp b/tests/meta/test_stepper.hpp index b12a783c..2b1830ce 100644 --- a/tests/meta/test_stepper.hpp +++ b/tests/meta/test_stepper.hpp @@ -749,4 +749,4 @@ TEST_F(FunctionSequenceTest, StatisticsAndDiagnostics) { EXPECT_EQ(stats.cacheMisses, 0); } -} // namespace atom::test \ No newline at end of file +} // namespace atom::test diff --git a/tests/meta/test_template_traits.hpp b/tests/meta/test_template_traits.hpp index 46767a0b..296a6913 100644 --- a/tests/meta/test_template_traits.hpp +++ b/tests/meta/test_template_traits.hpp @@ -596,4 +596,4 @@ TEST_F(TemplateTraitsTest, StaticDiagnosticsTests) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/tests/meta/test_type_info.hpp b/tests/meta/test_type_info.hpp index 019ebb80..7276c663 100644 --- a/tests/meta/test_type_info.hpp +++ b/tests/meta/test_type_info.hpp @@ -463,4 +463,4 @@ TEST_F(TypeInfoTest, RegisterCustomTypeInfo) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/tests/meta/test_vany.hpp b/tests/meta/test_vany.hpp index 1d4a973a..a91ce701 100644 --- a/tests/meta/test_vany.hpp +++ b/tests/meta/test_vany.hpp @@ -625,4 +625,4 @@ TEST_F(AnyTest, TypeInfo) { } // namespace atom::meta::test -#endif // ATOM_META_TEST_VANY_HPP \ No newline at end of file +#endif // ATOM_META_TEST_VANY_HPP diff --git a/tests/search/test_lru.hpp b/tests/search/test_lru.hpp index d4a9b1da..936c4c39 100644 --- a/tests/search/test_lru.hpp +++ b/tests/search/test_lru.hpp @@ -486,4 +486,4 @@ TEST_F(ThreadSafeLRUCacheTest, AccessOrder) { EXPECT_FALSE(cache->get("key2").has_value()); // Should be evicted EXPECT_TRUE(cache->get("key3").has_value()); EXPECT_TRUE(cache->get("key4").has_value()); -} \ No newline at end of file +} diff --git a/tests/search/test_ttl.hpp b/tests/search/test_ttl.hpp index 3070cdc6..8ca58916 100644 --- a/tests/search/test_ttl.hpp +++ b/tests/search/test_ttl.hpp @@ -320,4 +320,4 @@ TEST_F(TTLCacheTest, StressTest) { for (int i = 0; i < 50; i++) { EXPECT_FALSE(stressCache->get(i).has_value()); } -} \ No newline at end of file +} diff --git a/tests/serial/test_bluetooth_serial.hpp b/tests/serial/test_bluetooth_serial.hpp index 96a22d6e..5007a447 100644 --- a/tests/serial/test_bluetooth_serial.hpp +++ b/tests/serial/test_bluetooth_serial.hpp @@ -468,4 +468,4 @@ TEST_F(BluetoothSerialTest, MoveSemantics) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/tests/serial/test_scanner.cpp b/tests/serial/test_scanner.cpp index 4d8728f1..5daeebfd 100644 --- a/tests/serial/test_scanner.cpp +++ b/tests/serial/test_scanner.cpp @@ -280,4 +280,4 @@ TEST_F(SerialPortScannerTest, FullPortScanningWorkflow) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/tests/serial/test_serial_port.hpp b/tests/serial/test_serial_port.hpp index 50261aa3..e4d8ff2d 100644 --- a/tests/serial/test_serial_port.hpp +++ b/tests/serial/test_serial_port.hpp @@ -54,7 +54,7 @@ class SerialPortTest : public ::testing::Test { protected: void SetUp() override { mockImpl = std::make_shared(); - + // Setup default config for testing config.baudRate = 115200; config.dataBits = 8; @@ -63,19 +63,19 @@ class SerialPortTest : public ::testing::Test { config.flowControl = SerialConfig::FlowControl::None; config.readTimeout = 500ms; config.writeTimeout = 500ms; - + // Setup test data testData = {0x01, 0x02, 0x03, 0x04, 0x05}; } - + void TearDown() override { // Clean up test resources if needed } - + std::shared_ptr mockImpl; SerialConfig config; std::vector testData; - const std::string testPort = + const std::string testPort = #ifdef _WIN32 "COM3"; #else @@ -88,34 +88,34 @@ TEST_F(SerialPortTest, OpenClosePort) { // Setup expectations EXPECT_CALL(*mockImpl, open(testPort, _)) .Times(1); - + EXPECT_CALL(*mockImpl, isOpen()) .WillOnce(Return(true)) .WillOnce(Return(false)); - + EXPECT_CALL(*mockImpl, close()) .Times(1); - + EXPECT_CALL(*mockImpl, getPortName()) .WillOnce(Return(testPort)); - + // Create a SerialPort with our mock implementation // Note: In a real test, you would need a way to inject the mock SerialPort port; // For testing purposes, we'll simulate the behavior as if the mock was injected - + // Open the port port.open(testPort, config); - + // Verify port is open EXPECT_TRUE(port.isOpen()); - + // Verify port name EXPECT_EQ(testPort, port.getPortName()); - + // Close the port port.close(); - + // Verify port is closed EXPECT_FALSE(port.isOpen()); } @@ -125,7 +125,7 @@ TEST_F(SerialPortTest, OpenInvalidPort) { // Setup expectations EXPECT_CALL(*mockImpl, open("invalid_port", _)) .WillOnce(Throw(SerialIOException("Failed to open port: Access denied"))); - + // Try to open an invalid port // Note: Since we're simulating behavior, we'll just verify the expectation was set try { @@ -141,36 +141,36 @@ TEST_F(SerialPortTest, ReadData) { // Setup expectations EXPECT_CALL(*mockImpl, isOpen()) .WillRepeatedly(Return(true)); - + EXPECT_CALL(*mockImpl, read(5)) .WillOnce(Return(testData)); - + EXPECT_CALL(*mockImpl, readExactly(3, 1000ms)) .WillOnce(Return(std::vector{0x01, 0x02, 0x03})); - + EXPECT_CALL(*mockImpl, readAvailable()) .WillOnce(Return(testData)); - + EXPECT_CALL(*mockImpl, available()) .WillOnce(Return(5)); - + // Test regular read auto data = mockImpl->read(5); ASSERT_EQ(data.size(), 5); EXPECT_EQ(data, testData); - + // Test reading exactly N bytes auto exactData = mockImpl->readExactly(3, 1000ms); ASSERT_EQ(exactData.size(), 3); EXPECT_EQ(exactData[0], 0x01); EXPECT_EQ(exactData[1], 0x02); EXPECT_EQ(exactData[2], 0x03); - + // Test reading all available data auto availData = mockImpl->readAvailable(); ASSERT_EQ(availData.size(), 5); EXPECT_EQ(availData, testData); - + // Test checking bytes available size_t bytesAvailable = mockImpl->available(); EXPECT_EQ(bytesAvailable, 5); @@ -181,13 +181,13 @@ TEST_F(SerialPortTest, ReadFromClosedPort) { // Setup expectations EXPECT_CALL(*mockImpl, isOpen()) .WillRepeatedly(Return(false)); - + EXPECT_CALL(*mockImpl, read(_)) .WillOnce(Throw(SerialPortNotOpenException())); - + EXPECT_CALL(*mockImpl, readAvailable()) .WillOnce(Throw(SerialPortNotOpenException())); - + // Test reading from a closed port try { mockImpl->read(5); @@ -195,7 +195,7 @@ TEST_F(SerialPortTest, ReadFromClosedPort) { } catch (const SerialPortNotOpenException& e) { EXPECT_STREQ("Port not open", e.what()); } - + // Test reading available from a closed port try { mockImpl->readAvailable(); @@ -210,10 +210,10 @@ TEST_F(SerialPortTest, ReadTimeout) { // Setup expectations EXPECT_CALL(*mockImpl, isOpen()) .WillRepeatedly(Return(true)); - + EXPECT_CALL(*mockImpl, readExactly(10, _)) .WillOnce(Throw(SerialTimeoutException())); - + // Test read timeout try { mockImpl->readExactly(10, 500ms); @@ -229,11 +229,11 @@ TEST_F(SerialPortTest, AsyncRead) { std::atomic dataReceived{false}; std::mutex mutex; std::condition_variable cv; - + // Setup expectations EXPECT_CALL(*mockImpl, isOpen()) .WillRepeatedly(Return(true)); - + EXPECT_CALL(*mockImpl, asyncRead(_, _)) .WillOnce([this, &receivedData, &dataReceived, &cv](size_t maxBytes, auto callback) { // Simulate async read by calling the callback with test data @@ -244,18 +244,18 @@ TEST_F(SerialPortTest, AsyncRead) { cv.notify_one(); }).detach(); }); - + // Start async read mockImpl->asyncRead(10, [&receivedData](std::vector data) { receivedData = std::move(data); }); - + // Wait for async read to complete { std::unique_lock lock(mutex); cv.wait_for(lock, 5s, [&dataReceived]() { return dataReceived.load(); }); } - + // Verify received data ASSERT_TRUE(dataReceived.load()); ASSERT_EQ(receivedData.size(), 5); @@ -267,30 +267,30 @@ TEST_F(SerialPortTest, WriteData) { // Setup expectations EXPECT_CALL(*mockImpl, isOpen()) .WillRepeatedly(Return(true)); - + EXPECT_CALL(*mockImpl, write(std::span(testData))) .WillOnce(Return(5)); - + EXPECT_CALL(*mockImpl, write(std::string("Hello Serial"))) .WillOnce(Return(12)); - + EXPECT_CALL(*mockImpl, flush()) .Times(1); - + EXPECT_CALL(*mockImpl, drain()) .Times(1); - + // Test writing binary data size_t bytesWritten = mockImpl->write(std::span(testData)); EXPECT_EQ(bytesWritten, 5); - + // Test writing string data bytesWritten = mockImpl->write(std::string("Hello Serial")); EXPECT_EQ(bytesWritten, 12); - + // Test flush mockImpl->flush(); - + // Test drain mockImpl->drain(); } @@ -300,10 +300,10 @@ TEST_F(SerialPortTest, WriteToClosedPort) { // Setup expectations EXPECT_CALL(*mockImpl, isOpen()) .WillRepeatedly(Return(false)); - + EXPECT_CALL(*mockImpl, write(std::span(_))) .WillOnce(Throw(SerialPortNotOpenException())); - + // Test writing to a closed port try { mockImpl->write(std::span(testData)); @@ -318,10 +318,10 @@ TEST_F(SerialPortTest, WriteTimeout) { // Setup expectations EXPECT_CALL(*mockImpl, isOpen()) .WillRepeatedly(Return(true)); - + EXPECT_CALL(*mockImpl, write(std::span(_))) .WillOnce(Throw(SerialTimeoutException())); - + // Test write timeout try { mockImpl->write(std::span(testData)); @@ -336,19 +336,19 @@ TEST_F(SerialPortTest, Configuration) { // Setup expectations EXPECT_CALL(*mockImpl, isOpen()) .WillRepeatedly(Return(true)); - + EXPECT_CALL(*mockImpl, setConfig(_)) .Times(1); - + EXPECT_CALL(*mockImpl, getConfig()) .WillOnce(Return(config)); - + // Set configuration mockImpl->setConfig(config); - + // Get configuration auto retrievedConfig = mockImpl->getConfig(); - + // Verify configuration EXPECT_EQ(retrievedConfig.baudRate, 115200); EXPECT_EQ(retrievedConfig.dataBits, 8); @@ -364,43 +364,43 @@ TEST_F(SerialPortTest, SignalControl) { // Setup expectations EXPECT_CALL(*mockImpl, isOpen()) .WillRepeatedly(Return(true)); - + EXPECT_CALL(*mockImpl, setDTR(true)) .Times(1); - + EXPECT_CALL(*mockImpl, setRTS(false)) .Times(1); - + EXPECT_CALL(*mockImpl, getCTS()) .WillOnce(Return(true)); - + EXPECT_CALL(*mockImpl, getDSR()) .WillOnce(Return(false)); - + EXPECT_CALL(*mockImpl, getRI()) .WillOnce(Return(false)); - + EXPECT_CALL(*mockImpl, getCD()) .WillOnce(Return(true)); - + // Set DTR mockImpl->setDTR(true); - + // Set RTS mockImpl->setRTS(false); - + // Get CTS bool cts = mockImpl->getCTS(); EXPECT_TRUE(cts); - + // Get DSR bool dsr = mockImpl->getDSR(); EXPECT_FALSE(dsr); - + // Get RI bool ri = mockImpl->getRI(); EXPECT_FALSE(ri); - + // Get CD bool cd = mockImpl->getCD(); EXPECT_TRUE(cd); @@ -416,13 +416,13 @@ TEST_F(SerialPortTest, AvailablePorts) { "/dev/ttyS0", "/dev/ttyUSB0", "/dev/ttyACM0" #endif }; - + EXPECT_CALL(*mockImpl, getAvailablePorts()) .WillOnce(Return(availablePorts)); - + // Get available ports auto ports = mockImpl->getAvailablePorts(); - + // Verify ports ASSERT_EQ(ports.size(), 3); #ifdef _WIN32 @@ -441,15 +441,15 @@ TEST_F(SerialPortTest, Exceptions) { // Test base SerialException SerialException baseEx("Base serial exception"); EXPECT_STREQ("Base serial exception", baseEx.what()); - + // Test SerialPortNotOpenException SerialPortNotOpenException notOpenEx; EXPECT_STREQ("Port not open", notOpenEx.what()); - + // Test SerialTimeoutException SerialTimeoutException timeoutEx; EXPECT_STREQ("Serial operation timed out", timeoutEx.what()); - + // Test SerialIOException SerialIOException ioEx("I/O error: permission denied"); EXPECT_STREQ("I/O error: permission denied", ioEx.what()); @@ -459,24 +459,24 @@ TEST_F(SerialPortTest, Exceptions) { TEST_F(SerialPortTest, MoveSemantics) { // This would be tested with real SerialPort instances, not with mocks // Here we document how it could be tested - + // Create first SerialPort SerialPort port1; // Open a port // port1.open(testPort); - + // Move-construct a second port // SerialPort port2(std::move(port1)); - + // Verify port2 is now connected and port1 is in a valid but unspecified state // EXPECT_TRUE(port2.isOpen()); - + // Create another port // SerialPort port3; - + // Move-assign from port2 // port3 = std::move(port2); - + // Verify port3 is now connected and port2 is in a valid but unspecified state // EXPECT_TRUE(port3.isOpen()); } @@ -486,13 +486,13 @@ TEST_F(SerialPortTest, IOErrors) { // Setup expectations EXPECT_CALL(*mockImpl, isOpen()) .WillRepeatedly(Return(true)); - + EXPECT_CALL(*mockImpl, read(_)) .WillOnce(Throw(SerialIOException("Hardware error: device disconnected"))); - + EXPECT_CALL(*mockImpl, write(std::span(_))) .WillOnce(Throw(SerialIOException("Write error: device disconnected"))); - + // Test I/O error during read try { mockImpl->read(5); @@ -500,7 +500,7 @@ TEST_F(SerialPortTest, IOErrors) { } catch (const SerialIOException& e) { EXPECT_STREQ("Hardware error: device disconnected", e.what()); } - + // Test I/O error during write try { mockImpl->write(std::span(testData)); @@ -515,14 +515,14 @@ TEST_F(SerialPortTest, ConfigurationErrors) { // Setup expectations EXPECT_CALL(*mockImpl, isOpen()) .WillRepeatedly(Return(true)); - + // Invalid baud rate SerialConfig invalidConfig = config; invalidConfig.baudRate = -1; - + EXPECT_CALL(*mockImpl, setConfig(invalidConfig)) .WillOnce(Throw(SerialIOException("Invalid configuration: baud rate out of range"))); - + // Test configuration error try { mockImpl->setConfig(invalidConfig); @@ -537,17 +537,17 @@ TEST_F(SerialPortTest, ZeroLengthOperations) { // Setup expectations EXPECT_CALL(*mockImpl, isOpen()) .WillRepeatedly(Return(true)); - + EXPECT_CALL(*mockImpl, read(0)) .WillOnce(Return(std::vector{})); - + EXPECT_CALL(*mockImpl, write(std::span(std::vector{}))) .WillOnce(Return(0)); - + // Test zero-length read auto emptyRead = mockImpl->read(0); EXPECT_TRUE(emptyRead.empty()); - + // Test zero-length write std::vector emptyData; size_t bytesWritten = mockImpl->write(std::span(emptyData)); @@ -559,4 +559,4 @@ TEST_F(SerialPortTest, ZeroLengthOperations) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/tests/serial/test_usb.cpp b/tests/serial/test_usb.cpp index b68c7e16..6c0a240f 100644 --- a/tests/serial/test_usb.cpp +++ b/tests/serial/test_usb.cpp @@ -554,4 +554,4 @@ TEST_F(UsbContextTest, HotplugRegistrationFailure) { EXPECT_THROW(context.startHotplugDetection(handler), UsbException); } -#endif // ATOM_SERIAL_TEST_USB_HPP \ No newline at end of file +#endif // ATOM_SERIAL_TEST_USB_HPP diff --git a/tests/system/test_command.cpp b/tests/system/test_command.cpp index beaa53b5..8216a839 100644 --- a/tests/system/test_command.cpp +++ b/tests/system/test_command.cpp @@ -476,4 +476,4 @@ TEST_F(CommandEdgeCaseTest, VeryLongCommand) { } } -} // namespace atom::system::test \ No newline at end of file +} // namespace atom::system::test diff --git a/tests/system/test_crash_quotes.cpp b/tests/system/test_crash_quotes.cpp index d05e26e0..a7fad78b 100644 --- a/tests/system/test_crash_quotes.cpp +++ b/tests/system/test_crash_quotes.cpp @@ -441,4 +441,4 @@ TEST(QuoteManagerPerformance, DISABLED_LargeCollection) { std::cout << "Time to filter 10000 quotes by author: " << duration << "ms" << std::endl; EXPECT_EQ(100, byAuthor.size()); -} \ No newline at end of file +} diff --git a/tests/system/test_env.hpp b/tests/system/test_env.hpp index 6aae2ee6..2719bc72 100644 --- a/tests/system/test_env.hpp +++ b/tests/system/test_env.hpp @@ -484,4 +484,4 @@ TEST_F(EnvTest, PrintAllArgs) { EXPECT_FALSE(output.empty()); EXPECT_TRUE(output.find("key1") != std::string::npos); } -#endif \ No newline at end of file +#endif diff --git a/tests/system/test_gpio.hpp b/tests/system/test_gpio.hpp index 7ada8d82..d365d96f 100644 --- a/tests/system/test_gpio.hpp +++ b/tests/system/test_gpio.hpp @@ -465,4 +465,4 @@ TEST_F(GPIOTest, AsyncOperation) { // 验证结果 EXPECT_TRUE(result); -} \ No newline at end of file +} diff --git a/tests/system/test_lregistry.hpp b/tests/system/test_lregistry.hpp index 4f94c509..621282ab 100644 --- a/tests/system/test_lregistry.hpp +++ b/tests/system/test_lregistry.hpp @@ -26,10 +26,10 @@ class RegistryTest : public ::testing::Test { std::string testFilePath = (tempDir / "test_registry.dat").string(); testBackupPath = (tempDir / "test_registry_backup.dat").string(); testExportPath = (tempDir / "test_registry_export.dat").string(); - + // Initialize registry ASSERT_EQ(registry.initialize(testFilePath), RegistryResult::SUCCESS); - + // Create a test key for most tests ASSERT_EQ(registry.createKey(testKeyPath), RegistryResult::SUCCESS); } @@ -38,15 +38,15 @@ class RegistryTest : public ::testing::Test { // Clean up test files auto tempDir = std::filesystem::temp_directory_path(); std::string testFilePath = (tempDir / "test_registry.dat").string(); - + if (std::filesystem::exists(testFilePath)) { std::filesystem::remove(testFilePath); } - + if (std::filesystem::exists(testBackupPath)) { std::filesystem::remove(testBackupPath); } - + if (std::filesystem::exists(testExportPath)) { std::filesystem::remove(testExportPath); } @@ -58,11 +58,11 @@ TEST_F(RegistryTest, CreateKey) { // 测试创建新键 EXPECT_EQ(registry.createKey("NewKey"), RegistryResult::SUCCESS); EXPECT_TRUE(registry.keyExists("NewKey")); - + // 测试创建嵌套键 EXPECT_EQ(registry.createKey("Parent/Child/GrandChild"), RegistryResult::SUCCESS); EXPECT_TRUE(registry.keyExists("Parent/Child/GrandChild")); - + // 测试创建已存在的键 EXPECT_EQ(registry.createKey(testKeyPath), RegistryResult::ALREADY_EXISTS); } @@ -71,14 +71,14 @@ TEST_F(RegistryTest, DeleteKey) { // 创建要删除的键 ASSERT_EQ(registry.createKey("KeyToDelete"), RegistryResult::SUCCESS); EXPECT_TRUE(registry.keyExists("KeyToDelete")); - + // 测试删除键 EXPECT_EQ(registry.deleteKey("KeyToDelete"), RegistryResult::SUCCESS); EXPECT_FALSE(registry.keyExists("KeyToDelete")); - + // 测试删除不存在的键 EXPECT_EQ(registry.deleteKey("NonExistentKey"), RegistryResult::KEY_NOT_FOUND); - + // 测试删除有子键的键 ASSERT_EQ(registry.createKey("Parent/Child"), RegistryResult::SUCCESS); EXPECT_EQ(registry.deleteKey("Parent"), RegistryResult::SUCCESS); @@ -89,10 +89,10 @@ TEST_F(RegistryTest, DeleteKey) { TEST_F(RegistryTest, KeyExists) { // 已存在的键 EXPECT_TRUE(registry.keyExists(testKeyPath)); - + // 不存在的键 EXPECT_FALSE(registry.keyExists("NonExistentKey")); - + // 删除后的键 registry.deleteKey(testKeyPath); EXPECT_FALSE(registry.keyExists(testKeyPath)); @@ -103,16 +103,16 @@ TEST_F(RegistryTest, GetAllKeys) { registry.createKey("Key1"); registry.createKey("Key2"); registry.createKey("Key3/SubKey"); - + // 获取所有键 auto keys = registry.getAllKeys(); - + // 验证结果包含所有创建的键 EXPECT_THAT(keys, testing::Contains(testKeyPath)); EXPECT_THAT(keys, testing::Contains("Key1")); EXPECT_THAT(keys, testing::Contains("Key2")); EXPECT_THAT(keys, testing::Contains("Key3/SubKey")); - + // 删除键后重新验证 registry.deleteKey("Key1"); keys = registry.getAllKeys(); @@ -122,20 +122,20 @@ TEST_F(RegistryTest, GetAllKeys) { // 值操作测试 TEST_F(RegistryTest, SetAndGetValue) { // 设置一个普通值 - EXPECT_EQ(registry.setValue(testKeyPath, testValueName, testValueData), + EXPECT_EQ(registry.setValue(testKeyPath, testValueName, testValueData), RegistryResult::SUCCESS); - + // 获取该值 auto value = registry.getValue(testKeyPath, testValueName); EXPECT_TRUE(value.has_value()); EXPECT_EQ(value.value(), testValueData); - + // 设置不存在键的值 - EXPECT_EQ(registry.setValue("NonExistentKey", testValueName, testValueData), + EXPECT_EQ(registry.setValue("NonExistentKey", testValueName, testValueData), RegistryResult::KEY_NOT_FOUND); - + // 用空值覆盖现有值 - EXPECT_EQ(registry.setValue(testKeyPath, testValueName, ""), + EXPECT_EQ(registry.setValue(testKeyPath, testValueName, ""), RegistryResult::SUCCESS); value = registry.getValue(testKeyPath, testValueName); EXPECT_TRUE(value.has_value()); @@ -144,18 +144,18 @@ TEST_F(RegistryTest, SetAndGetValue) { TEST_F(RegistryTest, SetAndGetTypedValue) { // 设置一个带类型的值 - EXPECT_EQ(registry.setTypedValue(testKeyPath, testValueName, testValueData, "string"), + EXPECT_EQ(registry.setTypedValue(testKeyPath, testValueName, testValueData, "string"), RegistryResult::SUCCESS); - + // 获取该值及其类型 std::string type; auto value = registry.getTypedValue(testKeyPath, testValueName, type); EXPECT_TRUE(value.has_value()); EXPECT_EQ(value.value(), testValueData); EXPECT_EQ(type, "string"); - + // 设置不同类型的值 - EXPECT_EQ(registry.setTypedValue(testKeyPath, "IntValue", "42", "int"), + EXPECT_EQ(registry.setTypedValue(testKeyPath, "IntValue", "42", "int"), RegistryResult::SUCCESS); value = registry.getTypedValue(testKeyPath, "IntValue", type); EXPECT_TRUE(value.has_value()); @@ -165,35 +165,35 @@ TEST_F(RegistryTest, SetAndGetTypedValue) { TEST_F(RegistryTest, DeleteValue) { // 设置一个值然后删除它 - ASSERT_EQ(registry.setValue(testKeyPath, testValueName, testValueData), + ASSERT_EQ(registry.setValue(testKeyPath, testValueName, testValueData), RegistryResult::SUCCESS); EXPECT_TRUE(registry.valueExists(testKeyPath, testValueName)); - - EXPECT_EQ(registry.deleteValue(testKeyPath, testValueName), + + EXPECT_EQ(registry.deleteValue(testKeyPath, testValueName), RegistryResult::SUCCESS); EXPECT_FALSE(registry.valueExists(testKeyPath, testValueName)); - + // 删除不存在的值 - EXPECT_EQ(registry.deleteValue(testKeyPath, "NonExistentValue"), + EXPECT_EQ(registry.deleteValue(testKeyPath, "NonExistentValue"), RegistryResult::VALUE_NOT_FOUND); - + // 从不存在的键中删除值 - EXPECT_EQ(registry.deleteValue("NonExistentKey", testValueName), + EXPECT_EQ(registry.deleteValue("NonExistentKey", testValueName), RegistryResult::KEY_NOT_FOUND); } TEST_F(RegistryTest, ValueExists) { // 检查不存在的值 EXPECT_FALSE(registry.valueExists(testKeyPath, testValueName)); - + // 设置值 registry.setValue(testKeyPath, testValueName, testValueData); EXPECT_TRUE(registry.valueExists(testKeyPath, testValueName)); - + // 删除值后再检查 registry.deleteValue(testKeyPath, testValueName); EXPECT_FALSE(registry.valueExists(testKeyPath, testValueName)); - + // 检查不存在键中的值 EXPECT_FALSE(registry.valueExists("NonExistentKey", testValueName)); } @@ -203,22 +203,22 @@ TEST_F(RegistryTest, GetValueNames) { registry.setValue(testKeyPath, "Value1", "Data1"); registry.setValue(testKeyPath, "Value2", "Data2"); registry.setValue(testKeyPath, "Value3", "Data3"); - + // 获取值名 auto valueNames = registry.getValueNames(testKeyPath); - + // 验证结果 EXPECT_THAT(valueNames, testing::Contains("Value1")); EXPECT_THAT(valueNames, testing::Contains("Value2")); EXPECT_THAT(valueNames, testing::Contains("Value3")); EXPECT_EQ(valueNames.size(), 3); - + // 删除一个值后再检查 registry.deleteValue(testKeyPath, "Value2"); valueNames = registry.getValueNames(testKeyPath); EXPECT_THAT(valueNames, testing::Not(testing::Contains("Value2"))); EXPECT_EQ(valueNames.size(), 2); - + // 检查不存在键的值名 valueNames = registry.getValueNames("NonExistentKey"); EXPECT_TRUE(valueNames.empty()); @@ -227,9 +227,9 @@ TEST_F(RegistryTest, GetValueNames) { TEST_F(RegistryTest, GetValueInfo) { // 设置一个带类型的值 std::string testType = "string"; - ASSERT_EQ(registry.setTypedValue(testKeyPath, testValueName, testValueData, testType), + ASSERT_EQ(registry.setTypedValue(testKeyPath, testValueName, testValueData, testType), RegistryResult::SUCCESS); - + // 获取值信息 auto valueInfo = registry.getValueInfo(testKeyPath, testValueName); EXPECT_TRUE(valueInfo.has_value()); @@ -239,11 +239,11 @@ TEST_F(RegistryTest, GetValueInfo) { // 我们不能严格测试lastModified的具体值,但可以确保它是近期时间 auto now = std::time(nullptr); EXPECT_LE(std::abs(std::difftime(valueInfo->lastModified, now)), 60); // 60秒内 - + // 获取不存在值的信息 valueInfo = registry.getValueInfo(testKeyPath, "NonExistentValue"); EXPECT_FALSE(valueInfo.has_value()); - + // 从不存在的键获取值信息 valueInfo = registry.getValueInfo("NonExistentKey", testValueName); EXPECT_FALSE(valueInfo.has_value()); @@ -252,128 +252,128 @@ TEST_F(RegistryTest, GetValueInfo) { // 文件操作测试 TEST_F(RegistryTest, LoadRegistryFromFile) { // 首先存储一些数据 - ASSERT_EQ(registry.setValue(testKeyPath, testValueName, testValueData), + ASSERT_EQ(registry.setValue(testKeyPath, testValueName, testValueData), RegistryResult::SUCCESS); - + // 获取测试文件路径 auto tempDir = std::filesystem::temp_directory_path(); std::string testFilePath = (tempDir / "test_registry.dat").string(); - + // 创建一个新的注册表实例 Registry newRegistry; - + // 加载文件 - EXPECT_EQ(newRegistry.loadRegistryFromFile(testFilePath), + EXPECT_EQ(newRegistry.loadRegistryFromFile(testFilePath), RegistryResult::SUCCESS); - + // 验证数据已正确加载 EXPECT_TRUE(newRegistry.keyExists(testKeyPath)); auto value = newRegistry.getValue(testKeyPath, testValueName); EXPECT_TRUE(value.has_value()); EXPECT_EQ(value.value(), testValueData); - + // 尝试加载不存在的文件 - EXPECT_EQ(newRegistry.loadRegistryFromFile("non_existent_file.dat"), + EXPECT_EQ(newRegistry.loadRegistryFromFile("non_existent_file.dat"), RegistryResult::FILE_ERROR); } TEST_F(RegistryTest, BackupAndRestoreRegistry) { // 设置测试数据 - ASSERT_EQ(registry.setValue(testKeyPath, testValueName, testValueData), + ASSERT_EQ(registry.setValue(testKeyPath, testValueName, testValueData), RegistryResult::SUCCESS); - + // 备份注册表 - EXPECT_EQ(registry.backupRegistryData(testBackupPath), + EXPECT_EQ(registry.backupRegistryData(testBackupPath), RegistryResult::SUCCESS); EXPECT_TRUE(std::filesystem::exists(testBackupPath)); - + // 修改注册表数据 - ASSERT_EQ(registry.setValue(testKeyPath, testValueName, "ModifiedData"), + ASSERT_EQ(registry.setValue(testKeyPath, testValueName, "ModifiedData"), RegistryResult::SUCCESS); auto value = registry.getValue(testKeyPath, testValueName); EXPECT_EQ(value.value(), "ModifiedData"); - + // 从备份恢复 - EXPECT_EQ(registry.restoreRegistryData(testBackupPath), + EXPECT_EQ(registry.restoreRegistryData(testBackupPath), RegistryResult::SUCCESS); - + // 验证数据已恢复 value = registry.getValue(testKeyPath, testValueName); EXPECT_TRUE(value.has_value()); EXPECT_EQ(value.value(), testValueData); - + // 尝试从不存在的文件恢复 - EXPECT_EQ(registry.restoreRegistryData("non_existent_backup.dat"), + EXPECT_EQ(registry.restoreRegistryData("non_existent_backup.dat"), RegistryResult::FILE_ERROR); } TEST_F(RegistryTest, ExportAndImportRegistry) { // 设置测试数据 - ASSERT_EQ(registry.setValue(testKeyPath, testValueName, testValueData), + ASSERT_EQ(registry.setValue(testKeyPath, testValueName, testValueData), RegistryResult::SUCCESS); - ASSERT_EQ(registry.setValue(testKeyPath, "AnotherValue", "AnotherData"), + ASSERT_EQ(registry.setValue(testKeyPath, "AnotherValue", "AnotherData"), RegistryResult::SUCCESS); - + // 导出为不同格式 for (auto format : {RegistryFormat::TEXT, RegistryFormat::JSON, RegistryFormat::XML}) { // 导出注册表 - EXPECT_EQ(registry.exportRegistry(testExportPath, format), + EXPECT_EQ(registry.exportRegistry(testExportPath, format), RegistryResult::SUCCESS); EXPECT_TRUE(std::filesystem::exists(testExportPath)); - + // 创建新的注册表实例 Registry importedRegistry; - ASSERT_EQ(importedRegistry.initialize(testExportPath + ".import"), + ASSERT_EQ(importedRegistry.initialize(testExportPath + ".import"), RegistryResult::SUCCESS); - + // 导入注册表 - EXPECT_EQ(importedRegistry.importRegistry(testExportPath, format), + EXPECT_EQ(importedRegistry.importRegistry(testExportPath, format), RegistryResult::SUCCESS); - + // 验证数据已正确导入 EXPECT_TRUE(importedRegistry.keyExists(testKeyPath)); auto value = importedRegistry.getValue(testKeyPath, testValueName); EXPECT_TRUE(value.has_value()); EXPECT_EQ(value.value(), testValueData); - + value = importedRegistry.getValue(testKeyPath, "AnotherValue"); EXPECT_TRUE(value.has_value()); EXPECT_EQ(value.value(), "AnotherData"); - + // 删除测试文件 std::filesystem::remove(testExportPath); std::filesystem::remove(testExportPath + ".import"); } - + // 测试导入同时合并现有数据 - ASSERT_EQ(registry.exportRegistry(testExportPath, RegistryFormat::JSON), + ASSERT_EQ(registry.exportRegistry(testExportPath, RegistryFormat::JSON), RegistryResult::SUCCESS); - + // 创建一个带有部分不同数据的新注册表 Registry mergeRegistry; - ASSERT_EQ(mergeRegistry.initialize(testExportPath + ".merge"), + ASSERT_EQ(mergeRegistry.initialize(testExportPath + ".merge"), RegistryResult::SUCCESS); - ASSERT_EQ(mergeRegistry.createKey("UniqueKey"), + ASSERT_EQ(mergeRegistry.createKey("UniqueKey"), RegistryResult::SUCCESS); - ASSERT_EQ(mergeRegistry.setValue("UniqueKey", "UniqueValue", "UniqueData"), + ASSERT_EQ(mergeRegistry.setValue("UniqueKey", "UniqueValue", "UniqueData"), RegistryResult::SUCCESS); - + // 导入并合并 - EXPECT_EQ(mergeRegistry.importRegistry(testExportPath, RegistryFormat::JSON, true), + EXPECT_EQ(mergeRegistry.importRegistry(testExportPath, RegistryFormat::JSON, true), RegistryResult::SUCCESS); - + // 验证原数据和导入的数据都存在 EXPECT_TRUE(mergeRegistry.keyExists("UniqueKey")); EXPECT_TRUE(mergeRegistry.keyExists(testKeyPath)); - + auto value = mergeRegistry.getValue("UniqueKey", "UniqueValue"); EXPECT_TRUE(value.has_value()); EXPECT_EQ(value.value(), "UniqueData"); - + value = mergeRegistry.getValue(testKeyPath, testValueName); EXPECT_TRUE(value.has_value()); EXPECT_EQ(value.value(), testValueData); - + // 删除测试文件 std::filesystem::remove(testExportPath); std::filesystem::remove(testExportPath + ".merge"); @@ -386,20 +386,20 @@ TEST_F(RegistryTest, SearchKeys) { registry.createKey("SearchTest/Key2"); registry.createKey("SearchTest/SubDir/Key3"); registry.createKey("DifferentPath/Key4"); - + // 使用模式搜索键 auto results = registry.searchKeys("SearchTest/*"); EXPECT_EQ(results.size(), 3); EXPECT_THAT(results, testing::Contains("SearchTest/Key1")); EXPECT_THAT(results, testing::Contains("SearchTest/Key2")); EXPECT_THAT(results, testing::Contains("SearchTest/SubDir/Key3")); - + // 使用更具体的模式 results = registry.searchKeys("SearchTest/Key*"); EXPECT_EQ(results.size(), 2); EXPECT_THAT(results, testing::Contains("SearchTest/Key1")); EXPECT_THAT(results, testing::Contains("SearchTest/Key2")); - + // 使用不匹配任何内容的模式 results = registry.searchKeys("NonExistent*"); EXPECT_TRUE(results.empty()); @@ -411,11 +411,11 @@ TEST_F(RegistryTest, SearchValues) { registry.setValue("SearchTest/Key2", "Value2", "DifferentContent"); registry.setValue("SearchTest/Key3", "Value3", "SearchableContentWithMore"); registry.setValue("DifferentPath/Key4", "Value4", "SearchableContent"); - + // 搜索特定内容的值 auto results = registry.searchValues("Searchable"); EXPECT_EQ(results.size(), 3); - + // 验证结果包含正确的键值对 bool foundKey1 = false, foundKey3 = false, foundKey4 = false; for (const auto& [key, value] : results) { @@ -430,11 +430,11 @@ TEST_F(RegistryTest, SearchValues) { EXPECT_TRUE(foundKey1); EXPECT_TRUE(foundKey3); EXPECT_TRUE(foundKey4); - + // 使用更具体的模式 results = registry.searchValues("SearchableContent$"); EXPECT_EQ(results.size(), 2); - + // 使用不匹配任何内容的模式 results = registry.searchValues("NonExistentPattern"); EXPECT_TRUE(results.empty()); @@ -444,7 +444,7 @@ TEST_F(RegistryTest, SearchValues) { TEST_F(RegistryTest, EventCallbacks) { bool callbackFired = false; std::string callbackKey, callbackValue; - + // 注册回调 size_t callbackId = registry.registerEventCallback( [&callbackFired, &callbackKey, &callbackValue](const std::string& key, const std::string& value) { @@ -452,25 +452,25 @@ TEST_F(RegistryTest, EventCallbacks) { callbackKey = key; callbackValue = value; }); - + // 触发回调 registry.setValue(testKeyPath, testValueName, testValueData); - + // 验证回调被调用 EXPECT_TRUE(callbackFired); EXPECT_EQ(callbackKey, testKeyPath); EXPECT_EQ(callbackValue, testValueName); - + // 重置标志 callbackFired = false; - + // 取消注册回调 EXPECT_TRUE(registry.unregisterEventCallback(callbackId)); - + // 确认回调不再被触发 registry.setValue(testKeyPath, "NewValue", "NewData"); EXPECT_FALSE(callbackFired); - + // 尝试取消注册不存在的回调 EXPECT_FALSE(registry.unregisterEventCallback(99999)); } @@ -479,34 +479,34 @@ TEST_F(RegistryTest, EventCallbacks) { TEST_F(RegistryTest, Transactions) { // 开始事务 EXPECT_TRUE(registry.beginTransaction()); - + // 在事务中进行一些更改 registry.setValue(testKeyPath, "TransactionValue1", "Data1"); registry.setValue(testKeyPath, "TransactionValue2", "Data2"); registry.createKey("TransactionKey"); - + // 回滚事务 EXPECT_EQ(registry.rollbackTransaction(), RegistryResult::SUCCESS); - + // 验证更改已被撤销 EXPECT_FALSE(registry.valueExists(testKeyPath, "TransactionValue1")); EXPECT_FALSE(registry.valueExists(testKeyPath, "TransactionValue2")); EXPECT_FALSE(registry.keyExists("TransactionKey")); - + // 再次开始事务 EXPECT_TRUE(registry.beginTransaction()); - + // 进行一些更改 registry.setValue(testKeyPath, "CommitValue", "CommitData"); registry.createKey("CommitKey"); - + // 提交事务 EXPECT_EQ(registry.commitTransaction(), RegistryResult::SUCCESS); - + // 验证更改已被保存 EXPECT_TRUE(registry.valueExists(testKeyPath, "CommitValue")); EXPECT_TRUE(registry.keyExists("CommitKey")); - + // 尝试在没有活动事务的情况下回滚 EXPECT_EQ(registry.rollbackTransaction(), RegistryResult::UNKNOWN_ERROR); } @@ -515,40 +515,40 @@ TEST_F(RegistryTest, Transactions) { TEST_F(RegistryTest, AutoSave) { // 设置自动保存 registry.setAutoSave(true); - + // 进行更改 registry.setValue(testKeyPath, "AutoSaveValue", "AutoSaveData"); - + // 创建新的注册表实例 Registry newRegistry; - + // 获取测试文件路径 auto tempDir = std::filesystem::temp_directory_path(); std::string testFilePath = (tempDir / "test_registry.dat").string(); - + // 尝试加载文件,验证数据是否已自动保存 - EXPECT_EQ(newRegistry.loadRegistryFromFile(testFilePath), + EXPECT_EQ(newRegistry.loadRegistryFromFile(testFilePath), RegistryResult::SUCCESS); - + // 验证数据已保存 EXPECT_TRUE(newRegistry.valueExists(testKeyPath, "AutoSaveValue")); auto value = newRegistry.getValue(testKeyPath, "AutoSaveValue"); EXPECT_TRUE(value.has_value()); EXPECT_EQ(value.value(), "AutoSaveData"); - + // 禁用自动保存 registry.setAutoSave(false); - + // 进行新的更改 registry.setValue(testKeyPath, "ManualSaveValue", "ManualSaveData"); - + // 创建另一个新的注册表实例 Registry anotherRegistry; - + // 加载文件 - EXPECT_EQ(anotherRegistry.loadRegistryFromFile(testFilePath), + EXPECT_EQ(anotherRegistry.loadRegistryFromFile(testFilePath), RegistryResult::SUCCESS); - + // 验证新更改未自动保存 EXPECT_FALSE(anotherRegistry.valueExists(testKeyPath, "ManualSaveValue")); } @@ -556,16 +556,16 @@ TEST_F(RegistryTest, AutoSave) { // 错误处理测试 TEST_F(RegistryTest, ErrorHandling) { // 尝试执行一个会失败的操作 - EXPECT_EQ(registry.setValue("NonExistentKey", testValueName, testValueData), + EXPECT_EQ(registry.setValue("NonExistentKey", testValueName, testValueData), RegistryResult::KEY_NOT_FOUND); - + // 获取上次操作的错误信息 std::string errorMsg = registry.getLastError(); EXPECT_FALSE(errorMsg.empty()); EXPECT_THAT(errorMsg, testing::HasSubstr("KEY_NOT_FOUND")); - + // 执行成功的操作后,错误信息应该被清除或更新 - EXPECT_EQ(registry.setValue(testKeyPath, testValueName, testValueData), + EXPECT_EQ(registry.setValue(testKeyPath, testValueName, testValueData), RegistryResult::SUCCESS); errorMsg = registry.getLastError(); EXPECT_TRUE(errorMsg.empty() || errorMsg.find("SUCCESS") != std::string::npos); @@ -575,46 +575,46 @@ TEST_F(RegistryTest, ErrorHandling) { TEST_F(RegistryTest, ThreadSafety) { const int numThreads = 5; const int operationsPerThread = 100; - + std::vector threads; - + // 启动多个线程同时读写注册表 for (int t = 0; t < numThreads; ++t) { threads.emplace_back([&, t]() { std::string threadKeyPath = "ThreadTest/Thread" + std::to_string(t); registry.createKey(threadKeyPath); - + for (int i = 0; i < operationsPerThread; ++i) { std::string valueName = "Value" + std::to_string(i); std::string valueData = "Data" + std::to_string(i) + "_" + std::to_string(t); - + registry.setValue(threadKeyPath, valueName, valueData); - + auto value = registry.getValue(threadKeyPath, valueName); if (value.has_value()) { EXPECT_EQ(value.value(), valueData); } - + if (i % 10 == 0) { registry.deleteValue(threadKeyPath, "Value" + std::to_string(i / 10)); } } }); } - + // 等待所有线程完成 for (auto& thread : threads) { thread.join(); } - + // 验证结果 for (int t = 0; t < numThreads; ++t) { std::string threadKeyPath = "ThreadTest/Thread" + std::to_string(t); EXPECT_TRUE(registry.keyExists(threadKeyPath)); - + auto valueNames = registry.getValueNames(threadKeyPath); EXPECT_FALSE(valueNames.empty()); - + // 验证一些随机值 for (int i = operationsPerThread - 5; i < operationsPerThread; ++i) { std::string valueName = "Value" + std::to_string(i); @@ -632,35 +632,35 @@ TEST_F(RegistryTest, ThreadSafety) { TEST_F(RegistryTest, DISABLED_PerformanceTest) { const int numKeys = 1000; const int valuesPerKey = 10; - + auto start = std::chrono::high_resolution_clock::now(); - + // 创建大量键和值 for (int i = 0; i < numKeys; ++i) { std::string keyPath = "PerfTest/Key" + std::to_string(i); registry.createKey(keyPath); - + for (int j = 0; j < valuesPerKey; ++j) { std::string valueName = "Value" + std::to_string(j); std::string valueData = "Data" + std::to_string(i) + "_" + std::to_string(j); registry.setValue(keyPath, valueName, valueData); } } - + auto createEnd = std::chrono::high_resolution_clock::now(); auto createDuration = std::chrono::duration_cast( createEnd - start).count(); - - std::cout << "Created " << numKeys << " keys with " << valuesPerKey + + std::cout << "Created " << numKeys << " keys with " << valuesPerKey << " values each in " << createDuration << "ms" << std::endl; - + // 读取所有值 int readCount = 0; start = std::chrono::high_resolution_clock::now(); - + for (int i = 0; i < numKeys; ++i) { std::string keyPath = "PerfTest/Key" + std::to_string(i); - + for (int j = 0; j < valuesPerKey; ++j) { std::string valueName = "Value" + std::to_string(j); auto value = registry.getValue(keyPath, valueName); @@ -669,20 +669,20 @@ TEST_F(RegistryTest, DISABLED_PerformanceTest) { } } } - + auto readEnd = std::chrono::high_resolution_clock::now(); auto readDuration = std::chrono::duration_cast( readEnd - start).count(); - + std::cout << "Read " << readCount << " values in " << readDuration << "ms" << std::endl; - + // 验证读取的数量正确 EXPECT_EQ(readCount, numKeys * valuesPerKey); - + // 输出每秒操作数 double createOpsPerSecond = (double)(numKeys * valuesPerKey) / ((double)createDuration / 1000.0); double readOpsPerSecond = (double)readCount / ((double)readDuration / 1000.0); - + std::cout << "Create operations per second: " << createOpsPerSecond << std::endl; std::cout << "Read operations per second: " << readOpsPerSecond << std::endl; } @@ -693,35 +693,35 @@ TEST_F(RegistryTest, EdgeCases) { std::string longKeyPath(1000, 'a'); EXPECT_EQ(registry.createKey(longKeyPath), RegistryResult::SUCCESS); EXPECT_TRUE(registry.keyExists(longKeyPath)); - + // 非常长的值名称 std::string longValueName(1000, 'b'); - EXPECT_EQ(registry.setValue(testKeyPath, longValueName, "TestData"), + EXPECT_EQ(registry.setValue(testKeyPath, longValueName, "TestData"), RegistryResult::SUCCESS); EXPECT_TRUE(registry.valueExists(testKeyPath, longValueName)); - + // 非常长的值数据 std::string longValueData(10000, 'c'); - EXPECT_EQ(registry.setValue(testKeyPath, "LongDataValue", longValueData), + EXPECT_EQ(registry.setValue(testKeyPath, "LongDataValue", longValueData), RegistryResult::SUCCESS); auto value = registry.getValue(testKeyPath, "LongDataValue"); EXPECT_TRUE(value.has_value()); EXPECT_EQ(value.value(), longValueData); - + // 空键路径 EXPECT_EQ(registry.createKey(""), RegistryResult::INVALID_FORMAT); - + // 空值名称 - EXPECT_EQ(registry.setValue(testKeyPath, "", "EmptyNameData"), + EXPECT_EQ(registry.setValue(testKeyPath, "", "EmptyNameData"), RegistryResult::INVALID_FORMAT); - + // 嵌套级别非常深的键 std::string deepKeyPath; for (int i = 0; i < 100; ++i) { deepKeyPath += "Level" + std::to_string(i) + "/"; } deepKeyPath += "FinalKey"; - + EXPECT_EQ(registry.createKey(deepKeyPath), RegistryResult::SUCCESS); EXPECT_TRUE(registry.keyExists(deepKeyPath)); } @@ -730,38 +730,38 @@ TEST_F(RegistryTest, EdgeCases) { TEST_F(RegistryTest, Encryption) { // 初始化一个新的带加密的注册表 Registry encryptedRegistry; - + auto tempDir = std::filesystem::temp_directory_path(); std::string encryptedFilePath = (tempDir / "encrypted_registry.dat").string(); - - EXPECT_EQ(encryptedRegistry.initialize(encryptedFilePath, true), + + EXPECT_EQ(encryptedRegistry.initialize(encryptedFilePath, true), RegistryResult::SUCCESS); - + // 设置一些数据 EXPECT_EQ(encryptedRegistry.createKey("EncryptedKey"), RegistryResult::SUCCESS); - EXPECT_EQ(encryptedRegistry.setValue("EncryptedKey", "SecretValue", "SecretData"), + EXPECT_EQ(encryptedRegistry.setValue("EncryptedKey", "SecretValue", "SecretData"), RegistryResult::SUCCESS); - + // 确保数据已正确存储 auto value = encryptedRegistry.getValue("EncryptedKey", "SecretValue"); EXPECT_TRUE(value.has_value()); EXPECT_EQ(value.value(), "SecretData"); - + // 检查文件是否存在 EXPECT_TRUE(std::filesystem::exists(encryptedFilePath)); - + // 尝试不用加密打开加密的文件(应该会失败或者读取数据错误) Registry nonEncryptedRegistry; - EXPECT_EQ(nonEncryptedRegistry.initialize(encryptedFilePath, false), + EXPECT_EQ(nonEncryptedRegistry.initialize(encryptedFilePath, false), RegistryResult::SUCCESS); - + // 尝试读取数据,这可能成功或失败,取决于实现 // 但即使成功,也不应该匹配原始数据 auto attemptedValue = nonEncryptedRegistry.getValue("EncryptedKey", "SecretValue"); if (attemptedValue.has_value()) { EXPECT_NE(attemptedValue.value(), "SecretData"); } - + // 清理 std::filesystem::remove(encryptedFilePath); -} \ No newline at end of file +} diff --git a/tests/system/test_network_manager.hpp b/tests/system/test_network_manager.hpp index fd09d6de..eab1d90c 100644 --- a/tests/system/test_network_manager.hpp +++ b/tests/system/test_network_manager.hpp @@ -23,7 +23,7 @@ class NetworkManagerTest : public ::testing::Test { // Get a list of network interfaces for testing interfaces = manager->getNetworkInterfaces(); - + // If we have at least one interface, save its name for tests if (!interfaces.empty()) { test_interface_name = interfaces[0].getName(); @@ -47,7 +47,7 @@ class NetworkManagerTest : public ::testing::Test { // Helper method: wait for a condition to be true template - bool wait_for_condition(Func condition, + bool wait_for_condition(Func condition, std::chrono::milliseconds timeout = 5s) { auto start = std::chrono::steady_clock::now(); while (!condition()) { @@ -85,7 +85,7 @@ TEST_F(NetworkManagerTest, NetworkInterfaceBasics) { ASSERT_FALSE(mutable_addresses.empty()); std::string original_address = mutable_addresses[0]; mutable_addresses[0] = "10.0.0.1"; - + EXPECT_EQ(interface.getAddresses()[0], "10.0.0.1"); EXPECT_NE(interface.getAddresses()[0], original_address); } @@ -100,7 +100,7 @@ TEST_F(NetworkManagerTest, ConstructorDefault) { // Test getting network interfaces TEST_F(NetworkManagerTest, GetNetworkInterfaces) { auto interfaces = manager->getNetworkInterfaces(); - + // We should get at least one interface on most systems EXPECT_FALSE(interfaces.empty()); @@ -108,7 +108,7 @@ TEST_F(NetworkManagerTest, GetNetworkInterfaces) { for (const auto& interface : interfaces) { EXPECT_FALSE(interface.getName().empty()); EXPECT_FALSE(interface.getMac().empty()); - + // An interface may not have addresses, but if it does they should be valid for (const auto& address : interface.getAddresses()) { EXPECT_FALSE(address.empty()); @@ -128,10 +128,10 @@ TEST_F(NetworkManagerTest, EnableDisableInterface) { // Just verify the methods don't throw exceptions EXPECT_NO_THROW(NetworkManager::enableInterface(test_interface_name)); std::this_thread::sleep_for(wait_time); - + EXPECT_NO_THROW(NetworkManager::disableInterface(test_interface_name)); std::this_thread::sleep_for(wait_time); - + // Re-enable for good measure EXPECT_NO_THROW(NetworkManager::enableInterface(test_interface_name)); } @@ -140,10 +140,10 @@ TEST_F(NetworkManagerTest, EnableDisableInterface) { TEST_F(NetworkManagerTest, ResolveDNS) { // Try to resolve a common hostname std::string ip = NetworkManager::resolveDNS(test_hostname); - + // Verify we got a non-empty result EXPECT_FALSE(ip.empty()); - + // Check that it looks like an IPv4 or IPv6 address bool valid_format = ip.find('.') != std::string::npos || ip.find(':') != std::string::npos; EXPECT_TRUE(valid_format); @@ -153,7 +153,7 @@ TEST_F(NetworkManagerTest, ResolveDNS) { TEST_F(NetworkManagerTest, MonitorConnectionStatus) { // Since this starts a background task, we just verify it doesn't throw EXPECT_NO_THROW(manager->monitorConnectionStatus()); - + // Give it some time to run std::this_thread::sleep_for(300ms); } @@ -164,10 +164,10 @@ TEST_F(NetworkManagerTest, GetInterfaceStatus) { if (interfaces.empty()) { GTEST_SKIP() << "No network interfaces found for testing"; } - + // Get status of an interface std::string status = manager->getInterfaceStatus(test_interface_name); - + // Status should not be empty EXPECT_FALSE(status.empty()); } @@ -176,25 +176,25 @@ TEST_F(NetworkManagerTest, GetInterfaceStatus) { TEST_F(NetworkManagerTest, DNSServerManagement) { // Get current DNS servers auto original_dns = NetworkManager::getDNSServers(); - + // Add a test DNS server std::string test_dns = "8.8.8.8"; NetworkManager::addDNSServer(test_dns); - + // Get updated DNS servers auto updated_dns = NetworkManager::getDNSServers(); - + // The list may have changed but we can't always verify the exact content // as it may require admin privileges to actually change DNS settings - + // Try to restore original settings NetworkManager::setDNSServers(original_dns); - + // Try to remove a DNS server if (!updated_dns.empty()) { NetworkManager::removeDNSServer(updated_dns[0]); } - + // These tests mainly check that the methods don't throw exceptions SUCCEED(); } @@ -203,20 +203,20 @@ TEST_F(NetworkManagerTest, DNSServerManagement) { TEST_F(NetworkManagerTest, GetMacAddress) { // This test accesses a private method, so we can't directly test it // We can indirectly test it through the NetworkInterface objects - + // Skip if no interfaces if (interfaces.empty()) { GTEST_SKIP() << "No network interfaces found for testing"; } - + // Check that all interfaces have a MAC address for (const auto& interface : interfaces) { EXPECT_FALSE(interface.getMac().empty()); - + // Verify MAC address format (XX:XX:XX:XX:XX:XX) std::string mac = interface.getMac(); EXPECT_EQ(17, mac.length()); // 6 pairs of 2 hex digits + 5 colons - + int colon_count = 0; for (char c : mac) { if (c == ':') colon_count++; @@ -231,7 +231,7 @@ TEST_F(NetworkManagerTest, IsInterfaceUp) { if (interfaces.empty()) { GTEST_SKIP() << "No network interfaces found for testing"; } - + // We know each interface has an isUp method, so we can test it for (const auto& interface : interfaces) { // Just verify that we can get a status - can't predict what it should be @@ -243,19 +243,19 @@ TEST_F(NetworkManagerTest, IsInterfaceUp) { // Test getting network connections for a process TEST_F(NetworkManagerTest, GetNetworkConnections) { // Use the current process ID or a known process - int pid = + int pid = #ifdef _WIN32 4; // System process on Windows often has network connections #else 1; // Init process on Unix-like systems #endif - + // Get connections for the process auto connections = getNetworkConnections(pid); - + // We can't predict if there will be connections, but we can verify the method runs SUCCEED(); - + // If there are connections, check they have valid data for (const auto& conn : connections) { EXPECT_FALSE(conn.protocol.empty()); @@ -269,11 +269,11 @@ TEST_F(NetworkManagerTest, GetNetworkConnections) { // Test with invalid interface name TEST_F(NetworkManagerTest, InvalidInterfaceName) { std::string invalid_name = "nonexistent_interface_xyz"; - + // Test interface status for non-existent interface std::string status = manager->getInterfaceStatus(invalid_name); EXPECT_FALSE(status.empty()); // Should return some kind of error status - + // Test enable/disable with invalid interface // Should not throw, but probably won't succeed EXPECT_NO_THROW(NetworkManager::enableInterface(invalid_name)); @@ -283,7 +283,7 @@ TEST_F(NetworkManagerTest, InvalidInterfaceName) { // Test DNS resolution with invalid hostname TEST_F(NetworkManagerTest, InvalidHostname) { std::string invalid_hostname = "thishostnamedoesnotexist.example.xyz"; - + // Resolving non-existent hostname should either return empty string, // an error message, or throw an exception that we can catch try { @@ -301,11 +301,11 @@ TEST_F(NetworkManagerTest, ConcurrentAccess) { if (interfaces.empty()) { GTEST_SKIP() << "No network interfaces found for testing"; } - + // Create multiple threads to access NetworkManager simultaneously const int num_threads = 5; std::vector> futures; - + for (int i = 0; i < num_threads; ++i) { futures.push_back(std::async(std::launch::async, [this, i]() { for (int j = 0; j < 10; ++j) { @@ -324,12 +324,12 @@ TEST_F(NetworkManagerTest, ConcurrentAccess) { } })); } - + // Wait for all threads to finish for (auto& future : futures) { future.wait(); } - + // If we got here without crashes or exceptions, the test passed SUCCEED(); } @@ -337,25 +337,25 @@ TEST_F(NetworkManagerTest, ConcurrentAccess) { // Test with network stress TEST_F(NetworkManagerTest, DISABLED_NetworkStress) { // This is a potentially intensive test, so it's disabled by default - + // Rapidly get network interfaces and other info const int iterations = 100; - + for (int i = 0; i < iterations; ++i) { auto interfaces = manager->getNetworkInterfaces(); for (const auto& interface : interfaces) { manager->getInterfaceStatus(interface.getName()); } - + auto dns_servers = NetworkManager::getDNSServers(); NetworkManager::resolveDNS(test_hostname); - + if (i % 10 == 0) { // Every 10 iterations, output progress std::cout << "Network stress test progress: " << i << "/" << iterations << std::endl; } } - + // If we got here without errors, the test passed SUCCEED(); } @@ -364,15 +364,15 @@ TEST_F(NetworkManagerTest, DISABLED_NetworkStress) { // This is difficult to fully automate as it requires changing network state TEST_F(NetworkManagerTest, DISABLED_NetworkStateChanges) { // This test is disabled as it would require manual intervention - + std::cout << "This test requires manually changing network state:" << std::endl; std::cout << "1. Run the test" << std::endl; std::cout << "2. Manually disable/enable network interfaces or connections" << std::endl; std::cout << "3. The test will check for appropriate state changes" << std::endl; - + // Start monitoring connection status manager->monitorConnectionStatus(); - + // Monitor for 30 seconds, periodically checking interface status const int check_intervals = 30; for (int i = 0; i < check_intervals; ++i) { @@ -381,10 +381,10 @@ TEST_F(NetworkManagerTest, DISABLED_NetworkStateChanges) { std::string status = manager->getInterfaceStatus(interface.getName()); std::cout << "Interface " << interface.getName() << " status: " << status << std::endl; } - + std::this_thread::sleep_for(1s); } - + // If we got here without crashes, the test passed SUCCEED(); } @@ -393,4 +393,4 @@ TEST_F(NetworkManagerTest, DISABLED_NetworkStateChanges) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/tests/system/test_pidwatcher.hpp b/tests/system/test_pidwatcher.hpp index 455ab533..4e7df9cd 100644 --- a/tests/system/test_pidwatcher.hpp +++ b/tests/system/test_pidwatcher.hpp @@ -769,4 +769,4 @@ TEST_F(PidWatcherTest, DISABLED_LoadTest) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/tests/system/test_stat.hpp b/tests/system/test_stat.hpp index fdc2546e..e5747065 100644 --- a/tests/system/test_stat.hpp +++ b/tests/system/test_stat.hpp @@ -491,4 +491,4 @@ TEST_F(StatTest, FormatTimeEdgeCases) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/tests/system/test_voltage.cpp b/tests/system/test_voltage.cpp index 90a00af1..763ccb32 100644 --- a/tests/system/test_voltage.cpp +++ b/tests/system/test_voltage.cpp @@ -33,20 +33,20 @@ class VoltageMonitorTest : public ::testing::Test { void SetUp() override { // Create a real voltage monitor realMonitor = VoltageMonitor::create(); - + // Create a mock voltage monitor for controlled tests mockMonitor = std::make_unique<::testing::NiceMock>(); // Set up default behavior for the mock ON_CALL(*mockMonitor, getPlatformName()) .WillByDefault(::testing::Return("MockPlatform")); - + ON_CALL(*mockMonitor, getInputVoltage()) .WillByDefault(::testing::Return(std::optional(220.0))); - + ON_CALL(*mockMonitor, getBatteryVoltage()) .WillByDefault(::testing::Return(std::optional(12.0))); - + ON_CALL(*mockMonitor, getAllPowerSources()) .WillByDefault(::testing::Return(createSamplePowerSources())); } @@ -59,7 +59,7 @@ class VoltageMonitorTest : public ::testing::Test { // Helper method to create sample power sources for testing std::vector createSamplePowerSources() { std::vector sources; - + // Create an AC power source PowerSourceInfo acSource; acSource.name = "Test AC Adapter"; @@ -67,7 +67,7 @@ class VoltageMonitorTest : public ::testing::Test { acSource.voltage = 220.0; acSource.current = 1.5; sources.push_back(acSource); - + // Create a battery power source PowerSourceInfo batterySource; batterySource.name = "Test Battery"; @@ -77,7 +77,7 @@ class VoltageMonitorTest : public ::testing::Test { batterySource.chargePercent = 75; batterySource.isCharging = true; sources.push_back(batterySource); - + // Create a USB power source PowerSourceInfo usbSource; usbSource.name = "Test USB"; @@ -85,7 +85,7 @@ class VoltageMonitorTest : public ::testing::Test { usbSource.voltage = 5.0; usbSource.current = 0.5; sources.push_back(usbSource); - + return sources; } @@ -97,14 +97,14 @@ class VoltageMonitorTest : public ::testing::Test { TEST_F(VoltageMonitorTest, Create) { auto monitor = VoltageMonitor::create(); ASSERT_NE(monitor, nullptr); - + // Check that the platform name is not empty EXPECT_FALSE(monitor->getPlatformName().empty()); - + // Platform name should be Windows, Linux, or MacOS std::string platform = monitor->getPlatformName(); - bool validPlatform = (platform == "Windows" || - platform == "Linux" || + bool validPlatform = (platform == "Windows" || + platform == "Linux" || platform == "MacOS"); EXPECT_TRUE(validPlatform); } @@ -119,9 +119,9 @@ TEST_F(VoltageMonitorTest, PowerSourceInfoToString) { info.current = 1.2; info.chargePercent = 80; info.isCharging = true; - + std::string infoStr = info.toString(); - + // Verify all information is included in the string EXPECT_TRUE(infoStr.find("Test Source") != std::string::npos); EXPECT_TRUE(infoStr.find("Battery") != std::string::npos); @@ -129,13 +129,13 @@ TEST_F(VoltageMonitorTest, PowerSourceInfoToString) { EXPECT_TRUE(infoStr.find("1.20A") != std::string::npos); EXPECT_TRUE(infoStr.find("80%") != std::string::npos); EXPECT_TRUE(infoStr.find("Charging") != std::string::npos); - + // Now test with some fields missing PowerSourceInfo partialInfo; partialInfo.name = "Partial Info"; partialInfo.type = PowerSourceType::AC; // Missing voltage, current, etc. - + std::string partialStr = partialInfo.toString(); EXPECT_TRUE(partialStr.find("Partial Info") != std::string::npos); EXPECT_TRUE(partialStr.find("AC Power") != std::string::npos); @@ -148,7 +148,7 @@ TEST_F(VoltageMonitorTest, PowerSourceTypeToString) { EXPECT_EQ(powerSourceTypeToString(PowerSourceType::Battery), "Battery"); EXPECT_EQ(powerSourceTypeToString(PowerSourceType::USB), "USB"); EXPECT_EQ(powerSourceTypeToString(PowerSourceType::Unknown), "Unknown"); - + // Test with explicit cast to test default case EXPECT_EQ(powerSourceTypeToString(static_cast(999)), "Undefined"); } @@ -159,7 +159,7 @@ TEST_F(VoltageMonitorTest, GetInputVoltage) { auto voltage = mockMonitor->getInputVoltage(); ASSERT_TRUE(voltage.has_value()); EXPECT_EQ(*voltage, 220.0); - + // Test with the real monitor // Note: This might return nullopt if no AC power is connected auto realVoltage = realMonitor->getInputVoltage(); @@ -178,7 +178,7 @@ TEST_F(VoltageMonitorTest, GetBatteryVoltage) { auto voltage = mockMonitor->getBatteryVoltage(); ASSERT_TRUE(voltage.has_value()); EXPECT_EQ(*voltage, 12.0); - + // Test with the real monitor // Note: This might return nullopt if no battery is present auto realVoltage = realMonitor->getBatteryVoltage(); @@ -196,13 +196,13 @@ TEST_F(VoltageMonitorTest, GetAllPowerSources) { // Using the mock monitor for deterministic testing auto sources = mockMonitor->getAllPowerSources(); ASSERT_EQ(sources.size(), 3); - + // Check first source (AC) EXPECT_EQ(sources[0].name, "Test AC Adapter"); EXPECT_EQ(sources[0].type, PowerSourceType::AC); ASSERT_TRUE(sources[0].voltage.has_value()); EXPECT_EQ(*sources[0].voltage, 220.0); - + // Check second source (Battery) EXPECT_EQ(sources[1].name, "Test Battery"); EXPECT_EQ(sources[1].type, PowerSourceType::Battery); @@ -212,13 +212,13 @@ TEST_F(VoltageMonitorTest, GetAllPowerSources) { EXPECT_EQ(*sources[1].chargePercent, 75); ASSERT_TRUE(sources[1].isCharging.has_value()); EXPECT_TRUE(*sources[1].isCharging); - + // Check third source (USB) EXPECT_EQ(sources[2].name, "Test USB"); EXPECT_EQ(sources[2].type, PowerSourceType::USB); ASSERT_TRUE(sources[2].voltage.has_value()); EXPECT_EQ(*sources[2].voltage, 5.0); - + // Test with the real monitor auto realSources = realMonitor->getAllPowerSources(); // We don't know how many power sources are available on the test system @@ -237,11 +237,11 @@ TEST_F(VoltageMonitorTest, GetAllPowerSources) { TEST_F(VoltageMonitorTest, GetPlatformName) { // Using the mock monitor for deterministic testing EXPECT_EQ(mockMonitor->getPlatformName(), "MockPlatform"); - + // Test with the real monitor std::string platform = realMonitor->getPlatformName(); EXPECT_FALSE(platform.empty()); - + // Platform name should match the current platform #ifdef _WIN32 EXPECT_EQ(platform, "Windows"); @@ -257,7 +257,7 @@ TEST_F(VoltageMonitorTest, GetInputVoltageNullopt) { // Make the mock return nullopt EXPECT_CALL(*mockMonitor, getInputVoltage()) .WillOnce(::testing::Return(std::nullopt)); - + auto voltage = mockMonitor->getInputVoltage(); EXPECT_FALSE(voltage.has_value()); } @@ -267,7 +267,7 @@ TEST_F(VoltageMonitorTest, GetBatteryVoltageNullopt) { // Make the mock return nullopt EXPECT_CALL(*mockMonitor, getBatteryVoltage()) .WillOnce(::testing::Return(std::nullopt)); - + auto voltage = mockMonitor->getBatteryVoltage(); EXPECT_FALSE(voltage.has_value()); } @@ -277,7 +277,7 @@ TEST_F(VoltageMonitorTest, GetAllPowerSourcesEmpty) { // Make the mock return an empty list EXPECT_CALL(*mockMonitor, getAllPowerSources()) .WillOnce(::testing::Return(std::vector())); - + auto sources = mockMonitor->getAllPowerSources(); EXPECT_TRUE(sources.empty()); } @@ -289,10 +289,10 @@ TEST_F(VoltageMonitorTest, GetAllPowerSourcesEmpty) { TEST_F(VoltageMonitorTest, WindowsSpecificTests) { // Check that our real monitor is a WindowsVoltageMonitor EXPECT_EQ(typeid(*realMonitor).name(), typeid(WindowsVoltageMonitor).name()); - + // Test that platform name is correctly reported EXPECT_EQ(realMonitor->getPlatformName(), "Windows"); - + // Additional Windows-specific tests could go here } #elif defined(__linux__) @@ -300,18 +300,18 @@ TEST_F(VoltageMonitorTest, WindowsSpecificTests) { TEST_F(VoltageMonitorTest, LinuxSpecificTests) { // Check that our real monitor is a LinuxVoltageMonitor EXPECT_EQ(typeid(*realMonitor).name(), typeid(LinuxVoltageMonitor).name()); - + // Test that platform name is correctly reported EXPECT_EQ(realMonitor->getPlatformName(), "Linux"); - + // Test LinuxVoltageMonitor specific methods auto* linuxMonitor = dynamic_cast(realMonitor.get()); ASSERT_NE(linuxMonitor, nullptr); - + // Test conversion methods EXPECT_NEAR(LinuxVoltageMonitor::microvoltsToVolts("1000000"), 1.0, 0.001); EXPECT_NEAR(LinuxVoltageMonitor::microampsToAmps("1000000"), 1.0, 0.001); - + // Invalid input should return 0 EXPECT_EQ(LinuxVoltageMonitor::microvoltsToVolts("invalid"), 0.0); EXPECT_EQ(LinuxVoltageMonitor::microampsToAmps("invalid"), 0.0); @@ -326,7 +326,7 @@ TEST_F(VoltageMonitorTest, InvalidPowerSourceType) { info.name = "Invalid Type Test"; // Set an invalid type using a cast info.type = static_cast(999); - + std::string infoStr = info.toString(); EXPECT_TRUE(infoStr.find("Undefined") != std::string::npos); } @@ -336,14 +336,14 @@ TEST_F(VoltageMonitorTest, ExtremeValues) { PowerSourceInfo info; info.name = "Extreme Values Test"; info.type = PowerSourceType::Battery; - + // Very high voltage info.voltage = 1000000.0; // Very high current info.current = 1000000.0; // 100% charge info.chargePercent = 100; - + std::string infoStr = info.toString(); EXPECT_TRUE(infoStr.find("1000000.00V") != std::string::npos); EXPECT_TRUE(infoStr.find("1000000.00A") != std::string::npos); @@ -355,14 +355,14 @@ TEST_F(VoltageMonitorTest, NegativeValues) { PowerSourceInfo info; info.name = "Negative Values Test"; info.type = PowerSourceType::Battery; - + // Negative voltage (shouldn't happen in reality) info.voltage = -12.0; // Negative current (could indicate discharge) info.current = -1.5; // Negative charge percentage (shouldn't happen in reality) info.chargePercent = -10; - + std::string infoStr = info.toString(); EXPECT_TRUE(infoStr.find("-12.00V") != std::string::npos); EXPECT_TRUE(infoStr.find("-1.50A") != std::string::npos); @@ -373,22 +373,22 @@ TEST_F(VoltageMonitorTest, NegativeValues) { TEST_F(VoltageMonitorTest, IntegrationTest) { // Create a new monitor auto monitor = VoltageMonitor::create(); - + // Test platform name std::string platform = monitor->getPlatformName(); EXPECT_FALSE(platform.empty()); - + // Get input voltage auto inputVoltage = monitor->getInputVoltage(); // Don't assert on value, just that it works - + // Get battery voltage auto batteryVoltage = monitor->getBatteryVoltage(); // Don't assert on value, just that it works - + // Get all power sources auto sources = monitor->getAllPowerSources(); - + // Print all source information using toString for (const auto& source : sources) { std::string sourceInfo = source.toString(); @@ -400,20 +400,20 @@ TEST_F(VoltageMonitorTest, IntegrationTest) { TEST_F(VoltageMonitorTest, DISABLED_PerformanceTest) { // Time how long it takes to get power source information const int iterations = 100; - + auto start = std::chrono::high_resolution_clock::now(); - + for (int i = 0; i < iterations; ++i) { auto sources = realMonitor->getAllPowerSources(); } - + auto end = std::chrono::high_resolution_clock::now(); auto duration = std::chrono::duration_cast(end - start).count(); - - std::cout << "Average time to get all power sources: " - << (duration / static_cast(iterations)) + + std::cout << "Average time to get all power sources: " + << (duration / static_cast(iterations)) << " ms" << std::endl; - + // No specific assertion, but it shouldn't take too long } @@ -421,4 +421,4 @@ TEST_F(VoltageMonitorTest, DISABLED_PerformanceTest) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/tests/system/test_wregistry.cpp b/tests/system/test_wregistry.cpp index 74b57bf5..90f5bc40 100644 --- a/tests/system/test_wregistry.cpp +++ b/tests/system/test_wregistry.cpp @@ -448,4 +448,4 @@ TEST(WRegistryTest, NonWindowsPlatform) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/tests/type/test_auto_table.cpp b/tests/type/test_auto_table.cpp index 102fa856..420e9e55 100644 --- a/tests/type/test_auto_table.cpp +++ b/tests/type/test_auto_table.cpp @@ -563,4 +563,4 @@ TEST_F(CountingHashTableTest, DISABLED_PerformanceTest) { SUCCEED() << "Performance test completed"; } -#endif // ATOM_TYPE_TEST_AUTO_TABLE_HPP \ No newline at end of file +#endif // ATOM_TYPE_TEST_AUTO_TABLE_HPP diff --git a/tests/type/test_concurrent_set.hpp b/tests/type/test_concurrent_set.hpp index 6c659f71..643845f8 100644 --- a/tests/type/test_concurrent_set.hpp +++ b/tests/type/test_concurrent_set.hpp @@ -868,4 +868,4 @@ TEST_F(ConcurrentSetTest, FileOperationEdgeCases) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/tests/type/test_expected.cpp b/tests/type/test_expected.cpp index 04363e29..e1a6255a 100644 --- a/tests/type/test_expected.cpp +++ b/tests/type/test_expected.cpp @@ -506,4 +506,4 @@ TEST_F(ExpectedTest, CustomTypes) { EXPECT_EQ(result2.error().error(), "Person is underage"); } -} // namespace \ No newline at end of file +} // namespace diff --git a/tests/type/test_indestructible.hpp b/tests/type/test_indestructible.hpp index d74a3dc7..174e92ff 100644 --- a/tests/type/test_indestructible.hpp +++ b/tests/type/test_indestructible.hpp @@ -415,4 +415,4 @@ TEST_F(IndestructibleTest, DirectStructInit) { EXPECT_EQ(point->x, 30); EXPECT_EQ(point->y, 40); -} \ No newline at end of file +} diff --git a/tests/type/test_iter.hpp b/tests/type/test_iter.hpp index 0f6cc338..55c24086 100644 --- a/tests/type/test_iter.hpp +++ b/tests/type/test_iter.hpp @@ -588,4 +588,4 @@ TEST_F(IteratorTest, DISABLED_LargeContainer) { << " elements" << std::endl; EXPECT_EQ(count, SIZE / 2); -} \ No newline at end of file +} diff --git a/tests/type/test_json-schema.hpp b/tests/type/test_json-schema.hpp index 45a195c6..54ee2b90 100644 --- a/tests/type/test_json-schema.hpp +++ b/tests/type/test_json-schema.hpp @@ -486,4 +486,4 @@ TEST_F(JsonValidatorTest, SchemaDependency) { ASSERT_GE(errors.size(), 1); EXPECT_THAT(errors[0].message, HasSubstr("Missing required field")); EXPECT_THAT(errors[0].message, HasSubstr("security_code")); -} \ No newline at end of file +} diff --git a/tests/type/test_no_offset_ptr.hpp b/tests/type/test_no_offset_ptr.hpp index 38113f97..e172e843 100644 --- a/tests/type/test_no_offset_ptr.hpp +++ b/tests/type/test_no_offset_ptr.hpp @@ -27,13 +27,13 @@ class SimpleTestClass { SimpleTestClass(const SimpleTestClass& other) : value(other.value) { instances++; } - + // 修复未使用的参数警告 SimpleTestClass(SimpleTestClass&& other) noexcept : value(other.value) { other.value = 0; instances++; } - + ~SimpleTestClass() { instances--; } private: @@ -394,4 +394,4 @@ TEST(NoOffsetPtrPolicyTest, AtomicPolicy) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/tests/type/test_optional.hpp b/tests/type/test_optional.hpp index 76b612b8..33151d18 100644 --- a/tests/type/test_optional.hpp +++ b/tests/type/test_optional.hpp @@ -541,4 +541,4 @@ TEST(OptionalPerformanceTest, CompareWithStdOptional) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/tests/type/test_pod_vector.cpp b/tests/type/test_pod_vector.cpp index 8a57b4f5..c67d6140 100644 --- a/tests/type/test_pod_vector.cpp +++ b/tests/type/test_pod_vector.cpp @@ -517,4 +517,4 @@ TEST(PodVectorBoostTest, BoostFunctionality) { } // namespace atom::type::test -#endif // ATOM_TYPE_TEST_POD_VECTOR_HPP \ No newline at end of file +#endif // ATOM_TYPE_TEST_POD_VECTOR_HPP diff --git a/tests/type/test_pointer.hpp b/tests/type/test_pointer.hpp index fb55be50..d187a0a0 100644 --- a/tests/type/test_pointer.hpp +++ b/tests/type/test_pointer.hpp @@ -590,4 +590,4 @@ TEST_F(PointerSentinelTest, VoidReturnTypes) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/tests/type/test_rjson.cpp b/tests/type/test_rjson.cpp index 9f6dca6b..65f8604d 100644 --- a/tests/type/test_rjson.cpp +++ b/tests/type/test_rjson.cpp @@ -534,4 +534,4 @@ TEST_F(JsonParserTest, RoundtripComplexStructure) { // Check nested object EXPECT_EQ(value.asObject().at("object").asObject().at("key").asString(), reparsed.asObject().at("object").asObject().at("key").asString()); -} \ No newline at end of file +} diff --git a/tests/type/test_robin_hood.hpp b/tests/type/test_robin_hood.hpp index 4fe8a699..19b23fd4 100644 --- a/tests/type/test_robin_hood.hpp +++ b/tests/type/test_robin_hood.hpp @@ -41,17 +41,17 @@ TEST_F(RobinHoodMapTest, Construction) { unordered_flat_map map1; EXPECT_TRUE(map1.empty()); EXPECT_EQ(map1.size(), 0); - + // Constructor with threading policy unordered_flat_map map2( unordered_flat_map::threading_policy::mutex); EXPECT_TRUE(map2.empty()); - + // Constructor with allocator std::allocator> alloc; unordered_flat_map map3(alloc); EXPECT_TRUE(map3.empty()); - + // Constructor with bucket count and allocator unordered_flat_map map4(16, alloc); EXPECT_TRUE(map4.empty()); @@ -61,18 +61,18 @@ TEST_F(RobinHoodMapTest, Construction) { // Test basic capacity and size operations TEST_F(RobinHoodMapTest, CapacityAndSize) { unordered_flat_map map; - + EXPECT_TRUE(map.empty()); EXPECT_EQ(map.size(), 0); - + // Insert some elements map.insert(1, "one"); EXPECT_FALSE(map.empty()); EXPECT_EQ(map.size(), 1); - + map.insert(2, "two"); EXPECT_EQ(map.size(), 2); - + // Clear the map map.clear(); EXPECT_TRUE(map.empty()); @@ -82,23 +82,23 @@ TEST_F(RobinHoodMapTest, CapacityAndSize) { // Test basic insertion and lookup TEST_F(RobinHoodMapTest, InsertionAndLookup) { unordered_flat_map map; - + // Insert and verify auto [it1, inserted1] = map.insert(1, "one"); EXPECT_TRUE(inserted1); EXPECT_EQ(it1->first, 1); EXPECT_EQ(it1->second, "one"); - + // Lookup with at() EXPECT_EQ(map.at(1), "one"); - + // Check exception for non-existent key EXPECT_THROW(map.at(99), std::out_of_range); - + // Insert multiple elements map.insert(2, "two"); map.insert(3, "three"); - + EXPECT_EQ(map.size(), 3); EXPECT_EQ(map.at(2), "two"); EXPECT_EQ(map.at(3), "three"); @@ -108,7 +108,7 @@ TEST_F(RobinHoodMapTest, InsertionAndLookup) { TEST_F(RobinHoodMapTest, Iterators) { unordered_flat_map map; fill_test_map(map, 10); - + // Count elements using iterators size_t count = 0; for (auto it = map.begin(); it != map.end(); ++it) { @@ -117,7 +117,7 @@ TEST_F(RobinHoodMapTest, Iterators) { EXPECT_TRUE(std::find(test_keys.begin(), test_keys.end(), it->first) != test_keys.end()); } EXPECT_EQ(count, 10); - + // Test const iterators const auto& const_map = map; count = 0; @@ -125,7 +125,7 @@ TEST_F(RobinHoodMapTest, Iterators) { ++count; } EXPECT_EQ(count, 10); - + // Test cbegin/cend count = 0; for (auto it = map.cbegin(); it != map.cend(); ++it) { @@ -137,23 +137,23 @@ TEST_F(RobinHoodMapTest, Iterators) { // Test rehashing and load factor TEST_F(RobinHoodMapTest, RehashingAndLoadFactor) { unordered_flat_map map; - + // Default load factor should be 0.9 EXPECT_FLOAT_EQ(map.max_load_factor(), 0.9f); - + // Change load factor map.max_load_factor(0.75f); EXPECT_FLOAT_EQ(map.max_load_factor(), 0.75f); - + // Insert elements until rehashing occurs size_t initial_bucket_count = map.bucket_count(); if (initial_bucket_count > 0) { size_t elements_to_add = static_cast(initial_bucket_count * map.max_load_factor()) + 1; - + for (size_t i = 0; i < elements_to_add; ++i) { map.insert(static_cast(i), "value-" + std::to_string(i)); } - + // Verify that rehashing occurred EXPECT_GT(map.bucket_count(), initial_bucket_count); } @@ -162,15 +162,15 @@ TEST_F(RobinHoodMapTest, RehashingAndLoadFactor) { // Test with a large number of elements TEST_F(RobinHoodMapTest, LargeNumberOfElements) { unordered_flat_map map; - + // Insert a large number of elements const size_t num_elements = 1000; for (size_t i = 0; i < num_elements; ++i) { map.insert(static_cast(i), "value-" + std::to_string(i)); } - + EXPECT_EQ(map.size(), num_elements); - + // Verify all elements can be found for (size_t i = 0; i < num_elements; ++i) { EXPECT_EQ(map.at(static_cast(i)), "value-" + std::to_string(i)); @@ -181,14 +181,14 @@ TEST_F(RobinHoodMapTest, LargeNumberOfElements) { TEST_F(RobinHoodMapTest, ThreadSafetyWithReaderLocks) { unordered_flat_map map( unordered_flat_map::threading_policy::reader_lock); - + // Fill the map with some test data fill_test_map(map, 100); - + // Create multiple reader threads std::vector threads; std::vector results(10, false); - + for (size_t i = 0; i < 10; ++i) { threads.emplace_back([&map, i, &results]() { try { @@ -208,12 +208,12 @@ TEST_F(RobinHoodMapTest, ThreadSafetyWithReaderLocks) { } }); } - + // Wait for all threads to complete for (auto& thread : threads) { thread.join(); } - + // Verify all threads succeeded for (bool result : results) { EXPECT_TRUE(result); @@ -224,12 +224,12 @@ TEST_F(RobinHoodMapTest, ThreadSafetyWithReaderLocks) { TEST_F(RobinHoodMapTest, ThreadSafetyWithMutex) { unordered_flat_map map( unordered_flat_map::threading_policy::mutex); - + // Multiple threads insert different elements std::vector threads; const int num_threads = 10; const int elements_per_thread = 100; - + for (int i = 0; i < num_threads; ++i) { threads.emplace_back([&map, i, elements_per_thread]() { for (int j = 0; j < elements_per_thread; ++j) { @@ -238,15 +238,15 @@ TEST_F(RobinHoodMapTest, ThreadSafetyWithMutex) { } }); } - + // Wait for all threads to complete for (auto& thread : threads) { thread.join(); } - + // Verify size and all elements EXPECT_EQ(map.size(), static_cast(num_threads * elements_per_thread)); - + for (int i = 0; i < num_threads; ++i) { for (int j = 0; j < elements_per_thread; ++j) { int key = i * elements_per_thread + j; @@ -259,12 +259,12 @@ TEST_F(RobinHoodMapTest, ThreadSafetyWithMutex) { TEST_F(RobinHoodMapTest, ConcurrentReadsAndWrites) { unordered_flat_map map( unordered_flat_map::threading_policy::reader_lock); - + // Fill the map with initial data for (int i = 0; i < 100; ++i) { map.insert(i, "initial-" + std::to_string(i)); } - + // Create reader threads std::vector> reader_results; for (int i = 0; i < 5; ++i) { @@ -274,7 +274,7 @@ TEST_F(RobinHoodMapTest, ConcurrentReadsAndWrites) { for (int j = 0; j < 100; ++j) { try { std::string value = map.at(j); - if (value.find("initial-") == std::string::npos && + if (value.find("initial-") == std::string::npos && value.find("updated-") == std::string::npos) { return false; } @@ -287,7 +287,7 @@ TEST_F(RobinHoodMapTest, ConcurrentReadsAndWrites) { return true; })); } - + // Create writer threads std::vector> writer_results; for (int i = 0; i < 3; ++i) { @@ -304,12 +304,12 @@ TEST_F(RobinHoodMapTest, ConcurrentReadsAndWrites) { return true; })); } - + // Check results from all threads for (auto& result : reader_results) { EXPECT_TRUE(result.get()); } - + for (auto& result : writer_results) { EXPECT_TRUE(result.get()); } @@ -339,17 +339,17 @@ class CustomKeyEqual { TEST_F(RobinHoodMapTest, CustomHashAndKeyEqual) { unordered_flat_map map; - + // Insert with lowercase keys map.insert("one", 1); map.insert("two", 2); map.insert("three", 3); - + // Lookup with mixed case should work with our custom comparator EXPECT_EQ(map.at("ONE"), 1); EXPECT_EQ(map.at("Two"), 2); EXPECT_EQ(map.at("tHrEe"), 3); - + // Size should still be accurate EXPECT_EQ(map.size(), 3); } @@ -358,14 +358,14 @@ TEST_F(RobinHoodMapTest, CustomHashAndKeyEqual) { class MoveOnlyValue { public: explicit MoveOnlyValue(int val) : value(val) {} - + MoveOnlyValue(const MoveOnlyValue&) = delete; MoveOnlyValue& operator=(const MoveOnlyValue&) = delete; - + MoveOnlyValue(MoveOnlyValue&& other) noexcept : value(other.value) { other.value = -1; } - + MoveOnlyValue& operator=(MoveOnlyValue&& other) noexcept { if (this != &other) { value = other.value; @@ -373,20 +373,20 @@ class MoveOnlyValue { } return *this; } - + int get_value() const { return value; } - + private: int value; }; TEST_F(RobinHoodMapTest, MoveOnlyTypes) { unordered_flat_map map; - + // Insert with rvalue map.insert(1, MoveOnlyValue(100)); map.insert(2, MoveOnlyValue(200)); - + // Check values are correctly moved EXPECT_EQ(map.at(1).get_value(), 100); EXPECT_EQ(map.at(2).get_value(), 200); @@ -395,14 +395,14 @@ TEST_F(RobinHoodMapTest, MoveOnlyTypes) { // Test exception safety TEST_F(RobinHoodMapTest, ExceptionSafety) { unordered_flat_map map; - + // Insert some elements fill_test_map(map, 10); - + // Test exceptions from at() method EXPECT_THROW(map.at(999), std::out_of_range); EXPECT_EQ(map.size(), 10); // Size should be unchanged after exception - + // The const version const auto& const_map = map; EXPECT_THROW(const_map.at(999), std::out_of_range); @@ -412,4 +412,4 @@ TEST_F(RobinHoodMapTest, ExceptionSafety) { int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/tests/type/test_rtype.hpp b/tests/type/test_rtype.hpp index a3754f99..c530a85f 100644 --- a/tests/type/test_rtype.hpp +++ b/tests/type/test_rtype.hpp @@ -511,4 +511,4 @@ TEST_F(RTypeTest, RoundtripYamlSerialization) { NestedType deserializedObj = nestedTypeReflection.from_yaml(yaml); EXPECT_EQ(deserializedObj, originalObj); -} \ No newline at end of file +} diff --git a/tests/type/test_ryaml.cpp b/tests/type/test_ryaml.cpp index bcb11e02..ef772ee4 100644 --- a/tests/type/test_ryaml.cpp +++ b/tests/type/test_ryaml.cpp @@ -691,4 +691,4 @@ not_a_number: .nan } // namespace atom::type::test -#endif // ATOM_TYPE_TEST_RYAML_HPP \ No newline at end of file +#endif // ATOM_TYPE_TEST_RYAML_HPP diff --git a/tests/type/test_small_list.hpp b/tests/type/test_small_list.hpp index 0e7dc222..34853257 100644 --- a/tests/type/test_small_list.hpp +++ b/tests/type/test_small_list.hpp @@ -32,7 +32,7 @@ TEST_F(SmallListTest, CopyConstructor) { list.pushBack(1); list.pushBack(2); list.pushBack(3); - + SmallList copy(list); EXPECT_EQ(copy.size(), list.size()); EXPECT_TRUE(std::equal(copy.begin(), copy.end(), list.begin())); @@ -42,7 +42,7 @@ TEST_F(SmallListTest, MoveConstructor) { list.pushBack(1); list.pushBack(2); size_t originalSize = list.size(); - + SmallList moved(std::move(list)); EXPECT_EQ(moved.size(), originalSize); EXPECT_TRUE(list.empty()); @@ -59,10 +59,10 @@ TEST_F(SmallListTest, PushBackAndFront) { TEST_F(SmallListTest, PopBackAndFront) { list.pushBack(1); list.pushBack(2); - + list.popFront(); EXPECT_EQ(list.front(), 2); - + list.popBack(); EXPECT_TRUE(list.empty()); } @@ -73,7 +73,7 @@ TEST_F(SmallListTest, EmplaceOperations) { auto it = list.begin(); ++it; list.emplace(it, 3); - + std::vector expected = {2, 3, 1}; EXPECT_TRUE(std::equal(list.begin(), list.end(), expected.begin())); } @@ -83,7 +83,7 @@ TEST_F(SmallListTest, IteratorOperations) { for(int i = 0; i < 5; ++i) { list.pushBack(i); } - + auto it = list.begin(); EXPECT_EQ(*it, 0); ++it; @@ -95,7 +95,7 @@ TEST_F(SmallListTest, IteratorOperations) { TEST_F(SmallListTest, ConstIterator) { list.pushBack(1); list.pushBack(2); - + const SmallList& constList = list; auto it = constList.begin(); EXPECT_EQ(*it, 1); @@ -118,7 +118,7 @@ TEST_F(SmallListTest, InsertAndErase) { ++it; list.insert(it, 3); EXPECT_THAT(list, ElementsAre(1, 2, 3, 4, 5)); - + it = list.begin(); ++it; list.erase(it); @@ -137,7 +137,7 @@ TEST_F(SmallListTest, Resize) { list.resize(5, 0); EXPECT_EQ(list.size(), 5); EXPECT_EQ(list.back(), 0); - + list.resize(2); EXPECT_EQ(list.size(), 2); EXPECT_EQ(list.back(), 2); @@ -203,7 +203,7 @@ TEST_F(SmallListTest, LargeListOperations) { for(int i = 0; i < TEST_SIZE; ++i) { list.pushBack(i); } - + list.sort(); EXPECT_TRUE(std::is_sorted(list.begin(), list.end())); EXPECT_EQ(list.size(), TEST_SIZE); @@ -213,7 +213,7 @@ TEST_F(SmallListTest, LargeListOperations) { struct ThrowingCopy { int value; static bool shouldThrow; - + ThrowingCopy(int v) : value(v) {} ThrowingCopy(const ThrowingCopy& other) { if(shouldThrow) throw std::runtime_error("Copy error"); @@ -228,7 +228,7 @@ TEST_F(SmallListTest, ExceptionSafety) { ThrowingCopy::shouldThrow = false; SmallList throwingList; throwingList.pushBack(ThrowingCopy(1)); - + ThrowingCopy::shouldThrow = true; EXPECT_THROW(throwingList.pushBack(ThrowingCopy(2)), std::runtime_error); EXPECT_EQ(throwingList.size(), 1); // List should remain unchanged @@ -237,4 +237,4 @@ TEST_F(SmallListTest, ExceptionSafety) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/tests/type/test_small_vector.hpp b/tests/type/test_small_vector.hpp index d0f8e9d1..214a80db 100644 --- a/tests/type/test_small_vector.hpp +++ b/tests/type/test_small_vector.hpp @@ -1555,4 +1555,4 @@ TEST_F(SmallVectorTest, PopBack) { EXPECT_EQ(TestObject::destructor_count(), 1); EXPECT_EQ(sv.size(), 1u); } -} \ No newline at end of file +} diff --git a/tests/type/test_static_string.hpp b/tests/type/test_static_string.hpp index f731135b..4d7010ad 100644 --- a/tests/type/test_static_string.hpp +++ b/tests/type/test_static_string.hpp @@ -656,8 +656,8 @@ TEST_F(StaticStringTest, ConstexprUsage) { // Verify the constexpr values at runtime verifyStringEquals(constexpr_str, "Hello"); verifyStringEquals(str, "Hello"); - + // Additional runtime checks can go here EXPECT_EQ(constexpr_str.size(), 5); EXPECT_EQ(str.size(), 5); -} \ No newline at end of file +} diff --git a/tests/type/test_static_vector.hpp b/tests/type/test_static_vector.hpp index 921c31fa..224f53c8 100644 --- a/tests/type/test_static_vector.hpp +++ b/tests/type/test_static_vector.hpp @@ -938,4 +938,4 @@ TEST_F(StaticVectorTest, ThreadSafety) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/tests/type/test_string.cpp b/tests/type/test_string.cpp index 1ee4b356..086c617d 100644 --- a/tests/type/test_string.cpp +++ b/tests/type/test_string.cpp @@ -508,4 +508,4 @@ TEST_F(StringTest, StreamOperations) { String s2("original"); badStream >> s2; EXPECT_EQ(s2.data(), "original"); // Should remain unchanged -} \ No newline at end of file +} diff --git a/tests/type/test_trackable.cpp b/tests/type/test_trackable.cpp index 9f60c859..e8597fe7 100644 --- a/tests/type/test_trackable.cpp +++ b/tests/type/test_trackable.cpp @@ -261,4 +261,4 @@ TEST_F(TrackableTest, ComplexTypeTracking) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/tests/type/test_uint.cpp b/tests/type/test_uint.cpp index e48232a0..d5a36ffc 100644 --- a/tests/type/test_uint.cpp +++ b/tests/type/test_uint.cpp @@ -269,4 +269,4 @@ TEST_F(UintLiteralsTest, MaxConstants) { "MAX_UINT32 should be uint32_t"); } -} // namespace \ No newline at end of file +} // namespace diff --git a/tests/type/test_weak_ptr.hpp b/tests/type/test_weak_ptr.hpp index 6ca456a7..2add0e06 100644 --- a/tests/type/test_weak_ptr.hpp +++ b/tests/type/test_weak_ptr.hpp @@ -874,4 +874,4 @@ TEST_F(EnhancedWeakPtrTest, EdgeCases) { // Break cycle and test node.reset(); EXPECT_TRUE(self->weakSelf.expired()); -} \ No newline at end of file +} diff --git a/tests/utils/test_aes.hpp b/tests/utils/test_aes.hpp index 9abdb404..00504397 100644 --- a/tests/utils/test_aes.hpp +++ b/tests/utils/test_aes.hpp @@ -165,4 +165,4 @@ TEST_F(AESTest, CompressionRatio) { } // namespace atom::utils::test -#endif // ATOM_UTILS_TEST_AES_HPP \ No newline at end of file +#endif // ATOM_UTILS_TEST_AES_HPP diff --git a/tests/utils/test_aligned.hpp b/tests/utils/test_aligned.hpp index a64c45fc..621ac52d 100644 --- a/tests/utils/test_aligned.hpp +++ b/tests/utils/test_aligned.hpp @@ -147,4 +147,4 @@ struct CompilationFailureTests { } // namespace atom::utils::test -#endif // ATOM_UTILS_TEST_ALIGNED_HPP \ No newline at end of file +#endif // ATOM_UTILS_TEST_ALIGNED_HPP diff --git a/tests/utils/test_anyutils.hpp b/tests/utils/test_anyutils.hpp index 690bd0cb..1a6d83fe 100644 --- a/tests/utils/test_anyutils.hpp +++ b/tests/utils/test_anyutils.hpp @@ -489,4 +489,4 @@ TEST_F(CacheTest, CacheHitTest) { } // namespace atom::utils::test -#endif // ATOM_UTILS_TEST_ANYUTILS_HPP \ No newline at end of file +#endif // ATOM_UTILS_TEST_ANYUTILS_HPP diff --git a/tests/utils/test_bit.hpp b/tests/utils/test_bit.hpp index 67418558..545bcdbf 100644 --- a/tests/utils/test_bit.hpp +++ b/tests/utils/test_bit.hpp @@ -425,4 +425,4 @@ TEST_F(BitManipulationTest, ErrorHandling) { } // namespace atom::utils::test -#endif // ATOM_UTILS_TEST_BIT_HPP \ No newline at end of file +#endif // ATOM_UTILS_TEST_BIT_HPP diff --git a/tests/utils/test_container.hpp b/tests/utils/test_container.hpp index aa8d82ca..93ef78e9 100644 --- a/tests/utils/test_container.hpp +++ b/tests/utils/test_container.hpp @@ -464,4 +464,4 @@ TEST_F(ContainerTest, CombinedOperations) { } // namespace atom::utils::test -#endif // ATOM_UTILS_TEST_CONTAINER_HPP \ No newline at end of file +#endif // ATOM_UTILS_TEST_CONTAINER_HPP diff --git a/tests/utils/test_cstring.hpp b/tests/utils/test_cstring.hpp index cd3b8cfa..c95f91d0 100644 --- a/tests/utils/test_cstring.hpp +++ b/tests/utils/test_cstring.hpp @@ -36,19 +36,19 @@ TEST_F(CStringTest, Deduplicate) { // Basic deduplication auto result1 = deduplicate("hello"); EXPECT_EQ(arrayToString(result1), "helo"); - + // Empty string auto result2 = deduplicate(""); EXPECT_EQ(arrayToString(result2), ""); - + // String with no duplicates auto result3 = deduplicate("abcdef"); EXPECT_EQ(arrayToString(result3), "abcdef"); - + // String with all identical characters auto result4 = deduplicate("aaaaa"); EXPECT_EQ(arrayToString(result4), "a"); - + // String with special characters auto result5 = deduplicate("a!b!c!a!b!c!"); EXPECT_EQ(arrayToString(result5), "a!bc"); @@ -61,21 +61,21 @@ TEST_F(CStringTest, Split) { ASSERT_EQ(result1[0], "apple"); ASSERT_EQ(result1[1], "banana"); ASSERT_EQ(result1[2], "cherry"); - + // Split with empty parts auto result2 = split("apple,,cherry", ','); ASSERT_EQ(result2[0], "apple"); ASSERT_EQ(result2[1], ""); ASSERT_EQ(result2[2], "cherry"); - + // Split with no delimiter auto result3 = split("apple", ','); ASSERT_EQ(result3[0], "apple"); - + // Split empty string auto result4 = split("", ','); ASSERT_EQ(result4[0], ""); - + // Split with delimiter at start and end auto result5 = split(",apple,", ','); ASSERT_EQ(result5[0], ""); @@ -88,15 +88,15 @@ TEST_F(CStringTest, Replace) { // Basic replacement auto result1 = replace("hello", 'l', 'x'); EXPECT_EQ(arrayToString(result1), "hexxo"); - + // Replace character not in string auto result2 = replace("hello", 'z', 'x'); EXPECT_EQ(arrayToString(result2), "hello"); - + // Replace in empty string auto result3 = replace("", 'a', 'b'); EXPECT_EQ(arrayToString(result3), ""); - + // Replace with the same character auto result4 = replace("hello", 'l', 'l'); EXPECT_EQ(arrayToString(result4), "hello"); @@ -107,19 +107,19 @@ TEST_F(CStringTest, ToLower) { // Basic lowercase conversion auto result1 = toLower("HELLO"); EXPECT_EQ(arrayToString(result1), "hello"); - + // Mixed case auto result2 = toLower("HeLlO"); EXPECT_EQ(arrayToString(result2), "hello"); - + // Already lowercase auto result3 = toLower("hello"); EXPECT_EQ(arrayToString(result3), "hello"); - + // Empty string auto result4 = toLower(""); EXPECT_EQ(arrayToString(result4), ""); - + // Non-alphabetic characters auto result5 = toLower("Hello123!@#"); EXPECT_EQ(arrayToString(result5), "hello123!@#"); @@ -130,19 +130,19 @@ TEST_F(CStringTest, ToUpper) { // Basic uppercase conversion auto result1 = toUpper("hello"); EXPECT_EQ(arrayToString(result1), "HELLO"); - + // Mixed case auto result2 = toUpper("HeLlO"); EXPECT_EQ(arrayToString(result2), "HELLO"); - + // Already uppercase auto result3 = toUpper("HELLO"); EXPECT_EQ(arrayToString(result3), "HELLO"); - + // Empty string auto result4 = toUpper(""); EXPECT_EQ(arrayToString(result4), ""); - + // Non-alphabetic characters auto result5 = toUpper("Hello123!@#"); EXPECT_EQ(arrayToString(result5), "HELLO123!@#"); @@ -153,18 +153,18 @@ TEST_F(CStringTest, Concat) { // Basic concatenation auto result1 = concat("Hello, ", "World!"); EXPECT_EQ(arrayToString(result1), "Hello, World!"); - + // Concatenate with empty string auto result2 = concat("Hello", ""); EXPECT_EQ(arrayToString(result2), "Hello"); - + auto result3 = concat("", "World"); EXPECT_EQ(arrayToString(result3), "World"); - + // Concatenate two empty strings auto result4 = concat("", ""); EXPECT_EQ(arrayToString(result4), ""); - + // Concatenate with special characters auto result5 = concat("Hello\n", "World\t!"); EXPECT_EQ(arrayToString(result5), "Hello\nWorld\t!"); @@ -175,23 +175,23 @@ TEST_F(CStringTest, TrimCString) { // Basic trimming auto result1 = trim(" Hello "); EXPECT_EQ(arrayToString(result1), "Hello"); - + // No spaces to trim auto result2 = trim("Hello"); EXPECT_EQ(arrayToString(result2), "Hello"); - + // Only leading spaces auto result3 = trim(" Hello"); EXPECT_EQ(arrayToString(result3), "Hello"); - + // Only trailing spaces auto result4 = trim("Hello "); EXPECT_EQ(arrayToString(result4), "Hello"); - + // Only spaces auto result5 = trim(" "); EXPECT_EQ(arrayToString(result5), ""); - + // Empty string auto result6 = trim(""); EXPECT_EQ(arrayToString(result6), ""); @@ -202,19 +202,19 @@ TEST_F(CStringTest, Substring) { // Basic substring auto result1 = substring("Hello, World!", 7, 5); EXPECT_EQ(arrayToString(result1), "World"); - + // Substring from start auto result2 = substring("Hello, World!", 0, 5); EXPECT_EQ(arrayToString(result2), "Hello"); - + // Substring beyond string length auto result3 = substring("Hello", 0, 10); EXPECT_EQ(arrayToString(result3), "Hello"); - + // Empty substring auto result4 = substring("Hello", 0, 0); EXPECT_EQ(arrayToString(result4), ""); - + // Start beyond string length auto result5 = substring("Hello", 10, 5); EXPECT_EQ(arrayToString(result5), ""); @@ -224,19 +224,19 @@ TEST_F(CStringTest, Substring) { TEST_F(CStringTest, Equal) { // Equal strings EXPECT_TRUE(equal("Hello", "Hello")); - + // Different strings EXPECT_FALSE(equal("Hello", "World")); - + // Case sensitivity EXPECT_FALSE(equal("hello", "Hello")); - + // Different lengths EXPECT_FALSE(equal("Hello", "HelloWorld")); - + // Empty strings EXPECT_TRUE(equal("", "")); - + // One empty string EXPECT_FALSE(equal("Hello", "")); EXPECT_FALSE(equal("", "Hello")); @@ -246,19 +246,19 @@ TEST_F(CStringTest, Equal) { TEST_F(CStringTest, Find) { // Find existing character EXPECT_EQ(find("Hello", 'e'), 1); - + // Find first occurrence of repeated character EXPECT_EQ(find("Hello", 'l'), 2); - + // Character not found EXPECT_EQ(find("Hello", 'z'), 5); // Returns N-1 when not found - + // Empty string EXPECT_EQ(find("", 'a'), 0); // Returns N-1 (which is 0 for empty string) - + // Find in first position EXPECT_EQ(find("Hello", 'H'), 0); - + // Find in last position EXPECT_EQ(find("Hello", 'o'), 4); } @@ -267,13 +267,13 @@ TEST_F(CStringTest, Find) { TEST_F(CStringTest, Length) { // Basic length EXPECT_EQ(length("Hello"), 5); - + // Empty string EXPECT_EQ(length(""), 0); - + // String with spaces EXPECT_EQ(length("Hello World"), 11); - + // String with special characters EXPECT_EQ(length("Hello\nWorld"), 11); } @@ -283,19 +283,19 @@ TEST_F(CStringTest, Reverse) { // Basic reversal auto result1 = reverse("Hello"); EXPECT_EQ(arrayToString(result1), "olleH"); - + // Palindrome auto result2 = reverse("racecar"); EXPECT_EQ(arrayToString(result2), "racecar"); - + // Empty string auto result3 = reverse(""); EXPECT_EQ(arrayToString(result3), ""); - + // Single character auto result4 = reverse("A"); EXPECT_EQ(arrayToString(result4), "A"); - + // String with spaces auto result5 = reverse("Hello World"); EXPECT_EQ(arrayToString(result5), "dlroW olleH"); @@ -306,27 +306,27 @@ TEST_F(CStringTest, TrimStringView) { // Basic trimming std::string_view sv = " Hello "; EXPECT_EQ(trim(sv), "Hello"); - + // No spaces to trim sv = "Hello"; EXPECT_EQ(trim(sv), "Hello"); - + // Only leading spaces sv = " Hello"; EXPECT_EQ(trim(sv), "Hello"); - + // Only trailing spaces sv = "Hello "; EXPECT_EQ(trim(sv), "Hello"); - + // Only spaces sv = " "; EXPECT_EQ(trim(sv), ""); - + // Empty string sv = ""; EXPECT_EQ(trim(sv), ""); - + // All types of whitespace sv = " \t\n\r\fHello\v \t"; EXPECT_EQ(trim(sv), "Hello"); @@ -338,12 +338,12 @@ TEST_F(CStringTest, CharArrayConversion) { std::array input1 = {'H', 'e', 'l', 'l', 'o', '\0'}; auto result1 = charArrayToArrayConstexpr(input1); EXPECT_EQ(arrayToString(result1), "Hello"); - + // Test charArrayToArray std::array input2 = {'W', 'o', 'r', 'l', 'd', '\0'}; auto result2 = charArrayToArray(input2); EXPECT_EQ(arrayToString(result2), "World"); - + // Empty array std::array emptyArray = {'\0'}; auto result3 = charArrayToArrayConstexpr(emptyArray); @@ -355,15 +355,15 @@ TEST_F(CStringTest, IsNegative) { // Negative number std::array negative = {'-', '1', '\0'}; EXPECT_TRUE(isNegative(negative)); - + // Positive number std::array positive = {'4', '2', '\0'}; EXPECT_FALSE(isNegative(positive)); - + // Zero std::array zero = {'0', '\0'}; EXPECT_FALSE(isNegative(zero)); - + // Empty array std::array empty = {'\0'}; EXPECT_FALSE(isNegative(empty)); @@ -374,19 +374,19 @@ TEST_F(CStringTest, ArrayToInt) { // Basic conversion std::array num1 = {'1', '2', '3', '\0'}; EXPECT_EQ(arrayToInt(num1), 123); - + // Negative number std::array num2 = {'-', '4', '5', '\0'}; EXPECT_EQ(arrayToInt(num2), -45); - + // Leading zeros std::array num3 = {'0', '0', '4', '2', '\0'}; EXPECT_EQ(arrayToInt(num3), 42); - + // Binary base std::array bin = {'1', '0', '1', '0', '1', '\0'}; EXPECT_EQ(arrayToInt(bin, BASE_2), 21); // 10101 in binary is 21 in decimal - + // Hexadecimal base std::array hex = {'F', 'F', 'F', '\0'}; EXPECT_EQ(arrayToInt(hex, BASE_16), 4095); // FFF in hex is 4095 in decimal @@ -397,11 +397,11 @@ TEST_F(CStringTest, AbsoluteValue) { // Positive number std::array pos = {'4', '2', '\0'}; EXPECT_EQ(absoluteValue(pos), 42); - + // Negative number std::array neg = {'-', '4', '2', '\0'}; EXPECT_EQ(absoluteValue(neg), 42); - + // Zero std::array zero = {'0', '\0'}; EXPECT_EQ(absoluteValue(zero), 0); @@ -412,23 +412,23 @@ TEST_F(CStringTest, ConvertBase) { // Decimal to binary std::array dec1 = {'1', '0', '\0'}; EXPECT_EQ(convertBase(dec1, BASE_10, BASE_2), "1010"); // 10 to binary - + // Decimal to hex std::array dec2 = {'2', '5', '5', '\0'}; EXPECT_EQ(convertBase(dec2, BASE_10, BASE_16), "FF"); // 255 to hex - + // Binary to decimal std::array bin = {'1', '0', '1', '0', '1', '\0'}; EXPECT_EQ(convertBase(bin, BASE_2, BASE_10), "21"); // 10101 binary to decimal - + // Hex to decimal std::array hex = {'F', 'F', '\0'}; EXPECT_EQ(convertBase(hex, BASE_16, BASE_10), "255"); // FF to decimal - + // Zero conversion std::array zero = {'0', '\0'}; EXPECT_EQ(convertBase(zero, BASE_10, BASE_16), "0"); - + // Negative number std::array neg = {'-', '5', '\0'}; EXPECT_EQ(convertBase(neg, BASE_10, BASE_2), "-101"); // -5 to binary @@ -437,7 +437,7 @@ TEST_F(CStringTest, ConvertBase) { // Test compile-time capabilities TEST_F(CStringTest, CompileTimeOperations) { // These tests verify that the functions work at compile time - + // Create compile-time constants constexpr auto deduped = deduplicate("hello"); constexpr auto replaced = replace("hello", 'l', 'x'); @@ -448,7 +448,7 @@ TEST_F(CStringTest, CompileTimeOperations) { constexpr auto found = find("Hello", 'e'); constexpr auto len = length("Hello"); constexpr bool isEqual = equal("Hello", "Hello"); - + // Verify values EXPECT_EQ(arrayToString(deduped), "helo"); EXPECT_EQ(arrayToString(replaced), "hexxo"); @@ -470,14 +470,14 @@ TEST_F(CStringTest, ComplexCombinations) { constexpr auto step2 = replace(step1_str, ' ', '_'); constexpr const char step2_str[] = "hello_world"; constexpr auto step3 = reverse(step2_str); - + EXPECT_EQ(arrayToString(step3), "dlrow_olleh"); - + // Test with various special characters constexpr const char specialChars[] = "!@#$%^&*()_+{}:<>?"; auto revSpecial = reverse(specialChars); EXPECT_EQ(arrayToString(revSpecial), "?><:{}+_)(*&^%$#@!"); - + // Unicode handling is limited in C-style strings, so these tests are basic constexpr const char unicodeChars[] = "Привет"; // Russian word "hello" auto revUnicode = reverse(unicodeChars); @@ -488,4 +488,4 @@ TEST_F(CStringTest, ComplexCombinations) { } // namespace atom::utils::test -#endif // ATOM_UTILS_TEST_CSTRING_HPP \ No newline at end of file +#endif // ATOM_UTILS_TEST_CSTRING_HPP diff --git a/tests/utils/test_difflib.hpp b/tests/utils/test_difflib.hpp index 7fcb3de2..67f6ef12 100644 --- a/tests/utils/test_difflib.hpp +++ b/tests/utils/test_difflib.hpp @@ -450,4 +450,4 @@ inline void printMatchingBlocks( } // namespace atom::utils::test -#endif // ATOM_UTILS_TEST_DIFFLIB_HPP \ No newline at end of file +#endif // ATOM_UTILS_TEST_DIFFLIB_HPP diff --git a/tests/utils/test_lcg.hpp b/tests/utils/test_lcg.hpp index 159f8d83..82064c06 100644 --- a/tests/utils/test_lcg.hpp +++ b/tests/utils/test_lcg.hpp @@ -620,4 +620,4 @@ TEST_F(LCGTest, ThreadSafety) { } } -} // namespace atom::utils::tests \ No newline at end of file +} // namespace atom::utils::tests diff --git a/tests/utils/test_linq.hpp b/tests/utils/test_linq.hpp index e14fd826..1cc1be8e 100644 --- a/tests/utils/test_linq.hpp +++ b/tests/utils/test_linq.hpp @@ -579,4 +579,4 @@ TEST_F(LinqTest, NullPredicateHandling) { } */ -} // namespace atom::utils::tests \ No newline at end of file +} // namespace atom::utils::tests diff --git a/tests/utils/test_print.hpp b/tests/utils/test_print.hpp index c77418da..25b35291 100644 --- a/tests/utils/test_print.hpp +++ b/tests/utils/test_print.hpp @@ -612,4 +612,4 @@ TEST_F(PrintUtilsTest, MemoryTracker) { << "Buffer2 should still be reported"; } -} // namespace atom::utils::tests \ No newline at end of file +} // namespace atom::utils::tests diff --git a/tests/utils/test_qdatetime.hpp b/tests/utils/test_qdatetime.hpp index 9ab1a2d9..0c8c7ceb 100644 --- a/tests/utils/test_qdatetime.hpp +++ b/tests/utils/test_qdatetime.hpp @@ -251,4 +251,4 @@ TEST_F(QDateTimeTest, SecsToIntegratedTest) { << "Direct difference should equal sum of segment differences"; } -} // namespace atom::utils::tests \ No newline at end of file +} // namespace atom::utils::tests diff --git a/tests/utils/test_qprocess.hpp b/tests/utils/test_qprocess.hpp index d4b63327..f714973a 100644 --- a/tests/utils/test_qprocess.hpp +++ b/tests/utils/test_qprocess.hpp @@ -346,4 +346,4 @@ TEST_F(QProcessTerminateTest, TerminateWithCustomWorkingDirectory) { // 进程应该被终止 std::this_thread::sleep_for(std::chrono::milliseconds(100)); EXPECT_FALSE(process->isRunning()); -} \ No newline at end of file +} diff --git a/tests/utils/test_qtimer.hpp b/tests/utils/test_qtimer.hpp index b4d0fb2e..b00319b5 100644 --- a/tests/utils/test_qtimer.hpp +++ b/tests/utils/test_qtimer.hpp @@ -306,4 +306,4 @@ TEST_F(ElapsedTimerTest, StartHandlesExceptions) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/tests/utils/test_random.hpp b/tests/utils/test_random.hpp index a29067c3..101f3db3 100644 --- a/tests/utils/test_random.hpp +++ b/tests/utils/test_random.hpp @@ -585,4 +585,4 @@ TEST_F(RandomTest, GenerateRandomStringPerformance) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/tests/utils/test_switch.hpp b/tests/utils/test_switch.hpp index 0e5ee57b..d85ba0ca 100644 --- a/tests/utils/test_switch.hpp +++ b/tests/utils/test_switch.hpp @@ -191,4 +191,4 @@ TEST_F(StringSwitchTest, DifferentReturnTypes) { } // namespace atom::utils::test -#endif // ATOM_UTILS_TEST_SWITCH_HPP \ No newline at end of file +#endif // ATOM_UTILS_TEST_SWITCH_HPP diff --git a/tests/utils/test_time.hpp b/tests/utils/test_time.hpp index 081c6ba6..ab01a83a 100644 --- a/tests/utils/test_time.hpp +++ b/tests/utils/test_time.hpp @@ -411,4 +411,4 @@ TEST_F(TimeUtilsTest, TimestampWithMilliseconds) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/tests/utils/test_to_byte.hpp b/tests/utils/test_to_byte.hpp index fcf6e6fd..d6206fc1 100644 --- a/tests/utils/test_to_byte.hpp +++ b/tests/utils/test_to_byte.hpp @@ -555,4 +555,4 @@ TEST_F(SerializationTest, PartialDeserialization) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/tests/utils/test_to_string.hpp b/tests/utils/test_to_string.hpp index 53ee6d44..5ea06734 100644 --- a/tests/utils/test_to_string.hpp +++ b/tests/utils/test_to_string.hpp @@ -29,7 +29,7 @@ class StreamableClass { public: int value; explicit StreamableClass(int val) : value(val) {} - + friend std::ostream& operator<<(std::ostream& os, const StreamableClass& obj) { os << "StreamableClass(" << obj.value << ")"; return os; @@ -51,7 +51,7 @@ class ToStringTest : public ::testing::Test { void SetUp() override { // Setup test environment } - + void TearDown() override { // Clean up test environment } @@ -62,23 +62,23 @@ TEST_F(ToStringTest, StringTypes) { // std::string std::string str = "hello"; EXPECT_EQ(toString(str), "hello"); - + // const char* const char* cstr = "hello"; EXPECT_EQ(toString(cstr), "hello"); - + // char* char mutable_str[] = "hello"; EXPECT_EQ(toString(mutable_str), "hello"); - + // std::string_view std::string_view str_view = "hello"; EXPECT_EQ(toString(str_view), "hello"); - + // Null C-string pointer const char* null_str = nullptr; EXPECT_EQ(toString(null_str), "null"); - + // Empty string EXPECT_EQ(toString(""), ""); } @@ -102,14 +102,14 @@ TEST_F(ToStringTest, PointerType) { int value = 42; int* ptr = &value; std::string result = toString(ptr); - + EXPECT_THAT(result, StartsWith("Pointer(")); EXPECT_THAT(result, HasSubstr("42")); - + // Null pointer int* null_ptr = nullptr; EXPECT_EQ(toString(null_ptr), "nullptr"); - + // Pointer to complex type std::string str = "test"; std::string* str_ptr = &str; @@ -121,14 +121,14 @@ TEST_F(ToStringTest, PointerType) { TEST_F(ToStringTest, SmartPointerType) { auto shared_ptr = std::make_shared(42); std::string result = toString(shared_ptr); - + EXPECT_THAT(result, StartsWith("SmartPointer(")); EXPECT_THAT(result, HasSubstr("42")); - + // Null smart pointer std::shared_ptr null_shared_ptr; EXPECT_EQ(toString(null_shared_ptr), "nullptr"); - + // Unique pointer auto unique_ptr = std::make_unique(123); result = toString(unique_ptr); @@ -140,20 +140,20 @@ TEST_F(ToStringTest, SmartPointerType) { TEST_F(ToStringTest, VectorContainer) { std::vector vec = {1, 2, 3, 4, 5}; std::string result = toString(vec); - + EXPECT_EQ(result, "[1, 2, 3, 4, 5]"); - + // Empty vector std::vector empty_vec; EXPECT_EQ(toString(empty_vec), "[]"); - + // Vector with custom separator EXPECT_EQ(toString(vec, " | "), "[1 | 2 | 3 | 4 | 5]"); - + // Vector of strings std::vector str_vec = {"hello", "world"}; EXPECT_EQ(toString(str_vec), "[hello, world]"); - + // Nested vector std::vector> nested_vec = {{1, 2}, {3, 4}}; EXPECT_EQ(toString(nested_vec), "[[1, 2], [3, 4]]"); @@ -163,7 +163,7 @@ TEST_F(ToStringTest, VectorContainer) { TEST_F(ToStringTest, ListContainer) { std::list list = {1, 2, 3, 4, 5}; EXPECT_EQ(toString(list), "[1, 2, 3, 4, 5]"); - + // Empty list std::list empty_list; EXPECT_EQ(toString(empty_list), "[]"); @@ -174,7 +174,7 @@ TEST_F(ToStringTest, SetContainer) { std::set set = {5, 3, 1, 4, 2}; // Set will be ordered EXPECT_EQ(toString(set), "[1, 2, 3, 4, 5]"); - + // Empty set std::set empty_set; EXPECT_EQ(toString(empty_set), "[]"); @@ -184,27 +184,27 @@ TEST_F(ToStringTest, SetContainer) { TEST_F(ToStringTest, MapType) { std::map map = {{1, "one"}, {2, "two"}, {3, "three"}}; std::string result = toString(map); - + EXPECT_EQ(result, "{1: one, 2: two, 3: three}"); - + // Empty map std::map empty_map; EXPECT_EQ(toString(empty_map), "{}"); - + // Map with custom separator EXPECT_EQ(toString(map, " | "), "{1: one | 2: two | 3: three}"); - + // Map with string keys std::map str_map = {{"one", 1}, {"two", 2}, {"three", 3}}; EXPECT_EQ(toString(str_map), "{one: 1, three: 3, two: 2}"); - + // Nested map std::map> nested_map = { {1, {{1, "one-one"}, {2, "one-two"}}}, {2, {{1, "two-one"}, {2, "two-two"}}} }; EXPECT_EQ(toString(nested_map), "{1: {1: one-one, 2: one-two}, 2: {1: two-one, 2: two-two}}"); - + // Unordered map (order is not guaranteed, so just check length and specific elements) std::unordered_map umap = {{1, "one"}, {2, "two"}, {3, "three"}}; result = toString(umap); @@ -219,7 +219,7 @@ TEST_F(ToStringTest, MapType) { TEST_F(ToStringTest, ArrayType) { std::array arr = {1, 2, 3, 4, 5}; EXPECT_EQ(toString(arr), "[1, 2, 3, 4, 5]"); - + // Empty array std::array empty_arr = {}; EXPECT_EQ(toString(empty_arr), "[]"); @@ -229,18 +229,18 @@ TEST_F(ToStringTest, ArrayType) { TEST_F(ToStringTest, TupleType) { auto tuple = std::make_tuple(1, "hello", 3.14); EXPECT_EQ(toString(tuple), "(1, hello, 3.140000)"); - + // Empty tuple auto empty_tuple = std::make_tuple(); EXPECT_EQ(toString(empty_tuple), "()"); - + // Single element tuple auto single_tuple = std::make_tuple(42); EXPECT_EQ(toString(single_tuple), "(42)"); - + // Tuple with custom separator EXPECT_EQ(toString(tuple, " - "), "(1 - hello - 3.140000)"); - + // Nested tuple auto nested_tuple = std::make_tuple(std::make_tuple(1, 2), std::make_tuple("a", "b")); EXPECT_EQ(toString(nested_tuple), "((1, 2), (a, b))"); @@ -250,11 +250,11 @@ TEST_F(ToStringTest, TupleType) { TEST_F(ToStringTest, OptionalType) { std::optional opt = 42; EXPECT_EQ(toString(opt), "Optional(42)"); - + // Empty optional std::optional empty_opt; EXPECT_EQ(toString(empty_opt), "nullopt"); - + // Optional with complex type std::optional> opt_vec = std::vector{1, 2, 3}; EXPECT_EQ(toString(opt_vec), "Optional([1, 2, 3])"); @@ -264,13 +264,13 @@ TEST_F(ToStringTest, OptionalType) { TEST_F(ToStringTest, VariantType) { std::variant var = 42; EXPECT_EQ(toString(var), "42"); - + var = "hello"; EXPECT_EQ(toString(var), "hello"); - + var = 3.14; EXPECT_EQ(toString(var), "3.140000"); - + // Variant with complex type std::variant> var2 = std::vector{1, 2, 3}; EXPECT_EQ(toString(var2), "[1, 2, 3]"); @@ -281,11 +281,11 @@ TEST_F(ToStringTest, GeneralTypesStdToString) { // Integer EXPECT_EQ(toString(42), "42"); EXPECT_EQ(toString(-42), "-42"); - + // Float/Double EXPECT_EQ(toString(3.14f), "3.140000"); EXPECT_EQ(toString(-3.14), "-3.140000"); - + // Boolean EXPECT_EQ(toString(true), "1"); EXPECT_EQ(toString(false), "0"); @@ -305,16 +305,16 @@ TEST_F(ToStringTest, ErrorHandling) { nullptr, std::make_shared(3) }; - + std::string result = toString(vec); EXPECT_THAT(result, HasSubstr("[SmartPointer")); EXPECT_THAT(result, HasSubstr("nullptr")); - + // Exception in conversion should be caught and reported try { // This would cause a static_assert failure in actual code //toString(NonStreamableClass(42)); - + // Instead, simulate a conversion error throw ToStringException("Test exception"); } catch (const ToStringException& e) { @@ -326,17 +326,17 @@ TEST_F(ToStringTest, ErrorHandling) { // Test toStringArray function TEST_F(ToStringTest, ToStringArray) { std::vector vec = {1, 2, 3, 4, 5}; - + // Default separator (space) EXPECT_EQ(toStringArray(vec), "1 2 3 4 5"); - + // Custom separator EXPECT_EQ(toStringArray(vec, ", "), "1, 2, 3, 4, 5"); - + // Empty array std::vector empty_vec; EXPECT_EQ(toStringArray(empty_vec), ""); - + // Array with complex types std::vector> nested_vec = {{1, 2}, {3, 4}}; EXPECT_EQ(toStringArray(nested_vec), "[1, 2] [3, 4]"); @@ -345,16 +345,16 @@ TEST_F(ToStringTest, ToStringArray) { // Test toStringRange function TEST_F(ToStringTest, ToStringRange) { std::vector vec = {1, 2, 3, 4, 5}; - + // Default separator EXPECT_EQ(toStringRange(vec.begin(), vec.end()), "[1, 2, 3, 4, 5]"); - + // Custom separator EXPECT_EQ(toStringRange(vec.begin(), vec.end(), " | "), "[1 | 2 | 3 | 4 | 5]"); - + // Empty range EXPECT_EQ(toStringRange(vec.begin(), vec.begin()), "[]"); - + // Partial range EXPECT_EQ(toStringRange(vec.begin() + 1, vec.begin() + 4), "[2, 3, 4]"); } @@ -363,13 +363,13 @@ TEST_F(ToStringTest, ToStringRange) { TEST_F(ToStringTest, JoinCommandLine) { // Basic join EXPECT_EQ(joinCommandLine("program", "-f", "file.txt"), "program -f file.txt"); - + // Join with mixed types EXPECT_EQ(joinCommandLine("program", 42, 3.14, true), "program 42 3.140000 1"); - + // Join with no arguments EXPECT_EQ(joinCommandLine(), ""); - + // Join with single argument EXPECT_EQ(joinCommandLine("program"), "program"); } @@ -378,7 +378,7 @@ TEST_F(ToStringTest, JoinCommandLine) { TEST_F(ToStringTest, DequeContainer) { std::deque deq = {1, 2, 3, 4, 5}; EXPECT_EQ(toString(deq), "[1, 2, 3, 4, 5]"); - + // Empty deque std::deque empty_deq; EXPECT_EQ(toString(empty_deq), "[]"); @@ -388,10 +388,10 @@ TEST_F(ToStringTest, DequeContainer) { TEST_F(ToStringTest, CustomDelimiters) { std::vector vec = {1, 2, 3}; EXPECT_EQ(toString(vec, " -> "), "[1 -> 2 -> 3]"); - + std::map map = {{1, "one"}, {2, "two"}}; EXPECT_EQ(toString(map, " => "), "{1: one => 2: two}"); - + auto tuple = std::make_tuple(1, "hello", 3.14); EXPECT_EQ(toString(tuple, "; "), "(1; hello; 3.140000)"); } @@ -404,7 +404,7 @@ TEST_F(ToStringTest, NestedComplexStructures) { {2, {4, 5, 6}} }; EXPECT_EQ(toString(map_of_vecs), "{1: [1, 2, 3], 2: [4, 5, 6]}"); - + // Vector of optionals std::vector> vec_of_opts = { std::optional{1}, @@ -412,15 +412,15 @@ TEST_F(ToStringTest, NestedComplexStructures) { std::optional{3} }; EXPECT_EQ(toString(vec_of_opts), "[Optional(1), nullopt, Optional(3)]"); - + // Optional of vector std::optional> opt_vec = std::vector{1, 2, 3}; EXPECT_EQ(toString(opt_vec), "Optional([1, 2, 3])"); - + // Variant of container std::variant> var_vec = std::vector{1, 2, 3}; EXPECT_EQ(toString(var_vec), "[1, 2, 3]"); - + // Tuple with complex elements auto complex_tuple = std::make_tuple( std::vector{1, 2, 3}, @@ -434,15 +434,15 @@ TEST_F(ToStringTest, NestedComplexStructures) { TEST_F(ToStringTest, PointersToContainers) { auto vec_ptr = std::make_shared>(std::vector{1, 2, 3}); std::string result = toString(vec_ptr); - + EXPECT_THAT(result, StartsWith("SmartPointer(")); EXPECT_THAT(result, HasSubstr("[1, 2, 3]")); - + // Raw pointer to container std::vector vec = {1, 2, 3}; std::vector* raw_ptr = &vec; result = toString(raw_ptr); - + EXPECT_THAT(result, StartsWith("Pointer(")); EXPECT_THAT(result, HasSubstr("[1, 2, 3]")); } @@ -455,7 +455,7 @@ TEST_F(ToStringTest, ErrorInContainers) { nullptr, std::make_shared(3) }; - + std::string result = toString(vec); EXPECT_THAT(result, HasSubstr("[SmartPointer")); EXPECT_THAT(result, HasSubstr("nullptr")); @@ -478,20 +478,20 @@ TEST_F(ToStringTest, RecursiveStructures) { int value; std::shared_ptr next; }; - + auto node1 = std::make_shared(); auto node2 = std::make_shared(); auto node3 = std::make_shared(); - + node1->value = 1; node1->next = node2; - + node2->value = 2; node2->next = node3; - + node3->value = 3; node3->next = nullptr; - + std::string result = toString(node1); EXPECT_THAT(result, HasSubstr("SmartPointer")); EXPECT_THAT(result, HasSubstr("1")); @@ -507,18 +507,18 @@ TEST_F(ToStringTest, LargeStructurePerformance) { for (int i = 0; i < 10000; i++) { large_vec[i] = i; } - + // Measure time to convert to string auto start = std::chrono::high_resolution_clock::now(); std::string result = toString(large_vec); auto end = std::chrono::high_resolution_clock::now(); - + auto duration_ms = std::chrono::duration_cast(end - start).count(); - + // Verify correct conversion EXPECT_THAT(result, StartsWith("[0, 1, 2")); EXPECT_THAT(result, EndsWith("9998, 9999]")); - + // Just log performance - no strict assertion as it will vary by system std::cout << "Converted vector of 10000 elements in " << duration_ms << "ms" << std::endl; } @@ -527,18 +527,18 @@ TEST_F(ToStringTest, LargeStructurePerformance) { TEST_F(ToStringTest, ContainerAdaptors) { // stack, queue, and priority_queue don't satisfy the Container concept directly // but their underlying containers do when accessed properly - + // For testing purposes, we can use a custom adaptor wrapper std::vector vec = {1, 2, 3, 4, 5}; - + // Test with a custom wrapper that simulates container adaptors struct AdaptorWrapper { std::vector& container; - + auto begin() const { return container.begin(); } auto end() const { return container.end(); } }; - + AdaptorWrapper wrapper{vec}; EXPECT_EQ(toString(wrapper), "[1, 2, 3, 4, 5]"); } @@ -560,9 +560,9 @@ TEST_F(ToStringTest, RealWorldExample) { {"absent", std::nullopt} }} }; - + std::string result = toString(complex_data); - + // Check for key components in the result EXPECT_THAT(result, HasSubstr("int_value: 42")); EXPECT_THAT(result, HasSubstr("string_value: hello world")); @@ -575,4 +575,4 @@ TEST_F(ToStringTest, RealWorldExample) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/tests/utils/test_uuid.cpp b/tests/utils/test_uuid.cpp index 3f2a194d..a72fd5fe 100644 --- a/tests/utils/test_uuid.cpp +++ b/tests/utils/test_uuid.cpp @@ -670,4 +670,4 @@ TEST_F(FastUUIDTest, HashMethod) { EXPECT_EQ(uuidMap[uuid3], 3); } -#endif \ No newline at end of file +#endif diff --git a/tests/utils/test_valid_string.hpp b/tests/utils/test_valid_string.hpp index 9d8aeeae..8762a6c2 100644 --- a/tests/utils/test_valid_string.hpp +++ b/tests/utils/test_valid_string.hpp @@ -537,9 +537,9 @@ TEST_F(ValidStringTest, ProgrammingSyntax) { // SQL like syntax std::string sqlCode = R"( - SELECT * FROM users + SELECT * FROM users WHERE (age > 18) AND ( - status = 'active' OR + status = 'active' OR (registration_date > '2023-01-01') ) )"; diff --git a/tests/utils/test_xml.hpp b/tests/utils/test_xml.hpp index 68255f11..aeb6fc47 100644 --- a/tests/utils/test_xml.hpp +++ b/tests/utils/test_xml.hpp @@ -570,4 +570,4 @@ TEST_F(XMLReaderTest, ComplexXML) { int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); -} \ No newline at end of file +} diff --git a/tests/web/test_address.hpp b/tests/web/test_address.hpp index 6d899370..4bbefe97 100644 --- a/tests/web/test_address.hpp +++ b/tests/web/test_address.hpp @@ -39,22 +39,22 @@ TEST_F(UnixDomainTest, GetBroadcastAddressLogsWarning) { logOutput = message.message; return false; }); - + // Redirect the ERROR messages to our capture handler loguru::g_stderr_verbosity = loguru::Verbosity_OFF; - loguru::add_callback("test_callback", + loguru::add_callback("test_callback", [&logOutput](void*, const loguru::Message& message) { logOutput = message.message; - }, + }, loguru::Verbosity_WARNING); - + // Execute the method that should log a warning UnixDomain unixDomain("/tmp/test.sock"); unixDomain.getBroadcastAddress("255.255.255.0"); - + // Check if the log contains the expected warning message EXPECT_THAT(logOutput, HasSubstr("getBroadcastAddress operation not applicable for Unix domain sockets")); - + // Clean up loguru::remove_callback("test_callback"); } @@ -62,7 +62,7 @@ TEST_F(UnixDomainTest, GetBroadcastAddressLogsWarning) { // Test getBroadcastAddress with different types of masks TEST_F(UnixDomainTest, GetBroadcastAddressWithDifferentMasks) { UnixDomain unixDomain("/tmp/test.sock"); - + // Test with various mask formats EXPECT_TRUE(unixDomain.getBroadcastAddress("").empty()); EXPECT_TRUE(unixDomain.getBroadcastAddress("255.255.255.0").empty()); @@ -76,7 +76,7 @@ TEST_F(UnixDomainTest, GetBroadcastAddressWithLongPath) { // Create a Unix domain socket with a long path (but still valid) std::string longPath = "/tmp/" + std::string(90, 'a'); UnixDomain unixDomain(longPath); - + EXPECT_TRUE(unixDomain.getBroadcastAddress("255.255.255.0").empty()); } @@ -86,11 +86,11 @@ TEST_F(UnixDomainTest, GetBroadcastAddressAfterDifferentConstructions) { UnixDomain unixDomain1; unixDomain1.parse("/tmp/test1.sock"); EXPECT_TRUE(unixDomain1.getBroadcastAddress("255.255.255.0").empty()); - + // Direct construction with path UnixDomain unixDomain2("/tmp/test2.sock"); EXPECT_TRUE(unixDomain2.getBroadcastAddress("255.255.255.0").empty()); - + // Copy construction UnixDomain unixDomain3(unixDomain2); EXPECT_TRUE(unixDomain3.getBroadcastAddress("255.255.255.0").empty()); @@ -99,15 +99,15 @@ TEST_F(UnixDomainTest, GetBroadcastAddressAfterDifferentConstructions) { // Test interaction between getBroadcastAddress and other methods TEST_F(UnixDomainTest, GetBroadcastAddressInteractionWithOtherMethods) { UnixDomain unixDomain("/tmp/test.sock"); - + // Call other methods before getBroadcastAddress unixDomain.getType(); unixDomain.toBinary(); unixDomain.toHex(); - + // getBroadcastAddress should still return empty string EXPECT_TRUE(unixDomain.getBroadcastAddress("255.255.255.0").empty()); - + // Call methods after getBroadcastAddress EXPECT_EQ(unixDomain.getType(), "UnixDomain"); EXPECT_FALSE(unixDomain.toBinary().empty()); @@ -120,14 +120,14 @@ TEST_F(UnixDomainTest, CompareBroadcastAddressBehaviorWithOtherTypes) { UnixDomain unixDomain("/tmp/test.sock"); IPv4 ipv4("192.168.1.1"); IPv6 ipv6("2001:db8::1"); - + // For Unix domain sockets, getBroadcastAddress should return an empty string EXPECT_TRUE(unixDomain.getBroadcastAddress("255.255.255.0").empty()); - + // For IPv4, getBroadcastAddress should return a valid address EXPECT_FALSE(ipv4.getBroadcastAddress("255.255.255.0").empty()); EXPECT_EQ(ipv4.getBroadcastAddress("255.255.255.0"), "192.168.1.255"); - + // For IPv6, behavior depends on implementation details // (not testing exact result here since it's complex) EXPECT_NO_THROW(ipv6.getBroadcastAddress("ffff:ffff:ffff:ffff::")); @@ -139,7 +139,7 @@ TEST_F(UnixDomainTest, GetBroadcastAddressWithFactoryMethod) { auto address = Address::createFromString("/tmp/test.sock"); ASSERT_NE(address, nullptr); EXPECT_EQ(address->getType(), "UnixDomain"); - + // getBroadcastAddress should return an empty string EXPECT_TRUE(address->getBroadcastAddress("255.255.255.0").empty()); } @@ -153,13 +153,13 @@ TEST_F(UnixDomainTest, GetBroadcastAddressWithShortPath) { // Test multiple consecutive calls to getBroadcastAddress TEST_F(UnixDomainTest, MultipleBroadcastAddressCalls) { UnixDomain unixDomain("/tmp/test.sock"); - + // Call getBroadcastAddress multiple times consecutively EXPECT_TRUE(unixDomain.getBroadcastAddress("255.255.255.0").empty()); EXPECT_TRUE(unixDomain.getBroadcastAddress("255.255.0.0").empty()); EXPECT_TRUE(unixDomain.getBroadcastAddress("255.0.0.0").empty()); EXPECT_TRUE(unixDomain.getBroadcastAddress("0.0.0.0").empty()); - + // Verify the socket path is unchanged EXPECT_EQ(unixDomain.getAddress(), "/tmp/test.sock"); -} \ No newline at end of file +} diff --git a/tests/web/test_httpparser.hpp b/tests/web/test_httpparser.hpp index a341b41a..9cc7ae9b 100644 --- a/tests/web/test_httpparser.hpp +++ b/tests/web/test_httpparser.hpp @@ -180,4 +180,4 @@ TEST_F(HttpHeaderParserTest, BuildResponseWithBody) { EXPECT_EQ(newParser.getBody(), htmlBody); } -#endif // TEST_HTTPPARSER_HPP \ No newline at end of file +#endif // TEST_HTTPPARSER_HPP diff --git a/tests/web/test_minetype.hpp b/tests/web/test_minetype.hpp index a96a0f2b..2dd3335e 100644 --- a/tests/web/test_minetype.hpp +++ b/tests/web/test_minetype.hpp @@ -375,4 +375,4 @@ TEST_F(MimeTypesTest, LenientMode) { }); } -#endif // TEST_MINETYPE_HPP \ No newline at end of file +#endif // TEST_MINETYPE_HPP diff --git a/tests/xmake.lua b/tests/xmake.lua index 3fd79724..485f8ac2 100644 --- a/tests/xmake.lua +++ b/tests/xmake.lua @@ -22,22 +22,22 @@ function add_atom_test(name, files) target("test_" .. name) -- Set target kind to executable set_kind("binary") - + -- Add group for testing set_group("tests") - + -- Add source files add_files(files) - + -- Add dependencies add_deps("atom") - + -- Add packages add_packages("gtest", "loguru") - + -- Output directory set_targetdir("$(buildir)/tests") - + -- Set test target attributes on_run(function(target) os.execv(target:targetfile()) @@ -56,7 +56,7 @@ end target("test") set_kind("phony") set_group("tests") - + on_run(function(target) -- Run all test targets local test_targets = target.project.targets diff --git a/vcpkg.json b/vcpkg.json index fe8cb5d5..612921c7 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -61,4 +61,4 @@ ] } } -} \ No newline at end of file +} diff --git a/xmake.lua b/xmake.lua index f1fa954c..04ef12f7 100644 --- a/xmake.lua +++ b/xmake.lua @@ -77,19 +77,19 @@ task("install") on_run(function() import("core.project.project") import("core.platform.platform") - + -- Set install prefix local prefix = option.get("prefix") or "/usr/local" - + -- Build the project os.exec("xmake build") - + -- Install the project os.exec("xmake install -o " .. prefix) - + cprint("${bright green}Atom has been installed to " .. prefix) end) - + set_menu { usage = "xmake install", description = "Install Atom libraries and headers"