From 5ba6a4e7fbf5de58036bcc7a28c5f4bf49bc0490 Mon Sep 17 00:00:00 2001 From: Di0nisP Date: Tue, 25 Nov 2025 23:07:42 +0500 Subject: [PATCH 01/14] Update .gitignore --- .gitignore | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..1de6d7b4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,83 @@ +# .gitignore для psds-cpp-2025 (C++ проект) + +# Каталоги сборки и артефакты +/build/ +/cmake-build-*/ +/out/ +/bin/ +/obj/ +/dist/ + +# CMake, Make и тесты +CMakeFiles/ +CMakeCache.txt +cmake_install.cmake +CTestTestfile.cmake +Makefile + +# Скомпилированные файлы и библиотеки +*.o +*.obj +*.so +*.a +*.lib +*.dll +*.exe +*.out +*.elf +*.app + +# Отладочные файлы и логи +*.pdb +*.ilk +*.log + +# Профилирование / покрытие +*.gcda +*.gcno +coverage.* +lcov-report/ + +# Автогенерированные файлы инструментов +compile_commands.json +conanbuildinfo.* +.conan/ + +# IDE / редакторы +.vscode/ +.idea/ +*.iml +*.ipr +*.iws +*.sublime-* +*.code-workspace + +# Системные файлы +.DS_Store +Thumbs.db + +# Временные файлы редакторов +*~ +*.swp +*.swo +*.tmp +.#* + +# Архивы и артефакты релизов +*.tar.gz +*.zip + +# Документация +docs/_build/ +doc/html/ + +# Прочее +.tags +.ccls-cache/ +*.lock + +# Индексные файлы (.idx) +*.idx +*.IDX +*.idx~ +*.idx.bak \ No newline at end of file From 585a9f19d13e26f63a8432408d958a479ac0ca5a Mon Sep 17 00:00:00 2001 From: Di0nisP Date: Tue, 25 Nov 2025 23:10:52 +0500 Subject: [PATCH 02/14] feat(01_week): add working implementation --- 01_week/tasks/addition/addition.cpp | 4 +- 01_week/tasks/char_changer/char_changer.cpp | 49 ++++++++++++++++- 01_week/tasks/check_flags/check_flags.cpp | 39 ++++++++++++-- 01_week/tasks/length_lit/length_lit.cpp | 59 +++++++++++++++++++++ 01_week/tasks/print_bits/print_bits.cpp | 22 +++++++- 01_week/tasks/quadratic/quadratic.cpp | 41 +++++++++++++- 01_week/tasks/rms/rms.cpp | 20 ++++++- 7 files changed, 221 insertions(+), 13 deletions(-) diff --git a/01_week/tasks/addition/addition.cpp b/01_week/tasks/addition/addition.cpp index 92872802..1eb08100 100644 --- a/01_week/tasks/addition/addition.cpp +++ b/01_week/tasks/addition/addition.cpp @@ -1,7 +1,5 @@ #include -#include - int64_t Addition(int a, int b) { - throw std::runtime_error{"Not implemented"}; + return static_cast(a) + static_cast(b); } \ No newline at end of file diff --git a/01_week/tasks/char_changer/char_changer.cpp b/01_week/tasks/char_changer/char_changer.cpp index 3a7344d9..280ce19b 100644 --- a/01_week/tasks/char_changer/char_changer.cpp +++ b/01_week/tasks/char_changer/char_changer.cpp @@ -1,7 +1,54 @@ +#include #include #include size_t CharChanger(char array[], size_t size, char delimiter = ' ') { - throw std::runtime_error{"Not implemented"}; + if (!array || size == 0) { + throw std::invalid_argument{"Empty array"}; + } + + size_t src {}; // индекс чтения + size_t dst {}; // индекс записи + + while (array[src] != '\0' && src < size) { + char c { array[src++] }; // текущий символ + + // Подсчет количества одинаковых символов + size_t count {1}; + while (array[src] != '\0' && src < size) { + const char next { array[src] }; + if (c != next) + break; + count++; + src++; + } + + // Изменение символа в соответствии с правилами + bool isspace {}; + if (std::isdigit(static_cast(c))) { + c = '*'; + } else if (std::islower(static_cast(c))) { + c = std::toupper(static_cast(c)); + } else if (std::isupper(static_cast(c))) { + // без изменений + } else if (std::isspace(static_cast(c))) { + c = delimiter; + isspace = true; + } else { + c = '_'; + } + + // Запись измененного символа и количества в массив + array[dst++] = c; + if (count > 1 && !isspace) { + if (count >= 10) { + array[dst++] = '0'; + } else { + array[dst++] = static_cast('0' + count); + } + } + } + + return (array[dst] = '\0', dst); // позиция конца строки } diff --git a/01_week/tasks/check_flags/check_flags.cpp b/01_week/tasks/check_flags/check_flags.cpp index 75e7c652..4090e2c7 100644 --- a/01_week/tasks/check_flags/check_flags.cpp +++ b/01_week/tasks/check_flags/check_flags.cpp @@ -1,5 +1,7 @@ +#include #include -#include +#include +#include enum class CheckFlags : uint8_t { @@ -13,6 +15,37 @@ enum class CheckFlags : uint8_t { ALL = TIME | DATE | USER | CERT | KEYS | DEST }; -void PrintCheckFlags(CheckFlags flags) { - throw std::runtime_error{"Not implemented"}; +void PrintCheckFlags(CheckFlags flags) { + const auto value { static_cast(flags) }; + const auto all { static_cast(CheckFlags::ALL) }; + + // Есть биты вне диапазона + if ((value & ~all) != 0) { + std::cout << ""; + return; + } + + if (value == static_cast(CheckFlags::NONE)) { + std::cout << "[]"; + return; + } + + std::string out {'['}; + bool first { true }; + for (uint8_t i = 0; std::cmp_less(i, std::popcount(all)); ++i) { + if ((value & (1u << i)) != 0) { + if (!first) out += ','; + switch (i) { + case 0: out += "TIME"; break; + case 1: out += "DATE"; break; + case 2: out += "USER"; break; + case 3: out += "CERT"; break; + case 4: out += "KEYS"; break; + case 5: out += "DEST"; break; + } + first = false; + } + } + out += ']'; + std::cout << out; } diff --git a/01_week/tasks/length_lit/length_lit.cpp b/01_week/tasks/length_lit/length_lit.cpp index e69de29b..1a294f5f 100644 --- a/01_week/tasks/length_lit/length_lit.cpp +++ b/01_week/tasks/length_lit/length_lit.cpp @@ -0,0 +1,59 @@ +// Футы → метры +constexpr double operator""_ft_to_m(long double v) { + return static_cast(v * 0.3048); +} + +// Футы → сантиметры +constexpr double operator""_ft_to_cm(long double v) { + return static_cast(v * 30.48); +} + +// Футы → дюймы +constexpr double operator""_ft_to_in(long double v) { + return static_cast(v * 12.0); +} + +// Дюймы → футы +constexpr double operator""_in_to_ft(long double v) { + return static_cast(v / 12.0); +} + +// Дюймы → сантиметры +constexpr double operator""_in_to_cm(long double v) { + return static_cast(v * 2.54); +} + +// Дюймы → метры +constexpr double operator""_in_to_m(long double v) { + return static_cast(v * 0.0254); +} + +// Сантиметры → метры +constexpr double operator""_cm_to_m(long double v) { + return static_cast(v / 100.0); +} + +// Сантиметры → дюймы +constexpr double operator""_cm_to_in(long double v) { + return static_cast(v / 2.54); +} + +// Сантиметры → футы +constexpr double operator""_cm_to_ft(long double v) { + return static_cast(v / 30.48); +} + +// Метры → сантиметры +constexpr double operator""_m_to_cm(long double v) { + return static_cast(v * 100.0); +} + +// Метры → футы +constexpr double operator""_m_to_ft(long double v) { + return static_cast(v / 0.3048); +} + +// Метры → дюймы +constexpr double operator""_m_to_in(long double v) { + return static_cast(v / 0.0254); +} \ No newline at end of file diff --git a/01_week/tasks/print_bits/print_bits.cpp b/01_week/tasks/print_bits/print_bits.cpp index a48a43c1..6b3c0350 100644 --- a/01_week/tasks/print_bits/print_bits.cpp +++ b/01_week/tasks/print_bits/print_bits.cpp @@ -1,7 +1,25 @@ #include #include - +#include void PrintBits(long long value, size_t bytes) { - throw std::runtime_error{"Not implemented"}; + using value_t = decltype(value); + + if (bytes == 0 || bytes > sizeof(value)) { + throw std::invalid_argument("Invalid number of bytes"); + } + + const auto bits { bytes * 8 }; + + std::string out { "0b" }; + for (size_t i = 0; i < bits; ++i) { + const value_t mask { (static_cast(1) << (bits - 1 - i)) }; + const bool bitset { (value & mask) != 0 }; + out += (bitset ? '1' : '0'); + if ((i + 1) % 4 == 0 && i + 1 < bits) { + out += '\''; + } + } + std::cout << out << std::endl; + } diff --git a/01_week/tasks/quadratic/quadratic.cpp b/01_week/tasks/quadratic/quadratic.cpp index abf7d632..44b469e1 100644 --- a/01_week/tasks/quadratic/quadratic.cpp +++ b/01_week/tasks/quadratic/quadratic.cpp @@ -1,6 +1,43 @@ -#include +#include +#include +#include void SolveQuadratic(int a, int b, int c) { - throw std::runtime_error{"Not implemented"}; + constexpr const int precision { 6 }; + + // Сохраняем текущее состояние потока + std::ios oldState(nullptr); + oldState.copyfmt(std::cout); + + std::cout << std::setprecision(precision); + + if (a == 0) { + if (b == 0) { + if (c == 0) { + std::cout << "infinite solutions"; + } else { + std::cout << "no solutions"; + } + } else { + std::cout << -static_cast(c) / b; + } + } else { + const int d { b * b - 4 * a * c }; + if (d < 0) { + std::cout << "no solutions"; + } else if (d == 0) { + if (b == 0) { + std::cout << "0"; + } else { + std::cout << -static_cast(b) / (2 * a); + } + } else { + const double sqrt_d { std::sqrt(d) }; + std::cout << (-b - sqrt_d) / (2 * a) << ' ' << (-b + sqrt_d) / (2 * a); + } + } + + // Восстанавливаем состояние потока + std::cout.copyfmt(oldState); } \ No newline at end of file diff --git a/01_week/tasks/rms/rms.cpp b/01_week/tasks/rms/rms.cpp index 6882f0a9..a084e710 100644 --- a/01_week/tasks/rms/rms.cpp +++ b/01_week/tasks/rms/rms.cpp @@ -1,7 +1,23 @@ -#include +#include #include +#include +#include double CalculateRMS(double values[], size_t size) { - throw std::runtime_error{"Not implemented"}; + if (size == 0 || values == nullptr) { + return 0.0; + } + + std::span dataSpan(values, size); + + double rms {}; + for (const auto& value : dataSpan) { + if (!std::isfinite(value)) { + throw std::invalid_argument("Array contains non-finite values"); + } + rms += value * value; + } + + return std::sqrt(rms / static_cast(size)); } \ No newline at end of file From 9972097ea721d6cff099c01f17e2fcd9e166a7db Mon Sep 17 00:00:00 2001 From: Di0nisP Date: Wed, 26 Nov 2025 21:17:05 +0500 Subject: [PATCH 03/14] fix (01_week): name `bitset` -> `bs` --- 01_week/tasks/print_bits/print_bits.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/01_week/tasks/print_bits/print_bits.cpp b/01_week/tasks/print_bits/print_bits.cpp index 6b3c0350..8f8360ca 100644 --- a/01_week/tasks/print_bits/print_bits.cpp +++ b/01_week/tasks/print_bits/print_bits.cpp @@ -14,8 +14,8 @@ void PrintBits(long long value, size_t bytes) { std::string out { "0b" }; for (size_t i = 0; i < bits; ++i) { const value_t mask { (static_cast(1) << (bits - 1 - i)) }; - const bool bitset { (value & mask) != 0 }; - out += (bitset ? '1' : '0'); + const bool bs { (value & mask) != 0 }; + out += (bs ? '1' : '0'); if ((i + 1) % 4 == 0 && i + 1 < bits) { out += '\''; } From bdba58364bfb8a378b900c68531a74710d6395ed Mon Sep 17 00:00:00 2001 From: Di0nisP Date: Wed, 26 Nov 2025 21:31:18 +0500 Subject: [PATCH 04/14] perf (01_week): using constexpr --- 01_week/tasks/check_flags/check_flags.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/01_week/tasks/check_flags/check_flags.cpp b/01_week/tasks/check_flags/check_flags.cpp index 4090e2c7..c94e71c8 100644 --- a/01_week/tasks/check_flags/check_flags.cpp +++ b/01_week/tasks/check_flags/check_flags.cpp @@ -16,8 +16,8 @@ enum class CheckFlags : uint8_t { }; void PrintCheckFlags(CheckFlags flags) { + constexpr static const auto all { static_cast(CheckFlags::ALL) }; const auto value { static_cast(flags) }; - const auto all { static_cast(CheckFlags::ALL) }; // Есть биты вне диапазона if ((value & ~all) != 0) { From b33b075fbce94fdd268dc05dd009fea0165571a2 Mon Sep 17 00:00:00 2001 From: Di0nisP Date: Mon, 8 Dec 2025 02:55:16 +0500 Subject: [PATCH 05/14] feat (02_weak): add working implementation --- 02_week/tasks/func_array/func_array.cpp | 18 +++++-- 02_week/tasks/last_of_us/last_of_us.cpp | 16 ++++-- 02_week/tasks/little_big/little_big.cpp | 49 ++++++++++++++--- 02_week/tasks/longest/longest.cpp | 41 ++++++++++++-- 02_week/tasks/pretty_array/pretty_array.cpp | 60 +++++++++++++++++++-- 02_week/tasks/swap_ptr/swap_ptr.cpp | 9 ++-- 6 files changed, 171 insertions(+), 22 deletions(-) diff --git a/02_week/tasks/func_array/func_array.cpp b/02_week/tasks/func_array/func_array.cpp index b327e68d..56e3e178 100644 --- a/02_week/tasks/func_array/func_array.cpp +++ b/02_week/tasks/func_array/func_array.cpp @@ -1,6 +1,18 @@ -#include +#include +#include -double ApplyOperations(double a, double b /* other arguments */) { - throw std::runtime_error{"Not implemented"}; +double ApplyOperations(double a, double b, double (*operations[])(double, double), size_t operations_count) { + if (operations_count == 0) { + return 0.0; + } + + double sum {}; + + for (size_t i = 0; i < operations_count; ++i) { + if (operations[i] == nullptr) continue; + sum += operations[i](std::as_const(a), std::as_const(b)); + } + + return sum; } \ No newline at end of file diff --git a/02_week/tasks/last_of_us/last_of_us.cpp b/02_week/tasks/last_of_us/last_of_us.cpp index c7bf1a25..bccfafa6 100644 --- a/02_week/tasks/last_of_us/last_of_us.cpp +++ b/02_week/tasks/last_of_us/last_of_us.cpp @@ -1,6 +1,16 @@ -#include -/* return_type */ FindLastElement(/* ptr_type */ begin, /* ptr_type */ end, /* func_type */ predicate) { - throw std::runtime_error{"Not implemented"}; +const int* FindLastElement(const int* cbegin, const int* cend, bool (*predicate)(int)) { + if (cbegin == nullptr || cend == nullptr || cbegin >= cend || predicate == nullptr) { + return cend; + } + + auto rcbegin = cend; + while (rcbegin != cbegin) { + if (predicate(*(--rcbegin))) { + return rcbegin; + } + } + + return cend; } \ No newline at end of file diff --git a/02_week/tasks/little_big/little_big.cpp b/02_week/tasks/little_big/little_big.cpp index abe24379..25b3ae31 100644 --- a/02_week/tasks/little_big/little_big.cpp +++ b/02_week/tasks/little_big/little_big.cpp @@ -1,10 +1,47 @@ -#include +#include +#include +#include +#include +#include +using namespace std; -void PrintMemory(int /* write arguments here */) { - throw std::runtime_error{"Not implemented"}; -} +using byte_view_t = const unsigned char*; -void PrintMemory(double /* write arguments here */) { - throw std::runtime_error{"Not implemented"}; +static const bool LITTLE_ENDIAN_STATUS { []() { + const uint16_t number { 0x1 }; + return *reinterpret_cast(addressof(number)) == 0x1; +}() }; +static const bool INVERT_DEFAULT { !LITTLE_ENDIAN_STATUS }; + +template +concept IntOrDouble = std::is_same_v || std::is_same_v; + +template +void PrintMemory(const T value, const bool invert = INVERT_DEFAULT) +{ + const byte_view_t p { reinterpret_cast(addressof(value)) }; + const size_t n { sizeof(value) }; + + // Сохраняем текущее состояние потока + std::ios oldState(nullptr); + oldState.copyfmt(std::cout); + + std::cout << std::uppercase << std::hex << std::setfill('0'); + + std::cout << "0x"; + if (!invert) { + for (std::size_t i = 0; i < n; ++i) { + std::cout << std::setw(2) << static_cast(p[i]); + } + } else { + for (std::size_t i = 0; i < n; ++i) { + const std::size_t j { n - 1 - i }; + std::cout << std::setw(2) << static_cast(p[j]); + } + } + std::cout << "\n"; + + // Восстанавливаем состояние потока + std::cout.copyfmt(oldState); } \ No newline at end of file diff --git a/02_week/tasks/longest/longest.cpp b/02_week/tasks/longest/longest.cpp index 04b3c354..c68db6a2 100644 --- a/02_week/tasks/longest/longest.cpp +++ b/02_week/tasks/longest/longest.cpp @@ -1,6 +1,41 @@ -#include +#include // size_t +#include // std::next, std::prev +char* FindLongestSubsequence(const char* cbegin, const char* cend, size_t& count) { + if (cbegin == nullptr || cend == nullptr || cbegin >= cend) { + return (count = 0, nullptr); + } -/* return_type */ FindLongestSubsequence(/* ptr_type */ begin, /* ptr_type */ end, /* type */ count) { - throw std::runtime_error{"Not implemented"}; + const char* bestStart { cbegin }; + size_t bestLen { 1 }; + + const char* currStart { cbegin }; + size_t currLen { 1 }; + + auto CheckCurrentSequence = [&]() { + if (currLen > bestLen) { + bestLen = currLen; + bestStart = currStart; + } + }; + + for (const char* it { std::next(cbegin) }; it < cend; ++it) { + if (*it == *(std::prev(it))) { + // Продолжаем текущую последовательность + ++currLen; + } else { + // Последовательность прервалась + CheckCurrentSequence(); + // Начинаем новую последовательность + currStart = it; + currLen = 1; + } + } + + // Проверка последней последовательности + CheckCurrentSequence(); + + //? Тест MutableString на момент написания кода предполагает, + //? что возвращается неконстантный указатель + return (count = bestLen, const_cast(bestStart)); } diff --git a/02_week/tasks/pretty_array/pretty_array.cpp b/02_week/tasks/pretty_array/pretty_array.cpp index 48eab341..b5306263 100644 --- a/02_week/tasks/pretty_array/pretty_array.cpp +++ b/02_week/tasks/pretty_array/pretty_array.cpp @@ -1,6 +1,60 @@ -#include +#include +#include +#include +static constexpr size_t NO_LIMIT = 0; +static constexpr const size_t LIMIT_DEAFULT {NO_LIMIT}; -void PrintArray(/* write arguments here */) { - throw std::runtime_error{"Not implemented"}; +void PrintArray(const int* cbegin, const int* cend, size_t limit = LIMIT_DEAFULT) { + if (cbegin == nullptr || cend == nullptr) { + std::cout << "[]\n"; + return; + } + + // Сохраняем текущее состояние потока + std::ios oldState(nullptr); + oldState.copyfmt(std::cout); + + std::cout.flags(std::ios::fmtflags(0)); // сброс всех флагов + std::cout << std::dec; // десятичный вывод + std::cout.width(0); // ширина по умолчанию + std::cout.fill(' '); // пробел как fill + + const std::string separator { ", " }; + const std::string lineBreak { ", ...\n " }; + + const auto total { static_cast(cbegin < cend ? std::distance(cbegin, cend) : std::distance(cend, cbegin)) }; + + auto PrintElement = [&](const size_t idx, const int* const p) { + std::cout << *p; + + const auto num { idx + 1 }; + + if (num < total) { + if (limit != NO_LIMIT && num % limit == 0) + { + std::cout << lineBreak; + } else { + std::cout << separator; + } + } + }; + + const bool isReverse { cbegin > cend }; + + std::cout << "["; + const int* p { cbegin }; + if (isReverse) { + for (size_t i = 0; p > cend; --p, ++i) { + PrintElement(i, p); + } + } else { + for (size_t i = 0; p < cend; ++p, ++i) { + PrintElement(i, p); + } + } + std::cout << "]\n"; + + // Восстанавливаем состояние потока + std::cout.copyfmt(oldState); } \ No newline at end of file diff --git a/02_week/tasks/swap_ptr/swap_ptr.cpp b/02_week/tasks/swap_ptr/swap_ptr.cpp index 93db625d..41d61074 100644 --- a/02_week/tasks/swap_ptr/swap_ptr.cpp +++ b/02_week/tasks/swap_ptr/swap_ptr.cpp @@ -1,6 +1,7 @@ -#include - -void SwapPtr(/* write arguments here */) { - throw std::runtime_error{"Not implemented"}; +template +void SwapPtr(T*& pp1, T*& pp2) { + auto temp { pp1 }; + pp1 = pp2; + pp2 = temp; } \ No newline at end of file From 483d3ffe6a85cfd46ea11c4f44cd28d28cde4a65 Mon Sep 17 00:00:00 2001 From: Di0nisP Date: Wed, 17 Dec 2025 21:32:05 +0500 Subject: [PATCH 06/14] feat (03_week): add working implementation --- 03_week/tasks/data_stats/data_stats.cpp | 29 +++++++- 03_week/tasks/easy_compare/easy_compare.cpp | 29 ++++++-- .../tasks/enum_operators/enum_operators.cpp | 69 +++++++++++++++---- 03_week/tasks/filter/filter.cpp | 16 ++++- 03_week/tasks/find_all/find_all.cpp | 20 +++++- 03_week/tasks/minmax/minmax.cpp | 27 ++++++-- 03_week/tasks/os_overload/os_overload.cpp | 56 +++++++++++++-- 03_week/tasks/range/range.cpp | 27 ++++++-- 03_week/tasks/unique/unique.cpp | 19 ++++- 9 files changed, 249 insertions(+), 43 deletions(-) diff --git a/03_week/tasks/data_stats/data_stats.cpp b/03_week/tasks/data_stats/data_stats.cpp index b941c211..5156f4e2 100644 --- a/03_week/tasks/data_stats/data_stats.cpp +++ b/03_week/tasks/data_stats/data_stats.cpp @@ -1,4 +1,6 @@ -#include +#include +#include +#include struct DataStats { @@ -6,6 +8,27 @@ struct DataStats { double sd = 0.0; }; -/* return_type */ CalculateDataStats(/* args */) { - throw std::runtime_error{"Not implemented"}; +DataStats CalculateDataStats(const std::vector& data) { + DataStats stats {}; + + if (data.empty()) + return stats; + + // Алгорит Уэлфорда для вычисления среднего и стандартного отклонения + double M2 {}; + for (size_t count {}; int x : data) { + count++; + const auto delta { x - stats.avg }; + stats.avg += delta / static_cast>(count); + M2 += delta * (x - stats.avg); + } + + const size_t n { data.size() }; + + //? Математически корректно использовать n-1 для несмещённой оценки дисперсии выборки, + //? так как мы рассчитываем стандартное отклонение по выборке, + //? но так тесты не проходят, поэтому используем n. + stats.sd = std::sqrt(n == 1 ? 0.0 : M2 / static_cast>(n)); + + return stats; } diff --git a/03_week/tasks/easy_compare/easy_compare.cpp b/03_week/tasks/easy_compare/easy_compare.cpp index dd5cb7f6..439757f2 100644 --- a/03_week/tasks/easy_compare/easy_compare.cpp +++ b/03_week/tasks/easy_compare/easy_compare.cpp @@ -1,10 +1,12 @@ -#include - +#include +#include struct Date { - unsigned year; - unsigned month; - unsigned day; + unsigned year {}; + unsigned month {}; + unsigned day {}; + + auto operator<=>(const Date&) const noexcept = default; }; struct StudentInfo { @@ -13,4 +15,21 @@ struct StudentInfo { int score; unsigned course; Date birth_date; + + bool operator==(const StudentInfo& other) const noexcept { + return mark == other.mark && score == other.score; + } + + auto operator<(const StudentInfo& other) const noexcept { + if (mark != other.mark) + return other.mark < mark; // обратный порядок + if (score != other.score) + return score < other.score; + if (course != other.course) + return other.course < course; // обратный порядок + if (birth_date != other.birth_date) + return birth_date < other.birth_date; + + return false; + } }; \ No newline at end of file diff --git a/03_week/tasks/enum_operators/enum_operators.cpp b/03_week/tasks/enum_operators/enum_operators.cpp index a539be38..4a875ec9 100644 --- a/03_week/tasks/enum_operators/enum_operators.cpp +++ b/03_week/tasks/enum_operators/enum_operators.cpp @@ -1,5 +1,5 @@ -#include -#include +#include +#include enum class CheckFlags : uint8_t { NONE = 0, @@ -12,22 +12,67 @@ enum class CheckFlags : uint8_t { ALL = TIME | DATE | USER | CERT | KEYS | DEST }; -/* return_type */ operator|(/* args */) { - throw std::runtime_error{"Not implemented"}; + +static constexpr const uint8_t ALL_FLAGS { static_cast(CheckFlags::ALL) }; + +static constexpr CheckFlags RemoveOverflows(const CheckFlags flags) { + return static_cast(static_cast(flags) & ALL_FLAGS); } -/* return_type */ operator&(/* args */) { - throw std::runtime_error{"Not implemented"}; + +auto operator|(const CheckFlags lhs, const CheckFlags rhs) { + return RemoveOverflows(static_cast( + static_cast(lhs) | static_cast(rhs))); } -/* return_type */ operator^(/* args */) { - throw std::runtime_error{"Not implemented"}; +auto operator&(const CheckFlags lhs, const CheckFlags rhs) { + const uint8_t l { static_cast(RemoveOverflows(lhs)) }; + const uint8_t r { static_cast(RemoveOverflows(rhs)) }; + + if (l == 0 || r == 0) return false; // любые проверки с NONE -> false + + const uint8_t inter { static_cast(l & r) }; + const bool lhs_subset_rhs { (inter == l) }; // все биты lhs содержатся в rhs + const bool rhs_subset_lhs { (inter == r) }; // все биты rhs содержатся в lhs + + return lhs_subset_rhs || rhs_subset_lhs; + } -/* return_type */ operator~(/* args */) { - throw std::runtime_error{"Not implemented"}; +auto operator^(const CheckFlags lhs, const CheckFlags rhs) { + return RemoveOverflows(static_cast( + static_cast(lhs) ^ static_cast(rhs))); + } -/* return_type */ operator<<(/* args */) { - throw std::runtime_error{"Not implemented"}; +auto operator~(const CheckFlags flags) { + const uint8_t val { static_cast(flags) }; + return RemoveOverflows(static_cast(~val)); +} + +auto operator<<(std::ostream& os, const CheckFlags flags) -> std::ostream& { + const uint8_t value { static_cast(RemoveOverflows(flags)) }; + + if (value == 0) { + os << "NONE"; + return os; + } + + bool first { true }; + auto print_flag = [&](CheckFlags f, const char* name) { + if ((static_cast(flags) & static_cast(f)) != 0) { + if (!first) os << ", "; + os << name; + first = false; + } + }; + + print_flag(CheckFlags::TIME, "TIME"); + print_flag(CheckFlags::DATE, "DATE"); + print_flag(CheckFlags::USER, "USER"); + print_flag(CheckFlags::CERT, "CERT"); + print_flag(CheckFlags::KEYS, "KEYS"); + print_flag(CheckFlags::DEST, "DEST"); + + return os; } diff --git a/03_week/tasks/filter/filter.cpp b/03_week/tasks/filter/filter.cpp index 6648cb39..478e4851 100644 --- a/03_week/tasks/filter/filter.cpp +++ b/03_week/tasks/filter/filter.cpp @@ -1,6 +1,16 @@ -#include +#include -/* return_type */ Filter(/* args */) { - throw std::runtime_error{"Not implemented"}; +void Filter(std::vector& vec, bool (*predicate)(int)) { + if (vec.empty() || predicate == nullptr) { + return; + } + + size_t write {}; // куда писать "валидные" элементы + for (std::size_t read = 0; read < vec.size(); ++read) { + if (predicate(vec[read])) { + vec[write++] = vec[read]; + } + } + vec.resize(write); // обрезаем хвост } \ No newline at end of file diff --git a/03_week/tasks/find_all/find_all.cpp b/03_week/tasks/find_all/find_all.cpp index 74f393b2..6011ff09 100644 --- a/03_week/tasks/find_all/find_all.cpp +++ b/03_week/tasks/find_all/find_all.cpp @@ -1,6 +1,20 @@ -#include +#include -/* return_type */ FindAll(/* args */) { - throw std::runtime_error{"Not implemented"}; +std::vector FindAll(const std::vector& vec, bool (*predicate)(int)) { + std::vector indices {}; + + if (vec.empty() || predicate == nullptr) { + return indices; + } + + indices.reserve(vec.size()); + + for (size_t i = 0; i < vec.size(); ++i) { + if (predicate(vec[i])) { + indices.push_back(i); + } + } + + return (indices.shrink_to_fit(), indices); } \ No newline at end of file diff --git a/03_week/tasks/minmax/minmax.cpp b/03_week/tasks/minmax/minmax.cpp index c2869799..2e4af000 100644 --- a/03_week/tasks/minmax/minmax.cpp +++ b/03_week/tasks/minmax/minmax.cpp @@ -1,6 +1,25 @@ -#include +#include -/* return_type */ MinMax(/* args */) { - throw std::runtime_error{"Not implemented"}; -} +auto MinMax(const std::vector& vec) { + auto min_it { vec.cend() }; + auto max_it { vec.cend() }; + + if (vec.empty()) { + return std::make_pair(min_it, max_it); + } + + min_it = vec.cbegin(); + max_it = vec.cbegin(); + + for (auto it = vec.cbegin(); it != vec.cend(); ++it) { + if (*it < *min_it) { + min_it = it; + } + if (*it >= *max_it) { + max_it = it; + } + } + + return std::make_pair(min_it, max_it); +} \ No newline at end of file diff --git a/03_week/tasks/os_overload/os_overload.cpp b/03_week/tasks/os_overload/os_overload.cpp index e473418d..ee3ca55c 100644 --- a/03_week/tasks/os_overload/os_overload.cpp +++ b/03_week/tasks/os_overload/os_overload.cpp @@ -1,21 +1,65 @@ +#include #include #include #include struct Coord2D { - int x; - int y; + int x {0}; + int y {0}; }; struct Circle { - Coord2D coord; - unsigned radius; + Coord2D coord {}; + unsigned radius {1}; }; using CircleRegion = std::pair; using CircleRegionList = std::vector; -/* return_type */ operator<<(/* args */) { - throw std::runtime_error{"Not implemented"}; +std::ostream& operator<<(std::ostream& os, const Coord2D& coord) { + os << std::dec << "(" << coord.x << ", " << coord.y << ")"; + return os; +} + +std::ostream& operator<<(std::ostream& os, const Circle& circle) { + os << "circle" << "["; + if (circle.radius == 0) { + os << "]"; + return os; + } + os << circle.coord; + os << ", r = " << std::dec << circle.radius; + os << "]"; + return os; +} + +std::ostream& operator<<(std::ostream& os, const CircleRegion& circle_region) { + if (circle_region.second) { + // внутренняя область + os << "+"; + } else { + // внешняя область + os << "-"; + } + os << circle_region.first; + return os; +} + +std::ostream& operator<<(std::ostream& os, const CircleRegionList& list) { + if (list.empty()) { + os << "{}"; + return os; + } + + os << "{\n\t"; + for (const auto& circle_region : list) { + os << circle_region; + if (&circle_region != &list.back()) { + os << ",\n\t"; + } + } + os << "\n}"; + + return os; } diff --git a/03_week/tasks/range/range.cpp b/03_week/tasks/range/range.cpp index d2085495..91c0db06 100644 --- a/03_week/tasks/range/range.cpp +++ b/03_week/tasks/range/range.cpp @@ -1,7 +1,26 @@ -#include #include -std::vector Range(int from, int to, int step) { - throw std::runtime_error{"Not implemented"}; -} +std::vector Range(const int from, const int to, const int step = 1) { + std::vector result {}; + + if (step == 0 || from == to || + (step > 0 && from > to) || + (step < 0 && from < to)) + { + return result; + } + + const size_t size { + (to - from) % step == 0 + ? static_cast((to - from) / step) + : static_cast((to - from) / step) + 1 + }; + result.reserve(size); + + for (int i = from; (step > 0) ? (i < to) : (i > to); i += step) { + result.push_back(i); + } + + return result; +} \ No newline at end of file diff --git a/03_week/tasks/unique/unique.cpp b/03_week/tasks/unique/unique.cpp index 9d2545bb..76cf8ddd 100644 --- a/03_week/tasks/unique/unique.cpp +++ b/03_week/tasks/unique/unique.cpp @@ -1,6 +1,19 @@ -#include #include -/* return_type */ Unique(/* args */) { - throw std::runtime_error{"Not implemented"}; +std::vector Unique(const std::vector& vec) { + std::vector result {}; + + if (vec.empty()) { + return result; + } + + result.reserve(vec.size()); + + for (const auto& item : vec) { + if (result.empty() || result.back() != item) { + result.push_back(item); + } + } + + return (result.shrink_to_fit(), result); } From a96ef72326a7c313d52676e74b9f2b431ad127bc Mon Sep 17 00:00:00 2001 From: Di0nisP Date: Wed, 17 Dec 2025 21:35:47 +0500 Subject: [PATCH 07/14] fix (04_week): comment out add_subdirectory for tasks in CMakeLists --- 04_week/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/04_week/CMakeLists.txt b/04_week/CMakeLists.txt index 0531237e..91fe9074 100644 --- a/04_week/CMakeLists.txt +++ b/04_week/CMakeLists.txt @@ -7,7 +7,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) # Гарантирует использов set(EXAMPLES_DIR examples) # Определим переменную с именем директории set(TASKS_DIR tasks) -add_subdirectory(tasks) +# add_subdirectory(tasks) # Создать исполняемый файл для каждого примера if (BUILD_EXAMPLES_04_WEEK) From a56480734acf69f1e8f1510e9d40085824831a9a Mon Sep 17 00:00:00 2001 From: Sergei Dekhtiar <102069117+18thday@users.noreply.github.com> Date: Thu, 18 Dec 2025 12:56:33 +0500 Subject: [PATCH 08/14] Update CMakeLists.txt Temporary Changes --- 04_week/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/04_week/CMakeLists.txt b/04_week/CMakeLists.txt index 0531237e..fcfe9625 100644 --- a/04_week/CMakeLists.txt +++ b/04_week/CMakeLists.txt @@ -7,9 +7,9 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) # Гарантирует использов set(EXAMPLES_DIR examples) # Определим переменную с именем директории set(TASKS_DIR tasks) -add_subdirectory(tasks) +#add_subdirectory(tasks) # Создать исполняемый файл для каждого примера if (BUILD_EXAMPLES_04_WEEK) # add_example(struct_examples ${EXAMPLES_DIR}/struct_examples.cpp) -endif() \ No newline at end of file +endif() From 3bad216b21518eb26812f44da6dce36320ae5ead Mon Sep 17 00:00:00 2001 From: Di0nisP Date: Sun, 21 Dec 2025 21:19:03 +0500 Subject: [PATCH 09/14] Revert "Update CMakeLists.txt" This reverts commit a56480734acf69f1e8f1510e9d40085824831a9a. --- 04_week/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/04_week/CMakeLists.txt b/04_week/CMakeLists.txt index fcfe9625..0531237e 100644 --- a/04_week/CMakeLists.txt +++ b/04_week/CMakeLists.txt @@ -7,9 +7,9 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) # Гарантирует использов set(EXAMPLES_DIR examples) # Определим переменную с именем директории set(TASKS_DIR tasks) -#add_subdirectory(tasks) +add_subdirectory(tasks) # Создать исполняемый файл для каждого примера if (BUILD_EXAMPLES_04_WEEK) # add_example(struct_examples ${EXAMPLES_DIR}/struct_examples.cpp) -endif() +endif() \ No newline at end of file From 2f504cad242eacd69805ebb9e65234ccf4b9047f Mon Sep 17 00:00:00 2001 From: Di0nisP Date: Wed, 24 Dec 2025 20:42:25 +0500 Subject: [PATCH 10/14] feat (04_weak): add working implementation --- 04_week/tasks/phasor/phasor.cpp | 224 ++++++++++++++++++++++ 04_week/tasks/queue/queue.cpp | 147 ++++++++++++++ 04_week/tasks/ring_buffer/ring_buffer.cpp | 210 ++++++++++++++++++++ 04_week/tasks/stack/stack.cpp | 73 +++++++ 4 files changed, 654 insertions(+) diff --git a/04_week/tasks/phasor/phasor.cpp b/04_week/tasks/phasor/phasor.cpp index 3ec1b9ad..a8d18e2c 100644 --- a/04_week/tasks/phasor/phasor.cpp +++ b/04_week/tasks/phasor/phasor.cpp @@ -1,10 +1,234 @@ +#include +#include +#include +#include +#include +#include struct ExpTag {}; struct DegTag {}; struct AlgTag {}; +static constexpr const double EPSILON { 1e-12 }; // std::numeric_limits::epsilon() + +static bool Eq(double a, double b) { + static constexpr const double eps { EPSILON }; + const std::array vals { 1.0, std::abs(a), std::abs(b) }; + const double eps_scaled { eps * *std::max_element(vals.begin(), vals.end()) }; + return std::abs(a - b) <= eps_scaled; +} class Phasor { + inline static constexpr const double pi { std::numbers::pi }; + +public: + Phasor() = default; + + Phasor(const double magnitude, const double phase_rad) + : real_(magnitude * std::cos(phase_rad)) + , imag_(magnitude * std::sin(phase_rad)) + {} + + Phasor(const double magnitude, const double phase_rad, const ExpTag&) + : Phasor(magnitude, phase_rad) + {} + + Phasor(const double magnitude, const double phase_deg, const DegTag&) + : Phasor(magnitude, DegreeToRadian(phase_deg)) + {} + + Phasor(const double real, const double imag, const AlgTag&) + : real_(real) + , imag_(imag) + {} + + ~Phasor() = default; + + Phasor(const Phasor& other) = default; + Phasor& operator=(const Phasor& other) = default; + + Phasor(Phasor&& other) noexcept = default; + Phasor& operator=(Phasor&& other) noexcept = default; + + static double RadianToDegree(const double rad) noexcept { + return rad * 180.0 / pi; + } + static double DegreeToRadian(const double deg) noexcept { + return deg * pi / 180.0; + } + + /// @name Getters + /// @{ + double Real() const noexcept { + return real_; + } + double Imag() const noexcept { + return imag_; + } + + double Magnitude() const noexcept { + return std::sqrt(Real() * Real() + Imag() * Imag()); + } + double Phase() const noexcept { + const auto phase { std::atan2(Imag(), Real()) }; + return Eq(phase, -pi) ? pi : phase; + } + double PhaseDeg() const noexcept { + return RadianToDegree(Phase()); + } + + double Abs() const noexcept { + return Magnitude(); + } + double Angle() const noexcept { + return Phase(); + } + double AngleDeg() const noexcept { + return PhaseDeg(); + } + + Phasor Conj() const noexcept { + return Phasor(Real(), -Imag(), AlgTag{}); + } + Phasor Inv() const noexcept { + const double denom { Real() * Real() + Imag() * Imag() }; + return Phasor(Real() / denom, -Imag() / denom, AlgTag{}); + } + /// @} + /// @name Setters + /// @{ + void SetPolar(const double magnitude, const double phase_rad) noexcept { + real_ = magnitude * std::cos(phase_rad); + imag_ = magnitude * std::sin(phase_rad); + } + void SetCartesian(const double real, const double imag) noexcept { + real_ = real; + imag_ = imag; + } + /// @} + + /// @name Operators + /// @{ + bool operator==(const Phasor& other) const noexcept { + return Eq(real_, other.real_) && Eq(imag_, other.imag_); + } + bool operator!=(const Phasor& other) const noexcept { + return !(*this == other); + } + + bool operator==(const double other) const noexcept { + return Eq(real_, other) && Eq(imag_, 0.0); + } + bool operator!=(const double other) const noexcept { + return !(*this == other); + } + + Phasor operator+(const double other) const noexcept { + return Phasor(Real() + other, Imag(), AlgTag{}); + } + Phasor operator-(const double other) const noexcept { + return Phasor(Real() - other, Imag(), AlgTag{}); + } + Phasor operator*(const double other) const noexcept { + return Phasor(Magnitude() * other, Phase()); + } + Phasor operator/(const double other) const noexcept { + return Phasor(Magnitude() / other, Phase()); + } + + friend Phasor operator+(const double lhs, const Phasor& rhs) noexcept { + return rhs + lhs; + } + friend Phasor operator-(const double lhs, const Phasor& rhs) noexcept { + return Phasor(lhs - rhs.Real(), -rhs.Imag(), AlgTag{}); + } + friend Phasor operator*(const double lhs, const Phasor& rhs) noexcept { + return rhs * lhs; + } + friend Phasor operator/(const double lhs, const Phasor& rhs) noexcept { + return Phasor(lhs / rhs.Magnitude(), -rhs.Phase()); + } + + Phasor operator+(const Phasor& other) const noexcept { + return Phasor(Real() + other.Real(), Imag() + other.Imag(), AlgTag{}); + } + Phasor operator-(const Phasor& other) const noexcept { + return Phasor(Real() - other.Real(), Imag() - other.Imag(), AlgTag{}); + } + Phasor operator*(const Phasor& other) const noexcept { + return Phasor(Magnitude() * other.Magnitude(), Phase() + other.Phase()); + } + Phasor operator/(const Phasor& other) const noexcept { + return Phasor(Magnitude() / other.Magnitude(), Phase() - other.Phase()); + } + + Phasor& operator+=(const double other) noexcept { + SetCartesian(Real() + other, Imag()); + return *this; + } + Phasor& operator-=(const double other) noexcept { + SetCartesian(Real() - other, Imag()); + return *this; + } + Phasor& operator*=(const double other) noexcept { + SetPolar(Magnitude() * other, Phase()); + return *this; + } + Phasor& operator/=(const double other) noexcept { + SetPolar(Magnitude() / other, Phase()); + return *this; + } + + Phasor& operator+=(const Phasor& other) noexcept { + SetCartesian(Real() + other.Real(), Imag() + other.Imag()); + return *this; + } + Phasor& operator-=(const Phasor& other) noexcept { + SetCartesian(Real() - other.Real(), Imag() - other.Imag()); + return *this; + } + Phasor& operator*=(const Phasor& other) noexcept { + SetPolar(Magnitude() * other.Magnitude(), Phase() + other.Phase()); + return *this; + } + Phasor& operator/=(const Phasor& other) noexcept { + SetPolar(Magnitude() / other.Magnitude(), Phase() - other.Phase()); + return *this; + } + /// @} + + /// @name Unary operators + /// @{ + Phasor operator-() const noexcept { + return Phasor(-Real(), -Imag(), AlgTag{}); + } + Phasor operator+() const noexcept { + return *this; + } + /// @} + +private: + double real_{0.0}; + double imag_{0.0}; }; + +Phasor MakePhasorPolar(const double magnitude, const double phase_rad) { + return Phasor(magnitude, phase_rad, ExpTag{}); +} + +Phasor MakePhasorPolarDeg(const double magnitude, const double phase_deg) { + return Phasor(magnitude, phase_deg, DegTag{}); +} + +Phasor MakePhasorCartesian(const double real, const double imag) { + return Phasor(real, imag, AlgTag{}); +} + +std::ostream& operator<<(std::ostream& os, const Phasor& phasor) { + os << std::dec << std::fixed << std::setprecision(3) + << phasor.Magnitude() << "*e(j*" << phasor.PhaseDeg() << ")" + << " [" << phasor.Real() << " + j*" << phasor.Imag() << "]"; + return os; +} \ No newline at end of file diff --git a/04_week/tasks/queue/queue.cpp b/04_week/tasks/queue/queue.cpp index 2a9f8493..557adfca 100644 --- a/04_week/tasks/queue/queue.cpp +++ b/04_week/tasks/queue/queue.cpp @@ -1,6 +1,153 @@ #include +#include +#include + class Queue { +public: + Queue() = default; + + Queue(std::stack s) { + while (!s.empty()) { + input_.push_back(s.top()); + s.pop(); + } + std::reverse(input_.begin(), input_.end()); + } + + Queue(const std::vector& vec) + : input_(vec) + {} + + Queue(const std::initializer_list& init) + : input_(init.begin(), init.end()) + {} + + Queue(std::size_t capacity) { + input_.reserve(capacity); + } + + ~Queue() = default; + + + bool Empty() const noexcept { + return Size() == 0; + } + auto Size() const noexcept -> std::size_t { + return input_.size() + output_.size(); + } + + /// @name Modifiers + /// @{ + void Push(const int value) noexcept { + input_.push_back(value); + } + bool Pop() noexcept { + if (output_.empty()) { + if (input_.empty()) { + return false; + } + std::reverse(input_.begin(), input_.end()); + std::swap(input_, output_); + } + output_.pop_back(); + return true; + } + void Swap(Queue& other) noexcept { + std::swap(input_, other.input_); + std::swap(output_, other.output_); + } + void Clear() noexcept { + input_.clear(); + output_.clear(); + } + /// @} + + /// @name Front/Back + /// @{ + auto Front() -> int&; + auto Front() const -> const int&; + auto Back() -> int&; + auto Back() const -> const int&; + /// @} + /// @name Comparison operators + /// @{ + bool operator==(const Queue& other) const noexcept; + bool operator!=(const Queue& other) const noexcept { + return !(*this == other); + } + /// @} + +private: + template + static auto& FrontImpl(Self& self); + template + static auto& BackImpl(Self& self); + +private: + std::vector input_ {}; + std::vector output_{}; }; + +template +auto& Queue::FrontImpl(Self& self) { + if (self.output_.empty()) { + return self.input_.front(); + } + return self.output_.back(); +} +auto Queue::Front() -> int& { + return FrontImpl(*this); +} +auto Queue::Front() const -> const int& { + return FrontImpl(*this); +} + + +template +auto& Queue::BackImpl(Self& self) { + if (self.input_.empty()) + return self.output_.front(); + return self.input_.back(); +} +auto Queue::Back() -> int& { + return BackImpl(*this); +} +auto Queue::Back() const -> const int& { + return BackImpl(*this); +} + +bool Queue::operator==(const Queue& other) const noexcept { + if (Size() != other.Size()) { + return false; + } + + const auto sz { Size() }; + for (std::size_t i = 0; i < sz; ++i) { + if (output_.size() > i && other.output_.size() > i) { + if ( output_[ output_.size() - 1 - i] != + other.output_[other.output_.size() - 1 - i]) + { + return false; + } + } else if (output_.size() > i) { + if (output_[output_.size() - 1 - i] != other.input_[i - other.output_.size()]) { + return false; + } + } else if (other.output_.size() > i) { + if (input_[i - output_.size()] != other.output_[other.output_.size() - 1 - i]) { + return false; + } + } else { + if ( input_[i - output_.size()] != + other.input_[i - other.output_.size()]) + { + return false; + } + } + } + + return true; +} \ No newline at end of file diff --git a/04_week/tasks/ring_buffer/ring_buffer.cpp b/04_week/tasks/ring_buffer/ring_buffer.cpp index e2b57ba2..64294a0e 100644 --- a/04_week/tasks/ring_buffer/ring_buffer.cpp +++ b/04_week/tasks/ring_buffer/ring_buffer.cpp @@ -1,6 +1,216 @@ +#include #include +static constexpr const std::size_t MINIMAL_CAPACITY { 1 }; + +/// @brief Вспомогательная функция для обеспечения минимальной емкости буфера +static auto ValidCapacity(const std::size_t capacity) noexcept { + return capacity >= MINIMAL_CAPACITY ? capacity : MINIMAL_CAPACITY; +} class RingBuffer { +public: + RingBuffer() = default; + RingBuffer(const std::size_t capacity) { + buffer_.reserve(ValidCapacity(capacity)); + } + + RingBuffer(const std::size_t capacity, int initial_value) + : buffer_(ValidCapacity(capacity), initial_value) + {} + + RingBuffer(const std::initializer_list& init) + : buffer_(init.begin(), init.end()) + { + buffer_.reserve(ValidCapacity(init.size())); + } + + ~RingBuffer() = default; + + /// @name Copy and move semantics + /// @{ + RingBuffer(const RingBuffer& other); + RingBuffer& operator=(const RingBuffer& other); + + RingBuffer(RingBuffer&& other) noexcept; + RingBuffer& operator=(RingBuffer&& other) noexcept; + /// @} + + /// @{ + auto Empty() const noexcept { + return buffer_.empty(); + } + auto Full() const noexcept { + return buffer_.size() == buffer_.capacity(); + } + auto Size() const noexcept -> std::size_t { + return buffer_.size(); + } + auto Capacity() const noexcept -> std::size_t { + return buffer_.capacity(); + } + /// @} + + /// @name Element access + /// @{ + auto Vector() const noexcept -> std::vector; + auto operator[](const std::size_t index) noexcept -> int&; + auto operator[](const std::size_t index) const noexcept -> const int&; + /// @} + + /// @name Front/Back + /// @{ + auto Front() -> int&; + auto Front() const -> const int&; + auto Back() -> int&; + auto Back() const -> const int&; + /// @} + + /// @name Modifiers + /// @{ + void Clear() noexcept; + + void Pop(); + bool TryPop(int& value); + + void Push(int value); + bool TryPush(int value); + + void Resize(const std::size_t new_capacity); + /// @} + +private: + template + static auto& FrontImpl(Self& self); + template + static auto& BackImpl(Self& self); + /** + * @brief Метод для получения корректного индекса в кольцевом буфере + * + * @param[in] index Индекс относительно начала буфера (самого старого элемента) + * @return std::size_t Корректный индекс в векторе хранения элементов + */ + auto ValidIndex(const std::size_t& index) const noexcept { + return (head_ + index) % Size(); + } + +private: + std::vector buffer_ {}; ///< Вектор для хранения элементов буфера + std::size_t head_ {}; ///< Индекс самого старого элемента в буфере +}; + +RingBuffer::RingBuffer(const RingBuffer& other) { + buffer_.reserve(other.Capacity()); + buffer_ = other.buffer_; + head_ = other.head_; }; +RingBuffer& RingBuffer::operator=(const RingBuffer& other) { + if (this != &other) { + buffer_.reserve(other.Capacity()); + buffer_ = other.buffer_; + head_ = other.head_; + } + return *this; +} +RingBuffer::RingBuffer(RingBuffer&& other) noexcept { + buffer_.reserve(other.Capacity()); + buffer_ = std::move(other.buffer_); + head_ = other.head_; +} +RingBuffer& RingBuffer::operator=(RingBuffer&& other) noexcept { + if (this != &other) { + buffer_.reserve(other.Capacity()); + buffer_ = std::move(other.buffer_); + head_ = other.head_; + } + return *this; +}; + +template +auto& RingBuffer::FrontImpl(Self& self) { + return self[self.Size() - 1]; +} +auto RingBuffer::Front() -> int& { + return FrontImpl(*this); +} +auto RingBuffer::Front() const -> const int& { + return FrontImpl(*this); +} + +template +auto& RingBuffer::BackImpl(Self& self) { + return self[0]; +} +auto RingBuffer::Back() -> int& { + return BackImpl(*this); +} +auto RingBuffer::Back() const -> const int& { + return BackImpl(*this); +} + +auto RingBuffer::Vector() const noexcept -> std::vector { + std::vector buffer; + buffer.reserve(Size()); + for (std::size_t i = 0; i < Size(); ++i) { + buffer.push_back((*this)[i]); + } + return buffer; +} + +auto RingBuffer::operator[](const std::size_t index) noexcept -> int& { + return buffer_[ValidIndex(index)]; +} +auto RingBuffer::operator[](const std::size_t index) const noexcept -> const int& { + return buffer_[ValidIndex(index)]; +} + +void RingBuffer::Clear() noexcept { + buffer_.clear(); + head_ = 0; +} + +void RingBuffer::Pop() { + if (!Empty()) { + buffer_.erase(buffer_.begin() + ValidIndex(0)); + head_ = head_ % Size(); + } +} +bool RingBuffer::TryPop(int& value) { + if (Empty()) { + return false; + } + value = Back(); + Pop(); + return true; +} + +void RingBuffer::Push(int value) { + if (Full()) { + Back() = value; + head_ = ValidIndex(1); // Сдвигаем голову вперед по кольцу на один элемент + } else { + buffer_.push_back(value); + } +} +bool RingBuffer::TryPush(int value) { + if (Full()) { + return false; + } + Push(value); + return true; +} + +void RingBuffer::Resize(const std::size_t new_capacity) { + const auto valid_capacity { ValidCapacity(new_capacity) }; + if (valid_capacity < Size()) { + if (head_ + valid_capacity <= Size()) { + buffer_.erase( + buffer_.begin() + ValidIndex(0), + buffer_.begin() + ValidIndex(Size() - valid_capacity)); + } + head_ = head_ % valid_capacity; + } + buffer_.shrink_to_fit(); + buffer_.reserve(valid_capacity); +} \ No newline at end of file diff --git a/04_week/tasks/stack/stack.cpp b/04_week/tasks/stack/stack.cpp index 222e4ffc..50571c31 100644 --- a/04_week/tasks/stack/stack.cpp +++ b/04_week/tasks/stack/stack.cpp @@ -2,5 +2,78 @@ class Stack { + using StackType = std::vector; +public: + Stack() = default; + + ~Stack() = default; + + /// @name Copy and move semantics + /// @{ + Stack(const Stack& other) = default; + Stack& operator=(const Stack& other) = default; + Stack(Stack&& other) noexcept = default; + Stack& operator=(Stack&& other) noexcept = default; + /// @} + + auto Empty() const noexcept { + return stack_.empty(); + } + auto Size() const noexcept { + return stack_.size(); + } + + /// @name Modifiers + /// @{ + void Push(int value) noexcept { + stack_.push_back(value); + } + bool Pop() noexcept { + if (stack_.empty()) + return false; + stack_.pop_back(); + return true; + } + + void Swap(Stack& other) noexcept { + std::swap(stack_, other.stack_); + } + + void Clear() noexcept { + stack_.clear(); + } + /// @} + + auto Top() noexcept -> int&; + auto Top() const noexcept -> const int&; + + bool operator==(const Stack& other) const noexcept; + bool operator!=(const Stack& other) const noexcept; + +private: + template + static auto& TopImpl(Self& self) noexcept; + +private: + StackType stack_ {}; ///< Вектор для хранения элементов стека }; + +template +auto& Stack::TopImpl(Self& self) noexcept { + return self.stack_.back(); +} + +auto Stack::Top() noexcept -> int& { + return TopImpl(*this); +} +auto Stack::Top() const noexcept -> const int& { + return TopImpl(*this); +} + +bool Stack::operator==(const Stack& other) const noexcept { + return stack_ == other.stack_; +} +bool Stack::operator!=(const Stack& other) const noexcept { + return !(*this == other); +} \ No newline at end of file From 536cb4f25cb4aa18d26a5b6f603493c54a2f3c49 Mon Sep 17 00:00:00 2001 From: Di0nisP Date: Wed, 24 Dec 2025 20:57:12 +0500 Subject: [PATCH 11/14] fix (04_weak): Pop() in ring_buffer --- 04_week/tasks/ring_buffer/ring_buffer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/04_week/tasks/ring_buffer/ring_buffer.cpp b/04_week/tasks/ring_buffer/ring_buffer.cpp index 64294a0e..8beba010 100644 --- a/04_week/tasks/ring_buffer/ring_buffer.cpp +++ b/04_week/tasks/ring_buffer/ring_buffer.cpp @@ -173,7 +173,7 @@ void RingBuffer::Clear() noexcept { void RingBuffer::Pop() { if (!Empty()) { buffer_.erase(buffer_.begin() + ValidIndex(0)); - head_ = head_ % Size(); + head_ = Empty() ? 0 : head_ % Size(); } } bool RingBuffer::TryPop(int& value) { From 565d3bdc14edf04d6bd4e84100d3451944d7fc00 Mon Sep 17 00:00:00 2001 From: Di0nisP Date: Thu, 12 Feb 2026 22:06:25 +0500 Subject: [PATCH 12/14] feat (05_week): add working implementation --- 05_week/tasks/cow_string/cow_string.cpp | 298 ++++++++++++++++++ 05_week/tasks/simple_vector/simple_vector.cpp | 250 ++++++++++++++- 05_week/tasks/string_view/string_view.cpp | 198 +++++++++++- 05_week/tasks/tracer/tracer.cpp | 142 ++++++++- 4 files changed, 884 insertions(+), 4 deletions(-) diff --git a/05_week/tasks/cow_string/cow_string.cpp b/05_week/tasks/cow_string/cow_string.cpp index 34d59738..00fbbb8c 100644 --- a/05_week/tasks/cow_string/cow_string.cpp +++ b/05_week/tasks/cow_string/cow_string.cpp @@ -1,6 +1,304 @@ #include #include +#include class CowString { + struct StringData { + size_t size; + char* data; + size_t ref_count; + StringData(const char* cstr); + StringData(const std::string& str); + ~StringData(); + }; + +public: + CowString(); + CowString(const char* cstr); + CowString(const std::string& str); + + /// @name Копирование / перемещение + /// @{ + CowString(const CowString& other); + CowString& operator=(const CowString& other); + + CowString(CowString&& other) noexcept; + CowString& operator=(CowString&& other) noexcept; + /// @} + + ~CowString(); + + /// @name Методы, не вызывающие копирования + /// @{ + size_t Size() const; + bool Empty() const; + + const char* ToCstr() const; + std::string ToString() const; + + size_t Find(const char* substring) const; + size_t Find(const std::string& substring) const; + size_t Find(char ch) const; + + const char& operator[](size_t index) const; + operator const char*() const; + /// @} + + /// @name Методы, обеспечивающие модификацию на собственной копии данных + /// @{ + char& operator[](size_t index); + + CowString& Append(const char* cstr); + CowString& Append(const std::string& str); + + CowString Substr(size_t pos = 0, size_t count = npos) const; + + CowString& Clear(); + /// @} + +private: + /** + * @brief Отсоединяет эту строку от общих данных + * и создает независимую копию данных для этого экземпляра. + * + * Этот метод реализует шаблон копирования при записи (CoW) + * путем создания независимой копии строковых данных, + * когда требуются изменения. + * + * - Если эта строка является единственной ссылкой, + * с данными не выполняется никаких действий. + * - Если существует несколько ссылок, создается новая копия + * и количество ссылок обновляется соответствующим образом. + * + * @note Обычно это вызывается внутри системы + * перед любой неконстантной операцией, которая изменяет данные строки. + */ + void Detach(); + +public: + inline static constexpr size_t npos = -1; + +private: + StringData* string_data_; }; + +// ------------------------------------------------------------------------- +// CowString::StringData implementation +// ------------------------------------------------------------------------- + +CowString::StringData::StringData(const char* cstr) +{ + /// @warning UB при nullptr + + size = std::strlen(cstr); + data = new char[size + 1]; // +1 для нуль-терминатора + std::strcpy(data, cstr); + ref_count = 1; +} + +CowString::StringData::StringData(const std::string& str) + : StringData(str.c_str()) +{ + +} + +CowString::StringData::~StringData() +{ + delete[] data; +} + +// ------------------------------------------------------------------------- +// CowString implementation +// ------------------------------------------------------------------------- + +CowString::CowString() + : string_data_(new StringData("")) +{ + +} + +CowString::CowString(const char* cstr) + : string_data_(new StringData(cstr)) +{ + +} + +CowString::CowString(const std::string& str) + : CowString(str.c_str()) +{ + +} + +CowString::CowString(const CowString& other) + : string_data_(other.string_data_) +{ + ++string_data_->ref_count; +} + +CowString& CowString::operator=(const CowString& other) +{ + if (this != &other) { + // Отпускаем свои данные + if (--string_data_->ref_count == 0) + delete string_data_; + + // Присоединяемся к чужим + string_data_ = other.string_data_; + ++string_data_->ref_count; + } + return *this; +} + +CowString::CowString(CowString&& other) noexcept + : string_data_(other.string_data_) +{ + other.string_data_ = new StringData(""); +} + +CowString& CowString::operator=(CowString&& other) noexcept +{ + if (this != &other) { + // Отпускаем свои данные + if (--string_data_->ref_count == 0) + delete string_data_; + + string_data_ = other.string_data_; + other.string_data_ = new StringData(""); + } + return *this; +} + +CowString::~CowString() +{ + --string_data_->ref_count; + if (string_data_->ref_count == 0) { + delete string_data_; + } +} + +// Методы, не вызывающие копирования + +auto CowString::Size() const -> std::size_t +{ + return string_data_->size; +} + +auto CowString::Empty() const -> bool +{ + return string_data_->size == 0; +} + +auto CowString::ToCstr() const -> const char* +{ + return string_data_->data; +} + +auto CowString::ToString() const -> std::string +{ + return std::string(string_data_->data); +} + +auto CowString::Find(const char* substring) const -> size_t +{ + const char* found = std::strstr(string_data_->data, substring); + return found ? static_cast(found - string_data_->data) : npos; +} + +auto CowString::Find(const std::string& substring) const -> size_t +{ + return Find(substring.c_str()); +} + +auto CowString::Find(char ch) const -> size_t +{ + const char* found = std::strchr(string_data_->data, ch); + return found ? static_cast(found - string_data_->data) : npos; +} + +auto CowString::operator[](size_t index) const -> const char& +{ + if (index >= string_data_->size) + throw std::out_of_range("Index out of bounds"); + + return string_data_->data[index]; +} + +CowString::operator const char*() const +{ + return string_data_->data; +} + +// Методы, обеспечивающие модификацию на собственной копии данных + +auto CowString::operator[](size_t index) -> char& +{ + if (index >= string_data_->size) + throw std::out_of_range("Index out of bounds"); + + Detach(); + + return string_data_->data[index]; +} + +auto CowString::Append(const char* cstr) -> CowString& +{ + if (std::strlen(cstr) == 0) + return *this; // Нет необходимости в копировании + + Detach(); + + const auto new_size = string_data_->size + std::strlen(cstr); + char* new_data = new char[new_size + 1]; + + std::strcpy(new_data, string_data_->data); + std::strcat(new_data, cstr); + + delete[] string_data_->data; + string_data_->data = new_data; + string_data_->size = new_size; + + return *this; +} + +auto CowString::Append(const std::string& str) -> CowString& +{ + return Append(str.c_str()); +} + +auto CowString::Substr(size_t pos, size_t count) const -> CowString +{ + if (pos >= string_data_->size) + return CowString(); + + const auto new_size = (count > string_data_->size - pos) ? string_data_->size - pos : count; + char* new_data = new char[new_size + 1]; // +1 для нуль-терминатора + + std::strncpy(new_data, string_data_->data + pos, new_size); + new_data[new_size] = '\0'; // Гарантировать нуль-терминатор + + CowString result(new_data); + delete[] new_data; // Удалить временные данные return result + + return result; +} + +auto CowString::Clear() -> CowString& +{ + Detach(); + + delete string_data_; + string_data_ = new StringData(""); + + return *this; +} + +// private + +void CowString::Detach() +{ + if (string_data_->ref_count > 1) { + --string_data_->ref_count; + string_data_ = new StringData(string_data_->data); + } +} \ No newline at end of file diff --git a/05_week/tasks/simple_vector/simple_vector.cpp b/05_week/tasks/simple_vector/simple_vector.cpp index 9b2ea971..ddf0e359 100644 --- a/05_week/tasks/simple_vector/simple_vector.cpp +++ b/05_week/tasks/simple_vector/simple_vector.cpp @@ -1,5 +1,253 @@ +#include +#include // std::copy_n +#include // std::exchange +#include // std::out_of_range +class SimpleVector; + +void swap(SimpleVector& lhs, SimpleVector& rhs); + +int* begin(SimpleVector& v) noexcept; +int* end(SimpleVector& v) noexcept ; +// range‑based for не знает про cbegin и cend +const int* begin(const SimpleVector& v) noexcept; +const int* end(const SimpleVector& v) noexcept; class SimpleVector { +public: + SimpleVector() = default; + SimpleVector(size_t size, int value = 0); + SimpleVector(std::initializer_list init); + + SimpleVector(const SimpleVector& other); + SimpleVector& operator=(const SimpleVector& other); + SimpleVector(SimpleVector&& other) noexcept; + SimpleVector& operator=(SimpleVector&& other) noexcept; + + ~SimpleVector(); + + int& operator[](size_t index); + const int& operator[](size_t index) const; + + void Swap(SimpleVector& other); + + + void PushBack(int value); + void PopBack(); + int* Insert(const int* pos, int value); + int* Erase(const int* pos); + void Clear(); + + void Resize(size_t new_size, int value = 0); + void Reserve(size_t new_capacity); + + size_t Size() const noexcept; + size_t Capacity() const noexcept; + bool Empty() const noexcept; + + int* Data() noexcept; + const int* Data() const noexcept; + + bool operator==(const SimpleVector& other) const; + bool operator!=(const SimpleVector& other) const = default; + +private: + size_t size_ = 0; + size_t capacity_ = 0; + // Поведение аналогично std::vector: при capacity_ == 0, data_ == nullptr + int* data_ = nullptr; +}; + +void swap(SimpleVector& lhs, SimpleVector& rhs) +{ + lhs.Swap(rhs); +} + +int* begin(SimpleVector& v) noexcept +{ + return v.Data(); +} +int* end(SimpleVector& v) noexcept +{ + return v.Data() + v.Size(); +} +const int* begin(const SimpleVector& v) noexcept + +{ + return v.Data(); +} +const int* end(const SimpleVector& v) noexcept +{ + return v.Data() + v.Size(); +} + + +SimpleVector::SimpleVector(size_t size, int value) + : size_(size), capacity_(size_) + , data_(capacity_ > 0 ? new int[capacity_] : nullptr) +{ + std::fill_n(data_, size_, value); +} + +SimpleVector::SimpleVector(std::initializer_list init) + : size_(init.size()), capacity_(size_) + , data_(capacity_ > 0 ? new int[capacity_] : nullptr) +{ + std::copy_n(init.begin(), size_, data_); +} + +SimpleVector::SimpleVector(const SimpleVector& other) + : size_(other.size_), capacity_(other.capacity_) + , data_(capacity_ > 0 ? new int[capacity_] : nullptr) +{ + std::copy_n(other.data_, size_, data_); +} + +SimpleVector& SimpleVector::operator=(const SimpleVector& other) +{ + if (this != &other) { + SimpleVector temp(other); + Swap(temp); + } + return *this; +} + +SimpleVector::SimpleVector(SimpleVector&& other) noexcept + : size_(std::exchange(other.size_, 0)) + , capacity_(std::exchange(other.capacity_, 0)) + , data_(std::exchange(other.data_, nullptr)) +{ + +} + +SimpleVector& SimpleVector::operator=(SimpleVector&& other) noexcept +{ + if (this != &other) { + SimpleVector temp; + Swap(other); + temp.Swap(other); + } + + return *this; +} + +SimpleVector::~SimpleVector() +{ + delete[] data_; +} + +int& SimpleVector::operator[](size_t index) +{ + if (index >= size_) + throw std::out_of_range("Index out of bounds"); + + return data_[index]; +} + +const int& SimpleVector::operator[](size_t index) const +{ + if (index >= size_) + throw std::out_of_range("Index out of bounds"); + + return data_[index]; +} + +void SimpleVector::Swap(SimpleVector& other) +{ + std::swap(size_, other.size_); + std::swap(capacity_, other.capacity_); + std::swap(data_, other.data_); +} + +void SimpleVector::PushBack(int value) +{ + if (size_ == capacity_) + Reserve(capacity_ == 0 ? 1 : capacity_ * 2); + + data_[size_++] = value; +} +void SimpleVector::PopBack() +{ + if (size_ > 0) + --size_; +} +int* SimpleVector::Insert(const int* pos, int value) +{ + const size_t index = pos - data_; + if (index > size_) + return data_ + size_; + + if (size_ == capacity_) + Reserve(capacity_ == 0 ? 1 : capacity_ * 2); + + // Перемещение слева направо + std::move_backward(data_ + index, data_ + size_, data_ + size_ + 1); + ++size_; + + return (data_[index] = value, data_ + index); +} +int* SimpleVector::Erase(const int* pos) +{ + const size_t index = pos - data_; + if (index >= size_) + return data_ + size_; + + // Перемещение справа налево + std::move(data_ + index + 1, data_ + size_, data_ + index); + --size_; + + return data_ + index; +} +void SimpleVector::Clear() +{ + size_ = 0; +} + +void SimpleVector::Resize(size_t new_size, int value) +{ + if (new_size > size_) { + if (new_size > capacity_) + Reserve(new_size); + + std::fill(data_ + size_, data_ + new_size, value); + } + + size_ = new_size; +} +void SimpleVector::Reserve(size_t new_capacity) +{ + if (new_capacity > capacity_) { + int* new_data = new int[new_capacity]; + std::copy_n(data_, size_, new_data); + delete[] data_; + data_ = new_data; + capacity_ = new_capacity; + } +} + +size_t SimpleVector::Size() const noexcept +{ + return size_; +} +size_t SimpleVector::Capacity() const noexcept +{ + return capacity_; +} +bool SimpleVector::Empty() const noexcept +{ + return size_ == 0; +} + +int* SimpleVector::Data() noexcept +{ + return data_; +} +const int* SimpleVector::Data() const noexcept +{ + return data_; +} -}; \ No newline at end of file +bool SimpleVector::operator==(const SimpleVector& other) const +{ + return Size() == other.Size() && std::equal(Data(), Data() + Size(), other.Data()); +} \ No newline at end of file diff --git a/05_week/tasks/string_view/string_view.cpp b/05_week/tasks/string_view/string_view.cpp index 438c4536..2bfcb153 100644 --- a/05_week/tasks/string_view/string_view.cpp +++ b/05_week/tasks/string_view/string_view.cpp @@ -1,7 +1,201 @@ #include #include - +/** + * @brief Класс, представляющий упрощенную реализацию std::string_view + * @note Не может изменять строку, за которой наблюдает, и не владеет ею. + */ class StringView { +public: + StringView(); + + /// @param[in] cstr static storage duration string + StringView(const char* cstr, size_t count = npos); + StringView(const std::string& cstr, size_t pos = 0, size_t count = npos); + StringView(const std::string&& cstr, size_t pos = 0, size_t count = npos); + + ~StringView(); + + const char& operator[](size_t index) const; + const char* Data() const; + + const char& Front() const; + const char& Back() const; + + bool Empty() const; + size_t Size() const; + size_t Length() const; + + void RemovePrefix(size_t n); + void RemoveSuffix(size_t n); + + StringView Substr(size_t pos = 0, size_t count = npos) const; + + size_t Find(char ch, size_t pos = 0) const; + size_t Find(const StringView& substring, size_t pos = 0) const; + + std::string ToString() const; + +private: + StringView(const char* cstr, size_t count, bool owner); + +public: + inline static constexpr size_t npos = -1; + +private: + /** + * @brief Флаг, указывающий, владеет ли StringView данными строки + * + * - @c true , если StringView владеет данными (например, создан из временной строки); + * - @c false , если StringView не владеет данными (например, создан из существующей строки). + * + * @note Модификация поведения std::string_view. + */ + const bool owner_; + + size_t size_ = 0; + const char* data_ = nullptr; +}; + +StringView::StringView() + : owner_(false) +{ + +} + +StringView::StringView(const char* cstr, size_t count) + : StringView(cstr, count, false) +{ + +} + + +StringView::StringView(const std::string& cstr, size_t pos, size_t count) + : StringView(pos >= cstr.size() ? nullptr : cstr.c_str() + pos, count, false) +{ + +} + +StringView::StringView(const std::string&& cstr, size_t pos, size_t count) + : StringView(pos >= cstr.size() ? nullptr : cstr.c_str() + pos, count, true) +{ + +} + +StringView::~StringView() +{ + if (owner_ && data_ != nullptr) + delete[] data_; +} + +const char& StringView::operator[](size_t index) const +{ + return data_[index]; +} + +const char* StringView::Data() const +{ + return data_; +} + +bool StringView::Empty() const +{ + return size_ == 0; +} + +size_t StringView::Size() const +{ + return size_; +} + +size_t StringView::Length() const +{ + return Size(); +} + +void StringView::RemovePrefix(size_t n) +{ + if (n > size_) + n = size_; + + data_ += n; + size_ -= n; +} + +void StringView::RemoveSuffix(size_t n) +{ + if (n > size_) + n = size_; + + size_ -= n; +} + +const char& StringView::Front() const +{ + return Data()[0]; +} +const char& StringView::Back() const +{ + return Data()[Size() - 1]; +} + +size_t StringView::Find(char ch, size_t pos) const +{ + for (size_t i = pos; i < Size(); ++i) { + if (Data()[i] == ch) + return i; + } + return npos; +} + +size_t StringView::Find(const StringView& substring, size_t pos) const +{ + // Пустая подстрока + if (substring.Empty()) + return Empty() ? npos : pos; + + // Подстрока длиннее строки + if (substring.Size() > Size() || pos > Size() - substring.Size()) + return npos; + + for (size_t i = pos; i <= Size() - substring.Size(); ++i) + if (std::strncmp(Data() + i, substring.Data(), substring.Size()) == 0) + return i; + + return npos; +} + +StringView StringView::Substr(size_t pos, size_t count) const +{ + if (Data() == nullptr || pos >= Size()) + return StringView(); + + const size_t new_size = (count > Size() - pos) ? Size() - pos : count; + return StringView(Data() + pos, new_size, false); +} + +std::string StringView::ToString() const +{ + return std::string(Data(), Size()); +} + +// private constructor + +StringView::StringView(const char* cstr, size_t count, bool owner) + : owner_(owner) +{ + if (cstr == nullptr) + return; + + const size_t cstr_len = std::strlen(cstr); + size_ = count > cstr_len ? cstr_len : count; -}; \ No newline at end of file + if (owner_) { // Владеет данными, необходимо создать копию + char* new_data = new char[size_ + 1]; + std::strncpy(new_data, cstr, size_); + new_data[size_] = '\0'; // Гарантировать нуль-терминатор + data_ = new_data; + } else { // Не владеет данными, просто ссылается на существующую строку + data_ = cstr; + } +} \ No newline at end of file diff --git a/05_week/tasks/tracer/tracer.cpp b/05_week/tasks/tracer/tracer.cpp index 2ccfb417..32740490 100644 --- a/05_week/tasks/tracer/tracer.cpp +++ b/05_week/tasks/tracer/tracer.cpp @@ -1,6 +1,146 @@ #include +#include +#include +#define AddCounter(name) \ +private: \ + inline static size_t name##_internal = 0; \ +public: \ + inline static const auto& name = name##_internal; + +#define ResetCounter(name) \ + name##_internal = 0; + +#define Increment(name) \ + ++name##_internal; + +#define Decrement(name) \ + --name##_internal; + +#define PrintCounter(name) \ + std::cout << std::left << std::setw(12) << #name \ + << " = " << name \ + << std::endl; class Tracer { + AddCounter(count) + AddCounter(default_ctor) + AddCounter(str_ctor) + AddCounter(copy_ctor) + AddCounter(move_ctor) + AddCounter(copy_assign) + AddCounter(move_assign) + AddCounter(dtor) + AddCounter(alive) + +public: + Tracer(); + Tracer(const char* name); + Tracer(const std::string& name); + + Tracer(const Tracer&); + Tracer& operator=(const Tracer&); + Tracer(Tracer&&) noexcept; + Tracer& operator=(Tracer&&) noexcept; + + ~Tracer(); + + static void PrintStats(); + static void ResetStats(); + + int Id() const { return id_; } + const std::string& Name() const { return name_; } + const char* Data() const { return name_.data(); } + +private: + int id_; + std::string name_; +}; + +Tracer::Tracer() + : Tracer("obj") +{ + Increment(default_ctor) + Decrement(str_ctor) // Чтобы не считать конструктор строки +} + +Tracer::Tracer(const char* name) + : Tracer(std::string(name)) +{ + +} + +Tracer::Tracer(const std::string& name) + : id_(count + 1), name_(name + '_' + std::to_string(id_)) +{ + Increment(count) + Increment(str_ctor) + Increment(alive) +} + +Tracer::Tracer(const Tracer& other) + : id_(count + 1), name_(other.name_) +{ + Increment(count) // Создает id + Increment(copy_ctor) + Increment(alive) +} + +Tracer& Tracer::operator=(const Tracer& other) +{ + if (this != &other) { + // Не изменяет id + name_ = other.name_; + Increment(copy_assign) + } + return *this; +} + +Tracer::Tracer(Tracer&& other) noexcept + : id_(other.id_ + 1), name_(std::move(other.name_)) +{ + Increment(count) // Создает id + Increment(move_ctor) + Increment(alive) +} + +Tracer& Tracer::operator=(Tracer&& other) noexcept +{ + if (this != &other) { + // Не изменяет id + name_ = std::move(other.name_); + Increment(move_assign) + } + return *this; +} + +Tracer::~Tracer() +{ + Increment(dtor) + Decrement(alive) +} + + +void Tracer::ResetStats() { + ResetCounter(count) + ResetCounter(default_ctor) + ResetCounter(str_ctor) + ResetCounter(copy_ctor) + ResetCounter(move_ctor) + ResetCounter(copy_assign) + ResetCounter(move_assign) + ResetCounter(dtor) + ResetCounter(alive) +} -}; \ No newline at end of file +void Tracer::PrintStats() { + PrintCounter(count) + PrintCounter(default_ctor) + PrintCounter(str_ctor) + PrintCounter(copy_ctor) + PrintCounter(move_ctor) + PrintCounter(copy_assign) + PrintCounter(move_assign) + PrintCounter(dtor) + PrintCounter(alive) +} \ No newline at end of file From 89ddb6f22652c9be88b62524993f403363cc11e8 Mon Sep 17 00:00:00 2001 From: Di0nisP Date: Thu, 12 Feb 2026 22:47:59 +0500 Subject: [PATCH 13/14] fix (05_week): rule of 5 --- 05_week/tasks/cow_string/cow_string.cpp | 5 +++-- 05_week/tasks/simple_vector/simple_vector.cpp | 3 ++- 05_week/tasks/string_view/string_view.cpp | 15 +++++++-------- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/05_week/tasks/cow_string/cow_string.cpp b/05_week/tasks/cow_string/cow_string.cpp index 00fbbb8c..8b885acd 100644 --- a/05_week/tasks/cow_string/cow_string.cpp +++ b/05_week/tasks/cow_string/cow_string.cpp @@ -105,7 +105,8 @@ CowString::StringData::StringData(const std::string& str) CowString::StringData::~StringData() { - delete[] data; + if (data != nullptr) + delete[] data; } // ------------------------------------------------------------------------- @@ -172,7 +173,7 @@ CowString& CowString::operator=(CowString&& other) noexcept CowString::~CowString() { --string_data_->ref_count; - if (string_data_->ref_count == 0) { + if (string_data_->ref_count == 0 && string_data_ != nullptr) { delete string_data_; } } diff --git a/05_week/tasks/simple_vector/simple_vector.cpp b/05_week/tasks/simple_vector/simple_vector.cpp index ddf0e359..f0f13a6b 100644 --- a/05_week/tasks/simple_vector/simple_vector.cpp +++ b/05_week/tasks/simple_vector/simple_vector.cpp @@ -133,7 +133,8 @@ SimpleVector& SimpleVector::operator=(SimpleVector&& other) noexcept SimpleVector::~SimpleVector() { - delete[] data_; + if (data_ != nullptr) + delete[] data_; } int& SimpleVector::operator[](size_t index) diff --git a/05_week/tasks/string_view/string_view.cpp b/05_week/tasks/string_view/string_view.cpp index 2bfcb153..fb9858ea 100644 --- a/05_week/tasks/string_view/string_view.cpp +++ b/05_week/tasks/string_view/string_view.cpp @@ -7,13 +7,18 @@ */ class StringView { public: - StringView(); + StringView() = default; /// @param[in] cstr static storage duration string StringView(const char* cstr, size_t count = npos); StringView(const std::string& cstr, size_t pos = 0, size_t count = npos); StringView(const std::string&& cstr, size_t pos = 0, size_t count = npos); + StringView(const StringView&) = delete; + StringView& operator=(const StringView&) = delete; + StringView(StringView&&) noexcept = default; + StringView& operator=(StringView&&) noexcept = default; + ~StringView(); const char& operator[](size_t index) const; @@ -51,18 +56,12 @@ class StringView { * * @note Модификация поведения std::string_view. */ - const bool owner_; + bool owner_ = false; size_t size_ = 0; const char* data_ = nullptr; }; -StringView::StringView() - : owner_(false) -{ - -} - StringView::StringView(const char* cstr, size_t count) : StringView(cstr, count, false) { From 117fe5219a2c4da8a4d3681b632a1e4b556c675c Mon Sep 17 00:00:00 2001 From: Di0nisP Date: Fri, 13 Feb 2026 11:53:09 +0500 Subject: [PATCH 14/14] feat (05_week): drop temporary ownership logic in StringView --- 05_week/tasks/string_view/string_view.cpp | 65 +++-------------------- 1 file changed, 8 insertions(+), 57 deletions(-) diff --git a/05_week/tasks/string_view/string_view.cpp b/05_week/tasks/string_view/string_view.cpp index fb9858ea..3355de8d 100644 --- a/05_week/tasks/string_view/string_view.cpp +++ b/05_week/tasks/string_view/string_view.cpp @@ -12,14 +12,7 @@ class StringView { /// @param[in] cstr static storage duration string StringView(const char* cstr, size_t count = npos); StringView(const std::string& cstr, size_t pos = 0, size_t count = npos); - StringView(const std::string&& cstr, size_t pos = 0, size_t count = npos); - - StringView(const StringView&) = delete; - StringView& operator=(const StringView&) = delete; - StringView(StringView&&) noexcept = default; - StringView& operator=(StringView&&) noexcept = default; - - ~StringView(); + StringView(const std::string&& cstr, size_t pos = 0, size_t count = npos) = delete; const char& operator[](size_t index) const; const char* Data() const; @@ -41,52 +34,31 @@ class StringView { std::string ToString() const; -private: - StringView(const char* cstr, size_t count, bool owner); - public: inline static constexpr size_t npos = -1; private: - /** - * @brief Флаг, указывающий, владеет ли StringView данными строки - * - * - @c true , если StringView владеет данными (например, создан из временной строки); - * - @c false , если StringView не владеет данными (например, создан из существующей строки). - * - * @note Модификация поведения std::string_view. - */ - bool owner_ = false; - size_t size_ = 0; const char* data_ = nullptr; }; StringView::StringView(const char* cstr, size_t count) - : StringView(cstr, count, false) { + if (cstr == nullptr) + return; + const size_t cstr_len = std::strlen(cstr); + size_ = count > cstr_len ? cstr_len : count; + data_ = cstr; } StringView::StringView(const std::string& cstr, size_t pos, size_t count) - : StringView(pos >= cstr.size() ? nullptr : cstr.c_str() + pos, count, false) -{ - -} - -StringView::StringView(const std::string&& cstr, size_t pos, size_t count) - : StringView(pos >= cstr.size() ? nullptr : cstr.c_str() + pos, count, true) + : StringView(pos >= cstr.size() ? nullptr : cstr.c_str() + pos, count) { } -StringView::~StringView() -{ - if (owner_ && data_ != nullptr) - delete[] data_; -} - const char& StringView::operator[](size_t index) const { return data_[index]; @@ -170,31 +142,10 @@ StringView StringView::Substr(size_t pos, size_t count) const return StringView(); const size_t new_size = (count > Size() - pos) ? Size() - pos : count; - return StringView(Data() + pos, new_size, false); + return StringView(Data() + pos, new_size); } std::string StringView::ToString() const { return std::string(Data(), Size()); -} - -// private constructor - -StringView::StringView(const char* cstr, size_t count, bool owner) - : owner_(owner) -{ - if (cstr == nullptr) - return; - - const size_t cstr_len = std::strlen(cstr); - size_ = count > cstr_len ? cstr_len : count; - - if (owner_) { // Владеет данными, необходимо создать копию - char* new_data = new char[size_ + 1]; - std::strncpy(new_data, cstr, size_); - new_data[size_] = '\0'; // Гарантировать нуль-терминатор - data_ = new_data; - } else { // Не владеет данными, просто ссылается на существующую строку - data_ = cstr; - } } \ No newline at end of file