File indexing completed on 2024-05-05 05:53:43
0001 /* 0002 SPDX-FileCopyrightText: 2007-2008 Robert Knight <robertknight@gmail.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 // Own 0008 #include "ExtendedCharTable.h" 0009 0010 #include "charactersdebug.h" 0011 0012 using namespace Konsole; 0013 0014 ExtendedCharTable::ExtendedCharTable() = default; 0015 0016 ExtendedCharTable::~ExtendedCharTable() 0017 { 0018 // free all allocated character buffers 0019 QHashIterator<uint, char32_t *> iter(_extendedCharTable); 0020 while (iter.hasNext()) { 0021 iter.next(); 0022 delete[] iter.value(); 0023 } 0024 } 0025 0026 // global instance 0027 ExtendedCharTable ExtendedCharTable::instance; 0028 0029 char32_t ExtendedCharTable::createExtendedChar(const char32_t *unicodePoints, ushort length, const pExtendedChars extendedChars) 0030 { 0031 // look for this sequence of points in the table 0032 uint hash = extendedCharHash(unicodePoints, length); 0033 const uint initialHash = hash; 0034 bool triedCleaningSolution = false; 0035 0036 // check existing entry for match 0037 while (_extendedCharTable.contains(hash) && hash != 0) { // 0 has a special meaning for chars so we don't use it 0038 if (extendedCharMatch(hash, unicodePoints, length)) { 0039 // this sequence already has an entry in the table, 0040 // return its hash 0041 return hash; 0042 } 0043 // if hash is already used by another, different sequence of unicode character 0044 // points then try next hash 0045 hash++; 0046 0047 if (hash == initialHash) { 0048 if (!triedCleaningSolution) { 0049 triedCleaningSolution = true; 0050 // All the hashes are full, go to all Screens and try to free any 0051 // This is slow but should happen very rarely 0052 QSet<uint> usedExtendedChars = extendedChars(); 0053 0054 QHash<uint, char32_t *>::iterator it = _extendedCharTable.begin(); 0055 QHash<uint, char32_t *>::iterator itEnd = _extendedCharTable.end(); 0056 while (it != itEnd) { 0057 if (usedExtendedChars.contains(it.key())) { 0058 ++it; 0059 } else { 0060 it = _extendedCharTable.erase(it); 0061 } 0062 } 0063 } else { 0064 qCDebug(CharactersDebug) << "Using all the extended char hashes, going to miss this extended character"; 0065 return 0; 0066 } 0067 } 0068 } 0069 0070 // add the new sequence to the table and 0071 // return that index 0072 auto buffer = new char32_t[length + 1]; 0073 buffer[0] = length; 0074 std::copy_n(unicodePoints, length, &buffer[1]); 0075 0076 _extendedCharTable.insert(hash, buffer); 0077 0078 return hash; 0079 } 0080 0081 char32_t *ExtendedCharTable::lookupExtendedChar(uint hash, ushort &length) const 0082 { 0083 // look up index in table and if found, set the length 0084 // argument and return a pointer to the character sequence 0085 0086 char32_t *buffer = _extendedCharTable[hash]; 0087 if (buffer != nullptr) { 0088 length = ushort(buffer[0]); 0089 return buffer + 1; 0090 } 0091 length = 0; 0092 return nullptr; 0093 } 0094 0095 uint ExtendedCharTable::extendedCharHash(const char32_t *unicodePoints, ushort length) const 0096 { 0097 uint hash = 0; 0098 for (ushort i = 0; i < length; i++) { 0099 hash = 31 * hash + unicodePoints[i]; 0100 } 0101 return hash; 0102 } 0103 0104 bool ExtendedCharTable::extendedCharMatch(uint hash, const char32_t *unicodePoints, ushort length) const 0105 { 0106 char32_t *entry = _extendedCharTable[hash]; 0107 0108 // compare given length with stored sequence length ( given as the first ushort in the 0109 // stored buffer ) 0110 if (entry == nullptr || entry[0] != length) { 0111 return false; 0112 } 0113 // if the lengths match, each character must be checked. the stored buffer starts at 0114 // entry[1] 0115 for (int i = 0; i < length; i++) { 0116 if (entry[i + 1] != unicodePoints[i]) { 0117 return false; 0118 } 0119 } 0120 return true; 0121 }