Team Ai
Modelpublic

Felipe97/llama-cpp-compiled

sourceHugging Faceupdated 21d agoView on Hugging Face
0likes1.2kdownloads
value.h760 linesDownload Raw Back to jinja
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