From b4cf0a2e71ad2c204925b33f9600dc720e25b827 Mon Sep 17 00:00:00 2001
From: Joel Grunbaum <joelgrun@gmail.com>
Date: Sun, 09 Jan 2022 23:22:58 +0000
Subject: [PATCH] Initial shift to rapidjson

---
 rapidjson      |    1 
 .gitmodules    |    3 
 book.cpp       |    4 
 json.hpp       |    7 
 book.hpp       |    4 
 json.cpp       |  316 ++++++++++++---------------------------------------
 protocol.cpp   |    5 
 CMakeLists.txt |    6 
 8 files changed, 96 insertions(+), 250 deletions(-)

diff --git a/.gitmodules b/.gitmodules
index d553919..c935847 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -4,3 +4,6 @@
 [submodule "date"]
 	path = date
 	url = https://github.com/HowardHinnant/date.git
+[submodule "rapidjson"]
+	path = rapidjson
+	url = https://github.com/Tencent/rapidjson.git
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c086558..94cf3a1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -8,8 +8,12 @@
 add_compile_options(-g -Wall)
 
 add_subdirectory(date)
+# add_subdirectory(rapidjson)
 
-add_library(MAIN json.cpp date protocol.cpp book.cpp)
+add_library(JSON json.cpp)
+
+add_library(MAIN date protocol.cpp book.cpp)
+target_link_libraries(MAIN PUBLIC JSON)
 
 add_executable(test test.cpp strat.cpp)
 add_executable(bot bot.cpp strat.cpp)
diff --git a/book.cpp b/book.cpp
index ee014ed..381a7a2 100644
--- a/book.cpp
+++ b/book.cpp
@@ -74,14 +74,14 @@
 }
 
 Book::Book()
-    : bidSide(), askSide(), productType(TEST), product("a"), stationId("b"),
+    : bidSide(), askSide(), productType(TEST), product("a"), stationId(7),
       unit("c"), expiry(std::chrono::nanoseconds(0)), aggFee(1), pasFee(-1),
       broFee(2)
 {
 }
 
 Book::Book(ProductTypeEnum productType, std::string product,
-           std::string stationId, std::string unit,
+           int stationId, std::string unit,
            std::chrono::nanoseconds expiry, double aggFee, double pasFee,
            double broFee)
     : bidSide{}, askSide{}, productType{productType}, product(product),
diff --git a/book.hpp b/book.hpp
index 2240290..455506b 100644
--- a/book.hpp
+++ b/book.hpp
@@ -46,7 +46,7 @@
     std::vector<Level> askSide;
     ProductTypeEnum productType;
     std::string product;
-    std::string stationId;
+    int stationId;
     std::string unit;
     std::chrono::nanoseconds expiry;
     double aggFee;
@@ -55,7 +55,7 @@
 
     Book();
     Book(ProductTypeEnum productType, std::string product,
-         std::string stationId, std::string unit,
+         int stationId, std::string unit,
          std::chrono::nanoseconds expiry, double aggFee, double pasFee,
          double broFee);
     void ask(Order& order);
diff --git a/json.cpp b/json.cpp
index 11a97fa..5fbc996 100644
--- a/json.cpp
+++ b/json.cpp
@@ -2,6 +2,8 @@
 #include "book.hpp"
 #include "date/include/date/date.h"
 #include "protocol.hpp"
+#include "rapidjson/include/rapidjson/document.h"
+#include "rapidjson/include/rapidjson/rapidjson.h"
 #include <chrono>
 #include <cstddef>
 #include <cstdint>
@@ -51,66 +53,64 @@
     mapOrderSide = {{book::Buy, "BUY"}, {book::Sell, "SELL"}};
 }
 
