[TOC]
C++公用基础库,仿照chromium-base,提供一些基本的功能实现,可以在项目中方便导入,提高开发效率.
git submodule update --init --recursive
mkdir build
cd build
cmake .. -DCMAKE_BUILD_TYPE=Debug/Release
make
可以在make编译完后执行make test
,或者直接运行生成的单元测试程序base_unittest
.
先列着,慢慢来吧~~~
类或函数 | 文件 | 说明 | 完成情况 |
---|---|---|---|
TaskQueue | base/thread/task_queue.h | 任务队列 | 已完成 |
MessageLoop | base/thread/message_loop.h | 消息循环队列 | 已完成 |
Thread | base/thread/thread.h | 基于消息循环的线程 | 已完成 |
LOG | base/log/logging.h | 日志 | 已完成 |
Singleton | base/singleton.h | 单例模板类 | 已完成 |
AtExitManager | base/at_exit.h | 注册退出函数 | 已完成 |
Base64Encode/Base64Decode | base/encode/base64.h | base64加密和解密 | 已完成 |
Md5 | base/encode/md5.h | md5散列 | 已完成 |
CRC32 | base/hash/crc32.h | crc32校验值计算 | 已完成 |
Hash | base/hash/hash.h | hash散列 | 已完成 |
ThreadPool | base/thread/thread_pool.h | 基于消息循环线程的线程池 | 已完成 |
ElapsedTimer | base/timer/elapsed_timer.h | 计时器 | 已完成 |
DelayTimer | base/timer/delay_timer.h | 定时器 | 已完成 |
Json | 简单封装,复杂操作请直接使用rapidjson,位于src/base/third_party/rapidjson |
Json库封装 | 已完成,可参考单元测试src/test/json/json_unittest.cc |
TreeArray | base/array/tree_array.h | 树型数组 | 已完成 |
GUID | base/guid.h | 生成guid | 已完成 |
Rand | base/rand_util.h | 产生简单的随机数 | 已完成 |
String | base/string/string_utils.h | 提供字符串比较、判断开头和结尾等操作 | 部分完成,待后续完善 |
File | base/file/file.h | 文件跨平台封装 | 待开发 |
IPCHandler | base/ipc/ipc_handler.h | 封装跨平台进程间通信 | 待开发 |
Process | base/process/process.h | 封装跨平台进程创建和运行 | 待开发 |
TCPServer | base/net/tcp_server.h | 封装跨平台tcp server(两种网络模型) | 待开发 |
TCPClient | base/net/tcp_client.h | 封装跨平台tcp client | 待开发 |
UDPServer | base/net/udp_server.h | 封装跨平台udp server | 待开发 |
UDPClient | base/net/udp_client.h | 封装跨平台udp client | 待开发 |
Metrics | base/metrics.h | 封装数据统计接口 | 待开发 |
任务队列,提供任务入队和出队操作,提供锁保护
函数 | 说明 | 注意事项 |
---|---|---|
PushTask | 任务入队 | 自带锁保护 |
PopTask | 任务出队 | 自带锁保护 |
Empty | 任务队列是否为空 | |
Clear | 清空队列 | 自带锁保护 |
消息循环队列,使用它可以将任何当前线程改造成消息循环线程.
#include "base/thread/message_loop.h"
base::MessageLoop loop;
loop.BindToCurrentThread();
......
loop.RunLoop();
函数 | 说明 | 注意事项 |
---|---|---|
RunLoop | 调用之后,当前线程会进入循环,可以处理其他线程抛过来的任务 | 除非其他线程有调用它的Stop() 函数, 它才能退出循环 |
PostTask | 抛任务,任务执行完不会回调 | 可在任意线程上调用 |
PostTaskAndReply | 抛任务,带回调,抛出的任务执行完后,回调函数会被抛回源线程执行 | 传递的回调函数不能传递参数,带参数版本的借口待开发 |
PostDelayTask/PostDelayTaskAndReply | 延时执行任务的版本 | |
Stop | 任务都执行完后,停止消息循环 | 调用后就不会再接收新的任务 |
StopSoon | 清空任务队列,立即停止消息循环 |
- 提供可传递参数的PostTask回调:
PostTaskAndReplyWithResult
;
基于消息循环的线程类
#include "base/thread/thread.h"
base::Thread thread_io;
thread_io.Start();
thread_io.PostTaskAndReply(...);
函数 | 说明 | 注意事项 |
---|---|---|
SetName/GetName | 给线程取名 | |
Start/Stop | 启动/停止线程 | Start保证任务队列启动成功 |
PostTask/PostTaskAndReply | 抛任务 | 对MessageLoop借口的封装 |
PostDelayTask/PostDelayTaskAndReply | 延时执行的任务 | 对MessageLoop借口的封装 |
Stop | 执行完任务后,关闭线程 | |
StopSoon | 清空尚未执行的任务,关闭线程 |
日志格式: [进程号:线程号:日期/时间.微秒:日志级别:文件(行号)] 日志内容
使用示例:
#include "base/log/logging.h"
// 初始化日志配置
logging::InitLogging("test.log", logging::LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG, logging::APPEND_TO_OLD_LOG_FILE);
LOG(INFO) << "------------------------------END------------------------------------------" << 1;
函数或接口 | 说明 | 注意事项 |
---|---|---|
SetLogMessageHandler | 自定义日志处理函数,可用通过设置接口由程序自己控制日志处理. 函数原型bool(int severity, const char* file, const int line, const char* message)> |
当设置的日志回调函数返回true 时表示不再由日志系统对日志进行处理,返回false 时,日志系统将继续处理这条日志. |
GetLogMessageHandler | 获取当前自定义日志处理函数 | 默认为nullptr |
SetMinLogLevel/GetMinLogLevel | 设置或获取会被处理日志的最低级别.日志供分为LOG_DEBUG /LOG_INFO /LOG_WARNING /LOG_ERROR /LOG_FATAL ,其值分别标识-1~3 . |
默认debug模式下最低级别为LOG_DEBUG ,release模式下为LOG_WARNING |
InitLogging | 对默认日志配置进行修改,LoggingDestination 参数表示日志是要输出到文件还是控制台; OldFileDeletionState 参数决定当日志文件重名时,要不要删除旧文件重写 |
如果不调用这个接口,日志系统会以默认参数运行(日志只打印到控制台) |
LOG | 创建日志,可以使用LOG(DEBUG)/LOG(INFO)/LOG(WARNING)/LOG(ERROR)/LOG(FATAL) 来创建对应级别的日志. |
日志级别小于所设置的最低处理级别时,日志不会被处理. |
DLOG | DEBUG模式下才会处理的日志 | |
CHECK | 检查条件是否成立,类似assert 的作用 |
|
DCHECK | DEBUG模式下才会生效的CHECK |
- 日志文件大小限制,包括单个文件大小和总的日志文件大小;
- 合并写入日志文件,减少写文件操作.
一个简单的单例类模板,使用了锁保证创建单例对象的线程安全,但是不保证其他对象逻辑线程安全.
使用示例:
#include "base/singleton.h"
class A {...};
typedef Singleton<A> ASingleton;
ASingleton::GetInstance()->...
只为了在项目中创建单例类方便,很简单,没什么好讲的.
其作用类似atexit(),即在声明周期结束后执行所注册的回调。在该对象的生命周期内可注册多个回调函数,在对象销毁时所有的注册函数按照出栈的形式来调用。
示例:
#include "base/at_exit.h"
#include "base/log/logging.h"
void printResult(int sum) {
LOG(INFO) << "-------sum-------" << sum;
}
int main() {
base::AtExitManager exit_manager;
base::AtExitManager::RegisterCallback(std::bind(printResult, 100));
base::AtExitManager::RegisterCallback(std::bind(printResult, 101));
base::AtExitManager::RegisterCallback(std::bind(printResult, 102));
{
base::AtExitManager exit_manager_2;
base::AtExitManager::RegisterCallback(std::bind(printResult, 103));
base::AtExitManager::RegisterCallback(std::bind(printResult, 104));
base::AtExitManager::RegisterCallback(std::bind(printResult, 105));
}
base::AtExitManager exit_manager_3;
base::AtExitManager::RegisterCallback(std::bind(printResult, 107));
base::AtExitManager::RegisterCallback(std::bind(printResult, 108));
base::AtExitManager::RegisterCallback(std::bind(printResult, 109));
return 0;
}
最后运行结果:
[24643:24643:0518/133342.891162:INFO:thread_test.cc(35)] -------sum-------105
[24643:24643:0518/133342.891221:INFO:thread_test.cc(35)] -------sum-------104
[24643:24643:0518/133342.891242:INFO:thread_test.cc(35)] -------sum-------103
[24643:24643:0518/133342.891265:INFO:thread_test.cc(35)] -------sum-------109
[24643:24643:0518/133342.891290:INFO:thread_test.cc(35)] -------sum-------108
[24643:24643:0518/133342.891309:INFO:thread_test.cc(35)] -------sum-------107
[24643:24643:0518/133342.891330:INFO:thread_test.cc(35)] -------sum-------102
[24643:24643:0518/133342.891350:INFO:thread_test.cc(35)] -------sum-------101
[24643:24643:0518/133342.891369:INFO:thread_test.cc(35)] -------sum-------100
函数或接口 | 说明 | 注意事项 |
---|---|---|
RegisterCallback | 静态函数,注册退出时回调 | 调用顺序和注册顺序相反 |
RunCallbacksNow | 静态函数,立即执行当前AtExitManager 对象中注册的回调 |
提供简单的base64加密解解密功能,主要copy自chromium中的实现.
示例:
#include "base/log/logging.h"
#include "base/encode/base64.h"
std::string input = "121321321asdadadsadsad";
std::string result = base::Base64Encode(input);
std::string output;
bool valid = base::Base64Decode(result, &output);
LOG(WARNING) << input;
LOG(WARNING) << result;
LOG(WARNING) << valid << "-----" << output;
输出结果:
[22337:22337:0518/192643.265964:WARNING:thread_test.cc(104)] 121321321asdadadsadsad
[22337:22337:0518/192643.266039:WARNING:thread_test.cc(105)] MTIxMzIxMzIxYXNkYWRhZHNhZHNhZA==
[22337:22337:0518/192643.266075:WARNING:thread_test.cc(106)] 1-----121321321asdadadsadsad
函数或接口 | 说明 | 注意事项 |
---|---|---|
Base64Encode | base64加密函数 | |
Base64Decode | base64解密函数 | 输出注意是string指针 |
简单的线程池,基于base/thread/thread.h
,非阻塞. 注意在构造函数时就已经创建了线程,但是都还未运行,需要等到调用Start,才能开始接收任务.
示例:
#include "base/thread/thread_pool.h"
#include "base/log/logging.h"
#include "base/utils.h"
base::ThreadPool pool(10);
pool.Start();
auto timestamp = base::GetMillSecondsTimestamp();
for(int i= 0 ; i< 10000; i++) {
pool.PostTask([=]() {
LOG(WARNING) << "----------------------------" << i;
// std::this_thread::sleep_for(std::chrono::seconds(3));
});
}
pool.Stop();
LOG(WARNING) << "Use time: " << base::GetMillSecondsTimestamp() - timestamp << " ms";
函数或接口 | 说明 | 注意事项 |
---|---|---|
Start | 开始运行线程池 | 只有调用Start后才会开始接收任务,且此操作为非阻塞操作 |
Stop | 停止线程池 | 此接口需要得到已有任务完成才会完全退出. |
PostTask | 传递任务 |
改进方向:
- 提供接收回调任务接口;
- 提供延时任务接口.
简单的Hash散列计算函数. 基于cityhash项目.
示例:
#include "base/log/logging.h"
#include "base/hash/hash.h"
std::string test = "1232423中国1231312";
LOG(WARNING) << "--------------" << std::hex << base::Hash(test) << "---" << base::Hash64(test) << "----" << base::Hash128(test).first << base::Hash128(test).second;
std::wstring test1 = L"1232423中国1231312";
LOG(WARNING) << "-----2---------" << std::hex << base::Hash(test1) << "---" <<base::Hash64(test1) << "----" << base::Hash128(test1).first << base::Hash128(test1).second;
LOG(WARNING) << "-----md5------" << base::FastMD5(test);
运行结果:
[14202:14202:0519/210024.549851:WARNING:thread_test.cc(130)] --------------948f8e9c---c3ac8f11bcf5bfd9----7e9ce8a954094c9b1a6ac0c513b6bf4f
[14202:14202:0519/210024.549861:WARNING:thread_test.cc(132)] -----2---------948f8e9c---c3ac8f11bcf5bfd9----7e9ce8a954094c9b1a6ac0c513b6bf4f
[14202:14202:0519/210024.549981:WARNING:thread_test.cc(133)] -----md5------d482a1faf595dc83ecbc5378b25f90af
宽字符串也是先转换成char再进行计算hash值的.
函数或接口 | 说明 | 注意事项 |
---|---|---|
Hash | 得到32位整数值结果的hash | 注意存放结果的buff需要自己分配足够内存 |
Hash64 | 得到64位整数的hash | 注意存放结果的buff需要自己分配足够内存 |
Hash128 | 得到128位整数的hash | 结果以一个pair<64,64>保存; 注意存放结果的buff需要自己分配足够内存 |
FastMD5 | md5计算 | 快速计算一个字符串的md5值 |
FastFileMD5 | 文件的md5值计算 | 计算一个文件的md5值 |
MD5 | md5类 | 用于定制需求 |
Crc32 | crc32计算接口 | 提供了两个接口,分别计算字符串和文件的crc32值 |
一个简单的计时器. 创建时就开始计时.
示例:
#include "base/timer/elapsed_timer.h"
base::ElapsedTimer timer;
......
base::TimeDelta delta = timer.Elapsed();
LOG(WARNING) << delta.InMicroseconds();
LOG(WARNING) << timer.Begin() << "----" << timer.Elapsed();
函数或接口 | 说明 | 注意事项 |
---|---|---|
Elapsed | 获取到目前位置时间长度 | 返回base::TimeDelta 对象 |
Begin | 返回开始计时的时间戳(微秒) |
延时定时器,可以触发任务. 非阻塞操作依赖base::Thread
实现.
示例:
#include "base/time/time.h"
#include "base/timer/delay_timer.h"
#include "base/thread/thread.h"
void print_timestap(int index) {
LOG(WARNING) << index << "---------" << base::Now();
}
base::MessageLoop loop;
print_timestap(0);
base::Thread io;
io.Start();
io.PostDelayTask(base::TimeDelta::FromSeconds(3), std::bind(print_timestap, 1));
io.PostDelayTask(base::TimeDelta::FromSeconds(1), std::bind(print_timestap, 2));
io.PostTask(std::bind(print_timestap, 3));
io.PostTask(std::bind(print_timestap, 4));
io.PostTask(std::bind(print_timestap, 5));
io.PostTaskAndReply(nullptr, std::bind(print_timestap, 6));
base::DelayTimer delay_timer(base::TimeDelta::FromSeconds(5));
delay_timer.SyncBlockWait(std::bind(print_timestap, 6));
print_timestap(7);
delay_timer.SyncNoBlockWait(std::bind(print_timestap, 8));
delay_timer.AsyncWait(std::bind(print_timestap, 9));
delay_timer.AsyncWait(std::bind(print_timestap, 10));
delay_timer.Cancle();
print_timestap(11);
base::DelayTimer delay_timer2(base::TimeDelta::FromSeconds(3));
delay_timer2.AsyncWait(std::bind(print_timestap, 12));
loop.RunLoop();
输出:
[12847:12847:0523/105000.088835:WARNING:thread_test.cc(148)] 0---------1590202200088869
[12847:12848:0523/105000.089256:WARNING:thread_test.cc(148)] 3---------1590202200089288
[12847:12848:0523/105000.089332:WARNING:thread_test.cc(148)] 4---------1590202200089342
[12847:12848:0523/105000.089370:WARNING:thread_test.cc(148)] 5---------1590202200089377
[12847:12848:0523/105001.089233:WARNING:thread_test.cc(148)] 2---------1590202201089240
[12847:12848:0523/105003.089212:WARNING:thread_test.cc(148)] 1---------1590202203089219
[12847:12847:0523/105005.089382:WARNING:thread_test.cc(148)] 6---------1590202205089403
[12847:12847:0523/105005.089440:WARNING:thread_test.cc(148)] 7---------1590202205089446
[12847:12847:0523/105005.090000:WARNING:thread_test.cc(148)] 11---------1590202205090015
[12847:12847:0523/105005.090305:WARNING:thread_test.cc(148)] 6---------1590202205090323
[12847:12851:0523/105008.090304:WARNING:thread_test.cc(148)] 12---------1590202208090313
函数或接口 | 说明 | 注意事项 |
---|---|---|
SyncBlockWait | 同步阻塞等待,即需要定时器超时才能继续执行 | 不依赖MessageLoop;调用它定时器才会计时 |
SyncNoBlockWait | 同步非阻塞等待,即定时器超时后回调到源线程执行 | 依赖MessageLoop, 即原线程需要是消息循环线程,且不会被长期阻塞在某个任务上 |
AsyncWait | 异步等待,定时器超时后任务会在其他线程上执行 | 原线程不依赖于MessageLoop |
Cancle | 取消定时器 | 会立刻取消所有还未触发的任务 |
注意:本定时器,一个定时器可以多次wait,每次都是重新开始计时.
树型数组:就是用数组来模拟树状结构,常用在频繁执行数组前缀和计算的场景中. 有关介绍可以参考: https://www.cnblogs.com/xl2432/p/12974749.html .
示例:
#include "base/array/tree_array.h"
base::TreeArray<int> tree(100);
for(int i = 1; i <= 100; i++) {
tree.set(i, i);
}
LOG(WARNING) << "-----0-------" << tree.get(50);
LOG(WARNING) << "-----1-------" << tree.get(100);
LOG(WARNING) << "-----2-------" << tree.sum(50);
LOG(WARNING) << "-----3-------" << tree.sum(100);
tree.add(50, 1);
LOG(WARNING) << "-----0-------" << tree.get(50);
LOG(WARNING) << "-----4-------" << tree.sum(50);
LOG(WARNING) << "-----5-------" << tree.sum(100);
tree.set(50, 50);
LOG(WARNING) << "-----0-------" << tree.get(50);
LOG(WARNING) << "-----6-------" << tree.sum(50);
LOG(WARNING) << "-----7-------" << tree.sum(100);
输出:
[1150:1150:0527/170551.372410:WARNING:thread_test.cc(201)] -----0-------50
[1150:1150:0527/170551.372463:WARNING:thread_test.cc(202)] -----1-------100
[1150:1150:0527/170551.372481:WARNING:thread_test.cc(203)] -----2-------1275
[1150:1150:0527/170551.372501:WARNING:thread_test.cc(204)] -----3-------5050
[1150:1150:0527/170551.372519:WARNING:thread_test.cc(206)] -----0-------51
[1150:1150:0527/170551.372537:WARNING:thread_test.cc(207)] -----4-------1276
[1150:1150:0527/170551.372556:WARNING:thread_test.cc(208)] -----5-------5051
[1150:1150:0527/170551.372573:WARNING:thread_test.cc(210)] -----0-------50
[1150:1150:0527/170551.372591:WARNING:thread_test.cc(211)] -----6-------1275
[1150:1150:0527/170551.372608:WARNING:thread_test.cc(212)] -----7-------5050
注意: 只支持数学计算的类型,如int/float/double等; 数组索引是从1开始.
接口都很简单,一目了然.
全局唯一标识符(英語:Globally Unique Identifier,缩写:GUID)是一种由算法生成的唯一标识,通常表示成32个16进制数字(0-9,A-F)组成的字符串。
本项目中提供小写版本的guid生成器,格式类似:01234567-89ab-cdef-fedc-ba9876543210
。 需要大写的请使用base/string/string_convert.h
里的StrToUpper
将其再转成大写字母。
代码位置:src/base/guid.h
函数或接口 | 说明 | 注意事项 |
---|---|---|
GenerateGUID | 生成一个guid | |
IsValidGUID | 判断是否是合法的guid | |
RandomDataToGUIDString | 将一个uint64_t[2] 的数组转换为一个guid |
具体实例,请参考单元测试:src/test/guid/guid_unittest.cc
。
使用系统调用实现的不容易重复的随机数生成器,GUID是基于该Rand实现的,实测比C++库中的随机数生成器生成的数重复概率小。
代码位置: src/base/rand_util.h
函数或接口 | 说明 | 注意事项 |
---|---|---|
RandUint64 | 生成一个uint64_t随机数 | |
RandInt | 生成一个int随机数 | |
RandGenerator | 生成一个范围内的随机数 | |
RandDouble | 生成一个浮点随机数 | |
RandBytes | 使用随机数填充缓冲区 |
具体实例,请参考单元测试:src/test/guid/rand_unittest.cc
。
提供各种字符串操作。由于相关的操作比较多,待后续继续完善。
代码位置src/base/string/string_utils.h
、src/base/string/string_convert.h
。
函数或接口 | 说明 | 注意事项 |
---|---|---|
IsHexDigit | 模板函数,判断类是否是是16进制字符,大小写均可 | 支持char和wchar |
ToLowerASCII | 转换成小写 | char和wchar、string和wstring均可 |
ToUpperASCII | 转换成大写 | char和wchar、string和wstring均可 |
CompareCaseInsensitiveASCII | 忽略大小写比较字符串 | 前者比后者大,返回1;两者相等,返回0;前者比后者小,返回-1;从头往后找,因此长度长的不一定大;支持string和wstring |
EqualsCaseInsensitiveASCII | 判断两个字符串是否相等,忽略大小 | 支持string和wstring |
StartsWith | 判断字符串开头 | 支持string和wstring; 第三个参数可以指明是否忽略大小写 |
EndsWith | 判断字符串结尾 | 支持string和wstring; 第三个参数可以指明是否忽略大小写 |
IsDigitStrs | 判断字符串中是否只有数字字符 | 支持string和wstring |
SplitStr | 将字符串按照指定字符分割,以vector形式返回 | 注意如果最后一个字符恰好为指定字符,那么其后面不会认为是一个元素 |
AnsiToUnicode | char* 转 wchar_t* 或者 string转wstring | 两个版本 |
UnicodeToAnsi | wchar_t转char 或者wstring转string |
具体实例,请参考单元测试:src/test/string/string_unittest.cc
。