Add files via upload
This commit is contained in:
21
Makefile
Normal file
21
Makefile
Normal file
@@ -0,0 +1,21 @@
|
||||
app: main.o dynamic_array.o types.o
|
||||
gcc -g main.o dynamic_array.o types.o -o app
|
||||
|
||||
test: tests.o dynamic_array.o types.o
|
||||
gcc -g tests.o dynamic_array.o types.o -o test
|
||||
|
||||
main.o: main.c
|
||||
gcc main.c -c
|
||||
|
||||
tests.o : tests.c
|
||||
gcc tests.c -c
|
||||
|
||||
dynamic_array.o: dynamic_array.c dynamic_array.h
|
||||
gcc dynamic_array.c -c
|
||||
|
||||
types.o: types.h types.c type_info.h
|
||||
gcc types.c -c
|
||||
|
||||
clean:
|
||||
rm -f *.o
|
||||
|
||||
236
dynamic_array.c
Normal file
236
dynamic_array.c
Normal file
@@ -0,0 +1,236 @@
|
||||
#include "dynamic_array.h"
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define DA_DEFAULT_CAPACITY 4
|
||||
#define DA_GROWTH_FACTOR 2
|
||||
|
||||
#define ELEM_PTR(arr, i) \
|
||||
((arr)->data + (i) * (arr)->type->element_size)
|
||||
|
||||
static bool da_ensure_capacity(DynamicArray *arr, const size_t needed) {
|
||||
if (needed <= arr->capacity) return true;
|
||||
size_t new_cap = arr->capacity;
|
||||
while (new_cap < needed)
|
||||
new_cap *= DA_GROWTH_FACTOR;
|
||||
|
||||
char *new_data = realloc(arr->data, new_cap * arr->type->element_size);
|
||||
if (!new_data) {
|
||||
fprintf(stderr, "da_ensure_capacity: realloc failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
arr->data = new_data;
|
||||
arr->capacity = new_cap;
|
||||
return true;
|
||||
}
|
||||
|
||||
DynamicArray *da_create(const TypeInfo *type, size_t initial_capacity) {
|
||||
if (!type) {
|
||||
fprintf(stderr, "da_create: type is NULL\n");
|
||||
return NULL;
|
||||
}
|
||||
if (initial_capacity <= 0)
|
||||
initial_capacity = DA_DEFAULT_CAPACITY;
|
||||
|
||||
DynamicArray *arr = (DynamicArray *) malloc(sizeof(DynamicArray));
|
||||
if (!arr) {
|
||||
fprintf(stderr, "da_create: malloc failed\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
arr->data = (char *) malloc(initial_capacity * type->element_size);
|
||||
if (!arr->data) {
|
||||
fprintf(stderr, "da_create: malloc for data failed\n");
|
||||
free(arr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
arr->size = 0;
|
||||
arr->capacity = initial_capacity;
|
||||
arr->type = type;
|
||||
return arr;
|
||||
}
|
||||
|
||||
void da_destroy(DynamicArray *arr) {
|
||||
if (!arr) return;
|
||||
if (arr->type->destroy) {
|
||||
for (size_t i = 0; i < arr->size; i++)
|
||||
arr->type->destroy(ELEM_PTR(arr, i));
|
||||
}
|
||||
free(arr->data);
|
||||
free(arr);
|
||||
}
|
||||
|
||||
void *da_get(const DynamicArray *arr, const size_t index) {
|
||||
if (!arr || index >= arr->size) {
|
||||
fprintf(stderr, "da_get: index %zu out of bounds (size=%zu)\n",
|
||||
index, arr ? arr->size : 0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ELEM_PTR(arr, index);
|
||||
}
|
||||
|
||||
bool da_set(DynamicArray *arr, const size_t index, const void *value) {
|
||||
if (!arr || !value || index >= arr->size) {
|
||||
fprintf(stderr, "da_set: incorrect arguments\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
void *dest = ELEM_PTR(arr, index);
|
||||
if (arr->type->destroy)
|
||||
arr->type->destroy(dest);
|
||||
arr->type->copy(dest, value);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t da_size(const DynamicArray *arr) {
|
||||
return arr ? arr->size : 0;
|
||||
}
|
||||
|
||||
bool da_push_back(DynamicArray *arr, const void *value) {
|
||||
if (!arr || !value) return false;
|
||||
if (!da_ensure_capacity(arr, arr->size+1)) return false;
|
||||
|
||||
arr->type->copy(ELEM_PTR(arr, arr->size), value);
|
||||
arr->size++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool da_insert(DynamicArray *arr, const size_t index, const void *value) {
|
||||
if (!arr || !value || index > arr->size) {
|
||||
fprintf(stderr, "da_insert: invalid arguments\n");
|
||||
return false;
|
||||
}
|
||||
if (!da_ensure_capacity(arr, arr->size + 1)) return false;
|
||||
|
||||
const size_t es = arr->type->element_size;
|
||||
memmove(ELEM_PTR(arr, index + 1), ELEM_PTR(arr, index), (arr->size - index) * es); //
|
||||
arr->type->copy(ELEM_PTR(arr, index), value);
|
||||
arr->size++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool da_remove(DynamicArray *arr, const size_t index) {
|
||||
if (!arr || index >= arr->size) {
|
||||
fprintf(stderr, "da_remove: index %zu out of bounds\n", index);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (arr->type->destroy)
|
||||
arr->type->destroy(ELEM_PTR(arr, index));
|
||||
|
||||
const size_t es = arr->type->element_size;
|
||||
memmove(ELEM_PTR(arr, index), ELEM_PTR(arr, index + 1), (arr->size - index - 1) * es);
|
||||
arr->size--;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Вспомогательные функции сортировки
|
||||
static void swap(void *a, void *b, const TypeInfo *type) {
|
||||
void *temp = malloc(type->element_size);
|
||||
type->copy(temp, a);
|
||||
type->copy(a, b);
|
||||
type->copy(b, temp);
|
||||
|
||||
if (type->destroy) type->destroy(temp);
|
||||
free(temp);
|
||||
}
|
||||
|
||||
void da_sort(DynamicArray *arr) {
|
||||
for (size_t i = 0; i < arr->size; i++) {
|
||||
for (size_t j = i + 1; j < arr->size; j++) {
|
||||
if (arr->type->compare(ELEM_PTR(arr, i), ELEM_PTR(arr, j)) > 0)
|
||||
swap(ELEM_PTR(arr, i), ELEM_PTR(arr, j), arr->type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DynamicArray* da_map(const DynamicArray *arr, MapFunc f) {
|
||||
if (!arr || !f) return NULL;
|
||||
DynamicArray *result = da_create(arr->type, arr->size);
|
||||
if (!result) return NULL;
|
||||
|
||||
void *temp = malloc(arr->type->element_size); // Буффер для хранения результатов map
|
||||
if (!temp) {
|
||||
da_destroy(result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < arr->size; i++) {
|
||||
memset(temp, 0, arr->type->element_size);
|
||||
f(temp, ELEM_PTR(arr, i));
|
||||
da_push_back(result, temp);
|
||||
|
||||
if (arr->type->destroy)
|
||||
arr->type->destroy(temp);
|
||||
}
|
||||
free(temp);
|
||||
return result;
|
||||
}
|
||||
|
||||
DynamicArray* da_where(const DynamicArray *arr, Predicate pred) {
|
||||
if (!arr || !pred) return NULL;
|
||||
DynamicArray *result = da_create(arr->type, arr->size);
|
||||
if (!result) return NULL;
|
||||
|
||||
for (size_t i = 0; i < arr->size; i++) {
|
||||
void *elem = ELEM_PTR(arr, i);
|
||||
if (pred(elem))
|
||||
da_push_back(result, elem);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void da_reduce(const DynamicArray *arr, ReduceFunc f, void *initial, void *result) {
|
||||
if (!arr || !f || !result) return;
|
||||
|
||||
size_t es = arr->type->element_size;
|
||||
memcpy(result, initial, es);
|
||||
|
||||
for (size_t i = 0; i < arr->size; i++) {
|
||||
f(result, ELEM_PTR(arr, i));
|
||||
}
|
||||
}
|
||||
|
||||
DynamicArray* da_concat(const DynamicArray *a, const DynamicArray *b) {
|
||||
if (!a || !b) return NULL;
|
||||
if (!types_equal(a->type, b->type)) {
|
||||
fprintf(stderr, "da_concat: type missmatch (%s vs %s)\n",
|
||||
a->type->type_name, b->type->type_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DynamicArray *result = da_create(a->type, a->size + b->size);
|
||||
if (!result) return NULL;
|
||||
|
||||
for (size_t i = 0; i < a->size; i++)
|
||||
da_push_back(result, ELEM_PTR(a, i));
|
||||
for (size_t i = 0; i < b->size; i++)
|
||||
da_push_back(result, ELEM_PTR(b, i));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void da_print(const DynamicArray *arr) {
|
||||
if (!arr) {
|
||||
printf("(null)\n");
|
||||
return;
|
||||
}
|
||||
|
||||
printf("[%s] size=%zu, capacity=%zu\n",
|
||||
arr->type->type_name, arr->size, arr->capacity);
|
||||
printf("[ ");
|
||||
for (size_t i = 0; i < arr->size; i++) {
|
||||
if (i > 0) printf(", ");
|
||||
arr->type->print(ELEM_PTR(arr, i));
|
||||
}
|
||||
printf(" ]\n");
|
||||
}
|
||||
51
dynamic_array.h
Normal file
51
dynamic_array.h
Normal file
@@ -0,0 +1,51 @@
|
||||
#ifndef ARRAY_H
|
||||
#define ARRAY_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include "type_info.h"
|
||||
|
||||
typedef struct DynamicArray {
|
||||
char *data;
|
||||
const TypeInfo *type;
|
||||
size_t capacity; // ёмкость
|
||||
size_t size; // текущий размер
|
||||
} DynamicArray;
|
||||
|
||||
// Создание/уничтожение
|
||||
DynamicArray* da_create(const TypeInfo *type, size_t initial_capacity);
|
||||
void da_destroy(DynamicArray *arr);
|
||||
|
||||
// Доступ к элементам
|
||||
void* da_get(const DynamicArray *arr, const size_t index);
|
||||
bool da_set(DynamicArray *arr, const size_t index, const void *value);
|
||||
size_t da_size(const DynamicArray *arr);
|
||||
|
||||
// Модификация
|
||||
bool da_push_back(DynamicArray *arr, const void *value);
|
||||
bool da_insert(DynamicArray *arr, const size_t index, const void *value);
|
||||
bool da_remove(DynamicArray *arr, const size_t index);
|
||||
|
||||
// Операции
|
||||
// Сортировка (используется compare из TypeInfo)
|
||||
void da_sort(DynamicArray *arr);
|
||||
|
||||
// map: применить f к каждому элементу и вернуть новый массив
|
||||
typedef void (*MapFunc)(void *dest, const void *src);
|
||||
DynamicArray* da_map(const DynamicArray *arr, MapFunc f);
|
||||
|
||||
// where: фильтрация по предикату
|
||||
typedef bool (*Predicate)(const void *elem);
|
||||
DynamicArray* da_where(const DynamicArray *arr, Predicate pred);
|
||||
|
||||
// reduce: свёртка массива в один элемент
|
||||
typedef void (*ReduceFunc)(void *accumulator, const void *elem);
|
||||
void da_reduce(const DynamicArray *arr, ReduceFunc f, void *initial, void *result);
|
||||
|
||||
// Конкатенация: возвращает новый массив
|
||||
DynamicArray* da_concat(const DynamicArray *a, const DynamicArray *b);
|
||||
|
||||
// Вспомогательные функции
|
||||
void da_print(const DynamicArray *arr);
|
||||
|
||||
#endif // ARRAY_H
|
||||
427
main.c
Normal file
427
main.c
Normal file
@@ -0,0 +1,427 @@
|
||||
#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;
|
||||
}
|
||||
438
tests.c
Normal file
438
tests.c
Normal file
@@ -0,0 +1,438 @@
|
||||
#include "dynamic_array.h"
|
||||
#include "types.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
// Подсчёт тестов
|
||||
|
||||
static int tests_passed = 0;
|
||||
static int tests_failed = 0;
|
||||
|
||||
#define TEST(name) static bool name(void)
|
||||
#define RUN(name) do { \
|
||||
printf(" %-50s", #name); \
|
||||
if (name()) { \
|
||||
tests_passed++; \
|
||||
printf(" [OK]\n"); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ASSERT(cond) do { \
|
||||
if (!(cond)) { \
|
||||
printf(" [FAIL] %s:%d: %s\n", __FILE__, __LINE__, #cond); \
|
||||
tests_failed++; \
|
||||
return false; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// --------------- ТЕСТЫ ---------------
|
||||
// Создание и базовые операции
|
||||
|
||||
TEST(test_create_destroy) {
|
||||
DynamicArray *arr = da_create(get_double_type(), 0);
|
||||
ASSERT(arr != NULL);
|
||||
ASSERT(da_size(arr) == 0);
|
||||
da_destroy(arr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
TEST(test_push_back_double) {
|
||||
DynamicArray *arr = da_create(get_double_type(), 0);
|
||||
const double vals[] = {1.1, 2.2, 3.3};
|
||||
|
||||
for (size_t i = 0; i < 3; i++) {
|
||||
da_push_back(arr, &vals[i]);
|
||||
}
|
||||
ASSERT(da_size(arr) == 3);
|
||||
ASSERT(*(double *)da_get(arr, 0) == 1.1);
|
||||
ASSERT(*(double *)da_get(arr, 1) == 2.2);
|
||||
ASSERT(*(double *)da_get(arr, 2) == 3.3);
|
||||
da_destroy(arr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
TEST(test_push_back_complex) {
|
||||
DynamicArray *arr = da_create(get_complex_type(), 0);
|
||||
const Complex vals[] = {
|
||||
{1.1, 1}, {2.2, 2}, {3.3, 3}
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < 3; i++) {
|
||||
da_push_back(arr, &vals[i]);
|
||||
}
|
||||
Complex *c_get;
|
||||
ASSERT(da_size(arr) == 3);
|
||||
|
||||
c_get = (Complex *) da_get(arr, 0);
|
||||
ASSERT(c_get->re == 1.1 && c_get->im == 1);
|
||||
c_get = (Complex *) da_get(arr, 1);
|
||||
ASSERT(c_get->re == 2.2 && c_get->im == 2);
|
||||
c_get = (Complex *) da_get(arr, 2);
|
||||
ASSERT(c_get->re == 3.3 && c_get->im == 3);
|
||||
da_destroy(arr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
TEST(test_set_get) {
|
||||
DynamicArray *arr = da_create(get_double_type(), 0);
|
||||
const double v1 = 42, v2 = 99;
|
||||
da_push_back(arr, &v1);
|
||||
ASSERT(*(double *)da_get(arr, 0) == 42);
|
||||
da_set(arr, 0, &v2);
|
||||
ASSERT(*(double *)da_get(arr, 0) == 99);
|
||||
da_destroy(arr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
TEST(test_insert) {
|
||||
DynamicArray *arr = da_create(get_double_type(), 0);
|
||||
const double a = 1, b = 2, c = 3, ins = 99;
|
||||
da_push_back(arr, &a);
|
||||
da_push_back(arr, &b);
|
||||
da_push_back(arr, &c);
|
||||
da_insert(arr, 1, &ins);
|
||||
ASSERT(da_size(arr) == 4);
|
||||
ASSERT(*(double *)da_get(arr, 0) == 1);
|
||||
ASSERT(*(double *)da_get(arr, 1) == 99);
|
||||
ASSERT(*(double *)da_get(arr, 2) == 2);
|
||||
ASSERT(*(double *)da_get(arr, 3) == 3);
|
||||
da_destroy(arr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
TEST(test_remove) {
|
||||
DynamicArray *arr = da_create(get_double_type(), 0);
|
||||
const double vals[] = {10, 20, 30};
|
||||
for (int i = 0; i < 3; i++) da_push_back(arr, &vals[i]);
|
||||
da_remove(arr, 1);
|
||||
ASSERT(da_size(arr) == 2);
|
||||
ASSERT(*(double *)da_get(arr, 0) == 10);
|
||||
ASSERT(*(double *)da_get(arr, 1) == 30);
|
||||
da_destroy(arr);
|
||||
|
||||
return true;
|
||||
}
|
||||
// Граничные случаи
|
||||
|
||||
TEST(test_get_out_of_bounds) {
|
||||
DynamicArray *arr = da_create(get_double_type(), 0);
|
||||
ASSERT(da_get(arr, 0) == NULL);
|
||||
const double v = 1;
|
||||
da_push_back(arr, &v);
|
||||
ASSERT(da_get(arr, 1) == NULL);
|
||||
ASSERT(da_get(arr, 100) == NULL);
|
||||
da_destroy(arr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
TEST(test_remove_out_of_bounds) {
|
||||
DynamicArray *arr = da_create(get_double_type(), 0);
|
||||
ASSERT(da_remove(arr, 0) == false);
|
||||
da_destroy(arr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
TEST(test_empty_array_operations) {
|
||||
DynamicArray *arr = da_create(get_double_type(), 0);
|
||||
da_sort(arr); // Не должен ломаться
|
||||
ASSERT(da_size(arr) == 0);
|
||||
da_destroy(arr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
TEST(test_create_null_type) {
|
||||
DynamicArray *arr = da_create(NULL, 0);
|
||||
ASSERT(arr == NULL);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
TEST(test_capacity_growth) {
|
||||
DynamicArray *arr = da_create(get_int_type(), 2);
|
||||
for (int i = 0; i < 100; i++)
|
||||
ASSERT(da_push_back(arr, &i));
|
||||
ASSERT(da_size(arr) >= 100);
|
||||
for (int i = 0; i < 100; i++)
|
||||
ASSERT(*(int *)da_get(arr, i) == i);
|
||||
da_destroy(arr);
|
||||
|
||||
return true;
|
||||
}
|
||||
// Сортировка
|
||||
|
||||
TEST(test_sort_double) {
|
||||
DynamicArray *arr = da_create(get_double_type(), 0);
|
||||
const double vals[] = {3.14, 1.0, 2.71, 0.5};
|
||||
for (int i = 0; i < 4; i++) da_push_back(arr, &vals[i]);
|
||||
da_sort(arr);
|
||||
for (size_t i = 1; i < da_size(arr); i++)
|
||||
ASSERT(*(double *)da_get(arr, i - 1) <= *(double *)da_get(arr, i));
|
||||
da_destroy(arr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
TEST(test_sort_complex) {
|
||||
DynamicArray *arr = da_create(get_complex_type(), 0);
|
||||
const Complex vals[] = {
|
||||
{3, 4}, {1, 0}, {0, 2}
|
||||
}; // |5|, |1|, |2|
|
||||
for (int i = 0; i < 3; i++) da_push_back(arr, &vals[i]);
|
||||
da_sort(arr);
|
||||
|
||||
// Порядок по модулю: (1,0), (0,2), (3,4)
|
||||
const Complex *c0 = da_get(arr, 0);
|
||||
const Complex *c1 = da_get(arr, 1);
|
||||
const Complex *c2 = da_get(arr, 2);
|
||||
ASSERT(c0->re == 1.0 && c0->im == 0.0);
|
||||
ASSERT(c1->re == 0.0 && c1->im == 2.0);
|
||||
ASSERT(c2->re == 3.0 && c2->im == 4.0);
|
||||
da_destroy(arr);
|
||||
|
||||
return true;
|
||||
}
|
||||
// map
|
||||
|
||||
static void double_value(void *dest, const void *src) {
|
||||
*(double *)dest = *(const double *)src * 2;
|
||||
}
|
||||
|
||||
TEST(test_map_double) {
|
||||
DynamicArray *arr = da_create(get_double_type(), 0);
|
||||
const double vals[] = {1.0, 2.0, 3.0};
|
||||
for (int i = 0; i < 3; i++) da_push_back(arr, &vals[i]);
|
||||
DynamicArray *mapped = da_map(arr, double_value);
|
||||
ASSERT(mapped != NULL);
|
||||
ASSERT(da_size(mapped) == 3);
|
||||
ASSERT(*(double *)da_get(mapped, 0) == 2.0);
|
||||
ASSERT(*(double *)da_get(mapped, 1) == 4.0);
|
||||
ASSERT(*(double *)da_get(mapped, 2) == 6.0);
|
||||
da_destroy(arr);
|
||||
da_destroy(mapped);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
TEST(test_map_empty) {
|
||||
DynamicArray *arr = da_create(get_double_type(), 0);
|
||||
DynamicArray *mapped = da_map(arr, double_value);
|
||||
ASSERT(mapped != NULL);
|
||||
ASSERT(da_size(mapped) == 0);
|
||||
da_destroy(arr);
|
||||
da_destroy(mapped);
|
||||
|
||||
return true;
|
||||
}
|
||||
// where
|
||||
|
||||
static bool is_positive(const void *elem) {
|
||||
return *(const double *)elem > 0;
|
||||
}
|
||||
|
||||
static bool is_real(const void *elem) {
|
||||
const Complex *c_elem = (Complex *)elem;
|
||||
return c_elem->im == 0;
|
||||
}
|
||||
|
||||
TEST(test_where_double) {
|
||||
DynamicArray *arr = da_create(get_double_type(), 0);
|
||||
const double vals[] = {-1.0, 2.5, -3.0, 4.0};
|
||||
for (int i = 0; i < 4; i++)
|
||||
da_push_back(arr, &vals[i]);
|
||||
DynamicArray *filtered = da_where(arr, is_positive);
|
||||
ASSERT(da_size(filtered) == 2);
|
||||
ASSERT(*(double *)da_get(filtered, 0) == 2.5);
|
||||
ASSERT(*(double *)da_get(filtered, 1) == 4.0);
|
||||
da_destroy(arr);
|
||||
da_destroy(filtered);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
TEST(test_where_complex) {
|
||||
DynamicArray *arr = da_create(get_complex_type(), 0);
|
||||
const Complex vals[] = {
|
||||
{1.0, 2.0}, {4.0, 0.0}, {-1.0, 1.0}
|
||||
};
|
||||
for (int i = 0; i < 3; i++)
|
||||
da_push_back(arr, &vals[i]);
|
||||
DynamicArray *filtered = da_where(arr, is_real);
|
||||
ASSERT(da_size(filtered) == 1);
|
||||
const Complex *num = da_get(filtered, 0);
|
||||
ASSERT(num->re == 4.0 && num->im == 0.0);
|
||||
da_destroy(arr);
|
||||
da_destroy(filtered);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
TEST(test_where_none_match) {
|
||||
DynamicArray *arr = da_create(get_double_type(), 0);
|
||||
const double vals[] = {-1.0, -3.0, -5.0};
|
||||
for (int i = 0; i < 3; i++) da_push_back(arr, &vals[i]);
|
||||
DynamicArray *filtered = da_where(arr, is_positive);
|
||||
ASSERT(da_size(filtered) == 0);
|
||||
da_destroy(arr);
|
||||
da_destroy(filtered);
|
||||
|
||||
return true;
|
||||
}
|
||||
// reduce
|
||||
|
||||
static void sum_reduce_double(void *acc, const void *elem) {
|
||||
*(double *)acc += *(const double *)elem;
|
||||
}
|
||||
|
||||
static void sum_reduce_complex(void *acc, const void *elem) {
|
||||
Complex *c_acc = (Complex *)acc;
|
||||
const Complex *c_elem = (const Complex *)elem;
|
||||
|
||||
c_acc->re += c_elem->re;
|
||||
c_acc->im += c_elem->im;
|
||||
}
|
||||
|
||||
TEST(test_reduce_sum_double) {
|
||||
DynamicArray *arr = da_create(get_double_type(), 0);
|
||||
const double vals[] = {1.0, 2.0, 3.0, 4.0, 5.0};
|
||||
for (int i = 0; i < 5; i++) da_push_back(arr, &vals[i]);
|
||||
|
||||
double initial = 0.0, result = 0.0;
|
||||
da_reduce(arr, sum_reduce_double, &initial, &result);
|
||||
ASSERT(result == 15.0);
|
||||
da_destroy(arr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
TEST(test_reduce_sum_complex) {
|
||||
DynamicArray *arr = da_create(get_complex_type(), 0);
|
||||
const Complex vals[] = {
|
||||
{1.0, 0.0}, {2.0, 1.0}, {3.0, 2.0}
|
||||
};
|
||||
for (int i = 0; i < 3; i++) da_push_back(arr, &vals[i]);
|
||||
|
||||
Complex initial = {0.0, 0.0}, result = {0.0, 0.0};
|
||||
da_reduce(arr, sum_reduce_complex, &initial, &result);
|
||||
|
||||
ASSERT(result.re == 6.0 && result.im == 3.0);
|
||||
da_destroy(arr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
TEST(test_reduce_empty) {
|
||||
DynamicArray *arr = da_create(get_double_type(), 0);
|
||||
double initial = 42.0, result = 0.0;
|
||||
da_reduce(arr, sum_reduce_double, &initial, &result);
|
||||
ASSERT(result == 42);
|
||||
da_destroy(arr);
|
||||
|
||||
return true;
|
||||
}
|
||||
// Конкатенация
|
||||
|
||||
TEST(test_concat_double) {
|
||||
DynamicArray *a = da_create(get_double_type(), 0);
|
||||
DynamicArray *b = da_create(get_double_type(), 0);
|
||||
const double v1 = 1.0, v2 = 2.0, v3 = 3.0, v4 = 4.0;
|
||||
da_push_back(a, &v1);
|
||||
da_push_back(a, &v2);
|
||||
da_push_back(b, &v3);
|
||||
da_push_back(b, &v4);
|
||||
|
||||
DynamicArray *c = da_concat(a, b);
|
||||
|
||||
ASSERT(c != NULL);
|
||||
ASSERT(da_size(c) == 4);
|
||||
ASSERT(*(double *)da_get(c, 0) == 1.0);
|
||||
ASSERT(*(double *)da_get(c, 1) == 2.0);
|
||||
ASSERT(*(double *)da_get(c, 2) == 3.0);
|
||||
ASSERT(*(double *)da_get(c, 3) == 4.0);
|
||||
|
||||
da_destroy(a);
|
||||
da_destroy(b);
|
||||
da_destroy(c);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
TEST(test_concat_type_mismatch) {
|
||||
DynamicArray *a = da_create(get_double_type(), 0);
|
||||
DynamicArray *b = da_create(get_complex_type(), 0);
|
||||
DynamicArray *c = da_concat(a, b);
|
||||
ASSERT(c == NULL); // Несовпадение типов
|
||||
da_destroy(a);
|
||||
da_destroy(b);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
TEST(test_concat_with_empty) {
|
||||
DynamicArray *a = da_create(get_double_type(), 0);
|
||||
DynamicArray *b = da_create(get_double_type(), 0);
|
||||
const double v = 42.0;
|
||||
da_push_back(a, &v);
|
||||
DynamicArray *c = da_concat(a, b);
|
||||
ASSERT(da_size(c) == 1);
|
||||
ASSERT(*(double *)da_get(c, 0) == 42.0);
|
||||
da_destroy(a);
|
||||
da_destroy(b);
|
||||
da_destroy(c);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main() {
|
||||
printf(" === Модульные тесты ===\n");
|
||||
|
||||
printf("--- Создание и базовые операции ---\n");
|
||||
RUN(test_create_destroy);
|
||||
RUN(test_push_back_double);
|
||||
RUN(test_push_back_complex);
|
||||
RUN(test_set_get);
|
||||
RUN(test_insert);
|
||||
RUN(test_remove);
|
||||
|
||||
printf("--- Граничные случаи ---\n");
|
||||
RUN(test_get_out_of_bounds);
|
||||
RUN(test_remove_out_of_bounds);
|
||||
RUN(test_empty_array_operations);
|
||||
RUN(test_create_null_type);
|
||||
RUN(test_capacity_growth);
|
||||
|
||||
printf("--- Сортировка ---\n");
|
||||
RUN(test_sort_double);
|
||||
RUN(test_sort_complex);
|
||||
|
||||
printf("--- map ---\n");
|
||||
RUN(test_map_double);
|
||||
RUN(test_map_empty);
|
||||
|
||||
printf("--- where ---\n");
|
||||
RUN(test_where_double);
|
||||
RUN(test_where_complex);
|
||||
RUN(test_where_none_match);
|
||||
|
||||
printf("--- reduce ---\n");
|
||||
RUN(test_reduce_sum_double);
|
||||
RUN(test_reduce_sum_complex);
|
||||
RUN(test_reduce_empty);
|
||||
|
||||
printf("--- Конкатенация ---\n");
|
||||
RUN(test_concat_double);
|
||||
RUN(test_concat_type_mismatch);
|
||||
RUN(test_concat_with_empty);
|
||||
|
||||
printf("\n======================\n");
|
||||
printf("Итого: %d пройдено, %d провалено\n", tests_passed, tests_failed);
|
||||
|
||||
return tests_failed > 0 ? 1 : 0;
|
||||
}
|
||||
22
type_info.h
Normal file
22
type_info.h
Normal file
@@ -0,0 +1,22 @@
|
||||
#ifndef TYPE_INFO_H
|
||||
#define TYPE_INFO_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
typedef struct TypeInfo {
|
||||
size_t element_size;
|
||||
void (*copy)(void *dest, const void *src);
|
||||
void (*destroy)(void *elem);
|
||||
int (*compare)(const void *a, const void *b); // <0, 0, >0
|
||||
void (*print)(const void *elem);
|
||||
bool (*parse)(void *dest, const char *str); // для ввода
|
||||
const char *type_name;
|
||||
} TypeInfo;
|
||||
|
||||
// static inline используется для создания копии функции в каждом файле
|
||||
static inline bool types_equal(const TypeInfo *a, const TypeInfo *b) {
|
||||
return a == b;
|
||||
}
|
||||
|
||||
#endif // TYPE_INFO_H
|
||||
137
types.c
Normal file
137
types.c
Normal file
@@ -0,0 +1,137 @@
|
||||
#include "types.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
// ----------------- INT -----------------
|
||||
static void int_copy(void *dest, const void *src) {
|
||||
*(int *) dest = *(const int *) src;
|
||||
}
|
||||
|
||||
static int int_compare(const void *a, const void *b) {
|
||||
const int va = *(const int *) a;
|
||||
const int vb = *(const int *) b;
|
||||
|
||||
return (va > vb) - (va < vb);
|
||||
}
|
||||
|
||||
static void int_print(const void *elem) {
|
||||
printf("%d", *(const int *) elem);
|
||||
}
|
||||
|
||||
static bool int_parse(void *dest, const char *str) {
|
||||
char *end;
|
||||
const long val = strtol(str, &end, 10);
|
||||
if (end == str || *end != '\0') return false;
|
||||
|
||||
*(int *) dest = (int) val;
|
||||
return true;
|
||||
}
|
||||
|
||||
static TypeInfo INT_TYPE_INFO = {
|
||||
.element_size = sizeof(int),
|
||||
.copy = int_copy,
|
||||
.destroy = NULL,
|
||||
.compare = int_compare,
|
||||
.print = int_print,
|
||||
.parse = int_parse,
|
||||
.type_name = "int"
|
||||
};
|
||||
|
||||
const TypeInfo *get_int_type(void) {
|
||||
return &INT_TYPE_INFO;
|
||||
}
|
||||
|
||||
// ----------------- DOUBLE -----------------
|
||||
static void double_copy(void *dest, const void *src) {
|
||||
*(double *) dest = *(const double *) src;
|
||||
}
|
||||
|
||||
static int double_compare(const void *a, const void *b) {
|
||||
const double va = *(const double *) a;
|
||||
const double vb = *(const double *) b;
|
||||
const double error = 1e-12;
|
||||
|
||||
if (fabs(va - vb) < error) return 0;
|
||||
return (va > vb) ? 1 : -1;
|
||||
}
|
||||
|
||||
static void double_print(const void *elem) {
|
||||
printf("%.4f", *(const double *) elem);
|
||||
}
|
||||
|
||||
static bool double_parse(void *dest, const char *str) {
|
||||
char *end;
|
||||
const double val = strtod(str, &end);
|
||||
if (end == str || *end != '\0') return false;
|
||||
|
||||
*(double *) dest = val;
|
||||
return true;
|
||||
}
|
||||
|
||||
static TypeInfo DOUBLE_TYPE_INFO = {
|
||||
.element_size = sizeof(double),
|
||||
.copy = double_copy,
|
||||
.destroy = NULL,
|
||||
.compare = double_compare,
|
||||
.print = double_print,
|
||||
.parse = double_parse,
|
||||
.type_name = "double"
|
||||
};
|
||||
|
||||
const TypeInfo *get_double_type(void) {
|
||||
return &DOUBLE_TYPE_INFO;
|
||||
}
|
||||
|
||||
// ----------------- COMPLEX -----------------
|
||||
static void complex_copy(void *dest, const void *src) {
|
||||
*(Complex *) dest = *(const Complex *) src;
|
||||
}
|
||||
|
||||
static int complex_compare(const void *a, const void *b) {
|
||||
const Complex *ca = (const Complex *) a;
|
||||
const Complex *cb = (const Complex *) b;
|
||||
const double error = 1e-12;
|
||||
|
||||
const double ma = ca->re * ca->re + ca->im * ca->im;
|
||||
const double mb = cb->re * cb->re + cb->im * cb->im;
|
||||
|
||||
if (fabs(ma - mb) < error) return 0;
|
||||
return (ma > mb) ? 1 : -1;
|
||||
}
|
||||
|
||||
static void complex_print(const void *elem) {
|
||||
const Complex *c = (Complex*)elem;
|
||||
if (c->im > 0)
|
||||
printf("%.4f+%.4fi", c->re, c->im);
|
||||
else if (c->im == 0)
|
||||
printf("%.4f", c->re);
|
||||
else
|
||||
printf("%.4f%.4fi", c->re, c->im);
|
||||
}
|
||||
|
||||
static bool complex_parse(void *dest, const char *str) {
|
||||
Complex *c = (Complex *)dest;
|
||||
// Формат: "re im"
|
||||
if (sscanf(str, "%lf %lf", &c->re, &c->im) == 2)
|
||||
return true;
|
||||
// Попробуем только re
|
||||
c->im = 0;
|
||||
if (sscanf(str, "%lf", &c->re) == 1)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static TypeInfo COMPLEX_TYPE_INFO = {
|
||||
.element_size = sizeof(Complex),
|
||||
.copy = complex_copy,
|
||||
.destroy = NULL,
|
||||
.compare = complex_compare,
|
||||
.print = complex_print,
|
||||
.parse = complex_parse,
|
||||
.type_name = "complex"
|
||||
};
|
||||
|
||||
const TypeInfo *get_complex_type(void) {
|
||||
return &COMPLEX_TYPE_INFO;
|
||||
}
|
||||
Reference in New Issue
Block a user