-AnnounceMessage* announce(std::string& str);
-SettleMessage* settle(std::string& str);
-AddedMessage* added(std::string& str);
-DeletedMessage* deleted(std::string& str);
-TradeMessage* trade(std::string& str);
-BrokerRequest* brokerReq(std::string& str);
-BrokerAck* brokerAck(std::string& str);
-BrokerConfirm* brokerCon(std::string& str);
+Message* parseSingle(rapidjson::Value& d);
+AnnounceMessage* announce(rapidjson::Value& d);
+SettleMessage* settle(rapidjson::Value& d);
+AddedMessage* added(rapidjson::Value& d);
+DeletedMessage* deleted(rapidjson::Value& d);
+TradeMessage* trade(rapidjson::Value& d);
+BrokerRequest* brokerReq(rapidjson::Value& d);
+BrokerAck* brokerAck(rapidjson::Value& d);
+BrokerConfirm* brokerCon(rapidjson::Value& d);
 
-std::queue<Message*> parseMany(std::string& str)
+std::queue<Message*> parse(std::string& str)
 {
     std::queue<Message*> out;
-    std::size_t startIndex = 0, endIndex = 0;
-    while (true) {
-	startIndex = str.find("{", endIndex);
-	if (startIndex == std::string::npos) break;
-	endIndex = str.find("},", startIndex);
-	std::string substr = str.substr(startIndex, endIndex - startIndex + 1);
-	// std::cout << substr << std::endl;
-	Message* a = parseSingle(substr);
-	out.push(a);
+    rapidjson::Document d;
+    d.Parse(str.c_str());
+    if (d.IsArray()) {
+	for (rapidjson::SizeType i = 0; i < d.Size(); i++) {
+	    out.push(parseSingle(d[i]));
+	}
+    } else {
+	out.push(parseSingle(d));
     }
     return out;
 }
 
-Message* parseSingle(std::string& str)
+Message* parseSingle(rapidjson::Value& d)
 {
     if (mapTypes.empty()) {
 	initialise();
     }
-    std::size_t startIndex = str.find("\"type\": \"") + 9;
-    std::size_t endIndex = str.find("\"", startIndex + 1);
     Message* out;
-    switch (mapTypes[str.substr(startIndex, endIndex - startIndex)]) {
+    switch (mapTypes[d["type"].GetString()]) {
     case FUTURE_TYPE:
     case SPREAD_TYPE:
     case CALL_TYPE:
     case PUT_TYPE:
-	out = announce(str);
+	out = announce(d);
 	break;
     case SETTLEMENT:
-	out = settle(str);
+	out = settle(d);
 	break;
     case ADDED:
-	out = added(str);
+	out = added(d);
 	break;
     case DELETED:
-	out = deleted(str);
+	out = deleted(d);
 	break;
     case TRADE:
-	out = trade(str);
+	out = trade(d);
 	break;
     case BROKER_REQUEST:
-	out = brokerReq(str);
+	out = brokerReq(d);
 	break;
     case BROKER_ACK:
-	out = brokerAck(str);
+	out = brokerAck(d);
 	break;
     case BROKER_CONFIRM:
-	out = brokerCon(str);
+	out = brokerCon(d);
 	break;
     default:
 	out = new Message(NONE, "");
@@ -119,244 +119,82 @@
     return out;
 }
 
-inline std::pair<std::size_t, std::size_t>
-find_arg(std::string str, std::string a, bool quotes, bool end = false)
+AnnounceMessage* announce(rapidjson::Value& d)
 {
-    std::size_t out[2];
-    if (quotes) {
-	out[0] = str.find("\"" + a + "\": \"") + 5 + a.size();
-	if (end) {
-	    out[1] = str.find("\"}", out[0] + 1);
-	} else {
-	    out[1] = str.find("\",", out[0] + 1);
-	}
-    } else {
-	out[0] = str.find("\"" + a + "\": ") + 4 + a.size();
-	if (end) {
-	    out[1] = str.find("}", out[0] + 1);
-	} else {
-	    out[1] = str.find(",", out[0] + 1);
-	}
-    }
-    return std::make_pair(out[0], out[1]);
-}
-
-AnnounceMessage* announce(std::string& str)
-{
-    std::pair<std::size_t, std::size_t> type, product, stationId, stationName,
-	unit, expiry, aggFee, pasFee, broFee, sequence, timestamp;
-    type = find_arg(str, "type", true, false);
-    product = find_arg(str, "product", true, false);
-    stationId = find_arg(str, "stationId", false, false);
-    stationName = find_arg(str, "stationName", true, false);
-    unit = find_arg(str, "unit", true, false);
-    expiry = find_arg(str, "expiry", true, false);
-    aggFee = find_arg(str, "aggressiveFee", false, false);
-    pasFee = find_arg(str, "passiveFee", false, false);
-    broFee = find_arg(str, "brokerFee", false, false);
-    sequence = find_arg(str, "sequence", false, false);
-    timestamp = find_arg(str, "timestamp", false, true);
-    std::stringstream expiryStream(
-	str.substr(expiry.first, expiry.second - expiry.first));
+    // std::stringstream expiryStream(d["expiry"].GetString());
     std::chrono::nanoseconds exp_time(0);
     // expiryStream >>
-	// date::parse("%Y-%m-%f %H:%M%z", exp_time); // Parsing is broken
+    // date::parse("%Y-%m-%f %H:%M%z", exp_time); // Parsing is broken
     return new AnnounceMessage(
-	mapTypes[str.substr(type.first, type.second - type.first)],
-	str.substr(product.first, product.second - product.first),
-	str.substr(stationId.first, stationId.second - stationId.first),
-	str.substr(stationName.first, stationName.second - stationName.first),
-	str.substr(unit.first, unit.second - unit.first), exp_time,
-	std::stod(str.substr(aggFee.first, aggFee.second - aggFee.first)),
-	std::stod(str.substr(pasFee.first, pasFee.second - pasFee.first)),
-	std::stod(str.substr(broFee.first, broFee.second - broFee.first)),
-	std::stoll(
-	    str.substr(sequence.first, sequence.second - sequence.first)),
-	std::stod(
-	    str.substr(timestamp.first, timestamp.second - timestamp.first)));
+	mapTypes[d["type"].GetString()], d["product"].GetString(),
+	d["stationId"].GetInt(), d["stationName"].GetString(),
+	d["unit"].GetString(), exp_time, d["aggressiveFee"].GetDouble(),
+	d["passiveFee"].GetDouble(), d["brokerFee"].GetDouble(),
+	d["sequence"].GetInt(), d["timestamp"].GetDouble());
 }
 
-SettleMessage* settle(std::string& str)
+SettleMessage* settle(rapidjson::Value& d)
 {
-    std::pair<std::size_t, std::size_t> type, product, stationName, expiry,
-	price, sequence, timestamp;
-    type = find_arg(str, "type", true, false);
-    product = find_arg(str, "product", true, false);
-    stationName = find_arg(str, "stationName", true, false);
-    expiry = find_arg(str, "expiry", true, false);
-    price = find_arg(str, "price", false, false);
-    sequence = find_arg(str, "sequence", false, false);
-    timestamp = find_arg(str, "timestamp", false, true);
-    std::stringstream expiryStream(
-	str.substr(expiry.first, expiry.second - expiry.first));
-    std::chrono::nanoseconds exp_time;
-    expiryStream >> date::parse("%Y-%m-%d %H:%M%z", exp_time);
+    // std::stringstream expiryStream(d["expiry"].GetString());
+    std::chrono::nanoseconds exp_time(0);
+    // expiryStream >> date::parse("%Y-%m-%d %H:%M%z", exp_time);
     return new SettleMessage(
-	mapTypes[str.substr(type.first, type.second - type.first)],
-	str.substr(product.first, product.second - product.first),
-	str.substr(stationName.first, stationName.second - stationName.first),
-	exp_time,
-	std::stod(str.substr(price.first, price.second - price.first)),
-	std::stoll(
-	    str.substr(sequence.first, sequence.second - sequence.first)),
-	std::stod(
-	    str.substr(timestamp.first, timestamp.second - timestamp.first)));
+	mapTypes[d["type"].GetString()], d["product"].GetString(),
+	d["stationName"].GetString(), exp_time, d["price"].GetDouble(),
+	d["sequence"].GetInt(), d["timestamp"].GetDouble());
 }
 
-AddedMessage* added(std::string& str)
+AddedMessage* added(rapidjson::Value& d)
 {
-    std::pair<std::size_t, std::size_t> type, product, id, side, price, filled,
-	resting, sequence, timestamp;
-    type = find_arg(str, "type", true, false);
-    product = find_arg(str, "product", true, false);
-    sequence = find_arg(str, "sequence", false, false);
-    timestamp = find_arg(str, "timestamp", false, true);
-    id = find_arg(str, "id", true, false);
-    side = find_arg(str, "side", true, false);
-    price = find_arg(str, "price", false, false);
-    filled = find_arg(str, "filled", false, false);
-    resting = find_arg(str, "resting", false, false);
     return new AddedMessage(
-	mapTypes[str.substr(type.first, type.second - type.first)],
-	str.substr(product.first, product.second - product.first),
-	str.substr(id.first, id.second - id.first),
-	mapOrder[str.substr(side.first, side.second - side.first)],
-	std::stod(str.substr(price.first, price.second - price.first)),
-	std::stoll(str.substr(filled.first, filled.second - filled.first)),
-	std::stoll(str.substr(resting.first, resting.second - resting.first)),
-	std::stoll(
-	    str.substr(sequence.first, sequence.second - sequence.first)),
-	std::stod(
-	    str.substr(timestamp.first, timestamp.second - timestamp.first)));
+	mapTypes[d["type"].GetString()], d["product"].GetString(),
+	d["id"].GetString(), mapOrder[d["side"].GetString()],
+	d["price"].GetDouble(), d["filled"].GetInt(), d["resting"].GetInt(),
+	d["sequence"].GetInt(), d["timestamp"].GetDouble());
 }
 
