Материал: ИКПИ. Пример отчета по практике

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

test.cpp

#if defined(_WIN32) #include <Windows.h> double get_proc_time()

{

FILETIME createTime, exitTime, kernelTime, userTime;

if (GetProcessTimes(GetCurrentProcess(), &createTime, &exitTime, &kernelTime, &userTime) != -1) return (ULARGE_INTEGER{{userTime.dwLowDateTime, userTime.dwHighDateTime}}).QuadPart /

10000000.L; return 0;

}

#else

double get_proc_time()

{

return static_cast<double>(clock()) / CLOCKS_PER_SEC;

}

#endif

std::vector<fs::path> get_files_in_directory(const std::wstring &directory, std::wstring ext)

{

std::vector<fs::path> files_vector;

for (const auto &file : fs::directory_iterator(directory))

{

fs::path filepath = file.path();

if (fs::is_regular_file(filepath) && (ext.empty() || filepath.extension() == ext))

{

files_vector.emplace_back(filepath);

}

}

return files_vector;

}

std::wstring replace(const std::wstring &str,

const std::wstring &substr_from, const std::wstring &substr_to)

{

size_t pos = str.find(substr_from); if (pos != std::wstring::npos)

{

return str.substr(0, pos) + substr_to +

str.substr(pos + substr_from.size(), std::string::npos);

}

return str;

}

int main(int argc, char *argv[])

{

// set locale (required for wstring) std::locale::global(std::locale("C.UTF-8"));

//check args if (argc != 2)

{

std::wcout << "Use: ./test {number of tests}" << std::endl; return 1;

}

int n_tests = 0; try

{

n_tests = std::atoi(argv[1]); if (n_tests <= 0)

{

throw std::invalid_argument("Arg {number of tests} is non-positive number.");

}

}

catch (const std::exception &e)

{

std::wcout << e.what() << std::endl; return 2;

}

//find csv files in current directory

std::vector<fs::path> files_vector = get_files_in_directory(L"./", L".csv"); if (files_vector.empty())

{

26

test.cpp

std::wcout << "CSV files not found." << std::endl; return 3;

}

try

{

// start testing

MobileNumbersData mobile_numbers_data; double s = 0, start, finish;

for (const auto &file : files_vector)

{

std::wifstream wstream(file); if (!wstream.is_open())

{

std::wcout << "File \"" << file.wstring() << "\" skipped (open error)." << std::endl; continue;

}

start = get_proc_time(); mobile_numbers_data.add_data(wstream); finish = get_proc_time();

s += finish - start;

}

std::wcout << "-- Adding data from files: " << s << " seconds" << std::endl; s = 0;

for (int i = 0; i < n_tests; ++i)

{

auto mobile_number = mobile_numbers_data.generate(); start = get_proc_time();

auto range = mobile_numbers_data.find_without_check(mobile_number); finish = get_proc_time();

s += finish - start;

}

std::wcout << "== Without check results" << std::endl;

std::wcout << "-- Testing time: " << s << " seconds" << std::endl; s = 0;

for (int i = 0; i < n_tests; ++i)

{

auto mobile_number = mobile_numbers_data.generate(); start = get_proc_time();

auto range = mobile_numbers_data.find_with_check(mobile_number); finish = get_proc_time();

s += finish - start;

}

std::wcout << "== With check results" << std::endl;

std::wcout << "-- Testing time: " << s << " seconds" << std::endl;

}

catch (const std::exception &e)

{

std::wcout << e.what() << std::endl; return 4;

}

return 0;

}

Таблица 23. Файл lib/digits_tree.h lib/digits_tree.h

#ifndef DIGITS_TREE_H #define DIGITS_TREE_H

#include <cstdint> #include <memory> #include <cstdlib> #include <stdexcept> #include <deque>

#include "mobile_number_defines.h" #include "mobile_numbers_range.h"

template <size_t D = 10> class DigitsTree

