diff --git a/CMakeLists.txt b/CMakeLists.txt index edf2551..3ce7538 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,4 +15,5 @@ endfunction() define_lab(lab2) define_lab(lab3) -define_lab(lab4) \ No newline at end of file +define_lab(lab4) +define_lab(lab7) \ No newline at end of file diff --git a/README.md b/README.md index c28b897..8f259d6 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ - [Лабораторная работа 2](lab2/README.md) - [Лабораторная работа 3](lab3/README.md) - [Лабораторная работа 4](lab4/README.md) +- [Лабораторная работа 7](lab7/README.md) ## Запуск diff --git a/lab7/.execme b/lab7/.execme new file mode 100755 index 0000000..570d068 --- /dev/null +++ b/lab7/.execme @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +set -euo pipefail +IFS=$'\n\t' + +LAB_FILE="$1/lab7_switch_case.c_run" + +function test_string() { + local str=$1 + echo "Testing on string \`" $str "\`..." + echo -e $str | $LAB_FILE +} + +test_string "Hello :)" +test_string "24 character long string" +test_string "Hello World! Not 8-even-sized string" +test_string "The test string, even with NUMBERS!\n1234 and 5678." diff --git a/lab7/CMakeLists.txt b/lab7/CMakeLists.txt new file mode 100644 index 0000000..f1076db --- /dev/null +++ b/lab7/CMakeLists.txt @@ -0,0 +1,34 @@ +cmake_minimum_required(VERSION 3.16) +set(CMAKE_C_STANDARD 11) + +# Lab name +set(LAB_NAME "lab7") + +# Lab tasks +list(APPEND SOURCE_FILES + switch_case.c + ) +list(APPEND NON_COMPILABLE_SRC + .execme + ) + +### Here goes the template + +project("${LAB_NAME}" C) + +add_custom_target("${LAB_NAME}") + +foreach (file IN LISTS SOURCE_FILES) + add_executable("${LAB_NAME}_${file}_run" "${file}") + add_dependencies("${LAB_NAME}" "${LAB_NAME}_${file}_run") +endforeach () + +foreach (file IN LISTS NON_COMPILABLE_SRC) + add_custom_command( + TARGET "${LAB_NAME}" POST_BUILD + DEPENDS "${file}" + COMMAND ${CMAKE_COMMAND} -E copy + "${CMAKE_CURRENT_SOURCE_DIR}/${file}" + "${CMAKE_CURRENT_BINARY_DIR}/${file}" + ) +endforeach () \ No newline at end of file diff --git a/lab7/README.md b/lab7/README.md new file mode 100644 index 0000000..62cf56a --- /dev/null +++ b/lab7/README.md @@ -0,0 +1,17 @@ +# Лабораторная работа №7 + +Была поставлена задача разработать функцию, которая принимает строку и меняет +регистр через модификацию 6-ого бита. Для ускорения предлагается читать строку +из 32/64 бит, а не символ за один раз, если длина строки кратна 4/8 байт. + +В результате работы была разработана программа, использующая искомую функцию. В +целях оптимизации по памяти она считывает не строку целиком, а работает со вводом +по частям по 8 байт каждая. + +Поскольку при вводе из tty могут возникнуть проблемы с EOF (если длина ввода кратна +восьми, то нужно дважды подавать сигнал Ctrl-D), программа считывает символы по одному, +если обнаруживает, что `stdin` принадлежит tty. Также в tty программа останавливает чтение +строки на символе `\n` для удобства. + +Применение битовой маски для всего блока в памяти затрудняется тем, что ввод может состоять +не только из букв. \ No newline at end of file diff --git a/lab7/switch_case.c b/lab7/switch_case.c new file mode 100644 index 0000000..d771097 --- /dev/null +++ b/lab7/switch_case.c @@ -0,0 +1,71 @@ +#include +#include +#include +#include +#include + +#define IS_ALPHA(x) (((x) >= 'A' && (x) <= 'Z') || ((x) >= 'a' && (x) <= 'z')) + +typedef union { + uint64_t i64; + char chr[8]; +} str_block; + +#define CHUNK_SIZE (sizeof(str_block)) + +int chunk_switch_case(str_block *chunk) { + size_t i = 0; + for (; i < CHUNK_SIZE; ++i) { + if (!chunk->chr[i]) { + break; + } + if (IS_ALPHA(chunk->chr[i])) { + chunk->chr[i] ^= 0x20; + } + } + return i; +} + +char *str_switch_case(const char *str) { + size_t str_size = strlen(str); + size_t chunked_read_border = str_size - (str_size%CHUNK_SIZE); + char *result = malloc(str_size); + str_block chunk = {0}; + + for (size_t i = 0; i < chunked_read_border; i += CHUNK_SIZE) { + memcpy(chunk.chr,str + i, CHUNK_SIZE); + chunk_switch_case(&chunk); + memcpy(result + i, chunk.chr, CHUNK_SIZE); + } + for (size_t i = chunked_read_border; i < str_size; ++i) { + result[i] = str[i]; + if (IS_ALPHA(result[i])) { + result[i] ^= 0x20; + } + } + return result; +} + +int main(){ + str_block chunk = {0}; + char stop_reading = 0; + + do { + if (isatty(STDIN_FILENO)) { + for (size_t i = 0; i < CHUNK_SIZE; ++i) { + fread(&chunk.chr[i], 1, 1, stdin); + if (chunk.chr[i] == '\n') { + chunk.chr[i] = 0; + break; + } + } + } else { + fread(&chunk.i64, 1, CHUNK_SIZE, stdin); + } + stop_reading = (chunk_switch_case(&chunk) != CHUNK_SIZE); + fwrite(&chunk.chr, 1, CHUNK_SIZE, stdout); + chunk.i64 = 0; + } while (!stop_reading); + + return 0; +} \ No newline at end of file