Felipe97/llama-cpp-compiled
01.1k
1#pragma once2 3#include <string>4#include <sstream>5#include <algorithm>6#include <cstdint>7#include <cstring>8 9namespace jinja {10 11static void string_replace_all(std::string & s, const std::string & search, const std::string & replace) {12 if (search.empty()) {13 return;14 }15 std::string builder;16 builder.reserve(s.length());17 size_t pos = 0;18 size_t last_pos = 0;19 while ((pos = s.find(search, last_pos)) != std::string::npos) {20 builder.append(s, last_pos, pos - last_pos);21 builder.append(replace);22 last_pos = pos + search.length();23 }24 builder.append(s, last_pos, std::string::npos);25 s = std::move(builder);26}27 28// for displaying source code around error position29static std::string peak_source(const std::string & source, size_t pos, size_t max_peak_chars = 40) {30 if (source.empty()) {31 return "(no source available)";32 }33 std::string output;34 size_t start = (pos >= max_peak_chars) ? (pos - max_peak_chars) : 0;35 size_t end = std::min(pos + max_peak_chars, source.length());36 std::string substr = source.substr(start, end - start);37 string_replace_all(substr, "\n", "↵");38 output += "..." + substr + "...\n";39 std::string spaces(pos - start + 3, ' ');40 output += spaces + "^";41 return output;42}43 44static std::string fmt_error_with_source(const std::string & tag, const std::string & msg, const std::string & source, size_t pos) {45 std::ostringstream oss;46 oss << tag << ": " << msg << "\n";47 oss << peak_source(source, pos);48 return oss.str();49}50 51// Note: this is a simple hasher, not cryptographically secure, just for hash table usage52struct hasher {53 static constexpr auto size_t_digits = sizeof(size_t) * 8;54 static constexpr size_t prime = size_t_digits == 64 ? 0x100000001b3 : 0x01000193;55 static constexpr size_t seed = size_t_digits == 64 ? 0xcbf29ce484222325 : 0x811c9dc5;56 static constexpr auto block_size = sizeof(size_t); // in bytes; allowing the compiler to vectorize the computation57 58 static_assert(size_t_digits == 64 || size_t_digits == 32);59 static_assert(block_size == 8 || block_size == 4);60 61 uint8_t buffer[block_size];62 size_t idx = 0; // current index in buffer63 size_t state = seed;64 65 hasher() = default;66 hasher(const std::type_info & type_inf) noexcept {67 const auto type_hash = type_inf.hash_code();68 update(&type_hash, sizeof(type_hash));69 }70 71 // Properties:72 // - update is not associative: update(a).update(b) != update(b).update(a)73 // - update(a ~ b) == update(a).update(b) with ~ as concatenation operator --> useful for streaming74 // - update("", 0) --> state unchanged with empty input75 hasher& update(void const * bytes, size_t len) noexcept {76 const uint8_t * c = static_cast<uint8_t const *>(bytes);77 if (len == 0) {78 return *this;79 }80 size_t processed = 0;81 82 // first, fill the existing buffer if it's partial83 if (idx > 0) {84 size_t to_fill = block_size - idx;85 if (to_fill > len) {86 to_fill = len;87 }88 std::memcpy(buffer + idx, c, to_fill);89 idx += to_fill;90 processed += to_fill;91 if (idx == block_size) {92 update_block(buffer);93 idx = 0;94 }95 }96 97 // process full blocks from the remaining input98 for (; processed + block_size <= len; processed += block_size) {99 update_block(c + processed);100 }101 102 // buffer any remaining bytes103 size_t remaining = len - processed;104 if (remaining > 0) {105 std::memcpy(buffer, c + processed, remaining);106 idx = remaining;107 }108 return *this;109 }110 111 // convenience function for testing only112 hasher& update(const std::string & s) noexcept {113 return update(s.data(), s.size());114 }115 116 // finalize and get the hash value117 // note: after calling digest, the hasher state is modified, do not call update() again118 size_t digest() noexcept {119 // if there are remaining bytes in buffer, fill the rest with zeros and process120 if (idx > 0) {121 for (size_t i = idx; i < block_size; ++i) {122 buffer[i] = 0;123 }124 update_block(buffer);125 idx = 0;126 }127 128 return state;129 }130 131private:132 // IMPORTANT: block must have at least block_size bytes133 void update_block(const uint8_t * block) noexcept {134 size_t blk = static_cast<uint32_t>(block[0])135 | (static_cast<uint32_t>(block[1]) << 8)136 | (static_cast<uint32_t>(block[2]) << 16)137 | (static_cast<uint32_t>(block[3]) << 24);138 if constexpr (block_size == 8) {139 blk = blk | (static_cast<uint64_t>(block[4]) << 32)140 | (static_cast<uint64_t>(block[5]) << 40)141 | (static_cast<uint64_t>(block[6]) << 48)142 | (static_cast<uint64_t>(block[7]) << 56);143 }144 state ^= blk;145 state *= prime;146 }147};148 149} // namespace jinja150 