-DeletedMessage* deleted(std::string& str)
+DeletedMessage* deleted(rapidjson::Value& d)
 {
-    std::pair<std::size_t, std::size_t> type, product, id, side, sequence,
-	timestamp;
-    type = find_arg(str, "type", true, false);
-    product = find_arg(str, "product", true, false);
-    sequence = find_arg(str, "sequence", false, false);
-    timestamp = find_arg(str, "timestamp", false, true);
-    id = find_arg(str, "id", true, false);
-    side = find_arg(str, "side", true, false);
     return new DeletedMessage(
-	mapTypes[str.substr(type.first, type.second - type.first)],
-	str.substr(product.first, product.second - product.first),
-	str.substr(id.first, id.second - id.first),
-	mapOrder[str.substr(side.first, side.second - side.first)],
-	std::stoll(
-	    str.substr(sequence.first, sequence.second - sequence.first)),
-	std::stod(
-	    str.substr(timestamp.first, timestamp.second - timestamp.first)));
+	mapTypes[d["type"].GetString()], d["product"].GetString(),
+	d["id"].GetString(), mapOrder[d["side"].GetString()],
+	d["sequence"].GetInt(), d["timestamp"].GetDouble());
 }
 
-TradeMessage* trade(std::string& str)
+TradeMessage* trade(rapidjson::Value& d)
 {
-    std::pair<std::size_t, std::size_t> type, product, price, volume, buyer,
-	seller, tradeType, passiveOrder, passiveOrderRemaining, sequence,
-	timestamp;
-    type = find_arg(str, "type", true, false);
-    product = find_arg(str, "product", true, false);
-    sequence = find_arg(str, "sequence", false, false);
-    timestamp = find_arg(str, "timestamp", false, true);
-    price = find_arg(str, "price", false, false);
-    volume = find_arg(str, "volume", false, false);
-    buyer = find_arg(str, "buyer", true, false);
-    seller = find_arg(str, "seller", true, false);
-    tradeType = find_arg(str, "tradeType", true, false);
-    passiveOrder = find_arg(str, "passiveOrder", true, false);
-    passiveOrderRemaining =
-	find_arg(str, "passiveOrderRemaining", false, false);
-
     return new TradeMessage(
-	mapTypes[str.substr(type.first, type.second - type.first)],
-	str.substr(product.first, product.second - product.first),
-	std::stod(str.substr(price.first, price.second - price.first)),
-	std::stoll(str.substr(volume.first, volume.second - volume.first)),
-	str.substr(buyer.first, buyer.second - buyer.first),
-	str.substr(seller.first, seller.second - seller.first),
-	mapTrade[str.substr(tradeType.first,
-                            tradeType.second - tradeType.first)],
-	str.substr(passiveOrder.first,
-                   passiveOrder.second - passiveOrder.first),
-	std::stoll(str.substr(passiveOrderRemaining.first,
-                              passiveOrderRemaining.second -
-                                  passiveOrderRemaining.first)),
-	std::stoll(
-	    str.substr(sequence.first, sequence.second - sequence.first)),
-	std::stod(
-	    str.substr(timestamp.first, timestamp.second - timestamp.first)));
+	mapTypes[d["type"].GetString()], d["product"].GetString(),
+	d["price"].GetDouble(), d["volume"].GetInt(), d["buyer"].GetString(),
+	d["seller"].GetString(), mapTrade[d["tradeType"].GetString()],
+	d["passiveOrder"].GetString(), d["passiveOrderRemaining"].GetInt(),
+	d["sequence"].GetInt(), d["timestamp"].GetDouble());
 }
 
