Files
QTradeProgram/FTAPI/tool.h
2025-08-15 15:57:31 +08:00

270 lines
6.5 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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
}
};