From 38c059938014e6d6f63e6c036e6244be1547ed4c Mon Sep 17 00:00:00 2001 From: Chris Marsh Date: Mon, 24 Jul 2017 14:59:45 -0700 Subject: [PATCH] Just use stack allocations in parsing by default. --- src/discord-rpc.cpp | 65 ++++++++++++++++++++++++++++-------------- src/rpc_connection.cpp | 5 +++- src/serialization.cpp | 8 ++++-- src/serialization.h | 11 ++++--- 4 files changed, 59 insertions(+), 30 deletions(-) diff --git a/src/discord-rpc.cpp b/src/discord-rpc.cpp index be6f3f3..e0eb5d9 100644 --- a/src/discord-rpc.cpp +++ b/src/discord-rpc.cpp @@ -82,35 +82,56 @@ extern "C" void Discord_UpdateConnection() } else { // reads - JsonDocument message; - while (Connection->Read(message)) { + + // json parser will use this buffer first, then allocate more if needed; I seriously doubt we send any messages that would use all of this, though. + char parseBuffer[32 * 1024]; + for (;;) { + PoolAllocator pa(parseBuffer, sizeof(parseBuffer)); + StackAllocator sa; + JsonDocument message(rapidjson::kObjectType, &pa, sizeof(sa.fixedBuffer_), &sa); + + if (!Connection->Read(message)) { + break; + } + + const char* evtName = nullptr; + auto evt = message.FindMember("evt"); + if (evt != message.MemberEnd() && evt->value.IsString()) { + evtName = evt->value.GetString(); + } + auto nonce = message.FindMember("nonce"); if (nonce != message.MemberEnd() && nonce->value.IsString()) { // in responses only -- should use to match up response when needed. - //auto cmd = message.FindMember("cmd"); needed? + + if (evtName && strcmp(evtName, "ERROR") == 0) { + auto data = message.FindMember("data"); + LastErrorCode = data->value["code"].GetInt(); + StringCopy(LastErrorMessage, data->value["message"].GetString()); + GotErrorMessage.store(true); + } } else { // should have evt == name of event, optional data - auto evt = message.FindMember("evt"); - if (evt != message.MemberEnd() && evt->value.IsString()) { - const char* evtName = evt->value.GetString(); + if (evtName == nullptr) { + continue; + } - // todo ug - if (strcmp(evtName, "PRESENCE_REQUESTED") == 0) { - WasPresenceRequested.store(true); - } - else if (strcmp(evtName, "JOIN_GAME") == 0) { - auto data = message.FindMember("data"); - auto secret = data->value["secret"].GetString(); - StringCopy(JoinGameSecret, secret); - WasJoinGame.store(true); - } - else if (strcmp(evtName, "SPECTATE_GAME") == 0) { - auto data = message.FindMember("data"); - auto secret = data->value["secret"].GetString(); - StringCopy(SpectateGameSecret, secret); - WasSpectateGame.store(true); - } + // todo ug + if (strcmp(evtName, "PRESENCE_REQUESTED") == 0) { + WasPresenceRequested.store(true); + } + else if (strcmp(evtName, "JOIN_GAME") == 0) { + auto data = message.FindMember("data"); + auto secret = data->value["secret"].GetString(); + StringCopy(JoinGameSecret, secret); + WasJoinGame.store(true); + } + else if (strcmp(evtName, "SPECTATE_GAME") == 0) { + auto data = message.FindMember("data"); + auto secret = data->value["secret"].GetString(); + StringCopy(SpectateGameSecret, secret); + WasSpectateGame.store(true); } } } diff --git a/src/rpc_connection.cpp b/src/rpc_connection.cpp index ececc3e..50fc07c 100644 --- a/src/rpc_connection.cpp +++ b/src/rpc_connection.cpp @@ -34,7 +34,10 @@ void RpcConnection::Open() } if (state == State::SentHandshake) { - JsonDocument message; + char parseBuffer[32 * 1024]; + PoolAllocator pa(parseBuffer, sizeof(parseBuffer)); + StackAllocator sa; + JsonDocument message(rapidjson::kObjectType, &pa, sizeof(sa.fixedBuffer_), &sa); if (Read(message)) { auto cmd = message.FindMember("cmd"); if (cmd == message.MemberEnd() || !cmd->value.IsString()) { diff --git a/src/serialization.cpp b/src/serialization.cpp index 8b2a1ce..371db08 100644 --- a/src/serialization.cpp +++ b/src/serialization.cpp @@ -2,6 +2,8 @@ #include "connection.h" #include "discord-rpc.h" +MallocAllocator MallocAllocatorInst; + // it's ever so slightly faster to not have to strlen the key template void WriteKey(JsonWriter& w, T& k) { @@ -46,7 +48,7 @@ void JsonWriteCommandEnd(JsonWriter& writer) size_t JsonWriteRichPresenceObj(char* dest, size_t maxLen, int nonce, int pid, const DiscordRichPresence* presence) { DirectStringBuffer sb(dest, maxLen); - WriterAllocator wa; + StackAllocator wa; JsonWriter writer(sb, &wa, WriterNestingLevels); JsonWriteCommandStart(writer, nonce, "SET_ACTIVITY"); @@ -132,7 +134,7 @@ size_t JsonWriteRichPresenceObj(char* dest, size_t maxLen, int nonce, int pid, c size_t JsonWriteHandshakeObj(char* dest, size_t maxLen, int version, const char* applicationId) { DirectStringBuffer sb(dest, maxLen); - WriterAllocator wa; + StackAllocator wa; JsonWriter writer(sb, &wa, WriterNestingLevels); writer.StartObject(); @@ -148,7 +150,7 @@ size_t JsonWriteHandshakeObj(char* dest, size_t maxLen, int version, const char* size_t JsonWriteSubscribeCommand(char* dest, size_t maxLen, int nonce, const char* evtName) { DirectStringBuffer sb(dest, maxLen); - WriterAllocator wa; + StackAllocator wa; JsonWriter writer(sb, &wa, WriterNestingLevels); writer.StartObject(); diff --git a/src/serialization.h b/src/serialization.h index f1ab00b..9ddffc3 100644 --- a/src/serialization.h +++ b/src/serialization.h @@ -63,7 +63,7 @@ public: static void Free(void* ptr) { /* shrug */ } }; -template +template class FixedLinearAllocator : public LinearAllocator { public: char fixedBuffer_[Size]; @@ -98,9 +98,12 @@ public: } }; +using MallocAllocator = rapidjson::CrtAllocator; +extern MallocAllocator MallocAllocatorInst; +using PoolAllocator = rapidjson::MemoryPoolAllocator; using UTF8 = rapidjson::UTF8; // Writer appears to need about 16 bytes per nested object level (with 64bit size_t) -using WriterAllocator = FixedLinearAllocator<2048>; +using StackAllocator = FixedLinearAllocator<2048>; constexpr size_t WriterNestingLevels = 2048 / (2 * sizeof(size_t)); -using JsonWriter = rapidjson::Writer; -using JsonDocument = rapidjson::GenericDocument; +using JsonWriter = rapidjson::Writer; +using JsonDocument = rapidjson::GenericDocument>;