From 07f1cd5ff8e1f27416fee248738678df24dd823a Mon Sep 17 00:00:00 2001 From: Marcel Admiraal Date: Sat, 16 Jan 2021 15:28:54 +0000 Subject: Rename PHashTranslation to OptimizedTranslation --- core/string/compressed_translation.cpp | 288 --------------------------------- core/string/compressed_translation.h | 89 ---------- core/string/optimized_translation.cpp | 288 +++++++++++++++++++++++++++++++++ core/string/optimized_translation.h | 89 ++++++++++ core/string/translation_po.cpp | 2 +- 5 files changed, 378 insertions(+), 378 deletions(-) delete mode 100644 core/string/compressed_translation.cpp delete mode 100644 core/string/compressed_translation.h create mode 100644 core/string/optimized_translation.cpp create mode 100644 core/string/optimized_translation.h (limited to 'core/string') diff --git a/core/string/compressed_translation.cpp b/core/string/compressed_translation.cpp deleted file mode 100644 index 15abf63f7e..0000000000 --- a/core/string/compressed_translation.cpp +++ /dev/null @@ -1,288 +0,0 @@ -/*************************************************************************/ -/* compressed_translation.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "compressed_translation.h" - -#include "core/templates/pair.h" - -extern "C" { -#include "thirdparty/misc/smaz.h" -} - -struct _PHashTranslationCmp { - int orig_len; - CharString compressed; - int offset; -}; - -void PHashTranslation::generate(const Ref &p_from) { - // This method compresses a Translation instance. - // Right now, it doesn't handle context or plurals, so Translation subclasses using plurals or context (i.e TranslationPO) shouldn't be compressed. -#ifdef TOOLS_ENABLED - List keys; - p_from->get_message_list(&keys); - - int size = Math::larger_prime(keys.size()); - - Vector>> buckets; - Vector> table; - Vector hfunc_table; - Vector<_PHashTranslationCmp> compressed; - - table.resize(size); - hfunc_table.resize(size); - buckets.resize(size); - compressed.resize(keys.size()); - - int idx = 0; - int total_compression_size = 0; - int total_string_size = 0; - - for (List::Element *E = keys.front(); E; E = E->next()) { - //hash string - CharString cs = E->get().operator String().utf8(); - uint32_t h = hash(0, cs.get_data()); - Pair p; - p.first = idx; - p.second = cs; - buckets.write[h % size].push_back(p); - - //compress string - CharString src_s = p_from->get_message(E->get()).operator String().utf8(); - _PHashTranslationCmp ps; - ps.orig_len = src_s.size(); - ps.offset = total_compression_size; - - if (ps.orig_len != 0) { - CharString dst_s; - dst_s.resize(src_s.size()); - int ret = smaz_compress(src_s.get_data(), src_s.size(), dst_s.ptrw(), src_s.size()); - if (ret >= src_s.size()) { - //if compressed is larger than original, just use original - ps.orig_len = src_s.size(); - ps.compressed = src_s; - } else { - dst_s.resize(ret); - //ps.orig_len=; - ps.compressed = dst_s; - } - } else { - ps.orig_len = 1; - ps.compressed.resize(1); - ps.compressed[0] = 0; - } - - compressed.write[idx] = ps; - total_compression_size += ps.compressed.size(); - total_string_size += src_s.size(); - idx++; - } - - int bucket_table_size = 0; - - for (int i = 0; i < size; i++) { - const Vector> &b = buckets[i]; - Map &t = table.write[i]; - - if (b.size() == 0) { - continue; - } - - int d = 1; - int item = 0; - - while (item < b.size()) { - uint32_t slot = hash(d, b[item].second.get_data()); - if (t.has(slot)) { - item = 0; - d++; - t.clear(); - } else { - t[slot] = b[item].first; - item++; - } - } - - hfunc_table.write[i] = d; - bucket_table_size += 2 + b.size() * 4; - } - - ERR_FAIL_COND(bucket_table_size == 0); - - hash_table.resize(size); - bucket_table.resize(bucket_table_size); - - int *htwb = hash_table.ptrw(); - int *btwb = bucket_table.ptrw(); - - uint32_t *htw = (uint32_t *)&htwb[0]; - uint32_t *btw = (uint32_t *)&btwb[0]; - - int btindex = 0; - int collisions = 0; - - for (int i = 0; i < size; i++) { - const Map &t = table[i]; - if (t.size() == 0) { - htw[i] = 0xFFFFFFFF; //nothing - continue; - } else if (t.size() > 1) { - collisions += t.size() - 1; - } - - htw[i] = btindex; - btw[btindex++] = t.size(); - btw[btindex++] = hfunc_table[i]; - - for (Map::Element *E = t.front(); E; E = E->next()) { - btw[btindex++] = E->key(); - btw[btindex++] = compressed[E->get()].offset; - btw[btindex++] = compressed[E->get()].compressed.size(); - btw[btindex++] = compressed[E->get()].orig_len; - } - } - - strings.resize(total_compression_size); - uint8_t *cw = strings.ptrw(); - - for (int i = 0; i < compressed.size(); i++) { - memcpy(&cw[compressed[i].offset], compressed[i].compressed.get_data(), compressed[i].compressed.size()); - } - - ERR_FAIL_COND(btindex != bucket_table_size); - set_locale(p_from->get_locale()); - -#endif -} - -bool PHashTranslation::_set(const StringName &p_name, const Variant &p_value) { - String name = p_name.operator String(); - if (name == "hash_table") { - hash_table = p_value; - } else if (name == "bucket_table") { - bucket_table = p_value; - } else if (name == "strings") { - strings = p_value; - } else if (name == "load_from") { - generate(p_value); - } else { - return false; - } - - return true; -} - -bool PHashTranslation::_get(const StringName &p_name, Variant &r_ret) const { - String name = p_name.operator String(); - if (name == "hash_table") { - r_ret = hash_table; - } else if (name == "bucket_table") { - r_ret = bucket_table; - } else if (name == "strings") { - r_ret = strings; - } else { - return false; - } - - return true; -} - -StringName PHashTranslation::get_message(const StringName &p_src_text, const StringName &p_context) const { - // p_context passed in is ignore. The use of context is not yet supported in PHashTranslation. - - int htsize = hash_table.size(); - - if (htsize == 0) { - return StringName(); - } - - CharString str = p_src_text.operator String().utf8(); - uint32_t h = hash(0, str.get_data()); - - const int *htr = hash_table.ptr(); - const uint32_t *htptr = (const uint32_t *)&htr[0]; - const int *btr = bucket_table.ptr(); - const uint32_t *btptr = (const uint32_t *)&btr[0]; - const uint8_t *sr = strings.ptr(); - const char *sptr = (const char *)&sr[0]; - - uint32_t p = htptr[h % htsize]; - - if (p == 0xFFFFFFFF) { - return StringName(); //nothing - } - - const Bucket &bucket = *(const Bucket *)&btptr[p]; - - h = hash(bucket.func, str.get_data()); - - int idx = -1; - - for (int i = 0; i < bucket.size; i++) { - if (bucket.elem[i].key == h) { - idx = i; - break; - } - } - - if (idx == -1) { - return StringName(); - } - - if (bucket.elem[idx].comp_size == bucket.elem[idx].uncomp_size) { - String rstr; - rstr.parse_utf8(&sptr[bucket.elem[idx].str_offset], bucket.elem[idx].uncomp_size); - - return rstr; - } else { - CharString uncomp; - uncomp.resize(bucket.elem[idx].uncomp_size + 1); - smaz_decompress(&sptr[bucket.elem[idx].str_offset], bucket.elem[idx].comp_size, uncomp.ptrw(), bucket.elem[idx].uncomp_size); - String rstr; - rstr.parse_utf8(uncomp.get_data()); - return rstr; - } -} - -StringName PHashTranslation::get_plural_message(const StringName &p_src_text, const StringName &p_plural_text, int p_n, const StringName &p_context) const { - // The use of plurals translation is not yet supported in PHashTranslation. - return get_message(p_src_text, p_context); -} - -void PHashTranslation::_get_property_list(List *p_list) const { - p_list->push_back(PropertyInfo(Variant::PACKED_INT32_ARRAY, "hash_table")); - p_list->push_back(PropertyInfo(Variant::PACKED_INT32_ARRAY, "bucket_table")); - p_list->push_back(PropertyInfo(Variant::PACKED_BYTE_ARRAY, "strings")); - p_list->push_back(PropertyInfo(Variant::OBJECT, "load_from", PROPERTY_HINT_RESOURCE_TYPE, "Translation", PROPERTY_USAGE_EDITOR)); -} - -void PHashTranslation::_bind_methods() { - ClassDB::bind_method(D_METHOD("generate", "from"), &PHashTranslation::generate); -} diff --git a/core/string/compressed_translation.h b/core/string/compressed_translation.h deleted file mode 100644 index 0abb770178..0000000000 --- a/core/string/compressed_translation.h +++ /dev/null @@ -1,89 +0,0 @@ -/*************************************************************************/ -/* compressed_translation.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef COMPRESSED_TRANSLATION_H -#define COMPRESSED_TRANSLATION_H - -#include "core/string/translation.h" - -class PHashTranslation : public Translation { - GDCLASS(PHashTranslation, Translation); - - //this translation uses a sort of modified perfect hash algorithm - //it requires hashing strings twice and then does a binary search, - //so it's slower, but at the same time it has an extreemly high chance - //of catching untranslated strings - - //load/store friendly types - Vector hash_table; - Vector bucket_table; - Vector strings; - - struct Bucket { - int size; - uint32_t func; - - struct Elem { - uint32_t key; - uint32_t str_offset; - uint32_t comp_size; - uint32_t uncomp_size; - }; - - Elem elem[1]; - }; - - _FORCE_INLINE_ uint32_t hash(uint32_t d, const char *p_str) const { - if (d == 0) { - d = 0x1000193; - } - while (*p_str) { - d = (d * 0x1000193) ^ uint32_t(*p_str); - p_str++; - } - - return d; - } - -protected: - bool _set(const StringName &p_name, const Variant &p_value); - bool _get(const StringName &p_name, Variant &r_ret) const; - void _get_property_list(List *p_list) const; - static void _bind_methods(); - -public: - virtual StringName get_message(const StringName &p_src_text, const StringName &p_context = "") const override; //overridable for other implementations - virtual StringName get_plural_message(const StringName &p_src_text, const StringName &p_plural_text, int p_n, const StringName &p_context = "") const override; - void generate(const Ref &p_from); - - PHashTranslation() {} -}; - -#endif // COMPRESSED_TRANSLATION_H diff --git a/core/string/optimized_translation.cpp b/core/string/optimized_translation.cpp new file mode 100644 index 0000000000..53d0a8924d --- /dev/null +++ b/core/string/optimized_translation.cpp @@ -0,0 +1,288 @@ +/*************************************************************************/ +/* optimized_translation.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "optimized_translation.h" + +#include "core/templates/pair.h" + +extern "C" { +#include "thirdparty/misc/smaz.h" +} + +struct CompressedString { + int orig_len; + CharString compressed; + int offset; +}; + +void OptimizedTranslation::generate(const Ref &p_from) { + // This method compresses a Translation instance. + // Right now, it doesn't handle context or plurals, so Translation subclasses using plurals or context (i.e TranslationPO) shouldn't be compressed. +#ifdef TOOLS_ENABLED + List keys; + p_from->get_message_list(&keys); + + int size = Math::larger_prime(keys.size()); + + Vector>> buckets; + Vector> table; + Vector hfunc_table; + Vector compressed; + + table.resize(size); + hfunc_table.resize(size); + buckets.resize(size); + compressed.resize(keys.size()); + + int idx = 0; + int total_compression_size = 0; + int total_string_size = 0; + + for (List::Element *E = keys.front(); E; E = E->next()) { + //hash string + CharString cs = E->get().operator String().utf8(); + uint32_t h = hash(0, cs.get_data()); + Pair p; + p.first = idx; + p.second = cs; + buckets.write[h % size].push_back(p); + + //compress string + CharString src_s = p_from->get_message(E->get()).operator String().utf8(); + CompressedString ps; + ps.orig_len = src_s.size(); + ps.offset = total_compression_size; + + if (ps.orig_len != 0) { + CharString dst_s; + dst_s.resize(src_s.size()); + int ret = smaz_compress(src_s.get_data(), src_s.size(), dst_s.ptrw(), src_s.size()); + if (ret >= src_s.size()) { + //if compressed is larger than original, just use original + ps.orig_len = src_s.size(); + ps.compressed = src_s; + } else { + dst_s.resize(ret); + //ps.orig_len=; + ps.compressed = dst_s; + } + } else { + ps.orig_len = 1; + ps.compressed.resize(1); + ps.compressed[0] = 0; + } + + compressed.write[idx] = ps; + total_compression_size += ps.compressed.size(); + total_string_size += src_s.size(); + idx++; + } + + int bucket_table_size = 0; + + for (int i = 0; i < size; i++) { + const Vector> &b = buckets[i]; + Map &t = table.write[i]; + + if (b.size() == 0) { + continue; + } + + int d = 1; + int item = 0; + + while (item < b.size()) { + uint32_t slot = hash(d, b[item].second.get_data()); + if (t.has(slot)) { + item = 0; + d++; + t.clear(); + } else { + t[slot] = b[item].first; + item++; + } + } + + hfunc_table.write[i] = d; + bucket_table_size += 2 + b.size() * 4; + } + + ERR_FAIL_COND(bucket_table_size == 0); + + hash_table.resize(size); + bucket_table.resize(bucket_table_size); + + int *htwb = hash_table.ptrw(); + int *btwb = bucket_table.ptrw(); + + uint32_t *htw = (uint32_t *)&htwb[0]; + uint32_t *btw = (uint32_t *)&btwb[0]; + + int btindex = 0; + int collisions = 0; + + for (int i = 0; i < size; i++) { + const Map &t = table[i]; + if (t.size() == 0) { + htw[i] = 0xFFFFFFFF; //nothing + continue; + } else if (t.size() > 1) { + collisions += t.size() - 1; + } + + htw[i] = btindex; + btw[btindex++] = t.size(); + btw[btindex++] = hfunc_table[i]; + + for (Map::Element *E = t.front(); E; E = E->next()) { + btw[btindex++] = E->key(); + btw[btindex++] = compressed[E->get()].offset; + btw[btindex++] = compressed[E->get()].compressed.size(); + btw[btindex++] = compressed[E->get()].orig_len; + } + } + + strings.resize(total_compression_size); + uint8_t *cw = strings.ptrw(); + + for (int i = 0; i < compressed.size(); i++) { + memcpy(&cw[compressed[i].offset], compressed[i].compressed.get_data(), compressed[i].compressed.size()); + } + + ERR_FAIL_COND(btindex != bucket_table_size); + set_locale(p_from->get_locale()); + +#endif +} + +bool OptimizedTranslation::_set(const StringName &p_name, const Variant &p_value) { + String name = p_name.operator String(); + if (name == "hash_table") { + hash_table = p_value; + } else if (name == "bucket_table") { + bucket_table = p_value; + } else if (name == "strings") { + strings = p_value; + } else if (name == "load_from") { + generate(p_value); + } else { + return false; + } + + return true; +} + +bool OptimizedTranslation::_get(const StringName &p_name, Variant &r_ret) const { + String name = p_name.operator String(); + if (name == "hash_table") { + r_ret = hash_table; + } else if (name == "bucket_table") { + r_ret = bucket_table; + } else if (name == "strings") { + r_ret = strings; + } else { + return false; + } + + return true; +} + +StringName OptimizedTranslation::get_message(const StringName &p_src_text, const StringName &p_context) const { + // p_context passed in is ignore. The use of context is not yet supported in OptimizedTranslation. + + int htsize = hash_table.size(); + + if (htsize == 0) { + return StringName(); + } + + CharString str = p_src_text.operator String().utf8(); + uint32_t h = hash(0, str.get_data()); + + const int *htr = hash_table.ptr(); + const uint32_t *htptr = (const uint32_t *)&htr[0]; + const int *btr = bucket_table.ptr(); + const uint32_t *btptr = (const uint32_t *)&btr[0]; + const uint8_t *sr = strings.ptr(); + const char *sptr = (const char *)&sr[0]; + + uint32_t p = htptr[h % htsize]; + + if (p == 0xFFFFFFFF) { + return StringName(); //nothing + } + + const Bucket &bucket = *(const Bucket *)&btptr[p]; + + h = hash(bucket.func, str.get_data()); + + int idx = -1; + + for (int i = 0; i < bucket.size; i++) { + if (bucket.elem[i].key == h) { + idx = i; + break; + } + } + + if (idx == -1) { + return StringName(); + } + + if (bucket.elem[idx].comp_size == bucket.elem[idx].uncomp_size) { + String rstr; + rstr.parse_utf8(&sptr[bucket.elem[idx].str_offset], bucket.elem[idx].uncomp_size); + + return rstr; + } else { + CharString uncomp; + uncomp.resize(bucket.elem[idx].uncomp_size + 1); + smaz_decompress(&sptr[bucket.elem[idx].str_offset], bucket.elem[idx].comp_size, uncomp.ptrw(), bucket.elem[idx].uncomp_size); + String rstr; + rstr.parse_utf8(uncomp.get_data()); + return rstr; + } +} + +StringName OptimizedTranslation::get_plural_message(const StringName &p_src_text, const StringName &p_plural_text, int p_n, const StringName &p_context) const { + // The use of plurals translation is not yet supported in OptimizedTranslation. + return get_message(p_src_text, p_context); +} + +void OptimizedTranslation::_get_property_list(List *p_list) const { + p_list->push_back(PropertyInfo(Variant::PACKED_INT32_ARRAY, "hash_table")); + p_list->push_back(PropertyInfo(Variant::PACKED_INT32_ARRAY, "bucket_table")); + p_list->push_back(PropertyInfo(Variant::PACKED_BYTE_ARRAY, "strings")); + p_list->push_back(PropertyInfo(Variant::OBJECT, "load_from", PROPERTY_HINT_RESOURCE_TYPE, "Translation", PROPERTY_USAGE_EDITOR)); +} + +void OptimizedTranslation::_bind_methods() { + ClassDB::bind_method(D_METHOD("generate", "from"), &OptimizedTranslation::generate); +} diff --git a/core/string/optimized_translation.h b/core/string/optimized_translation.h new file mode 100644 index 0000000000..bccf932383 --- /dev/null +++ b/core/string/optimized_translation.h @@ -0,0 +1,89 @@ +/*************************************************************************/ +/* optimized_translation.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef OPTIMIZED_TRANSLATION_H +#define OPTIMIZED_TRANSLATION_H + +#include "core/string/translation.h" + +class OptimizedTranslation : public Translation { + GDCLASS(OptimizedTranslation, Translation); + + //this translation uses a sort of modified perfect hash algorithm + //it requires hashing strings twice and then does a binary search, + //so it's slower, but at the same time it has an extreemly high chance + //of catching untranslated strings + + //load/store friendly types + Vector hash_table; + Vector bucket_table; + Vector strings; + + struct Bucket { + int size; + uint32_t func; + + struct Elem { + uint32_t key; + uint32_t str_offset; + uint32_t comp_size; + uint32_t uncomp_size; + }; + + Elem elem[1]; + }; + + _FORCE_INLINE_ uint32_t hash(uint32_t d, const char *p_str) const { + if (d == 0) { + d = 0x1000193; + } + while (*p_str) { + d = (d * 0x1000193) ^ uint32_t(*p_str); + p_str++; + } + + return d; + } + +protected: + bool _set(const StringName &p_name, const Variant &p_value); + bool _get(const StringName &p_name, Variant &r_ret) const; + void _get_property_list(List *p_list) const; + static void _bind_methods(); + +public: + virtual StringName get_message(const StringName &p_src_text, const StringName &p_context = "") const override; //overridable for other implementations + virtual StringName get_plural_message(const StringName &p_src_text, const StringName &p_plural_text, int p_n, const StringName &p_context = "") const override; + void generate(const Ref &p_from); + + OptimizedTranslation() {} +}; + +#endif // OPTIMIZED_TRANSLATION_H diff --git a/core/string/translation_po.cpp b/core/string/translation_po.cpp index 42ba30fbe5..2efadaa9b7 100644 --- a/core/string/translation_po.cpp +++ b/core/string/translation_po.cpp @@ -275,7 +275,7 @@ void TranslationPO::erase_message(const StringName &p_src_text, const StringName } void TranslationPO::get_message_list(List *r_messages) const { - // PHashTranslation uses this function to get the list of msgid. + // OptimizedTranslation uses this function to get the list of msgid. // Return all the keys of translation_map under "" context. List context_l; -- cgit v1.2.3