-BrokerRequest* brokerReq(std::string& str)
+BrokerRequest* brokerReq(rapidjson::Value& d)
 {
-    std::pair<std::size_t, std::size_t> type, product, price, side, volume,
-	counterparty;
-    type = find_arg(str, "type", true, false);
-    product = find_arg(str, "product", true, false);
-    price = find_arg(str, "price", false, false);
-    side = find_arg(str, "side", true, false);
-    volume = find_arg(str, "volume", false, false);
-    counterparty = find_arg(str, "counterparty", true, false);
     return new BrokerRequest(
-	mapTypes[str.substr(type.first, type.second - type.first)],
-	str.substr(product.first, product.second - product.first),
-	std::stod(str.substr(price.first, price.second - price.first)),
-	mapOrder[str.substr(side.first, side.second - side.first)],
-	std::stoll(str.substr(volume.first, volume.second - volume.first)),
-	str.substr(counterparty.first,
-                   counterparty.second - counterparty.first));
+	mapTypes[d["type"].GetString()], d["product"].GetString(),
+	d["price"].GetDouble(), mapOrder[d["side"].GetString()],
+	d["volume"].GetInt(), d["counterparty"].GetString());
 }
 
-BrokerAck* brokerAck(std::string& str)
+BrokerAck* brokerAck(rapidjson::Value& d)
 {
-    std::pair<std::size_t, std::size_t> type, product, price, side, volume,
-	counterparty, id, brokerTradeStatus, owner;
-    type = find_arg(str, "type", true, false);
-    product = find_arg(str, "product", true, false);
-    price = find_arg(str, "price", false, false);
-    side = find_arg(str, "side", true, false);
-    volume = find_arg(str, "volume", false, false);
-    counterparty = find_arg(str, "counterparty", true, false);
-    id = find_arg(str, "id", true, false);
-    brokerTradeStatus = find_arg(str, "brokerTradeStatus", true, false);
-    owner = find_arg(str, "owner", true, false);
-
-    return new BrokerAck(
-	mapTypes[str.substr(type.first, type.second - type.first)],
-	str.substr(product.first, product.second - product.first),
-	std::stod(str.substr(price.first, price.second - price.first)),
-	mapOrder[str.substr(side.first, side.second - side.first)],
-	std::stoll(str.substr(volume.first, volume.second - volume.first)),
-	str.substr(counterparty.first,
-                   counterparty.second - counterparty.first),
-	str.substr(id.first, id.second - id.first),
-	str.substr(brokerTradeStatus.first,
-                   brokerTradeStatus.second - brokerTradeStatus.first),
-	str.substr(owner.first, owner.second - owner.first));
+    return new BrokerAck(mapTypes[d["type"].GetString()],
+                         d["product"].GetString(), d["price"].GetDouble(),
+                         mapOrder[d["side"].GetString()], d["volume"].GetInt(),
+                         d["counterparty"].GetString(), d["id"].GetString(),
+                         d["brokerTradeStatus"].GetString(),
+                         d["owner"].GetString());
 }
