Skip to content

Commit 36bc1f2

Browse files
committed
Remove rapidjson and fix time bug
1 parent 111dee3 commit 36bc1f2

50 files changed

Lines changed: 268 additions & 16427 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

cpp/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ SET(TEST_SOURCE_FILES
8383
${RCDB_HEADERS}
8484

8585
tests/test_ConditionType.cpp
86+
tests/test_Condition.cpp
8687

8788
tests/catch.hpp
8889
tests/catch.cpp

cpp/examples/get_fadc_masks.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040

4141
#include "RCDB/Connection.h"
4242
#include "RCDB/ConfigParser.h"
43+
#include <tao/json.hpp>
4344

4445

4546
using namespace std;
@@ -59,9 +60,9 @@ rcdb::ConfigFileParseResult GetMainConfigParsed(rcdb::Connection &connection, in
5960
}
6061

6162

62-
auto json = rtvsCondition->ToJsonDocument(); // The CODA rtvs is serialized as JSon dictionary.
63+
auto json = tao::json::from_string(rtvsCondition->ToString()); // The CODA rtvs is serialized as JSon dictionary.
6364

64-
string fileName(json["%(config)"].GetString()); // We need item with name '%(config)'
65+
string fileName = json.at("%(config)").get_string(); // We need item with name '%(config)'
6566
// That is our file name
6667

6768

@@ -146,7 +147,7 @@ int main ( int argc, char *argv[] )
146147

147148
// get all file names for this run
148149
cout<<"All files saved for run "<<runNumber<<endl;
149-
for (int i = 0; i < runFileNames.size(); ++i) {
150+
for (size_t i = 0; i < runFileNames.size(); ++i) {
150151
cout<<" "<<runFileNames[i]<<endl;
151152
}
152153

@@ -163,7 +164,7 @@ int main ( int argc, char *argv[] )
163164
auto comValues = comParseResult.SectionsBySlotNumber[3].NameVectors["FADC250_ALLCH_THR"]; // Parse it and return
164165

165166
cout<<"FADC250_ALLCH_THR for slot 3 is:"<<endl;
166-
for (int i = 0; i < comValues.size(); ++i) {
167+
for (size_t i = 0; i < comValues.size(); ++i) {
167168
cout<<" "<<comValues[i]<<endl;
168169
}
169170

@@ -181,7 +182,7 @@ int main ( int argc, char *argv[] )
181182
auto userValues = userParseResult.SectionsBySlotNumber[3].NameVectors["FADC250_TRG_MASK"]; // Parse it and return
182183

183184
cout<<"FADC250_TRG_MASK for slot 3 is:"<<endl;
184-
for (int i = 0; i < userValues.size(); ++i) {
185+
for (size_t i = 0; i < userValues.size(); ++i) {
185186
cout<<" "<<userValues[i]<<endl;
186187
}
187188
// Lets say we want to get values for roc8

cpp/examples/get_trigger_params.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838

3939
#include "RCDB/Connection.h"
4040
#include "RCDB/ConfigParser.h"
41+
#include <tao/json.hpp>
4142

4243
using namespace std;
4344

@@ -76,9 +77,9 @@ int main ( int argc, char *argv[] )
7677
}
7778

7879

79-
auto json = rtvsCondition->ToJsonDocument(); // The CODA rtvs is serialized as JSon dictionary.
80+
auto json = tao::json::from_string(rtvsCondition->ToString()); // The CODA rtvs is serialized as JSon dictionary.
8081

81-
string fileName(json["%(config)"].GetString()); // We need item with name '%(config)'
82+
string fileName = json.at("%(config)").get_string(); // We need item with name '%(config)'
8283
// That is our file name
8384

8485

cpp/examples/write_array_to_json.cpp

Lines changed: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,20 @@
11
/**
2-
* This is very simple example of how to save array to JSON using rapidjson
3-
* Full RapidJson documentation is available here:
4-
* http://rapidjson.org/index.html
2+
* This is very simple example of how to save an array to JSON.
3+
* RCDB bundles the taocpp/json library:
4+
* https://github.com/taocpp/json
55
*/
66
#include <string>
77
#include <iostream>
88

99
#include "RCDB/WritingConnection.h"
1010

11-
12-
#include "rapidjson/stringbuffer.h"
13-
#include "rapidjson/writer.h"
11+
#include <tao/json.hpp>
1412

1513

1614
int main ( int argc, char *argv[] )
1715
{
1816
using namespace std;
19-
using namespace rapidjson;
17+
using namespace tao;
2018

2119
// Get a connection string from arguments
2220
if ( argc != 2 ) {
@@ -60,19 +58,14 @@ int main ( int argc, char *argv[] )
6058
// P A R T 1 - w r i t i n g a r r a y
6159

6260
//We want to store some value and array to JSON file
63-
Document document;
64-
document.SetArray(); // document must be SetArray or SetObject
65-
auto& allocator = document.GetAllocator(); // You... just need this allocator. Imagine this is mantra
61+
auto document = json::value::array({}); // a JSON value holding an (empty) array
6662
for(int i=-5; i<5; i++)
6763
{
68-
document.PushBack(Value().SetInt(i), allocator); // Put array values
64+
document.emplace_back(i); // Put array values
6965
}
7066

7167
// Convert document to string
72-
StringBuffer buffer;
73-
Writer<StringBuffer> writer(buffer);
74-
document.Accept(writer);
75-
string output = buffer.GetString();
68+
string output = tao::json::to_string(document);
7669

7770
// Print the JSon we've got
7871
cout<<"Resulting json is:"<<endl;
@@ -83,14 +76,12 @@ int main ( int argc, char *argv[] )
8376

8477
// P A R T 2 - r e a d i n g a r r a y
8578
auto cnd = connection.GetCondition(999, "json_cnd");
86-
auto json = cnd->ToJsonDocument();
87-
88-
//string fileName(json["%(config)"].GetString()); // We need item with name '%(config)'
79+
auto json = tao::json::from_string(cnd->ToString());
8980

9081
// since we saved json as array, we can iterate it directly
91-
for(int i=0; i<json.Size(); i++)
82+
for(const auto& item : json.get_array())
9283
{
93-
std::cout<<" "<< json[i].GetInt();
84+
std::cout<<" "<< item.get_signed();
9485
}
9586
std::cout<<endl;
9687

cpp/examples/write_objects_to_json.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ using namespace tao;
1414

1515
int main(int argc, char *argv[]) {
1616
using namespace std;
17-
using namespace rapidjson;
1817

1918
// Get a connection string from arguments
2019
if (argc != 2) {
@@ -144,7 +143,7 @@ id name value_type created description
144143
// explicit data conversion
145144
auto trigger = data["daq_trigger"].get_string();
146145

147-
cout<<"trigger= "<<trigger<<" start_time="<<data["start_time"]<<endl;
146+
cout<<"event_count= "<<ev_cnt<<" trigger= "<<trigger<<" start_time="<<data["start_time"]<<endl;
148147

149148
return 0;
150149
}

cpp/include/RCDB/Condition.h

Lines changed: 37 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
#include "Exceptions.h"
1010
#include <chrono>
1111
#include <string>
12-
#include "rapidjson/document.h"
12+
#include <tao/json.hpp> // ToJsonDocument() returns a tao::json::value (was rapidjson)
1313

1414
class DataProvder;
1515

@@ -74,32 +74,41 @@ namespace rcdb {
7474

7575
if (GetValueType() != ValueTypes::Json &&
7676
GetValueType() != ValueTypes::String &&
77-
GetValueType() != ValueTypes::Blob) {
78-
throw rcdb::ValueFormatError("Value type of the condition is not String, Json or Blob");
77+
GetValueType() != ValueTypes::Blob &&
78+
GetValueType() != ValueTypes::Time) {
79+
throw rcdb::ValueFormatError("Value type of the condition is not String, Json, Blob or Time");
7980
}
8081

82+
// For Time values this is the raw stored datetime string
83+
// ("YYYY-MM-DD HH:MM:SS"); use ToTime() for a parsed time_point.
8184
return _text_value;
8285
}
8386

8487

85-
/// @deprecated use json ToJson() instead
86-
rapidjson::Document ToJsonDocument()
88+
/** Returns the condition value parsed as a JSON document.
89+
*
90+
* Only valid when the condition's value type is Json (e.g. the CODA 'rtvs'
91+
* dictionary). This is a drop-in for the historical rapidjson implementation:
92+
* the same text is parsed into the same JSON structure/values -- only the
93+
* returned type changed from rapidjson::Document to tao::json::value, so the
94+
* header no longer depends on rapidjson. Callers keep `auto json = ...;` but
95+
* use tao's accessors (e.g. json.at("%(config)").get_string()) instead of
96+
* rapidjson's (json["%(config)"].GetString()).
97+
*
98+
* Throws rcdb::ValueFormatError if the value type is not Json, or the text is
99+
* not parseable JSON -- the same error contract as the old implementation.
100+
*/
101+
tao::json::value ToJsonDocument()
87102
{
88-
using namespace rapidjson;
89-
90103
if (GetValueType() != ValueTypes::Json) {
91104
throw rcdb::ValueFormatError("Value type of the condition is not Json");
92105
}
93106

94-
Document document; // Default template parameter uses UTF8 and MemoryPoolAllocator.
95-
96-
97-
// "normal" parsing, decode strings to new buffers. Can use other input stream via ParseStream().
98-
if (document.Parse(_text_value.c_str()).HasParseError()) {
107+
try {
108+
return tao::json::from_string(_text_value);
109+
} catch (const std::exception &) {
99110
throw rcdb::ValueFormatError("Error while parsing JSon");
100111
}
101-
102-
return document;
103112
}
104113

105114

@@ -123,36 +132,36 @@ namespace rcdb {
123132
rcdb::ValueTypes GetValueType() { return _type.GetValueType(); }
124133

125134

126-
void SetId(unsigned long _id) {
127-
Condition::_id = _id;
135+
void SetId(unsigned long id) {
136+
_id = id;
128137
}
129138

130139
unsigned long GetId() {
131140
return _id;
132141
}
133142

134-
void SetRunNumber(unsigned long _runNumber) {
135-
Condition::_runNumber = _runNumber;
143+
void SetRunNumber(unsigned long runNumber) {
144+
_runNumber = runNumber;
136145
}
137146

138-
void SetTextValue(const std::string &_text_value) {
139-
Condition::_text_value = _text_value;
147+
void SetTextValue(const std::string &text_value) {
148+
_text_value = text_value;
140149
}
141150

142-
void SetIntValue(int _int_value) {
143-
Condition::_int_value = _int_value;
151+
void SetIntValue(int int_value) {
152+
_int_value = int_value;
144153
}
145154

146-
void SetFloatValue(double _float_value) {
147-
Condition::_float_value = _float_value;
155+
void SetFloatValue(double float_value) {
156+
_float_value = float_value;
148157
}
149158

150-
void SetBoolValue(bool _bool_value) {
151-
Condition::_bool_value = _bool_value;
159+
void SetBoolValue(bool bool_value) {
160+
_bool_value = bool_value;
152161
}
153162

154-
void SetTime(std::chrono::time_point<std::chrono::system_clock> _time) {
155-
Condition::_time = _time;
163+
void SetTime(std::chrono::time_point<std::chrono::system_clock> time) {
164+
_time = time;
156165
}
157166

158167
private:

cpp/include/RCDB/ConfigParser.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,9 @@ namespace rcdb
3838
{
3939
public:
4040

41-
ConfigFileParseResult(std::vector<std::string> SectionNames)
41+
ConfigFileParseResult(std::vector<std::string> sectionNames)
4242
{
43-
for(auto sectionName: SectionNames) {
43+
for(auto sectionName: sectionNames) {
4444
this->SectionNames.push_back(sectionName);
4545
}
4646
}

cpp/include/RCDB/MySqlProvider.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -136,11 +136,15 @@ namespace rcdb {
136136
if (row[int_column] == nullptr) return std::unique_ptr<Condition>();
137137
condition->SetIntValue(stoi(row[int_column]));
138138
return condition;
139-
case ValueTypes::Time:
139+
case ValueTypes::Time: {
140+
// time is stored as a datetime string in time_value (col 5),
141+
// NOT as an integer in int_value -- read and parse the string.
140142
if (row[time_column] == nullptr) return std::unique_ptr<Condition>();
141-
condition->SetTime(
142-
chrono::system_clock::from_time_t(stoul(row[int_column])));
143+
const std::string timeStr = row[time_column];
144+
condition->SetTextValue(timeStr); // keep raw value for ToString()
145+
condition->SetTime(StringUtils::ParseTime(timeStr));
143146
return condition;
147+
}
144148
default:
145149
throw std::logic_error("ValueTypes type is something different than one of possible values");
146150
}

cpp/include/RCDB/SqLiteProvider.h

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <memory>
1212
#include "DataProvider.h"
1313
#include "RcdbFile.h"
14+
#include "StringUtils.h"
1415

1516
namespace rcdb {
1617
class SqLiteProvider : public DataProvider {
@@ -112,12 +113,15 @@ namespace rcdb {
112113
if(_getConditionQuery.isColumnNull(int_column)) return std::unique_ptr<Condition>();
113114
condition->SetIntValue(_getConditionQuery.getColumn(int_column).getInt());
114115
return condition;
115-
case ValueTypes::Time:
116+
case ValueTypes::Time: {
117+
// time is stored as a datetime string in time_value (col 5),
118+
// NOT as an integer in int_value -- read and parse the string.
116119
if(_getConditionQuery.isColumnNull(time_column)) return std::unique_ptr<Condition>();
117-
condition->SetTime(
118-
std::chrono::system_clock::from_time_t(
119-
_getConditionQuery.getColumn(int_column).getInt64()));
120+
const std::string timeStr = _getConditionQuery.getColumn(time_column).getText();
121+
condition->SetTextValue(timeStr); // keep raw value for ToString()
122+
condition->SetTime(StringUtils::ParseTime(timeStr));
120123
return condition;
124+
}
121125
default:
122126
throw std::logic_error("ValueTypes type is something different than one of possible values");
123127
}
@@ -206,12 +210,15 @@ namespace rcdb {
206210
if(_getConditionQuery.isColumnNull(int_column)) return std::unique_ptr<Condition>();
207211
condition->SetIntValue(_getConditionQuery.getColumn(int_column).getInt());
208212
return condition;
209-
case ValueTypes::Time:
213+
case ValueTypes::Time: {
214+
// time is stored as a datetime string in time_value (col 5),
215+
// NOT as an integer in int_value -- read and parse the string.
210216
if(_getConditionQuery.isColumnNull(time_column)) return std::unique_ptr<Condition>();
211-
condition->SetTime(
212-
std::chrono::system_clock::from_time_t(
213-
_getConditionQuery.getColumn(int_column).getInt64()));
217+
const std::string timeStr = _getConditionQuery.getColumn(time_column).getText();
218+
condition->SetTextValue(timeStr); // keep raw value for ToString()
219+
condition->SetTime(StringUtils::ParseTime(timeStr));
214220
return condition;
221+
}
215222
default:
216223
throw std::logic_error("ValueTypes type is something different than one of possible values");
217224
}

cpp/include/RCDB/StringUtils.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@
1515
#include <cctype>
1616
#include <locale>
1717

18+
#include <chrono>
19+
#include <ctime>
20+
#include <iomanip>
21+
#include <sstream>
22+
1823

1924
#include <stdio.h>
2025
#include <stdlib.h>
@@ -36,6 +41,28 @@ class StringUtils {
3641
return GetFormattedTime(*localtime(&time));
3742
}
3843

44+
/** Parses an RCDB datetime string into a system_clock time_point.
45+
*
46+
* RCDB stores time-valued conditions (e.g. run_start_time) as a naive
47+
* wall-clock string "YYYY-MM-DD HH:MM:SS" (SQLite may append fractional
48+
* seconds, which are ignored). The naive value is interpreted as UTC so the
49+
* result is deterministic regardless of the reader's timezone --
50+
* system_clock::to_time_t() + gmtime() round-trips the stored fields. On an
51+
* unparseable string the epoch is returned.
52+
*/
53+
static inline std::chrono::system_clock::time_point ParseTime(const std::string &formatted) {
54+
std::tm tm = {};
55+
std::istringstream ss(formatted);
56+
ss >> std::get_time(&tm, "%Y-%m-%d %H:%M:%S");
57+
if (ss.fail()) {
58+
return std::chrono::system_clock::time_point{}; // epoch on bad input
59+
}
60+
// timegm() interprets the tm as UTC; available on Linux and macOS
61+
// (RCDB C++ does not target Windows).
62+
const std::time_t t = timegm(&tm);
63+
return std::chrono::system_clock::from_time_t(t);
64+
}
65+
3966
// trim from start (in place)
4067
static inline void ltrim(std::string &s) {
4168
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](char c) { return !isspace(c); }));

0 commit comments

Comments
 (0)