#include #include #include #include #include "dynamic_array.h" #include "types.h" #include "type_info.h" static void clear_stdin(void) { int c; while ((c = getchar()) != '\n' && c != EOF); } static int read_int(const char *prompt) { int val; printf("%s", prompt); while (scanf("%d", &val) != 1) { printf("Ошибка ввода. Повторите: "); clear_stdin(); } clear_stdin(); return val; } static void read_line(const char *prompt, char *buf, size_t size) { printf("%s", prompt); if (!fgets(buf, size, stdin)) buf[0] = '\0'; // Убираем перевод строки size_t len = strlen(buf); if (len > 0 && buf[len - 1] == '\n') buf[len - 1] = '\0'; } static const TypeInfo *choose_type(void) { printf("\nВыберите тип элементов:\n"); printf(" 1. Вещественные числа (double)\n"); printf(" 2. Комплексные числа\n"); int choice = read_int("Ваш выбор: "); switch (choice) { case 1: return get_double_type(); case 2: return get_complex_type(); default: printf("Неизвестный тип данных. Используется double.\n"); return get_double_type(); } } static bool input_element(const TypeInfo *type, void *dest) { char buf[512]; if (type == get_double_type()) { read_line("Введите вещественное число: ", buf, sizeof(buf)); } else if (type == get_complex_type()) { read_line("Введите комплексное число: ", buf, sizeof(buf)); } else { printf("Неизвестный тип\n"); return false; } return type->parse(dest, buf); } // --------------- MAP-функции (для демонстрации) --------------- static void double_double(void *dest, const void *src) { *(double *) dest = *(const double *) src * 2; } static void double_square(void *dest, const void *src) { const double v = *(const double *) src; *(double *) dest = v * v; } static void double_negate(void *dest, const void *src) { *(double *) dest = -(*(const double *) src); } static void complex_double(void *dest, const void *src) { Complex *c_dest = (Complex *) dest; const Complex *c_src = (const Complex *) src; c_dest->re = c_src->re * 2; c_dest->im = c_src->im * 2; } static void complex_square(void *dest, const void *src) { Complex *c_dest = (Complex *) dest; const Complex *c_src = (const Complex *) src; c_dest->re = (c_src->re * c_src->re) - (c_src->im * c_src->im); c_dest->im = 2.0 * (c_src->re * c_src->im); } static void complex_negate(void *dest, const void *src) { Complex *c_dest = (Complex *) dest; const Complex *c_src = (const Complex *) src; c_dest->re = -c_src->re; c_dest->im = -c_src->im; } static MapFunc choose_map_func(const TypeInfo *type) { printf("Выберите функцию для map:\n"); printf(" 1. Удвоить (x * 2)\n"); printf(" 2. Квадрат (x ^ 2)\n"); printf(" 3. Отрицание (-x)\n"); int choice = read_int("Ваш выбор: "); if (type == get_double_type()) { switch (choice) { case 1: return double_double; case 2: return double_square; case 3: return double_negate; default: printf("Неизвестный тип. Используется 1.\n"); return double_double; } } else if (type == get_complex_type()) { switch (choice) { case 1: return complex_double; case 2: return complex_square; case 3: return complex_negate; default: printf("Неизвестный тип. Используется 1.\n"); return complex_double; } } printf("Map не реализован для типа: %s\n", type->type_name); return NULL; } // --------------- WHERE-предикаты (для демонстрации) --------------- static bool double_is_positive(const void *e) { return *(const double *) e > 0; } static bool complex_is_real(const void *e) { const Complex *ce = (Complex *) e; return ce->im == 0; } static Predicate choose_predicate(const TypeInfo *type) { if (type == get_double_type()) { printf("Фильтр: положительные числа (x > 0)\n"); return double_is_positive; } else if (type == get_complex_type()) { printf("Фильтр: действительные числа.\n"); return complex_is_real; } printf("Where не реализован для типа: %s\n", type->type_name); return NULL; } // --------------- REDUCE-функции (для демонстрации) --------------- static void double_sum(void *acc, const void *elem) { *(double *) acc += *(const double *) elem; } static void complex_sum(void *acc, const void *elem) { Complex *c_acc = (Complex *) acc; const Complex *c_elem = (const Complex *) acc; c_acc->re += c_elem->re; c_acc->im += c_elem->im; } static ReduceFunc choose_reduce(const TypeInfo *type) { if (type == get_double_type()) { printf("Функция: сумма вещественных чисел\n"); return double_sum; } else if (type == get_complex_type()) { printf("Функция: сумма комплексных чисел.\n"); return complex_sum; } printf("Reduce не реализован для типа: %s\n", type->type_name); return NULL; } static void auto_fill(DynamicArray *arr) { int count = read_int("Количество элементов: "); if (count <= 0 || count > 10000) { printf("Некорректное количество.\n"); return; } const TypeInfo *type = arr->type; // random -> type if (type == get_double_type()) { for (int i = 0; i < count; i++) { double v = (rand() % 2001 - 1000) / 10.0; // [-100, 100] da_push_back(arr, &v); } } else if (type == get_complex_type()) { for (int i = 0; i < count; i++) { Complex c = { .re = (rand() % 201 - 100) / 10.0, .im = (rand() % 201 - 100) / 10.0 }; da_push_back(arr, &c); } } else { printf("Автозаполнение не поддерживается для типа: %s\n", type->type_name); return; } printf("Добавлено %d элементов.\n", count); } static void print_menu(void) { printf("\n╔═══════════════════════════════════════╗\n"); printf("║ Полиморфный динамический массив ║\n"); printf("╠═══════════════════════════════════════╣\n"); printf("║ 1. Показать массив ║\n"); printf("║ 2. Добавить элемент (в конец) ║\n"); printf("║ 3. Вставить элемент (по индексу) ║\n"); printf("║ 4. Удалить элемент (по индексу) ║\n"); printf("║ 5. Изменить элемент (по индексу) ║\n"); printf("║ 6. Сортировка ║\n"); printf("║ 7. map (преобразование) ║\n"); printf("║ 8. where (фильтрация) ║\n"); printf("║ 9. reduce (свёртка) ║\n"); printf("║ 10. Конкатенация (создать второй) ║\n"); printf("║ 11. Автозаполнение случайными ║\n"); printf("║ 0. Выход ║\n"); printf("╚═══════════════════════════════════════╝\n"); } int main(void) { srand(time(NULL)); // Выбор типа const TypeInfo *type = choose_type(); DynamicArray *arr = da_create(type, 0); if (!arr) { fprintf(stderr, "Не удалось создать массив.\n"); return 1; } printf("Создан массив типа: %s\n", type->type_name); void *elem; int index; int choice = -1; MapFunc map_f; Predicate pred; ReduceFunc reduce_f; // Основной цикл bool running = true; while (running) { print_menu(); choice = read_int(">>> "); switch (choice) { case 0: running = false; break; case 1: // Показать da_print(arr); break; case 2: // Добавить в конец elem = malloc(type->element_size); memset(elem, 0, type->element_size); if (input_element(type, elem)) { if (da_push_back(arr, elem)) printf("Элемент добавлен. Размер: %zu\n", da_size(arr)); else printf("Ошибка добавления элемента\n"); } else { printf("Ошибка разбора значения.\n"); } if (type->destroy) type->destroy(elem); free(elem); break; case 3: // Вставить index = read_int("Индекс: "); elem = malloc(type->element_size); memset(elem, 0, type->element_size); if (input_element(type, elem)) { if (da_insert(arr, index, elem)) printf("Элемент вставлен.\n"); else printf("Ошибка вставки.\n"); } else { printf("Ошибка разбора значения.\n"); } if (type->destroy) type->destroy(elem); free(elem); break; case 4: // Удалить index = read_int("Индекс: "); if (da_remove(arr, index)) printf("Элемент удалён. Размер: %zu\n", da_size(arr)); else printf("Ошибка удаления.\n"); break; case 5: // Изменить index = read_int("Индекс: "); elem = malloc(type->element_size); memset(elem, 0, type->element_size); if (input_element(type, elem)) { if (da_set(arr, index, elem)) printf("Элемент изменён.\n"); else printf("Ошибка изменения.\n"); } else { printf("Ошибка разбора значения.\n"); } if (type->destroy) type->destroy(elem); free(elem); break; case 6: // Сортировка da_sort(arr); printf("Массив отсортирован.\n"); da_print(arr); break; case 7: // map map_f = choose_map_func(type); if (!map_f) break; DynamicArray *mapped = da_map(arr, map_f); if (!mapped) break; printf("Результат map:\n"); da_print(mapped); da_destroy(mapped); break; case 8: // where pred = choose_predicate(type); if (!pred) break; DynamicArray *filtered = da_where(arr, pred); if (!filtered) break; printf("Результат where:\n"); da_print(filtered); da_destroy(filtered); break; case 9: // reduce reduce_f = choose_reduce(type); if (!reduce_f) break; if (type == get_double_type()) { double init = 0.0, result = 0.0; da_reduce(arr, reduce_f, &init, &result); printf("Результат reduce: "); type->print(&result); printf("\n"); } else if (type == get_complex_type()) { Complex init = { .re = 0.0, .im = 0.0 }; Complex result = { .re = 0.0, .im = 0.0 }; da_reduce(arr, reduce_f, &init, &result); printf("Результат reduce: "); type->print(&result); printf("\n"); } break; case 10: // Конкатенация printf("Создание второго массива с типом: %s\n", type->type_name); DynamicArray *b = da_create(type, 0); int n = read_int("Сколько элементов добавить во второй массив? "); for (int i = 0; i < n; i++) { elem = malloc(type->element_size); memset(elem, 0, type->element_size); printf("Элемент %d: ", i + 1); if (input_element(type, elem)) da_push_back(b, elem); if (type->destroy) type->destroy(elem); free(elem); } printf("Второй массив:\n"); da_print(b); DynamicArray *c = da_concat(arr, b); if (c) { printf("Результат конкатенации:\n"); da_print(c); da_destroy(c); } da_destroy(b); break; case 11: // Автозаполнение auto_fill(arr); da_print(arr); break; default: printf("Неизвестная команда.\n"); } } da_destroy(arr); printf("До свидания!\n"); return 0; }