-BrokerConfirm* brokerCon(std::string& str)
+BrokerConfirm* brokerCon(rapidjson::Value& d)
 {
-    std::pair<std::size_t, std::size_t> type, product, price, side, volume,
-	counterparty, id;
-    type = find_arg(str, "type", true, false);
-    product = find_arg(str, "product", true, false);
-    price = find_arg(str, "price", false, false);
-    side = find_arg(str, "side", true, false);
-    volume = find_arg(str, "volume", false, false);
-    counterparty = find_arg(str, "counterparty", true, false);
-    id = find_arg(str, "id", true, false);
-
     return new BrokerConfirm(
-	mapTypes[str.substr(type.first, type.second - type.first)],
-	str.substr(product.first, product.second - product.first),
-	std::stod(str.substr(price.first, price.second - price.first)),
-	mapOrder[str.substr(side.first, side.second - side.first)],
-	std::stoll(str.substr(volume.first, volume.second - volume.first)),
-	str.substr(counterparty.first,
-                   counterparty.second - counterparty.first),
-	str.substr(id.first, id.second - id.first));
+	mapTypes[d["type"].GetString()], d["product"].GetString(),
+	d["price"].GetDouble(), mapOrder[d["side"].GetString()],
+	d["volume"].GetInt(), d["counterparty"].GetString(),
+	d["id"].GetString());
 }
 
 Message::Message() : type(NONE), product("error") {}
