consolidate all repos to one for archive
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
#include "Buffer.hpp"
|
||||
|
||||
class BitReader
|
||||
{
|
||||
public:
|
||||
int k = 8;
|
||||
Buffer buffer;
|
||||
char x = 0;
|
||||
size_t pos = 0;
|
||||
|
||||
int readInt()
|
||||
{
|
||||
int ret = buffer.buffer[pos];
|
||||
pos += 4;
|
||||
return ret;
|
||||
}
|
||||
|
||||
char readByte()
|
||||
{
|
||||
x = buffer.buffer[pos];
|
||||
pos++;
|
||||
return x;
|
||||
}
|
||||
|
||||
bool readBit()
|
||||
{
|
||||
if (k == 8)
|
||||
{
|
||||
readByte();
|
||||
k = 0;
|
||||
}
|
||||
bool b = (x >> k) & 1;
|
||||
k++;
|
||||
return b;
|
||||
}
|
||||
};
|
@@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
#include "Buffer.hpp"
|
||||
|
||||
class BitWriter
|
||||
{
|
||||
public:
|
||||
int k = 0;
|
||||
Buffer buffer;
|
||||
char x = 0;
|
||||
|
||||
void writeByte(uint8_t x)
|
||||
{
|
||||
// f.write((char*)&x, 1);
|
||||
buffer.add_end(&x, sizeof(uint8_t));
|
||||
}
|
||||
|
||||
void writeInt(int x)
|
||||
{
|
||||
buffer.add_end((uint8_t *)&x, sizeof(x));
|
||||
}
|
||||
|
||||
void writeBit(bool b)
|
||||
{
|
||||
if (k == 8)
|
||||
{
|
||||
writeByte(x);
|
||||
k = 0;
|
||||
x = 0;
|
||||
}
|
||||
x ^= (-b ^ x) & (1 << k);
|
||||
k++;
|
||||
}
|
||||
|
||||
void finish()
|
||||
{
|
||||
if (k > 0)
|
||||
writeByte(x);
|
||||
}
|
||||
};
|
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
class Buffer
|
||||
{
|
||||
public:
|
||||
uint8_t *buffer = nullptr;
|
||||
size_t taken = 0;
|
||||
size_t size = 0;
|
||||
std::string file_path;
|
||||
|
||||
Buffer(size_t size);
|
||||
Buffer();
|
||||
~Buffer();
|
||||
bool resize(size_t new_size);
|
||||
int add_end(uint8_t *data, size_t data_size);
|
||||
int add_middle(uint8_t *data, size_t data_size, size_t index);
|
||||
|
||||
// Removes data from buffer without checking if it's in the buffer
|
||||
void remove_fast(uint8_t *data, size_t data_size);
|
||||
|
||||
void remove(size_t index, size_t data_size);
|
||||
|
||||
int find(uint8_t *data, size_t data_size);
|
||||
|
||||
void remove(uint8_t *data, size_t data_size);
|
||||
|
||||
void clear() { taken = 0; }
|
||||
|
||||
bool save_to_file();
|
||||
bool save_to_file(std::string file_path);
|
||||
|
||||
bool load_from_file();
|
||||
bool load_from_file(std::string file_path);
|
||||
};
|
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
#include "BitWriter.hpp"
|
||||
#include <vector>
|
||||
|
||||
class Compressor
|
||||
{
|
||||
|
||||
public:
|
||||
Compressor() = default;
|
||||
~Compressor() = default;
|
||||
void compress(std::vector<uint8_t> &input);
|
||||
BitWriter bitWriter;
|
||||
|
||||
private:
|
||||
void two_bit_dif(int8_t num);
|
||||
void tree_bit_dif(int8_t num);
|
||||
void four_bit_dif(int8_t num);
|
||||
void five_bit_dif(int8_t num);
|
||||
void encode_diff(int8_t num);
|
||||
void encode_abs(int16_t num);
|
||||
void write_zero();
|
||||
|
||||
int numOfZeros = 0;
|
||||
};
|
@@ -0,0 +1,15 @@
|
||||
#include "BitReader.hpp"
|
||||
#include <vector>
|
||||
|
||||
class Decompressor
|
||||
{
|
||||
public:
|
||||
std::vector<uint8_t> decompress();
|
||||
BitReader bitReader;
|
||||
|
||||
private:
|
||||
int8_t twoZero();
|
||||
int8_t treeZero();
|
||||
int8_t forZero();
|
||||
int8_t fiveZero();
|
||||
};
|
114
semester_5/racunalniska_vecpredstavnost/vaja_1/main.cpp
Normal file
114
semester_5/racunalniska_vecpredstavnost/vaja_1/main.cpp
Normal file
@@ -0,0 +1,114 @@
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
#include <chrono>
|
||||
#include <ctime>
|
||||
#include <random>
|
||||
|
||||
#include "Compressor.hpp"
|
||||
#include "Decompressor.hpp"
|
||||
|
||||
/*
|
||||
• Prikažite graf ali tabelo kompresijskega razmerja
|
||||
• Prikažite graf ali tabelo časa kompresije
|
||||
• Prikažite graf ali tabelo časa dekompresije
|
||||
• 5-10 stavkov ugotovitev
|
||||
|
||||
• Uporabite N števil
|
||||
• N = {5, 50, 500, 5000}
|
||||
• Naključno generirana števila na intervalu od 0 do 255
|
||||
• Števila (na intervalu med 0 in 255), ki se med seboj razlikujejo za M
|
||||
(razlika med sosednjima številoma je med 0 in M)
|
||||
• M = {5, 10, 15, 30}
|
||||
• Primer: N = 5 in M = 5; podatki: 135, 133, 136, 141, 141
|
||||
|
||||
|
||||
55 53 53 53 53 53 10 10 11 11 11 11
|
||||
|
||||
00110111 000000 01011 10100101011 01000 000010 01010 11
|
||||
*/
|
||||
|
||||
void genRandNum(int N, int M, std::vector<uint8_t> &vec)
|
||||
{
|
||||
|
||||
std::random_device rand_dev;
|
||||
std::mt19937 generator(rand_dev());
|
||||
std::uniform_real_distribution<double> distr(0.0, 1.0);
|
||||
|
||||
uint8_t last = 0;
|
||||
uint8_t max = 255;
|
||||
uint8_t min = 0;
|
||||
for (int i = 0; i < N; i++)
|
||||
{
|
||||
// std::cout << 25 + static_cast<int>((distr(generator) * (63 - 25 + 1))) << '\n';
|
||||
float r = distr(generator);
|
||||
uint8_t num = min + (r * (max - min));
|
||||
max = num + M;
|
||||
if (max > 255)
|
||||
max = 255;
|
||||
min = num - M;
|
||||
if (min < 0)
|
||||
min = 0;
|
||||
vec.push_back(num);
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
auto start = std::chrono::system_clock::now();
|
||||
std::vector<int> N = {5, 50, 500, 5000, 50000};
|
||||
std::vector<int> M = {2, 5, 10, 15, 30, 60};
|
||||
|
||||
printf("N, \t M, \t Compress time, \tDecompress time, \t Input size, \t Output size, \t Compression ratio, \n");
|
||||
|
||||
for (size_t i = 0; i < N.size(); i++)
|
||||
{
|
||||
for (size_t j = 0; j < M.size(); j++)
|
||||
{
|
||||
|
||||
std::vector<uint8_t> input;
|
||||
genRandNum(N[i], M[j], input);
|
||||
|
||||
Compressor compressor;
|
||||
|
||||
auto startCom = std::chrono::system_clock::now();
|
||||
compressor.compress(input);
|
||||
auto endCom = std::chrono::system_clock::now();
|
||||
|
||||
Decompressor decompressor;
|
||||
decompressor.bitReader.buffer.add_end(compressor.bitWriter.buffer.buffer, compressor.bitWriter.buffer.taken);
|
||||
|
||||
auto startDec = std::chrono::system_clock::now();
|
||||
std::vector<uint8_t> output = decompressor.decompress();
|
||||
auto endDec = std::chrono::system_clock::now();
|
||||
|
||||
for (size_t k = 0; k < input.size(); k++)
|
||||
{
|
||||
if (input[k] != output[k])
|
||||
{
|
||||
printf("Error\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
std::chrono::duration<double> compTime = endCom - startCom;
|
||||
std::chrono::duration<double> decTime = endDec - startDec;
|
||||
|
||||
printf("%d,\t %d,\t ", N[i], M[j]);
|
||||
printf("%f,\t\t", compTime.count());
|
||||
printf("%f,\t\t ", decTime.count());
|
||||
uint64_t input_size = N[i] * sizeof(uint8_t);
|
||||
uint64_t output_size = compressor.bitWriter.buffer.taken;
|
||||
printf("%ld,\t\t ", input_size);
|
||||
printf("%ld,\t\t ", output_size);
|
||||
printf("%f,\t", (float)input_size / (float)output_size);
|
||||
printf("\n");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
auto end = std::chrono::system_clock::now();
|
||||
std::chrono::duration<double> decTime = end - start;
|
||||
printf("Total time: %f\n", decTime.count());
|
||||
return 0;
|
||||
}
|
27
semester_5/racunalniska_vecpredstavnost/vaja_1/makefile
Normal file
27
semester_5/racunalniska_vecpredstavnost/vaja_1/makefile
Normal file
@@ -0,0 +1,27 @@
|
||||
CC=g++
|
||||
|
||||
CFLAGS= -std=c++23
|
||||
|
||||
INCLUDE_DIR= include
|
||||
|
||||
SRC_DIR= src
|
||||
|
||||
# Get all cpp files from src directory
|
||||
SRCS := $(wildcard $(SRC_DIR)/*.cpp)
|
||||
|
||||
all: main
|
||||
|
||||
main: main.cpp $(SRCS)
|
||||
$(CC) $(CFLAGS) -o3 -I$(INCLUDE_DIR) $(SRCS) main.cpp -o main
|
||||
|
||||
debug: main.cpp $(SRCS)
|
||||
$(CC) $(CFLAGS) -I$(INCLUDE_DIR) $(SRCS) -g main.cpp -o main
|
||||
|
||||
run: main
|
||||
./main
|
||||
|
||||
zip:
|
||||
zip -r main.zip src include makefile main.cpp
|
||||
|
||||
clean:
|
||||
rm main main.zip
|
153
semester_5/racunalniska_vecpredstavnost/vaja_1/src/Buffer.cpp
Normal file
153
semester_5/racunalniska_vecpredstavnost/vaja_1/src/Buffer.cpp
Normal file
@@ -0,0 +1,153 @@
|
||||
#include "Buffer.hpp"
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <cstring>
|
||||
|
||||
Buffer::Buffer()
|
||||
{
|
||||
buffer = nullptr;
|
||||
size = 0;
|
||||
taken = 0;
|
||||
}
|
||||
|
||||
Buffer::Buffer(size_t size)
|
||||
{
|
||||
this->size = size;
|
||||
this->buffer = new uint8_t[size];
|
||||
}
|
||||
|
||||
Buffer::~Buffer()
|
||||
{
|
||||
if (buffer)
|
||||
delete[] buffer;
|
||||
}
|
||||
|
||||
bool Buffer::resize(size_t new_size)
|
||||
{
|
||||
if (size >= new_size)
|
||||
return true;
|
||||
if (new_size < size * 2)
|
||||
new_size = size * 2;
|
||||
uint8_t *new_buffer = (uint8_t *)realloc(buffer, new_size);
|
||||
if (!new_buffer)
|
||||
{
|
||||
printf("Error resizing buffer\n");
|
||||
return false;
|
||||
}
|
||||
buffer = new_buffer;
|
||||
size = new_size;
|
||||
return true;
|
||||
}
|
||||
|
||||
int Buffer::add_end(uint8_t *data, size_t data_size)
|
||||
{
|
||||
if (taken + data_size > size)
|
||||
if (!resize(size + data_size))
|
||||
return -1;
|
||||
|
||||
memcpy(buffer + taken, data, data_size);
|
||||
taken += data_size;
|
||||
return taken - data_size;
|
||||
}
|
||||
|
||||
int Buffer::add_middle(uint8_t *data, size_t data_size, size_t index)
|
||||
{
|
||||
if (taken + data_size > size)
|
||||
if (!resize(size + data_size))
|
||||
return -1;
|
||||
memmove(buffer + index + data_size, buffer + index, taken - index);
|
||||
memcpy(buffer + index, data, data_size);
|
||||
taken += data_size;
|
||||
return index;
|
||||
}
|
||||
|
||||
void Buffer::remove_fast(uint8_t *data, size_t data_size)
|
||||
{
|
||||
int64_t index = data - buffer;
|
||||
if (index < 0 || index > taken || index + data_size > taken)
|
||||
{
|
||||
printf("Error removing from buffer\n");
|
||||
return;
|
||||
}
|
||||
memmove(buffer + index, buffer + index + data_size, taken - index - data_size);
|
||||
taken -= data_size;
|
||||
}
|
||||
|
||||
void Buffer::remove(size_t index, size_t data_size)
|
||||
{
|
||||
if (index + data_size > taken)
|
||||
{
|
||||
printf("Error removing from buffer\n");
|
||||
return;
|
||||
}
|
||||
memmove(buffer + index, buffer + index + data_size, taken - index - data_size);
|
||||
taken -= data_size;
|
||||
}
|
||||
|
||||
int Buffer::find(uint8_t *data, size_t data_size)
|
||||
{
|
||||
for (int i = 0; i < taken; i++)
|
||||
if (memcmp(buffer + i, data, data_size) == 0)
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void Buffer::remove(uint8_t *data, size_t data_size)
|
||||
{
|
||||
int index = find(data, data_size);
|
||||
if (index == -1)
|
||||
{
|
||||
printf("Error removing from buffer\n");
|
||||
return;
|
||||
}
|
||||
remove(index, data_size);
|
||||
}
|
||||
|
||||
bool Buffer::save_to_file()
|
||||
{
|
||||
std::ofstream file(this->file_path, std::ios::binary | std::ios::out);
|
||||
if (!file.is_open())
|
||||
{
|
||||
printf("Error saving file\n");
|
||||
return false;
|
||||
}
|
||||
file.write((char *)this->buffer, this->taken);
|
||||
file.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Buffer::save_to_file(std::string file_path)
|
||||
{
|
||||
this->file_path = file_path;
|
||||
return save_to_file();
|
||||
}
|
||||
|
||||
bool Buffer::load_from_file()
|
||||
{
|
||||
std::ifstream file(this->file_path, std::ios::binary | std::ios::in);
|
||||
if (!file.is_open())
|
||||
return false;
|
||||
|
||||
file.seekg(0, std::ios::end);
|
||||
|
||||
size_t file_size = file.tellg();
|
||||
resize(file_size);
|
||||
|
||||
file.seekg(0, std::ios::beg);
|
||||
file.read((char *)buffer, size);
|
||||
|
||||
if (file)
|
||||
taken = file_size;
|
||||
else
|
||||
taken = file.gcount();
|
||||
|
||||
file.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Buffer::load_from_file(std::string file_path)
|
||||
{
|
||||
this->file_path = file_path;
|
||||
return load_from_file();
|
||||
}
|
@@ -0,0 +1,158 @@
|
||||
#include "Compressor.hpp"
|
||||
|
||||
void Compressor::two_bit_dif(int8_t num)
|
||||
{
|
||||
bitWriter.writeBit(0);
|
||||
bitWriter.writeBit(0);
|
||||
|
||||
if (num < 0)
|
||||
num += 2;
|
||||
else
|
||||
num += 1;
|
||||
|
||||
bitWriter.writeBit(num & 2);
|
||||
bitWriter.writeBit(num & 1);
|
||||
}
|
||||
|
||||
void Compressor::tree_bit_dif(int8_t num)
|
||||
{
|
||||
bitWriter.writeBit(0);
|
||||
bitWriter.writeBit(1);
|
||||
|
||||
if (num < 0)
|
||||
num += 6;
|
||||
else
|
||||
num += 1;
|
||||
|
||||
bitWriter.writeBit(num & 4);
|
||||
bitWriter.writeBit(num & 2);
|
||||
bitWriter.writeBit(num & 1);
|
||||
}
|
||||
|
||||
void Compressor::four_bit_dif(int8_t num)
|
||||
{
|
||||
bitWriter.writeBit(1);
|
||||
bitWriter.writeBit(0);
|
||||
|
||||
if (num < 0)
|
||||
num += 14;
|
||||
else
|
||||
num += 1;
|
||||
|
||||
bitWriter.writeBit(num & 8);
|
||||
bitWriter.writeBit(num & 4);
|
||||
bitWriter.writeBit(num & 2);
|
||||
bitWriter.writeBit(num & 1);
|
||||
}
|
||||
|
||||
void Compressor::five_bit_dif(int8_t num)
|
||||
{
|
||||
bitWriter.writeBit(1);
|
||||
bitWriter.writeBit(1);
|
||||
|
||||
if (num < 0)
|
||||
num += 30;
|
||||
else
|
||||
num += 1;
|
||||
|
||||
bitWriter.writeBit(num & 16);
|
||||
bitWriter.writeBit(num & 8);
|
||||
bitWriter.writeBit(num & 4);
|
||||
bitWriter.writeBit(num & 2);
|
||||
bitWriter.writeBit(num & 1);
|
||||
}
|
||||
|
||||
void Compressor::encode_diff(int8_t num)
|
||||
{
|
||||
bitWriter.writeBit(0);
|
||||
bitWriter.writeBit(0);
|
||||
if (-2 <= num && num <= 2)
|
||||
two_bit_dif(num);
|
||||
else if (-6 <= num && num <= 6)
|
||||
tree_bit_dif(num);
|
||||
else if (-14 <= num && num <= 14)
|
||||
four_bit_dif(num);
|
||||
else if (-30 <= num && num <= 30)
|
||||
five_bit_dif(num);
|
||||
}
|
||||
|
||||
void Compressor::encode_abs(int16_t num)
|
||||
{
|
||||
bitWriter.writeBit(1);
|
||||
bitWriter.writeBit(0);
|
||||
|
||||
if (num < 0)
|
||||
{
|
||||
bitWriter.writeBit(1);
|
||||
num = -num;
|
||||
}
|
||||
else
|
||||
{
|
||||
bitWriter.writeBit(0);
|
||||
}
|
||||
|
||||
uint8_t numOfBits = num;
|
||||
|
||||
for (int i = 7; i >= 0; i--)
|
||||
bitWriter.writeBit(numOfBits & 1 << i);
|
||||
}
|
||||
|
||||
void Compressor::write_zero()
|
||||
{
|
||||
bitWriter.writeBit(0);
|
||||
bitWriter.writeBit(1);
|
||||
numOfZeros--;
|
||||
bitWriter.writeBit(numOfZeros & 4);
|
||||
bitWriter.writeBit(numOfZeros & 2);
|
||||
bitWriter.writeBit(numOfZeros & 1);
|
||||
numOfZeros = 0;
|
||||
}
|
||||
|
||||
void Compressor::compress(std::vector<uint8_t> &input)
|
||||
{
|
||||
std::vector<int16_t> diference;
|
||||
|
||||
diference.push_back(input[0]);
|
||||
for (size_t i = 1; i < input.size(); i++)
|
||||
{
|
||||
diference.push_back(input[i] - input[i - 1]);
|
||||
}
|
||||
|
||||
bitWriter.writeByte(diference[0]);
|
||||
for (size_t i = 1; i < diference.size(); i++)
|
||||
{
|
||||
int16_t j = diference[i];
|
||||
if (j == 0)
|
||||
{
|
||||
if (numOfZeros == 8)
|
||||
{
|
||||
write_zero();
|
||||
}
|
||||
|
||||
numOfZeros++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (numOfZeros > 0)
|
||||
{
|
||||
write_zero();
|
||||
}
|
||||
|
||||
if (-30 <= j && j <= 30)
|
||||
encode_diff(j);
|
||||
else
|
||||
encode_abs(j);
|
||||
|
||||
numOfZeros = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (numOfZeros > 0)
|
||||
{
|
||||
write_zero();
|
||||
}
|
||||
|
||||
bitWriter.writeBit(1);
|
||||
bitWriter.writeBit(1);
|
||||
bitWriter.finish();
|
||||
}
|
@@ -0,0 +1,125 @@
|
||||
#include "Decompressor.hpp"
|
||||
|
||||
int8_t Decompressor::twoZero()
|
||||
{
|
||||
int8_t val = 0;
|
||||
for (int i = 1; i >= 0; i--)
|
||||
val |= bitReader.readBit() << i;
|
||||
|
||||
if (val & 2)
|
||||
return val - 1;
|
||||
else
|
||||
return val - 2;
|
||||
}
|
||||
|
||||
int8_t Decompressor::treeZero()
|
||||
{
|
||||
int8_t val = 0;
|
||||
for (int i = 2; i >= 0; i--)
|
||||
val |= bitReader.readBit() << i;
|
||||
|
||||
if (val & 4)
|
||||
return val - 1;
|
||||
else
|
||||
return val - 6;
|
||||
}
|
||||
|
||||
int8_t Decompressor::forZero()
|
||||
{
|
||||
int8_t val = 0;
|
||||
for (int i = 3; i >= 0; i--)
|
||||
val |= bitReader.readBit() << i;
|
||||
|
||||
if (val & 8)
|
||||
return val - 1;
|
||||
else
|
||||
return val - 14;
|
||||
}
|
||||
|
||||
int8_t Decompressor::fiveZero()
|
||||
{
|
||||
int8_t val = 0;
|
||||
for (int i = 4; i >= 0; i--)
|
||||
val |= bitReader.readBit() << i;
|
||||
|
||||
if (val & 16)
|
||||
return val - 1;
|
||||
else
|
||||
return val - 30;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Decompressor::decompress()
|
||||
{
|
||||
std::vector<uint8_t> output;
|
||||
bool end = false;
|
||||
uint8_t previus = bitReader.readByte();
|
||||
output.push_back(previus);
|
||||
|
||||
do
|
||||
{
|
||||
uint8_t type = bitReader.readBit() << 1 | bitReader.readBit();
|
||||
switch (type)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
uint8_t numOfZero = bitReader.readBit() << 1 | bitReader.readBit();
|
||||
int8_t diff = 0;
|
||||
switch (numOfZero)
|
||||
{
|
||||
case 0:
|
||||
diff = twoZero();
|
||||
break;
|
||||
case 1:
|
||||
diff = treeZero();
|
||||
break;
|
||||
case 2:
|
||||
diff = forZero();
|
||||
break;
|
||||
case 3:
|
||||
diff = fiveZero();
|
||||
break;
|
||||
}
|
||||
|
||||
previus += diff;
|
||||
output.push_back(previus);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
{
|
||||
uint8_t numOfZero = bitReader.readBit() << 2 | bitReader.readBit() << 1 | bitReader.readBit();
|
||||
|
||||
numOfZero++;
|
||||
for (size_t i = 0; i < numOfZero; i++)
|
||||
{
|
||||
output.push_back(previus);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case 2:
|
||||
{
|
||||
uint8_t sign = bitReader.readBit();
|
||||
int16_t diff = 0;
|
||||
for (int i = 7; i >= 0; i--)
|
||||
{
|
||||
uint8_t bit = bitReader.readBit();
|
||||
diff |= bit << i;
|
||||
}
|
||||
if (sign)
|
||||
diff = -diff;
|
||||
|
||||
previus += diff;
|
||||
output.push_back(previus);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
end = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
} while (!end);
|
||||
return output;
|
||||
}
|
Reference in New Issue
Block a user