char-fork/llama.cpp

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

0jinja : fix quadratic cost in gather_string_parts (#27034)9e40df63b

char/aliceai-t5-moe
5.3 KiB213 linesraw
1#include "jinja/string.h"
2#include "jinja/value.h"
3
4#include <algorithm>
5#include <functional>
6#include <optional>
7#include <sstream>
8#include <string>
9#include <vector>
10
11namespace jinja {
12
13//
14// string_part
15//
16
17bool string_part::is_uppercase() const {
18    for (char c : val) {
19        if (std::islower(static_cast<unsigned char>(c))) {
20            return false;
21        }
22    }
23    return true;
24}
25
26bool string_part::is_lowercase() const {
27    for (char c : val) {
28        if (std::isupper(static_cast<unsigned char>(c))) {
29            return false;
30        }
31    }
32    return true;
33}
34
35//
36// string
37//
38
39void string::mark_input() {
40    for (auto & part : parts) {
41        part.is_input = true;
42    }
43}
44
45std::string string::str() const {
46    if (parts.size() == 1) {
47        return parts[0].val;
48    }
49    std::ostringstream oss;
50    for (const auto & part : parts) {
51        oss << part.val;
52    }
53    return oss.str();
54}
55
56size_t string::length() const {
57    size_t len = 0;
58    for (const auto & part : parts) {
59        len += part.val.length();
60    }
61    return len;
62}
63
64void string::hash_update(hasher & hash) const noexcept {
65    for (const auto & part : parts) {
66        hash.update(part.val.data(), part.val.length());
67    }
68}
69
70bool string::all_parts_are_input() const {
71    for (const auto & part : parts) {
72        if (!part.is_input) {
73            return false;
74        }
75    }
76    return true;
77}
78
79bool string::is_uppercase() const {
80    for (const auto & part : parts) {
81        if (!part.is_uppercase()) {
82            return false;
83        }
84    }
85    return true;
86}
87
88bool string::is_lowercase() const {
89    for (const auto & part : parts) {
90        if (!part.is_lowercase()) {
91            return false;
92        }
93    }
94    return true;
95}
96
97// mark this string as input if other has ALL parts as input
98void string::mark_input_based_on(const string & other) {
99    if (other.all_parts_are_input()) {
100        for (auto & part : parts) {
101            part.is_input = true;
102        }
103    }
104}
105
106string & string::append(const string & other) {
107    for (const auto & part : other.parts) {
108        parts.push_back(part);
109    }
110    return *this;
111}
112
113// in-place transformation
114
115using transform_fn = std::function<std::string(const std::string&)>;
116static string apply_transform(string & self, const transform_fn & fn) {
117    for (auto & part : self.parts) {
118        part.val = fn(part.val);
119    }
120    return self;
121}
122
123string string::uppercase() {
124    return apply_transform(*this, [](const std::string & s) {
125        std::string res = s;
126        std::transform(res.begin(), res.end(), res.begin(), ::toupper);
127        return res;
128    });
129}
130string string::lowercase() {
131    return apply_transform(*this, [](const std::string & s) {
132        std::string res = s;
133        std::transform(res.begin(), res.end(), res.begin(), ::tolower);
134        return res;
135    });
136}
137string string::capitalize() {
138    return apply_transform(*this, [](const std::string & s) {
139        if (s.empty()) return s;
140        std::string res = s;
141        res[0] = ::toupper(static_cast<unsigned char>(res[0]));
142        std::transform(res.begin() + 1, res.end(), res.begin() + 1, ::tolower);
143        return res;
144    });
145}
146string string::titlecase() {
147    return apply_transform(*this, [](const std::string & s) {
148        std::string res = s;
149        bool capitalize_next = true;
150        for (char &c : res) {
151            if (isspace(static_cast<unsigned char>(c))) {
152                capitalize_next = true;
153            } else if (capitalize_next) {
154                c = ::toupper(static_cast<unsigned char>(c));
155                capitalize_next = false;
156            } else {
157                c = ::tolower(static_cast<unsigned char>(c));
158            }
159        }
160        return res;
161    });
162}
163string string::strip(bool left, bool right, std::optional<const std::string_view> chars) {
164    static auto strip_part = [](const std::string & s, bool left, bool right, std::optional<const std::string_view> chars) -> std::string {
165        size_t start = 0;
166        size_t end = s.length();
167        auto match_char = [&chars](unsigned char c) -> bool {
168            return chars ? (*chars).find(c) != std::string::npos : isspace(c);
169        };
170        if (left) {
171            while (start < end && match_char(static_cast<unsigned char>(s[start]))) {
172                ++start;
173            }
174        }
175        if (right) {
176            while (end > start && match_char(static_cast<unsigned char>(s[end - 1]))) {
177                --end;
178            }
179        }
180        return s.substr(start, end - start);
181    };
182    if (parts.empty()) {
183        return *this;
184    }
185    if (left) {
186        for (size_t i = 0; i < parts.size(); ++i) {
187            parts[i].val = strip_part(parts[i].val, true, false, chars);
188            if (parts[i].val.empty()) {
189                // remove empty part
190                parts.erase(parts.begin() + i);
191                --i;
192                continue;
193            } else {
194                break;
195            }
196        }
197    }
198    if (right) {
199        for (size_t i = parts.size(); i-- > 0;) {
200            parts[i].val = strip_part(parts[i].val, false, true, chars);
201            if (parts[i].val.empty()) {
202                // remove empty part
203                parts.erase(parts.begin() + i);
204                continue;
205            } else {
206                break;
207            }
208        }
209    }
210    return *this;
211}
212
213} // namespace jinja