From 626b5a6cd9063b46b8c9347db60031a1577fbebb Mon Sep 17 00:00:00 2001 From: chatlanin Date: Wed, 10 Sep 2025 12:05:43 +0300 Subject: [PATCH] add new concepts and error and warn logger --- README.md | 4 +- bin/examples/concepts/main.cpp | 15 +-- bin/examples/logger/main.cpp | 10 ++ bin/meson.build | 2 +- src/hack/concepts/concepts.hpp | 198 +++++++++++----------------- src/hack/logger/logger.OLD.hpp | 209 ------------------------------ src/hack/logger/logger.hpp | 94 ++++++++++---- src/hack/patterns/ring_buffer.hpp | 4 +- src/hack/utils/color.hpp | 50 +++++++ 9 files changed, 209 insertions(+), 377 deletions(-) delete mode 100644 src/hack/logger/logger.OLD.hpp diff --git a/README.md b/README.md index 5bf9958..6ce1b5f 100755 --- a/README.md +++ b/README.md @@ -14,10 +14,10 @@ + patterns - набор различных паттернов проектирования + security - что-то типа защиты от чего-то + utils - вспомогательные решения для библиотеки ++ logger - реализация логирования -- logger - реализация логирования -- exception - универсальный класс обработки ошибок - iterators - набор разнообразных реализаций итераторов +- exception - универсальный класс обработки ошибок + - задукоментированно с коментариями и примерами - - доки в раборте, нужно делать и разбирать diff --git a/bin/examples/concepts/main.cpp b/bin/examples/concepts/main.cpp index ab66cc0..58b2825 100644 --- a/bin/examples/concepts/main.cpp +++ b/bin/examples/concepts/main.cpp @@ -1,3 +1,4 @@ +#include #include "hack/concepts/concepts.hpp" #include "hack/logger/logger.hpp" @@ -108,12 +109,6 @@ void example_is_any_container(const T& container) hack::log()("Any container with ", container.size(), " elements"); } -template -void example_is_iterable(const T& iterable) -{ - hack::log()("Iterable object"); -} - template void example_is_sized(const T& sized) { @@ -132,12 +127,6 @@ void check_support(const T& value) hack::log()("Type is supported"); } -template -void example_is_contiguous_container(const T& container) -{ - hack::log()("Contiguous memory container"); -} - template requires hack::concepts::can_push_front void example_can_push_front(Container& container, Value&& value) @@ -200,11 +189,9 @@ auto main(int argc, char *argv[]) -> int example_is_fixed_array(fixed_array); example_is_std_array(std_array); example_is_any_container(vec); - example_is_iterable(vec); example_is_sized(vec); check_support(a); check_support(custom); - example_is_contiguous_container(vec); example_can_push_front(list, 0); example_can_push_back(vec, 99); example_can_find(set, 3); diff --git a/bin/examples/logger/main.cpp b/bin/examples/logger/main.cpp index 64cfb3a..802587c 100644 --- a/bin/examples/logger/main.cpp +++ b/bin/examples/logger/main.cpp @@ -3,6 +3,7 @@ #include #include #include "hack/logger/logger.hpp" +#include "hack/patterns/ring_buffer.hpp" auto main(int argc, char *argv[]) -> int { @@ -24,6 +25,9 @@ auto main(int argc, char *argv[]) -> int sti.push(3); std::set si = { 1, 2, 3 }; std::unordered_set usi = { 1, 1, 1 }; + hack::patterns::ring_buffer rb; + rb.create(10); + for (int i = 0; i < 10; ++i) rb.put(i); hack::log().set_devider(", "); hack::log().no_func(); @@ -53,7 +57,13 @@ auto main(int argc, char *argv[]) -> int hack::log().reset(); hack::log().set_devider(", "); hack::log()(sti, 123, true); + hack::log().reset(); + hack::log()("log", 123, sti, false, 1.8f, vs); + hack::warn()("warn"); + hack::error()("error"); + + hack::log()(rb); return 0; } diff --git a/bin/meson.build b/bin/meson.build index cf101b7..73ddb99 100755 --- a/bin/meson.build +++ b/bin/meson.build @@ -5,7 +5,7 @@ executable( # 'examples/math/main.cpp', # 'examples/range/main.cpp', # 'examples/patterns/main.cpp', - 'examples/logger/main.cpp', + 'examples/logger/main.cpp', dependencies : deps, cpp_args: args, include_directories : inc diff --git a/src/hack/concepts/concepts.hpp b/src/hack/concepts/concepts.hpp index b48ef43..2e2dab0 100755 --- a/src/hack/concepts/concepts.hpp +++ b/src/hack/concepts/concepts.hpp @@ -89,6 +89,7 @@ namespace hack::concepts std::same_as> || std::same_as>); + // Адаптеры контейнеров // @brief Проверяет, является ли тип адаптером контейнера // @details Обнаруживает типы-обертки над другими контейнерами: @@ -156,88 +157,7 @@ namespace hack::concepts arr[0]; }; - // Универсальные концепты для категоризации - // @brief Проверяет, является ли тип любым контейнером - // @details Всеобъемлющий концепт для обнаружения контейнеров любого типа: - // - Последовательные контейнеры - // - Ассоциативные контейнеры - // - Адаптеры контейнеров - // - Массивы (C-style и std::array) - // Основной концепт для обобщенных алгоритмов работы с контейнерами - template - concept is_any_container = is_sequence_container || - is_associative_container || - is_unordered_associative_container || - is_container_adapter || - is_fixed_array || - is_std_array; - - // @brief Проверяет, является ли тип итерируемым - // @details Обнаруживает любые типы, по которым можно итерироваться: - // - Контейнеры STL с begin()/end() - // - Массивы (работают с std::begin/std::end) - // - Кортежи (хотя итерирование по ним особое) - // Самый общий концепт для range-based for и алгоритмов - template - concept is_iterable = has_iterator || is_fixed_array || is_tuple_like; - - // @brief Проверяет, имеет ли тип размер - // @details Обнаруживает типы, у которых можно узнать размер: - // - Контейнеры с методом size() - // - Массивы с известным размером - // - Кортежи с известным количеством элементов - // Важно для алгоритмов, требующих предварительного знания размера - template - concept is_sized = has_size || is_fixed_array || is_tuple_like; - - // Концепт для "неподдерживаемых" типов - // @brief Проверяет, является ли тип неподдерживаемым - // @details Обнаруживает типы, которые не входят в известные категории: - // - Пользовательские типы без ожидаемого интерфейса - // - Специфичные типы из сторонних библиотек - // - Типы, для которых нет специализированной обработки - // Используется для static_assert и генерации понятных ошибок - template - concept not_supported = !(std::integral || - std::floating_point || - is_string || - is_any_container || - is_tuple_like || - std::is_pointer_v); - - // @brief Проверяет, является ли тип контейнером с непрерывной памятью - // @details Обнаруживает контейнеры, элементы которых хранятся в непрерывной памяти: - // - std::vector - динамический массив - // - C-style массивы - // - std::array - статический массив - // Критически важно для низкоуровневых операций и взаимодействия с C API - template - concept is_contiguous_container = std::same_as> || - is_fixed_array || - is_std_array; - - // @brief Проверяет, поддерживает ли контейнер добавление в начало - // @details Обнаруживает контейнеры с push_front(): - // - deque, list, forward_list - // Полезно для алгоритмов, работающих с очередями и стеками - template - concept can_push_front = requires(Container c, Value&& v) { c.push_front(std::forward(v)); }; - - // @brief Проверяет, поддерживает ли контейнер добавление в конец - // @details Обнаруживает контейнеры с push_back(): - // - vector, deque, list - // Важно для алгоритмов, которые строят контейнеры последовательно - template - concept can_push_back = requires(Container c, Value&& v) { c.push_back(std::forward(v)); }; - - // @brief Проверяет, поддерживает ли контейнер поиск по ключу - // @details Обнаруживает контейнеры с методом find(): - // - map, set, unordered_map, unordered_set - // Ключевой концепт для алгоритмов поиска и проверки существования элементов - template - concept can_find = requires(Container c, Key&& key) { c.find(std::forward(key)); }; - - // @brief Проверяет, является ли тип bool + // @brief Проверяет, является ли тип bool template concept is_bool = std::is_same_v, bool>; @@ -278,46 +198,76 @@ namespace hack::concepts { s.empty() } -> std::same_as; { s.size() } -> std::convertible_to; }; + + + + // Универсальные концепты для категоризации + // @brief Проверяет, является ли тип любым контейнером + // @details Всеобъемлющий концепт для обнаружения контейнеров любого типа: + // - Последовательные контейнеры + // - Ассоциативные контейнеры + // - Адаптеры контейнеров + // - Массивы (C-style и std::array) + // Основной концепт для обобщенных алгоритмов работы с контейнерами + template + concept is_any_container = is_sequence_container || + is_associative_container || + is_unordered_associative_container || + is_container_adapter || + is_fixed_array || + is_set_like || + is_tuple_like || + is_stack || + is_std_array; + + // @brief Проверяет, имеет ли тип размер + // @details Обнаруживает типы, у которых можно узнать размер: + // - Контейнеры с методом size() + // - Массивы с известным размером + // - Кортежи с известным количеством элементов + // Важно для алгоритмов, требующих предварительного знания размера + template + concept is_sized = has_size || is_fixed_array || is_tuple_like; + + // Концепт для "неподдерживаемых" типов + // @brief Проверяет, является ли тип неподдерживаемым + // @details Обнаруживает типы, которые не входят в известные категории: + // - Пользовательские типы без ожидаемого интерфейса + // - Специфичные типы из сторонних библиотек + // - Типы, для которых нет специализированной обработки + // Используется для static_assert и генерации понятных ошибок + template + concept not_supported = !(is_number || + is_string || + is_bool || + is_any_container || + std::is_pointer_v); + + // @brief Проверяет, поддерживает ли контейнер добавление в начало + // @details Обнаруживает контейнеры с push_front(): + // - deque, list, forward_list + // Полезно для алгоритмов, работающих с очередями и стеками + template + concept can_push_front = requires(Container c, Value&& v) { c.push_front(std::forward(v)); }; + + // @brief Проверяет, поддерживает ли контейнер добавление в конец + // @details Обнаруживает контейнеры с push_back(): + // - vector, deque, list + // Важно для алгоритмов, которые строят контейнеры последовательно + template + concept can_push_back = requires(Container c, Value&& v) { c.push_back(std::forward(v)); }; + + // @brief Проверяет, поддерживает ли контейнер поиск по ключу + // @details Обнаруживает контейнеры с методом find(): + // - map, set, unordered_map, unordered_set + // Ключевой концепт для алгоритмов поиска и проверки существования элементов + template + concept can_find = requires(Container c, Key&& key) { c.find(std::forward(key)); }; + + // для логирования собственных структур + // мало где используется, только в логере для проверки и выдачи сообщения + template + concept has_get_logger_data = requires(T t) { + { t.get_logger_data() }; + }; } - -// namespace hack::concepts -// { -// template -// concept is_map = std::same_as> || -// std::same_as>; -// -// template -// concept is_tuple = requires (T t) { std::tuple_cat(t, std::make_tuple(1, "tuple")); }; -// -// template -// concept is_set = std::same_as>; -// -// template -// concept is_unordered_set = std::same_as>; -// -// template -// concept is_forward_list = std::same_as>; -// -// template -// concept is_string = std::is_convertible_v; -// -// template -// concept is_sequence_container = std::same_as> || std::same_as> || (std::is_array_v && N > 0); -// -// template -// concept is_associative_container = is_map || is_tuple || is_set || is_unordered_set; -// -// -// template -// concept not_defined = !std::enable_if_t || -// is_sequence_container || -// is_map || -// is_tuple || -// is_set || -// is_unordered_set || -// is_forward_list || -// std::is_array() || -// is_string), bool>() == true; -// } - - diff --git a/src/hack/logger/logger.OLD.hpp b/src/hack/logger/logger.OLD.hpp deleted file mode 100644 index aa10697..0000000 --- a/src/hack/logger/logger.OLD.hpp +++ /dev/null @@ -1,209 +0,0 @@ -#pragma once - -#include -#include - -#include "hack/utils/color.hpp" -#include "hack/concepts/concepts.hpp" -#include "hack/iterators/sequence_ostream_iterator.hpp" -#include "hack/iterators/associative_ostream_iterator.hpp" - -#include "hack/patterns/ring_buffer.hpp" - -namespace hack -{ - class log - { - public: - log(std::string devider_ = " ", std::experimental::source_location location_ = std::experimental::source_location::current()) : location { location_ } - { - this->devider = devider_; - } - - log(log&) = delete; - log(log&&) = delete; - - public: - template - void operator() (const Args&... args) - { - count = sizeof...(Args); - prepare(make_type_view, location); - print(args...); - } - - private: - std::experimental::source_location location; - inline static int count = 0; - inline static std::string devider = " "; - - private: - template - void prepare(T t, U u) - { - std::cout << t - << u.file_name() << ":" << utils::color::reset - << utils::color::italic << utils::color::yellow << u.function_name() << "()" << utils::color::reset - << utils::color::bold << utils::color::blue << "[" << u.line() << "]" << utils::color::reset << ": "; - } - - static void print() { std::cout << std::endl; } - - static std::ostream& make_type_view(std::ostream &os) - { - os << utils::color::bold << utils::color::green << "[ok]" << utils::color::reset << utils::color::green; - return os; - } - - template - static void print(const T& data, const Args&... args) - { - --count; - print_t(data); - print(args...); - } - - template - static void print_t(const T& data) - { - std::cout << data << (count != 0 ? devider : ""); - } - - template - static void print_t(const T& data) - { - std::cout << data << (count != 0 ? devider : ""); - } - - template - static void print_t(const T& data) - { - std::cout << "{ "; - std::copy(data.cbegin(), data.cend(), iterators::sequence_ostream_iterator(data.size(), std::cout)); - std::cout << " }" << (count != 0 ? devider : ""); - } - - template - static void print_t(const T& data) - { - std::cout << "{ "; - std::copy(data.cbegin(), data.cend(), iterators::sequence_ostream_iterator(data.size(), std::cout)); - std::cout << " }" << (count != 0 ? devider : ""); - } - - template - static void print_t(const T& data) - { - std::cout << "{ "; - std::copy(data.cbegin(), data.cend(), iterators::sequence_ostream_iterator(data.size(), std::cout)); - std::cout << " }" << (count != 0 ? devider : ""); - } - - template - static void print_t(const T& data) - { - std::cout << "{ "; - std::copy(data.cbegin(), data.cend(), iterators::sequence_ostream_iterator(std::distance(data.cbegin(), data.cend()), std::cout)); - std::cout << " }" << (count != 0 ? devider : ""); - } - - template - static void print_t(const T& data) - { - std::cout << "{"; - std::copy(data.begin(), data.cend(), iterators::associative_ostream_iterator(data.size(), std::cout)); - std::cout << "}" << (count != 0 ? devider : ""); - } - - template - static void print_t(const T& data) - { - print_t(data, std::make_index_sequence::value>{}); - } - - template - static void print_t(const T& data, std::index_sequence) - { - std::cout << "{ "; - ((std::cout << std::get(data) << (idx != std::tuple_size::value - 1 ? devider : "")), ...); - std::cout << " }" << (count != 0 ? devider : ""); - } - - template - static void print_t(const T& data) - { - std::cout << data << (count != 0 ? devider : ""); - } - - template - static void print_t(const hack::patterns::ring_buffer& rb) - { - print_t(rb.get_src()); - } - - friend class warn; - friend class error; - }; - - class warn : public log - { - public: - warn(std::string devider_ = " ", std::experimental::source_location location_ = std::experimental::source_location::current()) : location { location_ } - { - this->devider = devider_; - } - - warn(warn&) = delete; - warn(warn&&) = delete; - - public: - template - void operator() (const Args&... args) - { - prepare(make_type_view, location); - count = sizeof...(Args); - print(args...); - } - - private: - std::experimental::source_location location; - - private: - static std::ostream& make_type_view(std::ostream &os) - { - os << utils::color::bold << utils::color::yellow << "[WARN]" << utils::color::reset << utils::color::yellow; - return os; - } - }; - - class error : public log - { - public: - error(std::string devider_ = " ", std::experimental::source_location location_ = std::experimental::source_location::current()) : location { location_ } - { - this->devider = devider_; - } - error(error&) = delete; - error(error&&) = delete; - - public: - template - void operator() (const Args&... args) - { - prepare(make_type_view, location); - count = sizeof...(Args); - print(args...); - } - - private: - std::experimental::source_location location; - - private: - static std::ostream& make_type_view(std::ostream &os) - { - os << utils::color::bold << utils::color::red << "[ERROR]" << utils::color::reset << utils::color::red; - return os; - } - }; -} - diff --git a/src/hack/logger/logger.hpp b/src/hack/logger/logger.hpp index 0412aa2..918f2b2 100755 --- a/src/hack/logger/logger.hpp +++ b/src/hack/logger/logger.hpp @@ -8,11 +8,6 @@ #include "hack/concepts/concepts.hpp" #include "hack/iterators/sequence_ostream_iterator.hpp" #include "hack/iterators/associative_ostream_iterator.hpp" -#include - -#include -#include -#include // HERE // и нужно сделать реализацию где выводлится все в одной линии но при помощи цикла @@ -38,6 +33,11 @@ namespace hack m_bool_as_number = m_base_config.m_bool_as_number; } + public: + void on_log() { m_type = type::LOG; } + void on_warn() { m_type = type::WARN; } + void on_error() { m_type = type::ERROR; } + public: template void operator() (const Args&... args) @@ -58,17 +58,35 @@ namespace hack std::string m_devider = " "; // разделитель по умолчанию } m_base_config; + enum class type + { + LOG, + WARN, + ERROR + } m_type; + private: void prepare() { std::stringstream ss; - ss << utils::color::bold << utils::color::green << "[ok] " << utils::color::reset; + switch(m_type) + { + case type::LOG: + ss << utils::color::bold << utils::color::green << "[ok] " << utils::color::reset; + break; + case type::WARN: + ss << utils::color::bold << utils::color::magenta << "[WARN]" << utils::color::reset; + break; + case type::ERROR: + ss << utils::color::bold << utils::color::red << "[ERROR]" << utils::color::reset; + break; + } if (!m_no_file) ss << utils::color::green << m_location.file_name() << ":" << utils::color::reset; if (!m_no_func) - ss << utils::color::italic << utils::color::yellow << m_location.function_name() << utils::color::reset; + ss << utils::color::italic << utils::color::yellow<< m_location.function_name() << utils::color::reset; if (!m_no_row) ss << utils::color::bold << utils::color::blue << "[" << m_location.line() << "] " << utils::color::reset; @@ -171,25 +189,35 @@ namespace hack } // Для stack - выводим содержимое (но stack нельзя итерировать!) - template - void print_t(const T& stack) - { - T temp = stack; - - std::cout << "{ "; - - bool first = true; - while (!temp.empty()) + template + void print_t(const T& stack) { - if (!first) - std::cout << m_devider; - first = false; - std::cout << temp.top(); - temp.pop(); + T temp = stack; + + std::cout << "{ "; + + bool first = true; + while (!temp.empty()) + { + if (!first) + std::cout << m_devider; + first = false; + std::cout << temp.top(); + temp.pop(); + } + + std::cout << " }" << (m_count != 0 ? m_devider : ""); + } + + // для пользовательских типов + // у них должен быть отпределен метод get_data() + // возвращающий один из обработанных типов + template + void print_t(const T& rb) + { + static_assert(concepts::has_get_logger_data, "Type must have get_logger_data() method that returns value_type"); + print_t(rb.get_logger_data()); } - - std::cout << " }" << (m_count != 0 ? m_devider : ""); - } private: std::source_location m_location; @@ -199,12 +227,30 @@ namespace hack bool m_no_file = m_base_config.m_no_file; bool m_no_row = m_base_config.m_no_row; bool m_bool_as_number = m_base_config.m_bool_as_number; + + friend class warn; + friend class error; }; // основная функция вызова логера inline logger& log(std::source_location location = std::source_location::current()) { logger::instance().set_location(location); + logger::instance().on_log(); + return logger::instance(); + } + + inline logger& warn(std::source_location location = std::source_location::current()) + { + logger::instance().set_location(location); + logger::instance().on_warn(); + return logger::instance(); + } + + inline logger& error(std::source_location location = std::source_location::current()) + { + logger::instance().set_location(location); + logger::instance().on_error(); return logger::instance(); } } diff --git a/src/hack/patterns/ring_buffer.hpp b/src/hack/patterns/ring_buffer.hpp index 7e9a4b9..ba553c8 100644 --- a/src/hack/patterns/ring_buffer.hpp +++ b/src/hack/patterns/ring_buffer.hpp @@ -10,8 +10,6 @@ namespace hack::patterns { // Колцевой буфер. - // HERE - // сделать опсание каждой функции template class ring_buffer { @@ -91,7 +89,7 @@ namespace hack::patterns } } - std::vector& get_src() const noexcept + const std::vector& get_logger_data() const noexcept { return m_data; } diff --git a/src/hack/utils/color.hpp b/src/hack/utils/color.hpp index 6173e3f..40e633e 100755 --- a/src/hack/utils/color.hpp +++ b/src/hack/utils/color.hpp @@ -10,6 +10,7 @@ namespace hack::utils::color return os << "\033[0m"; } + // вид template std::basic_ostream& bold(std::basic_ostream &os) { @@ -28,6 +29,13 @@ namespace hack::utils::color return os << "\033[30m"; } + template + std::basic_ostream& underline(std::basic_ostream &os) + { + return os << "\033[4m"; + } + + // цвета template std::basic_ostream& red(std::basic_ostream &os) { @@ -69,4 +77,46 @@ namespace hack::utils::color { return os << "\033[37m"; } + + template + std::basic_ostream& gray(std::basic_ostream &os) + { + return os << "\033[90m"; // Яркий черный = серый + } + + template + std::basic_ostream& dark_gray(std::basic_ostream &os) + { + return os << "\033[30m"; // Темно-серый + } + + template + std::basic_ostream& brown(std::basic_ostream &os) + { + return os << "\033[33m"; // Коричневый (желтый) + } + + template + std::basic_ostream& orange(std::basic_ostream &os) + { + return os << "\033[38;5;208m"; // Оранжевый (256 цветов) + } + + template + std::basic_ostream& light_blue(std::basic_ostream &os) + { + return os << "\033[94m"; // Голубой (яркий синий) + } + + template + std::basic_ostream& violet(std::basic_ostream &os) + { + return os << "\033[95m"; // Фиолетовый (яркий пурпурный) + } + + template + std::basic_ostream& purple(std::basic_ostream &os) + { + return os << "\033[35m"; // Пурпурный + } }