{

public:

DigitsTree() : m_size(0)

27

lib/digits_tree.h

{

}

void push(const std::string &str, const MobileNumbersRange &obj)

{

++m_size;

if (str.empty())

{

if (!m_current)

{

m_current = std::make_unique<MobileNumbersRange>(obj); return;

}

else

{

throw std::invalid_argument("push -> obj already exists");

}

m_current = std::make_unique<MobileNumbersRange>(obj);

}

char first_digit = str[0];

if ('0' <= first_digit && first_digit <= '9')

{

size_t index = static_cast<size_t>(first_digit - '0'); if (!m_ranges[index])

{

m_ranges[index] = std::make_unique<DigitsTree>();

}

m_ranges[index]->push(str.substr(1), obj);

}

else

{

if (!m_current)

{

m_current = std::make_unique<MobileNumbersRange>(obj);

}

else

{

throw std::invalid_argument("push -> obj already exists");

}

}

}

MobileNumbersRange find(const std::string &str, size_t shift_ = 0) const

{

if (empty())

{

std::out_of_range("Data is empty. Use method 'push' before 'find'.");

}

if (m_current)

{

return *m_current;

}

if (str.empty())

{

throw std::invalid_argument("find -> str is empty");

}

if (shift_ >= str.size())

{

throw std::invalid_argument("find -> shift >= str.size()");

}

if (!('0' <= str[shift_] && str[shift_] <= '9'))

{

throw std::invalid_argument("find -> str[shift_] not in [0, 9]");

}

size_t index = static_cast<size_t>(str[shift_] - '0'); if (m_ranges[index])

{

return m_ranges[index]->find(str, shift_ + 1);

}

throw std::out_of_range("Not found.");

}

inline bool empty() const

{

28

lib/digits_tree.h

return m_size == 0;

}

MobileNumbersRange get_random() const

{

if (empty())

{

std::out_of_range("Data is empty. Use method 'add' before 'find'.");

}

if (!m_current)

{

std::deque<size_t> d;

for (size_t i = 0; i < D; ++i)

{

if (m_ranges[i])

{

d.push_back(i);

}

}

if (!d.empty())

{

return m_ranges[d[RandomGen::get_random_size_t_number(0, d.size() - 1)]]->get_random();

}

else

{

std::invalid_argument("get_random -> something is wrong");

}

}

return *m_current;

}

size_t size() const

{

return m_size;

}

private:

std::unique_ptr<DigitsTree> m_ranges[D]; std::unique_ptr<MobileNumbersRange> m_current; size_t m_size;

};

#endif // DIGITS_TREE_H

Таблица 24. Файл lib/mobile_number_defines.h lib/mobile_number_defines.h

#ifndef MOBILE_NUMBER_DEFINES_H #define MOBILE_NUMBER_DEFINES_H

#include <cmath> #include <string> #include <regex> #include <random> #include <functional>

namespace MobileNumberDefines

{

constexpr size_t COUNTRY_CODE_DIGITS = 1; constexpr size_t OPERATOR_CODE_DIGITS = 3; constexpr size_t CALLER_CODE_DIGITS = 7;

constexpr int MAX_COUNTRY_CODE = std::pow(10, COUNTRY_CODE_DIGITS) - 1; constexpr int MAX_OPERATOR_CODE = std::pow(10, OPERATOR_CODE_DIGITS) - 1; constexpr int MAX_CALLER_CODE = std::pow(10, CALLER_CODE_DIGITS) - 1;

const std::regex mobile_number_regex("^(?:(\\+?\\d)[\\- ]?)?(?:\\(?(\\d{3})\\)?[\\- ]?)(\\d{3})[\\- ]?(\\d{2})[\\- ]?(\\d{2})$");

/* Can work with next mobile numbers +79811742698 +7(981)1742698 +7-(981)-174-26-98 89811742698

29

lib/mobile_number_defines.h

9811742698

(981) 174 2698

(981)-174-2698

981-174-2698

981 174 2698

9811742698

...

country_code -- group #1 operator_code -- group #2 caller_code -- groups #3, #4 and #5

*/

const std::basic_regex<wchar_t> mobile_numbers_range_regex(L"^(\\d{3});(\\d{7});(\\d{7});[^;]*?;([^;]*);(.*)$");

/* Can work with next mobile numbers range

АВС/ DEF;От;До;Емкость;Оператор;Регион

301;2110000;2129999;20000;ПАО "Ростелеком";г. Улан-Удэ|Республика Бурятия 301;2150000;2169999;20000;ПАО "Ростелеком";г. Улан-Удэ|Республика Бурятия 301;2180000;2189999;10000;ПАО "Ростелеком";г. Улан-Удэ|Республика Бурятия

...

operator_code -- group #1 caller_code_from -- group #2 caller_code_to -- group #3 mobile_operator -- group #4 region -- group #5

*/

}

namespace RandomGen

{

extern std::random_device random_device_mn; extern std::mt19937 mt;

extern std::uniform_int_distribution<size_t> size_t_distribution; extern std::uniform_int_distribution<int> int_distribution; extern size_t get_random_size_t_number(size_t, size_t);

extern int get_random_int_number(int, int);

}

#endif // MOBILE_NUMBER_DEFINES_H

Таблица 25. Файл lib/mobile_number_defines.cpp lib/mobile_number_defines.cpp

#include "mobile_number_defines.h"

std::random_device RandomGen::random_device_mn;

std::mt19937 RandomGen::mt = std::mt19937(RandomGen::random_device_mn());

std::uniform_int_distribution<size_t> RandomGen::size_t_distribution(0,

std::numeric_limits<size_t>::max());

std::uniform_int_distribution<int> RandomGen::int_distribution(0, std::numeric_limits<int>::max());

size_t RandomGen::get_random_size_t_number(size_t from, size_t to)

{

return from + RandomGen::size_t_distribution(RandomGen::mt) % (to - from + 1);

}

int RandomGen::get_random_int_number(int from, int to)

{

return from + RandomGen::int_distribution(RandomGen::mt) % (to - from + 1);

}

30