@@ -384,7 +222,7 @@
 }
 
 AnnounceMessage::AnnounceMessage(MessageTypes type, std::string product,
-                                 std::string stationId, std::string stationName,
+                                 int stationId, std::string stationName,
                                  std::string unit,
                                  std::chrono::nanoseconds expiry, double aggFee,
                                  double pasFee, double broFee,
diff --git a/json.hpp b/json.hpp
index 5d1fc2b..19a4b68 100644
--- a/json.hpp
+++ b/json.hpp
@@ -62,7 +62,7 @@
 };
 
 struct AnnounceMessage : public FromExchange {
-    std::string stationId;
+    int stationId;
     std::string stationName;
     std::string unit;
     std::chrono::nanoseconds expiry;
@@ -71,7 +71,7 @@
     double broFee;
 
     AnnounceMessage(MessageTypes type, std::string product,
-                    std::string stationId, std::string stationName,
+                    int stationId, std::string stationName,
                     std::string unit, std::chrono::nanoseconds expiry,
                     double aggFee, double pasFee, double broFee,
                     uint64_t sequence, double timestamp);
@@ -164,6 +164,5 @@
                   std::string counterparty, std::string id);
 };
 
-Message* parseSingle(std::string& str);
-std::queue<Message*> parseMany(std::string& str);
+std::queue<Message*> parse(std::string& str);
 } // namespace json
diff --git a/protocol.cpp b/protocol.cpp
index a129985..604c725 100644
--- a/protocol.cpp
+++ b/protocol.cpp
@@ -37,7 +37,7 @@
     // auto res = cli.Get("/recover");
     std::string l;
     l = ss.str();
-    std::queue<json::Message*> a(json::parseMany(l));
+    std::queue<json::Message*> a(json::parse(l));
     while (!a.empty()) {
 	protocol::handleMessage(bs, a.front());
 	delete a.front();
@@ -166,7 +166,8 @@
 json::Message* send(std::string& message)
 {
     auto res = cli.Post("/execution", message, "text/plain");
-    return json::parseSingle(res->body);
+    std::queue<json::Message*> a = json::parse(res->body);
+    return a.front();
 }
 
 } // namespace protocol
diff --git a/rapidjson b/rapidjson
new file mode 160000
index 0000000..fd3dc29
--- /dev/null
+++ b/rapidjson
@@ -0,0 +1 @@
+Subproject commit fd3dc29a5c2852df569e1ea81dbde2c412ac5051

--
Gitblit v1.9.3