UNPKG

@babylonjs/core

Version:

Getting started? Play directly with the Babylon.js API using our [playground](https://playground.babylonjs.com/). It also contains a lot of samples to learn how to use it.

142 lines 5.93 kB
/* eslint-disable @typescript-eslint/naming-convention */ /** @internal */ export class ShaderDefineExpression { // eslint-disable-next-line @typescript-eslint/no-unused-vars isTrue(preprocessors) { return true; } static postfixToInfix(postfix) { const stack = []; for (const c of postfix) { if (ShaderDefineExpression._OperatorPriority[c] === undefined) { stack.push(c); } else { const v1 = stack[stack.length - 1], v2 = stack[stack.length - 2]; stack.length -= 2; stack.push(`(${v2}${c}${v1})`); } } return stack[stack.length - 1]; } /** * Converts an infix expression to a postfix expression. * * This method is used to transform infix expressions, which are more human-readable, * into postfix expressions, also known as Reverse Polish Notation (RPN), that can be * evaluated more efficiently by a computer. The conversion is based on the operator * priority defined in _OperatorPriority. * * The function employs a stack-based algorithm for the conversion and caches the result * to improve performance. The cache keeps track of each converted expression's access time * to manage the cache size and optimize memory usage. When the cache size exceeds a specified * limit, the least recently accessed items in the cache are deleted. * * The cache mechanism is particularly helpful for shader compilation, where the same infix * expressions might be encountered repeatedly, hence the caching can speed up the process. * * @param infix - The infix expression to be converted. * @returns The postfix expression as an array of strings. */ static infixToPostfix(infix) { // Is infix already in cache const cacheItem = ShaderDefineExpression._InfixToPostfixCache.get(infix); if (cacheItem) { cacheItem.accessTime = Date.now(); return cacheItem.result; } // Is infix contain any operator if (!infix.includes("&&") && !infix.includes("||") && !infix.includes(")") && !infix.includes("(")) { return [infix]; } const result = []; let stackIdx = -1; const pushOperand = () => { operand = operand.trim(); if (operand !== "") { result.push(operand); operand = ""; } }; const push = (s) => { if (stackIdx < ShaderDefineExpression._Stack.length - 1) { ShaderDefineExpression._Stack[++stackIdx] = s; } }; const peek = () => ShaderDefineExpression._Stack[stackIdx]; const pop = () => (stackIdx === -1 ? "!!INVALID EXPRESSION!!" : ShaderDefineExpression._Stack[stackIdx--]); let idx = 0, operand = ""; while (idx < infix.length) { const c = infix.charAt(idx), token = idx < infix.length - 1 ? infix.substring(idx, 2 + idx) : ""; if (c === "(") { operand = ""; push(c); } else if (c === ")") { pushOperand(); while (stackIdx !== -1 && peek() !== "(") { result.push(pop()); } pop(); } else if (ShaderDefineExpression._OperatorPriority[token] > 1) { pushOperand(); while (stackIdx !== -1 && ShaderDefineExpression._OperatorPriority[peek()] >= ShaderDefineExpression._OperatorPriority[token]) { result.push(pop()); } push(token); idx++; } else { operand += c; } idx++; } pushOperand(); while (stackIdx !== -1) { if (peek() === "(") { pop(); } else { result.push(pop()); } } // If the cache is at capacity, clear it before adding a new item if (ShaderDefineExpression._InfixToPostfixCache.size >= ShaderDefineExpression.InfixToPostfixCacheLimitSize) { ShaderDefineExpression.ClearCache(); } // Add the new item to the cache, including the current time as the last access time ShaderDefineExpression._InfixToPostfixCache.set(infix, { result, accessTime: Date.now() }); return result; } static ClearCache() { // Convert the cache to an array and sort by last access time const sortedCache = Array.from(ShaderDefineExpression._InfixToPostfixCache.entries()).sort((a, b) => a[1].accessTime - b[1].accessTime); // Remove the least recently accessed half of the cache for (let i = 0; i < ShaderDefineExpression.InfixToPostfixCacheCleanupSize; i++) { ShaderDefineExpression._InfixToPostfixCache.delete(sortedCache[i][0]); } } } /** * Cache items count limit for the InfixToPostfix cache. * It uses to improve the performance of the shader compilation. * For details see PR: https://github.com/BabylonJS/Babylon.js/pull/13936 */ ShaderDefineExpression.InfixToPostfixCacheLimitSize = 50000; /** * When the cache size is exceeded, a cache cleanup will be triggered * and the cache will be reduced by the size specified * in the InfixToPostfixCacheCleanupSize variable, removing entries * that have not been accessed the longest. */ ShaderDefineExpression.InfixToPostfixCacheCleanupSize = 25000; ShaderDefineExpression._InfixToPostfixCache = new Map(); ShaderDefineExpression._OperatorPriority = { ")": 0, "(": 1, "||": 2, "&&": 3, }; ShaderDefineExpression._Stack = ["", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""]; //# sourceMappingURL=shaderDefineExpression.js.map