428 lines
14 KiB
C
428 lines
14 KiB
C
#include <stdio.h>
|
||
#include <stddef.h>
|
||
#include <time.h>
|
||
#include <string.h>
|
||
#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;
|
||
}
|