Felipe97/llama-cpp-compiled
01.2k
1#pragma once2 3#include "string.h"4#include "utils.h"5 6#include <algorithm>7#include <cmath>8#include <cstdint>9#include <functional>10#include <map>11#include <memory>12#include <set>13#include <sstream>14#include <string>15#include <vector>16#include <unordered_map>17 18namespace jinja {19 20struct value_t;21using value = std::shared_ptr<value_t>;22 23 24// Helper to check the type of a value25template<typename T>26struct extract_pointee {27 using type = T;28};29template<typename U>30struct extract_pointee<std::shared_ptr<U>> {31 using type = U;32};33template<typename T>34bool is_val(const value & ptr) {35 using PointeeType = typename extract_pointee<T>::type;36 return dynamic_cast<const PointeeType*>(ptr.get()) != nullptr;37}38template<typename T>39bool is_val(const value_t * ptr) {40 using PointeeType = typename extract_pointee<T>::type;41 return dynamic_cast<const PointeeType*>(ptr) != nullptr;42}43template<typename T, typename... Args>44std::shared_ptr<typename extract_pointee<T>::type> mk_val(Args&&... args) {45 using PointeeType = typename extract_pointee<T>::type;46 return std::make_shared<PointeeType>(std::forward<Args>(args)...);47}48template<typename T>49const typename extract_pointee<T>::type * cast_val(const value & ptr) {50 using PointeeType = typename extract_pointee<T>::type;51 return dynamic_cast<const PointeeType*>(ptr.get());52}53template<typename T>54typename extract_pointee<T>::type * cast_val(value & ptr) {55 using PointeeType = typename extract_pointee<T>::type;56 return dynamic_cast<PointeeType*>(ptr.get());57}58// End Helper59 60 61struct context; // forward declaration62 63 64// for converting from JSON to jinja values65// example input JSON:66// {67// "messages": [68// {"role": "user", "content": "Hello!"},69// {"role": "assistant", "content": "Hi there!"}70// ],71// "bos_token": "<s>",72// "eos_token": "</s>",73// }74//75// to mark strings as user input, wrap them in a special object:76// {77// "messages": [78// {79// "role": "user",80// "content": {"__input__": "Hello!"} // this string is user input81// },82// ...83// ],84// }85//86// marking input can be useful for tracking data provenance87// and preventing template injection attacks88//89// Note: T_JSON can be common_json90template<typename T_JSON>91void global_from_json(context & ctx, const T_JSON & json_obj, bool mark_input);92 93//94// base value type95//96 97struct func_args; // function argument values98 99using func_hptr = value(const func_args &);100using func_handler = std::function<func_hptr>;101using func_builtins = std::map<std::string, func_handler>;102 103enum value_compare_op { eq, ge, gt, lt, ne };104bool value_compare(const value & a, const value & b, value_compare_op op);105 106struct value_t {107 int64_t val_int;108 double val_flt;109 string val_str;110 111 std::vector<value> val_arr;112 std::vector<std::pair<value, value>> val_obj;113 114 func_handler val_func;115 116 // only used if ctx.is_get_stats = true117 struct stats_t {118 bool used = false;119 // ops can be builtin calls or operators: "array_access", "object_access"120 std::set<std::string> ops;121 // utility to recursively mark value and its children as used122 static void mark_used(value & val, bool deep = false);123 } stats;124 125 value_t() = default;126 value_t(const value_t &) = default;127 virtual ~value_t() = default;128 129 // Note: only for debugging and error reporting purposes130 virtual std::string type() const { return ""; }131 132 virtual int64_t as_int() const { throw_type_error("is not an int value"); }133 virtual double as_float() const { throw_type_error("is not a float value"); }134 virtual string as_string() const { throw_type_error("is not a string value"); }135 virtual bool as_bool() const { throw_type_error("is not a bool value"); }136 virtual const std::vector<value> & as_array() const { throw_type_error("is not an array value"); }137 virtual const std::vector<std::pair<value, value>> & as_ordered_object() const { throw_type_error("is not an object value"); }138 virtual value invoke(const func_args &) const { throw_type_error("is not a function value"); }139 virtual bool is_none() const { return false; }140 virtual bool is_undefined() const { return false; }141 virtual const func_builtins & get_builtins() const { throw_type_error("has no builtins"); }142 143 virtual bool has_key(const value &) { throw_type_error("is not an object value"); }144 virtual void insert(const value & /* key */, const value & /* val */) { throw_type_error("is not an object value"); }145 virtual value & at(const value & /* key */, value & /* default_val */) { throw_type_error("is not an object value"); }146 virtual value & at(const value & /* key */) { throw_type_error("is not an object value"); }147 virtual value & at(const std::string & /* key */, value & /* default_val */) { throw_type_error("is not an object value"); }148 virtual value & at(const std::string & /* key */) { throw_type_error("is not an object value"); }149 virtual value & at(int64_t /* idx */, value & /* default_val */) { throw_type_error("is not an array value"); }150 virtual value & at(int64_t /* idx */) { throw_type_error("is not an array value"); }151 152 virtual bool is_numeric() const { return false; }153 virtual bool is_hashable() const { return false; }154 virtual bool is_immutable() const { return true; }155 virtual hasher unique_hash() const noexcept = 0;156 // TODO: C++20 <=> operator157 // NOTE: We are treating == as equivalent (for normal comparisons) and != as strict nonequal (for strict (is) comparisons)158 virtual bool operator==(const value_t & other) const { return equivalent(other); }159 virtual bool operator!=(const value_t & other) const { return nonequal(other); }160 161 // Note: only for debugging purposes162 virtual std::string as_repr() const { return as_string().str(); }163 164private:165 [[noreturn]] void throw_type_error(const char* expected) const {166 throw std::runtime_error(type() + " " + expected);167 }168 169protected:170 virtual bool equivalent(const value_t &) const = 0;171 virtual bool nonequal(const value_t & other) const { return !equivalent(other); }172};173 174//175// utils176//177 178const func_builtins & global_builtins();179 180std::string value_to_json(const value & val, int indent = -1, const std::string_view item_sep = ", ", const std::string_view key_sep = ": ");181 182// Note: only used for debugging purposes183std::string value_to_string_repr(const value & val);184 185struct not_implemented_exception : public std::runtime_error {186 not_implemented_exception(const std::string & msg) : std::runtime_error("NotImplemented: " + msg) {}187};188 189struct value_hasher {190 size_t operator()(const value & val) const noexcept {191 return val->unique_hash().digest();192 }193};194 195struct value_equivalence {196 bool operator()(const value & lhs, const value & rhs) const {197 return *lhs == *rhs;198 }199 bool operator()(const std::pair<value, value> & lhs, const std::pair<value, value> & rhs) const {200 return *(lhs.first) == *(rhs.first) && *(lhs.second) == *(rhs.second);201 }202};203 204struct value_equality {205 bool operator()(const value & lhs, const value & rhs) const {206 return !(*lhs != *rhs);207 }208};209 210//211// primitive value types212//213 214struct value_int_t : public value_t {215 value_int_t(int64_t v) {216 val_int = v;217 val_flt = static_cast<double>(v);218 if (static_cast<int64_t>(val_flt) != v) {219 val_flt = v < 0 ? -INFINITY : INFINITY;220 }221 }222 virtual std::string type() const override { return "Integer"; }223 virtual int64_t as_int() const override { return val_int; }224 virtual double as_float() const override { return val_flt; }225 virtual string as_string() const override { return std::to_string(val_int); }226 virtual bool as_bool() const override {227 return val_int != 0;228 }229 virtual const func_builtins & get_builtins() const override;230 virtual bool is_numeric() const override { return true; }231 virtual bool is_hashable() const override { return true; }232 virtual hasher unique_hash() const noexcept override {233 return hasher(typeid(*this))234 .update(&val_int, sizeof(val_int))235 .update(&val_flt, sizeof(val_flt));236 }237protected:238 virtual bool equivalent(const value_t & other) const override {239 return other.is_numeric() && val_int == other.val_int && val_flt == other.val_flt;240 }241 virtual bool nonequal(const value_t & other) const override {242 return !(typeid(*this) == typeid(other) && val_int == other.val_int);243 }244};245using value_int = std::shared_ptr<value_int_t>;246 247 248struct value_float_t : public value_t {249 value val;250 value_float_t(double v) {251 val_flt = v;252 val_int = std::isfinite(v) ? static_cast<int64_t>(v) : 0;253 val = mk_val<value_int>(val_int);254 }255 virtual std::string type() const override { return "Float"; }256 virtual double as_float() const override { return val_flt; }257 virtual int64_t as_int() const override { return val_int; }258 virtual string as_string() const override {259 std::string out = std::to_string(val_flt);260 out.erase(out.find_last_not_of('0') + 1, std::string::npos); // remove trailing zeros261 if (out.back() == '.') out.push_back('0'); // leave one zero if no decimals262 return out;263 }264 virtual bool as_bool() const override {265 return val_flt != 0.0;266 }267 virtual const func_builtins & get_builtins() const override;268 virtual bool is_numeric() const override { return true; }269 virtual bool is_hashable() const override { return true; }270 virtual hasher unique_hash() const noexcept override {271 if (static_cast<double>(val_int) == val_flt) {272 return val->unique_hash();273 } else {274 return hasher(typeid(*this))275 .update(&val_int, sizeof(val_int))276 .update(&val_flt, sizeof(val_flt));277 }278 }279protected:280 virtual bool equivalent(const value_t & other) const override {281 return other.is_numeric() && val_int == other.val_int && val_flt == other.val_flt;282 }283 virtual bool nonequal(const value_t & other) const override {284 return !(typeid(*this) == typeid(other) && val_flt == other.val_flt);285 }286};287using value_float = std::shared_ptr<value_float_t>;288 289 290struct value_string_t : public value_t {291 value_string_t() { val_str = string(); }292 value_string_t(const std::string & v) { val_str = string(v); }293 value_string_t(const string & v) { val_str = v; }294 virtual std::string type() const override { return "String"; }295 virtual string as_string() const override { return val_str; }296 virtual std::string as_repr() const override {297 std::ostringstream ss;298 for (const auto & part : val_str.parts) {299 ss << (part.is_input ? "INPUT: " : "TMPL: ") << part.val << "\n";300 }301 return ss.str();302 }303 virtual bool as_bool() const override {304 return val_str.length() > 0;305 }306 virtual const func_builtins & get_builtins() const override;307 virtual bool is_hashable() const override { return true; }308 virtual hasher unique_hash() const noexcept override {309 const auto type_hash = typeid(*this).hash_code();310 auto hash = hasher();311 hash.update(&type_hash, sizeof(type_hash));312 val_str.hash_update(hash);313 return hash;314 }315 void mark_input() {316 val_str.mark_input();317 }318protected:319 virtual bool equivalent(const value_t & other) const override {320 return typeid(*this) == typeid(other) && val_str.str() == other.val_str.str();321 }322};323using value_string = std::shared_ptr<value_string_t>;324 325 326struct value_bool_t : public value_t {327 value val;328 value_bool_t(bool v) {329 val_int = static_cast<int64_t>(v);330 val_flt = static_cast<double>(v);331 val = mk_val<value_int>(val_int);332 }333 virtual std::string type() const override { return "Boolean"; }334 virtual int64_t as_int() const override { return val_int; }335 virtual bool as_bool() const override { return val_int; }336 virtual string as_string() const override { return std::string(val_int ? "True" : "False"); }337 virtual const func_builtins & get_builtins() const override;338 virtual bool is_numeric() const override { return true; }339 virtual bool is_hashable() const override { return true; }340 virtual hasher unique_hash() const noexcept override {341 return val->unique_hash();342 }343protected:344 virtual bool equivalent(const value_t & other) const override {345 return other.is_numeric() && val_int == other.val_int && val_flt == other.val_flt;346 }347 virtual bool nonequal(const value_t & other) const override {348 return !(typeid(*this) == typeid(other) && val_int == other.val_int);349 }350};351using value_bool = std::shared_ptr<value_bool_t>;352 353 354struct value_array_t : public value_t {355 value_array_t() = default;356 value_array_t(value & v) {357 val_arr = v->val_arr;358 }359 value_array_t(std::vector<value> && arr) {360 val_arr = arr;361 }362 value_array_t(const std::vector<value> & arr) {363 val_arr = arr;364 }365 void reverse() {366 if (is_immutable()) {367 throw std::runtime_error("Attempting to modify immutable type");368 }369 std::reverse(val_arr.begin(), val_arr.end());370 }371 void push_back(const value & val) {372 if (is_immutable()) {373 throw std::runtime_error("Attempting to modify immutable type");374 }375 val_arr.push_back(val);376 }377 void push_back(value && val) {378 if (is_immutable()) {379 throw std::runtime_error("Attempting to modify immutable type");380 }381 val_arr.push_back(std::move(val));382 }383 value pop_at(int64_t index) {384 if (is_immutable()) {385 throw std::runtime_error("Attempting to modify immutable type");386 }387 if (index < 0) {388 index = static_cast<int64_t>(val_arr.size()) + index;389 }390 if (index < 0 || index >= static_cast<int64_t>(val_arr.size())) {391 throw std::runtime_error("Index " + std::to_string(index) + " out of bounds for array of size " + std::to_string(val_arr.size()));392 }393 value val = val_arr.at(static_cast<size_t>(index));394 val_arr.erase(val_arr.begin() + index);395 return val;396 }397 virtual std::string type() const override { return "Array"; }398 virtual bool is_immutable() const override { return false; }399 virtual const std::vector<value> & as_array() const override { return val_arr; }400 virtual string as_string() const override {401 const bool immutable = is_immutable();402 std::ostringstream ss;403 ss << (immutable ? "(" : "[");404 for (size_t i = 0; i < val_arr.size(); i++) {405 if (i > 0) ss << ", ";406 value val = val_arr.at(i);407 ss << value_to_string_repr(val);408 }409 if (immutable && val_arr.size() == 1) {410 ss << ",";411 }412 ss << (immutable ? ")" : "]");413 return ss.str();414 }415 virtual bool as_bool() const override {416 return !val_arr.empty();417 }418 virtual value & at(int64_t index, value & default_val) override {419 if (index < 0) {420 index += val_arr.size();421 }422 if (index < 0 || static_cast<size_t>(index) >= val_arr.size()) {423 return default_val;424 }425 return val_arr[index];426 }427 virtual value & at(int64_t index) override {428 if (index < 0) {429 index += val_arr.size();430 }431 if (index < 0 || static_cast<size_t>(index) >= val_arr.size()) {432 throw std::runtime_error("Index " + std::to_string(index) + " out of bounds for array of size " + std::to_string(val_arr.size()));433 }434 return val_arr[index];435 }436 virtual const func_builtins & get_builtins() const override;437 virtual bool is_hashable() const override {438 if (std::all_of(val_arr.begin(), val_arr.end(), [&](auto & val) -> bool {439 return val->is_immutable() && val->is_hashable();440 })) {441 return true;442 }443 return false;444 }445 virtual hasher unique_hash() const noexcept override {446 auto hash = hasher(typeid(*this));447 for (const auto & val : val_arr) {448 // must use digest to prevent problems from "concatenation" property of hasher449 // for ex. hash of [ "ab", "c" ] should be different from [ "a", "bc" ]450 const size_t val_hash = val->unique_hash().digest();451 hash.update(&val_hash, sizeof(size_t));452 }453 return hash;454 }455protected:456 virtual bool equivalent(const value_t & other) const override {457 return typeid(*this) == typeid(other) && is_hashable() && other.is_hashable() && std::equal(val_arr.begin(), val_arr.end(), other.val_arr.begin(), other.val_arr.end(), value_equivalence());458 }459};460using value_array = std::shared_ptr<value_array_t>;461 462 463struct value_tuple_t : public value_array_t {464 value_tuple_t(value & v) {465 val_arr = v->val_arr;466 }467 value_tuple_t(std::vector<value> && arr) {468 val_arr = arr;469 }470 value_tuple_t(const std::vector<value> & arr) {471 val_arr = arr;472 }473 value_tuple_t(const std::pair<value, value> & pair) {474 val_arr.push_back(pair.first);475 val_arr.push_back(pair.second);476 }477 virtual std::string type() const override { return "Tuple"; }478 virtual bool is_immutable() const override { return true; }479};480using value_tuple = std::shared_ptr<value_tuple_t>;481 482 483struct value_object_t : public value_t {484 std::unordered_map<value, value, value_hasher, value_equivalence> unordered;485 bool has_builtins = true; // context and loop objects do not have builtins486 value_object_t() = default;487 value_object_t(value & v) {488 val_obj = v->val_obj;489 for (const auto & pair : val_obj) {490 unordered[pair.first] = pair.second;491 }492 }493 value_object_t(const std::map<value, value> & obj) {494 for (const auto & pair : obj) {495 insert(pair.first, pair.second);496 }497 }498 value_object_t(const std::vector<std::pair<value, value>> & obj) {499 for (const auto & pair : obj) {500 insert(pair.first, pair.second);501 }502 }503 void insert(const std::string & key, const value & val) {504 insert(mk_val<value_string>(key), val);505 }506 virtual std::string type() const override { return "Object"; }507 virtual bool is_immutable() const override { return false; }508 virtual const std::vector<std::pair<value, value>> & as_ordered_object() const override { return val_obj; }509 virtual string as_string() const override {510 std::ostringstream ss;511 ss << "{";512 for (size_t i = 0; i < val_obj.size(); i++) {513 if (i > 0) ss << ", ";514 auto & [key, val] = val_obj.at(i);515 ss << value_to_string_repr(key) << ": " << value_to_string_repr(val);516 }517 ss << "}";518 return ss.str();519 }520 virtual bool as_bool() const override {521 return !unordered.empty();522 }523 virtual bool has_key(const value & key) override {524 if (!key->is_immutable() || !key->is_hashable()) {525 throw std::runtime_error("Object key of unhashable type: " + key->type());526 }527 return unordered.find(key) != unordered.end();528 }529 virtual void insert(const value & key, const value & val) override {530 bool replaced = false;531 if (is_immutable()) {532 throw std::runtime_error("Attempting to modify immutable type");533 }534 if (has_key(key)) {535 // if key exists, replace value in ordered list instead of appending536 for (auto & pair : val_obj) {537 if (*(pair.first) == *key) {538 pair.second = val;539 replaced = true;540 break;541 }542 }543 }544 unordered[key] = val;545 if (!replaced) {546 val_obj.push_back({key, val});547 }548 }549 virtual value & at(const value & key, value & default_val) override {550 if (!has_key(key)) {551 return default_val;552 }553 return unordered.at(key);554 }555 virtual value & at(const value & key) override {556 if (!has_key(key)) {557 throw std::runtime_error("Key '" + key->as_string().str() + "' not found in value of type " + type());558 }559 return unordered.at(key);560 }561 virtual value & at(const std::string & key, value & default_val) override {562 value key_val = mk_val<value_string>(key);563 return at(key_val, default_val);564 }565 virtual value & at(const std::string & key) override {566 value key_val = mk_val<value_string>(key);567 return at(key_val);568 }569 virtual const func_builtins & get_builtins() const override;570 virtual bool is_hashable() const override {571 if (std::all_of(val_obj.begin(), val_obj.end(), [&](auto & pair) -> bool {572 const auto & val = pair.second;573 return val->is_immutable() && val->is_hashable();574 })) {575 return true;576 }577 return false;578 }579 virtual hasher unique_hash() const noexcept override {580 auto hash = hasher(typeid(*this));581 for (const auto & [key, val] : val_obj) {582 // must use digest to prevent problems from "concatenation" property of hasher583 // for ex. hash of key="ab", value="c" should be different from key="a", value="bc"584 const size_t key_hash = key->unique_hash().digest();585 const size_t val_hash = val->unique_hash().digest();586 hash.update(&key_hash, sizeof(key_hash));587 hash.update(&val_hash, sizeof(val_hash));588 }589 return hash;590 }591protected:592 virtual bool equivalent(const value_t & other) const override {593 return typeid(*this) == typeid(other) && is_hashable() && other.is_hashable() && std::equal(val_obj.begin(), val_obj.end(), other.val_obj.begin(), other.val_obj.end(), value_equivalence());594 }595};596using value_object = std::shared_ptr<value_object_t>;597 598//599// none and undefined types600//601 602struct value_none_t : public value_t {603 virtual std::string type() const override { return "None"; }604 virtual bool is_none() const override { return true; }605 virtual bool as_bool() const override { return false; }606 virtual string as_string() const override { return string(type()); }607 virtual std::string as_repr() const override { return type(); }608 virtual const func_builtins & get_builtins() const override;609 virtual bool is_hashable() const override { return true; }610 virtual hasher unique_hash() const noexcept override {611 return hasher(typeid(*this));612 }613protected:614 virtual bool equivalent(const value_t & other) const override {615 return typeid(*this) == typeid(other);616 }617};618using value_none = std::shared_ptr<value_none_t>;619 620struct value_undefined_t : public value_t {621 std::string hint; // for debugging, to indicate where undefined came from622 value_undefined_t(const std::string & h = "") : hint(h) {}623 virtual std::string type() const override { return hint.empty() ? "Undefined" : "Undefined (hint: '" + hint + "')"; }624 virtual bool is_undefined() const override { return true; }625 virtual bool as_bool() const override { return false; }626 virtual std::string as_repr() const override { return type(); }627 virtual const func_builtins & get_builtins() const override;628 virtual hasher unique_hash() const noexcept override {629 return hasher(typeid(*this));630 }631protected:632 virtual bool equivalent(const value_t & other) const override {633 return is_undefined() == other.is_undefined();634 }635};636using value_undefined = std::shared_ptr<value_undefined_t>;637 638//639// function type640//641 642struct func_args {643public:644 std::string func_name; // for error messages645 context & ctx;646 func_args(context & ctx) : ctx(ctx) {}647 value get_kwarg(const std::string & key, value default_val) const;648 value get_kwarg_or_pos(const std::string & key, size_t pos) const;649 value get_pos(size_t pos) const;650 value get_pos(size_t pos, value default_val) const;651 const std::vector<value> & get_args() const;652 size_t count() const { return args.size(); }653 void push_back(const value & val);654 void push_front(const value & val);655 void ensure_count(size_t min, size_t max = 999) const {656 size_t n = args.size();657 if (n < min || n > max) {658 throw std::runtime_error("Function '" + func_name + "' expected between " + std::to_string(min) + " and " + std::to_string(max) + " arguments, got " + std::to_string(n));659 }660 }661 template<typename T> void ensure_val(const value & ptr) const {662 if (!is_val<T>(ptr)) {663 throw std::runtime_error("Function '" + func_name + "' expected value of type " + std::string(typeid(T).name()) + ", got " + ptr->type());664 }665 }666 void ensure_count(bool require0, bool require1, bool require2, bool require3) const {667 static auto bool_to_int = [](bool b) { return b ? 1 : 0; };668 size_t required = bool_to_int(require0) + bool_to_int(require1) + bool_to_int(require2) + bool_to_int(require3);669 ensure_count(required);670 }671 template<typename T0> void ensure_vals(bool required0 = true) const {672 ensure_count(required0, false, false, false);673 if (required0 && args.size() > 0) ensure_val<T0>(args[0]);674 }675 template<typename T0, typename T1> void ensure_vals(bool required0 = true, bool required1 = true) const {676 ensure_count(required0, required1, false, false);677 if (required0 && args.size() > 0) ensure_val<T0>(args[0]);678 if (required1 && args.size() > 1) ensure_val<T1>(args[1]);679 }680 template<typename T0, typename T1, typename T2> void ensure_vals(bool required0 = true, bool required1 = true, bool required2 = true) const {681 ensure_count(required0, required1, required2, false);682 if (required0 && args.size() > 0) ensure_val<T0>(args[0]);683 if (required1 && args.size() > 1) ensure_val<T1>(args[1]);684 if (required2 && args.size() > 2) ensure_val<T2>(args[2]);685 }686 template<typename T0, typename T1, typename T2, typename T3> void ensure_vals(bool required0 = true, bool required1 = true, bool required2 = true, bool required3 = true) const {687 ensure_count(required0, required1, required2, required3);688 if (required0 && args.size() > 0) ensure_val<T0>(args[0]);689 if (required1 && args.size() > 1) ensure_val<T1>(args[1]);690 if (required2 && args.size() > 2) ensure_val<T2>(args[2]);691 if (required3 && args.size() > 3) ensure_val<T3>(args[3]);692 }693private:694 std::vector<value> args;695};696 697struct value_func_t : public value_t {698 std::string name;699 value arg0; // bound "this" argument, if any700 value_func_t(const std::string & name, const func_handler & func) : name(name) {701 val_func = func;702 }703 value_func_t(const std::string & name, const func_handler & func, const value & arg_this) : name(name), arg0(arg_this) {704 val_func = func;705 }706 virtual value invoke(const func_args & args) const override {707 func_args new_args(args); // copy708 new_args.func_name = name;709 if (arg0) {710 new_args.push_front(arg0);711 }712 return val_func(new_args);713 }714 virtual std::string type() const override { return "Function"; }715 virtual std::string as_repr() const override { return type() + "<" + name + ">(" + (arg0 ? arg0->as_repr() : "") + ")"; }716 virtual bool is_hashable() const override { return false; }717 virtual hasher unique_hash() const noexcept override {718 // Note: this is unused for now, we don't support function as object keys719 // use function pointer as unique identifier720 const auto target = val_func.target<func_hptr>();721 return hasher(typeid(*this)).update(&target, sizeof(target));722 }723protected:724 virtual bool equivalent(const value_t & other) const override {725 // Note: this is unused for now, we don't support function as object keys726 // compare function pointers727 // (val_func == other.val_func does not work as std::function::operator== is only used for nullptr check)728 const auto target_this = this->val_func.target<func_hptr>();729 const auto target_other = other.val_func.target<func_hptr>();730 return typeid(*this) == typeid(other) && target_this == target_other;731 }732};733using value_func = std::shared_ptr<value_func_t>;734 735// special value for kwarg736struct value_kwarg_t : public value_t {737 std::string key;738 value val;739 value_kwarg_t(const std::string & k, const value & v) : key(k), val(v) {}740 virtual std::string type() const override { return "KwArg"; }741 virtual std::string as_repr() const override { return type(); }742 virtual bool is_hashable() const override { return true; }743 virtual hasher unique_hash() const noexcept override {744 const auto type_hash = typeid(*this).hash_code();745 auto hash = val->unique_hash();746 hash.update(&type_hash, sizeof(type_hash))747 .update(key.data(), key.size());748 return hash;749 }750protected:751 virtual bool equivalent(const value_t & other) const override {752 const value_kwarg_t & other_val = static_cast<const value_kwarg_t &>(other);753 return typeid(*this) == typeid(other) && key == other_val.key && val == other_val.val;754 }755};756using value_kwarg = std::shared_ptr<value_kwarg_t>;757 758 759} // namespace jinja760 