lib/mobile_numbers_range.cpp
throw std::invalid_argument("set_caller_code -> caller_code_from -- invalid argument: " + std::string(caller_code_from.begin(), caller_code_from.end()));
}
auto is_caller_code_to = std::all_of(caller_code_to.begin(), caller_code_to.end(), static_cast<int (*)(int)>(std::isdigit));
if (!is_caller_code_to)
{
throw std::invalid_argument("set_caller_code -> caller_code_to -- invalid argument: " + std::string(caller_code_to.begin(), caller_code_to.end()));
}
m_caller_code_from = std::stoi(caller_code_from); m_caller_code_to = std::stoi(caller_code_to);
}
void MobileNumbersRange::set_operator_name(const std::wstring &mobile_operator)
{
m_operator_name = mobile_operator;
}
void MobileNumbersRange::set_region(const std::wstring ®ion)
{
m_region = region;
}
// check
int MobileNumbersRange::cmp_in_range(long caller_code) const
{
long t = static_cast<long>(m_operator_code) * (MobileNumberDefines::MAX_CALLER_CODE + 1); long from = t + m_caller_code_from;
if (caller_code < from)
{
return -1;
}
long to = t + m_caller_code_to; if (caller_code > to)
{
return 1;
}
return 0;
}
bool operator<(const MobileNumbersRange &range1, const MobileNumbersRange &range2)
{
return range1.m_operator_code < range2.m_operator_code || (range1.m_operator_code == range2.m_operator_code &&
range1.m_caller_code_from < range2.m_caller_code_from);
}
Таблица 17. Файл lib/mobile_numbers_data.h lib/mobile_numbers_data.h
#ifndef MOBILE_NUMBERS_DATA_H #define MOBILE_NUMBERS_DATA_H
#include <istream> #include <string> #include <regex> #include <deque> #include <algorithm> #include <stdexcept>
#include "mobile_numbers_range.h" #include "mobile_number_defines.h"
class MobileNumbersData
{
public:
MobileNumbersData();
void add_data(std::wistream &);
MobileNumbersRange find_with_check(std::string) const; MobileNumbersRange find_without_check(std::string) const; std::string generate() const;
21
lib/mobile_numbers_data.h
static bool is_mobile_number(const std::string &);
private:
std::deque<MobileNumbersRange> m_data;
};
#endif // MOBILE_NUMBERS_DATA_H
Таблица 18. Файл lib/mobile_numbers_data.cpp lib/mobile_numbers_data.cpp
#include "mobile_numbers_data.h"
MobileNumbersData::MobileNumbersData()
{
}
void MobileNumbersData::add_data(std::wistream &stream)
{
bool maybe_header = true; MobileNumbersRange range;
size_t m_data_size_from = m_data.size(); std::match_results<std::wstring::const_iterator> sm; for (std::wstring line; std::getline(stream, line);)
{
if (std::regex_match(line, sm, MobileNumberDefines::mobile_numbers_range_regex))
{
range.set_operator_code(sm.str(1)); range.set_caller_code(sm.str(2), sm.str(3)); range.set_operator_name(sm.str(4)); range.set_region(sm.str(5)); m_data.emplace_back(range);
}
else
{
if (maybe_header && !(L'0' <= line[0] && line[0] <= L'9'))
{
maybe_header = false;
}
else
{
throw std::invalid_argument( std::string("Argument is invalid: ") + std::string(line.begin(), line.end()));
}
}
}
auto it = m_data.begin(); std::advance(it, m_data_size_from); if (!std::is_sorted(it, m_data.end()))
{
std::sort(it, m_data.end());
}
std::inplace_merge(m_data.begin(), it, m_data.end());
}
MobileNumbersRange MobileNumbersData::find_with_check(std::string mobile_number) const
{
std::smatch sm;
if (!std::regex_match(mobile_number, sm, MobileNumberDefines::mobile_number_regex))
{
throw std::out_of_range("Invalid mobile number.");
}
return find_without_check(sm.str(2) + sm.str(3) + sm.str(4) + sm.str(5));
}
MobileNumbersRange MobileNumbersData::find_without_check(std::string mobile_number) const
{
if (m_data.empty())
{
22
throw std::out_of_range("Data is empty. Use method 'add' before 'find'.");
}
size_t left = 0, right = m_data.size() - 1, mid; long target = std::stol(mobile_number);
while (left <= right && right != std::wstring::npos)
{
mid = left + ((right - left) >> 1);
int cmp = m_data[mid].cmp_in_range(target); if (cmp == -1)
{
right = mid - 1;
}
else if (cmp == 1)
{
left = mid + 1;
}
else
{
return m_data[mid];
}
}
throw std::range_error("Not found.");
}
std::string MobileNumbersData::generate() const
{
MobileNumbersRange range = m_data[RandomGen::get_random_size_t_number(0, m_data.size() - 1)]; std::string operator_code = range.operator_code();
std::string caller_code = std::to_string(RandomGen::get_random_int_number(range.caller_code_from_i(), range.caller_code_to_i()));
return std::string(MobileNumberDefines::OPERATOR_CODE_DIGITS - operator_code.size(), '0') + operator_code +
std::string(MobileNumberDefines::CALLER_CODE_DIGITS - caller_code.size(), '0') + caller_code;
}
bool MobileNumbersData::is_mobile_number(const std::string &arg)
{
return std::regex_match(arg, MobileNumberDefines::mobile_number_regex);
}
Таблица 19. Сборочный файл lib/Makefile lib/Makefile
.PHONY : all clean CXX=g++
CXXFLAGS=-std=c++17 -O4 -Werror -pedantic-errors -Wredundant-decls \ -Wall -Wextra -Wpedantic -Wcast-align -Wcast-qual \ -Wconversion -Wctor-dtor-privacy -Wduplicated-branches \ -Wduplicated-cond -Wextra-semi -Wfloat-equal -Wlogical-op \
-Wnon-virtual-dtor -Woverloaded-virtual -Wsign-conversion -Wsign-promo
all: $(patsubst %.cpp, %.o, $(wildcard *.cpp))
%.o: %.cpp %.h Makefile
$(CXX) $(CXXFLAGS) -c -o $@ $<
clean:
rm -f *.o
23
Таблица 20. Сборочный файл Makefile Makefile
.PHONY : all clean CXX=g++
CXXFLAGS=-std=c++17 -O4 -Werror -pedantic-errors -Wredundant-decls \ -Wall -Wextra -Wpedantic -Wcast-align -Wcast-qual \ -Wconversion -Wctor-dtor-privacy -Wduplicated-branches \ -Wduplicated-cond -Wextra-semi -Wfloat-equal -Wlogical-op \
-Wnon-virtual-dtor -Woverloaded-virtual -Wsign-conversion -Wsign-promo LIB_HEADERS=$(wildcard lib/*.h)
LIB_SOURCES=$(wildcard lib/*.cpp) LIB_OBJECTS=$(patsubst %.cpp, %.o, $(LIB_SOURCES))
all: main test
main: $(LIB_OBJECTS) main.o
$(CXX) $(CXXFLAGS) -o main $(LIB_OBJECTS) main.o
test: $(LIB_OBJECTS) test.o
$(CXX) $(CXXFLAGS) -o test $(LIB_OBJECTS) test.o
$(LIB_OBJECTS): $(LIB_SOURCES) $(LIB_HEADERS) @cd lib && $(MAKE) && cd ../
%.o: %.cpp Makefile
$(CXX) $(CXXFLAGS) -c -o $@ $<
clean:
rm -f *.o
Решение с деревом цифр и минимальным масками диапазонов состоит
из 11 файлов, представленных в таблицах 21-31.
Таблица 21. Файл main.cpp
main.cpp
#include <string> #include <iostream> #include <fstream> #include <filesystem> #include <stdexcept>
#include "lib/mobile_numbers_data.h"
namespace fs = std::filesystem;
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,
const std::wstring &repl_substr)
{
size_t pos = str.find(substr); if (pos != std::wstring::npos)
{
return str.substr(0, pos) + repl_substr +
str.substr(pos + substr.size(), std::string::npos);
24
main.cpp
}
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: ./main {mobile_number}" << std::endl; return 1;
}
// check mobile number
std::string mobile_number(argv[1]);
if (!MobileNumbersData::is_mobile_number(mobile_number))
{
std::wcout << "Invalid mobile number format." << std::endl; return 2;
}
// get csv files in current directory
std::vector<fs::path> files_vector = get_files_in_directory(L"./", L".csv"); if (files_vector.empty())
{
std::wcout << "CSV files not found." << std::endl; return 3;
}
try
{
MobileNumbersData mobile_numbers_data; 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;
}
mobile_numbers_data.add_data(wstream);
}
auto range = mobile_numbers_data.find_with_check(mobile_number); auto mobile_operator = range.operator_name();
auto region = range.region();
region = replace(region, L";", L", "); region = replace(region, L"|", L", ");
std::wcout << mobile_operator << ", " << region << std::endl;
}
catch (const std::exception &e)
{
std::wcout << e.what() << std::endl; return 4;
}
return 0;
}
Таблица 22. Файл test.cpp
test.cpp
#include <string> #include <iostream> #include <fstream> #include <filesystem> #include <stdexcept> #include <chrono>
#include "lib/mobile_numbers_data.h"
namespace fs = std::filesystem;
//Get the current time in seconds
//This function should be used only for measuring time
//(first call, algorithm, second call; then the difference between the values)
25