diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..614b7fb --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +build/ +.idea +cmake-build-debug +Lib \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..73f69e0 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..c7e59f5 --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +pro \ No newline at end of file diff --git a/.idea/cids-server.iml b/.idea/cids-server.iml new file mode 100644 index 0000000..f08604b --- /dev/null +++ b/.idea/cids-server.iml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..79b3c94 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..424a3a2 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..5445c04 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,60 @@ +cmake_minimum_required(VERSION 3.00) +project(cids_server_new) + +#Global Setting +SET(CMAKE_CXX_FLAGS -pthread) + +SET(CMAKE_CXX_STANDARD 14) + +#Thir Lib + + #find- nanodbc +if(NOT TARGET nanodbc) + find_package(nanodbc CONFIG REQUIRED) +endif() + + #find- rapidjson +find_package(RapidJSON REQUIRED) + + #already put muduo in the project + +#add include +include_directories(Include) +include_directories(Include/Third_Lib) + +include_directories(${RapidJSON_INCLUDE_DIR}) +#muduo in Include/Third_lib +#nanodbc in Include/Third_lib + +#add lib +link_directories(Lib) + +#My src +aux_source_directory(Src/Center CENTER_SRC) +aux_source_directory(Src/Mirror MIRROR_SRC) +aux_source_directory(Src/Common COMMON_SRC) + +#生成可执行文件 + +add_executable(center ${CENTER_SRC} ${COMMON_SRC}) +add_executable(mirror ${MIRROR_SRC} ${COMMON_SRC}) + +#Center绑定包 +target_link_libraries(center libmuduo_base.a libmuduo_net.a) #绑定muduo包 + + +#Center修改输出属性 +set_target_properties(center PROPERTIES OUTPUT_NAME cids_Center) +set_target_properties(center PROPERTIES PREFIX "") +set_target_properties(center PROPERTIES SUFFIX "") + + +#Mirror绑定包 +target_link_libraries(mirror libmuduo_base.a libmuduo_net.a) #绑定muduo包 +target_link_libraries(mirror ${RapidJSON_LIBS}) #绑定rapidjson包 +target_link_libraries(mirror nanodbc) #绑定nanodbc包 + +#Mirror修改输出树形 +set_target_properties(mirror PROPERTIES OUTPUT_NAME cids_Mirror) +set_target_properties(mirror PROPERTIES PREFIX "") +set_target_properties(mirror PROPERTIES SUFFIX "") diff --git a/README.md b/README.md index f468905..9b4d484 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,176 @@ # cids-servers + center server ,mirror server and driver + + + +your project path and other library project path should be like this: + + + +- dir + + - cids-server + + - rapidjson + - nanodbc + + - muduo + + + +after clone this project + + + +## Imporve projectPath + +```bash +-- mkdir lib #to find libraries + +-- mkdir include #to find headers +``` + +------ + + + +## Compile rapidJson + +```bash +git clone #download rapidjson + +cd rapidjson #change to rapidjson dir + +mkdir build #Put compiler output in build file + +cd build #change to build dir + +cmake .. #generate Makefile + +make #generate other things you can add '-j4' after 'make' to make it faster + +sudo make install #generate lib files and put them in /usr/lib(maybe) +``` + +------ + + + +## Compile nanodbc + +Before you compile nanodbc, you should download UnixOdbc: + +### download mariadb and configure + +### download unixodbc + +` sudo apt install unixodbc ` + +### download unixODBC-2.3.0.tar.gz -> to download odbc_config + +Download unixODBC-2.3.0.tar.gz ,you can also use `sudo apt install unixodbc ` to download but it's unuseful to my system + +```bash +tar -xzvf unixODBC-2.3.0.tar.gz + +cd unixODBC-2.3.0.tar.gz + +./configure --enable-gui=no + +make + +sudo make install + +odbc_config --version #check odbc_config is installed + +``` + +### download odbc-mariadb +{ + `sudo apt install odbc-mariadb` + +} + +### configure odbc-mariadb + +see complete info on "https://mariadb.com/kb/en/creating-a-data-source-with-mariadb-connectorodbc/" + +[MariaDB ODBC 3.0 Driver] +Description = MariaDB Connector/ODBC v.3.0 +Driver=/usr/lib/x86_64-linux-gnu/odbc/libmaodbc.so + + + +```bash +git clone #download nanodbc + +cd nanodbc #change to nanodbc dir + +mkdir build #Put compiler output in build file + +cd build #change to build dir + +cmake .. #generate Makefile + +make #generate other things you can add '-j4' after 'make' to make it faster + +sudo make install #add lib to your env + +``` +add these statements to your CMakeLists.txt + +```cmake +if (NOT TARGET nanodbc) + find_package(nanodbc CONFIG REQUIRED) +endif() + +#add exe here + +target_link_libraries(SRC nanodbc) + + + +------ + + + +## Compiler muduo + +```bash +git clone #download muduo + +cd muduo #change to muduo dir + +cp -r muduo ../cids-servser/include #copy include file to projectPath/include + +mkdir build #Put compiler output in build file + +cd build #change to build dir + +cmake .. #generate Makefile + +make #generate other things you can add '-j4' after 'make' to make it faster + +cd lib #change to lib dir + +cp * ../../../cids-servsers/lib #put lib file to projectPath/lib + +``` + +------ + + + +## now your project will like this: + +- cids-servsers + - include + - muduo + - net + - base + - nanodbc + - lib + - libxxx.a #7/10 lib files + + diff --git a/Src/Center/Center.cpp b/Src/Center/Center.cpp new file mode 100644 index 0000000..ecf12bd --- /dev/null +++ b/Src/Center/Center.cpp @@ -0,0 +1,450 @@ +#include + +void center::start() +{ + //任务队列最大数量 + pool_.setMaxQueueSize(30); + //用std::hard_ware_concurrency()确定硬件支持的最大并发数量, 该数量 * 2为此程序运行时占用线程数 + pool_.start(static_cast(2 * std::thread::hardware_concurrency())); + auto thd_start = [&](const char* info){ + std::clog << "thread start: " << info << std::endl; + }; + //提交定时读取配置文件的任务,监听cli登录, mir心跳的任务 + this->pool_.run( [this](){ read_config(); }); + thd_start("read config"); + this->pool_.run( [this](){ wait_cli_login(); }); + thd_start("wait cli login"); + this->pool_.run( [this](){ listen_mir_beat(); }); + thd_start("listen mir beat"); + this->pool_.run( [this](){ clear_mirs_data(); }); + thd_start("clear mir data"); + + //设置原子锁的值 + this->atom_mutex_ = false; + + //日志输出的文件和文件路径在telemeter命名空间下 + +} + +void center::read_config() +{ + static std::string config_file_path {"CenterConfig.txt"}; + static std::ifstream in {config_file_path, std::ios::in}; + Setting set {}; memset(&set, 0, sizeof(Setting)); + uint next_read_interval {15}; + + auto read_data = [&]() { + if(!in.is_open()) + in.open(config_file_path, std::ios::in); + std::string line {}; + while (in.good()) + { + std::getline(in, line, '\n'); + if(line.size() < 2 || line.front() == '/') + continue; + else if(line.find("next_read") != std::string::npos) + next_read_interval = std::stoi(std::string(line.begin() + line.find_first_of('[') + 1,line.begin() + line.find_first_of(']'))); + else if(line.find("load_record") != std::string::npos) + set.mir_load_record_interval_ = std::stoi(std::string(line.begin() + line.find_first_of('[') + 1,line.begin() + line.find_first_of(']'))); + else if(line.find("load_dblog") != std::string::npos) + set.mir_dblog_interval_ = std::stoi(std::string(line.begin() + line.find_first_of('[') + 1, line.begin() + line.find_first_of(']'))); + else if(line.find("max_disbeat") != std::string::npos) + set.mir_max_disbeat_time_ = std::stoi(std::string(line.begin() + line.find_first_of('[') + 1,line.begin() + line.find_first_of(']'))); + else if(line.find("login_cache") != std::string::npos) + set.cli_login_cache_time_ = std::stoi(std::string(line.begin() + line.find_first_of('[') + 1, line.begin() + line.find_first_of(']'))); + else if(line.find("balance") != std::string::npos) + set.load_balance_interval_ = std::stoi(std::string(line.begin() + line.find_first_of('[') + 1, line.begin() + line.find_first_of(']'))); + else if(line.find("clear_mirs") != std::string::npos) + set.clear_mirs_data_time_ = std::stoi(std::string(line.begin() + line.find_first_of('[') + 1, line.begin() + line.find_first_of(']'))); + } + }; + + auto swap = [](Setting* src, Setting* dst){ + Setting* tmp = dst; + dst = src; + src = tmp; + }; + + while(true) + { + //读取配置文件 + read_data(); + + //复制到配置副本中 + memcpy(telemeter::setting_copy, &set, sizeof(Setting)); + + //交换主副配置指针 + swap(telemeter::setting_copy, telemeter::setting); //atomic operation + + LOG_INFO << "read config, interval: " << next_read_interval << "s, current setting:"; + LOG_INFO << "load record interval: " << telemeter::setting->mir_load_record_interval_; + LOG_INFO << "load database interval: " << telemeter::setting->mir_dblog_interval_; + LOG_INFO << "load balance interval: " << telemeter::setting->load_balance_interval_; + LOG_INFO << "max disbeat interval: " << telemeter::setting->mir_max_disbeat_time_; + LOG_INFO << "clear mirs data time: " << telemeter::setting->clear_mirs_data_time_; + LOG_INFO << "login cache time: " << telemeter::setting->cli_login_cache_time_; + //挂起该进程 + sleep(next_read_interval); + } +} + +void center::wait_cli_login() +{ + static IP available_mir {0}; + static size_t login_count {0}; + auto load_balance_warpper = [&]() + { + available_mir = this->load_balance(); + }; + + //纠正树形结构中cli信息的任务, 将交给线程池异步执行 + auto correct_tree_structure = [&](uuid cli_id){ + LOG_INFO << "correct info in tree-like structure of client id: " << cli_id; + for(auto& kvp : mirs_data_) + { + if(kvp.second.contains(cli_id)) + { + kvp.second.erase_cli(cli_id); + } + } + + }; + + //用于接收数据的缓冲区 + std::array packet {0}; + std::array uidbuf {0}; + std::array statebuf {0}; + //创建socket + int sock_fd = socket(AF_INET, SOCK_DGRAM, 0); + //服务端addr和客户端addr, 后者保存发送方的信息 + struct sockaddr_in addr_serv, addr_cli; + + //初始化addr_serv, 无需初始化addr_cli + memset(&addr_serv, 0, sizeof(sockaddr_in)); + memset(&addr_cli, 0, sizeof(sockaddr_in)); + addr_serv.sin_family = AF_INET; //使用IPV4地址 + addr_serv.sin_port = htons(static_cast(port::kCLI_LOGIN_)); //端口 + /* INADDR_ANY表示不管是哪个网卡接收到数据,只要目的端口是SERV_PORT,就会被该应用程序接收到 */ + //int n = inet_aton("172.24.153.237", &addr_serv.sin_addr); + addr_serv.sin_addr.s_addr = htonl(INADDR_ANY); //自动获取IP地址 + unsigned int place_holder_1 = sizeof(addr_cli); + //const int place_holder_2 = 1; + + //进入循环前统一进行异常检测 + if(sock_fd < 0) + throw std::runtime_error("Init socket failed in port::kCLI_LOGIN_"); + //解决bind绑定失败的遗留 + //setsockopt(sock_fd,SOL_SOCKET,SO_REUSEADDR,&place_holder_2,sizeof(place_holder_2)); + int ret = bind(sock_fd, (sockaddr*)&addr_serv, sizeof(addr_serv)); + if(ret < 0) + throw std::runtime_error("Bind socket failed in port::kCLI_LOGIN_"); + + //线程主循环 + while(true) + { + char recv_buf[8]; + memset(recv_buf, 0, sizeof(recv_buf)); + int recv_num = recvfrom(sock_fd,recv_buf, protocol::kCLI_LOGIN_PACSIZE_, MSG_WAITALL, (sockaddr*)&addr_cli, &place_holder_1); + //MSG_WAITALL:要求阻塞操作,直到请求得到完整的满足。 + //如果捕捉到信号,错误或者连接断开发生,或者下次被接收的数据类型不同,仍会返回少于请求量的数据。 + + //可能是阻塞超时, 进行下次循环 + if(recv_num < 0){ + LOG_WARN << "recv from client error"; + continue; + } + + for(int i = 0; i < 8; i++) + packet[i] = recv_buf[i]; + //按照协议格式进行解析, 并且得到ip等其他信息 + memcpy(uidbuf.data(), packet.data(), protocol::kCLI_LOGIN_UID_); + for(auto& ch :uidbuf) + ch += '0'; + size_t uid = std::atol(uidbuf.data()); + memcpy(statebuf.data(), packet.data() + protocol::kCLI_LOGIN_UID_, protocol::kCLI_LOGIN_STATE_); + size_t state = statebuf[0]; + //state暂时不做处理 + + //是否在cookie中找到登陆记录 + bool cached {false}; + + //登录或者重新连接 + if(!this->cookie_.empty()) + { + while(true) + { + //空闲状态可以使用 + if(atom_mutex_ == false) + { + //进入临界区 + atom_mutex_ = true; + for(uuid cache : cookie_) + { + //找到登陆痕迹直接掠过 + if(cache == uid) + { + cached = true; + break; + } + } + //结束临界区 + atom_mutex_ = false; + break; + } + else //锁被pop队头或者push任务的任务使用中 + { + continue; + } + } + if(cached == true) + { + //此处应当分析包中state来统计网络不畅的情况, 暂时忽略 + continue; + } + } + + //cookie为空或者没有找到时, 记录cli登录信息 + if(cached == false) + { + if(this->mirs_data_.size() == 0) + memset(&available_mir, 0, sizeof(IP)); + else if(this->mirs_data_.size() == 1) + available_mir = (*mirs_data_.begin()).first; + //回复可用mir地址 + char send_buf[4] = {available_mir.seg0,available_mir.seg1,available_mir.seg2,available_mir.seg3}; + int send_num = sendto(sock_fd, send_buf, protocol::kCENT_RESPONSE_PACSIZE_, 0, (sockaddr*)&addr_cli, sizeof(addr_cli)); + login_count++; + + //数据库记录日志 + //dblog(cli_login, uid); + LOG_INFO << "client login, uid: " << uid << ", reply mirs ip: " << available_mir.to_string(); + if(this->all_cli_.count(uid) == 0) + this->all_cli_.insert(uid); + else + this->pool_.run(std::bind(correct_tree_structure, uid)); + while(true) + { + //空闲状态可以使用 + if(atom_mutex_ == false) + { + //进入临界区 + atom_mutex_ = true; + //这个push操作似乎不需要上锁 + cookie_.push_back(uid); + //结束临界区 + atom_mutex_ = false; + + //设置一段时间后pop掉队头的任务 + this->pool_.run( [this, &uid](){ + sleep(telemeter::setting->cli_login_cache_time_); + while(true) + { + if(atom_mutex_ == false) + { + atom_mutex_ = true; + uuid id = cookie_.front(); + cookie_.pop_front(); + atom_mutex_ = false; + LOG_INFO << "erase login cache of client: " << id; + } + else{ + LOG_INFO << "cached client login, no reply for client: " << uid; + continue; + } + + } + }); + break; + } + else //锁被pop队头或者查询任务使用中 + { + LOG_INFO << "cached client login, no reply for client : " << uid; + continue; + } + } + } + //重置输入缓冲区 + packet.fill(0); + + if(login_count >= telemeter::setting->load_balance_interval_) + { + //提交给线程池而不阻塞在io线程, 对available_mir的修改是跨线程操作变量 + this->pool_.run(load_balance_warpper); + login_count = 0; + } + } +} + +void center::listen_mir_beat() +{ + IP mir_ip {0}; //心跳的mir ip + size_t all_beat_count {0}; //用于判活算法 + + //用于接收数据的缓冲区 + std::array packet {0}; + std::array ipbuf {0}; + std::array loadbuf {0}; + //创建socket + int sock_fd = socket(AF_INET, SOCK_DGRAM, 0); + //服务端addr和客户端addr, 后者保存发送方的信息 + struct sockaddr_in addr_serv, addr_mir; + + //初始化addr_serv, 无需初始化addr_cli + memset(&addr_serv, 0, sizeof(sockaddr_in)); + memset(&addr_mir, 0, sizeof(sockaddr_in)); + addr_serv.sin_family = AF_INET; //使用IPV4地址 + addr_serv.sin_port = htons(port::kMIR_BEAT_); //端口 + /* INADDR_ANY表示不管是哪个网卡接收到数据,只要目的端口是SERV_PORT,就会被该应用程序接收到 */ + addr_serv.sin_addr.s_addr = htonl(INADDR_ANY); //自动获取IP地址 + unsigned int place_holder_1 = sizeof(addr_mir); + + //进入循环前统一进行异常检测 + if(sock_fd < 0) + throw std::runtime_error("Init socket failed in port::kMIR_BEAT_"); + if(bind(sock_fd, (sockaddr*)&addr_serv, sizeof(addr_serv)) < 0) + throw std::runtime_error("Bind socket failed in port::KMIR_BEAT_"); + + + //线程主循环 + while(true) + { + char recv_buf[8] = {0}; + memset(recv_buf, 0, sizeof(recv_buf)); + int recv_num = recvfrom(sock_fd, recv_buf, protocol::kMIR_BEAT_PACSIZE_, MSG_WAITALL, (sockaddr*)&addr_mir, &place_holder_1); + //MSG_WAITALL:要求阻塞操作,直到请求得到完整的满足。 + //如果捕捉到信号,错误或者连接断开发生,或者下次被接收的数据类型不同,仍会返回少于请求量的数据。 + + //可能是阻塞超时, 进行下次循环 + if(recv_num < 0) { + LOG_WARN << "recv from mirror error"; + continue; + } + + for(int i = 0; i < 8; i++) + packet[i] = recv_buf[i]; + //按照协议格式进行解析, 并且得到ip等其他信息 + memcpy(ipbuf.data(), packet.data(), protocol::kMIR_BEAT_IP_); + + memcpy(loadbuf.data(), packet.data() + protocol::kMIR_BEAT_IP_, protocol::kMIR_BEAT_LOAD_); + + mir_ip = IP(ipbuf[0], ipbuf[1], ipbuf[2], ipbuf[3]); + LOG_INFO << mir_ip.to_string() << " send packet " << packet.data(); + + if(mirs_data_.count(mir_ip) == 0) + { + mirs_data_.insert({mir_ip, MirDescript()}); + //dblog(MIR_LIGIN); + } + else + { + mirs_data_[mir_ip].reset_beat(telemeter::setting->mir_max_disbeat_time_); + //记录负载情况到缓存 + //mirs_data_[mir_ip].recordLoad(); + all_beat_count++; + if(all_beat_count >= mirs_data_.size() - 1) + { +// for(auto& kvp : mirs_data_) +// { +// if(kvp.second.decre_and_get_beat() <= 0); +// { +// //说明有mir掉线了 +// int i = 3; //占位避免编译器报warning +// //dblog(MIR_DISCONECT); +// mirs_data_.erase(kvp.first); +// LOG_INFO << "mirror disconnect: " << const_cast(&kvp.first)->to_string(); +// } +// } + } + } + + } +} + +void center::clear_mirs_data() +{ + auto get_next_zeropoint = [](){ + time_t t = time(NULL); + struct tm * tm= localtime(&t); + tm->tm_mday += 1; + tm->tm_hour = 0; + tm->tm_min = 0; + tm->tm_sec = 0; + return mktime(tm); + }; + + while(true) + { + sleep(get_next_zeropoint() - time(NULL) + telemeter::setting->clear_mirs_data_time_); + mirs_data_.clear(); + all_cli_.clear(); + LOG_INFO << "clear mirrors data successfully"; + } +} + +IP center::load_balance() +{ + LOG_INFO << "load balance occurs"; + //暂时不优化 + for(auto& kvp : mirs_data_) + { + if(kvp.second.get_load_level() == LoadLevel::light) + return kvp.first; + } + + for(auto& kvp : mirs_data_) + { + if(kvp.second.get_load_level() == LoadLevel::medium) + return kvp.first; + } + + for(auto& kvp : mirs_data_) + { + if(kvp.second.get_load_level() == LoadLevel::untapped) + { + kvp.second.set_load_level(LoadLevel::light); + return kvp.first; + } + } + + for(auto& kvp : mirs_data_) + { + if(kvp.second.get_load_level() == LoadLevel::heavy) + { + return kvp.first; + } + } + + //没有任何一个可用的服务器 + throw std::runtime_error("No available mir to dispatch"); +} + +void center::log_info(std::exception& e, const char* crush_file) +{ + //以后要改到json里面, 还缺详细个数的输出 + static std::ofstream log(crush_file, std::ios::out); + if(!log.is_open()) + log.open(crush_file, std::ios::out); + log <<"crush time: " << time(nullptr) <<"\nreason: " << e.what() << std::endl; + + log << "Mirrors & dispatched client:\n"; + for(auto& kvp : mirs_data_) + { + log << "ip: " << const_cast(&kvp.first)->to_string() + << " load state: " << tostring(kvp.second.get_load_level()) << '\n'; + log << "dispatched client: \n"; + for(auto uid : kvp.second.get_dispatched_cli()) + { + log << uid << '\n'; + } + } + + log << "cookie mutex: " << atom_mutex_ << '\n'; + if(cookie_.size() > 0) + { + log << "cookie :\n"; + for(auto uid : cookie_) + { + log << uid << '\n'; + } + } +} diff --git a/Src/Center/CenterMain.cpp b/Src/Center/CenterMain.cpp new file mode 100644 index 0000000..ee6095e --- /dev/null +++ b/Src/Center/CenterMain.cpp @@ -0,0 +1,19 @@ +#include + +#include + +int main() +{ + static const char* crush_log = "../crush.txt"; + + center ctr; + try + { + ctr.start(); + } + catch(std::exception& e) + { + std::cerr << e.what() << '\n'; + ctr.log_info(e, crush_log); + } +} diff --git a/Src/Center/MirDescript.cpp b/Src/Center/MirDescript.cpp new file mode 100644 index 0000000..e69de29 diff --git a/Src/Common/ServerBase.cpp b/Src/Common/ServerBase.cpp new file mode 100644 index 0000000..ee821af --- /dev/null +++ b/Src/Common/ServerBase.cpp @@ -0,0 +1,59 @@ +#include + +bool scu_time::operator=(const scu_time &rhs) { + return this->hour == rhs.hour && this->minute == rhs.minute; +} + +scu_time scu_time::operator-(const scu_time &rhs) const{ + size_t lMinute; + if (*this < rhs) + lMinute = (this->hour + 24) * 60 + this->minute; + else + lMinute = this->hour * 60 + this->minute; + size_t rMinute = rhs.hour * 60 + rhs.minute; + size_t nHour = (lMinute - rMinute) % 60; + size_t nMinute = (lMinute - rMinute) - nHour * 60; + return scu_time(nHour, nMinute); +} + +bool scu_time::operator<(const scu_time &rhs) const { + if (this->hour > rhs.hour) { + return false; + } else { + if (this->minute >= rhs.minute) { + return false; + } else { + return true; + } + } +} + +bool scu_time::operator<=(const scu_time &rhs) const { + if (this->hour > rhs.hour) { + return false; + } else { + if (this->minute > rhs.minute) + return false; + else + return true; + } +} + +unsigned scu_time::toSeconds() { + return this->hour * 3600 + this->minute * 60; +} + + +scu_time scu_time::toScutime(const muduo::Timestamp ×tamp){ + long allSeconds = std::stol(timestamp.toString()); + int seconds = allSeconds % 86400; + size_t hour = seconds / 3600; + size_t minute = (seconds - hour * 3600) / 60; + if(hour >= 16) + hour -= 16; + else + hour += 8; + return scu_time(hour, minute); +} + + diff --git a/Src/Mirror/Mirror.cpp b/Src/Mirror/Mirror.cpp new file mode 100644 index 0000000..086ac45 --- /dev/null +++ b/Src/Mirror/Mirror.cpp @@ -0,0 +1,759 @@ +#include + +//如果最后一节课.置空字符串+置零 +using std::placeholders::_1; +using std::placeholders::_2; +using std::placeholders::_3; + +void Mirror::init() { + + + auto judge_lesson_order = [this](const std::vector &time_table) -> size_t { + scu_time now{scu_time::toScutime(muduo::Timestamp::now())}; + if (now < time_table[0]) + return 0; + for (size_t i = 1; i < time_table.size(); i++) { + if (now < time_table[i]) + return i; + } + return 12; + }; + + //读取配置文件 + static std::string config_file_path = this->config_file_path; + + static std::ifstream in{config_file_path, std::ios::in}; + + if (!in.is_open()) + in.open(config_file_path, std::ios::in); + + std::string line{}; + + while (in.good()) { + std::getline(in, line, '\n'); + if (line.size() < 2 || line.front() == '/') + continue; + else if (line.find("mir_heart") != std::string::npos) + telemeter::setting->mir_heart_beat_interval = std::stoi( + std::string(line.begin() + line.find_first_of('[') + 1, line.begin() +line.find_first_of(']'))); + else if (line.find("mir_load") != std::string::npos) + telemeter::setting->mir_load_report_interval = std::stoi( + std::string(line.begin() +line.find_first_of('[') + 1,line.begin() + line.find_first_of(']'))); + else if (line.find("img_path") != std::string::npos) + telemeter::setting->img_path = std::string(line.begin() +line.find_first_of('[') + 1, line.begin() +line.find_first_of(']')); + else if (line.find("db_source") != std::string::npos) + telemeter::setting->db_source = std::string(line.begin() +line.find_first_of('[') + 1, line.begin() +line.find_first_of(']')); + else if (line.find("db_user") != std::string::npos) + telemeter::setting->db_user = std::string(line.begin() +line.find_first_of('[') + 1, line.begin() +line.find_first_of(']')); + else if (line.find("db_password") != std::string::npos) + telemeter::setting->db_password = std::string(line.begin() +line.find_first_of('[') + 1, line.begin() +line.find_first_of(']')); + else if (line.find("center_ip") != std::string::npos) + telemeter::setting->center_ip = std::string(line.begin() +line.find_first_of('[') + 1, line.begin() +line.find_first_of(']')); + else if (line.find("this_ip") != std::string::npos) + telemeter::setting->this_ip = std::string(line.begin() +line.find_first_of('[') + 1, line.begin() +line.find_first_of(']')); + else if (line.find("update_pic_interval") != std::string::npos) + telemeter::setting->update_pic_interval = std::stoi( + std::string(line.begin() +line.find_first_of('[') + 1,line.begin() + line.find_first_of(']'))); + else if (line.find("utc_time") != std::string::npos) + telemeter::setting->utc_time = std::stoi(std::string(line.begin() +line.find_first_of('[') + 1, line.begin() +line.find_first_of(']'))); + else if (line.find("update_calendar_time") != std::string::npos) + telemeter::setting->update_calendar_time = std::string(line.begin() +line.find_first_of('[') + 1, line.begin() +line.find_first_of(']')); + else if (line.find("clear_clients_time") != std::string::npos) + telemeter::setting->clear_clients_time = std::string(line.begin() +line.find_first_of('[') + 1, line.begin() +line.find_first_of(']')); + else if (line.find("course_interval") != std::string::npos) + telemeter::setting->course_interval = std::stoi( + std::string(line.begin() +line.find_first_of('[') + 1,line.begin() + line.find_first_of(']'))); + } + //初始化数据库 + this->conn = nanodbc::connection(telemeter::setting->db_source,telemeter::setting->db_user,telemeter::setting->db_password); + + //更新section + this->wj_section = judge_lesson_order(this->wj_Time); + this->ja_section = judge_lesson_order(this->ja_Time); + + //更新日期 + muduo::Timestamp now(muduo::Timestamp::now()); + std::string formattedTime = now.toFormattedString(false); + //获取年 + int year = std::stoi(formattedTime.substr(0, 4)); + //获取月 + int month = std::stoi(formattedTime.substr(4, 2)); + //获取日 + int date = std::stoi(formattedTime.substr(6, 2)); + //更新数据 + scu_date scudate = db_control::update_calendar(this->conn, year, month, date); + //更新至原子量 + this->day = scudate.day; + this->week = scudate.week; + + //下载图片缓存 + + + + std::vector backgrounds; + db_control::query_background(conn, backgrounds); + //数据 + + //循环 + for (auto iter = backgrounds.begin(); iter != backgrounds.end(); iter++) { + //解码 + 储存图片 + //路径 + std::string path = telemeter::setting->img_path + "/" + std::to_string(iter->PicId) + ".jpg"; + + + codec::downPic(path, iter->PicCode); + } + + +}; + +void Mirror::start() { + + + + //初始化配置文件及各数据 + this->init(); + + LOG_INFO << "init success"; + //任务队列最大数量 + pool_.setMaxQueueSize(30); + //用std::hard_ware_concurrency()确定硬件支持的最大并发数量, 该数量 * 2为此程序运行时占用线程数 + pool_.start(static_cast(2 * std::thread::hardware_concurrency())); + auto thd_start = [&](const char *info) { + std::clog << "thread start: " << info << std::endl; + }; + + //发送负载情况(Task2) + this->pool_.run([this]() { update_data_info(); }); + thd_start("update data info"); +// +// //更新数据缓存(Task3) +// this->pool_.run([this]() { update_clis_data(); }); +// thd_start("update clients data"); + + //读取配置文件(Task4) + this->pool_.run([this]() { read_config(); }); + thd_start("read config"); + + + this->pool_.run([this]() { clear_cli_data(); }); + thd_start("clear cli data"); + + this->pool_.run([this]() { update_course_section(); }); + thd_start("update_course_section"); + + this->pool_.run([this]() { update_school_calendar(); }); + thd_start("update school calendar"); + + this->pool_.run([this]() { update_pictures_info(); }); + thd_start("update_pictures_info"); + + //TCP相关(Task6) + this->listen_cli_beat(); + thd_start("listen client beat"); + //输出日志 +} + + +void Mirror::update_data_info() { + + // 发送‘心跳包’ + int sock; + if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) + std::cerr << "sock error" << std::endl; + struct sockaddr_in servaddr; + memset(&servaddr, 0, sizeof(servaddr)); + servaddr.sin_family = AF_INET; +// 设置发送端口 + servaddr.sin_port = htons(port::kMIR_BEAT_); +// 设置发送ip +/*修改:若发送失败,则沿用之前的ip*/ + servaddr.sin_addr.s_addr = inet_addr((telemeter::setting->center_ip).c_str()); + + // 更新间隔 + size_t time = 0; + // 发送消息 + char send_buf[8] = {0}; +// 定义计算服务器负载情况的函数 + auto cal_ser_load = [&]() -> uint8_t { + return '0'; + }; + +// 定义计算内存负载情况的函数 + auto cal_mem_load = [&]() -> uint8_t { + std::ifstream in; + std::string filename = ""; + return '0'; + }; + +// 定义计算网络负载情况的函数 + auto cal_net_load = [&]() -> uint8_t { + return '0'; + }; + + auto get_packet = [&]() { + + IP this_ip(telemeter::setting->this_ip); + + //calculate ServerLoad + unsigned char serverLoad = cal_ser_load(); + + // DtlLoadState.serve_load = serverLoad; + //calculate MemoryLoad + unsigned char memLoad = cal_mem_load(); +// DtlLoadState.mem_load = memLoad; + //calculate NetworkLoad + unsigned char netLoad = cal_net_load(); +// DtlLoadState.net_load_ = netLoad; + +//this_ip + std::vector ret; + ret.push_back(this_ip.seg0); + ret.push_back(this_ip.seg1); + ret.push_back(this_ip.seg2); + ret.push_back(this_ip.seg3); + ret.push_back(serverLoad); //服务器负载 + ret.push_back(memLoad); //内存负载 + ret.push_back(netLoad); //网络负载 + ret.push_back('\0'); + return ret; + }; + + //重置缓冲 + memset(send_buf, 0, sizeof(send_buf)); + + //获取负载情况 + std::vector info = get_packet(); + + //更新负载情况 + for (int i = 0; i < 7; i++) + send_buf[i] = info[i]; + + //最后位填充0 + send_buf[7] = '\0'; + + //重置time + time = 1; + + +//线程主循环 + while (true) { + + if (time == telemeter::setting->mir_load_report_interval) { + //to_string(8byte) = 4+1+1+1+1 true/false + //重置缓冲 + memset(send_buf, 0, sizeof(send_buf)); + //获取负载情况 + std::vector info = get_packet(); + //更新负载情况 + for (int i = 0; i < 7; i++) + send_buf[i] = info[i]; + //最后位填充0 + send_buf[7] = '\0'; + //重置time + time = 1; + + } + +// 发送缓存 + sendto(sock, send_buf, protocol::kMIR_BEAT_PACSIZE_, 0, (struct sockaddr *) &servaddr, sizeof(servaddr)); + // 统计发送心跳包次数 + time++; + //心跳包频率 + sleep(telemeter::setting->mir_heart_beat_interval); + } +} +//定时拉取数据库信息, 更新时间戳 + +//读取配置文件 +void Mirror::read_config() { + + +// 后可以考虑使用json格式 + static std::string config_file_path = this->config_file_path; + static std::ifstream in{config_file_path, std::ios::in}; + Setting set{}; + size_t next_read_interval{0}; + + auto read_data = [&]() { + if (!in.is_open()) + in.open(config_file_path, std::ios::in); + std::string line{}; + while (in.good()) { + std::getline(in, line, '\n'); + if (line.size() < 2 || line.front() == '/') + continue; + else if (line.find("next_read") != std::string::npos) + next_read_interval = std::stoi(std::string(line.begin() +line.find_first_of('[') + 1, line.begin() +line.find_first_of(']'))); + else if (line.find("mir_heart") != std::string::npos) + set.mir_heart_beat_interval = std::stoi( + std::string(line.begin() +line.find_first_of('[') + 1,line.begin() + line.find_first_of(']'))); + else if (line.find("mir_load") != std::string::npos) + set.mir_load_report_interval = std::stoi( + std::string(line.begin() +line.find_first_of('[') + 1,line.begin() + line.find_first_of(']'))); + else if (line.find("img_path") != std::string::npos) + set.img_path = std::string(line.begin() +line.find_first_of('[') + 1, line.begin() +line.find_first_of(']')); + else if (line.find("db_source") != std::string::npos) + set.db_source = std::string(line.begin() +line.find_first_of('[') + 1,line.begin() + line.find_first_of(']')); + else if (line.find("db_user") != std::string::npos) + set.db_user = std::string(line.begin() +line.find_first_of('[') + 1,line.begin() + line.find_first_of(']')); + else if (line.find("db_password") != std::string::npos) + set.db_password = std::string(line.begin() +line.find_first_of('[') + 1,line.begin() + line.find_first_of(']')); + else if (line.find("center_ip") != std::string::npos) + set.center_ip = std::string(line.begin() +line.find_first_of('[') + 1, line.begin() +line.find_first_of(']')); + else if (line.find("this_ip") != std::string::npos) + telemeter::setting->this_ip = std::string(line.begin() +line.find_first_of('[') + 1, line.begin() +line.find_first_of(']')); + else if (line.find("update_pic_interval") != std::string::npos) + set.update_pic_interval = std::stoi(std::string(line.begin() +line.find_first_of('[') + 1, line.begin() +line.find_first_of(']'))); + else if (line.find("utc_time: ") != std::string::npos) + set.utc_time = std::stoi(std::string(line.begin() +line.find_first_of('[') + 1, line.begin() +line.find_first_of(']'))); + else if (line.find("update_calendar_time:") != std::string::npos) + set.update_calendar_time = std::string(line.begin() +line.find_first_of('[') + 1, line.begin() +line.find_first_of(']')); + else if (line.find("clear_clients_time:") != std::string::npos) + set.clear_clients_time = std::string(line.begin() +line.find_first_of('[') + 1, line.begin() +line.find_first_of(']')); + else if (line.find("course_interval:") != std::string::npos) + set.course_interval = std::stoi(std::string(line.begin() +line.find_first_of('[') + 1, line.begin() +line.find_first_of(']'))); + + } + }; + + + auto swap = [](Setting *src, Setting *dst) { + Setting *tmp = dst; + dst = src; + src = tmp; + }; + + //主任务 + while (true) { + //读取配置文件 + read_data(); + + //复制到配置副本中 + *telemeter::setting_copy = set; + + //交换主副配置指针 + swap(telemeter::setting_copy, telemeter::setting); //atomic operation + + //挂起该进程 + sleep(next_read_interval); + } +} + +//清除mirror->client树信息 +void Mirror::clear_cli_data() { + + auto get_seconds_from_now = [&](const scu_time &time) { + scu_time nowTime = scu_time::toScutime(muduo::Timestamp::now()); + return time <= nowTime ? 0 : (time - nowTime).toSeconds(); + }; + + while (true) { + + //加锁 + Class2Campus.clear(); + + cli_info_.clear(); + + //配置文件读取upload,time + std::string clear_time = telemeter::setting->clear_clients_time; + int index = clear_time.find_last_of(":"); + //获取小时 + int hour = std::stoi(clear_time.substr(0, index)); + //获取分钟 + int minute = std::stoi(clear_time.substr(index + 1)); + + sleep(get_seconds_from_now(scu_time(hour, minute))); + //每日24时更新 + } +} + +//定时 更新课程节次信息,包括江安与望江 +//更新course间隔 +void Mirror::update_course_section() { + + auto judge_lesson_order = [this](const std::vector &time_table) -> size_t { + scu_time now{scu_time::toScutime(muduo::Timestamp::now())}; + if (now < time_table[0]) + return 0; + for (size_t i = 1; i < time_table.size(); i++) { + if (now < time_table[i]) + return i; + } + return 12; + }; + + + while (true) { + wj_section = judge_lesson_order(this->wj_Time); + ja_section = judge_lesson_order(this->ja_Time); + + sleep(telemeter::setting->course_interval); + } +} + +//定时 更新校历信息 +void Mirror::update_school_calendar() { + auto get_seconds_from_now = [&](const scu_time &time) { + scu_time nowTime = scu_time::toScutime(muduo::Timestamp::now()); + return time <= nowTime ? 0 : (time - nowTime).toSeconds(); + }; + while (true) { + //获取当前时间 + muduo::Timestamp now(muduo::Timestamp::now()); + std::string formattedTime = now.toFormattedString(false); + //获取年 + int year = std::stoi(formattedTime.substr(0, 4)); + //获取月 + int month = std::stoi(formattedTime.substr(4, 2)); + //获取日 + int date = std::stoi(formattedTime.substr(6, 2)); + //更新数据 + scu_date scudate = db_control::update_calendar(this->conn, year, month, date); + //更新至原子量 + day = scudate.day; + week = scudate.week; + //配置文件读取upload,time + + std::string update_time = telemeter::setting->update_calendar_time; + int index = update_time.find_last_of(":"); + //获取小时 + int hour = std::stoi(update_time.substr(0, index)); + //获取分钟 + int minute = std::stoi(update_time.substr(index + 1)); + + sleep(get_seconds_from_now(scu_time(hour, minute))); + //每日24时更新 + } +} + +//待修改配置文件 +void Mirror::update_pictures_info() { + + scu_time nowtime = scu_time::toScutime(muduo::Timestamp::now()); + //从6/12/18点开始更新 + if (nowtime < scu_time(6, 0)) + sleep((scu_time(6, 0) - nowtime).toSeconds()); + else if (nowtime < scu_time(12, 0)) + sleep((scu_time(12, 0) - nowtime).toSeconds()); + else if (nowtime < scu_time(18, 0)) + sleep((scu_time(18, 0) - nowtime).toSeconds()); + else + sleep((scu_time(24, 0) - nowtime).toSeconds()); + + while (true) { + //查询数据库 + + std::vector backgrounds; + + db_control::query_background(conn, backgrounds); + //图片信息与 + //数据 + //循环 + for (auto iter = backgrounds.begin(); iter != backgrounds.end(); iter++) { + //解码 + 储存图片 + //路径 + std::string path = telemeter::setting->img_path + "/" + std::to_string(iter->PicId) + ".jpg"; + + codec::downPic(path, iter->PicCode); + } + + sleep(telemeter::setting->update_pic_interval * 60 * 60); + } + +} + +//多并发 +void Mirror::listen_cli_beat() { + muduo::net::EventLoop loop_; + muduo::net::TcpServer server_(&loop_, muduo::net::InetAddress(port::kCLI_BEAT_), ""); + //set server.onConnect 连接函数 + server_.setMessageCallback(std::bind(&Mirror::on_message, this, _1, _2, _3)); + server_.start(); + loop_.loop(); +} + +//更新参数, 如Scu_date与scu_time->skjc + + +//待修改配置时间 +void Mirror::on_message(const muduo::net::TcpConnectionPtr &connectionPtr, + muduo::net::Buffer *msg, + muduo::Timestamp time) { + std::string src = msg->retrieveAllAsString(); + Cli::Uuid id; + std::string timeStamp; + json_control::getIdAndStamp(src, id, timeStamp); + OldHash old; + //查找到旧数据的哈希值 + if (this->cli_info_.find(id) != this->cli_info_.end()) { + old = this->cli_info_[id]; + } else { + std::deque msgs; + msgs.push_back(0); + OldHash temp_hush; + temp_hush.url_ = 0; + temp_hush.event_ = 0; + temp_hush.next_event_ = 0; + temp_hush.msgs_ = msgs; + this->cli_info_.insert(std::pair(id, temp_hush)); + old = this->cli_info_[id]; + } + + //去数据库中查询新数据 + std::string now_stamp = muduo::Timestamp::now().toString(); + //分析当前的时间戳 + unsigned long stamp = std::stoul(now_stamp); + stamp -= telemeter::setting->utc_time * 60 * 60;//(UTC+8h) //误差时间 + + int course_section; + if (Class2Campus.find(id) == Class2Campus.end()) { + CliDes new_des; + new_des.id = id; + new_des.campus = db_control::find_campus(this->conn, id); + new_des.stamp = now_stamp; + Class2Campus.insert(std::pair(id, new_des)); + } + + if (Class2Campus[id].campus == 3) { //江安校区 + course_section = this->ja_section; + } else { + course_section = this->wj_section; + } + + bool next_event = true; + if (course_section == 4 || course_section == 9 || course_section == 12) + next_event = false; + + + std::string pic_url = "http://" + telemeter::setting->this_ip + ":" + std::to_string(port::kMIR_HTTP_) + telemeter::setting->img_path + "/" + db_control::find_pic(this->conn, id) + ".jpg"; + + std::deque msgs = db_control::find_mes(this->conn, id, std::to_string(stamp)); //统一utc时间 + + Lesson lesson_1 = db_control::find_lesson(this->conn, id, course_section, scu_date(this->week, this->day)); + Lesson lesson_2; + if (next_event) { + lesson_2 = db_control::find_lesson(this->conn, id, course_section + 1, scu_date(this->week, this->day)); + } + OldHash new_hash; + new_hash.url_ = std::hash()(pic_url); + new_hash.event_ = std::hash()(lesson_1); + new_hash.next_event_ = std::hash()(lesson_2); + std::deque msgs_hash; + for (auto iter = msgs.begin(); iter != msgs.end(); iter++) { + msgs_hash.push_back(std::hash()(*iter)); + } + + if (new_hash == old) { + connectionPtr->send(json_control::no_need_update); + + }else { + cli_info_[id] = new_hash; + ClassMes sendInfo; + sendInfo.image_url = pic_url; + sendInfo.messages = msgs; + sendInfo.lesson_1 = lesson_1; + sendInfo.lesson_2 = lesson_2; + std::string info = json_control::getJsonInfo(sendInfo, now_stamp); + connectionPtr->send(info); + } + +} + + +//暂停该函数 +/* +void Mirror::update_clis_data() { + //cli-classinfo缓存 + std::unordered_map clis_data; + +// 校园日历 + scu_date sD{1, 1}; + scu_date sD_1{1, 1}; + scu_date *scuDate = &sD; + scu_date *scuDate_copy = &sD_1; + + scu_date scuDate_cache{}; + + scu_time nowTime{0, 0}; + + auto swap_scu_date_ptr = [&]() { + scu_date *tmp = scuDate; + scuDate_copy = scuDate; + scuDate = tmp; + }; + +//写当日date(其实不会出现冲突.但为以后消费者模型做准备工作) + auto update_scu_date = [&]() { +//更新当日上课信息 + db_control::check_week_and_day(conn, scuDate_cache); +//复制至副本 + memcpy(scuDate_copy, &scuDate_cache, sizeof(scu_date)); +//交换指针 + swap_scu_date_ptr(); + }; + +// 判断时间 + auto at_middle = [&](const scu_time &lTime, const scu_time &rTime) { + return (lTime <= nowTime) && (nowTime < rTime); + }; + + auto get_seconds_from_now = [&](const scu_time &time) { + nowTime = scu_time::toScutime(muduo::Timestamp::now()); + return time <= nowTime ? 0 : (time - nowTime).toSeconds(); + }; + + auto query_scu_time = [&](int &xqh, int &jc) -> scu_time { +// 获取迭代器,遍历时间表 + + auto iter1 = this->wj_Time.begin(); + auto iter2 = this->ja_Time.begin(); +// 上课节次,用于返回 + int skjc = 0; + + nowTime = scu_time::toScutime(muduo::Timestamp::now());//获取当前时间,进行分析 + + for (; iter1 != wj_Time.end(); iter1++, iter2++) { + skjc++; + jc = skjc; + if (skjc <= 4) { + if (nowTime <= *iter1) { + xqh = 1; + return scu_time(0, 15); + } else { + if (nowTime <= *iter2) { + xqh = 3; + if (skjc == 4) + return scu_time(2, 40); + else + return scu_time(0, 40); + } else { + continue; + } + } + } else { + if (nowTime <= *iter2) { + xqh = 3; + return scu_time(0, 10); + } else { + if (nowTime <= *iter1) { + xqh = 1; + if (skjc == 9) //晚餐 + return scu_time(1, 30); + else if (skjc == 7) + return scu_time(0, 55); + else if (skjc == 12) + return scu_time(0, 0); + else + return scu_time(0, 45); + } else { + continue; + } + } + } + } + return scu_time::toScutime(muduo::Timestamp::now()); + }; + + +// 自动计算当前时间 + auto query_clis_data = [&, this]() { + std::unordered_map clis_data_cache_; + bool two_lessons = true; + int xqh = 0; //校区号 + int jc = 0; //时间 + + auto update_uC_map = [](const std::unordered_map &data_map, + std::unordered_map *origin_map, + std::unordered_map *copy_map) { + //赋值 + *copy_map = data_map; +// 交换指针 + auto tmp = copy_map; + copy_map = origin_map; + origin_map = tmp; + }; + + + //获取应当更新的校区号与节次 + scu_time wait_time = query_scu_time(xqh, jc); + + if (jc == 4 || jc == 9 || jc == 12) + two_lessons = false; + size_t wait_second = wait_time.toSeconds(); + if (xqh == 1) { +// 更新值 +// 参数: 连接参数, 这节课节次,查询两节课信息, 要查询的uuid集合 + clis_data_cache_ = *(this->wj_clis_data_); +// 参数: 连接参数, 这节课节次,查询两节课信息, 要查询的uuid集合 + db_control::query_lessons(conn, jc, two_lessons, clis_data_cache_, scuDate); +// 获取当前时间戳 + muduo::Timestamp nTime = muduo::Timestamp::now(); +// 更新时间戳 + update_timestamp(nTime, wj_timestamp_, wj_timestamp_copy); + // 交换指针 + + update_uC_map(clis_data_cache_, this->wj_clis_data_, this->wj_clis_data_copy); + } else if (xqh == 3) { +// 更新值 + clis_data_cache_ = *ja_clis_data_; +// 参数: 连接参数, 这节课节次,查询两节课信息, 要查询的uuid集合 + db_control::query_lessons(conn, jc, two_lessons, clis_data_cache_, scuDate); +// 获取当前时间戳 + muduo::Timestamp nTime = muduo::Timestamp::now(); +// 更新时间戳 + update_timestamp(nTime, ja_timestamp_, ja_timestamp_copy); +// 交换指针 + update_uC_map(clis_data_cache_, this->ja_clis_data_, this->ja_clis_data_copy); + } + + return wait_second; + }; + +// mirror开机时,初始化当时时间 + update_scu_date(); + muduo::Timestamp nTime = muduo::Timestamp::now(); + nowTime = scu_time::toScutime(nTime); + + +// 进入任务线程阶段 + while (true) { +// 挂起. 7.55唤醒 + sleep(get_seconds_from_now(scu_time(7, 55))); + + while (true) { + nowTime = scu_time::toScutime(muduo::Timestamp::now());//记录当前时间 + size_t sleepSeconds = 0; + sleepSeconds = query_clis_data(); //更新数据,在函数体内自动计算时间 + + if (sleepSeconds == 0) + break; + //休眠至下一次更新 + sleep(sleepSeconds); + } + sleep(get_seconds_from_now(scu_time(24, 0)) ); //沉睡至24点 +// 24点更新当日上课信息 + update_scu_date(); + } + + +} +*/ + + +/* +void Mirror::update_timestamp(const muduo::Timestamp &dataStamp, muduo::Timestamp *origin_campus_stamp, + muduo::Timestamp *copy_campus_stamp) { + + // 赋值 + *copy_campus_stamp = dataStamp; + +// 交换指针 + auto swap = [](muduo::Timestamp *origin, muduo::Timestamp *copy) { + muduo::Timestamp *tmp = origin; + origin = copy; + copy = tmp; + }; + swap(origin_campus_stamp, copy_campus_stamp); +} +*/ \ No newline at end of file diff --git a/Src/Mirror/MirrorMain.cpp b/Src/Mirror/MirrorMain.cpp new file mode 100644 index 0000000..fd29af6 --- /dev/null +++ b/Src/Mirror/MirrorMain.cpp @@ -0,0 +1,18 @@ +#include + +#include + +int main() +{ + static const char* crush_log = "../crush.txt"; + + Mirror mir; + try + { + mir.start(); + } + catch(const std::exception& e) + { + LOG_WARN << "some error happens " << e.what() << '\n'; + } +} diff --git a/Src/Mirror/codec_lib.cpp b/Src/Mirror/codec_lib.cpp new file mode 100644 index 0000000..2eb9524 --- /dev/null +++ b/Src/Mirror/codec_lib.cpp @@ -0,0 +1,23 @@ +#include +#include +#include + +namespace codec { + using base64 = cppcodec::base64_rfc4648; + + void downPic( const std::string &path,const std::string &code) { + //打开文件 + std::ofstream ofs(path, std::ios::trunc | std::ios::binary); + //异常处理 + if (!ofs) { + ofs.open(path, std::ios::trunc | std::ios::binary); + } + //解码 + std::vector buff = base64::decode(code); + //写入文件 + ofs.write(reinterpret_cast(buff.data()), buff.size()); + //关闭文件 + ofs.close(); + } + +} \ No newline at end of file diff --git a/Src/Mirror/db_lib.cpp b/Src/Mirror/db_lib.cpp new file mode 100644 index 0000000..7808ef6 --- /dev/null +++ b/Src/Mirror/db_lib.cpp @@ -0,0 +1,277 @@ +#include +#include + +namespace db_control { + + using Cli::Uuid; + + /* + void check_week_and_day(nanodbc::connection conn, scu_date &date) { + if (date.day == 7) { + date.week += 1; + date.day = 1; + } else { + date.day += 1; + } + } +*/ + /* + * param CCmap uuid->ClassMes + * param skjc 上课节次 + * + */ +/*暂停使用 + void + query_lessons(nanodbc::connection conn, size_t skjc, bool two_lesson, std::unordered_map &CCmap, + scu_date *date, Uuid id) { + size_t week = date->week; //第几周 + size_t day = date->day; //星期几 + bool new_client = false; + std::string find_stmt{}; + + std::string uuid_stmt{}; + + if (id < 0) { + auto iter = CCmap.begin(); + uuid_stmt += "( U.uuid = " + std::to_string(iter->first); + for (auto iter = CCmap.begin(); iter != CCmap.end(); iter++) { + uuid_stmt += " OR\n U.uuid = "; + uuid_stmt += std::to_string(iter->first); + } + uuid_stmt += ") AND\n"; + } else { + uuid_stmt = std::string("U.uuid = " + std::to_string(id)); + new_client = true; + } + auto get_find_stmt = [&](size_t skJc) { + find_stmt = std::string(std::string("SELECT\n" + "U.uuid AS uuid,\n" + "P.kch AS `kch`,\n" + "P.kxh AS `kxh`,\n" + "K.kcm AS `kcm`,\n" + "P.jsxm AS `jsxm`,\n" + "P.jxdd AS `jdxx`,\n" + "p.jsszxqh AS `jsszxqh`\n" + "FROM\n" + "uuid_jxdd AS U\n" + "INNER JOIN pksj AS P ON U.jxdd = P.jxdd AND U.jsszxqh = P.jsszxqh\n" + "INNER JOIN kcb AS K ON P.kch = K.kch\n" + "WHERE\n") + + uuid_stmt + + "P.sksj <= " + std::to_string(skJc) + " AND\n" + "P.sksj+P.cxjc\t >= " + std::to_string(skJc) + + " AND\n" + + "P.skxq = " + std::to_string(day) + " AND\n" + + "SUBSTR(qsz," + + std::to_string(week) + ",1)=\'1\'"); + }; + + auto update_map = [&](size_t jc, bool first, bool new_cli = false) { + get_find_stmt(skjc); + try { + nanodbc::result find_row = nanodbc::execute(conn, find_stmt); + for (; find_row.next();) { + int uid = find_row.get(0); + + if (new_cli) { + int xqh = find_row.get(6); + std::string dd = find_row.get(5); + ClassPlace cp; + cp.jxdd_ = dd; + cp.jsszxqh = xqh; + ClassMes ci; + ci.classPlace_ = cp; + CCmap.insert(std::make_pair(id, ci)); + } + + if (CCmap.find(uid) != CCmap.end()) { + Lesson les = Lesson(find_row.get(1), find_row.get(2), + find_row.get(3), find_row.get(4), + find_row.get(5)); + if (first) + CCmap.at(uid).lesson_1 = les; + else + CCmap.at(uid).lesson_2 = les; + } else { + continue; + } + } + } catch (const std::exception &e) { + std::cerr << e.what() << std::endl; //更换为日志报错 + } + }; + +// 更新当前节次 + update_map(skjc, true, new_client); + if (two_lesson) { +// 更新下一节次 + update_map(skjc + 1, false, new_client); + } + + } +*/ + void query_background(nanodbc::connection &conn, std::vector &backgrounds) { + //查询所有 + std::string sel_stmt = "SELECT * FROM backgrounds"; + //执行语句 + nanodbc::result find_row = nanodbc::execute(conn, sel_stmt); + + for (; find_row.next();) { + int id = find_row.get(0); + std::string code = find_row.get(1); + std::string des = find_row.get(2); + + backgrounds.emplace_back(id, code, des); + } + + } + + std::string find_pic(nanodbc::connection &conn, Cli::Uuid id) { + nanodbc::statement statement(conn); + + nanodbc::prepare(statement, std::string("SELECT background FROM places WHERE UUID = ?")); + + statement.bind(0, &id); + + nanodbc::result row = nanodbc::execute(statement); + + while (row.next()) { + return row.get(0); + } + return ""; + } + + std::deque find_mes(nanodbc::connection &conn, Cli::Uuid id, const std::string &stamp) { + //准备结果 + std::deque res; + + nanodbc::statement statement(conn); + + nanodbc::prepare(statement, + std::string("SELECT title, expiretime, text FROM msg WHERE uuid = ? AND starttime = ? ;")); + + statement.bind(0, &id); + statement.bind(1, stamp.c_str()); + + nanodbc::result row = nanodbc::execute(statement); + + while (row.next()) { + Message mes; + mes.title = row.get(0); + mes.expireTime = row.get(1); + mes.text = row.get(2); + res.push_back(mes); + } + + return res; + } + + Lesson find_lesson(nanodbc::connection &conn, Cli::Uuid id, int skjc, const scu_date &date) { + //准备结果 + Lesson ret; + + std::string teacher_name; + + nanodbc::statement statement(conn); + + nanodbc::prepare(statement, + std::string("SELECT\n" + "U.UUID AS uuid,\n" + "P.kch AS kch,\n" + "P.kxh AS kxh,\n" + "K.kcm AS kcm,\n" + "P.jsxm AS jsxm,\n" + "P.jxdd AS jxdd,\n" + "P.jsszxqh AS jsszxqh\n" + "FROM\n" + "places AS U\n" + "INNER JOIN pksj AS P ON U.place = P.jxdd \n" + "INNER JOIN kcb AS K ON P.kch = K.kch\n" + "WHERE U.UUID = ?\n" + "AND \n" + "P.sksj <= ? AND\n" + "P.sksj + P.cxjc > ? AND\n" + "P.skxq = ? AND\n" + "SUBSTR(qsz,?,1)=1")); + + statement.bind(0, &id); + statement.bind(1, &skjc); + statement.bind(2, &date.day); + statement.bind(3, &date.day); + statement.bind(4, &date.week); + + + nanodbc::result row = nanodbc::execute(statement); + + for (int i = 0; row.next(); i++) { + + if (i != 0) { + teacher_name += ","; + } + ret.kch_ = row.get(1); + ret.kxh_ = row.get(2); + ret.kcm_ = row.get(3); + teacher_name += row.get(4); + ret.jxdd_ = row.get(5); + } + ret.jsxm_ = teacher_name; + + return ret; + } + + int find_campus(nanodbc::connection &conn, Cli::Uuid id) { + + int ret; + + nanodbc::statement statement(conn); + + nanodbc::prepare(statement, std::string("SELECT \n" + "distinct P.jsszxqh AS campus \n" + "FROM pksj AS P\n" + "INNER JOIN places AS PL ON P.jxdd = PL.place\n" + "WHERE PL.UUID = ?")); + + statement.bind(0, &id); + + nanodbc::result row = nanodbc::execute(statement); + + while (row.next()) { + ret = row.get(0); + } + + return ret; + } + + scu_date update_calendar(nanodbc::connection &conn, int year, int month, int date) { + + int week; + int day; + + nanodbc::statement statement(conn); + + nanodbc::prepare(statement, std::string("SELECT \n" + "now_week,\n" + "now_day\n" + "FROM\n" + "calendar\n" + "WHERE\n" + "year = ? AND\n" + "month = ? AND\n" + "date = ?")); + + statement.bind(0, &year); + statement.bind(1, &month); + statement.bind(2, &date); + + nanodbc::result row = nanodbc::execute(statement); + + while (row.next()) { + week = row.get(0); + day = row.get(1); + } + + return scu_date(week,day); + } + + +} diff --git a/Src/Mirror/json_lib.cpp b/Src/Mirror/json_lib.cpp new file mode 100644 index 0000000..d610ce8 --- /dev/null +++ b/Src/Mirror/json_lib.cpp @@ -0,0 +1,120 @@ +#include + +namespace json_control { + + std::string no_need_update = "{\"needUpdate\":false}"; + + void getJson(rapidjson::Writer &writer, const Message &mes) { + //开启对象 + writer.StartObject(); + //title + writer.Key("Title"); + writer.String(mes.title.c_str()); + + //text + writer.Key("text"); + writer.String(mes.text.c_str()); + + //expiretime + writer.Key("expireTime"); + writer.Int(mes.expireTime); + + //结束对象 + writer.EndObject(); + } + + void getJson(rapidjson::Writer &writer, const Lesson &les) { + //开始对象 + writer.StartObject(); + + //课程号 + writer.Key("kch"); + writer.String(les.kch_.c_str()); + + //课序号 + writer.Key("kxh"); + writer.Int(les.kxh_); + + //课程名 + writer.Key("kcm"); + writer.String(les.kcm_.c_str()); + + //教师姓名 + writer.Key("jsxm"); + writer.String(les.jsxm_.c_str()); + + //教学地点 + writer.Key("jxdd"); + writer.String(les.jxdd_.c_str()); + + //结束对象 + writer.EndObject(); + } + + std::string getJsonInfo(const ClassMes &mes, const std::string ×tamp) { + rapidjson::StringBuffer strBuf; + rapidjson::Writer writer(strBuf); + //声明strBuf与writer对象 + + //开启json对象 + writer.StartObject(); + + //时间戳 + writer.Key("time"); + writer.String(timestamp.c_str()); + + //图像的url + writer.Key("image_url"); + writer.String(mes.image_url.c_str()); + + //消息队列 + writer.Key("message"); + //开启数组 + writer.StartArray(); + for (auto iter = mes.messages.begin(); iter != mes.messages.end(); iter++) { + getJson(writer, *iter); + } + //结束数组 + writer.EndArray(); + + //第一节课信息 + writer.Key("event"); + + getJson(writer, mes.lesson_1); + + //第二节课信息 + writer.Key("next_event"); + + getJson(writer, mes.lesson_2); + + //需要更新 + writer.Key("needUpdate"); + writer.Bool(true); + + //结束json对象 + writer.EndObject(); + + std::string json = strBuf.GetString(); + + return json; + } + + void getIdAndStamp(const std::string &src, Cli::Uuid &id, std::string &stamp) { + +// 解析document + rapidjson::Document document; + document.Parse(src.c_str()); + +// 分析获取id和stamp + rapidjson::Value::ConstMemberIterator iter = document.FindMember("UUID"); + if (iter != document.MemberEnd()) { + id = std::stoi(iter->value.GetString()); + } + + iter = document.FindMember("time"); + if (iter != document.MemberEnd()) { + stamp = iter->value.GetString(); + } + + } +}//End namespace of json_control diff --git a/cmake-build-debug/CMakeCache.txt b/cmake-build-debug/CMakeCache.txt new file mode 100644 index 0000000..1962d1a --- /dev/null +++ b/cmake-build-debug/CMakeCache.txt @@ -0,0 +1,423 @@ +# This is the CMakeCache file. +# For build in directory: d:/2021_2/cids-server/cmake-build-debug +# It was generated by CMake: C:/Users/XM/AppData/Local/JetBrains/Toolbox/apps/CLion/ch-0/211.7142.21/bin/cmake/win/bin/cmake.exe +# You can edit this file to change values found and used by cmake. +# If you do not want to change any of the values, simply exit the editor. +# If you do want to change a value, simply edit, save, and exit the editor. +# The syntax for the file is as follows: +# KEY:TYPE=VALUE +# KEY is the name of a variable in the cache. +# TYPE is a hint to GUIs for the type of VALUE, DO NOT EDIT TYPE!. +# VALUE is the current value for the KEY. + +######################## +# EXTERNAL cache entries +######################## + +//Path to a program. +CMAKE_ADDR2LINE:FILEPATH=C:/BC/C/mingw64/bin/addr2line.exe + +//Path to a program. +CMAKE_AR:FILEPATH=C:/BC/C/mingw64/bin/ar.exe + +//Choose the type of build, options are: None Debug Release RelWithDebInfo +// MinSizeRel ... +CMAKE_BUILD_TYPE:STRING=Debug + +//Id string of the compiler for the CodeBlocks IDE. Automatically +// detected when left empty +CMAKE_CODEBLOCKS_COMPILER_ID:STRING= + +//The CodeBlocks executable +CMAKE_CODEBLOCKS_EXECUTABLE:FILEPATH=CMAKE_CODEBLOCKS_EXECUTABLE-NOTFOUND + +//Additional command line arguments when CodeBlocks invokes make. +// Enter e.g. -j to get parallel builds +CMAKE_CODEBLOCKS_MAKE_ARGUMENTS:STRING= + +//Enable/Disable color output during build. +CMAKE_COLOR_MAKEFILE:BOOL=ON + +//CXX compiler +CMAKE_CXX_COMPILER:FILEPATH=C:/BC/C/mingw64/bin/g++.exe + +//A wrapper around 'ar' adding the appropriate '--plugin' option +// for the GCC compiler +CMAKE_CXX_COMPILER_AR:FILEPATH=C:/BC/C/mingw64/bin/gcc-ar.exe + +//A wrapper around 'ranlib' adding the appropriate '--plugin' option +// for the GCC compiler +CMAKE_CXX_COMPILER_RANLIB:FILEPATH=C:/BC/C/mingw64/bin/gcc-ranlib.exe + +//Flags used by the CXX compiler during all build types. +CMAKE_CXX_FLAGS:STRING= + +//Flags used by the CXX compiler during DEBUG builds. +CMAKE_CXX_FLAGS_DEBUG:STRING=-g + +//Flags used by the CXX compiler during MINSIZEREL builds. +CMAKE_CXX_FLAGS_MINSIZEREL:STRING=-Os -DNDEBUG + +//Flags used by the CXX compiler during RELEASE builds. +CMAKE_CXX_FLAGS_RELEASE:STRING=-O3 -DNDEBUG + +//Flags used by the CXX compiler during RELWITHDEBINFO builds. +CMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING=-O2 -g -DNDEBUG + +//Libraries linked by default with all C++ applications. +CMAKE_CXX_STANDARD_LIBRARIES:STRING=-lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32 + +//C compiler +CMAKE_C_COMPILER:FILEPATH=C:/BC/C/mingw64/bin/gcc.exe + +//A wrapper around 'ar' adding the appropriate '--plugin' option +// for the GCC compiler +CMAKE_C_COMPILER_AR:FILEPATH=C:/BC/C/mingw64/bin/gcc-ar.exe + +//A wrapper around 'ranlib' adding the appropriate '--plugin' option +// for the GCC compiler +CMAKE_C_COMPILER_RANLIB:FILEPATH=C:/BC/C/mingw64/bin/gcc-ranlib.exe + +//Flags used by the C compiler during all build types. +CMAKE_C_FLAGS:STRING= + +//Flags used by the C compiler during DEBUG builds. +CMAKE_C_FLAGS_DEBUG:STRING=-g + +//Flags used by the C compiler during MINSIZEREL builds. +CMAKE_C_FLAGS_MINSIZEREL:STRING=-Os -DNDEBUG + +//Flags used by the C compiler during RELEASE builds. +CMAKE_C_FLAGS_RELEASE:STRING=-O3 -DNDEBUG + +//Flags used by the C compiler during RELWITHDEBINFO builds. +CMAKE_C_FLAGS_RELWITHDEBINFO:STRING=-O2 -g -DNDEBUG + +//Libraries linked by default with all C applications. +CMAKE_C_STANDARD_LIBRARIES:STRING=-lkernel32 -luser32 -lgdi32 -lwinspool -lshell32 -lole32 -loleaut32 -luuid -lcomdlg32 -ladvapi32 + +//Path to a program. +CMAKE_DLLTOOL:FILEPATH=C:/BC/C/mingw64/bin/dlltool.exe + +//Flags used by the linker during all build types. +CMAKE_EXE_LINKER_FLAGS:STRING= + +//Flags used by the linker during DEBUG builds. +CMAKE_EXE_LINKER_FLAGS_DEBUG:STRING= + +//Flags used by the linker during MINSIZEREL builds. +CMAKE_EXE_LINKER_FLAGS_MINSIZEREL:STRING= + +//Flags used by the linker during RELEASE builds. +CMAKE_EXE_LINKER_FLAGS_RELEASE:STRING= + +//Flags used by the linker during RELWITHDEBINFO builds. +CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO:STRING= + +//Convert GNU import libraries to MS format (requires Visual Studio) +CMAKE_GNUtoMS:BOOL=OFF + +//Install path prefix, prepended onto install directories. +CMAKE_INSTALL_PREFIX:PATH=C:/Program Files (x86)/pro + +//Path to a program. +CMAKE_LINKER:FILEPATH=C:/BC/C/mingw64/bin/ld.exe + +//Path to a program. +CMAKE_MAKE_PROGRAM:FILEPATH=C:/BC/C/mingw64/bin/mingw32-make.exe + +//Flags used by the linker during the creation of modules during +// all build types. +CMAKE_MODULE_LINKER_FLAGS:STRING= + +//Flags used by the linker during the creation of modules during +// DEBUG builds. +CMAKE_MODULE_LINKER_FLAGS_DEBUG:STRING= + +//Flags used by the linker during the creation of modules during +// MINSIZEREL builds. +CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL:STRING= + +//Flags used by the linker during the creation of modules during +// RELEASE builds. +CMAKE_MODULE_LINKER_FLAGS_RELEASE:STRING= + +//Flags used by the linker during the creation of modules during +// RELWITHDEBINFO builds. +CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO:STRING= + +//Path to a program. +CMAKE_NM:FILEPATH=C:/BC/C/mingw64/bin/nm.exe + +//Path to a program. +CMAKE_OBJCOPY:FILEPATH=C:/BC/C/mingw64/bin/objcopy.exe + +//Path to a program. +CMAKE_OBJDUMP:FILEPATH=C:/BC/C/mingw64/bin/objdump.exe + +//Value Computed by CMake +CMAKE_PROJECT_DESCRIPTION:STATIC= + +//Value Computed by CMake +CMAKE_PROJECT_HOMEPAGE_URL:STATIC= + +//Value Computed by CMake +CMAKE_PROJECT_NAME:STATIC=pro + +//Path to a program. +CMAKE_RANLIB:FILEPATH=C:/BC/C/mingw64/bin/ranlib.exe + +//RC compiler +CMAKE_RC_COMPILER:FILEPATH=C:/BC/C/mingw64/bin/windres.exe + +//Flags for Windows Resource Compiler during all build types. +CMAKE_RC_FLAGS:STRING= + +//Flags for Windows Resource Compiler during DEBUG builds. +CMAKE_RC_FLAGS_DEBUG:STRING= + +//Flags for Windows Resource Compiler during MINSIZEREL builds. +CMAKE_RC_FLAGS_MINSIZEREL:STRING= + +//Flags for Windows Resource Compiler during RELEASE builds. +CMAKE_RC_FLAGS_RELEASE:STRING= + +//Flags for Windows Resource Compiler during RELWITHDEBINFO builds. +CMAKE_RC_FLAGS_RELWITHDEBINFO:STRING= + +//Path to a program. +CMAKE_READELF:FILEPATH=C:/BC/C/mingw64/bin/readelf.exe + +//Flags used by the linker during the creation of shared libraries +// during all build types. +CMAKE_SHARED_LINKER_FLAGS:STRING= + +//Flags used by the linker during the creation of shared libraries +// during DEBUG builds. +CMAKE_SHARED_LINKER_FLAGS_DEBUG:STRING= + +//Flags used by the linker during the creation of shared libraries +// during MINSIZEREL builds. +CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL:STRING= + +//Flags used by the linker during the creation of shared libraries +// during RELEASE builds. +CMAKE_SHARED_LINKER_FLAGS_RELEASE:STRING= + +//Flags used by the linker during the creation of shared libraries +// during RELWITHDEBINFO builds. +CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO:STRING= + +//If set, runtime paths are not added when installing shared libraries, +// but are added when building. +CMAKE_SKIP_INSTALL_RPATH:BOOL=NO + +//If set, runtime paths are not added when using shared libraries. +CMAKE_SKIP_RPATH:BOOL=NO + +//Flags used by the linker during the creation of static libraries +// during all build types. +CMAKE_STATIC_LINKER_FLAGS:STRING= + +//Flags used by the linker during the creation of static libraries +// during DEBUG builds. +CMAKE_STATIC_LINKER_FLAGS_DEBUG:STRING= + +//Flags used by the linker during the creation of static libraries +// during MINSIZEREL builds. +CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL:STRING= + +//Flags used by the linker during the creation of static libraries +// during RELEASE builds. +CMAKE_STATIC_LINKER_FLAGS_RELEASE:STRING= + +//Flags used by the linker during the creation of static libraries +// during RELWITHDEBINFO builds. +CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO:STRING= + +//Path to a program. +CMAKE_STRIP:FILEPATH=C:/BC/C/mingw64/bin/strip.exe + +//If this value is on, makefiles will be generated without the +// .SILENT directive, and all commands will be echoed to the console +// during the make. This is useful for debugging only. With Visual +// Studio IDE projects all commands are done without /nologo. +CMAKE_VERBOSE_MAKEFILE:BOOL=FALSE + +//The directory containing a CMake configuration file for RapidJSON. +RapidJSON_DIR:PATH=RapidJSON_DIR-NOTFOUND + +//Value Computed by CMake +pro_BINARY_DIR:STATIC=D:/2021_2/cids-server/cmake-build-debug + +//Value Computed by CMake +pro_SOURCE_DIR:STATIC=D:/2021_2/cids-server + + +######################## +# INTERNAL cache entries +######################## + +//ADVANCED property for variable: CMAKE_ADDR2LINE +CMAKE_ADDR2LINE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_AR +CMAKE_AR-ADVANCED:INTERNAL=1 +//This is the directory where this CMakeCache.txt was created +CMAKE_CACHEFILE_DIR:INTERNAL=d:/2021_2/cids-server/cmake-build-debug +//Major version of cmake used to create the current loaded cache +CMAKE_CACHE_MAJOR_VERSION:INTERNAL=3 +//Minor version of cmake used to create the current loaded cache +CMAKE_CACHE_MINOR_VERSION:INTERNAL=19 +//Patch version of cmake used to create the current loaded cache +CMAKE_CACHE_PATCH_VERSION:INTERNAL=2 +//ADVANCED property for variable: CMAKE_COLOR_MAKEFILE +CMAKE_COLOR_MAKEFILE-ADVANCED:INTERNAL=1 +//Path to CMake executable. +CMAKE_COMMAND:INTERNAL=C:/Users/XM/AppData/Local/JetBrains/Toolbox/apps/CLion/ch-0/211.7142.21/bin/cmake/win/bin/cmake.exe +//Path to cpack program executable. +CMAKE_CPACK_COMMAND:INTERNAL=C:/Users/XM/AppData/Local/JetBrains/Toolbox/apps/CLion/ch-0/211.7142.21/bin/cmake/win/bin/cpack.exe +//Path to ctest program executable. +CMAKE_CTEST_COMMAND:INTERNAL=C:/Users/XM/AppData/Local/JetBrains/Toolbox/apps/CLion/ch-0/211.7142.21/bin/cmake/win/bin/ctest.exe +//ADVANCED property for variable: CMAKE_CXX_COMPILER +CMAKE_CXX_COMPILER-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_COMPILER_AR +CMAKE_CXX_COMPILER_AR-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_COMPILER_RANLIB +CMAKE_CXX_COMPILER_RANLIB-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_FLAGS +CMAKE_CXX_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_FLAGS_DEBUG +CMAKE_CXX_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_FLAGS_MINSIZEREL +CMAKE_CXX_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_FLAGS_RELEASE +CMAKE_CXX_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_FLAGS_RELWITHDEBINFO +CMAKE_CXX_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_CXX_STANDARD_LIBRARIES +CMAKE_CXX_STANDARD_LIBRARIES-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_COMPILER +CMAKE_C_COMPILER-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_COMPILER_AR +CMAKE_C_COMPILER_AR-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_COMPILER_RANLIB +CMAKE_C_COMPILER_RANLIB-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_FLAGS +CMAKE_C_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_FLAGS_DEBUG +CMAKE_C_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_FLAGS_MINSIZEREL +CMAKE_C_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_FLAGS_RELEASE +CMAKE_C_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_FLAGS_RELWITHDEBINFO +CMAKE_C_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_C_STANDARD_LIBRARIES +CMAKE_C_STANDARD_LIBRARIES-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_DLLTOOL +CMAKE_DLLTOOL-ADVANCED:INTERNAL=1 +//Executable file format +CMAKE_EXECUTABLE_FORMAT:INTERNAL=Unknown +//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS +CMAKE_EXE_LINKER_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_DEBUG +CMAKE_EXE_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_MINSIZEREL +CMAKE_EXE_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_RELEASE +CMAKE_EXE_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO +CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//Name of external makefile project generator. +CMAKE_EXTRA_GENERATOR:INTERNAL=CodeBlocks +//CXX compiler system defined macros +CMAKE_EXTRA_GENERATOR_CXX_SYSTEM_DEFINED_MACROS:INTERNAL=__STDC__;1;__STDC_VERSION__;201710L;__STDC_UTF_16__;1;__STDC_UTF_32__;1;__STDC_HOSTED__;1;__GNUC__;8;__GNUC_MINOR__;1;__GNUC_PATCHLEVEL__;0;__VERSION__;"8.1.0";__ATOMIC_RELAXED;0;__ATOMIC_SEQ_CST;5;__ATOMIC_ACQUIRE;2;__ATOMIC_RELEASE;3;__ATOMIC_ACQ_REL;4;__ATOMIC_CONSUME;1;__pic__;1;__PIC__;1;__FINITE_MATH_ONLY__;0;__SIZEOF_INT__;4;__SIZEOF_LONG__;4;__SIZEOF_LONG_LONG__;8;__SIZEOF_SHORT__;2;__SIZEOF_FLOAT__;4;__SIZEOF_DOUBLE__;8;__SIZEOF_LONG_DOUBLE__;16;__SIZEOF_SIZE_T__;8;__CHAR_BIT__;8;__BIGGEST_ALIGNMENT__;16;__ORDER_LITTLE_ENDIAN__;1234;__ORDER_BIG_ENDIAN__;4321;__ORDER_PDP_ENDIAN__;3412;__BYTE_ORDER__;__ORDER_LITTLE_ENDIAN__;__FLOAT_WORD_ORDER__;__ORDER_LITTLE_ENDIAN__;__SIZEOF_POINTER__;8;__SIZE_TYPE__;long long unsigned int;__PTRDIFF_TYPE__;long long int;__WCHAR_TYPE__;short unsigned int;__WINT_TYPE__;short unsigned int;__INTMAX_TYPE__;long long int;__UINTMAX_TYPE__;long long unsigned int;__CHAR16_TYPE__;short unsigned int;__CHAR32_TYPE__;unsigned int;__SIG_ATOMIC_TYPE__;int;__INT8_TYPE__;signed char;__INT16_TYPE__;short int;__INT32_TYPE__;int;__INT64_TYPE__;long long int;__UINT8_TYPE__;unsigned char;__UINT16_TYPE__;short unsigned int;__UINT32_TYPE__;unsigned int;__UINT64_TYPE__;long long unsigned int;__INT_LEAST8_TYPE__;signed char;__INT_LEAST16_TYPE__;short int;__INT_LEAST32_TYPE__;int;__INT_LEAST64_TYPE__;long long int;__UINT_LEAST8_TYPE__;unsigned char;__UINT_LEAST16_TYPE__;short unsigned int;__UINT_LEAST32_TYPE__;unsigned int;__UINT_LEAST64_TYPE__;long long unsigned int;__INT_FAST8_TYPE__;signed char;__INT_FAST16_TYPE__;short int;__INT_FAST32_TYPE__;int;__INT_FAST64_TYPE__;long long int;__UINT_FAST8_TYPE__;unsigned char;__UINT_FAST16_TYPE__;short unsigned int;__UINT_FAST32_TYPE__;unsigned int;__UINT_FAST64_TYPE__;long long unsigned int;__INTPTR_TYPE__;long long int;__UINTPTR_TYPE__;long long unsigned int;__has_include(STR);__has_include__(STR);__has_include_next(STR);__has_include_next__(STR);__GXX_ABI_VERSION;1012;__SCHAR_MAX__;0x7f;__SHRT_MAX__;0x7fff;__INT_MAX__;0x7fffffff;__LONG_MAX__;0x7fffffffL;__LONG_LONG_MAX__;0x7fffffffffffffffLL;__WCHAR_MAX__;0xffff;__WCHAR_MIN__;0;__WINT_MAX__;0xffff;__WINT_MIN__;0;__PTRDIFF_MAX__;0x7fffffffffffffffLL;__SIZE_MAX__;0xffffffffffffffffULL;__SCHAR_WIDTH__;8;__SHRT_WIDTH__;16;__INT_WIDTH__;32;__LONG_WIDTH__;32;__LONG_LONG_WIDTH__;64;__WCHAR_WIDTH__;16;__WINT_WIDTH__;16;__PTRDIFF_WIDTH__;64;__SIZE_WIDTH__;64;__INTMAX_MAX__;0x7fffffffffffffffLL;__INTMAX_C(c);c ## LL;__UINTMAX_MAX__;0xffffffffffffffffULL;__UINTMAX_C(c);c ## ULL;__INTMAX_WIDTH__;64;__SIG_ATOMIC_MAX__;0x7fffffff;__SIG_ATOMIC_MIN__;(-__SIG_ATOMIC_MAX__ - 1);__SIG_ATOMIC_WIDTH__;32;__INT8_MAX__;0x7f;__INT16_MAX__;0x7fff;__INT32_MAX__;0x7fffffff;__INT64_MAX__;0x7fffffffffffffffLL;__UINT8_MAX__;0xff;__UINT16_MAX__;0xffff;__UINT32_MAX__;0xffffffffU;__UINT64_MAX__;0xffffffffffffffffULL;__INT_LEAST8_MAX__;0x7f;__INT8_C(c);c;__INT_LEAST8_WIDTH__;8;__INT_LEAST16_MAX__;0x7fff;__INT16_C(c);c;__INT_LEAST16_WIDTH__;16;__INT_LEAST32_MAX__;0x7fffffff;__INT32_C(c);c;__INT_LEAST32_WIDTH__;32;__INT_LEAST64_MAX__;0x7fffffffffffffffLL;__INT64_C(c);c ## LL;__INT_LEAST64_WIDTH__;64;__UINT_LEAST8_MAX__;0xff;__UINT8_C(c);c;__UINT_LEAST16_MAX__;0xffff;__UINT16_C(c);c;__UINT_LEAST32_MAX__;0xffffffffU;__UINT32_C(c);c ## U;__UINT_LEAST64_MAX__;0xffffffffffffffffULL;__UINT64_C(c);c ## ULL;__INT_FAST8_MAX__;0x7f;__INT_FAST8_WIDTH__;8;__INT_FAST16_MAX__;0x7fff;__INT_FAST16_WIDTH__;16;__INT_FAST32_MAX__;0x7fffffff;__INT_FAST32_WIDTH__;32;__INT_FAST64_MAX__;0x7fffffffffffffffLL;__INT_FAST64_WIDTH__;64;__UINT_FAST8_MAX__;0xff;__UINT_FAST16_MAX__;0xffff;__UINT_FAST32_MAX__;0xffffffffU;__UINT_FAST64_MAX__;0xffffffffffffffffULL;__INTPTR_MAX__;0x7fffffffffffffffLL;__INTPTR_WIDTH__;64;__UINTPTR_MAX__;0xffffffffffffffffULL;__GCC_IEC_559;2;__GCC_IEC_559_COMPLEX;2;__FLT_EVAL_METHOD__;0;__FLT_EVAL_METHOD_TS_18661_3__;0;__DEC_EVAL_METHOD__;2;__FLT_RADIX__;2;__FLT_MANT_DIG__;24;__FLT_DIG__;6;__FLT_MIN_EXP__;(-125);__FLT_MIN_10_EXP__;(-37);__FLT_MAX_EXP__;128;__FLT_MAX_10_EXP__;38;__FLT_DECIMAL_DIG__;9;__FLT_MAX__;3.40282346638528859811704183484516925e+38F;__FLT_MIN__;1.17549435082228750796873653722224568e-38F;__FLT_EPSILON__;1.19209289550781250000000000000000000e-7F;__FLT_DENORM_MIN__;1.40129846432481707092372958328991613e-45F;__FLT_HAS_DENORM__;1;__FLT_HAS_INFINITY__;1;__FLT_HAS_QUIET_NAN__;1;__DBL_MANT_DIG__;53;__DBL_DIG__;15;__DBL_MIN_EXP__;(-1021);__DBL_MIN_10_EXP__;(-307);__DBL_MAX_EXP__;1024;__DBL_MAX_10_EXP__;308;__DBL_DECIMAL_DIG__;17;__DBL_MAX__;((double)1.79769313486231570814527423731704357e+308L);__DBL_MIN__;((double)2.22507385850720138309023271733240406e-308L);__DBL_EPSILON__;((double)2.22044604925031308084726333618164062e-16L);__DBL_DENORM_MIN__;((double)4.94065645841246544176568792868221372e-324L);__DBL_HAS_DENORM__;1;__DBL_HAS_INFINITY__;1;__DBL_HAS_QUIET_NAN__;1;__LDBL_MANT_DIG__;64;__LDBL_DIG__;18;__LDBL_MIN_EXP__;(-16381);__LDBL_MIN_10_EXP__;(-4931);__LDBL_MAX_EXP__;16384;__LDBL_MAX_10_EXP__;4932;__DECIMAL_DIG__;21;__LDBL_DECIMAL_DIG__;21;__LDBL_MAX__;1.18973149535723176502126385303097021e+4932L;__LDBL_MIN__;3.36210314311209350626267781732175260e-4932L;__LDBL_EPSILON__;1.08420217248550443400745280086994171e-19L;__LDBL_DENORM_MIN__;3.64519953188247460252840593361941982e-4951L;__LDBL_HAS_DENORM__;1;__LDBL_HAS_INFINITY__;1;__LDBL_HAS_QUIET_NAN__;1;__FLT32_MANT_DIG__;24;__FLT32_DIG__;6;__FLT32_MIN_EXP__;(-125);__FLT32_MIN_10_EXP__;(-37);__FLT32_MAX_EXP__;128;__FLT32_MAX_10_EXP__;38;__FLT32_DECIMAL_DIG__;9;__FLT32_MAX__;3.40282346638528859811704183484516925e+38F32;__FLT32_MIN__;1.17549435082228750796873653722224568e-38F32;__FLT32_EPSILON__;1.19209289550781250000000000000000000e-7F32;__FLT32_DENORM_MIN__;1.40129846432481707092372958328991613e-45F32;__FLT32_HAS_DENORM__;1;__FLT32_HAS_INFINITY__;1;__FLT32_HAS_QUIET_NAN__;1;__FLT64_MANT_DIG__;53;__FLT64_DIG__;15;__FLT64_MIN_EXP__;(-1021);__FLT64_MIN_10_EXP__;(-307);__FLT64_MAX_EXP__;1024;__FLT64_MAX_10_EXP__;308;__FLT64_DECIMAL_DIG__;17;__FLT64_MAX__;1.79769313486231570814527423731704357e+308F64;__FLT64_MIN__;2.22507385850720138309023271733240406e-308F64;__FLT64_EPSILON__;2.22044604925031308084726333618164062e-16F64;__FLT64_DENORM_MIN__;4.94065645841246544176568792868221372e-324F64;__FLT64_HAS_DENORM__;1;__FLT64_HAS_INFINITY__;1;__FLT64_HAS_QUIET_NAN__;1;__FLT128_MANT_DIG__;113;__FLT128_DIG__;33;__FLT128_MIN_EXP__;(-16381);__FLT128_MIN_10_EXP__;(-4931);__FLT128_MAX_EXP__;16384;__FLT128_MAX_10_EXP__;4932;__FLT128_DECIMAL_DIG__;36;__FLT128_MAX__;1.18973149535723176508575932662800702e+4932F128;__FLT128_MIN__;3.36210314311209350626267781732175260e-4932F128;__FLT128_EPSILON__;1.92592994438723585305597794258492732e-34F128;__FLT128_DENORM_MIN__;6.47517511943802511092443895822764655e-4966F128;__FLT128_HAS_DENORM__;1;__FLT128_HAS_INFINITY__;1;__FLT128_HAS_QUIET_NAN__;1;__FLT32X_MANT_DIG__;53;__FLT32X_DIG__;15;__FLT32X_MIN_EXP__;(-1021);__FLT32X_MIN_10_EXP__;(-307);__FLT32X_MAX_EXP__;1024;__FLT32X_MAX_10_EXP__;308;__FLT32X_DECIMAL_DIG__;17;__FLT32X_MAX__;1.79769313486231570814527423731704357e+308F32x;__FLT32X_MIN__;2.22507385850720138309023271733240406e-308F32x;__FLT32X_EPSILON__;2.22044604925031308084726333618164062e-16F32x;__FLT32X_DENORM_MIN__;4.94065645841246544176568792868221372e-324F32x;__FLT32X_HAS_DENORM__;1;__FLT32X_HAS_INFINITY__;1;__FLT32X_HAS_QUIET_NAN__;1;__FLT64X_MANT_DIG__;64;__FLT64X_DIG__;18;__FLT64X_MIN_EXP__;(-16381);__FLT64X_MIN_10_EXP__;(-4931);__FLT64X_MAX_EXP__;16384;__FLT64X_MAX_10_EXP__;4932;__FLT64X_DECIMAL_DIG__;21;__FLT64X_MAX__;1.18973149535723176502126385303097021e+4932F64x;__FLT64X_MIN__;3.36210314311209350626267781732175260e-4932F64x;__FLT64X_EPSILON__;1.08420217248550443400745280086994171e-19F64x;__FLT64X_DENORM_MIN__;3.64519953188247460252840593361941982e-4951F64x;__FLT64X_HAS_DENORM__;1;__FLT64X_HAS_INFINITY__;1;__FLT64X_HAS_QUIET_NAN__;1;__DEC32_MANT_DIG__;7;__DEC32_MIN_EXP__;(-94);__DEC32_MAX_EXP__;97;__DEC32_MIN__;1E-95DF;__DEC32_MAX__;9.999999E96DF;__DEC32_EPSILON__;1E-6DF;__DEC32_SUBNORMAL_MIN__;0.000001E-95DF;__DEC64_MANT_DIG__;16;__DEC64_MIN_EXP__;(-382);__DEC64_MAX_EXP__;385;__DEC64_MIN__;1E-383DD;__DEC64_MAX__;9.999999999999999E384DD;__DEC64_EPSILON__;1E-15DD;__DEC64_SUBNORMAL_MIN__;0.000000000000001E-383DD;__DEC128_MANT_DIG__;34;__DEC128_MIN_EXP__;(-6142);__DEC128_MAX_EXP__;6145;__DEC128_MIN__;1E-6143DL;__DEC128_MAX__;9.999999999999999999999999999999999E6144DL;__DEC128_EPSILON__;1E-33DL;__DEC128_SUBNORMAL_MIN__;0.000000000000000000000000000000001E-6143DL;__REGISTER_PREFIX__; ;__USER_LABEL_PREFIX__; ;__GNUC_STDC_INLINE__;1;__NO_INLINE__;1;__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1;1;__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2;1;__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4;1;__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8;1;__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16;1;__GCC_ATOMIC_BOOL_LOCK_FREE;2;__GCC_ATOMIC_CHAR_LOCK_FREE;2;__GCC_ATOMIC_CHAR16_T_LOCK_FREE;2;__GCC_ATOMIC_CHAR32_T_LOCK_FREE;2;__GCC_ATOMIC_WCHAR_T_LOCK_FREE;2;__GCC_ATOMIC_SHORT_LOCK_FREE;2;__GCC_ATOMIC_INT_LOCK_FREE;2;__GCC_ATOMIC_LONG_LOCK_FREE;2;__GCC_ATOMIC_LLONG_LOCK_FREE;2;__GCC_ATOMIC_TEST_AND_SET_TRUEVAL;1;__GCC_ATOMIC_POINTER_LOCK_FREE;2;__PRAGMA_REDEFINE_EXTNAME;1;__SIZEOF_INT128__;16;__SIZEOF_WCHAR_T__;2;__SIZEOF_WINT_T__;2;__SIZEOF_PTRDIFF_T__;8;__amd64;1;__amd64__;1;__x86_64;1;__x86_64__;1;__SIZEOF_FLOAT80__;16;__SIZEOF_FLOAT128__;16;__ATOMIC_HLE_ACQUIRE;65536;__ATOMIC_HLE_RELEASE;131072;__GCC_ASM_FLAG_OUTPUTS__;1;__nocona;1;__nocona__;1;__tune_core2__;1;__code_model_medium__;1;__MMX__;1;__SSE__;1;__SSE2__;1;__SSE3__;1;__FXSR__;1;__SSE_MATH__;1;__SSE2_MATH__;1;__SEG_FS;1;__SEG_GS;1;__SEH__;1;__stdcall;__attribute__((__stdcall__));__fastcall;__attribute__((__fastcall__));__thiscall;__attribute__((__thiscall__));__cdecl;__attribute__((__cdecl__));_stdcall;__attribute__((__stdcall__));_fastcall;__attribute__((__fastcall__));_thiscall;__attribute__((__thiscall__));_cdecl;__attribute__((__cdecl__));__GXX_MERGED_TYPEINFO_NAMES;0;__GXX_TYPEINFO_EQUALITY_INLINE;0;__MSVCRT__;1;__MINGW32__;1;_WIN32;1;__WIN32;1;__WIN32__;1;WIN32;1;__WINNT;1;__WINNT__;1;WINNT;1;_INTEGRAL_MAX_BITS;64;__MINGW64__;1;__WIN64;1;__WIN64__;1;WIN64;1;_WIN64;1;__declspec(x);__attribute__((x));__DECIMAL_BID_FORMAT__;1;_REENTRANT;1;__STDC__;1;__cplusplus;201402L;__STDC_UTF_16__;1;__STDC_UTF_32__;1;__STDC_HOSTED__;1;__GNUC__;8;__GNUC_MINOR__;1;__GNUC_PATCHLEVEL__;0;__VERSION__;"8.1.0";__ATOMIC_RELAXED;0;__ATOMIC_SEQ_CST;5;__ATOMIC_ACQUIRE;2;__ATOMIC_RELEASE;3;__ATOMIC_ACQ_REL;4;__ATOMIC_CONSUME;1;__pic__;1;__PIC__;1;__FINITE_MATH_ONLY__;0;__SIZEOF_INT__;4;__SIZEOF_LONG__;4;__SIZEOF_LONG_LONG__;8;__SIZEOF_SHORT__;2;__SIZEOF_FLOAT__;4;__SIZEOF_DOUBLE__;8;__SIZEOF_LONG_DOUBLE__;16;__SIZEOF_SIZE_T__;8;__CHAR_BIT__;8;__BIGGEST_ALIGNMENT__;16;__ORDER_LITTLE_ENDIAN__;1234;__ORDER_BIG_ENDIAN__;4321;__ORDER_PDP_ENDIAN__;3412;__BYTE_ORDER__;__ORDER_LITTLE_ENDIAN__;__FLOAT_WORD_ORDER__;__ORDER_LITTLE_ENDIAN__;__SIZEOF_POINTER__;8;__GNUG__;8;__SIZE_TYPE__;long long unsigned int;__PTRDIFF_TYPE__;long long int;__WCHAR_TYPE__;short unsigned int;__WINT_TYPE__;short unsigned int;__INTMAX_TYPE__;long long int;__UINTMAX_TYPE__;long long unsigned int;__CHAR16_TYPE__;short unsigned int;__CHAR32_TYPE__;unsigned int;__SIG_ATOMIC_TYPE__;int;__INT8_TYPE__;signed char;__INT16_TYPE__;short int;__INT32_TYPE__;int;__INT64_TYPE__;long long int;__UINT8_TYPE__;unsigned char;__UINT16_TYPE__;short unsigned int;__UINT32_TYPE__;unsigned int;__UINT64_TYPE__;long long unsigned int;__INT_LEAST8_TYPE__;signed char;__INT_LEAST16_TYPE__;short int;__INT_LEAST32_TYPE__;int;__INT_LEAST64_TYPE__;long long int;__UINT_LEAST8_TYPE__;unsigned char;__UINT_LEAST16_TYPE__;short unsigned int;__UINT_LEAST32_TYPE__;unsigned int;__UINT_LEAST64_TYPE__;long long unsigned int;__INT_FAST8_TYPE__;signed char;__INT_FAST16_TYPE__;short int;__INT_FAST32_TYPE__;int;__INT_FAST64_TYPE__;long long int;__UINT_FAST8_TYPE__;unsigned char;__UINT_FAST16_TYPE__;short unsigned int;__UINT_FAST32_TYPE__;unsigned int;__UINT_FAST64_TYPE__;long long unsigned int;__INTPTR_TYPE__;long long int;__UINTPTR_TYPE__;long long unsigned int;__has_include(STR);__has_include__(STR);__has_include_next(STR);__has_include_next__(STR);__GXX_WEAK__;1;__DEPRECATED;1;__GXX_RTTI;1;__cpp_rtti;199711;__GXX_EXPERIMENTAL_CXX0X__;1;__cpp_binary_literals;201304;__cpp_hex_float;201603;__cpp_runtime_arrays;198712;__cpp_unicode_characters;200704;__cpp_raw_strings;200710;__cpp_unicode_literals;200710;__cpp_user_defined_literals;200809;__cpp_lambdas;200907;__cpp_range_based_for;200907;__cpp_static_assert;200410;__cpp_decltype;200707;__cpp_attributes;200809;__cpp_rvalue_reference;200610;__cpp_rvalue_references;200610;__cpp_variadic_templates;200704;__cpp_initializer_lists;200806;__cpp_delegating_constructors;200604;__cpp_nsdmi;200809;__cpp_inheriting_constructors;201511;__cpp_ref_qualifiers;200710;__cpp_alias_templates;200704;__cpp_return_type_deduction;201304;__cpp_init_captures;201304;__cpp_generic_lambdas;201304;__cpp_constexpr;201304;__cpp_decltype_auto;201304;__cpp_aggregate_nsdmi;201304;__cpp_variable_templates;201304;__cpp_digit_separators;201309;__cpp_sized_deallocation;201309;__cpp_threadsafe_static_init;200806;__EXCEPTIONS;1;__cpp_exceptions;199711;__GXX_ABI_VERSION;1012;__SCHAR_MAX__;0x7f;__SHRT_MAX__;0x7fff;__INT_MAX__;0x7fffffff;__LONG_MAX__;0x7fffffffL;__LONG_LONG_MAX__;0x7fffffffffffffffLL;__WCHAR_MAX__;0xffff;__WCHAR_MIN__;0;__WINT_MAX__;0xffff;__WINT_MIN__;0;__PTRDIFF_MAX__;0x7fffffffffffffffLL;__SIZE_MAX__;0xffffffffffffffffULL;__SCHAR_WIDTH__;8;__SHRT_WIDTH__;16;__INT_WIDTH__;32;__LONG_WIDTH__;32;__LONG_LONG_WIDTH__;64;__WCHAR_WIDTH__;16;__WINT_WIDTH__;16;__PTRDIFF_WIDTH__;64;__SIZE_WIDTH__;64;__GLIBCXX_TYPE_INT_N_0;__int128;__GLIBCXX_BITSIZE_INT_N_0;128;__INTMAX_MAX__;0x7fffffffffffffffLL;__INTMAX_C(c);c ## LL;__UINTMAX_MAX__;0xffffffffffffffffULL;__UINTMAX_C(c);c ## ULL;__INTMAX_WIDTH__;64;__SIG_ATOMIC_MAX__;0x7fffffff;__SIG_ATOMIC_MIN__;(-__SIG_ATOMIC_MAX__ - 1);__SIG_ATOMIC_WIDTH__;32;__INT8_MAX__;0x7f;__INT16_MAX__;0x7fff;__INT32_MAX__;0x7fffffff;__INT64_MAX__;0x7fffffffffffffffLL;__UINT8_MAX__;0xff;__UINT16_MAX__;0xffff;__UINT32_MAX__;0xffffffffU;__UINT64_MAX__;0xffffffffffffffffULL;__INT_LEAST8_MAX__;0x7f;__INT8_C(c);c;__INT_LEAST8_WIDTH__;8;__INT_LEAST16_MAX__;0x7fff;__INT16_C(c);c;__INT_LEAST16_WIDTH__;16;__INT_LEAST32_MAX__;0x7fffffff;__INT32_C(c);c;__INT_LEAST32_WIDTH__;32;__INT_LEAST64_MAX__;0x7fffffffffffffffLL;__INT64_C(c);c ## LL;__INT_LEAST64_WIDTH__;64;__UINT_LEAST8_MAX__;0xff;__UINT8_C(c);c;__UINT_LEAST16_MAX__;0xffff;__UINT16_C(c);c;__UINT_LEAST32_MAX__;0xffffffffU;__UINT32_C(c);c ## U;__UINT_LEAST64_MAX__;0xffffffffffffffffULL;__UINT64_C(c);c ## ULL;__INT_FAST8_MAX__;0x7f;__INT_FAST8_WIDTH__;8;__INT_FAST16_MAX__;0x7fff;__INT_FAST16_WIDTH__;16;__INT_FAST32_MAX__;0x7fffffff;__INT_FAST32_WIDTH__;32;__INT_FAST64_MAX__;0x7fffffffffffffffLL;__INT_FAST64_WIDTH__;64;__UINT_FAST8_MAX__;0xff;__UINT_FAST16_MAX__;0xffff;__UINT_FAST32_MAX__;0xffffffffU;__UINT_FAST64_MAX__;0xffffffffffffffffULL;__INTPTR_MAX__;0x7fffffffffffffffLL;__INTPTR_WIDTH__;64;__UINTPTR_MAX__;0xffffffffffffffffULL;__GCC_IEC_559;2;__GCC_IEC_559_COMPLEX;2;__FLT_EVAL_METHOD__;0;__FLT_EVAL_METHOD_TS_18661_3__;0;__DEC_EVAL_METHOD__;2;__FLT_RADIX__;2;__FLT_MANT_DIG__;24;__FLT_DIG__;6;__FLT_MIN_EXP__;(-125);__FLT_MIN_10_EXP__;(-37);__FLT_MAX_EXP__;128;__FLT_MAX_10_EXP__;38;__FLT_DECIMAL_DIG__;9;__FLT_MAX__;3.40282346638528859811704183484516925e+38F;__FLT_MIN__;1.17549435082228750796873653722224568e-38F;__FLT_EPSILON__;1.19209289550781250000000000000000000e-7F;__FLT_DENORM_MIN__;1.40129846432481707092372958328991613e-45F;__FLT_HAS_DENORM__;1;__FLT_HAS_INFINITY__;1;__FLT_HAS_QUIET_NAN__;1;__DBL_MANT_DIG__;53;__DBL_DIG__;15;__DBL_MIN_EXP__;(-1021);__DBL_MIN_10_EXP__;(-307);__DBL_MAX_EXP__;1024;__DBL_MAX_10_EXP__;308;__DBL_DECIMAL_DIG__;17;__DBL_MAX__;double(1.79769313486231570814527423731704357e+308L);__DBL_MIN__;double(2.22507385850720138309023271733240406e-308L);__DBL_EPSILON__;double(2.22044604925031308084726333618164062e-16L);__DBL_DENORM_MIN__;double(4.94065645841246544176568792868221372e-324L);__DBL_HAS_DENORM__;1;__DBL_HAS_INFINITY__;1;__DBL_HAS_QUIET_NAN__;1;__LDBL_MANT_DIG__;64;__LDBL_DIG__;18;__LDBL_MIN_EXP__;(-16381);__LDBL_MIN_10_EXP__;(-4931);__LDBL_MAX_EXP__;16384;__LDBL_MAX_10_EXP__;4932;__DECIMAL_DIG__;21;__LDBL_DECIMAL_DIG__;21;__LDBL_MAX__;1.18973149535723176502126385303097021e+4932L;__LDBL_MIN__;3.36210314311209350626267781732175260e-4932L;__LDBL_EPSILON__;1.08420217248550443400745280086994171e-19L;__LDBL_DENORM_MIN__;3.64519953188247460252840593361941982e-4951L;__LDBL_HAS_DENORM__;1;__LDBL_HAS_INFINITY__;1;__LDBL_HAS_QUIET_NAN__;1;__FLT32_MANT_DIG__;24;__FLT32_DIG__;6;__FLT32_MIN_EXP__;(-125);__FLT32_MIN_10_EXP__;(-37);__FLT32_MAX_EXP__;128;__FLT32_MAX_10_EXP__;38;__FLT32_DECIMAL_DIG__;9;__FLT32_MAX__;3.40282346638528859811704183484516925e+38F32;__FLT32_MIN__;1.17549435082228750796873653722224568e-38F32;__FLT32_EPSILON__;1.19209289550781250000000000000000000e-7F32;__FLT32_DENORM_MIN__;1.40129846432481707092372958328991613e-45F32;__FLT32_HAS_DENORM__;1;__FLT32_HAS_INFINITY__;1;__FLT32_HAS_QUIET_NAN__;1;__FLT64_MANT_DIG__;53;__FLT64_DIG__;15;__FLT64_MIN_EXP__;(-1021);__FLT64_MIN_10_EXP__;(-307);__FLT64_MAX_EXP__;1024;__FLT64_MAX_10_EXP__;308;__FLT64_DECIMAL_DIG__;17;__FLT64_MAX__;1.79769313486231570814527423731704357e+308F64;__FLT64_MIN__;2.22507385850720138309023271733240406e-308F64;__FLT64_EPSILON__;2.22044604925031308084726333618164062e-16F64;__FLT64_DENORM_MIN__;4.94065645841246544176568792868221372e-324F64;__FLT64_HAS_DENORM__;1;__FLT64_HAS_INFINITY__;1;__FLT64_HAS_QUIET_NAN__;1;__FLT128_MANT_DIG__;113;__FLT128_DIG__;33;__FLT128_MIN_EXP__;(-16381);__FLT128_MIN_10_EXP__;(-4931);__FLT128_MAX_EXP__;16384;__FLT128_MAX_10_EXP__;4932;__FLT128_DECIMAL_DIG__;36;__FLT128_MAX__;1.18973149535723176508575932662800702e+4932F128;__FLT128_MIN__;3.36210314311209350626267781732175260e-4932F128;__FLT128_EPSILON__;1.92592994438723585305597794258492732e-34F128;__FLT128_DENORM_MIN__;6.47517511943802511092443895822764655e-4966F128;__FLT128_HAS_DENORM__;1;__FLT128_HAS_INFINITY__;1;__FLT128_HAS_QUIET_NAN__;1;__FLT32X_MANT_DIG__;53;__FLT32X_DIG__;15;__FLT32X_MIN_EXP__;(-1021);__FLT32X_MIN_10_EXP__;(-307);__FLT32X_MAX_EXP__;1024;__FLT32X_MAX_10_EXP__;308;__FLT32X_DECIMAL_DIG__;17;__FLT32X_MAX__;1.79769313486231570814527423731704357e+308F32x;__FLT32X_MIN__;2.22507385850720138309023271733240406e-308F32x;__FLT32X_EPSILON__;2.22044604925031308084726333618164062e-16F32x;__FLT32X_DENORM_MIN__;4.94065645841246544176568792868221372e-324F32x;__FLT32X_HAS_DENORM__;1;__FLT32X_HAS_INFINITY__;1;__FLT32X_HAS_QUIET_NAN__;1;__FLT64X_MANT_DIG__;64;__FLT64X_DIG__;18;__FLT64X_MIN_EXP__;(-16381);__FLT64X_MIN_10_EXP__;(-4931);__FLT64X_MAX_EXP__;16384;__FLT64X_MAX_10_EXP__;4932;__FLT64X_DECIMAL_DIG__;21;__FLT64X_MAX__;1.18973149535723176502126385303097021e+4932F64x;__FLT64X_MIN__;3.36210314311209350626267781732175260e-4932F64x;__FLT64X_EPSILON__;1.08420217248550443400745280086994171e-19F64x;__FLT64X_DENORM_MIN__;3.64519953188247460252840593361941982e-4951F64x;__FLT64X_HAS_DENORM__;1;__FLT64X_HAS_INFINITY__;1;__FLT64X_HAS_QUIET_NAN__;1;__DEC32_MANT_DIG__;7;__DEC32_MIN_EXP__;(-94);__DEC32_MAX_EXP__;97;__DEC32_MIN__;1E-95DF;__DEC32_MAX__;9.999999E96DF;__DEC32_EPSILON__;1E-6DF;__DEC32_SUBNORMAL_MIN__;0.000001E-95DF;__DEC64_MANT_DIG__;16;__DEC64_MIN_EXP__;(-382);__DEC64_MAX_EXP__;385;__DEC64_MIN__;1E-383DD;__DEC64_MAX__;9.999999999999999E384DD;__DEC64_EPSILON__;1E-15DD;__DEC64_SUBNORMAL_MIN__;0.000000000000001E-383DD;__DEC128_MANT_DIG__;34;__DEC128_MIN_EXP__;(-6142);__DEC128_MAX_EXP__;6145;__DEC128_MIN__;1E-6143DL;__DEC128_MAX__;9.999999999999999999999999999999999E6144DL;__DEC128_EPSILON__;1E-33DL;__DEC128_SUBNORMAL_MIN__;0.000000000000000000000000000000001E-6143DL;__REGISTER_PREFIX__; ;__USER_LABEL_PREFIX__; ;__GNUC_STDC_INLINE__;1;__NO_INLINE__;1;__WCHAR_UNSIGNED__;1;__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1;1;__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2;1;__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4;1;__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8;1;__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16;1;__GCC_ATOMIC_BOOL_LOCK_FREE;2;__GCC_ATOMIC_CHAR_LOCK_FREE;2;__GCC_ATOMIC_CHAR16_T_LOCK_FREE;2;__GCC_ATOMIC_CHAR32_T_LOCK_FREE;2;__GCC_ATOMIC_WCHAR_T_LOCK_FREE;2;__GCC_ATOMIC_SHORT_LOCK_FREE;2;__GCC_ATOMIC_INT_LOCK_FREE;2;__GCC_ATOMIC_LONG_LOCK_FREE;2;__GCC_ATOMIC_LLONG_LOCK_FREE;2;__GCC_ATOMIC_TEST_AND_SET_TRUEVAL;1;__GCC_ATOMIC_POINTER_LOCK_FREE;2;__PRAGMA_REDEFINE_EXTNAME;1;__SIZEOF_INT128__;16;__SIZEOF_WCHAR_T__;2;__SIZEOF_WINT_T__;2;__SIZEOF_PTRDIFF_T__;8;__amd64;1;__amd64__;1;__x86_64;1;__x86_64__;1;__SIZEOF_FLOAT80__;16;__SIZEOF_FLOAT128__;16;__ATOMIC_HLE_ACQUIRE;65536;__ATOMIC_HLE_RELEASE;131072;__GCC_ASM_FLAG_OUTPUTS__;1;__nocona;1;__nocona__;1;__tune_core2__;1;__code_model_medium__;1;__MMX__;1;__SSE__;1;__SSE2__;1;__SSE3__;1;__FXSR__;1;__SSE_MATH__;1;__SSE2_MATH__;1;__SEG_FS;1;__SEG_GS;1;__SEH__;1;__stdcall;__attribute__((__stdcall__));__fastcall;__attribute__((__fastcall__));__thiscall;__attribute__((__thiscall__));__cdecl;__attribute__((__cdecl__));_stdcall;__attribute__((__stdcall__));_fastcall;__attribute__((__fastcall__));_thiscall;__attribute__((__thiscall__));_cdecl;__attribute__((__cdecl__));__GXX_MERGED_TYPEINFO_NAMES;0;__GXX_TYPEINFO_EQUALITY_INLINE;0;__MSVCRT__;1;__MINGW32__;1;_WIN32;1;__WIN32;1;__WIN32__;1;WIN32;1;__WINNT;1;__WINNT__;1;WINNT;1;_INTEGRAL_MAX_BITS;64;__MINGW64__;1;__WIN64;1;__WIN64__;1;WIN64;1;_WIN64;1;__declspec(x);__attribute__((x));__DECIMAL_BID_FORMAT__;1;_REENTRANT;1 +//CXX compiler system include directories +CMAKE_EXTRA_GENERATOR_CXX_SYSTEM_INCLUDE_DIRS:INTERNAL=C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/x86_64-w64-mingw32;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/backward;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include-fixed;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/include +//C compiler system defined macros +CMAKE_EXTRA_GENERATOR_C_SYSTEM_DEFINED_MACROS:INTERNAL=__STDC__;1;__STDC_VERSION__;201710L;__STDC_UTF_16__;1;__STDC_UTF_32__;1;__STDC_HOSTED__;1;__GNUC__;8;__GNUC_MINOR__;1;__GNUC_PATCHLEVEL__;0;__VERSION__;"8.1.0";__ATOMIC_RELAXED;0;__ATOMIC_SEQ_CST;5;__ATOMIC_ACQUIRE;2;__ATOMIC_RELEASE;3;__ATOMIC_ACQ_REL;4;__ATOMIC_CONSUME;1;__pic__;1;__PIC__;1;__FINITE_MATH_ONLY__;0;__SIZEOF_INT__;4;__SIZEOF_LONG__;4;__SIZEOF_LONG_LONG__;8;__SIZEOF_SHORT__;2;__SIZEOF_FLOAT__;4;__SIZEOF_DOUBLE__;8;__SIZEOF_LONG_DOUBLE__;16;__SIZEOF_SIZE_T__;8;__CHAR_BIT__;8;__BIGGEST_ALIGNMENT__;16;__ORDER_LITTLE_ENDIAN__;1234;__ORDER_BIG_ENDIAN__;4321;__ORDER_PDP_ENDIAN__;3412;__BYTE_ORDER__;__ORDER_LITTLE_ENDIAN__;__FLOAT_WORD_ORDER__;__ORDER_LITTLE_ENDIAN__;__SIZEOF_POINTER__;8;__SIZE_TYPE__;long long unsigned int;__PTRDIFF_TYPE__;long long int;__WCHAR_TYPE__;short unsigned int;__WINT_TYPE__;short unsigned int;__INTMAX_TYPE__;long long int;__UINTMAX_TYPE__;long long unsigned int;__CHAR16_TYPE__;short unsigned int;__CHAR32_TYPE__;unsigned int;__SIG_ATOMIC_TYPE__;int;__INT8_TYPE__;signed char;__INT16_TYPE__;short int;__INT32_TYPE__;int;__INT64_TYPE__;long long int;__UINT8_TYPE__;unsigned char;__UINT16_TYPE__;short unsigned int;__UINT32_TYPE__;unsigned int;__UINT64_TYPE__;long long unsigned int;__INT_LEAST8_TYPE__;signed char;__INT_LEAST16_TYPE__;short int;__INT_LEAST32_TYPE__;int;__INT_LEAST64_TYPE__;long long int;__UINT_LEAST8_TYPE__;unsigned char;__UINT_LEAST16_TYPE__;short unsigned int;__UINT_LEAST32_TYPE__;unsigned int;__UINT_LEAST64_TYPE__;long long unsigned int;__INT_FAST8_TYPE__;signed char;__INT_FAST16_TYPE__;short int;__INT_FAST32_TYPE__;int;__INT_FAST64_TYPE__;long long int;__UINT_FAST8_TYPE__;unsigned char;__UINT_FAST16_TYPE__;short unsigned int;__UINT_FAST32_TYPE__;unsigned int;__UINT_FAST64_TYPE__;long long unsigned int;__INTPTR_TYPE__;long long int;__UINTPTR_TYPE__;long long unsigned int;__has_include(STR);__has_include__(STR);__has_include_next(STR);__has_include_next__(STR);__GXX_ABI_VERSION;1012;__SCHAR_MAX__;0x7f;__SHRT_MAX__;0x7fff;__INT_MAX__;0x7fffffff;__LONG_MAX__;0x7fffffffL;__LONG_LONG_MAX__;0x7fffffffffffffffLL;__WCHAR_MAX__;0xffff;__WCHAR_MIN__;0;__WINT_MAX__;0xffff;__WINT_MIN__;0;__PTRDIFF_MAX__;0x7fffffffffffffffLL;__SIZE_MAX__;0xffffffffffffffffULL;__SCHAR_WIDTH__;8;__SHRT_WIDTH__;16;__INT_WIDTH__;32;__LONG_WIDTH__;32;__LONG_LONG_WIDTH__;64;__WCHAR_WIDTH__;16;__WINT_WIDTH__;16;__PTRDIFF_WIDTH__;64;__SIZE_WIDTH__;64;__INTMAX_MAX__;0x7fffffffffffffffLL;__INTMAX_C(c);c ## LL;__UINTMAX_MAX__;0xffffffffffffffffULL;__UINTMAX_C(c);c ## ULL;__INTMAX_WIDTH__;64;__SIG_ATOMIC_MAX__;0x7fffffff;__SIG_ATOMIC_MIN__;(-__SIG_ATOMIC_MAX__ - 1);__SIG_ATOMIC_WIDTH__;32;__INT8_MAX__;0x7f;__INT16_MAX__;0x7fff;__INT32_MAX__;0x7fffffff;__INT64_MAX__;0x7fffffffffffffffLL;__UINT8_MAX__;0xff;__UINT16_MAX__;0xffff;__UINT32_MAX__;0xffffffffU;__UINT64_MAX__;0xffffffffffffffffULL;__INT_LEAST8_MAX__;0x7f;__INT8_C(c);c;__INT_LEAST8_WIDTH__;8;__INT_LEAST16_MAX__;0x7fff;__INT16_C(c);c;__INT_LEAST16_WIDTH__;16;__INT_LEAST32_MAX__;0x7fffffff;__INT32_C(c);c;__INT_LEAST32_WIDTH__;32;__INT_LEAST64_MAX__;0x7fffffffffffffffLL;__INT64_C(c);c ## LL;__INT_LEAST64_WIDTH__;64;__UINT_LEAST8_MAX__;0xff;__UINT8_C(c);c;__UINT_LEAST16_MAX__;0xffff;__UINT16_C(c);c;__UINT_LEAST32_MAX__;0xffffffffU;__UINT32_C(c);c ## U;__UINT_LEAST64_MAX__;0xffffffffffffffffULL;__UINT64_C(c);c ## ULL;__INT_FAST8_MAX__;0x7f;__INT_FAST8_WIDTH__;8;__INT_FAST16_MAX__;0x7fff;__INT_FAST16_WIDTH__;16;__INT_FAST32_MAX__;0x7fffffff;__INT_FAST32_WIDTH__;32;__INT_FAST64_MAX__;0x7fffffffffffffffLL;__INT_FAST64_WIDTH__;64;__UINT_FAST8_MAX__;0xff;__UINT_FAST16_MAX__;0xffff;__UINT_FAST32_MAX__;0xffffffffU;__UINT_FAST64_MAX__;0xffffffffffffffffULL;__INTPTR_MAX__;0x7fffffffffffffffLL;__INTPTR_WIDTH__;64;__UINTPTR_MAX__;0xffffffffffffffffULL;__GCC_IEC_559;2;__GCC_IEC_559_COMPLEX;2;__FLT_EVAL_METHOD__;0;__FLT_EVAL_METHOD_TS_18661_3__;0;__DEC_EVAL_METHOD__;2;__FLT_RADIX__;2;__FLT_MANT_DIG__;24;__FLT_DIG__;6;__FLT_MIN_EXP__;(-125);__FLT_MIN_10_EXP__;(-37);__FLT_MAX_EXP__;128;__FLT_MAX_10_EXP__;38;__FLT_DECIMAL_DIG__;9;__FLT_MAX__;3.40282346638528859811704183484516925e+38F;__FLT_MIN__;1.17549435082228750796873653722224568e-38F;__FLT_EPSILON__;1.19209289550781250000000000000000000e-7F;__FLT_DENORM_MIN__;1.40129846432481707092372958328991613e-45F;__FLT_HAS_DENORM__;1;__FLT_HAS_INFINITY__;1;__FLT_HAS_QUIET_NAN__;1;__DBL_MANT_DIG__;53;__DBL_DIG__;15;__DBL_MIN_EXP__;(-1021);__DBL_MIN_10_EXP__;(-307);__DBL_MAX_EXP__;1024;__DBL_MAX_10_EXP__;308;__DBL_DECIMAL_DIG__;17;__DBL_MAX__;((double)1.79769313486231570814527423731704357e+308L);__DBL_MIN__;((double)2.22507385850720138309023271733240406e-308L);__DBL_EPSILON__;((double)2.22044604925031308084726333618164062e-16L);__DBL_DENORM_MIN__;((double)4.94065645841246544176568792868221372e-324L);__DBL_HAS_DENORM__;1;__DBL_HAS_INFINITY__;1;__DBL_HAS_QUIET_NAN__;1;__LDBL_MANT_DIG__;64;__LDBL_DIG__;18;__LDBL_MIN_EXP__;(-16381);__LDBL_MIN_10_EXP__;(-4931);__LDBL_MAX_EXP__;16384;__LDBL_MAX_10_EXP__;4932;__DECIMAL_DIG__;21;__LDBL_DECIMAL_DIG__;21;__LDBL_MAX__;1.18973149535723176502126385303097021e+4932L;__LDBL_MIN__;3.36210314311209350626267781732175260e-4932L;__LDBL_EPSILON__;1.08420217248550443400745280086994171e-19L;__LDBL_DENORM_MIN__;3.64519953188247460252840593361941982e-4951L;__LDBL_HAS_DENORM__;1;__LDBL_HAS_INFINITY__;1;__LDBL_HAS_QUIET_NAN__;1;__FLT32_MANT_DIG__;24;__FLT32_DIG__;6;__FLT32_MIN_EXP__;(-125);__FLT32_MIN_10_EXP__;(-37);__FLT32_MAX_EXP__;128;__FLT32_MAX_10_EXP__;38;__FLT32_DECIMAL_DIG__;9;__FLT32_MAX__;3.40282346638528859811704183484516925e+38F32;__FLT32_MIN__;1.17549435082228750796873653722224568e-38F32;__FLT32_EPSILON__;1.19209289550781250000000000000000000e-7F32;__FLT32_DENORM_MIN__;1.40129846432481707092372958328991613e-45F32;__FLT32_HAS_DENORM__;1;__FLT32_HAS_INFINITY__;1;__FLT32_HAS_QUIET_NAN__;1;__FLT64_MANT_DIG__;53;__FLT64_DIG__;15;__FLT64_MIN_EXP__;(-1021);__FLT64_MIN_10_EXP__;(-307);__FLT64_MAX_EXP__;1024;__FLT64_MAX_10_EXP__;308;__FLT64_DECIMAL_DIG__;17;__FLT64_MAX__;1.79769313486231570814527423731704357e+308F64;__FLT64_MIN__;2.22507385850720138309023271733240406e-308F64;__FLT64_EPSILON__;2.22044604925031308084726333618164062e-16F64;__FLT64_DENORM_MIN__;4.94065645841246544176568792868221372e-324F64;__FLT64_HAS_DENORM__;1;__FLT64_HAS_INFINITY__;1;__FLT64_HAS_QUIET_NAN__;1;__FLT128_MANT_DIG__;113;__FLT128_DIG__;33;__FLT128_MIN_EXP__;(-16381);__FLT128_MIN_10_EXP__;(-4931);__FLT128_MAX_EXP__;16384;__FLT128_MAX_10_EXP__;4932;__FLT128_DECIMAL_DIG__;36;__FLT128_MAX__;1.18973149535723176508575932662800702e+4932F128;__FLT128_MIN__;3.36210314311209350626267781732175260e-4932F128;__FLT128_EPSILON__;1.92592994438723585305597794258492732e-34F128;__FLT128_DENORM_MIN__;6.47517511943802511092443895822764655e-4966F128;__FLT128_HAS_DENORM__;1;__FLT128_HAS_INFINITY__;1;__FLT128_HAS_QUIET_NAN__;1;__FLT32X_MANT_DIG__;53;__FLT32X_DIG__;15;__FLT32X_MIN_EXP__;(-1021);__FLT32X_MIN_10_EXP__;(-307);__FLT32X_MAX_EXP__;1024;__FLT32X_MAX_10_EXP__;308;__FLT32X_DECIMAL_DIG__;17;__FLT32X_MAX__;1.79769313486231570814527423731704357e+308F32x;__FLT32X_MIN__;2.22507385850720138309023271733240406e-308F32x;__FLT32X_EPSILON__;2.22044604925031308084726333618164062e-16F32x;__FLT32X_DENORM_MIN__;4.94065645841246544176568792868221372e-324F32x;__FLT32X_HAS_DENORM__;1;__FLT32X_HAS_INFINITY__;1;__FLT32X_HAS_QUIET_NAN__;1;__FLT64X_MANT_DIG__;64;__FLT64X_DIG__;18;__FLT64X_MIN_EXP__;(-16381);__FLT64X_MIN_10_EXP__;(-4931);__FLT64X_MAX_EXP__;16384;__FLT64X_MAX_10_EXP__;4932;__FLT64X_DECIMAL_DIG__;21;__FLT64X_MAX__;1.18973149535723176502126385303097021e+4932F64x;__FLT64X_MIN__;3.36210314311209350626267781732175260e-4932F64x;__FLT64X_EPSILON__;1.08420217248550443400745280086994171e-19F64x;__FLT64X_DENORM_MIN__;3.64519953188247460252840593361941982e-4951F64x;__FLT64X_HAS_DENORM__;1;__FLT64X_HAS_INFINITY__;1;__FLT64X_HAS_QUIET_NAN__;1;__DEC32_MANT_DIG__;7;__DEC32_MIN_EXP__;(-94);__DEC32_MAX_EXP__;97;__DEC32_MIN__;1E-95DF;__DEC32_MAX__;9.999999E96DF;__DEC32_EPSILON__;1E-6DF;__DEC32_SUBNORMAL_MIN__;0.000001E-95DF;__DEC64_MANT_DIG__;16;__DEC64_MIN_EXP__;(-382);__DEC64_MAX_EXP__;385;__DEC64_MIN__;1E-383DD;__DEC64_MAX__;9.999999999999999E384DD;__DEC64_EPSILON__;1E-15DD;__DEC64_SUBNORMAL_MIN__;0.000000000000001E-383DD;__DEC128_MANT_DIG__;34;__DEC128_MIN_EXP__;(-6142);__DEC128_MAX_EXP__;6145;__DEC128_MIN__;1E-6143DL;__DEC128_MAX__;9.999999999999999999999999999999999E6144DL;__DEC128_EPSILON__;1E-33DL;__DEC128_SUBNORMAL_MIN__;0.000000000000000000000000000000001E-6143DL;__REGISTER_PREFIX__; ;__USER_LABEL_PREFIX__; ;__GNUC_STDC_INLINE__;1;__NO_INLINE__;1;__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1;1;__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2;1;__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4;1;__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8;1;__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16;1;__GCC_ATOMIC_BOOL_LOCK_FREE;2;__GCC_ATOMIC_CHAR_LOCK_FREE;2;__GCC_ATOMIC_CHAR16_T_LOCK_FREE;2;__GCC_ATOMIC_CHAR32_T_LOCK_FREE;2;__GCC_ATOMIC_WCHAR_T_LOCK_FREE;2;__GCC_ATOMIC_SHORT_LOCK_FREE;2;__GCC_ATOMIC_INT_LOCK_FREE;2;__GCC_ATOMIC_LONG_LOCK_FREE;2;__GCC_ATOMIC_LLONG_LOCK_FREE;2;__GCC_ATOMIC_TEST_AND_SET_TRUEVAL;1;__GCC_ATOMIC_POINTER_LOCK_FREE;2;__PRAGMA_REDEFINE_EXTNAME;1;__SIZEOF_INT128__;16;__SIZEOF_WCHAR_T__;2;__SIZEOF_WINT_T__;2;__SIZEOF_PTRDIFF_T__;8;__amd64;1;__amd64__;1;__x86_64;1;__x86_64__;1;__SIZEOF_FLOAT80__;16;__SIZEOF_FLOAT128__;16;__ATOMIC_HLE_ACQUIRE;65536;__ATOMIC_HLE_RELEASE;131072;__GCC_ASM_FLAG_OUTPUTS__;1;__nocona;1;__nocona__;1;__tune_core2__;1;__code_model_medium__;1;__MMX__;1;__SSE__;1;__SSE2__;1;__SSE3__;1;__FXSR__;1;__SSE_MATH__;1;__SSE2_MATH__;1;__SEG_FS;1;__SEG_GS;1;__SEH__;1;__stdcall;__attribute__((__stdcall__));__fastcall;__attribute__((__fastcall__));__thiscall;__attribute__((__thiscall__));__cdecl;__attribute__((__cdecl__));_stdcall;__attribute__((__stdcall__));_fastcall;__attribute__((__fastcall__));_thiscall;__attribute__((__thiscall__));_cdecl;__attribute__((__cdecl__));__GXX_MERGED_TYPEINFO_NAMES;0;__GXX_TYPEINFO_EQUALITY_INLINE;0;__MSVCRT__;1;__MINGW32__;1;_WIN32;1;__WIN32;1;__WIN32__;1;WIN32;1;__WINNT;1;__WINNT__;1;WINNT;1;_INTEGRAL_MAX_BITS;64;__MINGW64__;1;__WIN64;1;__WIN64__;1;WIN64;1;_WIN64;1;__declspec(x);__attribute__((x));__DECIMAL_BID_FORMAT__;1;_REENTRANT;1 +//C compiler system include directories +CMAKE_EXTRA_GENERATOR_C_SYSTEM_INCLUDE_DIRS:INTERNAL=C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include-fixed;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/include +//Name of generator. +CMAKE_GENERATOR:INTERNAL=MinGW Makefiles +//Generator instance identifier. +CMAKE_GENERATOR_INSTANCE:INTERNAL= +//Name of generator platform. +CMAKE_GENERATOR_PLATFORM:INTERNAL= +//Name of generator toolset. +CMAKE_GENERATOR_TOOLSET:INTERNAL= +//Source directory with the top level CMakeLists.txt file for this +// project +CMAKE_HOME_DIRECTORY:INTERNAL=D:/2021_2/cids-server +//ADVANCED property for variable: CMAKE_LINKER +CMAKE_LINKER-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MAKE_PROGRAM +CMAKE_MAKE_PROGRAM-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS +CMAKE_MODULE_LINKER_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_DEBUG +CMAKE_MODULE_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL +CMAKE_MODULE_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_RELEASE +CMAKE_MODULE_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO +CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_NM +CMAKE_NM-ADVANCED:INTERNAL=1 +//number of local generators +CMAKE_NUMBER_OF_MAKEFILES:INTERNAL=1 +//ADVANCED property for variable: CMAKE_OBJCOPY +CMAKE_OBJCOPY-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_OBJDUMP +CMAKE_OBJDUMP-ADVANCED:INTERNAL=1 +//Platform information initialized +CMAKE_PLATFORM_INFO_INITIALIZED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_RANLIB +CMAKE_RANLIB-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_RC_COMPILER +CMAKE_RC_COMPILER-ADVANCED:INTERNAL=1 +CMAKE_RC_COMPILER_WORKS:INTERNAL=1 +//ADVANCED property for variable: CMAKE_RC_FLAGS +CMAKE_RC_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_RC_FLAGS_DEBUG +CMAKE_RC_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_RC_FLAGS_MINSIZEREL +CMAKE_RC_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_RC_FLAGS_RELEASE +CMAKE_RC_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_RC_FLAGS_RELWITHDEBINFO +CMAKE_RC_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_READELF +CMAKE_READELF-ADVANCED:INTERNAL=1 +//Path to CMake installation. +CMAKE_ROOT:INTERNAL=C:/Users/XM/AppData/Local/JetBrains/Toolbox/apps/CLion/ch-0/211.7142.21/bin/cmake/win/share/cmake-3.19 +//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS +CMAKE_SHARED_LINKER_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_DEBUG +CMAKE_SHARED_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL +CMAKE_SHARED_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_RELEASE +CMAKE_SHARED_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO +CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SKIP_INSTALL_RPATH +CMAKE_SKIP_INSTALL_RPATH-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_SKIP_RPATH +CMAKE_SKIP_RPATH-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS +CMAKE_STATIC_LINKER_FLAGS-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_DEBUG +CMAKE_STATIC_LINKER_FLAGS_DEBUG-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL +CMAKE_STATIC_LINKER_FLAGS_MINSIZEREL-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_RELEASE +CMAKE_STATIC_LINKER_FLAGS_RELEASE-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO +CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_STRIP +CMAKE_STRIP-ADVANCED:INTERNAL=1 +//ADVANCED property for variable: CMAKE_VERBOSE_MAKEFILE +CMAKE_VERBOSE_MAKEFILE-ADVANCED:INTERNAL=1 + diff --git a/cmake-build-debug/CMakeFiles/3.19.2/CMakeCCompiler.cmake b/cmake-build-debug/CMakeFiles/3.19.2/CMakeCCompiler.cmake new file mode 100644 index 0000000..67f5999 --- /dev/null +++ b/cmake-build-debug/CMakeFiles/3.19.2/CMakeCCompiler.cmake @@ -0,0 +1,77 @@ +set(CMAKE_C_COMPILER "C:/BC/C/mingw64/bin/gcc.exe") +set(CMAKE_C_COMPILER_ARG1 "") +set(CMAKE_C_COMPILER_ID "GNU") +set(CMAKE_C_COMPILER_VERSION "8.1.0") +set(CMAKE_C_COMPILER_VERSION_INTERNAL "") +set(CMAKE_C_COMPILER_WRAPPER "") +set(CMAKE_C_STANDARD_COMPUTED_DEFAULT "11") +set(CMAKE_C_COMPILE_FEATURES "c_std_90;c_function_prototypes;c_std_99;c_restrict;c_variadic_macros;c_std_11;c_static_assert") +set(CMAKE_C90_COMPILE_FEATURES "c_std_90;c_function_prototypes") +set(CMAKE_C99_COMPILE_FEATURES "c_std_99;c_restrict;c_variadic_macros") +set(CMAKE_C11_COMPILE_FEATURES "c_std_11;c_static_assert") + +set(CMAKE_C_PLATFORM_ID "MinGW") +set(CMAKE_C_SIMULATE_ID "") +set(CMAKE_C_COMPILER_FRONTEND_VARIANT "") +set(CMAKE_C_SIMULATE_VERSION "") + + + + +set(CMAKE_AR "C:/BC/C/mingw64/bin/ar.exe") +set(CMAKE_C_COMPILER_AR "C:/BC/C/mingw64/bin/gcc-ar.exe") +set(CMAKE_RANLIB "C:/BC/C/mingw64/bin/ranlib.exe") +set(CMAKE_C_COMPILER_RANLIB "C:/BC/C/mingw64/bin/gcc-ranlib.exe") +set(CMAKE_LINKER "C:/BC/C/mingw64/bin/ld.exe") +set(CMAKE_MT "") +set(CMAKE_COMPILER_IS_GNUCC 1) +set(CMAKE_C_COMPILER_LOADED 1) +set(CMAKE_C_COMPILER_WORKS TRUE) +set(CMAKE_C_ABI_COMPILED TRUE) +set(CMAKE_COMPILER_IS_MINGW 1) +set(CMAKE_COMPILER_IS_CYGWIN ) +if(CMAKE_COMPILER_IS_CYGWIN) + set(CYGWIN 1) + set(UNIX 1) +endif() + +set(CMAKE_C_COMPILER_ENV_VAR "CC") + +if(CMAKE_COMPILER_IS_MINGW) + set(MINGW 1) +endif() +set(CMAKE_C_COMPILER_ID_RUN 1) +set(CMAKE_C_SOURCE_FILE_EXTENSIONS c;m) +set(CMAKE_C_IGNORE_EXTENSIONS h;H;o;O;obj;OBJ;def;DEF;rc;RC) +set(CMAKE_C_LINKER_PREFERENCE 10) + +# Save compiler ABI information. +set(CMAKE_C_SIZEOF_DATA_PTR "8") +set(CMAKE_C_COMPILER_ABI "") +set(CMAKE_C_LIBRARY_ARCHITECTURE "") + +if(CMAKE_C_SIZEOF_DATA_PTR) + set(CMAKE_SIZEOF_VOID_P "${CMAKE_C_SIZEOF_DATA_PTR}") +endif() + +if(CMAKE_C_COMPILER_ABI) + set(CMAKE_INTERNAL_PLATFORM_ABI "${CMAKE_C_COMPILER_ABI}") +endif() + +if(CMAKE_C_LIBRARY_ARCHITECTURE) + set(CMAKE_LIBRARY_ARCHITECTURE "") +endif() + +set(CMAKE_C_CL_SHOWINCLUDES_PREFIX "") +if(CMAKE_C_CL_SHOWINCLUDES_PREFIX) + set(CMAKE_CL_SHOWINCLUDES_PREFIX "${CMAKE_C_CL_SHOWINCLUDES_PREFIX}") +endif() + + + + + +set(CMAKE_C_IMPLICIT_INCLUDE_DIRECTORIES "C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include;C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include-fixed;C:/BC/C/mingw64/x86_64-w64-mingw32/include") +set(CMAKE_C_IMPLICIT_LINK_LIBRARIES "mingw32;gcc;moldname;mingwex;pthread;advapi32;shell32;user32;kernel32;iconv;mingw32;gcc;moldname;mingwex") +set(CMAKE_C_IMPLICIT_LINK_DIRECTORIES "C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0;C:/BC/C/mingw64/lib/gcc;C:/BC/C/mingw64/x86_64-w64-mingw32/lib;C:/BC/C/mingw64/lib") +set(CMAKE_C_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "") diff --git a/cmake-build-debug/CMakeFiles/3.19.2/CMakeCXXCompiler.cmake b/cmake-build-debug/CMakeFiles/3.19.2/CMakeCXXCompiler.cmake new file mode 100644 index 0000000..1766f01 --- /dev/null +++ b/cmake-build-debug/CMakeFiles/3.19.2/CMakeCXXCompiler.cmake @@ -0,0 +1,89 @@ +set(CMAKE_CXX_COMPILER "C:/BC/C/mingw64/bin/g++.exe") +set(CMAKE_CXX_COMPILER_ARG1 "") +set(CMAKE_CXX_COMPILER_ID "GNU") +set(CMAKE_CXX_COMPILER_VERSION "8.1.0") +set(CMAKE_CXX_COMPILER_VERSION_INTERNAL "") +set(CMAKE_CXX_COMPILER_WRAPPER "") +set(CMAKE_CXX_STANDARD_COMPUTED_DEFAULT "14") +set(CMAKE_CXX_COMPILE_FEATURES "cxx_std_98;cxx_template_template_parameters;cxx_std_11;cxx_alias_templates;cxx_alignas;cxx_alignof;cxx_attributes;cxx_auto_type;cxx_constexpr;cxx_decltype;cxx_decltype_incomplete_return_types;cxx_default_function_template_args;cxx_defaulted_functions;cxx_defaulted_move_initializers;cxx_delegating_constructors;cxx_deleted_functions;cxx_enum_forward_declarations;cxx_explicit_conversions;cxx_extended_friend_declarations;cxx_extern_templates;cxx_final;cxx_func_identifier;cxx_generalized_initializers;cxx_inheriting_constructors;cxx_inline_namespaces;cxx_lambdas;cxx_local_type_template_args;cxx_long_long_type;cxx_noexcept;cxx_nonstatic_member_init;cxx_nullptr;cxx_override;cxx_range_for;cxx_raw_string_literals;cxx_reference_qualified_functions;cxx_right_angle_brackets;cxx_rvalue_references;cxx_sizeof_member;cxx_static_assert;cxx_strong_enums;cxx_thread_local;cxx_trailing_return_types;cxx_unicode_literals;cxx_uniform_initialization;cxx_unrestricted_unions;cxx_user_literals;cxx_variadic_macros;cxx_variadic_templates;cxx_std_14;cxx_aggregate_default_initializers;cxx_attribute_deprecated;cxx_binary_literals;cxx_contextual_conversions;cxx_decltype_auto;cxx_digit_separators;cxx_generic_lambdas;cxx_lambda_init_captures;cxx_relaxed_constexpr;cxx_return_type_deduction;cxx_variable_templates;cxx_std_17;cxx_std_20") +set(CMAKE_CXX98_COMPILE_FEATURES "cxx_std_98;cxx_template_template_parameters") +set(CMAKE_CXX11_COMPILE_FEATURES "cxx_std_11;cxx_alias_templates;cxx_alignas;cxx_alignof;cxx_attributes;cxx_auto_type;cxx_constexpr;cxx_decltype;cxx_decltype_incomplete_return_types;cxx_default_function_template_args;cxx_defaulted_functions;cxx_defaulted_move_initializers;cxx_delegating_constructors;cxx_deleted_functions;cxx_enum_forward_declarations;cxx_explicit_conversions;cxx_extended_friend_declarations;cxx_extern_templates;cxx_final;cxx_func_identifier;cxx_generalized_initializers;cxx_inheriting_constructors;cxx_inline_namespaces;cxx_lambdas;cxx_local_type_template_args;cxx_long_long_type;cxx_noexcept;cxx_nonstatic_member_init;cxx_nullptr;cxx_override;cxx_range_for;cxx_raw_string_literals;cxx_reference_qualified_functions;cxx_right_angle_brackets;cxx_rvalue_references;cxx_sizeof_member;cxx_static_assert;cxx_strong_enums;cxx_thread_local;cxx_trailing_return_types;cxx_unicode_literals;cxx_uniform_initialization;cxx_unrestricted_unions;cxx_user_literals;cxx_variadic_macros;cxx_variadic_templates") +set(CMAKE_CXX14_COMPILE_FEATURES "cxx_std_14;cxx_aggregate_default_initializers;cxx_attribute_deprecated;cxx_binary_literals;cxx_contextual_conversions;cxx_decltype_auto;cxx_digit_separators;cxx_generic_lambdas;cxx_lambda_init_captures;cxx_relaxed_constexpr;cxx_return_type_deduction;cxx_variable_templates") +set(CMAKE_CXX17_COMPILE_FEATURES "cxx_std_17") +set(CMAKE_CXX20_COMPILE_FEATURES "cxx_std_20") + +set(CMAKE_CXX_PLATFORM_ID "MinGW") +set(CMAKE_CXX_SIMULATE_ID "") +set(CMAKE_CXX_COMPILER_FRONTEND_VARIANT "") +set(CMAKE_CXX_SIMULATE_VERSION "") + + + + +set(CMAKE_AR "C:/BC/C/mingw64/bin/ar.exe") +set(CMAKE_CXX_COMPILER_AR "C:/BC/C/mingw64/bin/gcc-ar.exe") +set(CMAKE_RANLIB "C:/BC/C/mingw64/bin/ranlib.exe") +set(CMAKE_CXX_COMPILER_RANLIB "C:/BC/C/mingw64/bin/gcc-ranlib.exe") +set(CMAKE_LINKER "C:/BC/C/mingw64/bin/ld.exe") +set(CMAKE_MT "") +set(CMAKE_COMPILER_IS_GNUCXX 1) +set(CMAKE_CXX_COMPILER_LOADED 1) +set(CMAKE_CXX_COMPILER_WORKS TRUE) +set(CMAKE_CXX_ABI_COMPILED TRUE) +set(CMAKE_COMPILER_IS_MINGW 1) +set(CMAKE_COMPILER_IS_CYGWIN ) +if(CMAKE_COMPILER_IS_CYGWIN) + set(CYGWIN 1) + set(UNIX 1) +endif() + +set(CMAKE_CXX_COMPILER_ENV_VAR "CXX") + +if(CMAKE_COMPILER_IS_MINGW) + set(MINGW 1) +endif() +set(CMAKE_CXX_COMPILER_ID_RUN 1) +set(CMAKE_CXX_SOURCE_FILE_EXTENSIONS C;M;c++;cc;cpp;cxx;m;mm;CPP) +set(CMAKE_CXX_IGNORE_EXTENSIONS inl;h;hpp;HPP;H;o;O;obj;OBJ;def;DEF;rc;RC) + +foreach (lang C OBJC OBJCXX) + if (CMAKE_${lang}_COMPILER_ID_RUN) + foreach(extension IN LISTS CMAKE_${lang}_SOURCE_FILE_EXTENSIONS) + list(REMOVE_ITEM CMAKE_CXX_SOURCE_FILE_EXTENSIONS ${extension}) + endforeach() + endif() +endforeach() + +set(CMAKE_CXX_LINKER_PREFERENCE 30) +set(CMAKE_CXX_LINKER_PREFERENCE_PROPAGATES 1) + +# Save compiler ABI information. +set(CMAKE_CXX_SIZEOF_DATA_PTR "8") +set(CMAKE_CXX_COMPILER_ABI "") +set(CMAKE_CXX_LIBRARY_ARCHITECTURE "") + +if(CMAKE_CXX_SIZEOF_DATA_PTR) + set(CMAKE_SIZEOF_VOID_P "${CMAKE_CXX_SIZEOF_DATA_PTR}") +endif() + +if(CMAKE_CXX_COMPILER_ABI) + set(CMAKE_INTERNAL_PLATFORM_ABI "${CMAKE_CXX_COMPILER_ABI}") +endif() + +if(CMAKE_CXX_LIBRARY_ARCHITECTURE) + set(CMAKE_LIBRARY_ARCHITECTURE "") +endif() + +set(CMAKE_CXX_CL_SHOWINCLUDES_PREFIX "") +if(CMAKE_CXX_CL_SHOWINCLUDES_PREFIX) + set(CMAKE_CL_SHOWINCLUDES_PREFIX "${CMAKE_CXX_CL_SHOWINCLUDES_PREFIX}") +endif() + + + + + +set(CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES "C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++;C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/x86_64-w64-mingw32;C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/backward;C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include;C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include-fixed;C:/BC/C/mingw64/x86_64-w64-mingw32/include") +set(CMAKE_CXX_IMPLICIT_LINK_LIBRARIES "stdc++;mingw32;gcc_s;gcc;moldname;mingwex;pthread;advapi32;shell32;user32;kernel32;iconv;mingw32;gcc_s;gcc;moldname;mingwex") +set(CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES "C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0;C:/BC/C/mingw64/lib/gcc;C:/BC/C/mingw64/x86_64-w64-mingw32/lib;C:/BC/C/mingw64/lib") +set(CMAKE_CXX_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "") diff --git a/cmake-build-debug/CMakeFiles/3.19.2/CMakeDetermineCompilerABI_C.bin b/cmake-build-debug/CMakeFiles/3.19.2/CMakeDetermineCompilerABI_C.bin new file mode 100644 index 0000000..89ba4ac Binary files /dev/null and b/cmake-build-debug/CMakeFiles/3.19.2/CMakeDetermineCompilerABI_C.bin differ diff --git a/cmake-build-debug/CMakeFiles/3.19.2/CMakeDetermineCompilerABI_CXX.bin b/cmake-build-debug/CMakeFiles/3.19.2/CMakeDetermineCompilerABI_CXX.bin new file mode 100644 index 0000000..f47a09a Binary files /dev/null and b/cmake-build-debug/CMakeFiles/3.19.2/CMakeDetermineCompilerABI_CXX.bin differ diff --git a/cmake-build-debug/CMakeFiles/3.19.2/CMakeRCCompiler.cmake b/cmake-build-debug/CMakeFiles/3.19.2/CMakeRCCompiler.cmake new file mode 100644 index 0000000..9a9eb15 --- /dev/null +++ b/cmake-build-debug/CMakeFiles/3.19.2/CMakeRCCompiler.cmake @@ -0,0 +1,6 @@ +set(CMAKE_RC_COMPILER "C:/BC/C/mingw64/bin/windres.exe") +set(CMAKE_RC_COMPILER_ARG1 "") +set(CMAKE_RC_COMPILER_LOADED 1) +set(CMAKE_RC_SOURCE_FILE_EXTENSIONS rc;RC) +set(CMAKE_RC_OUTPUT_EXTENSION .obj) +set(CMAKE_RC_COMPILER_ENV_VAR "RC") diff --git a/cmake-build-debug/CMakeFiles/3.19.2/CMakeSystem.cmake b/cmake-build-debug/CMakeFiles/3.19.2/CMakeSystem.cmake new file mode 100644 index 0000000..1bcc695 --- /dev/null +++ b/cmake-build-debug/CMakeFiles/3.19.2/CMakeSystem.cmake @@ -0,0 +1,15 @@ +set(CMAKE_HOST_SYSTEM "Windows-10.0.19041") +set(CMAKE_HOST_SYSTEM_NAME "Windows") +set(CMAKE_HOST_SYSTEM_VERSION "10.0.19041") +set(CMAKE_HOST_SYSTEM_PROCESSOR "AMD64") + + + +set(CMAKE_SYSTEM "Windows-10.0.19041") +set(CMAKE_SYSTEM_NAME "Windows") +set(CMAKE_SYSTEM_VERSION "10.0.19041") +set(CMAKE_SYSTEM_PROCESSOR "AMD64") + +set(CMAKE_CROSSCOMPILING "FALSE") + +set(CMAKE_SYSTEM_LOADED 1) diff --git a/cmake-build-debug/CMakeFiles/3.19.2/CompilerIdC/CMakeCCompilerId.c b/cmake-build-debug/CMakeFiles/3.19.2/CompilerIdC/CMakeCCompilerId.c new file mode 100644 index 0000000..c126ec7 --- /dev/null +++ b/cmake-build-debug/CMakeFiles/3.19.2/CompilerIdC/CMakeCCompilerId.c @@ -0,0 +1,691 @@ +#ifdef __cplusplus +# error "A C++ compiler has been selected for C." +#endif + +#if defined(__18CXX) +# define ID_VOID_MAIN +#endif +#if defined(__CLASSIC_C__) +/* cv-qualifiers did not exist in K&R C */ +# define const +# define volatile +#endif + + +/* Version number components: V=Version, R=Revision, P=Patch + Version date components: YYYY=Year, MM=Month, DD=Day */ + +#if defined(__INTEL_COMPILER) || defined(__ICC) +# define COMPILER_ID "Intel" +# if defined(_MSC_VER) +# define SIMULATE_ID "MSVC" +# endif +# if defined(__GNUC__) +# define SIMULATE_ID "GNU" +# endif + /* __INTEL_COMPILER = VRP */ +# define COMPILER_VERSION_MAJOR DEC(__INTEL_COMPILER/100) +# define COMPILER_VERSION_MINOR DEC(__INTEL_COMPILER/10 % 10) +# if defined(__INTEL_COMPILER_UPDATE) +# define COMPILER_VERSION_PATCH DEC(__INTEL_COMPILER_UPDATE) +# else +# define COMPILER_VERSION_PATCH DEC(__INTEL_COMPILER % 10) +# endif +# if defined(__INTEL_COMPILER_BUILD_DATE) + /* __INTEL_COMPILER_BUILD_DATE = YYYYMMDD */ +# define COMPILER_VERSION_TWEAK DEC(__INTEL_COMPILER_BUILD_DATE) +# endif +# if defined(_MSC_VER) + /* _MSC_VER = VVRR */ +# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100) +# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100) +# endif +# if defined(__GNUC__) +# define SIMULATE_VERSION_MAJOR DEC(__GNUC__) +# elif defined(__GNUG__) +# define SIMULATE_VERSION_MAJOR DEC(__GNUG__) +# endif +# if defined(__GNUC_MINOR__) +# define SIMULATE_VERSION_MINOR DEC(__GNUC_MINOR__) +# endif +# if defined(__GNUC_PATCHLEVEL__) +# define SIMULATE_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__) +# endif + +#elif defined(__PATHCC__) +# define COMPILER_ID "PathScale" +# define COMPILER_VERSION_MAJOR DEC(__PATHCC__) +# define COMPILER_VERSION_MINOR DEC(__PATHCC_MINOR__) +# if defined(__PATHCC_PATCHLEVEL__) +# define COMPILER_VERSION_PATCH DEC(__PATHCC_PATCHLEVEL__) +# endif + +#elif defined(__BORLANDC__) && defined(__CODEGEARC_VERSION__) +# define COMPILER_ID "Embarcadero" +# define COMPILER_VERSION_MAJOR HEX(__CODEGEARC_VERSION__>>24 & 0x00FF) +# define COMPILER_VERSION_MINOR HEX(__CODEGEARC_VERSION__>>16 & 0x00FF) +# define COMPILER_VERSION_PATCH DEC(__CODEGEARC_VERSION__ & 0xFFFF) + +#elif defined(__BORLANDC__) +# define COMPILER_ID "Borland" + /* __BORLANDC__ = 0xVRR */ +# define COMPILER_VERSION_MAJOR HEX(__BORLANDC__>>8) +# define COMPILER_VERSION_MINOR HEX(__BORLANDC__ & 0xFF) + +#elif defined(__WATCOMC__) && __WATCOMC__ < 1200 +# define COMPILER_ID "Watcom" + /* __WATCOMC__ = VVRR */ +# define COMPILER_VERSION_MAJOR DEC(__WATCOMC__ / 100) +# define COMPILER_VERSION_MINOR DEC((__WATCOMC__ / 10) % 10) +# if (__WATCOMC__ % 10) > 0 +# define COMPILER_VERSION_PATCH DEC(__WATCOMC__ % 10) +# endif + +#elif defined(__WATCOMC__) +# define COMPILER_ID "OpenWatcom" + /* __WATCOMC__ = VVRP + 1100 */ +# define COMPILER_VERSION_MAJOR DEC((__WATCOMC__ - 1100) / 100) +# define COMPILER_VERSION_MINOR DEC((__WATCOMC__ / 10) % 10) +# if (__WATCOMC__ % 10) > 0 +# define COMPILER_VERSION_PATCH DEC(__WATCOMC__ % 10) +# endif + +#elif defined(__SUNPRO_C) +# define COMPILER_ID "SunPro" +# if __SUNPRO_C >= 0x5100 + /* __SUNPRO_C = 0xVRRP */ +# define COMPILER_VERSION_MAJOR HEX(__SUNPRO_C>>12) +# define COMPILER_VERSION_MINOR HEX(__SUNPRO_C>>4 & 0xFF) +# define COMPILER_VERSION_PATCH HEX(__SUNPRO_C & 0xF) +# else + /* __SUNPRO_CC = 0xVRP */ +# define COMPILER_VERSION_MAJOR HEX(__SUNPRO_C>>8) +# define COMPILER_VERSION_MINOR HEX(__SUNPRO_C>>4 & 0xF) +# define COMPILER_VERSION_PATCH HEX(__SUNPRO_C & 0xF) +# endif + +#elif defined(__HP_cc) +# define COMPILER_ID "HP" + /* __HP_cc = VVRRPP */ +# define COMPILER_VERSION_MAJOR DEC(__HP_cc/10000) +# define COMPILER_VERSION_MINOR DEC(__HP_cc/100 % 100) +# define COMPILER_VERSION_PATCH DEC(__HP_cc % 100) + +#elif defined(__DECC) +# define COMPILER_ID "Compaq" + /* __DECC_VER = VVRRTPPPP */ +# define COMPILER_VERSION_MAJOR DEC(__DECC_VER/10000000) +# define COMPILER_VERSION_MINOR DEC(__DECC_VER/100000 % 100) +# define COMPILER_VERSION_PATCH DEC(__DECC_VER % 10000) + +#elif defined(__IBMC__) && defined(__COMPILER_VER__) +# define COMPILER_ID "zOS" + /* __IBMC__ = VRP */ +# define COMPILER_VERSION_MAJOR DEC(__IBMC__/100) +# define COMPILER_VERSION_MINOR DEC(__IBMC__/10 % 10) +# define COMPILER_VERSION_PATCH DEC(__IBMC__ % 10) + +#elif defined(__ibmxl__) && defined(__clang__) +# define COMPILER_ID "XLClang" +# define COMPILER_VERSION_MAJOR DEC(__ibmxl_version__) +# define COMPILER_VERSION_MINOR DEC(__ibmxl_release__) +# define COMPILER_VERSION_PATCH DEC(__ibmxl_modification__) +# define COMPILER_VERSION_TWEAK DEC(__ibmxl_ptf_fix_level__) + + +#elif defined(__IBMC__) && !defined(__COMPILER_VER__) && __IBMC__ >= 800 +# define COMPILER_ID "XL" + /* __IBMC__ = VRP */ +# define COMPILER_VERSION_MAJOR DEC(__IBMC__/100) +# define COMPILER_VERSION_MINOR DEC(__IBMC__/10 % 10) +# define COMPILER_VERSION_PATCH DEC(__IBMC__ % 10) + +#elif defined(__IBMC__) && !defined(__COMPILER_VER__) && __IBMC__ < 800 +# define COMPILER_ID "VisualAge" + /* __IBMC__ = VRP */ +# define COMPILER_VERSION_MAJOR DEC(__IBMC__/100) +# define COMPILER_VERSION_MINOR DEC(__IBMC__/10 % 10) +# define COMPILER_VERSION_PATCH DEC(__IBMC__ % 10) + +#elif defined(__PGI) +# define COMPILER_ID "PGI" +# define COMPILER_VERSION_MAJOR DEC(__PGIC__) +# define COMPILER_VERSION_MINOR DEC(__PGIC_MINOR__) +# if defined(__PGIC_PATCHLEVEL__) +# define COMPILER_VERSION_PATCH DEC(__PGIC_PATCHLEVEL__) +# endif + +#elif defined(_CRAYC) +# define COMPILER_ID "Cray" +# define COMPILER_VERSION_MAJOR DEC(_RELEASE_MAJOR) +# define COMPILER_VERSION_MINOR DEC(_RELEASE_MINOR) + +#elif defined(__TI_COMPILER_VERSION__) +# define COMPILER_ID "TI" + /* __TI_COMPILER_VERSION__ = VVVRRRPPP */ +# define COMPILER_VERSION_MAJOR DEC(__TI_COMPILER_VERSION__/1000000) +# define COMPILER_VERSION_MINOR DEC(__TI_COMPILER_VERSION__/1000 % 1000) +# define COMPILER_VERSION_PATCH DEC(__TI_COMPILER_VERSION__ % 1000) + +#elif defined(__FUJITSU) || defined(__FCC_VERSION) || defined(__fcc_version) +# define COMPILER_ID "Fujitsu" + +#elif defined(__ghs__) +# define COMPILER_ID "GHS" +/* __GHS_VERSION_NUMBER = VVVVRP */ +# ifdef __GHS_VERSION_NUMBER +# define COMPILER_VERSION_MAJOR DEC(__GHS_VERSION_NUMBER / 100) +# define COMPILER_VERSION_MINOR DEC(__GHS_VERSION_NUMBER / 10 % 10) +# define COMPILER_VERSION_PATCH DEC(__GHS_VERSION_NUMBER % 10) +# endif + +#elif defined(__TINYC__) +# define COMPILER_ID "TinyCC" + +#elif defined(__BCC__) +# define COMPILER_ID "Bruce" + +#elif defined(__SCO_VERSION__) +# define COMPILER_ID "SCO" + +#elif defined(__ARMCC_VERSION) && !defined(__clang__) +# define COMPILER_ID "ARMCC" +#if __ARMCC_VERSION >= 1000000 + /* __ARMCC_VERSION = VRRPPPP */ + # define COMPILER_VERSION_MAJOR DEC(__ARMCC_VERSION/1000000) + # define COMPILER_VERSION_MINOR DEC(__ARMCC_VERSION/10000 % 100) + # define COMPILER_VERSION_PATCH DEC(__ARMCC_VERSION % 10000) +#else + /* __ARMCC_VERSION = VRPPPP */ + # define COMPILER_VERSION_MAJOR DEC(__ARMCC_VERSION/100000) + # define COMPILER_VERSION_MINOR DEC(__ARMCC_VERSION/10000 % 10) + # define COMPILER_VERSION_PATCH DEC(__ARMCC_VERSION % 10000) +#endif + + +#elif defined(__clang__) && defined(__apple_build_version__) +# define COMPILER_ID "AppleClang" +# if defined(_MSC_VER) +# define SIMULATE_ID "MSVC" +# endif +# define COMPILER_VERSION_MAJOR DEC(__clang_major__) +# define COMPILER_VERSION_MINOR DEC(__clang_minor__) +# define COMPILER_VERSION_PATCH DEC(__clang_patchlevel__) +# if defined(_MSC_VER) + /* _MSC_VER = VVRR */ +# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100) +# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100) +# endif +# define COMPILER_VERSION_TWEAK DEC(__apple_build_version__) + +#elif defined(__clang__) && defined(__ARMCOMPILER_VERSION) +# define COMPILER_ID "ARMClang" + # define COMPILER_VERSION_MAJOR DEC(__ARMCOMPILER_VERSION/1000000) + # define COMPILER_VERSION_MINOR DEC(__ARMCOMPILER_VERSION/10000 % 100) + # define COMPILER_VERSION_PATCH DEC(__ARMCOMPILER_VERSION % 10000) +# define COMPILER_VERSION_INTERNAL DEC(__ARMCOMPILER_VERSION) + +#elif defined(__clang__) +# define COMPILER_ID "Clang" +# if defined(_MSC_VER) +# define SIMULATE_ID "MSVC" +# endif +# define COMPILER_VERSION_MAJOR DEC(__clang_major__) +# define COMPILER_VERSION_MINOR DEC(__clang_minor__) +# define COMPILER_VERSION_PATCH DEC(__clang_patchlevel__) +# if defined(_MSC_VER) + /* _MSC_VER = VVRR */ +# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100) +# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100) +# endif + +#elif defined(__GNUC__) +# define COMPILER_ID "GNU" +# define COMPILER_VERSION_MAJOR DEC(__GNUC__) +# if defined(__GNUC_MINOR__) +# define COMPILER_VERSION_MINOR DEC(__GNUC_MINOR__) +# endif +# if defined(__GNUC_PATCHLEVEL__) +# define COMPILER_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__) +# endif + +#elif defined(_MSC_VER) +# define COMPILER_ID "MSVC" + /* _MSC_VER = VVRR */ +# define COMPILER_VERSION_MAJOR DEC(_MSC_VER / 100) +# define COMPILER_VERSION_MINOR DEC(_MSC_VER % 100) +# if defined(_MSC_FULL_VER) +# if _MSC_VER >= 1400 + /* _MSC_FULL_VER = VVRRPPPPP */ +# define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 100000) +# else + /* _MSC_FULL_VER = VVRRPPPP */ +# define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 10000) +# endif +# endif +# if defined(_MSC_BUILD) +# define COMPILER_VERSION_TWEAK DEC(_MSC_BUILD) +# endif + +#elif defined(__VISUALDSPVERSION__) || defined(__ADSPBLACKFIN__) || defined(__ADSPTS__) || defined(__ADSP21000__) +# define COMPILER_ID "ADSP" +#if defined(__VISUALDSPVERSION__) + /* __VISUALDSPVERSION__ = 0xVVRRPP00 */ +# define COMPILER_VERSION_MAJOR HEX(__VISUALDSPVERSION__>>24) +# define COMPILER_VERSION_MINOR HEX(__VISUALDSPVERSION__>>16 & 0xFF) +# define COMPILER_VERSION_PATCH HEX(__VISUALDSPVERSION__>>8 & 0xFF) +#endif + +#elif defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ICC) +# define COMPILER_ID "IAR" +# if defined(__VER__) && defined(__ICCARM__) +# define COMPILER_VERSION_MAJOR DEC((__VER__) / 1000000) +# define COMPILER_VERSION_MINOR DEC(((__VER__) / 1000) % 1000) +# define COMPILER_VERSION_PATCH DEC((__VER__) % 1000) +# define COMPILER_VERSION_INTERNAL DEC(__IAR_SYSTEMS_ICC__) +# elif defined(__VER__) && (defined(__ICCAVR__) || defined(__ICCRX__) || defined(__ICCRH850__) || defined(__ICCRL78__) || defined(__ICC430__) || defined(__ICCRISCV__) || defined(__ICCV850__) || defined(__ICC8051__)) +# define COMPILER_VERSION_MAJOR DEC((__VER__) / 100) +# define COMPILER_VERSION_MINOR DEC((__VER__) - (((__VER__) / 100)*100)) +# define COMPILER_VERSION_PATCH DEC(__SUBVERSION__) +# define COMPILER_VERSION_INTERNAL DEC(__IAR_SYSTEMS_ICC__) +# endif + +#elif defined(__SDCC_VERSION_MAJOR) || defined(SDCC) +# define COMPILER_ID "SDCC" +# if defined(__SDCC_VERSION_MAJOR) +# define COMPILER_VERSION_MAJOR DEC(__SDCC_VERSION_MAJOR) +# define COMPILER_VERSION_MINOR DEC(__SDCC_VERSION_MINOR) +# define COMPILER_VERSION_PATCH DEC(__SDCC_VERSION_PATCH) +# else + /* SDCC = VRP */ +# define COMPILER_VERSION_MAJOR DEC(SDCC/100) +# define COMPILER_VERSION_MINOR DEC(SDCC/10 % 10) +# define COMPILER_VERSION_PATCH DEC(SDCC % 10) +# endif + + +/* These compilers are either not known or too old to define an + identification macro. Try to identify the platform and guess that + it is the native compiler. */ +#elif defined(__hpux) || defined(__hpua) +# define COMPILER_ID "HP" + +#else /* unknown compiler */ +# define COMPILER_ID "" +#endif + +/* Construct the string literal in pieces to prevent the source from + getting matched. Store it in a pointer rather than an array + because some compilers will just produce instructions to fill the + array rather than assigning a pointer to a static array. */ +char const* info_compiler = "INFO" ":" "compiler[" COMPILER_ID "]"; +#ifdef SIMULATE_ID +char const* info_simulate = "INFO" ":" "simulate[" SIMULATE_ID "]"; +#endif + +#ifdef __QNXNTO__ +char const* qnxnto = "INFO" ":" "qnxnto[]"; +#endif + +#if defined(_CRAYC) || defined(__cray__) +char const *info_cray = "INFO" ":" "compiler_wrapper[CrayPrgEnv]"; +#endif + +#define STRINGIFY_HELPER(X) #X +#define STRINGIFY(X) STRINGIFY_HELPER(X) + +/* Identify known platforms by name. */ +#if defined(__linux) || defined(__linux__) || defined(linux) +# define PLATFORM_ID "Linux" + +#elif defined(__CYGWIN__) +# define PLATFORM_ID "Cygwin" + +#elif defined(__MINGW32__) +# define PLATFORM_ID "MinGW" + +#elif defined(__APPLE__) +# define PLATFORM_ID "Darwin" + +#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32) +# define PLATFORM_ID "Windows" + +#elif defined(__FreeBSD__) || defined(__FreeBSD) +# define PLATFORM_ID "FreeBSD" + +#elif defined(__NetBSD__) || defined(__NetBSD) +# define PLATFORM_ID "NetBSD" + +#elif defined(__OpenBSD__) || defined(__OPENBSD) +# define PLATFORM_ID "OpenBSD" + +#elif defined(__sun) || defined(sun) +# define PLATFORM_ID "SunOS" + +#elif defined(_AIX) || defined(__AIX) || defined(__AIX__) || defined(__aix) || defined(__aix__) +# define PLATFORM_ID "AIX" + +#elif defined(__hpux) || defined(__hpux__) +# define PLATFORM_ID "HP-UX" + +#elif defined(__HAIKU__) +# define PLATFORM_ID "Haiku" + +#elif defined(__BeOS) || defined(__BEOS__) || defined(_BEOS) +# define PLATFORM_ID "BeOS" + +#elif defined(__QNX__) || defined(__QNXNTO__) +# define PLATFORM_ID "QNX" + +#elif defined(__tru64) || defined(_tru64) || defined(__TRU64__) +# define PLATFORM_ID "Tru64" + +#elif defined(__riscos) || defined(__riscos__) +# define PLATFORM_ID "RISCos" + +#elif defined(__sinix) || defined(__sinix__) || defined(__SINIX__) +# define PLATFORM_ID "SINIX" + +#elif defined(__UNIX_SV__) +# define PLATFORM_ID "UNIX_SV" + +#elif defined(__bsdos__) +# define PLATFORM_ID "BSDOS" + +#elif defined(_MPRAS) || defined(MPRAS) +# define PLATFORM_ID "MP-RAS" + +#elif defined(__osf) || defined(__osf__) +# define PLATFORM_ID "OSF1" + +#elif defined(_SCO_SV) || defined(SCO_SV) || defined(sco_sv) +# define PLATFORM_ID "SCO_SV" + +#elif defined(__ultrix) || defined(__ultrix__) || defined(_ULTRIX) +# define PLATFORM_ID "ULTRIX" + +#elif defined(__XENIX__) || defined(_XENIX) || defined(XENIX) +# define PLATFORM_ID "Xenix" + +#elif defined(__WATCOMC__) +# if defined(__LINUX__) +# define PLATFORM_ID "Linux" + +# elif defined(__DOS__) +# define PLATFORM_ID "DOS" + +# elif defined(__OS2__) +# define PLATFORM_ID "OS2" + +# elif defined(__WINDOWS__) +# define PLATFORM_ID "Windows3x" + +# elif defined(__VXWORKS__) +# define PLATFORM_ID "VxWorks" + +# else /* unknown platform */ +# define PLATFORM_ID +# endif + +#elif defined(__INTEGRITY) +# if defined(INT_178B) +# define PLATFORM_ID "Integrity178" + +# else /* regular Integrity */ +# define PLATFORM_ID "Integrity" +# endif + +#else /* unknown platform */ +# define PLATFORM_ID + +#endif + +/* For windows compilers MSVC and Intel we can determine + the architecture of the compiler being used. This is because + the compilers do not have flags that can change the architecture, + but rather depend on which compiler is being used +*/ +#if defined(_WIN32) && defined(_MSC_VER) +# if defined(_M_IA64) +# define ARCHITECTURE_ID "IA64" + +# elif defined(_M_X64) || defined(_M_AMD64) +# define ARCHITECTURE_ID "x64" + +# elif defined(_M_IX86) +# define ARCHITECTURE_ID "X86" + +# elif defined(_M_ARM64) +# define ARCHITECTURE_ID "ARM64" + +# elif defined(_M_ARM) +# if _M_ARM == 4 +# define ARCHITECTURE_ID "ARMV4I" +# elif _M_ARM == 5 +# define ARCHITECTURE_ID "ARMV5I" +# else +# define ARCHITECTURE_ID "ARMV" STRINGIFY(_M_ARM) +# endif + +# elif defined(_M_MIPS) +# define ARCHITECTURE_ID "MIPS" + +# elif defined(_M_SH) +# define ARCHITECTURE_ID "SHx" + +# else /* unknown architecture */ +# define ARCHITECTURE_ID "" +# endif + +#elif defined(__WATCOMC__) +# if defined(_M_I86) +# define ARCHITECTURE_ID "I86" + +# elif defined(_M_IX86) +# define ARCHITECTURE_ID "X86" + +# else /* unknown architecture */ +# define ARCHITECTURE_ID "" +# endif + +#elif defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ICC) +# if defined(__ICCARM__) +# define ARCHITECTURE_ID "ARM" + +# elif defined(__ICCRX__) +# define ARCHITECTURE_ID "RX" + +# elif defined(__ICCRH850__) +# define ARCHITECTURE_ID "RH850" + +# elif defined(__ICCRL78__) +# define ARCHITECTURE_ID "RL78" + +# elif defined(__ICCRISCV__) +# define ARCHITECTURE_ID "RISCV" + +# elif defined(__ICCAVR__) +# define ARCHITECTURE_ID "AVR" + +# elif defined(__ICC430__) +# define ARCHITECTURE_ID "MSP430" + +# elif defined(__ICCV850__) +# define ARCHITECTURE_ID "V850" + +# elif defined(__ICC8051__) +# define ARCHITECTURE_ID "8051" + +# else /* unknown architecture */ +# define ARCHITECTURE_ID "" +# endif + +#elif defined(__ghs__) +# if defined(__PPC64__) +# define ARCHITECTURE_ID "PPC64" + +# elif defined(__ppc__) +# define ARCHITECTURE_ID "PPC" + +# elif defined(__ARM__) +# define ARCHITECTURE_ID "ARM" + +# elif defined(__x86_64__) +# define ARCHITECTURE_ID "x64" + +# elif defined(__i386__) +# define ARCHITECTURE_ID "X86" + +# else /* unknown architecture */ +# define ARCHITECTURE_ID "" +# endif + +#elif defined(__TI_COMPILER_VERSION__) +# if defined(__TI_ARM__) +# define ARCHITECTURE_ID "ARM" + +# elif defined(__MSP430__) +# define ARCHITECTURE_ID "MSP430" + +# elif defined(__TMS320C28XX__) +# define ARCHITECTURE_ID "TMS320C28x" + +# elif defined(__TMS320C6X__) || defined(_TMS320C6X) +# define ARCHITECTURE_ID "TMS320C6x" + +# else /* unknown architecture */ +# define ARCHITECTURE_ID "" +# endif + +#else +# define ARCHITECTURE_ID +#endif + +/* Convert integer to decimal digit literals. */ +#define DEC(n) \ + ('0' + (((n) / 10000000)%10)), \ + ('0' + (((n) / 1000000)%10)), \ + ('0' + (((n) / 100000)%10)), \ + ('0' + (((n) / 10000)%10)), \ + ('0' + (((n) / 1000)%10)), \ + ('0' + (((n) / 100)%10)), \ + ('0' + (((n) / 10)%10)), \ + ('0' + ((n) % 10)) + +/* Convert integer to hex digit literals. */ +#define HEX(n) \ + ('0' + ((n)>>28 & 0xF)), \ + ('0' + ((n)>>24 & 0xF)), \ + ('0' + ((n)>>20 & 0xF)), \ + ('0' + ((n)>>16 & 0xF)), \ + ('0' + ((n)>>12 & 0xF)), \ + ('0' + ((n)>>8 & 0xF)), \ + ('0' + ((n)>>4 & 0xF)), \ + ('0' + ((n) & 0xF)) + +/* Construct a string literal encoding the version number components. */ +#ifdef COMPILER_VERSION_MAJOR +char const info_version[] = { + 'I', 'N', 'F', 'O', ':', + 'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','[', + COMPILER_VERSION_MAJOR, +# ifdef COMPILER_VERSION_MINOR + '.', COMPILER_VERSION_MINOR, +# ifdef COMPILER_VERSION_PATCH + '.', COMPILER_VERSION_PATCH, +# ifdef COMPILER_VERSION_TWEAK + '.', COMPILER_VERSION_TWEAK, +# endif +# endif +# endif + ']','\0'}; +#endif + +/* Construct a string literal encoding the internal version number. */ +#ifdef COMPILER_VERSION_INTERNAL +char const info_version_internal[] = { + 'I', 'N', 'F', 'O', ':', + 'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','_', + 'i','n','t','e','r','n','a','l','[', + COMPILER_VERSION_INTERNAL,']','\0'}; +#endif + +/* Construct a string literal encoding the version number components. */ +#ifdef SIMULATE_VERSION_MAJOR +char const info_simulate_version[] = { + 'I', 'N', 'F', 'O', ':', + 's','i','m','u','l','a','t','e','_','v','e','r','s','i','o','n','[', + SIMULATE_VERSION_MAJOR, +# ifdef SIMULATE_VERSION_MINOR + '.', SIMULATE_VERSION_MINOR, +# ifdef SIMULATE_VERSION_PATCH + '.', SIMULATE_VERSION_PATCH, +# ifdef SIMULATE_VERSION_TWEAK + '.', SIMULATE_VERSION_TWEAK, +# endif +# endif +# endif + ']','\0'}; +#endif + +/* Construct the string literal in pieces to prevent the source from + getting matched. Store it in a pointer rather than an array + because some compilers will just produce instructions to fill the + array rather than assigning a pointer to a static array. */ +char const* info_platform = "INFO" ":" "platform[" PLATFORM_ID "]"; +char const* info_arch = "INFO" ":" "arch[" ARCHITECTURE_ID "]"; + + + +#if !defined(__STDC__) +# if (defined(_MSC_VER) && !defined(__clang__)) \ + || (defined(__ibmxl__) || defined(__IBMC__)) +# define C_DIALECT "90" +# else +# define C_DIALECT +# endif +#elif __STDC_VERSION__ >= 201000L +# define C_DIALECT "11" +#elif __STDC_VERSION__ >= 199901L +# define C_DIALECT "99" +#else +# define C_DIALECT "90" +#endif +const char* info_language_dialect_default = + "INFO" ":" "dialect_default[" C_DIALECT "]"; + +/*--------------------------------------------------------------------------*/ + +#ifdef ID_VOID_MAIN +void main() {} +#else +# if defined(__CLASSIC_C__) +int main(argc, argv) int argc; char *argv[]; +# else +int main(int argc, char* argv[]) +# endif +{ + int require = 0; + require += info_compiler[argc]; + require += info_platform[argc]; + require += info_arch[argc]; +#ifdef COMPILER_VERSION_MAJOR + require += info_version[argc]; +#endif +#ifdef COMPILER_VERSION_INTERNAL + require += info_version_internal[argc]; +#endif +#ifdef SIMULATE_ID + require += info_simulate[argc]; +#endif +#ifdef SIMULATE_VERSION_MAJOR + require += info_simulate_version[argc]; +#endif +#if defined(_CRAYC) || defined(__cray__) + require += info_cray[argc]; +#endif + require += info_language_dialect_default[argc]; + (void)argv; + return require; +} +#endif diff --git a/cmake-build-debug/CMakeFiles/3.19.2/CompilerIdC/a.exe b/cmake-build-debug/CMakeFiles/3.19.2/CompilerIdC/a.exe new file mode 100644 index 0000000..b361293 Binary files /dev/null and b/cmake-build-debug/CMakeFiles/3.19.2/CompilerIdC/a.exe differ diff --git a/cmake-build-debug/CMakeFiles/3.19.2/CompilerIdCXX/CMakeCXXCompilerId.cpp b/cmake-build-debug/CMakeFiles/3.19.2/CompilerIdCXX/CMakeCXXCompilerId.cpp new file mode 100644 index 0000000..0c63d62 --- /dev/null +++ b/cmake-build-debug/CMakeFiles/3.19.2/CompilerIdCXX/CMakeCXXCompilerId.cpp @@ -0,0 +1,680 @@ +/* This source file must have a .cpp extension so that all C++ compilers + recognize the extension without flags. Borland does not know .cxx for + example. */ +#ifndef __cplusplus +# error "A C compiler has been selected for C++." +#endif + + +/* Version number components: V=Version, R=Revision, P=Patch + Version date components: YYYY=Year, MM=Month, DD=Day */ + +#if defined(__COMO__) +# define COMPILER_ID "Comeau" + /* __COMO_VERSION__ = VRR */ +# define COMPILER_VERSION_MAJOR DEC(__COMO_VERSION__ / 100) +# define COMPILER_VERSION_MINOR DEC(__COMO_VERSION__ % 100) + +#elif defined(__INTEL_COMPILER) || defined(__ICC) +# define COMPILER_ID "Intel" +# if defined(_MSC_VER) +# define SIMULATE_ID "MSVC" +# endif +# if defined(__GNUC__) +# define SIMULATE_ID "GNU" +# endif + /* __INTEL_COMPILER = VRP */ +# define COMPILER_VERSION_MAJOR DEC(__INTEL_COMPILER/100) +# define COMPILER_VERSION_MINOR DEC(__INTEL_COMPILER/10 % 10) +# if defined(__INTEL_COMPILER_UPDATE) +# define COMPILER_VERSION_PATCH DEC(__INTEL_COMPILER_UPDATE) +# else +# define COMPILER_VERSION_PATCH DEC(__INTEL_COMPILER % 10) +# endif +# if defined(__INTEL_COMPILER_BUILD_DATE) + /* __INTEL_COMPILER_BUILD_DATE = YYYYMMDD */ +# define COMPILER_VERSION_TWEAK DEC(__INTEL_COMPILER_BUILD_DATE) +# endif +# if defined(_MSC_VER) + /* _MSC_VER = VVRR */ +# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100) +# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100) +# endif +# if defined(__GNUC__) +# define SIMULATE_VERSION_MAJOR DEC(__GNUC__) +# elif defined(__GNUG__) +# define SIMULATE_VERSION_MAJOR DEC(__GNUG__) +# endif +# if defined(__GNUC_MINOR__) +# define SIMULATE_VERSION_MINOR DEC(__GNUC_MINOR__) +# endif +# if defined(__GNUC_PATCHLEVEL__) +# define SIMULATE_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__) +# endif + +#elif defined(__PATHCC__) +# define COMPILER_ID "PathScale" +# define COMPILER_VERSION_MAJOR DEC(__PATHCC__) +# define COMPILER_VERSION_MINOR DEC(__PATHCC_MINOR__) +# if defined(__PATHCC_PATCHLEVEL__) +# define COMPILER_VERSION_PATCH DEC(__PATHCC_PATCHLEVEL__) +# endif + +#elif defined(__BORLANDC__) && defined(__CODEGEARC_VERSION__) +# define COMPILER_ID "Embarcadero" +# define COMPILER_VERSION_MAJOR HEX(__CODEGEARC_VERSION__>>24 & 0x00FF) +# define COMPILER_VERSION_MINOR HEX(__CODEGEARC_VERSION__>>16 & 0x00FF) +# define COMPILER_VERSION_PATCH DEC(__CODEGEARC_VERSION__ & 0xFFFF) + +#elif defined(__BORLANDC__) +# define COMPILER_ID "Borland" + /* __BORLANDC__ = 0xVRR */ +# define COMPILER_VERSION_MAJOR HEX(__BORLANDC__>>8) +# define COMPILER_VERSION_MINOR HEX(__BORLANDC__ & 0xFF) + +#elif defined(__WATCOMC__) && __WATCOMC__ < 1200 +# define COMPILER_ID "Watcom" + /* __WATCOMC__ = VVRR */ +# define COMPILER_VERSION_MAJOR DEC(__WATCOMC__ / 100) +# define COMPILER_VERSION_MINOR DEC((__WATCOMC__ / 10) % 10) +# if (__WATCOMC__ % 10) > 0 +# define COMPILER_VERSION_PATCH DEC(__WATCOMC__ % 10) +# endif + +#elif defined(__WATCOMC__) +# define COMPILER_ID "OpenWatcom" + /* __WATCOMC__ = VVRP + 1100 */ +# define COMPILER_VERSION_MAJOR DEC((__WATCOMC__ - 1100) / 100) +# define COMPILER_VERSION_MINOR DEC((__WATCOMC__ / 10) % 10) +# if (__WATCOMC__ % 10) > 0 +# define COMPILER_VERSION_PATCH DEC(__WATCOMC__ % 10) +# endif + +#elif defined(__SUNPRO_CC) +# define COMPILER_ID "SunPro" +# if __SUNPRO_CC >= 0x5100 + /* __SUNPRO_CC = 0xVRRP */ +# define COMPILER_VERSION_MAJOR HEX(__SUNPRO_CC>>12) +# define COMPILER_VERSION_MINOR HEX(__SUNPRO_CC>>4 & 0xFF) +# define COMPILER_VERSION_PATCH HEX(__SUNPRO_CC & 0xF) +# else + /* __SUNPRO_CC = 0xVRP */ +# define COMPILER_VERSION_MAJOR HEX(__SUNPRO_CC>>8) +# define COMPILER_VERSION_MINOR HEX(__SUNPRO_CC>>4 & 0xF) +# define COMPILER_VERSION_PATCH HEX(__SUNPRO_CC & 0xF) +# endif + +#elif defined(__HP_aCC) +# define COMPILER_ID "HP" + /* __HP_aCC = VVRRPP */ +# define COMPILER_VERSION_MAJOR DEC(__HP_aCC/10000) +# define COMPILER_VERSION_MINOR DEC(__HP_aCC/100 % 100) +# define COMPILER_VERSION_PATCH DEC(__HP_aCC % 100) + +#elif defined(__DECCXX) +# define COMPILER_ID "Compaq" + /* __DECCXX_VER = VVRRTPPPP */ +# define COMPILER_VERSION_MAJOR DEC(__DECCXX_VER/10000000) +# define COMPILER_VERSION_MINOR DEC(__DECCXX_VER/100000 % 100) +# define COMPILER_VERSION_PATCH DEC(__DECCXX_VER % 10000) + +#elif defined(__IBMCPP__) && defined(__COMPILER_VER__) +# define COMPILER_ID "zOS" + /* __IBMCPP__ = VRP */ +# define COMPILER_VERSION_MAJOR DEC(__IBMCPP__/100) +# define COMPILER_VERSION_MINOR DEC(__IBMCPP__/10 % 10) +# define COMPILER_VERSION_PATCH DEC(__IBMCPP__ % 10) + +#elif defined(__ibmxl__) && defined(__clang__) +# define COMPILER_ID "XLClang" +# define COMPILER_VERSION_MAJOR DEC(__ibmxl_version__) +# define COMPILER_VERSION_MINOR DEC(__ibmxl_release__) +# define COMPILER_VERSION_PATCH DEC(__ibmxl_modification__) +# define COMPILER_VERSION_TWEAK DEC(__ibmxl_ptf_fix_level__) + + +#elif defined(__IBMCPP__) && !defined(__COMPILER_VER__) && __IBMCPP__ >= 800 +# define COMPILER_ID "XL" + /* __IBMCPP__ = VRP */ +# define COMPILER_VERSION_MAJOR DEC(__IBMCPP__/100) +# define COMPILER_VERSION_MINOR DEC(__IBMCPP__/10 % 10) +# define COMPILER_VERSION_PATCH DEC(__IBMCPP__ % 10) + +#elif defined(__IBMCPP__) && !defined(__COMPILER_VER__) && __IBMCPP__ < 800 +# define COMPILER_ID "VisualAge" + /* __IBMCPP__ = VRP */ +# define COMPILER_VERSION_MAJOR DEC(__IBMCPP__/100) +# define COMPILER_VERSION_MINOR DEC(__IBMCPP__/10 % 10) +# define COMPILER_VERSION_PATCH DEC(__IBMCPP__ % 10) + +#elif defined(__PGI) +# define COMPILER_ID "PGI" +# define COMPILER_VERSION_MAJOR DEC(__PGIC__) +# define COMPILER_VERSION_MINOR DEC(__PGIC_MINOR__) +# if defined(__PGIC_PATCHLEVEL__) +# define COMPILER_VERSION_PATCH DEC(__PGIC_PATCHLEVEL__) +# endif + +#elif defined(_CRAYC) +# define COMPILER_ID "Cray" +# define COMPILER_VERSION_MAJOR DEC(_RELEASE_MAJOR) +# define COMPILER_VERSION_MINOR DEC(_RELEASE_MINOR) + +#elif defined(__TI_COMPILER_VERSION__) +# define COMPILER_ID "TI" + /* __TI_COMPILER_VERSION__ = VVVRRRPPP */ +# define COMPILER_VERSION_MAJOR DEC(__TI_COMPILER_VERSION__/1000000) +# define COMPILER_VERSION_MINOR DEC(__TI_COMPILER_VERSION__/1000 % 1000) +# define COMPILER_VERSION_PATCH DEC(__TI_COMPILER_VERSION__ % 1000) + +#elif defined(__FUJITSU) || defined(__FCC_VERSION) || defined(__fcc_version) +# define COMPILER_ID "Fujitsu" + +#elif defined(__ghs__) +# define COMPILER_ID "GHS" +/* __GHS_VERSION_NUMBER = VVVVRP */ +# ifdef __GHS_VERSION_NUMBER +# define COMPILER_VERSION_MAJOR DEC(__GHS_VERSION_NUMBER / 100) +# define COMPILER_VERSION_MINOR DEC(__GHS_VERSION_NUMBER / 10 % 10) +# define COMPILER_VERSION_PATCH DEC(__GHS_VERSION_NUMBER % 10) +# endif + +#elif defined(__SCO_VERSION__) +# define COMPILER_ID "SCO" + +#elif defined(__ARMCC_VERSION) && !defined(__clang__) +# define COMPILER_ID "ARMCC" +#if __ARMCC_VERSION >= 1000000 + /* __ARMCC_VERSION = VRRPPPP */ + # define COMPILER_VERSION_MAJOR DEC(__ARMCC_VERSION/1000000) + # define COMPILER_VERSION_MINOR DEC(__ARMCC_VERSION/10000 % 100) + # define COMPILER_VERSION_PATCH DEC(__ARMCC_VERSION % 10000) +#else + /* __ARMCC_VERSION = VRPPPP */ + # define COMPILER_VERSION_MAJOR DEC(__ARMCC_VERSION/100000) + # define COMPILER_VERSION_MINOR DEC(__ARMCC_VERSION/10000 % 10) + # define COMPILER_VERSION_PATCH DEC(__ARMCC_VERSION % 10000) +#endif + + +#elif defined(__clang__) && defined(__apple_build_version__) +# define COMPILER_ID "AppleClang" +# if defined(_MSC_VER) +# define SIMULATE_ID "MSVC" +# endif +# define COMPILER_VERSION_MAJOR DEC(__clang_major__) +# define COMPILER_VERSION_MINOR DEC(__clang_minor__) +# define COMPILER_VERSION_PATCH DEC(__clang_patchlevel__) +# if defined(_MSC_VER) + /* _MSC_VER = VVRR */ +# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100) +# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100) +# endif +# define COMPILER_VERSION_TWEAK DEC(__apple_build_version__) + +#elif defined(__clang__) && defined(__ARMCOMPILER_VERSION) +# define COMPILER_ID "ARMClang" + # define COMPILER_VERSION_MAJOR DEC(__ARMCOMPILER_VERSION/1000000) + # define COMPILER_VERSION_MINOR DEC(__ARMCOMPILER_VERSION/10000 % 100) + # define COMPILER_VERSION_PATCH DEC(__ARMCOMPILER_VERSION % 10000) +# define COMPILER_VERSION_INTERNAL DEC(__ARMCOMPILER_VERSION) + +#elif defined(__clang__) +# define COMPILER_ID "Clang" +# if defined(_MSC_VER) +# define SIMULATE_ID "MSVC" +# endif +# define COMPILER_VERSION_MAJOR DEC(__clang_major__) +# define COMPILER_VERSION_MINOR DEC(__clang_minor__) +# define COMPILER_VERSION_PATCH DEC(__clang_patchlevel__) +# if defined(_MSC_VER) + /* _MSC_VER = VVRR */ +# define SIMULATE_VERSION_MAJOR DEC(_MSC_VER / 100) +# define SIMULATE_VERSION_MINOR DEC(_MSC_VER % 100) +# endif + +#elif defined(__GNUC__) || defined(__GNUG__) +# define COMPILER_ID "GNU" +# if defined(__GNUC__) +# define COMPILER_VERSION_MAJOR DEC(__GNUC__) +# else +# define COMPILER_VERSION_MAJOR DEC(__GNUG__) +# endif +# if defined(__GNUC_MINOR__) +# define COMPILER_VERSION_MINOR DEC(__GNUC_MINOR__) +# endif +# if defined(__GNUC_PATCHLEVEL__) +# define COMPILER_VERSION_PATCH DEC(__GNUC_PATCHLEVEL__) +# endif + +#elif defined(_MSC_VER) +# define COMPILER_ID "MSVC" + /* _MSC_VER = VVRR */ +# define COMPILER_VERSION_MAJOR DEC(_MSC_VER / 100) +# define COMPILER_VERSION_MINOR DEC(_MSC_VER % 100) +# if defined(_MSC_FULL_VER) +# if _MSC_VER >= 1400 + /* _MSC_FULL_VER = VVRRPPPPP */ +# define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 100000) +# else + /* _MSC_FULL_VER = VVRRPPPP */ +# define COMPILER_VERSION_PATCH DEC(_MSC_FULL_VER % 10000) +# endif +# endif +# if defined(_MSC_BUILD) +# define COMPILER_VERSION_TWEAK DEC(_MSC_BUILD) +# endif + +#elif defined(__VISUALDSPVERSION__) || defined(__ADSPBLACKFIN__) || defined(__ADSPTS__) || defined(__ADSP21000__) +# define COMPILER_ID "ADSP" +#if defined(__VISUALDSPVERSION__) + /* __VISUALDSPVERSION__ = 0xVVRRPP00 */ +# define COMPILER_VERSION_MAJOR HEX(__VISUALDSPVERSION__>>24) +# define COMPILER_VERSION_MINOR HEX(__VISUALDSPVERSION__>>16 & 0xFF) +# define COMPILER_VERSION_PATCH HEX(__VISUALDSPVERSION__>>8 & 0xFF) +#endif + +#elif defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ICC) +# define COMPILER_ID "IAR" +# if defined(__VER__) && defined(__ICCARM__) +# define COMPILER_VERSION_MAJOR DEC((__VER__) / 1000000) +# define COMPILER_VERSION_MINOR DEC(((__VER__) / 1000) % 1000) +# define COMPILER_VERSION_PATCH DEC((__VER__) % 1000) +# define COMPILER_VERSION_INTERNAL DEC(__IAR_SYSTEMS_ICC__) +# elif defined(__VER__) && (defined(__ICCAVR__) || defined(__ICCRX__) || defined(__ICCRH850__) || defined(__ICCRL78__) || defined(__ICC430__) || defined(__ICCRISCV__) || defined(__ICCV850__) || defined(__ICC8051__)) +# define COMPILER_VERSION_MAJOR DEC((__VER__) / 100) +# define COMPILER_VERSION_MINOR DEC((__VER__) - (((__VER__) / 100)*100)) +# define COMPILER_VERSION_PATCH DEC(__SUBVERSION__) +# define COMPILER_VERSION_INTERNAL DEC(__IAR_SYSTEMS_ICC__) +# endif + + +/* These compilers are either not known or too old to define an + identification macro. Try to identify the platform and guess that + it is the native compiler. */ +#elif defined(__hpux) || defined(__hpua) +# define COMPILER_ID "HP" + +#else /* unknown compiler */ +# define COMPILER_ID "" +#endif + +/* Construct the string literal in pieces to prevent the source from + getting matched. Store it in a pointer rather than an array + because some compilers will just produce instructions to fill the + array rather than assigning a pointer to a static array. */ +char const* info_compiler = "INFO" ":" "compiler[" COMPILER_ID "]"; +#ifdef SIMULATE_ID +char const* info_simulate = "INFO" ":" "simulate[" SIMULATE_ID "]"; +#endif + +#ifdef __QNXNTO__ +char const* qnxnto = "INFO" ":" "qnxnto[]"; +#endif + +#if defined(_CRAYC) || defined(__cray__) +char const *info_cray = "INFO" ":" "compiler_wrapper[CrayPrgEnv]"; +#endif + +#define STRINGIFY_HELPER(X) #X +#define STRINGIFY(X) STRINGIFY_HELPER(X) + +/* Identify known platforms by name. */ +#if defined(__linux) || defined(__linux__) || defined(linux) +# define PLATFORM_ID "Linux" + +#elif defined(__CYGWIN__) +# define PLATFORM_ID "Cygwin" + +#elif defined(__MINGW32__) +# define PLATFORM_ID "MinGW" + +#elif defined(__APPLE__) +# define PLATFORM_ID "Darwin" + +#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32) +# define PLATFORM_ID "Windows" + +#elif defined(__FreeBSD__) || defined(__FreeBSD) +# define PLATFORM_ID "FreeBSD" + +#elif defined(__NetBSD__) || defined(__NetBSD) +# define PLATFORM_ID "NetBSD" + +#elif defined(__OpenBSD__) || defined(__OPENBSD) +# define PLATFORM_ID "OpenBSD" + +#elif defined(__sun) || defined(sun) +# define PLATFORM_ID "SunOS" + +#elif defined(_AIX) || defined(__AIX) || defined(__AIX__) || defined(__aix) || defined(__aix__) +# define PLATFORM_ID "AIX" + +#elif defined(__hpux) || defined(__hpux__) +# define PLATFORM_ID "HP-UX" + +#elif defined(__HAIKU__) +# define PLATFORM_ID "Haiku" + +#elif defined(__BeOS) || defined(__BEOS__) || defined(_BEOS) +# define PLATFORM_ID "BeOS" + +#elif defined(__QNX__) || defined(__QNXNTO__) +# define PLATFORM_ID "QNX" + +#elif defined(__tru64) || defined(_tru64) || defined(__TRU64__) +# define PLATFORM_ID "Tru64" + +#elif defined(__riscos) || defined(__riscos__) +# define PLATFORM_ID "RISCos" + +#elif defined(__sinix) || defined(__sinix__) || defined(__SINIX__) +# define PLATFORM_ID "SINIX" + +#elif defined(__UNIX_SV__) +# define PLATFORM_ID "UNIX_SV" + +#elif defined(__bsdos__) +# define PLATFORM_ID "BSDOS" + +#elif defined(_MPRAS) || defined(MPRAS) +# define PLATFORM_ID "MP-RAS" + +#elif defined(__osf) || defined(__osf__) +# define PLATFORM_ID "OSF1" + +#elif defined(_SCO_SV) || defined(SCO_SV) || defined(sco_sv) +# define PLATFORM_ID "SCO_SV" + +#elif defined(__ultrix) || defined(__ultrix__) || defined(_ULTRIX) +# define PLATFORM_ID "ULTRIX" + +#elif defined(__XENIX__) || defined(_XENIX) || defined(XENIX) +# define PLATFORM_ID "Xenix" + +#elif defined(__WATCOMC__) +# if defined(__LINUX__) +# define PLATFORM_ID "Linux" + +# elif defined(__DOS__) +# define PLATFORM_ID "DOS" + +# elif defined(__OS2__) +# define PLATFORM_ID "OS2" + +# elif defined(__WINDOWS__) +# define PLATFORM_ID "Windows3x" + +# elif defined(__VXWORKS__) +# define PLATFORM_ID "VxWorks" + +# else /* unknown platform */ +# define PLATFORM_ID +# endif + +#elif defined(__INTEGRITY) +# if defined(INT_178B) +# define PLATFORM_ID "Integrity178" + +# else /* regular Integrity */ +# define PLATFORM_ID "Integrity" +# endif + +#else /* unknown platform */ +# define PLATFORM_ID + +#endif + +/* For windows compilers MSVC and Intel we can determine + the architecture of the compiler being used. This is because + the compilers do not have flags that can change the architecture, + but rather depend on which compiler is being used +*/ +#if defined(_WIN32) && defined(_MSC_VER) +# if defined(_M_IA64) +# define ARCHITECTURE_ID "IA64" + +# elif defined(_M_X64) || defined(_M_AMD64) +# define ARCHITECTURE_ID "x64" + +# elif defined(_M_IX86) +# define ARCHITECTURE_ID "X86" + +# elif defined(_M_ARM64) +# define ARCHITECTURE_ID "ARM64" + +# elif defined(_M_ARM) +# if _M_ARM == 4 +# define ARCHITECTURE_ID "ARMV4I" +# elif _M_ARM == 5 +# define ARCHITECTURE_ID "ARMV5I" +# else +# define ARCHITECTURE_ID "ARMV" STRINGIFY(_M_ARM) +# endif + +# elif defined(_M_MIPS) +# define ARCHITECTURE_ID "MIPS" + +# elif defined(_M_SH) +# define ARCHITECTURE_ID "SHx" + +# else /* unknown architecture */ +# define ARCHITECTURE_ID "" +# endif + +#elif defined(__WATCOMC__) +# if defined(_M_I86) +# define ARCHITECTURE_ID "I86" + +# elif defined(_M_IX86) +# define ARCHITECTURE_ID "X86" + +# else /* unknown architecture */ +# define ARCHITECTURE_ID "" +# endif + +#elif defined(__IAR_SYSTEMS_ICC__) || defined(__IAR_SYSTEMS_ICC) +# if defined(__ICCARM__) +# define ARCHITECTURE_ID "ARM" + +# elif defined(__ICCRX__) +# define ARCHITECTURE_ID "RX" + +# elif defined(__ICCRH850__) +# define ARCHITECTURE_ID "RH850" + +# elif defined(__ICCRL78__) +# define ARCHITECTURE_ID "RL78" + +# elif defined(__ICCRISCV__) +# define ARCHITECTURE_ID "RISCV" + +# elif defined(__ICCAVR__) +# define ARCHITECTURE_ID "AVR" + +# elif defined(__ICC430__) +# define ARCHITECTURE_ID "MSP430" + +# elif defined(__ICCV850__) +# define ARCHITECTURE_ID "V850" + +# elif defined(__ICC8051__) +# define ARCHITECTURE_ID "8051" + +# else /* unknown architecture */ +# define ARCHITECTURE_ID "" +# endif + +#elif defined(__ghs__) +# if defined(__PPC64__) +# define ARCHITECTURE_ID "PPC64" + +# elif defined(__ppc__) +# define ARCHITECTURE_ID "PPC" + +# elif defined(__ARM__) +# define ARCHITECTURE_ID "ARM" + +# elif defined(__x86_64__) +# define ARCHITECTURE_ID "x64" + +# elif defined(__i386__) +# define ARCHITECTURE_ID "X86" + +# else /* unknown architecture */ +# define ARCHITECTURE_ID "" +# endif + +#elif defined(__TI_COMPILER_VERSION__) +# if defined(__TI_ARM__) +# define ARCHITECTURE_ID "ARM" + +# elif defined(__MSP430__) +# define ARCHITECTURE_ID "MSP430" + +# elif defined(__TMS320C28XX__) +# define ARCHITECTURE_ID "TMS320C28x" + +# elif defined(__TMS320C6X__) || defined(_TMS320C6X) +# define ARCHITECTURE_ID "TMS320C6x" + +# else /* unknown architecture */ +# define ARCHITECTURE_ID "" +# endif + +#else +# define ARCHITECTURE_ID +#endif + +/* Convert integer to decimal digit literals. */ +#define DEC(n) \ + ('0' + (((n) / 10000000)%10)), \ + ('0' + (((n) / 1000000)%10)), \ + ('0' + (((n) / 100000)%10)), \ + ('0' + (((n) / 10000)%10)), \ + ('0' + (((n) / 1000)%10)), \ + ('0' + (((n) / 100)%10)), \ + ('0' + (((n) / 10)%10)), \ + ('0' + ((n) % 10)) + +/* Convert integer to hex digit literals. */ +#define HEX(n) \ + ('0' + ((n)>>28 & 0xF)), \ + ('0' + ((n)>>24 & 0xF)), \ + ('0' + ((n)>>20 & 0xF)), \ + ('0' + ((n)>>16 & 0xF)), \ + ('0' + ((n)>>12 & 0xF)), \ + ('0' + ((n)>>8 & 0xF)), \ + ('0' + ((n)>>4 & 0xF)), \ + ('0' + ((n) & 0xF)) + +/* Construct a string literal encoding the version number components. */ +#ifdef COMPILER_VERSION_MAJOR +char const info_version[] = { + 'I', 'N', 'F', 'O', ':', + 'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','[', + COMPILER_VERSION_MAJOR, +# ifdef COMPILER_VERSION_MINOR + '.', COMPILER_VERSION_MINOR, +# ifdef COMPILER_VERSION_PATCH + '.', COMPILER_VERSION_PATCH, +# ifdef COMPILER_VERSION_TWEAK + '.', COMPILER_VERSION_TWEAK, +# endif +# endif +# endif + ']','\0'}; +#endif + +/* Construct a string literal encoding the internal version number. */ +#ifdef COMPILER_VERSION_INTERNAL +char const info_version_internal[] = { + 'I', 'N', 'F', 'O', ':', + 'c','o','m','p','i','l','e','r','_','v','e','r','s','i','o','n','_', + 'i','n','t','e','r','n','a','l','[', + COMPILER_VERSION_INTERNAL,']','\0'}; +#endif + +/* Construct a string literal encoding the version number components. */ +#ifdef SIMULATE_VERSION_MAJOR +char const info_simulate_version[] = { + 'I', 'N', 'F', 'O', ':', + 's','i','m','u','l','a','t','e','_','v','e','r','s','i','o','n','[', + SIMULATE_VERSION_MAJOR, +# ifdef SIMULATE_VERSION_MINOR + '.', SIMULATE_VERSION_MINOR, +# ifdef SIMULATE_VERSION_PATCH + '.', SIMULATE_VERSION_PATCH, +# ifdef SIMULATE_VERSION_TWEAK + '.', SIMULATE_VERSION_TWEAK, +# endif +# endif +# endif + ']','\0'}; +#endif + +/* Construct the string literal in pieces to prevent the source from + getting matched. Store it in a pointer rather than an array + because some compilers will just produce instructions to fill the + array rather than assigning a pointer to a static array. */ +char const* info_platform = "INFO" ":" "platform[" PLATFORM_ID "]"; +char const* info_arch = "INFO" ":" "arch[" ARCHITECTURE_ID "]"; + + + +#if defined(__INTEL_COMPILER) && defined(_MSVC_LANG) && _MSVC_LANG < 201403L +# if defined(__INTEL_CXX11_MODE__) +# if defined(__cpp_aggregate_nsdmi) +# define CXX_STD 201402L +# else +# define CXX_STD 201103L +# endif +# else +# define CXX_STD 199711L +# endif +#elif defined(_MSC_VER) && defined(_MSVC_LANG) +# define CXX_STD _MSVC_LANG +#else +# define CXX_STD __cplusplus +#endif + +const char* info_language_dialect_default = "INFO" ":" "dialect_default[" +#if CXX_STD > 201703L + "20" +#elif CXX_STD >= 201703L + "17" +#elif CXX_STD >= 201402L + "14" +#elif CXX_STD >= 201103L + "11" +#else + "98" +#endif +"]"; + +/*--------------------------------------------------------------------------*/ + +int main(int argc, char* argv[]) +{ + int require = 0; + require += info_compiler[argc]; + require += info_platform[argc]; +#ifdef COMPILER_VERSION_MAJOR + require += info_version[argc]; +#endif +#ifdef COMPILER_VERSION_INTERNAL + require += info_version_internal[argc]; +#endif +#ifdef SIMULATE_ID + require += info_simulate[argc]; +#endif +#ifdef SIMULATE_VERSION_MAJOR + require += info_simulate_version[argc]; +#endif +#if defined(_CRAYC) || defined(__cray__) + require += info_cray[argc]; +#endif + require += info_language_dialect_default[argc]; + (void)argv; + return require; +} diff --git a/cmake-build-debug/CMakeFiles/3.19.2/CompilerIdCXX/a.exe b/cmake-build-debug/CMakeFiles/3.19.2/CompilerIdCXX/a.exe new file mode 100644 index 0000000..d786dda Binary files /dev/null and b/cmake-build-debug/CMakeFiles/3.19.2/CompilerIdCXX/a.exe differ diff --git a/cmake-build-debug/CMakeFiles/CMakeOutput.log b/cmake-build-debug/CMakeFiles/CMakeOutput.log new file mode 100644 index 0000000..201400b --- /dev/null +++ b/cmake-build-debug/CMakeFiles/CMakeOutput.log @@ -0,0 +1,498 @@ +The system is: Windows - 10.0.19041 - AMD64 +Compiling the C compiler identification source file "CMakeCCompilerId.c" succeeded. +Compiler: C:/BC/C/mingw64/bin/gcc.exe +Build flags: +Id flags: + +The output was: +0 + + +Compilation of the C compiler identification source "CMakeCCompilerId.c" produced "a.exe" + +The C compiler identification is GNU, found in "D:/2021_2/cids-server/cmake-build-debug/CMakeFiles/3.19.2/CompilerIdC/a.exe" + +Compiling the CXX compiler identification source file "CMakeCXXCompilerId.cpp" succeeded. +Compiler: C:/BC/C/mingw64/bin/g++.exe +Build flags: +Id flags: + +The output was: +0 + + +Compilation of the CXX compiler identification source "CMakeCXXCompilerId.cpp" produced "a.exe" + +The CXX compiler identification is GNU, found in "D:/2021_2/cids-server/cmake-build-debug/CMakeFiles/3.19.2/CompilerIdCXX/a.exe" + +Detecting C compiler ABI info compiled with the following output: +Change Dir: D:/2021_2/cids-server/cmake-build-debug/CMakeFiles/CMakeTmp + +Run Build Command(s):C:/BC/C/mingw64/bin/mingw32-make.exe cmTC_0d28b/fast && C:/BC/C/mingw64/bin/mingw32-make.exe -f CMakeFiles\cmTC_0d28b.dir\build.make CMakeFiles/cmTC_0d28b.dir/build +mingw32-make.exe[1]: Entering directory 'D:/2021_2/cids-server/cmake-build-debug/CMakeFiles/CMakeTmp' +Building C object CMakeFiles/cmTC_0d28b.dir/CMakeCCompilerABI.c.obj +C:\BC\C\mingw64\bin\gcc.exe -v -o CMakeFiles\cmTC_0d28b.dir\CMakeCCompilerABI.c.obj -c C:\Users\XM\AppData\Local\JetBrains\Toolbox\apps\CLion\ch-0\211.7142.21\bin\cmake\win\share\cmake-3.19\Modules\CMakeCCompilerABI.c +Using built-in specs. +COLLECT_GCC=C:\BC\C\mingw64\bin\gcc.exe +Target: x86_64-w64-mingw32 +Configured with: ../../../src/gcc-8.1.0/configure --host=x86_64-w64-mingw32 --build=x86_64-w64-mingw32 --target=x86_64-w64-mingw32 --prefix=/mingw64 --with-sysroot=/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64 --enable-shared --enable-static --disable-multilib --enable-languages=c,c++,fortran,lto --enable-libstdcxx-time=yes --enable-threads=posix --enable-libgomp --enable-libatomic --enable-lto --enable-graphite --enable-checking=release --enable-fully-dynamic-string --enable-version-specific-runtime-libs --disable-libstdcxx-pch --disable-libstdcxx-debug --enable-bootstrap --disable-rpath --disable-win32-registry --disable-nls --disable-werror --disable-symvers --with-gnu-as --with-gnu-ld --with-arch=nocona --with-tune=core2 --with-libiconv --with-system-zlib --with-gmp=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-mpfr=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-mpc=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-isl=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-pkgversion='x86_64-posix-seh-rev0, Built by MinGW-W64 project' --with-bugurl=https://sourceforge.net/projects/mingw-w64 CFLAGS='-O2 -pipe -fno-ident -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' CXXFLAGS='-O2 -pipe -fno-ident -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' CPPFLAGS=' -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' LDFLAGS='-pipe -fno-ident -L/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/lib -L/c/mingw810/prerequisites/x86_64-zlib-static/lib -L/c/mingw810/prerequisites/x86_64-w64-mingw32-static/lib ' +Thread model: posix +gcc version 8.1.0 (x86_64-posix-seh-rev0, Built by MinGW-W64 project) +COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles\cmTC_0d28b.dir\CMakeCCompilerABI.c.obj' '-c' '-mtune=core2' '-march=nocona' + C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/cc1.exe -quiet -v -iprefix C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/ -D_REENTRANT C:\Users\XM\AppData\Local\JetBrains\Toolbox\apps\CLion\ch-0\211.7142.21\bin\cmake\win\share\cmake-3.19\Modules\CMakeCCompilerABI.c -quiet -dumpbase CMakeCCompilerABI.c -mtune=core2 -march=nocona -auxbase-strip CMakeFiles\cmTC_0d28b.dir\CMakeCCompilerABI.c.obj -version -o C:\Users\XM\AppData\Local\Temp\ccoWv3hA.s +GNU C17 (x86_64-posix-seh-rev0, Built by MinGW-W64 project) version 8.1.0 (x86_64-w64-mingw32) + compiled by GNU C version 8.1.0, GMP version 6.1.2, MPFR version 4.0.1, MPC version 1.1.0, isl version isl-0.18-GMP + +GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072 +ignoring duplicate directory "C:/BC/C/mingw64/lib/gcc/../../lib/gcc/x86_64-w64-mingw32/8.1.0/include" +ignoring nonexistent directory "C:/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64C:/msys64/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../include" +ignoring duplicate directory "C:/BC/C/mingw64/lib/gcc/../../lib/gcc/x86_64-w64-mingw32/8.1.0/include-fixed" +ignoring duplicate directory "C:/BC/C/mingw64/lib/gcc/../../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/include" +ignoring nonexistent directory "C:/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/mingw/include" +#include "..." search starts here: +#include <...> search starts here: + C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include + C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include-fixed + C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/include +End of search list. +GNU C17 (x86_64-posix-seh-rev0, Built by MinGW-W64 project) version 8.1.0 (x86_64-w64-mingw32) + compiled by GNU C version 8.1.0, GMP version 6.1.2, MPFR version 4.0.1, MPC version 1.1.0, isl version isl-0.18-GMP + +GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072 +Compiler executable checksum: 985ce7ae6dd3a696cd146ca9896b0035 +COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles\cmTC_0d28b.dir\CMakeCCompilerABI.c.obj' '-c' '-mtune=core2' '-march=nocona' + C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/bin/as.exe -v -o CMakeFiles\cmTC_0d28b.dir\CMakeCCompilerABI.c.obj C:\Users\XM\AppData\Local\Temp\ccoWv3hA.s +GNU assembler version 2.30 (x86_64-w64-mingw32) using BFD version (GNU Binutils) 2.30 +COMPILER_PATH=C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/;C:/BC/C/mingw64/bin/../libexec/gcc/;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/bin/ +LIBRARY_PATH=C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/;C:/BC/C/mingw64/bin/../lib/gcc/;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/../lib/;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../lib/;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../ +COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles\cmTC_0d28b.dir\CMakeCCompilerABI.c.obj' '-c' '-mtune=core2' '-march=nocona' +Linking C executable cmTC_0d28b.exe +C:\Users\XM\AppData\Local\JetBrains\Toolbox\apps\CLion\ch-0\211.7142.21\bin\cmake\win\bin\cmake.exe -E cmake_link_script CMakeFiles\cmTC_0d28b.dir\link.txt --verbose=1 +C:\Users\XM\AppData\Local\JetBrains\Toolbox\apps\CLion\ch-0\211.7142.21\bin\cmake\win\bin\cmake.exe -E rm -f CMakeFiles\cmTC_0d28b.dir/objects.a +C:\BC\C\mingw64\bin\ar.exe cr CMakeFiles\cmTC_0d28b.dir/objects.a @CMakeFiles\cmTC_0d28b.dir\objects1.rsp +C:\BC\C\mingw64\bin\gcc.exe -v -Wl,--whole-archive CMakeFiles\cmTC_0d28b.dir/objects.a -Wl,--no-whole-archive -o cmTC_0d28b.exe -Wl,--out-implib,libcmTC_0d28b.dll.a -Wl,--major-image-version,0,--minor-image-version,0 +Using built-in specs. +COLLECT_GCC=C:\BC\C\mingw64\bin\gcc.exe +COLLECT_LTO_WRAPPER=C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/lto-wrapper.exe +Target: x86_64-w64-mingw32 +Configured with: ../../../src/gcc-8.1.0/configure --host=x86_64-w64-mingw32 --build=x86_64-w64-mingw32 --target=x86_64-w64-mingw32 --prefix=/mingw64 --with-sysroot=/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64 --enable-shared --enable-static --disable-multilib --enable-languages=c,c++,fortran,lto --enable-libstdcxx-time=yes --enable-threads=posix --enable-libgomp --enable-libatomic --enable-lto --enable-graphite --enable-checking=release --enable-fully-dynamic-string --enable-version-specific-runtime-libs --disable-libstdcxx-pch --disable-libstdcxx-debug --enable-bootstrap --disable-rpath --disable-win32-registry --disable-nls --disable-werror --disable-symvers --with-gnu-as --with-gnu-ld --with-arch=nocona --with-tune=core2 --with-libiconv --with-system-zlib --with-gmp=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-mpfr=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-mpc=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-isl=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-pkgversion='x86_64-posix-seh-rev0, Built by MinGW-W64 project' --with-bugurl=https://sourceforge.net/projects/mingw-w64 CFLAGS='-O2 -pipe -fno-ident -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' CXXFLAGS='-O2 -pipe -fno-ident -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' CPPFLAGS=' -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' LDFLAGS='-pipe -fno-ident -L/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/lib -L/c/mingw810/prerequisites/x86_64-zlib-static/lib -L/c/mingw810/prerequisites/x86_64-w64-mingw32-static/lib ' +Thread model: posix +gcc version 8.1.0 (x86_64-posix-seh-rev0, Built by MinGW-W64 project) +COMPILER_PATH=C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/;C:/BC/C/mingw64/bin/../libexec/gcc/;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/bin/ +LIBRARY_PATH=C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/;C:/BC/C/mingw64/bin/../lib/gcc/;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/../lib/;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../lib/;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../ +COLLECT_GCC_OPTIONS='-v' '-o' 'cmTC_0d28b.exe' '-mtune=core2' '-march=nocona' + C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/collect2.exe -plugin C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/liblto_plugin-0.dll -plugin-opt=C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/lto-wrapper.exe -plugin-opt=-fresolution=C:\Users\XM\AppData\Local\Temp\ccTDRnSd.res -plugin-opt=-pass-through=-lmingw32 -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_eh -plugin-opt=-pass-through=-lmoldname -plugin-opt=-pass-through=-lmingwex -plugin-opt=-pass-through=-lmsvcrt -plugin-opt=-pass-through=-lpthread -plugin-opt=-pass-through=-ladvapi32 -plugin-opt=-pass-through=-lshell32 -plugin-opt=-pass-through=-luser32 -plugin-opt=-pass-through=-lkernel32 -plugin-opt=-pass-through=-liconv -plugin-opt=-pass-through=-lmingw32 -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_eh -plugin-opt=-pass-through=-lmoldname -plugin-opt=-pass-through=-lmingwex -plugin-opt=-pass-through=-lmsvcrt --sysroot=C:/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64 -m i386pep -Bdynamic -o cmTC_0d28b.exe C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/../lib/crt2.o C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/crtbegin.o -LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0 -LC:/BC/C/mingw64/bin/../lib/gcc -LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/../lib -LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../lib -LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib -LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../.. --whole-archive CMakeFiles\cmTC_0d28b.dir/objects.a --no-whole-archive --out-implib libcmTC_0d28b.dll.a --major-image-version 0 --minor-image-version 0 -lmingw32 -lgcc -lgcc_eh -lmoldname -lmingwex -lmsvcrt -lpthread -ladvapi32 -lshell32 -luser32 -lkernel32 -liconv -lmingw32 -lgcc -lgcc_eh -lmoldname -lmingwex -lmsvcrt C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/crtend.o +COLLECT_GCC_OPTIONS='-v' '-o' 'cmTC_0d28b.exe' '-mtune=core2' '-march=nocona' +mingw32-make.exe[1]: Leaving directory 'D:/2021_2/cids-server/cmake-build-debug/CMakeFiles/CMakeTmp' + + + +Parsed C implicit include dir info from above output: rv=done + found start of include info + found start of implicit include info + add: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include] + add: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include-fixed] + add: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/include] + end of search list found + collapse include dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include] ==> [C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include] + collapse include dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include-fixed] ==> [C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include-fixed] + collapse include dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/include] ==> [C:/BC/C/mingw64/x86_64-w64-mingw32/include] + implicit include dirs: [C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include;C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include-fixed;C:/BC/C/mingw64/x86_64-w64-mingw32/include] + + +Parsed C implicit link information from above output: + link line regex: [^( *|.*[/\])(ld\.exe|CMAKE_LINK_STARTFILE-NOTFOUND|([^/\]+-)?ld|collect2)[^/\]*( |$)] + ignore line: [Change Dir: D:/2021_2/cids-server/cmake-build-debug/CMakeFiles/CMakeTmp] + ignore line: [] + ignore line: [Run Build Command(s):C:/BC/C/mingw64/bin/mingw32-make.exe cmTC_0d28b/fast && C:/BC/C/mingw64/bin/mingw32-make.exe -f CMakeFiles\cmTC_0d28b.dir\build.make CMakeFiles/cmTC_0d28b.dir/build] + ignore line: [mingw32-make.exe[1]: Entering directory 'D:/2021_2/cids-server/cmake-build-debug/CMakeFiles/CMakeTmp'] + ignore line: [Building C object CMakeFiles/cmTC_0d28b.dir/CMakeCCompilerABI.c.obj] + ignore line: [C:\BC\C\mingw64\bin\gcc.exe -v -o CMakeFiles\cmTC_0d28b.dir\CMakeCCompilerABI.c.obj -c C:\Users\XM\AppData\Local\JetBrains\Toolbox\apps\CLion\ch-0\211.7142.21\bin\cmake\win\share\cmake-3.19\Modules\CMakeCCompilerABI.c] + ignore line: [Using built-in specs.] + ignore line: [COLLECT_GCC=C:\BC\C\mingw64\bin\gcc.exe] + ignore line: [Target: x86_64-w64-mingw32] + ignore line: [Configured with: ../../../src/gcc-8.1.0/configure --host=x86_64-w64-mingw32 --build=x86_64-w64-mingw32 --target=x86_64-w64-mingw32 --prefix=/mingw64 --with-sysroot=/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64 --enable-shared --enable-static --disable-multilib --enable-languages=c,c++,fortran,lto --enable-libstdcxx-time=yes --enable-threads=posix --enable-libgomp --enable-libatomic --enable-lto --enable-graphite --enable-checking=release --enable-fully-dynamic-string --enable-version-specific-runtime-libs --disable-libstdcxx-pch --disable-libstdcxx-debug --enable-bootstrap --disable-rpath --disable-win32-registry --disable-nls --disable-werror --disable-symvers --with-gnu-as --with-gnu-ld --with-arch=nocona --with-tune=core2 --with-libiconv --with-system-zlib --with-gmp=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-mpfr=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-mpc=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-isl=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-pkgversion='x86_64-posix-seh-rev0, Built by MinGW-W64 project' --with-bugurl=https://sourceforge.net/projects/mingw-w64 CFLAGS='-O2 -pipe -fno-ident -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' CXXFLAGS='-O2 -pipe -fno-ident -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' CPPFLAGS=' -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' LDFLAGS='-pipe -fno-ident -L/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/lib -L/c/mingw810/prerequisites/x86_64-zlib-static/lib -L/c/mingw810/prerequisites/x86_64-w64-mingw32-static/lib '] + ignore line: [Thread model: posix] + ignore line: [gcc version 8.1.0 (x86_64-posix-seh-rev0 Built by MinGW-W64 project) ] + ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles\cmTC_0d28b.dir\CMakeCCompilerABI.c.obj' '-c' '-mtune=core2' '-march=nocona'] + ignore line: [ C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/cc1.exe -quiet -v -iprefix C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/ -D_REENTRANT C:\Users\XM\AppData\Local\JetBrains\Toolbox\apps\CLion\ch-0\211.7142.21\bin\cmake\win\share\cmake-3.19\Modules\CMakeCCompilerABI.c -quiet -dumpbase CMakeCCompilerABI.c -mtune=core2 -march=nocona -auxbase-strip CMakeFiles\cmTC_0d28b.dir\CMakeCCompilerABI.c.obj -version -o C:\Users\XM\AppData\Local\Temp\ccoWv3hA.s] + ignore line: [GNU C17 (x86_64-posix-seh-rev0 Built by MinGW-W64 project) version 8.1.0 (x86_64-w64-mingw32)] + ignore line: [ compiled by GNU C version 8.1.0 GMP version 6.1.2 MPFR version 4.0.1 MPC version 1.1.0 isl version isl-0.18-GMP] + ignore line: [] + ignore line: [GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072] + ignore line: [ignoring duplicate directory "C:/BC/C/mingw64/lib/gcc/../../lib/gcc/x86_64-w64-mingw32/8.1.0/include"] + ignore line: [ignoring nonexistent directory "C:/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64C:/msys64/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../include"] + ignore line: [ignoring duplicate directory "C:/BC/C/mingw64/lib/gcc/../../lib/gcc/x86_64-w64-mingw32/8.1.0/include-fixed"] + ignore line: [ignoring duplicate directory "C:/BC/C/mingw64/lib/gcc/../../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/include"] + ignore line: [ignoring nonexistent directory "C:/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/mingw/include"] + ignore line: [#include "..." search starts here:] + ignore line: [#include <...> search starts here:] + ignore line: [ C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include] + ignore line: [ C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include-fixed] + ignore line: [ C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/include] + ignore line: [End of search list.] + ignore line: [GNU C17 (x86_64-posix-seh-rev0 Built by MinGW-W64 project) version 8.1.0 (x86_64-w64-mingw32)] + ignore line: [ compiled by GNU C version 8.1.0 GMP version 6.1.2 MPFR version 4.0.1 MPC version 1.1.0 isl version isl-0.18-GMP] + ignore line: [] + ignore line: [GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072] + ignore line: [Compiler executable checksum: 985ce7ae6dd3a696cd146ca9896b0035] + ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles\cmTC_0d28b.dir\CMakeCCompilerABI.c.obj' '-c' '-mtune=core2' '-march=nocona'] + ignore line: [ C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/bin/as.exe -v -o CMakeFiles\cmTC_0d28b.dir\CMakeCCompilerABI.c.obj C:\Users\XM\AppData\Local\Temp\ccoWv3hA.s] + ignore line: [GNU assembler version 2.30 (x86_64-w64-mingw32) using BFD version (GNU Binutils) 2.30] + ignore line: [COMPILER_PATH=C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/] + ignore line: [C:/BC/C/mingw64/bin/../libexec/gcc/] + ignore line: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/bin/] + ignore line: [LIBRARY_PATH=C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/] + ignore line: [C:/BC/C/mingw64/bin/../lib/gcc/] + ignore line: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/../lib/] + ignore line: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../lib/] + ignore line: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/] + ignore line: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../] + ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles\cmTC_0d28b.dir\CMakeCCompilerABI.c.obj' '-c' '-mtune=core2' '-march=nocona'] + ignore line: [Linking C executable cmTC_0d28b.exe] + ignore line: [C:\Users\XM\AppData\Local\JetBrains\Toolbox\apps\CLion\ch-0\211.7142.21\bin\cmake\win\bin\cmake.exe -E cmake_link_script CMakeFiles\cmTC_0d28b.dir\link.txt --verbose=1] + ignore line: [C:\Users\XM\AppData\Local\JetBrains\Toolbox\apps\CLion\ch-0\211.7142.21\bin\cmake\win\bin\cmake.exe -E rm -f CMakeFiles\cmTC_0d28b.dir/objects.a] + ignore line: [C:\BC\C\mingw64\bin\ar.exe cr CMakeFiles\cmTC_0d28b.dir/objects.a @CMakeFiles\cmTC_0d28b.dir\objects1.rsp] + ignore line: [C:\BC\C\mingw64\bin\gcc.exe -v -Wl --whole-archive CMakeFiles\cmTC_0d28b.dir/objects.a -Wl --no-whole-archive -o cmTC_0d28b.exe -Wl --out-implib libcmTC_0d28b.dll.a -Wl --major-image-version 0 --minor-image-version 0 ] + ignore line: [Using built-in specs.] + ignore line: [COLLECT_GCC=C:\BC\C\mingw64\bin\gcc.exe] + ignore line: [COLLECT_LTO_WRAPPER=C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/lto-wrapper.exe] + ignore line: [Target: x86_64-w64-mingw32] + ignore line: [Configured with: ../../../src/gcc-8.1.0/configure --host=x86_64-w64-mingw32 --build=x86_64-w64-mingw32 --target=x86_64-w64-mingw32 --prefix=/mingw64 --with-sysroot=/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64 --enable-shared --enable-static --disable-multilib --enable-languages=c,c++,fortran,lto --enable-libstdcxx-time=yes --enable-threads=posix --enable-libgomp --enable-libatomic --enable-lto --enable-graphite --enable-checking=release --enable-fully-dynamic-string --enable-version-specific-runtime-libs --disable-libstdcxx-pch --disable-libstdcxx-debug --enable-bootstrap --disable-rpath --disable-win32-registry --disable-nls --disable-werror --disable-symvers --with-gnu-as --with-gnu-ld --with-arch=nocona --with-tune=core2 --with-libiconv --with-system-zlib --with-gmp=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-mpfr=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-mpc=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-isl=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-pkgversion='x86_64-posix-seh-rev0, Built by MinGW-W64 project' --with-bugurl=https://sourceforge.net/projects/mingw-w64 CFLAGS='-O2 -pipe -fno-ident -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' CXXFLAGS='-O2 -pipe -fno-ident -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' CPPFLAGS=' -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' LDFLAGS='-pipe -fno-ident -L/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/lib -L/c/mingw810/prerequisites/x86_64-zlib-static/lib -L/c/mingw810/prerequisites/x86_64-w64-mingw32-static/lib '] + ignore line: [Thread model: posix] + ignore line: [gcc version 8.1.0 (x86_64-posix-seh-rev0 Built by MinGW-W64 project) ] + ignore line: [COMPILER_PATH=C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/] + ignore line: [C:/BC/C/mingw64/bin/../libexec/gcc/] + ignore line: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/bin/] + ignore line: [LIBRARY_PATH=C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/] + ignore line: [C:/BC/C/mingw64/bin/../lib/gcc/] + ignore line: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/../lib/] + ignore line: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../lib/] + ignore line: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/] + ignore line: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../] + ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'cmTC_0d28b.exe' '-mtune=core2' '-march=nocona'] + link line: [ C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/collect2.exe -plugin C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/liblto_plugin-0.dll -plugin-opt=C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/lto-wrapper.exe -plugin-opt=-fresolution=C:\Users\XM\AppData\Local\Temp\ccTDRnSd.res -plugin-opt=-pass-through=-lmingw32 -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_eh -plugin-opt=-pass-through=-lmoldname -plugin-opt=-pass-through=-lmingwex -plugin-opt=-pass-through=-lmsvcrt -plugin-opt=-pass-through=-lpthread -plugin-opt=-pass-through=-ladvapi32 -plugin-opt=-pass-through=-lshell32 -plugin-opt=-pass-through=-luser32 -plugin-opt=-pass-through=-lkernel32 -plugin-opt=-pass-through=-liconv -plugin-opt=-pass-through=-lmingw32 -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_eh -plugin-opt=-pass-through=-lmoldname -plugin-opt=-pass-through=-lmingwex -plugin-opt=-pass-through=-lmsvcrt --sysroot=C:/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64 -m i386pep -Bdynamic -o cmTC_0d28b.exe C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/../lib/crt2.o C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/crtbegin.o -LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0 -LC:/BC/C/mingw64/bin/../lib/gcc -LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/../lib -LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../lib -LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib -LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../.. --whole-archive CMakeFiles\cmTC_0d28b.dir/objects.a --no-whole-archive --out-implib libcmTC_0d28b.dll.a --major-image-version 0 --minor-image-version 0 -lmingw32 -lgcc -lgcc_eh -lmoldname -lmingwex -lmsvcrt -lpthread -ladvapi32 -lshell32 -luser32 -lkernel32 -liconv -lmingw32 -lgcc -lgcc_eh -lmoldname -lmingwex -lmsvcrt C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/crtend.o] + arg [C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/collect2.exe] ==> ignore + arg [-plugin] ==> ignore + arg [C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/liblto_plugin-0.dll] ==> ignore + arg [-plugin-opt=C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/lto-wrapper.exe] ==> ignore + arg [-plugin-opt=-fresolution=C:\Users\XM\AppData\Local\Temp\ccTDRnSd.res] ==> ignore + arg [-plugin-opt=-pass-through=-lmingw32] ==> ignore + arg [-plugin-opt=-pass-through=-lgcc] ==> ignore + arg [-plugin-opt=-pass-through=-lgcc_eh] ==> ignore + arg [-plugin-opt=-pass-through=-lmoldname] ==> ignore + arg [-plugin-opt=-pass-through=-lmingwex] ==> ignore + arg [-plugin-opt=-pass-through=-lmsvcrt] ==> ignore + arg [-plugin-opt=-pass-through=-lpthread] ==> ignore + arg [-plugin-opt=-pass-through=-ladvapi32] ==> ignore + arg [-plugin-opt=-pass-through=-lshell32] ==> ignore + arg [-plugin-opt=-pass-through=-luser32] ==> ignore + arg [-plugin-opt=-pass-through=-lkernel32] ==> ignore + arg [-plugin-opt=-pass-through=-liconv] ==> ignore + arg [-plugin-opt=-pass-through=-lmingw32] ==> ignore + arg [-plugin-opt=-pass-through=-lgcc] ==> ignore + arg [-plugin-opt=-pass-through=-lgcc_eh] ==> ignore + arg [-plugin-opt=-pass-through=-lmoldname] ==> ignore + arg [-plugin-opt=-pass-through=-lmingwex] ==> ignore + arg [-plugin-opt=-pass-through=-lmsvcrt] ==> ignore + arg [--sysroot=C:/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64] ==> ignore + arg [-m] ==> ignore + arg [i386pep] ==> ignore + arg [-Bdynamic] ==> ignore + arg [-o] ==> ignore + arg [cmTC_0d28b.exe] ==> ignore + arg [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/../lib/crt2.o] ==> ignore + arg [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/crtbegin.o] ==> ignore + arg [-LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0] ==> dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0] + arg [-LC:/BC/C/mingw64/bin/../lib/gcc] ==> dir [C:/BC/C/mingw64/bin/../lib/gcc] + arg [-LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/../lib] ==> dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/../lib] + arg [-LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../lib] ==> dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../lib] + arg [-LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib] ==> dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib] + arg [-LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../..] ==> dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../..] + arg [--whole-archive] ==> ignore + arg [CMakeFiles\cmTC_0d28b.dir/objects.a] ==> ignore + arg [--no-whole-archive] ==> ignore + arg [--out-implib] ==> ignore + arg [libcmTC_0d28b.dll.a] ==> ignore + arg [--major-image-version] ==> ignore + arg [0] ==> ignore + arg [--minor-image-version] ==> ignore + arg [0] ==> ignore + arg [-lmingw32] ==> lib [mingw32] + arg [-lgcc] ==> lib [gcc] + arg [-lgcc_eh] ==> lib [gcc_eh] + arg [-lmoldname] ==> lib [moldname] + arg [-lmingwex] ==> lib [mingwex] + arg [-lmsvcrt] ==> lib [msvcrt] + arg [-lpthread] ==> lib [pthread] + arg [-ladvapi32] ==> lib [advapi32] + arg [-lshell32] ==> lib [shell32] + arg [-luser32] ==> lib [user32] + arg [-lkernel32] ==> lib [kernel32] + arg [-liconv] ==> lib [iconv] + arg [-lmingw32] ==> lib [mingw32] + arg [-lgcc] ==> lib [gcc] + arg [-lgcc_eh] ==> lib [gcc_eh] + arg [-lmoldname] ==> lib [moldname] + arg [-lmingwex] ==> lib [mingwex] + arg [-lmsvcrt] ==> lib [msvcrt] + arg [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/crtend.o] ==> ignore + remove lib [gcc_eh] + remove lib [msvcrt] + remove lib [gcc_eh] + remove lib [msvcrt] + collapse library dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0] ==> [C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0] + collapse library dir [C:/BC/C/mingw64/bin/../lib/gcc] ==> [C:/BC/C/mingw64/lib/gcc] + collapse library dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/../lib] ==> [C:/BC/C/mingw64/x86_64-w64-mingw32/lib] + collapse library dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../lib] ==> [C:/BC/C/mingw64/lib] + collapse library dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib] ==> [C:/BC/C/mingw64/x86_64-w64-mingw32/lib] + collapse library dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../..] ==> [C:/BC/C/mingw64/lib] + implicit libs: [mingw32;gcc;moldname;mingwex;pthread;advapi32;shell32;user32;kernel32;iconv;mingw32;gcc;moldname;mingwex] + implicit dirs: [C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0;C:/BC/C/mingw64/lib/gcc;C:/BC/C/mingw64/x86_64-w64-mingw32/lib;C:/BC/C/mingw64/lib] + implicit fwks: [] + + +Detecting CXX compiler ABI info compiled with the following output: +Change Dir: D:/2021_2/cids-server/cmake-build-debug/CMakeFiles/CMakeTmp + +Run Build Command(s):C:/BC/C/mingw64/bin/mingw32-make.exe cmTC_84b36/fast && C:/BC/C/mingw64/bin/mingw32-make.exe -f CMakeFiles\cmTC_84b36.dir\build.make CMakeFiles/cmTC_84b36.dir/build +mingw32-make.exe[1]: Entering directory 'D:/2021_2/cids-server/cmake-build-debug/CMakeFiles/CMakeTmp' +Building CXX object CMakeFiles/cmTC_84b36.dir/CMakeCXXCompilerABI.cpp.obj +C:\BC\C\mingw64\bin\g++.exe -v -o CMakeFiles\cmTC_84b36.dir\CMakeCXXCompilerABI.cpp.obj -c C:\Users\XM\AppData\Local\JetBrains\Toolbox\apps\CLion\ch-0\211.7142.21\bin\cmake\win\share\cmake-3.19\Modules\CMakeCXXCompilerABI.cpp +Using built-in specs. +COLLECT_GCC=C:\BC\C\mingw64\bin\g++.exe +Target: x86_64-w64-mingw32 +Configured with: ../../../src/gcc-8.1.0/configure --host=x86_64-w64-mingw32 --build=x86_64-w64-mingw32 --target=x86_64-w64-mingw32 --prefix=/mingw64 --with-sysroot=/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64 --enable-shared --enable-static --disable-multilib --enable-languages=c,c++,fortran,lto --enable-libstdcxx-time=yes --enable-threads=posix --enable-libgomp --enable-libatomic --enable-lto --enable-graphite --enable-checking=release --enable-fully-dynamic-string --enable-version-specific-runtime-libs --disable-libstdcxx-pch --disable-libstdcxx-debug --enable-bootstrap --disable-rpath --disable-win32-registry --disable-nls --disable-werror --disable-symvers --with-gnu-as --with-gnu-ld --with-arch=nocona --with-tune=core2 --with-libiconv --with-system-zlib --with-gmp=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-mpfr=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-mpc=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-isl=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-pkgversion='x86_64-posix-seh-rev0, Built by MinGW-W64 project' --with-bugurl=https://sourceforge.net/projects/mingw-w64 CFLAGS='-O2 -pipe -fno-ident -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' CXXFLAGS='-O2 -pipe -fno-ident -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' CPPFLAGS=' -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' LDFLAGS='-pipe -fno-ident -L/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/lib -L/c/mingw810/prerequisites/x86_64-zlib-static/lib -L/c/mingw810/prerequisites/x86_64-w64-mingw32-static/lib ' +Thread model: posix +gcc version 8.1.0 (x86_64-posix-seh-rev0, Built by MinGW-W64 project) +COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles\cmTC_84b36.dir\CMakeCXXCompilerABI.cpp.obj' '-c' '-shared-libgcc' '-mtune=core2' '-march=nocona' + C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/cc1plus.exe -quiet -v -iprefix C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/ -D_REENTRANT C:\Users\XM\AppData\Local\JetBrains\Toolbox\apps\CLion\ch-0\211.7142.21\bin\cmake\win\share\cmake-3.19\Modules\CMakeCXXCompilerABI.cpp -quiet -dumpbase CMakeCXXCompilerABI.cpp -mtune=core2 -march=nocona -auxbase-strip CMakeFiles\cmTC_84b36.dir\CMakeCXXCompilerABI.cpp.obj -version -o C:\Users\XM\AppData\Local\Temp\ccj3lm8R.s +GNU C++14 (x86_64-posix-seh-rev0, Built by MinGW-W64 project) version 8.1.0 (x86_64-w64-mingw32) + compiled by GNU C version 8.1.0, GMP version 6.1.2, MPFR version 4.0.1, MPC version 1.1.0, isl version isl-0.18-GMP + +GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072 +ignoring duplicate directory "C:/BC/C/mingw64/lib/gcc/../../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++" +ignoring duplicate directory "C:/BC/C/mingw64/lib/gcc/../../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/x86_64-w64-mingw32" +ignoring duplicate directory "C:/BC/C/mingw64/lib/gcc/../../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/backward" +ignoring duplicate directory "C:/BC/C/mingw64/lib/gcc/../../lib/gcc/x86_64-w64-mingw32/8.1.0/include" +ignoring nonexistent directory "C:/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64C:/msys64/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../include" +ignoring duplicate directory "C:/BC/C/mingw64/lib/gcc/../../lib/gcc/x86_64-w64-mingw32/8.1.0/include-fixed" +ignoring duplicate directory "C:/BC/C/mingw64/lib/gcc/../../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/include" +ignoring nonexistent directory "C:/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/mingw/include" +#include "..." search starts here: +#include <...> search starts here: + C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++ + C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/x86_64-w64-mingw32 + C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/backward + C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include + C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include-fixed + C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/include +End of search list. +GNU C++14 (x86_64-posix-seh-rev0, Built by MinGW-W64 project) version 8.1.0 (x86_64-w64-mingw32) + compiled by GNU C version 8.1.0, GMP version 6.1.2, MPFR version 4.0.1, MPC version 1.1.0, isl version isl-0.18-GMP + +GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072 +Compiler executable checksum: 82f0c9785fd37a38ba7b7f8357369a82 +COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles\cmTC_84b36.dir\CMakeCXXCompilerABI.cpp.obj' '-c' '-shared-libgcc' '-mtune=core2' '-march=nocona' + C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/bin/as.exe -v -o CMakeFiles\cmTC_84b36.dir\CMakeCXXCompilerABI.cpp.obj C:\Users\XM\AppData\Local\Temp\ccj3lm8R.s +GNU assembler version 2.30 (x86_64-w64-mingw32) using BFD version (GNU Binutils) 2.30 +COMPILER_PATH=C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/;C:/BC/C/mingw64/bin/../libexec/gcc/;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/bin/ +LIBRARY_PATH=C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/;C:/BC/C/mingw64/bin/../lib/gcc/;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/../lib/;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../lib/;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../ +COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles\cmTC_84b36.dir\CMakeCXXCompilerABI.cpp.obj' '-c' '-shared-libgcc' '-mtune=core2' '-march=nocona' +Linking CXX executable cmTC_84b36.exe +C:\Users\XM\AppData\Local\JetBrains\Toolbox\apps\CLion\ch-0\211.7142.21\bin\cmake\win\bin\cmake.exe -E cmake_link_script CMakeFiles\cmTC_84b36.dir\link.txt --verbose=1 +C:\Users\XM\AppData\Local\JetBrains\Toolbox\apps\CLion\ch-0\211.7142.21\bin\cmake\win\bin\cmake.exe -E rm -f CMakeFiles\cmTC_84b36.dir/objects.a +C:\BC\C\mingw64\bin\ar.exe cr CMakeFiles\cmTC_84b36.dir/objects.a @CMakeFiles\cmTC_84b36.dir\objects1.rsp +C:\BC\C\mingw64\bin\g++.exe -v -Wl,--whole-archive CMakeFiles\cmTC_84b36.dir/objects.a -Wl,--no-whole-archive -o cmTC_84b36.exe -Wl,--out-implib,libcmTC_84b36.dll.a -Wl,--major-image-version,0,--minor-image-version,0 +Using built-in specs. +COLLECT_GCC=C:\BC\C\mingw64\bin\g++.exe +COLLECT_LTO_WRAPPER=C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/lto-wrapper.exe +Target: x86_64-w64-mingw32 +Configured with: ../../../src/gcc-8.1.0/configure --host=x86_64-w64-mingw32 --build=x86_64-w64-mingw32 --target=x86_64-w64-mingw32 --prefix=/mingw64 --with-sysroot=/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64 --enable-shared --enable-static --disable-multilib --enable-languages=c,c++,fortran,lto --enable-libstdcxx-time=yes --enable-threads=posix --enable-libgomp --enable-libatomic --enable-lto --enable-graphite --enable-checking=release --enable-fully-dynamic-string --enable-version-specific-runtime-libs --disable-libstdcxx-pch --disable-libstdcxx-debug --enable-bootstrap --disable-rpath --disable-win32-registry --disable-nls --disable-werror --disable-symvers --with-gnu-as --with-gnu-ld --with-arch=nocona --with-tune=core2 --with-libiconv --with-system-zlib --with-gmp=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-mpfr=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-mpc=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-isl=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-pkgversion='x86_64-posix-seh-rev0, Built by MinGW-W64 project' --with-bugurl=https://sourceforge.net/projects/mingw-w64 CFLAGS='-O2 -pipe -fno-ident -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' CXXFLAGS='-O2 -pipe -fno-ident -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' CPPFLAGS=' -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' LDFLAGS='-pipe -fno-ident -L/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/lib -L/c/mingw810/prerequisites/x86_64-zlib-static/lib -L/c/mingw810/prerequisites/x86_64-w64-mingw32-static/lib ' +Thread model: posix +gcc version 8.1.0 (x86_64-posix-seh-rev0, Built by MinGW-W64 project) +COMPILER_PATH=C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/;C:/BC/C/mingw64/bin/../libexec/gcc/;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/bin/ +LIBRARY_PATH=C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/;C:/BC/C/mingw64/bin/../lib/gcc/;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/../lib/;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../lib/;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/;C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../ +COLLECT_GCC_OPTIONS='-v' '-o' 'cmTC_84b36.exe' '-shared-libgcc' '-mtune=core2' '-march=nocona' + C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/collect2.exe -plugin C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/liblto_plugin-0.dll -plugin-opt=C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/lto-wrapper.exe -plugin-opt=-fresolution=C:\Users\XM\AppData\Local\Temp\ccmeLhKb.res -plugin-opt=-pass-through=-lmingw32 -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lmoldname -plugin-opt=-pass-through=-lmingwex -plugin-opt=-pass-through=-lmsvcrt -plugin-opt=-pass-through=-lpthread -plugin-opt=-pass-through=-ladvapi32 -plugin-opt=-pass-through=-lshell32 -plugin-opt=-pass-through=-luser32 -plugin-opt=-pass-through=-lkernel32 -plugin-opt=-pass-through=-liconv -plugin-opt=-pass-through=-lmingw32 -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lmoldname -plugin-opt=-pass-through=-lmingwex -plugin-opt=-pass-through=-lmsvcrt --sysroot=C:/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64 -m i386pep -Bdynamic -o cmTC_84b36.exe C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/../lib/crt2.o C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/crtbegin.o -LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0 -LC:/BC/C/mingw64/bin/../lib/gcc -LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/../lib -LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../lib -LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib -LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../.. --whole-archive CMakeFiles\cmTC_84b36.dir/objects.a --no-whole-archive --out-implib libcmTC_84b36.dll.a --major-image-version 0 --minor-image-version 0 -lstdc++ -lmingw32 -lgcc_s -lgcc -lmoldname -lmingwex -lmsvcrt -lpthread -ladvapi32 -lshell32 -luser32 -lkernel32 -liconv -lmingw32 -lgcc_s -lgcc -lmoldname -lmingwex -lmsvcrt C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/crtend.o +COLLECT_GCC_OPTIONS='-v' '-o' 'cmTC_84b36.exe' '-shared-libgcc' '-mtune=core2' '-march=nocona' +mingw32-make.exe[1]: Leaving directory 'D:/2021_2/cids-server/cmake-build-debug/CMakeFiles/CMakeTmp' + + + +Parsed CXX implicit include dir info from above output: rv=done + found start of include info + found start of implicit include info + add: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++] + add: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/x86_64-w64-mingw32] + add: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/backward] + add: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include] + add: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include-fixed] + add: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/include] + end of search list found + collapse include dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++] ==> [C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++] + collapse include dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/x86_64-w64-mingw32] ==> [C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/x86_64-w64-mingw32] + collapse include dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/backward] ==> [C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/backward] + collapse include dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include] ==> [C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include] + collapse include dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include-fixed] ==> [C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include-fixed] + collapse include dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/include] ==> [C:/BC/C/mingw64/x86_64-w64-mingw32/include] + implicit include dirs: [C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++;C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/x86_64-w64-mingw32;C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/backward;C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include;C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/include-fixed;C:/BC/C/mingw64/x86_64-w64-mingw32/include] + + +Parsed CXX implicit link information from above output: + link line regex: [^( *|.*[/\])(ld\.exe|CMAKE_LINK_STARTFILE-NOTFOUND|([^/\]+-)?ld|collect2)[^/\]*( |$)] + ignore line: [Change Dir: D:/2021_2/cids-server/cmake-build-debug/CMakeFiles/CMakeTmp] + ignore line: [] + ignore line: [Run Build Command(s):C:/BC/C/mingw64/bin/mingw32-make.exe cmTC_84b36/fast && C:/BC/C/mingw64/bin/mingw32-make.exe -f CMakeFiles\cmTC_84b36.dir\build.make CMakeFiles/cmTC_84b36.dir/build] + ignore line: [mingw32-make.exe[1]: Entering directory 'D:/2021_2/cids-server/cmake-build-debug/CMakeFiles/CMakeTmp'] + ignore line: [Building CXX object CMakeFiles/cmTC_84b36.dir/CMakeCXXCompilerABI.cpp.obj] + ignore line: [C:\BC\C\mingw64\bin\g++.exe -v -o CMakeFiles\cmTC_84b36.dir\CMakeCXXCompilerABI.cpp.obj -c C:\Users\XM\AppData\Local\JetBrains\Toolbox\apps\CLion\ch-0\211.7142.21\bin\cmake\win\share\cmake-3.19\Modules\CMakeCXXCompilerABI.cpp] + ignore line: [Using built-in specs.] + ignore line: [COLLECT_GCC=C:\BC\C\mingw64\bin\g++.exe] + ignore line: [Target: x86_64-w64-mingw32] + ignore line: [Configured with: ../../../src/gcc-8.1.0/configure --host=x86_64-w64-mingw32 --build=x86_64-w64-mingw32 --target=x86_64-w64-mingw32 --prefix=/mingw64 --with-sysroot=/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64 --enable-shared --enable-static --disable-multilib --enable-languages=c,c++,fortran,lto --enable-libstdcxx-time=yes --enable-threads=posix --enable-libgomp --enable-libatomic --enable-lto --enable-graphite --enable-checking=release --enable-fully-dynamic-string --enable-version-specific-runtime-libs --disable-libstdcxx-pch --disable-libstdcxx-debug --enable-bootstrap --disable-rpath --disable-win32-registry --disable-nls --disable-werror --disable-symvers --with-gnu-as --with-gnu-ld --with-arch=nocona --with-tune=core2 --with-libiconv --with-system-zlib --with-gmp=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-mpfr=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-mpc=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-isl=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-pkgversion='x86_64-posix-seh-rev0, Built by MinGW-W64 project' --with-bugurl=https://sourceforge.net/projects/mingw-w64 CFLAGS='-O2 -pipe -fno-ident -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' CXXFLAGS='-O2 -pipe -fno-ident -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' CPPFLAGS=' -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' LDFLAGS='-pipe -fno-ident -L/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/lib -L/c/mingw810/prerequisites/x86_64-zlib-static/lib -L/c/mingw810/prerequisites/x86_64-w64-mingw32-static/lib '] + ignore line: [Thread model: posix] + ignore line: [gcc version 8.1.0 (x86_64-posix-seh-rev0 Built by MinGW-W64 project) ] + ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles\cmTC_84b36.dir\CMakeCXXCompilerABI.cpp.obj' '-c' '-shared-libgcc' '-mtune=core2' '-march=nocona'] + ignore line: [ C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/cc1plus.exe -quiet -v -iprefix C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/ -D_REENTRANT C:\Users\XM\AppData\Local\JetBrains\Toolbox\apps\CLion\ch-0\211.7142.21\bin\cmake\win\share\cmake-3.19\Modules\CMakeCXXCompilerABI.cpp -quiet -dumpbase CMakeCXXCompilerABI.cpp -mtune=core2 -march=nocona -auxbase-strip CMakeFiles\cmTC_84b36.dir\CMakeCXXCompilerABI.cpp.obj -version -o C:\Users\XM\AppData\Local\Temp\ccj3lm8R.s] + ignore line: [GNU C++14 (x86_64-posix-seh-rev0 Built by MinGW-W64 project) version 8.1.0 (x86_64-w64-mingw32)] + ignore line: [ compiled by GNU C version 8.1.0 GMP version 6.1.2 MPFR version 4.0.1 MPC version 1.1.0 isl version isl-0.18-GMP] + ignore line: [] + ignore line: [GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072] + ignore line: [ignoring duplicate directory "C:/BC/C/mingw64/lib/gcc/../../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++"] + ignore line: [ignoring duplicate directory "C:/BC/C/mingw64/lib/gcc/../../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/x86_64-w64-mingw32"] + ignore line: [ignoring duplicate directory "C:/BC/C/mingw64/lib/gcc/../../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/backward"] + ignore line: [ignoring duplicate directory "C:/BC/C/mingw64/lib/gcc/../../lib/gcc/x86_64-w64-mingw32/8.1.0/include"] + ignore line: [ignoring nonexistent directory "C:/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64C:/msys64/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../include"] + ignore line: [ignoring duplicate directory "C:/BC/C/mingw64/lib/gcc/../../lib/gcc/x86_64-w64-mingw32/8.1.0/include-fixed"] + ignore line: [ignoring duplicate directory "C:/BC/C/mingw64/lib/gcc/../../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/include"] + ignore line: [ignoring nonexistent directory "C:/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/mingw/include"] + ignore line: [#include "..." search starts here:] + ignore line: [#include <...> search starts here:] + ignore line: [ C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++] + ignore line: [ C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/x86_64-w64-mingw32] + ignore line: [ C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include/c++/backward] + ignore line: [ C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include] + ignore line: [ C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/include-fixed] + ignore line: [ C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/include] + ignore line: [End of search list.] + ignore line: [GNU C++14 (x86_64-posix-seh-rev0 Built by MinGW-W64 project) version 8.1.0 (x86_64-w64-mingw32)] + ignore line: [ compiled by GNU C version 8.1.0 GMP version 6.1.2 MPFR version 4.0.1 MPC version 1.1.0 isl version isl-0.18-GMP] + ignore line: [] + ignore line: [GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072] + ignore line: [Compiler executable checksum: 82f0c9785fd37a38ba7b7f8357369a82] + ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles\cmTC_84b36.dir\CMakeCXXCompilerABI.cpp.obj' '-c' '-shared-libgcc' '-mtune=core2' '-march=nocona'] + ignore line: [ C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/bin/as.exe -v -o CMakeFiles\cmTC_84b36.dir\CMakeCXXCompilerABI.cpp.obj C:\Users\XM\AppData\Local\Temp\ccj3lm8R.s] + ignore line: [GNU assembler version 2.30 (x86_64-w64-mingw32) using BFD version (GNU Binutils) 2.30] + ignore line: [COMPILER_PATH=C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/] + ignore line: [C:/BC/C/mingw64/bin/../libexec/gcc/] + ignore line: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/bin/] + ignore line: [LIBRARY_PATH=C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/] + ignore line: [C:/BC/C/mingw64/bin/../lib/gcc/] + ignore line: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/../lib/] + ignore line: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../lib/] + ignore line: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/] + ignore line: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../] + ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'CMakeFiles\cmTC_84b36.dir\CMakeCXXCompilerABI.cpp.obj' '-c' '-shared-libgcc' '-mtune=core2' '-march=nocona'] + ignore line: [Linking CXX executable cmTC_84b36.exe] + ignore line: [C:\Users\XM\AppData\Local\JetBrains\Toolbox\apps\CLion\ch-0\211.7142.21\bin\cmake\win\bin\cmake.exe -E cmake_link_script CMakeFiles\cmTC_84b36.dir\link.txt --verbose=1] + ignore line: [C:\Users\XM\AppData\Local\JetBrains\Toolbox\apps\CLion\ch-0\211.7142.21\bin\cmake\win\bin\cmake.exe -E rm -f CMakeFiles\cmTC_84b36.dir/objects.a] + ignore line: [C:\BC\C\mingw64\bin\ar.exe cr CMakeFiles\cmTC_84b36.dir/objects.a @CMakeFiles\cmTC_84b36.dir\objects1.rsp] + ignore line: [C:\BC\C\mingw64\bin\g++.exe -v -Wl --whole-archive CMakeFiles\cmTC_84b36.dir/objects.a -Wl --no-whole-archive -o cmTC_84b36.exe -Wl --out-implib libcmTC_84b36.dll.a -Wl --major-image-version 0 --minor-image-version 0 ] + ignore line: [Using built-in specs.] + ignore line: [COLLECT_GCC=C:\BC\C\mingw64\bin\g++.exe] + ignore line: [COLLECT_LTO_WRAPPER=C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/lto-wrapper.exe] + ignore line: [Target: x86_64-w64-mingw32] + ignore line: [Configured with: ../../../src/gcc-8.1.0/configure --host=x86_64-w64-mingw32 --build=x86_64-w64-mingw32 --target=x86_64-w64-mingw32 --prefix=/mingw64 --with-sysroot=/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64 --enable-shared --enable-static --disable-multilib --enable-languages=c,c++,fortran,lto --enable-libstdcxx-time=yes --enable-threads=posix --enable-libgomp --enable-libatomic --enable-lto --enable-graphite --enable-checking=release --enable-fully-dynamic-string --enable-version-specific-runtime-libs --disable-libstdcxx-pch --disable-libstdcxx-debug --enable-bootstrap --disable-rpath --disable-win32-registry --disable-nls --disable-werror --disable-symvers --with-gnu-as --with-gnu-ld --with-arch=nocona --with-tune=core2 --with-libiconv --with-system-zlib --with-gmp=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-mpfr=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-mpc=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-isl=/c/mingw810/prerequisites/x86_64-w64-mingw32-static --with-pkgversion='x86_64-posix-seh-rev0, Built by MinGW-W64 project' --with-bugurl=https://sourceforge.net/projects/mingw-w64 CFLAGS='-O2 -pipe -fno-ident -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' CXXFLAGS='-O2 -pipe -fno-ident -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' CPPFLAGS=' -I/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/include -I/c/mingw810/prerequisites/x86_64-zlib-static/include -I/c/mingw810/prerequisites/x86_64-w64-mingw32-static/include' LDFLAGS='-pipe -fno-ident -L/c/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64/opt/lib -L/c/mingw810/prerequisites/x86_64-zlib-static/lib -L/c/mingw810/prerequisites/x86_64-w64-mingw32-static/lib '] + ignore line: [Thread model: posix] + ignore line: [gcc version 8.1.0 (x86_64-posix-seh-rev0 Built by MinGW-W64 project) ] + ignore line: [COMPILER_PATH=C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/] + ignore line: [C:/BC/C/mingw64/bin/../libexec/gcc/] + ignore line: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/bin/] + ignore line: [LIBRARY_PATH=C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/] + ignore line: [C:/BC/C/mingw64/bin/../lib/gcc/] + ignore line: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/../lib/] + ignore line: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../lib/] + ignore line: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/] + ignore line: [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../] + ignore line: [COLLECT_GCC_OPTIONS='-v' '-o' 'cmTC_84b36.exe' '-shared-libgcc' '-mtune=core2' '-march=nocona'] + link line: [ C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/collect2.exe -plugin C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/liblto_plugin-0.dll -plugin-opt=C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/lto-wrapper.exe -plugin-opt=-fresolution=C:\Users\XM\AppData\Local\Temp\ccmeLhKb.res -plugin-opt=-pass-through=-lmingw32 -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lmoldname -plugin-opt=-pass-through=-lmingwex -plugin-opt=-pass-through=-lmsvcrt -plugin-opt=-pass-through=-lpthread -plugin-opt=-pass-through=-ladvapi32 -plugin-opt=-pass-through=-lshell32 -plugin-opt=-pass-through=-luser32 -plugin-opt=-pass-through=-lkernel32 -plugin-opt=-pass-through=-liconv -plugin-opt=-pass-through=-lmingw32 -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lmoldname -plugin-opt=-pass-through=-lmingwex -plugin-opt=-pass-through=-lmsvcrt --sysroot=C:/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64 -m i386pep -Bdynamic -o cmTC_84b36.exe C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/../lib/crt2.o C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/crtbegin.o -LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0 -LC:/BC/C/mingw64/bin/../lib/gcc -LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/../lib -LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../lib -LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib -LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../.. --whole-archive CMakeFiles\cmTC_84b36.dir/objects.a --no-whole-archive --out-implib libcmTC_84b36.dll.a --major-image-version 0 --minor-image-version 0 -lstdc++ -lmingw32 -lgcc_s -lgcc -lmoldname -lmingwex -lmsvcrt -lpthread -ladvapi32 -lshell32 -luser32 -lkernel32 -liconv -lmingw32 -lgcc_s -lgcc -lmoldname -lmingwex -lmsvcrt C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/crtend.o] + arg [C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/collect2.exe] ==> ignore + arg [-plugin] ==> ignore + arg [C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/liblto_plugin-0.dll] ==> ignore + arg [-plugin-opt=C:/BC/C/mingw64/bin/../libexec/gcc/x86_64-w64-mingw32/8.1.0/lto-wrapper.exe] ==> ignore + arg [-plugin-opt=-fresolution=C:\Users\XM\AppData\Local\Temp\ccmeLhKb.res] ==> ignore + arg [-plugin-opt=-pass-through=-lmingw32] ==> ignore + arg [-plugin-opt=-pass-through=-lgcc_s] ==> ignore + arg [-plugin-opt=-pass-through=-lgcc] ==> ignore + arg [-plugin-opt=-pass-through=-lmoldname] ==> ignore + arg [-plugin-opt=-pass-through=-lmingwex] ==> ignore + arg [-plugin-opt=-pass-through=-lmsvcrt] ==> ignore + arg [-plugin-opt=-pass-through=-lpthread] ==> ignore + arg [-plugin-opt=-pass-through=-ladvapi32] ==> ignore + arg [-plugin-opt=-pass-through=-lshell32] ==> ignore + arg [-plugin-opt=-pass-through=-luser32] ==> ignore + arg [-plugin-opt=-pass-through=-lkernel32] ==> ignore + arg [-plugin-opt=-pass-through=-liconv] ==> ignore + arg [-plugin-opt=-pass-through=-lmingw32] ==> ignore + arg [-plugin-opt=-pass-through=-lgcc_s] ==> ignore + arg [-plugin-opt=-pass-through=-lgcc] ==> ignore + arg [-plugin-opt=-pass-through=-lmoldname] ==> ignore + arg [-plugin-opt=-pass-through=-lmingwex] ==> ignore + arg [-plugin-opt=-pass-through=-lmsvcrt] ==> ignore + arg [--sysroot=C:/mingw810/x86_64-810-posix-seh-rt_v6-rev0/mingw64] ==> ignore + arg [-m] ==> ignore + arg [i386pep] ==> ignore + arg [-Bdynamic] ==> ignore + arg [-o] ==> ignore + arg [cmTC_84b36.exe] ==> ignore + arg [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/../lib/crt2.o] ==> ignore + arg [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/crtbegin.o] ==> ignore + arg [-LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0] ==> dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0] + arg [-LC:/BC/C/mingw64/bin/../lib/gcc] ==> dir [C:/BC/C/mingw64/bin/../lib/gcc] + arg [-LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/../lib] ==> dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/../lib] + arg [-LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../lib] ==> dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../lib] + arg [-LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib] ==> dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib] + arg [-LC:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../..] ==> dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../..] + arg [--whole-archive] ==> ignore + arg [CMakeFiles\cmTC_84b36.dir/objects.a] ==> ignore + arg [--no-whole-archive] ==> ignore + arg [--out-implib] ==> ignore + arg [libcmTC_84b36.dll.a] ==> ignore + arg [--major-image-version] ==> ignore + arg [0] ==> ignore + arg [--minor-image-version] ==> ignore + arg [0] ==> ignore + arg [-lstdc++] ==> lib [stdc++] + arg [-lmingw32] ==> lib [mingw32] + arg [-lgcc_s] ==> lib [gcc_s] + arg [-lgcc] ==> lib [gcc] + arg [-lmoldname] ==> lib [moldname] + arg [-lmingwex] ==> lib [mingwex] + arg [-lmsvcrt] ==> lib [msvcrt] + arg [-lpthread] ==> lib [pthread] + arg [-ladvapi32] ==> lib [advapi32] + arg [-lshell32] ==> lib [shell32] + arg [-luser32] ==> lib [user32] + arg [-lkernel32] ==> lib [kernel32] + arg [-liconv] ==> lib [iconv] + arg [-lmingw32] ==> lib [mingw32] + arg [-lgcc_s] ==> lib [gcc_s] + arg [-lgcc] ==> lib [gcc] + arg [-lmoldname] ==> lib [moldname] + arg [-lmingwex] ==> lib [mingwex] + arg [-lmsvcrt] ==> lib [msvcrt] + arg [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/crtend.o] ==> ignore + remove lib [msvcrt] + remove lib [msvcrt] + collapse library dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0] ==> [C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0] + collapse library dir [C:/BC/C/mingw64/bin/../lib/gcc] ==> [C:/BC/C/mingw64/lib/gcc] + collapse library dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib/../lib] ==> [C:/BC/C/mingw64/x86_64-w64-mingw32/lib] + collapse library dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../lib] ==> [C:/BC/C/mingw64/lib] + collapse library dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../../../x86_64-w64-mingw32/lib] ==> [C:/BC/C/mingw64/x86_64-w64-mingw32/lib] + collapse library dir [C:/BC/C/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/8.1.0/../../..] ==> [C:/BC/C/mingw64/lib] + implicit libs: [stdc++;mingw32;gcc_s;gcc;moldname;mingwex;pthread;advapi32;shell32;user32;kernel32;iconv;mingw32;gcc_s;gcc;moldname;mingwex] + implicit dirs: [C:/BC/C/mingw64/lib/gcc/x86_64-w64-mingw32/8.1.0;C:/BC/C/mingw64/lib/gcc;C:/BC/C/mingw64/x86_64-w64-mingw32/lib;C:/BC/C/mingw64/lib] + implicit fwks: [] + + diff --git a/cmake-build-debug/CMakeFiles/clion-environment.txt b/cmake-build-debug/CMakeFiles/clion-environment.txt new file mode 100644 index 0000000..bd31bb7 --- /dev/null +++ b/cmake-build-debug/CMakeFiles/clion-environment.txt @@ -0,0 +1,4 @@ +ToolSet: w64 6.0 (local)@C:\BC\C\mingw64 +Options: + +Options: \ No newline at end of file diff --git a/cmake-build-debug/CMakeFiles/clion-log.txt b/cmake-build-debug/CMakeFiles/clion-log.txt new file mode 100644 index 0000000..8d31f15 --- /dev/null +++ b/cmake-build-debug/CMakeFiles/clion-log.txt @@ -0,0 +1,4 @@ +C:\Users\XM\AppData\Local\JetBrains\Toolbox\apps\CLion\ch-0\211.7142.21\bin\cmake\win\bin\cmake.exe -DCMAKE_BUILD_TYPE=Debug -G "CodeBlocks - MinGW Makefiles" D:\2021_2\cids-server +-- Configuring done +-- Generating done +-- Build files have been written to: D:/2021_2/cids-server/cmake-build-debug diff --git a/cmake-build-debug/CMakeFiles/cmake.check_cache b/cmake-build-debug/CMakeFiles/cmake.check_cache new file mode 100644 index 0000000..3dccd73 --- /dev/null +++ b/cmake-build-debug/CMakeFiles/cmake.check_cache @@ -0,0 +1 @@ +# This file is generated by cmake for dependency checking of the CMakeCache.txt file diff --git a/include/Common/ServerBase.hpp b/include/Common/ServerBase.hpp new file mode 100644 index 0000000..cbfb213 --- /dev/null +++ b/include/Common/ServerBase.hpp @@ -0,0 +1,46 @@ +// +// Created by XM on 2021/5/18. +// + +#ifndef PRO_SERVERBASE_HPP +#define PRO_SERVERBASE_HPP + +#pragma once + +#include + +struct scu_date { + int week; + int day; + scu_date(int w, int d): week(w), day(d) { }; +}; + +class scu_time { + +private: + size_t hour; + size_t minute; + +public: + + scu_time(size_t h, size_t m) : hour(h), minute(m) {} + + scu_time(const scu_time &that) : hour(that.hour), minute(that.minute) {} + + scu_time operator-(const scu_time &rhs) const; + + bool operator<(const scu_time& rhs) const; + + bool operator=(const scu_time &rhs); + + bool operator<=(const scu_time &rhs) const; + + unsigned toSeconds(); + + static scu_time toScutime(const muduo::Timestamp ×tamp) ; + + +}; + + +#endif //PRO_SERVERBASE_HPP diff --git a/include/Common/Telemeter.hpp b/include/Common/Telemeter.hpp new file mode 100644 index 0000000..745f667 --- /dev/null +++ b/include/Common/Telemeter.hpp @@ -0,0 +1,128 @@ +#ifndef SRC_TELEMETER_H +#define SRC_TELEMETER_H + +#pragma once + +#include + +#include +#include + +enum class LoadLevel : uint8_t { + untapped = 0, //no client dispatched on this mirror + light = 1, //[0% - 50%] + medium = 2, //[50% - 80%] + heavy = 3, //[ >= 80%] +}; + +static std::string tostring(LoadLevel ll) { + switch (ll) { + case LoadLevel::untapped: + return "untapped"; + case LoadLevel::light: + return "light"; + case LoadLevel::medium: + return "medium"; + case LoadLevel::heavy: + return "heavy"; + default: + return "undefined"; + } +} + + +//POD type +struct DetailLoadState { + uint8_t mem_load, serve_load, net_load_, reserve_seg_; +}; + +#ifdef SRC_CENTER_H +//center的setting, POD type +struct Setting +{ + uint mir_load_record_interval_; //记录mirror负载到缓存的间隔(按照心跳包的个数来计数), 从配置文件中读 + uint mir_dblog_interval_; //将mirror负载缓存更新到数据库(数据文件)的间隔(缓存了这么多之后打一次log), 从配置文件中读 + uint mir_max_disbeat_time_; //多少个心跳轮无心跳视为断线 + uint cli_login_cache_time_; //清空一个cli登录缓冲的时间 + uint load_balance_interval_; //多少个cli启动后运行一次负载均衡调度算法 + uint clear_mirs_data_time_; //自0点开始何时清空一次mir_data中的信息 + //unsigned long reserve_seg_; //保留段 +}; +//第一字段为60表示一分钟(60个心跳包)记录一次mir的负载情况, +//第二字段为5表示5分钟(缓存5次)输出到遥测数据库一次 + +const constexpr uint _permanent_thread_num_ = 4U; //center的常驻线程数量 + +#endif + +#ifdef SRC_MIRROR_H +//mirror的setting, POD type +struct Setting +{ + int mir_heart_beat_interval; + int mir_load_report_interval; + std::string img_path; + std::string db_source; + std::string db_user; + std::string db_password; + std::string center_ip; + std::string this_ip; + int update_pic_interval; + int utc_time; + std::string update_calendar_time; + std::string clear_clients_time; + int course_interval; + //数据库ip? +}; +#endif + +#define RESERVE_SEGMENG_INIT_VALUE 0U + +namespace telemeter { + const constexpr char *klog_file = "TelemeterLog.txt"; //临时的遥测日志文件 + +#ifdef SRC_CENTER_H + //双缓冲配置表解决一写多读线程安全问题 + + static Setting _set_cache_one = {60, 5, 15, 60, 20, 0}; + static Setting _set_cache_two = {60, 5, 15, 60, 20, 0}; + //主要使用这个指针获取当前配置, 每次读取数据到第二个指针中, 然后交换两个指针的值 + static Setting* setting = &_set_cache_one; + static Setting* setting_copy = &_set_cache_two; + + //将配置信息返回成一个字符串输出 + // static auto settting_info = [](Setting* set = telemeter::setting) -> std::string + // { + // return fmt::format("mir load record interval: -{0}\n \ + // nmir database log interval: -{1}\n \ + // mir max disbeat time: -{2}\n \ + // cli login cache time: -{3}\n \ + // load balance interval: -{4}\n \ + // clear mirs data time: -{5}", + // set->mir_load_record_interval_, + // set->mir_dblog_interval_, + // set->mir_max_disbeat_time_, + // set->cli_login_cache_time_, + // set->load_balance_interval_, + // set->clear_mirs_data_time_); + // }; +#endif + +#ifdef SRC_MIRROR_H + static Setting _set_cache_one = {1, 60, "/var/www/html/images", "Scucids-server","teacher","zhirui208+", "192.168.233.14","192.168.233.13", 6,8,"24:00","24:00",60}; + static Setting _set_cache_two = {1, 60, "/var/www/html/images", "Scucids-server","teacher","zhirui208+", "192.168.233.14", "192.168.233.13",6,8,"24:00","24:00",60}; + //主要使用这个指针获取当前配置, 每次读取数据到第二个指针中, 然后交换两个指针的值 + static Setting* setting = &_set_cache_one; + static Setting* setting_copy = &_set_cache_two; + +#endif + //获取本机负载情况的函数, 需要统计空闲内存占比, cpu负载, 空闲磁盘占比 + //LoadLevel getLocalLoadLevel(); + + //int getLocalMemLoad(); + //int getLocalSevLoad(); + //int getLocalNetLoad(); +} + + +#endif //SRC_TELEMETER_H \ No newline at end of file diff --git a/include/Common/Udp.hpp b/include/Common/Udp.hpp new file mode 100644 index 0000000..96b3624 --- /dev/null +++ b/include/Common/Udp.hpp @@ -0,0 +1,124 @@ +#ifndef SRC_UDP_H +#define SRC_UDP_H + +#pragma once + +#include +#include +#include +#include +#include +#include /* struct hostent */ +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace port +{ + const constexpr size_t kCLI_LOGIN_ = 20800; + const constexpr size_t kCLI_BEAT_ = 20801; + const constexpr size_t kMIR_BEAT_ = 20802; + const constexpr size_t kMIR_HTTP_ = 20803; +} + +namespace protocol +{ + //以字节计算的每个包的大小和协议中每一部分的大小, 二级缩进的和应该等于第一级缩进 + const constexpr size_t kCLI_LOGIN_PACSIZE_ = 8; + const constexpr size_t kCLI_LOGIN_UID_ = 7; + const constexpr size_t kCLI_LOGIN_STATE_ = 1; + + const constexpr size_t kCENT_RESPONSE_PACSIZE_ = 4; + + const constexpr size_t kMIR_BEAT_PACSIZE_ = 8; + const constexpr size_t kMIR_BEAT_IP_ = 4; + const constexpr size_t kMIR_BEAT_LOAD_ = 4; +} + +struct IP { + unsigned char seg0; + unsigned char seg1; + unsigned char seg2; + unsigned char seg3; + + IP(int i0 = 0, int i1 = 0, int i2 = 0, int i3 = 0) : seg0(i0), seg1(i1), seg2(i2), seg3(i3) {}; + + IP(std::string addr) { + std::istringstream iss(addr); + std::string buffer; + std::vector res; + while (std::getline(iss, buffer, '.')) { + res.push_back((unsigned char) (std::stoi(buffer))); + } + if (res.size() != 4) { + //异常 + } + this->seg0 = res[0]; + this->seg1 = res[1]; + this->seg2 = res[2]; + this->seg3 = res[3]; + } + + std::string to_string() + { + return std::to_string(this->seg0) + '.' + std::to_string(this->seg1) + '.' + std::to_string(this->seg2) + '.' + std::to_string(this->seg3); + } + + bool operator==(const IP& ip)const{ + return this->seg0 == ip.seg0 + && this->seg1 == ip.seg1 + && this->seg2 == ip.seg2 + && this->seg3 == ip.seg3; + } + + IP& operator=(const IP& rhs){ + if(this == &rhs) + return *this; + this->seg0 = rhs.seg0; + this->seg1 = rhs.seg1; + this->seg2 = rhs.seg2; + this->seg3 = rhs.seg3; + return *this; + } +}; + +namespace std { + template<> + struct hash : public __hash_base + { + size_t operator()(const IP &ip) const noexcept //这个const noexpect一定要写上去 + { + return (((size_t)ip.seg0) << 24) + (((size_t)ip.seg1) << 16) + (((size_t)ip.seg2) << 8) + ((size_t)ip.seg3) ; + } + }; +} + + +static bool GetHostInfo(std::string& hostName, std::string& Ip) { + char name[256]; + gethostname(name, sizeof(name)); + hostName = name; + + struct hostent* host = gethostbyname(name); + char ipStr[32]; + const char* ret = inet_ntop(host->h_addrtype, host->h_addr_list[0], ipStr, sizeof(ipStr)); + if (NULL==ret) { +// std::cout << "hostname transform to ip failed"; + return false; + } + Ip = ipStr; + return true; +} + + + + +#endif //SRC_UDP_H + + diff --git a/include/Third_Lib/boost/any.hpp b/include/Third_Lib/boost/any.hpp new file mode 100644 index 0000000..892d47c --- /dev/null +++ b/include/Third_Lib/boost/any.hpp @@ -0,0 +1,342 @@ +// See http://www.boost.org/libs/any for Documentation. + +#ifndef BOOST_ANY_INCLUDED +#define BOOST_ANY_INCLUDED + +#if defined(_MSC_VER) +# pragma once +#endif + +// what: variant type boost::any +// who: contributed by Kevlin Henney, +// with features contributed and bugs found by +// Antony Polukhin, Ed Brey, Mark Rodgers, +// Peter Dimov, and James Curran +// when: July 2001, April 2013 - 2020 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost +{ + class any + { + public: // structors + + BOOST_CONSTEXPR any() BOOST_NOEXCEPT + : content(0) + { + } + + template + any(const ValueType & value) + : content(new holder< + BOOST_DEDUCED_TYPENAME remove_cv::type>::type + >(value)) + { + } + + any(const any & other) + : content(other.content ? other.content->clone() : 0) + { + } + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + // Move constructor + any(any&& other) BOOST_NOEXCEPT + : content(other.content) + { + other.content = 0; + } + + // Perfect forwarding of ValueType + template + any(ValueType&& value + , typename boost::disable_if >::type* = 0 // disable if value has type `any&` + , typename boost::disable_if >::type* = 0) // disable if value has type `const ValueType&&` + : content(new holder< typename decay::type >(static_cast(value))) + { + } +#endif + + ~any() BOOST_NOEXCEPT + { + delete content; + } + + public: // modifiers + + any & swap(any & rhs) BOOST_NOEXCEPT + { + placeholder* tmp = content; + content = rhs.content; + rhs.content = tmp; + return *this; + } + + +#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES + template + any & operator=(const ValueType & rhs) + { + any(rhs).swap(*this); + return *this; + } + + any & operator=(any rhs) + { + rhs.swap(*this); + return *this; + } + +#else + any & operator=(const any& rhs) + { + any(rhs).swap(*this); + return *this; + } + + // move assignment + any & operator=(any&& rhs) BOOST_NOEXCEPT + { + rhs.swap(*this); + any().swap(rhs); + return *this; + } + + // Perfect forwarding of ValueType + template + any & operator=(ValueType&& rhs) + { + any(static_cast(rhs)).swap(*this); + return *this; + } +#endif + + public: // queries + + bool empty() const BOOST_NOEXCEPT + { + return !content; + } + + void clear() BOOST_NOEXCEPT + { + any().swap(*this); + } + + const boost::typeindex::type_info& type() const BOOST_NOEXCEPT + { + return content ? content->type() : boost::typeindex::type_id().type_info(); + } + +#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS + private: // types +#else + public: // types (public so any_cast can be non-friend) +#endif + + class BOOST_SYMBOL_VISIBLE placeholder + { + public: // structors + + virtual ~placeholder() + { + } + + public: // queries + + virtual const boost::typeindex::type_info& type() const BOOST_NOEXCEPT = 0; + + virtual placeholder * clone() const = 0; + + }; + + template + class holder +#ifndef BOOST_NO_CXX11_FINAL + final +#endif + : public placeholder + { + public: // structors + + holder(const ValueType & value) + : held(value) + { + } + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + holder(ValueType&& value) + : held(static_cast< ValueType&& >(value)) + { + } +#endif + public: // queries + + const boost::typeindex::type_info& type() const BOOST_NOEXCEPT BOOST_OVERRIDE + { + return boost::typeindex::type_id().type_info(); + } + + placeholder * clone() const BOOST_OVERRIDE + { + return new holder(held); + } + + public: // representation + + ValueType held; + + private: // intentionally left unimplemented + holder & operator=(const holder &); + }; + +#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS + + private: // representation + + template + friend ValueType * any_cast(any *) BOOST_NOEXCEPT; + + template + friend ValueType * unsafe_any_cast(any *) BOOST_NOEXCEPT; + +#else + + public: // representation (public so any_cast can be non-friend) + +#endif + + placeholder * content; + + }; + + inline void swap(any & lhs, any & rhs) BOOST_NOEXCEPT +{ + lhs.swap(rhs); +} + +class BOOST_SYMBOL_VISIBLE bad_any_cast : +#ifndef BOOST_NO_RTTI +public std::bad_cast +#else +public std::exception +#endif +{ +public: +const char * what() const BOOST_NOEXCEPT_OR_NOTHROW BOOST_OVERRIDE + { + return "boost::bad_any_cast: " + "failed conversion using boost::any_cast"; + } +}; + +template +ValueType * any_cast(any * operand) BOOST_NOEXCEPT +{ +return operand && operand->type() == boost::typeindex::type_id() +? boost::addressof( +static_cast::type> *>(operand->content)->held +) +: 0; +} + +template +inline const ValueType * any_cast(const any * operand) BOOST_NOEXCEPT +{ +return any_cast(const_cast(operand)); +} + +template +ValueType any_cast(any & operand) +{ + typedef BOOST_DEDUCED_TYPENAME remove_reference::type nonref; + + + nonref * result = any_cast(boost::addressof(operand)); + if(!result) + boost::throw_exception(bad_any_cast()); + + // Attempt to avoid construction of a temporary object in cases when + // `ValueType` is not a reference. Example: + // `static_cast(*result);` + // which is equal to `std::string(*result);` + typedef BOOST_DEDUCED_TYPENAME boost::conditional< + boost::is_reference::value, + ValueType, + BOOST_DEDUCED_TYPENAME boost::add_reference::type + >::type ref_type; + +#ifdef BOOST_MSVC + # pragma warning(push) +# pragma warning(disable: 4172) // "returning address of local variable or temporary" but *result is not local! +#endif + return static_cast(*result); +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif +} + +template +inline ValueType any_cast(const any & operand) +{ + typedef BOOST_DEDUCED_TYPENAME remove_reference::type nonref; + return any_cast(const_cast(operand)); +} + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +template +inline ValueType any_cast(any&& operand) +{ + BOOST_STATIC_ASSERT_MSG( + boost::is_rvalue_reference::value /*true if ValueType is rvalue or just a value*/ + || boost::is_const< typename boost::remove_reference::type >::value, + "boost::any_cast shall not be used for getting nonconst references to temporary objects" + ); + return any_cast(operand); +} +#endif + + +// Note: The "unsafe" versions of any_cast are not part of the +// public interface and may be removed at any time. They are +// required where we know what type is stored in the any and can't +// use typeid() comparison, e.g., when our types may travel across +// different shared libraries. +template +inline ValueType * unsafe_any_cast(any * operand) BOOST_NOEXCEPT +{ +return boost::addressof( +static_cast *>(operand->content)->held +); +} + +template +inline const ValueType * unsafe_any_cast(const any * operand) BOOST_NOEXCEPT +{ +return unsafe_any_cast(const_cast(operand)); +} +} + +// Copyright Kevlin Henney, 2000, 2001, 2002. All rights reserved. +// Copyright Antony Polukhin, 2013-2020. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#endif diff --git a/include/Third_Lib/cppcodec/base32_crockford.hpp b/include/Third_Lib/cppcodec/base32_crockford.hpp new file mode 100644 index 0000000..6c2ae36 --- /dev/null +++ b/include/Third_Lib/cppcodec/base32_crockford.hpp @@ -0,0 +1,91 @@ +/** + * Copyright (C) 2015 Topology LP + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef CPPCODEC_BASE32_CROCKFORD +#define CPPCODEC_BASE32_CROCKFORD + +#include "detail/codec.hpp" +#include "detail/base32.hpp" + +namespace cppcodec { + +namespace detail { + +static constexpr const char base32_crockford_alphabet[] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', // at index 10 + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', // 18 - no I + 'J', 'K', // 20 - no L + 'M', 'N', // 22 - no O + 'P', 'Q', 'R', 'S', 'T', // 27 - no U + 'V', 'W', 'X', 'Y', 'Z' // 32 +}; + +class base32_crockford_base +{ +public: + static CPPCODEC_ALWAYS_INLINE constexpr size_t alphabet_size() { + static_assert(sizeof(base32_crockford_alphabet) == 32, "base32 alphabet must have 32 values"); + return sizeof(base32_crockford_alphabet); + } + static CPPCODEC_ALWAYS_INLINE constexpr char symbol(alphabet_index_t idx) + { + return base32_crockford_alphabet[idx]; + } + static CPPCODEC_ALWAYS_INLINE constexpr char normalized_symbol(char c) + { + // Hex decoding is always case-insensitive (even in RFC 4648), the question + // is only for encoding whether to use upper-case or lower-case letters. + return (c == 'O' || c == 'o') ? '0' + : (c == 'I' || c == 'i' || c == 'L' || c == 'l') ? '1' + : (c >= 'a' && c <= 'z') ? (c - 'a' + 'A') + : c; + } + + static CPPCODEC_ALWAYS_INLINE constexpr bool generates_padding() { return false; } + static CPPCODEC_ALWAYS_INLINE constexpr bool requires_padding() { return false; } + static CPPCODEC_ALWAYS_INLINE constexpr bool is_padding_symbol(char) { return false; } + static CPPCODEC_ALWAYS_INLINE constexpr bool is_eof_symbol(char c) { return c == '\0'; } + + static CPPCODEC_ALWAYS_INLINE constexpr bool should_ignore(char c) { + return c == '-'; // "Hyphens (-) can be inserted into strings [for readability]." + } +}; + +// base32_crockford is a concatenative iterative (i.e. streaming) interpretation of Crockford base32. +// It interprets the statement "zero-extend the number to make its bit-length a multiple of 5" +// to mean zero-extending it on the right. +// (The other possible interpretation is base32_crockford_num, a place-based single number encoding system. +// See http://merrigrove.blogspot.ca/2014/04/what-heck-is-base64-encoding-really.html for more info.) +class base32_crockford : public base32_crockford_base +{ +public: + template using codec_impl = stream_codec; +}; + +} // namespace detail + +using base32_crockford = detail::codec>; + +} // namespace cppcodec + +#endif // CPPCODEC_BASE32_CROCKFORD diff --git a/include/Third_Lib/cppcodec/base32_default_crockford.hpp b/include/Third_Lib/cppcodec/base32_default_crockford.hpp new file mode 100644 index 0000000..73e94eb --- /dev/null +++ b/include/Third_Lib/cppcodec/base32_default_crockford.hpp @@ -0,0 +1,31 @@ +/** + * Copyright (C) 2015 Topology LP + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef CPPCODEC_BASE32_DEFAULT_CROCKFORD +#define CPPCODEC_BASE32_DEFAULT_CROCKFORD + +#include "base32_crockford.hpp" + +using base32 = cppcodec::base32_crockford; + +#endif // CPPCODEC_BASE32_DEFAULT_CROCKFORD diff --git a/include/Third_Lib/cppcodec/base32_default_hex.hpp b/include/Third_Lib/cppcodec/base32_default_hex.hpp new file mode 100644 index 0000000..4cd8336 --- /dev/null +++ b/include/Third_Lib/cppcodec/base32_default_hex.hpp @@ -0,0 +1,31 @@ +/** + * Copyright (C) 2015, 2016 Topology LP + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef CPPCODEC_BASE32_DEFAULT_HEX +#define CPPCODEC_BASE32_DEFAULT_HEX + +#include "base32_hex.hpp" + +using base32 = cppcodec::base32_hex; + +#endif // CPPCODEC_BASE32_DEFAULT_HEX diff --git a/include/Third_Lib/cppcodec/base32_default_rfc4648.hpp b/include/Third_Lib/cppcodec/base32_default_rfc4648.hpp new file mode 100644 index 0000000..75561bc --- /dev/null +++ b/include/Third_Lib/cppcodec/base32_default_rfc4648.hpp @@ -0,0 +1,31 @@ +/** + * Copyright (C) 2015 Topology LP + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef CPPCODEC_BASE32_DEFAULT_RFC4648 +#define CPPCODEC_BASE32_DEFAULT_RFC4648 + +#include "base32_rfc4648.hpp" + +using base32 = cppcodec::base32_rfc4648; + +#endif // CPPCODEC_BASE32_DEFAULT_RFC4648 diff --git a/include/Third_Lib/cppcodec/base32_hex.hpp b/include/Third_Lib/cppcodec/base32_hex.hpp new file mode 100644 index 0000000..ce1d84d --- /dev/null +++ b/include/Third_Lib/cppcodec/base32_hex.hpp @@ -0,0 +1,76 @@ +/** + * Copyright (C) 2015, 2016 Topology LP + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef CPPCODEC_BASE32_HEX +#define CPPCODEC_BASE32_HEX + +#include "detail/codec.hpp" +#include "detail/base32.hpp" + +namespace cppcodec { + +namespace detail { + +// RFC 4648 also specifies a hex encoding system which uses 0-9, then A-V. +static constexpr const char base32_hex_alphabet[] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', + 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V' +}; + +class base32_hex +{ +public: + template using codec_impl = stream_codec; + + static CPPCODEC_ALWAYS_INLINE constexpr size_t alphabet_size() { + static_assert(sizeof(base32_hex_alphabet) == 32, "base32 alphabet must have 32 values"); + return sizeof(base32_hex_alphabet); + } + static CPPCODEC_ALWAYS_INLINE constexpr char symbol(alphabet_index_t idx) + { + return base32_hex_alphabet[idx]; + } + static CPPCODEC_ALWAYS_INLINE constexpr char normalized_symbol(char c) + { + // Lower-case letters are accepted, though not generally expected. + return (c >= 'a' && c <= 'v') ? (c - 'a' + 'A') : c; + } + + static CPPCODEC_ALWAYS_INLINE constexpr bool generates_padding() { return true; } + static CPPCODEC_ALWAYS_INLINE constexpr bool requires_padding() { return true; } + static CPPCODEC_ALWAYS_INLINE constexpr char padding_symbol() { return '='; } + static CPPCODEC_ALWAYS_INLINE constexpr bool is_padding_symbol(char c) { return c == '='; } + static CPPCODEC_ALWAYS_INLINE constexpr bool is_eof_symbol(char c) { return c == '\0'; } + + // RFC4648 does not specify any whitespace being allowed in base32 encodings. + static CPPCODEC_ALWAYS_INLINE constexpr bool should_ignore(char) { return false; } +}; + +} // namespace detail + +using base32_hex = detail::codec>; + +} // namespace cppcodec + +#endif // CPPCODEC_BASE32_HEX diff --git a/include/Third_Lib/cppcodec/base32_rfc4648.hpp b/include/Third_Lib/cppcodec/base32_rfc4648.hpp new file mode 100644 index 0000000..c039702 --- /dev/null +++ b/include/Third_Lib/cppcodec/base32_rfc4648.hpp @@ -0,0 +1,76 @@ +/** + * Copyright (C) 2015 Topology LP + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef CPPCODEC_BASE32_RFC4648 +#define CPPCODEC_BASE32_RFC4648 + +#include "detail/codec.hpp" +#include "detail/base32.hpp" + +namespace cppcodec { + +namespace detail { + +// RFC 4648 uses a simple alphabet: A-Z starting at index 0, then 2-7 starting at index 26. +static constexpr const char base32_rfc4648_alphabet[] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', // at index 26 + '2', '3', '4', '5', '6', '7' +}; + +class base32_rfc4648 +{ +public: + template using codec_impl = stream_codec; + + static CPPCODEC_ALWAYS_INLINE constexpr size_t alphabet_size() { + static_assert(sizeof(base32_rfc4648_alphabet) == 32, "base32 alphabet must have 32 values"); + return sizeof(base32_rfc4648_alphabet); + } + static CPPCODEC_ALWAYS_INLINE constexpr char symbol(alphabet_index_t idx) + { + return base32_rfc4648_alphabet[idx]; + } + static CPPCODEC_ALWAYS_INLINE constexpr char normalized_symbol(char c) + { + // Lower-case letters are accepted, though not generally expected. + return (c >= 'a' && c <= 'z') ? (c - 'a' + 'A') : c; + } + + static CPPCODEC_ALWAYS_INLINE constexpr bool generates_padding() { return true; } + static CPPCODEC_ALWAYS_INLINE constexpr bool requires_padding() { return true; } + static CPPCODEC_ALWAYS_INLINE constexpr char padding_symbol() { return '='; } + static CPPCODEC_ALWAYS_INLINE constexpr bool is_padding_symbol(char c) { return c == '='; } + static CPPCODEC_ALWAYS_INLINE constexpr bool is_eof_symbol(char c) { return c == '\0'; } + + // RFC4648 does not specify any whitespace being allowed in base32 encodings. + static CPPCODEC_ALWAYS_INLINE constexpr bool should_ignore(char) { return false; } +}; + +} // namespace detail + +using base32_rfc4648 = detail::codec>; + +} // namespace cppcodec + +#endif // CPPCODEC_BASE32_RFC4648 diff --git a/include/Third_Lib/cppcodec/base64_default_rfc4648.hpp b/include/Third_Lib/cppcodec/base64_default_rfc4648.hpp new file mode 100644 index 0000000..3b39a00 --- /dev/null +++ b/include/Third_Lib/cppcodec/base64_default_rfc4648.hpp @@ -0,0 +1,31 @@ +/** + * Copyright (C) 2015 Topology LP + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef CPPCODEC_BASE64_DEFAULT_RFC4648 +#define CPPCODEC_BASE64_DEFAULT_RFC4648 + +#include "base64_rfc4648.hpp" + +using base64 = cppcodec::base64_rfc4648; + +#endif // CPPCODEC_BASE64_DEFAULT_RFC4648 diff --git a/include/Third_Lib/cppcodec/base64_default_url.hpp b/include/Third_Lib/cppcodec/base64_default_url.hpp new file mode 100644 index 0000000..7db2a39 --- /dev/null +++ b/include/Third_Lib/cppcodec/base64_default_url.hpp @@ -0,0 +1,31 @@ +/** + * Copyright (C) 2015 Topology LP + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef CPPCODEC_BASE64_DEFAULT_URL +#define CPPCODEC_BASE64_DEFAULT_URL + +#include "base64_url.hpp" + +using base64 = cppcodec::base64_url; + +#endif // CPPCODEC_BASE64_DEFAULT_URL diff --git a/include/Third_Lib/cppcodec/base64_default_url_unpadded.hpp b/include/Third_Lib/cppcodec/base64_default_url_unpadded.hpp new file mode 100644 index 0000000..3173966 --- /dev/null +++ b/include/Third_Lib/cppcodec/base64_default_url_unpadded.hpp @@ -0,0 +1,31 @@ +/** + * Copyright (C) 2016 Topology LP + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef CPPCODEC_BASE64_DEFAULT_URL_UNPADDED +#define CPPCODEC_BASE64_DEFAULT_URL_UNPADDED + +#include "base64_url_unpadded.hpp" + +using base64 = cppcodec::base64_url_unpadded; + +#endif // CPPCODEC_BASE64_DEFAULT_URL_UNPADDED diff --git a/include/Third_Lib/cppcodec/base64_rfc4648.hpp b/include/Third_Lib/cppcodec/base64_rfc4648.hpp new file mode 100644 index 0000000..717dcec --- /dev/null +++ b/include/Third_Lib/cppcodec/base64_rfc4648.hpp @@ -0,0 +1,73 @@ +/** + * Copyright (C) 2015 Topology LP + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef CPPCODEC_BASE64_RFC4648 +#define CPPCODEC_BASE64_RFC4648 + +#include "detail/codec.hpp" +#include "detail/base64.hpp" + +namespace cppcodec { + +namespace detail { + +static constexpr const char base64_rfc4648_alphabet[] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' +}; + +class base64_rfc4648 +{ +public: + template using codec_impl = stream_codec; + + static CPPCODEC_ALWAYS_INLINE constexpr size_t alphabet_size() { + static_assert(sizeof(base64_rfc4648_alphabet) == 64, "base64 alphabet must have 64 values"); + return sizeof(base64_rfc4648_alphabet); + } + static CPPCODEC_ALWAYS_INLINE constexpr char symbol(alphabet_index_t idx) + { + return base64_rfc4648_alphabet[idx]; + } + static CPPCODEC_ALWAYS_INLINE constexpr char normalized_symbol(char c) { return c; } + + static CPPCODEC_ALWAYS_INLINE constexpr bool generates_padding() { return true; } + static CPPCODEC_ALWAYS_INLINE constexpr bool requires_padding() { return true; } + static CPPCODEC_ALWAYS_INLINE constexpr char padding_symbol() { return '='; } + static CPPCODEC_ALWAYS_INLINE constexpr bool is_padding_symbol(char c) { return c == '='; } + static CPPCODEC_ALWAYS_INLINE constexpr bool is_eof_symbol(char c) { return c == '\0'; } + + // RFC4648 does not specify any whitespace being allowed in base64 encodings. + static CPPCODEC_ALWAYS_INLINE constexpr bool should_ignore(char) { return false; } +}; + +} // namespace detail + +using base64_rfc4648 = detail::codec>; + +} // namespace cppcodec + +#endif // CPPCODEC_BASE64_RFC4648 diff --git a/include/Third_Lib/cppcodec/base64_url.hpp b/include/Third_Lib/cppcodec/base64_url.hpp new file mode 100644 index 0000000..04c2f8b --- /dev/null +++ b/include/Third_Lib/cppcodec/base64_url.hpp @@ -0,0 +1,75 @@ +/** + * Copyright (C) 2015 Topology LP + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef CPPCODEC_BASE64_URL +#define CPPCODEC_BASE64_URL + +#include "detail/codec.hpp" +#include "detail/base64.hpp" + +namespace cppcodec { + +namespace detail { + +// The URL and filename safe alphabet is also specified by RFC4648, named "base64url". +// We keep the underscore ("base64_url") for consistency with the other codec variants. +static constexpr const char base64_url_alphabet[] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_' +}; + +class base64_url +{ +public: + template using codec_impl = stream_codec; + + static CPPCODEC_ALWAYS_INLINE constexpr size_t alphabet_size() { + static_assert(sizeof(base64_url_alphabet) == 64, "base64 alphabet must have 64 values"); + return sizeof(base64_url_alphabet); + } + static CPPCODEC_ALWAYS_INLINE constexpr char symbol(alphabet_index_t idx) + { + return base64_url_alphabet[idx]; + } + static CPPCODEC_ALWAYS_INLINE constexpr char normalized_symbol(char c) { return c; } + + static CPPCODEC_ALWAYS_INLINE constexpr bool generates_padding() { return true; } + static CPPCODEC_ALWAYS_INLINE constexpr bool requires_padding() { return true; } + static CPPCODEC_ALWAYS_INLINE constexpr char padding_symbol() { return '='; } + static CPPCODEC_ALWAYS_INLINE constexpr bool is_padding_symbol(char c) { return c == '='; } + static CPPCODEC_ALWAYS_INLINE constexpr bool is_eof_symbol(char c) { return c == '\0'; } + + // RFC4648 does not specify any whitespace being allowed in base64 encodings. + static CPPCODEC_ALWAYS_INLINE constexpr bool should_ignore(char) { return false; } +}; + +} // namespace detail + +using base64_url = detail::codec>; + +} // namespace cppcodec + +#endif // CPPCODEC_BASE64_URL diff --git a/include/Third_Lib/cppcodec/base64_url_unpadded.hpp b/include/Third_Lib/cppcodec/base64_url_unpadded.hpp new file mode 100644 index 0000000..e9a5d3f --- /dev/null +++ b/include/Third_Lib/cppcodec/base64_url_unpadded.hpp @@ -0,0 +1,48 @@ +/** + * Copyright (C) 2016 Topology LP + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef CPPCODEC_BASE64_URL_UNPADDED +#define CPPCODEC_BASE64_URL_UNPADDED + +#include "base64_url.hpp" + +namespace cppcodec { + +namespace detail { + +class base64_url_unpadded : public base64_url +{ +public: + template using codec_impl = stream_codec; + + static CPPCODEC_ALWAYS_INLINE constexpr bool generates_padding() { return false; } + static CPPCODEC_ALWAYS_INLINE constexpr bool requires_padding() { return false; } +}; + +} // namespace detail + +using base64_url_unpadded = detail::codec>; + +} // namespace cppcodec + +#endif // CPPCODEC_BASE64_URL_UNPADDED diff --git a/include/Third_Lib/cppcodec/data/access.hpp b/include/Third_Lib/cppcodec/data/access.hpp new file mode 100644 index 0000000..432a3c7 --- /dev/null +++ b/include/Third_Lib/cppcodec/data/access.hpp @@ -0,0 +1,328 @@ +/** + * Copyright (C) 2015 Topology LP + * Copyright (C) 2018 Jakob Petsovits + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef CPPCODEC_DETAIL_DATA_ACCESS +#define CPPCODEC_DETAIL_DATA_ACCESS + +#include // for size_t +#include // for static_assert() checking that string will be optimized +#include // for std::enable_if, std::remove_reference, and such +#include // for std::declval +#include // for static_assert() checking that vector will be optimized + +#include "../detail/config.hpp" // for CPPCODEC_ALWAYS_INLINE + +namespace cppcodec { +namespace data { + +// This file contains a number of templated data accessors that can be +// implemented in the cppcodec::data namespace for types that don't fulfill +// the default type requirements: +// For result types: init(Result&, ResultState&, size_t capacity), +// put(Result&, ResultState&, char), finish(Result&, State&) +// For const (read-only) types: char_data(const T&) +// For both const and result types: size(const T&) + +template +CPPCODEC_ALWAYS_INLINE size_t size(const T& t) { return t.size(); } + +template +CPPCODEC_ALWAYS_INLINE constexpr size_t size(const T (&t)[N]) noexcept { + return (void)t, N * sizeof(t[0]); +} + +class general_t {}; +class specific_t : public general_t {}; + +class empty_result_state { + template + CPPCODEC_ALWAYS_INLINE void size(const Result& result) { return size(result); } +}; + +// SFINAE: Generic fallback in case no specific state function applies. +template +CPPCODEC_ALWAYS_INLINE empty_result_state create_state(Result&, general_t) +{ + return empty_result_state(); +} + +// +// Generic templates for containers: Use these init()/put()/finish() +// implementations if no specialization was found. +// + +template +CPPCODEC_ALWAYS_INLINE void init(Result& result, empty_result_state&, size_t capacity) +{ + result.resize(0); + result.reserve(capacity); +} + +template +CPPCODEC_ALWAYS_INLINE void finish(Result&, empty_result_state&) +{ + // Default is to push_back(), which already increases the size. +} + +// For the put() default implementation, we try calling push_back() with either uint8_t or char, +// whichever compiles. Scary-fancy template magic from http://stackoverflow.com/a/1386390. +namespace fallback { + struct flag { char c[2]; }; // sizeof > 1 + flag put_uint8(...); + + int operator,(flag, flag); + template void operator,(flag, T&); // map everything else to void + char operator,(int, flag); // sizeof 1 +} + +template inline void put_uint8(Result& result, uint8_t c) { result.push_back(c); } + +template struct put_impl; +template <> struct put_impl { // put_uint8() available + template + static CPPCODEC_ALWAYS_INLINE void put(Result& result, uint8_t c) + { + put_uint8(result, c); + } +}; +template <> struct put_impl { // put_uint8() not available + template + static CPPCODEC_ALWAYS_INLINE void put(Result& result, uint8_t c) + { + result.push_back(static_cast(c)); + } +}; + +template +CPPCODEC_ALWAYS_INLINE void put(Result& result, empty_result_state&, uint8_t c) +{ + using namespace fallback; + put_impl::put(result, c); +} + +// +// Specialization for container types with direct mutable data access, +// e.g. std::vector. +// +// The expected way to specialize is to draft a new xyz_result_state type and +// return an instance of it from a create_state() template specialization. +// You can then create overloads for init(), put() and finish() +// for the new result state type. +// +// If desired, a non-templated overload for both specific types +// (result & state) can be added to tailor it to that particular result type. +// + +template +constexpr auto data_is_mutable(T* t) -> decltype(t->data()[size_t(0)] = 'x', bool()) +{ + return (void)t, true; +} +constexpr bool data_is_mutable(...) { return false; } + +template +class direct_data_access_result_state +{ +public: + CPPCODEC_ALWAYS_INLINE void init(Result& result, size_t capacity) + { + // reserve() may not actually allocate the storage right away, + // and it isn't guaranteed that it will be untouched upon the + //.next resize(). In that light, resize from the start and + // slightly reduce the size at the end if necessary. + result.resize(capacity); + + // result.data() may perform a calculation to retrieve the address. + // E.g. std::string (since C++11) will use small string optimization, + // so it needs to check if it's using allocated data or (ab)using + // its own member variables interpreted as char array. + // (This result_state is used for std::string starting with C++17.) + // Conditional code paths are slow so we only do it once, at the start. + m_buffer = result.data(); + } + CPPCODEC_ALWAYS_INLINE void put(Result&, char c) + { + m_buffer[m_offset++] = c; + } + CPPCODEC_ALWAYS_INLINE void finish(Result& result) + { + result.resize(m_offset); + } + CPPCODEC_ALWAYS_INLINE size_t size(const Result&) + { + return m_offset; + } +private: + // Make sure to get the mutable buffer decltype by using assignment. + typename std::remove_reference< + decltype(std::declval().data()[size_t(0)] = 'x')>::type* m_buffer; + size_t m_offset = 0; +}; + +// SFINAE: Select a specific state based on the result type and possible result state type. +// Implement this if direct data access (`result.data()[0] = 'x') isn't already possible +// and you want to specialize it for your own result type. +// Note: The enable_if should ideally be part of the class declaration, +// but Visual Studio C++ will not compile it that way. +// Have it here in the factory function instead. +template (nullptr))>::type> +CPPCODEC_ALWAYS_INLINE direct_data_access_result_state create_state(Result&, specific_t) +{ + return direct_data_access_result_state(); +} + +static_assert(std::is_same< + decltype(create_state(*static_cast*>(nullptr), specific_t())), + direct_data_access_result_state>>::value, + "std::vector must be handled by direct_data_access_result_state"); + +// Specialized init(), put() and finish() functions for direct_data_access_result_state. +template +CPPCODEC_ALWAYS_INLINE void init(Result& result, direct_data_access_result_state& state, size_t capacity) +{ + state.init(result, capacity); +} + +template +CPPCODEC_ALWAYS_INLINE void put(Result& result, direct_data_access_result_state& state, char c) +{ + state.put(result, c); +} + +template +CPPCODEC_ALWAYS_INLINE void finish(Result& result, direct_data_access_result_state& state) +{ + state.finish(result); +} + +// +// Specialization for container types with direct mutable array access, +// e.g. std::string. This is generally faster because bound checks are +// minimal and operator[] is more likely noexcept. In addition, +// std::string::push_back() needs to write a null character on every +// expansion, which should be more efficient when done in bulk by resize(). +// +// Compared to the above, tracking an extra offset variable is cheap. +// + +template +constexpr auto array_access_is_mutable(T* t) -> decltype((*t)[size_t(0)] = 'x', bool()) +{ + return (void)t, true; +} +constexpr bool array_access_is_mutable(...) { return false; } + +template +class array_access_result_state +{ +public: + CPPCODEC_ALWAYS_INLINE void init(Result& result, size_t capacity) + { + // reserve() may not actually allocate the storage right away, + // and it isn't guaranteed that it will be untouched upon the + //.next resize(). In that light, resize from the start and + // slightly reduce the size at the end if necessary. + result.resize(capacity); + } + CPPCODEC_ALWAYS_INLINE void put(Result& result, char c) + { + result[m_offset++] = c; + } + CPPCODEC_ALWAYS_INLINE void finish(Result& result) + { + result.resize(m_offset); + } + CPPCODEC_ALWAYS_INLINE size_t size(const Result&) + { + return m_offset; + } +private: + size_t m_offset = 0; +}; + +// SFINAE: Select a specific state based on the result type and possible result state type. +// Note: The enable_if should ideally be part of the class declaration, +// but Visual Studio C++ will not compile it that way. +// Have it here in the factory function instead. +template (nullptr)) // no more than one template option + && array_access_is_mutable(static_cast(nullptr))>::type> +CPPCODEC_ALWAYS_INLINE array_access_result_state create_state(Result&, specific_t) +{ + return array_access_result_state(); +} + +#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG > 201703L) +static_assert(std::is_same< + decltype(create_state(*static_cast(nullptr), specific_t())), + direct_data_access_result_state>::value, + "std::string (C++17 and later) must be handled by direct_data_access_result_state"); +#elif __cplusplus < 201703 && !defined(_MSVC_LANG) // we can't trust MSVC to set this right +static_assert(std::is_same< + decltype(create_state(*static_cast(nullptr), specific_t())), + array_access_result_state>::value, + "std::string (pre-C++17) must be handled by array_access_result_state"); +#endif + +// Specialized init(), put() and finish() functions for array_access_result_state. +template +CPPCODEC_ALWAYS_INLINE void init(Result& result, array_access_result_state& state, size_t capacity) +{ + state.init(result, capacity); +} + +template +CPPCODEC_ALWAYS_INLINE void put(Result& result, array_access_result_state& state, char c) +{ + state.put(result, c); +} + +template +CPPCODEC_ALWAYS_INLINE void finish(Result& result, array_access_result_state& state) +{ + state.finish(result); +} + +// char_data() is only used to read, not for result buffers. +template inline const char* char_data(const T& t) +{ + return reinterpret_cast(t.data()); +} +template inline const char* char_data(const T (&t)[N]) noexcept +{ + return reinterpret_cast(&(t[0])); +} + +template inline const uint8_t* uchar_data(const T& t) +{ + return reinterpret_cast(char_data(t)); +} + +} // namespace data +} // namespace cppcodec + +#endif diff --git a/include/Third_Lib/cppcodec/data/raw_result_buffer.hpp b/include/Third_Lib/cppcodec/data/raw_result_buffer.hpp new file mode 100644 index 0000000..65b0de5 --- /dev/null +++ b/include/Third_Lib/cppcodec/data/raw_result_buffer.hpp @@ -0,0 +1,70 @@ +/** + * Copyright (C) 2015 Topology LP + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef CPPCODEC_DETAIL_RAW_RESULT_BUFFER +#define CPPCODEC_DETAIL_RAW_RESULT_BUFFER + +#include // for size_t +#include // for abort() + +#include "access.hpp" + +namespace cppcodec { +namespace data { + +class raw_result_buffer +{ +public: + raw_result_buffer(char* data, size_t capacity) + : m_ptr(data + capacity) + , m_begin(data) + { + } + + CPPCODEC_ALWAYS_INLINE void push_back(char c) { *m_ptr = c; ++m_ptr; } + CPPCODEC_ALWAYS_INLINE size_t size() const { return m_ptr - m_begin; } + CPPCODEC_ALWAYS_INLINE void resize(size_t size) { m_ptr = m_begin + size; } + +private: + char* m_ptr; + char* m_begin; +}; + + +template <> inline void init( + raw_result_buffer& result, empty_result_state&, size_t capacity) +{ + // This version of init() doesn't do a reserve(), and instead checks whether the + // initial size (capacity) is enough before resetting m_ptr to m_begin. + // The codec is expected not to exceed this capacity. + if (capacity > result.size()) { + abort(); + } + result.resize(0); +} +template <> inline void finish(raw_result_buffer&, empty_result_state&) { } + +} // namespace data +} // namespace cppcodec + +#endif diff --git a/include/Third_Lib/cppcodec/detail/base32.hpp b/include/Third_Lib/cppcodec/detail/base32.hpp new file mode 100644 index 0000000..7113b7a --- /dev/null +++ b/include/Third_Lib/cppcodec/detail/base32.hpp @@ -0,0 +1,166 @@ +/** + * Copyright (C) 2015 Trustifier Inc. + * Copyright (C) 2015 Ahmed Masud + * Copyright (C) 2015 Topology LP + * Copyright (C) 2018 Jakob Petsovits + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Adapted from https://github.com/ahmed-masud/libbase32, + * commit 79761b2b79b0545697945efe0987a8d3004512f9. + * Quite different now. + */ + +#ifndef CPPCODEC_DETAIL_BASE32 +#define CPPCODEC_DETAIL_BASE32 + +#include +#include // for abort() + +#include "../data/access.hpp" +#include "../parse_error.hpp" +#include "config.hpp" +#include "stream_codec.hpp" + +namespace cppcodec { +namespace detail { + +template +class base32 : public CodecVariant::template codec_impl> +{ +public: + static inline constexpr uint8_t binary_block_size() { return 5; } + static inline constexpr uint8_t encoded_block_size() { return 8; } + + static CPPCODEC_ALWAYS_INLINE constexpr uint8_t num_encoded_tail_symbols(uint8_t num_bytes) + { + return (num_bytes == 1) ? 2 // 2 symbols, 6 padding characters + : (num_bytes == 2) ? 4 // 4 symbols, 4 padding characters + : (num_bytes == 3) ? 5 // 5 symbols, 3 padding characters + : (num_bytes == 4) ? 7 // 7 symbols, 1 padding characters + : throw std::domain_error("invalid number of bytes in a tail block"); + } + + template + static CPPCODEC_ALWAYS_INLINE constexpr uint8_t index( + const uint8_t* b /*binary block*/) noexcept + { + static_assert(I >= 0 && I < encoded_block_size(), + "invalid encoding symbol index in a block"); + + return (I == 0) ? ((b[0] >> 3) & 0x1F) // first 5 bits + : (I == 1) ? (((b[0] << 2) & 0x1C) | ((b[1] >> 6) & 0x3)) + : (I == 2) ? ((b[1] >> 1) & 0x1F) + : (I == 3) ? (((b[1] << 4) & 0x10) | ((b[2] >> 4) & 0xF)) + : (I == 4) ? (((b[2] << 1) & 0x1E) | ((b[3] >> 7) & 0x1)) + : (I == 5) ? ((b[3] >> 2) & 0x1F) + : (I == 6) ? (((b[3] << 3) & 0x18) | ((b[4] >> 5) & 0x7)) + : /*I == 7*/ (b[4] & 0x1F); // last 5 bits; + } + + template + using uint8_if = typename std::enable_if::type; + + template + static CPPCODEC_ALWAYS_INLINE constexpr + uint8_if index_last( + const uint8_t* b /*binary block*/) noexcept + { + return (I == 1) ? ((b[0] << 2) & 0x1C) // abbreviated 2nd symbol + : (I == 3) ? ((b[1] << 4) & 0x10) // abbreviated 4th symbol + : (I == 4) ? ((b[2] << 1) & 0x1E) // abbreviated 5th symbol + : /*I == 6*/ ((b[3] << 3) & 0x18); // abbreviated 7th symbol + } + + template + static CPPCODEC_ALWAYS_INLINE + uint8_if index_last( + const uint8_t* /*binary block*/) + { + throw std::domain_error("invalid last encoding symbol index in a tail"); + } + + template + static CPPCODEC_ALWAYS_INLINE void decode_block( + Result& decoded, ResultState&, const alphabet_index_t* idx); + + template + static CPPCODEC_ALWAYS_INLINE void decode_tail( + Result& decoded, ResultState&, const alphabet_index_t* idx, size_t idx_len); +}; + +// +// 11111111 10101010 10110011 10111100 10010100 +// => 11111 11110 10101 01011 00111 01111 00100 10100 +// + +template +template +CPPCODEC_ALWAYS_INLINE void base32::decode_block( + Result& decoded, ResultState& state, const alphabet_index_t* idx) +{ + put(decoded, state, static_cast(((idx[0] << 3) & 0xF8) | ((idx[1] >> 2) & 0x7))); + put(decoded, state, static_cast(((idx[1] << 6) & 0xC0) | ((idx[2] << 1) & 0x3E) | ((idx[3] >> 4) & 0x1))); + put(decoded, state, static_cast(((idx[3] << 4) & 0xF0) | ((idx[4] >> 1) & 0xF))); + put(decoded, state, static_cast(((idx[4] << 7) & 0x80) | ((idx[5] << 2) & 0x7C) | ((idx[6] >> 3) & 0x3))); + put(decoded, state, static_cast(((idx[6] << 5) & 0xE0) | (idx[7] & 0x1F))); +} + +template +template +CPPCODEC_ALWAYS_INLINE void base32::decode_tail( + Result& decoded, ResultState& state, const alphabet_index_t* idx, size_t idx_len) +{ + if (idx_len == 1) { + throw invalid_input_length( + "invalid number of symbols in last base32 block: found 1, expected 2, 4, 5 or 7"); + } + if (idx_len == 3) { + throw invalid_input_length( + "invalid number of symbols in last base32 block: found 3, expected 2, 4, 5 or 7"); + } + if (idx_len == 6) { + throw invalid_input_length( + "invalid number of symbols in last base32 block: found 6, expected 2, 4, 5 or 7"); + } + + // idx_len == 2: decoded size 1 + put(decoded, state, static_cast(((idx[0] << 3) & 0xF8) | ((idx[1] >> 2) & 0x7))); + if (idx_len == 2) { + return; + } + // idx_len == 4: decoded size 2 + put(decoded, state, static_cast(((idx[1] << 6) & 0xC0) | ((idx[2] << 1) & 0x3E) | ((idx[3] >> 4) & 0x1))); + if (idx_len == 4) { + return; + } + // idx_len == 5: decoded size 3 + put(decoded, state, static_cast(((idx[3] << 4) & 0xF0) | ((idx[4] >> 1) & 0xF))); + if (idx_len == 5) { + return; + } + // idx_len == 7: decoded size 4 + put(decoded, state, static_cast(((idx[4] << 7) & 0x80) | ((idx[5] << 2) & 0x7C) | ((idx[6] >> 3) & 0x3))); +} + +} // namespace detail +} // namespace cppcodec + +#endif // CPPCODEC_DETAIL_BASE32 diff --git a/include/Third_Lib/cppcodec/detail/base64.hpp b/include/Third_Lib/cppcodec/detail/base64.hpp new file mode 100644 index 0000000..b6db6d7 --- /dev/null +++ b/include/Third_Lib/cppcodec/detail/base64.hpp @@ -0,0 +1,132 @@ +/** + * Copyright (C) 2015 Topology LP + * Copyright (C) 2013 Adam Rudd (bit calculations) + * Copyright (C) 2018 Jakob Petsovits + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Bit calculations adapted from https://github.com/adamvr/arduino-base64, + * commit 999595783185a0afcba156d7276dfeaa9cb5382f. + */ + +#ifndef CPPCODEC_DETAIL_BASE64 +#define CPPCODEC_DETAIL_BASE64 + +#include +#include + +#include "../data/access.hpp" +#include "../parse_error.hpp" +#include "config.hpp" +#include "stream_codec.hpp" + +namespace cppcodec { +namespace detail { + +template +class base64 : public CodecVariant::template codec_impl> +{ +public: + static inline constexpr uint8_t binary_block_size() { return 3; } + static inline constexpr uint8_t encoded_block_size() { return 4; } + + static CPPCODEC_ALWAYS_INLINE constexpr uint8_t num_encoded_tail_symbols(uint8_t num_bytes) + { + return (num_bytes == 1) ? 2 // 2 symbols, 2 padding characters + : (num_bytes == 2) ? 3 // 3 symbols, 1 padding character + : throw std::domain_error("invalid number of bytes in a tail block"); + } + + template + static CPPCODEC_ALWAYS_INLINE constexpr uint8_t index( + const uint8_t* b /*binary block*/) noexcept + { + static_assert(I >= 0 && I < encoded_block_size(), + "invalid encoding symbol index in a block"); + + return (I == 0) ? (b[0] >> 2) // first 6 bits + : (I == 1) ? (((b[0] & 0x3) << 4) | (b[1] >> 4)) + : (I == 2) ? (((b[1] & 0xF) << 2) | (b[2] >> 6)) + : /*I == 3*/ (b[2] & 0x3F); // last 6 bits + } + + template + using uint8_if = typename std::enable_if::type; + + template + static CPPCODEC_ALWAYS_INLINE constexpr uint8_if index_last( + const uint8_t* b /*binary block*/) noexcept + { + return (I == 1) ? ((b[0] & 0x3) << 4) // abbreviated 2nd symbol + : /*I == 2*/ ((b[1] & 0xF) << 2); // abbreviated 3rd symbol + } + + template + static CPPCODEC_ALWAYS_INLINE uint8_if index_last( + const uint8_t* /*binary block*/) + { + throw std::domain_error("invalid last encoding symbol index in a tail"); + } + + template + static CPPCODEC_ALWAYS_INLINE void decode_block( + Result& decoded, ResultState&, const alphabet_index_t* idx); + + template + static CPPCODEC_ALWAYS_INLINE void decode_tail( + Result& decoded, ResultState&, const alphabet_index_t* idx, size_t idx_len); +}; + + +template +template +CPPCODEC_ALWAYS_INLINE void base64::decode_block( + Result& decoded, ResultState& state, const alphabet_index_t* idx) +{ + uint_fast32_t dec = (idx[0] << 18) | (idx[1] << 12) | (idx[2] << 6) | idx[3]; + data::put(decoded, state, static_cast(dec >> 16)); + data::put(decoded, state, static_cast((dec >> 8) & 0xFF)); + data::put(decoded, state, static_cast(dec & 0xFF)); +} + +template +template +CPPCODEC_ALWAYS_INLINE void base64::decode_tail( + Result& decoded, ResultState& state, const alphabet_index_t* idx, size_t idx_len) +{ + if (idx_len == 1) { + throw invalid_input_length( + "invalid number of symbols in last base64 block: found 1, expected 2 or 3"); + } + + // idx_len == 2: decoded size 1 + data::put(decoded, state, static_cast((idx[0] << 2) + ((idx[1] & 0x30) >> 4))); + if (idx_len == 2) { + return; + } + + // idx_len == 3: decoded size 2 + data::put(decoded, state, static_cast(((idx[1] & 0xF) << 4) + ((idx[2] & 0x3C) >> 2))); +} + +} // namespace detail +} // namespace cppcodec + +#endif // CPPCODEC_DETAIL_BASE64 diff --git a/include/Third_Lib/cppcodec/detail/codec.hpp b/include/Third_Lib/cppcodec/detail/codec.hpp new file mode 100644 index 0000000..47d9802 --- /dev/null +++ b/include/Third_Lib/cppcodec/detail/codec.hpp @@ -0,0 +1,327 @@ +/** + * Copyright (C) 2015 Topology LP + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef CPPCODEC_DETAIL_CODEC +#define CPPCODEC_DETAIL_CODEC + +#include +#include +#include +#include + +#include "../data/access.hpp" +#include "../data/raw_result_buffer.hpp" + +namespace cppcodec { +namespace detail { + +// SFINAE: Templates sometimes beat sensible overloads - make sure we don't call the wrong one. +template +struct non_numeric : std::enable_if::value> { }; + + +/** + * Public interface for all the codecs. For API documentation, see README.md. + */ +template +class codec +{ +public: + // + // Encoding + + // Convenient version, returns an std::string. + static std::string encode(const uint8_t* binary, size_t binary_size); + static std::string encode(const char* binary, size_t binary_size); + // static std::string encode(const T& binary); -> provided by template below + + // Convenient version with templated result type. + template static Result encode(const uint8_t* binary, size_t binary_size); + template static Result encode(const char* binary, size_t binary_size); + template > + static Result encode(const T& binary); + + // Reused result container version. Resizes encoded_result before writing to it. + template + static void encode(Result& encoded_result, const uint8_t* binary, size_t binary_size); + template + static void encode(Result& encoded_result, const char* binary, size_t binary_size); + template ::type* = nullptr> + static void encode(Result& encoded_result, const T& binary); + + // Raw pointer output, assumes pre-allocated memory with size > encoded_size(binary_size). + static size_t encode( + char* encoded_result, size_t encoded_buffer_size, + const uint8_t* binary, size_t binary_size) noexcept; + static size_t encode( + char* encoded_result, size_t encoded_buffer_size, + const char* binary, size_t binary_size) noexcept; + template + static size_t encode( + char* encoded_result, size_t encoded_buffer_size, + const T& binary) noexcept; + + // Calculate the exact length of the encoded string based on binary size. + static constexpr size_t encoded_size(size_t binary_size) noexcept; + + // + // Decoding + + // Convenient version, returns an std::vector. + static std::vector decode(const char* encoded, size_t encoded_size); + // static std::vector decode(const T& encoded); -> provided by template below + + // Convenient version with templated result type. + template static Result decode(const char* encoded, size_t encoded_size); + template , typename T = std::string> + static Result decode(const T& encoded); + + // Reused result container version. Resizes binary_result before writing to it. + template + static void decode(Result& binary_result, const char* encoded, size_t encoded_size); + template ::type* = nullptr> + static void decode(Result& binary_result, const T& encoded); + + // Raw pointer output, assumes pre-allocated memory with size > decoded_max_size(encoded_size). + static size_t decode( + uint8_t* binary_result, size_t binary_buffer_size, + const char* encoded, size_t encoded_size); + static size_t decode( + char* binary_result, size_t binary_buffer_size, + const char* encoded, size_t encoded_size); + template static size_t decode( + uint8_t* binary_result, size_t binary_buffer_size, const T& encoded); + template static size_t decode( + char* binary_result, size_t binary_buffer_size, const T& encoded); + + // Calculate the maximum size of the decoded binary buffer based on the encoded string length. + static constexpr size_t decoded_max_size(size_t encoded_size) noexcept; +}; + + +// +// Inline definitions of the above functions, using CRTP to call into CodecImpl +// + +// +// Encoding + +template +inline std::string codec::encode(const uint8_t* binary, size_t binary_size) +{ + return encode(binary, binary_size); +} + +template +inline std::string codec::encode(const char* binary, size_t binary_size) +{ + return encode(reinterpret_cast(binary), binary_size); +} + +template +template +inline Result codec::encode(const uint8_t* binary, size_t binary_size) +{ + Result encoded_result; + encode(encoded_result, binary, binary_size); + return encoded_result; +} + +template +template +inline Result codec::encode(const char* binary, size_t binary_size) +{ + return encode(reinterpret_cast(binary), binary_size); +} + +template +template +inline Result codec::encode(const T& binary) +{ + return encode(data::uchar_data(binary), data::size(binary)); +} + +template +template +inline void codec::encode( + Result& encoded_result, const uint8_t* binary, size_t binary_size) +{ + // This overload is where we reserve buffer capacity and call into CodecImpl. + size_t encoded_buffer_size = encoded_size(binary_size); + auto state = data::create_state(encoded_result, data::specific_t()); + data::init(encoded_result, state, encoded_buffer_size); + + CodecImpl::encode(encoded_result, state, binary, binary_size); + data::finish(encoded_result, state); + assert(data::size(encoded_result) == encoded_buffer_size); +} + +template +template +inline void codec::encode( + Result& encoded_result, const char* binary, size_t binary_size) +{ + encode(encoded_result, reinterpret_cast(binary), binary_size); +} + +template +template ::type*> +inline void codec::encode(Result& encoded_result, const T& binary) +{ + encode(encoded_result, data::uchar_data(binary), data::size(binary)); +} + +template +inline size_t codec::encode( + char* encoded_result, size_t encoded_buffer_size, + const uint8_t* binary, size_t binary_size) noexcept +{ + // This overload is where we wrap the result pointer & size. + data::raw_result_buffer encoded(encoded_result, encoded_buffer_size); + encode(encoded, binary, binary_size); + + size_t encoded_size = data::size(encoded); + if (encoded_size < encoded_buffer_size) { + encoded_result[encoded_size] = '\0'; + } + return encoded_size; +} + +template +inline size_t codec::encode( + char* encoded_result, size_t encoded_buffer_size, + const char* binary, size_t binary_size) noexcept +{ + // This overload is where we wrap the result pointer & size. + return encode(encoded_result, encoded_buffer_size, + reinterpret_cast(binary), binary_size); +} + +template +template +inline size_t codec::encode( + char* encoded_result, size_t encoded_buffer_size, + const T& binary) noexcept +{ + return encode(encoded_result, encoded_buffer_size, data::uchar_data(binary), data::size(binary)); +} + +template +inline constexpr size_t codec::encoded_size(size_t binary_size) noexcept +{ + return CodecImpl::encoded_size(binary_size); +} + + +// +// Decoding + +template +inline std::vector codec::decode(const char* encoded, size_t encoded_size) +{ + return decode>(encoded, encoded_size); +} + +template +template +inline Result codec::decode(const char* encoded, size_t encoded_size) +{ + Result result; + decode(result, encoded, encoded_size); + return result; +} + +template +template +inline Result codec::decode(const T& encoded) +{ + return decode(data::char_data(encoded), data::size(encoded)); +} + +template +template +inline void codec::decode(Result& binary_result, const char* encoded, size_t encoded_size) +{ + // This overload is where we reserve buffer capacity and call into CodecImpl. + size_t binary_buffer_size = decoded_max_size(encoded_size); + auto state = data::create_state(binary_result, data::specific_t()); + data::init(binary_result, state, binary_buffer_size); + + CodecImpl::decode(binary_result, state, encoded, encoded_size); + data::finish(binary_result, state); + assert(data::size(binary_result) <= binary_buffer_size); +} + + +template +template ::type*> +inline void codec::decode(Result& binary_result, const T& encoded) +{ + decode(binary_result, data::char_data(encoded), data::size(encoded)); +} + +template +inline size_t codec::decode( + uint8_t* binary_result, size_t binary_buffer_size, + const char* encoded, size_t encoded_size) +{ + return decode(reinterpret_cast(binary_result), binary_buffer_size, encoded, encoded_size); +} + +template +inline size_t codec::decode( + char* binary_result, size_t binary_buffer_size, + const char* encoded, size_t encoded_size) +{ + // This overload is where we wrap the result pointer & size. + data::raw_result_buffer binary(binary_result, binary_buffer_size); + decode(binary, encoded, encoded_size); + return data::size(binary); +} + +template +template +inline size_t codec::decode( + uint8_t* binary_result, size_t binary_buffer_size, const T& encoded) +{ + return decode(reinterpret_cast(binary_result), binary_buffer_size, encoded); +} + +template +template +inline size_t codec::decode(char* binary_result, size_t binary_buffer_size, const T& encoded) +{ + return decode(binary_result, binary_buffer_size, data::char_data(encoded), data::size(encoded)); +} + +template +inline constexpr size_t codec::decoded_max_size(size_t encoded_size) noexcept +{ + return CodecImpl::decoded_max_size(encoded_size); +} + + +} // namespace detail +} // namespace cppcodec + +#endif diff --git a/include/Third_Lib/cppcodec/detail/config.hpp b/include/Third_Lib/cppcodec/detail/config.hpp new file mode 100644 index 0000000..dc66f8f --- /dev/null +++ b/include/Third_Lib/cppcodec/detail/config.hpp @@ -0,0 +1,40 @@ +/** + * Copyright (C) 2015 Topology LP + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef CPPCODEC_DETAIL_CONFIG_HPP +#define CPPCODEC_DETAIL_CONFIG_HPP + +#ifndef __has_attribute + #define __has_attribute(x) 0 +#endif + +#if __GNUC__ || __has_attribute(always_inline) +#define CPPCODEC_ALWAYS_INLINE inline __attribute__((always_inline)) +#elif defined(_MSC_VER) && !defined(__INTEL_COMPILER) +#define CPPCODEC_ALWAYS_INLINE inline __forceinline +#else +#define CPPCODEC_ALWAYS_INLINE inline +#endif + +#endif // CPPCODEC_DETAIL_CONFIG_HPP + diff --git a/include/Third_Lib/cppcodec/detail/hex.hpp b/include/Third_Lib/cppcodec/detail/hex.hpp new file mode 100644 index 0000000..f86be93 --- /dev/null +++ b/include/Third_Lib/cppcodec/detail/hex.hpp @@ -0,0 +1,114 @@ +/** + * Copyright (C) 2015 Topology LP + * Copyright (C) 2018 Jakob Petsovits + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef CPPCODEC_DETAIL_HEX +#define CPPCODEC_DETAIL_HEX + +#include +#include // for abort() + +#include "../data/access.hpp" +#include "../parse_error.hpp" +#include "stream_codec.hpp" + +namespace cppcodec { +namespace detail { + +template +class hex : public CodecVariant::template codec_impl> +{ +public: + static inline constexpr uint8_t binary_block_size() { return 1; } + static inline constexpr uint8_t encoded_block_size() { return 2; } + + static CPPCODEC_ALWAYS_INLINE constexpr uint8_t num_encoded_tail_symbols(uint8_t /*num_bytes*/) noexcept + { + // Hex encoding only works on full bytes so there are no tails, + // no padding characters, and this function should (must) never be called. + return 0; + } + + template + static CPPCODEC_ALWAYS_INLINE constexpr uint8_t index( + const uint8_t* b /*binary block*/) noexcept + { + static_assert(I >= 0 && I < encoded_block_size(), + "invalid encoding symbol index in a block"); + + return (I == 0) ? (b[0] >> 4) // first 4 bits + : /*I == 1*/ (b[0] & 0xF); // last 4 bits + } + + // With only 2 bytes, enc<1> will always result in a full index() call and + // enc<0> will be protected by a not-reached assertion, so we don't actually + // care about index_last() except optimizing it out as good as possible. + template + using uint8_if = typename std::enable_if::type; + + template + static CPPCODEC_ALWAYS_INLINE constexpr uint8_if index_last( + const uint8_t* /*binary block*/) noexcept + { + return 0; + } + + template + static CPPCODEC_ALWAYS_INLINE uint8_if index_last( + const uint8_t* /*binary block*/) + { + throw std::domain_error("invalid last encoding symbol index in a tail"); + } + + template + static CPPCODEC_ALWAYS_INLINE void decode_block( + Result& decoded, ResultState&, const alphabet_index_t* idx); + + template + static CPPCODEC_ALWAYS_INLINE void decode_tail( + Result& decoded, ResultState&, const alphabet_index_t* idx, size_t idx_len); +}; + + +template +template +CPPCODEC_ALWAYS_INLINE void hex::decode_block( + Result& decoded, ResultState& state, const alphabet_index_t* idx) +{ + data::put(decoded, state, static_cast((idx[0] << 4) | idx[1])); +} + +template +template +CPPCODEC_ALWAYS_INLINE void hex::decode_tail( + Result&, ResultState&, const alphabet_index_t*, size_t) +{ + throw invalid_input_length( + "odd-length hex input is not supported by the streaming octet decoder, " + "use a place-based number decoder instead"); +} + +} // namespace detail +} // namespace cppcodec + +#endif // CPPCODEC_DETAIL_HEX diff --git a/include/Third_Lib/cppcodec/detail/stream_codec.hpp b/include/Third_Lib/cppcodec/detail/stream_codec.hpp new file mode 100644 index 0000000..ddc52e3 --- /dev/null +++ b/include/Third_Lib/cppcodec/detail/stream_codec.hpp @@ -0,0 +1,439 @@ +/** + * Copyright (C) 2015 Topology LP + * Copyright (C) 2018 Jakob Petsovits + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef CPPCODEC_DETAIL_STREAM_CODEC +#define CPPCODEC_DETAIL_STREAM_CODEC + +#include +#include // for abort() +#include + +#include "../parse_error.hpp" +#include "config.hpp" + +namespace cppcodec { +namespace detail { + +using alphabet_index_t = uint_fast16_t; + +template +class stream_codec +{ +public: + template static void encode( + Result& encoded_result, ResultState&, const uint8_t* binary, size_t binary_size); + + template static void decode( + Result& binary_result, ResultState&, const char* encoded, size_t encoded_size); + + static constexpr size_t encoded_size(size_t binary_size) noexcept; + static constexpr size_t decoded_max_size(size_t encoded_size) noexcept; +}; + +template // default for CodecVariant::generates_padding() == false +struct padder { + template + static CPPCODEC_ALWAYS_INLINE void pad(Result&, ResultState&, SizeT) { } +}; + +template<> // specialization for CodecVariant::generates_padding() == true +struct padder { + template + static CPPCODEC_ALWAYS_INLINE void pad( + Result& encoded, ResultState& state, SizeT num_padding_characters) + { + for (SizeT i = 0; i < num_padding_characters; ++i) { + data::put(encoded, state, CodecVariant::padding_symbol()); + } + } +}; + +template +struct enc { + // Block encoding: Go from 0 to (block size - 1), append a symbol for each iteration unconditionally. + template + static CPPCODEC_ALWAYS_INLINE void block(Result& encoded, ResultState& state, const uint8_t* src) + { + using EncodedBlockSizeT = decltype(Codec::encoded_block_size()); + constexpr static const EncodedBlockSizeT SymbolIndex = static_cast(I - 1); + + enc().template block(encoded, state, src); + data::put(encoded, state, CodecVariant::symbol(Codec::template index(src))); + } + + // Tail encoding: Go from 0 until (runtime) num_symbols, append a symbol for each iteration. + template + static CPPCODEC_ALWAYS_INLINE void tail( + Result& encoded, ResultState& state, const uint8_t* src, EncodedBlockSizeT num_symbols) + { + constexpr static const EncodedBlockSizeT SymbolIndex = Codec::encoded_block_size() - I; + constexpr static const EncodedBlockSizeT NumSymbols = SymbolIndex + static_cast(1); + + if (num_symbols == NumSymbols) { + data::put(encoded, state, CodecVariant::symbol(Codec::template index_last(src))); + return; + } + data::put(encoded, state, CodecVariant::symbol(Codec::template index(src))); + enc().template tail(encoded, state, src, num_symbols); + } +}; + +template<> // terminating specialization +struct enc<0> { + template + static CPPCODEC_ALWAYS_INLINE void block(Result&, ResultState&, const uint8_t*) { } + + template + static CPPCODEC_ALWAYS_INLINE void tail(Result&, ResultState&, const uint8_t*, EncodedBlockSizeT) + { + abort(); // Not reached: block() should be called if num_symbols == block size, not tail(). + } +}; + +template +template +inline void stream_codec::encode( + Result& encoded_result, ResultState& state, + const uint8_t* src, size_t src_size) +{ + using encoder = enc; + + const uint8_t* src_end = src + src_size; + + if (src_size >= Codec::binary_block_size()) { + src_end -= Codec::binary_block_size(); + + for (; src <= src_end; src += Codec::binary_block_size()) { + encoder::template block(encoded_result, state, src); + } + src_end += Codec::binary_block_size(); + } + + if (src_end > src) { + auto remaining_src_len = src_end - src; + if (!remaining_src_len || remaining_src_len >= Codec::binary_block_size()) { + abort(); + return; + } + + auto num_symbols = Codec::num_encoded_tail_symbols( + static_cast(remaining_src_len)); + + encoder::template tail(encoded_result, state, src, num_symbols); + + padder::template pad( + encoded_result, state, Codec::encoded_block_size() - num_symbols); + } +} + +// Range & lookup table generation, see +// http://stackoverflow.com/questions/13313980/populate-an-array-using-constexpr-at-compile-time +// and http://cplusadd.blogspot.ca/2013/02/c11-compile-time-lookup-tablearray-with.html + +template struct seq {}; + +template +struct gen_seq : gen_seq { + // Clang up to 3.6 has a limit of 256 for template recursion, + // so pass a few more symbols at once to make it work. + static_assert(N % 4 == 0, "I must be divisible by 4 to eventually end at 0"); +}; +template +struct gen_seq<0, Is...> : seq {}; + +template +struct lookup_table_t { + alphabet_index_t lookup[N]; + static constexpr size_t size = N; +}; + +template +constexpr lookup_table_t make_lookup_table(seq, LambdaType value_for_index) { + return { { value_for_index(Is)... } }; +} + +template +constexpr lookup_table_t make_lookup_table(LambdaType evalFunc) { + return make_lookup_table(gen_seq(), evalFunc); +} + +// CodecVariant::symbol() provides a symbol for an index. +// Use recursive templates to get the inverse lookup table for fast decoding. + +template +static CPPCODEC_ALWAYS_INLINE constexpr size_t num_possible_values() +{ + return static_cast( + static_cast((std::numeric_limits::max)()) + - static_cast((std::numeric_limits::min)()) + 1); +} + +template +struct index_if_in_alphabet { + static CPPCODEC_ALWAYS_INLINE constexpr alphabet_index_t for_symbol(char symbol) + { + return (CodecVariant::symbol( + static_cast(CodecVariant::alphabet_size() - I)) == symbol) + ? static_cast(CodecVariant::alphabet_size() - I) + : index_if_in_alphabet::for_symbol(symbol); + } +}; +template +struct index_if_in_alphabet { // terminating specialization + static CPPCODEC_ALWAYS_INLINE constexpr alphabet_index_t for_symbol(char) + { + return InvalidIdx; + } +}; + +template +struct padding_searcher { + static CPPCODEC_ALWAYS_INLINE constexpr bool exists_padding_symbol() + { + // Clang up to 3.6 has a limit of 256 for template recursion, + // so pass a few more symbols at once to make it work. + static_assert(I % 4 == 0, "I must be divisible by 4 to eventually end at 0"); + + return CodecVariant::is_padding_symbol( + static_cast(num_possible_values() - I - 4)) + || CodecVariant::is_padding_symbol( + static_cast(num_possible_values() - I - 3)) + || CodecVariant::is_padding_symbol( + static_cast(num_possible_values() - I - 2)) + || CodecVariant::is_padding_symbol( + static_cast(num_possible_values() - I - 1)) + || padding_searcher::exists_padding_symbol(); + } +}; +template +struct padding_searcher { // terminating specialization + static CPPCODEC_ALWAYS_INLINE constexpr bool exists_padding_symbol() { return false; } +}; + +template +struct alphabet_index_info +{ + static constexpr const size_t num_possible_symbols = num_possible_values(); + + static constexpr const alphabet_index_t padding_idx = 1 << 8; + static constexpr const alphabet_index_t invalid_idx = 1 << 9; + static constexpr const alphabet_index_t eof_idx = 1 << 10; + static constexpr const alphabet_index_t stop_character_mask = static_cast(~0xFFu); + + static constexpr const bool padding_allowed = padding_searcher< + CodecVariant, num_possible_symbols>::exists_padding_symbol(); + + static CPPCODEC_ALWAYS_INLINE constexpr bool allows_padding() + { + return padding_allowed; + } + static CPPCODEC_ALWAYS_INLINE constexpr bool is_padding(alphabet_index_t idx) + { + return allows_padding() ? (idx == padding_idx) : false; + } + static CPPCODEC_ALWAYS_INLINE constexpr bool is_invalid(alphabet_index_t idx) { return idx == invalid_idx; } + static CPPCODEC_ALWAYS_INLINE constexpr bool is_eof(alphabet_index_t idx) { return idx == eof_idx; } + static CPPCODEC_ALWAYS_INLINE constexpr bool is_stop_character(alphabet_index_t idx) + { + return (idx & stop_character_mask) != 0; + } + +private: + static CPPCODEC_ALWAYS_INLINE constexpr + alphabet_index_t valid_index_or(alphabet_index_t a, alphabet_index_t b) + { + return a == invalid_idx ? b : a; + } + + using idx_if_in_alphabet = index_if_in_alphabet< + CodecVariant, invalid_idx, CodecVariant::alphabet_size()>; + + static CPPCODEC_ALWAYS_INLINE constexpr alphabet_index_t index_of(char symbol) + { + return valid_index_or(idx_if_in_alphabet::for_symbol(symbol), + CodecVariant::is_eof_symbol(symbol) ? eof_idx + : CodecVariant::is_padding_symbol(symbol) ? padding_idx + : invalid_idx); + } + + // GCC <= 4.9 has a bug with retaining constexpr when passing a function pointer. + // To get around this, we'll create a callable with operator() and pass that one. + // Unfortunately, MSVC prior to VS 2017 (for MinSizeRel or Release builds) + // chokes on this by compiling the project in 20 minutes instead of seconds. + // So let's define two separate variants and remove the old GCC one whenever we + // decide not to support GCC < 5.0 anymore. +#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 5 + struct index_at { + CPPCODEC_ALWAYS_INLINE constexpr alphabet_index_t operator()(size_t symbol) const { + return index_of(CodecVariant::normalized_symbol(static_cast(symbol))); + } + }; +#else + static CPPCODEC_ALWAYS_INLINE constexpr alphabet_index_t index_at(size_t symbol) + { + return index_of(CodecVariant::normalized_symbol(static_cast(symbol))); + } +#endif + +public: + struct lookup { + static CPPCODEC_ALWAYS_INLINE alphabet_index_t for_symbol(char symbol) + { +#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 5 + static constexpr const auto t = make_lookup_table(index_at()); +#else + static constexpr const auto t = make_lookup_table(&index_at); +#endif + static_assert(t.size == num_possible_symbols, + "lookup table must cover each possible (character) symbol"); + return t.lookup[static_cast(symbol)]; + } + }; +}; + +// +// At long last! The actual decode/encode functions. + +template +template +inline void stream_codec::decode( + Result& binary_result, ResultState& state, + const char* src_encoded, size_t src_size) +{ + using alphabet_index_lookup = typename alphabet_index_info::lookup; + const char* src = src_encoded; + const char* src_end = src + src_size; + + alphabet_index_t alphabet_indexes[Codec::encoded_block_size()] = {}; + alphabet_indexes[0] = alphabet_index_info::eof_idx; + + alphabet_index_t* const alphabet_index_start = &alphabet_indexes[0]; + alphabet_index_t* const alphabet_index_end = &alphabet_indexes[Codec::encoded_block_size()]; + alphabet_index_t* alphabet_index_ptr = &alphabet_indexes[0]; + + while (src < src_end) { + if (CodecVariant::should_ignore(*src)) { + ++src; + continue; + } + *alphabet_index_ptr = alphabet_index_lookup::for_symbol(*src); + if (alphabet_index_info::is_stop_character(*alphabet_index_ptr)) { + break; + } + ++src; + ++alphabet_index_ptr; + + if (alphabet_index_ptr == alphabet_index_end) { + Codec::decode_block(binary_result, state, alphabet_indexes); + alphabet_index_ptr = alphabet_index_start; + } + } + + if (alphabet_index_info::is_invalid(*alphabet_index_ptr)) { + throw symbol_error(*src); + } + ++src; + + alphabet_index_t* last_index_ptr = alphabet_index_ptr; + if (alphabet_index_info::is_padding(*last_index_ptr)) { + if (last_index_ptr == alphabet_index_start) { + // Don't accept padding at the start of a block. + // The encoder should have omitted that padding altogether. + throw padding_error(); + } + // We're in here because we just read a (first) padding character. Try to read more. + // Count with last_index_ptr, but store in alphabet_index_ptr so we don't + // overflow the array in case the input data is too long. + ++last_index_ptr; + while (src < src_end) { + *alphabet_index_ptr = alphabet_index_lookup::for_symbol(*(src++)); + + if (alphabet_index_info::is_eof(*alphabet_index_ptr)) { + *alphabet_index_ptr = alphabet_index_info::padding_idx; + break; + } + if (!alphabet_index_info::is_padding(*alphabet_index_ptr)) { + throw padding_error(); + } + + ++last_index_ptr; + if (last_index_ptr > alphabet_index_end) { + throw padding_error(); + } + } + } + + if (last_index_ptr != alphabet_index_start) { + if ((CodecVariant::requires_padding() + || alphabet_index_info::is_padding(*alphabet_index_ptr) + ) && last_index_ptr != alphabet_index_end) + { + // If the input is not a multiple of the block size then the input is incorrect. + throw padding_error(); + } + if (alphabet_index_ptr >= alphabet_index_end) { + abort(); + return; + } + Codec::decode_tail(binary_result, state, alphabet_indexes, + static_cast(alphabet_index_ptr - alphabet_index_start)); + } +} + +template +inline constexpr size_t stream_codec::encoded_size(size_t binary_size) noexcept +{ + using C = Codec; + + // constexpr rules make this a lot harder to read than it actually is. + return CodecVariant::generates_padding() + // With padding, the encoded size is a multiple of the encoded block size. + // To calculate that, round the binary size up to multiple of the binary block size, + // then convert to encoded by multiplying with { base32: 8/5, base64: 4/3 }. + ? (binary_size + (C::binary_block_size() - 1) + - ((binary_size + (C::binary_block_size() - 1)) % C::binary_block_size())) + * C::encoded_block_size() / C::binary_block_size() + // No padding: only pad to the next multiple of 5 bits, i.e. at most a single extra byte. + : (binary_size * C::encoded_block_size() / C::binary_block_size()) + + (((binary_size * C::encoded_block_size()) % C::binary_block_size()) ? 1 : 0); +} + +template +inline constexpr size_t stream_codec::decoded_max_size(size_t encoded_size) noexcept +{ + using C = Codec; + + return CodecVariant::requires_padding() + ? (encoded_size / C::encoded_block_size() * C::binary_block_size()) + : (encoded_size / C::encoded_block_size() * C::binary_block_size()) + + ((encoded_size % C::encoded_block_size()) + * C::binary_block_size() / C::encoded_block_size()); +} + +} // namespace detail +} // namespace cppcodec + +#endif // CPPCODEC_DETAIL_STREAM_CODEC diff --git a/include/Third_Lib/cppcodec/hex_default_lower.hpp b/include/Third_Lib/cppcodec/hex_default_lower.hpp new file mode 100644 index 0000000..3b10675 --- /dev/null +++ b/include/Third_Lib/cppcodec/hex_default_lower.hpp @@ -0,0 +1,31 @@ +/** + * Copyright (C) 2015 Topology LP + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef CPPCODEC_HEX_DEFAULT_LOWER +#define CPPCODEC_HEX_DEFAULT_LOWER + +#include "hex_lower.hpp" + +using hex = cppcodec::hex_lower; + +#endif // CPPCODEC_HEX_DEFAULT_LOWER diff --git a/include/Third_Lib/cppcodec/hex_default_upper.hpp b/include/Third_Lib/cppcodec/hex_default_upper.hpp new file mode 100644 index 0000000..a960f02 --- /dev/null +++ b/include/Third_Lib/cppcodec/hex_default_upper.hpp @@ -0,0 +1,31 @@ +/** + * Copyright (C) 2015 Topology LP + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef CPPCODEC_HEX_DEFAULT_UPPER +#define CPPCODEC_HEX_DEFAULT_UPPER + +#include "hex_upper.hpp" + +using hex = cppcodec::hex_upper; + +#endif // CPPCODEC_HEX_DEFAULT_UPPER diff --git a/include/Third_Lib/cppcodec/hex_lower.hpp b/include/Third_Lib/cppcodec/hex_lower.hpp new file mode 100644 index 0000000..36ad583 --- /dev/null +++ b/include/Third_Lib/cppcodec/hex_lower.hpp @@ -0,0 +1,75 @@ +/** + * Copyright (C) 2015 Topology LP + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef CPPCODEC_HEX_LOWER +#define CPPCODEC_HEX_LOWER + +#include "detail/codec.hpp" +#include "detail/hex.hpp" + +namespace cppcodec { + +namespace detail { + +static constexpr const char hex_lower_alphabet[] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', // at index 10 + 'a', 'b', 'c', 'd', 'e', 'f' +}; + +class hex_lower +{ +public: + template using codec_impl = stream_codec; + + static CPPCODEC_ALWAYS_INLINE constexpr size_t alphabet_size() { + static_assert(sizeof(hex_lower_alphabet) == 16, "hex alphabet must have 16 values"); + return sizeof(hex_lower_alphabet); + } + static CPPCODEC_ALWAYS_INLINE constexpr char symbol(alphabet_index_t index) + { + return hex_lower_alphabet[index]; + } + static CPPCODEC_ALWAYS_INLINE constexpr char normalized_symbol(char c) + { + // Hex decoding is always case-insensitive (even in RFC 4648), the question + // is only for encoding whether to use upper-case or lower-case letters. + return (c >= 'A' && c <= 'F') ? (c - 'A' + 'a') : c; + } + + static CPPCODEC_ALWAYS_INLINE constexpr bool generates_padding() { return false; } + // FIXME: doesn't require padding, but requires a multiple of the encoded block size (2) + static CPPCODEC_ALWAYS_INLINE constexpr bool requires_padding() { return false; } + static CPPCODEC_ALWAYS_INLINE constexpr bool is_padding_symbol(char) { return false; } + static CPPCODEC_ALWAYS_INLINE constexpr bool is_eof_symbol(char c) { return c == '\0'; } + + // Sometimes hex strings include whitespace, but this variant forbids it. + static CPPCODEC_ALWAYS_INLINE constexpr bool should_ignore(char) { return false; } +}; + +} // namespace detail + +using hex_lower = detail::codec>; + +} // namespace cppcodec + +#endif // CPPCODEC_HEX_LOWER diff --git a/include/Third_Lib/cppcodec/hex_upper.hpp b/include/Third_Lib/cppcodec/hex_upper.hpp new file mode 100644 index 0000000..9b811c6 --- /dev/null +++ b/include/Third_Lib/cppcodec/hex_upper.hpp @@ -0,0 +1,75 @@ +/** + * Copyright (C) 2015 Topology LP + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef CPPCODEC_HEX_UPPER +#define CPPCODEC_HEX_UPPER + +#include "detail/codec.hpp" +#include "detail/hex.hpp" + +namespace cppcodec { + +namespace detail { + +static constexpr const char hex_upper_alphabet[] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F' +}; + +class hex_upper +{ +public: + template using codec_impl = stream_codec; + + static CPPCODEC_ALWAYS_INLINE constexpr size_t alphabet_size() { + static_assert(sizeof(hex_upper_alphabet) == 16, "hex alphabet must have 16 values"); + return sizeof(hex_upper_alphabet); + } + static CPPCODEC_ALWAYS_INLINE constexpr char symbol(alphabet_index_t index) + { + return hex_upper_alphabet[index]; + } + static CPPCODEC_ALWAYS_INLINE constexpr char normalized_symbol(char c) + { + // Hex decoding is always case-insensitive (even in RFC 4648), the question + // is only for encoding whether to use upper-case or lower-case letters. + return (c >= 'a' && c <= 'f') ? (c - 'a' + 'A') : c; + } + + static CPPCODEC_ALWAYS_INLINE constexpr bool generates_padding() { return false; } + // FIXME: doesn't require padding, but requires a multiple of the encoded block size (2) + static CPPCODEC_ALWAYS_INLINE constexpr bool requires_padding() { return false; } + static CPPCODEC_ALWAYS_INLINE constexpr bool is_padding_symbol(char) { return false; } + static CPPCODEC_ALWAYS_INLINE constexpr bool is_eof_symbol(char c) { return c == '\0'; } + + // Sometimes hex strings include whitespace, but this variant forbids it. + static CPPCODEC_ALWAYS_INLINE constexpr bool should_ignore(char) { return false; } +}; + +} // namespace detail + +using hex_upper = detail::codec>; + +} // namespace cppcodec + +#endif // CPPCODEC_HEX_UPPER diff --git a/include/Third_Lib/cppcodec/parse_error.hpp b/include/Third_Lib/cppcodec/parse_error.hpp new file mode 100644 index 0000000..97438ad --- /dev/null +++ b/include/Third_Lib/cppcodec/parse_error.hpp @@ -0,0 +1,109 @@ +/** + * Copyright (C) 2015 Topology LP + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef CPPCODEC_PARSE_ERROR +#define CPPCODEC_PARSE_ERROR + +#include +#include + +namespace cppcodec { + +namespace detail { +// <*stream> headers include a lot of code and noticeably increase compile times. +// The only thing we want from them really is a char-to-string conversion. +// That's easy to implement with many less lines of code, so let's do it ourselves. +template +static void uctoa(unsigned char n, char (&s)[N]) +{ + static_assert(N >= 4, "need at least 4 bytes to convert an unsigned char to string safely"); + int i = sizeof(s) - 1; + int num_chars = 1; + s[i--] = '\0'; + do { // generate digits in reverse order + s[i--] = n % 10 + '0'; // get next digit + ++num_chars; + } while ((n /= 10) > 0); // delete it + + if (num_chars == sizeof(s)) { + return; + } + for (i = 0; i < num_chars; ++i) { // move chars to front of string + s[i] = s[i + (sizeof(s) - num_chars)]; + } +} +} // end namespace detail + + +class parse_error : public std::domain_error +{ +public: + using std::domain_error::domain_error; +}; + +// Avoids memory allocation, so it can be used in constexpr functions. +class symbol_error : public parse_error +{ +public: + symbol_error(char c) + : parse_error(symbol_error::make_error_message(c)) + , m_symbol(c) + { + } + + symbol_error(const symbol_error&) = default; + + char symbol() const noexcept { return m_symbol; } + +private: + static std::string make_error_message(char c) + { + char s[4]; + detail::uctoa(*reinterpret_cast(&c), s); + return std::string("parse error: character [") + &(s[0]) + " '" + c + "'] out of bounds"; + } + +private: + char m_symbol; +}; + +class invalid_input_length : public parse_error +{ +public: + using parse_error::parse_error; +}; + +class padding_error : public invalid_input_length +{ +public: + padding_error() + : invalid_input_length("parse error: codec expects padded input string but padding was invalid") + { + } + + padding_error(const padding_error&) = default; +}; + +} // namespace cppcodec + +#endif // CPPCODEC_PARSE_ERROR diff --git a/include/Third_Lib/fmt/core.h b/include/Third_Lib/fmt/core.h new file mode 100644 index 0000000..5e829fd --- /dev/null +++ b/include/Third_Lib/fmt/core.h @@ -0,0 +1,2744 @@ +// Formatting library for C++ - the core API +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_CORE_H_ +#define FMT_CORE_H_ + +#include // INT_MAX +#include // std::FILE +#include +#include +#include +#include + +// The fmt library version in the form major * 10000 + minor * 100 + patch. +#define FMT_VERSION 70104 + +#ifdef __clang__ +# define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__) +#else +# define FMT_CLANG_VERSION 0 +#endif + +#if defined(__GNUC__) && !defined(__clang__) +# define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) +# define FMT_GCC_PRAGMA(arg) _Pragma(arg) +#else +# define FMT_GCC_VERSION 0 +# define FMT_GCC_PRAGMA(arg) +#endif + +#if defined(__INTEL_COMPILER) +# define FMT_ICC_VERSION __INTEL_COMPILER +#else +# define FMT_ICC_VERSION 0 +#endif + +#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define FMT_HAS_GXX_CXX11 FMT_GCC_VERSION +#else +# define FMT_HAS_GXX_CXX11 0 +#endif + +// Check if constexpr std::char_traits<>::compare,length is supported. +#if defined(__GLIBCXX__) +# if __cplusplus >= 201703L && defined(_GLIBCXX_RELEASE) && \ + _GLIBCXX_RELEASE >= 7 // GCC 7+ libstdc++ has _GLIBCXX_RELEASE. +# define FMT_CONSTEXPR_CHAR_TRAITS constexpr +# endif +#elif defined(_LIBCPP_VERSION) +# if __cplusplus >= 201703L && _LIBCPP_VERSION >= 4000 +# define FMT_CONSTEXPR_CHAR_TRAITS constexpr +# endif +#elif defined(_MSC_VER) +# if _MSVC_LANG >= 201703L && _MSC_VER >= 1914 +# define FMT_CONSTEXPR_CHAR_TRAITS constexpr +# endif +#endif +#ifndef FMT_CONSTEXPR_CHAR_TRAITS +# define FMT_CONSTEXPR_CHAR_TRAITS +#endif + +#ifdef __NVCC__ +# define FMT_NVCC __NVCC__ +#else +# define FMT_NVCC 0 +#endif + +#ifdef _MSC_VER +# define FMT_MSC_VER _MSC_VER +# define FMT_MSC_WARNING(...) __pragma(warning(__VA_ARGS__)) +#else +# define FMT_MSC_VER 0 +# define FMT_MSC_WARNING(...) +#endif + +#ifdef __has_feature +# define FMT_HAS_FEATURE(x) __has_feature(x) +#else +# define FMT_HAS_FEATURE(x) 0 +#endif + +#if defined(__has_include) && !defined(__INTELLISENSE__) && \ + (!FMT_ICC_VERSION || FMT_ICC_VERSION >= 1600) +# define FMT_HAS_INCLUDE(x) __has_include(x) +#else +# define FMT_HAS_INCLUDE(x) 0 +#endif + +#ifdef __has_cpp_attribute +# define FMT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) +#else +# define FMT_HAS_CPP_ATTRIBUTE(x) 0 +#endif + +#define FMT_HAS_CPP14_ATTRIBUTE(attribute) \ + (__cplusplus >= 201402L && FMT_HAS_CPP_ATTRIBUTE(attribute)) + +#define FMT_HAS_CPP17_ATTRIBUTE(attribute) \ + (__cplusplus >= 201703L && FMT_HAS_CPP_ATTRIBUTE(attribute)) + +// Check if relaxed C++14 constexpr is supported. +// GCC doesn't allow throw in constexpr until version 6 (bug 67371). +#ifndef FMT_USE_CONSTEXPR +# define FMT_USE_CONSTEXPR \ + (FMT_HAS_FEATURE(cxx_relaxed_constexpr) || FMT_MSC_VER >= 1910 || \ + (FMT_GCC_VERSION >= 600 && __cplusplus >= 201402L)) && \ + !FMT_NVCC && !FMT_ICC_VERSION +#endif +#if FMT_USE_CONSTEXPR +# define FMT_CONSTEXPR constexpr +# define FMT_CONSTEXPR_DECL constexpr +#else +# define FMT_CONSTEXPR +# define FMT_CONSTEXPR_DECL +#endif + +#ifndef FMT_OVERRIDE +# if FMT_HAS_FEATURE(cxx_override_control) || \ + (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900 +# define FMT_OVERRIDE override +# else +# define FMT_OVERRIDE +# endif +#endif + +// Check if exceptions are disabled. +#ifndef FMT_EXCEPTIONS +# if (defined(__GNUC__) && !defined(__EXCEPTIONS)) || \ + FMT_MSC_VER && !_HAS_EXCEPTIONS +# define FMT_EXCEPTIONS 0 +# else +# define FMT_EXCEPTIONS 1 +# endif +#endif + +// Define FMT_USE_NOEXCEPT to make fmt use noexcept (C++11 feature). +#ifndef FMT_USE_NOEXCEPT +# define FMT_USE_NOEXCEPT 0 +#endif + +#if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \ + (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900 +# define FMT_DETECTED_NOEXCEPT noexcept +# define FMT_HAS_CXX11_NOEXCEPT 1 +#else +# define FMT_DETECTED_NOEXCEPT throw() +# define FMT_HAS_CXX11_NOEXCEPT 0 +#endif + +#ifndef FMT_NOEXCEPT +# if FMT_EXCEPTIONS || FMT_HAS_CXX11_NOEXCEPT +# define FMT_NOEXCEPT FMT_DETECTED_NOEXCEPT +# else +# define FMT_NOEXCEPT +# endif +#endif + +// [[noreturn]] is disabled on MSVC and NVCC because of bogus unreachable code +// warnings. +#if FMT_EXCEPTIONS && FMT_HAS_CPP_ATTRIBUTE(noreturn) && !FMT_MSC_VER && \ + !FMT_NVCC +# define FMT_NORETURN [[noreturn]] +#else +# define FMT_NORETURN +#endif + +#ifndef FMT_MAYBE_UNUSED +# if FMT_HAS_CPP17_ATTRIBUTE(maybe_unused) +# define FMT_MAYBE_UNUSED [[maybe_unused]] +# else +# define FMT_MAYBE_UNUSED +# endif +#endif + +#ifndef FMT_DEPRECATED +# if FMT_HAS_CPP14_ATTRIBUTE(deprecated) || FMT_MSC_VER >= 1900 +# define FMT_DEPRECATED [[deprecated]] +# else +# if (defined(__GNUC__) && !defined(__LCC__)) || defined(__clang__) +# define FMT_DEPRECATED __attribute__((deprecated)) +# elif FMT_MSC_VER +# define FMT_DEPRECATED __declspec(deprecated) +# else +# define FMT_DEPRECATED /* deprecated */ +# endif +# endif +#endif + +// Workaround broken [[deprecated]] in the Intel, PGI and NVCC compilers. +#if FMT_ICC_VERSION || defined(__PGI) || FMT_NVCC +# define FMT_DEPRECATED_ALIAS +#else +# define FMT_DEPRECATED_ALIAS FMT_DEPRECATED +#endif + +#ifndef FMT_INLINE +# if FMT_GCC_VERSION || FMT_CLANG_VERSION +# define FMT_INLINE inline __attribute__((always_inline)) +# else +# define FMT_INLINE inline +# endif +#endif + +#ifndef FMT_USE_INLINE_NAMESPACES +# if FMT_HAS_FEATURE(cxx_inline_namespaces) || FMT_GCC_VERSION >= 404 || \ + (FMT_MSC_VER >= 1900 && (!defined(_MANAGED) || !_MANAGED)) +# define FMT_USE_INLINE_NAMESPACES 1 +# else +# define FMT_USE_INLINE_NAMESPACES 0 +# endif +#endif + +#ifndef FMT_BEGIN_NAMESPACE +# if FMT_USE_INLINE_NAMESPACES +# define FMT_INLINE_NAMESPACE inline namespace +# define FMT_END_NAMESPACE \ + } \ + } +# else +# define FMT_INLINE_NAMESPACE namespace +# define FMT_END_NAMESPACE \ + } \ + using namespace v7; \ + } +# endif +# define FMT_BEGIN_NAMESPACE \ + namespace fmt { \ + FMT_INLINE_NAMESPACE v7 { +#endif + +#ifndef FMT_MODULE_EXPORT +# define FMT_MODULE_EXPORT +#endif +#ifndef FMT_MODULE_EXPORT_BEGIN +# define FMT_MODULE_EXPORT_BEGIN +#endif +#ifndef FMT_MODULE_EXPORT_END +# define FMT_MODULE_EXPORT_END +#endif +#ifndef FMT_BEGIN_DETAIL_NAMESPACE +# define FMT_BEGIN_DETAIL_NAMESPACE \ + namespace detail { +#endif +#ifndef FMT_END_DETAIL_NAMESPACE +# define FMT_END_DETAIL_NAMESPACE \ + } +#endif + +#if !defined(FMT_HEADER_ONLY) && defined(_WIN32) +# define FMT_CLASS_API FMT_MSC_WARNING(suppress : 4275) +# ifdef FMT_EXPORT +# define FMT_API __declspec(dllexport) +# elif defined(FMT_SHARED) +# define FMT_API __declspec(dllimport) +# endif +#else +# define FMT_CLASS_API +#endif +#ifndef FMT_API +# define FMT_API +#endif + +#if FMT_GCC_VERSION +# define FMT_GCC_VISIBILITY_HIDDEN __attribute__((visibility("hidden"))) +#else +# define FMT_GCC_VISIBILITY_HIDDEN +#endif + +// libc++ supports string_view in pre-c++17. +#if (FMT_HAS_INCLUDE() && \ + (__cplusplus > 201402L || defined(_LIBCPP_VERSION))) || \ + (defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910) +# include +# define FMT_USE_STRING_VIEW +#elif FMT_HAS_INCLUDE("experimental/string_view") && __cplusplus >= 201402L +# include +# define FMT_USE_EXPERIMENTAL_STRING_VIEW +#endif + +#ifndef FMT_UNICODE +# define FMT_UNICODE !FMT_MSC_VER +#endif + +#ifndef FMT_COMPILE_TIME_CHECKS +# define FMT_COMPILE_TIME_CHECKS 0 +#endif + +#ifndef FMT_USE_NONTYPE_TEMPLATE_PARAMETERS +# if defined(__cpp_nontype_template_args) && \ + ((FMT_GCC_VERSION >= 903 && __cplusplus >= 201709L) || \ + __cpp_nontype_template_args >= 201911L) +# define FMT_USE_NONTYPE_TEMPLATE_PARAMETERS 1 +# else +# define FMT_USE_NONTYPE_TEMPLATE_PARAMETERS 0 +# endif +#endif + +// Enable minimal optimizations for more compact code in debug mode. +FMT_GCC_PRAGMA("GCC push_options") +#ifndef __OPTIMIZE__ +FMT_GCC_PRAGMA("GCC optimize(\"Og\")") +#endif + +FMT_BEGIN_NAMESPACE + FMT_MODULE_EXPORT_BEGIN + +// Implementations of enable_if_t and other metafunctions for older systems. + template + using enable_if_t = typename std::enable_if::type; + template + using conditional_t = typename std::conditional::type; + template using bool_constant = std::integral_constant; + template + using remove_reference_t = typename std::remove_reference::type; + template + using remove_const_t = typename std::remove_const::type; + template + using remove_cvref_t = typename std::remove_cv>::type; + template struct type_identity { using type = T; }; + template using type_identity_t = typename type_identity::type; + + struct monostate {}; + +// An enable_if helper to be used in template parameters which results in much +// shorter symbols: https://godbolt.org/z/sWw4vP. Extra parentheses are needed +// to workaround a bug in MSVC 2019 (see #1140 and #1186). +#ifdef FMT_DOC +# define FMT_ENABLE_IF(...) +#else +# define FMT_ENABLE_IF(...) enable_if_t<(__VA_ARGS__), int> = 0 +#endif + + FMT_BEGIN_DETAIL_NAMESPACE + + constexpr FMT_INLINE bool is_constant_evaluated() FMT_NOEXCEPT { +#ifdef __cpp_lib_is_constant_evaluated + return std::is_constant_evaluated(); +#else + return false; +#endif + } + +// A helper function to suppress "conditional expression is constant" warnings. + template constexpr T const_check(T value) { return value; } + + FMT_NORETURN FMT_API void assert_fail(const char* file, int line, + const char* message); + +#ifndef FMT_ASSERT +# ifdef NDEBUG + // FMT_ASSERT is not empty to avoid -Werror=empty-body. +# define FMT_ASSERT(condition, message) ((void)0) +# else +# define FMT_ASSERT(condition, message) \ + ((condition) /* void() fails with -Winvalid-constexpr on clang 4.0.1 */ \ + ? (void)0 \ + : ::fmt::detail::assert_fail(__FILE__, __LINE__, (message))) +# endif +#endif + +#if defined(FMT_USE_STRING_VIEW) + template using std_string_view = std::basic_string_view; +#elif defined(FMT_USE_EXPERIMENTAL_STRING_VIEW) + template + using std_string_view = std::experimental::basic_string_view; +#else + template struct std_string_view {}; +#endif + +#ifdef FMT_USE_INT128 + // Do nothing. +#elif defined(__SIZEOF_INT128__) && !FMT_NVCC && \ + !(FMT_CLANG_VERSION && FMT_MSC_VER) +# define FMT_USE_INT128 1 + using int128_t = __int128_t; + using uint128_t = __uint128_t; +#else +# define FMT_USE_INT128 0 +#endif +#if !FMT_USE_INT128 + struct int128_t {}; +struct uint128_t {}; +#endif + +// Casts a nonnegative integer to unsigned. + template + FMT_CONSTEXPR typename std::make_unsigned::type to_unsigned(Int value) { + FMT_ASSERT(value >= 0, "negative value"); + return static_cast::type>(value); + } + + FMT_MSC_WARNING(suppress : 4566) constexpr unsigned char micro[] = "\u00B5"; + + template constexpr bool is_unicode() { + return FMT_UNICODE || sizeof(Char) != 1 || + (sizeof(micro) == 3 && micro[0] == 0xC2 && micro[1] == 0xB5); + } + + FMT_END_DETAIL_NAMESPACE + +/** + An implementation of ``std::basic_string_view`` for pre-C++17. It provides a + subset of the API. ``fmt::basic_string_view`` is used for format strings even + if ``std::string_view`` is available to prevent issues when a library is + compiled with a different ``-std`` option than the client code (which is not + recommended). + */ + template class basic_string_view { + private: + const Char* data_; + size_t size_; + + public: + using value_type = Char; + using iterator = const Char*; + + constexpr basic_string_view() FMT_NOEXCEPT : data_(nullptr), size_(0) {} + + /** Constructs a string reference object from a C string and a size. */ + constexpr basic_string_view(const Char* s, size_t count) FMT_NOEXCEPT + : data_(s), + size_(count) {} + + /** + \rst + Constructs a string reference object from a C string computing + the size with ``std::char_traits::length``. + \endrst + */ + FMT_CONSTEXPR_CHAR_TRAITS + FMT_INLINE + basic_string_view(const Char* s) : data_(s) { + if (detail::const_check(std::is_same::value && + !detail::is_constant_evaluated())) + size_ = std::strlen(reinterpret_cast(s)); + else + size_ = std::char_traits::length(s); + } + + /** Constructs a string reference from a ``std::basic_string`` object. */ + template + FMT_CONSTEXPR basic_string_view( + const std::basic_string& s) FMT_NOEXCEPT + : data_(s.data()), + size_(s.size()) {} + + template >::value)> + FMT_CONSTEXPR basic_string_view(S s) FMT_NOEXCEPT : data_(s.data()), + size_(s.size()) {} + + /** Returns a pointer to the string data. */ + constexpr const Char* data() const { return data_; } + + /** Returns the string size. */ + constexpr size_t size() const { return size_; } + + constexpr iterator begin() const { return data_; } + constexpr iterator end() const { return data_ + size_; } + + constexpr const Char& operator[](size_t pos) const { return data_[pos]; } + + FMT_CONSTEXPR void remove_prefix(size_t n) { + data_ += n; + size_ -= n; + } + + // Lexicographically compare this string reference to other. + FMT_CONSTEXPR_CHAR_TRAITS int compare(basic_string_view other) const { + size_t str_size = size_ < other.size_ ? size_ : other.size_; + int result = std::char_traits::compare(data_, other.data_, str_size); + if (result == 0) + result = size_ == other.size_ ? 0 : (size_ < other.size_ ? -1 : 1); + return result; + } + + FMT_CONSTEXPR_CHAR_TRAITS friend bool operator==(basic_string_view lhs, + basic_string_view rhs) { + return lhs.compare(rhs) == 0; + } + friend bool operator!=(basic_string_view lhs, basic_string_view rhs) { + return lhs.compare(rhs) != 0; + } + friend bool operator<(basic_string_view lhs, basic_string_view rhs) { + return lhs.compare(rhs) < 0; + } + friend bool operator<=(basic_string_view lhs, basic_string_view rhs) { + return lhs.compare(rhs) <= 0; + } + friend bool operator>(basic_string_view lhs, basic_string_view rhs) { + return lhs.compare(rhs) > 0; + } + friend bool operator>=(basic_string_view lhs, basic_string_view rhs) { + return lhs.compare(rhs) >= 0; + } + }; + + using string_view = basic_string_view; + using wstring_view = basic_string_view; + +/** Specifies if ``T`` is a character type. Can be specialized by users. */ + template struct is_char : std::false_type {}; + template <> struct is_char : std::true_type {}; + template <> struct is_char : std::true_type {}; + +/** + \rst + Returns a string view of `s`. In order to add custom string type support to + {fmt} provide an overload of `to_string_view` for it in the same namespace as + the type for the argument-dependent lookup to work. + + **Example**:: + + namespace my_ns { + inline string_view to_string_view(const my_string& s) { + return {s.data(), s.length()}; + } + } + std::string message = fmt::format(my_string("The answer is {}"), 42); + \endrst + */ + template ::value)> + FMT_INLINE basic_string_view to_string_view(const Char* s) { + return s; + } + + template + inline basic_string_view to_string_view( + const std::basic_string& s) { + return s; + } + + template + constexpr basic_string_view to_string_view(basic_string_view s) { + return s; + } + + template >::value)> + inline basic_string_view to_string_view(detail::std_string_view s) { + return s; + } + +// A base class for compile-time strings. It is defined in the fmt namespace to +// make formatting functions visible via ADL, e.g. format(FMT_STRING("{}"), 42). + struct compile_string {}; + + template + struct is_compile_string : std::is_base_of {}; + + template ::value)> + constexpr basic_string_view to_string_view(const S& s) { + return s; + } + + FMT_BEGIN_DETAIL_NAMESPACE + + void to_string_view(...); + using fmt::v7::to_string_view; + +// Specifies whether S is a string type convertible to fmt::basic_string_view. +// It should be a constexpr function but MSVC 2017 fails to compile it in +// enable_if and MSVC 2015 fails to compile it as an alias template. + template + struct is_string : std::is_class()))> { + }; + + template struct char_t_impl {}; + template struct char_t_impl::value>> { + using result = decltype(to_string_view(std::declval())); + using type = typename result::value_type; + }; + +// Reports a compile-time error if S is not a valid format string. + template ::value)> + FMT_INLINE void check_format_string(const S&) { +#ifdef FMT_ENFORCE_COMPILE_STRING + static_assert(is_compile_string::value, + "FMT_ENFORCE_COMPILE_STRING requires all format strings to use " + "FMT_STRING."); +#endif + } + template ::value)> + void check_format_string(S); + + struct error_handler { + constexpr error_handler() = default; + constexpr error_handler(const error_handler&) = default; + + // This function is intentionally not constexpr to give a compile-time error. + FMT_NORETURN FMT_API void on_error(const char* message); + }; + + FMT_END_DETAIL_NAMESPACE + +/** String's character type. */ + template using char_t = typename detail::char_t_impl::type; + +/** + \rst + Parsing context consisting of a format string range being parsed and an + argument counter for automatic indexing. + + You can use one of the following type aliases for common character types: + + +-----------------------+-------------------------------------+ + | Type | Definition | + +=======================+=====================================+ + | format_parse_context | basic_format_parse_context | + +-----------------------+-------------------------------------+ + | wformat_parse_context | basic_format_parse_context | + +-----------------------+-------------------------------------+ + \endrst + */ + template + class basic_format_parse_context : private ErrorHandler { + private: + basic_string_view format_str_; + int next_arg_id_; + + public: + using char_type = Char; + using iterator = typename basic_string_view::iterator; + + explicit constexpr basic_format_parse_context( + basic_string_view format_str, ErrorHandler eh = {}, + int next_arg_id = 0) + : ErrorHandler(eh), format_str_(format_str), next_arg_id_(next_arg_id) {} + + /** + Returns an iterator to the beginning of the format string range being + parsed. + */ + constexpr iterator begin() const FMT_NOEXCEPT { return format_str_.begin(); } + + /** + Returns an iterator past the end of the format string range being parsed. + */ + constexpr iterator end() const FMT_NOEXCEPT { return format_str_.end(); } + + /** Advances the begin iterator to ``it``. */ + FMT_CONSTEXPR void advance_to(iterator it) { + format_str_.remove_prefix(detail::to_unsigned(it - begin())); + } + + /** + Reports an error if using the manual argument indexing; otherwise returns + the next argument index and switches to the automatic indexing. + */ + FMT_CONSTEXPR int next_arg_id() { + // Don't check if the argument id is valid to avoid overhead and because it + // will be checked during formatting anyway. + if (next_arg_id_ >= 0) return next_arg_id_++; + on_error("cannot switch from manual to automatic argument indexing"); + return 0; + } + + /** + Reports an error if using the automatic argument indexing; otherwise + switches to the manual indexing. + */ + FMT_CONSTEXPR void check_arg_id(int) { + if (next_arg_id_ > 0) + on_error("cannot switch from automatic to manual argument indexing"); + else + next_arg_id_ = -1; + } + + FMT_CONSTEXPR void check_arg_id(basic_string_view) {} + + FMT_CONSTEXPR void on_error(const char* message) { + ErrorHandler::on_error(message); + } + + constexpr ErrorHandler error_handler() const { return *this; } + }; + + using format_parse_context = basic_format_parse_context; + using wformat_parse_context = basic_format_parse_context; + + template class basic_format_arg; + template class basic_format_args; + template class dynamic_format_arg_store; + +// A formatter for objects of type T. + template + struct formatter { + // A deleted default constructor indicates a disabled formatter. + formatter() = delete; + }; + +// DEPRECATED! +// Specifies if T has an enabled formatter specialization. A type can be +// formattable even if it doesn't have a formatter e.g. via a conversion. + template + using has_formatter = + std::is_constructible>; + +// Checks whether T is a container with contiguous storage. + template struct is_contiguous : std::false_type {}; + template + struct is_contiguous> : std::true_type {}; + + FMT_BEGIN_DETAIL_NAMESPACE + +// Extracts a reference to the container from back_insert_iterator. + template + inline Container& get_container(std::back_insert_iterator it) { + using bi_iterator = std::back_insert_iterator; + struct accessor : bi_iterator { + accessor(bi_iterator iter) : bi_iterator(iter) {} + using bi_iterator::container; + }; + return *accessor(it).container; + } + +/** + \rst + A contiguous memory buffer with an optional growing ability. It is an internal + class and shouldn't be used directly, only via `~fmt::basic_memory_buffer`. + \endrst + */ + template class buffer { + private: + T* ptr_; + size_t size_; + size_t capacity_; + + protected: + // Don't initialize ptr_ since it is not accessed to save a few cycles. + FMT_MSC_WARNING(suppress : 26495) + buffer(size_t sz) FMT_NOEXCEPT : size_(sz), capacity_(sz) {} + + buffer(T* p = nullptr, size_t sz = 0, size_t cap = 0) FMT_NOEXCEPT + : ptr_(p), + size_(sz), + capacity_(cap) {} + + ~buffer() = default; + + /** Sets the buffer data and capacity. */ + void set(T* buf_data, size_t buf_capacity) FMT_NOEXCEPT { + ptr_ = buf_data; + capacity_ = buf_capacity; + } + + /** Increases the buffer capacity to hold at least *capacity* elements. */ + virtual void grow(size_t capacity) = 0; + + public: + using value_type = T; + using const_reference = const T&; + + buffer(const buffer&) = delete; + void operator=(const buffer&) = delete; + + T* begin() FMT_NOEXCEPT { return ptr_; } + T* end() FMT_NOEXCEPT { return ptr_ + size_; } + + const T* begin() const FMT_NOEXCEPT { return ptr_; } + const T* end() const FMT_NOEXCEPT { return ptr_ + size_; } + + /** Returns the size of this buffer. */ + size_t size() const FMT_NOEXCEPT { return size_; } + + /** Returns the capacity of this buffer. */ + size_t capacity() const FMT_NOEXCEPT { return capacity_; } + + /** Returns a pointer to the buffer data. */ + T* data() FMT_NOEXCEPT { return ptr_; } + + /** Returns a pointer to the buffer data. */ + const T* data() const FMT_NOEXCEPT { return ptr_; } + + /** Clears this buffer. */ + void clear() { size_ = 0; } + + // Tries resizing the buffer to contain *count* elements. If T is a POD type + // the new elements may not be initialized. + void try_resize(size_t count) { + try_reserve(count); + size_ = count <= capacity_ ? count : capacity_; + } + + // Tries increasing the buffer capacity to *new_capacity*. It can increase the + // capacity by a smaller amount than requested but guarantees there is space + // for at least one additional element either by increasing the capacity or by + // flushing the buffer if it is full. + void try_reserve(size_t new_capacity) { + if (new_capacity > capacity_) grow(new_capacity); + } + + void push_back(const T& value) { + try_reserve(size_ + 1); + ptr_[size_++] = value; + } + + /** Appends data to the end of the buffer. */ + template void append(const U* begin, const U* end); + + template T& operator[](I index) { return ptr_[index]; } + template const T& operator[](I index) const { + return ptr_[index]; + } + }; + + struct buffer_traits { + explicit buffer_traits(size_t) {} + size_t count() const { return 0; } + size_t limit(size_t size) { return size; } + }; + + class fixed_buffer_traits { + private: + size_t count_ = 0; + size_t limit_; + + public: + explicit fixed_buffer_traits(size_t limit) : limit_(limit) {} + size_t count() const { return count_; } + size_t limit(size_t size) { + size_t n = limit_ > count_ ? limit_ - count_ : 0; + count_ += size; + return size < n ? size : n; + } + }; + +// A buffer that writes to an output iterator when flushed. + template + class iterator_buffer final : public Traits, public buffer { + private: + OutputIt out_; + enum { buffer_size = 256 }; + T data_[buffer_size]; + + protected: + void grow(size_t) final FMT_OVERRIDE { + if (this->size() == buffer_size) flush(); + } + void flush(); + + public: + explicit iterator_buffer(OutputIt out, size_t n = buffer_size) + : Traits(n), buffer(data_, 0, buffer_size), out_(out) {} + ~iterator_buffer() { flush(); } + + OutputIt out() { + flush(); + return out_; + } + size_t count() const { return Traits::count() + this->size(); } + }; + + template class iterator_buffer final : public buffer { + protected: + void grow(size_t) final FMT_OVERRIDE {} + + public: + explicit iterator_buffer(T* out, size_t = 0) : buffer(out, 0, ~size_t()) {} + + T* out() { return &*this->end(); } + }; + +// A buffer that writes to a container with the contiguous storage. + template + class iterator_buffer, + enable_if_t::value, + typename Container::value_type>> + final : public buffer { + private: + Container& container_; + + protected: + void grow(size_t capacity) final FMT_OVERRIDE { + container_.resize(capacity); + this->set(&container_[0], capacity); + } + + public: + explicit iterator_buffer(Container& c) + : buffer(c.size()), container_(c) {} + explicit iterator_buffer(std::back_insert_iterator out, size_t = 0) + : iterator_buffer(get_container(out)) {} + std::back_insert_iterator out() { + return std::back_inserter(container_); + } + }; + +// A buffer that counts the number of code units written discarding the output. + template class counting_buffer final : public buffer { + private: + enum { buffer_size = 256 }; + T data_[buffer_size]; + size_t count_ = 0; + + protected: + void grow(size_t) final FMT_OVERRIDE { + if (this->size() != buffer_size) return; + count_ += this->size(); + this->clear(); + } + + public: + counting_buffer() : buffer(data_, 0, buffer_size) {} + + size_t count() { return count_ + this->size(); } + }; + +// An output iterator that appends to the buffer. +// It is used to reduce symbol sizes for the common case. + template + class buffer_appender : public std::back_insert_iterator> { + using base = std::back_insert_iterator>; + + public: + using std::back_insert_iterator>::back_insert_iterator; + buffer_appender(base it) : base(it) {} + using _Unchecked_type = buffer_appender; // Mark iterator as checked. + + buffer_appender& operator++() { + base::operator++(); + return *this; + } + + buffer_appender operator++(int) { + buffer_appender tmp = *this; + ++*this; + return tmp; + } + }; + +// Maps an output iterator into a buffer. + template + iterator_buffer get_buffer(OutputIt); + template buffer& get_buffer(buffer_appender); + + template OutputIt get_buffer_init(OutputIt out) { + return out; + } + template buffer& get_buffer_init(buffer_appender out) { + return get_container(out); + } + + template + auto get_iterator(Buffer& buf) -> decltype(buf.out()) { + return buf.out(); + } + template buffer_appender get_iterator(buffer& buf) { + return buffer_appender(buf); + } + + template + struct fallback_formatter { + fallback_formatter() = delete; + }; + +// Specifies if T has an enabled fallback_formatter specialization. + template + using has_fallback_formatter = + std::is_constructible>; + + struct view {}; + + template struct named_arg : view { + const Char* name; + const T& value; + named_arg(const Char* n, const T& v) : name(n), value(v) {} + }; + + template struct named_arg_info { + const Char* name; + int id; + }; + + template + struct arg_data { + // args_[0].named_args points to named_args_ to avoid bloating format_args. + // +1 to workaround a bug in gcc 7.5 that causes duplicated-branches warning. + T args_[1 + (NUM_ARGS != 0 ? NUM_ARGS : +1)]; + named_arg_info named_args_[NUM_NAMED_ARGS]; + + template + arg_data(const U&... init) : args_{T(named_args_, NUM_NAMED_ARGS), init...} {} + arg_data(const arg_data& other) = delete; + const T* args() const { return args_ + 1; } + named_arg_info* named_args() { return named_args_; } + }; + + template + struct arg_data { + // +1 to workaround a bug in gcc 7.5 that causes duplicated-branches warning. + T args_[NUM_ARGS != 0 ? NUM_ARGS : +1]; + + template + FMT_CONSTEXPR FMT_INLINE arg_data(const U&... init) : args_{init...} {} + FMT_CONSTEXPR FMT_INLINE const T* args() const { return args_; } + FMT_CONSTEXPR FMT_INLINE std::nullptr_t named_args() { return nullptr; } + }; + + template + inline void init_named_args(named_arg_info*, int, int) {} + + template struct is_named_arg : std::false_type {}; + template struct is_statically_named_arg : std::false_type {}; + + template + struct is_named_arg> : std::true_type {}; + + template ::value)> + void init_named_args(named_arg_info* named_args, int arg_count, + int named_arg_count, const T&, const Tail&... args) { + init_named_args(named_args, arg_count + 1, named_arg_count, args...); + } + + template ::value)> + void init_named_args(named_arg_info* named_args, int arg_count, + int named_arg_count, const T& arg, const Tail&... args) { + named_args[named_arg_count++] = {arg.name, arg_count}; + init_named_args(named_args, arg_count + 1, named_arg_count, args...); + } + + template + FMT_CONSTEXPR FMT_INLINE void init_named_args(std::nullptr_t, int, int, + const Args&...) {} + + template constexpr size_t count() { return B ? 1 : 0; } + template constexpr size_t count() { + return (B1 ? 1 : 0) + count(); + } + + template constexpr size_t count_named_args() { + return count::value...>(); + } + + enum class type { + none_type, + // Integer types should go first, + int_type, + uint_type, + long_long_type, + ulong_long_type, + int128_type, + uint128_type, + bool_type, + char_type, + last_integer_type = char_type, + // followed by floating-point types. + float_type, + double_type, + long_double_type, + last_numeric_type = long_double_type, + cstring_type, + string_type, + pointer_type, + custom_type + }; + +// Maps core type T to the corresponding type enum constant. + template + struct type_constant : std::integral_constant {}; + +#define FMT_TYPE_CONSTANT(Type, constant) \ + template \ + struct type_constant \ + : std::integral_constant {} + + FMT_TYPE_CONSTANT(int, int_type); + FMT_TYPE_CONSTANT(unsigned, uint_type); + FMT_TYPE_CONSTANT(long long, long_long_type); + FMT_TYPE_CONSTANT(unsigned long long, ulong_long_type); + FMT_TYPE_CONSTANT(int128_t, int128_type); + FMT_TYPE_CONSTANT(uint128_t, uint128_type); + FMT_TYPE_CONSTANT(bool, bool_type); + FMT_TYPE_CONSTANT(Char, char_type); + FMT_TYPE_CONSTANT(float, float_type); + FMT_TYPE_CONSTANT(double, double_type); + FMT_TYPE_CONSTANT(long double, long_double_type); + FMT_TYPE_CONSTANT(const Char*, cstring_type); + FMT_TYPE_CONSTANT(basic_string_view, string_type); + FMT_TYPE_CONSTANT(const void*, pointer_type); + + constexpr bool is_integral_type(type t) { + return t > type::none_type && t <= type::last_integer_type; + } + + constexpr bool is_arithmetic_type(type t) { + return t > type::none_type && t <= type::last_numeric_type; + } + + template struct string_value { + const Char* data; + size_t size; + }; + + template struct named_arg_value { + const named_arg_info* data; + size_t size; + }; + + template struct custom_value { + using parse_context = typename Context::parse_context_type; + const void* value; + void (*format)(const void* arg, parse_context& parse_ctx, Context& ctx); + }; + +// A formatting argument value. + template class value { + public: + using char_type = typename Context::char_type; + + union { + int int_value; + unsigned uint_value; + long long long_long_value; + unsigned long long ulong_long_value; + int128_t int128_value; + uint128_t uint128_value; + bool bool_value; + char_type char_value; + float float_value; + double double_value; + long double long_double_value; + const void* pointer; + string_value string; + custom_value custom; + named_arg_value named_args; + }; + + constexpr FMT_INLINE value(int val = 0) : int_value(val) {} + constexpr FMT_INLINE value(unsigned val) : uint_value(val) {} + constexpr FMT_INLINE value(long long val) : long_long_value(val) {} + constexpr FMT_INLINE value(unsigned long long val) : ulong_long_value(val) {} + FMT_INLINE value(int128_t val) : int128_value(val) {} + FMT_INLINE value(uint128_t val) : uint128_value(val) {} + FMT_INLINE value(float val) : float_value(val) {} + FMT_INLINE value(double val) : double_value(val) {} + FMT_INLINE value(long double val) : long_double_value(val) {} + constexpr FMT_INLINE value(bool val) : bool_value(val) {} + constexpr FMT_INLINE value(char_type val) : char_value(val) {} + FMT_CONSTEXPR FMT_INLINE value(const char_type* val) { + string.data = val; + if (is_constant_evaluated()) string.size = {}; + } + FMT_CONSTEXPR FMT_INLINE value(basic_string_view val) { + string.data = val.data(); + string.size = val.size(); + } + FMT_INLINE value(const void* val) : pointer(val) {} + FMT_INLINE value(const named_arg_info* args, size_t size) + : named_args{args, size} {} + + template FMT_INLINE value(const T& val) { + custom.value = &val; + // Get the formatter type through the context to allow different contexts + // have different extension points, e.g. `formatter` for `format` and + // `printf_formatter` for `printf`. + custom.format = format_custom_arg< + T, conditional_t::value, + typename Context::template formatter_type, + fallback_formatter>>; + } + + private: + // Formats an argument of a custom type, such as a user-defined class. + template + static void format_custom_arg(const void* arg, + typename Context::parse_context_type& parse_ctx, + Context& ctx) { + Formatter f; + parse_ctx.advance_to(f.parse(parse_ctx)); + ctx.advance_to(f.format(*static_cast(arg), ctx)); + } + }; + + template + FMT_CONSTEXPR basic_format_arg make_arg(const T& value); + +// To minimize the number of types we need to deal with, long is translated +// either to int or to long long depending on its size. + enum { long_short = sizeof(long) == sizeof(int) }; + using long_type = conditional_t; + using ulong_type = conditional_t; + + struct unformattable {}; + +// Maps formatting arguments to core types. + template struct arg_mapper { + using char_type = typename Context::char_type; + + FMT_CONSTEXPR FMT_INLINE int map(signed char val) { return val; } + FMT_CONSTEXPR FMT_INLINE unsigned map(unsigned char val) { return val; } + FMT_CONSTEXPR FMT_INLINE int map(short val) { return val; } + FMT_CONSTEXPR FMT_INLINE unsigned map(unsigned short val) { return val; } + FMT_CONSTEXPR FMT_INLINE int map(int val) { return val; } + FMT_CONSTEXPR FMT_INLINE unsigned map(unsigned val) { return val; } + FMT_CONSTEXPR FMT_INLINE long_type map(long val) { return val; } + FMT_CONSTEXPR FMT_INLINE ulong_type map(unsigned long val) { return val; } + FMT_CONSTEXPR FMT_INLINE long long map(long long val) { return val; } + FMT_CONSTEXPR FMT_INLINE unsigned long long map(unsigned long long val) { + return val; + } + FMT_CONSTEXPR FMT_INLINE int128_t map(int128_t val) { return val; } + FMT_CONSTEXPR FMT_INLINE uint128_t map(uint128_t val) { return val; } + FMT_CONSTEXPR FMT_INLINE bool map(bool val) { return val; } + + template ::value)> + FMT_CONSTEXPR FMT_INLINE char_type map(T val) { + static_assert( + std::is_same::value || std::is_same::value, + "mixing character types is disallowed"); + return val; + } + + FMT_CONSTEXPR FMT_INLINE float map(float val) { return val; } + FMT_CONSTEXPR FMT_INLINE double map(double val) { return val; } + FMT_CONSTEXPR FMT_INLINE long double map(long double val) { return val; } + + FMT_CONSTEXPR FMT_INLINE const char_type* map(char_type* val) { return val; } + FMT_CONSTEXPR FMT_INLINE const char_type* map(const char_type* val) { + return val; + } + template ::value)> + FMT_CONSTEXPR FMT_INLINE basic_string_view map(const T& val) { + static_assert(std::is_same>::value, + "mixing character types is disallowed"); + return to_string_view(val); + } + template , T>::value && + !is_string::value && !has_formatter::value && + !has_fallback_formatter::value)> + FMT_CONSTEXPR FMT_INLINE basic_string_view map(const T& val) { + return basic_string_view(val); + } + template < + typename T, + FMT_ENABLE_IF( + std::is_constructible, T>::value && + !std::is_constructible, T>::value && + !is_string::value && !has_formatter::value && + !has_fallback_formatter::value)> + FMT_CONSTEXPR FMT_INLINE basic_string_view map(const T& val) { + return std_string_view(val); + } + FMT_CONSTEXPR FMT_INLINE const char* map(const signed char* val) { + static_assert(std::is_same::value, "invalid string type"); + return reinterpret_cast(val); + } + FMT_CONSTEXPR FMT_INLINE const char* map(const unsigned char* val) { + static_assert(std::is_same::value, "invalid string type"); + return reinterpret_cast(val); + } + FMT_CONSTEXPR FMT_INLINE const char* map(signed char* val) { + const auto* const_val = val; + return map(const_val); + } + FMT_CONSTEXPR FMT_INLINE const char* map(unsigned char* val) { + const auto* const_val = val; + return map(const_val); + } + + FMT_CONSTEXPR FMT_INLINE const void* map(void* val) { return val; } + FMT_CONSTEXPR FMT_INLINE const void* map(const void* val) { return val; } + FMT_CONSTEXPR FMT_INLINE const void* map(std::nullptr_t val) { return val; } + + // We use SFINAE instead of a const T* parameter to avoid conflicting with + // the C array overload. + template + FMT_CONSTEXPR auto map(T) -> enable_if_t::value, int> { + // Formatting of arbitrary pointers is disallowed. If you want to output + // a pointer cast it to "void *" or "const void *". In particular, this + // forbids formatting of "[const] volatile char *" which is printed as bool + // by iostreams. + static_assert(!sizeof(T), "formatting of non-void pointers is disallowed"); + return 0; + } + + template + FMT_CONSTEXPR FMT_INLINE auto map(const T (&values)[N]) -> const T (&)[N] { + return values; + } + + template ::value && + !has_formatter::value && + !has_fallback_formatter::value)> + FMT_CONSTEXPR FMT_INLINE auto map(const T& val) + -> decltype(std::declval().map( + static_cast::type>(val))) { + return map(static_cast::type>(val)); + } + template ::value && !is_char::value && + (has_formatter::value || + has_fallback_formatter::value))> + FMT_CONSTEXPR FMT_INLINE const T& map(const T& val) { + return val; + } + + template ::value)> + FMT_CONSTEXPR FMT_INLINE auto map(const T& named_arg) + -> decltype(std::declval().map(named_arg.value)) { + return map(named_arg.value); + } + + unformattable map(...) { return {}; } + }; + +// A type constant after applying arg_mapper. + template + using mapped_type_constant = + type_constant().map(std::declval())), + typename Context::char_type>; + + enum { packed_arg_bits = 4 }; +// Maximum number of arguments with packed types. + enum { max_packed_args = 62 / packed_arg_bits }; + enum : unsigned long long { is_unpacked_bit = 1ULL << 63 }; + enum : unsigned long long { has_named_args_bit = 1ULL << 62 }; + + FMT_END_DETAIL_NAMESPACE + +// A formatting argument. It is a trivially copyable/constructible type to +// allow storage in basic_memory_buffer. + template class basic_format_arg { + private: + detail::value value_; + detail::type type_; + + template + friend FMT_CONSTEXPR basic_format_arg detail::make_arg( + const T& value); + + template + friend FMT_CONSTEXPR auto visit_format_arg(Visitor&& vis, + const basic_format_arg& arg) + -> decltype(vis(0)); + + friend class basic_format_args; + friend class dynamic_format_arg_store; + + using char_type = typename Context::char_type; + + template + friend struct detail::arg_data; + + basic_format_arg(const detail::named_arg_info* args, size_t size) + : value_(args, size) {} + + public: + class handle { + public: + explicit handle(detail::custom_value custom) : custom_(custom) {} + + void format(typename Context::parse_context_type& parse_ctx, + Context& ctx) const { + custom_.format(custom_.value, parse_ctx, ctx); + } + + private: + detail::custom_value custom_; + }; + + constexpr basic_format_arg() : type_(detail::type::none_type) {} + + constexpr explicit operator bool() const FMT_NOEXCEPT { + return type_ != detail::type::none_type; + } + + detail::type type() const { return type_; } + + bool is_integral() const { return detail::is_integral_type(type_); } + bool is_arithmetic() const { return detail::is_arithmetic_type(type_); } + }; + +/** + \rst + Visits an argument dispatching to the appropriate visit method based on + the argument type. For example, if the argument type is ``double`` then + ``vis(value)`` will be called with the value of type ``double``. + \endrst + */ + template + FMT_CONSTEXPR_DECL FMT_INLINE auto visit_format_arg( + Visitor&& vis, const basic_format_arg& arg) -> decltype(vis(0)) { + using char_type = typename Context::char_type; + switch (arg.type_) { + case detail::type::none_type: + break; + case detail::type::int_type: + return vis(arg.value_.int_value); + case detail::type::uint_type: + return vis(arg.value_.uint_value); + case detail::type::long_long_type: + return vis(arg.value_.long_long_value); + case detail::type::ulong_long_type: + return vis(arg.value_.ulong_long_value); +#if FMT_USE_INT128 + case detail::type::int128_type: + return vis(arg.value_.int128_value); + case detail::type::uint128_type: + return vis(arg.value_.uint128_value); +#else + case detail::type::int128_type: + case detail::type::uint128_type: + break; +#endif + case detail::type::bool_type: + return vis(arg.value_.bool_value); + case detail::type::char_type: + return vis(arg.value_.char_value); + case detail::type::float_type: + return vis(arg.value_.float_value); + case detail::type::double_type: + return vis(arg.value_.double_value); + case detail::type::long_double_type: + return vis(arg.value_.long_double_value); + case detail::type::cstring_type: + return vis(arg.value_.string.data); + case detail::type::string_type: + return vis(basic_string_view(arg.value_.string.data, + arg.value_.string.size)); + case detail::type::pointer_type: + return vis(arg.value_.pointer); + case detail::type::custom_type: + return vis(typename basic_format_arg::handle(arg.value_.custom)); + } + return vis(monostate()); + } + + FMT_BEGIN_DETAIL_NAMESPACE + +#if FMT_GCC_VERSION && FMT_GCC_VERSION < 500 + // A workaround for gcc 4.8 to make void_t work in a SFINAE context. +template struct void_t_impl { using type = void; }; +template +using void_t = typename detail::void_t_impl::type; +#else + template using void_t = void; +#endif + + template + struct is_output_iterator : std::false_type {}; + + template + struct is_output_iterator< + It, T, + void_t::iterator_category, + decltype(*std::declval() = std::declval())>> + : std::true_type {}; + + template + struct is_back_insert_iterator : std::false_type {}; + template + struct is_back_insert_iterator> + : std::true_type {}; + + template + struct is_contiguous_back_insert_iterator : std::false_type {}; + template + struct is_contiguous_back_insert_iterator> + : is_contiguous {}; + template + struct is_contiguous_back_insert_iterator> + : std::true_type {}; + +// A type-erased reference to an std::locale to avoid heavy include. + class locale_ref { + private: + const void* locale_; // A type-erased pointer to std::locale. + + public: + constexpr locale_ref() : locale_(nullptr) {} + template explicit locale_ref(const Locale& loc); + + explicit operator bool() const FMT_NOEXCEPT { return locale_ != nullptr; } + + template Locale get() const; + }; + + template constexpr unsigned long long encode_types() { return 0; } + + template + constexpr unsigned long long encode_types() { + return static_cast(mapped_type_constant::value) | + (encode_types() << packed_arg_bits); + } + + template + FMT_CONSTEXPR basic_format_arg make_arg(const T& value) { + basic_format_arg arg; + arg.type_ = mapped_type_constant::value; + arg.value_ = arg_mapper().map(value); + return arg; + } + +// The type template parameter is there to avoid an ODR violation when using +// a fallback formatter in one translation unit and an implicit conversion in +// another (not recommended). + template + FMT_CONSTEXPR FMT_INLINE value make_arg(const T& val) { + const auto& arg = arg_mapper().map(val); + static_assert( + !std::is_same::value, + "Cannot format an argument. To make type T formattable provide a " + "formatter specialization: https://fmt.dev/latest/api.html#udt"); + return arg; + } + + template + inline basic_format_arg make_arg(const T& value) { + return make_arg(value); + } + + FMT_END_DETAIL_NAMESPACE + +// Formatting context. + template class basic_format_context { + public: + /** The character type for the output. */ + using char_type = Char; + + private: + OutputIt out_; + basic_format_args args_; + detail::locale_ref loc_; + + public: + using iterator = OutputIt; + using format_arg = basic_format_arg; + using parse_context_type = basic_format_parse_context; + template using formatter_type = formatter; + + basic_format_context(basic_format_context&&) = default; + basic_format_context(const basic_format_context&) = delete; + void operator=(const basic_format_context&) = delete; + /** + Constructs a ``basic_format_context`` object. References to the arguments are + stored in the object so make sure they have appropriate lifetimes. + */ + constexpr basic_format_context( + OutputIt out, basic_format_args ctx_args, + detail::locale_ref loc = detail::locale_ref()) + : out_(out), args_(ctx_args), loc_(loc) {} + + constexpr format_arg arg(int id) const { return args_.get(id); } + FMT_CONSTEXPR format_arg arg(basic_string_view name) { + return args_.get(name); + } + int arg_id(basic_string_view name) { return args_.get_id(name); } + const basic_format_args& args() const { return args_; } + + FMT_CONSTEXPR detail::error_handler error_handler() { return {}; } + void on_error(const char* message) { error_handler().on_error(message); } + + // Returns an iterator to the beginning of the output range. + FMT_CONSTEXPR iterator out() { return out_; } + + // Advances the begin iterator to ``it``. + void advance_to(iterator it) { + if (!detail::is_back_insert_iterator()) out_ = it; + } + + FMT_CONSTEXPR detail::locale_ref locale() { return loc_; } + }; + + template + using buffer_context = + basic_format_context, Char>; + using format_context = buffer_context; + using wformat_context = buffer_context; + +// Workaround an alias issue: https://stackoverflow.com/q/62767544/471164. +#define FMT_BUFFER_CONTEXT(Char) \ + basic_format_context, Char> + + template + using is_formattable = bool_constant< + !std::is_same>().map( + std::declval())), + detail::unformattable>::value && + !detail::has_fallback_formatter::value>; + +/** + \rst + An array of references to arguments. It can be implicitly converted into + `~fmt::basic_format_args` for passing into type-erased formatting functions + such as `~fmt::vformat`. + \endrst + */ + template + class format_arg_store +#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 + // Workaround a GCC template argument substitution bug. + : public basic_format_args +#endif + { + private: + static const size_t num_args = sizeof...(Args); + static const size_t num_named_args = detail::count_named_args(); + static const bool is_packed = num_args <= detail::max_packed_args; + + using value_type = conditional_t, + basic_format_arg>; + + detail::arg_data + data_; + + friend class basic_format_args; + + static constexpr unsigned long long desc = + (is_packed ? detail::encode_types() + : detail::is_unpacked_bit | num_args) | + (num_named_args != 0 + ? static_cast(detail::has_named_args_bit) + : 0); + + public: + FMT_CONSTEXPR FMT_INLINE format_arg_store(const Args&... args) + : +#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 + basic_format_args(*this), +#endif + data_{detail::make_arg< + is_packed, Context, + detail::mapped_type_constant::value>(args)...} { + detail::init_named_args(data_.named_args(), 0, 0, args...); + } + }; + +/** + \rst + Constructs a `~fmt::format_arg_store` object that contains references to + arguments and can be implicitly converted to `~fmt::format_args`. `Context` + can be omitted in which case it defaults to `~fmt::context`. + See `~fmt::arg` for lifetime considerations. + \endrst + */ + template + constexpr format_arg_store make_format_args( + const Args&... args) { + return {args...}; + } + +/** + \rst + Constructs a `~fmt::format_arg_store` object that contains references + to arguments and can be implicitly converted to `~fmt::format_args`. + If ``format_str`` is a compile-time string then `make_args_checked` checks + its validity at compile time. + \endrst + */ + template > + FMT_INLINE auto make_args_checked(const S& format_str, + const remove_reference_t&... args) + -> format_arg_store, remove_reference_t...> { + static_assert( + detail::count<( + std::is_base_of>::value && + std::is_reference::value)...>() == 0, + "passing views as lvalues is disallowed"); + detail::check_format_string(format_str); + return {args...}; + } + +/** + \rst + Returns a named argument to be used in a formatting function. + It should only be used in a call to a formatting function or + `dynamic_format_arg_store::push_back`. + + **Example**:: + + fmt::print("Elapsed time: {s:.2f} seconds", fmt::arg("s", 1.23)); + \endrst + */ + template + inline detail::named_arg arg(const Char* name, const T& arg) { + static_assert(!detail::is_named_arg(), "nested named arguments"); + return {name, arg}; + } + +/** + \rst + A view of a collection of formatting arguments. To avoid lifetime issues it + should only be used as a parameter type in type-erased functions such as + ``vformat``:: + + void vlog(string_view format_str, format_args args); // OK + format_args args = make_format_args(42); // Error: dangling reference + \endrst + */ + template class basic_format_args { + public: + using size_type = int; + using format_arg = basic_format_arg; + + private: + // A descriptor that contains information about formatting arguments. + // If the number of arguments is less or equal to max_packed_args then + // argument types are passed in the descriptor. This reduces binary code size + // per formatting function call. + unsigned long long desc_; + union { + // If is_packed() returns true then argument values are stored in values_; + // otherwise they are stored in args_. This is done to improve cache + // locality and reduce compiled code size since storing larger objects + // may require more code (at least on x86-64) even if the same amount of + // data is actually copied to stack. It saves ~10% on the bloat test. + const detail::value* values_; + const format_arg* args_; + }; + + constexpr bool is_packed() const { + return (desc_ & detail::is_unpacked_bit) == 0; + } + bool has_named_args() const { + return (desc_ & detail::has_named_args_bit) != 0; + } + + FMT_CONSTEXPR detail::type type(int index) const { + int shift = index * detail::packed_arg_bits; + unsigned int mask = (1 << detail::packed_arg_bits) - 1; + return static_cast((desc_ >> shift) & mask); + } + + constexpr FMT_INLINE basic_format_args(unsigned long long desc, + const detail::value* values) + : desc_(desc), values_(values) {} + constexpr basic_format_args(unsigned long long desc, const format_arg* args) + : desc_(desc), args_(args) {} + + public: + constexpr basic_format_args() : desc_(0), args_(nullptr) {} + + /** + \rst + Constructs a `basic_format_args` object from `~fmt::format_arg_store`. + \endrst + */ + template + constexpr FMT_INLINE basic_format_args( + const format_arg_store& store) + : basic_format_args(format_arg_store::desc, + store.data_.args()) {} + + /** + \rst + Constructs a `basic_format_args` object from + `~fmt::dynamic_format_arg_store`. + \endrst + */ + constexpr FMT_INLINE basic_format_args( + const dynamic_format_arg_store& store) + : basic_format_args(store.get_types(), store.data()) {} + + /** + \rst + Constructs a `basic_format_args` object from a dynamic set of arguments. + \endrst + */ + constexpr basic_format_args(const format_arg* args, int count) + : basic_format_args(detail::is_unpacked_bit | detail::to_unsigned(count), + args) {} + + /** Returns the argument with the specified id. */ + FMT_CONSTEXPR format_arg get(int id) const { + format_arg arg; + if (!is_packed()) { + if (id < max_size()) arg = args_[id]; + return arg; + } + if (id >= detail::max_packed_args) return arg; + arg.type_ = type(id); + if (arg.type_ == detail::type::none_type) return arg; + arg.value_ = values_[id]; + return arg; + } + + template format_arg get(basic_string_view name) const { + int id = get_id(name); + return id >= 0 ? get(id) : format_arg(); + } + + template int get_id(basic_string_view name) const { + if (!has_named_args()) return -1; + const auto& named_args = + (is_packed() ? values_[-1] : args_[-1].value_).named_args; + for (size_t i = 0; i < named_args.size; ++i) { + if (named_args.data[i].name == name) return named_args.data[i].id; + } + return -1; + } + + int max_size() const { + unsigned long long max_packed = detail::max_packed_args; + return static_cast(is_packed() ? max_packed + : desc_ & ~detail::is_unpacked_bit); + } + }; + +/** An alias to ``basic_format_args``. */ +// Separate types would result in shorter symbols but break ABI compatibility +// between clang and gcc on ARM (#1919). + using format_args = basic_format_args; + using wformat_args = basic_format_args; + +// We cannot use enum classes as bit fields because of a gcc bug +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61414. + namespace align { + enum type { none, left, right, center, numeric }; + } + using align_t = align::type; + namespace sign { + enum type { none, minus, plus, space }; + } + using sign_t = sign::type; + + FMT_BEGIN_DETAIL_NAMESPACE + + void throw_format_error(const char* message); + +// Workaround an array initialization issue in gcc 4.8. + template struct fill_t { + private: + enum { max_size = 4 }; + Char data_[max_size] = {Char(' '), Char(0), Char(0), Char(0)}; + unsigned char size_ = 1; + + public: + FMT_CONSTEXPR void operator=(basic_string_view s) { + auto size = s.size(); + if (size > max_size) return throw_format_error("invalid fill"); + for (size_t i = 0; i < size; ++i) data_[i] = s[i]; + size_ = static_cast(size); + } + + constexpr size_t size() const { return size_; } + constexpr const Char* data() const { return data_; } + + FMT_CONSTEXPR Char& operator[](size_t index) { return data_[index]; } + FMT_CONSTEXPR const Char& operator[](size_t index) const { + return data_[index]; + } + }; + + FMT_END_DETAIL_NAMESPACE + +// Format specifiers for built-in and string types. + template struct basic_format_specs { + int width; + int precision; + char type; + align_t align : 4; + sign_t sign : 3; + bool alt : 1; // Alternate form ('#'). + bool localized : 1; + detail::fill_t fill; + + constexpr basic_format_specs() + : width(0), + precision(-1), + type(0), + align(align::none), + sign(sign::none), + alt(false), + localized(false) {} + }; + + using format_specs = basic_format_specs; + + FMT_BEGIN_DETAIL_NAMESPACE + + enum class arg_id_kind { none, index, name }; + +// An argument reference. + template struct arg_ref { + FMT_CONSTEXPR arg_ref() : kind(arg_id_kind::none), val() {} + + FMT_CONSTEXPR explicit arg_ref(int index) + : kind(arg_id_kind::index), val(index) {} + FMT_CONSTEXPR explicit arg_ref(basic_string_view name) + : kind(arg_id_kind::name), val(name) {} + + FMT_CONSTEXPR arg_ref& operator=(int idx) { + kind = arg_id_kind::index; + val.index = idx; + return *this; + } + + arg_id_kind kind; + union value { + FMT_CONSTEXPR value(int id = 0) : index{id} {} + FMT_CONSTEXPR value(basic_string_view n) : name(n) {} + + int index; + basic_string_view name; + } val; + }; + +// Format specifiers with width and precision resolved at formatting rather +// than parsing time to allow re-using the same parsed specifiers with +// different sets of arguments (precompilation of format strings). + template + struct dynamic_format_specs : basic_format_specs { + arg_ref width_ref; + arg_ref precision_ref; + }; + + struct auto_id {}; + +// A format specifier handler that sets fields in basic_format_specs. + template class specs_setter { + public: + explicit FMT_CONSTEXPR specs_setter(basic_format_specs& specs) + : specs_(specs) {} + + FMT_CONSTEXPR specs_setter(const specs_setter& other) + : specs_(other.specs_) {} + + FMT_CONSTEXPR void on_align(align_t align) { specs_.align = align; } + FMT_CONSTEXPR void on_fill(basic_string_view fill) { + specs_.fill = fill; + } + FMT_CONSTEXPR void on_plus() { specs_.sign = sign::plus; } + FMT_CONSTEXPR void on_minus() { specs_.sign = sign::minus; } + FMT_CONSTEXPR void on_space() { specs_.sign = sign::space; } + FMT_CONSTEXPR void on_hash() { specs_.alt = true; } + FMT_CONSTEXPR void on_localized() { specs_.localized = true; } + + FMT_CONSTEXPR void on_zero() { + specs_.align = align::numeric; + specs_.fill[0] = Char('0'); + } + + FMT_CONSTEXPR void on_width(int width) { specs_.width = width; } + FMT_CONSTEXPR void on_precision(int precision) { + specs_.precision = precision; + } + FMT_CONSTEXPR void end_precision() {} + + FMT_CONSTEXPR void on_type(Char type) { + specs_.type = static_cast(type); + } + + protected: + basic_format_specs& specs_; + }; + +// Format spec handler that saves references to arguments representing dynamic +// width and precision to be resolved at formatting time. + template + class dynamic_specs_handler + : public specs_setter { + public: + using char_type = typename ParseContext::char_type; + + FMT_CONSTEXPR dynamic_specs_handler(dynamic_format_specs& specs, + ParseContext& ctx) + : specs_setter(specs), specs_(specs), context_(ctx) {} + + FMT_CONSTEXPR dynamic_specs_handler(const dynamic_specs_handler& other) + : specs_setter(other), + specs_(other.specs_), + context_(other.context_) {} + + template FMT_CONSTEXPR void on_dynamic_width(Id arg_id) { + specs_.width_ref = make_arg_ref(arg_id); + } + + template FMT_CONSTEXPR void on_dynamic_precision(Id arg_id) { + specs_.precision_ref = make_arg_ref(arg_id); + } + + FMT_CONSTEXPR void on_error(const char* message) { + context_.on_error(message); + } + + private: + using arg_ref_type = arg_ref; + + FMT_CONSTEXPR arg_ref_type make_arg_ref(int arg_id) { + context_.check_arg_id(arg_id); + return arg_ref_type(arg_id); + } + + FMT_CONSTEXPR arg_ref_type make_arg_ref(auto_id) { + return arg_ref_type(context_.next_arg_id()); + } + + FMT_CONSTEXPR arg_ref_type make_arg_ref(basic_string_view arg_id) { + context_.check_arg_id(arg_id); + basic_string_view format_str( + context_.begin(), to_unsigned(context_.end() - context_.begin())); + return arg_ref_type(arg_id); + } + + dynamic_format_specs& specs_; + ParseContext& context_; + }; + + template constexpr bool is_ascii_letter(Char c) { + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); + } + +// Converts a character to ASCII. Returns a number > 127 on conversion failure. + template ::value)> + constexpr Char to_ascii(Char value) { + return value; + } + template ::value)> + constexpr typename std::underlying_type::type to_ascii(Char value) { + return value; + } + + template + FMT_CONSTEXPR int code_point_length(const Char* begin) { + if (const_check(sizeof(Char) != 1)) return 1; + constexpr char lengths[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3, 4, 0}; + int len = lengths[static_cast(*begin) >> 3]; + + // Compute the pointer to the next character early so that the next + // iteration can start working on the next character. Neither Clang + // nor GCC figure out this reordering on their own. + return len + !len; + } + +// Parses the range [begin, end) as an unsigned integer. This function assumes +// that the range is non-empty and the first character is a digit. + template + FMT_CONSTEXPR int parse_nonnegative_int(const Char*& begin, const Char* end, + ErrorHandler&& eh) { + FMT_ASSERT(begin != end && '0' <= *begin && *begin <= '9', ""); + unsigned value = 0; + // Convert to unsigned to prevent a warning. + const unsigned max_int = to_unsigned(INT_MAX); + unsigned big = max_int / 10; + do { + // Check for overflow. + if (value > big) { + value = max_int + 1; + break; + } + value = value * 10 + unsigned(*begin - '0'); + ++begin; + } while (begin != end && '0' <= *begin && *begin <= '9'); + if (value > max_int) eh.on_error("number is too big"); + return static_cast(value); + } + +// Parses fill and alignment. + template + FMT_CONSTEXPR const Char* parse_align(const Char* begin, const Char* end, + Handler&& handler) { + FMT_ASSERT(begin != end, ""); + auto align = align::none; + auto p = begin + code_point_length(begin); + if (p >= end) p = begin; + for (;;) { + switch (to_ascii(*p)) { + case '<': + align = align::left; + break; + case '>': + align = align::right; + break; + case '^': + align = align::center; + break; + default: + break; + } + if (align != align::none) { + if (p != begin) { + auto c = *begin; + if (c == '{') + return handler.on_error("invalid fill character '{'"), begin; + handler.on_fill(basic_string_view(begin, to_unsigned(p - begin))); + begin = p + 1; + } else + ++begin; + handler.on_align(align); + break; + } else if (p == begin) { + break; + } + p = begin; + } + return begin; + } + + template FMT_CONSTEXPR bool is_name_start(Char c) { + return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || '_' == c; + } + + template + FMT_CONSTEXPR const Char* do_parse_arg_id(const Char* begin, const Char* end, + IDHandler&& handler) { + FMT_ASSERT(begin != end, ""); + Char c = *begin; + if (c >= '0' && c <= '9') { + int index = 0; + if (c != '0') + index = parse_nonnegative_int(begin, end, handler); + else + ++begin; + if (begin == end || (*begin != '}' && *begin != ':')) + handler.on_error("invalid format string"); + else + handler(index); + return begin; + } + if (!is_name_start(c)) { + handler.on_error("invalid format string"); + return begin; + } + auto it = begin; + do { + ++it; + } while (it != end && (is_name_start(c = *it) || ('0' <= c && c <= '9'))); + handler(basic_string_view(begin, to_unsigned(it - begin))); + return it; + } + + template + FMT_CONSTEXPR_DECL FMT_INLINE const Char* parse_arg_id(const Char* begin, + const Char* end, + IDHandler&& handler) { + Char c = *begin; + if (c != '}' && c != ':') return do_parse_arg_id(begin, end, handler); + handler(); + return begin; + } + +// Adapts SpecHandler to IDHandler API for dynamic width. + template struct width_adapter { + explicit FMT_CONSTEXPR width_adapter(SpecHandler& h) : handler(h) {} + + FMT_CONSTEXPR void operator()() { handler.on_dynamic_width(auto_id()); } + FMT_CONSTEXPR void operator()(int id) { handler.on_dynamic_width(id); } + FMT_CONSTEXPR void operator()(basic_string_view id) { + handler.on_dynamic_width(id); + } + + FMT_CONSTEXPR void on_error(const char* message) { + handler.on_error(message); + } + + SpecHandler& handler; + }; + + template + FMT_CONSTEXPR const Char* parse_width(const Char* begin, const Char* end, + Handler&& handler) { + FMT_ASSERT(begin != end, ""); + if ('0' <= *begin && *begin <= '9') { + handler.on_width(parse_nonnegative_int(begin, end, handler)); + } else if (*begin == '{') { + ++begin; + if (begin != end) + begin = parse_arg_id(begin, end, width_adapter(handler)); + if (begin == end || *begin != '}') + return handler.on_error("invalid format string"), begin; + ++begin; + } + return begin; + } + +// Adapts SpecHandler to IDHandler API for dynamic precision. + template struct precision_adapter { + explicit FMT_CONSTEXPR precision_adapter(SpecHandler& h) : handler(h) {} + + FMT_CONSTEXPR void operator()() { handler.on_dynamic_precision(auto_id()); } + FMT_CONSTEXPR void operator()(int id) { handler.on_dynamic_precision(id); } + FMT_CONSTEXPR void operator()(basic_string_view id) { + handler.on_dynamic_precision(id); + } + + FMT_CONSTEXPR void on_error(const char* message) { + handler.on_error(message); + } + + SpecHandler& handler; + }; + + template + FMT_CONSTEXPR const Char* parse_precision(const Char* begin, const Char* end, + Handler&& handler) { + ++begin; + auto c = begin != end ? *begin : Char(); + if ('0' <= c && c <= '9') { + handler.on_precision(parse_nonnegative_int(begin, end, handler)); + } else if (c == '{') { + ++begin; + if (begin != end) { + begin = + parse_arg_id(begin, end, precision_adapter(handler)); + } + if (begin == end || *begin++ != '}') + return handler.on_error("invalid format string"), begin; + } else { + return handler.on_error("missing precision specifier"), begin; + } + handler.end_precision(); + return begin; + } + +// Parses standard format specifiers and sends notifications about parsed +// components to handler. + template + FMT_CONSTEXPR_DECL FMT_INLINE const Char* parse_format_specs( + const Char* begin, const Char* end, SpecHandler&& handler) { + if (begin + 1 < end && begin[1] == '}' && is_ascii_letter(*begin) && + *begin != 'L') { + handler.on_type(*begin++); + return begin; + } + + if (begin == end) return begin; + + begin = parse_align(begin, end, handler); + if (begin == end) return begin; + + // Parse sign. + switch (to_ascii(*begin)) { + case '+': + handler.on_plus(); + ++begin; + break; + case '-': + handler.on_minus(); + ++begin; + break; + case ' ': + handler.on_space(); + ++begin; + break; + default: + break; + } + if (begin == end) return begin; + + if (*begin == '#') { + handler.on_hash(); + if (++begin == end) return begin; + } + + // Parse zero flag. + if (*begin == '0') { + handler.on_zero(); + if (++begin == end) return begin; + } + + begin = parse_width(begin, end, handler); + if (begin == end) return begin; + + // Parse precision. + if (*begin == '.') { + begin = parse_precision(begin, end, handler); + if (begin == end) return begin; + } + + if (*begin == 'L') { + handler.on_localized(); + ++begin; + } + + // Parse type. + if (begin != end && *begin != '}') handler.on_type(*begin++); + return begin; + } + +// Return the result via the out param to workaround gcc bug 77539. + template + FMT_CONSTEXPR bool find(Ptr first, Ptr last, T value, Ptr& out) { + for (out = first; out != last; ++out) { + if (*out == value) return true; + } + return false; + } + + template <> + inline bool find(const char* first, const char* last, char value, + const char*& out) { + out = static_cast( + std::memchr(first, value, to_unsigned(last - first))); + return out != nullptr; + } + + template struct id_adapter { + Handler& handler; + int arg_id; + + FMT_CONSTEXPR void operator()() { arg_id = handler.on_arg_id(); } + FMT_CONSTEXPR void operator()(int id) { arg_id = handler.on_arg_id(id); } + FMT_CONSTEXPR void operator()(basic_string_view id) { + arg_id = handler.on_arg_id(id); + } + FMT_CONSTEXPR void on_error(const char* message) { + handler.on_error(message); + } + }; + + template + FMT_CONSTEXPR const Char* parse_replacement_field(const Char* begin, + const Char* end, + Handler&& handler) { + ++begin; + if (begin == end) return handler.on_error("invalid format string"), end; + if (*begin == '}') { + handler.on_replacement_field(handler.on_arg_id(), begin); + } else if (*begin == '{') { + handler.on_text(begin, begin + 1); + } else { + auto adapter = id_adapter{handler, 0}; + begin = parse_arg_id(begin, end, adapter); + Char c = begin != end ? *begin : Char(); + if (c == '}') { + handler.on_replacement_field(adapter.arg_id, begin); + } else if (c == ':') { + begin = handler.on_format_specs(adapter.arg_id, begin + 1, end); + if (begin == end || *begin != '}') + return handler.on_error("unknown format specifier"), end; + } else { + return handler.on_error("missing '}' in format string"), end; + } + } + return begin + 1; + } + + template + FMT_CONSTEXPR_DECL FMT_INLINE void parse_format_string( + basic_string_view format_str, Handler&& handler) { + // this is most likely a name-lookup defect in msvc's modules implementation + using detail::find; + + auto begin = format_str.data(); + auto end = begin + format_str.size(); + if (end - begin < 32) { + // Use a simple loop instead of memchr for small strings. + const Char* p = begin; + while (p != end) { + auto c = *p++; + if (c == '{') { + handler.on_text(begin, p - 1); + begin = p = parse_replacement_field(p - 1, end, handler); + } else if (c == '}') { + if (p == end || *p != '}') + return handler.on_error("unmatched '}' in format string"); + handler.on_text(begin, p); + begin = ++p; + } + } + handler.on_text(begin, end); + return; + } + struct writer { + FMT_CONSTEXPR void operator()(const Char* pbegin, const Char* pend) { + if (pbegin == pend) return; + for (;;) { + const Char* p = nullptr; + if (!find(pbegin, pend, '}', p)) + return handler_.on_text(pbegin, pend); + ++p; + if (p == pend || *p != '}') + return handler_.on_error("unmatched '}' in format string"); + handler_.on_text(pbegin, p); + pbegin = p + 1; + } + } + Handler& handler_; + } write{handler}; + while (begin != end) { + // Doing two passes with memchr (one for '{' and another for '}') is up to + // 2.5x faster than the naive one-pass implementation on big format strings. + const Char* p = begin; + if (*begin != '{' && !find(begin + 1, end, '{', p)) + return write(begin, end); + write(begin, p); + begin = parse_replacement_field(p, end, handler); + } + } + + template + FMT_CONSTEXPR const typename ParseContext::char_type* parse_format_specs( + ParseContext& ctx) { + using char_type = typename ParseContext::char_type; + using context = buffer_context; + using mapped_type = conditional_t< + mapped_type_constant::value != type::custom_type, + decltype(arg_mapper().map(std::declval())), T>; + auto f = conditional_t::value, + formatter, + fallback_formatter>(); + return f.parse(ctx); + } + +// A parse context with extra argument id checks. It is only used at compile +// time because adding checks at runtime would introduce substantial overhead +// and would be redundant since argument ids are checked when arguments are +// retrieved anyway. + template + class compile_parse_context + : public basic_format_parse_context { + private: + int num_args_; + using base = basic_format_parse_context; + + public: + explicit FMT_CONSTEXPR compile_parse_context( + basic_string_view format_str, int num_args = INT_MAX, + ErrorHandler eh = {}) + : base(format_str, eh), num_args_(num_args) {} + + FMT_CONSTEXPR int next_arg_id() { + int id = base::next_arg_id(); + if (id >= num_args_) this->on_error("argument not found"); + return id; + } + + FMT_CONSTEXPR void check_arg_id(int id) { + base::check_arg_id(id); + if (id >= num_args_) this->on_error("argument not found"); + } + using base::check_arg_id; + }; + + constexpr int invalid_arg_index = -1; + +#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS + template +constexpr int get_arg_index_by_name(basic_string_view name) { + if constexpr (detail::is_statically_named_arg()) { + if (name == T::name) return N; + } + if constexpr (sizeof...(Args) > 0) + return get_arg_index_by_name(name); + return invalid_arg_index; +} +#endif + + template + FMT_CONSTEXPR int get_arg_index_by_name(basic_string_view name) { +#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS + if constexpr (sizeof...(Args) > 0) + return get_arg_index_by_name<0, Args...>(name); +#endif + (void)name; + return invalid_arg_index; + } + + template + class format_string_checker { + public: + explicit FMT_CONSTEXPR format_string_checker( + basic_string_view format_str, ErrorHandler eh) + : context_(format_str, num_args, eh), + parse_funcs_{&parse_format_specs...} {} + + FMT_CONSTEXPR void on_text(const Char*, const Char*) {} + + FMT_CONSTEXPR int on_arg_id() { return context_.next_arg_id(); } + FMT_CONSTEXPR int on_arg_id(int id) { return context_.check_arg_id(id), id; } + FMT_CONSTEXPR int on_arg_id(basic_string_view id) { +#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS + auto index = get_arg_index_by_name(id); + if (index == invalid_arg_index) on_error("named argument is not found"); + return context_.check_arg_id(index), index; +#else + (void)id; + on_error("compile-time checks for named arguments require C++20 support"); + return 0; +#endif + } + + FMT_CONSTEXPR void on_replacement_field(int, const Char*) {} + + FMT_CONSTEXPR const Char* on_format_specs(int id, const Char* begin, + const Char*) { + advance_to(context_, begin); + // id >= 0 check is a workaround for gcc 10 bug (#2065). + return id >= 0 && id < num_args ? parse_funcs_[id](context_) : begin; + } + + FMT_CONSTEXPR void on_error(const char* message) { + context_.on_error(message); + } + + private: + using parse_context_type = compile_parse_context; + enum { num_args = sizeof...(Args) }; + + // Format specifier parsing function. + using parse_func = const Char* (*)(parse_context_type&); + + parse_context_type context_; + parse_func parse_funcs_[num_args > 0 ? num_args : 1]; + }; + + template ::value), int>> + void check_format_string(S format_str) { + FMT_CONSTEXPR_DECL auto s = to_string_view(format_str); + using checker = format_string_checker...>; + FMT_CONSTEXPR_DECL bool invalid_format = + (parse_format_string(s, checker(s, {})), true); + (void)invalid_format; + } + +// Converts string literals to basic_string_view. + template + FMT_CONSTEXPR basic_string_view compile_string_to_view( + const Char (&s)[N]) { + // Remove trailing null character if needed. Won't be present if this is used + // with raw character array (i.e. not defined as a string). + return {s, + N - ((std::char_traits::to_int_type(s[N - 1]) == 0) ? 1 : 0)}; + } + +// Converts string_view to basic_string_view. + template + FMT_CONSTEXPR basic_string_view compile_string_to_view( + const std_string_view& s) { + return {s.data(), s.size()}; + } + +#define FMT_STRING_IMPL(s, base) \ + [] { \ + /* Use the hidden visibility as a workaround for a GCC bug (#1973). */ \ + /* Use a macro-like name to avoid shadowing warnings. */ \ + struct FMT_GCC_VISIBILITY_HIDDEN FMT_COMPILE_STRING : base { \ + using char_type = fmt::remove_cvref_t; \ + FMT_MAYBE_UNUSED FMT_CONSTEXPR \ + operator fmt::basic_string_view() const { \ + return fmt::detail::compile_string_to_view(s); \ + } \ + }; \ + return FMT_COMPILE_STRING(); \ + }() + +/** + \rst + Constructs a compile-time format string from a string literal *s*. + + **Example**:: + + // A compile-time error because 'd' is an invalid specifier for strings. + std::string s = fmt::format(FMT_STRING("{:d}"), "foo"); + \endrst + */ +#define FMT_STRING(s) FMT_STRING_IMPL(s, fmt::compile_string) + + template ::value)> + std::basic_string vformat( + basic_string_view format_str, + basic_format_args>> args); + + FMT_API std::string vformat(string_view format_str, format_args args); + + template + void vformat_to( + buffer& buf, basic_string_view format_str, + basic_format_args)> args, + detail::locale_ref loc = {}); + + template ::value)> + inline void vprint_mojibake(std::FILE*, basic_string_view, const Args&) {} + + FMT_API void vprint_mojibake(std::FILE*, string_view, format_args); +#ifndef _WIN32 + inline void vprint_mojibake(std::FILE*, string_view, format_args) {} +#endif + + FMT_END_DETAIL_NAMESPACE + +/** Formats a string and writes the output to ``out``. */ +// GCC 8 and earlier cannot handle std::back_insert_iterator with +// vformat_to(...) overload, so SFINAE on iterator type instead. + template , + bool enable = detail::is_output_iterator::value> + auto vformat_to(OutputIt out, const S& format_str, + basic_format_args>> args) + -> typename std::enable_if::type { + decltype(detail::get_buffer(out)) buf(detail::get_buffer_init(out)); + detail::vformat_to(buf, to_string_view(format_str), args); + return detail::get_iterator(buf); + } + +/** + \rst + Formats arguments, writes the result to the output iterator ``out`` and returns + the iterator past the end of the output range. + + **Example**:: + + std::vector out; + fmt::format_to(std::back_inserter(out), "{}", 42); + \endrst + */ +// We cannot use FMT_ENABLE_IF because of a bug in gcc 8.3. + template >::value> + inline auto format_to(OutputIt out, const S& format_str, Args&&... args) -> + typename std::enable_if::type { + const auto& vargs = fmt::make_args_checked(format_str, args...); + return vformat_to(out, to_string_view(format_str), vargs); + } + + template struct format_to_n_result { + /** Iterator past the end of the output range. */ + OutputIt out; + /** Total (not truncated) output size. */ + size_t size; + }; + + template ::value)> + inline format_to_n_result vformat_to_n( + OutputIt out, size_t n, basic_string_view format_str, + basic_format_args>> args) { + detail::iterator_buffer buf(out, + n); + detail::vformat_to(buf, format_str, args); + return {buf.out(), buf.count()}; + } + +/** + \rst + Formats arguments, writes up to ``n`` characters of the result to the output + iterator ``out`` and returns the total output size and the iterator past the + end of the output range. + \endrst + */ + template >::value> + inline auto format_to_n(OutputIt out, size_t n, const S& format_str, + const Args&... args) -> + typename std::enable_if>::type { + const auto& vargs = fmt::make_args_checked(format_str, args...); + return vformat_to_n(out, n, to_string_view(format_str), vargs); + } + +/** + Returns the number of characters in the output of + ``format(format_str, args...)``. + */ + template > + inline size_t formatted_size(const S& format_str, Args&&... args) { + const auto& vargs = fmt::make_args_checked(format_str, args...); + detail::counting_buffer<> buf; + detail::vformat_to(buf, to_string_view(format_str), vargs); + return buf.count(); + } + + template > + FMT_INLINE std::basic_string vformat( + const S& format_str, + basic_format_args>> args) { + return detail::vformat(to_string_view(format_str), args); + } + +/** + \rst + Formats arguments and returns the result as a string. + + **Example**:: + + #include + std::string message = fmt::format("The answer is {}", 42); + \endrst +*/ +// Pass char_t as a default template parameter instead of using +// std::basic_string> to reduce the symbol size. + template , + FMT_ENABLE_IF(!FMT_COMPILE_TIME_CHECKS || + !std::is_same::value)> + FMT_INLINE std::basic_string format(const S& format_str, Args&&... args) { + const auto& vargs = fmt::make_args_checked(format_str, args...); + return detail::vformat(to_string_view(format_str), vargs); + } + + FMT_API void vprint(string_view, format_args); + FMT_API void vprint(std::FILE*, string_view, format_args); + +/** + \rst + Formats ``args`` according to specifications in ``format_str`` and writes the + output to the file ``f``. Strings are assumed to be Unicode-encoded unless the + ``FMT_UNICODE`` macro is set to 0. + + **Example**:: + + fmt::print(stderr, "Don't {}!", "panic"); + \endrst + */ + template > + inline void print(std::FILE* f, const S& format_str, Args&&... args) { + const auto& vargs = fmt::make_args_checked(format_str, args...); + return detail::is_unicode() + ? vprint(f, to_string_view(format_str), vargs) + : detail::vprint_mojibake(f, to_string_view(format_str), vargs); + } + +/** + \rst + Formats ``args`` according to specifications in ``format_str`` and writes + the output to ``stdout``. Strings are assumed to be Unicode-encoded unless + the ``FMT_UNICODE`` macro is set to 0. + + **Example**:: + + fmt::print("Elapsed time: {0:.2f} seconds", 1.23); + \endrst + */ + template > + inline void print(const S& format_str, Args&&... args) { + const auto& vargs = fmt::make_args_checked(format_str, args...); + return detail::is_unicode() + ? vprint(to_string_view(format_str), vargs) + : detail::vprint_mojibake(stdout, to_string_view(format_str), + vargs); + } + + FMT_MODULE_EXPORT_END + FMT_GCC_PRAGMA("GCC pop_options") +FMT_END_NAMESPACE + +#ifdef FMT_HEADER_ONLY +# include "format.h" +#endif +#endif // FMT_CORE_H_ diff --git a/include/Third_Lib/muduo/base/AsyncLogging.cc b/include/Third_Lib/muduo/base/AsyncLogging.cc new file mode 100644 index 0000000..0f82444 --- /dev/null +++ b/include/Third_Lib/muduo/base/AsyncLogging.cc @@ -0,0 +1,136 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/base/AsyncLogging.h" +#include "muduo/base/LogFile.h" +#include "muduo/base/Timestamp.h" + +#include + +using namespace muduo; + +AsyncLogging::AsyncLogging(const string& basename, + off_t rollSize, + int flushInterval) + : flushInterval_(flushInterval), + running_(false), + basename_(basename), + rollSize_(rollSize), + thread_(std::bind(&AsyncLogging::threadFunc, this), "Logging"), + latch_(1), + mutex_(), + cond_(mutex_), + currentBuffer_(new Buffer), + nextBuffer_(new Buffer), + buffers_() +{ + currentBuffer_->bzero(); + nextBuffer_->bzero(); + buffers_.reserve(16); +} + +void AsyncLogging::append(const char* logline, int len) +{ + muduo::MutexLockGuard lock(mutex_); + if (currentBuffer_->avail() > len) + { + currentBuffer_->append(logline, len); + } + else + { + buffers_.push_back(std::move(currentBuffer_)); + + if (nextBuffer_) + { + currentBuffer_ = std::move(nextBuffer_); + } + else + { + currentBuffer_.reset(new Buffer); // Rarely happens + } + currentBuffer_->append(logline, len); + cond_.notify(); + } +} + +void AsyncLogging::threadFunc() +{ + assert(running_ == true); + latch_.countDown(); + LogFile output(basename_, rollSize_, false); + BufferPtr newBuffer1(new Buffer); + BufferPtr newBuffer2(new Buffer); + newBuffer1->bzero(); + newBuffer2->bzero(); + BufferVector buffersToWrite; + buffersToWrite.reserve(16); + while (running_) + { + assert(newBuffer1 && newBuffer1->length() == 0); + assert(newBuffer2 && newBuffer2->length() == 0); + assert(buffersToWrite.empty()); + + { + muduo::MutexLockGuard lock(mutex_); + if (buffers_.empty()) // unusual usage! + { + cond_.waitForSeconds(flushInterval_); + } + buffers_.push_back(std::move(currentBuffer_)); + currentBuffer_ = std::move(newBuffer1); + buffersToWrite.swap(buffers_); + if (!nextBuffer_) + { + nextBuffer_ = std::move(newBuffer2); + } + } + + assert(!buffersToWrite.empty()); + + if (buffersToWrite.size() > 25) + { + char buf[256]; + snprintf(buf, sizeof buf, "Dropped log messages at %s, %zd larger buffers\n", + Timestamp::now().toFormattedString().c_str(), + buffersToWrite.size()-2); + fputs(buf, stderr); + output.append(buf, static_cast(strlen(buf))); + buffersToWrite.erase(buffersToWrite.begin()+2, buffersToWrite.end()); + } + + for (const auto& buffer : buffersToWrite) + { + // FIXME: use unbuffered stdio FILE ? or use ::writev ? + output.append(buffer->data(), buffer->length()); + } + + if (buffersToWrite.size() > 2) + { + // drop non-bzero-ed buffers, avoid trashing + buffersToWrite.resize(2); + } + + if (!newBuffer1) + { + assert(!buffersToWrite.empty()); + newBuffer1 = std::move(buffersToWrite.back()); + buffersToWrite.pop_back(); + newBuffer1->reset(); + } + + if (!newBuffer2) + { + assert(!buffersToWrite.empty()); + newBuffer2 = std::move(buffersToWrite.back()); + buffersToWrite.pop_back(); + newBuffer2->reset(); + } + + buffersToWrite.clear(); + output.flush(); + } + output.flush(); +} + diff --git a/include/Third_Lib/muduo/base/AsyncLogging.h b/include/Third_Lib/muduo/base/AsyncLogging.h new file mode 100644 index 0000000..46e77dd --- /dev/null +++ b/include/Third_Lib/muduo/base/AsyncLogging.h @@ -0,0 +1,77 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_ASYNCLOGGING_H +#define MUDUO_BASE_ASYNCLOGGING_H + +#include "muduo/base/BlockingQueue.h" +#include "muduo/base/BoundedBlockingQueue.h" +#include "muduo/base/CountDownLatch.h" +#include "muduo/base/Mutex.h" +#include "muduo/base/Thread.h" +#include "muduo/base/LogStream.h" + +#include +#include + +namespace muduo +{ + +class AsyncLogging : noncopyable +{ + public: + + AsyncLogging(const string& basename, + off_t rollSize, + int flushInterval = 3); + + ~AsyncLogging() + { + if (running_) + { + stop(); + } + } + + void append(const char* logline, int len); + + void start() + { + running_ = true; + thread_.start(); + latch_.wait(); + } + + void stop() NO_THREAD_SAFETY_ANALYSIS + { + running_ = false; + cond_.notify(); + thread_.join(); + } + + private: + + void threadFunc(); + + typedef muduo::detail::FixedBuffer Buffer; + typedef std::vector> BufferVector; + typedef BufferVector::value_type BufferPtr; + + const int flushInterval_; + std::atomic running_; + const string basename_; + const off_t rollSize_; + muduo::Thread thread_; + muduo::CountDownLatch latch_; + muduo::MutexLock mutex_; + muduo::Condition cond_ GUARDED_BY(mutex_); + BufferPtr currentBuffer_ GUARDED_BY(mutex_); + BufferPtr nextBuffer_ GUARDED_BY(mutex_); + BufferVector buffers_ GUARDED_BY(mutex_); +}; + +} // namespace muduo + +#endif // MUDUO_BASE_ASYNCLOGGING_H diff --git a/include/Third_Lib/muduo/base/Atomic.h b/include/Third_Lib/muduo/base/Atomic.h new file mode 100644 index 0000000..6158fac --- /dev/null +++ b/include/Third_Lib/muduo/base/Atomic.h @@ -0,0 +1,97 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_ATOMIC_H +#define MUDUO_BASE_ATOMIC_H + +#include "muduo/base/noncopyable.h" + +#include + +namespace muduo +{ + +namespace detail +{ +template +class AtomicIntegerT : noncopyable +{ + public: + AtomicIntegerT() + : value_(0) + { + } + + // uncomment if you need copying and assignment + // + // AtomicIntegerT(const AtomicIntegerT& that) + // : value_(that.get()) + // {} + // + // AtomicIntegerT& operator=(const AtomicIntegerT& that) + // { + // getAndSet(that.get()); + // return *this; + // } + + T get() + { + // in gcc >= 4.7: __atomic_load_n(&value_, __ATOMIC_SEQ_CST) + return __sync_val_compare_and_swap(&value_, 0, 0); + } + + T getAndAdd(T x) + { + // in gcc >= 4.7: __atomic_fetch_add(&value_, x, __ATOMIC_SEQ_CST) + return __sync_fetch_and_add(&value_, x); + } + + T addAndGet(T x) + { + return getAndAdd(x) + x; + } + + T incrementAndGet() + { + return addAndGet(1); + } + + T decrementAndGet() + { + return addAndGet(-1); + } + + void add(T x) + { + getAndAdd(x); + } + + void increment() + { + incrementAndGet(); + } + + void decrement() + { + decrementAndGet(); + } + + T getAndSet(T newValue) + { + // in gcc >= 4.7: __atomic_exchange_n(&value_, newValue, __ATOMIC_SEQ_CST) + return __sync_lock_test_and_set(&value_, newValue); + } + + private: + volatile T value_; +}; +} // namespace detail + +typedef detail::AtomicIntegerT AtomicInt32; +typedef detail::AtomicIntegerT AtomicInt64; + +} // namespace muduo + +#endif // MUDUO_BASE_ATOMIC_H diff --git a/include/Third_Lib/muduo/base/BUILD.bazel b/include/Third_Lib/muduo/base/BUILD.bazel new file mode 100644 index 0000000..48b598f --- /dev/null +++ b/include/Third_Lib/muduo/base/BUILD.bazel @@ -0,0 +1,23 @@ +cc_library( + name = "base", + srcs = [ + "AsyncLogging.cc", + "Condition.cc", + "CountDownLatch.cc", + "CurrentThread.cc", + "Date.cc", + "Exception.cc", + "FileUtil.cc", + "LogFile.cc", + "LogStream.cc", + "Logging.cc", + "ProcessInfo.cc", + "Thread.cc", + "ThreadPool.cc", + "TimeZone.cc", + "Timestamp.cc", + ], + hdrs = glob(["*.h"]), + linkopts = ["-pthread"], + visibility = ["//visibility:public"], +) diff --git a/include/Third_Lib/muduo/base/BlockingQueue.h b/include/Third_Lib/muduo/base/BlockingQueue.h new file mode 100644 index 0000000..407c012 --- /dev/null +++ b/include/Third_Lib/muduo/base/BlockingQueue.h @@ -0,0 +1,72 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_BLOCKINGQUEUE_H +#define MUDUO_BASE_BLOCKINGQUEUE_H + +#include "muduo/base/Condition.h" +#include "muduo/base/Mutex.h" + +#include +#include + +namespace muduo +{ + +template +class BlockingQueue : noncopyable +{ + public: + BlockingQueue() + : mutex_(), + notEmpty_(mutex_), + queue_() + { + } + + void put(const T& x) + { + MutexLockGuard lock(mutex_); + queue_.push_back(x); + notEmpty_.notify(); // wait morphing saves us + // http://www.domaigne.com/blog/computing/condvars-signal-with-mutex-locked-or-not/ + } + + void put(T&& x) + { + MutexLockGuard lock(mutex_); + queue_.push_back(std::move(x)); + notEmpty_.notify(); + } + + T take() + { + MutexLockGuard lock(mutex_); + // always use a while-loop, due to spurious wakeup + while (queue_.empty()) + { + notEmpty_.wait(); + } + assert(!queue_.empty()); + T front(std::move(queue_.front())); + queue_.pop_front(); + return front; + } + + size_t size() const + { + MutexLockGuard lock(mutex_); + return queue_.size(); + } + + private: + mutable MutexLock mutex_; + Condition notEmpty_ GUARDED_BY(mutex_); + std::deque queue_ GUARDED_BY(mutex_); +}; + +} // namespace muduo + +#endif // MUDUO_BASE_BLOCKINGQUEUE_H diff --git a/include/Third_Lib/muduo/base/BoundedBlockingQueue.h b/include/Third_Lib/muduo/base/BoundedBlockingQueue.h new file mode 100644 index 0000000..cfb4d3b --- /dev/null +++ b/include/Third_Lib/muduo/base/BoundedBlockingQueue.h @@ -0,0 +1,101 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_BOUNDEDBLOCKINGQUEUE_H +#define MUDUO_BASE_BOUNDEDBLOCKINGQUEUE_H + +#include "muduo/base/Condition.h" +#include "muduo/base/Mutex.h" + +#include +#include + +namespace muduo +{ + +template +class BoundedBlockingQueue : noncopyable +{ + public: + explicit BoundedBlockingQueue(int maxSize) + : mutex_(), + notEmpty_(mutex_), + notFull_(mutex_), + queue_(maxSize) + { + } + + void put(const T& x) + { + MutexLockGuard lock(mutex_); + while (queue_.full()) + { + notFull_.wait(); + } + assert(!queue_.full()); + queue_.push_back(x); + notEmpty_.notify(); + } + + void put(T&& x) + { + MutexLockGuard lock(mutex_); + while (queue_.full()) + { + notFull_.wait(); + } + assert(!queue_.full()); + queue_.push_back(std::move(x)); + notEmpty_.notify(); + } + + T take() + { + MutexLockGuard lock(mutex_); + while (queue_.empty()) + { + notEmpty_.wait(); + } + assert(!queue_.empty()); + T front(std::move(queue_.front())); + queue_.pop_front(); + notFull_.notify(); + return front; + } + + bool empty() const + { + MutexLockGuard lock(mutex_); + return queue_.empty(); + } + + bool full() const + { + MutexLockGuard lock(mutex_); + return queue_.full(); + } + + size_t size() const + { + MutexLockGuard lock(mutex_); + return queue_.size(); + } + + size_t capacity() const + { + MutexLockGuard lock(mutex_); + return queue_.capacity(); + } + + private: + mutable MutexLock mutex_; + Condition notEmpty_ GUARDED_BY(mutex_); + Condition notFull_ GUARDED_BY(mutex_); + boost::circular_buffer queue_ GUARDED_BY(mutex_); +}; + +} // namespace muduo + +#endif // MUDUO_BASE_BOUNDEDBLOCKINGQUEUE_H diff --git a/include/Third_Lib/muduo/base/CMakeLists.txt b/include/Third_Lib/muduo/base/CMakeLists.txt new file mode 100644 index 0000000..96e2d02 --- /dev/null +++ b/include/Third_Lib/muduo/base/CMakeLists.txt @@ -0,0 +1,34 @@ +set(base_SRCS + AsyncLogging.cc + Condition.cc + CountDownLatch.cc + CurrentThread.cc + Date.cc + Exception.cc + FileUtil.cc + LogFile.cc + Logging.cc + LogStream.cc + ProcessInfo.cc + Timestamp.cc + Thread.cc + ThreadPool.cc + TimeZone.cc + ) + +add_library(muduo_base ${base_SRCS}) +target_link_libraries(muduo_base pthread rt) + +#add_library(muduo_base_cpp11 ${base_SRCS}) +#target_link_libraries(muduo_base_cpp11 pthread rt) +#set_target_properties(muduo_base_cpp11 PROPERTIES COMPILE_FLAGS "-std=c++0x") + +install(TARGETS muduo_base DESTINATION lib) +#install(TARGETS muduo_base_cpp11 DESTINATION lib) + +file(GLOB HEADERS "*.h") +install(FILES ${HEADERS} DESTINATION include/muduo/base) + +if(MUDUO_BUILD_EXAMPLES) + add_subdirectory(tests) +endif() diff --git a/include/Third_Lib/muduo/base/Condition.cc b/include/Third_Lib/muduo/base/Condition.cc new file mode 100644 index 0000000..47e9d23 --- /dev/null +++ b/include/Third_Lib/muduo/base/Condition.cc @@ -0,0 +1,26 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/base/Condition.h" + +#include + +// returns true if time out, false otherwise. +bool muduo::Condition::waitForSeconds(double seconds) +{ + struct timespec abstime; + // FIXME: use CLOCK_MONOTONIC or CLOCK_MONOTONIC_RAW to prevent time rewind. + clock_gettime(CLOCK_REALTIME, &abstime); + + const int64_t kNanoSecondsPerSecond = 1000000000; + int64_t nanoseconds = static_cast(seconds * kNanoSecondsPerSecond); + + abstime.tv_sec += static_cast((abstime.tv_nsec + nanoseconds) / kNanoSecondsPerSecond); + abstime.tv_nsec = static_cast((abstime.tv_nsec + nanoseconds) % kNanoSecondsPerSecond); + + MutexLock::UnassignGuard ug(mutex_); + return ETIMEDOUT == pthread_cond_timedwait(&pcond_, mutex_.getPthreadMutex(), &abstime); +} + diff --git a/include/Third_Lib/muduo/base/Condition.h b/include/Third_Lib/muduo/base/Condition.h new file mode 100644 index 0000000..0181550 --- /dev/null +++ b/include/Third_Lib/muduo/base/Condition.h @@ -0,0 +1,56 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_CONDITION_H +#define MUDUO_BASE_CONDITION_H + +#include "muduo/base/Mutex.h" + +#include + +namespace muduo +{ + +class Condition : noncopyable +{ + public: + explicit Condition(MutexLock& mutex) + : mutex_(mutex) + { + MCHECK(pthread_cond_init(&pcond_, NULL)); + } + + ~Condition() + { + MCHECK(pthread_cond_destroy(&pcond_)); + } + + void wait() + { + MutexLock::UnassignGuard ug(mutex_); + MCHECK(pthread_cond_wait(&pcond_, mutex_.getPthreadMutex())); + } + + // returns true if time out, false otherwise. + bool waitForSeconds(double seconds); + + void notify() + { + MCHECK(pthread_cond_signal(&pcond_)); + } + + void notifyAll() + { + MCHECK(pthread_cond_broadcast(&pcond_)); + } + + private: + MutexLock& mutex_; + pthread_cond_t pcond_; +}; + +} // namespace muduo + +#endif // MUDUO_BASE_CONDITION_H diff --git a/include/Third_Lib/muduo/base/CountDownLatch.cc b/include/Third_Lib/muduo/base/CountDownLatch.cc new file mode 100644 index 0000000..72d26cc --- /dev/null +++ b/include/Third_Lib/muduo/base/CountDownLatch.cc @@ -0,0 +1,41 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/base/CountDownLatch.h" + +using namespace muduo; + +CountDownLatch::CountDownLatch(int count) + : mutex_(), + condition_(mutex_), + count_(count) +{ +} + +void CountDownLatch::wait() +{ + MutexLockGuard lock(mutex_); + while (count_ > 0) + { + condition_.wait(); + } +} + +void CountDownLatch::countDown() +{ + MutexLockGuard lock(mutex_); + --count_; + if (count_ == 0) + { + condition_.notifyAll(); + } +} + +int CountDownLatch::getCount() const +{ + MutexLockGuard lock(mutex_); + return count_; +} + diff --git a/include/Third_Lib/muduo/base/CountDownLatch.h b/include/Third_Lib/muduo/base/CountDownLatch.h new file mode 100644 index 0000000..9919aef --- /dev/null +++ b/include/Third_Lib/muduo/base/CountDownLatch.h @@ -0,0 +1,34 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_COUNTDOWNLATCH_H +#define MUDUO_BASE_COUNTDOWNLATCH_H + +#include "muduo/base/Condition.h" +#include "muduo/base/Mutex.h" + +namespace muduo +{ + +class CountDownLatch : noncopyable +{ + public: + + explicit CountDownLatch(int count); + + void wait(); + + void countDown(); + + int getCount() const; + + private: + mutable MutexLock mutex_; + Condition condition_ GUARDED_BY(mutex_); + int count_ GUARDED_BY(mutex_); +}; + +} // namespace muduo +#endif // MUDUO_BASE_COUNTDOWNLATCH_H diff --git a/include/Third_Lib/muduo/base/CurrentThread.cc b/include/Third_Lib/muduo/base/CurrentThread.cc new file mode 100644 index 0000000..15edff0 --- /dev/null +++ b/include/Third_Lib/muduo/base/CurrentThread.cc @@ -0,0 +1,77 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/base/CurrentThread.h" + +#include +#include +#include + +namespace muduo +{ +namespace CurrentThread +{ +__thread int t_cachedTid = 0; +__thread char t_tidString[32]; +__thread int t_tidStringLength = 6; +__thread const char* t_threadName = "unknown"; +static_assert(std::is_same::value, "pid_t should be int"); + +string stackTrace(bool demangle) +{ + string stack; + const int max_frames = 200; + void* frame[max_frames]; + int nptrs = ::backtrace(frame, max_frames); + char** strings = ::backtrace_symbols(frame, nptrs); + if (strings) + { + size_t len = 256; + char* demangled = demangle ? static_cast(::malloc(len)) : nullptr; + for (int i = 1; i < nptrs; ++i) // skipping the 0-th, which is this function + { + if (demangle) + { + // https://panthema.net/2008/0901-stacktrace-demangled/ + // bin/exception_test(_ZN3Bar4testEv+0x79) [0x401909] + char* left_par = nullptr; + char* plus = nullptr; + for (char* p = strings[i]; *p; ++p) + { + if (*p == '(') + left_par = p; + else if (*p == '+') + plus = p; + } + + if (left_par && plus) + { + *plus = '\0'; + int status = 0; + char* ret = abi::__cxa_demangle(left_par+1, demangled, &len, &status); + *plus = '+'; + if (status == 0) + { + demangled = ret; // ret could be realloc() + stack.append(strings[i], left_par+1); + stack.append(demangled); + stack.append(plus); + stack.push_back('\n'); + continue; + } + } + } + // Fallback to mangled names + stack.append(strings[i]); + stack.push_back('\n'); + } + free(demangled); + free(strings); + } + return stack; +} + +} // namespace CurrentThread +} // namespace muduo diff --git a/include/Third_Lib/muduo/base/CurrentThread.h b/include/Third_Lib/muduo/base/CurrentThread.h new file mode 100644 index 0000000..33fd8c0 --- /dev/null +++ b/include/Third_Lib/muduo/base/CurrentThread.h @@ -0,0 +1,54 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_CURRENTTHREAD_H +#define MUDUO_BASE_CURRENTTHREAD_H + +#include "muduo/base/Types.h" + +namespace muduo +{ +namespace CurrentThread +{ + // internal + extern __thread int t_cachedTid; + extern __thread char t_tidString[32]; + extern __thread int t_tidStringLength; + extern __thread const char* t_threadName; + void cacheTid(); + + inline int tid() + { + if (__builtin_expect(t_cachedTid == 0, 0)) + { + cacheTid(); + } + return t_cachedTid; + } + + inline const char* tidString() // for logging + { + return t_tidString; + } + + inline int tidStringLength() // for logging + { + return t_tidStringLength; + } + + inline const char* name() + { + return t_threadName; + } + + bool isMainThread(); + + void sleepUsec(int64_t usec); // for testing + + string stackTrace(bool demangle); +} // namespace CurrentThread +} // namespace muduo + +#endif // MUDUO_BASE_CURRENTTHREAD_H diff --git a/include/Third_Lib/muduo/base/Date.cc b/include/Third_Lib/muduo/base/Date.cc new file mode 100644 index 0000000..86b6071 --- /dev/null +++ b/include/Third_Lib/muduo/base/Date.cc @@ -0,0 +1,76 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/base/Date.h" +#include // snprintf +#include // struct tm + +namespace muduo +{ +namespace detail +{ + +char require_32_bit_integer_at_least[sizeof(int) >= sizeof(int32_t) ? 1 : -1]; + +// algorithm and explanation see: +// http://www.faqs.org/faqs/calendars/faq/part2/ +// http://blog.csdn.net/Solstice + +int getJulianDayNumber(int year, int month, int day) +{ + (void) require_32_bit_integer_at_least; // no warning please + int a = (14 - month) / 12; + int y = year + 4800 - a; + int m = month + 12 * a - 3; + return day + (153*m + 2) / 5 + y*365 + y/4 - y/100 + y/400 - 32045; +} + +struct Date::YearMonthDay getYearMonthDay(int julianDayNumber) +{ + int a = julianDayNumber + 32044; + int b = (4 * a + 3) / 146097; + int c = a - ((b * 146097) / 4); + int d = (4 * c + 3) / 1461; + int e = c - ((1461 * d) / 4); + int m = (5 * e + 2) / 153; + Date::YearMonthDay ymd; + ymd.day = e - ((153 * m + 2) / 5) + 1; + ymd.month = m + 3 - 12 * (m / 10); + ymd.year = b * 100 + d - 4800 + (m / 10); + return ymd; +} +} // namespace detail +const int Date::kJulianDayOf1970_01_01 = detail::getJulianDayNumber(1970, 1, 1); +} // namespace muduo + +using namespace muduo; +using namespace muduo::detail; + +Date::Date(int y, int m, int d) + : julianDayNumber_(getJulianDayNumber(y, m, d)) +{ +} + +Date::Date(const struct tm& t) + : julianDayNumber_(getJulianDayNumber( + t.tm_year+1900, + t.tm_mon+1, + t.tm_mday)) +{ +} + +string Date::toIsoString() const +{ + char buf[32]; + YearMonthDay ymd(yearMonthDay()); + snprintf(buf, sizeof buf, "%4d-%02d-%02d", ymd.year, ymd.month, ymd.day); + return buf; +} + +Date::YearMonthDay Date::yearMonthDay() const +{ + return getYearMonthDay(julianDayNumber_); +} + diff --git a/include/Third_Lib/muduo/base/Date.h b/include/Third_Lib/muduo/base/Date.h new file mode 100644 index 0000000..2e27b19 --- /dev/null +++ b/include/Third_Lib/muduo/base/Date.h @@ -0,0 +1,119 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_DATE_H +#define MUDUO_BASE_DATE_H + +#include "muduo/base/copyable.h" +#include "muduo/base/Types.h" + +struct tm; + +namespace muduo +{ + +/// +/// Date in Gregorian calendar. +/// +/// This class is immutable. +/// It's recommended to pass it by value, since it's passed in register on x64. +/// +class Date : public muduo::copyable + // public boost::less_than_comparable, + // public boost::equality_comparable +{ + public: + + struct YearMonthDay + { + int year; // [1900..2500] + int month; // [1..12] + int day; // [1..31] + }; + + static const int kDaysPerWeek = 7; + static const int kJulianDayOf1970_01_01; + + /// + /// Constucts an invalid Date. + /// + Date() + : julianDayNumber_(0) + {} + + /// + /// Constucts a yyyy-mm-dd Date. + /// + /// 1 <= month <= 12 + Date(int year, int month, int day); + + /// + /// Constucts a Date from Julian Day Number. + /// + explicit Date(int julianDayNum) + : julianDayNumber_(julianDayNum) + {} + + /// + /// Constucts a Date from struct tm + /// + explicit Date(const struct tm&); + + // default copy/assignment/dtor are Okay + + void swap(Date& that) + { + std::swap(julianDayNumber_, that.julianDayNumber_); + } + + bool valid() const { return julianDayNumber_ > 0; } + + /// + /// Converts to yyyy-mm-dd format. + /// + string toIsoString() const; + + struct YearMonthDay yearMonthDay() const; + + int year() const + { + return yearMonthDay().year; + } + + int month() const + { + return yearMonthDay().month; + } + + int day() const + { + return yearMonthDay().day; + } + + // [0, 1, ..., 6] => [Sunday, Monday, ..., Saturday ] + int weekDay() const + { + return (julianDayNumber_+1) % kDaysPerWeek; + } + + int julianDayNumber() const { return julianDayNumber_; } + + private: + int julianDayNumber_; +}; + +inline bool operator<(Date x, Date y) +{ + return x.julianDayNumber() < y.julianDayNumber(); +} + +inline bool operator==(Date x, Date y) +{ + return x.julianDayNumber() == y.julianDayNumber(); +} + +} // namespace muduo + +#endif // MUDUO_BASE_DATE_H diff --git a/include/Third_Lib/muduo/base/Exception.cc b/include/Third_Lib/muduo/base/Exception.cc new file mode 100644 index 0000000..6e2afbe --- /dev/null +++ b/include/Third_Lib/muduo/base/Exception.cc @@ -0,0 +1,18 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/base/Exception.h" +#include "muduo/base/CurrentThread.h" + +namespace muduo +{ + +Exception::Exception(string msg) + : message_(std::move(msg)), + stack_(CurrentThread::stackTrace(/*demangle=*/false)) +{ +} + +} // namespace muduo diff --git a/include/Third_Lib/muduo/base/Exception.h b/include/Third_Lib/muduo/base/Exception.h new file mode 100644 index 0000000..2a74622 --- /dev/null +++ b/include/Third_Lib/muduo/base/Exception.h @@ -0,0 +1,40 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_EXCEPTION_H +#define MUDUO_BASE_EXCEPTION_H + +#include "muduo/base/Types.h" +#include + +namespace muduo +{ + +class Exception : public std::exception +{ + public: + Exception(string what); + ~Exception() noexcept override = default; + + // default copy-ctor and operator= are okay. + + const char* what() const noexcept override + { + return message_.c_str(); + } + + const char* stackTrace() const noexcept + { + return stack_.c_str(); + } + + private: + string message_; + string stack_; +}; + +} // namespace muduo + +#endif // MUDUO_BASE_EXCEPTION_H diff --git a/include/Third_Lib/muduo/base/FileUtil.cc b/include/Third_Lib/muduo/base/FileUtil.cc new file mode 100644 index 0000000..2a73886 --- /dev/null +++ b/include/Third_Lib/muduo/base/FileUtil.cc @@ -0,0 +1,181 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/base/FileUtil.h" +#include "muduo/base/Logging.h" + +#include +#include +#include +#include +#include +#include + +using namespace muduo; + +FileUtil::AppendFile::AppendFile(StringArg filename) + : fp_(::fopen(filename.c_str(), "ae")), // 'e' for O_CLOEXEC + writtenBytes_(0) +{ + assert(fp_); + ::setbuffer(fp_, buffer_, sizeof buffer_); + // posix_fadvise POSIX_FADV_DONTNEED ? +} + +FileUtil::AppendFile::~AppendFile() +{ + ::fclose(fp_); +} + +void FileUtil::AppendFile::append(const char* logline, const size_t len) +{ + size_t n = write(logline, len); + size_t remain = len - n; + while (remain > 0) + { + size_t x = write(logline + n, remain); + if (x == 0) + { + int err = ferror(fp_); + if (err) + { + fprintf(stderr, "AppendFile::append() failed %s\n", strerror_tl(err)); + } + break; + } + n += x; + remain = len - n; // remain -= x + } + + writtenBytes_ += len; +} + +void FileUtil::AppendFile::flush() +{ + ::fflush(fp_); +} + +size_t FileUtil::AppendFile::write(const char* logline, size_t len) +{ + // #undef fwrite_unlocked + return ::fwrite_unlocked(logline, 1, len, fp_); +} + +FileUtil::ReadSmallFile::ReadSmallFile(StringArg filename) + : fd_(::open(filename.c_str(), O_RDONLY | O_CLOEXEC)), + err_(0) +{ + buf_[0] = '\0'; + if (fd_ < 0) + { + err_ = errno; + } +} + +FileUtil::ReadSmallFile::~ReadSmallFile() +{ + if (fd_ >= 0) + { + ::close(fd_); // FIXME: check EINTR + } +} + +// return errno +template +int FileUtil::ReadSmallFile::readToString(int maxSize, + String* content, + int64_t* fileSize, + int64_t* modifyTime, + int64_t* createTime) +{ + static_assert(sizeof(off_t) == 8, "_FILE_OFFSET_BITS = 64"); + assert(content != NULL); + int err = err_; + if (fd_ >= 0) + { + content->clear(); + + if (fileSize) + { + struct stat statbuf; + if (::fstat(fd_, &statbuf) == 0) + { + if (S_ISREG(statbuf.st_mode)) + { + *fileSize = statbuf.st_size; + content->reserve(static_cast(std::min(implicit_cast(maxSize), *fileSize))); + } + else if (S_ISDIR(statbuf.st_mode)) + { + err = EISDIR; + } + if (modifyTime) + { + *modifyTime = statbuf.st_mtime; + } + if (createTime) + { + *createTime = statbuf.st_ctime; + } + } + else + { + err = errno; + } + } + + while (content->size() < implicit_cast(maxSize)) + { + size_t toRead = std::min(implicit_cast(maxSize) - content->size(), sizeof(buf_)); + ssize_t n = ::read(fd_, buf_, toRead); + if (n > 0) + { + content->append(buf_, n); + } + else + { + if (n < 0) + { + err = errno; + } + break; + } + } + } + return err; +} + +int FileUtil::ReadSmallFile::readToBuffer(int* size) +{ + int err = err_; + if (fd_ >= 0) + { + ssize_t n = ::pread(fd_, buf_, sizeof(buf_)-1, 0); + if (n >= 0) + { + if (size) + { + *size = static_cast(n); + } + buf_[n] = '\0'; + } + else + { + err = errno; + } + } + return err; +} + +template int FileUtil::readFile(StringArg filename, + int maxSize, + string* content, + int64_t*, int64_t*, int64_t*); + +template int FileUtil::ReadSmallFile::readToString( + int maxSize, + string* content, + int64_t*, int64_t*, int64_t*); + diff --git a/include/Third_Lib/muduo/base/FileUtil.h b/include/Third_Lib/muduo/base/FileUtil.h new file mode 100644 index 0000000..62ddebc --- /dev/null +++ b/include/Third_Lib/muduo/base/FileUtil.h @@ -0,0 +1,89 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_BASE_FILEUTIL_H +#define MUDUO_BASE_FILEUTIL_H + +#include "muduo/base/noncopyable.h" +#include "muduo/base/StringPiece.h" +#include // for off_t + +namespace muduo +{ +namespace FileUtil +{ + +// read small file < 64KB +class ReadSmallFile : noncopyable +{ + public: + ReadSmallFile(StringArg filename); + ~ReadSmallFile(); + + // return errno + template + int readToString(int maxSize, + String* content, + int64_t* fileSize, + int64_t* modifyTime, + int64_t* createTime); + + /// Read at maxium kBufferSize into buf_ + // return errno + int readToBuffer(int* size); + + const char* buffer() const { return buf_; } + + static const int kBufferSize = 64*1024; + + private: + int fd_; + int err_; + char buf_[kBufferSize]; +}; + +// read the file content, returns errno if error happens. +template +int readFile(StringArg filename, + int maxSize, + String* content, + int64_t* fileSize = NULL, + int64_t* modifyTime = NULL, + int64_t* createTime = NULL) +{ + ReadSmallFile file(filename); + return file.readToString(maxSize, content, fileSize, modifyTime, createTime); +} + +// not thread safe +class AppendFile : noncopyable +{ + public: + explicit AppendFile(StringArg filename); + + ~AppendFile(); + + void append(const char* logline, size_t len); + + void flush(); + + off_t writtenBytes() const { return writtenBytes_; } + + private: + + size_t write(const char* logline, size_t len); + + FILE* fp_; + char buffer_[64*1024]; + off_t writtenBytes_; +}; + +} // namespace FileUtil +} // namespace muduo + +#endif // MUDUO_BASE_FILEUTIL_H + diff --git a/include/Third_Lib/muduo/base/GzipFile.h b/include/Third_Lib/muduo/base/GzipFile.h new file mode 100644 index 0000000..68a538c --- /dev/null +++ b/include/Third_Lib/muduo/base/GzipFile.h @@ -0,0 +1,89 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#pragma once + +#include "muduo/base/StringPiece.h" +#include "muduo/base/noncopyable.h" +#include + +namespace muduo +{ + +class GzipFile : noncopyable +{ + public: + GzipFile(GzipFile&& rhs) noexcept + : file_(rhs.file_) + { + rhs.file_ = NULL; + } + + ~GzipFile() + { + if (file_) + { + ::gzclose(file_); + } + } + + GzipFile& operator=(GzipFile&& rhs) noexcept + { + swap(rhs); + return *this; + } + + bool valid() const { return file_ != NULL; } + void swap(GzipFile& rhs) { std::swap(file_, rhs.file_); } +#if ZLIB_VERNUM >= 0x1240 + bool setBuffer(int size) { return ::gzbuffer(file_, size) == 0; } +#endif + + // return the number of uncompressed bytes actually read, 0 for eof, -1 for error + int read(void* buf, int len) { return ::gzread(file_, buf, len); } + + // return the number of uncompressed bytes actually written + int write(StringPiece buf) { return ::gzwrite(file_, buf.data(), buf.size()); } + + // number of uncompressed bytes + off_t tell() const { return ::gztell(file_); } + +#if ZLIB_VERNUM >= 0x1240 + // number of compressed bytes + off_t offset() const { return ::gzoffset(file_); } +#endif + + // int flush(int f) { return ::gzflush(file_, f); } + + static GzipFile openForRead(StringArg filename) + { + return GzipFile(::gzopen(filename.c_str(), "rbe")); + } + + static GzipFile openForAppend(StringArg filename) + { + return GzipFile(::gzopen(filename.c_str(), "abe")); + } + + static GzipFile openForWriteExclusive(StringArg filename) + { + return GzipFile(::gzopen(filename.c_str(), "wbxe")); + } + + static GzipFile openForWriteTruncate(StringArg filename) + { + return GzipFile(::gzopen(filename.c_str(), "wbe")); + } + + private: + explicit GzipFile(gzFile file) + : file_(file) + { + } + + gzFile file_; +}; + +} // namespace muduo diff --git a/include/Third_Lib/muduo/base/LogFile.cc b/include/Third_Lib/muduo/base/LogFile.cc new file mode 100644 index 0000000..2a12abe --- /dev/null +++ b/include/Third_Lib/muduo/base/LogFile.cc @@ -0,0 +1,133 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/base/LogFile.h" + +#include "muduo/base/FileUtil.h" +#include "muduo/base/ProcessInfo.h" + +#include +#include +#include + +using namespace muduo; + +LogFile::LogFile(const string& basename, + off_t rollSize, + bool threadSafe, + int flushInterval, + int checkEveryN) + : basename_(basename), + rollSize_(rollSize), + flushInterval_(flushInterval), + checkEveryN_(checkEveryN), + count_(0), + mutex_(threadSafe ? new MutexLock : NULL), + startOfPeriod_(0), + lastRoll_(0), + lastFlush_(0) +{ + assert(basename.find('/') == string::npos); + rollFile(); +} + +LogFile::~LogFile() = default; + +void LogFile::append(const char* logline, int len) +{ + if (mutex_) + { + MutexLockGuard lock(*mutex_); + append_unlocked(logline, len); + } + else + { + append_unlocked(logline, len); + } +} + +void LogFile::flush() +{ + if (mutex_) + { + MutexLockGuard lock(*mutex_); + file_->flush(); + } + else + { + file_->flush(); + } +} + +void LogFile::append_unlocked(const char* logline, int len) +{ + file_->append(logline, len); + + if (file_->writtenBytes() > rollSize_) + { + rollFile(); + } + else + { + ++count_; + if (count_ >= checkEveryN_) + { + count_ = 0; + time_t now = ::time(NULL); + time_t thisPeriod_ = now / kRollPerSeconds_ * kRollPerSeconds_; + if (thisPeriod_ != startOfPeriod_) + { + rollFile(); + } + else if (now - lastFlush_ > flushInterval_) + { + lastFlush_ = now; + file_->flush(); + } + } + } +} + +bool LogFile::rollFile() +{ + time_t now = 0; + string filename = getLogFileName(basename_, &now); + time_t start = now / kRollPerSeconds_ * kRollPerSeconds_; + + if (now > lastRoll_) + { + lastRoll_ = now; + lastFlush_ = now; + startOfPeriod_ = start; + file_.reset(new FileUtil::AppendFile(filename)); + return true; + } + return false; +} + +string LogFile::getLogFileName(const string& basename, time_t* now) +{ + string filename; + filename.reserve(basename.size() + 64); + filename = basename; + + char timebuf[32]; + struct tm tm; + *now = time(NULL); + gmtime_r(now, &tm); // FIXME: localtime_r ? + strftime(timebuf, sizeof timebuf, ".%Y%m%d-%H%M%S.", &tm); + filename += timebuf; + + filename += ProcessInfo::hostname(); + + char pidbuf[32]; + snprintf(pidbuf, sizeof pidbuf, ".%d", ProcessInfo::pid()); + filename += pidbuf; + + filename += ".log"; + + return filename; +} + diff --git a/include/Third_Lib/muduo/base/LogFile.h b/include/Third_Lib/muduo/base/LogFile.h new file mode 100644 index 0000000..7abd583 --- /dev/null +++ b/include/Third_Lib/muduo/base/LogFile.h @@ -0,0 +1,58 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_LOGFILE_H +#define MUDUO_BASE_LOGFILE_H + +#include "muduo/base/Mutex.h" +#include "muduo/base/Types.h" + +#include + +namespace muduo +{ + +namespace FileUtil +{ +class AppendFile; +} + +class LogFile : noncopyable +{ + public: + LogFile(const string& basename, + off_t rollSize, + bool threadSafe = true, + int flushInterval = 3, + int checkEveryN = 1024); + ~LogFile(); + + void append(const char* logline, int len); + void flush(); + bool rollFile(); + + private: + void append_unlocked(const char* logline, int len); + + static string getLogFileName(const string& basename, time_t* now); + + const string basename_; + const off_t rollSize_; + const int flushInterval_; + const int checkEveryN_; + + int count_; + + std::unique_ptr mutex_; + time_t startOfPeriod_; + time_t lastRoll_; + time_t lastFlush_; + std::unique_ptr file_; + + const static int kRollPerSeconds_ = 60*60*24; +}; + +} // namespace muduo +#endif // MUDUO_BASE_LOGFILE_H diff --git a/include/Third_Lib/muduo/base/LogStream.cc b/include/Third_Lib/muduo/base/LogStream.cc new file mode 100644 index 0000000..cafd5b8 --- /dev/null +++ b/include/Third_Lib/muduo/base/LogStream.cc @@ -0,0 +1,342 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/base/LogStream.h" + +#include +#include +#include +#include +#include +#include +#include + +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif + +#include + + +using namespace muduo; +using namespace muduo::detail; + +// TODO: better itoa. +#if defined(__clang__) +#pragma clang diagnostic ignored "-Wtautological-compare" +#else +#pragma GCC diagnostic ignored "-Wtype-limits" +#endif + +namespace muduo +{ +namespace detail +{ + +const char digits[] = "9876543210123456789"; +const char* zero = digits + 9; +static_assert(sizeof(digits) == 20, "wrong number of digits"); + +const char digitsHex[] = "0123456789ABCDEF"; +static_assert(sizeof digitsHex == 17, "wrong number of digitsHex"); + +// Efficient Integer to String Conversions, by Matthew Wilson. +template +size_t convert(char buf[], T value) +{ + T i = value; + char* p = buf; + + do + { + int lsd = static_cast(i % 10); + i /= 10; + *p++ = zero[lsd]; + } while (i != 0); + + if (value < 0) + { + *p++ = '-'; + } + *p = '\0'; + std::reverse(buf, p); + + return p - buf; +} + +size_t convertHex(char buf[], uintptr_t value) +{ + uintptr_t i = value; + char* p = buf; + + do + { + int lsd = static_cast(i % 16); + i /= 16; + *p++ = digitsHex[lsd]; + } while (i != 0); + + *p = '\0'; + std::reverse(buf, p); + + return p - buf; +} + +template class FixedBuffer; +template class FixedBuffer; + +} // namespace detail + +/* + Format a number with 5 characters, including SI units. + [0, 999] + [1.00k, 999k] + [1.00M, 999M] + [1.00G, 999G] + [1.00T, 999T] + [1.00P, 999P] + [1.00E, inf) +*/ +std::string formatSI(int64_t s) +{ + double n = static_cast(s); + char buf[64]; + if (s < 1000) + snprintf(buf, sizeof(buf), "%" PRId64, s); + else if (s < 9995) + snprintf(buf, sizeof(buf), "%.2fk", n/1e3); + else if (s < 99950) + snprintf(buf, sizeof(buf), "%.1fk", n/1e3); + else if (s < 999500) + snprintf(buf, sizeof(buf), "%.0fk", n/1e3); + else if (s < 9995000) + snprintf(buf, sizeof(buf), "%.2fM", n/1e6); + else if (s < 99950000) + snprintf(buf, sizeof(buf), "%.1fM", n/1e6); + else if (s < 999500000) + snprintf(buf, sizeof(buf), "%.0fM", n/1e6); + else if (s < 9995000000) + snprintf(buf, sizeof(buf), "%.2fG", n/1e9); + else if (s < 99950000000) + snprintf(buf, sizeof(buf), "%.1fG", n/1e9); + else if (s < 999500000000) + snprintf(buf, sizeof(buf), "%.0fG", n/1e9); + else if (s < 9995000000000) + snprintf(buf, sizeof(buf), "%.2fT", n/1e12); + else if (s < 99950000000000) + snprintf(buf, sizeof(buf), "%.1fT", n/1e12); + else if (s < 999500000000000) + snprintf(buf, sizeof(buf), "%.0fT", n/1e12); + else if (s < 9995000000000000) + snprintf(buf, sizeof(buf), "%.2fP", n/1e15); + else if (s < 99950000000000000) + snprintf(buf, sizeof(buf), "%.1fP", n/1e15); + else if (s < 999500000000000000) + snprintf(buf, sizeof(buf), "%.0fP", n/1e15); + else + snprintf(buf, sizeof(buf), "%.2fE", n/1e18); + return buf; +} + +/* + [0, 1023] + [1.00Ki, 9.99Ki] + [10.0Ki, 99.9Ki] + [ 100Ki, 1023Ki] + [1.00Mi, 9.99Mi] +*/ +std::string formatIEC(int64_t s) +{ + double n = static_cast(s); + char buf[64]; + const double Ki = 1024.0; + const double Mi = Ki * 1024.0; + const double Gi = Mi * 1024.0; + const double Ti = Gi * 1024.0; + const double Pi = Ti * 1024.0; + const double Ei = Pi * 1024.0; + + if (n < Ki) + snprintf(buf, sizeof buf, "%" PRId64, s); + else if (n < Ki*9.995) + snprintf(buf, sizeof buf, "%.2fKi", n / Ki); + else if (n < Ki*99.95) + snprintf(buf, sizeof buf, "%.1fKi", n / Ki); + else if (n < Ki*1023.5) + snprintf(buf, sizeof buf, "%.0fKi", n / Ki); + + else if (n < Mi*9.995) + snprintf(buf, sizeof buf, "%.2fMi", n / Mi); + else if (n < Mi*99.95) + snprintf(buf, sizeof buf, "%.1fMi", n / Mi); + else if (n < Mi*1023.5) + snprintf(buf, sizeof buf, "%.0fMi", n / Mi); + + else if (n < Gi*9.995) + snprintf(buf, sizeof buf, "%.2fGi", n / Gi); + else if (n < Gi*99.95) + snprintf(buf, sizeof buf, "%.1fGi", n / Gi); + else if (n < Gi*1023.5) + snprintf(buf, sizeof buf, "%.0fGi", n / Gi); + + else if (n < Ti*9.995) + snprintf(buf, sizeof buf, "%.2fTi", n / Ti); + else if (n < Ti*99.95) + snprintf(buf, sizeof buf, "%.1fTi", n / Ti); + else if (n < Ti*1023.5) + snprintf(buf, sizeof buf, "%.0fTi", n / Ti); + + else if (n < Pi*9.995) + snprintf(buf, sizeof buf, "%.2fPi", n / Pi); + else if (n < Pi*99.95) + snprintf(buf, sizeof buf, "%.1fPi", n / Pi); + else if (n < Pi*1023.5) + snprintf(buf, sizeof buf, "%.0fPi", n / Pi); + + else if (n < Ei*9.995) + snprintf(buf, sizeof buf, "%.2fEi", n / Ei ); + else + snprintf(buf, sizeof buf, "%.1fEi", n / Ei ); + return buf; +} + +} // namespace muduo + +template +const char* FixedBuffer::debugString() +{ + *cur_ = '\0'; + return data_; +} + +template +void FixedBuffer::cookieStart() +{ +} + +template +void FixedBuffer::cookieEnd() +{ +} + +void LogStream::staticCheck() +{ + static_assert(kMaxNumericSize - 10 > std::numeric_limits::digits10, + "kMaxNumericSize is large enough"); + static_assert(kMaxNumericSize - 10 > std::numeric_limits::digits10, + "kMaxNumericSize is large enough"); + static_assert(kMaxNumericSize - 10 > std::numeric_limits::digits10, + "kMaxNumericSize is large enough"); + static_assert(kMaxNumericSize - 10 > std::numeric_limits::digits10, + "kMaxNumericSize is large enough"); +} + +template +void LogStream::formatInteger(T v) +{ + if (buffer_.avail() >= kMaxNumericSize) + { + size_t len = convert(buffer_.current(), v); + buffer_.add(len); + } +} + +LogStream& LogStream::operator<<(short v) +{ + *this << static_cast(v); + return *this; +} + +LogStream& LogStream::operator<<(unsigned short v) +{ + *this << static_cast(v); + return *this; +} + +LogStream& LogStream::operator<<(int v) +{ + formatInteger(v); + return *this; +} + +LogStream& LogStream::operator<<(unsigned int v) +{ + formatInteger(v); + return *this; +} + +LogStream& LogStream::operator<<(long v) +{ + formatInteger(v); + return *this; +} + +LogStream& LogStream::operator<<(unsigned long v) +{ + formatInteger(v); + return *this; +} + +LogStream& LogStream::operator<<(long long v) +{ + formatInteger(v); + return *this; +} + +LogStream& LogStream::operator<<(unsigned long long v) +{ + formatInteger(v); + return *this; +} + +LogStream& LogStream::operator<<(const void* p) +{ + uintptr_t v = reinterpret_cast(p); + if (buffer_.avail() >= kMaxNumericSize) + { + char* buf = buffer_.current(); + buf[0] = '0'; + buf[1] = 'x'; + size_t len = convertHex(buf+2, v); + buffer_.add(len+2); + } + return *this; +} + +// FIXME: replace this with Grisu3 by Florian Loitsch. +LogStream& LogStream::operator<<(double v) +{ + if (buffer_.avail() >= kMaxNumericSize) + { + int len = snprintf(buffer_.current(), kMaxNumericSize, "%.12g", v); + buffer_.add(len); + } + return *this; +} + +template +Fmt::Fmt(const char* fmt, T val) +{ + static_assert(std::is_arithmetic::value == true, "Must be arithmetic type"); + + length_ = snprintf(buf_, sizeof buf_, fmt, val); + assert(static_cast(length_) < sizeof buf_); +} + +// Explicit instantiations + +template Fmt::Fmt(const char* fmt, char); + +template Fmt::Fmt(const char* fmt, short); +template Fmt::Fmt(const char* fmt, unsigned short); +template Fmt::Fmt(const char* fmt, int); +template Fmt::Fmt(const char* fmt, unsigned int); +template Fmt::Fmt(const char* fmt, long); +template Fmt::Fmt(const char* fmt, unsigned long); +template Fmt::Fmt(const char* fmt, long long); +template Fmt::Fmt(const char* fmt, unsigned long long); + +template Fmt::Fmt(const char* fmt, float); +template Fmt::Fmt(const char* fmt, double); diff --git a/include/Third_Lib/muduo/base/LogStream.h b/include/Third_Lib/muduo/base/LogStream.h new file mode 100644 index 0000000..a28eb46 --- /dev/null +++ b/include/Third_Lib/muduo/base/LogStream.h @@ -0,0 +1,203 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_LOGSTREAM_H +#define MUDUO_BASE_LOGSTREAM_H + +#include "muduo/base/noncopyable.h" +#include "muduo/base/StringPiece.h" +#include "muduo/base/Types.h" +#include +#include // memcpy + +namespace muduo +{ + +namespace detail +{ + +const int kSmallBuffer = 4000; +const int kLargeBuffer = 4000*1000; + +template +class FixedBuffer : noncopyable +{ + public: + FixedBuffer() + : cur_(data_) + { + setCookie(cookieStart); + } + + ~FixedBuffer() + { + setCookie(cookieEnd); + } + + void append(const char* /*restrict*/ buf, size_t len) + { + // FIXME: append partially + if (implicit_cast(avail()) > len) + { + memcpy(cur_, buf, len); + cur_ += len; + } + } + + const char* data() const { return data_; } + int length() const { return static_cast(cur_ - data_); } + + // write to data_ directly + char* current() { return cur_; } + int avail() const { return static_cast(end() - cur_); } + void add(size_t len) { cur_ += len; } + + void reset() { cur_ = data_; } + void bzero() { memZero(data_, sizeof data_); } + + // for used by GDB + const char* debugString(); + void setCookie(void (*cookie)()) { cookie_ = cookie; } + // for used by unit test + string toString() const { return string(data_, length()); } + StringPiece toStringPiece() const { return StringPiece(data_, length()); } + + private: + const char* end() const { return data_ + sizeof data_; } + // Must be outline function for cookies. + static void cookieStart(); + static void cookieEnd(); + + void (*cookie_)(); + char data_[SIZE]; + char* cur_; +}; + +} // namespace detail + +class LogStream : noncopyable +{ + typedef LogStream self; + public: + typedef detail::FixedBuffer Buffer; + + self& operator<<(bool v) + { + buffer_.append(v ? "1" : "0", 1); + return *this; + } + + self& operator<<(short); + self& operator<<(unsigned short); + self& operator<<(int); + self& operator<<(unsigned int); + self& operator<<(long); + self& operator<<(unsigned long); + self& operator<<(long long); + self& operator<<(unsigned long long); + + self& operator<<(const void*); + + self& operator<<(float v) + { + *this << static_cast(v); + return *this; + } + self& operator<<(double); + // self& operator<<(long double); + + self& operator<<(char v) + { + buffer_.append(&v, 1); + return *this; + } + + // self& operator<<(signed char); + // self& operator<<(unsigned char); + + self& operator<<(const char* str) + { + if (str) + { + buffer_.append(str, strlen(str)); + } + else + { + buffer_.append("(null)", 6); + } + return *this; + } + + self& operator<<(const unsigned char* str) + { + return operator<<(reinterpret_cast(str)); + } + + self& operator<<(const string& v) + { + buffer_.append(v.c_str(), v.size()); + return *this; + } + + self& operator<<(const StringPiece& v) + { + buffer_.append(v.data(), v.size()); + return *this; + } + + self& operator<<(const Buffer& v) + { + *this << v.toStringPiece(); + return *this; + } + + void append(const char* data, int len) { buffer_.append(data, len); } + const Buffer& buffer() const { return buffer_; } + void resetBuffer() { buffer_.reset(); } + + private: + void staticCheck(); + + template + void formatInteger(T); + + Buffer buffer_; + + static const int kMaxNumericSize = 32; +}; + +class Fmt // : noncopyable +{ + public: + template + Fmt(const char* fmt, T val); + + const char* data() const { return buf_; } + int length() const { return length_; } + + private: + char buf_[32]; + int length_; +}; + +inline LogStream& operator<<(LogStream& s, const Fmt& fmt) +{ + s.append(fmt.data(), fmt.length()); + return s; +} + +// Format quantity n in SI units (k, M, G, T, P, E). +// The returned string is atmost 5 characters long. +// Requires n >= 0 +string formatSI(int64_t n); + +// Format quantity n in IEC (binary) units (Ki, Mi, Gi, Ti, Pi, Ei). +// The returned string is atmost 6 characters long. +// Requires n >= 0 +string formatIEC(int64_t n); + +} // namespace muduo + +#endif // MUDUO_BASE_LOGSTREAM_H diff --git a/include/Third_Lib/muduo/base/Logging.cc b/include/Third_Lib/muduo/base/Logging.cc new file mode 100644 index 0000000..c09a8ce --- /dev/null +++ b/include/Third_Lib/muduo/base/Logging.cc @@ -0,0 +1,227 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/base/Logging.h" + +#include "muduo/base/CurrentThread.h" +#include "muduo/base/Timestamp.h" +#include "muduo/base/TimeZone.h" + +#include +#include +#include + +#include + +namespace muduo +{ + +/* +class LoggerImpl +{ + public: + typedef Logger::LogLevel LogLevel; + LoggerImpl(LogLevel level, int old_errno, const char* file, int line); + void finish(); + + Timestamp time_; + LogStream stream_; + LogLevel level_; + int line_; + const char* fullname_; + const char* basename_; +}; +*/ + +__thread char t_errnobuf[512]; +__thread char t_time[64]; +__thread time_t t_lastSecond; + +const char* strerror_tl(int savedErrno) +{ + return strerror_r(savedErrno, t_errnobuf, sizeof t_errnobuf); +} + +Logger::LogLevel initLogLevel() +{ + if (::getenv("MUDUO_LOG_TRACE")) + return Logger::TRACE; + else if (::getenv("MUDUO_LOG_DEBUG")) + return Logger::DEBUG; + else + return Logger::INFO; +} + +Logger::LogLevel g_logLevel = initLogLevel(); + +const char* LogLevelName[Logger::NUM_LOG_LEVELS] = +{ + "TRACE ", + "DEBUG ", + "INFO ", + "WARN ", + "ERROR ", + "FATAL ", +}; + +// helper class for known string length at compile time +class T +{ + public: + T(const char* str, unsigned len) + :str_(str), + len_(len) + { + assert(strlen(str) == len_); + } + + const char* str_; + const unsigned len_; +}; + +inline LogStream& operator<<(LogStream& s, T v) +{ + s.append(v.str_, v.len_); + return s; +} + +inline LogStream& operator<<(LogStream& s, const Logger::SourceFile& v) +{ + s.append(v.data_, v.size_); + return s; +} + +void defaultOutput(const char* msg, int len) +{ + size_t n = fwrite(msg, 1, len, stdout); + //FIXME check n + (void)n; +} + +void defaultFlush() +{ + fflush(stdout); +} + +Logger::OutputFunc g_output = defaultOutput; +Logger::FlushFunc g_flush = defaultFlush; +TimeZone g_logTimeZone; + +} // namespace muduo + +using namespace muduo; + +Logger::Impl::Impl(LogLevel level, int savedErrno, const SourceFile& file, int line) + : time_(Timestamp::now()), + stream_(), + level_(level), + line_(line), + basename_(file) +{ + formatTime(); + CurrentThread::tid(); + stream_ << T(CurrentThread::tidString(), CurrentThread::tidStringLength()); + stream_ << T(LogLevelName[level], 6); + if (savedErrno != 0) + { + stream_ << strerror_tl(savedErrno) << " (errno=" << savedErrno << ") "; + } +} + +void Logger::Impl::formatTime() +{ + int64_t microSecondsSinceEpoch = time_.microSecondsSinceEpoch(); + time_t seconds = static_cast(microSecondsSinceEpoch / Timestamp::kMicroSecondsPerSecond); + int microseconds = static_cast(microSecondsSinceEpoch % Timestamp::kMicroSecondsPerSecond); + if (seconds != t_lastSecond) + { + t_lastSecond = seconds; + struct tm tm_time; + if (g_logTimeZone.valid()) + { + tm_time = g_logTimeZone.toLocalTime(seconds); + } + else + { + ::gmtime_r(&seconds, &tm_time); // FIXME TimeZone::fromUtcTime + } + + int len = snprintf(t_time, sizeof(t_time), "%4d%02d%02d %02d:%02d:%02d", + tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday, + tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec); + assert(len == 17); (void)len; + } + + if (g_logTimeZone.valid()) + { + Fmt us(".%06d ", microseconds); + assert(us.length() == 8); + stream_ << T(t_time, 17) << T(us.data(), 8); + } + else + { + Fmt us(".%06dZ ", microseconds); + assert(us.length() == 9); + stream_ << T(t_time, 17) << T(us.data(), 9); + } +} + +void Logger::Impl::finish() +{ + stream_ << " - " << basename_ << ':' << line_ << '\n'; +} + +Logger::Logger(SourceFile file, int line) + : impl_(INFO, 0, file, line) +{ +} + +Logger::Logger(SourceFile file, int line, LogLevel level, const char* func) + : impl_(level, 0, file, line) +{ + impl_.stream_ << func << ' '; +} + +Logger::Logger(SourceFile file, int line, LogLevel level) + : impl_(level, 0, file, line) +{ +} + +Logger::Logger(SourceFile file, int line, bool toAbort) + : impl_(toAbort?FATAL:ERROR, errno, file, line) +{ +} + +Logger::~Logger() +{ + impl_.finish(); + const LogStream::Buffer& buf(stream().buffer()); + g_output(buf.data(), buf.length()); + if (impl_.level_ == FATAL) + { + g_flush(); + abort(); + } +} + +void Logger::setLogLevel(Logger::LogLevel level) +{ + g_logLevel = level; +} + +void Logger::setOutput(OutputFunc out) +{ + g_output = out; +} + +void Logger::setFlush(FlushFunc flush) +{ + g_flush = flush; +} + +void Logger::setTimeZone(const TimeZone& tz) +{ + g_logTimeZone = tz; +} diff --git a/include/Third_Lib/muduo/base/Logging.h b/include/Third_Lib/muduo/base/Logging.h new file mode 100644 index 0000000..be56689 --- /dev/null +++ b/include/Third_Lib/muduo/base/Logging.h @@ -0,0 +1,159 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_LOGGING_H +#define MUDUO_BASE_LOGGING_H + +#include "muduo/base/LogStream.h" +#include "muduo/base/Timestamp.h" + +namespace muduo +{ + +class TimeZone; + +class Logger +{ + public: + enum LogLevel + { + TRACE, + DEBUG, + INFO, + WARN, + ERROR, + FATAL, + NUM_LOG_LEVELS, + }; + + // compile time calculation of basename of source file + class SourceFile + { + public: + template + SourceFile(const char (&arr)[N]) + : data_(arr), + size_(N-1) + { + const char* slash = strrchr(data_, '/'); // builtin function + if (slash) + { + data_ = slash + 1; + size_ -= static_cast(data_ - arr); + } + } + + explicit SourceFile(const char* filename) + : data_(filename) + { + const char* slash = strrchr(filename, '/'); + if (slash) + { + data_ = slash + 1; + } + size_ = static_cast(strlen(data_)); + } + + const char* data_; + int size_; + }; + + Logger(SourceFile file, int line); + Logger(SourceFile file, int line, LogLevel level); + Logger(SourceFile file, int line, LogLevel level, const char* func); + Logger(SourceFile file, int line, bool toAbort); + ~Logger(); + + LogStream& stream() { return impl_.stream_; } + + static LogLevel logLevel(); + static void setLogLevel(LogLevel level); + + typedef void (*OutputFunc)(const char* msg, int len); + typedef void (*FlushFunc)(); + static void setOutput(OutputFunc); + static void setFlush(FlushFunc); + static void setTimeZone(const TimeZone& tz); + + private: + +class Impl +{ + public: + typedef Logger::LogLevel LogLevel; + Impl(LogLevel level, int old_errno, const SourceFile& file, int line); + void formatTime(); + void finish(); + + Timestamp time_; + LogStream stream_; + LogLevel level_; + int line_; + SourceFile basename_; +}; + + Impl impl_; + +}; + +extern Logger::LogLevel g_logLevel; + +inline Logger::LogLevel Logger::logLevel() +{ + return g_logLevel; +} + +// +// CAUTION: do not write: +// +// if (good) +// LOG_INFO << "Good news"; +// else +// LOG_WARN << "Bad news"; +// +// this expends to +// +// if (good) +// if (logging_INFO) +// logInfoStream << "Good news"; +// else +// logWarnStream << "Bad news"; +// +#define LOG_TRACE if (muduo::Logger::logLevel() <= muduo::Logger::TRACE) \ + muduo::Logger(__FILE__, __LINE__, muduo::Logger::TRACE, __func__).stream() +#define LOG_DEBUG if (muduo::Logger::logLevel() <= muduo::Logger::DEBUG) \ + muduo::Logger(__FILE__, __LINE__, muduo::Logger::DEBUG, __func__).stream() +#define LOG_INFO if (muduo::Logger::logLevel() <= muduo::Logger::INFO) \ + muduo::Logger(__FILE__, __LINE__).stream() +#define LOG_WARN muduo::Logger(__FILE__, __LINE__, muduo::Logger::WARN).stream() +#define LOG_ERROR muduo::Logger(__FILE__, __LINE__, muduo::Logger::ERROR).stream() +#define LOG_FATAL muduo::Logger(__FILE__, __LINE__, muduo::Logger::FATAL).stream() +#define LOG_SYSERR muduo::Logger(__FILE__, __LINE__, false).stream() +#define LOG_SYSFATAL muduo::Logger(__FILE__, __LINE__, true).stream() + +const char* strerror_tl(int savedErrno); + +// Taken from glog/logging.h +// +// Check that the input is non NULL. This very useful in constructor +// initializer lists. + +#define CHECK_NOTNULL(val) \ + ::muduo::CheckNotNull(__FILE__, __LINE__, "'" #val "' Must be non NULL", (val)) + +// A small helper for CHECK_NOTNULL(). +template +T* CheckNotNull(Logger::SourceFile file, int line, const char *names, T* ptr) +{ + if (ptr == NULL) + { + Logger(file, line, Logger::FATAL).stream() << names; + } + return ptr; +} + +} // namespace muduo + +#endif // MUDUO_BASE_LOGGING_H diff --git a/include/Third_Lib/muduo/base/Mutex.h b/include/Third_Lib/muduo/base/Mutex.h new file mode 100644 index 0000000..20746bd --- /dev/null +++ b/include/Third_Lib/muduo/base/Mutex.h @@ -0,0 +1,233 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_MUTEX_H +#define MUDUO_BASE_MUTEX_H + +#include "muduo/base/CurrentThread.h" +#include "muduo/base/noncopyable.h" +#include +#include + +// Thread safety annotations { +// https://clang.llvm.org/docs/ThreadSafetyAnalysis.html + +// Enable thread safety attributes only with clang. +// The attributes can be safely erased when compiling with other compilers. +#if defined(__clang__) && (!defined(SWIG)) +#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x)) +#else +#define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op +#endif + +#define CAPABILITY(x) \ + THREAD_ANNOTATION_ATTRIBUTE__(capability(x)) + +#define SCOPED_CAPABILITY \ + THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable) + +#define GUARDED_BY(x) \ + THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x)) + +#define PT_GUARDED_BY(x) \ + THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x)) + +#define ACQUIRED_BEFORE(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__)) + +#define ACQUIRED_AFTER(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__)) + +#define REQUIRES(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(__VA_ARGS__)) + +#define REQUIRES_SHARED(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(requires_shared_capability(__VA_ARGS__)) + +#define ACQUIRE(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(__VA_ARGS__)) + +#define ACQUIRE_SHARED(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__)) + +#define RELEASE(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(release_capability(__VA_ARGS__)) + +#define RELEASE_SHARED(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__)) + +#define TRY_ACQUIRE(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__)) + +#define TRY_ACQUIRE_SHARED(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__)) + +#define EXCLUDES(...) \ + THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__)) + +#define ASSERT_CAPABILITY(x) \ + THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(x)) + +#define ASSERT_SHARED_CAPABILITY(x) \ + THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(x)) + +#define RETURN_CAPABILITY(x) \ + THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x)) + +#define NO_THREAD_SAFETY_ANALYSIS \ + THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis) + +// End of thread safety annotations } + +#ifdef CHECK_PTHREAD_RETURN_VALUE + +#ifdef NDEBUG +__BEGIN_DECLS +extern void __assert_perror_fail (int errnum, + const char *file, + unsigned int line, + const char *function) + noexcept __attribute__ ((__noreturn__)); +__END_DECLS +#endif + +#define MCHECK(ret) ({ __typeof__ (ret) errnum = (ret); \ + if (__builtin_expect(errnum != 0, 0)) \ + __assert_perror_fail (errnum, __FILE__, __LINE__, __func__);}) + +#else // CHECK_PTHREAD_RETURN_VALUE + +#define MCHECK(ret) ({ __typeof__ (ret) errnum = (ret); \ + assert(errnum == 0); (void) errnum;}) + +#endif // CHECK_PTHREAD_RETURN_VALUE + +namespace muduo +{ + +// Use as data member of a class, eg. +// +// class Foo +// { +// public: +// int size() const; +// +// private: +// mutable MutexLock mutex_; +// std::vector data_ GUARDED_BY(mutex_); +// }; +class CAPABILITY("mutex") MutexLock : noncopyable +{ + public: + MutexLock() + : holder_(0) + { + MCHECK(pthread_mutex_init(&mutex_, NULL)); + } + + ~MutexLock() + { + assert(holder_ == 0); + MCHECK(pthread_mutex_destroy(&mutex_)); + } + + // must be called when locked, i.e. for assertion + bool isLockedByThisThread() const + { + return holder_ == CurrentThread::tid(); + } + + void assertLocked() const ASSERT_CAPABILITY(this) + { + assert(isLockedByThisThread()); + } + + // internal usage + + void lock() ACQUIRE() + { + MCHECK(pthread_mutex_lock(&mutex_)); + assignHolder(); + } + + void unlock() RELEASE() + { + unassignHolder(); + MCHECK(pthread_mutex_unlock(&mutex_)); + } + + pthread_mutex_t* getPthreadMutex() /* non-const */ + { + return &mutex_; + } + + private: + friend class Condition; + + class UnassignGuard : noncopyable + { + public: + explicit UnassignGuard(MutexLock& owner) + : owner_(owner) + { + owner_.unassignHolder(); + } + + ~UnassignGuard() + { + owner_.assignHolder(); + } + + private: + MutexLock& owner_; + }; + + void unassignHolder() + { + holder_ = 0; + } + + void assignHolder() + { + holder_ = CurrentThread::tid(); + } + + pthread_mutex_t mutex_; + pid_t holder_; +}; + +// Use as a stack variable, eg. +// int Foo::size() const +// { +// MutexLockGuard lock(mutex_); +// return data_.size(); +// } +class SCOPED_CAPABILITY MutexLockGuard : noncopyable +{ + public: + explicit MutexLockGuard(MutexLock& mutex) ACQUIRE(mutex) + : mutex_(mutex) + { + mutex_.lock(); + } + + ~MutexLockGuard() RELEASE() + { + mutex_.unlock(); + } + + private: + + MutexLock& mutex_; +}; + +} // namespace muduo + +// Prevent misuse like: +// MutexLockGuard(mutex_); +// A tempory object doesn't hold the lock for long! +#define MutexLockGuard(x) error "Missing guard object name" + +#endif // MUDUO_BASE_MUTEX_H diff --git a/include/Third_Lib/muduo/base/ProcessInfo.cc b/include/Third_Lib/muduo/base/ProcessInfo.cc new file mode 100644 index 0000000..6ab5ad1 --- /dev/null +++ b/include/Third_Lib/muduo/base/ProcessInfo.cc @@ -0,0 +1,246 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/base/ProcessInfo.h" +#include "muduo/base/CurrentThread.h" +#include "muduo/base/FileUtil.h" + +#include + +#include +#include +#include +#include // snprintf +#include +#include +#include +#include + +namespace muduo +{ +namespace detail +{ +__thread int t_numOpenedFiles = 0; +int fdDirFilter(const struct dirent* d) +{ + if (::isdigit(d->d_name[0])) + { + ++t_numOpenedFiles; + } + return 0; +} + +__thread std::vector* t_pids = NULL; +int taskDirFilter(const struct dirent* d) +{ + if (::isdigit(d->d_name[0])) + { + t_pids->push_back(atoi(d->d_name)); + } + return 0; +} + +int scanDir(const char *dirpath, int (*filter)(const struct dirent *)) +{ + struct dirent** namelist = NULL; + int result = ::scandir(dirpath, &namelist, filter, alphasort); + assert(namelist == NULL); + return result; +} + +Timestamp g_startTime = Timestamp::now(); +// assume those won't change during the life time of a process. +int g_clockTicks = static_cast(::sysconf(_SC_CLK_TCK)); +int g_pageSize = static_cast(::sysconf(_SC_PAGE_SIZE)); +} // namespace detail +} // namespace muduo + +using namespace muduo; +using namespace muduo::detail; + +pid_t ProcessInfo::pid() +{ + return ::getpid(); +} + +string ProcessInfo::pidString() +{ + char buf[32]; + snprintf(buf, sizeof buf, "%d", pid()); + return buf; +} + +uid_t ProcessInfo::uid() +{ + return ::getuid(); +} + +string ProcessInfo::username() +{ + struct passwd pwd; + struct passwd* result = NULL; + char buf[8192]; + const char* name = "unknownuser"; + + getpwuid_r(uid(), &pwd, buf, sizeof buf, &result); + if (result) + { + name = pwd.pw_name; + } + return name; +} + +uid_t ProcessInfo::euid() +{ + return ::geteuid(); +} + +Timestamp ProcessInfo::startTime() +{ + return g_startTime; +} + +int ProcessInfo::clockTicksPerSecond() +{ + return g_clockTicks; +} + +int ProcessInfo::pageSize() +{ + return g_pageSize; +} + +bool ProcessInfo::isDebugBuild() +{ +#ifdef NDEBUG + return false; +#else + return true; +#endif +} + +string ProcessInfo::hostname() +{ + // HOST_NAME_MAX 64 + // _POSIX_HOST_NAME_MAX 255 + char buf[256]; + if (::gethostname(buf, sizeof buf) == 0) + { + buf[sizeof(buf)-1] = '\0'; + return buf; + } + else + { + return "unknownhost"; + } +} + +string ProcessInfo::procname() +{ + return procname(procStat()).as_string(); +} + +StringPiece ProcessInfo::procname(const string& stat) +{ + StringPiece name; + size_t lp = stat.find('('); + size_t rp = stat.rfind(')'); + if (lp != string::npos && rp != string::npos && lp < rp) + { + name.set(stat.data()+lp+1, static_cast(rp-lp-1)); + } + return name; +} + +string ProcessInfo::procStatus() +{ + string result; + FileUtil::readFile("/proc/self/status", 65536, &result); + return result; +} + +string ProcessInfo::procStat() +{ + string result; + FileUtil::readFile("/proc/self/stat", 65536, &result); + return result; +} + +string ProcessInfo::threadStat() +{ + char buf[64]; + snprintf(buf, sizeof buf, "/proc/self/task/%d/stat", CurrentThread::tid()); + string result; + FileUtil::readFile(buf, 65536, &result); + return result; +} + +string ProcessInfo::exePath() +{ + string result; + char buf[1024]; + ssize_t n = ::readlink("/proc/self/exe", buf, sizeof buf); + if (n > 0) + { + result.assign(buf, n); + } + return result; +} + +int ProcessInfo::openedFiles() +{ + t_numOpenedFiles = 0; + scanDir("/proc/self/fd", fdDirFilter); + return t_numOpenedFiles; +} + +int ProcessInfo::maxOpenFiles() +{ + struct rlimit rl; + if (::getrlimit(RLIMIT_NOFILE, &rl)) + { + return openedFiles(); + } + else + { + return static_cast(rl.rlim_cur); + } +} + +ProcessInfo::CpuTime ProcessInfo::cpuTime() +{ + ProcessInfo::CpuTime t; + struct tms tms; + if (::times(&tms) >= 0) + { + const double hz = static_cast(clockTicksPerSecond()); + t.userSeconds = static_cast(tms.tms_utime) / hz; + t.systemSeconds = static_cast(tms.tms_stime) / hz; + } + return t; +} + +int ProcessInfo::numThreads() +{ + int result = 0; + string status = procStatus(); + size_t pos = status.find("Threads:"); + if (pos != string::npos) + { + result = ::atoi(status.c_str() + pos + 8); + } + return result; +} + +std::vector ProcessInfo::threads() +{ + std::vector result; + t_pids = &result; + scanDir("/proc/self/task", taskDirFilter); + t_pids = NULL; + std::sort(result.begin(), result.end()); + return result; +} + diff --git a/include/Third_Lib/muduo/base/ProcessInfo.h b/include/Third_Lib/muduo/base/ProcessInfo.h new file mode 100644 index 0000000..eae1498 --- /dev/null +++ b/include/Third_Lib/muduo/base/ProcessInfo.h @@ -0,0 +1,68 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_BASE_PROCESSINFO_H +#define MUDUO_BASE_PROCESSINFO_H + +#include "muduo/base/StringPiece.h" +#include "muduo/base/Types.h" +#include "muduo/base/Timestamp.h" +#include +#include + +namespace muduo +{ + +namespace ProcessInfo +{ + pid_t pid(); + string pidString(); + uid_t uid(); + string username(); + uid_t euid(); + Timestamp startTime(); + int clockTicksPerSecond(); + int pageSize(); + bool isDebugBuild(); // constexpr + + string hostname(); + string procname(); + StringPiece procname(const string& stat); + + /// read /proc/self/status + string procStatus(); + + /// read /proc/self/stat + string procStat(); + + /// read /proc/self/task/tid/stat + string threadStat(); + + /// readlink /proc/self/exe + string exePath(); + + int openedFiles(); + int maxOpenFiles(); + + struct CpuTime + { + double userSeconds; + double systemSeconds; + + CpuTime() : userSeconds(0.0), systemSeconds(0.0) { } + + double total() const { return userSeconds + systemSeconds; } + }; + CpuTime cpuTime(); + + int numThreads(); + std::vector threads(); +} // namespace ProcessInfo + +} // namespace muduo + +#endif // MUDUO_BASE_PROCESSINFO_H diff --git a/include/Third_Lib/muduo/base/Singleton.h b/include/Third_Lib/muduo/base/Singleton.h new file mode 100644 index 0000000..5949436 --- /dev/null +++ b/include/Third_Lib/muduo/base/Singleton.h @@ -0,0 +1,77 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_SINGLETON_H +#define MUDUO_BASE_SINGLETON_H + +#include "muduo/base/noncopyable.h" + +#include +#include +#include // atexit + +namespace muduo +{ + +namespace detail +{ +// This doesn't detect inherited member functions! +// http://stackoverflow.com/questions/1966362/sfinae-to-check-for-inherited-member-functions +template +struct has_no_destroy +{ + template static char test(decltype(&C::no_destroy)); + template static int32_t test(...); + const static bool value = sizeof(test(0)) == 1; +}; +} // namespace detail + +template +class Singleton : noncopyable +{ + public: + Singleton() = delete; + ~Singleton() = delete; + + static T& instance() + { + pthread_once(&ponce_, &Singleton::init); + assert(value_ != NULL); + return *value_; + } + + private: + static void init() + { + value_ = new T(); + if (!detail::has_no_destroy::value) + { + ::atexit(destroy); + } + } + + static void destroy() + { + typedef char T_must_be_complete_type[sizeof(T) == 0 ? -1 : 1]; + T_must_be_complete_type dummy; (void) dummy; + + delete value_; + value_ = NULL; + } + + private: + static pthread_once_t ponce_; + static T* value_; +}; + +template +pthread_once_t Singleton::ponce_ = PTHREAD_ONCE_INIT; + +template +T* Singleton::value_ = NULL; + +} // namespace muduo + +#endif // MUDUO_BASE_SINGLETON_H diff --git a/include/Third_Lib/muduo/base/StringPiece.h b/include/Third_Lib/muduo/base/StringPiece.h new file mode 100644 index 0000000..a62eda0 --- /dev/null +++ b/include/Third_Lib/muduo/base/StringPiece.h @@ -0,0 +1,189 @@ +// Taken from PCRE pcre_stringpiece.h +// +// Copyright (c) 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Author: Sanjay Ghemawat +// +// A string like object that points into another piece of memory. +// Useful for providing an interface that allows clients to easily +// pass in either a "const char*" or a "string". +// +// Arghh! I wish C++ literals were automatically of type "string". + +#ifndef MUDUO_BASE_STRINGPIECE_H +#define MUDUO_BASE_STRINGPIECE_H + +#include +#include // for ostream forward-declaration + +#include "muduo/base/Types.h" + +namespace muduo +{ + +// For passing C-style string argument to a function. +class StringArg // copyable +{ + public: + StringArg(const char* str) + : str_(str) + { } + + StringArg(const string& str) + : str_(str.c_str()) + { } + + const char* c_str() const { return str_; } + + private: + const char* str_; +}; + +class StringPiece { + private: + const char* ptr_; + int length_; + + public: + // We provide non-explicit singleton constructors so users can pass + // in a "const char*" or a "string" wherever a "StringPiece" is + // expected. + StringPiece() + : ptr_(NULL), length_(0) { } + StringPiece(const char* str) + : ptr_(str), length_(static_cast(strlen(ptr_))) { } + StringPiece(const unsigned char* str) + : ptr_(reinterpret_cast(str)), + length_(static_cast(strlen(ptr_))) { } + StringPiece(const string& str) + : ptr_(str.data()), length_(static_cast(str.size())) { } + StringPiece(const char* offset, int len) + : ptr_(offset), length_(len) { } + + // data() may return a pointer to a buffer with embedded NULs, and the + // returned buffer may or may not be null terminated. Therefore it is + // typically a mistake to pass data() to a routine that expects a NUL + // terminated string. Use "as_string().c_str()" if you really need to do + // this. Or better yet, change your routine so it does not rely on NUL + // termination. + const char* data() const { return ptr_; } + int size() const { return length_; } + bool empty() const { return length_ == 0; } + const char* begin() const { return ptr_; } + const char* end() const { return ptr_ + length_; } + + void clear() { ptr_ = NULL; length_ = 0; } + void set(const char* buffer, int len) { ptr_ = buffer; length_ = len; } + void set(const char* str) { + ptr_ = str; + length_ = static_cast(strlen(str)); + } + void set(const void* buffer, int len) { + ptr_ = reinterpret_cast(buffer); + length_ = len; + } + + char operator[](int i) const { return ptr_[i]; } + + void remove_prefix(int n) { + ptr_ += n; + length_ -= n; + } + + void remove_suffix(int n) { + length_ -= n; + } + + bool operator==(const StringPiece& x) const { + return ((length_ == x.length_) && + (memcmp(ptr_, x.ptr_, length_) == 0)); + } + bool operator!=(const StringPiece& x) const { + return !(*this == x); + } + +#define STRINGPIECE_BINARY_PREDICATE(cmp,auxcmp) \ + bool operator cmp (const StringPiece& x) const { \ + int r = memcmp(ptr_, x.ptr_, length_ < x.length_ ? length_ : x.length_); \ + return ((r auxcmp 0) || ((r == 0) && (length_ cmp x.length_))); \ + } + STRINGPIECE_BINARY_PREDICATE(<, <); + STRINGPIECE_BINARY_PREDICATE(<=, <); + STRINGPIECE_BINARY_PREDICATE(>=, >); + STRINGPIECE_BINARY_PREDICATE(>, >); +#undef STRINGPIECE_BINARY_PREDICATE + + int compare(const StringPiece& x) const { + int r = memcmp(ptr_, x.ptr_, length_ < x.length_ ? length_ : x.length_); + if (r == 0) { + if (length_ < x.length_) r = -1; + else if (length_ > x.length_) r = +1; + } + return r; + } + + string as_string() const { + return string(data(), size()); + } + + void CopyToString(string* target) const { + target->assign(ptr_, length_); + } + + // Does "this" start with "x" + bool starts_with(const StringPiece& x) const { + return ((length_ >= x.length_) && (memcmp(ptr_, x.ptr_, x.length_) == 0)); + } +}; + +} // namespace muduo + +// ------------------------------------------------------------------ +// Functions used to create STL containers that use StringPiece +// Remember that a StringPiece's lifetime had better be less than +// that of the underlying string or char*. If it is not, then you +// cannot safely store a StringPiece into an STL container +// ------------------------------------------------------------------ + +#ifdef HAVE_TYPE_TRAITS +// This makes vector really fast for some STL implementations +template<> struct __type_traits { + typedef __true_type has_trivial_default_constructor; + typedef __true_type has_trivial_copy_constructor; + typedef __true_type has_trivial_assignment_operator; + typedef __true_type has_trivial_destructor; + typedef __true_type is_POD_type; +}; +#endif + +// allow StringPiece to be logged +std::ostream& operator<<(std::ostream& o, const muduo::StringPiece& piece); + +#endif // MUDUO_BASE_STRINGPIECE_H diff --git a/include/Third_Lib/muduo/base/Thread.cc b/include/Third_Lib/muduo/base/Thread.cc new file mode 100644 index 0000000..630a0c9 --- /dev/null +++ b/include/Third_Lib/muduo/base/Thread.cc @@ -0,0 +1,200 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/base/Thread.h" +#include "muduo/base/CurrentThread.h" +#include "muduo/base/Exception.h" +#include "muduo/base/Logging.h" + +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace muduo +{ +namespace detail +{ + +pid_t gettid() +{ + return static_cast(::syscall(SYS_gettid)); +} + +void afterFork() +{ + muduo::CurrentThread::t_cachedTid = 0; + muduo::CurrentThread::t_threadName = "main"; + CurrentThread::tid(); + // no need to call pthread_atfork(NULL, NULL, &afterFork); +} + +class ThreadNameInitializer +{ + public: + ThreadNameInitializer() + { + muduo::CurrentThread::t_threadName = "main"; + CurrentThread::tid(); + pthread_atfork(NULL, NULL, &afterFork); + } +}; + +ThreadNameInitializer init; + +struct ThreadData +{ + typedef muduo::Thread::ThreadFunc ThreadFunc; + ThreadFunc func_; + string name_; + pid_t* tid_; + CountDownLatch* latch_; + + ThreadData(ThreadFunc func, + const string& name, + pid_t* tid, + CountDownLatch* latch) + : func_(std::move(func)), + name_(name), + tid_(tid), + latch_(latch) + { } + + void runInThread() + { + *tid_ = muduo::CurrentThread::tid(); + tid_ = NULL; + latch_->countDown(); + latch_ = NULL; + + muduo::CurrentThread::t_threadName = name_.empty() ? "muduoThread" : name_.c_str(); + ::prctl(PR_SET_NAME, muduo::CurrentThread::t_threadName); + try + { + func_(); + muduo::CurrentThread::t_threadName = "finished"; + } + catch (const Exception& ex) + { + muduo::CurrentThread::t_threadName = "crashed"; + fprintf(stderr, "exception caught in Thread %s\n", name_.c_str()); + fprintf(stderr, "reason: %s\n", ex.what()); + fprintf(stderr, "stack trace: %s\n", ex.stackTrace()); + abort(); + } + catch (const std::exception& ex) + { + muduo::CurrentThread::t_threadName = "crashed"; + fprintf(stderr, "exception caught in Thread %s\n", name_.c_str()); + fprintf(stderr, "reason: %s\n", ex.what()); + abort(); + } + catch (...) + { + muduo::CurrentThread::t_threadName = "crashed"; + fprintf(stderr, "unknown exception caught in Thread %s\n", name_.c_str()); + throw; // rethrow + } + } +}; + +void* startThread(void* obj) +{ + ThreadData* data = static_cast(obj); + data->runInThread(); + delete data; + return NULL; +} + +} // namespace detail + +void CurrentThread::cacheTid() +{ + if (t_cachedTid == 0) + { + t_cachedTid = detail::gettid(); + t_tidStringLength = snprintf(t_tidString, sizeof t_tidString, "%5d ", t_cachedTid); + } +} + +bool CurrentThread::isMainThread() +{ + return tid() == ::getpid(); +} + +void CurrentThread::sleepUsec(int64_t usec) +{ + struct timespec ts = { 0, 0 }; + ts.tv_sec = static_cast(usec / Timestamp::kMicroSecondsPerSecond); + ts.tv_nsec = static_cast(usec % Timestamp::kMicroSecondsPerSecond * 1000); + ::nanosleep(&ts, NULL); +} + +AtomicInt32 Thread::numCreated_; + +Thread::Thread(ThreadFunc func, const string& n) + : started_(false), + joined_(false), + pthreadId_(0), + tid_(0), + func_(std::move(func)), + name_(n), + latch_(1) +{ + setDefaultName(); +} + +Thread::~Thread() +{ + if (started_ && !joined_) + { + pthread_detach(pthreadId_); + } +} + +void Thread::setDefaultName() +{ + int num = numCreated_.incrementAndGet(); + if (name_.empty()) + { + char buf[32]; + snprintf(buf, sizeof buf, "Thread%d", num); + name_ = buf; + } +} + +void Thread::start() +{ + assert(!started_); + started_ = true; + // FIXME: move(func_) + detail::ThreadData* data = new detail::ThreadData(func_, name_, &tid_, &latch_); + if (pthread_create(&pthreadId_, NULL, &detail::startThread, data)) + { + started_ = false; + delete data; // or no delete? + LOG_SYSFATAL << "Failed in pthread_create"; + } + else + { + latch_.wait(); + assert(tid_ > 0); + } +} + +int Thread::join() +{ + assert(started_); + assert(!joined_); + joined_ = true; + return pthread_join(pthreadId_, NULL); +} + +} // namespace muduo diff --git a/include/Third_Lib/muduo/base/Thread.h b/include/Third_Lib/muduo/base/Thread.h new file mode 100644 index 0000000..d2305a2 --- /dev/null +++ b/include/Third_Lib/muduo/base/Thread.h @@ -0,0 +1,54 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_THREAD_H +#define MUDUO_BASE_THREAD_H + +#include "muduo/base/Atomic.h" +#include "muduo/base/CountDownLatch.h" +#include "muduo/base/Types.h" + +#include +#include +#include + +namespace muduo +{ + +class Thread : noncopyable +{ + public: + typedef std::function ThreadFunc; + + explicit Thread(ThreadFunc, const string& name = string()); + // FIXME: make it movable in C++11 + ~Thread(); + + void start(); + int join(); // return pthread_join() + + bool started() const { return started_; } + // pthread_t pthreadId() const { return pthreadId_; } + pid_t tid() const { return tid_; } + const string& name() const { return name_; } + + static int numCreated() { return numCreated_.get(); } + + private: + void setDefaultName(); + + bool started_; + bool joined_; + pthread_t pthreadId_; + pid_t tid_; + ThreadFunc func_; + string name_; + CountDownLatch latch_; + + static AtomicInt32 numCreated_; +}; + +} // namespace muduo +#endif // MUDUO_BASE_THREAD_H diff --git a/include/Third_Lib/muduo/base/ThreadLocal.h b/include/Third_Lib/muduo/base/ThreadLocal.h new file mode 100644 index 0000000..b8283bc --- /dev/null +++ b/include/Third_Lib/muduo/base/ThreadLocal.h @@ -0,0 +1,59 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_THREADLOCAL_H +#define MUDUO_BASE_THREADLOCAL_H + +#include "muduo/base/Mutex.h" +#include "muduo/base/noncopyable.h" + +#include + +namespace muduo +{ + +template +class ThreadLocal : noncopyable +{ + public: + ThreadLocal() + { + MCHECK(pthread_key_create(&pkey_, &ThreadLocal::destructor)); + } + + ~ThreadLocal() + { + MCHECK(pthread_key_delete(pkey_)); + } + + T& value() + { + T* perThreadValue = static_cast(pthread_getspecific(pkey_)); + if (!perThreadValue) + { + T* newObj = new T(); + MCHECK(pthread_setspecific(pkey_, newObj)); + perThreadValue = newObj; + } + return *perThreadValue; + } + + private: + + static void destructor(void *x) + { + T* obj = static_cast(x); + typedef char T_must_be_complete_type[sizeof(T) == 0 ? -1 : 1]; + T_must_be_complete_type dummy; (void) dummy; + delete obj; + } + + private: + pthread_key_t pkey_; +}; + +} // namespace muduo + +#endif // MUDUO_BASE_THREADLOCAL_H diff --git a/include/Third_Lib/muduo/base/ThreadLocalSingleton.h b/include/Third_Lib/muduo/base/ThreadLocalSingleton.h new file mode 100644 index 0000000..5c544df --- /dev/null +++ b/include/Third_Lib/muduo/base/ThreadLocalSingleton.h @@ -0,0 +1,82 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_THREADLOCALSINGLETON_H +#define MUDUO_BASE_THREADLOCALSINGLETON_H + +#include "muduo/base/noncopyable.h" + +#include +#include + +namespace muduo +{ + +template +class ThreadLocalSingleton : noncopyable +{ + public: + ThreadLocalSingleton() = delete; + ~ThreadLocalSingleton() = delete; + + static T& instance() + { + if (!t_value_) + { + t_value_ = new T(); + deleter_.set(t_value_); + } + return *t_value_; + } + + static T* pointer() + { + return t_value_; + } + + private: + static void destructor(void* obj) + { + assert(obj == t_value_); + typedef char T_must_be_complete_type[sizeof(T) == 0 ? -1 : 1]; + T_must_be_complete_type dummy; (void) dummy; + delete t_value_; + t_value_ = 0; + } + + class Deleter + { + public: + Deleter() + { + pthread_key_create(&pkey_, &ThreadLocalSingleton::destructor); + } + + ~Deleter() + { + pthread_key_delete(pkey_); + } + + void set(T* newObj) + { + assert(pthread_getspecific(pkey_) == NULL); + pthread_setspecific(pkey_, newObj); + } + + pthread_key_t pkey_; + }; + + static __thread T* t_value_; + static Deleter deleter_; +}; + +template +__thread T* ThreadLocalSingleton::t_value_ = 0; + +template +typename ThreadLocalSingleton::Deleter ThreadLocalSingleton::deleter_; + +} // namespace muduo +#endif // MUDUO_BASE_THREADLOCALSINGLETON_H diff --git a/include/Third_Lib/muduo/base/ThreadPool.cc b/include/Third_Lib/muduo/base/ThreadPool.cc new file mode 100644 index 0000000..6905dd7 --- /dev/null +++ b/include/Third_Lib/muduo/base/ThreadPool.cc @@ -0,0 +1,156 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/base/ThreadPool.h" + +#include "muduo/base/Exception.h" + +#include +#include + +using namespace muduo; + +ThreadPool::ThreadPool(const string& nameArg) + : mutex_(), + notEmpty_(mutex_), + notFull_(mutex_), + name_(nameArg), + maxQueueSize_(0), + running_(false) +{ +} + +ThreadPool::~ThreadPool() +{ + if (running_) + { + stop(); + } +} + +void ThreadPool::start(int numThreads) +{ + assert(threads_.empty()); + running_ = true; + threads_.reserve(numThreads); + for (int i = 0; i < numThreads; ++i) + { + char id[32]; + snprintf(id, sizeof id, "%d", i+1); + threads_.emplace_back(new muduo::Thread( + std::bind(&ThreadPool::runInThread, this), name_+id)); + threads_[i]->start(); + } + if (numThreads == 0 && threadInitCallback_) + { + threadInitCallback_(); + } +} + +void ThreadPool::stop() +{ + { + MutexLockGuard lock(mutex_); + running_ = false; + notEmpty_.notifyAll(); + notFull_.notifyAll(); + } + for (auto& thr : threads_) + { + thr->join(); + } +} + +size_t ThreadPool::queueSize() const +{ + MutexLockGuard lock(mutex_); + return queue_.size(); +} + +void ThreadPool::run(Task task) +{ + if (threads_.empty()) + { + task(); + } + else + { + MutexLockGuard lock(mutex_); + while (isFull() && running_) + { + notFull_.wait(); + } + if (!running_) return; + assert(!isFull()); + + queue_.push_back(std::move(task)); + notEmpty_.notify(); + } +} + +ThreadPool::Task ThreadPool::take() +{ + MutexLockGuard lock(mutex_); + // always use a while-loop, due to spurious wakeup + while (queue_.empty() && running_) + { + notEmpty_.wait(); + } + Task task; + if (!queue_.empty()) + { + task = queue_.front(); + queue_.pop_front(); + if (maxQueueSize_ > 0) + { + notFull_.notify(); + } + } + return task; +} + +bool ThreadPool::isFull() const +{ + mutex_.assertLocked(); + return maxQueueSize_ > 0 && queue_.size() >= maxQueueSize_; +} + +void ThreadPool::runInThread() +{ + try + { + if (threadInitCallback_) + { + threadInitCallback_(); + } + while (running_) + { + Task task(take()); + if (task) + { + task(); + } + } + } + catch (const Exception& ex) + { + fprintf(stderr, "exception caught in ThreadPool %s\n", name_.c_str()); + fprintf(stderr, "reason: %s\n", ex.what()); + fprintf(stderr, "stack trace: %s\n", ex.stackTrace()); + abort(); + } + catch (const std::exception& ex) + { + fprintf(stderr, "exception caught in ThreadPool %s\n", name_.c_str()); + fprintf(stderr, "reason: %s\n", ex.what()); + abort(); + } + catch (...) + { + fprintf(stderr, "unknown exception caught in ThreadPool %s\n", name_.c_str()); + throw; // rethrow + } +} + diff --git a/include/Third_Lib/muduo/base/ThreadPool.h b/include/Third_Lib/muduo/base/ThreadPool.h new file mode 100644 index 0000000..385c1bb --- /dev/null +++ b/include/Third_Lib/muduo/base/ThreadPool.h @@ -0,0 +1,67 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_THREADPOOL_H +#define MUDUO_BASE_THREADPOOL_H + +#include "muduo/base/Condition.h" +#include "muduo/base/Mutex.h" +#include "muduo/base/Thread.h" +#include "muduo/base/Types.h" + +#include +#include + +namespace muduo +{ + +class ThreadPool : noncopyable +{ + public: + typedef std::function Task; + + explicit ThreadPool(const string& nameArg = string("ThreadPool")); + ~ThreadPool(); + + // Must be called before start(). + void setMaxQueueSize(int maxSize) { maxQueueSize_ = maxSize; } + void setThreadInitCallback(const Task& cb) + { threadInitCallback_ = cb; } + + void start(int numThreads); + void stop(); + + const string& name() const + { return name_; } + + size_t queueSize() const; + + // Could block if maxQueueSize > 0 + // Call after stop() will return immediately. + // There is no move-only version of std::function in C++ as of C++14. + // So we don't need to overload a const& and an && versions + // as we do in (Bounded)BlockingQueue. + // https://stackoverflow.com/a/25408989 + void run(Task f); + + private: + bool isFull() const REQUIRES(mutex_); + void runInThread(); + Task take(); + + mutable MutexLock mutex_; + Condition notEmpty_ GUARDED_BY(mutex_); + Condition notFull_ GUARDED_BY(mutex_); + string name_; + Task threadInitCallback_; + std::vector> threads_; + std::deque queue_ GUARDED_BY(mutex_); + size_t maxQueueSize_; + bool running_; +}; + +} // namespace muduo + +#endif // MUDUO_BASE_THREADPOOL_H diff --git a/include/Third_Lib/muduo/base/TimeZone.cc b/include/Third_Lib/muduo/base/TimeZone.cc new file mode 100644 index 0000000..9544385 --- /dev/null +++ b/include/Third_Lib/muduo/base/TimeZone.cc @@ -0,0 +1,363 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/base/TimeZone.h" +#include "muduo/base/noncopyable.h" +#include "muduo/base/Date.h" + +#include +#include +#include +#include + +#include +//#define _BSD_SOURCE +#include + +#include +#include + +namespace muduo +{ +namespace detail +{ + +struct Transition +{ + time_t gmttime; + time_t localtime; + int localtimeIdx; + + Transition(time_t t, time_t l, int localIdx) + : gmttime(t), localtime(l), localtimeIdx(localIdx) + { } + +}; + +struct Comp +{ + bool compareGmt; + + Comp(bool gmt) + : compareGmt(gmt) + { + } + + bool operator()(const Transition& lhs, const Transition& rhs) const + { + if (compareGmt) + return lhs.gmttime < rhs.gmttime; + else + return lhs.localtime < rhs.localtime; + } + + bool equal(const Transition& lhs, const Transition& rhs) const + { + if (compareGmt) + return lhs.gmttime == rhs.gmttime; + else + return lhs.localtime == rhs.localtime; + } +}; + +struct Localtime +{ + time_t gmtOffset; + bool isDst; + int arrbIdx; + + Localtime(time_t offset, bool dst, int arrb) + : gmtOffset(offset), isDst(dst), arrbIdx(arrb) + { } +}; + +inline void fillHMS(unsigned seconds, struct tm* utc) +{ + utc->tm_sec = seconds % 60; + unsigned minutes = seconds / 60; + utc->tm_min = minutes % 60; + utc->tm_hour = minutes / 60; +} + +} // namespace detail +const int kSecondsPerDay = 24*60*60; +} // namespace muduo + +using namespace muduo; +using namespace std; + +struct TimeZone::Data +{ + vector transitions; + vector localtimes; + vector names; + string abbreviation; +}; + +namespace muduo +{ +namespace detail +{ + +class File : noncopyable +{ + public: + File(const char* file) + : fp_(::fopen(file, "rb")) + { + } + + ~File() + { + if (fp_) + { + ::fclose(fp_); + } + } + + bool valid() const { return fp_; } + + string readBytes(int n) + { + char buf[n]; + ssize_t nr = ::fread(buf, 1, n, fp_); + if (nr != n) + throw logic_error("no enough data"); + return string(buf, n); + } + + int32_t readInt32() + { + int32_t x = 0; + ssize_t nr = ::fread(&x, 1, sizeof(int32_t), fp_); + if (nr != sizeof(int32_t)) + throw logic_error("bad int32_t data"); + return be32toh(x); + } + + uint8_t readUInt8() + { + uint8_t x = 0; + ssize_t nr = ::fread(&x, 1, sizeof(uint8_t), fp_); + if (nr != sizeof(uint8_t)) + throw logic_error("bad uint8_t data"); + return x; + } + + private: + FILE* fp_; +}; + +bool readTimeZoneFile(const char* zonefile, struct TimeZone::Data* data) +{ + File f(zonefile); + if (f.valid()) + { + try + { + string head = f.readBytes(4); + if (head != "TZif") + throw logic_error("bad head"); + string version = f.readBytes(1); + f.readBytes(15); + + int32_t isgmtcnt = f.readInt32(); + int32_t isstdcnt = f.readInt32(); + int32_t leapcnt = f.readInt32(); + int32_t timecnt = f.readInt32(); + int32_t typecnt = f.readInt32(); + int32_t charcnt = f.readInt32(); + + vector trans; + vector localtimes; + trans.reserve(timecnt); + for (int i = 0; i < timecnt; ++i) + { + trans.push_back(f.readInt32()); + } + + for (int i = 0; i < timecnt; ++i) + { + uint8_t local = f.readUInt8(); + localtimes.push_back(local); + } + + for (int i = 0; i < typecnt; ++i) + { + int32_t gmtoff = f.readInt32(); + uint8_t isdst = f.readUInt8(); + uint8_t abbrind = f.readUInt8(); + + data->localtimes.push_back(Localtime(gmtoff, isdst, abbrind)); + } + + for (int i = 0; i < timecnt; ++i) + { + int localIdx = localtimes[i]; + time_t localtime = trans[i] + data->localtimes[localIdx].gmtOffset; + data->transitions.push_back(Transition(trans[i], localtime, localIdx)); + } + + data->abbreviation = f.readBytes(charcnt); + + // leapcnt + for (int i = 0; i < leapcnt; ++i) + { + // int32_t leaptime = f.readInt32(); + // int32_t cumleap = f.readInt32(); + } + // FIXME + (void) isstdcnt; + (void) isgmtcnt; + } + catch (logic_error& e) + { + fprintf(stderr, "%s\n", e.what()); + } + } + return true; +} + +const Localtime* findLocaltime(const TimeZone::Data& data, Transition sentry, Comp comp) +{ + const Localtime* local = NULL; + + if (data.transitions.empty() || comp(sentry, data.transitions.front())) + { + // FIXME: should be first non dst time zone + local = &data.localtimes.front(); + } + else + { + vector::const_iterator transI = lower_bound(data.transitions.begin(), + data.transitions.end(), + sentry, + comp); + if (transI != data.transitions.end()) + { + if (!comp.equal(sentry, *transI)) + { + assert(transI != data.transitions.begin()); + --transI; + } + local = &data.localtimes[transI->localtimeIdx]; + } + else + { + // FIXME: use TZ-env + local = &data.localtimes[data.transitions.back().localtimeIdx]; + } + } + + return local; +} + +} // namespace detail +} // namespace muduo + + +TimeZone::TimeZone(const char* zonefile) + : data_(new TimeZone::Data) +{ + if (!detail::readTimeZoneFile(zonefile, data_.get())) + { + data_.reset(); + } +} + +TimeZone::TimeZone(int eastOfUtc, const char* name) + : data_(new TimeZone::Data) +{ + data_->localtimes.push_back(detail::Localtime(eastOfUtc, false, 0)); + data_->abbreviation = name; +} + +struct tm TimeZone::toLocalTime(time_t seconds) const +{ + struct tm localTime; + memZero(&localTime, sizeof(localTime)); + assert(data_ != NULL); + const Data& data(*data_); + + detail::Transition sentry(seconds, 0, 0); + const detail::Localtime* local = findLocaltime(data, sentry, detail::Comp(true)); + + if (local) + { + time_t localSeconds = seconds + local->gmtOffset; + ::gmtime_r(&localSeconds, &localTime); // FIXME: fromUtcTime + localTime.tm_isdst = local->isDst; + localTime.tm_gmtoff = local->gmtOffset; + localTime.tm_zone = &data.abbreviation[local->arrbIdx]; + } + + return localTime; +} + +time_t TimeZone::fromLocalTime(const struct tm& localTm) const +{ + assert(data_ != NULL); + const Data& data(*data_); + + struct tm tmp = localTm; + time_t seconds = ::timegm(&tmp); // FIXME: toUtcTime + detail::Transition sentry(0, seconds, 0); + const detail::Localtime* local = findLocaltime(data, sentry, detail::Comp(false)); + if (localTm.tm_isdst) + { + struct tm tryTm = toLocalTime(seconds - local->gmtOffset); + if (!tryTm.tm_isdst + && tryTm.tm_hour == localTm.tm_hour + && tryTm.tm_min == localTm.tm_min) + { + // FIXME: HACK + seconds -= 3600; + } + } + return seconds - local->gmtOffset; +} + +struct tm TimeZone::toUtcTime(time_t secondsSinceEpoch, bool yday) +{ + struct tm utc; + memZero(&utc, sizeof(utc)); + utc.tm_zone = "GMT"; + int seconds = static_cast(secondsSinceEpoch % kSecondsPerDay); + int days = static_cast(secondsSinceEpoch / kSecondsPerDay); + if (seconds < 0) + { + seconds += kSecondsPerDay; + --days; + } + detail::fillHMS(seconds, &utc); + Date date(days + Date::kJulianDayOf1970_01_01); + Date::YearMonthDay ymd = date.yearMonthDay(); + utc.tm_year = ymd.year - 1900; + utc.tm_mon = ymd.month - 1; + utc.tm_mday = ymd.day; + utc.tm_wday = date.weekDay(); + + if (yday) + { + Date startOfYear(ymd.year, 1, 1); + utc.tm_yday = date.julianDayNumber() - startOfYear.julianDayNumber(); + } + return utc; +} + +time_t TimeZone::fromUtcTime(const struct tm& utc) +{ + return fromUtcTime(utc.tm_year + 1900, utc.tm_mon + 1, utc.tm_mday, + utc.tm_hour, utc.tm_min, utc.tm_sec); +} + +time_t TimeZone::fromUtcTime(int year, int month, int day, + int hour, int minute, int seconds) +{ + Date date(year, month, day); + int secondsInDay = hour * 3600 + minute * 60 + seconds; + time_t days = date.julianDayNumber() - Date::kJulianDayOf1970_01_01; + return days * kSecondsPerDay + secondsInDay; +} diff --git a/include/Third_Lib/muduo/base/TimeZone.h b/include/Third_Lib/muduo/base/TimeZone.h new file mode 100644 index 0000000..6586630 --- /dev/null +++ b/include/Third_Lib/muduo/base/TimeZone.h @@ -0,0 +1,52 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_TIMEZONE_H +#define MUDUO_BASE_TIMEZONE_H + +#include "muduo/base/copyable.h" +#include +#include + +namespace muduo +{ + +// TimeZone for 1970~2030 +class TimeZone : public muduo::copyable +{ + public: + explicit TimeZone(const char* zonefile); + TimeZone(int eastOfUtc, const char* tzname); // a fixed timezone + TimeZone() = default; // an invalid timezone + + // default copy ctor/assignment/dtor are Okay. + + bool valid() const + { + // 'explicit operator bool() const' in C++11 + return static_cast(data_); + } + + struct tm toLocalTime(time_t secondsSinceEpoch) const; + time_t fromLocalTime(const struct tm&) const; + + // gmtime(3) + static struct tm toUtcTime(time_t secondsSinceEpoch, bool yday = false); + // timegm(3) + static time_t fromUtcTime(const struct tm&); + // year in [1900..2500], month in [1..12], day in [1..31] + static time_t fromUtcTime(int year, int month, int day, + int hour, int minute, int seconds); + + struct Data; + + private: + + std::shared_ptr data_; +}; + +} // namespace muduo + +#endif // MUDUO_BASE_TIMEZONE_H diff --git a/include/Third_Lib/muduo/base/Timestamp.cc b/include/Third_Lib/muduo/base/Timestamp.cc new file mode 100644 index 0000000..fc0ed70 --- /dev/null +++ b/include/Third_Lib/muduo/base/Timestamp.cc @@ -0,0 +1,62 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/base/Timestamp.h" + +#include +#include + +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif + +#include + +using namespace muduo; + +static_assert(sizeof(Timestamp) == sizeof(int64_t), + "Timestamp should be same size as int64_t"); + +string Timestamp::toString() const +{ + char buf[32] = {0}; + int64_t seconds = microSecondsSinceEpoch_ / kMicroSecondsPerSecond; + int64_t microseconds = microSecondsSinceEpoch_ % kMicroSecondsPerSecond; + snprintf(buf, sizeof(buf), "%" PRId64 ".%06" PRId64 "", seconds, microseconds); + return buf; +} + +string Timestamp::toFormattedString(bool showMicroseconds) const +{ + char buf[64] = {0}; + time_t seconds = static_cast(microSecondsSinceEpoch_ / kMicroSecondsPerSecond); + struct tm tm_time; + gmtime_r(&seconds, &tm_time); + + if (showMicroseconds) + { + int microseconds = static_cast(microSecondsSinceEpoch_ % kMicroSecondsPerSecond); + snprintf(buf, sizeof(buf), "%4d%02d%02d %02d:%02d:%02d.%06d", + tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday, + tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec, + microseconds); + } + else + { + snprintf(buf, sizeof(buf), "%4d%02d%02d %02d:%02d:%02d", + tm_time.tm_year + 1900, tm_time.tm_mon + 1, tm_time.tm_mday, + tm_time.tm_hour, tm_time.tm_min, tm_time.tm_sec); + } + return buf; +} + +Timestamp Timestamp::now() +{ + struct timeval tv; + gettimeofday(&tv, NULL); + int64_t seconds = tv.tv_sec; + return Timestamp(seconds * kMicroSecondsPerSecond + tv.tv_usec); +} + diff --git a/include/Third_Lib/muduo/base/Timestamp.h b/include/Third_Lib/muduo/base/Timestamp.h new file mode 100644 index 0000000..ccb522d --- /dev/null +++ b/include/Third_Lib/muduo/base/Timestamp.h @@ -0,0 +1,123 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_TIMESTAMP_H +#define MUDUO_BASE_TIMESTAMP_H + +#include "muduo/base/copyable.h" +#include "muduo/base/Types.h" + +#include + +namespace muduo +{ + +/// +/// Time stamp in UTC, in microseconds resolution. +/// +/// This class is immutable. +/// It's recommended to pass it by value, since it's passed in register on x64. +/// +class Timestamp : public muduo::copyable, + public boost::equality_comparable, + public boost::less_than_comparable +{ + public: + /// + /// Constucts an invalid Timestamp. + /// + Timestamp() + : microSecondsSinceEpoch_(0) + { + } + + /// + /// Constucts a Timestamp at specific time + /// + /// @param microSecondsSinceEpoch + explicit Timestamp(int64_t microSecondsSinceEpochArg) + : microSecondsSinceEpoch_(microSecondsSinceEpochArg) + { + } + + void swap(Timestamp& that) + { + std::swap(microSecondsSinceEpoch_, that.microSecondsSinceEpoch_); + } + + // default copy/assignment/dtor are Okay + + string toString() const; + string toFormattedString(bool showMicroseconds = true) const; + + bool valid() const { return microSecondsSinceEpoch_ > 0; } + + // for internal usage. + int64_t microSecondsSinceEpoch() const { return microSecondsSinceEpoch_; } + time_t secondsSinceEpoch() const + { return static_cast(microSecondsSinceEpoch_ / kMicroSecondsPerSecond); } + + /// + /// Get time of now. + /// + static Timestamp now(); + static Timestamp invalid() + { + return Timestamp(); + } + + static Timestamp fromUnixTime(time_t t) + { + return fromUnixTime(t, 0); + } + + static Timestamp fromUnixTime(time_t t, int microseconds) + { + return Timestamp(static_cast(t) * kMicroSecondsPerSecond + microseconds); + } + + static const int kMicroSecondsPerSecond = 1000 * 1000; + + private: + int64_t microSecondsSinceEpoch_; +}; + +inline bool operator<(Timestamp lhs, Timestamp rhs) +{ + return lhs.microSecondsSinceEpoch() < rhs.microSecondsSinceEpoch(); +} + +inline bool operator==(Timestamp lhs, Timestamp rhs) +{ + return lhs.microSecondsSinceEpoch() == rhs.microSecondsSinceEpoch(); +} + +/// +/// Gets time difference of two timestamps, result in seconds. +/// +/// @param high, low +/// @return (high-low) in seconds +/// @c double has 52-bit precision, enough for one-microsecond +/// resolution for next 100 years. +inline double timeDifference(Timestamp high, Timestamp low) +{ + int64_t diff = high.microSecondsSinceEpoch() - low.microSecondsSinceEpoch(); + return static_cast(diff) / Timestamp::kMicroSecondsPerSecond; +} + +/// +/// Add @c seconds to given timestamp. +/// +/// @return timestamp+seconds as Timestamp +/// +inline Timestamp addTime(Timestamp timestamp, double seconds) +{ + int64_t delta = static_cast(seconds * Timestamp::kMicroSecondsPerSecond); + return Timestamp(timestamp.microSecondsSinceEpoch() + delta); +} + +} // namespace muduo + +#endif // MUDUO_BASE_TIMESTAMP_H diff --git a/include/Third_Lib/muduo/base/Types.h b/include/Third_Lib/muduo/base/Types.h new file mode 100644 index 0000000..ad94756 --- /dev/null +++ b/include/Third_Lib/muduo/base/Types.h @@ -0,0 +1,123 @@ +#ifndef MUDUO_BASE_TYPES_H +#define MUDUO_BASE_TYPES_H + +#include +#include // memset +#include + +#ifndef NDEBUG +#include +#endif + +/// +/// The most common stuffs. +/// +namespace muduo +{ + +using std::string; + +inline void memZero(void* p, size_t n) +{ + memset(p, 0, n); +} + +// Taken from google-protobuf stubs/common.h +// +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) and others +// +// Contains basic types and utilities used by the rest of the library. + +// +// Use implicit_cast as a safe version of static_cast or const_cast +// for upcasting in the type hierarchy (i.e. casting a pointer to Foo +// to a pointer to SuperclassOfFoo or casting a pointer to Foo to +// a const pointer to Foo). +// When you use implicit_cast, the compiler checks that the cast is safe. +// Such explicit implicit_casts are necessary in surprisingly many +// situations where C++ demands an exact type match instead of an +// argument type convertable to a target type. +// +// The From type can be inferred, so the preferred syntax for using +// implicit_cast is the same as for static_cast etc.: +// +// implicit_cast(expr) +// +// implicit_cast would have been part of the C++ standard library, +// but the proposal was submitted too late. It will probably make +// its way into the language in the future. +template +inline To implicit_cast(From const &f) +{ + return f; +} + +// When you upcast (that is, cast a pointer from type Foo to type +// SuperclassOfFoo), it's fine to use implicit_cast<>, since upcasts +// always succeed. When you downcast (that is, cast a pointer from +// type Foo to type SubclassOfFoo), static_cast<> isn't safe, because +// how do you know the pointer is really of type SubclassOfFoo? It +// could be a bare Foo, or of type DifferentSubclassOfFoo. Thus, +// when you downcast, you should use this macro. In debug mode, we +// use dynamic_cast<> to double-check the downcast is legal (we die +// if it's not). In normal mode, we do the efficient static_cast<> +// instead. Thus, it's important to test in debug mode to make sure +// the cast is legal! +// This is the only place in the code we should use dynamic_cast<>. +// In particular, you SHOULDN'T be using dynamic_cast<> in order to +// do RTTI (eg code like this: +// if (dynamic_cast(foo)) HandleASubclass1Object(foo); +// if (dynamic_cast(foo)) HandleASubclass2Object(foo); +// You should design the code some other way not to need this. + +template // use like this: down_cast(foo); +inline To down_cast(From* f) // so we only accept pointers +{ + // Ensures that To is a sub-type of From *. This test is here only + // for compile-time type checking, and has no overhead in an + // optimized build at run-time, as it will be optimized away + // completely. + if (false) + { + implicit_cast(0); + } + +#if !defined(NDEBUG) && !defined(GOOGLE_PROTOBUF_NO_RTTI) + assert(f == NULL || dynamic_cast(f) != NULL); // RTTI: debug mode only! +#endif + return static_cast(f); +} + +} // namespace muduo + +#endif // MUDUO_BASE_TYPES_H diff --git a/include/Third_Lib/muduo/base/WeakCallback.h b/include/Third_Lib/muduo/base/WeakCallback.h new file mode 100644 index 0000000..5e4650c --- /dev/null +++ b/include/Third_Lib/muduo/base/WeakCallback.h @@ -0,0 +1,65 @@ +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef MUDUO_BASE_WEAKCALLBACK_H +#define MUDUO_BASE_WEAKCALLBACK_H + +#include +#include + +namespace muduo +{ + +// A barely usable WeakCallback + +template +class WeakCallback +{ + public: + + WeakCallback(const std::weak_ptr& object, + const std::function& function) + : object_(object), function_(function) + { + } + + // Default dtor, copy ctor and assignment are okay + + void operator()(ARGS&&... args) const + { + std::shared_ptr ptr(object_.lock()); + if (ptr) + { + function_(ptr.get(), std::forward(args)...); + } + // else + // { + // LOG_TRACE << "expired"; + // } + } + + private: + + std::weak_ptr object_; + std::function function_; +}; + +template +WeakCallback makeWeakCallback(const std::shared_ptr& object, + void (CLASS::*function)(ARGS...)) +{ + return WeakCallback(object, function); +} + +template +WeakCallback makeWeakCallback(const std::shared_ptr& object, + void (CLASS::*function)(ARGS...) const) +{ + return WeakCallback(object, function); +} + +} // namespace muduo + +#endif // MUDUO_BASE_WEAKCALLBACK_H diff --git a/include/Third_Lib/muduo/base/copyable.h b/include/Third_Lib/muduo/base/copyable.h new file mode 100644 index 0000000..352b287 --- /dev/null +++ b/include/Third_Lib/muduo/base/copyable.h @@ -0,0 +1,19 @@ +#ifndef MUDUO_BASE_COPYABLE_H +#define MUDUO_BASE_COPYABLE_H + +namespace muduo +{ + +/// A tag class emphasises the objects are copyable. +/// The empty base class optimization applies. +/// Any derived class of copyable should be a value type. +class copyable +{ + protected: + copyable() = default; + ~copyable() = default; +}; + +} // namespace muduo + +#endif // MUDUO_BASE_COPYABLE_H diff --git a/include/Third_Lib/muduo/base/noncopyable.h b/include/Third_Lib/muduo/base/noncopyable.h new file mode 100644 index 0000000..79931f9 --- /dev/null +++ b/include/Third_Lib/muduo/base/noncopyable.h @@ -0,0 +1,20 @@ +#ifndef MUDUO_BASE_NONCOPYABLE_H +#define MUDUO_BASE_NONCOPYABLE_H + +namespace muduo +{ + +class noncopyable +{ + public: + noncopyable(const noncopyable&) = delete; + void operator=(const noncopyable&) = delete; + + protected: + noncopyable() = default; + ~noncopyable() = default; +}; + +} // namespace muduo + +#endif // MUDUO_BASE_NONCOPYABLE_H diff --git a/include/Third_Lib/muduo/base/tests/AsyncLogging_test.cc b/include/Third_Lib/muduo/base/tests/AsyncLogging_test.cc new file mode 100644 index 0000000..ad6fde4 --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/AsyncLogging_test.cc @@ -0,0 +1,64 @@ +#include "muduo/base/AsyncLogging.h" +#include "muduo/base/Logging.h" +#include "muduo/base/Timestamp.h" + +#include +#include +#include + +off_t kRollSize = 500*1000*1000; + +muduo::AsyncLogging* g_asyncLog = NULL; + +void asyncOutput(const char* msg, int len) +{ + g_asyncLog->append(msg, len); +} + +void bench(bool longLog) +{ + muduo::Logger::setOutput(asyncOutput); + + int cnt = 0; + const int kBatch = 1000; + muduo::string empty = " "; + muduo::string longStr(3000, 'X'); + longStr += " "; + + for (int t = 0; t < 30; ++t) + { + muduo::Timestamp start = muduo::Timestamp::now(); + for (int i = 0; i < kBatch; ++i) + { + LOG_INFO << "Hello 0123456789" << " abcdefghijklmnopqrstuvwxyz " + << (longLog ? longStr : empty) + << cnt; + ++cnt; + } + muduo::Timestamp end = muduo::Timestamp::now(); + printf("%f\n", timeDifference(end, start)*1000000/kBatch); + struct timespec ts = { 0, 500*1000*1000 }; + nanosleep(&ts, NULL); + } +} + +int main(int argc, char* argv[]) +{ + { + // set max virtual memory to 2GB. + size_t kOneGB = 1000*1024*1024; + rlimit rl = { 2*kOneGB, 2*kOneGB }; + setrlimit(RLIMIT_AS, &rl); + } + + printf("pid = %d\n", getpid()); + + char name[256] = { '\0' }; + strncpy(name, argv[0], sizeof name - 1); + muduo::AsyncLogging log(::basename(name), kRollSize); + log.start(); + g_asyncLog = &log; + + bool longLog = argc > 1; + bench(longLog); +} diff --git a/include/Third_Lib/muduo/base/tests/Atomic_unittest.cc b/include/Third_Lib/muduo/base/tests/Atomic_unittest.cc new file mode 100644 index 0000000..11d6107 --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/Atomic_unittest.cc @@ -0,0 +1,38 @@ +#include "muduo/base/Atomic.h" +#include + +int main() +{ + { + muduo::AtomicInt64 a0; + assert(a0.get() == 0); + assert(a0.getAndAdd(1) == 0); + assert(a0.get() == 1); + assert(a0.addAndGet(2) == 3); + assert(a0.get() == 3); + assert(a0.incrementAndGet() == 4); + assert(a0.get() == 4); + a0.increment(); + assert(a0.get() == 5); + assert(a0.addAndGet(-3) == 2); + assert(a0.getAndSet(100) == 2); + assert(a0.get() == 100); + } + + { + muduo::AtomicInt32 a1; + assert(a1.get() == 0); + assert(a1.getAndAdd(1) == 0); + assert(a1.get() == 1); + assert(a1.addAndGet(2) == 3); + assert(a1.get() == 3); + assert(a1.incrementAndGet() == 4); + assert(a1.get() == 4); + a1.increment(); + assert(a1.get() == 5); + assert(a1.addAndGet(-3) == 2); + assert(a1.getAndSet(100) == 2); + assert(a1.get() == 100); + } +} + diff --git a/include/Third_Lib/muduo/base/tests/BlockingQueue_bench.cc b/include/Third_Lib/muduo/base/tests/BlockingQueue_bench.cc new file mode 100644 index 0000000..bd65bfa --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/BlockingQueue_bench.cc @@ -0,0 +1,106 @@ +#include "muduo/base/BlockingQueue.h" +#include "muduo/base/CountDownLatch.h" +#include "muduo/base/Thread.h" +#include "muduo/base/Timestamp.h" + +#include +#include +#include +#include +#include + +class Bench +{ + public: + Bench(int numThreads) + : latch_(numThreads) + { + threads_.reserve(numThreads); + for (int i = 0; i < numThreads; ++i) + { + char name[32]; + snprintf(name, sizeof name, "work thread %d", i); + threads_.emplace_back(new muduo::Thread( + std::bind(&Bench::threadFunc, this), muduo::string(name))); + } + for (auto& thr : threads_) + { + thr->start(); + } + } + + void run(int times) + { + printf("waiting for count down latch\n"); + latch_.wait(); + printf("all threads started\n"); + for (int i = 0; i < times; ++i) + { + muduo::Timestamp now(muduo::Timestamp::now()); + queue_.put(now); + usleep(1000); + } + } + + void joinAll() + { + for (size_t i = 0; i < threads_.size(); ++i) + { + queue_.put(muduo::Timestamp::invalid()); + } + + for (auto& thr : threads_) + { + thr->join(); + } + } + + private: + + void threadFunc() + { + printf("tid=%d, %s started\n", + muduo::CurrentThread::tid(), + muduo::CurrentThread::name()); + + std::map delays; + latch_.countDown(); + bool running = true; + while (running) + { + muduo::Timestamp t(queue_.take()); + muduo::Timestamp now(muduo::Timestamp::now()); + if (t.valid()) + { + int delay = static_cast(timeDifference(now, t) * 1000000); + // printf("tid=%d, latency = %d us\n", + // muduo::CurrentThread::tid(), delay); + ++delays[delay]; + } + running = t.valid(); + } + + printf("tid=%d, %s stopped\n", + muduo::CurrentThread::tid(), + muduo::CurrentThread::name()); + for (const auto& delay : delays) + { + printf("tid = %d, delay = %d, count = %d\n", + muduo::CurrentThread::tid(), + delay.first, delay.second); + } + } + + muduo::BlockingQueue queue_; + muduo::CountDownLatch latch_; + std::vector> threads_; +}; + +int main(int argc, char* argv[]) +{ + int threads = argc > 1 ? atoi(argv[1]) : 1; + + Bench t(threads); + t.run(10000); + t.joinAll(); +} diff --git a/include/Third_Lib/muduo/base/tests/BlockingQueue_test.cc b/include/Third_Lib/muduo/base/tests/BlockingQueue_test.cc new file mode 100644 index 0000000..413fbd2 --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/BlockingQueue_test.cc @@ -0,0 +1,106 @@ +#include "muduo/base/BlockingQueue.h" +#include "muduo/base/CountDownLatch.h" +#include "muduo/base/Thread.h" + +#include +#include +#include +#include +#include + +class Test +{ + public: + Test(int numThreads) + : latch_(numThreads) + { + for (int i = 0; i < numThreads; ++i) + { + char name[32]; + snprintf(name, sizeof name, "work thread %d", i); + threads_.emplace_back(new muduo::Thread( + std::bind(&Test::threadFunc, this), muduo::string(name))); + } + for (auto& thr : threads_) + { + thr->start(); + } + } + + void run(int times) + { + printf("waiting for count down latch\n"); + latch_.wait(); + printf("all threads started\n"); + for (int i = 0; i < times; ++i) + { + char buf[32]; + snprintf(buf, sizeof buf, "hello %d", i); + queue_.put(buf); + printf("tid=%d, put data = %s, size = %zd\n", muduo::CurrentThread::tid(), buf, queue_.size()); + } + } + + void joinAll() + { + for (size_t i = 0; i < threads_.size(); ++i) + { + queue_.put("stop"); + } + + for (auto& thr : threads_) + { + thr->join(); + } + } + + private: + + void threadFunc() + { + printf("tid=%d, %s started\n", + muduo::CurrentThread::tid(), + muduo::CurrentThread::name()); + + latch_.countDown(); + bool running = true; + while (running) + { + std::string d(queue_.take()); + printf("tid=%d, get data = %s, size = %zd\n", muduo::CurrentThread::tid(), d.c_str(), queue_.size()); + running = (d != "stop"); + } + + printf("tid=%d, %s stopped\n", + muduo::CurrentThread::tid(), + muduo::CurrentThread::name()); + } + + muduo::BlockingQueue queue_; + muduo::CountDownLatch latch_; + std::vector> threads_; +}; + +void testMove() +{ + muduo::BlockingQueue> queue; + queue.put(std::unique_ptr(new int(42))); + std::unique_ptr x = queue.take(); + printf("took %d\n", *x); + *x = 123; + queue.put(std::move(x)); + std::unique_ptr y = queue.take(); + printf("took %d\n", *y); +} + +int main() +{ + printf("pid=%d, tid=%d\n", ::getpid(), muduo::CurrentThread::tid()); + Test t(5); + t.run(100); + t.joinAll(); + + testMove(); + + printf("number of created threads %d\n", muduo::Thread::numCreated()); +} diff --git a/include/Third_Lib/muduo/base/tests/BoundedBlockingQueue_test.cc b/include/Third_Lib/muduo/base/tests/BoundedBlockingQueue_test.cc new file mode 100644 index 0000000..49f57fb --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/BoundedBlockingQueue_test.cc @@ -0,0 +1,110 @@ +#include "muduo/base/BoundedBlockingQueue.h" +#include "muduo/base/CountDownLatch.h" +#include "muduo/base/Thread.h" + +#include +#include + +#include +#include + +class Test +{ + public: + Test(int numThreads) + : queue_(20), + latch_(numThreads) + { + threads_.reserve(numThreads); + for (int i = 0; i < numThreads; ++i) + { + char name[32]; + snprintf(name, sizeof name, "work thread %d", i); + threads_.emplace_back(new muduo::Thread( + std::bind(&Test::threadFunc, this), muduo::string(name))); + } + for (auto& thr : threads_) + { + thr->start(); + } + } + + void run(int times) + { + printf("waiting for count down latch\n"); + latch_.wait(); + printf("all threads started\n"); + for (int i = 0; i < times; ++i) + { + char buf[32]; + snprintf(buf, sizeof buf, "hello %d", i); + queue_.put(buf); + printf("tid=%d, put data = %s, size = %zd\n", muduo::CurrentThread::tid(), buf, queue_.size()); + } + } + + void joinAll() + { + for (size_t i = 0; i < threads_.size(); ++i) + { + queue_.put("stop"); + } + + for (auto& thr : threads_) + { + thr->join(); + } + } + + private: + + void threadFunc() + { + printf("tid=%d, %s started\n", + muduo::CurrentThread::tid(), + muduo::CurrentThread::name()); + + latch_.countDown(); + bool running = true; + while (running) + { + std::string d(queue_.take()); + printf("tid=%d, get data = %s, size = %zd\n", muduo::CurrentThread::tid(), d.c_str(), queue_.size()); + running = (d != "stop"); + } + + printf("tid=%d, %s stopped\n", + muduo::CurrentThread::tid(), + muduo::CurrentThread::name()); + } + + muduo::BoundedBlockingQueue queue_; + muduo::CountDownLatch latch_; + std::vector> threads_; +}; + +void testMove() +{ +#if BOOST_VERSION >= 105500L + muduo::BoundedBlockingQueue> queue(10); + queue.put(std::unique_ptr(new int(42))); + std::unique_ptr x = queue.take(); + printf("took %d\n", *x); + *x = 123; + queue.put(std::move(x)); + std::unique_ptr y; + y = queue.take(); + printf("took %d\n", *y); +#endif +} + +int main() +{ + printf("pid=%d, tid=%d\n", ::getpid(), muduo::CurrentThread::tid()); + testMove(); + Test t(5); + t.run(100); + t.joinAll(); + + printf("number of created threads %d\n", muduo::Thread::numCreated()); +} diff --git a/include/Third_Lib/muduo/base/tests/CMakeLists.txt b/include/Third_Lib/muduo/base/tests/CMakeLists.txt new file mode 100644 index 0000000..01a1c7a --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/CMakeLists.txt @@ -0,0 +1,86 @@ +add_executable(asynclogging_test AsyncLogging_test.cc) +target_link_libraries(asynclogging_test muduo_base) + +add_executable(atomic_unittest Atomic_unittest.cc) +add_test(NAME atomic_unittest COMMAND atomic_unittest) + +add_executable(blockingqueue_test BlockingQueue_test.cc) +target_link_libraries(blockingqueue_test muduo_base) + +add_executable(blockingqueue_bench BlockingQueue_bench.cc) +target_link_libraries(blockingqueue_bench muduo_base) + +add_executable(boundedblockingqueue_test BoundedBlockingQueue_test.cc) +target_link_libraries(boundedblockingqueue_test muduo_base) + +add_executable(date_unittest Date_unittest.cc) +target_link_libraries(date_unittest muduo_base) +add_test(NAME date_unittest COMMAND date_unittest) + +add_executable(exception_test Exception_test.cc) +target_link_libraries(exception_test muduo_base) +add_test(NAME exception_test COMMAND exception_test) + +add_executable(fileutil_test FileUtil_test.cc) +target_link_libraries(fileutil_test muduo_base) +add_test(NAME fileutil_test COMMAND fileutil_test) + +add_executable(fork_test Fork_test.cc) +target_link_libraries(fork_test muduo_base) + +if(ZLIB_FOUND) + add_executable(gzipfile_test GzipFile_test.cc) + target_link_libraries(gzipfile_test muduo_base z) + add_test(NAME gzipfile_test COMMAND gzipfile_test) +endif() + +add_executable(logfile_test LogFile_test.cc) +target_link_libraries(logfile_test muduo_base) + +add_executable(logging_test Logging_test.cc) +target_link_libraries(logging_test muduo_base) + +add_executable(logstream_bench LogStream_bench.cc) +target_link_libraries(logstream_bench muduo_base) + +if(BOOSTTEST_LIBRARY) +add_executable(logstream_test LogStream_test.cc) +target_link_libraries(logstream_test muduo_base boost_unit_test_framework) +add_test(NAME logstream_test COMMAND logstream_test) +endif() + +add_executable(mutex_test Mutex_test.cc) +target_link_libraries(mutex_test muduo_base) + +add_executable(processinfo_test ProcessInfo_test.cc) +target_link_libraries(processinfo_test muduo_base) + +add_executable(singleton_test Singleton_test.cc) +target_link_libraries(singleton_test muduo_base) + +add_executable(singleton_threadlocal_test SingletonThreadLocal_test.cc) +target_link_libraries(singleton_threadlocal_test muduo_base) + +add_executable(thread_bench Thread_bench.cc) +target_link_libraries(thread_bench muduo_base) + +add_executable(thread_test Thread_test.cc) +target_link_libraries(thread_test muduo_base) + +add_executable(threadlocal_test ThreadLocal_test.cc) +target_link_libraries(threadlocal_test muduo_base) + +add_executable(threadlocalsingleton_test ThreadLocalSingleton_test.cc) +target_link_libraries(threadlocalsingleton_test muduo_base) + +add_executable(threadpool_test ThreadPool_test.cc) +target_link_libraries(threadpool_test muduo_base) + +add_executable(timestamp_unittest Timestamp_unittest.cc) +target_link_libraries(timestamp_unittest muduo_base) +add_test(NAME timestamp_unittest COMMAND timestamp_unittest) + +add_executable(timezone_unittest TimeZone_unittest.cc) +target_link_libraries(timezone_unittest muduo_base) +add_test(NAME timezone_unittest COMMAND timezone_unittest) + diff --git a/include/Third_Lib/muduo/base/tests/Date_unittest.cc b/include/Third_Lib/muduo/base/tests/Date_unittest.cc new file mode 100644 index 0000000..bf2d386 --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/Date_unittest.cc @@ -0,0 +1,88 @@ +#include "muduo/base/Date.h" +#include +#include + +using muduo::Date; + +const int kMonthsOfYear = 12; + +int isLeapYear(int year) +{ + if (year % 400 == 0) + return 1; + else if (year % 100 == 0) + return 0; + else if (year % 4 == 0) + return 1; + else + return 0; +} + +int daysOfMonth(int year, int month) +{ + static int days[2][kMonthsOfYear+1] = + { + { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, + { 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, + }; + return days[isLeapYear(year)][month]; +} + +void passByConstReference(const Date& x) +{ + printf("%s\n", x.toIsoString().c_str()); +} + +void passByValue(Date x) +{ + printf("%s\n", x.toIsoString().c_str()); +} + +int main() +{ + time_t now = time(NULL); + struct tm t1 = *gmtime(&now); + struct tm t2 = *localtime(&now); + Date someDay(2008, 9, 10); + printf("%s\n", someDay.toIsoString().c_str()); + passByValue(someDay); + passByConstReference(someDay); + Date todayUtc(t1); + printf("%s\n", todayUtc.toIsoString().c_str()); + Date todayLocal(t2); + printf("%s\n", todayLocal.toIsoString().c_str()); + + int julianDayNumber = 2415021; + int weekDay = 1; // Monday + + for (int year = 1900; year < 2500; ++year) + { + assert(Date(year, 3, 1).julianDayNumber() - Date(year, 2, 29).julianDayNumber() + == isLeapYear(year)); + for (int month = 1; month <= kMonthsOfYear; ++month) + { + for (int day = 1; day <= daysOfMonth(year, month); ++day) + { + Date d(year, month, day); + // printf("%s %d\n", d.toString().c_str(), d.weekDay()); + assert(year == d.year()); + assert(month == d.month()); + assert(day == d.day()); + assert(weekDay == d.weekDay()); + assert(julianDayNumber == d.julianDayNumber()); + + Date d2(julianDayNumber); + assert(year == d2.year()); + assert(month == d2.month()); + assert(day == d2.day()); + assert(weekDay == d2.weekDay()); + assert(julianDayNumber == d2.julianDayNumber()); + + ++julianDayNumber; + weekDay = (weekDay+1) % 7; + } + } + } + printf("All passed.\n"); +} + diff --git a/include/Third_Lib/muduo/base/tests/Exception_test.cc b/include/Third_Lib/muduo/base/tests/Exception_test.cc new file mode 100644 index 0000000..7fd8004 --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/Exception_test.cc @@ -0,0 +1,51 @@ +#include "muduo/base/CurrentThread.h" +#include "muduo/base/Exception.h" +#include +#include +#include + +class Bar +{ + public: + void test(std::vector names = {}) + { + printf("Stack:\n%s\n", muduo::CurrentThread::stackTrace(true).c_str()); + [] { + printf("Stack inside lambda:\n%s\n", muduo::CurrentThread::stackTrace(true).c_str()); + }(); + std::function func([] { + printf("Stack inside std::function:\n%s\n", muduo::CurrentThread::stackTrace(true).c_str()); + }); + func(); + + func = std::bind(&Bar::callback, this); + func(); + + throw muduo::Exception("oops"); + } + + private: + void callback() + { + printf("Stack inside std::bind:\n%s\n", muduo::CurrentThread::stackTrace(true).c_str()); + } +}; + +void foo() +{ + Bar b; + b.test(); +} + +int main() +{ + try + { + foo(); + } + catch (const muduo::Exception& ex) + { + printf("reason: %s\n", ex.what()); + printf("stack trace:\n%s\n", ex.stackTrace()); + } +} diff --git a/include/Third_Lib/muduo/base/tests/FileUtil_test.cc b/include/Third_Lib/muduo/base/tests/FileUtil_test.cc new file mode 100644 index 0000000..9abe299 --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/FileUtil_test.cc @@ -0,0 +1,30 @@ +#include "muduo/base/FileUtil.h" + +#include +#define __STDC_FORMAT_MACROS +#include + +using namespace muduo; + +int main() +{ + string result; + int64_t size = 0; + int err = FileUtil::readFile("/proc/self", 1024, &result, &size); + printf("%d %zd %" PRIu64 "\n", err, result.size(), size); + err = FileUtil::readFile("/proc/self", 1024, &result, NULL); + printf("%d %zd %" PRIu64 "\n", err, result.size(), size); + err = FileUtil::readFile("/proc/self/cmdline", 1024, &result, &size); + printf("%d %zd %" PRIu64 "\n", err, result.size(), size); + err = FileUtil::readFile("/dev/null", 1024, &result, &size); + printf("%d %zd %" PRIu64 "\n", err, result.size(), size); + err = FileUtil::readFile("/dev/zero", 1024, &result, &size); + printf("%d %zd %" PRIu64 "\n", err, result.size(), size); + err = FileUtil::readFile("/notexist", 1024, &result, &size); + printf("%d %zd %" PRIu64 "\n", err, result.size(), size); + err = FileUtil::readFile("/dev/zero", 102400, &result, &size); + printf("%d %zd %" PRIu64 "\n", err, result.size(), size); + err = FileUtil::readFile("/dev/zero", 102400, &result, NULL); + printf("%d %zd %" PRIu64 "\n", err, result.size(), size); +} + diff --git a/include/Third_Lib/muduo/base/tests/Fork_test.cc b/include/Third_Lib/muduo/base/tests/Fork_test.cc new file mode 100644 index 0000000..6a3cba6 --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/Fork_test.cc @@ -0,0 +1,46 @@ +#include "muduo/base/CurrentThread.h" + +#include +#include +#include + +namespace +{ +__thread int x = 0; +} + +void print() +{ + printf("pid=%d tid=%d x=%d\n", getpid(), muduo::CurrentThread::tid(), x); +} + +int main() +{ + printf("parent %d\n", getpid()); + print(); + x = 1; + print(); + pid_t p = fork(); + + if (p == 0) + { + printf("chlid %d\n", getpid()); + // child + print(); + x = 2; + print(); + + if (fork() == 0) + { + printf("grandchlid %d\n", getpid()); + print(); + x = 3; + print(); + } + } + else + { + // parent + print(); + } +} diff --git a/include/Third_Lib/muduo/base/tests/GzipFile_test.cc b/include/Third_Lib/muduo/base/tests/GzipFile_test.cc new file mode 100644 index 0000000..d3f9cc3 --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/GzipFile_test.cc @@ -0,0 +1,54 @@ +#include "muduo/base/GzipFile.h" + +#include "muduo/base/Logging.h" + +int main() +{ + const char* filename = "/tmp/gzipfile_test.gz"; + ::unlink(filename); + const char data[] = "123456789012345678901234567890123456789012345678901234567890\n"; + { + muduo::GzipFile writer = muduo::GzipFile::openForAppend(filename); + if (writer.valid()) + { + LOG_INFO << "tell " << writer.tell(); + LOG_INFO << "wrote " << writer.write(data); + LOG_INFO << "tell " << writer.tell(); + } + } + + { + printf("testing reader\n"); + muduo::GzipFile reader = muduo::GzipFile::openForRead(filename); + if (reader.valid()) + { + char buf[256]; + LOG_INFO << "tell " << reader.tell(); + int nr = reader.read(buf, sizeof buf); + printf("read %d\n", nr); + if (nr >= 0) + { + buf[nr] = '\0'; + printf("data %s", buf); + } + LOG_INFO << "tell " << reader.tell(); + if (strncmp(buf, data, strlen(data)) != 0) + { + printf("failed!!!\n"); + abort(); + } + else + { + printf("PASSED\n"); + } + } + } + + { + muduo::GzipFile writer = muduo::GzipFile::openForWriteExclusive(filename); + if (writer.valid() || errno != EEXIST) + { + printf("FAILED\n"); + } + } +} diff --git a/include/Third_Lib/muduo/base/tests/LogFile_test.cc b/include/Third_Lib/muduo/base/tests/LogFile_test.cc new file mode 100644 index 0000000..a0b753a --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/LogFile_test.cc @@ -0,0 +1,34 @@ +#include "muduo/base/LogFile.h" +#include "muduo/base/Logging.h" + +#include + +std::unique_ptr g_logFile; + +void outputFunc(const char* msg, int len) +{ + g_logFile->append(msg, len); +} + +void flushFunc() +{ + g_logFile->flush(); +} + +int main(int argc, char* argv[]) +{ + char name[256] = { '\0' }; + strncpy(name, argv[0], sizeof name - 1); + g_logFile.reset(new muduo::LogFile(::basename(name), 200*1000)); + muduo::Logger::setOutput(outputFunc); + muduo::Logger::setFlush(flushFunc); + + muduo::string line = "1234567890 abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ "; + + for (int i = 0; i < 10000; ++i) + { + LOG_INFO << line << i; + + usleep(1000); + } +} diff --git a/include/Third_Lib/muduo/base/tests/LogStream_bench.cc b/include/Third_Lib/muduo/base/tests/LogStream_bench.cc new file mode 100644 index 0000000..c91637a --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/LogStream_bench.cc @@ -0,0 +1,82 @@ +#include "muduo/base/LogStream.h" +#include "muduo/base/Timestamp.h" + +#include +#include +#define __STDC_FORMAT_MACROS +#include + +using namespace muduo; + +const size_t N = 1000000; + +#pragma GCC diagnostic ignored "-Wold-style-cast" + +template +void benchPrintf(const char* fmt) +{ + char buf[32]; + Timestamp start(Timestamp::now()); + for (size_t i = 0; i < N; ++i) + snprintf(buf, sizeof buf, fmt, (T)(i)); + Timestamp end(Timestamp::now()); + + printf("benchPrintf %f\n", timeDifference(end, start)); +} + +template +void benchStringStream() +{ + Timestamp start(Timestamp::now()); + std::ostringstream os; + + for (size_t i = 0; i < N; ++i) + { + os << (T)(i); + os.seekp(0, std::ios_base::beg); + } + Timestamp end(Timestamp::now()); + + printf("benchStringStream %f\n", timeDifference(end, start)); +} + +template +void benchLogStream() +{ + Timestamp start(Timestamp::now()); + LogStream os; + for (size_t i = 0; i < N; ++i) + { + os << (T)(i); + os.resetBuffer(); + } + Timestamp end(Timestamp::now()); + + printf("benchLogStream %f\n", timeDifference(end, start)); +} + +int main() +{ + benchPrintf("%d"); + + puts("int"); + benchPrintf("%d"); + benchStringStream(); + benchLogStream(); + + puts("double"); + benchPrintf("%.12g"); + benchStringStream(); + benchLogStream(); + + puts("int64_t"); + benchPrintf("%" PRId64); + benchStringStream(); + benchLogStream(); + + puts("void*"); + benchPrintf("%p"); + benchStringStream(); + benchLogStream(); + +} diff --git a/include/Third_Lib/muduo/base/tests/LogStream_test.cc b/include/Third_Lib/muduo/base/tests/LogStream_test.cc new file mode 100644 index 0000000..b6070e1 --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/LogStream_test.cc @@ -0,0 +1,286 @@ +#include "muduo/base/LogStream.h" + +#include +#include + +//#define BOOST_TEST_MODULE LogStreamTest +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK +#include + +using muduo::string; + +BOOST_AUTO_TEST_CASE(testLogStreamBooleans) +{ + muduo::LogStream os; + const muduo::LogStream::Buffer& buf = os.buffer(); + BOOST_CHECK_EQUAL(buf.toString(), string("")); + os << true; + BOOST_CHECK_EQUAL(buf.toString(), string("1")); + os << '\n'; + BOOST_CHECK_EQUAL(buf.toString(), string("1\n")); + os << false; + BOOST_CHECK_EQUAL(buf.toString(), string("1\n0")); +} + +BOOST_AUTO_TEST_CASE(testLogStreamIntegers) +{ + muduo::LogStream os; + const muduo::LogStream::Buffer& buf = os.buffer(); + BOOST_CHECK_EQUAL(buf.toString(), string("")); + os << 1; + BOOST_CHECK_EQUAL(buf.toString(), string("1")); + os << 0; + BOOST_CHECK_EQUAL(buf.toString(), string("10")); + os << -1; + BOOST_CHECK_EQUAL(buf.toString(), string("10-1")); + os.resetBuffer(); + + os << 0 << " " << 123 << 'x' << 0x64; + BOOST_CHECK_EQUAL(buf.toString(), string("0 123x100")); +} + +BOOST_AUTO_TEST_CASE(testLogStreamIntegerLimits) +{ + muduo::LogStream os; + const muduo::LogStream::Buffer& buf = os.buffer(); + os << -2147483647; + BOOST_CHECK_EQUAL(buf.toString(), string("-2147483647")); + os << static_cast(-2147483647 - 1); + BOOST_CHECK_EQUAL(buf.toString(), string("-2147483647-2147483648")); + os << ' '; + os << 2147483647; + BOOST_CHECK_EQUAL(buf.toString(), string("-2147483647-2147483648 2147483647")); + os.resetBuffer(); + + os << std::numeric_limits::min(); + BOOST_CHECK_EQUAL(buf.toString(), string("-32768")); + os.resetBuffer(); + + os << std::numeric_limits::max(); + BOOST_CHECK_EQUAL(buf.toString(), string("32767")); + os.resetBuffer(); + + os << std::numeric_limits::min(); + BOOST_CHECK_EQUAL(buf.toString(), string("0")); + os.resetBuffer(); + + os << std::numeric_limits::max(); + BOOST_CHECK_EQUAL(buf.toString(), string("65535")); + os.resetBuffer(); + + os << std::numeric_limits::min(); + BOOST_CHECK_EQUAL(buf.toString(), string("-2147483648")); + os.resetBuffer(); + + os << std::numeric_limits::max(); + BOOST_CHECK_EQUAL(buf.toString(), string("2147483647")); + os.resetBuffer(); + + os << std::numeric_limits::min(); + BOOST_CHECK_EQUAL(buf.toString(), string("0")); + os.resetBuffer(); + + os << std::numeric_limits::max(); + BOOST_CHECK_EQUAL(buf.toString(), string("4294967295")); + os.resetBuffer(); + + os << std::numeric_limits::min(); + BOOST_CHECK_EQUAL(buf.toString(), string("-9223372036854775808")); + os.resetBuffer(); + + os << std::numeric_limits::max(); + BOOST_CHECK_EQUAL(buf.toString(), string("9223372036854775807")); + os.resetBuffer(); + + os << std::numeric_limits::min(); + BOOST_CHECK_EQUAL(buf.toString(), string("0")); + os.resetBuffer(); + + os << std::numeric_limits::max(); + BOOST_CHECK_EQUAL(buf.toString(), string("18446744073709551615")); + os.resetBuffer(); + + int16_t a = 0; + int32_t b = 0; + int64_t c = 0; + os << a; + os << b; + os << c; + BOOST_CHECK_EQUAL(buf.toString(), string("000")); +} + +BOOST_AUTO_TEST_CASE(testLogStreamFloats) +{ + muduo::LogStream os; + const muduo::LogStream::Buffer& buf = os.buffer(); + + os << 0.0; + BOOST_CHECK_EQUAL(buf.toString(), string("0")); + os.resetBuffer(); + + os << 1.0; + BOOST_CHECK_EQUAL(buf.toString(), string("1")); + os.resetBuffer(); + + os << 0.1; + BOOST_CHECK_EQUAL(buf.toString(), string("0.1")); + os.resetBuffer(); + + os << 0.05; + BOOST_CHECK_EQUAL(buf.toString(), string("0.05")); + os.resetBuffer(); + + os << 0.15; + BOOST_CHECK_EQUAL(buf.toString(), string("0.15")); + os.resetBuffer(); + + double a = 0.1; + os << a; + BOOST_CHECK_EQUAL(buf.toString(), string("0.1")); + os.resetBuffer(); + + double b = 0.05; + os << b; + BOOST_CHECK_EQUAL(buf.toString(), string("0.05")); + os.resetBuffer(); + + double c = 0.15; + os << c; + BOOST_CHECK_EQUAL(buf.toString(), string("0.15")); + os.resetBuffer(); + + os << a+b; + BOOST_CHECK_EQUAL(buf.toString(), string("0.15")); + os.resetBuffer(); + + BOOST_CHECK(a+b != c); + + os << 1.23456789; + BOOST_CHECK_EQUAL(buf.toString(), string("1.23456789")); + os.resetBuffer(); + + os << 1.234567; + BOOST_CHECK_EQUAL(buf.toString(), string("1.234567")); + os.resetBuffer(); + + os << -123.456; + BOOST_CHECK_EQUAL(buf.toString(), string("-123.456")); + os.resetBuffer(); +} + +BOOST_AUTO_TEST_CASE(testLogStreamVoid) +{ + muduo::LogStream os; + const muduo::LogStream::Buffer& buf = os.buffer(); + + os << static_cast(0); + BOOST_CHECK_EQUAL(buf.toString(), string("0x0")); + os.resetBuffer(); + + os << reinterpret_cast(8888); + BOOST_CHECK_EQUAL(buf.toString(), string("0x22B8")); + os.resetBuffer(); +} + +BOOST_AUTO_TEST_CASE(testLogStreamStrings) +{ + muduo::LogStream os; + const muduo::LogStream::Buffer& buf = os.buffer(); + + os << "Hello "; + BOOST_CHECK_EQUAL(buf.toString(), string("Hello ")); + + string chenshuo = "Shuo Chen"; + os << chenshuo; + BOOST_CHECK_EQUAL(buf.toString(), string("Hello Shuo Chen")); +} + +BOOST_AUTO_TEST_CASE(testLogStreamFmts) +{ + muduo::LogStream os; + const muduo::LogStream::Buffer& buf = os.buffer(); + + os << muduo::Fmt("%4d", 1); + BOOST_CHECK_EQUAL(buf.toString(), string(" 1")); + os.resetBuffer(); + + os << muduo::Fmt("%4.2f", 1.2); + BOOST_CHECK_EQUAL(buf.toString(), string("1.20")); + os.resetBuffer(); + + os << muduo::Fmt("%4.2f", 1.2) << muduo::Fmt("%4d", 43); + BOOST_CHECK_EQUAL(buf.toString(), string("1.20 43")); + os.resetBuffer(); +} + +BOOST_AUTO_TEST_CASE(testLogStreamLong) +{ + muduo::LogStream os; + const muduo::LogStream::Buffer& buf = os.buffer(); + for (int i = 0; i < 399; ++i) + { + os << "123456789 "; + BOOST_CHECK_EQUAL(buf.length(), 10*(i+1)); + BOOST_CHECK_EQUAL(buf.avail(), 4000 - 10*(i+1)); + } + + os << "abcdefghi "; + BOOST_CHECK_EQUAL(buf.length(), 3990); + BOOST_CHECK_EQUAL(buf.avail(), 10); + + os << "abcdefghi"; + BOOST_CHECK_EQUAL(buf.length(), 3999); + BOOST_CHECK_EQUAL(buf.avail(), 1); +} + +BOOST_AUTO_TEST_CASE(testFormatSI) +{ + BOOST_CHECK_EQUAL(muduo::formatSI(0), string("0")); + BOOST_CHECK_EQUAL(muduo::formatSI(999), string("999")); + BOOST_CHECK_EQUAL(muduo::formatSI(1000), string("1.00k")); + BOOST_CHECK_EQUAL(muduo::formatSI(9990), string("9.99k")); + BOOST_CHECK_EQUAL(muduo::formatSI(9994), string("9.99k")); + BOOST_CHECK_EQUAL(muduo::formatSI(9995), string("10.0k")); + BOOST_CHECK_EQUAL(muduo::formatSI(10000), string("10.0k")); + BOOST_CHECK_EQUAL(muduo::formatSI(10049), string("10.0k")); + BOOST_CHECK_EQUAL(muduo::formatSI(10050), string("10.1k")); + BOOST_CHECK_EQUAL(muduo::formatSI(99900), string("99.9k")); + BOOST_CHECK_EQUAL(muduo::formatSI(99949), string("99.9k")); + BOOST_CHECK_EQUAL(muduo::formatSI(99950), string("100k")); + BOOST_CHECK_EQUAL(muduo::formatSI(100499), string("100k")); + // FIXME: + // BOOST_CHECK_EQUAL(muduo::formatSI(100500), string("101k")); + BOOST_CHECK_EQUAL(muduo::formatSI(100501), string("101k")); + BOOST_CHECK_EQUAL(muduo::formatSI(999499), string("999k")); + BOOST_CHECK_EQUAL(muduo::formatSI(999500), string("1.00M")); + BOOST_CHECK_EQUAL(muduo::formatSI(1004999), string("1.00M")); + // BOOST_CHECK_EQUAL(muduo::formatSI(1005000), string("1.01M")); + BOOST_CHECK_EQUAL(muduo::formatSI(1005001), string("1.01M")); + BOOST_CHECK_EQUAL(muduo::formatSI(INT64_MAX), string("9.22E")); +} + +BOOST_AUTO_TEST_CASE(testFormatIEC) +{ + BOOST_CHECK_EQUAL(muduo::formatIEC(0), string("0")); + BOOST_CHECK_EQUAL(muduo::formatIEC(1023), string("1023")); + BOOST_CHECK_EQUAL(muduo::formatIEC(1024), string("1.00Ki")); + BOOST_CHECK_EQUAL(muduo::formatIEC(10234), string("9.99Ki")); + BOOST_CHECK_EQUAL(muduo::formatIEC(10235), string("10.0Ki")); + BOOST_CHECK_EQUAL(muduo::formatIEC(10240), string("10.0Ki")); + BOOST_CHECK_EQUAL(muduo::formatIEC(10291), string("10.0Ki")); + BOOST_CHECK_EQUAL(muduo::formatIEC(10292), string("10.1Ki")); + BOOST_CHECK_EQUAL(muduo::formatIEC(102348), string("99.9Ki")); + BOOST_CHECK_EQUAL(muduo::formatIEC(102349), string("100Ki")); + BOOST_CHECK_EQUAL(muduo::formatIEC(102912), string("100Ki")); + BOOST_CHECK_EQUAL(muduo::formatIEC(102913), string("101Ki")); + BOOST_CHECK_EQUAL(muduo::formatIEC(1022976), string("999Ki")); + BOOST_CHECK_EQUAL(muduo::formatIEC(1047552), string("1023Ki")); + BOOST_CHECK_EQUAL(muduo::formatIEC(1047961), string("1023Ki")); + BOOST_CHECK_EQUAL(muduo::formatIEC(1048063), string("1023Ki")); + BOOST_CHECK_EQUAL(muduo::formatIEC(1048064), string("1.00Mi")); + BOOST_CHECK_EQUAL(muduo::formatIEC(1048576), string("1.00Mi")); + BOOST_CHECK_EQUAL(muduo::formatIEC(10480517), string("9.99Mi")); + BOOST_CHECK_EQUAL(muduo::formatIEC(10480518), string("10.0Mi")); + BOOST_CHECK_EQUAL(muduo::formatIEC(INT64_MAX), string("8.00Ei")); +} diff --git a/include/Third_Lib/muduo/base/tests/Logging_test.cc b/include/Third_Lib/muduo/base/tests/Logging_test.cc new file mode 100644 index 0000000..3de5e86 --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/Logging_test.cc @@ -0,0 +1,122 @@ +#include "muduo/base/Logging.h" +#include "muduo/base/LogFile.h" +#include "muduo/base/ThreadPool.h" +#include "muduo/base/TimeZone.h" + +#include +#include + +int g_total; +FILE* g_file; +std::unique_ptr g_logFile; + +void dummyOutput(const char* msg, int len) +{ + g_total += len; + if (g_file) + { + fwrite(msg, 1, len, g_file); + } + else if (g_logFile) + { + g_logFile->append(msg, len); + } +} + +void bench(const char* type) +{ + muduo::Logger::setOutput(dummyOutput); + muduo::Timestamp start(muduo::Timestamp::now()); + g_total = 0; + + int n = 1000*1000; + const bool kLongLog = false; + muduo::string empty = " "; + muduo::string longStr(3000, 'X'); + longStr += " "; + for (int i = 0; i < n; ++i) + { + LOG_INFO << "Hello 0123456789" << " abcdefghijklmnopqrstuvwxyz" + << (kLongLog ? longStr : empty) + << i; + } + muduo::Timestamp end(muduo::Timestamp::now()); + double seconds = timeDifference(end, start); + printf("%12s: %f seconds, %d bytes, %10.2f msg/s, %.2f MiB/s\n", + type, seconds, g_total, n / seconds, g_total / seconds / (1024 * 1024)); +} + +void logInThread() +{ + LOG_INFO << "logInThread"; + usleep(1000); +} + +int main() +{ + getppid(); // for ltrace and strace + + muduo::ThreadPool pool("pool"); + pool.start(5); + pool.run(logInThread); + pool.run(logInThread); + pool.run(logInThread); + pool.run(logInThread); + pool.run(logInThread); + + LOG_TRACE << "trace"; + LOG_DEBUG << "debug"; + LOG_INFO << "Hello"; + LOG_WARN << "World"; + LOG_ERROR << "Error"; + LOG_INFO << sizeof(muduo::Logger); + LOG_INFO << sizeof(muduo::LogStream); + LOG_INFO << sizeof(muduo::Fmt); + LOG_INFO << sizeof(muduo::LogStream::Buffer); + + sleep(1); + bench("nop"); + + char buffer[64*1024]; + + g_file = fopen("/dev/null", "w"); + setbuffer(g_file, buffer, sizeof buffer); + bench("/dev/null"); + fclose(g_file); + + g_file = fopen("/tmp/log", "w"); + setbuffer(g_file, buffer, sizeof buffer); + bench("/tmp/log"); + fclose(g_file); + + g_file = NULL; + g_logFile.reset(new muduo::LogFile("test_log_st", 500*1000*1000, false)); + bench("test_log_st"); + + g_logFile.reset(new muduo::LogFile("test_log_mt", 500*1000*1000, true)); + bench("test_log_mt"); + g_logFile.reset(); + + { + g_file = stdout; + sleep(1); + muduo::TimeZone beijing(8*3600, "CST"); + muduo::Logger::setTimeZone(beijing); + LOG_TRACE << "trace CST"; + LOG_DEBUG << "debug CST"; + LOG_INFO << "Hello CST"; + LOG_WARN << "World CST"; + LOG_ERROR << "Error CST"; + + sleep(1); + muduo::TimeZone newyork("/usr/share/zoneinfo/America/New_York"); + muduo::Logger::setTimeZone(newyork); + LOG_TRACE << "trace NYT"; + LOG_DEBUG << "debug NYT"; + LOG_INFO << "Hello NYT"; + LOG_WARN << "World NYT"; + LOG_ERROR << "Error NYT"; + g_file = NULL; + } + bench("timezone nop"); +} diff --git a/include/Third_Lib/muduo/base/tests/Mutex_test.cc b/include/Third_Lib/muduo/base/tests/Mutex_test.cc new file mode 100644 index 0000000..0c22d71 --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/Mutex_test.cc @@ -0,0 +1,82 @@ +#include "muduo/base/CountDownLatch.h" +#include "muduo/base/Mutex.h" +#include "muduo/base/Thread.h" +#include "muduo/base/Timestamp.h" + +#include +#include + +using namespace muduo; +using namespace std; + +MutexLock g_mutex; +vector g_vec; +const int kCount = 10*1000*1000; + +void threadFunc() +{ + for (int i = 0; i < kCount; ++i) + { + MutexLockGuard lock(g_mutex); + g_vec.push_back(i); + } +} + +int foo() __attribute__ ((noinline)); + +int g_count = 0; +int foo() +{ + MutexLockGuard lock(g_mutex); + if (!g_mutex.isLockedByThisThread()) + { + printf("FAIL\n"); + return -1; + } + + ++g_count; + return 0; +} + +int main() +{ + MCHECK(foo()); + if (g_count != 1) + { + printf("MCHECK calls twice.\n"); + abort(); + } + + const int kMaxThreads = 8; + g_vec.reserve(kMaxThreads * kCount); + + Timestamp start(Timestamp::now()); + for (int i = 0; i < kCount; ++i) + { + g_vec.push_back(i); + } + + printf("single thread without lock %f\n", timeDifference(Timestamp::now(), start)); + + start = Timestamp::now(); + threadFunc(); + printf("single thread with lock %f\n", timeDifference(Timestamp::now(), start)); + + for (int nthreads = 1; nthreads < kMaxThreads; ++nthreads) + { + std::vector> threads; + g_vec.clear(); + start = Timestamp::now(); + for (int i = 0; i < nthreads; ++i) + { + threads.emplace_back(new Thread(&threadFunc)); + threads.back()->start(); + } + for (int i = 0; i < nthreads; ++i) + { + threads[i]->join(); + } + printf("%d thread(s) with lock %f\n", nthreads, timeDifference(Timestamp::now(), start)); + } +} + diff --git a/include/Third_Lib/muduo/base/tests/ProcessInfo_test.cc b/include/Third_Lib/muduo/base/tests/ProcessInfo_test.cc new file mode 100644 index 0000000..6e30bad --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/ProcessInfo_test.cc @@ -0,0 +1,17 @@ +#include "muduo/base/ProcessInfo.h" +#include +#define __STDC_FORMAT_MACROS +#include + +int main() +{ + printf("pid = %d\n", muduo::ProcessInfo::pid()); + printf("uid = %d\n", muduo::ProcessInfo::uid()); + printf("euid = %d\n", muduo::ProcessInfo::euid()); + printf("start time = %s\n", muduo::ProcessInfo::startTime().toFormattedString().c_str()); + printf("hostname = %s\n", muduo::ProcessInfo::hostname().c_str()); + printf("opened files = %d\n", muduo::ProcessInfo::openedFiles()); + printf("threads = %zd\n", muduo::ProcessInfo::threads().size()); + printf("num threads = %d\n", muduo::ProcessInfo::numThreads()); + printf("status = %s\n", muduo::ProcessInfo::procStatus().c_str()); +} diff --git a/include/Third_Lib/muduo/base/tests/SingletonThreadLocal_test.cc b/include/Third_Lib/muduo/base/tests/SingletonThreadLocal_test.cc new file mode 100644 index 0000000..29edf6c --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/SingletonThreadLocal_test.cc @@ -0,0 +1,58 @@ +#include "muduo/base/Singleton.h" +#include "muduo/base/CurrentThread.h" +#include "muduo/base/ThreadLocal.h" +#include "muduo/base/Thread.h" + +#include +#include + +class Test : muduo::noncopyable +{ + public: + Test() + { + printf("tid=%d, constructing %p\n", muduo::CurrentThread::tid(), this); + } + + ~Test() + { + printf("tid=%d, destructing %p %s\n", muduo::CurrentThread::tid(), this, name_.c_str()); + } + + const muduo::string& name() const { return name_; } + void setName(const muduo::string& n) { name_ = n; } + + private: + muduo::string name_; +}; + +#define STL muduo::Singleton >::instance().value() + +void print() +{ + printf("tid=%d, %p name=%s\n", + muduo::CurrentThread::tid(), + &STL, + STL.name().c_str()); +} + +void threadFunc(const char* changeTo) +{ + print(); + STL.setName(changeTo); + sleep(1); + print(); +} + +int main() +{ + STL.setName("main one"); + muduo::Thread t1(std::bind(threadFunc, "thread1")); + muduo::Thread t2(std::bind(threadFunc, "thread2")); + t1.start(); + t2.start(); + t1.join(); + print(); + t2.join(); + pthread_exit(0); +} diff --git a/include/Third_Lib/muduo/base/tests/Singleton_test.cc b/include/Third_Lib/muduo/base/tests/Singleton_test.cc new file mode 100644 index 0000000..124d7f7 --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/Singleton_test.cc @@ -0,0 +1,65 @@ +#include "muduo/base/Singleton.h" +#include "muduo/base/CurrentThread.h" +#include "muduo/base/Thread.h" + +#include + +class Test : muduo::noncopyable +{ + public: + Test() + { + printf("tid=%d, constructing %p\n", muduo::CurrentThread::tid(), this); + } + + ~Test() + { + printf("tid=%d, destructing %p %s\n", muduo::CurrentThread::tid(), this, name_.c_str()); + } + + const muduo::string& name() const { return name_; } + void setName(const muduo::string& n) { name_ = n; } + + private: + muduo::string name_; +}; + +class TestNoDestroy : muduo::noncopyable +{ + public: + // Tag member for Singleton + void no_destroy(); + + TestNoDestroy() + { + printf("tid=%d, constructing TestNoDestroy %p\n", muduo::CurrentThread::tid(), this); + } + + ~TestNoDestroy() + { + printf("tid=%d, destructing TestNoDestroy %p\n", muduo::CurrentThread::tid(), this); + } +}; + +void threadFunc() +{ + printf("tid=%d, %p name=%s\n", + muduo::CurrentThread::tid(), + &muduo::Singleton::instance(), + muduo::Singleton::instance().name().c_str()); + muduo::Singleton::instance().setName("only one, changed"); +} + +int main() +{ + muduo::Singleton::instance().setName("only one"); + muduo::Thread t1(threadFunc); + t1.start(); + t1.join(); + printf("tid=%d, %p name=%s\n", + muduo::CurrentThread::tid(), + &muduo::Singleton::instance(), + muduo::Singleton::instance().name().c_str()); + muduo::Singleton::instance(); + printf("with valgrind, you should see %zd-byte memory leak.\n", sizeof(TestNoDestroy)); +} diff --git a/include/Third_Lib/muduo/base/tests/ThreadLocalSingleton_test.cc b/include/Third_Lib/muduo/base/tests/ThreadLocalSingleton_test.cc new file mode 100644 index 0000000..efe485a --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/ThreadLocalSingleton_test.cc @@ -0,0 +1,58 @@ +#include "muduo/base/ThreadLocalSingleton.h" +#include "muduo/base/CurrentThread.h" +#include "muduo/base/Thread.h" + +#include + +class Test : muduo::noncopyable +{ + public: + Test() + { + printf("tid=%d, constructing %p\n", muduo::CurrentThread::tid(), this); + } + + ~Test() + { + printf("tid=%d, destructing %p %s\n", muduo::CurrentThread::tid(), this, name_.c_str()); + } + + const muduo::string& name() const { return name_; } + void setName(const muduo::string& n) { name_ = n; } + + private: + muduo::string name_; +}; + +void threadFunc(const char* changeTo) +{ + printf("tid=%d, %p name=%s\n", + muduo::CurrentThread::tid(), + &muduo::ThreadLocalSingleton::instance(), + muduo::ThreadLocalSingleton::instance().name().c_str()); + muduo::ThreadLocalSingleton::instance().setName(changeTo); + printf("tid=%d, %p name=%s\n", + muduo::CurrentThread::tid(), + &muduo::ThreadLocalSingleton::instance(), + muduo::ThreadLocalSingleton::instance().name().c_str()); + + // no need to manually delete it + // muduo::ThreadLocalSingleton::destroy(); +} + +int main() +{ + muduo::ThreadLocalSingleton::instance().setName("main one"); + muduo::Thread t1(std::bind(threadFunc, "thread1")); + muduo::Thread t2(std::bind(threadFunc, "thread2")); + t1.start(); + t2.start(); + t1.join(); + printf("tid=%d, %p name=%s\n", + muduo::CurrentThread::tid(), + &muduo::ThreadLocalSingleton::instance(), + muduo::ThreadLocalSingleton::instance().name().c_str()); + t2.join(); + + pthread_exit(0); +} diff --git a/include/Third_Lib/muduo/base/tests/ThreadLocal_test.cc b/include/Third_Lib/muduo/base/tests/ThreadLocal_test.cc new file mode 100644 index 0000000..a5b89cf --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/ThreadLocal_test.cc @@ -0,0 +1,61 @@ +#include "muduo/base/ThreadLocal.h" +#include "muduo/base/CurrentThread.h" +#include "muduo/base/Thread.h" + +#include + +class Test : muduo::noncopyable +{ + public: + Test() + { + printf("tid=%d, constructing %p\n", muduo::CurrentThread::tid(), this); + } + + ~Test() + { + printf("tid=%d, destructing %p %s\n", muduo::CurrentThread::tid(), this, name_.c_str()); + } + + const muduo::string& name() const { return name_; } + void setName(const muduo::string& n) { name_ = n; } + + private: + muduo::string name_; +}; + +muduo::ThreadLocal testObj1; +muduo::ThreadLocal testObj2; + +void print() +{ + printf("tid=%d, obj1 %p name=%s\n", + muduo::CurrentThread::tid(), + &testObj1.value(), + testObj1.value().name().c_str()); + printf("tid=%d, obj2 %p name=%s\n", + muduo::CurrentThread::tid(), + &testObj2.value(), + testObj2.value().name().c_str()); +} + +void threadFunc() +{ + print(); + testObj1.value().setName("changed 1"); + testObj2.value().setName("changed 42"); + print(); +} + +int main() +{ + testObj1.value().setName("main one"); + print(); + muduo::Thread t1(threadFunc); + t1.start(); + t1.join(); + testObj2.value().setName("main two"); + print(); + + pthread_exit(0); +} diff --git a/include/Third_Lib/muduo/base/tests/ThreadPool_test.cc b/include/Third_Lib/muduo/base/tests/ThreadPool_test.cc new file mode 100644 index 0000000..de0dd60 --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/ThreadPool_test.cc @@ -0,0 +1,97 @@ +#include "muduo/base/ThreadPool.h" +#include "muduo/base/CountDownLatch.h" +#include "muduo/base/CurrentThread.h" +#include "muduo/base/Logging.h" + +#include +#include // usleep + +void print() +{ + printf("tid=%d\n", muduo::CurrentThread::tid()); +} + +void printString(const std::string& str) +{ + LOG_INFO << str; + usleep(100*1000); +} + +void test(int maxSize) +{ + LOG_WARN << "Test ThreadPool with max queue size = " << maxSize; + muduo::ThreadPool pool("MainThreadPool"); + pool.setMaxQueueSize(maxSize); + pool.start(5); + + LOG_WARN << "Adding"; + pool.run(print); + pool.run(print); + for (int i = 0; i < 100; ++i) + { + char buf[32]; + snprintf(buf, sizeof buf, "task %d", i); + pool.run(std::bind(printString, std::string(buf))); + } + LOG_WARN << "Done"; + + muduo::CountDownLatch latch(1); + pool.run(std::bind(&muduo::CountDownLatch::countDown, &latch)); + latch.wait(); + pool.stop(); +} + +/* + * Wish we could do this in the future. +void testMove() +{ + muduo::ThreadPool pool; + pool.start(2); + + std::unique_ptr x(new int(42)); + pool.run([y = std::move(x)]{ printf("%d: %d\n", muduo::CurrentThread::tid(), *y); }); + pool.stop(); +} +*/ + +void longTask(int num) +{ + LOG_INFO << "longTask " << num; + muduo::CurrentThread::sleepUsec(3000000); +} + +void test2() +{ + LOG_WARN << "Test ThreadPool by stoping early."; + muduo::ThreadPool pool("ThreadPool"); + pool.setMaxQueueSize(5); + pool.start(3); + + muduo::Thread thread1([&pool]() + { + for (int i = 0; i < 20; ++i) + { + pool.run(std::bind(longTask, i)); + } + }, "thread1"); + thread1.start(); + + muduo::CurrentThread::sleepUsec(5000000); + LOG_WARN << "stop pool"; + pool.stop(); // early stop + + thread1.join(); + // run() after stop() + pool.run(print); + LOG_WARN << "test2 Done"; +} + +int main() +{ + test(0); + test(1); + test(5); + test(10); + test(50); + test2(); +} diff --git a/include/Third_Lib/muduo/base/tests/Thread_bench.cc b/include/Third_Lib/muduo/base/tests/Thread_bench.cc new file mode 100644 index 0000000..ae3d49c --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/Thread_bench.cc @@ -0,0 +1,86 @@ +#include "muduo/base/CurrentThread.h" +#include "muduo/base/Mutex.h" +#include "muduo/base/Thread.h" +#include "muduo/base/Timestamp.h" + +#include +#include +#include +#include +#include + +muduo::MutexLock g_mutex; +std::map g_delays; + +void threadFunc() +{ + //printf("tid=%d\n", muduo::CurrentThread::tid()); +} + +void threadFunc2(muduo::Timestamp start) +{ + muduo::Timestamp now(muduo::Timestamp::now()); + int delay = static_cast(timeDifference(now, start) * 1000000); + muduo::MutexLockGuard lock(g_mutex); + ++g_delays[delay]; +} + +void forkBench() +{ + sleep(10); + muduo::Timestamp start(muduo::Timestamp::now()); + int kProcesses = 10*1000; + + for (int i = 0; i < kProcesses; ++i) + { + pid_t child = fork(); + if (child == 0) + { + exit(0); + } + else + { + waitpid(child, NULL, 0); + } + } + + double timeUsed = timeDifference(muduo::Timestamp::now(), start); + printf("process creation time used %f us\n", timeUsed*1000000/kProcesses); + printf("number of created processes %d\n", kProcesses); +} + +int main(int argc, char* argv[]) +{ + printf("pid=%d, tid=%d\n", ::getpid(), muduo::CurrentThread::tid()); + muduo::Timestamp start(muduo::Timestamp::now()); + + int kThreads = 100*1000; + for (int i = 0; i < kThreads; ++i) + { + muduo::Thread t1(threadFunc); + t1.start(); + t1.join(); + } + + double timeUsed = timeDifference(muduo::Timestamp::now(), start); + printf("thread creation time %f us\n", timeUsed*1000000/kThreads); + printf("number of created threads %d\n", muduo::Thread::numCreated()); + + for (int i = 0; i < kThreads; ++i) + { + muduo::Timestamp now(muduo::Timestamp::now()); + muduo::Thread t2(std::bind(threadFunc2, now)); + t2.start(); + t2.join(); + } + { + muduo::MutexLockGuard lock(g_mutex); + for (const auto& delay : g_delays) + { + printf("delay = %d, count = %d\n", + delay.first, delay.second); + } + } + + forkBench(); +} diff --git a/include/Third_Lib/muduo/base/tests/Thread_test.cc b/include/Third_Lib/muduo/base/tests/Thread_test.cc new file mode 100644 index 0000000..d6e78b9 --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/Thread_test.cc @@ -0,0 +1,91 @@ +#include "muduo/base/Thread.h" +#include "muduo/base/CurrentThread.h" + +#include +#include +#include + +void mysleep(int seconds) +{ + timespec t = { seconds, 0 }; + nanosleep(&t, NULL); +} + +void threadFunc() +{ + printf("tid=%d\n", muduo::CurrentThread::tid()); +} + +void threadFunc2(int x) +{ + printf("tid=%d, x=%d\n", muduo::CurrentThread::tid(), x); +} + +void threadFunc3() +{ + printf("tid=%d\n", muduo::CurrentThread::tid()); + mysleep(1); +} + +class Foo +{ + public: + explicit Foo(double x) + : x_(x) + { + } + + void memberFunc() + { + printf("tid=%d, Foo::x_=%f\n", muduo::CurrentThread::tid(), x_); + } + + void memberFunc2(const std::string& text) + { + printf("tid=%d, Foo::x_=%f, text=%s\n", muduo::CurrentThread::tid(), x_, text.c_str()); + } + + private: + double x_; +}; + +int main() +{ + printf("pid=%d, tid=%d\n", ::getpid(), muduo::CurrentThread::tid()); + + muduo::Thread t1(threadFunc); + t1.start(); + printf("t1.tid=%d\n", t1.tid()); + t1.join(); + + muduo::Thread t2(std::bind(threadFunc2, 42), + "thread for free function with argument"); + t2.start(); + printf("t2.tid=%d\n", t2.tid()); + t2.join(); + + Foo foo(87.53); + muduo::Thread t3(std::bind(&Foo::memberFunc, &foo), + "thread for member function without argument"); + t3.start(); + t3.join(); + + muduo::Thread t4(std::bind(&Foo::memberFunc2, std::ref(foo), std::string("Shuo Chen"))); + t4.start(); + t4.join(); + + { + muduo::Thread t5(threadFunc3); + t5.start(); + // t5 may destruct eariler than thread creation. + } + mysleep(2); + { + muduo::Thread t6(threadFunc3); + t6.start(); + mysleep(2); + // t6 destruct later than thread creation. + } + sleep(2); + printf("number of created threads %d\n", muduo::Thread::numCreated()); +} diff --git a/include/Third_Lib/muduo/base/tests/TimeZone_unittest.cc b/include/Third_Lib/muduo/base/tests/TimeZone_unittest.cc new file mode 100644 index 0000000..5d1de82 --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/TimeZone_unittest.cc @@ -0,0 +1,276 @@ +#include "muduo/base/TimeZone.h" +#include "muduo/base/Types.h" + +#include +#include +#include + +using muduo::TimeZone; + +struct tm getTm(int year, int month, int day, + int hour, int minute, int seconds) +{ + struct tm gmt; + muduo::memZero(&gmt, sizeof gmt); + gmt.tm_year = year - 1900; + gmt.tm_mon = month - 1; + gmt.tm_mday = day; + gmt.tm_hour = hour; + gmt.tm_min = minute; + gmt.tm_sec = seconds; + return gmt; +} + +struct tm getTm(const char* str) +{ + struct tm gmt; + muduo::memZero(&gmt, sizeof gmt); + strptime(str, "%F %T", &gmt); + return gmt; +} + +time_t getGmt(int year, int month, int day, + int hour, int minute, int seconds) +{ + struct tm gmt = getTm(year, month, day, hour, minute, seconds); + return timegm(&gmt); +} + +time_t getGmt(const char* str) +{ + struct tm gmt = getTm(str); + return timegm(&gmt); +} + +struct TestCase +{ + const char* gmt; + const char* local; + bool isdst; +}; + +void test(const TimeZone& tz, TestCase tc) +{ + time_t gmt = getGmt(tc.gmt); + + { + struct tm local = tz.toLocalTime(gmt); + char buf[256]; + strftime(buf, sizeof buf, "%F %T%z(%Z)", &local); + + if (strcmp(buf, tc.local) != 0 || tc.isdst != local.tm_isdst) + { + printf("WRONG: "); + } + printf("%s -> %s\n", tc.gmt, buf); + } + + { + struct tm local = getTm(tc.local); + local.tm_isdst = tc.isdst; + time_t result = tz.fromLocalTime(local); + if (result != gmt) + { + struct tm local2 = tz.toLocalTime(result); + char buf[256]; + strftime(buf, sizeof buf, "%F %T%z(%Z)", &local2); + + printf("WRONG fromLocalTime: %ld %ld %s\n", + static_cast(gmt), static_cast(result), buf); + } + } +} + +void testNewYork() +{ + TimeZone tz("/usr/share/zoneinfo/America/New_York"); + TestCase cases[] = + { + + { "2006-03-07 00:00:00", "2006-03-06 19:00:00-0500(EST)", false }, + { "2006-04-02 06:59:59", "2006-04-02 01:59:59-0500(EST)", false }, + { "2006-04-02 07:00:00", "2006-04-02 03:00:00-0400(EDT)", true }, + { "2006-05-01 00:00:00", "2006-04-30 20:00:00-0400(EDT)", true }, + { "2006-05-02 01:00:00", "2006-05-01 21:00:00-0400(EDT)", true }, + { "2006-10-21 05:00:00", "2006-10-21 01:00:00-0400(EDT)", true }, + { "2006-10-29 05:59:59", "2006-10-29 01:59:59-0400(EDT)", true }, + { "2006-10-29 06:00:00", "2006-10-29 01:00:00-0500(EST)", false }, + { "2006-10-29 06:59:59", "2006-10-29 01:59:59-0500(EST)", false }, + { "2006-12-31 06:00:00", "2006-12-31 01:00:00-0500(EST)", false }, + { "2007-01-01 00:00:00", "2006-12-31 19:00:00-0500(EST)", false }, + + { "2007-03-07 00:00:00", "2007-03-06 19:00:00-0500(EST)", false }, + { "2007-03-11 06:59:59", "2007-03-11 01:59:59-0500(EST)", false }, + { "2007-03-11 07:00:00", "2007-03-11 03:00:00-0400(EDT)", true }, + { "2007-05-01 00:00:00", "2007-04-30 20:00:00-0400(EDT)", true }, + { "2007-05-02 01:00:00", "2007-05-01 21:00:00-0400(EDT)", true }, + { "2007-10-31 05:00:00", "2007-10-31 01:00:00-0400(EDT)", true }, + { "2007-11-04 05:59:59", "2007-11-04 01:59:59-0400(EDT)", true }, + { "2007-11-04 06:00:00", "2007-11-04 01:00:00-0500(EST)", false }, + { "2007-11-04 06:59:59", "2007-11-04 01:59:59-0500(EST)", false }, + { "2007-12-31 06:00:00", "2007-12-31 01:00:00-0500(EST)", false }, + { "2008-01-01 00:00:00", "2007-12-31 19:00:00-0500(EST)", false }, + + { "2009-03-07 00:00:00", "2009-03-06 19:00:00-0500(EST)", false }, + { "2009-03-08 06:59:59", "2009-03-08 01:59:59-0500(EST)", false }, + { "2009-03-08 07:00:00", "2009-03-08 03:00:00-0400(EDT)", true }, + { "2009-05-01 00:00:00", "2009-04-30 20:00:00-0400(EDT)", true }, + { "2009-05-02 01:00:00", "2009-05-01 21:00:00-0400(EDT)", true }, + { "2009-10-31 05:00:00", "2009-10-31 01:00:00-0400(EDT)", true }, + { "2009-11-01 05:59:59", "2009-11-01 01:59:59-0400(EDT)", true }, + { "2009-11-01 06:00:00", "2009-11-01 01:00:00-0500(EST)", false }, + { "2009-11-01 06:59:59", "2009-11-01 01:59:59-0500(EST)", false }, + { "2009-12-31 06:00:00", "2009-12-31 01:00:00-0500(EST)", false }, + { "2010-01-01 00:00:00", "2009-12-31 19:00:00-0500(EST)", false }, + + { "2010-03-13 00:00:00", "2010-03-12 19:00:00-0500(EST)", false }, + { "2010-03-14 06:59:59", "2010-03-14 01:59:59-0500(EST)", false }, + { "2010-03-14 07:00:00", "2010-03-14 03:00:00-0400(EDT)", true }, + { "2010-05-01 00:00:00", "2010-04-30 20:00:00-0400(EDT)", true }, + { "2010-05-02 01:00:00", "2010-05-01 21:00:00-0400(EDT)", true }, + { "2010-11-06 05:00:00", "2010-11-06 01:00:00-0400(EDT)", true }, + { "2010-11-07 05:59:59", "2010-11-07 01:59:59-0400(EDT)", true }, + { "2010-11-07 06:00:00", "2010-11-07 01:00:00-0500(EST)", false }, + { "2010-11-07 06:59:59", "2010-11-07 01:59:59-0500(EST)", false }, + { "2010-12-31 06:00:00", "2010-12-31 01:00:00-0500(EST)", false }, + { "2011-01-01 00:00:00", "2010-12-31 19:00:00-0500(EST)", false }, + + { "2011-03-01 00:00:00", "2011-02-28 19:00:00-0500(EST)", false }, + { "2011-03-13 06:59:59", "2011-03-13 01:59:59-0500(EST)", false }, + { "2011-03-13 07:00:00", "2011-03-13 03:00:00-0400(EDT)", true }, + { "2011-05-01 00:00:00", "2011-04-30 20:00:00-0400(EDT)", true }, + { "2011-05-02 01:00:00", "2011-05-01 21:00:00-0400(EDT)", true }, + { "2011-11-06 05:59:59", "2011-11-06 01:59:59-0400(EDT)", true }, + { "2011-11-06 06:00:00", "2011-11-06 01:00:00-0500(EST)", false }, + { "2011-11-06 06:59:59", "2011-11-06 01:59:59-0500(EST)", false }, + { "2011-12-31 06:00:00", "2011-12-31 01:00:00-0500(EST)", false }, + { "2012-01-01 00:00:00", "2011-12-31 19:00:00-0500(EST)", false }, + + }; + + for (const auto& c : cases) + { + test(tz, c); + } +} + +void testLondon() +{ + TimeZone tz("/usr/share/zoneinfo/Europe/London"); + TestCase cases[] = + { + + { "2011-03-26 00:00:00", "2011-03-26 00:00:00+0000(GMT)", false }, + { "2011-03-27 00:59:59", "2011-03-27 00:59:59+0000(GMT)", false }, + { "2011-03-27 01:00:00", "2011-03-27 02:00:00+0100(BST)", true }, + { "2011-10-30 00:59:59", "2011-10-30 01:59:59+0100(BST)", true }, + { "2011-10-30 01:00:00", "2011-10-30 01:00:00+0000(GMT)", false }, + { "2012-10-30 01:59:59", "2012-10-30 01:59:59+0000(GMT)", false }, + { "2011-12-31 22:00:00", "2011-12-31 22:00:00+0000(GMT)", false }, + { "2012-01-01 00:00:00", "2012-01-01 00:00:00+0000(GMT)", false }, + + { "2012-03-24 00:00:00", "2012-03-24 00:00:00+0000(GMT)", false }, + { "2012-03-25 00:59:59", "2012-03-25 00:59:59+0000(GMT)", false }, + { "2012-03-25 01:00:00", "2012-03-25 02:00:00+0100(BST)", true }, + { "2012-10-28 00:59:59", "2012-10-28 01:59:59+0100(BST)", true }, + { "2012-10-28 01:00:00", "2012-10-28 01:00:00+0000(GMT)", false }, + { "2012-10-28 01:59:59", "2012-10-28 01:59:59+0000(GMT)", false }, + { "2012-12-31 22:00:00", "2012-12-31 22:00:00+0000(GMT)", false }, + { "2013-01-01 00:00:00", "2013-01-01 00:00:00+0000(GMT)", false }, + + }; + + for (const auto& c : cases) + { + test(tz, c); + } +} + +void testHongKong() +{ + TimeZone tz("/usr/share/zoneinfo/Asia/Hong_Kong"); + TestCase cases[] = + { + + { "2011-04-03 00:00:00", "2011-04-03 08:00:00+0800(HKT)", false}, + + }; + + for (const auto& c : cases) + { + test(tz, c); + } +} + +void testSydney() +{ + TimeZone tz("/usr/share/zoneinfo/Australia/Sydney"); + TestCase cases[] = + { + + { "2011-01-01 00:00:00", "2011-01-01 11:00:00+1100(EST)", true }, + { "2011-04-02 15:59:59", "2011-04-03 02:59:59+1100(EST)", true }, + { "2011-04-02 16:00:00", "2011-04-03 02:00:00+1000(EST)", false }, + { "2011-04-02 16:59:59", "2011-04-03 02:59:59+1000(EST)", false }, + { "2011-05-02 01:00:00", "2011-05-02 11:00:00+1000(EST)", false }, + { "2011-10-01 15:59:59", "2011-10-02 01:59:59+1000(EST)", false }, + { "2011-10-01 16:00:00", "2011-10-02 03:00:00+1100(EST)", true }, + { "2011-12-31 22:00:00", "2012-01-01 09:00:00+1100(EST)", true }, + + }; + + for (const auto& c : cases) + { + test(tz, c); + } +} + +void testUtc() +{ + const int kRange = 100*1000*1000; + for (time_t t = -kRange; t <= kRange; t += 11) + { + struct tm* t1 = gmtime(&t); + struct tm t2 = TimeZone::toUtcTime(t, true); + char buf1[80], buf2[80]; + strftime(buf1, sizeof buf1, "%F %T %u %j", t1); + strftime(buf2, sizeof buf2, "%F %T %u %j", &t2); + if (strcmp(buf1, buf2) != 0) + { + printf("'%s' != '%s'\n", buf1, buf2); + assert(0); + } + time_t t3 = TimeZone::fromUtcTime(t2); + if (t != t3) + { + printf("%ld != %ld\n", static_cast(t), static_cast(t3)); + assert(0); + } + } +} + +void testFixedTimezone() +{ + TimeZone tz(8*3600, "CST"); + TestCase cases[] = + { + + { "2014-04-03 00:00:00", "2014-04-03 08:00:00+0800(CST)", false}, + + }; + + for (const auto& c : cases) + { + test(tz, c); + } +} + +int main() +{ + testNewYork(); + testLondon(); + testSydney(); + testHongKong(); + testFixedTimezone(); + testUtc(); +} diff --git a/include/Third_Lib/muduo/base/tests/Timestamp_unittest.cc b/include/Third_Lib/muduo/base/tests/Timestamp_unittest.cc new file mode 100644 index 0000000..5e27592 --- /dev/null +++ b/include/Third_Lib/muduo/base/tests/Timestamp_unittest.cc @@ -0,0 +1,66 @@ +#include "muduo/base/Timestamp.h" +#include +#include + +using muduo::Timestamp; + +void passByConstReference(const Timestamp& x) +{ + printf("%s\n", x.toString().c_str()); +} + +void passByValue(Timestamp x) +{ + printf("%s\n", x.toString().c_str()); +} + +void benchmark() +{ + const int kNumber = 1000*1000; + + std::vector stamps; + stamps.reserve(kNumber); + for (int i = 0; i < kNumber; ++i) + { + stamps.push_back(Timestamp::now()); + } + printf("%s\n", stamps.front().toString().c_str()); + printf("%s\n", stamps.back().toString().c_str()); + printf("%f\n", timeDifference(stamps.back(), stamps.front())); + + int increments[100] = { 0 }; + int64_t start = stamps.front().microSecondsSinceEpoch(); + for (int i = 1; i < kNumber; ++i) + { + int64_t next = stamps[i].microSecondsSinceEpoch(); + int64_t inc = next - start; + start = next; + if (inc < 0) + { + printf("reverse!\n"); + } + else if (inc < 100) + { + ++increments[inc]; + } + else + { + printf("big gap %d\n", static_cast(inc)); + } + } + + for (int i = 0; i < 100; ++i) + { + printf("%2d: %d\n", i, increments[i]); + } +} + +int main() +{ + Timestamp now(Timestamp::now()); + printf("%s\n", now.toString().c_str()); + passByValue(now); + passByConstReference(now); + benchmark(); +} + diff --git a/include/Third_Lib/muduo/net/Acceptor.cc b/include/Third_Lib/muduo/net/Acceptor.cc new file mode 100644 index 0000000..39d0cb6 --- /dev/null +++ b/include/Third_Lib/muduo/net/Acceptor.cc @@ -0,0 +1,89 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/Acceptor.h" + +#include "muduo/base/Logging.h" +#include "muduo/net/EventLoop.h" +#include "muduo/net/InetAddress.h" +#include "muduo/net/SocketsOps.h" + +#include +#include +//#include +//#include +#include + +using namespace muduo; +using namespace muduo::net; + +Acceptor::Acceptor(EventLoop* loop, const InetAddress& listenAddr, bool reuseport) + : loop_(loop), + acceptSocket_(sockets::createNonblockingOrDie(listenAddr.family())), + acceptChannel_(loop, acceptSocket_.fd()), + listening_(false), + idleFd_(::open("/dev/null", O_RDONLY | O_CLOEXEC)) +{ + assert(idleFd_ >= 0); + acceptSocket_.setReuseAddr(true); + acceptSocket_.setReusePort(reuseport); + acceptSocket_.bindAddress(listenAddr); + acceptChannel_.setReadCallback( + std::bind(&Acceptor::handleRead, this)); +} + +Acceptor::~Acceptor() +{ + acceptChannel_.disableAll(); + acceptChannel_.remove(); + ::close(idleFd_); +} + +void Acceptor::listen() +{ + loop_->assertInLoopThread(); + listening_ = true; + acceptSocket_.listen(); + acceptChannel_.enableReading(); +} + +void Acceptor::handleRead() +{ + loop_->assertInLoopThread(); + InetAddress peerAddr; + //FIXME loop until no more + int connfd = acceptSocket_.accept(&peerAddr); + if (connfd >= 0) + { + // string hostport = peerAddr.toIpPort(); + // LOG_TRACE << "Accepts of " << hostport; + if (newConnectionCallback_) + { + newConnectionCallback_(connfd, peerAddr); + } + else + { + sockets::close(connfd); + } + } + else + { + LOG_SYSERR << "in Acceptor::handleRead"; + // Read the section named "The special problem of + // accept()ing when you can't" in libev's doc. + // By Marc Lehmann, author of libev. + if (errno == EMFILE) + { + ::close(idleFd_); + idleFd_ = ::accept(acceptSocket_.fd(), NULL, NULL); + ::close(idleFd_); + idleFd_ = ::open("/dev/null", O_RDONLY | O_CLOEXEC); + } + } +} + diff --git a/include/Third_Lib/muduo/net/Acceptor.h b/include/Third_Lib/muduo/net/Acceptor.h new file mode 100644 index 0000000..761d073 --- /dev/null +++ b/include/Third_Lib/muduo/net/Acceptor.h @@ -0,0 +1,63 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_ACCEPTOR_H +#define MUDUO_NET_ACCEPTOR_H + +#include + +#include "muduo/net/Channel.h" +#include "muduo/net/Socket.h" + +namespace muduo +{ +namespace net +{ + +class EventLoop; +class InetAddress; + +/// +/// Acceptor of incoming TCP connections. +/// +class Acceptor : noncopyable +{ + public: + typedef std::function NewConnectionCallback; + + Acceptor(EventLoop* loop, const InetAddress& listenAddr, bool reuseport); + ~Acceptor(); + + void setNewConnectionCallback(const NewConnectionCallback& cb) + { newConnectionCallback_ = cb; } + + void listen(); + + bool listening() const { return listening_; } + + // Deprecated, use the correct spelling one above. + // Leave the wrong spelling here in case one needs to grep it for error messages. + // bool listenning() const { return listening(); } + + private: + void handleRead(); + + EventLoop* loop_; + Socket acceptSocket_; + Channel acceptChannel_; + NewConnectionCallback newConnectionCallback_; + bool listening_; + int idleFd_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_ACCEPTOR_H diff --git a/include/Third_Lib/muduo/net/BUILD.bazel b/include/Third_Lib/muduo/net/BUILD.bazel new file mode 100644 index 0000000..33d78d1 --- /dev/null +++ b/include/Third_Lib/muduo/net/BUILD.bazel @@ -0,0 +1,51 @@ +cc_library( + name = "net", + srcs = [ + "Acceptor.cc", + "Buffer.cc", + "Channel.cc", + "Connector.cc", + "EventLoop.cc", + "EventLoopThread.cc", + "EventLoopThreadPool.cc", + "InetAddress.cc", + "Poller.cc", + "Socket.cc", + "SocketsOps.cc", + "TcpClient.cc", + "TcpConnection.cc", + "TcpServer.cc", + "Timer.cc", + "TimerQueue.cc", + "poller/DefaultPoller.cc", + "poller/EPollPoller.cc", + "poller/PollPoller.cc", + ], + hdrs = [ + "Acceptor.h", + "Buffer.h", + "Callbacks.h", + "Channel.h", + "Connector.h", + "Endian.h", + "EventLoop.h", + "EventLoopThread.h", + "EventLoopThreadPool.h", + "InetAddress.h", + "Poller.h", + "Socket.h", + "SocketsOps.h", + "TcpClient.h", + "TcpConnection.h", + "TcpServer.h", + "Timer.h", + "TimerId.h", + "TimerQueue.h", + "poller/EPollPoller.h", + "poller/PollPoller.h", + ], + visibility = ["//visibility:public"], + deps = [ + "//muduo/base", + ], +) diff --git a/include/Third_Lib/muduo/net/Buffer.cc b/include/Third_Lib/muduo/net/Buffer.cc new file mode 100644 index 0000000..7c921fc --- /dev/null +++ b/include/Third_Lib/muduo/net/Buffer.cc @@ -0,0 +1,58 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// + +#include "muduo/net/Buffer.h" + +#include "muduo/net/SocketsOps.h" + +#include +#include + +using namespace muduo; +using namespace muduo::net; + +const char Buffer::kCRLF[] = "\r\n"; + +const size_t Buffer::kCheapPrepend; +const size_t Buffer::kInitialSize; + +ssize_t Buffer::readFd(int fd, int* savedErrno) +{ + // saved an ioctl()/FIONREAD call to tell how much to read + char extrabuf[65536]; + struct iovec vec[2]; + const size_t writable = writableBytes(); + vec[0].iov_base = begin()+writerIndex_; + vec[0].iov_len = writable; + vec[1].iov_base = extrabuf; + vec[1].iov_len = sizeof extrabuf; + // when there is enough space in this buffer, don't read into extrabuf. + // when extrabuf is used, we read 128k-1 bytes at most. + const int iovcnt = (writable < sizeof extrabuf) ? 2 : 1; + const ssize_t n = sockets::readv(fd, vec, iovcnt); + if (n < 0) + { + *savedErrno = errno; + } + else if (implicit_cast(n) <= writable) + { + writerIndex_ += n; + } + else + { + writerIndex_ = buffer_.size(); + append(extrabuf, n - writable); + } + // if (n == writable + sizeof extrabuf) + // { + // goto line_30; + // } + return n; +} + diff --git a/include/Third_Lib/muduo/net/Buffer.h b/include/Third_Lib/muduo/net/Buffer.h new file mode 100644 index 0000000..4fa82d4 --- /dev/null +++ b/include/Third_Lib/muduo/net/Buffer.h @@ -0,0 +1,422 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_BUFFER_H +#define MUDUO_NET_BUFFER_H + +#include "muduo/base/copyable.h" +#include "muduo/base/StringPiece.h" +#include "muduo/base/Types.h" + +#include "muduo/net/Endian.h" + +#include +#include + +#include +#include +//#include // ssize_t + +namespace muduo +{ +namespace net +{ + +/// A buffer class modeled after org.jboss.netty.buffer.ChannelBuffer +/// +/// @code +/// +-------------------+------------------+------------------+ +/// | prependable bytes | readable bytes | writable bytes | +/// | | (CONTENT) | | +/// +-------------------+------------------+------------------+ +/// | | | | +/// 0 <= readerIndex <= writerIndex <= size +/// @endcode +class Buffer : public muduo::copyable +{ + public: + static const size_t kCheapPrepend = 8; + static const size_t kInitialSize = 1024; + + explicit Buffer(size_t initialSize = kInitialSize) + : buffer_(kCheapPrepend + initialSize), + readerIndex_(kCheapPrepend), + writerIndex_(kCheapPrepend) + { + assert(readableBytes() == 0); + assert(writableBytes() == initialSize); + assert(prependableBytes() == kCheapPrepend); + } + + // implicit copy-ctor, move-ctor, dtor and assignment are fine + // NOTE: implicit move-ctor is added in g++ 4.6 + + void swap(Buffer& rhs) + { + buffer_.swap(rhs.buffer_); + std::swap(readerIndex_, rhs.readerIndex_); + std::swap(writerIndex_, rhs.writerIndex_); + } + + size_t readableBytes() const + { return writerIndex_ - readerIndex_; } + + size_t writableBytes() const + { return buffer_.size() - writerIndex_; } + + size_t prependableBytes() const + { return readerIndex_; } + + const char* peek() const + { return begin() + readerIndex_; } + + const char* findCRLF() const + { + // FIXME: replace with memmem()? + const char* crlf = std::search(peek(), beginWrite(), kCRLF, kCRLF+2); + return crlf == beginWrite() ? NULL : crlf; + } + + const char* findCRLF(const char* start) const + { + assert(peek() <= start); + assert(start <= beginWrite()); + // FIXME: replace with memmem()? + const char* crlf = std::search(start, beginWrite(), kCRLF, kCRLF+2); + return crlf == beginWrite() ? NULL : crlf; + } + + const char* findEOL() const + { + const void* eol = memchr(peek(), '\n', readableBytes()); + return static_cast(eol); + } + + const char* findEOL(const char* start) const + { + assert(peek() <= start); + assert(start <= beginWrite()); + const void* eol = memchr(start, '\n', beginWrite() - start); + return static_cast(eol); + } + + // retrieve returns void, to prevent + // string str(retrieve(readableBytes()), readableBytes()); + // the evaluation of two functions are unspecified + void retrieve(size_t len) + { + assert(len <= readableBytes()); + if (len < readableBytes()) + { + readerIndex_ += len; + } + else + { + retrieveAll(); + } + } + + void retrieveUntil(const char* end) + { + assert(peek() <= end); + assert(end <= beginWrite()); + retrieve(end - peek()); + } + + void retrieveInt64() + { + retrieve(sizeof(int64_t)); + } + + void retrieveInt32() + { + retrieve(sizeof(int32_t)); + } + + void retrieveInt16() + { + retrieve(sizeof(int16_t)); + } + + void retrieveInt8() + { + retrieve(sizeof(int8_t)); + } + + void retrieveAll() + { + readerIndex_ = kCheapPrepend; + writerIndex_ = kCheapPrepend; + } + + string retrieveAllAsString() + { + return retrieveAsString(readableBytes()); + } + + string retrieveAsString(size_t len) + { + assert(len <= readableBytes()); + string result(peek(), len); + retrieve(len); + return result; + } + + StringPiece toStringPiece() const + { + return StringPiece(peek(), static_cast(readableBytes())); + } + + void append(const StringPiece& str) + { + append(str.data(), str.size()); + } + + void append(const char* /*restrict*/ data, size_t len) + { + ensureWritableBytes(len); + std::copy(data, data+len, beginWrite()); + hasWritten(len); + } + + void append(const void* /*restrict*/ data, size_t len) + { + append(static_cast(data), len); + } + + void ensureWritableBytes(size_t len) + { + if (writableBytes() < len) + { + makeSpace(len); + } + assert(writableBytes() >= len); + } + + char* beginWrite() + { return begin() + writerIndex_; } + + const char* beginWrite() const + { return begin() + writerIndex_; } + + void hasWritten(size_t len) + { + assert(len <= writableBytes()); + writerIndex_ += len; + } + + void unwrite(size_t len) + { + assert(len <= readableBytes()); + writerIndex_ -= len; + } + + /// + /// Append int64_t using network endian + /// + void appendInt64(int64_t x) + { + int64_t be64 = sockets::hostToNetwork64(x); + append(&be64, sizeof be64); + } + + /// + /// Append int32_t using network endian + /// + void appendInt32(int32_t x) + { + int32_t be32 = sockets::hostToNetwork32(x); + append(&be32, sizeof be32); + } + + void appendInt16(int16_t x) + { + int16_t be16 = sockets::hostToNetwork16(x); + append(&be16, sizeof be16); + } + + void appendInt8(int8_t x) + { + append(&x, sizeof x); + } + + /// + /// Read int64_t from network endian + /// + /// Require: buf->readableBytes() >= sizeof(int32_t) + int64_t readInt64() + { + int64_t result = peekInt64(); + retrieveInt64(); + return result; + } + + /// + /// Read int32_t from network endian + /// + /// Require: buf->readableBytes() >= sizeof(int32_t) + int32_t readInt32() + { + int32_t result = peekInt32(); + retrieveInt32(); + return result; + } + + int16_t readInt16() + { + int16_t result = peekInt16(); + retrieveInt16(); + return result; + } + + int8_t readInt8() + { + int8_t result = peekInt8(); + retrieveInt8(); + return result; + } + + /// + /// Peek int64_t from network endian + /// + /// Require: buf->readableBytes() >= sizeof(int64_t) + int64_t peekInt64() const + { + assert(readableBytes() >= sizeof(int64_t)); + int64_t be64 = 0; + ::memcpy(&be64, peek(), sizeof be64); + return sockets::networkToHost64(be64); + } + + /// + /// Peek int32_t from network endian + /// + /// Require: buf->readableBytes() >= sizeof(int32_t) + int32_t peekInt32() const + { + assert(readableBytes() >= sizeof(int32_t)); + int32_t be32 = 0; + ::memcpy(&be32, peek(), sizeof be32); + return sockets::networkToHost32(be32); + } + + int16_t peekInt16() const + { + assert(readableBytes() >= sizeof(int16_t)); + int16_t be16 = 0; + ::memcpy(&be16, peek(), sizeof be16); + return sockets::networkToHost16(be16); + } + + int8_t peekInt8() const + { + assert(readableBytes() >= sizeof(int8_t)); + int8_t x = *peek(); + return x; + } + + /// + /// Prepend int64_t using network endian + /// + void prependInt64(int64_t x) + { + int64_t be64 = sockets::hostToNetwork64(x); + prepend(&be64, sizeof be64); + } + + /// + /// Prepend int32_t using network endian + /// + void prependInt32(int32_t x) + { + int32_t be32 = sockets::hostToNetwork32(x); + prepend(&be32, sizeof be32); + } + + void prependInt16(int16_t x) + { + int16_t be16 = sockets::hostToNetwork16(x); + prepend(&be16, sizeof be16); + } + + void prependInt8(int8_t x) + { + prepend(&x, sizeof x); + } + + void prepend(const void* /*restrict*/ data, size_t len) + { + assert(len <= prependableBytes()); + readerIndex_ -= len; + const char* d = static_cast(data); + std::copy(d, d+len, begin()+readerIndex_); + } + + void shrink(size_t reserve) + { + // FIXME: use vector::shrink_to_fit() in C++ 11 if possible. + Buffer other; + other.ensureWritableBytes(readableBytes()+reserve); + other.append(toStringPiece()); + swap(other); + } + + size_t internalCapacity() const + { + return buffer_.capacity(); + } + + /// Read data directly into buffer. + /// + /// It may implement with readv(2) + /// @return result of read(2), @c errno is saved + ssize_t readFd(int fd, int* savedErrno); + + private: + + char* begin() + { return &*buffer_.begin(); } + + const char* begin() const + { return &*buffer_.begin(); } + + void makeSpace(size_t len) + { + if (writableBytes() + prependableBytes() < len + kCheapPrepend) + { + // FIXME: move readable data + buffer_.resize(writerIndex_+len); + } + else + { + // move readable data to the front, make space inside buffer + assert(kCheapPrepend < readerIndex_); + size_t readable = readableBytes(); + std::copy(begin()+readerIndex_, + begin()+writerIndex_, + begin()+kCheapPrepend); + readerIndex_ = kCheapPrepend; + writerIndex_ = readerIndex_ + readable; + assert(readable == readableBytes()); + } + } + + private: + std::vector buffer_; + size_t readerIndex_; + size_t writerIndex_; + + static const char kCRLF[]; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_BUFFER_H diff --git a/include/Third_Lib/muduo/net/CMakeLists.txt b/include/Third_Lib/muduo/net/CMakeLists.txt new file mode 100644 index 0000000..7510d87 --- /dev/null +++ b/include/Third_Lib/muduo/net/CMakeLists.txt @@ -0,0 +1,69 @@ +include(CheckFunctionExists) + +check_function_exists(accept4 HAVE_ACCEPT4) +if(NOT HAVE_ACCEPT4) + set_source_files_properties(SocketsOps.cc PROPERTIES COMPILE_FLAGS "-DNO_ACCEPT4") +endif() + +set(net_SRCS + Acceptor.cc + Buffer.cc + Channel.cc + Connector.cc + EventLoop.cc + EventLoopThread.cc + EventLoopThreadPool.cc + InetAddress.cc + Poller.cc + poller/DefaultPoller.cc + poller/EPollPoller.cc + poller/PollPoller.cc + Socket.cc + SocketsOps.cc + TcpClient.cc + TcpConnection.cc + TcpServer.cc + Timer.cc + TimerQueue.cc + ) + +add_library(muduo_net ${net_SRCS}) +target_link_libraries(muduo_net muduo_base) + +#add_library(muduo_net_cpp11 ${net_SRCS}) +#target_link_libraries(muduo_net_cpp11 muduo_base_cpp11) +#set_target_properties(muduo_net_cpp11 PROPERTIES COMPILE_FLAGS "-std=c++0x") + +install(TARGETS muduo_net DESTINATION lib) +#install(TARGETS muduo_net_cpp11 DESTINATION lib) + +set(HEADERS + Buffer.h + Callbacks.h + Channel.h + Endian.h + EventLoop.h + EventLoopThread.h + EventLoopThreadPool.h + InetAddress.h + TcpClient.h + TcpConnection.h + TcpServer.h + TimerId.h + ) +install(FILES ${HEADERS} DESTINATION include/muduo/net) + +add_subdirectory(http) +add_subdirectory(inspect) + +if(MUDUO_BUILD_EXAMPLES) + add_subdirectory(tests) +endif() + +if(PROTOBUF_FOUND) + add_subdirectory(protobuf) + add_subdirectory(protorpc) +else() + add_subdirectory(protobuf EXCLUDE_FROM_ALL) + add_subdirectory(protorpc EXCLUDE_FROM_ALL) +endif() diff --git a/include/Third_Lib/muduo/net/Callbacks.h b/include/Third_Lib/muduo/net/Callbacks.h new file mode 100644 index 0000000..443ed79 --- /dev/null +++ b/include/Third_Lib/muduo/net/Callbacks.h @@ -0,0 +1,82 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_CALLBACKS_H +#define MUDUO_NET_CALLBACKS_H + +#include "muduo/base/Timestamp.h" + +#include +#include + +namespace muduo +{ + +using std::placeholders::_1; +using std::placeholders::_2; +using std::placeholders::_3; + +// should really belong to base/Types.h, but is not included there. + +template +inline T* get_pointer(const std::shared_ptr& ptr) +{ + return ptr.get(); +} + +template +inline T* get_pointer(const std::unique_ptr& ptr) +{ + return ptr.get(); +} + +// Adapted from google-protobuf stubs/common.h +// see License in muduo/base/Types.h +template +inline ::std::shared_ptr down_pointer_cast(const ::std::shared_ptr& f) { + if (false) + { + implicit_cast(0); + } + +#ifndef NDEBUG + assert(f == NULL || dynamic_cast(get_pointer(f)) != NULL); +#endif + return ::std::static_pointer_cast(f); +} + +namespace net +{ + +// All client visible callbacks go here. + +class Buffer; +class TcpConnection; +typedef std::shared_ptr TcpConnectionPtr; +typedef std::function TimerCallback; +typedef std::function ConnectionCallback; +typedef std::function CloseCallback; +typedef std::function WriteCompleteCallback; +typedef std::function HighWaterMarkCallback; + +// the data has been read to (buf, len) +typedef std::function MessageCallback; + +void defaultConnectionCallback(const TcpConnectionPtr& conn); +void defaultMessageCallback(const TcpConnectionPtr& conn, + Buffer* buffer, + Timestamp receiveTime); + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_CALLBACKS_H diff --git a/include/Third_Lib/muduo/net/Channel.cc b/include/Third_Lib/muduo/net/Channel.cc new file mode 100644 index 0000000..1e9a40a --- /dev/null +++ b/include/Third_Lib/muduo/net/Channel.cc @@ -0,0 +1,146 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/base/Logging.h" +#include "muduo/net/Channel.h" +#include "muduo/net/EventLoop.h" + +#include + +#include + +using namespace muduo; +using namespace muduo::net; + +const int Channel::kNoneEvent = 0; +const int Channel::kReadEvent = POLLIN | POLLPRI; +const int Channel::kWriteEvent = POLLOUT; + +Channel::Channel(EventLoop* loop, int fd__) + : loop_(loop), + fd_(fd__), + events_(0), + revents_(0), + index_(-1), + logHup_(true), + tied_(false), + eventHandling_(false), + addedToLoop_(false) +{ +} + +Channel::~Channel() +{ + assert(!eventHandling_); + assert(!addedToLoop_); + if (loop_->isInLoopThread()) + { + assert(!loop_->hasChannel(this)); + } +} + +void Channel::tie(const std::shared_ptr& obj) +{ + tie_ = obj; + tied_ = true; +} + +void Channel::update() +{ + addedToLoop_ = true; + loop_->updateChannel(this); +} + +void Channel::remove() +{ + assert(isNoneEvent()); + addedToLoop_ = false; + loop_->removeChannel(this); +} + +void Channel::handleEvent(Timestamp receiveTime) +{ + std::shared_ptr guard; + if (tied_) + { + guard = tie_.lock(); + if (guard) + { + handleEventWithGuard(receiveTime); + } + } + else + { + handleEventWithGuard(receiveTime); + } +} + +void Channel::handleEventWithGuard(Timestamp receiveTime) +{ + eventHandling_ = true; + LOG_TRACE << reventsToString(); + if ((revents_ & POLLHUP) && !(revents_ & POLLIN)) + { + if (logHup_) + { + LOG_WARN << "fd = " << fd_ << " Channel::handle_event() POLLHUP"; + } + if (closeCallback_) closeCallback_(); + } + + if (revents_ & POLLNVAL) + { + LOG_WARN << "fd = " << fd_ << " Channel::handle_event() POLLNVAL"; + } + + if (revents_ & (POLLERR | POLLNVAL)) + { + if (errorCallback_) errorCallback_(); + } + if (revents_ & (POLLIN | POLLPRI | POLLRDHUP)) + { + if (readCallback_) readCallback_(receiveTime); + } + if (revents_ & POLLOUT) + { + if (writeCallback_) writeCallback_(); + } + eventHandling_ = false; +} + +string Channel::reventsToString() const +{ + return eventsToString(fd_, revents_); +} + +string Channel::eventsToString() const +{ + return eventsToString(fd_, events_); +} + +string Channel::eventsToString(int fd, int ev) +{ + std::ostringstream oss; + oss << fd << ": "; + if (ev & POLLIN) + oss << "IN "; + if (ev & POLLPRI) + oss << "PRI "; + if (ev & POLLOUT) + oss << "OUT "; + if (ev & POLLHUP) + oss << "HUP "; + if (ev & POLLRDHUP) + oss << "RDHUP "; + if (ev & POLLERR) + oss << "ERR "; + if (ev & POLLNVAL) + oss << "NVAL "; + + return oss.str(); +} diff --git a/include/Third_Lib/muduo/net/Channel.h b/include/Third_Lib/muduo/net/Channel.h new file mode 100644 index 0000000..bafa224 --- /dev/null +++ b/include/Third_Lib/muduo/net/Channel.h @@ -0,0 +1,113 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_CHANNEL_H +#define MUDUO_NET_CHANNEL_H + +#include "muduo/base/noncopyable.h" +#include "muduo/base/Timestamp.h" + +#include +#include + +namespace muduo +{ +namespace net +{ + +class EventLoop; + +/// +/// A selectable I/O channel. +/// +/// This class doesn't own the file descriptor. +/// The file descriptor could be a socket, +/// an eventfd, a timerfd, or a signalfd +class Channel : noncopyable +{ + public: + typedef std::function EventCallback; + typedef std::function ReadEventCallback; + + Channel(EventLoop* loop, int fd); + ~Channel(); + + void handleEvent(Timestamp receiveTime); + void setReadCallback(ReadEventCallback cb) + { readCallback_ = std::move(cb); } + void setWriteCallback(EventCallback cb) + { writeCallback_ = std::move(cb); } + void setCloseCallback(EventCallback cb) + { closeCallback_ = std::move(cb); } + void setErrorCallback(EventCallback cb) + { errorCallback_ = std::move(cb); } + + /// Tie this channel to the owner object managed by shared_ptr, + /// prevent the owner object being destroyed in handleEvent. + void tie(const std::shared_ptr&); + + int fd() const { return fd_; } + int events() const { return events_; } + void set_revents(int revt) { revents_ = revt; } // used by pollers + // int revents() const { return revents_; } + bool isNoneEvent() const { return events_ == kNoneEvent; } + + void enableReading() { events_ |= kReadEvent; update(); } + void disableReading() { events_ &= ~kReadEvent; update(); } + void enableWriting() { events_ |= kWriteEvent; update(); } + void disableWriting() { events_ &= ~kWriteEvent; update(); } + void disableAll() { events_ = kNoneEvent; update(); } + bool isWriting() const { return events_ & kWriteEvent; } + bool isReading() const { return events_ & kReadEvent; } + + // for Poller + int index() { return index_; } + void set_index(int idx) { index_ = idx; } + + // for debug + string reventsToString() const; + string eventsToString() const; + + void doNotLogHup() { logHup_ = false; } + + EventLoop* ownerLoop() { return loop_; } + void remove(); + + private: + static string eventsToString(int fd, int ev); + + void update(); + void handleEventWithGuard(Timestamp receiveTime); + + static const int kNoneEvent; + static const int kReadEvent; + static const int kWriteEvent; + + EventLoop* loop_; + const int fd_; + int events_; + int revents_; // it's the received event types of epoll or poll + int index_; // used by Poller. + bool logHup_; + + std::weak_ptr tie_; + bool tied_; + bool eventHandling_; + bool addedToLoop_; + ReadEventCallback readCallback_; + EventCallback writeCallback_; + EventCallback closeCallback_; + EventCallback errorCallback_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_CHANNEL_H diff --git a/include/Third_Lib/muduo/net/Connector.cc b/include/Third_Lib/muduo/net/Connector.cc new file mode 100644 index 0000000..0b492ad --- /dev/null +++ b/include/Third_Lib/muduo/net/Connector.cc @@ -0,0 +1,226 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// + +#include "muduo/net/Connector.h" + +#include "muduo/base/Logging.h" +#include "muduo/net/Channel.h" +#include "muduo/net/EventLoop.h" +#include "muduo/net/SocketsOps.h" + +#include + +using namespace muduo; +using namespace muduo::net; + +const int Connector::kMaxRetryDelayMs; + +Connector::Connector(EventLoop* loop, const InetAddress& serverAddr) + : loop_(loop), + serverAddr_(serverAddr), + connect_(false), + state_(kDisconnected), + retryDelayMs_(kInitRetryDelayMs) +{ + LOG_DEBUG << "ctor[" << this << "]"; +} + +Connector::~Connector() +{ + LOG_DEBUG << "dtor[" << this << "]"; + assert(!channel_); +} + +void Connector::start() +{ + connect_ = true; + loop_->runInLoop(std::bind(&Connector::startInLoop, this)); // FIXME: unsafe +} + +void Connector::startInLoop() +{ + loop_->assertInLoopThread(); + assert(state_ == kDisconnected); + if (connect_) + { + connect(); + } + else + { + LOG_DEBUG << "do not connect"; + } +} + +void Connector::stop() +{ + connect_ = false; + loop_->queueInLoop(std::bind(&Connector::stopInLoop, this)); // FIXME: unsafe + // FIXME: cancel timer +} + +void Connector::stopInLoop() +{ + loop_->assertInLoopThread(); + if (state_ == kConnecting) + { + setState(kDisconnected); + int sockfd = removeAndResetChannel(); + retry(sockfd); + } +} + +void Connector::connect() +{ + int sockfd = sockets::createNonblockingOrDie(serverAddr_.family()); + int ret = sockets::connect(sockfd, serverAddr_.getSockAddr()); + int savedErrno = (ret == 0) ? 0 : errno; + switch (savedErrno) + { + case 0: + case EINPROGRESS: + case EINTR: + case EISCONN: + connecting(sockfd); + break; + + case EAGAIN: + case EADDRINUSE: + case EADDRNOTAVAIL: + case ECONNREFUSED: + case ENETUNREACH: + retry(sockfd); + break; + + case EACCES: + case EPERM: + case EAFNOSUPPORT: + case EALREADY: + case EBADF: + case EFAULT: + case ENOTSOCK: + LOG_SYSERR << "connect error in Connector::startInLoop " << savedErrno; + sockets::close(sockfd); + break; + + default: + LOG_SYSERR << "Unexpected error in Connector::startInLoop " << savedErrno; + sockets::close(sockfd); + // connectErrorCallback_(); + break; + } +} + +void Connector::restart() +{ + loop_->assertInLoopThread(); + setState(kDisconnected); + retryDelayMs_ = kInitRetryDelayMs; + connect_ = true; + startInLoop(); +} + +void Connector::connecting(int sockfd) +{ + setState(kConnecting); + assert(!channel_); + channel_.reset(new Channel(loop_, sockfd)); + channel_->setWriteCallback( + std::bind(&Connector::handleWrite, this)); // FIXME: unsafe + channel_->setErrorCallback( + std::bind(&Connector::handleError, this)); // FIXME: unsafe + + // channel_->tie(shared_from_this()); is not working, + // as channel_ is not managed by shared_ptr + channel_->enableWriting(); +} + +int Connector::removeAndResetChannel() +{ + channel_->disableAll(); + channel_->remove(); + int sockfd = channel_->fd(); + // Can't reset channel_ here, because we are inside Channel::handleEvent + loop_->queueInLoop(std::bind(&Connector::resetChannel, this)); // FIXME: unsafe + return sockfd; +} + +void Connector::resetChannel() +{ + channel_.reset(); +} + +void Connector::handleWrite() +{ + LOG_TRACE << "Connector::handleWrite " << state_; + + if (state_ == kConnecting) + { + int sockfd = removeAndResetChannel(); + int err = sockets::getSocketError(sockfd); + if (err) + { + LOG_WARN << "Connector::handleWrite - SO_ERROR = " + << err << " " << strerror_tl(err); + retry(sockfd); + } + else if (sockets::isSelfConnect(sockfd)) + { + LOG_WARN << "Connector::handleWrite - Self connect"; + retry(sockfd); + } + else + { + setState(kConnected); + if (connect_) + { + newConnectionCallback_(sockfd); + } + else + { + sockets::close(sockfd); + } + } + } + else + { + // what happened? + assert(state_ == kDisconnected); + } +} + +void Connector::handleError() +{ + LOG_ERROR << "Connector::handleError state=" << state_; + if (state_ == kConnecting) + { + int sockfd = removeAndResetChannel(); + int err = sockets::getSocketError(sockfd); + LOG_TRACE << "SO_ERROR = " << err << " " << strerror_tl(err); + retry(sockfd); + } +} + +void Connector::retry(int sockfd) +{ + sockets::close(sockfd); + setState(kDisconnected); + if (connect_) + { + LOG_INFO << "Connector::retry - Retry connecting to " << serverAddr_.toIpPort() + << " in " << retryDelayMs_ << " milliseconds. "; + loop_->runAfter(retryDelayMs_/1000.0, + std::bind(&Connector::startInLoop, shared_from_this())); + retryDelayMs_ = std::min(retryDelayMs_ * 2, kMaxRetryDelayMs); + } + else + { + LOG_DEBUG << "do not connect"; + } +} + diff --git a/include/Third_Lib/muduo/net/Connector.h b/include/Third_Lib/muduo/net/Connector.h new file mode 100644 index 0000000..4b79fb2 --- /dev/null +++ b/include/Third_Lib/muduo/net/Connector.h @@ -0,0 +1,74 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_CONNECTOR_H +#define MUDUO_NET_CONNECTOR_H + +#include "muduo/base/noncopyable.h" +#include "muduo/net/InetAddress.h" + +#include +#include + +namespace muduo +{ +namespace net +{ + +class Channel; +class EventLoop; + +class Connector : noncopyable, + public std::enable_shared_from_this +{ + public: + typedef std::function NewConnectionCallback; + + Connector(EventLoop* loop, const InetAddress& serverAddr); + ~Connector(); + + void setNewConnectionCallback(const NewConnectionCallback& cb) + { newConnectionCallback_ = cb; } + + void start(); // can be called in any thread + void restart(); // must be called in loop thread + void stop(); // can be called in any thread + + const InetAddress& serverAddress() const { return serverAddr_; } + + private: + enum States { kDisconnected, kConnecting, kConnected }; + static const int kMaxRetryDelayMs = 30*1000; + static const int kInitRetryDelayMs = 500; + + void setState(States s) { state_ = s; } + void startInLoop(); + void stopInLoop(); + void connect(); + void connecting(int sockfd); + void handleWrite(); + void handleError(); + void retry(int sockfd); + int removeAndResetChannel(); + void resetChannel(); + + EventLoop* loop_; + InetAddress serverAddr_; + bool connect_; // atomic + States state_; // FIXME: use atomic variable + std::unique_ptr channel_; + NewConnectionCallback newConnectionCallback_; + int retryDelayMs_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_CONNECTOR_H diff --git a/include/Third_Lib/muduo/net/Endian.h b/include/Third_Lib/muduo/net/Endian.h new file mode 100644 index 0000000..82bd730 --- /dev/null +++ b/include/Third_Lib/muduo/net/Endian.h @@ -0,0 +1,65 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_ENDIAN_H +#define MUDUO_NET_ENDIAN_H + +#include +#include + +namespace muduo +{ +namespace net +{ +namespace sockets +{ + +// the inline assembler code makes type blur, +// so we disable warnings for a while. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#pragma GCC diagnostic ignored "-Wold-style-cast" +inline uint64_t hostToNetwork64(uint64_t host64) +{ + return htobe64(host64); +} + +inline uint32_t hostToNetwork32(uint32_t host32) +{ + return htobe32(host32); +} + +inline uint16_t hostToNetwork16(uint16_t host16) +{ + return htobe16(host16); +} + +inline uint64_t networkToHost64(uint64_t net64) +{ + return be64toh(net64); +} + +inline uint32_t networkToHost32(uint32_t net32) +{ + return be32toh(net32); +} + +inline uint16_t networkToHost16(uint16_t net16) +{ + return be16toh(net16); +} + +#pragma GCC diagnostic pop + +} // namespace sockets +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_ENDIAN_H diff --git a/include/Third_Lib/muduo/net/EventLoop.cc b/include/Third_Lib/muduo/net/EventLoop.cc new file mode 100644 index 0000000..b3feebe --- /dev/null +++ b/include/Third_Lib/muduo/net/EventLoop.cc @@ -0,0 +1,278 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/EventLoop.h" + +#include "muduo/base/Logging.h" +#include "muduo/base/Mutex.h" +#include "muduo/net/Channel.h" +#include "muduo/net/Poller.h" +#include "muduo/net/SocketsOps.h" +#include "muduo/net/TimerQueue.h" + +#include + +#include +#include +#include + +using namespace muduo; +using namespace muduo::net; + +namespace +{ +__thread EventLoop* t_loopInThisThread = 0; + +const int kPollTimeMs = 10000; + +int createEventfd() +{ + int evtfd = ::eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); + if (evtfd < 0) + { + LOG_SYSERR << "Failed in eventfd"; + abort(); + } + return evtfd; +} + +#pragma GCC diagnostic ignored "-Wold-style-cast" +class IgnoreSigPipe +{ + public: + IgnoreSigPipe() + { + ::signal(SIGPIPE, SIG_IGN); + // LOG_TRACE << "Ignore SIGPIPE"; + } +}; +#pragma GCC diagnostic error "-Wold-style-cast" + +IgnoreSigPipe initObj; +} // namespace + +EventLoop* EventLoop::getEventLoopOfCurrentThread() +{ + return t_loopInThisThread; +} + +EventLoop::EventLoop() + : looping_(false), + quit_(false), + eventHandling_(false), + callingPendingFunctors_(false), + iteration_(0), + threadId_(CurrentThread::tid()), + poller_(Poller::newDefaultPoller(this)), + timerQueue_(new TimerQueue(this)), + wakeupFd_(createEventfd()), + wakeupChannel_(new Channel(this, wakeupFd_)), + currentActiveChannel_(NULL) +{ + LOG_DEBUG << "EventLoop created " << this << " in thread " << threadId_; + if (t_loopInThisThread) + { + LOG_FATAL << "Another EventLoop " << t_loopInThisThread + << " exists in this thread " << threadId_; + } + else + { + t_loopInThisThread = this; + } + wakeupChannel_->setReadCallback( + std::bind(&EventLoop::handleRead, this)); + // we are always reading the wakeupfd + wakeupChannel_->enableReading(); +} + +EventLoop::~EventLoop() +{ + LOG_DEBUG << "EventLoop " << this << " of thread " << threadId_ + << " destructs in thread " << CurrentThread::tid(); + wakeupChannel_->disableAll(); + wakeupChannel_->remove(); + ::close(wakeupFd_); + t_loopInThisThread = NULL; +} + +void EventLoop::loop() +{ + assert(!looping_); + assertInLoopThread(); + looping_ = true; + quit_ = false; // FIXME: what if someone calls quit() before loop() ? + LOG_TRACE << "EventLoop " << this << " start looping"; + + while (!quit_) + { + activeChannels_.clear(); + pollReturnTime_ = poller_->poll(kPollTimeMs, &activeChannels_); + ++iteration_; + if (Logger::logLevel() <= Logger::TRACE) + { + printActiveChannels(); + } + // TODO sort channel by priority + eventHandling_ = true; + for (Channel* channel : activeChannels_) + { + currentActiveChannel_ = channel; + currentActiveChannel_->handleEvent(pollReturnTime_); + } + currentActiveChannel_ = NULL; + eventHandling_ = false; + doPendingFunctors(); + } + + LOG_TRACE << "EventLoop " << this << " stop looping"; + looping_ = false; +} + +void EventLoop::quit() +{ + quit_ = true; + // There is a chance that loop() just executes while(!quit_) and exits, + // then EventLoop destructs, then we are accessing an invalid object. + // Can be fixed using mutex_ in both places. + if (!isInLoopThread()) + { + wakeup(); + } +} + +void EventLoop::runInLoop(Functor cb) +{ + if (isInLoopThread()) + { + cb(); + } + else + { + queueInLoop(std::move(cb)); + } +} + +void EventLoop::queueInLoop(Functor cb) +{ + { + MutexLockGuard lock(mutex_); + pendingFunctors_.push_back(std::move(cb)); + } + + if (!isInLoopThread() || callingPendingFunctors_) + { + wakeup(); + } +} + +size_t EventLoop::queueSize() const +{ + MutexLockGuard lock(mutex_); + return pendingFunctors_.size(); +} + +TimerId EventLoop::runAt(Timestamp time, TimerCallback cb) +{ + return timerQueue_->addTimer(std::move(cb), time, 0.0); +} + +TimerId EventLoop::runAfter(double delay, TimerCallback cb) +{ + Timestamp time(addTime(Timestamp::now(), delay)); + return runAt(time, std::move(cb)); +} + +TimerId EventLoop::runEvery(double interval, TimerCallback cb) +{ + Timestamp time(addTime(Timestamp::now(), interval)); + return timerQueue_->addTimer(std::move(cb), time, interval); +} + +void EventLoop::cancel(TimerId timerId) +{ + return timerQueue_->cancel(timerId); +} + +void EventLoop::updateChannel(Channel* channel) +{ + assert(channel->ownerLoop() == this); + assertInLoopThread(); + poller_->updateChannel(channel); +} + +void EventLoop::removeChannel(Channel* channel) +{ + assert(channel->ownerLoop() == this); + assertInLoopThread(); + if (eventHandling_) + { + assert(currentActiveChannel_ == channel || + std::find(activeChannels_.begin(), activeChannels_.end(), channel) == activeChannels_.end()); + } + poller_->removeChannel(channel); +} + +bool EventLoop::hasChannel(Channel* channel) +{ + assert(channel->ownerLoop() == this); + assertInLoopThread(); + return poller_->hasChannel(channel); +} + +void EventLoop::abortNotInLoopThread() +{ + LOG_FATAL << "EventLoop::abortNotInLoopThread - EventLoop " << this + << " was created in threadId_ = " << threadId_ + << ", current thread id = " << CurrentThread::tid(); +} + +void EventLoop::wakeup() +{ + uint64_t one = 1; + ssize_t n = sockets::write(wakeupFd_, &one, sizeof one); + if (n != sizeof one) + { + LOG_ERROR << "EventLoop::wakeup() writes " << n << " bytes instead of 8"; + } +} + +void EventLoop::handleRead() +{ + uint64_t one = 1; + ssize_t n = sockets::read(wakeupFd_, &one, sizeof one); + if (n != sizeof one) + { + LOG_ERROR << "EventLoop::handleRead() reads " << n << " bytes instead of 8"; + } +} + +void EventLoop::doPendingFunctors() +{ + std::vector functors; + callingPendingFunctors_ = true; + + { + MutexLockGuard lock(mutex_); + functors.swap(pendingFunctors_); + } + + for (const Functor& functor : functors) + { + functor(); + } + callingPendingFunctors_ = false; +} + +void EventLoop::printActiveChannels() const +{ + for (const Channel* channel : activeChannels_) + { + LOG_TRACE << "{" << channel->reventsToString() << "} "; + } +} + diff --git a/include/Third_Lib/muduo/net/EventLoop.h b/include/Third_Lib/muduo/net/EventLoop.h new file mode 100644 index 0000000..c2c53d3 --- /dev/null +++ b/include/Third_Lib/muduo/net/EventLoop.h @@ -0,0 +1,166 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_EVENTLOOP_H +#define MUDUO_NET_EVENTLOOP_H + +#include +#include +#include + +#include + +#include "muduo/base/Mutex.h" +#include "muduo/base/CurrentThread.h" +#include "muduo/base/Timestamp.h" +#include "muduo/net/Callbacks.h" +#include "muduo/net/TimerId.h" + +namespace muduo +{ +namespace net +{ + +class Channel; +class Poller; +class TimerQueue; + +/// +/// Reactor, at most one per thread. +/// +/// This is an interface class, so don't expose too much details. +class EventLoop : noncopyable +{ + public: + typedef std::function Functor; + + EventLoop(); + ~EventLoop(); // force out-line dtor, for std::unique_ptr members. + + /// + /// Loops forever. + /// + /// Must be called in the same thread as creation of the object. + /// + void loop(); + + /// Quits loop. + /// + /// This is not 100% thread safe, if you call through a raw pointer, + /// better to call through shared_ptr for 100% safety. + void quit(); + + /// + /// Time when poll returns, usually means data arrival. + /// + Timestamp pollReturnTime() const { return pollReturnTime_; } + + int64_t iteration() const { return iteration_; } + + /// Runs callback immediately in the loop thread. + /// It wakes up the loop, and run the cb. + /// If in the same loop thread, cb is run within the function. + /// Safe to call from other threads. + void runInLoop(Functor cb); + /// Queues callback in the loop thread. + /// Runs after finish pooling. + /// Safe to call from other threads. + void queueInLoop(Functor cb); + + size_t queueSize() const; + + // timers + + /// + /// Runs callback at 'time'. + /// Safe to call from other threads. + /// + TimerId runAt(Timestamp time, TimerCallback cb); + /// + /// Runs callback after @c delay seconds. + /// Safe to call from other threads. + /// + TimerId runAfter(double delay, TimerCallback cb); + /// + /// Runs callback every @c interval seconds. + /// Safe to call from other threads. + /// + TimerId runEvery(double interval, TimerCallback cb); + /// + /// Cancels the timer. + /// Safe to call from other threads. + /// + void cancel(TimerId timerId); + + // internal usage + void wakeup(); + void updateChannel(Channel* channel); + void removeChannel(Channel* channel); + bool hasChannel(Channel* channel); + + // pid_t threadId() const { return threadId_; } + void assertInLoopThread() + { + if (!isInLoopThread()) + { + abortNotInLoopThread(); + } + } + bool isInLoopThread() const { return threadId_ == CurrentThread::tid(); } + // bool callingPendingFunctors() const { return callingPendingFunctors_; } + bool eventHandling() const { return eventHandling_; } + + void setContext(const boost::any& context) + { context_ = context; } + + const boost::any& getContext() const + { return context_; } + + boost::any* getMutableContext() + { return &context_; } + + static EventLoop* getEventLoopOfCurrentThread(); + + private: + void abortNotInLoopThread(); + void handleRead(); // waked up + void doPendingFunctors(); + + void printActiveChannels() const; // DEBUG + + typedef std::vector ChannelList; + + bool looping_; /* atomic */ + std::atomic quit_; + bool eventHandling_; /* atomic */ + bool callingPendingFunctors_; /* atomic */ + int64_t iteration_; + const pid_t threadId_; + Timestamp pollReturnTime_; + std::unique_ptr poller_; + std::unique_ptr timerQueue_; + int wakeupFd_; + // unlike in TimerQueue, which is an internal class, + // we don't expose Channel to client. + std::unique_ptr wakeupChannel_; + boost::any context_; + + // scratch variables + ChannelList activeChannels_; + Channel* currentActiveChannel_; + + mutable MutexLock mutex_; + std::vector pendingFunctors_ GUARDED_BY(mutex_); +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_EVENTLOOP_H diff --git a/include/Third_Lib/muduo/net/EventLoopThread.cc b/include/Third_Lib/muduo/net/EventLoopThread.cc new file mode 100644 index 0000000..c1b6fa5 --- /dev/null +++ b/include/Third_Lib/muduo/net/EventLoopThread.cc @@ -0,0 +1,77 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/EventLoopThread.h" + +#include "muduo/net/EventLoop.h" + +using namespace muduo; +using namespace muduo::net; + +EventLoopThread::EventLoopThread(const ThreadInitCallback& cb, + const string& name) + : loop_(NULL), + exiting_(false), + thread_(std::bind(&EventLoopThread::threadFunc, this), name), + mutex_(), + cond_(mutex_), + callback_(cb) +{ +} + +EventLoopThread::~EventLoopThread() +{ + exiting_ = true; + if (loop_ != NULL) // not 100% race-free, eg. threadFunc could be running callback_. + { + // still a tiny chance to call destructed object, if threadFunc exits just now. + // but when EventLoopThread destructs, usually programming is exiting anyway. + loop_->quit(); + thread_.join(); + } +} + +EventLoop* EventLoopThread::startLoop() +{ + assert(!thread_.started()); + thread_.start(); + + EventLoop* loop = NULL; + { + MutexLockGuard lock(mutex_); + while (loop_ == NULL) + { + cond_.wait(); + } + loop = loop_; + } + + return loop; +} + +void EventLoopThread::threadFunc() +{ + EventLoop loop; + + if (callback_) + { + callback_(&loop); + } + + { + MutexLockGuard lock(mutex_); + loop_ = &loop; + cond_.notify(); + } + + loop.loop(); + //assert(exiting_); + MutexLockGuard lock(mutex_); + loop_ = NULL; +} + diff --git a/include/Third_Lib/muduo/net/EventLoopThread.h b/include/Third_Lib/muduo/net/EventLoopThread.h new file mode 100644 index 0000000..7e839d7 --- /dev/null +++ b/include/Third_Lib/muduo/net/EventLoopThread.h @@ -0,0 +1,50 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_EVENTLOOPTHREAD_H +#define MUDUO_NET_EVENTLOOPTHREAD_H + +#include "muduo/base/Condition.h" +#include "muduo/base/Mutex.h" +#include "muduo/base/Thread.h" + +namespace muduo +{ +namespace net +{ + +class EventLoop; + +class EventLoopThread : noncopyable +{ + public: + typedef std::function ThreadInitCallback; + + EventLoopThread(const ThreadInitCallback& cb = ThreadInitCallback(), + const string& name = string()); + ~EventLoopThread(); + EventLoop* startLoop(); + + private: + void threadFunc(); + + EventLoop* loop_ GUARDED_BY(mutex_); + bool exiting_; + Thread thread_; + MutexLock mutex_; + Condition cond_ GUARDED_BY(mutex_); + ThreadInitCallback callback_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_EVENTLOOPTHREAD_H + diff --git a/include/Third_Lib/muduo/net/EventLoopThreadPool.cc b/include/Third_Lib/muduo/net/EventLoopThreadPool.cc new file mode 100644 index 0000000..1ee5949 --- /dev/null +++ b/include/Third_Lib/muduo/net/EventLoopThreadPool.cc @@ -0,0 +1,97 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/EventLoopThreadPool.h" + +#include "muduo/net/EventLoop.h" +#include "muduo/net/EventLoopThread.h" + +#include + +using namespace muduo; +using namespace muduo::net; + +EventLoopThreadPool::EventLoopThreadPool(EventLoop* baseLoop, const string& nameArg) + : baseLoop_(baseLoop), + name_(nameArg), + started_(false), + numThreads_(0), + next_(0) +{ +} + +EventLoopThreadPool::~EventLoopThreadPool() +{ + // Don't delete loop, it's stack variable +} + +void EventLoopThreadPool::start(const ThreadInitCallback& cb) +{ + assert(!started_); + baseLoop_->assertInLoopThread(); + + started_ = true; + + for (int i = 0; i < numThreads_; ++i) + { + char buf[name_.size() + 32]; + snprintf(buf, sizeof buf, "%s%d", name_.c_str(), i); + EventLoopThread* t = new EventLoopThread(cb, buf); + threads_.push_back(std::unique_ptr(t)); + loops_.push_back(t->startLoop()); + } + if (numThreads_ == 0 && cb) + { + cb(baseLoop_); + } +} + +EventLoop* EventLoopThreadPool::getNextLoop() +{ + baseLoop_->assertInLoopThread(); + assert(started_); + EventLoop* loop = baseLoop_; + + if (!loops_.empty()) + { + // round-robin + loop = loops_[next_]; + ++next_; + if (implicit_cast(next_) >= loops_.size()) + { + next_ = 0; + } + } + return loop; +} + +EventLoop* EventLoopThreadPool::getLoopForHash(size_t hashCode) +{ + baseLoop_->assertInLoopThread(); + EventLoop* loop = baseLoop_; + + if (!loops_.empty()) + { + loop = loops_[hashCode % loops_.size()]; + } + return loop; +} + +std::vector EventLoopThreadPool::getAllLoops() +{ + baseLoop_->assertInLoopThread(); + assert(started_); + if (loops_.empty()) + { + return std::vector(1, baseLoop_); + } + else + { + return loops_; + } +} diff --git a/include/Third_Lib/muduo/net/EventLoopThreadPool.h b/include/Third_Lib/muduo/net/EventLoopThreadPool.h new file mode 100644 index 0000000..7389148 --- /dev/null +++ b/include/Third_Lib/muduo/net/EventLoopThreadPool.h @@ -0,0 +1,69 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_EVENTLOOPTHREADPOOL_H +#define MUDUO_NET_EVENTLOOPTHREADPOOL_H + +#include "muduo/base/noncopyable.h" +#include "muduo/base/Types.h" + +#include +#include +#include + +namespace muduo +{ + +namespace net +{ + +class EventLoop; +class EventLoopThread; + +class EventLoopThreadPool : noncopyable +{ + public: + typedef std::function ThreadInitCallback; + + EventLoopThreadPool(EventLoop* baseLoop, const string& nameArg); + ~EventLoopThreadPool(); + void setThreadNum(int numThreads) { numThreads_ = numThreads; } + void start(const ThreadInitCallback& cb = ThreadInitCallback()); + + // valid after calling start() + /// round-robin + EventLoop* getNextLoop(); + + /// with the same hash code, it will always return the same EventLoop + EventLoop* getLoopForHash(size_t hashCode); + + std::vector getAllLoops(); + + bool started() const + { return started_; } + + const string& name() const + { return name_; } + + private: + + EventLoop* baseLoop_; + string name_; + bool started_; + int numThreads_; + int next_; + std::vector> threads_; + std::vector loops_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_EVENTLOOPTHREADPOOL_H diff --git a/include/Third_Lib/muduo/net/InetAddress.cc b/include/Third_Lib/muduo/net/InetAddress.cc new file mode 100644 index 0000000..7c5e0ae --- /dev/null +++ b/include/Third_Lib/muduo/net/InetAddress.cc @@ -0,0 +1,149 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/InetAddress.h" + +#include "muduo/base/Logging.h" +#include "muduo/net/Endian.h" +#include "muduo/net/SocketsOps.h" + +#include +#include + +// INADDR_ANY use (type)value casting. +#pragma GCC diagnostic ignored "-Wold-style-cast" +static const in_addr_t kInaddrAny = INADDR_ANY; +static const in_addr_t kInaddrLoopback = INADDR_LOOPBACK; +#pragma GCC diagnostic error "-Wold-style-cast" + +// /* Structure describing an Internet socket address. */ +// struct sockaddr_in { +// sa_family_t sin_family; /* address family: AF_INET */ +// uint16_t sin_port; /* port in network byte order */ +// struct in_addr sin_addr; /* internet address */ +// }; + +// /* Internet address. */ +// typedef uint32_t in_addr_t; +// struct in_addr { +// in_addr_t s_addr; /* address in network byte order */ +// }; + +// struct sockaddr_in6 { +// sa_family_t sin6_family; /* address family: AF_INET6 */ +// uint16_t sin6_port; /* port in network byte order */ +// uint32_t sin6_flowinfo; /* IPv6 flow information */ +// struct in6_addr sin6_addr; /* IPv6 address */ +// uint32_t sin6_scope_id; /* IPv6 scope-id */ +// }; + +using namespace muduo; +using namespace muduo::net; + +static_assert(sizeof(InetAddress) == sizeof(struct sockaddr_in6), + "InetAddress is same size as sockaddr_in6"); +static_assert(offsetof(sockaddr_in, sin_family) == 0, "sin_family offset 0"); +static_assert(offsetof(sockaddr_in6, sin6_family) == 0, "sin6_family offset 0"); +static_assert(offsetof(sockaddr_in, sin_port) == 2, "sin_port offset 2"); +static_assert(offsetof(sockaddr_in6, sin6_port) == 2, "sin6_port offset 2"); + +InetAddress::InetAddress(uint16_t port, bool loopbackOnly, bool ipv6) +{ + static_assert(offsetof(InetAddress, addr6_) == 0, "addr6_ offset 0"); + static_assert(offsetof(InetAddress, addr_) == 0, "addr_ offset 0"); + if (ipv6) + { + memZero(&addr6_, sizeof addr6_); + addr6_.sin6_family = AF_INET6; + in6_addr ip = loopbackOnly ? in6addr_loopback : in6addr_any; + addr6_.sin6_addr = ip; + addr6_.sin6_port = sockets::hostToNetwork16(port); + } + else + { + memZero(&addr_, sizeof addr_); + addr_.sin_family = AF_INET; + in_addr_t ip = loopbackOnly ? kInaddrLoopback : kInaddrAny; + addr_.sin_addr.s_addr = sockets::hostToNetwork32(ip); + addr_.sin_port = sockets::hostToNetwork16(port); + } +} + +InetAddress::InetAddress(StringArg ip, uint16_t port, bool ipv6) +{ + if (ipv6 || strchr(ip.c_str(), ':')) + { + memZero(&addr6_, sizeof addr6_); + sockets::fromIpPort(ip.c_str(), port, &addr6_); + } + else + { + memZero(&addr_, sizeof addr_); + sockets::fromIpPort(ip.c_str(), port, &addr_); + } +} + +string InetAddress::toIpPort() const +{ + char buf[64] = ""; + sockets::toIpPort(buf, sizeof buf, getSockAddr()); + return buf; +} + +string InetAddress::toIp() const +{ + char buf[64] = ""; + sockets::toIp(buf, sizeof buf, getSockAddr()); + return buf; +} + +uint32_t InetAddress::ipv4NetEndian() const +{ + assert(family() == AF_INET); + return addr_.sin_addr.s_addr; +} + +uint16_t InetAddress::port() const +{ + return sockets::networkToHost16(portNetEndian()); +} + +static __thread char t_resolveBuffer[64 * 1024]; + +bool InetAddress::resolve(StringArg hostname, InetAddress* out) +{ + assert(out != NULL); + struct hostent hent; + struct hostent* he = NULL; + int herrno = 0; + memZero(&hent, sizeof(hent)); + + int ret = gethostbyname_r(hostname.c_str(), &hent, t_resolveBuffer, sizeof t_resolveBuffer, &he, &herrno); + if (ret == 0 && he != NULL) + { + assert(he->h_addrtype == AF_INET && he->h_length == sizeof(uint32_t)); + out->addr_.sin_addr = *reinterpret_cast(he->h_addr); + return true; + } + else + { + if (ret) + { + LOG_SYSERR << "InetAddress::resolve"; + } + return false; + } +} + +void InetAddress::setScopeId(uint32_t scope_id) +{ + if (family() == AF_INET6) + { + addr6_.sin6_scope_id = scope_id; + } +} diff --git a/include/Third_Lib/muduo/net/InetAddress.h b/include/Third_Lib/muduo/net/InetAddress.h new file mode 100644 index 0000000..c5263a7 --- /dev/null +++ b/include/Third_Lib/muduo/net/InetAddress.h @@ -0,0 +1,86 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_INETADDRESS_H +#define MUDUO_NET_INETADDRESS_H + +#include "muduo/base/copyable.h" +#include "muduo/base/StringPiece.h" + +#include + +namespace muduo +{ +namespace net +{ +namespace sockets +{ +const struct sockaddr* sockaddr_cast(const struct sockaddr_in6* addr); +} + +/// +/// Wrapper of sockaddr_in. +/// +/// This is an POD interface class. +class InetAddress : public muduo::copyable +{ + public: + /// Constructs an endpoint with given port number. + /// Mostly used in TcpServer listening. + explicit InetAddress(uint16_t port = 0, bool loopbackOnly = false, bool ipv6 = false); + + /// Constructs an endpoint with given ip and port. + /// @c ip should be "1.2.3.4" + InetAddress(StringArg ip, uint16_t port, bool ipv6 = false); + + /// Constructs an endpoint with given struct @c sockaddr_in + /// Mostly used when accepting new connections + explicit InetAddress(const struct sockaddr_in& addr) + : addr_(addr) + { } + + explicit InetAddress(const struct sockaddr_in6& addr) + : addr6_(addr) + { } + + sa_family_t family() const { return addr_.sin_family; } + string toIp() const; + string toIpPort() const; + uint16_t port() const; + + // default copy/assignment are Okay + + const struct sockaddr* getSockAddr() const { return sockets::sockaddr_cast(&addr6_); } + void setSockAddrInet6(const struct sockaddr_in6& addr6) { addr6_ = addr6; } + + uint32_t ipv4NetEndian() const; + uint16_t portNetEndian() const { return addr_.sin_port; } + + // resolve hostname to IP address, not changing port or sin_family + // return true on success. + // thread safe + static bool resolve(StringArg hostname, InetAddress* result); + // static std::vector resolveAll(const char* hostname, uint16_t port = 0); + + // set IPv6 ScopeID + void setScopeId(uint32_t scope_id); + + private: + union + { + struct sockaddr_in addr_; + struct sockaddr_in6 addr6_; + }; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_INETADDRESS_H diff --git a/include/Third_Lib/muduo/net/Poller.cc b/include/Third_Lib/muduo/net/Poller.cc new file mode 100644 index 0000000..cfe4c3c --- /dev/null +++ b/include/Third_Lib/muduo/net/Poller.cc @@ -0,0 +1,29 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/Poller.h" + +#include "muduo/net/Channel.h" + +using namespace muduo; +using namespace muduo::net; + +Poller::Poller(EventLoop* loop) + : ownerLoop_(loop) +{ +} + +Poller::~Poller() = default; + +bool Poller::hasChannel(Channel* channel) const +{ + assertInLoopThread(); + ChannelMap::const_iterator it = channels_.find(channel->fd()); + return it != channels_.end() && it->second == channel; +} + diff --git a/include/Third_Lib/muduo/net/Poller.h b/include/Third_Lib/muduo/net/Poller.h new file mode 100644 index 0000000..089e60b --- /dev/null +++ b/include/Third_Lib/muduo/net/Poller.h @@ -0,0 +1,71 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_POLLER_H +#define MUDUO_NET_POLLER_H + +#include +#include + +#include "muduo/base/Timestamp.h" +#include "muduo/net/EventLoop.h" + +namespace muduo +{ +namespace net +{ + +class Channel; + +/// +/// Base class for IO Multiplexing +/// +/// This class doesn't own the Channel objects. +class Poller : noncopyable +{ + public: + typedef std::vector ChannelList; + + Poller(EventLoop* loop); + virtual ~Poller(); + + /// Polls the I/O events. + /// Must be called in the loop thread. + virtual Timestamp poll(int timeoutMs, ChannelList* activeChannels) = 0; + + /// Changes the interested I/O events. + /// Must be called in the loop thread. + virtual void updateChannel(Channel* channel) = 0; + + /// Remove the channel, when it destructs. + /// Must be called in the loop thread. + virtual void removeChannel(Channel* channel) = 0; + + virtual bool hasChannel(Channel* channel) const; + + static Poller* newDefaultPoller(EventLoop* loop); + + void assertInLoopThread() const + { + ownerLoop_->assertInLoopThread(); + } + + protected: + typedef std::map ChannelMap; + ChannelMap channels_; + + private: + EventLoop* ownerLoop_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_POLLER_H diff --git a/include/Third_Lib/muduo/net/Socket.cc b/include/Third_Lib/muduo/net/Socket.cc new file mode 100644 index 0000000..fc13147 --- /dev/null +++ b/include/Third_Lib/muduo/net/Socket.cc @@ -0,0 +1,128 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/Socket.h" + +#include "muduo/base/Logging.h" +#include "muduo/net/InetAddress.h" +#include "muduo/net/SocketsOps.h" + +#include +#include +#include // snprintf + +using namespace muduo; +using namespace muduo::net; + +Socket::~Socket() +{ + sockets::close(sockfd_); +} + +bool Socket::getTcpInfo(struct tcp_info* tcpi) const +{ + socklen_t len = sizeof(*tcpi); + memZero(tcpi, len); + return ::getsockopt(sockfd_, SOL_TCP, TCP_INFO, tcpi, &len) == 0; +} + +bool Socket::getTcpInfoString(char* buf, int len) const +{ + struct tcp_info tcpi; + bool ok = getTcpInfo(&tcpi); + if (ok) + { + snprintf(buf, len, "unrecovered=%u " + "rto=%u ato=%u snd_mss=%u rcv_mss=%u " + "lost=%u retrans=%u rtt=%u rttvar=%u " + "sshthresh=%u cwnd=%u total_retrans=%u", + tcpi.tcpi_retransmits, // Number of unrecovered [RTO] timeouts + tcpi.tcpi_rto, // Retransmit timeout in usec + tcpi.tcpi_ato, // Predicted tick of soft clock in usec + tcpi.tcpi_snd_mss, + tcpi.tcpi_rcv_mss, + tcpi.tcpi_lost, // Lost packets + tcpi.tcpi_retrans, // Retransmitted packets out + tcpi.tcpi_rtt, // Smoothed round trip time in usec + tcpi.tcpi_rttvar, // Medium deviation + tcpi.tcpi_snd_ssthresh, + tcpi.tcpi_snd_cwnd, + tcpi.tcpi_total_retrans); // Total retransmits for entire connection + } + return ok; +} + +void Socket::bindAddress(const InetAddress& addr) +{ + sockets::bindOrDie(sockfd_, addr.getSockAddr()); +} + +void Socket::listen() +{ + sockets::listenOrDie(sockfd_); +} + +int Socket::accept(InetAddress* peeraddr) +{ + struct sockaddr_in6 addr; + memZero(&addr, sizeof addr); + int connfd = sockets::accept(sockfd_, &addr); + if (connfd >= 0) + { + peeraddr->setSockAddrInet6(addr); + } + return connfd; +} + +void Socket::shutdownWrite() +{ + sockets::shutdownWrite(sockfd_); +} + +void Socket::setTcpNoDelay(bool on) +{ + int optval = on ? 1 : 0; + ::setsockopt(sockfd_, IPPROTO_TCP, TCP_NODELAY, + &optval, static_cast(sizeof optval)); + // FIXME CHECK +} + +void Socket::setReuseAddr(bool on) +{ + int optval = on ? 1 : 0; + ::setsockopt(sockfd_, SOL_SOCKET, SO_REUSEADDR, + &optval, static_cast(sizeof optval)); + // FIXME CHECK +} + +void Socket::setReusePort(bool on) +{ +#ifdef SO_REUSEPORT + int optval = on ? 1 : 0; + int ret = ::setsockopt(sockfd_, SOL_SOCKET, SO_REUSEPORT, + &optval, static_cast(sizeof optval)); + if (ret < 0 && on) + { + LOG_SYSERR << "SO_REUSEPORT failed."; + } +#else + if (on) + { + LOG_ERROR << "SO_REUSEPORT is not supported."; + } +#endif +} + +void Socket::setKeepAlive(bool on) +{ + int optval = on ? 1 : 0; + ::setsockopt(sockfd_, SOL_SOCKET, SO_KEEPALIVE, + &optval, static_cast(sizeof optval)); + // FIXME CHECK +} + diff --git a/include/Third_Lib/muduo/net/Socket.h b/include/Third_Lib/muduo/net/Socket.h new file mode 100644 index 0000000..17567be --- /dev/null +++ b/include/Third_Lib/muduo/net/Socket.h @@ -0,0 +1,89 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_SOCKET_H +#define MUDUO_NET_SOCKET_H + +#include "muduo/base/noncopyable.h" + +// struct tcp_info is in +struct tcp_info; + +namespace muduo +{ +/// +/// TCP networking. +/// +namespace net +{ + +class InetAddress; + +/// +/// Wrapper of socket file descriptor. +/// +/// It closes the sockfd when desctructs. +/// It's thread safe, all operations are delagated to OS. +class Socket : noncopyable +{ + public: + explicit Socket(int sockfd) + : sockfd_(sockfd) + { } + + // Socket(Socket&&) // move constructor in C++11 + ~Socket(); + + int fd() const { return sockfd_; } + // return true if success. + bool getTcpInfo(struct tcp_info*) const; + bool getTcpInfoString(char* buf, int len) const; + + /// abort if address in use + void bindAddress(const InetAddress& localaddr); + /// abort if address in use + void listen(); + + /// On success, returns a non-negative integer that is + /// a descriptor for the accepted socket, which has been + /// set to non-blocking and close-on-exec. *peeraddr is assigned. + /// On error, -1 is returned, and *peeraddr is untouched. + int accept(InetAddress* peeraddr); + + void shutdownWrite(); + + /// + /// Enable/disable TCP_NODELAY (disable/enable Nagle's algorithm). + /// + void setTcpNoDelay(bool on); + + /// + /// Enable/disable SO_REUSEADDR + /// + void setReuseAddr(bool on); + + /// + /// Enable/disable SO_REUSEPORT + /// + void setReusePort(bool on); + + /// + /// Enable/disable SO_KEEPALIVE + /// + void setKeepAlive(bool on); + + private: + const int sockfd_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_SOCKET_H diff --git a/include/Third_Lib/muduo/net/SocketsOps.cc b/include/Third_Lib/muduo/net/SocketsOps.cc new file mode 100644 index 0000000..465c507 --- /dev/null +++ b/include/Third_Lib/muduo/net/SocketsOps.cc @@ -0,0 +1,316 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/SocketsOps.h" + +#include "muduo/base/Logging.h" +#include "muduo/base/Types.h" +#include "muduo/net/Endian.h" + +#include +#include +#include // snprintf +#include +#include // readv +#include + +using namespace muduo; +using namespace muduo::net; + +namespace +{ + +typedef struct sockaddr SA; + + +#if VALGRIND || defined (NO_ACCEPT4) +void setNonBlockAndCloseOnExec(int sockfd) +{ + // non-block + int flags = ::fcntl(sockfd, F_GETFL, 0); + flags |= O_NONBLOCK; + int ret = ::fcntl(sockfd, F_SETFL, flags); + // FIXME check + + // close-on-exec + flags = ::fcntl(sockfd, F_GETFD, 0); + flags |= FD_CLOEXEC; + ret = ::fcntl(sockfd, F_SETFD, flags); + // FIXME check + + (void)ret; +} +#endif + +} // namespace + +const struct sockaddr* sockets::sockaddr_cast(const struct sockaddr_in6* addr) +{ + return static_cast(implicit_cast(addr)); +} + +struct sockaddr* sockets::sockaddr_cast(struct sockaddr_in6* addr) +{ + return static_cast(implicit_cast(addr)); +} + +const struct sockaddr* sockets::sockaddr_cast(const struct sockaddr_in* addr) +{ + return static_cast(implicit_cast(addr)); +} + +const struct sockaddr_in* sockets::sockaddr_in_cast(const struct sockaddr* addr) +{ + return static_cast(implicit_cast(addr)); +} + +const struct sockaddr_in6* sockets::sockaddr_in6_cast(const struct sockaddr* addr) +{ + return static_cast(implicit_cast(addr)); +} + +int sockets::createNonblockingOrDie(sa_family_t family) +{ +#if VALGRIND + int sockfd = ::socket(family, SOCK_STREAM, IPPROTO_TCP); + if (sockfd < 0) + { + LOG_SYSFATAL << "sockets::createNonblockingOrDie"; + } + + setNonBlockAndCloseOnExec(sockfd); +#else + int sockfd = ::socket(family, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, IPPROTO_TCP); + if (sockfd < 0) + { + LOG_SYSFATAL << "sockets::createNonblockingOrDie"; + } +#endif + return sockfd; +} + +void sockets::bindOrDie(int sockfd, const struct sockaddr* addr) +{ + int ret = ::bind(sockfd, addr, static_cast(sizeof(struct sockaddr_in6))); + if (ret < 0) + { + LOG_SYSFATAL << "sockets::bindOrDie"; + } +} + +void sockets::listenOrDie(int sockfd) +{ + int ret = ::listen(sockfd, SOMAXCONN); + if (ret < 0) + { + LOG_SYSFATAL << "sockets::listenOrDie"; + } +} + +int sockets::accept(int sockfd, struct sockaddr_in6* addr) +{ + socklen_t addrlen = static_cast(sizeof *addr); +#if VALGRIND || defined (NO_ACCEPT4) + int connfd = ::accept(sockfd, sockaddr_cast(addr), &addrlen); + setNonBlockAndCloseOnExec(connfd); +#else + int connfd = ::accept4(sockfd, sockaddr_cast(addr), + &addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC); +#endif + if (connfd < 0) + { + int savedErrno = errno; + LOG_SYSERR << "Socket::accept"; + switch (savedErrno) + { + case EAGAIN: + case ECONNABORTED: + case EINTR: + case EPROTO: // ??? + case EPERM: + case EMFILE: // per-process lmit of open file desctiptor ??? + // expected errors + errno = savedErrno; + break; + case EBADF: + case EFAULT: + case EINVAL: + case ENFILE: + case ENOBUFS: + case ENOMEM: + case ENOTSOCK: + case EOPNOTSUPP: + // unexpected errors + LOG_FATAL << "unexpected error of ::accept " << savedErrno; + break; + default: + LOG_FATAL << "unknown error of ::accept " << savedErrno; + break; + } + } + return connfd; +} + +int sockets::connect(int sockfd, const struct sockaddr* addr) +{ + return ::connect(sockfd, addr, static_cast(sizeof(struct sockaddr_in6))); +} + +ssize_t sockets::read(int sockfd, void *buf, size_t count) +{ + return ::read(sockfd, buf, count); +} + +ssize_t sockets::readv(int sockfd, const struct iovec *iov, int iovcnt) +{ + return ::readv(sockfd, iov, iovcnt); +} + +ssize_t sockets::write(int sockfd, const void *buf, size_t count) +{ + return ::write(sockfd, buf, count); +} + +void sockets::close(int sockfd) +{ + if (::close(sockfd) < 0) + { + LOG_SYSERR << "sockets::close"; + } +} + +void sockets::shutdownWrite(int sockfd) +{ + if (::shutdown(sockfd, SHUT_WR) < 0) + { + LOG_SYSERR << "sockets::shutdownWrite"; + } +} + +void sockets::toIpPort(char* buf, size_t size, + const struct sockaddr* addr) +{ + if (addr->sa_family == AF_INET6) + { + buf[0] = '['; + toIp(buf+1, size-1, addr); + size_t end = ::strlen(buf); + const struct sockaddr_in6* addr6 = sockaddr_in6_cast(addr); + uint16_t port = sockets::networkToHost16(addr6->sin6_port); + assert(size > end); + snprintf(buf+end, size-end, "]:%u", port); + return; + } + toIp(buf, size, addr); + size_t end = ::strlen(buf); + const struct sockaddr_in* addr4 = sockaddr_in_cast(addr); + uint16_t port = sockets::networkToHost16(addr4->sin_port); + assert(size > end); + snprintf(buf+end, size-end, ":%u", port); +} + +void sockets::toIp(char* buf, size_t size, + const struct sockaddr* addr) +{ + if (addr->sa_family == AF_INET) + { + assert(size >= INET_ADDRSTRLEN); + const struct sockaddr_in* addr4 = sockaddr_in_cast(addr); + ::inet_ntop(AF_INET, &addr4->sin_addr, buf, static_cast(size)); + } + else if (addr->sa_family == AF_INET6) + { + assert(size >= INET6_ADDRSTRLEN); + const struct sockaddr_in6* addr6 = sockaddr_in6_cast(addr); + ::inet_ntop(AF_INET6, &addr6->sin6_addr, buf, static_cast(size)); + } +} + +void sockets::fromIpPort(const char* ip, uint16_t port, + struct sockaddr_in* addr) +{ + addr->sin_family = AF_INET; + addr->sin_port = hostToNetwork16(port); + if (::inet_pton(AF_INET, ip, &addr->sin_addr) <= 0) + { + LOG_SYSERR << "sockets::fromIpPort"; + } +} + +void sockets::fromIpPort(const char* ip, uint16_t port, + struct sockaddr_in6* addr) +{ + addr->sin6_family = AF_INET6; + addr->sin6_port = hostToNetwork16(port); + if (::inet_pton(AF_INET6, ip, &addr->sin6_addr) <= 0) + { + LOG_SYSERR << "sockets::fromIpPort"; + } +} + +int sockets::getSocketError(int sockfd) +{ + int optval; + socklen_t optlen = static_cast(sizeof optval); + + if (::getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0) + { + return errno; + } + else + { + return optval; + } +} + +struct sockaddr_in6 sockets::getLocalAddr(int sockfd) +{ + struct sockaddr_in6 localaddr; + memZero(&localaddr, sizeof localaddr); + socklen_t addrlen = static_cast(sizeof localaddr); + if (::getsockname(sockfd, sockaddr_cast(&localaddr), &addrlen) < 0) + { + LOG_SYSERR << "sockets::getLocalAddr"; + } + return localaddr; +} + +struct sockaddr_in6 sockets::getPeerAddr(int sockfd) +{ + struct sockaddr_in6 peeraddr; + memZero(&peeraddr, sizeof peeraddr); + socklen_t addrlen = static_cast(sizeof peeraddr); + if (::getpeername(sockfd, sockaddr_cast(&peeraddr), &addrlen) < 0) + { + LOG_SYSERR << "sockets::getPeerAddr"; + } + return peeraddr; +} + +bool sockets::isSelfConnect(int sockfd) +{ + struct sockaddr_in6 localaddr = getLocalAddr(sockfd); + struct sockaddr_in6 peeraddr = getPeerAddr(sockfd); + if (localaddr.sin6_family == AF_INET) + { + const struct sockaddr_in* laddr4 = reinterpret_cast(&localaddr); + const struct sockaddr_in* raddr4 = reinterpret_cast(&peeraddr); + return laddr4->sin_port == raddr4->sin_port + && laddr4->sin_addr.s_addr == raddr4->sin_addr.s_addr; + } + else if (localaddr.sin6_family == AF_INET6) + { + return localaddr.sin6_port == peeraddr.sin6_port + && memcmp(&localaddr.sin6_addr, &peeraddr.sin6_addr, sizeof localaddr.sin6_addr) == 0; + } + else + { + return false; + } +} + diff --git a/include/Third_Lib/muduo/net/SocketsOps.h b/include/Third_Lib/muduo/net/SocketsOps.h new file mode 100644 index 0000000..9c46597 --- /dev/null +++ b/include/Third_Lib/muduo/net/SocketsOps.h @@ -0,0 +1,64 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_SOCKETSOPS_H +#define MUDUO_NET_SOCKETSOPS_H + +#include + +namespace muduo +{ +namespace net +{ +namespace sockets +{ + +/// +/// Creates a non-blocking socket file descriptor, +/// abort if any error. +int createNonblockingOrDie(sa_family_t family); + +int connect(int sockfd, const struct sockaddr* addr); +void bindOrDie(int sockfd, const struct sockaddr* addr); +void listenOrDie(int sockfd); +int accept(int sockfd, struct sockaddr_in6* addr); +ssize_t read(int sockfd, void *buf, size_t count); +ssize_t readv(int sockfd, const struct iovec *iov, int iovcnt); +ssize_t write(int sockfd, const void *buf, size_t count); +void close(int sockfd); +void shutdownWrite(int sockfd); + +void toIpPort(char* buf, size_t size, + const struct sockaddr* addr); +void toIp(char* buf, size_t size, + const struct sockaddr* addr); + +void fromIpPort(const char* ip, uint16_t port, + struct sockaddr_in* addr); +void fromIpPort(const char* ip, uint16_t port, + struct sockaddr_in6* addr); + +int getSocketError(int sockfd); + +const struct sockaddr* sockaddr_cast(const struct sockaddr_in* addr); +const struct sockaddr* sockaddr_cast(const struct sockaddr_in6* addr); +struct sockaddr* sockaddr_cast(struct sockaddr_in6* addr); +const struct sockaddr_in* sockaddr_in_cast(const struct sockaddr* addr); +const struct sockaddr_in6* sockaddr_in6_cast(const struct sockaddr* addr); + +struct sockaddr_in6 getLocalAddr(int sockfd); +struct sockaddr_in6 getPeerAddr(int sockfd); +bool isSelfConnect(int sockfd); + +} // namespace sockets +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_SOCKETSOPS_H diff --git a/include/Third_Lib/muduo/net/TcpClient.cc b/include/Third_Lib/muduo/net/TcpClient.cc new file mode 100644 index 0000000..1e668b3 --- /dev/null +++ b/include/Third_Lib/muduo/net/TcpClient.cc @@ -0,0 +1,181 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// + +#include "muduo/net/TcpClient.h" + +#include "muduo/base/Logging.h" +#include "muduo/net/Connector.h" +#include "muduo/net/EventLoop.h" +#include "muduo/net/SocketsOps.h" + +#include // snprintf + +using namespace muduo; +using namespace muduo::net; + +// TcpClient::TcpClient(EventLoop* loop) +// : loop_(loop) +// { +// } + +// TcpClient::TcpClient(EventLoop* loop, const string& host, uint16_t port) +// : loop_(CHECK_NOTNULL(loop)), +// serverAddr_(host, port) +// { +// } + +namespace muduo +{ +namespace net +{ +namespace detail +{ + +void removeConnection(EventLoop* loop, const TcpConnectionPtr& conn) +{ + loop->queueInLoop(std::bind(&TcpConnection::connectDestroyed, conn)); +} + +void removeConnector(const ConnectorPtr& connector) +{ + //connector-> +} + +} // namespace detail +} // namespace net +} // namespace muduo + +TcpClient::TcpClient(EventLoop* loop, + const InetAddress& serverAddr, + const string& nameArg) + : loop_(CHECK_NOTNULL(loop)), + connector_(new Connector(loop, serverAddr)), + name_(nameArg), + connectionCallback_(defaultConnectionCallback), + messageCallback_(defaultMessageCallback), + retry_(false), + connect_(true), + nextConnId_(1) +{ + connector_->setNewConnectionCallback( + std::bind(&TcpClient::newConnection, this, _1)); + // FIXME setConnectFailedCallback + LOG_INFO << "TcpClient::TcpClient[" << name_ + << "] - connector " << get_pointer(connector_); +} + +TcpClient::~TcpClient() +{ + LOG_INFO << "TcpClient::~TcpClient[" << name_ + << "] - connector " << get_pointer(connector_); + TcpConnectionPtr conn; + bool unique = false; + { + MutexLockGuard lock(mutex_); + unique = connection_.unique(); + conn = connection_; + } + if (conn) + { + assert(loop_ == conn->getLoop()); + // FIXME: not 100% safe, if we are in different thread + CloseCallback cb = std::bind(&detail::removeConnection, loop_, _1); + loop_->runInLoop( + std::bind(&TcpConnection::setCloseCallback, conn, cb)); + if (unique) + { + conn->forceClose(); + } + } + else + { + connector_->stop(); + // FIXME: HACK + loop_->runAfter(1, std::bind(&detail::removeConnector, connector_)); + } +} + +void TcpClient::connect() +{ + // FIXME: check state + LOG_INFO << "TcpClient::connect[" << name_ << "] - connecting to " + << connector_->serverAddress().toIpPort(); + connect_ = true; + connector_->start(); +} + +void TcpClient::disconnect() +{ + connect_ = false; + + { + MutexLockGuard lock(mutex_); + if (connection_) + { + connection_->shutdown(); + } + } +} + +void TcpClient::stop() +{ + connect_ = false; + connector_->stop(); +} + +void TcpClient::newConnection(int sockfd) +{ + loop_->assertInLoopThread(); + InetAddress peerAddr(sockets::getPeerAddr(sockfd)); + char buf[32]; + snprintf(buf, sizeof buf, ":%s#%d", peerAddr.toIpPort().c_str(), nextConnId_); + ++nextConnId_; + string connName = name_ + buf; + + InetAddress localAddr(sockets::getLocalAddr(sockfd)); + // FIXME poll with zero timeout to double confirm the new connection + // FIXME use make_shared if necessary + TcpConnectionPtr conn(new TcpConnection(loop_, + connName, + sockfd, + localAddr, + peerAddr)); + + conn->setConnectionCallback(connectionCallback_); + conn->setMessageCallback(messageCallback_); + conn->setWriteCompleteCallback(writeCompleteCallback_); + conn->setCloseCallback( + std::bind(&TcpClient::removeConnection, this, _1)); // FIXME: unsafe + { + MutexLockGuard lock(mutex_); + connection_ = conn; + } + conn->connectEstablished(); +} + +void TcpClient::removeConnection(const TcpConnectionPtr& conn) +{ + loop_->assertInLoopThread(); + assert(loop_ == conn->getLoop()); + + { + MutexLockGuard lock(mutex_); + assert(connection_ == conn); + connection_.reset(); + } + + loop_->queueInLoop(std::bind(&TcpConnection::connectDestroyed, conn)); + if (retry_ && connect_) + { + LOG_INFO << "TcpClient::connect[" << name_ << "] - Reconnecting to " + << connector_->serverAddress().toIpPort(); + connector_->restart(); + } +} + diff --git a/include/Third_Lib/muduo/net/TcpClient.h b/include/Third_Lib/muduo/net/TcpClient.h new file mode 100644 index 0000000..c498cb3 --- /dev/null +++ b/include/Third_Lib/muduo/net/TcpClient.h @@ -0,0 +1,90 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_TCPCLIENT_H +#define MUDUO_NET_TCPCLIENT_H + +#include "muduo/base/Mutex.h" +#include "muduo/net/TcpConnection.h" + +namespace muduo +{ +namespace net +{ + +class Connector; +typedef std::shared_ptr ConnectorPtr; + +class TcpClient : noncopyable +{ + public: + // TcpClient(EventLoop* loop); + // TcpClient(EventLoop* loop, const string& host, uint16_t port); + TcpClient(EventLoop* loop, + const InetAddress& serverAddr, + const string& nameArg); + ~TcpClient(); // force out-line dtor, for std::unique_ptr members. + + void connect(); + void disconnect(); + void stop(); + + TcpConnectionPtr connection() const + { + MutexLockGuard lock(mutex_); + return connection_; + } + + EventLoop* getLoop() const { return loop_; } + bool retry() const { return retry_; } + void enableRetry() { retry_ = true; } + + const string& name() const + { return name_; } + + /// Set connection callback. + /// Not thread safe. + void setConnectionCallback(ConnectionCallback cb) + { connectionCallback_ = std::move(cb); } + + /// Set message callback. + /// Not thread safe. + void setMessageCallback(MessageCallback cb) + { messageCallback_ = std::move(cb); } + + /// Set write complete callback. + /// Not thread safe. + void setWriteCompleteCallback(WriteCompleteCallback cb) + { writeCompleteCallback_ = std::move(cb); } + + private: + /// Not thread safe, but in loop + void newConnection(int sockfd); + /// Not thread safe, but in loop + void removeConnection(const TcpConnectionPtr& conn); + + EventLoop* loop_; + ConnectorPtr connector_; // avoid revealing Connector + const string name_; + ConnectionCallback connectionCallback_; + MessageCallback messageCallback_; + WriteCompleteCallback writeCompleteCallback_; + bool retry_; // atomic + bool connect_; // atomic + // always in loop thread + int nextConnId_; + mutable MutexLock mutex_; + TcpConnectionPtr connection_ GUARDED_BY(mutex_); +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_TCPCLIENT_H diff --git a/include/Third_Lib/muduo/net/TcpConnection.cc b/include/Third_Lib/muduo/net/TcpConnection.cc new file mode 100644 index 0000000..37f58a4 --- /dev/null +++ b/include/Third_Lib/muduo/net/TcpConnection.cc @@ -0,0 +1,429 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/TcpConnection.h" + +#include "muduo/base/Logging.h" +#include "muduo/base/WeakCallback.h" +#include "muduo/net/Channel.h" +#include "muduo/net/EventLoop.h" +#include "muduo/net/Socket.h" +#include "muduo/net/SocketsOps.h" + +#include + +using namespace muduo; +using namespace muduo::net; + +void muduo::net::defaultConnectionCallback(const TcpConnectionPtr& conn) +{ + LOG_TRACE << conn->localAddress().toIpPort() << " -> " + << conn->peerAddress().toIpPort() << " is " + << (conn->connected() ? "UP" : "DOWN"); + // do not call conn->forceClose(), because some users want to register message callback only. +} + +void muduo::net::defaultMessageCallback(const TcpConnectionPtr&, + Buffer* buf, + Timestamp) +{ + buf->retrieveAll(); +} + +TcpConnection::TcpConnection(EventLoop* loop, + const string& nameArg, + int sockfd, + const InetAddress& localAddr, + const InetAddress& peerAddr) + : loop_(CHECK_NOTNULL(loop)), + name_(nameArg), + state_(kConnecting), + reading_(true), + socket_(new Socket(sockfd)), + channel_(new Channel(loop, sockfd)), + localAddr_(localAddr), + peerAddr_(peerAddr), + highWaterMark_(64*1024*1024) +{ + channel_->setReadCallback( + std::bind(&TcpConnection::handleRead, this, _1)); + channel_->setWriteCallback( + std::bind(&TcpConnection::handleWrite, this)); + channel_->setCloseCallback( + std::bind(&TcpConnection::handleClose, this)); + channel_->setErrorCallback( + std::bind(&TcpConnection::handleError, this)); + LOG_DEBUG << "TcpConnection::ctor[" << name_ << "] at " << this + << " fd=" << sockfd; + socket_->setKeepAlive(true); +} + +TcpConnection::~TcpConnection() +{ + LOG_DEBUG << "TcpConnection::dtor[" << name_ << "] at " << this + << " fd=" << channel_->fd() + << " state=" << stateToString(); + assert(state_ == kDisconnected); +} + +bool TcpConnection::getTcpInfo(struct tcp_info* tcpi) const +{ + return socket_->getTcpInfo(tcpi); +} + +string TcpConnection::getTcpInfoString() const +{ + char buf[1024]; + buf[0] = '\0'; + socket_->getTcpInfoString(buf, sizeof buf); + return buf; +} + +void TcpConnection::send(const void* data, int len) +{ + send(StringPiece(static_cast(data), len)); +} + +void TcpConnection::send(const StringPiece& message) +{ + if (state_ == kConnected) + { + if (loop_->isInLoopThread()) + { + sendInLoop(message); + } + else + { + void (TcpConnection::*fp)(const StringPiece& message) = &TcpConnection::sendInLoop; + loop_->runInLoop( + std::bind(fp, + this, // FIXME + message.as_string())); + //std::forward(message))); + } + } +} + +// FIXME efficiency!!! +void TcpConnection::send(Buffer* buf) +{ + if (state_ == kConnected) + { + if (loop_->isInLoopThread()) + { + sendInLoop(buf->peek(), buf->readableBytes()); + buf->retrieveAll(); + } + else + { + void (TcpConnection::*fp)(const StringPiece& message) = &TcpConnection::sendInLoop; + loop_->runInLoop( + std::bind(fp, + this, // FIXME + buf->retrieveAllAsString())); + //std::forward(message))); + } + } +} + +void TcpConnection::sendInLoop(const StringPiece& message) +{ + sendInLoop(message.data(), message.size()); +} + +void TcpConnection::sendInLoop(const void* data, size_t len) +{ + loop_->assertInLoopThread(); + ssize_t nwrote = 0; + size_t remaining = len; + bool faultError = false; + if (state_ == kDisconnected) + { + LOG_WARN << "disconnected, give up writing"; + return; + } + // if no thing in output queue, try writing directly + if (!channel_->isWriting() && outputBuffer_.readableBytes() == 0) + { + nwrote = sockets::write(channel_->fd(), data, len); + if (nwrote >= 0) + { + remaining = len - nwrote; + if (remaining == 0 && writeCompleteCallback_) + { + loop_->queueInLoop(std::bind(writeCompleteCallback_, shared_from_this())); + } + } + else // nwrote < 0 + { + nwrote = 0; + if (errno != EWOULDBLOCK) + { + LOG_SYSERR << "TcpConnection::sendInLoop"; + if (errno == EPIPE || errno == ECONNRESET) // FIXME: any others? + { + faultError = true; + } + } + } + } + + assert(remaining <= len); + if (!faultError && remaining > 0) + { + size_t oldLen = outputBuffer_.readableBytes(); + if (oldLen + remaining >= highWaterMark_ + && oldLen < highWaterMark_ + && highWaterMarkCallback_) + { + loop_->queueInLoop(std::bind(highWaterMarkCallback_, shared_from_this(), oldLen + remaining)); + } + outputBuffer_.append(static_cast(data)+nwrote, remaining); + if (!channel_->isWriting()) + { + channel_->enableWriting(); + } + } +} + +void TcpConnection::shutdown() +{ + // FIXME: use compare and swap + if (state_ == kConnected) + { + setState(kDisconnecting); + // FIXME: shared_from_this()? + loop_->runInLoop(std::bind(&TcpConnection::shutdownInLoop, this)); + } +} + +void TcpConnection::shutdownInLoop() +{ + loop_->assertInLoopThread(); + if (!channel_->isWriting()) + { + // we are not writing + socket_->shutdownWrite(); + } +} + +// void TcpConnection::shutdownAndForceCloseAfter(double seconds) +// { +// // FIXME: use compare and swap +// if (state_ == kConnected) +// { +// setState(kDisconnecting); +// loop_->runInLoop(std::bind(&TcpConnection::shutdownAndForceCloseInLoop, this, seconds)); +// } +// } + +// void TcpConnection::shutdownAndForceCloseInLoop(double seconds) +// { +// loop_->assertInLoopThread(); +// if (!channel_->isWriting()) +// { +// // we are not writing +// socket_->shutdownWrite(); +// } +// loop_->runAfter( +// seconds, +// makeWeakCallback(shared_from_this(), +// &TcpConnection::forceCloseInLoop)); +// } + +void TcpConnection::forceClose() +{ + // FIXME: use compare and swap + if (state_ == kConnected || state_ == kDisconnecting) + { + setState(kDisconnecting); + loop_->queueInLoop(std::bind(&TcpConnection::forceCloseInLoop, shared_from_this())); + } +} + +void TcpConnection::forceCloseWithDelay(double seconds) +{ + if (state_ == kConnected || state_ == kDisconnecting) + { + setState(kDisconnecting); + loop_->runAfter( + seconds, + makeWeakCallback(shared_from_this(), + &TcpConnection::forceClose)); // not forceCloseInLoop to avoid race condition + } +} + +void TcpConnection::forceCloseInLoop() +{ + loop_->assertInLoopThread(); + if (state_ == kConnected || state_ == kDisconnecting) + { + // as if we received 0 byte in handleRead(); + handleClose(); + } +} + +const char* TcpConnection::stateToString() const +{ + switch (state_) + { + case kDisconnected: + return "kDisconnected"; + case kConnecting: + return "kConnecting"; + case kConnected: + return "kConnected"; + case kDisconnecting: + return "kDisconnecting"; + default: + return "unknown state"; + } +} + +void TcpConnection::setTcpNoDelay(bool on) +{ + socket_->setTcpNoDelay(on); +} + +void TcpConnection::startRead() +{ + loop_->runInLoop(std::bind(&TcpConnection::startReadInLoop, this)); +} + +void TcpConnection::startReadInLoop() +{ + loop_->assertInLoopThread(); + if (!reading_ || !channel_->isReading()) + { + channel_->enableReading(); + reading_ = true; + } +} + +void TcpConnection::stopRead() +{ + loop_->runInLoop(std::bind(&TcpConnection::stopReadInLoop, this)); +} + +void TcpConnection::stopReadInLoop() +{ + loop_->assertInLoopThread(); + if (reading_ || channel_->isReading()) + { + channel_->disableReading(); + reading_ = false; + } +} + +void TcpConnection::connectEstablished() +{ + loop_->assertInLoopThread(); + assert(state_ == kConnecting); + setState(kConnected); + channel_->tie(shared_from_this()); + channel_->enableReading(); + + connectionCallback_(shared_from_this()); +} + +void TcpConnection::connectDestroyed() +{ + loop_->assertInLoopThread(); + if (state_ == kConnected) + { + setState(kDisconnected); + channel_->disableAll(); + + connectionCallback_(shared_from_this()); + } + channel_->remove(); +} + +void TcpConnection::handleRead(Timestamp receiveTime) +{ + loop_->assertInLoopThread(); + int savedErrno = 0; + ssize_t n = inputBuffer_.readFd(channel_->fd(), &savedErrno); + if (n > 0) + { + messageCallback_(shared_from_this(), &inputBuffer_, receiveTime); + } + else if (n == 0) + { + handleClose(); + } + else + { + errno = savedErrno; + LOG_SYSERR << "TcpConnection::handleRead"; + handleError(); + } +} + +void TcpConnection::handleWrite() +{ + loop_->assertInLoopThread(); + if (channel_->isWriting()) + { + ssize_t n = sockets::write(channel_->fd(), + outputBuffer_.peek(), + outputBuffer_.readableBytes()); + if (n > 0) + { + outputBuffer_.retrieve(n); + if (outputBuffer_.readableBytes() == 0) + { + channel_->disableWriting(); + if (writeCompleteCallback_) + { + loop_->queueInLoop(std::bind(writeCompleteCallback_, shared_from_this())); + } + if (state_ == kDisconnecting) + { + shutdownInLoop(); + } + } + } + else + { + LOG_SYSERR << "TcpConnection::handleWrite"; + // if (state_ == kDisconnecting) + // { + // shutdownInLoop(); + // } + } + } + else + { + LOG_TRACE << "Connection fd = " << channel_->fd() + << " is down, no more writing"; + } +} + +void TcpConnection::handleClose() +{ + loop_->assertInLoopThread(); + LOG_TRACE << "fd = " << channel_->fd() << " state = " << stateToString(); + assert(state_ == kConnected || state_ == kDisconnecting); + // we don't close fd, leave it to dtor, so we can find leaks easily. + setState(kDisconnected); + channel_->disableAll(); + + TcpConnectionPtr guardThis(shared_from_this()); + connectionCallback_(guardThis); + // must be the last line + closeCallback_(guardThis); +} + +void TcpConnection::handleError() +{ + int err = sockets::getSocketError(channel_->fd()); + LOG_ERROR << "TcpConnection::handleError [" << name_ + << "] - SO_ERROR = " << err << " " << strerror_tl(err); +} + diff --git a/include/Third_Lib/muduo/net/TcpConnection.h b/include/Third_Lib/muduo/net/TcpConnection.h new file mode 100644 index 0000000..cb76331 --- /dev/null +++ b/include/Third_Lib/muduo/net/TcpConnection.h @@ -0,0 +1,161 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_TCPCONNECTION_H +#define MUDUO_NET_TCPCONNECTION_H + +#include "muduo/base/noncopyable.h" +#include "muduo/base/StringPiece.h" +#include "muduo/base/Types.h" +#include "muduo/net/Callbacks.h" +#include "muduo/net/Buffer.h" +#include "muduo/net/InetAddress.h" + +#include + +#include + +// struct tcp_info is in +struct tcp_info; + +namespace muduo +{ +namespace net +{ + +class Channel; +class EventLoop; +class Socket; + +/// +/// TCP connection, for both client and server usage. +/// +/// This is an interface class, so don't expose too much details. +class TcpConnection : noncopyable, + public std::enable_shared_from_this +{ + public: + /// Constructs a TcpConnection with a connected sockfd + /// + /// User should not create this object. + TcpConnection(EventLoop* loop, + const string& name, + int sockfd, + const InetAddress& localAddr, + const InetAddress& peerAddr); + ~TcpConnection(); + + EventLoop* getLoop() const { return loop_; } + const string& name() const { return name_; } + const InetAddress& localAddress() const { return localAddr_; } + const InetAddress& peerAddress() const { return peerAddr_; } + bool connected() const { return state_ == kConnected; } + bool disconnected() const { return state_ == kDisconnected; } + // return true if success. + bool getTcpInfo(struct tcp_info*) const; + string getTcpInfoString() const; + + // void send(string&& message); // C++11 + void send(const void* message, int len); + void send(const StringPiece& message); + // void send(Buffer&& message); // C++11 + void send(Buffer* message); // this one will swap data + void shutdown(); // NOT thread safe, no simultaneous calling + // void shutdownAndForceCloseAfter(double seconds); // NOT thread safe, no simultaneous calling + void forceClose(); + void forceCloseWithDelay(double seconds); + void setTcpNoDelay(bool on); + // reading or not + void startRead(); + void stopRead(); + bool isReading() const { return reading_; }; // NOT thread safe, may race with start/stopReadInLoop + + void setContext(const boost::any& context) + { context_ = context; } + + const boost::any& getContext() const + { return context_; } + + boost::any* getMutableContext() + { return &context_; } + + void setConnectionCallback(const ConnectionCallback& cb) + { connectionCallback_ = cb; } + + void setMessageCallback(const MessageCallback& cb) + { messageCallback_ = cb; } + + void setWriteCompleteCallback(const WriteCompleteCallback& cb) + { writeCompleteCallback_ = cb; } + + void setHighWaterMarkCallback(const HighWaterMarkCallback& cb, size_t highWaterMark) + { highWaterMarkCallback_ = cb; highWaterMark_ = highWaterMark; } + + /// Advanced interface + Buffer* inputBuffer() + { return &inputBuffer_; } + + Buffer* outputBuffer() + { return &outputBuffer_; } + + /// Internal use only. + void setCloseCallback(const CloseCallback& cb) + { closeCallback_ = cb; } + + // called when TcpServer accepts a new connection + void connectEstablished(); // should be called only once + // called when TcpServer has removed me from its map + void connectDestroyed(); // should be called only once + + private: + enum StateE { kDisconnected, kConnecting, kConnected, kDisconnecting }; + void handleRead(Timestamp receiveTime); + void handleWrite(); + void handleClose(); + void handleError(); + // void sendInLoop(string&& message); + void sendInLoop(const StringPiece& message); + void sendInLoop(const void* message, size_t len); + void shutdownInLoop(); + // void shutdownAndForceCloseInLoop(double seconds); + void forceCloseInLoop(); + void setState(StateE s) { state_ = s; } + const char* stateToString() const; + void startReadInLoop(); + void stopReadInLoop(); + + EventLoop* loop_; + const string name_; + StateE state_; // FIXME: use atomic variable + bool reading_; + // we don't expose those classes to client. + std::unique_ptr socket_; + std::unique_ptr channel_; + const InetAddress localAddr_; + const InetAddress peerAddr_; + ConnectionCallback connectionCallback_; + MessageCallback messageCallback_; + WriteCompleteCallback writeCompleteCallback_; + HighWaterMarkCallback highWaterMarkCallback_; + CloseCallback closeCallback_; + size_t highWaterMark_; + Buffer inputBuffer_; + Buffer outputBuffer_; // FIXME: use list as output buffer. + boost::any context_; + // FIXME: creationTime_, lastReceiveTime_ + // bytesReceived_, bytesSent_ +}; + +typedef std::shared_ptr TcpConnectionPtr; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_TCPCONNECTION_H diff --git a/include/Third_Lib/muduo/net/TcpServer.cc b/include/Third_Lib/muduo/net/TcpServer.cc new file mode 100644 index 0000000..e4f8e24 --- /dev/null +++ b/include/Third_Lib/muduo/net/TcpServer.cc @@ -0,0 +1,118 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/TcpServer.h" + +#include "muduo/base/Logging.h" +#include "muduo/net/Acceptor.h" +#include "muduo/net/EventLoop.h" +#include "muduo/net/EventLoopThreadPool.h" +#include "muduo/net/SocketsOps.h" + +#include // snprintf + +using namespace muduo; +using namespace muduo::net; + +TcpServer::TcpServer(EventLoop* loop, + const InetAddress& listenAddr, + const string& nameArg, + Option option) + : loop_(CHECK_NOTNULL(loop)), + ipPort_(listenAddr.toIpPort()), + name_(nameArg), + acceptor_(new Acceptor(loop, listenAddr, option == kReusePort)), + threadPool_(new EventLoopThreadPool(loop, name_)), + connectionCallback_(defaultConnectionCallback), + messageCallback_(defaultMessageCallback), + nextConnId_(1) +{ + acceptor_->setNewConnectionCallback( + std::bind(&TcpServer::newConnection, this, _1, _2)); +} + +TcpServer::~TcpServer() +{ + loop_->assertInLoopThread(); + LOG_TRACE << "TcpServer::~TcpServer [" << name_ << "] destructing"; + + for (auto& item : connections_) + { + TcpConnectionPtr conn(item.second); + item.second.reset(); + conn->getLoop()->runInLoop( + std::bind(&TcpConnection::connectDestroyed, conn)); + } +} + +void TcpServer::setThreadNum(int numThreads) +{ + assert(0 <= numThreads); + threadPool_->setThreadNum(numThreads); +} + +void TcpServer::start() +{ + if (started_.getAndSet(1) == 0) + { + threadPool_->start(threadInitCallback_); + + assert(!acceptor_->listening()); + loop_->runInLoop( + std::bind(&Acceptor::listen, get_pointer(acceptor_))); + } +} + +void TcpServer::newConnection(int sockfd, const InetAddress& peerAddr) +{ + loop_->assertInLoopThread(); + EventLoop* ioLoop = threadPool_->getNextLoop(); + char buf[64]; + snprintf(buf, sizeof buf, "-%s#%d", ipPort_.c_str(), nextConnId_); + ++nextConnId_; + string connName = name_ + buf; + + LOG_INFO << "TcpServer::newConnection [" << name_ + << "] - new connection [" << connName + << "] from " << peerAddr.toIpPort(); + InetAddress localAddr(sockets::getLocalAddr(sockfd)); + // FIXME poll with zero timeout to double confirm the new connection + // FIXME use make_shared if necessary + TcpConnectionPtr conn(new TcpConnection(ioLoop, + connName, + sockfd, + localAddr, + peerAddr)); + connections_[connName] = conn; + conn->setConnectionCallback(connectionCallback_); + conn->setMessageCallback(messageCallback_); + conn->setWriteCompleteCallback(writeCompleteCallback_); + conn->setCloseCallback( + std::bind(&TcpServer::removeConnection, this, _1)); // FIXME: unsafe + ioLoop->runInLoop(std::bind(&TcpConnection::connectEstablished, conn)); +} + +void TcpServer::removeConnection(const TcpConnectionPtr& conn) +{ + // FIXME: unsafe + loop_->runInLoop(std::bind(&TcpServer::removeConnectionInLoop, this, conn)); +} + +void TcpServer::removeConnectionInLoop(const TcpConnectionPtr& conn) +{ + loop_->assertInLoopThread(); + LOG_INFO << "TcpServer::removeConnectionInLoop [" << name_ + << "] - connection " << conn->name(); + size_t n = connections_.erase(conn->name()); + (void)n; + assert(n == 1); + EventLoop* ioLoop = conn->getLoop(); + ioLoop->queueInLoop( + std::bind(&TcpConnection::connectDestroyed, conn)); +} + diff --git a/include/Third_Lib/muduo/net/TcpServer.h b/include/Third_Lib/muduo/net/TcpServer.h new file mode 100644 index 0000000..3fbfead --- /dev/null +++ b/include/Third_Lib/muduo/net/TcpServer.h @@ -0,0 +1,120 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_TCPSERVER_H +#define MUDUO_NET_TCPSERVER_H + +#include "muduo/base/Atomic.h" +#include "muduo/base/Types.h" +#include "muduo/net/TcpConnection.h" + +#include + +namespace muduo +{ +namespace net +{ + +class Acceptor; +class EventLoop; +class EventLoopThreadPool; + +/// +/// TCP server, supports single-threaded and thread-pool models. +/// +/// This is an interface class, so don't expose too much details. +class TcpServer : noncopyable +{ + public: + typedef std::function ThreadInitCallback; + enum Option + { + kNoReusePort, + kReusePort, + }; + + //TcpServer(EventLoop* loop, const InetAddress& listenAddr); + TcpServer(EventLoop* loop, + const InetAddress& listenAddr, + const string& nameArg, + Option option = kNoReusePort); + ~TcpServer(); // force out-line dtor, for std::unique_ptr members. + + const string& ipPort() const { return ipPort_; } + const string& name() const { return name_; } + EventLoop* getLoop() const { return loop_; } + + /// Set the number of threads for handling input. + /// + /// Always accepts new connection in loop's thread. + /// Must be called before @c start + /// @param numThreads + /// - 0 means all I/O in loop's thread, no thread will created. + /// this is the default value. + /// - 1 means all I/O in another thread. + /// - N means a thread pool with N threads, new connections + /// are assigned on a round-robin basis. + void setThreadNum(int numThreads); + void setThreadInitCallback(const ThreadInitCallback& cb) + { threadInitCallback_ = cb; } + /// valid after calling start() + std::shared_ptr threadPool() + { return threadPool_; } + + /// Starts the server if it's not listening. + /// + /// It's harmless to call it multiple times. + /// Thread safe. + void start(); + + /// Set connection callback. + /// Not thread safe. + void setConnectionCallback(const ConnectionCallback& cb) + { connectionCallback_ = cb; } + + /// Set message callback. + /// Not thread safe. + void setMessageCallback(const MessageCallback& cb) + { messageCallback_ = cb; } + + /// Set write complete callback. + /// Not thread safe. + void setWriteCompleteCallback(const WriteCompleteCallback& cb) + { writeCompleteCallback_ = cb; } + + private: + /// Not thread safe, but in loop + void newConnection(int sockfd, const InetAddress& peerAddr); + /// Thread safe. + void removeConnection(const TcpConnectionPtr& conn); + /// Not thread safe, but in loop + void removeConnectionInLoop(const TcpConnectionPtr& conn); + + typedef std::map ConnectionMap; + + EventLoop* loop_; // the acceptor loop + const string ipPort_; + const string name_; + std::unique_ptr acceptor_; // avoid revealing Acceptor + std::shared_ptr threadPool_; + ConnectionCallback connectionCallback_; + MessageCallback messageCallback_; + WriteCompleteCallback writeCompleteCallback_; + ThreadInitCallback threadInitCallback_; + AtomicInt32 started_; + // always in loop thread + int nextConnId_; + ConnectionMap connections_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_TCPSERVER_H diff --git a/include/Third_Lib/muduo/net/Timer.cc b/include/Third_Lib/muduo/net/Timer.cc new file mode 100644 index 0000000..a4d4433 --- /dev/null +++ b/include/Third_Lib/muduo/net/Timer.cc @@ -0,0 +1,26 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/Timer.h" + +using namespace muduo; +using namespace muduo::net; + +AtomicInt64 Timer::s_numCreated_; + +void Timer::restart(Timestamp now) +{ + if (repeat_) + { + expiration_ = addTime(now, interval_); + } + else + { + expiration_ = Timestamp::invalid(); + } +} diff --git a/include/Third_Lib/muduo/net/Timer.h b/include/Third_Lib/muduo/net/Timer.h new file mode 100644 index 0000000..904584e --- /dev/null +++ b/include/Third_Lib/muduo/net/Timer.h @@ -0,0 +1,63 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_TIMER_H +#define MUDUO_NET_TIMER_H + +#include "muduo/base/Atomic.h" +#include "muduo/base/Timestamp.h" +#include "muduo/net/Callbacks.h" + +namespace muduo +{ +namespace net +{ + +/// +/// Internal class for timer event. +/// +class Timer : noncopyable +{ + public: + Timer(TimerCallback cb, Timestamp when, double interval) + : callback_(std::move(cb)), + expiration_(when), + interval_(interval), + repeat_(interval > 0.0), + sequence_(s_numCreated_.incrementAndGet()) + { } + + void run() const + { + callback_(); + } + + Timestamp expiration() const { return expiration_; } + bool repeat() const { return repeat_; } + int64_t sequence() const { return sequence_; } + + void restart(Timestamp now); + + static int64_t numCreated() { return s_numCreated_.get(); } + + private: + const TimerCallback callback_; + Timestamp expiration_; + const double interval_; + const bool repeat_; + const int64_t sequence_; + + static AtomicInt64 s_numCreated_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_TIMER_H diff --git a/include/Third_Lib/muduo/net/TimerId.h b/include/Third_Lib/muduo/net/TimerId.h new file mode 100644 index 0000000..fcc5264 --- /dev/null +++ b/include/Third_Lib/muduo/net/TimerId.h @@ -0,0 +1,53 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_TIMERID_H +#define MUDUO_NET_TIMERID_H + +#include "muduo/base/copyable.h" + +namespace muduo +{ +namespace net +{ + +class Timer; + +/// +/// An opaque identifier, for canceling Timer. +/// +class TimerId : public muduo::copyable +{ + public: + TimerId() + : timer_(NULL), + sequence_(0) + { + } + + TimerId(Timer* timer, int64_t seq) + : timer_(timer), + sequence_(seq) + { + } + + // default copy-ctor, dtor and assignment are okay + + friend class TimerQueue; + + private: + Timer* timer_; + int64_t sequence_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_TIMERID_H diff --git a/include/Third_Lib/muduo/net/TimerQueue.cc b/include/Third_Lib/muduo/net/TimerQueue.cc new file mode 100644 index 0000000..89119ae --- /dev/null +++ b/include/Third_Lib/muduo/net/TimerQueue.cc @@ -0,0 +1,260 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS +#endif + +#include "muduo/net/TimerQueue.h" + +#include "muduo/base/Logging.h" +#include "muduo/net/EventLoop.h" +#include "muduo/net/Timer.h" +#include "muduo/net/TimerId.h" + +#include +#include + +namespace muduo +{ +namespace net +{ +namespace detail +{ + +int createTimerfd() +{ + int timerfd = ::timerfd_create(CLOCK_MONOTONIC, + TFD_NONBLOCK | TFD_CLOEXEC); + if (timerfd < 0) + { + LOG_SYSFATAL << "Failed in timerfd_create"; + } + return timerfd; +} + +struct timespec howMuchTimeFromNow(Timestamp when) +{ + int64_t microseconds = when.microSecondsSinceEpoch() + - Timestamp::now().microSecondsSinceEpoch(); + if (microseconds < 100) + { + microseconds = 100; + } + struct timespec ts; + ts.tv_sec = static_cast( + microseconds / Timestamp::kMicroSecondsPerSecond); + ts.tv_nsec = static_cast( + (microseconds % Timestamp::kMicroSecondsPerSecond) * 1000); + return ts; +} + +void readTimerfd(int timerfd, Timestamp now) +{ + uint64_t howmany; + ssize_t n = ::read(timerfd, &howmany, sizeof howmany); + LOG_TRACE << "TimerQueue::handleRead() " << howmany << " at " << now.toString(); + if (n != sizeof howmany) + { + LOG_ERROR << "TimerQueue::handleRead() reads " << n << " bytes instead of 8"; + } +} + +void resetTimerfd(int timerfd, Timestamp expiration) +{ + // wake up loop by timerfd_settime() + struct itimerspec newValue; + struct itimerspec oldValue; + memZero(&newValue, sizeof newValue); + memZero(&oldValue, sizeof oldValue); + newValue.it_value = howMuchTimeFromNow(expiration); + int ret = ::timerfd_settime(timerfd, 0, &newValue, &oldValue); + if (ret) + { + LOG_SYSERR << "timerfd_settime()"; + } +} + +} // namespace detail +} // namespace net +} // namespace muduo + +using namespace muduo; +using namespace muduo::net; +using namespace muduo::net::detail; + +TimerQueue::TimerQueue(EventLoop* loop) + : loop_(loop), + timerfd_(createTimerfd()), + timerfdChannel_(loop, timerfd_), + timers_(), + callingExpiredTimers_(false) +{ + timerfdChannel_.setReadCallback( + std::bind(&TimerQueue::handleRead, this)); + // we are always reading the timerfd, we disarm it with timerfd_settime. + timerfdChannel_.enableReading(); +} + +TimerQueue::~TimerQueue() +{ + timerfdChannel_.disableAll(); + timerfdChannel_.remove(); + ::close(timerfd_); + // do not remove channel, since we're in EventLoop::dtor(); + for (const Entry& timer : timers_) + { + delete timer.second; + } +} + +TimerId TimerQueue::addTimer(TimerCallback cb, + Timestamp when, + double interval) +{ + Timer* timer = new Timer(std::move(cb), when, interval); + loop_->runInLoop( + std::bind(&TimerQueue::addTimerInLoop, this, timer)); + return TimerId(timer, timer->sequence()); +} + +void TimerQueue::cancel(TimerId timerId) +{ + loop_->runInLoop( + std::bind(&TimerQueue::cancelInLoop, this, timerId)); +} + +void TimerQueue::addTimerInLoop(Timer* timer) +{ + loop_->assertInLoopThread(); + bool earliestChanged = insert(timer); + + if (earliestChanged) + { + resetTimerfd(timerfd_, timer->expiration()); + } +} + +void TimerQueue::cancelInLoop(TimerId timerId) +{ + loop_->assertInLoopThread(); + assert(timers_.size() == activeTimers_.size()); + ActiveTimer timer(timerId.timer_, timerId.sequence_); + ActiveTimerSet::iterator it = activeTimers_.find(timer); + if (it != activeTimers_.end()) + { + size_t n = timers_.erase(Entry(it->first->expiration(), it->first)); + assert(n == 1); (void)n; + delete it->first; // FIXME: no delete please + activeTimers_.erase(it); + } + else if (callingExpiredTimers_) + { + cancelingTimers_.insert(timer); + } + assert(timers_.size() == activeTimers_.size()); +} + +void TimerQueue::handleRead() +{ + loop_->assertInLoopThread(); + Timestamp now(Timestamp::now()); + readTimerfd(timerfd_, now); + + std::vector expired = getExpired(now); + + callingExpiredTimers_ = true; + cancelingTimers_.clear(); + // safe to callback outside critical section + for (const Entry& it : expired) + { + it.second->run(); + } + callingExpiredTimers_ = false; + + reset(expired, now); +} + +std::vector TimerQueue::getExpired(Timestamp now) +{ + assert(timers_.size() == activeTimers_.size()); + std::vector expired; + Entry sentry(now, reinterpret_cast(UINTPTR_MAX)); + TimerList::iterator end = timers_.lower_bound(sentry); + assert(end == timers_.end() || now < end->first); + std::copy(timers_.begin(), end, back_inserter(expired)); + timers_.erase(timers_.begin(), end); + + for (const Entry& it : expired) + { + ActiveTimer timer(it.second, it.second->sequence()); + size_t n = activeTimers_.erase(timer); + assert(n == 1); (void)n; + } + + assert(timers_.size() == activeTimers_.size()); + return expired; +} + +void TimerQueue::reset(const std::vector& expired, Timestamp now) +{ + Timestamp nextExpire; + + for (const Entry& it : expired) + { + ActiveTimer timer(it.second, it.second->sequence()); + if (it.second->repeat() + && cancelingTimers_.find(timer) == cancelingTimers_.end()) + { + it.second->restart(now); + insert(it.second); + } + else + { + // FIXME move to a free list + delete it.second; // FIXME: no delete please + } + } + + if (!timers_.empty()) + { + nextExpire = timers_.begin()->second->expiration(); + } + + if (nextExpire.valid()) + { + resetTimerfd(timerfd_, nextExpire); + } +} + +bool TimerQueue::insert(Timer* timer) +{ + loop_->assertInLoopThread(); + assert(timers_.size() == activeTimers_.size()); + bool earliestChanged = false; + Timestamp when = timer->expiration(); + TimerList::iterator it = timers_.begin(); + if (it == timers_.end() || when < it->first) + { + earliestChanged = true; + } + { + std::pair result + = timers_.insert(Entry(when, timer)); + assert(result.second); (void)result; + } + { + std::pair result + = activeTimers_.insert(ActiveTimer(timer, timer->sequence())); + assert(result.second); (void)result; + } + + assert(timers_.size() == activeTimers_.size()); + return earliestChanged; +} + diff --git a/include/Third_Lib/muduo/net/TimerQueue.h b/include/Third_Lib/muduo/net/TimerQueue.h new file mode 100644 index 0000000..85da6b7 --- /dev/null +++ b/include/Third_Lib/muduo/net/TimerQueue.h @@ -0,0 +1,86 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_TIMERQUEUE_H +#define MUDUO_NET_TIMERQUEUE_H + +#include +#include + +#include "muduo/base/Mutex.h" +#include "muduo/base/Timestamp.h" +#include "muduo/net/Callbacks.h" +#include "muduo/net/Channel.h" + +namespace muduo +{ +namespace net +{ + +class EventLoop; +class Timer; +class TimerId; + +/// +/// A best efforts timer queue. +/// No guarantee that the callback will be on time. +/// +class TimerQueue : noncopyable +{ + public: + explicit TimerQueue(EventLoop* loop); + ~TimerQueue(); + + /// + /// Schedules the callback to be run at given time, + /// repeats if @c interval > 0.0. + /// + /// Must be thread safe. Usually be called from other threads. + TimerId addTimer(TimerCallback cb, + Timestamp when, + double interval); + + void cancel(TimerId timerId); + + private: + + // FIXME: use unique_ptr instead of raw pointers. + // This requires heterogeneous comparison lookup (N3465) from C++14 + // so that we can find an T* in a set>. + typedef std::pair Entry; + typedef std::set TimerList; + typedef std::pair ActiveTimer; + typedef std::set ActiveTimerSet; + + void addTimerInLoop(Timer* timer); + void cancelInLoop(TimerId timerId); + // called when timerfd alarms + void handleRead(); + // move out all expired timers + std::vector getExpired(Timestamp now); + void reset(const std::vector& expired, Timestamp now); + + bool insert(Timer* timer); + + EventLoop* loop_; + const int timerfd_; + Channel timerfdChannel_; + // Timer list sorted by expiration + TimerList timers_; + + // for cancel() + ActiveTimerSet activeTimers_; + bool callingExpiredTimers_; /* atomic */ + ActiveTimerSet cancelingTimers_; +}; + +} // namespace net +} // namespace muduo +#endif // MUDUO_NET_TIMERQUEUE_H diff --git a/include/Third_Lib/muduo/net/ZlibStream.h b/include/Third_Lib/muduo/net/ZlibStream.h new file mode 100644 index 0000000..0f143b0 --- /dev/null +++ b/include/Third_Lib/muduo/net/ZlibStream.h @@ -0,0 +1,145 @@ +#pragma once + +#include "muduo/base/noncopyable.h" +#include "muduo/net/Buffer.h" +#pragma GCC diagnostic ignored "-Wold-style-cast" +#include + +namespace muduo +{ +namespace net +{ + +// input is zlib compressed data, output uncompressed data +// FIXME: finish this +class ZlibInputStream : noncopyable +{ + public: + explicit ZlibInputStream(Buffer* output) + : output_(output), + zerror_(Z_OK) + { + memZero(&zstream_, sizeof zstream_); + zerror_ = inflateInit(&zstream_); + } + + ~ZlibInputStream() + { + finish(); + } + + bool write(StringPiece buf); + bool write(Buffer* input); + bool finish(); + // inflateEnd(&zstream_); + + private: + int decompress(int flush); + + Buffer* output_; + z_stream zstream_; + int zerror_; +}; + +// input is uncompressed data, output zlib compressed data +class ZlibOutputStream : noncopyable +{ + public: + explicit ZlibOutputStream(Buffer* output) + : output_(output), + zerror_(Z_OK), + bufferSize_(1024) + { + memZero(&zstream_, sizeof zstream_); + zerror_ = deflateInit(&zstream_, Z_DEFAULT_COMPRESSION); + } + + ~ZlibOutputStream() + { + finish(); + } + + // Return last error message or NULL if no error. + const char* zlibErrorMessage() const { return zstream_.msg; } + + int zlibErrorCode() const { return zerror_; } + int64_t inputBytes() const { return zstream_.total_in; } + int64_t outputBytes() const { return zstream_.total_out; } + int internalOutputBufferSize() const { return bufferSize_; } + + bool write(StringPiece buf) + { + if (zerror_ != Z_OK) + return false; + + assert(zstream_.next_in == NULL && zstream_.avail_in == 0); + void* in = const_cast(buf.data()); + zstream_.next_in = static_cast(in); + zstream_.avail_in = buf.size(); + while (zstream_.avail_in > 0 && zerror_ == Z_OK) + { + zerror_ = compress(Z_NO_FLUSH); + } + if (zstream_.avail_in == 0) + { + assert(static_cast(zstream_.next_in) == buf.end()); + zstream_.next_in = NULL; + } + return zerror_ == Z_OK; + } + + // compress input as much as possible, not guarantee consuming all data. + bool write(Buffer* input) + { + if (zerror_ != Z_OK) + return false; + + void* in = const_cast(input->peek()); + zstream_.next_in = static_cast(in); + zstream_.avail_in = static_cast(input->readableBytes()); + if (zstream_.avail_in > 0 && zerror_ == Z_OK) + { + zerror_ = compress(Z_NO_FLUSH); + } + input->retrieve(input->readableBytes() - zstream_.avail_in); + return zerror_ == Z_OK; + } + + bool finish() + { + if (zerror_ != Z_OK) + return false; + + while (zerror_ == Z_OK) + { + zerror_ = compress(Z_FINISH); + } + zerror_ = deflateEnd(&zstream_); + bool ok = zerror_ == Z_OK; + zerror_ = Z_STREAM_END; + return ok; + } + + private: + int compress(int flush) + { + output_->ensureWritableBytes(bufferSize_); + zstream_.next_out = reinterpret_cast(output_->beginWrite()); + zstream_.avail_out = static_cast(output_->writableBytes()); + int error = ::deflate(&zstream_, flush); + output_->hasWritten(output_->writableBytes() - zstream_.avail_out); + if (output_->writableBytes() == 0 && bufferSize_ < 65536) + { + bufferSize_ *= 2; + } + return error; + } + + Buffer* output_; + z_stream zstream_; + int zerror_; + int bufferSize_; +}; + +} // namespace net +} // namespace muduo diff --git a/include/Third_Lib/muduo/net/boilerplate.cc b/include/Third_Lib/muduo/net/boilerplate.cc new file mode 100644 index 0000000..d0ebe26 --- /dev/null +++ b/include/Third_Lib/muduo/net/boilerplate.cc @@ -0,0 +1,15 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// + +#include "muduo/net/BoilerPlate.h" + +using namespace muduo; +using namespace muduo::net; + + diff --git a/include/Third_Lib/muduo/net/boilerplate.h b/include/Third_Lib/muduo/net/boilerplate.h new file mode 100644 index 0000000..780661c --- /dev/null +++ b/include/Third_Lib/muduo/net/boilerplate.h @@ -0,0 +1,32 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_BOILERPLATE_H +#define MUDUO_NET_BOILERPLATE_H + +#include "muduo/base/noncopyable.h" + +namespace muduo +{ +namespace net +{ + +class BoilerPlate : noncopyable +{ + public: + + private: +}; + +} +} + +#endif // MUDUO_NET_BOILERPLATE_H diff --git a/include/Third_Lib/muduo/net/http/BUILD.bazel b/include/Third_Lib/muduo/net/http/BUILD.bazel new file mode 100644 index 0000000..08b98a4 --- /dev/null +++ b/include/Third_Lib/muduo/net/http/BUILD.bazel @@ -0,0 +1,9 @@ +cc_library( + name = "http", + srcs = glob(["*.cc"]), + hdrs = glob(["*.h"]), + visibility = ["//visibility:public"], + deps = [ + "//muduo/net", + ], +) diff --git a/include/Third_Lib/muduo/net/http/CMakeLists.txt b/include/Third_Lib/muduo/net/http/CMakeLists.txt new file mode 100644 index 0000000..51dd981 --- /dev/null +++ b/include/Third_Lib/muduo/net/http/CMakeLists.txt @@ -0,0 +1,30 @@ +set(http_SRCS + HttpServer.cc + HttpResponse.cc + HttpContext.cc + ) + +add_library(muduo_http ${http_SRCS}) +target_link_libraries(muduo_http muduo_net) + +install(TARGETS muduo_http DESTINATION lib) +set(HEADERS + HttpContext.h + HttpRequest.h + HttpResponse.h + HttpServer.h + ) +install(FILES ${HEADERS} DESTINATION include/muduo/net/http) + +if(MUDUO_BUILD_EXAMPLES) +add_executable(httpserver_test tests/HttpServer_test.cc) +target_link_libraries(httpserver_test muduo_http) + +if(BOOSTTEST_LIBRARY) +add_executable(httprequest_unittest tests/HttpRequest_unittest.cc) +target_link_libraries(httprequest_unittest muduo_http boost_unit_test_framework) +endif() + +endif() + +# add_subdirectory(tests) diff --git a/include/Third_Lib/muduo/net/http/HttpContext.cc b/include/Third_Lib/muduo/net/http/HttpContext.cc new file mode 100644 index 0000000..bef3a80 --- /dev/null +++ b/include/Third_Lib/muduo/net/http/HttpContext.cc @@ -0,0 +1,118 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// + +#include "muduo/net/Buffer.h" +#include "muduo/net/http/HttpContext.h" + +using namespace muduo; +using namespace muduo::net; + +bool HttpContext::processRequestLine(const char* begin, const char* end) +{ + bool succeed = false; + const char* start = begin; + const char* space = std::find(start, end, ' '); + if (space != end && request_.setMethod(start, space)) + { + start = space+1; + space = std::find(start, end, ' '); + if (space != end) + { + const char* question = std::find(start, space, '?'); + if (question != space) + { + request_.setPath(start, question); + request_.setQuery(question, space); + } + else + { + request_.setPath(start, space); + } + start = space+1; + succeed = end-start == 8 && std::equal(start, end-1, "HTTP/1."); + if (succeed) + { + if (*(end-1) == '1') + { + request_.setVersion(HttpRequest::kHttp11); + } + else if (*(end-1) == '0') + { + request_.setVersion(HttpRequest::kHttp10); + } + else + { + succeed = false; + } + } + } + } + return succeed; +} + +// return false if any error +bool HttpContext::parseRequest(Buffer* buf, Timestamp receiveTime) +{ + bool ok = true; + bool hasMore = true; + while (hasMore) + { + if (state_ == kExpectRequestLine) + { + const char* crlf = buf->findCRLF(); + if (crlf) + { + ok = processRequestLine(buf->peek(), crlf); + if (ok) + { + request_.setReceiveTime(receiveTime); + buf->retrieveUntil(crlf + 2); + state_ = kExpectHeaders; + } + else + { + hasMore = false; + } + } + else + { + hasMore = false; + } + } + else if (state_ == kExpectHeaders) + { + const char* crlf = buf->findCRLF(); + if (crlf) + { + const char* colon = std::find(buf->peek(), crlf, ':'); + if (colon != crlf) + { + request_.addHeader(buf->peek(), colon, crlf); + } + else + { + // empty line, end of header + // FIXME: + state_ = kGotAll; + hasMore = false; + } + buf->retrieveUntil(crlf + 2); + } + else + { + hasMore = false; + } + } + else if (state_ == kExpectBody) + { + // FIXME: + } + } + return ok; +} diff --git a/include/Third_Lib/muduo/net/http/HttpContext.h b/include/Third_Lib/muduo/net/http/HttpContext.h new file mode 100644 index 0000000..4beee5c --- /dev/null +++ b/include/Third_Lib/muduo/net/http/HttpContext.h @@ -0,0 +1,72 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_HTTP_HTTPCONTEXT_H +#define MUDUO_NET_HTTP_HTTPCONTEXT_H + +#include "muduo/base/copyable.h" + +#include "muduo/net/http/HttpRequest.h" + +namespace muduo +{ +namespace net +{ + +class Buffer; + +class HttpContext : public muduo::copyable +{ + public: + enum HttpRequestParseState + { + kExpectRequestLine, + kExpectHeaders, + kExpectBody, + kGotAll, + }; + + HttpContext() + : state_(kExpectRequestLine) + { + } + + // default copy-ctor, dtor and assignment are fine + + // return false if any error + bool parseRequest(Buffer* buf, Timestamp receiveTime); + + bool gotAll() const + { return state_ == kGotAll; } + + void reset() + { + state_ = kExpectRequestLine; + HttpRequest dummy; + request_.swap(dummy); + } + + const HttpRequest& request() const + { return request_; } + + HttpRequest& request() + { return request_; } + + private: + bool processRequestLine(const char* begin, const char* end); + + HttpRequestParseState state_; + HttpRequest request_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_HTTP_HTTPCONTEXT_H diff --git a/include/Third_Lib/muduo/net/http/HttpRequest.h b/include/Third_Lib/muduo/net/http/HttpRequest.h new file mode 100644 index 0000000..9c70c5d --- /dev/null +++ b/include/Third_Lib/muduo/net/http/HttpRequest.h @@ -0,0 +1,187 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_HTTP_HTTPREQUEST_H +#define MUDUO_NET_HTTP_HTTPREQUEST_H + +#include "muduo/base/copyable.h" +#include "muduo/base/Timestamp.h" +#include "muduo/base/Types.h" + +#include +#include +#include + +namespace muduo +{ +namespace net +{ + +class HttpRequest : public muduo::copyable +{ + public: + enum Method + { + kInvalid, kGet, kPost, kHead, kPut, kDelete + }; + enum Version + { + kUnknown, kHttp10, kHttp11 + }; + + HttpRequest() + : method_(kInvalid), + version_(kUnknown) + { + } + + void setVersion(Version v) + { + version_ = v; + } + + Version getVersion() const + { return version_; } + + bool setMethod(const char* start, const char* end) + { + assert(method_ == kInvalid); + string m(start, end); + if (m == "GET") + { + method_ = kGet; + } + else if (m == "POST") + { + method_ = kPost; + } + else if (m == "HEAD") + { + method_ = kHead; + } + else if (m == "PUT") + { + method_ = kPut; + } + else if (m == "DELETE") + { + method_ = kDelete; + } + else + { + method_ = kInvalid; + } + return method_ != kInvalid; + } + + Method method() const + { return method_; } + + const char* methodString() const + { + const char* result = "UNKNOWN"; + switch(method_) + { + case kGet: + result = "GET"; + break; + case kPost: + result = "POST"; + break; + case kHead: + result = "HEAD"; + break; + case kPut: + result = "PUT"; + break; + case kDelete: + result = "DELETE"; + break; + default: + break; + } + return result; + } + + void setPath(const char* start, const char* end) + { + path_.assign(start, end); + } + + const string& path() const + { return path_; } + + void setQuery(const char* start, const char* end) + { + query_.assign(start, end); + } + + const string& query() const + { return query_; } + + void setReceiveTime(Timestamp t) + { receiveTime_ = t; } + + Timestamp receiveTime() const + { return receiveTime_; } + + void addHeader(const char* start, const char* colon, const char* end) + { + string field(start, colon); + ++colon; + while (colon < end && isspace(*colon)) + { + ++colon; + } + string value(colon, end); + while (!value.empty() && isspace(value[value.size()-1])) + { + value.resize(value.size()-1); + } + headers_[field] = value; + } + + string getHeader(const string& field) const + { + string result; + std::map::const_iterator it = headers_.find(field); + if (it != headers_.end()) + { + result = it->second; + } + return result; + } + + const std::map& headers() const + { return headers_; } + + void swap(HttpRequest& that) + { + std::swap(method_, that.method_); + std::swap(version_, that.version_); + path_.swap(that.path_); + query_.swap(that.query_); + receiveTime_.swap(that.receiveTime_); + headers_.swap(that.headers_); + } + + private: + Method method_; + Version version_; + string path_; + string query_; + Timestamp receiveTime_; + std::map headers_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_HTTP_HTTPREQUEST_H diff --git a/include/Third_Lib/muduo/net/http/HttpResponse.cc b/include/Third_Lib/muduo/net/http/HttpResponse.cc new file mode 100644 index 0000000..0e2e74d --- /dev/null +++ b/include/Third_Lib/muduo/net/http/HttpResponse.cc @@ -0,0 +1,47 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// + +#include "muduo/net/http/HttpResponse.h" +#include "muduo/net/Buffer.h" + +#include + +using namespace muduo; +using namespace muduo::net; + +void HttpResponse::appendToBuffer(Buffer* output) const +{ + char buf[32]; + snprintf(buf, sizeof buf, "HTTP/1.1 %d ", statusCode_); + output->append(buf); + output->append(statusMessage_); + output->append("\r\n"); + + if (closeConnection_) + { + output->append("Connection: close\r\n"); + } + else + { + snprintf(buf, sizeof buf, "Content-Length: %zd\r\n", body_.size()); + output->append(buf); + output->append("Connection: Keep-Alive\r\n"); + } + + for (const auto& header : headers_) + { + output->append(header.first); + output->append(": "); + output->append(header.second); + output->append("\r\n"); + } + + output->append("\r\n"); + output->append(body_); +} diff --git a/include/Third_Lib/muduo/net/http/HttpResponse.h b/include/Third_Lib/muduo/net/http/HttpResponse.h new file mode 100644 index 0000000..eb3910f --- /dev/null +++ b/include/Third_Lib/muduo/net/http/HttpResponse.h @@ -0,0 +1,79 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_HTTP_HTTPRESPONSE_H +#define MUDUO_NET_HTTP_HTTPRESPONSE_H + +#include "muduo/base/copyable.h" +#include "muduo/base/Types.h" + +#include + +namespace muduo +{ +namespace net +{ + +class Buffer; +class HttpResponse : public muduo::copyable +{ + public: + enum HttpStatusCode + { + kUnknown, + k200Ok = 200, + k301MovedPermanently = 301, + k400BadRequest = 400, + k404NotFound = 404, + }; + + explicit HttpResponse(bool close) + : statusCode_(kUnknown), + closeConnection_(close) + { + } + + void setStatusCode(HttpStatusCode code) + { statusCode_ = code; } + + void setStatusMessage(const string& message) + { statusMessage_ = message; } + + void setCloseConnection(bool on) + { closeConnection_ = on; } + + bool closeConnection() const + { return closeConnection_; } + + void setContentType(const string& contentType) + { addHeader("Content-Type", contentType); } + + // FIXME: replace string with StringPiece + void addHeader(const string& key, const string& value) + { headers_[key] = value; } + + void setBody(const string& body) + { body_ = body; } + + void appendToBuffer(Buffer* output) const; + + private: + std::map headers_; + HttpStatusCode statusCode_; + // FIXME: add http version + string statusMessage_; + bool closeConnection_; + string body_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_HTTP_HTTPRESPONSE_H diff --git a/include/Third_Lib/muduo/net/http/HttpServer.cc b/include/Third_Lib/muduo/net/http/HttpServer.cc new file mode 100644 index 0000000..f7d4678 --- /dev/null +++ b/include/Third_Lib/muduo/net/http/HttpServer.cc @@ -0,0 +1,100 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// + +#include "muduo/net/http/HttpServer.h" + +#include "muduo/base/Logging.h" +#include "muduo/net/http/HttpContext.h" +#include "muduo/net/http/HttpRequest.h" +#include "muduo/net/http/HttpResponse.h" + +using namespace muduo; +using namespace muduo::net; + +namespace muduo +{ +namespace net +{ +namespace detail +{ + +void defaultHttpCallback(const HttpRequest&, HttpResponse* resp) +{ + resp->setStatusCode(HttpResponse::k404NotFound); + resp->setStatusMessage("Not Found"); + resp->setCloseConnection(true); +} + +} // namespace detail +} // namespace net +} // namespace muduo + +HttpServer::HttpServer(EventLoop* loop, + const InetAddress& listenAddr, + const string& name, + TcpServer::Option option) + : server_(loop, listenAddr, name, option), + httpCallback_(detail::defaultHttpCallback) +{ + server_.setConnectionCallback( + std::bind(&HttpServer::onConnection, this, _1)); + server_.setMessageCallback( + std::bind(&HttpServer::onMessage, this, _1, _2, _3)); +} + +void HttpServer::start() +{ + LOG_WARN << "HttpServer[" << server_.name() + << "] starts listening on " << server_.ipPort(); + server_.start(); +} + +void HttpServer::onConnection(const TcpConnectionPtr& conn) +{ + if (conn->connected()) + { + conn->setContext(HttpContext()); + } +} + +void HttpServer::onMessage(const TcpConnectionPtr& conn, + Buffer* buf, + Timestamp receiveTime) +{ + HttpContext* context = boost::any_cast(conn->getMutableContext()); + + if (!context->parseRequest(buf, receiveTime)) + { + conn->send("HTTP/1.1 400 Bad Request\r\n\r\n"); + conn->shutdown(); + } + + if (context->gotAll()) + { + onRequest(conn, context->request()); + context->reset(); + } +} + +void HttpServer::onRequest(const TcpConnectionPtr& conn, const HttpRequest& req) +{ + const string& connection = req.getHeader("Connection"); + bool close = connection == "close" || + (req.getVersion() == HttpRequest::kHttp10 && connection != "Keep-Alive"); + HttpResponse response(close); + httpCallback_(req, &response); + Buffer buf; + response.appendToBuffer(&buf); + conn->send(&buf); + if (response.closeConnection()) + { + conn->shutdown(); + } +} + diff --git a/include/Third_Lib/muduo/net/http/HttpServer.h b/include/Third_Lib/muduo/net/http/HttpServer.h new file mode 100644 index 0000000..9609a11 --- /dev/null +++ b/include/Third_Lib/muduo/net/http/HttpServer.h @@ -0,0 +1,68 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_HTTP_HTTPSERVER_H +#define MUDUO_NET_HTTP_HTTPSERVER_H + +#include "muduo/net/TcpServer.h" + +namespace muduo +{ +namespace net +{ + +class HttpRequest; +class HttpResponse; + +/// A simple embeddable HTTP server designed for report status of a program. +/// It is not a fully HTTP 1.1 compliant server, but provides minimum features +/// that can communicate with HttpClient and Web browser. +/// It is synchronous, just like Java Servlet. +class HttpServer : noncopyable +{ + public: + typedef std::function HttpCallback; + + HttpServer(EventLoop* loop, + const InetAddress& listenAddr, + const string& name, + TcpServer::Option option = TcpServer::kNoReusePort); + + EventLoop* getLoop() const { return server_.getLoop(); } + + /// Not thread safe, callback be registered before calling start(). + void setHttpCallback(const HttpCallback& cb) + { + httpCallback_ = cb; + } + + void setThreadNum(int numThreads) + { + server_.setThreadNum(numThreads); + } + + void start(); + + private: + void onConnection(const TcpConnectionPtr& conn); + void onMessage(const TcpConnectionPtr& conn, + Buffer* buf, + Timestamp receiveTime); + void onRequest(const TcpConnectionPtr&, const HttpRequest&); + + TcpServer server_; + HttpCallback httpCallback_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_HTTP_HTTPSERVER_H diff --git a/include/Third_Lib/muduo/net/http/tests/HttpRequest_unittest.cc b/include/Third_Lib/muduo/net/http/tests/HttpRequest_unittest.cc new file mode 100644 index 0000000..cb89305 --- /dev/null +++ b/include/Third_Lib/muduo/net/http/tests/HttpRequest_unittest.cc @@ -0,0 +1,79 @@ +#include "muduo/net/http/HttpContext.h" +#include "muduo/net/Buffer.h" + +//#define BOOST_TEST_MODULE BufferTest +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK +#include + +using muduo::string; +using muduo::Timestamp; +using muduo::net::Buffer; +using muduo::net::HttpContext; +using muduo::net::HttpRequest; + +BOOST_AUTO_TEST_CASE(testParseRequestAllInOne) +{ + HttpContext context; + Buffer input; + input.append("GET /index.html HTTP/1.1\r\n" + "Host: www.chenshuo.com\r\n" + "\r\n"); + + BOOST_CHECK(context.parseRequest(&input, Timestamp::now())); + BOOST_CHECK(context.gotAll()); + const HttpRequest& request = context.request(); + BOOST_CHECK_EQUAL(request.method(), HttpRequest::kGet); + BOOST_CHECK_EQUAL(request.path(), string("/index.html")); + BOOST_CHECK_EQUAL(request.getVersion(), HttpRequest::kHttp11); + BOOST_CHECK_EQUAL(request.getHeader("Host"), string("www.chenshuo.com")); + BOOST_CHECK_EQUAL(request.getHeader("User-Agent"), string("")); +} + +BOOST_AUTO_TEST_CASE(testParseRequestInTwoPieces) +{ + string all("GET /index.html HTTP/1.1\r\n" + "Host: www.chenshuo.com\r\n" + "\r\n"); + + for (size_t sz1 = 0; sz1 < all.size(); ++sz1) + { + HttpContext context; + Buffer input; + input.append(all.c_str(), sz1); + BOOST_CHECK(context.parseRequest(&input, Timestamp::now())); + BOOST_CHECK(!context.gotAll()); + + size_t sz2 = all.size() - sz1; + input.append(all.c_str() + sz1, sz2); + BOOST_CHECK(context.parseRequest(&input, Timestamp::now())); + BOOST_CHECK(context.gotAll()); + const HttpRequest& request = context.request(); + BOOST_CHECK_EQUAL(request.method(), HttpRequest::kGet); + BOOST_CHECK_EQUAL(request.path(), string("/index.html")); + BOOST_CHECK_EQUAL(request.getVersion(), HttpRequest::kHttp11); + BOOST_CHECK_EQUAL(request.getHeader("Host"), string("www.chenshuo.com")); + BOOST_CHECK_EQUAL(request.getHeader("User-Agent"), string("")); + } +} + +BOOST_AUTO_TEST_CASE(testParseRequestEmptyHeaderValue) +{ + HttpContext context; + Buffer input; + input.append("GET /index.html HTTP/1.1\r\n" + "Host: www.chenshuo.com\r\n" + "User-Agent:\r\n" + "Accept-Encoding: \r\n" + "\r\n"); + + BOOST_CHECK(context.parseRequest(&input, Timestamp::now())); + BOOST_CHECK(context.gotAll()); + const HttpRequest& request = context.request(); + BOOST_CHECK_EQUAL(request.method(), HttpRequest::kGet); + BOOST_CHECK_EQUAL(request.path(), string("/index.html")); + BOOST_CHECK_EQUAL(request.getVersion(), HttpRequest::kHttp11); + BOOST_CHECK_EQUAL(request.getHeader("Host"), string("www.chenshuo.com")); + BOOST_CHECK_EQUAL(request.getHeader("User-Agent"), string("")); + BOOST_CHECK_EQUAL(request.getHeader("Accept-Encoding"), string("")); +} diff --git a/include/Third_Lib/muduo/net/http/tests/HttpServer_test.cc b/include/Third_Lib/muduo/net/http/tests/HttpServer_test.cc new file mode 100644 index 0000000..0ec38fb --- /dev/null +++ b/include/Third_Lib/muduo/net/http/tests/HttpServer_test.cc @@ -0,0 +1,150 @@ +#include "muduo/net/http/HttpServer.h" +#include "muduo/net/http/HttpRequest.h" +#include "muduo/net/http/HttpResponse.h" +#include "muduo/net/EventLoop.h" +#include "muduo/base/Logging.h" + +#include +#include + +using namespace muduo; +using namespace muduo::net; + +extern char favicon[555]; +bool benchmark = false; + +void onRequest(const HttpRequest& req, HttpResponse* resp) +{ + std::cout << "Headers " << req.methodString() << " " << req.path() << std::endl; + if (!benchmark) + { + const std::map& headers = req.headers(); + for (const auto& header : headers) + { + std::cout << header.first << ": " << header.second << std::endl; + } + } + + if (req.path() == "/") + { + resp->setStatusCode(HttpResponse::k200Ok); + resp->setStatusMessage("OK"); + resp->setContentType("text/html"); + resp->addHeader("Server", "Muduo"); + string now = Timestamp::now().toFormattedString(); + resp->setBody("This is title" + "

Hello

Now is " + now + + ""); + } + else if (req.path() == "/favicon.ico") + { + resp->setStatusCode(HttpResponse::k200Ok); + resp->setStatusMessage("OK"); + resp->setContentType("image/png"); + resp->setBody(string(favicon, sizeof favicon)); + } + else if (req.path() == "/hello") + { + resp->setStatusCode(HttpResponse::k200Ok); + resp->setStatusMessage("OK"); + resp->setContentType("text/plain"); + resp->addHeader("Server", "Muduo"); + resp->setBody("hello, world!\n"); + } + else + { + resp->setStatusCode(HttpResponse::k404NotFound); + resp->setStatusMessage("Not Found"); + resp->setCloseConnection(true); + } +} + +int main(int argc, char* argv[]) +{ + int numThreads = 0; + if (argc > 1) + { + benchmark = true; + Logger::setLogLevel(Logger::WARN); + numThreads = atoi(argv[1]); + } + EventLoop loop; + HttpServer server(&loop, InetAddress(8000), "dummy"); + server.setHttpCallback(onRequest); + server.setThreadNum(numThreads); + server.start(); + loop.loop(); +} + +char favicon[555] = { + '\x89', 'P', 'N', 'G', '\xD', '\xA', '\x1A', '\xA', + '\x0', '\x0', '\x0', '\xD', 'I', 'H', 'D', 'R', + '\x0', '\x0', '\x0', '\x10', '\x0', '\x0', '\x0', '\x10', + '\x8', '\x6', '\x0', '\x0', '\x0', '\x1F', '\xF3', '\xFF', + 'a', '\x0', '\x0', '\x0', '\x19', 't', 'E', 'X', + 't', 'S', 'o', 'f', 't', 'w', 'a', 'r', + 'e', '\x0', 'A', 'd', 'o', 'b', 'e', '\x20', + 'I', 'm', 'a', 'g', 'e', 'R', 'e', 'a', + 'd', 'y', 'q', '\xC9', 'e', '\x3C', '\x0', '\x0', + '\x1', '\xCD', 'I', 'D', 'A', 'T', 'x', '\xDA', + '\x94', '\x93', '9', 'H', '\x3', 'A', '\x14', '\x86', + '\xFF', '\x5D', 'b', '\xA7', '\x4', 'R', '\xC4', 'm', + '\x22', '\x1E', '\xA0', 'F', '\x24', '\x8', '\x16', '\x16', + 'v', '\xA', '6', '\xBA', 'J', '\x9A', '\x80', '\x8', + 'A', '\xB4', 'q', '\x85', 'X', '\x89', 'G', '\xB0', + 'I', '\xA9', 'Q', '\x24', '\xCD', '\xA6', '\x8', '\xA4', + 'H', 'c', '\x91', 'B', '\xB', '\xAF', 'V', '\xC1', + 'F', '\xB4', '\x15', '\xCF', '\x22', 'X', '\x98', '\xB', + 'T', 'H', '\x8A', 'd', '\x93', '\x8D', '\xFB', 'F', + 'g', '\xC9', '\x1A', '\x14', '\x7D', '\xF0', 'f', 'v', + 'f', '\xDF', '\x7C', '\xEF', '\xE7', 'g', 'F', '\xA8', + '\xD5', 'j', 'H', '\x24', '\x12', '\x2A', '\x0', '\x5', + '\xBF', 'G', '\xD4', '\xEF', '\xF7', '\x2F', '6', '\xEC', + '\x12', '\x20', '\x1E', '\x8F', '\xD7', '\xAA', '\xD5', '\xEA', + '\xAF', 'I', '5', 'F', '\xAA', 'T', '\x5F', '\x9F', + '\x22', 'A', '\x2A', '\x95', '\xA', '\x83', '\xE5', 'r', + '9', 'd', '\xB3', 'Y', '\x96', '\x99', 'L', '\x6', + '\xE9', 't', '\x9A', '\x25', '\x85', '\x2C', '\xCB', 'T', + '\xA7', '\xC4', 'b', '1', '\xB5', '\x5E', '\x0', '\x3', + 'h', '\x9A', '\xC6', '\x16', '\x82', '\x20', 'X', 'R', + '\x14', 'E', '6', 'S', '\x94', '\xCB', 'e', 'x', + '\xBD', '\x5E', '\xAA', 'U', 'T', '\x23', 'L', '\xC0', + '\xE0', '\xE2', '\xC1', '\x8F', '\x0', '\x9E', '\xBC', '\x9', + 'A', '\x7C', '\x3E', '\x1F', '\x83', 'D', '\x22', '\x11', + '\xD5', 'T', '\x40', '\x3F', '8', '\x80', 'w', '\xE5', + '3', '\x7', '\xB8', '\x5C', '\x2E', 'H', '\x92', '\x4', + '\x87', '\xC3', '\x81', '\x40', '\x20', '\x40', 'g', '\x98', + '\xE9', '6', '\x1A', '\xA6', 'g', '\x15', '\x4', '\xE3', + '\xD7', '\xC8', '\xBD', '\x15', '\xE1', 'i', '\xB7', 'C', + '\xAB', '\xEA', 'x', '\x2F', 'j', 'X', '\x92', '\xBB', + '\x18', '\x20', '\x9F', '\xCF', '3', '\xC3', '\xB8', '\xE9', + 'N', '\xA7', '\xD3', 'l', 'J', '\x0', 'i', '6', + '\x7C', '\x8E', '\xE1', '\xFE', 'V', '\x84', '\xE7', '\x3C', + '\x9F', 'r', '\x2B', '\x3A', 'B', '\x7B', '7', 'f', + 'w', '\xAE', '\x8E', '\xE', '\xF3', '\xBD', 'R', '\xA9', + 'd', '\x2', 'B', '\xAF', '\x85', '2', 'f', 'F', + '\xBA', '\xC', '\xD9', '\x9F', '\x1D', '\x9A', 'l', '\x22', + '\xE6', '\xC7', '\x3A', '\x2C', '\x80', '\xEF', '\xC1', '\x15', + '\x90', '\x7', '\x93', '\xA2', '\x28', '\xA0', 'S', 'j', + '\xB1', '\xB8', '\xDF', '\x29', '5', 'C', '\xE', '\x3F', + 'X', '\xFC', '\x98', '\xDA', 'y', 'j', 'P', '\x40', + '\x0', '\x87', '\xAE', '\x1B', '\x17', 'B', '\xB4', '\x3A', + '\x3F', '\xBE', 'y', '\xC7', '\xA', '\x26', '\xB6', '\xEE', + '\xD9', '\x9A', '\x60', '\x14', '\x93', '\xDB', '\x8F', '\xD', + '\xA', '\x2E', '\xE9', '\x23', '\x95', '\x29', 'X', '\x0', + '\x27', '\xEB', 'n', 'V', 'p', '\xBC', '\xD6', '\xCB', + '\xD6', 'G', '\xAB', '\x3D', 'l', '\x7D', '\xB8', '\xD2', + '\xDD', '\xA0', '\x60', '\x83', '\xBA', '\xEF', '\x5F', '\xA4', + '\xEA', '\xCC', '\x2', 'N', '\xAE', '\x5E', 'p', '\x1A', + '\xEC', '\xB3', '\x40', '9', '\xAC', '\xFE', '\xF2', '\x91', + '\x89', 'g', '\x91', '\x85', '\x21', '\xA8', '\x87', '\xB7', + 'X', '\x7E', '\x7E', '\x85', '\xBB', '\xCD', 'N', 'N', + 'b', 't', '\x40', '\xFA', '\x93', '\x89', '\xEC', '\x1E', + '\xEC', '\x86', '\x2', 'H', '\x26', '\x93', '\xD0', 'u', + '\x1D', '\x7F', '\x9', '2', '\x95', '\xBF', '\x1F', '\xDB', + '\xD7', 'c', '\x8A', '\x1A', '\xF7', '\x5C', '\xC1', '\xFF', + '\x22', 'J', '\xC3', '\x87', '\x0', '\x3', '\x0', 'K', + '\xBB', '\xF8', '\xD6', '\x2A', 'v', '\x98', 'I', '\x0', + '\x0', '\x0', '\x0', 'I', 'E', 'N', 'D', '\xAE', + 'B', '\x60', '\x82', +}; diff --git a/include/Third_Lib/muduo/net/inspect/BUILD.bazel b/include/Third_Lib/muduo/net/inspect/BUILD.bazel new file mode 100644 index 0000000..0592e50 --- /dev/null +++ b/include/Third_Lib/muduo/net/inspect/BUILD.bazel @@ -0,0 +1,9 @@ +cc_library( + name = "inspect", + srcs = glob(["*.cc"]), + hdrs = glob(["*.h"]), + visibility = ["//visibility:public"], + deps = [ + "//muduo/net/http", + ], +) diff --git a/include/Third_Lib/muduo/net/inspect/CMakeLists.txt b/include/Third_Lib/muduo/net/inspect/CMakeLists.txt new file mode 100644 index 0000000..1ce908f --- /dev/null +++ b/include/Third_Lib/muduo/net/inspect/CMakeLists.txt @@ -0,0 +1,26 @@ +set(inspect_SRCS + Inspector.cc + PerformanceInspector.cc + ProcessInspector.cc + SystemInspector.cc + ) + +add_library(muduo_inspect ${inspect_SRCS}) +target_link_libraries(muduo_inspect muduo_http) + +if(TCMALLOC_INCLUDE_DIR AND TCMALLOC_LIBRARY) + set_target_properties(muduo_inspect PROPERTIES COMPILE_FLAGS "-DHAVE_TCMALLOC") + target_link_libraries(muduo_inspect tcmalloc_and_profiler) +endif() + +install(TARGETS muduo_inspect DESTINATION lib) +set(HEADERS + Inspector.h + ) +install(FILES ${HEADERS} DESTINATION include/muduo/net/inspect) + +if(MUDUO_BUILD_EXAMPLES) +add_executable(inspector_test tests/Inspector_test.cc) +target_link_libraries(inspector_test muduo_inspect) +endif() + diff --git a/include/Third_Lib/muduo/net/inspect/Inspector.cc b/include/Third_Lib/muduo/net/inspect/Inspector.cc new file mode 100644 index 0000000..894abd3 --- /dev/null +++ b/include/Third_Lib/muduo/net/inspect/Inspector.cc @@ -0,0 +1,383 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// + +#include "muduo/net/inspect/Inspector.h" + +#include "muduo/base/Logging.h" +#include "muduo/base/Thread.h" +#include "muduo/net/EventLoop.h" +#include "muduo/net/http/HttpRequest.h" +#include "muduo/net/http/HttpResponse.h" +#include "muduo/net/inspect/ProcessInspector.h" +#include "muduo/net/inspect/PerformanceInspector.h" +#include "muduo/net/inspect/SystemInspector.h" + +//#include +//#include +//#include +//#include +//#include + +using namespace muduo; +using namespace muduo::net; + +namespace +{ +Inspector* g_globalInspector = 0; + +// Looks buggy +std::vector split(const string& str) +{ + std::vector result; + size_t start = 0; + size_t pos = str.find('/'); + while (pos != string::npos) + { + if (pos > start) + { + result.push_back(str.substr(start, pos-start)); + } + start = pos+1; + pos = str.find('/', start); + } + + if (start < str.length()) + { + result.push_back(str.substr(start)); + } + + return result; +} + +} // namespace + +extern char favicon[1743]; + +Inspector::Inspector(EventLoop* loop, + const InetAddress& httpAddr, + const string& name) + : server_(loop, httpAddr, "Inspector:"+name), + processInspector_(new ProcessInspector), + systemInspector_(new SystemInspector) +{ + assert(CurrentThread::isMainThread()); + assert(g_globalInspector == 0); + g_globalInspector = this; + server_.setHttpCallback(std::bind(&Inspector::onRequest, this, _1, _2)); + processInspector_->registerCommands(this); + systemInspector_->registerCommands(this); +#ifdef HAVE_TCMALLOC + performanceInspector_.reset(new PerformanceInspector); + performanceInspector_->registerCommands(this); +#endif + loop->runAfter(0, std::bind(&Inspector::start, this)); // little race condition +} + +Inspector::~Inspector() +{ + assert(CurrentThread::isMainThread()); + g_globalInspector = NULL; +} + +void Inspector::add(const string& module, + const string& command, + const Callback& cb, + const string& help) +{ + MutexLockGuard lock(mutex_); + modules_[module][command] = cb; + helps_[module][command] = help; +} + +void Inspector::remove(const string& module, const string& command) +{ + MutexLockGuard lock(mutex_); + std::map::iterator it = modules_.find(module); + if (it != modules_.end()) + { + it->second.erase(command); + helps_[module].erase(command); + } +} + +void Inspector::start() +{ + server_.start(); +} + +void Inspector::onRequest(const HttpRequest& req, HttpResponse* resp) +{ + if (req.path() == "/") + { + string result; + MutexLockGuard lock(mutex_); + for (std::map::const_iterator helpListI = helps_.begin(); + helpListI != helps_.end(); + ++helpListI) + { + const HelpList& list = helpListI->second; + for (const auto& it : list) + { + result += "/"; + result += helpListI->first; + result += "/"; + result += it.first; + size_t len = helpListI->first.size() + it.first.size(); + result += string(len >= 25 ? 1 : 25 - len, ' '); + result += it.second; + result += "\n"; + } + } + resp->setStatusCode(HttpResponse::k200Ok); + resp->setStatusMessage("OK"); + resp->setContentType("text/plain"); + resp->setBody(result); + } + else + { + std::vector result = split(req.path()); + // boost::split(result, req.path(), boost::is_any_of("/")); + //std::copy(result.begin(), result.end(), std::ostream_iterator(std::cout, ", ")); + //std::cout << "\n"; + bool ok = false; + if (result.size() == 0) + { + LOG_DEBUG << req.path(); + } + else if (result.size() == 1) + { + string module = result[0]; + if (module == "favicon.ico") + { + resp->setStatusCode(HttpResponse::k200Ok); + resp->setStatusMessage("OK"); + resp->setContentType("image/png"); + resp->setBody(string(favicon, sizeof favicon)); + + ok = true; + } + else + { + LOG_ERROR << "Unimplemented " << module; + } + } + else + { + string module = result[0]; + MutexLockGuard lock(mutex_); + std::map::const_iterator commListI = modules_.find(module); + if (commListI != modules_.end()) + { + string command = result[1]; + const CommandList& commList = commListI->second; + CommandList::const_iterator it = commList.find(command); + if (it != commList.end()) + { + ArgList args(result.begin()+2, result.end()); + if (it->second) + { + resp->setStatusCode(HttpResponse::k200Ok); + resp->setStatusMessage("OK"); + resp->setContentType("text/plain"); + const Callback& cb = it->second; + resp->setBody(cb(req.method(), args)); + ok = true; + } + } + } + + } + + if (!ok) + { + resp->setStatusCode(HttpResponse::k404NotFound); + resp->setStatusMessage("Not Found"); + } + //resp->setCloseConnection(true); + } +} + +char favicon[1743] = +{ + '\x89', '\x50', '\x4e', '\x47', '\x0d', '\x0a', '\x1a', '\x0a', '\x00', '\x00', + '\x00', '\x0d', '\x49', '\x48', '\x44', '\x52', '\x00', '\x00', '\x00', '\x10', + '\x00', '\x00', '\x00', '\x10', '\x08', '\x06', '\x00', '\x00', '\x00', '\x1f', + '\xf3', '\xff', '\x61', '\x00', '\x00', '\x00', '\x04', '\x73', '\x42', '\x49', + '\x54', '\x08', '\x08', '\x08', '\x08', '\x7c', '\x08', '\x64', '\x88', '\x00', + '\x00', '\x00', '\x09', '\x70', '\x48', '\x59', '\x73', '\x00', '\x00', '\x0b', + '\x12', '\x00', '\x00', '\x0b', '\x12', '\x01', '\xd2', '\xdd', '\x7e', '\xfc', + '\x00', '\x00', '\x00', '\x1c', '\x74', '\x45', '\x58', '\x74', '\x53', '\x6f', + '\x66', '\x74', '\x77', '\x61', '\x72', '\x65', '\x00', '\x41', '\x64', '\x6f', + '\x62', '\x65', '\x20', '\x46', '\x69', '\x72', '\x65', '\x77', '\x6f', '\x72', + '\x6b', '\x73', '\x20', '\x43', '\x53', '\x33', '\x98', '\xd6', '\x46', '\x03', + '\x00', '\x00', '\x00', '\x15', '\x74', '\x45', '\x58', '\x74', '\x43', '\x72', + '\x65', '\x61', '\x74', '\x69', '\x6f', '\x6e', '\x20', '\x54', '\x69', '\x6d', + '\x65', '\x00', '\x32', '\x2f', '\x31', '\x37', '\x2f', '\x30', '\x38', '\x20', + '\x9c', '\xaa', '\x58', '\x00', '\x00', '\x04', '\x11', '\x74', '\x45', '\x58', + '\x74', '\x58', '\x4d', '\x4c', '\x3a', '\x63', '\x6f', '\x6d', '\x2e', '\x61', + '\x64', '\x6f', '\x62', '\x65', '\x2e', '\x78', '\x6d', '\x70', '\x00', '\x3c', + '\x3f', '\x78', '\x70', '\x61', '\x63', '\x6b', '\x65', '\x74', '\x20', '\x62', + '\x65', '\x67', '\x69', '\x6e', '\x3d', '\x22', '\x20', '\x20', '\x20', '\x22', + '\x20', '\x69', '\x64', '\x3d', '\x22', '\x57', '\x35', '\x4d', '\x30', '\x4d', + '\x70', '\x43', '\x65', '\x68', '\x69', '\x48', '\x7a', '\x72', '\x65', '\x53', + '\x7a', '\x4e', '\x54', '\x63', '\x7a', '\x6b', '\x63', '\x39', '\x64', '\x22', + '\x3f', '\x3e', '\x0a', '\x3c', '\x78', '\x3a', '\x78', '\x6d', '\x70', '\x6d', + '\x65', '\x74', '\x61', '\x20', '\x78', '\x6d', '\x6c', '\x6e', '\x73', '\x3a', + '\x78', '\x3d', '\x22', '\x61', '\x64', '\x6f', '\x62', '\x65', '\x3a', '\x6e', + '\x73', '\x3a', '\x6d', '\x65', '\x74', '\x61', '\x2f', '\x22', '\x20', '\x78', + '\x3a', '\x78', '\x6d', '\x70', '\x74', '\x6b', '\x3d', '\x22', '\x41', '\x64', + '\x6f', '\x62', '\x65', '\x20', '\x58', '\x4d', '\x50', '\x20', '\x43', '\x6f', + '\x72', '\x65', '\x20', '\x34', '\x2e', '\x31', '\x2d', '\x63', '\x30', '\x33', + '\x34', '\x20', '\x34', '\x36', '\x2e', '\x32', '\x37', '\x32', '\x39', '\x37', + '\x36', '\x2c', '\x20', '\x53', '\x61', '\x74', '\x20', '\x4a', '\x61', '\x6e', + '\x20', '\x32', '\x37', '\x20', '\x32', '\x30', '\x30', '\x37', '\x20', '\x32', + '\x32', '\x3a', '\x31', '\x31', '\x3a', '\x34', '\x31', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x22', '\x3e', '\x0a', '\x20', '\x20', + '\x20', '\x3c', '\x72', '\x64', '\x66', '\x3a', '\x52', '\x44', '\x46', '\x20', + '\x78', '\x6d', '\x6c', '\x6e', '\x73', '\x3a', '\x72', '\x64', '\x66', '\x3d', + '\x22', '\x68', '\x74', '\x74', '\x70', '\x3a', '\x2f', '\x2f', '\x77', '\x77', + '\x77', '\x2e', '\x77', '\x33', '\x2e', '\x6f', '\x72', '\x67', '\x2f', '\x31', + '\x39', '\x39', '\x39', '\x2f', '\x30', '\x32', '\x2f', '\x32', '\x32', '\x2d', + '\x72', '\x64', '\x66', '\x2d', '\x73', '\x79', '\x6e', '\x74', '\x61', '\x78', + '\x2d', '\x6e', '\x73', '\x23', '\x22', '\x3e', '\x0a', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x3c', '\x72', '\x64', '\x66', '\x3a', '\x44', '\x65', + '\x73', '\x63', '\x72', '\x69', '\x70', '\x74', '\x69', '\x6f', '\x6e', '\x20', + '\x72', '\x64', '\x66', '\x3a', '\x61', '\x62', '\x6f', '\x75', '\x74', '\x3d', + '\x22', '\x22', '\x0a', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x78', '\x6d', '\x6c', '\x6e', '\x73', + '\x3a', '\x78', '\x61', '\x70', '\x3d', '\x22', '\x68', '\x74', '\x74', '\x70', + '\x3a', '\x2f', '\x2f', '\x6e', '\x73', '\x2e', '\x61', '\x64', '\x6f', '\x62', + '\x65', '\x2e', '\x63', '\x6f', '\x6d', '\x2f', '\x78', '\x61', '\x70', '\x2f', + '\x31', '\x2e', '\x30', '\x2f', '\x22', '\x3e', '\x0a', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x3c', '\x78', '\x61', '\x70', + '\x3a', '\x43', '\x72', '\x65', '\x61', '\x74', '\x6f', '\x72', '\x54', '\x6f', + '\x6f', '\x6c', '\x3e', '\x41', '\x64', '\x6f', '\x62', '\x65', '\x20', '\x46', + '\x69', '\x72', '\x65', '\x77', '\x6f', '\x72', '\x6b', '\x73', '\x20', '\x43', + '\x53', '\x33', '\x3c', '\x2f', '\x78', '\x61', '\x70', '\x3a', '\x43', '\x72', + '\x65', '\x61', '\x74', '\x6f', '\x72', '\x54', '\x6f', '\x6f', '\x6c', '\x3e', + '\x0a', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x3c', '\x78', '\x61', '\x70', '\x3a', '\x43', '\x72', '\x65', '\x61', '\x74', + '\x65', '\x44', '\x61', '\x74', '\x65', '\x3e', '\x32', '\x30', '\x30', '\x38', + '\x2d', '\x30', '\x32', '\x2d', '\x31', '\x37', '\x54', '\x30', '\x32', '\x3a', + '\x33', '\x36', '\x3a', '\x34', '\x35', '\x5a', '\x3c', '\x2f', '\x78', '\x61', + '\x70', '\x3a', '\x43', '\x72', '\x65', '\x61', '\x74', '\x65', '\x44', '\x61', + '\x74', '\x65', '\x3e', '\x0a', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x3c', '\x78', '\x61', '\x70', '\x3a', '\x4d', '\x6f', + '\x64', '\x69', '\x66', '\x79', '\x44', '\x61', '\x74', '\x65', '\x3e', '\x32', + '\x30', '\x30', '\x38', '\x2d', '\x30', '\x33', '\x2d', '\x32', '\x34', '\x54', + '\x31', '\x39', '\x3a', '\x30', '\x30', '\x3a', '\x34', '\x32', '\x5a', '\x3c', + '\x2f', '\x78', '\x61', '\x70', '\x3a', '\x4d', '\x6f', '\x64', '\x69', '\x66', + '\x79', '\x44', '\x61', '\x74', '\x65', '\x3e', '\x0a', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x3c', '\x2f', '\x72', '\x64', '\x66', '\x3a', '\x44', + '\x65', '\x73', '\x63', '\x72', '\x69', '\x70', '\x74', '\x69', '\x6f', '\x6e', + '\x3e', '\x0a', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x3c', '\x72', + '\x64', '\x66', '\x3a', '\x44', '\x65', '\x73', '\x63', '\x72', '\x69', '\x70', + '\x74', '\x69', '\x6f', '\x6e', '\x20', '\x72', '\x64', '\x66', '\x3a', '\x61', + '\x62', '\x6f', '\x75', '\x74', '\x3d', '\x22', '\x22', '\x0a', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x78', '\x6d', '\x6c', '\x6e', '\x73', '\x3a', '\x64', '\x63', '\x3d', '\x22', + '\x68', '\x74', '\x74', '\x70', '\x3a', '\x2f', '\x2f', '\x70', '\x75', '\x72', + '\x6c', '\x2e', '\x6f', '\x72', '\x67', '\x2f', '\x64', '\x63', '\x2f', '\x65', + '\x6c', '\x65', '\x6d', '\x65', '\x6e', '\x74', '\x73', '\x2f', '\x31', '\x2e', + '\x31', '\x2f', '\x22', '\x3e', '\x0a', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x3c', '\x64', '\x63', '\x3a', '\x66', '\x6f', + '\x72', '\x6d', '\x61', '\x74', '\x3e', '\x69', '\x6d', '\x61', '\x67', '\x65', + '\x2f', '\x70', '\x6e', '\x67', '\x3c', '\x2f', '\x64', '\x63', '\x3a', '\x66', + '\x6f', '\x72', '\x6d', '\x61', '\x74', '\x3e', '\x0a', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x3c', '\x2f', '\x72', '\x64', '\x66', '\x3a', '\x44', + '\x65', '\x73', '\x63', '\x72', '\x69', '\x70', '\x74', '\x69', '\x6f', '\x6e', + '\x3e', '\x0a', '\x20', '\x20', '\x20', '\x3c', '\x2f', '\x72', '\x64', '\x66', + '\x3a', '\x52', '\x44', '\x46', '\x3e', '\x0a', '\x3c', '\x2f', '\x78', '\x3a', + '\x78', '\x6d', '\x70', '\x6d', '\x65', '\x74', '\x61', '\x3e', '\x0a', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x0a', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x0a', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', '\x20', + '\x20', '\x20', '\x35', '\x1d', '\x52', '\x64', '\x00', '\x00', '\x02', '\x0b', + '\x49', '\x44', '\x41', '\x54', '\x38', '\x8d', '\xa5', '\x93', '\x41', '\x6b', + '\x1a', '\x41', '\x18', '\x86', '\x9f', '\x89', '\x06', '\x23', '\x2e', '\x74', + '\xf5', '\x20', '\x4a', '\x0e', '\x6b', '\x20', '\xe4', '\xe2', '\xa5', '\x78', + '\xc8', '\xa1', '\x78', '\x89', '\x82', '\x17', '\x85', '\x82', '\x82', '\x3d', + '\x26', '\x62', '\x58', '\x72', '\xcd', '\x4f', '\xf1', '\x18', '\x4b', '\x1b', + '\x2f', '\xa5', '\x32', '\xe0', '\xb5', '\x9e', '\x35', '\x1a', '\x58', '\x2f', + '\xe9', '\x0f', '\xe8', '\x65', '\x6d', '\x84', '\xa2', '\x84', '\x2c', '\x0a', + '\x6b', '\x58', '\x62', '\xa7', '\x87', '\x68', '\x68', '\x13', '\xa1', '\xa5', + '\x79', '\xe1', '\x3b', '\x0c', '\xc3', '\xfb', '\xcc', '\x37', '\xef', '\x7c', + '\x23', '\x94', '\x52', '\xbc', '\x44', '\x7e', '\x00', '\x21', '\x04', '\x00', + '\xad', '\x56', '\xcb', '\x18', '\x8f', '\xc7', '\x0d', '\xdb', '\xb6', '\xd3', + '\x8e', '\xe3', '\xf8', '\x83', '\xc1', '\xa0', '\x8a', '\xc7', '\xe3', '\x3f', + '\x12', '\x89', '\x44', '\xb9', '\x5c', '\x2e', '\xf7', '\x56', '\xa6', '\xdf', + '\x0f', '\x15', '\x4a', '\x29', '\x84', '\x10', '\x34', '\x9b', '\xcd', '\x77', + '\x96', '\x65', '\x7d', '\x36', '\x0c', '\x43', '\xe4', '\x72', '\x39', '\xe2', + '\xf1', '\x38', '\xb7', '\xb7', '\xb7', '\xf4', '\xfb', '\x7d', '\x06', '\x83', + '\x01', '\xa9', '\x54', '\xea', '\x43', '\xa5', '\x52', '\x39', '\x7e', '\x0a', + '\x40', '\x29', '\x45', '\xab', '\xd5', '\x32', '\x4e', '\x4f', '\x4f', '\x7f', + '\x4a', '\x29', '\xd5', '\xdd', '\xdd', '\xdd', '\xb3', '\xea', '\xf5', '\x7a', + '\xea', '\xe4', '\xe4', '\x44', '\x49', '\x29', '\xd3', '\x2b', '\xcf', '\xaa', + '\x36', '\x00', '\xc6', '\xe3', '\x71', '\x63', '\x67', '\x67', '\x47', '\xe4', + '\xf3', '\x79', '\x00', '\x3c', '\xcf', '\xa3', '\x50', '\x28', '\xe0', '\xba', + '\x2e', '\x9e', '\xe7', '\x91', '\x4a', '\xa5', '\xd8', '\xdb', '\xdb', '\x63', + '\x34', '\x1a', '\x7d', '\x7c', '\x9a', '\xc1', '\x06', '\x80', '\x6d', '\xdb', + '\xe9', '\x6c', '\x36', '\x8b', '\xcf', '\xe7', '\xc3', '\xf3', '\x3c', '\x5c', + '\xd7', '\x05', '\x60', '\x36', '\x9b', '\xe1', '\xba', '\x2e', '\x8b', '\xc5', + '\x82', '\x4c', '\x26', '\x83', '\x6d', '\xdb', '\xbb', '\x6b', '\x43', '\x74', + '\x1c', '\xc7', '\x1f', '\x8b', '\xc5', '\x00', '\x28', '\x16', '\x8b', '\x8f', + '\x9b', '\xd5', '\x6a', '\x15', '\x00', '\x29', '\x25', '\x9a', '\xa6', '\x31', + '\x9f', '\xcf', '\xc5', '\x5a', '\xc0', '\xd6', '\xd6', '\x96', '\x9a', '\x4c', + '\x26', '\x22', '\x14', '\x0a', '\x21', '\xa5', '\x64', '\x36', '\x9b', '\x51', + '\xad', '\x56', '\xa9', '\xd5', '\x6a', '\x68', '\x9a', '\x06', '\xc0', '\xf5', + '\xf5', '\x35', '\xba', '\xae', '\xdf', '\xaf', '\xbd', '\x82', '\x61', '\x18', + '\xdf', '\x2c', '\xcb', '\x7a', '\x20', '\xfa', '\xfd', '\x04', '\x02', '\x01', + '\x00', '\x34', '\x4d', '\x23', '\x10', '\x08', '\xb0', '\x58', '\x2c', '\xe8', + '\x76', '\xbb', '\x24', '\x12', '\x89', '\x8b', '\xb5', '\x1d', '\x6c', '\x6f', + '\x6f', '\x1f', '\x75', '\x3a', '\x9d', '\x7e', '\x38', '\x1c', '\x26', '\x97', + '\xcb', '\x21', '\x84', '\x40', '\x4a', '\x09', '\xc0', '\xe6', '\xe6', '\x26', + '\xed', '\x76', '\x9b', '\xc9', '\x64', '\xa2', '\xa6', '\xd3', '\xe9', '\x27', + '\x78', '\x98', '\x9b', '\xd5', '\x53', '\x3e', '\xce', '\xc1', '\xf9', '\xf9', + '\xf9', '\xfb', '\xc1', '\x60', '\x70', '\x9c', '\x4c', '\x26', '\xd9', '\xdf', + '\xdf', '\x27', '\x12', '\x89', '\x30', '\x1c', '\x0e', '\xb9', '\xbc', '\xbc', + '\xe4', '\xe6', '\xe6', '\x46', '\xf9', '\x7c', '\xbe', '\x2f', '\xd3', '\xe9', + '\x34', '\x0f', '\x34', '\xea', '\xf5', '\x7a', '\xe5', '\x19', '\x60', '\x19', + '\xd6', '\x9b', '\xd1', '\x68', '\xd4', '\x18', '\x0e', '\x87', '\xbb', '\xf3', + '\xf9', '\x5c', '\xe8', '\xba', '\x7e', '\x6f', '\x18', '\xc6', '\x45', '\x34', + '\x1a', '\x3d', '\x2c', '\x95', '\x4a', '\xdf', '\x4d', '\xd3', '\xbc', '\x02', + '\x5e', '\x03', '\x5f', '\x81', '\x83', '\xb3', '\xb3', '\x33', '\xe7', '\x0f', + '\xc0', '\xdf', '\x64', '\x9a', '\xa6', '\xb1', '\x34', '\xeb', '\x80', '\x03', + '\x1c', '\x6c', '\xfc', '\x93', '\x73', '\xa9', '\x7a', '\xbd', '\x6e', '\x03', + '\x47', '\xcb', '\xa5', '\x0e', '\xbc', '\xe2', '\x7f', '\x7e', '\xa3', '\x69', + '\x9a', '\x87', '\xa6', '\x69', '\xbe', '\x55', '\x4a', '\x3d', '\x64', '\xf0', + '\x12', '\xfd', '\x02', '\x0d', '\x53', '\x06', '\x24', '\x88', '\x3f', '\xe1', + '\x69', '\x00', '\x00', '\x00', '\x00', '\x49', '\x45', '\x4e', '\x44', '\xae', + '\x42', '\x60', '\x82', +}; diff --git a/include/Third_Lib/muduo/net/inspect/Inspector.h b/include/Third_Lib/muduo/net/inspect/Inspector.h new file mode 100644 index 0000000..09041d1 --- /dev/null +++ b/include/Third_Lib/muduo/net/inspect/Inspector.h @@ -0,0 +1,67 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_INSPECT_INSPECTOR_H +#define MUDUO_NET_INSPECT_INSPECTOR_H + +#include "muduo/base/Mutex.h" +#include "muduo/net/http/HttpRequest.h" +#include "muduo/net/http/HttpServer.h" + +#include + +namespace muduo +{ +namespace net +{ + +class ProcessInspector; +class PerformanceInspector; +class SystemInspector; + +// An internal inspector of the running process, usually a singleton. +// Better to run in a seperated thread, as some method may block for seconds +class Inspector : noncopyable +{ + public: + typedef std::vector ArgList; + typedef std::function Callback; + Inspector(EventLoop* loop, + const InetAddress& httpAddr, + const string& name); + ~Inspector(); + + /// Add a Callback for handling the special uri : /mudule/command + void add(const string& module, + const string& command, + const Callback& cb, + const string& help); + void remove(const string& module, const string& command); + + private: + typedef std::map CommandList; + typedef std::map HelpList; + + void start(); + void onRequest(const HttpRequest& req, HttpResponse* resp); + + HttpServer server_; + std::unique_ptr processInspector_; + std::unique_ptr performanceInspector_; + std::unique_ptr systemInspector_; + MutexLock mutex_; + std::map modules_ GUARDED_BY(mutex_); + std::map helps_ GUARDED_BY(mutex_); +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_INSPECT_INSPECTOR_H diff --git a/include/Third_Lib/muduo/net/inspect/PerformanceInspector.cc b/include/Third_Lib/muduo/net/inspect/PerformanceInspector.cc new file mode 100644 index 0000000..a0fb9e9 --- /dev/null +++ b/include/Third_Lib/muduo/net/inspect/PerformanceInspector.cc @@ -0,0 +1,106 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// + +#include "muduo/net/inspect/PerformanceInspector.h" +#include "muduo/base/FileUtil.h" +#include "muduo/base/LogStream.h" +#include "muduo/base/ProcessInfo.h" + +#include + +#ifdef HAVE_TCMALLOC +#include +#include + +using namespace muduo; +using namespace muduo::net; + +void PerformanceInspector::registerCommands(Inspector* ins) +{ + ins->add("pprof", "heap", PerformanceInspector::heap, "get heap information"); + ins->add("pprof", "growth", PerformanceInspector::growth, "get heap growth information"); + ins->add("pprof", "profile", PerformanceInspector::profile, + "get cpu profiling information. CAUTION: blocking thread for 30 seconds!"); + ins->add("pprof", "cmdline", PerformanceInspector::cmdline, "get command line"); + ins->add("pprof", "memstats", PerformanceInspector::memstats, "get memory stats"); + ins->add("pprof", "memhistogram", PerformanceInspector::memhistogram, "get memory histogram"); + ins->add("pprof", "releasefreememory", PerformanceInspector::releaseFreeMemory, "release free memory"); +} + +string PerformanceInspector::heap(HttpRequest::Method, const Inspector::ArgList&) +{ + std::string result; + MallocExtension::instance()->GetHeapSample(&result); + return string(result.data(), result.size()); +} + +string PerformanceInspector::growth(HttpRequest::Method, const Inspector::ArgList&) +{ + std::string result; + MallocExtension::instance()->GetHeapGrowthStacks(&result); + return string(result.data(), result.size()); +} + +string PerformanceInspector::profile(HttpRequest::Method, const Inspector::ArgList&) +{ + string filename = "/tmp/" + ProcessInfo::procname(); + filename += "."; + filename += ProcessInfo::pidString(); + filename += "."; + filename += Timestamp::now().toString(); + filename += ".profile"; + + string profile; + if (ProfilerStart(filename.c_str())) + { + // FIXME: async + CurrentThread::sleepUsec(30 * 1000 * 1000); + ProfilerStop(); + FileUtil::readFile(filename, 1024*1024, &profile, NULL, NULL); + ::unlink(filename.c_str()); + } + return profile; +} + +string PerformanceInspector::cmdline(HttpRequest::Method, const Inspector::ArgList&) +{ + return ""; +} + +string PerformanceInspector::memstats(HttpRequest::Method, const Inspector::ArgList&) +{ + char buf[1024*64]; + MallocExtension::instance()->GetStats(buf, sizeof buf); + return buf; +} + +string PerformanceInspector::memhistogram(HttpRequest::Method, const Inspector::ArgList&) +{ + int blocks = 0; + size_t total = 0; + int histogram[kMallocHistogramSize] = { 0, }; + + MallocExtension::instance()->MallocMemoryStats(&blocks, &total, histogram); + LogStream s; + s << "blocks " << blocks << "\ntotal " << total << "\n"; + for (int i = 0; i < kMallocHistogramSize; ++i) + s << i << " " << histogram[i] << "\n"; + return s.buffer().toString(); +} + +string PerformanceInspector::releaseFreeMemory(HttpRequest::Method, const Inspector::ArgList&) +{ + char buf[256]; + snprintf(buf, sizeof buf, "memory release rate: %f\nAll free memory released.\n", + MallocExtension::instance()->GetMemoryReleaseRate()); + MallocExtension::instance()->ReleaseFreeMemory(); + return buf; +} + +#endif diff --git a/include/Third_Lib/muduo/net/inspect/PerformanceInspector.h b/include/Third_Lib/muduo/net/inspect/PerformanceInspector.h new file mode 100644 index 0000000..2416824 --- /dev/null +++ b/include/Third_Lib/muduo/net/inspect/PerformanceInspector.h @@ -0,0 +1,40 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_INSPECT_PERFORMANCEINSPECTOR_H +#define MUDUO_NET_INSPECT_PERFORMANCEINSPECTOR_H + +#include "muduo/net/inspect/Inspector.h" + +namespace muduo +{ +namespace net +{ + +class PerformanceInspector : noncopyable +{ + public: + void registerCommands(Inspector* ins); + + static string heap(HttpRequest::Method, const Inspector::ArgList&); + static string growth(HttpRequest::Method, const Inspector::ArgList&); + static string profile(HttpRequest::Method, const Inspector::ArgList&); + static string cmdline(HttpRequest::Method, const Inspector::ArgList&); + static string memstats(HttpRequest::Method, const Inspector::ArgList&); + static string memhistogram(HttpRequest::Method, const Inspector::ArgList&); + static string releaseFreeMemory(HttpRequest::Method, const Inspector::ArgList&); + + static string symbol(HttpRequest::Method, const Inspector::ArgList&); +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_INSPECT_PERFORMANCEINSPECTOR_H diff --git a/include/Third_Lib/muduo/net/inspect/ProcessInspector.cc b/include/Third_Lib/muduo/net/inspect/ProcessInspector.cc new file mode 100644 index 0000000..d89f0ce --- /dev/null +++ b/include/Third_Lib/muduo/net/inspect/ProcessInspector.cc @@ -0,0 +1,239 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// + +#include "muduo/net/inspect/ProcessInspector.h" +#include "muduo/base/FileUtil.h" +#include "muduo/base/ProcessInfo.h" +#include +#include +#include +#include + +using namespace muduo; +using namespace muduo::net; + +namespace muduo +{ +namespace inspect +{ + +string uptime(Timestamp now, Timestamp start, bool showMicroseconds) +{ + char buf[256]; + int64_t age = now.microSecondsSinceEpoch() - start.microSecondsSinceEpoch(); + int seconds = static_cast(age / Timestamp::kMicroSecondsPerSecond); + int days = seconds/86400; + int hours = (seconds % 86400) / 3600; + int minutes = (seconds % 3600) / 60; + if (showMicroseconds) + { + int microseconds = static_cast(age % Timestamp::kMicroSecondsPerSecond); + snprintf(buf, sizeof buf, "%d days %02d:%02d:%02d.%06d", + days, hours, minutes, seconds % 60, microseconds); + } + else + { + snprintf(buf, sizeof buf, "%d days %02d:%02d:%02d", + days, hours, minutes, seconds % 60); + } + return buf; +} + +long getLong(const string& procStatus, const char* key) +{ + long result = 0; + size_t pos = procStatus.find(key); + if (pos != string::npos) + { + result = ::atol(procStatus.c_str() + pos + strlen(key)); + } + return result; +} + +string getProcessName(const string& procStatus) +{ + string result; + size_t pos = procStatus.find("Name:"); + if (pos != string::npos) + { + pos += strlen("Name:"); + while (procStatus[pos] == '\t') + ++pos; + size_t eol = pos; + while (procStatus[eol] != '\n') + ++eol; + result = procStatus.substr(pos, eol-pos); + } + return result; +} + +StringPiece next(StringPiece data) +{ + const char* sp = static_cast(::memchr(data.data(), ' ', data.size())); + if (sp) + { + data.remove_prefix(static_cast(sp+1-data.begin())); + return data; + } + return ""; +} + +ProcessInfo::CpuTime getCpuTime(StringPiece data) +{ + ProcessInfo::CpuTime t; + + for (int i = 0; i < 10; ++i) + { + data = next(data); + } + long utime = strtol(data.data(), NULL, 10); + data = next(data); + long stime = strtol(data.data(), NULL, 10); + const double hz = static_cast(ProcessInfo::clockTicksPerSecond()); + t.userSeconds = static_cast(utime) / hz; + t.systemSeconds = static_cast(stime) / hz; + return t; +} + +int stringPrintf(string* out, const char* fmt, ...) __attribute__ ((format (printf, 2, 3))); + +int stringPrintf(string* out, const char* fmt, ...) +{ + char buf[256]; + va_list args; + va_start(args, fmt); + int ret = vsnprintf(buf, sizeof buf, fmt, args); + va_end(args); + out->append(buf); + return ret; +} + +} // namespace inspect +} // namespace muduo + +using namespace muduo::inspect; + +string ProcessInspector::username_ = ProcessInfo::username(); + +void ProcessInspector::registerCommands(Inspector* ins) +{ + ins->add("proc", "overview", ProcessInspector::overview, "print basic overview"); + ins->add("proc", "pid", ProcessInspector::pid, "print pid"); + ins->add("proc", "status", ProcessInspector::procStatus, "print /proc/self/status"); + // ins->add("proc", "opened_files", ProcessInspector::openedFiles, "count /proc/self/fd"); + ins->add("proc", "threads", ProcessInspector::threads, "list /proc/self/task"); +} + +string ProcessInspector::overview(HttpRequest::Method, const Inspector::ArgList&) +{ + string result; + result.reserve(1024); + Timestamp now = Timestamp::now(); + result += "Page generated at "; + result += now.toFormattedString(); + result += " (UTC)\nStarted at "; + result += ProcessInfo::startTime().toFormattedString(); + result += " (UTC), up for "; + result += uptime(now, ProcessInfo::startTime(), true/* show microseconds */); + result += "\n"; + + string procStatus = ProcessInfo::procStatus(); + result += getProcessName(procStatus); + result += " ("; + result += ProcessInfo::exePath(); + result += ") running as "; + result += username_; + result += " on "; + result += ProcessInfo::hostname(); // cache ? + result += "\n"; + + if (ProcessInfo::isDebugBuild()) + { + result += "WARNING: debug build!\n"; + } + + stringPrintf(&result, "pid %d, num of threads %ld, bits %zd\n", + ProcessInfo::pid(), getLong(procStatus, "Threads:"), CHAR_BIT * sizeof(void*)); + + result += "Virtual memory: "; + stringPrintf(&result, "%.3f MiB, ", + static_cast(getLong(procStatus, "VmSize:")) / 1024.0); + + result += "RSS memory: "; + stringPrintf(&result, "%.3f MiB\n", + static_cast(getLong(procStatus, "VmRSS:")) / 1024.0); + + // FIXME: VmData: + + stringPrintf(&result, "Opened files: %d, limit: %d\n", + ProcessInfo::openedFiles(), ProcessInfo::maxOpenFiles()); + + // string procStat = ProcessInfo::procStat(); + + /* + stringPrintf(&result, "ppid %ld\n", getStatField(procStat, 0)); + stringPrintf(&result, "pgid %ld\n", getStatField(procStat, 1)); + */ + + ProcessInfo::CpuTime t = ProcessInfo::cpuTime(); + stringPrintf(&result, "User time: %12.3fs\nSys time: %12.3fs\n", + t.userSeconds, t.systemSeconds); + + // FIXME: add context switches + + return result; +} + +string ProcessInspector::pid(HttpRequest::Method, const Inspector::ArgList&) +{ + char buf[32]; + snprintf(buf, sizeof buf, "%d", ProcessInfo::pid()); + return buf; +} + +string ProcessInspector::procStatus(HttpRequest::Method, const Inspector::ArgList&) +{ + return ProcessInfo::procStatus(); +} + +string ProcessInspector::openedFiles(HttpRequest::Method, const Inspector::ArgList&) +{ + char buf[32]; + snprintf(buf, sizeof buf, "%d", ProcessInfo::openedFiles()); + return buf; +} + +string ProcessInspector::threads(HttpRequest::Method, const Inspector::ArgList&) +{ + std::vector threads = ProcessInfo::threads(); + string result = " TID NAME S User Time System Time\n"; + result.reserve(threads.size() * 64); + string stat; + for (pid_t tid : threads) + { + char buf[256]; + snprintf(buf, sizeof buf, "/proc/%d/task/%d/stat", ProcessInfo::pid(), tid); + if (FileUtil::readFile(buf, 65536, &stat) == 0) + { + StringPiece name = ProcessInfo::procname(stat); + const char* rp = name.end(); + assert(*rp == ')'); + const char* state = rp + 2; + *const_cast(rp) = '\0'; // don't do this at home + StringPiece data(stat); + data.remove_prefix(static_cast(state - data.data() + 2)); + ProcessInfo::CpuTime t = getCpuTime(data); + snprintf(buf, sizeof buf, "%5d %-16s %c %12.3f %12.3f\n", + tid, name.data(), *state, t.userSeconds, t.systemSeconds); + result += buf; + } + } + return result; +} + diff --git a/include/Third_Lib/muduo/net/inspect/ProcessInspector.h b/include/Third_Lib/muduo/net/inspect/ProcessInspector.h new file mode 100644 index 0000000..f1df478 --- /dev/null +++ b/include/Third_Lib/muduo/net/inspect/ProcessInspector.h @@ -0,0 +1,38 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_INSPECT_PROCESSINSPECTOR_H +#define MUDUO_NET_INSPECT_PROCESSINSPECTOR_H + +#include "muduo/net/inspect/Inspector.h" + +namespace muduo +{ +namespace net +{ + +class ProcessInspector : noncopyable +{ + public: + void registerCommands(Inspector* ins); + + static string overview(HttpRequest::Method, const Inspector::ArgList&); + static string pid(HttpRequest::Method, const Inspector::ArgList&); + static string procStatus(HttpRequest::Method, const Inspector::ArgList&); + static string openedFiles(HttpRequest::Method, const Inspector::ArgList&); + static string threads(HttpRequest::Method, const Inspector::ArgList&); + + static string username_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_INSPECT_PROCESSINSPECTOR_H diff --git a/include/Third_Lib/muduo/net/inspect/SystemInspector.cc b/include/Third_Lib/muduo/net/inspect/SystemInspector.cc new file mode 100644 index 0000000..fb45e76 --- /dev/null +++ b/include/Third_Lib/muduo/net/inspect/SystemInspector.cc @@ -0,0 +1,132 @@ +// Copyright 2014, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// + +#include "muduo/net/inspect/SystemInspector.h" +#include "muduo/base/FileUtil.h" + +#include + +using namespace muduo; +using namespace muduo::net; + +namespace muduo +{ +namespace inspect +{ +string uptime(Timestamp now, Timestamp start, bool showMicroseconds); +long getLong(const string& content, const char* key); +int stringPrintf(string* out, const char* fmt, ...) __attribute__ ((format (printf, 2, 3))); +} +} + +using namespace muduo::inspect; + +void SystemInspector::registerCommands(Inspector* ins) +{ + ins->add("sys", "overview", SystemInspector::overview, "print system overview"); + ins->add("sys", "loadavg", SystemInspector::loadavg, "print /proc/loadavg"); + ins->add("sys", "version", SystemInspector::version, "print /proc/version"); + ins->add("sys", "cpuinfo", SystemInspector::cpuinfo, "print /proc/cpuinfo"); + ins->add("sys", "meminfo", SystemInspector::meminfo, "print /proc/meminfo"); + ins->add("sys", "stat", SystemInspector::stat, "print /proc/stat"); +} + +string SystemInspector::loadavg(HttpRequest::Method, const Inspector::ArgList&) +{ + string loadavg; + FileUtil::readFile("/proc/loadavg", 65536, &loadavg); + return loadavg; +} + +string SystemInspector::version(HttpRequest::Method, const Inspector::ArgList&) +{ + string version; + FileUtil::readFile("/proc/version", 65536, &version); + return version; +} + +string SystemInspector::cpuinfo(HttpRequest::Method, const Inspector::ArgList&) +{ + string cpuinfo; + FileUtil::readFile("/proc/cpuinfo", 65536, &cpuinfo); + return cpuinfo; +} + +string SystemInspector::meminfo(HttpRequest::Method, const Inspector::ArgList&) +{ + string meminfo; + FileUtil::readFile("/proc/meminfo", 65536, &meminfo); + return meminfo; +} + +string SystemInspector::stat(HttpRequest::Method, const Inspector::ArgList&) +{ + string stat; + FileUtil::readFile("/proc/stat", 65536, &stat); + return stat; +} + +string SystemInspector::overview(HttpRequest::Method, const Inspector::ArgList&) +{ + string result; + result.reserve(1024); + Timestamp now = Timestamp::now(); + result += "Page generated at "; + result += now.toFormattedString(); + result += " (UTC)\n"; + // Hardware and OS + { + struct utsname un; + if (::uname(&un) == 0) + { + stringPrintf(&result, "Hostname: %s\n", un.nodename); + stringPrintf(&result, "Machine: %s\n", un.machine); + stringPrintf(&result, "OS: %s %s %s\n", un.sysname, un.release, un.version); + } + } + string stat; + FileUtil::readFile("/proc/stat", 65536, &stat); + Timestamp bootTime(Timestamp::kMicroSecondsPerSecond * getLong(stat, "btime ")); + result += "Boot time: "; + result += bootTime.toFormattedString(false /* show microseconds */); + result += " (UTC)\n"; + result += "Up time: "; + result += uptime(now, bootTime, false /* show microseconds */); + result += "\n"; + + // CPU load + { + string loadavg; + FileUtil::readFile("/proc/loadavg", 65536, &loadavg); + stringPrintf(&result, "Processes created: %ld\n", getLong(stat, "processes ")); + stringPrintf(&result, "Loadavg: %s\n", loadavg.c_str()); + } + + // Memory + { + string meminfo; + FileUtil::readFile("/proc/meminfo", 65536, &meminfo); + long total_kb = getLong(meminfo, "MemTotal:"); + long free_kb = getLong(meminfo, "MemFree:"); + long buffers_kb = getLong(meminfo, "Buffers:"); + long cached_kb = getLong(meminfo, "Cached:"); + + stringPrintf(&result, "Total Memory: %6ld MiB\n", total_kb / 1024); + stringPrintf(&result, "Free Memory: %6ld MiB\n", free_kb / 1024); + stringPrintf(&result, "Buffers: %6ld MiB\n", buffers_kb / 1024); + stringPrintf(&result, "Cached: %6ld MiB\n", cached_kb / 1024); + stringPrintf(&result, "Real Used: %6ld MiB\n", (total_kb - free_kb - buffers_kb - cached_kb) / 1024); + stringPrintf(&result, "Real Free: %6ld MiB\n", (free_kb + buffers_kb + cached_kb) / 1024); + + // Swap + } + // Disk + // Network + return result; +} diff --git a/include/Third_Lib/muduo/net/inspect/SystemInspector.h b/include/Third_Lib/muduo/net/inspect/SystemInspector.h new file mode 100644 index 0000000..8f2a604 --- /dev/null +++ b/include/Third_Lib/muduo/net/inspect/SystemInspector.h @@ -0,0 +1,37 @@ +// Copyright 2014, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_INSPECT_SYSTEMINSPECTOR_H +#define MUDUO_NET_INSPECT_SYSTEMINSPECTOR_H + +#include "muduo/net/inspect/Inspector.h" + +namespace muduo +{ +namespace net +{ + +class SystemInspector : noncopyable +{ + public: + void registerCommands(Inspector* ins); + + static string overview(HttpRequest::Method, const Inspector::ArgList&); + static string loadavg(HttpRequest::Method, const Inspector::ArgList&); + static string version(HttpRequest::Method, const Inspector::ArgList&); + static string cpuinfo(HttpRequest::Method, const Inspector::ArgList&); + static string meminfo(HttpRequest::Method, const Inspector::ArgList&); + static string stat(HttpRequest::Method, const Inspector::ArgList&); +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_INSPECT_SYSTEMINSPECTOR_H diff --git a/include/Third_Lib/muduo/net/inspect/tests/BUILD.bazel b/include/Third_Lib/muduo/net/inspect/tests/BUILD.bazel new file mode 100644 index 0000000..e7f0ca7 --- /dev/null +++ b/include/Third_Lib/muduo/net/inspect/tests/BUILD.bazel @@ -0,0 +1,7 @@ +cc_binary( + name = "inspector", + srcs = ["Inspector_test.cc"], + deps = [ + "//muduo/net/inspect", + ], +) diff --git a/include/Third_Lib/muduo/net/inspect/tests/Inspector_test.cc b/include/Third_Lib/muduo/net/inspect/tests/Inspector_test.cc new file mode 100644 index 0000000..20025ff --- /dev/null +++ b/include/Third_Lib/muduo/net/inspect/tests/Inspector_test.cc @@ -0,0 +1,15 @@ +#include "muduo/net/inspect/Inspector.h" +#include "muduo/net/EventLoop.h" +#include "muduo/net/EventLoopThread.h" + +using namespace muduo; +using namespace muduo::net; + +int main() +{ + EventLoop loop; + EventLoopThread t; + Inspector ins(t.startLoop(), InetAddress(12345), "test"); + loop.loop(); +} + diff --git a/include/Third_Lib/muduo/net/poller/DefaultPoller.cc b/include/Third_Lib/muduo/net/poller/DefaultPoller.cc new file mode 100644 index 0000000..5ea0d03 --- /dev/null +++ b/include/Third_Lib/muduo/net/poller/DefaultPoller.cc @@ -0,0 +1,27 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/Poller.h" +#include "muduo/net/poller/PollPoller.h" +#include "muduo/net/poller/EPollPoller.h" + +#include + +using namespace muduo::net; + +Poller* Poller::newDefaultPoller(EventLoop* loop) +{ + if (::getenv("MUDUO_USE_POLL")) + { + return new PollPoller(loop); + } + else + { + return new EPollPoller(loop); + } +} diff --git a/include/Third_Lib/muduo/net/poller/EPollPoller.cc b/include/Third_Lib/muduo/net/poller/EPollPoller.cc new file mode 100644 index 0000000..b2f913a --- /dev/null +++ b/include/Third_Lib/muduo/net/poller/EPollPoller.cc @@ -0,0 +1,208 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/poller/EPollPoller.h" + +#include "muduo/base/Logging.h" +#include "muduo/net/Channel.h" + +#include +#include +#include +#include +#include + +using namespace muduo; +using namespace muduo::net; + +// On Linux, the constants of poll(2) and epoll(4) +// are expected to be the same. +static_assert(EPOLLIN == POLLIN, "epoll uses same flag values as poll"); +static_assert(EPOLLPRI == POLLPRI, "epoll uses same flag values as poll"); +static_assert(EPOLLOUT == POLLOUT, "epoll uses same flag values as poll"); +static_assert(EPOLLRDHUP == POLLRDHUP, "epoll uses same flag values as poll"); +static_assert(EPOLLERR == POLLERR, "epoll uses same flag values as poll"); +static_assert(EPOLLHUP == POLLHUP, "epoll uses same flag values as poll"); + +namespace +{ +const int kNew = -1; +const int kAdded = 1; +const int kDeleted = 2; +} + +EPollPoller::EPollPoller(EventLoop* loop) + : Poller(loop), + epollfd_(::epoll_create1(EPOLL_CLOEXEC)), + events_(kInitEventListSize) +{ + if (epollfd_ < 0) + { + LOG_SYSFATAL << "EPollPoller::EPollPoller"; + } +} + +EPollPoller::~EPollPoller() +{ + ::close(epollfd_); +} + +Timestamp EPollPoller::poll(int timeoutMs, ChannelList* activeChannels) +{ + LOG_TRACE << "fd total count " << channels_.size(); + int numEvents = ::epoll_wait(epollfd_, + &*events_.begin(), + static_cast(events_.size()), + timeoutMs); + int savedErrno = errno; + Timestamp now(Timestamp::now()); + if (numEvents > 0) + { + LOG_TRACE << numEvents << " events happened"; + fillActiveChannels(numEvents, activeChannels); + if (implicit_cast(numEvents) == events_.size()) + { + events_.resize(events_.size()*2); + } + } + else if (numEvents == 0) + { + LOG_TRACE << "nothing happened"; + } + else + { + // error happens, log uncommon ones + if (savedErrno != EINTR) + { + errno = savedErrno; + LOG_SYSERR << "EPollPoller::poll()"; + } + } + return now; +} + +void EPollPoller::fillActiveChannels(int numEvents, + ChannelList* activeChannels) const +{ + assert(implicit_cast(numEvents) <= events_.size()); + for (int i = 0; i < numEvents; ++i) + { + Channel* channel = static_cast(events_[i].data.ptr); +#ifndef NDEBUG + int fd = channel->fd(); + ChannelMap::const_iterator it = channels_.find(fd); + assert(it != channels_.end()); + assert(it->second == channel); +#endif + channel->set_revents(events_[i].events); + activeChannels->push_back(channel); + } +} + +void EPollPoller::updateChannel(Channel* channel) +{ + Poller::assertInLoopThread(); + const int index = channel->index(); + LOG_TRACE << "fd = " << channel->fd() + << " events = " << channel->events() << " index = " << index; + if (index == kNew || index == kDeleted) + { + // a new one, add with EPOLL_CTL_ADD + int fd = channel->fd(); + if (index == kNew) + { + assert(channels_.find(fd) == channels_.end()); + channels_[fd] = channel; + } + else // index == kDeleted + { + assert(channels_.find(fd) != channels_.end()); + assert(channels_[fd] == channel); + } + + channel->set_index(kAdded); + update(EPOLL_CTL_ADD, channel); + } + else + { + // update existing one with EPOLL_CTL_MOD/DEL + int fd = channel->fd(); + (void)fd; + assert(channels_.find(fd) != channels_.end()); + assert(channels_[fd] == channel); + assert(index == kAdded); + if (channel->isNoneEvent()) + { + update(EPOLL_CTL_DEL, channel); + channel->set_index(kDeleted); + } + else + { + update(EPOLL_CTL_MOD, channel); + } + } +} + +void EPollPoller::removeChannel(Channel* channel) +{ + Poller::assertInLoopThread(); + int fd = channel->fd(); + LOG_TRACE << "fd = " << fd; + assert(channels_.find(fd) != channels_.end()); + assert(channels_[fd] == channel); + assert(channel->isNoneEvent()); + int index = channel->index(); + assert(index == kAdded || index == kDeleted); + size_t n = channels_.erase(fd); + (void)n; + assert(n == 1); + + if (index == kAdded) + { + update(EPOLL_CTL_DEL, channel); + } + channel->set_index(kNew); +} + +void EPollPoller::update(int operation, Channel* channel) +{ + struct epoll_event event; + memZero(&event, sizeof event); + event.events = channel->events(); + event.data.ptr = channel; + int fd = channel->fd(); + LOG_TRACE << "epoll_ctl op = " << operationToString(operation) + << " fd = " << fd << " event = { " << channel->eventsToString() << " }"; + if (::epoll_ctl(epollfd_, operation, fd, &event) < 0) + { + if (operation == EPOLL_CTL_DEL) + { + LOG_SYSERR << "epoll_ctl op =" << operationToString(operation) << " fd =" << fd; + } + else + { + LOG_SYSFATAL << "epoll_ctl op =" << operationToString(operation) << " fd =" << fd; + } + } +} + +const char* EPollPoller::operationToString(int op) +{ + switch (op) + { + case EPOLL_CTL_ADD: + return "ADD"; + case EPOLL_CTL_DEL: + return "DEL"; + case EPOLL_CTL_MOD: + return "MOD"; + default: + assert(false && "ERROR op"); + return "Unknown Operation"; + } +} diff --git a/include/Third_Lib/muduo/net/poller/EPollPoller.h b/include/Third_Lib/muduo/net/poller/EPollPoller.h new file mode 100644 index 0000000..c112f18 --- /dev/null +++ b/include/Third_Lib/muduo/net/poller/EPollPoller.h @@ -0,0 +1,55 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_POLLER_EPOLLPOLLER_H +#define MUDUO_NET_POLLER_EPOLLPOLLER_H + +#include "muduo/net/Poller.h" + +#include + +struct epoll_event; + +namespace muduo +{ +namespace net +{ + +/// +/// IO Multiplexing with epoll(4). +/// +class EPollPoller : public Poller +{ + public: + EPollPoller(EventLoop* loop); + ~EPollPoller() override; + + Timestamp poll(int timeoutMs, ChannelList* activeChannels) override; + void updateChannel(Channel* channel) override; + void removeChannel(Channel* channel) override; + + private: + static const int kInitEventListSize = 16; + + static const char* operationToString(int op); + + void fillActiveChannels(int numEvents, + ChannelList* activeChannels) const; + void update(int operation, Channel* channel); + + typedef std::vector EventList; + + int epollfd_; + EventList events_; +}; + +} // namespace net +} // namespace muduo +#endif // MUDUO_NET_POLLER_EPOLLPOLLER_H diff --git a/include/Third_Lib/muduo/net/poller/PollPoller.cc b/include/Third_Lib/muduo/net/poller/PollPoller.cc new file mode 100644 index 0000000..7933079 --- /dev/null +++ b/include/Third_Lib/muduo/net/poller/PollPoller.cc @@ -0,0 +1,141 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/poller/PollPoller.h" + +#include "muduo/base/Logging.h" +#include "muduo/base/Types.h" +#include "muduo/net/Channel.h" + +#include +#include +#include + +using namespace muduo; +using namespace muduo::net; + +PollPoller::PollPoller(EventLoop* loop) + : Poller(loop) +{ +} + +PollPoller::~PollPoller() = default; + +Timestamp PollPoller::poll(int timeoutMs, ChannelList* activeChannels) +{ + // XXX pollfds_ shouldn't change + int numEvents = ::poll(&*pollfds_.begin(), pollfds_.size(), timeoutMs); + int savedErrno = errno; + Timestamp now(Timestamp::now()); + if (numEvents > 0) + { + LOG_TRACE << numEvents << " events happened"; + fillActiveChannels(numEvents, activeChannels); + } + else if (numEvents == 0) + { + LOG_TRACE << " nothing happened"; + } + else + { + if (savedErrno != EINTR) + { + errno = savedErrno; + LOG_SYSERR << "PollPoller::poll()"; + } + } + return now; +} + +void PollPoller::fillActiveChannels(int numEvents, + ChannelList* activeChannels) const +{ + for (PollFdList::const_iterator pfd = pollfds_.begin(); + pfd != pollfds_.end() && numEvents > 0; ++pfd) + { + if (pfd->revents > 0) + { + --numEvents; + ChannelMap::const_iterator ch = channels_.find(pfd->fd); + assert(ch != channels_.end()); + Channel* channel = ch->second; + assert(channel->fd() == pfd->fd); + channel->set_revents(pfd->revents); + // pfd->revents = 0; + activeChannels->push_back(channel); + } + } +} + +void PollPoller::updateChannel(Channel* channel) +{ + Poller::assertInLoopThread(); + LOG_TRACE << "fd = " << channel->fd() << " events = " << channel->events(); + if (channel->index() < 0) + { + // a new one, add to pollfds_ + assert(channels_.find(channel->fd()) == channels_.end()); + struct pollfd pfd; + pfd.fd = channel->fd(); + pfd.events = static_cast(channel->events()); + pfd.revents = 0; + pollfds_.push_back(pfd); + int idx = static_cast(pollfds_.size())-1; + channel->set_index(idx); + channels_[pfd.fd] = channel; + } + else + { + // update existing one + assert(channels_.find(channel->fd()) != channels_.end()); + assert(channels_[channel->fd()] == channel); + int idx = channel->index(); + assert(0 <= idx && idx < static_cast(pollfds_.size())); + struct pollfd& pfd = pollfds_[idx]; + assert(pfd.fd == channel->fd() || pfd.fd == -channel->fd()-1); + pfd.fd = channel->fd(); + pfd.events = static_cast(channel->events()); + pfd.revents = 0; + if (channel->isNoneEvent()) + { + // ignore this pollfd + pfd.fd = -channel->fd()-1; + } + } +} + +void PollPoller::removeChannel(Channel* channel) +{ + Poller::assertInLoopThread(); + LOG_TRACE << "fd = " << channel->fd(); + assert(channels_.find(channel->fd()) != channels_.end()); + assert(channels_[channel->fd()] == channel); + assert(channel->isNoneEvent()); + int idx = channel->index(); + assert(0 <= idx && idx < static_cast(pollfds_.size())); + const struct pollfd& pfd = pollfds_[idx]; (void)pfd; + assert(pfd.fd == -channel->fd()-1 && pfd.events == channel->events()); + size_t n = channels_.erase(channel->fd()); + assert(n == 1); (void)n; + if (implicit_cast(idx) == pollfds_.size()-1) + { + pollfds_.pop_back(); + } + else + { + int channelAtEnd = pollfds_.back().fd; + iter_swap(pollfds_.begin()+idx, pollfds_.end()-1); + if (channelAtEnd < 0) + { + channelAtEnd = -channelAtEnd-1; + } + channels_[channelAtEnd]->set_index(idx); + pollfds_.pop_back(); + } +} + diff --git a/include/Third_Lib/muduo/net/poller/PollPoller.h b/include/Third_Lib/muduo/net/poller/PollPoller.h new file mode 100644 index 0000000..4657534 --- /dev/null +++ b/include/Third_Lib/muduo/net/poller/PollPoller.h @@ -0,0 +1,49 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is an internal header file, you should not include this. + +#ifndef MUDUO_NET_POLLER_POLLPOLLER_H +#define MUDUO_NET_POLLER_POLLPOLLER_H + +#include "muduo/net/Poller.h" + +#include + +struct pollfd; + +namespace muduo +{ +namespace net +{ + +/// +/// IO Multiplexing with poll(2). +/// +class PollPoller : public Poller +{ + public: + + PollPoller(EventLoop* loop); + ~PollPoller() override; + + Timestamp poll(int timeoutMs, ChannelList* activeChannels) override; + void updateChannel(Channel* channel) override; + void removeChannel(Channel* channel) override; + + private: + void fillActiveChannels(int numEvents, + ChannelList* activeChannels) const; + + typedef std::vector PollFdList; + PollFdList pollfds_; +}; + +} // namespace net +} // namespace muduo +#endif // MUDUO_NET_POLLER_POLLPOLLER_H diff --git a/include/Third_Lib/muduo/net/protobuf/BufferStream.h b/include/Third_Lib/muduo/net/protobuf/BufferStream.h new file mode 100644 index 0000000..322bc44 --- /dev/null +++ b/include/Third_Lib/muduo/net/protobuf/BufferStream.h @@ -0,0 +1,56 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. +#pragma once +#include "muduo/net/Buffer.h" +#include +namespace muduo +{ +namespace net +{ + +// FIXME: +// class BufferInputStream : google::protobuf::io::ZeroCopyInputStream +// { +// }; + +class BufferOutputStream : public google::protobuf::io::ZeroCopyOutputStream +{ + public: + BufferOutputStream(Buffer* buf) + : buffer_(CHECK_NOTNULL(buf)), + originalSize_(buffer_->readableBytes()) + { + } + + virtual bool Next(void** data, int* size) // override + { + buffer_->ensureWritableBytes(4096); + *data = buffer_->beginWrite(); + *size = static_cast(buffer_->writableBytes()); + buffer_->hasWritten(*size); + return true; + } + + virtual void BackUp(int count) // override + { + buffer_->unwrite(count); + } + + virtual int64_t ByteCount() const // override + { + return buffer_->readableBytes() - originalSize_; + } + + private: + Buffer* buffer_; + size_t originalSize_; +}; + +} +} diff --git a/include/Third_Lib/muduo/net/protobuf/CMakeLists.txt b/include/Third_Lib/muduo/net/protobuf/CMakeLists.txt new file mode 100644 index 0000000..a7e49d9 --- /dev/null +++ b/include/Third_Lib/muduo/net/protobuf/CMakeLists.txt @@ -0,0 +1,15 @@ +add_library(muduo_protobuf_codec ProtobufCodecLite.cc) +set_target_properties(muduo_protobuf_codec PROPERTIES COMPILE_FLAGS "-Wno-error=shadow") +target_link_libraries(muduo_protobuf_codec muduo_net protobuf z) + +#add_library(muduo_protobuf_codec_cpp11 ProtobufCodecLite.cc) +#set_target_properties(muduo_protobuf_codec_cpp11 PROPERTIES COMPILE_FLAGS "-std=c++0x -Wno-error=shadow") +#target_link_libraries(muduo_protobuf_codec_cpp11 muduo_net_cpp11 protobuf z) + + +install(TARGETS muduo_protobuf_codec DESTINATION lib) +#install(TARGETS muduo_protobuf_codec_cpp11 DESTINATION lib) + +file(GLOB HEADERS "*.h") +install(FILES ${HEADERS} DESTINATION include/muduo/net/protobuf) + diff --git a/include/Third_Lib/muduo/net/protobuf/ProtobufCodecLite.cc b/include/Third_Lib/muduo/net/protobuf/ProtobufCodecLite.cc new file mode 100644 index 0000000..9d406ee --- /dev/null +++ b/include/Third_Lib/muduo/net/protobuf/ProtobufCodecLite.cc @@ -0,0 +1,243 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/protobuf/ProtobufCodecLite.h" +// #include + +#include "muduo/base/Logging.h" +#include "muduo/net/Endian.h" +#include "muduo/net/TcpConnection.h" +#include "muduo/net/protorpc/google-inl.h" + +#include +#include + +using namespace muduo; +using namespace muduo::net; + +namespace +{ + int ProtobufVersionCheck() + { + GOOGLE_PROTOBUF_VERIFY_VERSION; + return 0; + } + int __attribute__ ((unused)) dummy = ProtobufVersionCheck(); +} + +void ProtobufCodecLite::send(const TcpConnectionPtr& conn, + const ::google::protobuf::Message& message) +{ + // FIXME: serialize to TcpConnection::outputBuffer() + muduo::net::Buffer buf; + fillEmptyBuffer(&buf, message); + conn->send(&buf); +} + +void ProtobufCodecLite::fillEmptyBuffer(muduo::net::Buffer* buf, + const google::protobuf::Message& message) +{ + assert(buf->readableBytes() == 0); + // FIXME: can we move serialization & checksum to other thread? + buf->append(tag_); + + int byte_size = serializeToBuffer(message, buf); + + int32_t checkSum = checksum(buf->peek(), static_cast(buf->readableBytes())); + buf->appendInt32(checkSum); + assert(buf->readableBytes() == tag_.size() + byte_size + kChecksumLen); (void) byte_size; + int32_t len = sockets::hostToNetwork32(static_cast(buf->readableBytes())); + buf->prepend(&len, sizeof len); +} + +void ProtobufCodecLite::onMessage(const TcpConnectionPtr& conn, + Buffer* buf, + Timestamp receiveTime) +{ + while (buf->readableBytes() >= static_cast(kMinMessageLen+kHeaderLen)) + { + const int32_t len = buf->peekInt32(); + if (len > kMaxMessageLen || len < kMinMessageLen) + { + errorCallback_(conn, buf, receiveTime, kInvalidLength); + break; + } + else if (buf->readableBytes() >= implicit_cast(kHeaderLen+len)) + { + if (rawCb_ && !rawCb_(conn, StringPiece(buf->peek(), kHeaderLen+len), receiveTime)) + { + buf->retrieve(kHeaderLen+len); + continue; + } + MessagePtr message(prototype_->New()); + // FIXME: can we move deserialization & callback to other thread? + ErrorCode errorCode = parse(buf->peek()+kHeaderLen, len, message.get()); + if (errorCode == kNoError) + { + // FIXME: try { } catch (...) { } + messageCallback_(conn, message, receiveTime); + buf->retrieve(kHeaderLen+len); + } + else + { + errorCallback_(conn, buf, receiveTime, errorCode); + break; + } + } + else + { + break; + } + } +} + +bool ProtobufCodecLite::parseFromBuffer(StringPiece buf, google::protobuf::Message* message) +{ + return message->ParseFromArray(buf.data(), buf.size()); +} + +int ProtobufCodecLite::serializeToBuffer(const google::protobuf::Message& message, Buffer* buf) +{ + // TODO: use BufferOutputStream + // BufferOutputStream os(buf); + // message.SerializeToZeroCopyStream(&os); + // return static_cast(os.ByteCount()); + + // code copied from MessageLite::SerializeToArray() and MessageLite::SerializePartialToArray(). + GOOGLE_DCHECK(message.IsInitialized()) << InitializationErrorMessage("serialize", message); + + /** + * 'ByteSize()' of message is deprecated in Protocol Buffers v3.4.0 firstly. But, till to v3.11.0, it just getting start to be marked by '__attribute__((deprecated()))'. + * So, here, v3.9.2 is selected as maximum version using 'ByteSize()' to avoid potential effect for previous muduo code/projects as far as possible. + * Note: All information above just INFER from + * 1) https://github.com/protocolbuffers/protobuf/releases/tag/v3.4.0 + * 2) MACRO in file 'include/google/protobuf/port_def.inc'. eg. '#define PROTOBUF_DEPRECATED_MSG(msg) __attribute__((deprecated(msg)))'. + * In addition, usage of 'ToIntSize()' comes from Impl of ByteSize() in new version's Protocol Buffers. + */ + + #if GOOGLE_PROTOBUF_VERSION > 3009002 + int byte_size = google::protobuf::internal::ToIntSize(message.ByteSizeLong()); + #else + int byte_size = message.ByteSize(); + #endif + buf->ensureWritableBytes(byte_size + kChecksumLen); + + uint8_t* start = reinterpret_cast(buf->beginWrite()); + uint8_t* end = message.SerializeWithCachedSizesToArray(start); + if (end - start != byte_size) + { + #if GOOGLE_PROTOBUF_VERSION > 3009002 + ByteSizeConsistencyError(byte_size, google::protobuf::internal::ToIntSize(message.ByteSizeLong()), static_cast(end - start)); + #else + ByteSizeConsistencyError(byte_size, message.ByteSize(), static_cast(end - start)); + #endif + } + buf->hasWritten(byte_size); + return byte_size; +} + +namespace +{ + const string kNoErrorStr = "NoError"; + const string kInvalidLengthStr = "InvalidLength"; + const string kCheckSumErrorStr = "CheckSumError"; + const string kInvalidNameLenStr = "InvalidNameLen"; + const string kUnknownMessageTypeStr = "UnknownMessageType"; + const string kParseErrorStr = "ParseError"; + const string kUnknownErrorStr = "UnknownError"; +} + +const string& ProtobufCodecLite::errorCodeToString(ErrorCode errorCode) +{ + switch (errorCode) + { + case kNoError: + return kNoErrorStr; + case kInvalidLength: + return kInvalidLengthStr; + case kCheckSumError: + return kCheckSumErrorStr; + case kInvalidNameLen: + return kInvalidNameLenStr; + case kUnknownMessageType: + return kUnknownMessageTypeStr; + case kParseError: + return kParseErrorStr; + default: + return kUnknownErrorStr; + } +} + +void ProtobufCodecLite::defaultErrorCallback(const TcpConnectionPtr& conn, + Buffer* buf, + Timestamp, + ErrorCode errorCode) +{ + LOG_ERROR << "ProtobufCodecLite::defaultErrorCallback - " << errorCodeToString(errorCode); + if (conn && conn->connected()) + { + conn->shutdown(); + } +} + +int32_t ProtobufCodecLite::asInt32(const char* buf) +{ + int32_t be32 = 0; + ::memcpy(&be32, buf, sizeof(be32)); + return sockets::networkToHost32(be32); +} + +int32_t ProtobufCodecLite::checksum(const void* buf, int len) +{ + return static_cast( + ::adler32(1, static_cast(buf), len)); +} + +bool ProtobufCodecLite::validateChecksum(const char* buf, int len) +{ + // check sum + int32_t expectedCheckSum = asInt32(buf + len - kChecksumLen); + int32_t checkSum = checksum(buf, len - kChecksumLen); + return checkSum == expectedCheckSum; +} + +ProtobufCodecLite::ErrorCode ProtobufCodecLite::parse(const char* buf, + int len, + ::google::protobuf::Message* message) +{ + ErrorCode error = kNoError; + + if (validateChecksum(buf, len)) + { + if (memcmp(buf, tag_.data(), tag_.size()) == 0) + { + // parse from buffer + const char* data = buf + tag_.size(); + int32_t dataLen = len - kChecksumLen - static_cast(tag_.size()); + if (parseFromBuffer(StringPiece(data, dataLen), message)) + { + error = kNoError; + } + else + { + error = kParseError; + } + } + else + { + error = kUnknownMessageType; + } + } + else + { + error = kCheckSumError; + } + + return error; +} + diff --git a/include/Third_Lib/muduo/net/protobuf/ProtobufCodecLite.h b/include/Third_Lib/muduo/net/protobuf/ProtobufCodecLite.h new file mode 100644 index 0000000..134ee7b --- /dev/null +++ b/include/Third_Lib/muduo/net/protobuf/ProtobufCodecLite.h @@ -0,0 +1,192 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +// For Protobuf codec supporting multiple message types, check +// examples/protobuf/codec + +#ifndef MUDUO_NET_PROTOBUF_PROTOBUFCODECLITE_H +#define MUDUO_NET_PROTOBUF_PROTOBUFCODECLITE_H + +#include "muduo/base/noncopyable.h" +#include "muduo/base/StringPiece.h" +#include "muduo/base/Timestamp.h" +#include "muduo/net/Callbacks.h" + +#include +#include + +namespace google +{ +namespace protobuf +{ +class Message; +} +} + +namespace muduo +{ +namespace net +{ + +typedef std::shared_ptr MessagePtr; + +// wire format +// +// Field Length Content +// +// size 4-byte M+N+4 +// tag M-byte could be "RPC0", etc. +// payload N-byte +// checksum 4-byte adler32 of tag+payload +// +// This is an internal class, you should use ProtobufCodecT instead. +class ProtobufCodecLite : noncopyable +{ + public: + const static int kHeaderLen = sizeof(int32_t); + const static int kChecksumLen = sizeof(int32_t); + const static int kMaxMessageLen = 64*1024*1024; // same as codec_stream.h kDefaultTotalBytesLimit + + enum ErrorCode + { + kNoError = 0, + kInvalidLength, + kCheckSumError, + kInvalidNameLen, + kUnknownMessageType, + kParseError, + }; + + // return false to stop parsing protobuf message + typedef std::function RawMessageCallback; + + typedef std::function ProtobufMessageCallback; + + typedef std::function ErrorCallback; + + ProtobufCodecLite(const ::google::protobuf::Message* prototype, + StringPiece tagArg, + const ProtobufMessageCallback& messageCb, + const RawMessageCallback& rawCb = RawMessageCallback(), + const ErrorCallback& errorCb = defaultErrorCallback) + : prototype_(prototype), + tag_(tagArg.as_string()), + messageCallback_(messageCb), + rawCb_(rawCb), + errorCallback_(errorCb), + kMinMessageLen(tagArg.size() + kChecksumLen) + { + } + + virtual ~ProtobufCodecLite() = default; + + const string& tag() const { return tag_; } + + void send(const TcpConnectionPtr& conn, + const ::google::protobuf::Message& message); + + void onMessage(const TcpConnectionPtr& conn, + Buffer* buf, + Timestamp receiveTime); + + virtual bool parseFromBuffer(StringPiece buf, google::protobuf::Message* message); + virtual int serializeToBuffer(const google::protobuf::Message& message, Buffer* buf); + + static const string& errorCodeToString(ErrorCode errorCode); + + // public for unit tests + ErrorCode parse(const char* buf, int len, ::google::protobuf::Message* message); + void fillEmptyBuffer(muduo::net::Buffer* buf, const google::protobuf::Message& message); + + static int32_t checksum(const void* buf, int len); + static bool validateChecksum(const char* buf, int len); + static int32_t asInt32(const char* buf); + static void defaultErrorCallback(const TcpConnectionPtr&, + Buffer*, + Timestamp, + ErrorCode); + + private: + const ::google::protobuf::Message* prototype_; + const string tag_; + ProtobufMessageCallback messageCallback_; + RawMessageCallback rawCb_; + ErrorCallback errorCallback_; + const int kMinMessageLen; +}; + +template // TAG must be a variable with external linkage, not a string literal +class ProtobufCodecLiteT +{ + static_assert(std::is_base_of::value, "CODEC should be derived from ProtobufCodecLite"); + public: + typedef std::shared_ptr ConcreteMessagePtr; + typedef std::function ProtobufMessageCallback; + typedef ProtobufCodecLite::RawMessageCallback RawMessageCallback; + typedef ProtobufCodecLite::ErrorCallback ErrorCallback; + + explicit ProtobufCodecLiteT(const ProtobufMessageCallback& messageCb, + const RawMessageCallback& rawCb = RawMessageCallback(), + const ErrorCallback& errorCb = ProtobufCodecLite::defaultErrorCallback) + : messageCallback_(messageCb), + codec_(&MSG::default_instance(), + TAG, + std::bind(&ProtobufCodecLiteT::onRpcMessage, this, _1, _2, _3), + rawCb, + errorCb) + { + } + + const string& tag() const { return codec_.tag(); } + + void send(const TcpConnectionPtr& conn, + const MSG& message) + { + codec_.send(conn, message); + } + + void onMessage(const TcpConnectionPtr& conn, + Buffer* buf, + Timestamp receiveTime) + { + codec_.onMessage(conn, buf, receiveTime); + } + + // internal + void onRpcMessage(const TcpConnectionPtr& conn, + const MessagePtr& message, + Timestamp receiveTime) + { + messageCallback_(conn, ::muduo::down_pointer_cast(message), receiveTime); + } + + void fillEmptyBuffer(muduo::net::Buffer* buf, const MSG& message) + { + codec_.fillEmptyBuffer(buf, message); + } + + private: + ProtobufMessageCallback messageCallback_; + CODEC codec_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_PROTOBUF_PROTOBUFCODECLITE_H diff --git a/include/Third_Lib/muduo/net/protorpc/CMakeLists.txt b/include/Third_Lib/muduo/net/protorpc/CMakeLists.txt new file mode 100644 index 0000000..1e5f153 --- /dev/null +++ b/include/Third_Lib/muduo/net/protorpc/CMakeLists.txt @@ -0,0 +1,42 @@ +add_custom_command(OUTPUT rpc.pb.cc rpc.pb.h + COMMAND protoc + ARGS --cpp_out . ${CMAKE_CURRENT_SOURCE_DIR}/rpc.proto -I${CMAKE_CURRENT_SOURCE_DIR} + DEPENDS rpc.proto + VERBATIM ) + +set_source_files_properties(rpc.pb.cc PROPERTIES COMPILE_FLAGS "-Wno-conversion") +include_directories(${PROJECT_BINARY_DIR}) + +add_library(muduo_protorpc_wire rpc.pb.cc RpcCodec.cc) +set_target_properties(muduo_protorpc_wire PROPERTIES COMPILE_FLAGS "-Wno-error=shadow") + +#add_library(muduo_protorpc_wire_cpp11 rpc.pb.cc RpcCodec.cc) +#set_target_properties(muduo_protorpc_wire_cpp11 PROPERTIES COMPILE_FLAGS "-std=c++0x -Wno-error=shadow") + +if(MUDUO_BUILD_EXAMPLES) +add_executable(protobuf_rpc_wire_test RpcCodec_test.cc) +target_link_libraries(protobuf_rpc_wire_test muduo_protorpc_wire muduo_protobuf_codec) +set_target_properties(protobuf_rpc_wire_test PROPERTIES COMPILE_FLAGS "-Wno-error=shadow") +endif() + +add_library(muduo_protorpc RpcChannel.cc RpcServer.cc) +set_target_properties(muduo_protorpc PROPERTIES COMPILE_FLAGS "-Wno-error=shadow") +target_link_libraries(muduo_protorpc muduo_protorpc_wire muduo_protobuf_codec muduo_net protobuf z) + +if(TCMALLOC_LIBRARY) + target_link_libraries(muduo_protorpc tcmalloc_and_profiler) +endif() + +install(TARGETS muduo_protorpc_wire muduo_protorpc DESTINATION lib) +#install(TARGETS muduo_protorpc_wire_cpp11 DESTINATION lib) + +set(HEADERS + RpcCodec.h + RpcChannel.h + RpcServer.h + rpc.proto + rpcservice.proto + ${PROJECT_BINARY_DIR}/muduo/net/protorpc/rpc.pb.h + ) +install(FILES ${HEADERS} DESTINATION include/muduo/net/protorpc) + diff --git a/include/Third_Lib/muduo/net/protorpc/README b/include/Third_Lib/muduo/net/protorpc/README new file mode 100644 index 0000000..0db4c85 --- /dev/null +++ b/include/Third_Lib/muduo/net/protorpc/README @@ -0,0 +1,5 @@ +This is an proof of concept implementation of Google Protobuf RPC using muduo. +The object lifetime management is for from ideal and doesn't follow the usual +muduo approach. + +Please consider using http://github.com/chenshuo/muduo-protorpc instead. diff --git a/include/Third_Lib/muduo/net/protorpc/RpcChannel.cc b/include/Third_Lib/muduo/net/protorpc/RpcChannel.cc new file mode 100644 index 0000000..d18e081 --- /dev/null +++ b/include/Third_Lib/muduo/net/protorpc/RpcChannel.cc @@ -0,0 +1,184 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/protorpc/RpcChannel.h" + +#include "muduo/base/Logging.h" +#include "muduo/net/protorpc/rpc.pb.h" + +#include + +using namespace muduo; +using namespace muduo::net; + +RpcChannel::RpcChannel() + : codec_(std::bind(&RpcChannel::onRpcMessage, this, _1, _2, _3)), + services_(NULL) +{ + LOG_INFO << "RpcChannel::ctor - " << this; +} + +RpcChannel::RpcChannel(const TcpConnectionPtr& conn) + : codec_(std::bind(&RpcChannel::onRpcMessage, this, _1, _2, _3)), + conn_(conn), + services_(NULL) +{ + LOG_INFO << "RpcChannel::ctor - " << this; +} + +RpcChannel::~RpcChannel() +{ + LOG_INFO << "RpcChannel::dtor - " << this; + for (const auto& outstanding : outstandings_) + { + OutstandingCall out = outstanding.second; + delete out.response; + delete out.done; + } +} + + // Call the given method of the remote service. The signature of this + // procedure looks the same as Service::CallMethod(), but the requirements + // are less strict in one important way: the request and response objects + // need not be of any specific class as long as their descriptors are + // method->input_type() and method->output_type(). +void RpcChannel::CallMethod(const ::google::protobuf::MethodDescriptor* method, + google::protobuf::RpcController* controller, + const ::google::protobuf::Message* request, + ::google::protobuf::Message* response, + ::google::protobuf::Closure* done) +{ + RpcMessage message; + message.set_type(REQUEST); + int64_t id = id_.incrementAndGet(); + message.set_id(id); + message.set_service(method->service()->full_name()); + message.set_method(method->name()); + message.set_request(request->SerializeAsString()); // FIXME: error check + + OutstandingCall out = { response, done }; + { + MutexLockGuard lock(mutex_); + outstandings_[id] = out; + } + codec_.send(conn_, message); +} + +void RpcChannel::onMessage(const TcpConnectionPtr& conn, + Buffer* buf, + Timestamp receiveTime) +{ + codec_.onMessage(conn, buf, receiveTime); +} + +void RpcChannel::onRpcMessage(const TcpConnectionPtr& conn, + const RpcMessagePtr& messagePtr, + Timestamp receiveTime) +{ + assert(conn == conn_); + //printf("%s\n", message.DebugString().c_str()); + RpcMessage& message = *messagePtr; + if (message.type() == RESPONSE) + { + int64_t id = message.id(); + assert(message.has_response() || message.has_error()); + + OutstandingCall out = { NULL, NULL }; + + { + MutexLockGuard lock(mutex_); + std::map::iterator it = outstandings_.find(id); + if (it != outstandings_.end()) + { + out = it->second; + outstandings_.erase(it); + } + } + + if (out.response) + { + std::unique_ptr d(out.response); + if (message.has_response()) + { + out.response->ParseFromString(message.response()); + } + if (out.done) + { + out.done->Run(); + } + } + } + else if (message.type() == REQUEST) + { + // FIXME: extract to a function + ErrorCode error = WRONG_PROTO; + if (services_) + { + std::map::const_iterator it = services_->find(message.service()); + if (it != services_->end()) + { + google::protobuf::Service* service = it->second; + assert(service != NULL); + const google::protobuf::ServiceDescriptor* desc = service->GetDescriptor(); + const google::protobuf::MethodDescriptor* method + = desc->FindMethodByName(message.method()); + if (method) + { + std::unique_ptr request(service->GetRequestPrototype(method).New()); + if (request->ParseFromString(message.request())) + { + google::protobuf::Message* response = service->GetResponsePrototype(method).New(); + // response is deleted in doneCallback + int64_t id = message.id(); + service->CallMethod(method, NULL, get_pointer(request), response, + NewCallback(this, &RpcChannel::doneCallback, response, id)); + error = NO_ERROR; + } + else + { + error = INVALID_REQUEST; + } + } + else + { + error = NO_METHOD; + } + } + else + { + error = NO_SERVICE; + } + } + else + { + error = NO_SERVICE; + } + if (error != NO_ERROR) + { + RpcMessage response; + response.set_type(RESPONSE); + response.set_id(message.id()); + response.set_error(error); + codec_.send(conn_, response); + } + } + else if (message.type() == ERROR) + { + } +} + +void RpcChannel::doneCallback(::google::protobuf::Message* response, int64_t id) +{ + std::unique_ptr d(response); + RpcMessage message; + message.set_type(RESPONSE); + message.set_id(id); + message.set_response(response->SerializeAsString()); // FIXME: error check + codec_.send(conn_, message); +} + diff --git a/include/Third_Lib/muduo/net/protorpc/RpcChannel.h b/include/Third_Lib/muduo/net/protorpc/RpcChannel.h new file mode 100644 index 0000000..172b41e --- /dev/null +++ b/include/Third_Lib/muduo/net/protorpc/RpcChannel.h @@ -0,0 +1,152 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_PROTORPC_RPCCHANNEL_H +#define MUDUO_NET_PROTORPC_RPCCHANNEL_H + +#include "muduo/base/Atomic.h" +#include "muduo/base/Mutex.h" +#include "muduo/net/protorpc/RpcCodec.h" + +#include + +#include + +// Service and RpcChannel classes are incorporated from +// google/protobuf/service.h + +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +namespace google { +namespace protobuf { + +// Defined in other files. +class Descriptor; // descriptor.h +class ServiceDescriptor; // descriptor.h +class MethodDescriptor; // descriptor.h +class Message; // message.h + +class Closure; + +class RpcController; +class Service; + +} // namespace protobuf +} // namespace google + + +namespace muduo +{ +namespace net +{ + +// Abstract interface for an RPC channel. An RpcChannel represents a +// communication line to a Service which can be used to call that Service's +// methods. The Service may be running on another machine. Normally, you +// should not call an RpcChannel directly, but instead construct a stub Service +// wrapping it. Example: +// FIXME: update here +// RpcChannel* channel = new MyRpcChannel("remotehost.example.com:1234"); +// MyService* service = new MyService::Stub(channel); +// service->MyMethod(request, &response, callback); +class RpcChannel : public ::google::protobuf::RpcChannel +{ + public: + RpcChannel(); + + explicit RpcChannel(const TcpConnectionPtr& conn); + + ~RpcChannel() override; + + void setConnection(const TcpConnectionPtr& conn) + { + conn_ = conn; + } + + void setServices(const std::map* services) + { + services_ = services; + } + + // Call the given method of the remote service. The signature of this + // procedure looks the same as Service::CallMethod(), but the requirements + // are less strict in one important way: the request and response objects + // need not be of any specific class as long as their descriptors are + // method->input_type() and method->output_type(). + void CallMethod(const ::google::protobuf::MethodDescriptor* method, + ::google::protobuf::RpcController* controller, + const ::google::protobuf::Message* request, + ::google::protobuf::Message* response, + ::google::protobuf::Closure* done) override; + + void onMessage(const TcpConnectionPtr& conn, + Buffer* buf, + Timestamp receiveTime); + + private: + void onRpcMessage(const TcpConnectionPtr& conn, + const RpcMessagePtr& messagePtr, + Timestamp receiveTime); + + void doneCallback(::google::protobuf::Message* response, int64_t id); + + struct OutstandingCall + { + ::google::protobuf::Message* response; + ::google::protobuf::Closure* done; + }; + + RpcCodec codec_; + TcpConnectionPtr conn_; + AtomicInt64 id_; + + MutexLock mutex_; + std::map outstandings_ GUARDED_BY(mutex_); + + const std::map* services_; +}; +typedef std::shared_ptr RpcChannelPtr; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_PROTORPC_RPCCHANNEL_H diff --git a/include/Third_Lib/muduo/net/protorpc/RpcCodec.cc b/include/Third_Lib/muduo/net/protorpc/RpcCodec.cc new file mode 100644 index 0000000..e466e1d --- /dev/null +++ b/include/Third_Lib/muduo/net/protorpc/RpcCodec.cc @@ -0,0 +1,37 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/protorpc/RpcCodec.h" + +#include "muduo/base/Logging.h" +#include "muduo/net/Endian.h" +#include "muduo/net/TcpConnection.h" + +#include "muduo/net/protorpc/rpc.pb.h" +#include "muduo/net/protorpc/google-inl.h" + +using namespace muduo; +using namespace muduo::net; + +namespace +{ + int ProtobufVersionCheck() + { + GOOGLE_PROTOBUF_VERIFY_VERSION; + return 0; + } + int dummy __attribute__ ((unused)) = ProtobufVersionCheck(); +} + +namespace muduo +{ +namespace net +{ +const char rpctag [] = "RPC0"; +} +} diff --git a/include/Third_Lib/muduo/net/protorpc/RpcCodec.h b/include/Third_Lib/muduo/net/protorpc/RpcCodec.h new file mode 100644 index 0000000..07fab9c --- /dev/null +++ b/include/Third_Lib/muduo/net/protorpc/RpcCodec.h @@ -0,0 +1,45 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_PROTORPC_RPCCODEC_H +#define MUDUO_NET_PROTORPC_RPCCODEC_H + +#include "muduo/base/Timestamp.h" +#include "muduo/net/protobuf/ProtobufCodecLite.h" + +namespace muduo +{ +namespace net +{ + +class Buffer; +class TcpConnection; +typedef std::shared_ptr TcpConnectionPtr; + +class RpcMessage; +typedef std::shared_ptr RpcMessagePtr; +extern const char rpctag[];// = "RPC0"; + +// wire format +// +// Field Length Content +// +// size 4-byte N+8 +// "RPC0" 4-byte +// payload N-byte +// checksum 4-byte adler32 of "RPC0"+payload +// + +typedef ProtobufCodecLiteT RpcCodec; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_PROTORPC_RPCCODEC_H diff --git a/include/Third_Lib/muduo/net/protorpc/RpcCodec_test.cc b/include/Third_Lib/muduo/net/protorpc/RpcCodec_test.cc new file mode 100644 index 0000000..645fffd --- /dev/null +++ b/include/Third_Lib/muduo/net/protorpc/RpcCodec_test.cc @@ -0,0 +1,81 @@ +#undef NDEBUG +#include "muduo/net/protorpc/RpcCodec.h" +#include "muduo/net/protorpc/rpc.pb.h" +#include "muduo/net/protobuf/ProtobufCodecLite.h" +#include "muduo/net/Buffer.h" + +#include + +using namespace muduo; +using namespace muduo::net; + +void rpcMessageCallback(const TcpConnectionPtr&, + const RpcMessagePtr&, + Timestamp) +{ +} + +MessagePtr g_msgptr; +void messageCallback(const TcpConnectionPtr&, + const MessagePtr& msg, + Timestamp) +{ + g_msgptr = msg; +} + +void print(const Buffer& buf) +{ + printf("encoded to %zd bytes\n", buf.readableBytes()); + for (size_t i = 0; i < buf.readableBytes(); ++i) + { + unsigned char ch = static_cast(buf.peek()[i]); + + printf("%2zd: 0x%02x %c\n", i, ch, isgraph(ch) ? ch : ' '); + } +} + +char rpctag[] = "RPC0"; + +int main() +{ + RpcMessage message; + message.set_type(REQUEST); + message.set_id(2); + char wire[] = "\0\0\0\x13" "RPC0" "\x08\x01\x11\x02\0\0\0\0\0\0\0" "\x0f\xef\x01\x32"; + string expected(wire, sizeof(wire)-1); + string s1, s2; + Buffer buf1, buf2; + { + RpcCodec codec(rpcMessageCallback); + codec.fillEmptyBuffer(&buf1, message); + print(buf1); + s1 = buf1.toStringPiece().as_string(); + } + + { + ProtobufCodecLite codec(&RpcMessage::default_instance(), "RPC0", messageCallback); + codec.fillEmptyBuffer(&buf2, message); + print(buf2); + s2 = buf2.toStringPiece().as_string(); + codec.onMessage(TcpConnectionPtr(), &buf1, Timestamp::now()); + assert(g_msgptr); + assert(g_msgptr->DebugString() == message.DebugString()); + g_msgptr.reset(); + } + assert(s1 == s2); + assert(s1 == expected); + assert(s2 == expected); + + { + Buffer buf; + ProtobufCodecLite codec(&RpcMessage::default_instance(), "XYZ", messageCallback); + codec.fillEmptyBuffer(&buf, message); + print(buf); + s2 = buf.toStringPiece().as_string(); + codec.onMessage(TcpConnectionPtr(), &buf, Timestamp::now()); + assert(g_msgptr); + assert(g_msgptr->DebugString() == message.DebugString()); + } + + google::protobuf::ShutdownProtobufLibrary(); +} diff --git a/include/Third_Lib/muduo/net/protorpc/RpcServer.cc b/include/Third_Lib/muduo/net/protorpc/RpcServer.cc new file mode 100644 index 0000000..fc1248b --- /dev/null +++ b/include/Third_Lib/muduo/net/protorpc/RpcServer.cc @@ -0,0 +1,68 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) + +#include "muduo/net/protorpc/RpcServer.h" + +#include "muduo/base/Logging.h" +#include "muduo/net/protorpc/RpcChannel.h" + +#include +#include + +using namespace muduo; +using namespace muduo::net; + +RpcServer::RpcServer(EventLoop* loop, + const InetAddress& listenAddr) + : server_(loop, listenAddr, "RpcServer") +{ + server_.setConnectionCallback( + std::bind(&RpcServer::onConnection, this, _1)); +// server_.setMessageCallback( +// std::bind(&RpcServer::onMessage, this, _1, _2, _3)); +} + +void RpcServer::registerService(google::protobuf::Service* service) +{ + const google::protobuf::ServiceDescriptor* desc = service->GetDescriptor(); + services_[desc->full_name()] = service; +} + +void RpcServer::start() +{ + server_.start(); +} + +void RpcServer::onConnection(const TcpConnectionPtr& conn) +{ + LOG_INFO << "RpcServer - " << conn->peerAddress().toIpPort() << " -> " + << conn->localAddress().toIpPort() << " is " + << (conn->connected() ? "UP" : "DOWN"); + if (conn->connected()) + { + RpcChannelPtr channel(new RpcChannel(conn)); + channel->setServices(&services_); + conn->setMessageCallback( + std::bind(&RpcChannel::onMessage, get_pointer(channel), _1, _2, _3)); + conn->setContext(channel); + } + else + { + conn->setContext(RpcChannelPtr()); + // FIXME: + } +} + +// void RpcServer::onMessage(const TcpConnectionPtr& conn, +// Buffer* buf, +// Timestamp time) +// { +// RpcChannelPtr& channel = boost::any_cast(conn->getContext()); +// channel->onMessage(conn, buf, time); +// } + diff --git a/include/Third_Lib/muduo/net/protorpc/RpcServer.h b/include/Third_Lib/muduo/net/protorpc/RpcServer.h new file mode 100644 index 0000000..6818801 --- /dev/null +++ b/include/Third_Lib/muduo/net/protorpc/RpcServer.h @@ -0,0 +1,57 @@ +// Copyright 2010, Shuo Chen. All rights reserved. +// http://code.google.com/p/muduo/ +// +// Use of this source code is governed by a BSD-style license +// that can be found in the License file. + +// Author: Shuo Chen (chenshuo at chenshuo dot com) +// +// This is a public header file, it must only include public header files. + +#ifndef MUDUO_NET_PROTORPC_RPCSERVER_H +#define MUDUO_NET_PROTORPC_RPCSERVER_H + +#include "muduo/net/TcpServer.h" + +namespace google { +namespace protobuf { + +class Service; + +} // namespace protobuf +} // namespace google + +namespace muduo +{ +namespace net +{ + +class RpcServer +{ + public: + RpcServer(EventLoop* loop, + const InetAddress& listenAddr); + + void setThreadNum(int numThreads) + { + server_.setThreadNum(numThreads); + } + + void registerService(::google::protobuf::Service*); + void start(); + + private: + void onConnection(const TcpConnectionPtr& conn); + + // void onMessage(const TcpConnectionPtr& conn, + // Buffer* buf, + // Timestamp time); + + TcpServer server_; + std::map services_; +}; + +} // namespace net +} // namespace muduo + +#endif // MUDUO_NET_PROTORPC_RPCSERVER_H diff --git a/include/Third_Lib/muduo/net/protorpc/google-inl.h b/include/Third_Lib/muduo/net/protorpc/google-inl.h new file mode 100644 index 0000000..2a905a9 --- /dev/null +++ b/include/Third_Lib/muduo/net/protorpc/google-inl.h @@ -0,0 +1,84 @@ +// ByteSizeConsistencyError and InitializationErrorMessage are +// copied from google/protobuf/message_lite.cc + +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Authors: wink@google.com (Wink Saville), +// kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include + +// When serializing, we first compute the byte size, then serialize the message. +// If serialization produces a different number of bytes than expected, we +// call this function, which crashes. The problem could be due to a bug in the +// protobuf implementation but is more likely caused by concurrent modification +// of the message. This function attempts to distinguish between the two and +// provide a useful error message. +inline +void ByteSizeConsistencyError(int byte_size_before_serialization, + int byte_size_after_serialization, + int bytes_produced_by_serialization) +{ + GOOGLE_CHECK_EQ(byte_size_before_serialization, byte_size_after_serialization) + << "Protocol message was modified concurrently during serialization."; + GOOGLE_CHECK_EQ(bytes_produced_by_serialization, byte_size_before_serialization) + << "Byte size calculation and serialization were inconsistent. This " + "may indicate a bug in protocol buffers or it may be caused by " + "concurrent modification of the message."; + GOOGLE_LOG(FATAL) << "This shouldn't be called if all the sizes are equal."; +} + +inline +std::string InitializationErrorMessage(const char* action, + const google::protobuf::MessageLite& message) +{ + // Note: We want to avoid depending on strutil in the lite library, otherwise + // we'd use: + // + // return strings::Substitute( + // "Can't $0 message of type \"$1\" because it is missing required " + // "fields: $2", + // action, message.GetTypeName(), + // message.InitializationErrorString()); + + std::string result; + result += "Can't "; + result += action; + result += " message of type \""; + result += message.GetTypeName(); + result += "\" because it is missing required fields: "; + result += message.InitializationErrorString(); + return result; +} + + diff --git a/include/Third_Lib/muduo/net/protorpc/rpc.proto b/include/Third_Lib/muduo/net/protorpc/rpc.proto new file mode 100644 index 0000000..941e235 --- /dev/null +++ b/include/Third_Lib/muduo/net/protorpc/rpc.proto @@ -0,0 +1,36 @@ +package muduo.net; +// option go_package = "muduorpc"; +option java_package = "com.chenshuo.muduo.protorpc"; +option java_outer_classname = "RpcProto"; + +enum MessageType +{ + REQUEST = 1; + RESPONSE = 2; + ERROR = 3; // not used +} + +enum ErrorCode +{ + NO_ERROR = 0; + WRONG_PROTO = 1; + NO_SERVICE = 2; + NO_METHOD = 3; + INVALID_REQUEST = 4; + INVALID_RESPONSE = 5; + TIMEOUT = 6; +} + +message RpcMessage +{ + required MessageType type = 1; + required fixed64 id = 2; + + optional string service = 3; + optional string method = 4; + optional bytes request = 5; + + optional bytes response = 6; + + optional ErrorCode error = 7; +} diff --git a/include/Third_Lib/muduo/net/protorpc/rpcservice.proto b/include/Third_Lib/muduo/net/protorpc/rpcservice.proto new file mode 100644 index 0000000..f973234 --- /dev/null +++ b/include/Third_Lib/muduo/net/protorpc/rpcservice.proto @@ -0,0 +1,44 @@ +package muduo.net; + +option cc_generic_services = true; +option java_generic_services = true; +option py_generic_services = true; + +option java_package = "com.chenshuo.muduo.protorpc"; +option java_outer_classname = "RpcServiceProto"; + +//import "google/protobuf/descriptor.proto"; +import "rpc.proto"; + +message ListRpcRequest +{ + optional string service_name = 1; + optional bool list_method = 2; +} + +message ListRpcResponse +{ + required ErrorCode error = 1; + repeated string service_name = 2; + repeated string method_name = 3; +} + +message GetServiceRequest +{ + required string service_name = 1; +} + +message GetServiceResponse +{ + required ErrorCode error = 1; + repeated string proto_file = 2; + repeated string proto_file_name = 3; +} + +// the meta service +service RpcService +{ + rpc listRpc (ListRpcRequest) returns (ListRpcResponse); + rpc getService (GetServiceRequest) returns (GetServiceResponse); +} + diff --git a/include/Third_Lib/muduo/net/tests/Buffer_unittest.cc b/include/Third_Lib/muduo/net/tests/Buffer_unittest.cc new file mode 100644 index 0000000..af7fb81 --- /dev/null +++ b/include/Third_Lib/muduo/net/tests/Buffer_unittest.cc @@ -0,0 +1,170 @@ +#include "muduo/net/Buffer.h" + +//#define BOOST_TEST_MODULE BufferTest +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK +#include + +using muduo::string; +using muduo::net::Buffer; + +BOOST_AUTO_TEST_CASE(testBufferAppendRetrieve) +{ + Buffer buf; + BOOST_CHECK_EQUAL(buf.readableBytes(), 0); + BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize); + BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend); + + const string str(200, 'x'); + buf.append(str); + BOOST_CHECK_EQUAL(buf.readableBytes(), str.size()); + BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize - str.size()); + BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend); + + const string str2 = buf.retrieveAsString(50); + BOOST_CHECK_EQUAL(str2.size(), 50); + BOOST_CHECK_EQUAL(buf.readableBytes(), str.size() - str2.size()); + BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize - str.size()); + BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend + str2.size()); + BOOST_CHECK_EQUAL(str2, string(50, 'x')); + + buf.append(str); + BOOST_CHECK_EQUAL(buf.readableBytes(), 2*str.size() - str2.size()); + BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize - 2*str.size()); + BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend + str2.size()); + + const string str3 = buf.retrieveAllAsString(); + BOOST_CHECK_EQUAL(str3.size(), 350); + BOOST_CHECK_EQUAL(buf.readableBytes(), 0); + BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize); + BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend); + BOOST_CHECK_EQUAL(str3, string(350, 'x')); +} + +BOOST_AUTO_TEST_CASE(testBufferGrow) +{ + Buffer buf; + buf.append(string(400, 'y')); + BOOST_CHECK_EQUAL(buf.readableBytes(), 400); + BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize-400); + + buf.retrieve(50); + BOOST_CHECK_EQUAL(buf.readableBytes(), 350); + BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize-400); + BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend+50); + + buf.append(string(1000, 'z')); + BOOST_CHECK_EQUAL(buf.readableBytes(), 1350); + BOOST_CHECK_EQUAL(buf.writableBytes(), 0); + BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend+50); // FIXME + + buf.retrieveAll(); + BOOST_CHECK_EQUAL(buf.readableBytes(), 0); + BOOST_CHECK_EQUAL(buf.writableBytes(), 1400); // FIXME + BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend); +} + +BOOST_AUTO_TEST_CASE(testBufferInsideGrow) +{ + Buffer buf; + buf.append(string(800, 'y')); + BOOST_CHECK_EQUAL(buf.readableBytes(), 800); + BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize-800); + + buf.retrieve(500); + BOOST_CHECK_EQUAL(buf.readableBytes(), 300); + BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize-800); + BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend+500); + + buf.append(string(300, 'z')); + BOOST_CHECK_EQUAL(buf.readableBytes(), 600); + BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize-600); + BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend); +} + +BOOST_AUTO_TEST_CASE(testBufferShrink) +{ + Buffer buf; + buf.append(string(2000, 'y')); + BOOST_CHECK_EQUAL(buf.readableBytes(), 2000); + BOOST_CHECK_EQUAL(buf.writableBytes(), 0); + BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend); + + buf.retrieve(1500); + BOOST_CHECK_EQUAL(buf.readableBytes(), 500); + BOOST_CHECK_EQUAL(buf.writableBytes(), 0); + BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend+1500); + + buf.shrink(0); + BOOST_CHECK_EQUAL(buf.readableBytes(), 500); + BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize-500); + BOOST_CHECK_EQUAL(buf.retrieveAllAsString(), string(500, 'y')); + BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend); +} + +BOOST_AUTO_TEST_CASE(testBufferPrepend) +{ + Buffer buf; + buf.append(string(200, 'y')); + BOOST_CHECK_EQUAL(buf.readableBytes(), 200); + BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize-200); + BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend); + + int x = 0; + buf.prepend(&x, sizeof x); + BOOST_CHECK_EQUAL(buf.readableBytes(), 204); + BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize-200); + BOOST_CHECK_EQUAL(buf.prependableBytes(), Buffer::kCheapPrepend - 4); +} + +BOOST_AUTO_TEST_CASE(testBufferReadInt) +{ + Buffer buf; + buf.append("HTTP"); + + BOOST_CHECK_EQUAL(buf.readableBytes(), 4); + BOOST_CHECK_EQUAL(buf.peekInt8(), 'H'); + int top16 = buf.peekInt16(); + BOOST_CHECK_EQUAL(top16, 'H'*256 + 'T'); + BOOST_CHECK_EQUAL(buf.peekInt32(), top16*65536 + 'T'*256 + 'P'); + + BOOST_CHECK_EQUAL(buf.readInt8(), 'H'); + BOOST_CHECK_EQUAL(buf.readInt16(), 'T'*256 + 'T'); + BOOST_CHECK_EQUAL(buf.readInt8(), 'P'); + BOOST_CHECK_EQUAL(buf.readableBytes(), 0); + BOOST_CHECK_EQUAL(buf.writableBytes(), Buffer::kInitialSize); + + buf.appendInt8(-1); + buf.appendInt16(-2); + buf.appendInt32(-3); + BOOST_CHECK_EQUAL(buf.readableBytes(), 7); + BOOST_CHECK_EQUAL(buf.readInt8(), -1); + BOOST_CHECK_EQUAL(buf.readInt16(), -2); + BOOST_CHECK_EQUAL(buf.readInt32(), -3); +} + +BOOST_AUTO_TEST_CASE(testBufferFindEOL) +{ + Buffer buf; + buf.append(string(100000, 'x')); + const char* null = NULL; + BOOST_CHECK_EQUAL(buf.findEOL(), null); + BOOST_CHECK_EQUAL(buf.findEOL(buf.peek()+90000), null); +} + +void output(Buffer&& buf, const void* inner) +{ + Buffer newbuf(std::move(buf)); + // printf("New Buffer at %p, inner %p\n", &newbuf, newbuf.peek()); + BOOST_CHECK_EQUAL(inner, newbuf.peek()); +} + +// NOTE: This test fails in g++ 4.4, passes in g++ 4.6. +BOOST_AUTO_TEST_CASE(testMove) +{ + Buffer buf; + buf.append("muduo", 5); + const void* inner = buf.peek(); + // printf("Buffer at %p, inner %p\n", &buf, inner); + output(std::move(buf), inner); +} diff --git a/include/Third_Lib/muduo/net/tests/CMakeLists.txt b/include/Third_Lib/muduo/net/tests/CMakeLists.txt new file mode 100644 index 0000000..a7aa3a0 --- /dev/null +++ b/include/Third_Lib/muduo/net/tests/CMakeLists.txt @@ -0,0 +1,48 @@ +add_executable(channel_test Channel_test.cc) +target_link_libraries(channel_test muduo_net) + +add_executable(echoserver_unittest EchoServer_unittest.cc) +target_link_libraries(echoserver_unittest muduo_net) + +add_executable(echoclient_unittest EchoClient_unittest.cc) +target_link_libraries(echoclient_unittest muduo_net) + +add_executable(eventloop_unittest EventLoop_unittest.cc) +target_link_libraries(eventloop_unittest muduo_net) + +add_executable(eventloopthread_unittest EventLoopThread_unittest.cc) +target_link_libraries(eventloopthread_unittest muduo_net) + +add_executable(eventloopthreadpool_unittest EventLoopThreadPool_unittest.cc) +target_link_libraries(eventloopthreadpool_unittest muduo_net) + +if(BOOSTTEST_LIBRARY) +add_executable(buffer_unittest Buffer_unittest.cc) +target_link_libraries(buffer_unittest muduo_net boost_unit_test_framework) +add_test(NAME buffer_unittest COMMAND buffer_unittest) + +add_executable(inetaddress_unittest InetAddress_unittest.cc) +target_link_libraries(inetaddress_unittest muduo_net boost_unit_test_framework) +add_test(NAME inetaddress_unittest COMMAND inetaddress_unittest) + +if(ZLIB_FOUND) + add_executable(zlibstream_unittest ZlibStream_unittest.cc) + target_link_libraries(zlibstream_unittest muduo_net boost_unit_test_framework z) + # set_target_properties(zlibstream_unittest PROPERTIES COMPILE_FLAGS "-std=c++0x") +endif() + +endif() + +add_executable(tcpclient_reg1 TcpClient_reg1.cc) +target_link_libraries(tcpclient_reg1 muduo_net) + +add_executable(tcpclient_reg2 TcpClient_reg2.cc) +target_link_libraries(tcpclient_reg2 muduo_net) + +add_executable(tcpclient_reg3 TcpClient_reg3.cc) +target_link_libraries(tcpclient_reg3 muduo_net) + +add_executable(timerqueue_unittest TimerQueue_unittest.cc) +target_link_libraries(timerqueue_unittest muduo_net) +add_test(NAME timerqueue_unittest COMMAND timerqueue_unittest) + diff --git a/include/Third_Lib/muduo/net/tests/Channel_test.cc b/include/Third_Lib/muduo/net/tests/Channel_test.cc new file mode 100644 index 0000000..6276531 --- /dev/null +++ b/include/Third_Lib/muduo/net/tests/Channel_test.cc @@ -0,0 +1,112 @@ +#include "muduo/base/Logging.h" +#include "muduo/net/Channel.h" +#include "muduo/net/EventLoop.h" + +#include +#include + +#include +#include +#include + +using namespace muduo; +using namespace muduo::net; + +void print(const char* msg) +{ + static std::map lasts; + Timestamp& last = lasts[msg]; + Timestamp now = Timestamp::now(); + printf("%s tid %d %s delay %f\n", now.toString().c_str(), CurrentThread::tid(), + msg, timeDifference(now, last)); + last = now; +} + +namespace muduo +{ +namespace net +{ +namespace detail +{ +int createTimerfd(); +void readTimerfd(int timerfd, Timestamp now); +} +} +} + +// Use relative time, immunized to wall clock changes. +class PeriodicTimer +{ + public: + PeriodicTimer(EventLoop* loop, double interval, const TimerCallback& cb) + : loop_(loop), + timerfd_(muduo::net::detail::createTimerfd()), + timerfdChannel_(loop, timerfd_), + interval_(interval), + cb_(cb) + { + timerfdChannel_.setReadCallback( + std::bind(&PeriodicTimer::handleRead, this)); + timerfdChannel_.enableReading(); + } + + void start() + { + struct itimerspec spec; + memZero(&spec, sizeof spec); + spec.it_interval = toTimeSpec(interval_); + spec.it_value = spec.it_interval; + int ret = ::timerfd_settime(timerfd_, 0 /* relative timer */, &spec, NULL); + if (ret) + { + LOG_SYSERR << "timerfd_settime()"; + } + } + + ~PeriodicTimer() + { + timerfdChannel_.disableAll(); + timerfdChannel_.remove(); + ::close(timerfd_); + } + + private: + void handleRead() + { + loop_->assertInLoopThread(); + muduo::net::detail::readTimerfd(timerfd_, Timestamp::now()); + if (cb_) + cb_(); + } + + static struct timespec toTimeSpec(double seconds) + { + struct timespec ts; + memZero(&ts, sizeof ts); + const int64_t kNanoSecondsPerSecond = 1000000000; + const int kMinInterval = 100000; + int64_t nanoseconds = static_cast(seconds * kNanoSecondsPerSecond); + if (nanoseconds < kMinInterval) + nanoseconds = kMinInterval; + ts.tv_sec = static_cast(nanoseconds / kNanoSecondsPerSecond); + ts.tv_nsec = static_cast(nanoseconds % kNanoSecondsPerSecond); + return ts; + } + + EventLoop* loop_; + const int timerfd_; + Channel timerfdChannel_; + const double interval_; // in seconds + TimerCallback cb_; +}; + +int main(int argc, char* argv[]) +{ + LOG_INFO << "pid = " << getpid() << ", tid = " << CurrentThread::tid() + << " Try adjusting the wall clock, see what happens."; + EventLoop loop; + PeriodicTimer timer(&loop, 1, std::bind(print, "PeriodicTimer")); + timer.start(); + loop.runEvery(1, std::bind(print, "EventLoop::runEvery")); + loop.loop(); +} diff --git a/include/Third_Lib/muduo/net/tests/EchoClient_unittest.cc b/include/Third_Lib/muduo/net/tests/EchoClient_unittest.cc new file mode 100644 index 0000000..44d973a --- /dev/null +++ b/include/Third_Lib/muduo/net/tests/EchoClient_unittest.cc @@ -0,0 +1,114 @@ +#include "muduo/net/TcpClient.h" + +#include "muduo/base/Logging.h" +#include "muduo/base/Thread.h" +#include "muduo/net/EventLoop.h" +#include "muduo/net/InetAddress.h" + +#include + +#include +#include + +using namespace muduo; +using namespace muduo::net; + +int numThreads = 0; +class EchoClient; +std::vector> clients; +int current = 0; + +class EchoClient : noncopyable +{ + public: + EchoClient(EventLoop* loop, const InetAddress& listenAddr, const string& id) + : loop_(loop), + client_(loop, listenAddr, "EchoClient"+id) + { + client_.setConnectionCallback( + std::bind(&EchoClient::onConnection, this, _1)); + client_.setMessageCallback( + std::bind(&EchoClient::onMessage, this, _1, _2, _3)); + //client_.enableRetry(); + } + + void connect() + { + client_.connect(); + } + // void stop(); + + private: + void onConnection(const TcpConnectionPtr& conn) + { + LOG_TRACE << conn->localAddress().toIpPort() << " -> " + << conn->peerAddress().toIpPort() << " is " + << (conn->connected() ? "UP" : "DOWN"); + + if (conn->connected()) + { + ++current; + if (implicit_cast(current) < clients.size()) + { + clients[current]->connect(); + } + LOG_INFO << "*** connected " << current; + } + conn->send("world\n"); + } + + void onMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp time) + { + string msg(buf->retrieveAllAsString()); + LOG_TRACE << conn->name() << " recv " << msg.size() << " bytes at " << time.toString(); + if (msg == "quit\n") + { + conn->send("bye\n"); + conn->shutdown(); + } + else if (msg == "shutdown\n") + { + loop_->quit(); + } + else + { + conn->send(msg); + } + } + + EventLoop* loop_; + TcpClient client_; +}; + +int main(int argc, char* argv[]) +{ + LOG_INFO << "pid = " << getpid() << ", tid = " << CurrentThread::tid(); + if (argc > 1) + { + EventLoop loop; + bool ipv6 = argc > 3; + InetAddress serverAddr(argv[1], 2000, ipv6); + + int n = 1; + if (argc > 2) + { + n = atoi(argv[2]); + } + + clients.reserve(n); + for (int i = 0; i < n; ++i) + { + char buf[32]; + snprintf(buf, sizeof buf, "%d", i+1); + clients.emplace_back(new EchoClient(&loop, serverAddr, buf)); + } + + clients[current]->connect(); + loop.loop(); + } + else + { + printf("Usage: %s host_ip [current#]\n", argv[0]); + } +} + diff --git a/include/Third_Lib/muduo/net/tests/EchoServer_unittest.cc b/include/Third_Lib/muduo/net/tests/EchoServer_unittest.cc new file mode 100644 index 0000000..0875668 --- /dev/null +++ b/include/Third_Lib/muduo/net/tests/EchoServer_unittest.cc @@ -0,0 +1,86 @@ +#include "muduo/net/TcpServer.h" + +#include "muduo/base/Logging.h" +#include "muduo/base/Thread.h" +#include "muduo/net/EventLoop.h" +#include "muduo/net/InetAddress.h" + +#include + +#include +#include + +using namespace muduo; +using namespace muduo::net; + +int numThreads = 0; + +class EchoServer +{ + public: + EchoServer(EventLoop* loop, const InetAddress& listenAddr) + : loop_(loop), + server_(loop, listenAddr, "EchoServer") + { + server_.setConnectionCallback( + std::bind(&EchoServer::onConnection, this, _1)); + server_.setMessageCallback( + std::bind(&EchoServer::onMessage, this, _1, _2, _3)); + server_.setThreadNum(numThreads); + } + + void start() + { + server_.start(); + } + // void stop(); + + private: + void onConnection(const TcpConnectionPtr& conn) + { + LOG_TRACE << conn->peerAddress().toIpPort() << " -> " + << conn->localAddress().toIpPort() << " is " + << (conn->connected() ? "UP" : "DOWN"); + LOG_INFO << conn->getTcpInfoString(); + + conn->send("hello\n"); + } + + void onMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp time) + { + string msg(buf->retrieveAllAsString()); + LOG_TRACE << conn->name() << " recv " << msg.size() << " bytes at " << time.toString(); + if (msg == "exit\n") + { + conn->send("bye\n"); + conn->shutdown(); + } + if (msg == "quit\n") + { + loop_->quit(); + } + conn->send(msg); + } + + EventLoop* loop_; + TcpServer server_; +}; + +int main(int argc, char* argv[]) +{ + LOG_INFO << "pid = " << getpid() << ", tid = " << CurrentThread::tid(); + LOG_INFO << "sizeof TcpConnection = " << sizeof(TcpConnection); + if (argc > 1) + { + numThreads = atoi(argv[1]); + } + bool ipv6 = argc > 2; + EventLoop loop; + InetAddress listenAddr(2000, false, ipv6); + EchoServer server(&loop, listenAddr); + + server.start(); + + loop.loop(); +} + diff --git a/include/Third_Lib/muduo/net/tests/EventLoopThreadPool_unittest.cc b/include/Third_Lib/muduo/net/tests/EventLoopThreadPool_unittest.cc new file mode 100644 index 0000000..1bf1bd3 --- /dev/null +++ b/include/Third_Lib/muduo/net/tests/EventLoopThreadPool_unittest.cc @@ -0,0 +1,68 @@ +#include "muduo/net/EventLoopThreadPool.h" +#include "muduo/net/EventLoop.h" +#include "muduo/base/Thread.h" + +#include +#include + +using namespace muduo; +using namespace muduo::net; + +void print(EventLoop* p = NULL) +{ + printf("main(): pid = %d, tid = %d, loop = %p\n", + getpid(), CurrentThread::tid(), p); +} + +void init(EventLoop* p) +{ + printf("init(): pid = %d, tid = %d, loop = %p\n", + getpid(), CurrentThread::tid(), p); +} + +int main() +{ + print(); + + EventLoop loop; + loop.runAfter(11, std::bind(&EventLoop::quit, &loop)); + + { + printf("Single thread %p:\n", &loop); + EventLoopThreadPool model(&loop, "single"); + model.setThreadNum(0); + model.start(init); + assert(model.getNextLoop() == &loop); + assert(model.getNextLoop() == &loop); + assert(model.getNextLoop() == &loop); + } + + { + printf("Another thread:\n"); + EventLoopThreadPool model(&loop, "another"); + model.setThreadNum(1); + model.start(init); + EventLoop* nextLoop = model.getNextLoop(); + nextLoop->runAfter(2, std::bind(print, nextLoop)); + assert(nextLoop != &loop); + assert(nextLoop == model.getNextLoop()); + assert(nextLoop == model.getNextLoop()); + ::sleep(3); + } + + { + printf("Three threads:\n"); + EventLoopThreadPool model(&loop, "three"); + model.setThreadNum(3); + model.start(init); + EventLoop* nextLoop = model.getNextLoop(); + nextLoop->runInLoop(std::bind(print, nextLoop)); + assert(nextLoop != &loop); + assert(nextLoop != model.getNextLoop()); + assert(nextLoop != model.getNextLoop()); + assert(nextLoop == model.getNextLoop()); + } + + loop.loop(); +} + diff --git a/include/Third_Lib/muduo/net/tests/EventLoopThread_unittest.cc b/include/Third_Lib/muduo/net/tests/EventLoopThread_unittest.cc new file mode 100644 index 0000000..d67c128 --- /dev/null +++ b/include/Third_Lib/muduo/net/tests/EventLoopThread_unittest.cc @@ -0,0 +1,48 @@ +#include "muduo/net/EventLoopThread.h" +#include "muduo/net/EventLoop.h" +#include "muduo/base/Thread.h" +#include "muduo/base/CountDownLatch.h" + +#include +#include + +using namespace muduo; +using namespace muduo::net; + +void print(EventLoop* p = NULL) +{ + printf("print: pid = %d, tid = %d, loop = %p\n", + getpid(), CurrentThread::tid(), p); +} + +void quit(EventLoop* p) +{ + print(p); + p->quit(); +} + +int main() +{ + print(); + + { + EventLoopThread thr1; // never start + } + + { + // dtor calls quit() + EventLoopThread thr2; + EventLoop* loop = thr2.startLoop(); + loop->runInLoop(std::bind(print, loop)); + CurrentThread::sleepUsec(500 * 1000); + } + + { + // quit() before dtor + EventLoopThread thr3; + EventLoop* loop = thr3.startLoop(); + loop->runInLoop(std::bind(quit, loop)); + CurrentThread::sleepUsec(500 * 1000); + } +} + diff --git a/include/Third_Lib/muduo/net/tests/EventLoop_unittest.cc b/include/Third_Lib/muduo/net/tests/EventLoop_unittest.cc new file mode 100644 index 0000000..6cb6d7d --- /dev/null +++ b/include/Third_Lib/muduo/net/tests/EventLoop_unittest.cc @@ -0,0 +1,42 @@ +#include "muduo/net/EventLoop.h" +#include "muduo/base/Thread.h" + +#include +#include +#include + +using namespace muduo; +using namespace muduo::net; + +EventLoop* g_loop; + +void callback() +{ + printf("callback(): pid = %d, tid = %d\n", getpid(), CurrentThread::tid()); + EventLoop anotherLoop; +} + +void threadFunc() +{ + printf("threadFunc(): pid = %d, tid = %d\n", getpid(), CurrentThread::tid()); + + assert(EventLoop::getEventLoopOfCurrentThread() == NULL); + EventLoop loop; + assert(EventLoop::getEventLoopOfCurrentThread() == &loop); + loop.runAfter(1.0, callback); + loop.loop(); +} + +int main() +{ + printf("main(): pid = %d, tid = %d\n", getpid(), CurrentThread::tid()); + + assert(EventLoop::getEventLoopOfCurrentThread() == NULL); + EventLoop loop; + assert(EventLoop::getEventLoopOfCurrentThread() == &loop); + + Thread thread(threadFunc); + thread.start(); + + loop.loop(); +} diff --git a/include/Third_Lib/muduo/net/tests/InetAddress_unittest.cc b/include/Third_Lib/muduo/net/tests/InetAddress_unittest.cc new file mode 100644 index 0000000..bdd31e0 --- /dev/null +++ b/include/Third_Lib/muduo/net/tests/InetAddress_unittest.cc @@ -0,0 +1,70 @@ +#include "muduo/net/InetAddress.h" + +#include "muduo/base/Logging.h" + +//#define BOOST_TEST_MODULE InetAddressTest +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK +#include + +using muduo::string; +using muduo::net::InetAddress; + +BOOST_AUTO_TEST_CASE(testInetAddress) +{ + InetAddress addr0(1234); + BOOST_CHECK_EQUAL(addr0.toIp(), string("0.0.0.0")); + BOOST_CHECK_EQUAL(addr0.toIpPort(), string("0.0.0.0:1234")); + BOOST_CHECK_EQUAL(addr0.port(), 1234); + + InetAddress addr1(4321, true); + BOOST_CHECK_EQUAL(addr1.toIp(), string("127.0.0.1")); + BOOST_CHECK_EQUAL(addr1.toIpPort(), string("127.0.0.1:4321")); + BOOST_CHECK_EQUAL(addr1.port(), 4321); + + InetAddress addr2("1.2.3.4", 8888); + BOOST_CHECK_EQUAL(addr2.toIp(), string("1.2.3.4")); + BOOST_CHECK_EQUAL(addr2.toIpPort(), string("1.2.3.4:8888")); + BOOST_CHECK_EQUAL(addr2.port(), 8888); + + InetAddress addr3("255.254.253.252", 65535); + BOOST_CHECK_EQUAL(addr3.toIp(), string("255.254.253.252")); + BOOST_CHECK_EQUAL(addr3.toIpPort(), string("255.254.253.252:65535")); + BOOST_CHECK_EQUAL(addr3.port(), 65535); +} + +BOOST_AUTO_TEST_CASE(testInet6Address) +{ + InetAddress addr0(1234, false, true); + BOOST_CHECK_EQUAL(addr0.toIp(), string("::")); + BOOST_CHECK_EQUAL(addr0.toIpPort(), string("[::]:1234")); + BOOST_CHECK_EQUAL(addr0.port(), 1234); + + InetAddress addr1(1234, true, true); + BOOST_CHECK_EQUAL(addr1.toIp(), string("::1")); + BOOST_CHECK_EQUAL(addr1.toIpPort(), string("[::1]:1234")); + BOOST_CHECK_EQUAL(addr1.port(), 1234); + + InetAddress addr2("2001:db8::1", 8888, true); + BOOST_CHECK_EQUAL(addr2.toIp(), string("2001:db8::1")); + BOOST_CHECK_EQUAL(addr2.toIpPort(), string("[2001:db8::1]:8888")); + BOOST_CHECK_EQUAL(addr2.port(), 8888); + + InetAddress addr3("fe80::1234:abcd:1", 8888); + BOOST_CHECK_EQUAL(addr3.toIp(), string("fe80::1234:abcd:1")); + BOOST_CHECK_EQUAL(addr3.toIpPort(), string("[fe80::1234:abcd:1]:8888")); + BOOST_CHECK_EQUAL(addr3.port(), 8888); +} + +BOOST_AUTO_TEST_CASE(testInetAddressResolve) +{ + InetAddress addr(80); + if (InetAddress::resolve("google.com", &addr)) + { + LOG_INFO << "google.com resolved to " << addr.toIpPort(); + } + else + { + LOG_ERROR << "Unable to resolve google.com"; + } +} diff --git a/include/Third_Lib/muduo/net/tests/TcpClient_reg1.cc b/include/Third_Lib/muduo/net/tests/TcpClient_reg1.cc new file mode 100644 index 0000000..41b76b2 --- /dev/null +++ b/include/Third_Lib/muduo/net/tests/TcpClient_reg1.cc @@ -0,0 +1,29 @@ +// TcpClient::stop() called in the same iteration of IO event + +#include "muduo/base/Logging.h" +#include "muduo/net/EventLoop.h" +#include "muduo/net/TcpClient.h" + +using namespace muduo; +using namespace muduo::net; + +TcpClient* g_client; + +void timeout() +{ + LOG_INFO << "timeout"; + g_client->stop(); +} + +int main(int argc, char* argv[]) +{ + EventLoop loop; + InetAddress serverAddr("127.0.0.1", 2); // no such server + TcpClient client(&loop, serverAddr, "TcpClient"); + g_client = &client; + loop.runAfter(0.0, timeout); + loop.runAfter(1.0, std::bind(&EventLoop::quit, &loop)); + client.connect(); + CurrentThread::sleepUsec(100 * 1000); + loop.loop(); +} diff --git a/include/Third_Lib/muduo/net/tests/TcpClient_reg2.cc b/include/Third_Lib/muduo/net/tests/TcpClient_reg2.cc new file mode 100644 index 0000000..1637dbd --- /dev/null +++ b/include/Third_Lib/muduo/net/tests/TcpClient_reg2.cc @@ -0,0 +1,30 @@ +// TcpClient destructs when TcpConnection is connected but unique. + +#include "muduo/base/Logging.h" +#include "muduo/base/Thread.h" +#include "muduo/net/EventLoop.h" +#include "muduo/net/TcpClient.h" + +using namespace muduo; +using namespace muduo::net; + +void threadFunc(EventLoop* loop) +{ + InetAddress serverAddr("127.0.0.1", 1234); // should succeed + TcpClient client(loop, serverAddr, "TcpClient"); + client.connect(); + + CurrentThread::sleepUsec(1000*1000); + // client destructs when connected. +} + +int main(int argc, char* argv[]) +{ + Logger::setLogLevel(Logger::DEBUG); + + EventLoop loop; + loop.runAfter(3.0, std::bind(&EventLoop::quit, &loop)); + Thread thr(std::bind(threadFunc, &loop)); + thr.start(); + loop.loop(); +} diff --git a/include/Third_Lib/muduo/net/tests/TcpClient_reg3.cc b/include/Third_Lib/muduo/net/tests/TcpClient_reg3.cc new file mode 100644 index 0000000..bb1e5ee --- /dev/null +++ b/include/Third_Lib/muduo/net/tests/TcpClient_reg3.cc @@ -0,0 +1,24 @@ +// TcpClient destructs in a different thread. + +#include "muduo/base/Logging.h" +#include "muduo/net/EventLoopThread.h" +#include "muduo/net/TcpClient.h" + +using namespace muduo; +using namespace muduo::net; + +int main(int argc, char* argv[]) +{ + Logger::setLogLevel(Logger::DEBUG); + + EventLoopThread loopThread; + { + InetAddress serverAddr("127.0.0.1", 1234); // should succeed + TcpClient client(loopThread.startLoop(), serverAddr, "TcpClient"); + client.connect(); + CurrentThread::sleepUsec(500 * 1000); // wait for connect + client.disconnect(); + } + + CurrentThread::sleepUsec(1000 * 1000); +} diff --git a/include/Third_Lib/muduo/net/tests/TimerQueue_unittest.cc b/include/Third_Lib/muduo/net/tests/TimerQueue_unittest.cc new file mode 100644 index 0000000..65cff93 --- /dev/null +++ b/include/Third_Lib/muduo/net/tests/TimerQueue_unittest.cc @@ -0,0 +1,66 @@ +#include "muduo/net/EventLoop.h" +#include "muduo/net/EventLoopThread.h" +#include "muduo/base/Thread.h" + +#include +#include + +using namespace muduo; +using namespace muduo::net; + +int cnt = 0; +EventLoop* g_loop; + +void printTid() +{ + printf("pid = %d, tid = %d\n", getpid(), CurrentThread::tid()); + printf("now %s\n", Timestamp::now().toString().c_str()); +} + +void print(const char* msg) +{ + printf("msg %s %s\n", Timestamp::now().toString().c_str(), msg); + if (++cnt == 20) + { + g_loop->quit(); + } +} + +void cancel(TimerId timer) +{ + g_loop->cancel(timer); + printf("cancelled at %s\n", Timestamp::now().toString().c_str()); +} + +int main() +{ + printTid(); + sleep(1); + { + EventLoop loop; + g_loop = &loop; + + print("main"); + loop.runAfter(1, std::bind(print, "once1")); + loop.runAfter(1.5, std::bind(print, "once1.5")); + loop.runAfter(2.5, std::bind(print, "once2.5")); + loop.runAfter(3.5, std::bind(print, "once3.5")); + TimerId t45 = loop.runAfter(4.5, std::bind(print, "once4.5")); + loop.runAfter(4.2, std::bind(cancel, t45)); + loop.runAfter(4.8, std::bind(cancel, t45)); + loop.runEvery(2, std::bind(print, "every2")); + TimerId t3 = loop.runEvery(3, std::bind(print, "every3")); + loop.runAfter(9.001, std::bind(cancel, t3)); + + loop.loop(); + print("main loop exits"); + } + sleep(1); + { + EventLoopThread loopThread; + EventLoop* loop = loopThread.startLoop(); + loop->runAfter(2, printTid); + sleep(3); + print("thread loop exits"); + } +} diff --git a/include/Third_Lib/muduo/net/tests/ZlibStream_unittest.cc b/include/Third_Lib/muduo/net/tests/ZlibStream_unittest.cc new file mode 100644 index 0000000..144dda0 --- /dev/null +++ b/include/Third_Lib/muduo/net/tests/ZlibStream_unittest.cc @@ -0,0 +1,91 @@ +#include "muduo/net/ZlibStream.h" + +#include "muduo/base/Logging.h" + +#define BOOST_TEST_MAIN +#define BOOST_TEST_DYN_LINK +#include + +#include + +BOOST_AUTO_TEST_CASE(testZlibOutputStream) +{ + muduo::net::Buffer output; + { + muduo::net::ZlibOutputStream stream(&output); + BOOST_CHECK_EQUAL(output.readableBytes(), 0); + } + BOOST_CHECK_EQUAL(output.readableBytes(), 8); +} + +BOOST_AUTO_TEST_CASE(testZlibOutputStream1) +{ + muduo::net::Buffer output; + muduo::net::ZlibOutputStream stream(&output); + BOOST_CHECK_EQUAL(stream.zlibErrorCode(), Z_OK); + stream.finish(); + BOOST_CHECK_EQUAL(stream.zlibErrorCode(), Z_STREAM_END); +} + +BOOST_AUTO_TEST_CASE(testZlibOutputStream2) +{ + muduo::net::Buffer output; + muduo::net::ZlibOutputStream stream(&output); + BOOST_CHECK_EQUAL(stream.zlibErrorCode(), Z_OK); + BOOST_CHECK(stream.write("01234567890123456789012345678901234567890123456789")); + stream.finish(); + // printf("%zd\n", output.readableBytes()); + BOOST_CHECK_EQUAL(stream.zlibErrorCode(), Z_STREAM_END); +} + +BOOST_AUTO_TEST_CASE(testZlibOutputStream3) +{ + muduo::net::Buffer output; + muduo::net::ZlibOutputStream stream(&output); + BOOST_CHECK_EQUAL(stream.zlibErrorCode(), Z_OK); + for (int i = 0; i < 1024*1024; ++i) + { + BOOST_CHECK(stream.write("01234567890123456789012345678901234567890123456789")); + } + stream.finish(); + // printf("total %zd\n", output.readableBytes()); + BOOST_CHECK_EQUAL(stream.zlibErrorCode(), Z_STREAM_END); +} + +BOOST_AUTO_TEST_CASE(testZlibOutputStream4) +{ + muduo::net::Buffer output; + muduo::net::ZlibOutputStream stream(&output); + BOOST_CHECK_EQUAL(stream.zlibErrorCode(), Z_OK); + muduo::string input; + for (int i = 0; i < 32768; ++i) + { + input += "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-"[rand() % 64]; + } + + for (int i = 0; i < 10; ++i) + { + BOOST_CHECK(stream.write(input)); + } + stream.finish(); + // printf("total %zd\n", output.readableBytes()); + BOOST_CHECK_EQUAL(stream.zlibErrorCode(), Z_STREAM_END); +} + +BOOST_AUTO_TEST_CASE(testZlibOutputStream5) +{ + muduo::net::Buffer output; + muduo::net::ZlibOutputStream stream(&output); + BOOST_CHECK_EQUAL(stream.zlibErrorCode(), Z_OK); + muduo::string input(1024*1024, '_'); + for (int i = 0; i < 64; ++i) + { + BOOST_CHECK(stream.write(input)); + } + printf("bufsiz %d\n", stream.internalOutputBufferSize()); + LOG_INFO << "total_in " << stream.inputBytes(); + LOG_INFO << "total_out " << stream.outputBytes(); + stream.finish(); + printf("total %zd\n", output.readableBytes()); + BOOST_CHECK_EQUAL(stream.zlibErrorCode(), Z_STREAM_END); +} diff --git a/include/center/MirDescript.h b/include/center/MirDescript.h new file mode 100644 index 0000000..1705a7a --- /dev/null +++ b/include/center/MirDescript.h @@ -0,0 +1,69 @@ +#ifndef SRC_CENTER_MIRDESPCRIPT_H +#define SRC_CENTER_MIRDESPCRIPT_H + +#pragma once + +#include +#include + +#include + +#include + + +using uuid = size_t; + +class MirDescript +{ +private: + uint8_t beat_; //心跳次数计数, 用于 + LoadLevel load_level_; //粗略描述负载情况 + DetailLoadState load_state_; //详细负载情况todo: memcpy(this_state, mir_descript.load_state_) + std::unordered_set cli_ids_; //当前负责的cli_ip为了O(1)查找 + std::vector load_cache_; //记录过去一段时间mir负载的缓冲 + +public: + static const constexpr int noexist = -1; + +public: + //mirdescrip只可能被默认创建后进行修改, 因此无其他构造函数 + MirDescript() + : beat_(telemeter::setting->mir_max_disbeat_time_), + load_level_(LoadLevel::untapped), + load_state_({0, 0, 0, RESERVE_SEGMENG_INIT_VALUE}), + cli_ids_(), + load_cache_() {} + + MirDescript(const MirDescript& md) + : beat_(md.beat_), + load_level_(md.load_level_), + load_state_(md.load_state_), + cli_ids_(md.cli_ids_), + load_cache_(md.load_cache_) {} + +public: + uint decre_and_get_beat() { beat_--; return static_cast(beat_); } + + void reset_beat(uint max_disbeat) { assert(max_disbeat <= 128), this->beat_ = max_disbeat; } + + LoadLevel get_load_level() const { return this->load_level_; } + + void set_load_level(LoadLevel ll) { this->load_level_ = ll; } + + void set_detail_state(DetailLoadState&& load) { memcpy(&(this->load_state_), &load, sizeof(DetailLoadState)); } + + bool contains(uuid cli_id) { return this->cli_ids_.find(cli_id) == std::end(this->cli_ids_) ? false : true; } + + void erase_cli(uuid cli_id) { this->cli_ids_.erase(cli_id); } + + std::vector get_dispatched_cli() { + std::vector ret {}; + ret.reserve(cli_ids_.size()); + for(auto cli_id : cli_ids_) + ret.push_back(cli_id); + return ret; + } +}; + + +#endif //SRC_CENTER_MIRDESPCRIPT_H \ No newline at end of file diff --git a/include/center/TcpEcho.h b/include/center/TcpEcho.h new file mode 100644 index 0000000..166fe38 --- /dev/null +++ b/include/center/TcpEcho.h @@ -0,0 +1,24 @@ +#ifndef SRC_CENTER_TCPECHO_H +#define SRC_CENTER_TCPECHO_H + +#include + +class EchoServer +{ +public: + EchoServer(muduo::net::EventLoop* loop, + const muduo::net::InetAddress& listenAddr); + + void start(); // calls server_.start(); + +private: + void onConnection(const muduo::net::TcpConnectionPtr& conn); + + void onMessage(const muduo::net::TcpConnectionPtr& conn, + muduo::net::Buffer* buf, + muduo::Timestamp time); + + muduo::net::TcpServer server_; +}; + +#endif //SRC_CENTER_TCPECHO_H \ No newline at end of file diff --git a/include/center/center.h b/include/center/center.h new file mode 100644 index 0000000..8c29de0 --- /dev/null +++ b/include/center/center.h @@ -0,0 +1,67 @@ +#ifndef SRC_CENTER_H +#define SRC_CENTER_H +#pragma once +#include "netinet/in.h" +#include "sys/socket.h" +#include "arpa/inet.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "MirDescript.h" + +class center +{ +private: + std::set all_cli_; //查找频繁, 不从mirs_data中遍历, 额外保存 + std::unordered_map mirs_data_; //记录信息的树形结构 + + std::atomic atom_mutex_; //读写cookie的原子锁 + std::list cookie_; //记录最近登陆过的cli缓冲 + + muduo::ThreadPool pool_; //线程池 + +private: + //读取配置文件, 交换主副setting指针, 设置下次定时读取的任务 + void read_config(); + + //开启监听cli登录的udp线程, 每隔几十次登录调用一次负载均衡分配算法更改当前的current_available_mir + void wait_cli_login(); + + //开启收听mir心跳的udp线程, mir心跳断线的算法在这里实现, 记录最近一段时间遥测信息的算法也在这里, + void listen_mir_beat(); + + //定时清空登录信息, 默认时间每晚十二点 + void clear_mirs_data(); + + //负载均衡算法, 返回当前能用的mir + IP load_balance(); + +public: + center() + : all_cli_(), + mirs_data_(), + atom_mutex_(false), + pool_() {}; + + center(const center& ) = delete; + + void start(); + + //崩溃时输出程序中当前全部信息到log中 + void log_info(std::exception& e, const char* crush_file); +}; + +#endif //SRC_CENTER_H \ No newline at end of file diff --git a/include/center_head b/include/center_head new file mode 100644 index 0000000..5d423c8 --- /dev/null +++ b/include/center_head @@ -0,0 +1,5 @@ +#pragma once + +#include "Center/center.h" +#include "Center/MirDescript.h" +#include "Center/TcpEcho.h" \ No newline at end of file diff --git a/include/common_head b/include/common_head new file mode 100644 index 0000000..d4b71d9 --- /dev/null +++ b/include/common_head @@ -0,0 +1,5 @@ +#pragma once + +#include "Common/ServerBase.hpp" +#include "Common/Telemeter.hpp" +#include "Common/Udp.hpp" \ No newline at end of file diff --git a/include/mirror/BackGround.hpp b/include/mirror/BackGround.hpp new file mode 100644 index 0000000..5fbab9a --- /dev/null +++ b/include/mirror/BackGround.hpp @@ -0,0 +1,11 @@ +#pragma once + +#include + +struct BackGround{ + int PicId; + std::string PicCode; + std::string PicDes; + + BackGround(int id, const std::string& code,const std::string &des): PicId(id), PicCode(code), PicDes(des){}; +}; \ No newline at end of file diff --git a/include/mirror/ClassMes.hpp b/include/mirror/ClassMes.hpp new file mode 100644 index 0000000..f3547b4 --- /dev/null +++ b/include/mirror/ClassMes.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include +#include +#include + +#include "Lesson.hpp" +#include "CliDescript.hpp" +#include "Message.hpp" + +struct ClassMes final{ + //ClassPlace classPlace_; //教室地点 暂不做内容发送 + Lesson lesson_1; //课程信息 + Lesson lesson_2; + std::string image_url; + std::deque messages; +}; diff --git a/include/mirror/CliDescript.hpp b/include/mirror/CliDescript.hpp new file mode 100644 index 0000000..a4beb73 --- /dev/null +++ b/include/mirror/CliDescript.hpp @@ -0,0 +1,22 @@ +// +// Created by XM on 2021/5/20. +// + +#pragma once + +#include + +namespace Cli{ + using Uuid = unsigned int; +} + +struct CliDes{ + Cli::Uuid id; + int campus; + std::string stamp; +}; + +struct ClassPlace final{ + std::string jxdd_; //教室地点 + unsigned int jsszxqh; //教室所在校区号 +}; diff --git a/include/mirror/Message.hpp b/include/mirror/Message.hpp new file mode 100644 index 0000000..dabc795 --- /dev/null +++ b/include/mirror/Message.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include "CliDescript.hpp" + +struct Message { + std::string title; + std::string text; + size_t expireTime;//seconds +}; + +namespace std { + template<> + struct hash : public __hash_base { + size_t operator()(const Message &rhs) const noexcept //这个const noexpect一定要写上去 + { + return ((std::hash()(rhs.title) << 1) ^ + (std::hash()(rhs.text) << 1) ^ + (std::hash()(rhs.expireTime))); //当然,可以使用其他的方式来组合这个哈希值, + //这里是cppreference里面的例子,产生的数够乱就行。 + } + }; +} \ No newline at end of file diff --git a/include/mirror/Mirror.hpp b/include/mirror/Mirror.hpp new file mode 100644 index 0000000..23dbe42 --- /dev/null +++ b/include/mirror/Mirror.hpp @@ -0,0 +1,165 @@ +#ifndef SRC_MIRROR_H +#define SRC_MIRROR_H + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +//udp使用 +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#include +#include +#include +#include + +#include + +#include + + +#include "ClassMes.hpp" + +using Cli::Uuid; + +class Mirror final { + + struct OldHash { + size_t url_, event_, next_event_; + std::deque msgs_; + + bool operator==(const OldHash &x) { + auto iter1 = msgs_.begin(); + auto iter2 = x.msgs_.begin(); + for(; iter1 != msgs_.end(); iter1++, iter2++){ + if(*iter1 != *iter2) + return false; + } + return this->url_ == x.url_ + && this->event_ == x.event_ + && this->next_event_ == x.next_event_; + //最后一位暂时不做比较 + } + }; + +private: + + //停用内存相关与timestamp + /* + std::unordered_map *wj_clis_data_ = new std::unordered_map; //uuid->info + std::unordered_map *wj_clis_data_copy = new std::unordered_map; //uuid->info + std::unordered_map *ja_clis_data_ = new std::unordered_map; //uuid->info + std::unordered_map *ja_clis_data_copy = new std::unordered_map; //uuid->info + + muduo::Timestamp *wj_timestamp_ = nullptr; + muduo::Timestamp *wj_timestamp_copy = nullptr; + muduo::Timestamp *ja_timestamp_ = nullptr; + muduo::Timestamp *ja_timestamp_copy = nullptr; + */ + + std::unordered_map Class2Campus; + std::unordered_map cli_info_; + + std::atomic_size_t wj_section; + std::atomic_size_t ja_section; + std::atomic_size_t week; + std::atomic_size_t day; + +// 数据库连接 + nanodbc::connection conn; +// 线程池 + muduo::ThreadPool pool_; + +// 数据库配置相关,仅在程序开始时使用 +// 在配置文件获取 + + const std::string config_file_path{"MirrorConfig.txt"}; + + //配置文件 + std::vector wj_Time = { + scu_time(8, 0), scu_time(8, 55), scu_time(10, 0), + scu_time(10, 55), scu_time(14, 0), scu_time(14, 55), + scu_time(15, 30), scu_time(16, 55), scu_time(17, 50), + scu_time(19, 30), scu_time(20, 25), scu_time(21, 20) + }; + + std::vector ja_Time = { + scu_time(8, 15), scu_time(9, 10), scu_time(10, 15), + scu_time(11, 10), scu_time(13, 50), scu_time(14, 45), + scu_time(15, 40), scu_time(16, 45), scu_time(17, 40), + scu_time(19, 20), scu_time(20, 15), scu_time(21, 10) + }; + +private: + //mirror start: + +//Center相关 + + //更新load情况 Task2,udp信息 + void update_data_info(); + +// 自我更新相关 + //更新数据库 Task3 + //暂停该函数 + /* + void update_clis_data(); //定时更新wj_clis_data 和 ja_clis_data + */ + + //定时读取配置文件, 交换主副setting指针, 设置下次定时读取的任务 Task4 + void read_config(); + + //定时清空IP信息的算法, 例如每晚十二点, Task5 + void clear_cli_data(); + + //定时 更新图片与内存信息 + void update_pictures_info(); + + //定时 更新课程节次信息,包括江安与望江 + void update_course_section(); + + //定时 更新校历信息 + void update_school_calendar(); + + //Client相关 + void listen_cli_beat(); + + + + //回调查询信息 + void on_message(const muduo::net::TcpConnectionPtr &conn, + muduo::net::Buffer *msg, + muduo::Timestamp time); + + +/* + void update_timestamp(const muduo::Timestamp &dataStamp, muduo::Timestamp *origin_campus_stamp, + muduo::Timestamp *copy_campus_stamp); +*/ +//配置文件,初始化等 + void init(); + +public: + + //start开始读取配置文件 + void start(); + + Mirror() = default; +}; + +#endif //SRC_MIRROR_H \ No newline at end of file diff --git a/include/mirror/Util.hpp b/include/mirror/Util.hpp new file mode 100644 index 0000000..dafb01b --- /dev/null +++ b/include/mirror/Util.hpp @@ -0,0 +1,65 @@ +#pragma once + +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include + + +namespace db_control { + using Cli::Uuid; + +// void check_week_and_day(nanodbc::connection conn, scu_date &date); + + /* + * param CCmap uuid->ClassMes + * param skjc 上课节次 + * + */ + //暂停使用 +// void +// query_lessons(nanodbc::connection conn, size_t skjc, bool two_lesson, std::unordered_map &CCmap, +// scu_date *date, Uuid id = -1); + + + void query_background(nanodbc::connection &conn, std::vector& backgrounds); + + std::string find_pic(nanodbc::connection &conn, Cli::Uuid id); + + std::deque find_mes(nanodbc::connection &conn, Cli::Uuid id, const std::string &stamp); + + Lesson find_lesson(nanodbc::connection &conn, Cli::Uuid id, int skjc, const scu_date &date); + + int find_campus(nanodbc::connection &conn, Cli::Uuid id); + + scu_date update_calendar(nanodbc::connection &conn, int year, int month, int date); +} + + +namespace json_control { + extern std::string no_need_update; + + void getJson(rapidjson::Writer &writer, const Message &mes); + + void getJson(rapidjson::Writer &writer, const Lesson &les); + + std::string getJsonInfo(const ClassMes &mes, const std::string ×tamp); + + void getIdAndStamp(const std::string& src, Cli::Uuid &id, std::string& stamp); +}//End namespace of json_control + +namespace codec{ + void downPic(const std::string& path, const std::string &code); + +} \ No newline at end of file diff --git a/include/mirror/lesson.hpp b/include/mirror/lesson.hpp new file mode 100644 index 0000000..af0a313 --- /dev/null +++ b/include/mirror/lesson.hpp @@ -0,0 +1,36 @@ +#pragma once + +#include +//#include + +struct Lesson final { + std::string kch_{""}; //课程号 + int kxh_{0}; //课序号 + std::string kcm_{""}; //课程名 + std::string jsxm_{""}; //教师姓名 + std::string jxdd_{""}; //教学地点 + + +// JsonValue get_Event(); + + Lesson(std::string kch, unsigned short kxh, std::string kcm, std::string jsxm, std::string jxdd) : + kch_(kch), kxh_(kxh), kcm_(kcm), jsxm_(jsxm), jxdd_(jxdd) {} + + Lesson() {} + +}; + +namespace std { + template<> + struct hash : public __hash_base + { + size_t operator()(const Lesson &rhs) const noexcept //这个const noexpect一定要写上去 + { + return ((std::hash()(rhs.kch_) << 1) ^ + std::hash()(rhs.kxh_) ^ (std::hash()(rhs.kcm_) << 1) ^ + (std::hash()(rhs.jsxm_) << 1) ^ + (std::hash()(rhs.jxdd_) << 1)); + + } + }; +} diff --git a/include/mirror_head b/include/mirror_head new file mode 100644 index 0000000..7e916c5 --- /dev/null +++ b/include/mirror_head @@ -0,0 +1,9 @@ +#pragma once + +#include "Mirror/ClassMes.hpp" +#include "Mirror/CliDescript.hpp" +#include "Mirror/Lesson.hpp" +#include "Mirror/Message.hpp" +#include "Mirror/Mirror.hpp" +#include "Mirror/BackGround.hpp" +#include "Mirror/Util.hpp" diff --git a/step.md b/step.md new file mode 100644 index 0000000..8dc8973 --- /dev/null +++ b/step.md @@ -0,0 +1,102 @@ +* 切换为root + +sudo -s +(**you passwd**) + +* 基本工具 +apt update +apt upgrade +apt install g++ +apt install cmake +apt install make +apt install git + +* 准备环境 +cd home +mkdir server +cd server + +* 准备第三方库 + + # 下载boost库 +tar -jxvpf boost_1_74_0.tar.bz2 +cd boost_1_74_0 +./bootstrap.sh --with-libraries=all --with-toolset=gcc +./b2 install + + +cd /home/server +# muduo库 + +git clone https://github.com/chenshuo/muduo.git +cd muduo +mkdir build +cd build +cmake .. +make -12 + +# 准备lib里的内容 + + +cd /home/server +# rapidjson库 + +git clone https://github.com/Tencent/rapidjson.git +cd rapidjson +mkdir build +cd build +cmake .. +make -j12 +make install + +# 准备包(package) + +cd /home/server +# nanodbc库 + +# 准备mariadb(已准备) + +# 下载unixodbc +apt install unixodbc + +#下载odbc_config +tar -xzvf unixODBC-2.3.9.tar.gz +cd unixODBC-2.3.9 +./configure --enable-gui=no +make +sudo make install +odbc_config --version #check odbc_config is installed + +# 下载odbc_mariadb +apt install odbc-mariadb + + +# 配置odbc_mariadb +### configure odbc-mariadb + +see complete info on "https://mariadb.com/kb/en/creating-a-data-source-with-mariadb-connectorodbc/" + +[MariaDB ODBC 3.0 Driver] +Description = MariaDB Connector/ODBC v.3.0 +Driver=/usr/lib/x86_64-linux-gnu/odbc/libmaodbc.so + + +cd /home/server +# 下载nanodbc库 +git clone https://github.com/nanodbc/nanodbc.git +cd nanodbc +mkdir build +cd build +cmake .. +make -j12 +make install + +cd /home/server +# 准备好 +cp ./muduo/build/lib/*.a ./cids-pack/Lib/ + +cd /cids-pack +mkdir build +cmake .. +make -j12 + diff --git a/test_driver/client_bootstrap.csc b/test_driver/client_bootstrap.csc index c8c84b8..743e600 100644 --- a/test_driver/client_bootstrap.csc +++ b/test_driver/client_bootstrap.csc @@ -11,18 +11,12 @@ var uuid = "0x46a8e4d9515650e4"hex.shift_left(8) var reconnect_time = 0 function send_bootstrap() - var header = uuid.logic_or(bitset.from_number(reconnect_time)) - system.out.println(header.to_string()) - var header_str = new string - foreach i in range(8) - header_str += char.from_ascii(header.logic_and("0xFF"hex).to_number()) - header = header.shift_right(8) - end + var header = "12345670" var sock = new net.udp.socket sock.open_v4() - foreach i in range(10) do sock.send_to(header_str, server_ep) + foreach i in range(10) do sock.send_to(header, server_ep) try - return runtime.wait_until(100, sock.receive_from, {32, server_ep}) + return runtime.wait_until(100, sock.receive_from, {128, server_ep}) catch e if reconnect_time < 254 ++reconnect_time @@ -36,5 +30,7 @@ loop if ip != null system.out.println("Get: " + ip + ", Reconnect Time: " + reconnect_time) break + else + system.out.println("failed get ip") end end \ No newline at end of file