[Perf] Message: Optimize emoji counting algorithm (#5028)

This commit is contained in:
zubiden 2024-09-30 13:13:00 +02:00 committed by Alexander Zinchuk
parent 276a3dc355
commit 74689ba4fb

View File

@ -1,11 +1,10 @@
import twemojiRegex from '../../lib/twemojiRegex'; import EMOJI_REGEX from '../../lib/twemojiRegex';
import fixNonStandardEmoji from './fixNonStandardEmoji'; import fixNonStandardEmoji from './fixNonStandardEmoji';
const DETECT_UP_TO = 100; const DETECT_UP_TO = 100;
const MAX_LENGTH = DETECT_UP_TO * 8; // Maximum 8 per one emoji. const MAX_LENGTH = DETECT_UP_TO * 8; // Maximum 8 code points per one emoji.
const RE_EMOJI_ONLY = new RegExp(`^(?:${twemojiRegex.source})+$`, '');
const parseEmojiOnlyString = (text: string): number | false => { export default function parseEmojiOnlyString(text: string): number | false {
const standardizedText = fixNonStandardEmoji(text); const standardizedText = fixNonStandardEmoji(text);
const lines = standardizedText.split('\n'); const lines = standardizedText.split('\n');
const textWithoutNewlines = lines.join(''); const textWithoutNewlines = lines.join('');
@ -13,35 +12,43 @@ const parseEmojiOnlyString = (text: string): number | false => {
return false; return false;
} }
const isEmojiOnly = Boolean(textWithoutNewlines.match(RE_EMOJI_ONLY)); const totalCount = countIfEmojiOnly(textWithoutNewlines);
if (!isEmojiOnly) { if (!totalCount || totalCount > DETECT_UP_TO) {
return false; return false;
} }
const countPerLine = lines.map((line) => {
let emojiCount = 0;
while (twemojiRegex.exec(line)) {
emojiCount++;
if (emojiCount > DETECT_UP_TO) {
twemojiRegex.lastIndex = 0;
return -1;
}
}
return emojiCount;
});
// Calculate max emoji count per column or line. Used in UI to determine the size of the emoji.
let max = lines.length; let max = lines.length;
for (let i = 0; i < countPerLine.length; i++) { for (const line of lines) {
if (countPerLine[i] === -1) { const count = countIfEmojiOnly(line);
if (count === false) {
return false; return false;
} }
if (countPerLine[i] > max) { if (count > max) {
max = countPerLine[i]; max = count;
} }
} }
return max; return max;
}; }
export default parseEmojiOnlyString; function countIfEmojiOnly(line: string): false | number {
const iterator = line.matchAll(EMOJI_REGEX);
let count = 0;
let currentIndex = 0;
for (const match of iterator) {
if (match.index !== currentIndex) {
return false;
}
count++;
currentIndex = match.index + match[0].length;
}
if (currentIndex !== line.length) {
return false;
}
return count;
}