update code
This commit is contained in:
269
FTAPI/tool.h
Normal file
269
FTAPI/tool.h
Normal file
@@ -0,0 +1,269 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <time.h>
|
||||
#include <semaphore.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
#include <iostream>
|
||||
#include <stdint.h>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <stdlib.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#include <google/protobuf/io/zero_copy_stream_impl.h>
|
||||
|
||||
#include "Include_FTAPI.h"
|
||||
#include "Include_3rd_protobuf.h"
|
||||
using namespace google;
|
||||
using namespace Futu;
|
||||
|
||||
#pragma warning(disable:4100)
|
||||
#pragma warning(disable:4189)
|
||||
|
||||
inline void ProtoBufToBodyData(const protobuf::Message& pbObj, string& strBody)
|
||||
{
|
||||
protobuf::util::JsonPrintOptions ops;
|
||||
ops.add_whitespace = true;
|
||||
ops.always_print_enums_as_ints = true;
|
||||
|
||||
protobuf::util::Status status = MessageToJsonString(pbObj, &strBody, ops);
|
||||
if (status.error_code() != protobuf::util::error::OK)
|
||||
{
|
||||
strBody.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// 基础优化,提升3-5倍速度
|
||||
inline void ProtoBufToBodyData_Ex(const protobuf::Message& pbObj, std::string& strBody) {
|
||||
thread_local static std::string buffer; // 线程局部复用缓冲区
|
||||
buffer.clear();
|
||||
|
||||
protobuf::util::JsonPrintOptions ops;
|
||||
ops.add_whitespace = false; // 关闭非必要空白
|
||||
ops.preserve_proto_field_names = true;// 避免字段名转换
|
||||
ops.always_print_primitive_fields = false; // 跳过空字段
|
||||
|
||||
if (protobuf::util::MessageToJsonString(pbObj, &buffer, ops).ok()) {
|
||||
strBody.swap(buffer); // 零拷贝交换缓冲区
|
||||
}
|
||||
else {
|
||||
strBody.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// 修改ProtoBufToBodyData_Ex函数
|
||||
inline void ProtoBufToBodyData_Binary(const protobuf::Message& pbObj, std::string& strBody) noexcept {
|
||||
thread_local static std::string buffer;
|
||||
pbObj.SerializeToString(&buffer); // 直接序列化为二进制
|
||||
strBody.swap(buffer);
|
||||
buffer.clear();
|
||||
}
|
||||
|
||||
//// 解析二进制数据
|
||||
//void parse_protobuf(const char* buffer, int length) {
|
||||
// // 反序列化
|
||||
// Qot_GetPlateSet::Response response;
|
||||
// if (!response.ParseFromArray(buffer, length)) {
|
||||
// std::cerr << "Failed to parse protobuf data." << std::endl;
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// // 检查返回状态
|
||||
// if (response.rettype() != 0) { // 假设 0 表示成功
|
||||
// std::cerr << "Error: " << response.retmsg()
|
||||
// << " (Code: " << response.errcode() << ")" << std::endl;
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// // 检查是否存在 s2c 字段
|
||||
// if (!response.has_s2c()) {
|
||||
// std::cout << "No data in response." << std::endl;
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// const Qot_GetPlateSet::S2C& s2c = response.s2c();
|
||||
// //std::cout << "Last Page: " << s2c.plateinfolist().size();
|
||||
// // << ", Total Count: " << s2c.allcount() << std::endl;
|
||||
//
|
||||
// //遍历板块列表
|
||||
// for (int i = 0; i < s2c.plateinfolist_size(); ++i) {
|
||||
// const::Qot_Common::PlateInfo& plateinfo = s2c.plateinfolist(i);
|
||||
// string name = plateinfo.name();
|
||||
// string code = plateinfo.plate().code();
|
||||
// }
|
||||
//}
|
||||
|
||||
inline void FastSerializeProto(const protobuf::Message& pbObj, std::string& strBody) noexcept {
|
||||
// 线程局部内存池
|
||||
thread_local static struct {
|
||||
std::string buffer;
|
||||
size_t last_capacity = 0;
|
||||
} tls_pool;
|
||||
|
||||
// 智能预分配策略
|
||||
const size_t need_size = pbObj.ByteSizeLong();
|
||||
if (tls_pool.last_capacity < need_size * 1.2) {
|
||||
tls_pool.buffer.reserve(std::max(need_size * 2, size_t(4096)));
|
||||
tls_pool.last_capacity = tls_pool.buffer.capacity();
|
||||
}
|
||||
|
||||
// 零拷贝序列化
|
||||
tls_pool.buffer.clear();
|
||||
pbObj.SerializeToString(&tls_pool.buffer);
|
||||
strBody.swap(tls_pool.buffer); // O(1)交换操作
|
||||
}
|
||||
|
||||
// 在公共头文件中添加
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
# define MY_PREDICT_FALSE(x) (__builtin_expect(!!(x), 0))
|
||||
# define MY_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1))
|
||||
#else
|
||||
# define MY_PREDICT_FALSE(x) (x)
|
||||
# define MY_PREDICT_TRUE(x) (x)
|
||||
#endif
|
||||
|
||||
inline bool FastDeserializeProto(const std::string& strBody, protobuf::Message& pbObj) noexcept {
|
||||
// 零拷贝解析器
|
||||
protobuf::io::ArrayInputStream raw_input(strBody.data(), strBody.size());
|
||||
protobuf::io::CodedInputStream coded_input(&raw_input);
|
||||
|
||||
// 设置解析限制(防止恶意大包)
|
||||
coded_input.SetTotalBytesLimit(100 * 1024 * 1024, 50 * 1024 * 1024); // 100MB最大限制
|
||||
|
||||
// 快速解析主逻辑
|
||||
if (MY_PREDICT_FALSE(!pbObj.ParseFromCodedStream(&coded_input))) {
|
||||
pbObj.Clear(); // 确保对象状态可复用
|
||||
return false;
|
||||
}
|
||||
|
||||
// 校验必填字段
|
||||
if (MY_PREDICT_FALSE(!pbObj.IsInitialized())) {
|
||||
pbObj.Clear();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
inline string UTF8ToGBK(const string &strUTF8)
|
||||
{
|
||||
int nLen = MultiByteToWideChar(CP_UTF8, 0, strUTF8.c_str(), -1, NULL, 0);
|
||||
wchar_t* wszGBK = new wchar_t[nLen + 1];
|
||||
memset(wszGBK, 0, nLen * 2 + 2);
|
||||
MultiByteToWideChar(CP_UTF8, 0, strUTF8.c_str(), -1, wszGBK, nLen);
|
||||
nLen = WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, NULL, 0, NULL, NULL);
|
||||
char* szGBK = new char[nLen + 1];
|
||||
memset(szGBK, 0, nLen + 1);
|
||||
WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, szGBK, nLen, NULL, NULL);
|
||||
string strGBK(szGBK);
|
||||
if (wszGBK) delete[] wszGBK;
|
||||
if (szGBK) delete[] szGBK;
|
||||
return strGBK;
|
||||
}
|
||||
#endif
|
||||
|
||||
inline string UTF8ToLocal(const string &strUTF8)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
int nCodePage = GetConsoleOutputCP();
|
||||
if (nCodePage == 936)
|
||||
{
|
||||
return UTF8ToGBK(strUTF8);
|
||||
}
|
||||
else
|
||||
{
|
||||
return strUTF8;
|
||||
}
|
||||
#else
|
||||
return strUTF8;
|
||||
#endif
|
||||
}
|
||||
|
||||
#define PrintRsp(str) std::cout << str << endl;\
|
||||
string strBody;\
|
||||
ProtoBufToBodyData(stRsp, strBody);\
|
||||
std::cout << strBody << endl;
|
||||
|
||||
#define Print(str) std::cout << str << endl;
|
||||
|
||||
|
||||
#define PrintError(errMsg) std::cout << "ERROR: " << __FUNCTION__ << ", retMsg = " << errMsg << std::endl;
|
||||
|
||||
#define PrintUTF8(errMsg) std::cout << "ERROR: " << __FUNCTION__ << ", retMsg = " << UTF8ToLocal(errMsg) << std::endl;
|
||||
|
||||
inline void CPSleep(int32_t nSec)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
Sleep(nSec * 1000);
|
||||
#else
|
||||
struct timespec spec;
|
||||
spec.tv_sec = nSec;
|
||||
spec.tv_nsec = 0;
|
||||
nanosleep(&spec, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
class Semaphore
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
HANDLE m_sema;
|
||||
#else
|
||||
sem_t *m_sem;
|
||||
#endif
|
||||
|
||||
public:
|
||||
Semaphore(int32_t initValue)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
m_sema = ::CreateSemaphoreA(NULL, initValue, 0x7fffffff, NULL);
|
||||
#else
|
||||
pid_t pid = getpid();
|
||||
stringstream str;
|
||||
str << "ftapi.sample." << (long)pid;
|
||||
m_sem = ::sem_open(str.str().c_str(), O_CREAT | O_EXCL, S_IRWXU, initValue);
|
||||
#endif
|
||||
}
|
||||
|
||||
~Semaphore()
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
::CloseHandle(m_sema);
|
||||
#else
|
||||
::sem_close(m_sem);
|
||||
#endif
|
||||
}
|
||||
|
||||
void wait()
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
::WaitForSingleObject(m_sema, INFINITE);
|
||||
#else
|
||||
::sem_wait(m_sem);
|
||||
#endif
|
||||
}
|
||||
|
||||
void post()
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
::ReleaseSemaphore(m_sema, 1, NULL);
|
||||
#else
|
||||
::sem_post(m_sem);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool trywait()
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
return WAIT_OBJECT_0 == ::WaitForSingleObject(m_sema, 0);
|
||||
#else
|
||||
return 0 == ::sem_trywait(m_sem);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user