Skip to content

Commit e1927c6

Browse files
committed
(API) remove freestanding API
this change seems necessary to allow for internally managing the lifetime of strings. * enable string management in logic_rule: currently all strings are stored in logic_data until the logic_rule object is destructed. This may lead to string accumulation over time, if a rule generates many strings. e.g., through string concatenation. * remove ast-core. It is no longer needed as the user-side no longer accesses the any_expr directly. * move essential types for logic_data into ast-full.hpp
1 parent 0c4f422 commit e1927c6

File tree

9 files changed

+252
-223
lines changed

9 files changed

+252
-223
lines changed

cpp/bench/src/benchmark-complex1.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ int main(int argc, const char **argv) try {
9191
// Create jsonlogic benchmark
9292
auto jv_xy = boost::json::parse(expr);
9393
boost::json::object data_obj;
94+
jsonlogic::logic_rule rule = jsonlogic::create_logic(jv_xy);
9495

9596
size_t matches = 0;
9697
auto jl_lambda = [&] {
@@ -99,8 +100,8 @@ int main(int argc, const char **argv) try {
99100
data_obj["x"] = xs[i];
100101
data_obj["y"] = ys[i];
101102
data_obj["z"] = zs[i];
102-
auto data = boost::json::value_from(data_obj);
103-
auto v_xy = jsonlogic::apply(jv_xy, data);
103+
auto varaccess = jsonlogic::json_accessor(boost::json::value_from(data_obj));
104+
auto v_xy = rule.apply(varaccess);
104105

105106
bool val = jsonlogic::truthy(v_xy);
106107

@@ -116,9 +117,9 @@ int main(int argc, const char **argv) try {
116117

117118
auto jl2_lambda = [&] {
118119
matches = 0;
119-
auto [rule, ignore1, igmore2] = jsonlogic::create_logic(jv_xy);
120+
jsonlogic::logic_rule rule = jsonlogic::create_logic(jv_xy);
120121
for (size_t i = 0; i < N; ++i) {
121-
auto v_xy = jsonlogic::apply(rule, {xs[i], ys[i], zs[i]});
122+
auto v_xy = rule.apply({xs[i], ys[i], zs[i]});
122123
bool val = jsonlogic::truthy(v_xy);
123124

124125
if (val) {

cpp/bench/src/benchmark-equality.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -162,11 +162,13 @@ int main(int argc, const char **argv) try {
162162
size_t matches = 0;
163163
auto jl_lambda = [&] {
164164
matches = 0;
165+
auto rule = jsonlogic::create_logic(jv_xy);
166+
165167
for (size_t i = 0; i < N; ++i) {
166168
data_obj["x"] = xs[i];
167169
data_obj["y"] = ys[i];
168-
auto data = boost::json::value_from(data_obj);
169-
auto v_xy = jsonlogic::apply(jv_xy, data);
170+
auto accessor = jsonlogic::json_accessor(boost::json::value_from(data_obj));
171+
auto v_xy = rule.apply(accessor);
170172

171173
bool val = jsonlogic::truthy(v_xy);
172174

@@ -182,9 +184,9 @@ int main(int argc, const char **argv) try {
182184

183185
auto jl2_lambda = [&] {
184186
matches = 0;
185-
auto [rule, ignore1, igmore2] = jsonlogic::create_logic(jv_xy);
187+
auto rule = jsonlogic::create_logic(jv_xy);
186188
for (size_t i = 0; i < N; ++i) {
187-
auto v_xy = jsonlogic::apply(rule, {xs[i], ys[i]});
189+
auto v_xy = rule.apply({xs[i], ys[i]});
188190
bool val = jsonlogic::truthy(v_xy);
189191

190192
if (val) {

cpp/bench/src/benchmark-membership.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,16 +85,15 @@ int main(int argc, const char **argv) try {
8585
std::cout << "initialized data_obj\n";
8686
// data_obj["haystack"] = haystack;
8787
size_t matches = 0;
88-
jsonlogic::any_expr rule;
89-
std::tie(rule, std::ignore, std::ignore) = jsonlogic::create_logic(jv_in);
88+
jsonlogic::logic_rule rule = jsonlogic::create_logic(jv_in);
9089

9190
auto jl_lambda = [&] {
9291
matches = 0;
9392
for (size_t i = 0; i < N; ++i) {
9493
data_obj["x"] = xs[i];
9594
auto varaccess =
96-
jsonlogic::data_accessor(boost::json::value_from(data_obj));
97-
auto v_in = jsonlogic::apply(rule, varaccess);
95+
jsonlogic::json_accessor(boost::json::value_from(data_obj));
96+
auto v_in = rule.apply(varaccess);
9897

9998
bool val = jsonlogic::truthy(v_in);
10099

cpp/bench/src/benchmark-simple-and.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,15 +81,16 @@ int main(int argc, const char **argv) try {
8181

8282
auto jv_expr = boost::json::parse(expr);
8383
boost::json::object data_obj;
84+
jsonlogic::logic_rule rule = jsonlogic::create_logic(jv_expr);
8485

8586
size_t matches = 0;
8687
auto jl1_lambda = [&] {
8788
matches = 0;
8889
for (size_t i = 0; i < N; ++i) {
8990
data_obj["x"] = xs[i];
9091
data_obj["y"] = ys[i];
91-
auto data = boost::json::value_from(data_obj);
92-
auto result = jsonlogic::apply(jv_expr, data);
92+
auto varaccess = jsonlogic::json_accessor(boost::json::value_from(data_obj));
93+
auto result = rule.apply(varaccess);
9394

9495
bool val = jsonlogic::truthy(result);
9596

@@ -105,9 +106,9 @@ int main(int argc, const char **argv) try {
105106

106107
auto jl2_lambda = [&] {
107108
matches = 0;
108-
auto [rule, ignore1, ignore2] = jsonlogic::create_logic(jv_expr);
109+
jsonlogic::logic_rule rule = jsonlogic::create_logic(jv_expr);
109110
for (size_t i = 0; i < N; ++i) {
110-
auto result = jsonlogic::apply(rule, {xs[i], ys[i]});
111+
auto result = rule.apply({xs[i], ys[i]});
111112
bool val = jsonlogic::truthy(result);
112113

113114
if (val) {

cpp/include/jsonlogic/details/ast-core.hpp

Lines changed: 0 additions & 29 deletions
This file was deleted.

cpp/include/jsonlogic/details/ast-full.hpp

Lines changed: 78 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,38 @@
11
#pragma once
22

3-
#include <boost/json.hpp>
3+
#include <memory>
44
#include <map>
5+
#include <set>
56
#include <vector>
7+
#include <iosfwd>
68

7-
#include "ast-core.hpp"
89
#include "cxx-compat.hpp"
910

1011
#if !defined(WITH_JSONLOGIC_EXTENSIONS)
1112
#define WITH_JSONLOGIC_EXTENSIONS 1
1213
#endif /* !defined(WITH_JSONLOGIC_EXTENSIONS) */
1314

1415
namespace jsonlogic {
16+
17+
struct visitor;
18+
19+
// the root class
20+
struct expr {
21+
expr() = default;
22+
virtual ~expr() = default;
23+
24+
virtual void accept(visitor &) const = 0;
25+
26+
private:
27+
expr(expr &&) = delete;
28+
expr(const expr &) = delete;
29+
expr &operator=(expr &&) = delete;
30+
expr &operator=(const expr &) = delete;
31+
};
32+
33+
using any_expr = std::unique_ptr<expr>;
34+
35+
1536
struct oper : expr, private std::vector<any_expr> {
1637
using container_type = std::vector<any_expr>;
1738

@@ -557,4 +578,59 @@ auto generic_visit(ast_functor fn, ast_node *n, arguments... args)
557578
n->accept(disp);
558579
return std::move(disp).result();
559580
}
581+
582+
583+
//
584+
// logic internal data
585+
586+
/// type for string storage
587+
/// \note if the compiler uses small string optimization, we cannot
588+
/// use an std::vector because resizing invalidates the
589+
/// string_views.
590+
/// alternatives include forward_list or deque
591+
using string_table_base = std::set<std::string>;
592+
593+
/// string table ensures lifetime of string exceeds lifetime of string_views
594+
struct string_table : private string_table_base
595+
{
596+
using string_table_base::size;
597+
598+
std::string_view safe_string(std::string v)
599+
{
600+
auto res = this->emplace(std::move(v));
601+
return *res.first;
602+
}
603+
604+
template <class iterator>
605+
std::string_view safe_string(iterator aa, iterator zz)
606+
{
607+
return safe_string(std::string(aa, zz));
608+
}
609+
};
610+
611+
612+
using logic_data_base = std::tuple<any_expr, std::vector<std::string_view>, string_table, bool>;
613+
struct logic_data : logic_data_base
614+
{
615+
using base = logic_data_base;
616+
using base::base;
617+
618+
/// returns the logic expression
619+
any_expr const &syntax_tree() const { return std::get<0>(*this); }
620+
621+
/// returns static variable names (i.e., variable names that are not computed)
622+
std::vector<std::string_view> const &variable_names() const { return std::get<1>(*this); }
623+
624+
/// returns the string table
625+
string_table& strings() { return std::get<2>(*this); }
626+
string_table const& strings() const { return std::get<2>(*this); }
627+
628+
/// returns if the expression contains computed names.
629+
bool has_computed_variable_names() const { return std::get<3>(*this); }
630+
};
631+
632+
633+
634+
635+
560636
} // namespace jsonlogic

0 commit comments

Comments
 (0)