add string_view polyfill

This commit is contained in:
pantor
2019-01-21 21:34:34 +01:00
parent 5d99c2b703
commit dbcd5265fc
14 changed files with 2777 additions and 119 deletions

View File

@@ -4,6 +4,13 @@ sudo: required
matrix:
include:
- os: linux
compiler: gcc
env: COMPILER=g++-6
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: g++-6
- os: linux
compiler: gcc
env:

View File

@@ -1,11 +1,12 @@
#ifndef PANTOR_INJA_BYTECODE_HPP
#define PANTOR_INJA_BYTECODE_HPP
#include <string_view>
#include <utility>
#include <nlohmann/json.hpp>
#include "string_view.hpp"
namespace inja {
@@ -120,7 +121,7 @@ struct Bytecode {
Bytecode(): args(0), flags(0) {}
explicit Bytecode(Op op, unsigned int args = 0): op(op), args(args), flags(0) {}
explicit Bytecode(Op op, std::string_view str, unsigned int flags): op(op), args(0), flags(flags), str(str) {}
explicit Bytecode(Op op, nonstd::string_view str, unsigned int flags): op(op), args(0), flags(flags), str(str) {}
explicit Bytecode(Op op, json&& value, unsigned int flags): op(op), args(0), flags(flags), value(std::move(value)) {}
};

View File

@@ -3,7 +3,8 @@
#include <functional>
#include <string>
#include <string_view>
#include "string_view.hpp"
namespace inja {

View File

@@ -5,7 +5,6 @@
#include <fstream>
#include <sstream>
#include <string>
#include <string_view>
#include <nlohmann/json.hpp>
@@ -14,6 +13,7 @@
#include "parser.hpp"
#include "polyfill.hpp"
#include "renderer.hpp"
#include "string_view.hpp"
#include "template.hpp"
@@ -82,7 +82,7 @@ class Environment {
}
Template parse(std::string_view input) {
Template parse(nonstd::string_view input) {
Parser parser(m_impl->parser_config, m_impl->lexer_config, m_impl->included_templates);
return parser.parse(input);
}
@@ -92,7 +92,7 @@ class Environment {
return parser.parse_template(m_impl->input_path + static_cast<std::string>(filename));
}
std::string render(std::string_view input, const json& data) {
std::string render(nonstd::string_view input, const json& data) {
return render(parse(input), data);
}
@@ -166,14 +166,14 @@ class Environment {
/*!
@brief render with default settings to a string
*/
inline std::string render(std::string_view input, const json& data) {
inline std::string render(nonstd::string_view input, const json& data) {
return Environment().render(input, data);
}
/*!
@brief render with default settings to the given output stream
*/
inline void render_to(std::ostream& os, std::string_view input, const json& data) {
inline void render_to(std::ostream& os, nonstd::string_view input, const json& data) {
Environment env;
env.render_to(os, env.parse(input), data);
}

View File

@@ -1,9 +1,8 @@
#ifndef PANTOR_INJA_FUNCTION_STORAGE_HPP
#define PANTOR_INJA_FUNCTION_STORAGE_HPP
#include <string_view>
#include "bytecode.hpp"
#include "string_view.hpp"
namespace inja {
@@ -15,24 +14,24 @@ using CallbackFunction = std::function<json(Arguments& args)>;
class FunctionStorage {
public:
void add_builtin(std::string_view name, unsigned int num_args, Bytecode::Op op) {
void add_builtin(nonstd::string_view name, unsigned int num_args, Bytecode::Op op) {
auto& data = get_or_new(name, num_args);
data.op = op;
}
void add_callback(std::string_view name, unsigned int num_args, const CallbackFunction& function) {
void add_callback(nonstd::string_view name, unsigned int num_args, const CallbackFunction& function) {
auto& data = get_or_new(name, num_args);
data.function = function;
}
Bytecode::Op find_builtin(std::string_view name, unsigned int num_args) const {
Bytecode::Op find_builtin(nonstd::string_view name, unsigned int num_args) const {
if (auto ptr = get(name, num_args)) {
return ptr->op;
}
return Bytecode::Op::Nop;
}
CallbackFunction find_callback(std::string_view name, unsigned int num_args) const {
CallbackFunction find_callback(nonstd::string_view name, unsigned int num_args) const {
if (auto ptr = get(name, num_args)) {
return ptr->function;
}
@@ -46,7 +45,7 @@ class FunctionStorage {
CallbackFunction function; // for callbacks
};
FunctionData& get_or_new(std::string_view name, unsigned int num_args) {
FunctionData& get_or_new(nonstd::string_view name, unsigned int num_args) {
auto &vec = m_map[static_cast<std::string>(name)];
for (auto &i: vec) {
if (i.num_args == num_args) return i;
@@ -56,7 +55,7 @@ class FunctionStorage {
return vec.back();
}
const FunctionData* get(std::string_view name, unsigned int num_args) const {
const FunctionData* get(nonstd::string_view name, unsigned int num_args) const {
auto it = m_map.find(static_cast<std::string>(name));
if (it == m_map.end()) return nullptr;
for (auto &&i: it->second) {

View File

@@ -7,12 +7,12 @@
#include <memory>
#include <sstream>
#include <string>
#include <string_view>
#include <vector>
#include <nlohmann/json.hpp>
#include "environment.hpp"
#include "string_view.hpp"
#include "template.hpp"
#include "parser.hpp"
#include "renderer.hpp"

View File

@@ -25,14 +25,14 @@ class Lexer {
} m_state;
const LexerConfig& m_config;
std::string_view m_in;
nonstd::string_view m_in;
size_t m_tok_start;
size_t m_pos;
public:
explicit Lexer(const LexerConfig& config) : m_config(config) {}
void start(std::string_view in) {
void start(nonstd::string_view in) {
m_in = in;
m_tok_start = 0;
m_pos = 0;
@@ -50,7 +50,7 @@ class Lexer {
case State::Text: {
// fast-scan to first open character
size_t open_start = m_in.substr(m_pos).find_first_of(m_config.open_chars);
if (open_start == std::string_view::npos) {
if (open_start == nonstd::string_view::npos) {
// didn't find open, return remaining text as text token
m_pos = m_in.size();
return make_token(Token::Kind::Text);
@@ -58,15 +58,15 @@ class Lexer {
m_pos += open_start;
// try to match one of the opening sequences, and get the close
std::string_view open_str = m_in.substr(m_pos);
if (string_view::starts_with(open_str, m_config.expression_open)) {
nonstd::string_view open_str = m_in.substr(m_pos);
if (inja::string_view::starts_with(open_str, m_config.expression_open)) {
m_state = State::ExpressionStart;
} else if (string_view::starts_with(open_str, m_config.statement_open)) {
} else if (inja::string_view::starts_with(open_str, m_config.statement_open)) {
m_state = State::StatementStart;
} else if (string_view::starts_with(open_str, m_config.comment_open)) {
} else if (inja::string_view::starts_with(open_str, m_config.comment_open)) {
m_state = State::CommentStart;
} else if ((m_pos == 0 || m_in[m_pos - 1] == '\n') &&
string_view::starts_with(open_str, m_config.line_statement)) {
inja::string_view::starts_with(open_str, m_config.line_statement)) {
m_state = State::LineStart;
} else {
m_pos += 1; // wasn't actually an opening sequence
@@ -104,7 +104,7 @@ class Lexer {
case State::CommentBody: {
// fast-scan to comment close
size_t end = m_in.substr(m_pos).find(m_config.comment_close);
if (end == std::string_view::npos) {
if (end == nonstd::string_view::npos) {
m_pos = m_in.size();
return make_token(Token::Kind::Eof);
}
@@ -119,7 +119,7 @@ class Lexer {
const LexerConfig& get_config() const { return m_config; }
private:
Token scan_body(std::string_view close, Token::Kind closeKind) {
Token scan_body(nonstd::string_view close, Token::Kind closeKind) {
again:
// skip whitespace (except for \n as it might be a close)
if (m_tok_start >= m_in.size()) return make_token(Token::Kind::Eof);
@@ -130,7 +130,7 @@ class Lexer {
}
// check for close
if (string_view::starts_with(m_in.substr(m_tok_start), close)) {
if (inja::string_view::starts_with(m_in.substr(m_tok_start), close)) {
m_state = State::Text;
m_pos = m_tok_start + close.size();
return make_token(closeKind);

View File

@@ -128,7 +128,7 @@ class Parser {
}
bool parse_expression_datum(Template& tmpl) {
std::string_view json_first;
nonstd::string_view json_first;
size_t bracket_level = 0;
size_t brace_level = 0;
@@ -253,13 +253,13 @@ class Parser {
returnJson:
// bridge across all intermediate tokens
std::string_view json_text(json_first.data(), m_tok.text.data() - json_first.data() + m_tok.text.size());
nonstd::string_view json_text(json_first.data(), m_tok.text.data() - json_first.data() + m_tok.text.size());
tmpl.bytecodes.emplace_back(Bytecode::Op::Push, json::parse(json_text), Bytecode::Flag::ValueImmediate);
get_next_token();
return true;
}
bool parse_statement(Template& tmpl, std::string_view path) {
bool parse_statement(Template& tmpl, nonstd::string_view path) {
if (m_tok.kind != Token::Kind::Id) return false;
if (m_tok.text == "if") {
@@ -352,7 +352,7 @@ class Parser {
if (!key_token.text.empty()) {
tmpl.bytecodes.back().value = key_token.text;
}
tmpl.bytecodes.back().str = value_token.text;
tmpl.bytecodes.back().str = static_cast<std::string>(value_token.text);
} else if (m_tok.text == "endfor") {
get_next_token();
if (m_loop_stack.empty()) {
@@ -409,7 +409,7 @@ class Parser {
tmpl.bytecodes.emplace_back(op, num_args);
}
void append_callback(Template& tmpl, std::string_view name, unsigned int num_args) {
void append_callback(Template& tmpl, nonstd::string_view name, unsigned int num_args) {
// we can merge with back-to-back push value (not lookup)
if (!tmpl.bytecodes.empty()) {
Bytecode& last = tmpl.bytecodes.back();
@@ -417,17 +417,17 @@ class Parser {
(last.flags & Bytecode::Flag::ValueMask) == Bytecode::Flag::ValueImmediate) {
last.op = Bytecode::Op::Callback;
last.args = num_args;
last.str = name;
last.str = static_cast<std::string>(name);
return;
}
}
// otherwise just add it to the end
tmpl.bytecodes.emplace_back(Bytecode::Op::Callback, num_args);
tmpl.bytecodes.back().str = name;
tmpl.bytecodes.back().str = static_cast<std::string>(name);
}
void parse_into(Template& tmpl, std::string_view path) {
void parse_into(Template& tmpl, nonstd::string_view path) {
m_lexer.start(tmpl.content);
for (;;) {
@@ -480,28 +480,28 @@ class Parser {
}
}
Template parse(std::string_view input, std::string_view path) {
Template parse(nonstd::string_view input, nonstd::string_view path) {
Template result;
result.content = input;
result.content = static_cast<std::string>(input);
parse_into(result, path);
return result;
}
Template parse(std::string_view input) {
Template parse(nonstd::string_view input) {
return parse(input, "./");
}
Template parse_template(std::string_view filename) {
Template parse_template(nonstd::string_view filename) {
Template result;
result.content = load_file(filename);
std::string_view path = filename.substr(0, filename.find_last_of("/\\") + 1);
nonstd::string_view path = filename.substr(0, filename.find_last_of("/\\") + 1);
// StringRef path = sys::path::parent_path(filename);
Parser(m_config, m_lexer.get_config(), m_included_templates).parse_into(result, path);
return result;
}
std::string load_file(std::string_view filename) {
std::string load_file(nonstd::string_view filename) {
std::ifstream file(static_cast<std::string>(filename));
std::string text((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
return text;

View File

@@ -13,15 +13,15 @@
namespace inja {
inline std::string_view convert_dot_to_json_pointer(std::string_view dot, std::string& out) {
inline nonstd::string_view convert_dot_to_json_pointer(nonstd::string_view dot, std::string& out) {
out.clear();
do {
std::string_view part;
nonstd::string_view part;
std::tie(part, dot) = string_view::split(dot, '.');
out.push_back('/');
out.append(part.begin(), part.end());
} while (!dot.empty());
return std::string_view(out.data(), out.size());
return nonstd::string_view(out.data(), out.size());
}
class Renderer {
@@ -60,7 +60,7 @@ class Renderer {
const json* get_imm(const Bytecode& bc) {
std::string ptr_buffer;
std::string_view ptr;
nonstd::string_view ptr;
switch (bc.flags & Bytecode::Flag::ValueMask) {
case Bytecode::Flag::ValuePop:
return nullptr;
@@ -136,8 +136,8 @@ class Renderer {
std::vector<json> m_stack;
struct LoopLevel {
std::string_view key_name; // variable name for keys
std::string_view value_name; // variable name for values
nonstd::string_view key_name; // variable name for keys
nonstd::string_view value_name; // variable name for values
json data; // data with loop info added
json values; // values to iterate over
@@ -148,7 +148,7 @@ class Renderer {
size_t size; // length of list
// loop over map
using KeyValue = std::pair<std::string_view, json*>;
using KeyValue = std::pair<nonstd::string_view, json*>;
using MapValues = std::vector<KeyValue>;
MapValues map_values; // values to iterate over
MapValues::iterator map_it; // iterator over values

1320
include/inja/string_view.hpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
#ifndef PANTOR_INJA_TOKEN_HPP
#define PANTOR_INJA_TOKEN_HPP
#include <string_view>
#include "string_view.hpp"
namespace inja {
@@ -38,10 +38,10 @@ struct Token {
Eof
} kind {Kind::Unknown};
std::string_view text;
nonstd::string_view text;
constexpr Token() = default;
constexpr Token(Kind kind, std::string_view text): kind(kind), text(text) {}
constexpr Token(Kind kind, nonstd::string_view text): kind(kind), text(text) {}
std::string describe() const {
switch (kind) {

View File

@@ -2,7 +2,8 @@
#define PANTOR_INJA_UTILS_HPP
#include <stdexcept>
#include <string_view>
#include "string_view.hpp"
namespace inja {
@@ -12,21 +13,21 @@ inline void inja_throw(const std::string& type, const std::string& message) {
}
namespace string_view {
inline std::string_view slice(std::string_view view, size_t start, size_t end) {
inline nonstd::string_view slice(nonstd::string_view view, size_t start, size_t end) {
start = std::min(start, view.size());
end = std::min(std::max(start, end), view.size());
return view.substr(start, end - start); // StringRef(Data + Start, End - Start);
}
inline std::pair<std::string_view, std::string_view> split(std::string_view view, char Separator) {
inline std::pair<nonstd::string_view, nonstd::string_view> split(nonstd::string_view view, char Separator) {
size_t idx = view.find(Separator);
if (idx == std::string_view::npos) {
return std::make_pair(view, std::string_view());
if (idx == nonstd::string_view::npos) {
return std::make_pair(view, nonstd::string_view());
}
return std::make_pair(slice(view, 0, idx), slice(view, idx + 1, std::string_view::npos));
return std::make_pair(slice(view, 0, idx), slice(view, idx + 1, nonstd::string_view::npos));
}
inline bool starts_with(std::string_view view, std::string_view prefix) {
inline bool starts_with(nonstd::string_view view, nonstd::string_view prefix) {
return (view.size() >= prefix.size() && view.compare(0, prefix.size(), prefix) == 0);
}
} // namespace string

File diff suppressed because it is too large Load Diff

View File

@@ -261,12 +261,12 @@ TEST_CASE("callbacks") {
data["age"] = 28;
env.add_callback("double", 1, [](inja::Arguments& args) {
int number = args.at(0)->get<double>();
int number = args.at(0)->get<int>();
return 2 * number;
});
env.add_callback("half", 1, [](inja::Arguments args) {
int number = args.at(0)->get<double>();
int number = args.at(0)->get<int>();
return number / 2;
});