diff --git a/src/discord-rpc.cpp b/src/discord-rpc.cpp index 12411c7..faa189b 100644 --- a/src/discord-rpc.cpp +++ b/src/discord-rpc.cpp @@ -79,7 +79,7 @@ extern "C" void Discord_UpdateConnection() } else { // reads - rapidjson::Document message; + JsonDocument message; while (Connection->Read(message)) { auto nonce = message.FindMember("nonce"); if (nonce != message.MemberEnd() && nonce->value.IsString()) { diff --git a/src/rpc_connection.cpp b/src/rpc_connection.cpp index 052402b..ececc3e 100644 --- a/src/rpc_connection.cpp +++ b/src/rpc_connection.cpp @@ -34,7 +34,7 @@ void RpcConnection::Open() } if (state == State::SentHandshake) { - rapidjson::Document message; + JsonDocument message; if (Read(message)) { auto cmd = message.FindMember("cmd"); if (cmd == message.MemberEnd() || !cmd->value.IsString()) { @@ -86,7 +86,7 @@ bool RpcConnection::Write(const void* data, size_t length) return true; } -bool RpcConnection::Read(rapidjson::Document& message) +bool RpcConnection::Read(JsonDocument& message) { if (state != State::Connected && state != State::SentHandshake) { return false; diff --git a/src/rpc_connection.h b/src/rpc_connection.h index c0e20dd..49ced0f 100644 --- a/src/rpc_connection.h +++ b/src/rpc_connection.h @@ -1,7 +1,7 @@ #pragma once #include "connection.h" -#include "rapidjson/document.h" +#include "serialization.h" // I took this from the buffer size libuv uses for named pipes; I suspect ours would usually be much smaller. constexpr size_t MaxRpcFrameSize = 64 * 1024; @@ -50,5 +50,5 @@ struct RpcConnection { void Open(); void Close(); bool Write(const void* data, size_t length); - bool Read(rapidjson::Document& message); + bool Read(JsonDocument& message); }; diff --git a/src/serialization.cpp b/src/serialization.cpp index c864928..8b2a1ce 100644 --- a/src/serialization.cpp +++ b/src/serialization.cpp @@ -1,85 +1,7 @@ +#include "serialization.h" #include "connection.h" #include "discord-rpc.h" -#include "rapidjson/writer.h" -#include "rapidjson/stringbuffer.h" -#include "rapidjson/internal/itoa.h" - -// I want to use as few allocations as I can get away with, and to do that with RapidJson, you need to supply some of -// your own allocators for stuff rather than use the defaults - -class LinearAllocator { -public: - char* buffer_; - char* end_; - LinearAllocator() { - assert(0); // needed for some default case in rapidjson, should not use - } - LinearAllocator(char* buffer, size_t size) : buffer_(buffer), end_(buffer + size) {} - static const bool kNeedFree = false; - void* Malloc(size_t size) - { - char* res = buffer_; - buffer_ += size; - if (buffer_ > end_) { - buffer_ = res; - return nullptr; - } - return res; - } - void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) - { - if (newSize == 0) { - return nullptr; - } - // allocate how much you need in the first place - assert(!originalPtr && !originalSize); - return Malloc(newSize); - } - static void Free(void* ptr) { /* shrug */ } -}; - -template -class FixedLinearAllocator : public LinearAllocator { -public: - char fixedBuffer_[Size]; - FixedLinearAllocator() : LinearAllocator(fixedBuffer_, Size) {} - static const bool kNeedFree = false; -}; - -// wonder why this isn't a thing already, maybe I missed it -class DirectStringBuffer { -public: - typedef typename char Ch; - char* buffer_; - char* end_; - char* current_; - - DirectStringBuffer(char* buffer, size_t maxLen) - : buffer_(buffer) - , end_(buffer + maxLen) - , current_(buffer) - {} - - void Put(char c) - { - if (current_ < end_) { - *current_++ = c; - } - } - void Flush() {} - size_t GetSize() const - { - return current_ - buffer_; - } -}; - -using Encoding = rapidjson::UTF8; -// Writer appears to need about 16 bytes per nested object level (with 64bit size_t) -using WriterAllocator = FixedLinearAllocator<2048>; -constexpr size_t WriterNestingLevels = 2048 / 16; -using JsonWriter = rapidjson::Writer; - // it's ever so slightly faster to not have to strlen the key template void WriteKey(JsonWriter& w, T& k) { diff --git a/src/serialization.h b/src/serialization.h index 65e393a..f1ab00b 100644 --- a/src/serialization.h +++ b/src/serialization.h @@ -2,6 +2,11 @@ #include +#include "rapidjson/document.h" +#include "rapidjson/writer.h" +#include "rapidjson/stringbuffer.h" +#include "rapidjson/internal/itoa.h" + // if only there was a standard library function for this template inline size_t StringCopy(char (&dest)[Len], const char* src) { @@ -23,3 +28,79 @@ size_t JsonWriteHandshakeObj(char* dest, size_t maxLen, int version, const char* struct DiscordRichPresence; size_t JsonWriteRichPresenceObj(char* dest, size_t maxLen, int nonce, int pid, const DiscordRichPresence* presence); size_t JsonWriteSubscribeCommand(char* dest, size_t maxLen, int nonce, const char* evtName); + +// I want to use as few allocations as I can get away with, and to do that with RapidJson, you need to supply some of +// your own allocators for stuff rather than use the defaults + +class LinearAllocator { +public: + char* buffer_; + char* end_; + LinearAllocator() { + assert(0); // needed for some default case in rapidjson, should not use + } + LinearAllocator(char* buffer, size_t size) : buffer_(buffer), end_(buffer + size) {} + static const bool kNeedFree = false; + void* Malloc(size_t size) + { + char* res = buffer_; + buffer_ += size; + if (buffer_ > end_) { + buffer_ = res; + return nullptr; + } + return res; + } + void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) + { + if (newSize == 0) { + return nullptr; + } + // allocate how much you need in the first place + assert(!originalPtr && !originalSize); + return Malloc(newSize); + } + static void Free(void* ptr) { /* shrug */ } +}; + +template +class FixedLinearAllocator : public LinearAllocator { +public: + char fixedBuffer_[Size]; + FixedLinearAllocator() : LinearAllocator(fixedBuffer_, Size) {} + static const bool kNeedFree = false; +}; + +// wonder why this isn't a thing already, maybe I missed it +class DirectStringBuffer { +public: + typedef typename char Ch; + char* buffer_; + char* end_; + char* current_; + + DirectStringBuffer(char* buffer, size_t maxLen) + : buffer_(buffer) + , end_(buffer + maxLen) + , current_(buffer) + {} + + void Put(char c) + { + if (current_ < end_) { + *current_++ = c; + } + } + void Flush() {} + size_t GetSize() const + { + return current_ - buffer_; + } +}; + +using UTF8 = rapidjson::UTF8; +// Writer appears to need about 16 bytes per nested object level (with 64bit size_t) +using WriterAllocator = FixedLinearAllocator<2048>; +constexpr size_t WriterNestingLevels = 2048 / (2 * sizeof(size_t)); +using JsonWriter = rapidjson::Writer; +using JsonDocument = rapidjson::GenericDocument;