diff --git a/.github/workflows/testing_week_01.yml b/.github/workflows/testing_week_01.yml index 380a5e87..be25e996 100644 --- a/.github/workflows/testing_week_01.yml +++ b/.github/workflows/testing_week_01.yml @@ -36,7 +36,7 @@ jobs: - name: Determine tasks to run id: get-tasks run: | - if [[ "${{ github.event_name }}" = "schedule" ]] || + if [["${{ github.event_name }}" = "schedule"]] || [[ "${{ github.event.inputs.tasks }}" = "all" ]]; then # Find all tasks TASKS=() diff --git a/.github/workflows/testing_week_02.yml b/.github/workflows/testing_week_02.yml index dac708d3..f4f63b94 100644 --- a/.github/workflows/testing_week_02.yml +++ b/.github/workflows/testing_week_02.yml @@ -35,7 +35,7 @@ jobs: - name: Determine tasks to run id: get-tasks run: | - if [[ "${{ github.event_name }}" = "schedule" ]] || + if [["${{ github.event_name }}" = "schedule"]] || [[ "${{ github.event.inputs.tasks }}" = "all" ]]; then # Find all tasks TASKS=() diff --git a/.github/workflows/testing_week_03.yml b/.github/workflows/testing_week_03.yml index 4c5b8fe8..38993cfa 100644 --- a/.github/workflows/testing_week_03.yml +++ b/.github/workflows/testing_week_03.yml @@ -38,7 +38,7 @@ jobs: - name: Determine tasks to run id: get-tasks run: | - if [[ "${{ github.event_name }}" = "schedule" ]] || + if [["${{ github.event_name }}" = "schedule"]] || [[ "${{ github.event.inputs.tasks }}" = "all" ]]; then # Find all tasks TASKS=() diff --git a/.github/workflows/testing_week_04.yml b/.github/workflows/testing_week_04.yml index 39322f99..e27e55bb 100644 --- a/.github/workflows/testing_week_04.yml +++ b/.github/workflows/testing_week_04.yml @@ -33,7 +33,7 @@ jobs: - name: Determine tasks to run id: get-tasks run: | - if [[ "${{ github.event_name }}" = "schedule" ]] || + if [["${{ github.event_name }}" = "schedule"]] || [[ "${{ github.event.inputs.tasks }}" = "all" ]]; then # Find all tasks TASKS=() diff --git a/.github/workflows/testing_week_05.yml b/.github/workflows/testing_week_05.yml index 380dbe2d..312f5c25 100644 --- a/.github/workflows/testing_week_05.yml +++ b/.github/workflows/testing_week_05.yml @@ -16,7 +16,7 @@ on: - simple_vector schedule: - - cron: '59 20 17 02 *' # UTC: 20:59 = 23:59 MSK 17 February + - cron: '59 20 16 02 *' # UTC: 20:59 = 23:59 MSK 16 February jobs: test: @@ -33,7 +33,7 @@ jobs: - name: Determine tasks to run id: get-tasks run: | - if [[ "${{ github.event_name }}" = "schedule" ]] || + if [["${{ github.event_name }}" = "schedule"]] || [[ "${{ github.event.inputs.tasks }}" = "all" ]]; then # Find all tasks TASKS=() diff --git a/01_week/tasks/addition/addition.cpp b/01_week/tasks/addition/addition.cpp index 92872802..3ca160a1 100644 --- a/01_week/tasks/addition/addition.cpp +++ b/01_week/tasks/addition/addition.cpp @@ -1,7 +1,10 @@ -#include -#include - +#include // заголовочный файл с целочисленными типами фиксированного размера +#include // из этого мы ничего не используем +// функция принимает две перменных типа int и возвращает число типа int64_t int64_t Addition(int a, int b) { - throw std::runtime_error{"Not implemented"}; -} \ No newline at end of file + + // Чтобы сложение выполнялось в int64_t, приводим a и b к этому типу +// static_cast<новый тип>(переменная) + return static_cast(a) + static_cast(b); +} diff --git a/01_week/tasks/char_changer/char_changer.cpp b/01_week/tasks/char_changer/char_changer.cpp index 3a7344d9..6cec0357 100644 --- a/01_week/tasks/char_changer/char_changer.cpp +++ b/01_week/tasks/char_changer/char_changer.cpp @@ -1,7 +1,88 @@ #include -#include - +#include // применял isspace, isdigit, isupper, islower, toupper size_t CharChanger(char array[], size_t size, char delimiter = ' ') { - throw std::runtime_error{"Not implemented"}; + if (size == 0) { + return 0; + } + + size_t read = 0; // это индекс для чтения + size_t write = 0; // это индекс для запси символов + + // идем по массиву пока не выйдем за него + // и пока текущий символ не конец строки, конец строки по условию это '\0' + while (read < size && array[read] != '\0') { + // в cppreference указано, что isspace должно принимать безнаковый символ, + // поэтому преобразуем текущий символ из char в unsigned char + unsigned char uc = static_cast(array[read]); + // если текущий символ пробельный + if (std::isspace(uc)) { + + // пропускаем все подряд идущие пробельные символы + while (read < size && array[read] != '\0') { + unsigned char c = static_cast(array[read]); + if (!std::isspace(c)) { + break; // текущий символ больше не пробел — выходим + } + ++read; // пробел — пропускаем и идём дальше + } + // теперь когда мы прочитали все пробелы записывыем в write только один пробел + array[write++] = delimiter; + + } else { + // Теперь рассматриваем случай когда у нас идут подряд одинаковые символы + // Текущий символ массива + char current = array[read]; + size_t count = 0; // это как счетчик, то есть сколько повторябщихся символов + // идем пока текущий символ не превзойдет размер массива и + // символ не конец строки и символ на текущей позиции такой же как и currentт + while (read < size && array[read] != '\0' && array[read] == current) { + ++count; + ++read; + } + + // Определяем, какой символ писать по правилам + // в cppreference указано, что isdigit,isupper,islower должно принимать безнаковый символ, + // поэтому преобразуем текущий символ current из char в unsigned char + unsigned char cu = static_cast(current); + char Char; + + if (std::isdigit(cu)) { // цифры заменяем на '*' + Char = '*'; + } else if (std::isupper(cu)) { //прописные латинские не меняем + Char = current; + } else if (std::islower(cu)) { // строчные на прописные + Char = static_cast(std::toupper(cu)); + } else { // остальное на '_' + Char = '_'; + } + + // записываем символ в write + array[write++] = Char; + + // пишем количество повторений, если count > 1 + if (count > 1) { + if (count >= 10) { // Если повторений не менее 10, указывается `0` после символа + array[write++] = '0'; + } else { + // записываем в write число посторений (то есть елси 2222, то 4), + // Например, если было "2222", то count = 4, и мы должны записать символ '4'. + // В кодировке ASCII код символа '0' равен 48 + // Поэтому, чтобы получить символ '4', берём код '0' (48) и прибавляем 4 (48 + 4 = 52 — это код '4') + array[write++] = static_cast('0' + count); // + } + } + } + } + + // завершаем строку + if (write >= size) { + write = size - 1; + } + array[write] = '\0'; + + return write; } + + + diff --git a/01_week/tasks/check_flags/check_flags.cpp b/01_week/tasks/check_flags/check_flags.cpp index 75e7c652..665139dd 100644 --- a/01_week/tasks/check_flags/check_flags.cpp +++ b/01_week/tasks/check_flags/check_flags.cpp @@ -1,8 +1,8 @@ -#include -#include + #include + #include - -enum class CheckFlags : uint8_t { + // каждый флаг это один бит в маске, флаг занимает ровно один + enum class CheckFlags : uint8_t { NONE = 0, TIME = (1 << 0), DATE = (1 << 1), @@ -12,7 +12,82 @@ enum class CheckFlags : uint8_t { DEST = (1 << 5), ALL = TIME | DATE | USER | CERT | KEYS | DEST }; + void PrintCheckFlags(CheckFlags flags) { + // мы не можем напрямую работать с flags, поэтому преобразуем + // flags из типа CheckFlags в обычное число типа uint8_t + // uint8_t потому что все флаги храняться в одном байте + uint8_t mask = static_cast(flags); + // так как маска = 8 бит, то и все разрешенные флаги тоже 8 бит (поэтому uint8_t) + // но в целом как для mask, так и для allowedFlags могли написать int и не париться, но с uint8_t корректнее + uint8_t allowedFlags = static_cast(CheckFlags::ALL); + + // Если передано значение выходит из возможного диапазона значений, то вывод следует оставить пустым. + // к примеру если мы на вход подаем значение 128, а 128 в двочиной это 10000000 (mask), allowedFlags = 01111111, то + // 10000000 + // 11000000 (инверсия) + // -------- + // 10000000 (такого флага в маске нет) + if (mask & ~allowedFlags) { + return; + } + + // Если передан флаг отсутствия проверок, то выводим пустые `[]` + if (mask == 0) { + std::cout << "[]"; + return; + } + + // дальше расматриваем все возможные случаи проверок + std::cout << "["; + // флаг состояний для запятой + bool first = true; + + if (mask & static_cast(CheckFlags::TIME)) { + if (!first) { + std::cout << ","; + } + std::cout << "TIME"; + first = false; + } + + if (mask & static_cast(CheckFlags::DATE)) { + if (!first) { + std::cout << ","; + } + std::cout << "DATE"; + first = false; + } + + if (mask & static_cast(CheckFlags::USER)) { + if (!first) { + std::cout << ","; + } + std::cout << "USER"; + first = false; + } + + if (mask & static_cast(CheckFlags::CERT)) { + if (!first) { + std::cout << ","; + } + std::cout << "CERT"; + first = false; + } + + if (mask & static_cast(CheckFlags::KEYS)) { + if (!first) { + std::cout << ","; + } + std::cout << "KEYS"; + first = false; + } + + if (mask & static_cast(CheckFlags::DEST)) { + if (!first) { + std::cout << ","; + } + std::cout << "DEST"; + } -void PrintCheckFlags(CheckFlags flags) { - throw std::runtime_error{"Not implemented"}; + std::cout << "]"; } diff --git a/01_week/tasks/length_lit/length_lit.cpp b/01_week/tasks/length_lit/length_lit.cpp index e69de29b..d90ec9f8 100644 --- a/01_week/tasks/length_lit/length_lit.cpp +++ b/01_week/tasks/length_lit/length_lit.cpp @@ -0,0 +1,62 @@ +// в метрах +const double INCH = 0.0254; +const double FOOT = 0.3048; +const double CM = 0.01; + +// перевод из дюймов в метры +double operator"" _in_to_m(long double v) { + return v * INCH; +} +// перевод из дюймов в сантиметры +double operator"" _in_to_cm(long double v) { + double m = v * INCH; + return m / CM; +} +// перевод из дюймов в футы +double operator"" _in_to_ft(long double v) { + double m = v * INCH; + return m / FOOT; +} + +// перевод из футов в метры +double operator"" _ft_to_m(long double v) { + return v * FOOT; +} +// перевод из футов в сантиметры +double operator"" _ft_to_cm(long double v) { + double m = v * FOOT; + return m / CM; +} +// перевод из футов в дюймы +double operator"" _ft_to_in(long double v) { + double m = v * FOOT; + return m / INCH; +} + +// перевод из сантиметров в метры +double operator"" _cm_to_m(long double v) { + return v * CM; +} +// перевод из сантиметров в дюймы +double operator"" _cm_to_in(long double v) { + double m = v * CM; + return m / INCH; +} +// перевод из сантиметров в футы +double operator"" _cm_to_ft(long double v) { + double m = v * CM; + return m / FOOT; +} + +// перевод из метров в сантиметры +double operator"" _m_to_cm(long double v) { + return v / CM; +} +// перевод из метров в дюймы +double operator"" _m_to_in(long double v) { + return v / INCH; +} +// перевод из метров в футы +double operator"" _m_to_ft(long double v) { + return v / FOOT; +} diff --git a/01_week/tasks/print_bits/print_bits.cpp b/01_week/tasks/print_bits/print_bits.cpp index a48a43c1..69e712a7 100644 --- a/01_week/tasks/print_bits/print_bits.cpp +++ b/01_week/tasks/print_bits/print_bits.cpp @@ -1,7 +1,30 @@ #include #include - +// value - целое число, его нужно вывести в двоичной форме +// bytes типа size_t потому что bytes это количсевто байт void PrintBits(long long value, size_t bytes) { - throw std::runtime_error{"Not implemented"}; + // по условию мы не можем выполнить функцию когда у нас + // количсевто байт = 0, либо количесвто байт > 8 + if (bytes == 0 || bytes > 8) { + return; + } + // Считаем общее количсевто бит, 1 байт = 1 бит + size_t bits = bytes * 8; + // выводим префикс "0b", дальше будет идти предствление числа + std::cout << "0b"; + // цикл будет выполняться bits раз + for (size_t i = 0; i < bits; ++i) { + size_t bit_index = bits - 1 - i; + // побитовый сдвиг, сравниваем младший бит с 1 и выводим результат + std::cout << ((value >> bit_index) & 1); + + // если i + 1 делится на 4 без остатка и это не полседний бит, + // ставим "'" + if ((i + 1) % 4 == 0 && (i + 1) != bits) { + std::cout << "'"; + } + } + // перевод строки + std::cout << '\n'; } diff --git a/01_week/tasks/quadratic/quadratic.cpp b/01_week/tasks/quadratic/quadratic.cpp index abf7d632..daa8eb20 100644 --- a/01_week/tasks/quadratic/quadratic.cpp +++ b/01_week/tasks/quadratic/quadratic.cpp @@ -1,6 +1,85 @@ -#include +#include +#include +#include void SolveQuadratic(int a, int b, int c) { - throw std::runtime_error{"Not implemented"}; -} \ No newline at end of file + // первый случай: если a = b = c = 0, то уравнение примнимает бесконченое количесвто решений + if (a == 0 && b == 0 && c == 0) { + std::cout << "infinite solutions"; + return; + } + + // второй случай: если a = b = 0, то уравнение решений не имеет + if (a == 0 && b == 0) { + std::cout << "no solutions"; + return; + } + + std::cout << std::setprecision(6); + + // третий случай: a == 0, b != 0 → b*x + c = 0 + if (a == 0) { + double x = -static_cast(c) / static_cast(b); // x = -c / b + + // Убираем возможный "-0" + if (x == -0.0) { + x = 0.0; + } + + std::cout << x; + return; + } + + // 4) четвертый случай: a неравно 0, то есть уже само квадартное уравнение + double A = static_cast(a); + double B = static_cast(b); + double C = static_cast(c); + + // Дискриминант + double D = B * B - 4 * A * C; + + // Нет вещественных корней + if (D < 0) { + std::cout << "no solutions"; + return; + } + + // Один вещественный корень + if (D == 0) { + double root = -B / (2 * A); + double x = static_cast(root); + + // Убираем "-0" + if (x == -0.0) { + x = 0.0; + } + + std::cout << x; + return; + } + + // если D > 0, то имеем два различных корня + double sqrtD = std::sqrt(D); + + double root1 = (-B - sqrtD) / (2 * A); + double root2 = (-B + sqrtD) / (2 * A); + + double x1 = static_cast(root1); + double x2 = static_cast(root2); + + // Убираем "-0" для каждого корня + if (x1 == -0.0) { + x1 = 0.0; + } + if (x2 == -0.0) { + x2 = 0.0; + } + + // выводим так, чтобы x1 < x2 + if (x1 > x2) { + std::swap(x1, x2); + } + + std::cout << x1 << ' ' << x2; +} diff --git a/01_week/tasks/rms/rms.cpp b/01_week/tasks/rms/rms.cpp index 6882f0a9..afc9b67c 100644 --- a/01_week/tasks/rms/rms.cpp +++ b/01_week/tasks/rms/rms.cpp @@ -1,7 +1,19 @@ -#include +#include #include - +#include double CalculateRMS(double values[], size_t size) { - throw std::runtime_error{"Not implemented"}; -} \ No newline at end of file + + // в случае пустовго массива возращаем 0.0 + if (size == 0 || values == nullptr) { + return 0.0; + } + + double sumSq = 0.0; + // сумма квадратов + for (size_t i = 0; i < size; ++i) { + sumSq += values[i] * values[i]; + } + // RMS + return std::sqrt(sumSq /size); +} diff --git a/02_week/tasks/func_array/func_array.cpp b/02_week/tasks/func_array/func_array.cpp index b327e68d..3b332cb6 100644 --- a/02_week/tasks/func_array/func_array.cpp +++ b/02_week/tasks/func_array/func_array.cpp @@ -1,6 +1,29 @@ #include +double ApplyOperations( + double a, + double b, + double (*mathOperations[])(double, double), // массив указателей, который принимает два числа типа double + size_t size // рамзер массива +) { + // если массив пуст - возвращаем 0.0 + if (size == 0) { + return 0.0; + } + // переменная для суммы мат операций + double sum = 0.0; + // проходим по каждому элементу массива + for (size_t i = 0; i < size; ++i) { -double ApplyOperations(double a, double b /* other arguments */) { - throw std::runtime_error{"Not implemented"}; + // если один из указателей массива пустой, то пропускаем + if (mathOperations[i] == nullptr) { + continue; // пропускаем пустую функцию + } + // вызываем i-ю функцию с числами a и b, кладем в v + double v = mathOperations[i](a, b); + // прибавляем к общей сумме + sum += v; + } + + 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..ae0eeec2 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,29 @@ #include +// для случая (nullptr, nullptr) +int* FindLastElement(std::nullptr_t, std::nullptr_t, bool (*)(int)) { + return nullptr; +} +// Функция ищет последний элемент, удовлетворяющий предикату, +// в диапазоне [begin, end). Возвращает указатель на найденный элемент. +// Если элемент не найден или диапазон некорректный, возвращает end. +int* FindLastElement(int* begin, int* end, bool (*predicate)(int)) { + if (begin == nullptr || end == nullptr || begin > end || predicate == nullptr) { + return end; + } + // Перебираем элементы с конца диапазона + for (int* i = end - 1; i >= begin; --i) { + if (predicate(*i)) { + return i; // сразу возвращаем первый подходящий справа + } + } -/* return_type */ FindLastElement(/* ptr_type */ begin, /* ptr_type */ end, /* func_type */ predicate) { - throw std::runtime_error{"Not implemented"}; + // если ничего не нашли, то возвращаем end + return end; +} + +// Перегрузка для const int*. +// Снимаем const, чтобы переиспользовать логику из версии для int*. +const int* FindLastElement(const int* begin, const int* end, bool (*predicate)(int)) { + return FindLastElement(const_cast(begin), const_cast(end), predicate); } \ No newline at end of file diff --git a/02_week/tasks/longest/longest.cpp b/02_week/tasks/longest/longest.cpp index 04b3c354..e4a78575 100644 --- a/02_week/tasks/longest/longest.cpp +++ b/02_week/tasks/longest/longest.cpp @@ -1,6 +1,57 @@ -#include +#include +// Функция ищет самую длинную подпоследовательность одинаковых символов +// в диапазоне [begin, end). Длину подпоследовательности записывает в count. +// Возвращает указатель на начало найденной подпоследовательности. +// В случае ошибки возвращает nullptr. В count записывает 0. +char* FindLongestSubsequence(char* begin, char* end, size_t& count) { + // проверка корректнсти + if (begin == nullptr || end == nullptr || begin >= end) { + count = 0; + return nullptr; + } -/* return_type */ FindLongestSubsequence(/* ptr_type */ begin, /* ptr_type */ end, /* type */ count) { - throw std::runtime_error{"Not implemented"}; + char* best_start = begin; // начало лучшей подпоследовательности + size_t best_length = 1; // длина лучшей последовательности + + char* curr_start = begin; // начало текущей последовательности + size_t curr_length = 1; // длина текущей последовательности + + // Перебираем символы, начиная со второго + for (char* i = begin + 1; i < end; ++i) { + // тут проверка на совпадения + // если совпадает, то увеличивам длину текущей подпоследовательности curr_length + if (*i == *(i - 1)) { + ++curr_length; + } else { + // Если текущая последовательность строго длиннее лучшей, то + // обновляем результат. При равных длинах не обновляем, так как + // по условию возвращается первая + if (curr_length > best_length) { + best_start = curr_start; + best_length = curr_length; + } + curr_start = i; // начинаем новую подпоследовательность с текущего символа + curr_length = 1; // начало новой подпоследовательность + } + } + // Проверяем последнюю подпоследовательность (она могла закончится концом строки) + if (curr_length > best_length) { + best_length = curr_length; + best_start = curr_start; + } + // записываем в count лучшую длину + count = best_length; + return best_start; +} + + +// Перегрузка для const char*. +// Код поиска наибольшей подпоследовтаельности уже реализован в версии для char*, +// поэтому здесь будем использовать его, +// временно снимаем const, чтобы вызвать существующую логику +const char* FindLongestSubsequence(const char* begin, const char* end, size_t& count) { + char* result = FindLongestSubsequence(const_cast(begin), const_cast(end), count); + return result; } + diff --git a/02_week/tasks/swap_ptr/swap_ptr.cpp b/02_week/tasks/swap_ptr/swap_ptr.cpp index 93db625d..dc835ee2 100644 --- a/02_week/tasks/swap_ptr/swap_ptr.cpp +++ b/02_week/tasks/swap_ptr/swap_ptr.cpp @@ -1,6 +1,57 @@ #include +#include +// Есть три вида Template parameters: +// 1. constant template parameter +// 2. type template parameter (нам нужен этот) +// 3. template template parameter +template // параметр-тип +void SwapPtr(T*& a, T*& b) { + T* tmp = a; // сохраняем адрес из a + a = b; // кладём в a адрес из b + b = tmp; // в b кладём старый адрес a +} -void SwapPtr(/* write arguments here */) { - throw std::runtime_error{"Not implemented"}; -} \ No newline at end of file +// версия без использования парметр-тип: +/* void SwapPtr(int*& a, int*& b) { + int* tmp = a; + a = b; + b = tmp; +} + +void SwapPtr(const int*& a, const int*& b) { + const int* tmp = a; + a = b; + b = tmp; +} + +void SwapPtr(int**& a, int**& b) { + int** tmp = a; + a = b; + b = tmp; +} +*/ + + + +// это для визуальной проверки +/* int main() { + int x = 1; + int y = 2; + + int* a = &x; + int* b = &y; + + std::cout << "До SwapPtr\n"; + std::cout << "Адрес a = " << a << ", *a = " << *a << "\n"; + std::cout << "Адрес b = " << b << ", *b = " << *b << "\n"; + + SwapPtr(a, b); + + std::cout << "После SwapPtr\n"; + std::cout << "Адрес a = " << a << ", *a = " << *a << "\n"; + std::cout << "Адрес b = " << b << ", *b = " << *b << "\n"; + + return 0; +} */ + \ No newline at end of file diff --git a/03_week/tasks/data_stats/data_stats.cpp b/03_week/tasks/data_stats/data_stats.cpp index b941c211..fcafac91 100644 --- a/03_week/tasks/data_stats/data_stats.cpp +++ b/03_week/tasks/data_stats/data_stats.cpp @@ -1,11 +1,32 @@ #include - +#include +#include struct DataStats { double avg = 0.0; double sd = 0.0; }; -/* return_type */ CalculateDataStats(/* args */) { - throw std::runtime_error{"Not implemented"}; -} +DataStats CalculateDataStats(const std::vector& data) { + if (data.empty()) { + return DataStats{}; + } + + double mean = 0.0; + double M2 = 0.0; + std::size_t n = 0; + + for (int x : data) { + ++n; + double delta = x - mean; + mean += delta / n; + double delta2 = x - mean; + M2 += delta * delta2; + } + + DataStats result; + result.avg = mean; + result.sd = std::sqrt(M2 / n); + + return result; +} \ No newline at end of file diff --git a/03_week/tasks/easy_compare/easy_compare.cpp b/03_week/tasks/easy_compare/easy_compare.cpp index dd5cb7f6..4bb736d7 100644 --- a/03_week/tasks/easy_compare/easy_compare.cpp +++ b/03_week/tasks/easy_compare/easy_compare.cpp @@ -2,15 +2,60 @@ struct Date { - unsigned year; - unsigned month; - unsigned day; + unsigned year = 0; + unsigned month = 0; + unsigned day = 0; }; +bool operator==(const Date& a, const Date& b) { + return std::tie(a.year, a.month, a.day) == std::tie(b.year, b.month, b.day); +} + +bool operator<(const Date& a, const Date& b) { + return std::tie(a.year, a.month, a.day) < std::tie(b.year, b.month, b.day); +} + +bool operator!=(const Date& a, const Date& b) { + return !(a == b); +} + +bool operator<=(const Date& a, const Date& b) { + return !(b < a); +} + +bool operator>(const Date& a, const Date& b) { + return b < a; +} + +bool operator>=(const Date& a, const Date& b) { + return !(a < b); +} + struct StudentInfo { size_t id; char mark; int score; unsigned course; Date birth_date; -}; \ No newline at end of file +}; + +bool operator==(const StudentInfo& a, const StudentInfo& b) { + return a.mark == b.mark && a.score == b.score; +} + +bool operator!=(const StudentInfo& a, const StudentInfo& b) { + return !(a == b); +} + +bool operator<(const StudentInfo& a, const StudentInfo& b) { + if (a.mark != b.mark) + return a.mark > b.mark; + + if (a.score != b.score) + return a.score < b.score; + + if (a.course != b.course) + return a.course > b.course; + + return a.birth_date < b.birth_date; +} \ 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..4b35b03c 100644 --- a/03_week/tasks/enum_operators/enum_operators.cpp +++ b/03_week/tasks/enum_operators/enum_operators.cpp @@ -12,22 +12,82 @@ enum class CheckFlags : uint8_t { ALL = TIME | DATE | USER | CERT | KEYS | DEST }; -/* return_type */ operator|(/* args */) { - throw std::runtime_error{"Not implemented"}; +static constexpr uint8_t flags_bits(CheckFlags flags) { + return static_cast(flags); } -/* return_type */ operator&(/* args */) { - throw std::runtime_error{"Not implemented"}; +static constexpr uint8_t VALID_FLAGS = flags_bits(CheckFlags::ALL); + +CheckFlags operator|(CheckFlags left, CheckFlags right) { + return static_cast( + (flags_bits(left) | flags_bits(right)) & VALID_FLAGS + ); } -/* return_type */ operator^(/* args */) { - throw std::runtime_error{"Not implemented"}; +bool operator&(CheckFlags left, CheckFlags right) { + uint8_t left_flags = flags_bits(left) & VALID_FLAGS; + uint8_t right_flags = flags_bits(right) & VALID_FLAGS; + + return left_flags && right_flags && + ((left_flags & right_flags) == left_flags || + (left_flags & right_flags) == right_flags); } -/* return_type */ operator~(/* args */) { - throw std::runtime_error{"Not implemented"}; +CheckFlags operator^(CheckFlags left, CheckFlags right) { + return static_cast( + (flags_bits(left) ^ flags_bits(right)) & VALID_FLAGS + ); } -/* return_type */ operator<<(/* args */) { - throw std::runtime_error{"Not implemented"}; +CheckFlags operator~(CheckFlags flags) { + return static_cast( + (~flags_bits(flags)) & VALID_FLAGS + ); } + +std::ostream& operator<<(std::ostream& output, CheckFlags flags) { + uint8_t active_flags = flags_bits(flags) & VALID_FLAGS; + + if (active_flags == 0) { + output << "NONE"; + return output; + } + + bool add_separator = false; + + if (active_flags & flags_bits(CheckFlags::TIME)) { + output << "TIME"; + add_separator = true; + } + + if (active_flags & flags_bits(CheckFlags::DATE)) { + if (add_separator) output << ", "; + output << "DATE"; + add_separator = true; + } + + if (active_flags & flags_bits(CheckFlags::USER)) { + if (add_separator) output << ", "; + output << "USER"; + add_separator = true; + } + + if (active_flags & flags_bits(CheckFlags::CERT)) { + if (add_separator) output << ", "; + output << "CERT"; + add_separator = true; + } + + if (active_flags & flags_bits(CheckFlags::KEYS)) { + if (add_separator) output << ", "; + output << "KEYS"; + add_separator = true; + } + + if (active_flags & flags_bits(CheckFlags::DEST)) { + if (add_separator) output << ", "; + output << "DEST"; + } + + return output; +} \ No newline at end of file diff --git a/03_week/tasks/filter/filter.cpp b/03_week/tasks/filter/filter.cpp index 6648cb39..4af7c907 100644 --- a/03_week/tasks/filter/filter.cpp +++ b/03_week/tasks/filter/filter.cpp @@ -1,6 +1,19 @@ #include +#include +void Filter(std::vector& data, bool (*pred)(int)) { + if (!pred) { + return; + } -/* return_type */ Filter(/* args */) { - throw std::runtime_error{"Not implemented"}; + std::size_t write = 0; + + for (std::size_t read = 0; read < data.size(); ++read) { + if (pred(data[read])) { + data[write] = data[read]; + ++write; + } + } + + data.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..9744a9cc 100644 --- a/03_week/tasks/find_all/find_all.cpp +++ b/03_week/tasks/find_all/find_all.cpp @@ -1,6 +1,21 @@ #include +#include +std::vector FindAll(const std::vector& vec, bool (*predicate)(int)) +{ + std::vector result; -/* return_type */ FindAll(/* args */) { - throw std::runtime_error{"Not implemented"}; -} \ No newline at end of file + if (predicate == nullptr) { + return result; + } + + for (size_t i = 0; i < vec.size(); ++i) { + if (predicate(vec[i])) { + result.push_back(i); + } + } + + result.shrink_to_fit(); + + return result; +} diff --git a/03_week/tasks/minmax/minmax.cpp b/03_week/tasks/minmax/minmax.cpp index c2869799..46d319b1 100644 --- a/03_week/tasks/minmax/minmax.cpp +++ b/03_week/tasks/minmax/minmax.cpp @@ -1,6 +1,35 @@ #include +#include +std::pair::const_iterator, + std::vector::const_iterator> +MinMax(const std::vector& v) { + if (v.empty()) { + return {v.end(), v.end()}; + } -/* return_type */ MinMax(/* args */) { - throw std::runtime_error{"Not implemented"}; -} + auto min_it = v.begin(); // итератор минимума + auto max_it = v.begin(); // итератор максимума + bool all_eq = true; + int first = *v.begin(); + + for (auto it = v.begin(); it != v.end(); ++it) { + if (*it != first) { + all_eq = false; + } + + if (*it < *min_it) { + min_it = it; // первое вхождение минимума + } + + if (*it >= *max_it) { + max_it = it; // последнее вхождение максимума + } + } + + if (all_eq) { + return {v.end() - 1, v.begin()}; + } + + return {min_it, max_it}; +} \ No newline at end of file diff --git a/04_week/tasks/phasor/phasor.cpp b/04_week/tasks/phasor/phasor.cpp index 3ec1b9ad..e97dc793 100644 --- a/04_week/tasks/phasor/phasor.cpp +++ b/04_week/tasks/phasor/phasor.cpp @@ -1,4 +1,6 @@ - +#include +#include +#include struct ExpTag {}; struct DegTag {}; @@ -6,5 +8,171 @@ struct AlgTag {}; class Phasor { +public: + Phasor() : real_(0.0), imag_(0.0) {} + + Phasor(double magnitude, double phase_rad) { + SetPolar(magnitude, phase_rad); + } + + Phasor(double magnitude, double phase_rad, ExpTag) + : Phasor(magnitude, phase_rad) {} + + Phasor(double magnitude, double phase_deg, DegTag) { + SetPolar(magnitude, DegToRad(phase_deg)); + } + + Phasor(double real, double imag, AlgTag) + : real_(real), imag_(imag) {} + + void SetPolar(double magnitude, double phase_rad) { + if (magnitude < 0) { + magnitude = -magnitude; + phase_rad += M_PI; + } + real_ = magnitude * std::cos(phase_rad); + imag_ = magnitude * std::sin(phase_rad); + } + + void SetCartesian(double real, double imag) { + real_ = real; + imag_ = imag; + } + + double Real() const { return real_; } + double Imag() const { return imag_; } + + double Magnitude() const { + return std::hypot(real_, imag_); + } + + double Abs() const { return Magnitude(); } + + double Phase() const { + return NormalizeRad(std::atan2(imag_, real_)); + } + + double Angle() const { return Phase(); } + + double PhaseDeg() const { + return NormalizeDeg(RadToDeg(Phase())); + } + + double AngleDeg() const { return PhaseDeg(); } + + Phasor Conj() const { + return Phasor(real_, -imag_, AlgTag{}); + } + + Phasor Inv() const { + double d = real_ * real_ + imag_ * imag_; + return Phasor(real_ / d, -imag_ / d, AlgTag{}); + } + + Phasor& operator+=(const Phasor& rhs) { + real_ += rhs.real_; + imag_ += rhs.imag_; + return *this; + } + + Phasor& operator-=(const Phasor& rhs) { + real_ -= rhs.real_; + imag_ -= rhs.imag_; + return *this; + } + Phasor& operator*=(const Phasor& rhs) { + double mag = Magnitude() * rhs.Magnitude(); + double phase = Phase() + rhs.Phase(); + SetPolar(mag, phase); + return *this; + } + + Phasor& operator/=(const Phasor& rhs) { + double mag = Magnitude() / rhs.Magnitude(); + double phase = Phase() - rhs.Phase(); + SetPolar(mag, phase); + return *this; + } + + Phasor& operator+=(double x) { return *this += Phasor(x, 0.0, AlgTag{}); } + Phasor& operator-=(double x) { return *this -= Phasor(x, 0.0, AlgTag{}); } + Phasor& operator*=(double x) { return *this *= Phasor(x, 0.0); } + Phasor& operator/=(double x) { return *this /= Phasor(x, 0.0); } + + Phasor operator-() const { + return Phasor(-real_, -imag_, AlgTag{}); + } + + bool operator==(const Phasor& rhs) const { + return NearlyEqual(real_, rhs.real_) && + NearlyEqual(imag_, rhs.imag_); + } + + bool operator!=(const Phasor& rhs) const { + return !(*this == rhs); + } + +private: + double real_; + double imag_; + + static bool NearlyEqual(double a, double b, double eps = 1e-12) { + return std::fabs(a - b) < eps; + } + + static double NormalizeRad(double x) { + while (x <= -M_PI) x += 2 * M_PI; + while (x > M_PI) x -= 2 * M_PI; + return x; + } + + static double NormalizeDeg(double x) { + while (x <= -180.0) x += 360.0; + while (x > 180.0) x -= 360.0; + return x; + } + + static double DegToRad(double d) { + return d * M_PI / 180.0; + } + + static double RadToDeg(double r) { + return r * 180.0 / M_PI; + } }; + +inline Phasor operator+(Phasor lhs, const Phasor& rhs) { return lhs += rhs; } +inline Phasor operator-(Phasor lhs, const Phasor& rhs) { return lhs -= rhs; } +inline Phasor operator*(Phasor lhs, const Phasor& rhs) { return lhs *= rhs; } +inline Phasor operator/(Phasor lhs, const Phasor& rhs) { return lhs /= rhs; } + +inline Phasor operator+(Phasor p, double x) { return p += x; } +inline Phasor operator-(Phasor p, double x) { return p -= x; } +inline Phasor operator*(Phasor p, double x) { return p *= x; } +inline Phasor operator/(Phasor p, double x) { return p /= x; } + +inline Phasor operator+(double x, Phasor p) { return p + x; } +inline Phasor operator-(double x, Phasor p) { return Phasor(x, 0.0, AlgTag{}) - p; } +inline Phasor operator*(double x, Phasor p) { return p * x; } +inline Phasor operator/(double x, Phasor p) { return Phasor(x, 0.0) / p; } + +inline Phasor MakePhasorCartesian(double real, double imag) { + return Phasor(real, imag, AlgTag{}); +} + +inline Phasor MakePhasorPolar(double mag, double phase_rad) { + return Phasor(mag, phase_rad); +} + +inline Phasor MakePhasorPolarDeg(double mag, double phase_deg) { + return Phasor(mag, phase_deg, DegTag{}); +} + +inline std::ostream& operator<<(std::ostream& os, const Phasor& p) { + os << std::fixed << std::setprecision(3) + << p.Magnitude() + << "*e(j*" << p.PhaseDeg() << ") " + << "[" << p.Real() << " + j*" << p.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..2c2256d3 100644 --- a/04_week/tasks/queue/queue.cpp +++ b/04_week/tasks/queue/queue.cpp @@ -1,6 +1,125 @@ #include - +#include +#include class Queue { +public: + Queue() = default; + + explicit Queue(size_t capacity) { + in_.reserve(capacity); + } + + explicit Queue(const std::vector& vec) { + in_ = vec; + } + + explicit Queue(const std::stack& st) { + std::stack tmp = st; + std::vector rev; + rev.reserve(tmp.size()); + while (!tmp.empty()) { + rev.push_back(tmp.top()); + tmp.pop(); + } + std::reverse(rev.begin(), rev.end()); + in_ = std::move(rev); + } + + Queue(std::initializer_list init) { + in_.assign(init.begin(), init.end()); + } + + void Push(int value) { + in_.push_back(value); + } + + bool Pop() { + if (Empty()) { + return false; + } + EnsureOutNotEmpty(); + out_.pop_back(); + return true; + } + + int& Front() { + EnsureOutNotEmpty(); + return out_.back(); + } + + const int& Front() const { + EnsureOutNotEmpty(); + return out_.back(); + } + + int& Back() { + if (!in_.empty()) { + return in_.back(); + } + return out_.front(); + } + + const int& Back() const { + if (!in_.empty()) { + return in_.back(); + } + return out_.front(); + } + + bool Empty() const { + return in_.empty() && out_.empty(); + } + + size_t Size() const { + return in_.size() + out_.size(); + } + + void Clear() { + in_.clear(); + out_.clear(); + } + + void Swap(Queue& other) { + if (this == &other) return; + in_.swap(other.in_); + out_.swap(other.out_); + } + + friend bool operator==(const Queue& a, const Queue& b) { + if (a.Size() != b.Size()) { + return false; + } + return a.ToVector() == b.ToVector(); + } + + friend bool operator!=(const Queue& a, const Queue& b) { + return !(a == b); + } + +private: + mutable std::vector in_; + mutable std::vector out_; + + void EnsureOutNotEmpty() const { + if (!out_.empty()) { + return; + } + while (!in_.empty()) { + out_.push_back(in_.back()); + in_.pop_back(); + } + } + std::vector ToVector() const { + std::vector result; + result.reserve(Size()); + for (auto it = out_.rbegin(); it != out_.rend(); ++it) { + result.push_back(*it); + } + for (int x : in_) { + result.push_back(x); + } + return result; + } }; diff --git a/04_week/tasks/ring_buffer/ring_buffer.cpp b/04_week/tasks/ring_buffer/ring_buffer.cpp index e2b57ba2..2fa5f1ab 100644 --- a/04_week/tasks/ring_buffer/ring_buffer.cpp +++ b/04_week/tasks/ring_buffer/ring_buffer.cpp @@ -1,6 +1,133 @@ #include - +#include class RingBuffer { +public: + explicit RingBuffer(size_t capacity) + : data_(capacity == 0 ? 1 : capacity), head_(0), size_(0) {} + + RingBuffer(size_t capacity, int value) + : data_(capacity == 0 ? 1 : capacity, value), + head_(0), + size_(capacity == 0 ? 1 : capacity) {} + + RingBuffer(std::initializer_list init) + : data_(init), head_(0), size_(init.size()) { + if (data_.empty()) { + data_.resize(1); + size_ = 0; + } + } + + void Push(int value) { + if (Full()) { + data_[head_] = value; + head_ = (head_ + 1) % data_.size(); + } else { + data_[Index(size_)] = value; + ++size_; + } + } + + bool TryPush(int value) { + if (Full()) { + return false; + } + Push(value); + return true; + } + + void Pop() { + if (Empty()) { + return; + } + head_ = (head_ + 1) % data_.size(); + --size_; + } + + bool TryPop(int& value) { + if (Empty()) { + return false; + } + value = data_[head_]; + Pop(); + return true; + } + + int& operator[](size_t index) { + return data_[Index(index)]; + } + + const int& operator[](size_t index) const { + return data_[Index(index)]; + } + + int& Front() { + return data_[Index(size_ - 1)]; + } + + int& Back() { + return data_[head_]; + } + + bool Empty() const { + return size_ == 0; + } + + bool Full() const { + return size_ == data_.size(); + } + + size_t Size() const { + return size_; + } + + size_t Capacity() const { + return data_.size(); + } + + void Clear() { + head_ = 0; + size_ = 0; + } + + void Resize(size_t new_capacity) { + if (new_capacity == 0) { + new_capacity = 1; + } + + std::vector new_data; + new_data.reserve(new_capacity); + + size_t new_size = size_ < new_capacity ? size_ : new_capacity; + + for (size_t i = size_ - new_size; i < size_; ++i) { + new_data.push_back((*this)[i]); + } + + data_ = std::move(new_data); + data_.resize(new_capacity); + + head_ = 0; + size_ = new_size; + } + + std::vector Vector() const { + std::vector result; + result.reserve(size_); + + for (size_t i = 0; i < size_; ++i) { + result.push_back((*this)[i]); + } + return result; + } + +private: + std::vector data_; + size_t head_; + size_t size_; + size_t Index(size_t logical_index) const { + return (head_ + logical_index) % data_.size(); + } }; diff --git a/05_week/tasks/cow_string/cow_string.cpp b/05_week/tasks/cow_string/cow_string.cpp index 34d59738..a8d23f46 100644 --- a/05_week/tasks/cow_string/cow_string.cpp +++ b/05_week/tasks/cow_string/cow_string.cpp @@ -1,6 +1,227 @@ +#include #include #include class CowString { +public: + static constexpr std::size_t npos = static_cast(-1); + // Конструктор по умолчанию + CowString(); + // Конструктор от const char* + CowString(const char* cstr); + // Конструктор от std::string + CowString(const std::string& s); + + // Конструктор копирования + CowString(const CowString& other); + // Присваивание копированием + CowString& operator=(const CowString& other); + + // Конструктор перемещения + CowString(CowString&& other) noexcept; + // Присваивание перемещением + CowString& operator=(CowString&& other) noexcept; + + // Деструктор + ~CowString(); + + std::size_t Size() const; + bool Empty() const; + + const char* ToCstr() const; + std::string ToString() const; + + // [] чтение + const char& operator[](std::size_t i) const; + // [] запись + char& operator[](std::size_t i); + + // Преобразование к C-строке + operator const char*() const; + + CowString& Append(const char* tail); + CowString& Append(const std::string& tail); + + CowString Substr(std::size_t pos = 0, std::size_t count = npos) const; + + void Clear(); + + std::size_t Find(const char* needle) const; + std::size_t Find(const std::string& needle) const; + std::size_t Find(char ch) const; + +private: + struct Buffer { + char* data; + std::size_t size; + std::size_t ref_count; + + Buffer(const char* src, std::size_t len); + ~Buffer(); + }; + + Buffer* buf_; + + void Detach(); + void Release(); }; + +//Buffer + +CowString::Buffer::Buffer(const char* src, std::size_t len) + : data(new char[len + 1]), size(len), ref_count(1) { + if (len) std::memcpy(data, src, len); + data[len] = '\0'; +} + +CowString::Buffer::~Buffer() { + delete[] data; +} + +//Внутренние методы + +void CowString::Release() { + if (!buf_) return; + if (--buf_->ref_count == 0) delete buf_; + buf_ = nullptr; +} + +void CowString::Detach() { + if (buf_->ref_count == 1) return; + Buffer* fresh = new Buffer(buf_->data, buf_->size); + --buf_->ref_count; + buf_ = fresh; +} + +//Конструкторы / деструктор + +CowString::CowString() + : buf_(new Buffer("", 0)) {} + +CowString::CowString(const char* cstr) + : buf_(nullptr) { + if (!cstr) cstr = ""; + buf_ = new Buffer(cstr, std::strlen(cstr)); +} + +CowString::CowString(const std::string& s) + : CowString(s.c_str()) {} + +CowString::CowString(const CowString& other) + : buf_(other.buf_) { + ++buf_->ref_count; +} + +CowString& CowString::operator=(const CowString& other) { + if (this == &other) return *this; + Release(); + buf_ = other.buf_; + ++buf_->ref_count; + return *this; +} + +CowString::CowString(CowString&& other) noexcept + : buf_(other.buf_) { + other.buf_ = new Buffer("", 0); +} + +CowString& CowString::operator=(CowString&& other) noexcept { + if (this == &other) return *this; + Release(); + buf_ = other.buf_; + other.buf_ = new Buffer("", 0); + return *this; +} + +CowString::~CowString() { + Release(); +} + +// Методы + +std::size_t CowString::Size() const { + return buf_->size; +} + +bool CowString::Empty() const { + return buf_->size == 0; +} + +const char* CowString::ToCstr() const { + return buf_->data; +} + +std::string CowString::ToString() const { + return std::string(buf_->data); +} + +const char& CowString::operator[](std::size_t i) const { + return buf_->data[i]; +} + +char& CowString::operator[](std::size_t i) { + Detach(); + return buf_->data[i]; +} + +CowString::operator const char*() const { + return buf_->data; +} + +CowString& CowString::Append(const char* tail) { + if (!tail || tail[0] == '\0') return *this; + + Detach(); + + const std::size_t add = std::strlen(tail); + const std::size_t new_size = buf_->size + add; + + char* new_data = new char[new_size + 1]; + if (buf_->size) std::memcpy(new_data, buf_->data, buf_->size); + std::memcpy(new_data + buf_->size, tail, add); + new_data[new_size] = '\0'; + + delete[] buf_->data; + buf_->data = new_data; + buf_->size = new_size; + + return *this; +} + +CowString& CowString::Append(const std::string& tail) { + return Append(tail.c_str()); +} + +CowString CowString::Substr(std::size_t pos, std::size_t count) const { + if (pos >= buf_->size) return CowString(); + + std::size_t avail = buf_->size - pos; + std::size_t take = (count == npos || count > avail) ? avail : count; + + return CowString(std::string(buf_->data + pos, take)); +} + +void CowString::Clear() { + Detach(); + delete[] buf_->data; + buf_->data = new char[1]{'\0'}; + buf_->size = 0; +} + +std::size_t CowString::Find(const char* needle) const { + if (!needle) return npos; + if (needle[0] == '\0') return 0; + + const char* p = std::strstr(buf_->data, needle); + return p ? static_cast(p - buf_->data) : npos; +} + +std::size_t CowString::Find(const std::string& needle) const { + return Find(needle.c_str()); +} + +std::size_t CowString::Find(char ch) const { + const void* p = std::memchr(buf_->data, static_cast(ch), buf_->size); + return p ? static_cast(static_cast(p) - buf_->data) : npos; +} diff --git a/05_week/tasks/simple_vector/README.md b/05_week/tasks/simple_vector/README.md index d3913644..6b7a4c47 100644 --- a/05_week/tasks/simple_vector/README.md +++ b/05_week/tasks/simple_vector/README.md @@ -60,8 +60,7 @@ - Устройство вектора обсуждалось в конце третьей лекции - Для поддержки range-based for необходимы методы `begin`, `end` или внешние функции `begin`, `end`, принимающие заданную коллекцию, поэтому допустимо, чтобы они не - соответствовали стайлгайду. Если не хочется нарушать стайлгайд, то методы класса - могут быть с большой буквы, но внешние функции должны быть с маленькой + соответствовали стайлгайду. Если стайлгайд не хочется - Для совместимости с алгоритмами стандартной библиотеки **STL** может потребоваться `swap`, ситуация аналогичная, но поскольку требуется внутри класса `Swap`, достаточно реализовать внешнюю функцию, вызывающую метод `Swap` контейнера diff --git a/05_week/tasks/string_view/string_view.cpp b/05_week/tasks/string_view/string_view.cpp index 438c4536..65a73217 100644 --- a/05_week/tasks/string_view/string_view.cpp +++ b/05_week/tasks/string_view/string_view.cpp @@ -1,7 +1,130 @@ #include #include - class StringView { +public: + using SizeType = std::size_t; + static constexpr SizeType npos = static_cast(-1); // аналог std::string::npos + + // Конструктор по умолчанию + StringView() noexcept : data_(nullptr), size_(0) {} + + // Конструктор от std::string (с позицией и длиной подстроки) + explicit StringView(const std::string& str, + SizeType pos = 0, + SizeType count = npos) noexcept { + if (pos >= str.size()) { + Reset(); // если pos вне строки → пусто + return; + } + data_ = str.data() + pos; + SizeType max_len = str.size() - pos; + size_ = (count == npos || count > max_len) ? max_len : count; + } + + // Конструктор от C-строки (const char*) + StringView(const char* cstr) noexcept { + if (!cstr) { + Reset(); + return; + } + data_ = cstr; + size_ = std::strlen(cstr); + } + + // Конструктор от C-строки с заданной длиной + StringView(const char* cstr, SizeType len) noexcept { + if (!cstr) { + Reset(); + return; + } + data_ = cstr; + size_ = len; + } + + // доступ к символам (только чтение) + const char& operator[](SizeType i) const noexcept { return data_[i]; } + + // указатель на данные + const char* Data() const noexcept { return data_; } + + // первый и последний символ + const char& Front() const noexcept { return data_[0]; } + const char& Back() const noexcept { return data_[size_ - 1]; } + + // размер представления + SizeType Size() const noexcept { return size_; } + SizeType Length() const noexcept { return size_; } + + // проверка на пустоту + bool Empty() const noexcept { return size_ == 0; } + + // убрать n символов с начала + void RemovePrefix(SizeType n) noexcept { + if (n >= size_) { + Reset(); + return; + } + data_ += n; + size_ -= n; + } + + // убрать n символов с конца + void RemoveSuffix(SizeType n) noexcept { + if (n >= size_) { + Reset(); + return; + } + size_ -= n; + } + + // получить подстроку (новое представление) + StringView Substr(SizeType pos, SizeType count = npos) const noexcept { + if (pos >= size_) return StringView(); + + SizeType max_len = size_ - pos; + SizeType len = (count == npos || count > max_len) ? max_len : count; + + return StringView(data_ + pos, len); + } + + // поиск символа + SizeType Find(char ch, SizeType pos = 0) const noexcept { + if (pos >= size_) return npos; + + for (SizeType i = pos; i < size_; ++i) { + if (data_[i] == ch) return i; + } + return npos; + } + + // поиск подстроки + SizeType Find(StringView substr, SizeType pos = 0) const noexcept { + if (substr.size_ == 0) { + return (pos <= size_) ? pos : npos; + } + if (pos > size_ || substr.size_ > size_ - pos) return npos; + + for (SizeType i = pos; i + substr.size_ <= size_; ++i) { + if (std::memcmp(data_ + i, substr.data_, substr.size_) == 0) { + return i; + } + } + return npos; + } + + // преобразование в std::string + std::string ToString() const { + return (data_ && size_) ? std::string(data_, size_) : std::string(); + } + +private: + const char* data_; // указатель на начало строки + SizeType size_; // длина представления -}; \ No newline at end of file + // сделать объект пустым + void Reset() noexcept { + data_ = nullptr; + size_ = 0; + } +}; diff --git a/05_week/tasks/tracer/tracer.cpp b/05_week/tasks/tracer/tracer.cpp index 2ccfb417..7b0ea110 100644 --- a/05_week/tasks/tracer/tracer.cpp +++ b/05_week/tasks/tracer/tracer.cpp @@ -1,6 +1,95 @@ #include - +#include class Tracer { +public: + // Счетчики (доступны извне) + inline static int count = 0; // сколько объектов когда-либо создано (и генератор id) + inline static int default_ctor = 0; + inline static int str_ctor = 0; + inline static int copy_ctor = 0; + inline static int move_ctor = 0; + inline static int copy_assign = 0; + inline static int move_assign = 0; + inline static int dtor = 0; + inline static int alive = 0; + + // Конструктор по умолчанию + Tracer() : id_(NextId()), name_("obj_" + std::to_string(id_)) { + ++default_ctor; + ++alive; + } + + // Конструктор от строки std::string + Tracer(const std::string& base_name) : id_(NextId()), name_(base_name + "_" + std::to_string(id_)) { + ++str_ctor; + ++alive; + } + + // Конструктор от C-строки + Tracer(const char* base_name) : Tracer(std::string(base_name ? base_name : "")) {} + + // Копирующий конструктор: копирует имя, но создаёт новый id + Tracer(const Tracer& other) : id_(NextId()), name_(other.name_) { + ++copy_ctor; + ++alive; + } + + // Перемещающий конструктор: перемещает имя, но создаёт новый id + Tracer(Tracer&& other) noexcept : id_(NextId()), name_(std::move(other.name_)) { + ++move_ctor; + ++alive; + } + + // Копирующее присваивание: копирует имя, id не меняется + Tracer& operator=(const Tracer& other) { + if (this == &other) { + return *this; // self-assignment: не считаем, не меняем + } + name_ = other.name_; + ++copy_assign; + return *this; + } + + // Перемещающее присваивание: перемещает имя, id не меняется + Tracer& operator=(Tracer&& other) noexcept { + if (this == &other) { + return *this; // self-move: не считаем, не меняем + } + name_ = std::move(other.name_); + ++move_assign; + return *this; + } + + // Деструктор + ~Tracer() { + ++dtor; + --alive; + } + + // Id, Name, Data + int Id() const { return id_; } + const std::string& Name() const { return name_; } + const char* Data() const { return name_.c_str(); } + + // Сброс статистики + static void ResetStats() { + count = 0; + default_ctor = 0; + str_ctor = 0; + copy_ctor = 0; + move_ctor = 0; + copy_assign = 0; + move_assign = 0; + dtor = 0; + alive = 0; + } + +private: + int id_; + std::string name_; -}; \ No newline at end of file + static int NextId() { + return ++count; // id начинается с 1 + } +}; diff --git a/06_week/tasks/simple_list/simple_list.cpp b/06_week/tasks/simple_list/simple_list.cpp index e97b2a81..7a485f28 100644 --- a/06_week/tasks/simple_list/simple_list.cpp +++ b/06_week/tasks/simple_list/simple_list.cpp @@ -2,4 +2,188 @@ class SimpleList { -}; \ No newline at end of file + // Узел двусвязного списка + struct Node { + std::string value; // значение + Node* next; // следующий элемент + Node* prev; // предыдущий элемент + + Node(const std::string& v) : value(v), next(nullptr), prev(nullptr) {} + Node(std::string&& v) : value(std::move(v)), next(nullptr), prev(nullptr) {} + }; + + Node* head = nullptr; // первый элемент списка + Node* tail = nullptr; // последний элемент списка + size_t size_ = 0; // количество элементов + +public: + + SimpleList() = default; // конструктор + + ~SimpleList() { Clear(); } // освобождение памяти + + // конструктор копирования + SimpleList(const SimpleList& other) { + for (Node* cur = other.head; cur; cur = cur->next) + PushBack(cur->value); + } + + // конструктор перемещения + SimpleList(SimpleList&& other) noexcept + : head(other.head), tail(other.tail), size_(other.size_) { + + other.head = other.tail = nullptr; + other.size_ = 0; + } + + // оператор копирующего присваивания + SimpleList& operator=(const SimpleList& other) { + + if (this != &other) { + Clear(); + for (Node* cur = other.head; cur; cur = cur->next) + PushBack(cur->value); + } + + return *this; + } + + // оператор перемещающего присваивания + SimpleList& operator=(SimpleList&& other) noexcept { + + if (this != &other) { + + Clear(); + + head = other.head; + tail = other.tail; + size_ = other.size_; + + other.head = other.tail = nullptr; + other.size_ = 0; + } + + return *this; + } + + // обмен содержимым списков + void Swap(SimpleList& other) { + std::swap(head, other.head); + std::swap(tail, other.tail); + std::swap(size_, other.size_); + } + + size_t Size() const { return size_; } // вернуть размер + + bool Empty() const { return size_ == 0; } // список пуст + + // вставка в конец + void PushBack(const std::string& v) { + + Node* n = new Node(v); + + if (!tail) + head = tail = n; + else { + tail->next = n; + n->prev = tail; + tail = n; + } + + ++size_; + } + + // вставка в конец (перемещение) + void PushBack(std::string&& v) { + + Node* n = new Node(std::move(v)); + + if (!tail) + head = tail = n; + else { + tail->next = n; + n->prev = tail; + tail = n; + } + + ++size_; + } + + // вставка в начало + void PushFront(const std::string& v) { + + Node* n = new Node(v); + + if (!head) + head = tail = n; + else { + n->next = head; + head->prev = n; + head = n; + } + + ++size_; + } + + // вставка в начало (перемещение) + void PushFront(std::string&& v) { + + Node* n = new Node(std::move(v)); + + if (!head) + head = tail = n; + else { + n->next = head; + head->prev = n; + head = n; + } + + ++size_; + } + + // удалить последний элемент + void PopBack() { + + if (!tail) return; + + Node* t = tail; + tail = tail->prev; + + if (tail) tail->next = nullptr; + else head = nullptr; + + delete t; + --size_; + } + + // удалить первый элемент + void PopFront() { + + if (!head) return; + + Node* h = head; + head = head->next; + + if (head) head->prev = nullptr; + else tail = nullptr; + + delete h; + --size_; + } + + std::string& Front() { return head->value; } // первый элемент + const std::string& Front() const { return head->value; } + + std::string& Back() { return tail->value; } // последний элемент + const std::string& Back() const { return tail->value; } + + // очистить список + void Clear() { + while (head) PopFront(); + } +}; + +// внешний Swap +inline void Swap(SimpleList& a, SimpleList& b) { + a.Swap(b); +} \ No newline at end of file diff --git a/06_week/tasks/unique_ptr/unique_ptr.cpp b/06_week/tasks/unique_ptr/unique_ptr.cpp index db8729ad..5e6dc5a9 100644 --- a/06_week/tasks/unique_ptr/unique_ptr.cpp +++ b/06_week/tasks/unique_ptr/unique_ptr.cpp @@ -1,6 +1,85 @@ #include - +#include class UniquePtr { +private: + std::string* ptr_; + +public: + + // Конструктор по умолчанию + UniquePtr() : ptr_(nullptr) {} + + // Конструктор от сырого указателя + explicit UniquePtr(std::string* ptr) : ptr_(ptr) {} + + // Удаляем копирование + UniquePtr(const UniquePtr&) = delete; + UniquePtr& operator=(const UniquePtr&) = delete; + + // Конструктор перемещения + UniquePtr(UniquePtr&& other) noexcept : ptr_(other.ptr_) { + other.ptr_ = nullptr; + } + + // Оператор перемещения + UniquePtr& operator=(UniquePtr&& other) noexcept { + if (this != &other) { + delete ptr_; + ptr_ = other.ptr_; + other.ptr_ = nullptr; + } + return *this; + } + + // Деструктор + ~UniquePtr() { + delete ptr_; + } + + // Операторы указателя + std::string& operator*() const { + return *ptr_; + } + + std::string* operator->() const { + return ptr_; + } + + // Получить сырой указатель + std::string* Get() const { + return ptr_; + } + + // Освободить владение + std::string* Release() { + std::string* temp = ptr_; + ptr_ = nullptr; + return temp; + } + + // Сбросить указатель + void Reset(std::string* ptr = nullptr) { + delete ptr_; + ptr_ = ptr; + } + + // Обмен указателями + void Swap(UniquePtr& other) { + std::swap(ptr_, other.ptr_); + } + + // bool преобразование + explicit operator bool() const { + return ptr_ != nullptr; + } +}; + +template +UniquePtr MakeUnique(T&& value) { + return UniquePtr(new std::string(std::forward(value))); +} -}; \ No newline at end of file +void Swap(UniquePtr& a, UniquePtr& b) { + a.Swap(b); +} \ No newline at end of file diff --git a/07_week/tasks/array/array.cpp b/07_week/tasks/array/array.cpp index b1b8feab..2f80b025 100644 --- a/07_week/tasks/array/array.cpp +++ b/07_week/tasks/array/array.cpp @@ -1,6 +1,258 @@ #include +#include - +template class Array { +public: + // Конструкторы и деструктор + Array(); + Array(std::initializer_list init); + Array(const Array& other); + Array(Array&& other); + Array& operator=(const Array& other); + Array& operator=(Array&& other); + ~Array(); + + // Операторы индексирования [] + T& operator[](std::size_t index); + const T& operator[](std::size_t index) const; + + // Возвращает ссылку на первый элемент массива + T& Front(); + const T& Front() const; + + // Возвращает ссылку на последний элемент массива + T& Back(); + const T& Back() const; + + // Прямой доступ к памяти + T* Data(); + const T* Data() const; + + // Возвращает true, если контейнер пуст + bool Empty() const; + + // Возвращает размер контейнера + std::size_t Size() const; + + // Заполняет контейнер определенным элементом + void Fill(const T& value); + + // Обменивается содержимым с другим аналогичным контейнером + void Swap(Array& other); + + // Поддержка range-based for + T* begin(); + const T* begin() const; + + T* end(); + const T* end() const; + + // Возвращающие указатель на соответствующий константный элемент + const T* cbegin() const; + const T* cend() const; + +private: + // Массив на стеке + T data_[N == 0 ? 1 : N]{}; +}; + +template +Array::Array() = default; + +template +Array::Array(std::initializer_list init) { + std::size_t i = 0; + for (const auto& value : init) { + if (i >= N) { + break; + } + data_[i] = value; + ++i; + } +} + +template +Array::Array(const Array& other) = default; + +template +Array::Array(Array&& other) = default; + +template +Array& Array::operator=(const Array& other) = default; + +template +Array& Array::operator=(Array&& other) = default; + +template +Array::~Array() = default; + +template +T& Array::operator[](std::size_t index) { + return data_[index]; +} + +template +const T& Array::operator[](std::size_t index) const { + return data_[index]; +} + +template +T& Array::Front() { + return data_[0]; +} + +template +const T& Array::Front() const { + return data_[0]; +} + +template +T& Array::Back() { + return data_[N - 1]; +} + +template +const T& Array::Back() const { + return data_[N - 1]; +} + +template +T* Array::Data() { + return data_; +} + +template +const T* Array::Data() const { + return data_; +} + +template +bool Array::Empty() const { + return N == 0; +} + +template +std::size_t Array::Size() const { + return N; +} + +template +void Array::Fill(const T& value) { + for (std::size_t i = 0; i < N; ++i) { + data_[i] = value; + } +} + +template +void Array::Swap(Array& other) { + for (std::size_t i = 0; i < N; ++i) { + std::swap(data_[i], other.data_[i]); + } +} + +template +T* Array::begin() { + return data_; +} + +template +const T* Array::begin() const { + return data_; +} + +template +T* Array::end() { + return data_ + N; +} + +template +const T* Array::end() const { + return data_ + N; +} + +template +const T* Array::cbegin() const { + return data_; +} + +template +const T* Array::cend() const { + return data_ + N; +} + +// Операторы сравнения +template +bool operator==(const Array& lhs, const Array& rhs) { + for (std::size_t i = 0; i < N; ++i) { + if (!(lhs[i] == rhs[i])) { + return false; + } + } + return true; +} + +template +bool operator!=(const Array& lhs, const Array& rhs) { + return !(lhs == rhs); +} + +// Лексикографическое сравнение +template +bool operator<(const Array& lhs, const Array& rhs) { + for (std::size_t i = 0; i < N; ++i) { + if (lhs[i] < rhs[i]) { + return true; + } + if (rhs[i] < lhs[i]) { + return false; + } + } + return false; +} + +template +bool operator>(const Array& lhs, const Array& rhs) { + return rhs < lhs; +} + +template +bool operator<=(const Array& lhs, const Array& rhs) { + return !(rhs < lhs); +} + +template +bool operator>=(const Array& lhs, const Array& rhs) { + return !(lhs < rhs); +} + +// Функция swap +template +void swap(Array& lhs, Array& rhs) { + lhs.Swap(rhs); +} + +// Функция get +template +T& get(Array& array) { + static_assert(I < N); + return array[I]; +} + +template +const T& get(const Array& array) { + static_assert(I < N); + return array[I]; +} + +template +T&& get(Array&& array) { + static_assert(I < N); + return std::move(array[I]); +} -}; \ No newline at end of file +template +const T&& get(const Array&& array) { + static_assert(I < N); + return std::move(array[I]); +} \ No newline at end of file diff --git a/07_week/tasks/make_unique/make_unique.cpp b/07_week/tasks/make_unique/make_unique.cpp index e0fdcbd7..818ab0c7 100644 --- a/07_week/tasks/make_unique/make_unique.cpp +++ b/07_week/tasks/make_unique/make_unique.cpp @@ -1,4 +1,10 @@ #include +#include - -/* return_type */ MakeUnique( /* args */ ); +// Создаёт объект типа T в динамической памяти +// и возвращает std::unique_ptr на него. +// Аргументы конструктора передаются через perfect forwarding. +template +std::unique_ptr MakeUnique(Args&&... args) { + return std::unique_ptr(new T(std::forward(args)...)); +} \ No newline at end of file