char-fork/llama.cpp

git clone https://git.t4t.associates/char-fork/llama.cpp

Xuan-Son Nguyencommon: add json.h abstraction (#27511)d9f918d2d

char/aliceai-t5-moe
28.9 KiB759 linesraw
1#pragma once
2
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 value
25template<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 Helper
59
60
61struct context; // forward declaration
62
63
64// for converting from JSON to jinja values
65// 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 input
81//     },
82//     ...
83//   ],
84// }
85//
86// marking input can be useful for tracking data provenance
87// and preventing template injection attacks
88//
89// Note: T_JSON can be common_json
90template<typename T_JSON>
91void global_from_json(context & ctx, const T_JSON & json_obj, bool mark_input);
92
93//
94// base value type
95//
96
97struct func_args; // function argument values
98
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 = true
117    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 used
122        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 purposes
130    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 <=> operator
157    // 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 purposes
162    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// utils
176//
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 purposes
183std::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 types
212//
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 zeros
261        if (out.back() == '.') out.push_back('0'); // leave one zero if no decimals
262        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 hasher
449            // 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 builtins
486    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 appending
536            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 hasher
583            // 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 types
600//
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 from
622    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 type
640//
641
642struct func_args {
643public:
644    std::string func_name; // for error messages
645    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 any
700    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); // copy
708        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 keys
719        // use function pointer as unique identifier
720        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 keys
726        // compare function pointers
727        // (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 kwarg
736struct 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 jinja