// Copyright 2014 Cognitect. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS-IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. goog.provide("com.cognitect.transit.caching"); goog.require("com.cognitect.transit.delimiters"); goog.scope(function() { var caching = com.cognitect.transit.caching, d = com.cognitect.transit.delimiters; /** * @const * @type {number} */ caching.MIN_SIZE_CACHEABLE = 3; /** * @const * @type {number} */ caching.BASE_CHAR_IDX = 48; /** * @const * @type {number} */ caching.CACHE_CODE_DIGITS = 44; /** * @const * @type {number} */ caching.MAX_CACHE_ENTRIES = caching.CACHE_CODE_DIGITS*caching.CACHE_CODE_DIGITS; /** * @const * @type {number} */ caching.MAX_CACHE_SIZE = 4096; caching.isCacheable = function(string, asMapKey) { if(string.length > caching.MIN_SIZE_CACHEABLE) { if(asMapKey) { return true; } else { var c0 = string.charAt(0), c1 = string.charAt(1); if(c0 === d.ESC) { return c1 === ":" || c1 === "$" || c1 === "#"; } else { return false; } } } else { return false; } }; // ============================================================================= // WriteCache caching.idxToCode = function(idx) { var hi = Math.floor(idx / caching.CACHE_CODE_DIGITS), lo = idx % caching.CACHE_CODE_DIGITS, loc = String.fromCharCode(lo + caching.BASE_CHAR_IDX) if(hi === 0) { return d.SUB + loc; } else { return d.SUB + String.fromCharCode(hi + caching.BASE_CHAR_IDX) + loc; } }; /** * @constructor */ caching.WriteCache = function() { this.idx = 0; this.gen = 0; this.cacheSize = 0; this.cache = {}; }; caching.WriteCache.prototype.write = function(string, asMapKey) { if(caching.isCacheable(string, asMapKey)) { if(this.cacheSize === caching.MAX_CACHE_SIZE) { this.clear(); this.gen = 0; this.cache = {}; } else if(this.idx === caching.MAX_CACHE_ENTRIES) { this.clear(); } var entry = this.cache[string]; if(entry == null) { this.cache[string] = [caching.idxToCode(this.idx), this.gen]; this.idx++; return string; } else if(entry[1] != this.gen) { entry[1] = this.gen; entry[0] = caching.idxToCode(this.idx); this.idx++; return string; } else { return entry[0]; } } else { return string; } }; caching.WriteCache.prototype.clear = function Transit$WriteCache() { this.idx = 0; this.gen++; }; caching.writeCache = function() { return new caching.WriteCache(); }; // ============================================================================= // ReadCache caching.isCacheCode = function(string) { return (string.charAt(0) === d.SUB) && (string.charAt(1) !== " "); }; caching.codeToIdx = function(code) { if(code.length === 2) { return code.charCodeAt(1) - caching.BASE_CHAR_IDX; } else { var hi = (code.charCodeAt(1) - caching.BASE_CHAR_IDX) * caching.CACHE_CODE_DIGITS, lo = (code.charCodeAt(2) - caching.BASE_CHAR_IDX); return hi + lo; } }; /** * @constructor */ caching.ReadCache = function Transit$ReadCache() { this.idx = 0; this.cache = []; }; caching.ReadCache.prototype.write = function(obj, asMapKey) { if(this.idx == caching.MAX_CACHE_ENTRIES) { this.idx = 0; } this.cache[this.idx] = obj; this.idx++; return obj; }; caching.ReadCache.prototype.read = function(string, asMapKey) { return this.cache[caching.codeToIdx(string)]; }; caching.ReadCache.prototype.clear = function() { this.idx = 0; }; caching.readCache = function() { return new caching.ReadCache(); }; });