docs: add CONTRIBUTING.md and CHANGELOG.md; optimize chat parser allocation
Some checks are pending
Build / Build (arm64) (push) Waiting to run
Build / Build (x86-64) (push) Waiting to run
Build / Build (macOS arm64) (push) Waiting to run
Build / Build (windows-arm64) (push) Waiting to run
Build / Build (windows-x86-64) (push) Waiting to run
Security / CodeQL (C/C++) (push) Waiting to run
Security / Semgrep (push) Waiting to run
Security / Sanitizer Build (ASan/UBSan) (push) Waiting to run

CONTRIBUTING.md: code style, PR process, architecture pointers, packet
handler pattern, key files for new contributors.

CHANGELOG.md: grouped changes since v1.8.1-preview into Performance,
Bug Fixes, Features, Security, and Code Quality sections.

Chat parser: use stack-allocated std::array<char, 256> for typical chat
messages instead of heap-allocated std::string. Only falls back to heap
for messages > 256 bytes. Reduces allocator pressure on high-frequency
chat packet handling.
This commit is contained in:
Kelsi 2026-03-27 18:47:35 -07:00
parent e2383725f0
commit 3762dceaa6
3 changed files with 144 additions and 12 deletions

View file

@ -5,6 +5,7 @@
#include "auth/crypto.hpp"
#include "core/logger.hpp"
#include <algorithm>
#include <array>
#include <cctype>
#include <cstring>
#include <sstream>
@ -1478,29 +1479,35 @@ bool MessageChatParser::parse(network::Packet& packet, MessageChatData& data) {
return false;
}
std::string tmp;
tmp.resize(len);
// Stack buffer for typical messages; heap fallback for oversized ones.
static constexpr uint32_t kStackBufSize = 256;
std::array<char, kStackBufSize> stackBuf;
std::string heapBuf;
char* buf;
if (len <= kStackBufSize) {
buf = stackBuf.data();
} else {
heapBuf.resize(len);
buf = heapBuf.data();
}
for (uint32_t i = 0; i < len; ++i) {
tmp[i] = static_cast<char>(packet.readUInt8());
buf[i] = static_cast<char>(packet.readUInt8());
}
if (tmp.empty() || tmp.back() != '\0') {
if (buf[len - 1] != '\0') {
packet.setReadPos(start);
return false;
}
tmp.pop_back();
if (tmp.empty()) {
packet.setReadPos(start);
return false;
}
for (char c : tmp) {
unsigned char uc = static_cast<unsigned char>(c);
// len >= 2 guaranteed above, so len-1 >= 1 — string body is non-empty.
for (uint32_t i = 0; i < len - 1; ++i) {
auto uc = static_cast<unsigned char>(buf[i]);
if (uc < 32 || uc > 126) {
packet.setReadPos(start);
return false;
}
}
out = std::move(tmp);
out.assign(buf, len - 1);
return true;
};