Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
255 changes: 28 additions & 227 deletions src/stan/callbacks/json_writer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#include <stan/math/prim/fun/Eigen.hpp>
#include <stan/math/prim/meta.hpp>
#include <stan/callbacks/structured_writer.hpp>
#include <ostream>
#include <stan/io/json/write_json_value.hpp>
#include <string>
#include <vector>
#include <memory>
Expand Down Expand Up @@ -51,115 +51,23 @@ class json_writer final : public structured_writer {
*output_ << "\n";
}

/**
* Process a string to escape special characters.
* Valid json strings cannot contain any of the special characters
* `'\\', '"', '/', '\b', '\f', '\n', '\r', '\t', '\v', '\a', '\0'`.
* In order to print these characters, they must be escaped.
* @param value The string to process.
* @return The processed string.
*/
std::string process_string(const std::string& value) {
static constexpr std::array<char, 11> chars_to_escape
= {'\\', '"', '/', '\b', '\f', '\n', '\r', '\t', '\v', '\a', '\0'};
static constexpr std::array<const char*, 11> chars_to_replace
= {"\\\\", "\\\"", "\\/", "\\b", "\\f", "\\n",
"\\r", "\\t", "\\v", "\\a", "\\0"};
// Replacing every value leads to 2x the size
std::string new_value(value.size() * 2, 'x');
std::size_t pos = 0;
std::size_t count = 0;
std::size_t prev_pos = 0;
while ((pos = value.find_first_of(chars_to_escape.data(), pos, 10))
!= std::string::npos) {
for (int i = prev_pos; i < pos; ++i) {
new_value[i + count] = value[i];
}
int idx
= strchr(chars_to_escape.data(), value[pos]) - chars_to_escape.data();
new_value[pos + count] = chars_to_replace[idx][0];
new_value[pos + count + 1] = chars_to_replace[idx][1];
pos += 1;
count++;
prev_pos = pos;
}
for (int i = prev_pos; i < value.size(); ++i) {
new_value[i + count] = value[i];
}
// Shrink any unused space
new_value.resize(value.size() + count);
return new_value;
}

/**
* Writes key plus colon for key-value pair.
*
* @param[in] key member name.
*/
void write_key(const std::string& key) {
*output_ << std::string(record_depth_ * 2, ' ') << "\""
<< process_string(key) << "\" : ";
stan::json::write_key(output_, key, record_depth_);
}

template <typename T>
void write_int_like(const std::string& key, T value) {
void write_value(const std::string& key, const T& value) {
if (output_ == nullptr) {
return;
}
write_sep();
write_key(key);
*output_ << value;
}

/**
* Writes a single value. Corrects capitalization for inf and nans.
*
* @param[in] v value
*/
void write_value(double v) {
if (unlikely(std::isinf(v))) {
if (v > 0) {
*output_ << "Inf";
} else {
*output_ << "-Inf";
}
} else if (unlikely(std::isnan(v))) {
*output_ << "NaN";
} else {
*output_ << v;
}
}

/**
* Writes a single complex value.
*
* @param[in] v value
*/
void write_complex_value(std::complex<double> v) {
*output_ << "[";
write_value(v.real());
*output_ << ", ";
write_value(v.imag());
*output_ << "]";
}

/**
* Writes the set of comma separated values in an Eigen (row) vector.
*
* @param[in] v Values in an `Eigen::Vector`
*/
template <typename Derived>
void write_eigen_vector(const Eigen::DenseBase<Derived>& v) {
*output_ << "[ ";
if (v.size() > 0) {
size_t last = v.size() - 1;
for (Eigen::Index i = 0; i < last; ++i) {
write_value(v[i]);
*output_ << ", ";
}
write_value(v[last]);
}
*output_ << " ]";
stan::json::write_json_value(output_, value, record_depth_);
}

public:
Expand Down Expand Up @@ -251,13 +159,7 @@ class json_writer final : public structured_writer {
* @param value string to write.
*/
void write(const std::string& key, const std::string& value) {
if (output_ == nullptr) {
return;
}
std::string processsed_string = process_string(value);
write_sep();
write_key(key);
*output_ << "\"" << processsed_string << "\"";
write_value(key, value);
}

/**
Expand All @@ -266,13 +168,7 @@ class json_writer final : public structured_writer {
* @param value pointer to chars to write.
*/
void write(const std::string& key, const char* value) {
if (output_ == nullptr) {
return;
}
std::string processsed_string = process_string(value);
write_sep();
write_key(key);
*output_ << "\"" << processsed_string << "\"";
write_value(key, value);
}

/**
Expand All @@ -294,15 +190,18 @@ class json_writer final : public structured_writer {
* @param key Name of the value pair
* @param value int to write.
*/
void write(const std::string& key, int value) { write_int_like(key, value); }
void write(const std::string& key, int value) { write_value(key, value); }

/**
* Write a key-value pair where the value is an `std::size_t`.
* @param key Name of the value pair
* @param value `std::size_t` to write.
*/
void write(const std::string& key, std::size_t value) {
write_int_like(key, value);
/// Write a key-value pair with an unsigned long value.
void write(const std::string& key,
unsigned long value) { // NOLINT(runtime/int)
write_value(key, value);
}

/// Write a key-value pair with an unsigned long long value.
void write(const std::string& key,
unsigned long long value) { // NOLINT(runtime/int)
write_value(key, value);
}

/**
Expand All @@ -313,7 +212,7 @@ class json_writer final : public structured_writer {
void write(const std::string& key,
long long int value // NOLINT(runtime/int)
) {
write_int_like(key, value);
write_value(key, value);
}

/**
Expand All @@ -322,35 +221,23 @@ class json_writer final : public structured_writer {
* @param value `unsigned int` to write.
*/
void write(const std::string& key, unsigned int value) {
write_int_like(key, value);
write_value(key, value);
}

/**
* Write a key-value pair where the value is a double.
* @param key Name of the value pair
* @param value double to write.
*/
void write(const std::string& key, double value) {
if (output_ == nullptr) {
return;
}
write_sep();
write_key(key);
write_value(value);
}
void write(const std::string& key, double value) { write_value(key, value); }

/**
* Write a key-value pair where the value is a complex value.
* @param key Name of the value pair
* @param value complex value to write.
*/
void write(const std::string& key, const std::complex<double>& value) {
if (output_ == nullptr) {
return;
}
write_sep();
write_key(key);
write_complex_value(value);
write_value(key, value);
}

/**
Expand All @@ -359,22 +246,7 @@ class json_writer final : public structured_writer {
* @param values vector to write.
*/
void write(const std::string& key, const std::vector<std::string>& values) {
if (output_ == nullptr) {
return;
}
write_sep();
write_key(key);

*output_ << "[ ";
if (values.size() > 0) {
auto last = values.end();
--last;
for (auto it = values.begin(); it != last; ++it) {
*output_ << process_string(*it) << ", ";
}
*output_ << process_string(values.back());
}
*output_ << " ]";
write_value(key, values);
}

/**
Expand All @@ -383,23 +255,7 @@ class json_writer final : public structured_writer {
* @param values vector to write.
*/
void write(const std::string& key, const std::vector<double>& values) {
if (output_ == nullptr) {
return;
}
write_sep();
write_key(key);

*output_ << "[ ";
if (values.size() > 0) {
auto last = values.end();
--last;
for (auto it = values.begin(); it != last; ++it) {
write_value(*it);
*output_ << ", ";
}
write_value(values.back());
}
*output_ << " ]";
write_value(key, values);
}

/**
Expand All @@ -408,22 +264,7 @@ class json_writer final : public structured_writer {
* @param values vector to write.
*/
void write(const std::string& key, const std::vector<int>& values) {
if (output_ == nullptr) {
return;
}
write_sep();
write_key(key);

*output_ << "[ ";
if (values.size() > 0) {
auto last = values.end();
--last;
for (auto it = values.begin(); it != last; ++it) {
*output_ << *it << ", ";
}
*output_ << values.back();
}
*output_ << " ]";
write_value(key, values);
}

/**
Expand All @@ -433,23 +274,7 @@ class json_writer final : public structured_writer {
*/
void write(const std::string& key,
const std::vector<std::complex<double>>& values) {
if (output_ == nullptr) {
return;
}
write_sep();
write_key(key);

*output_ << "[ ";
if (values.size() > 0) {
auto last = values.end();
--last;
for (auto it = values.begin(); it != last; ++it) {
write_complex_value(*it);
*output_ << ", ";
}
write_complex_value(values.back());
}
*output_ << " ]";
write_value(key, values);
}

/**
Expand All @@ -458,12 +283,7 @@ class json_writer final : public structured_writer {
* @param vec Eigen Vector to write.
*/
void write(const std::string& key, const Eigen::VectorXd& vec) {
if (output_ == nullptr) {
return;
}
write_sep();
write_key(key);
write_eigen_vector(vec);
write_value(key, vec);
}

/**
Expand All @@ -472,12 +292,7 @@ class json_writer final : public structured_writer {
* @param vec Eigen Vector to write.
*/
void write(const std::string& key, const Eigen::RowVectorXd& vec) {
if (output_ == nullptr) {
return;
}
write_sep();
write_key(key);
write_eigen_vector(vec);
write_value(key, vec);
}

/**
Expand All @@ -486,21 +301,7 @@ class json_writer final : public structured_writer {
* @param mat Eigen Matrix to write.
*/
void write(const std::string& key, const Eigen::MatrixXd& mat) {
if (output_ == nullptr) {
return;
}
write_sep();
write_key(key);
*output_ << "[ ";
if (mat.rows() > 0) {
Eigen::Index last = mat.rows() - 1;
for (Eigen::Index i = 0; i < last; ++i) {
write_eigen_vector(mat.row(i));
*output_ << ", ";
}
write_eigen_vector(mat.row(last));
}
*output_ << " ]";
write_value(key, mat);
}
};

Expand Down
Loading
Loading