diff --git a/JavaScript/8-timeout.js b/JavaScript/8-timeout.js new file mode 100644 index 0000000..aa89832 --- /dev/null +++ b/JavaScript/8-timeout.js @@ -0,0 +1,77 @@ +'use strict'; + +const memoize = (fn, msec = 100) => { + const cache = {}; + let timer = null; + const hasKey = (key) => Object.keys(cache).includes(key); + const generateKey = (args) => { + let key = ''; + for (const arg of args) + key += `${arg}~${typeof arg}|`; + return key; + }; + + const throwGarbage = () => { + const cleaningTime = new Date(); + const removingTime = cleaningTime - msec; + + const toDelete = Object.keys(cache) + .filter(key => cache[key].lastUse >= removingTime); + + for (const key in cache) { + if (toDelete.includes(key)) { + console.log(`${key} deleted.`); + delete cache[key]; + } + if (Object.keys(cache).length === 0) { + console.log('Cache is empty'); + clearInterval(timer); + timer = null; + } + } + }; + + const setTimer = (msec) => { + const timer = setInterval(() => throwGarbage(), msec); + return timer; + }; + + timer = setTimer(msec); + + const func = (...args) => { + if (!timer) timer = setTimer(msec); + const key = generateKey(args); + + if (hasKey(key)) { + console.log(`From cache: ${args} = ${cache[key].value}`); + cache[key].lastUse = new Date(); + console.log(cache); + return cache[key].value; + } + + console.log(`Calculate: ${args} = ${fn(...args)}`); + const res = fn(...args); + if (res !== undefined) + cache[key] = { value: res, lastUse: new Date() }; + console.log(cache); + return res; + }; + + return func; +}; + +const sum = (a, b) => a + b; + +const sumM = memoize(sum, 250); + +//USAGE +sumM(1, -1); +sumM(2, -1); +setTimeout(() => { + sumM(1, -1); + setTimeout(() => sumM(2, -1), 100); + setTimeout(() => { + sumM(2, 3); + setTimeout(() => sumM(3, 4), 1000); + }, 500); +}, 200); diff --git a/JavaScript/9-least.js b/JavaScript/9-least.js new file mode 100644 index 0000000..c9460aa --- /dev/null +++ b/JavaScript/9-least.js @@ -0,0 +1,48 @@ +'use strict'; + +const memoizeLimited = (fn, size) => { + const cache = {}; + + const generateKey = (...args) => args.join('|'); + + const leastUsed = () => { + let toDelete = Object.keys(cache)[0]; + for (const i in cache) { + if (cache[i].uses < cache[toDelete].uses) { + toDelete = i; + } + } + console.log('Deleting', toDelete); + return toDelete; + }; + + return (...args) => { + const key = generateKey(...args); + + if (cache[key]) { + console.log(`From cache: ${args}`); + cache[key].uses++; + return cache[key].value; + } + + if (Object.keys(cache).length === size) + delete cache[leastUsed()]; + + const res = { value: fn(...args), uses: 0 }; + console.log(`Calculating ${args}`); + cache[key] = res; + return cache[key].value; + }; +}; + +//USAGE + +const sum = (a, b) => a + b; +const sumM = memoizeLimited(sum, 3); + +console.log(`sumM(1, 2) = ${sumM(1, 2)}`); //uses: 0 +console.log(`sumM(2, 3) = ${sumM(2, 3)}`); //uses: 0 +console.log(`sumM(1, 2) = ${sumM(1, 2)}`); //uses: 1 +console.log(`sumM(2, 3) = ${sumM(2, 3)}`); //uses: 2 +console.log(`sumM(1, 3) = ${sumM(1, 3)}`); //uses: 0 +console.log(`sumM(5, 6) = ${sumM(5, 6)}`); //uses: 0 diff --git a/JavaScript/a-bytes.js b/JavaScript/a-bytes.js new file mode 100644 index 0000000..8b25c0e --- /dev/null +++ b/JavaScript/a-bytes.js @@ -0,0 +1,76 @@ +'use strict'; + +const memoizeBytes = (fn, size = '1K', logging = true) => { + let cache = new Map(); + + const generateKey = (...args) => args.join('|'); + + const sizeToBytes = (size) => { + const length = size.length; + const data = parseFloat(size, 10); + let k = 1; + switch (size.charAt(length - 1)) { + case 'T': k *= 1000; + case 'G': k *= 1000; + case 'M': k *= 1000; + case 'K': k *= 1000; + case 'B': break; + default: break; + } + return data * k; + }; + + const sizeInBytes = sizeToBytes(size); + + const getSize = (obj) => { + let bytes = 0; + const dictTypes = { + number: () => 8, + boolean: () => 4, + string: (str) => str.length * 2, + object: (ob) => getSize(ob), + }; + obj.forEach((value) => { + const getBytes = dictTypes[typeof value]; + bytes += getBytes(value); + }); + return bytes; + }; + + return (...args) => { + const key = generateKey(...args); + const record = cache.get(key); + + if (record) { + if (logging) console.log(`From cache: ${key}`); + return cache[key]; + } + + const sizeOfCache = getSize(cache); + if (sizeOfCache >= sizeInBytes) { + console.log(`Cache with size ${sizeOfCache} bytes cleaned`); + cache = new Map(); + } + + if (logging) console.log(`Calculating: ${key}`); + const res = fn(...args); + cache.set(key, res); + if (logging) console.dir(`Cache size: ${sizeOfCache}`); + return res; + }; +}; + +//USAGE + +const sum = (a, b) => a + b; +const sum1 = memoizeBytes(sum, '32B'); +console.log(`sum1(1, 2) = ${sum1(1, 2)}`); +console.log(`sum1(1, 2) = ${sum1(1, 2)}`); +console.log(`sum1(2, 3) = ${sum1(2, 3)}`); +console.log(`sum1(3, 2) = ${sum1(3, 2)}`); +console.log(`sum1(4, 2) = ${sum1(4, 2)}`); +console.log(`sum1(2, 3) = ${sum1(2, 3)}`); +console.log(`sum1(1, 3) = ${sum1(1, 3)}`); + +const sum2 = memoizeBytes(sum, '0.5K', false); +for (let i = 0; i < 100; i++, sum2(i, i - 1)); diff --git a/JavaScript/b-universal.js b/JavaScript/b-universal.js new file mode 100644 index 0000000..90e2826 --- /dev/null +++ b/JavaScript/b-universal.js @@ -0,0 +1,54 @@ +'use strict'; + +const memeizeUniversal = fn => { + const cache = {}; + const generateKey = (...args) => args.join('|'); + + return (...args) => { + let callback; + if (typeof args[args.length - 1] === 'function') + callback = args.pop(); + const key = generateKey(...args); + + if (cache[key]) { + if (callback) { + console.log(`Async cache: ${key}`); + callback(cache[key].err, cache[key].data); + return; + } + console.log(`Sync cache: ${key}`); + return cache[key]; + } + + if (callback) { + console.log(`Async calc: ${key}`); + fn(...args, (err, data) => { + cache[key] = { err, data }; + callback(err, data); + }); + return; + } + console.log(`Sync calc: ${key}`); + cache[key] = fn(...args); + return cache[key]; + }; +}; + +//USAGE + +const fs = require('fs'); + +const asyncRead = memeizeUniversal(fs.readFile); + +asyncRead('b-universal.js', 'utf8', (err, data) => { + console.log('data length:', data.length); + asyncRead('b-universal.js', 'utf8', (err, data) => { + console.log('data length:', data.length); + }); +}); + +const сум = (a, b) => a + ' => ' + b; +const журба = memeizeUniversal(сум); +console.log(журба('Грушевський', 'Житомир')); +console.log(журба('Скоропадський', 'Мотовилівка')); +console.log(журба('Грушевський', 'Житомир')); diff --git a/JavaScript/c-object.js b/JavaScript/c-object.js new file mode 100644 index 0000000..dd8793f --- /dev/null +++ b/JavaScript/c-object.js @@ -0,0 +1,134 @@ +'use strict'; + +const generateKey = (...args) => args.join('|'); +const getSize = (obj) => { + let bytes = 0; + for (const i in obj) { + switch (typeof obj[i]) { + case 'number': + bytes += 8; + break; + case 'boolean': + bytes += 4; + break; + case 'string': + bytes += obj[i].length * 2; + break; + case 'object': + bytes += getSize(obj[i]); + break; + default: throw new Error('getSize: Wrong field type.'); + } + } + return bytes; +}; + +const memoizator = fn => { + let cache = {}; + const events = []; + + const func = (...args) => { + const key = generateKey(...args); + + if (func.timeout && !func.timer) { + func.timer = setTimeout(() => { + cache = {}; + console.log(`Cache cleared after ${func.timeout} msec`); + }, func.timeout); + } + + if (cache[key]) { + console.log(`From cache ${key}`); + return cache[key]; + } + + if (func.maxSize && getSize(cache) >= func.maxSize) { + console.log(`Cache with size ${getSize(cache)} bytes cleaned`); + cache = {}; + } + + const cacheSize = Object.keys(cache).length; + if (func.maxCount && cacheSize >= func.maxCount) { + console.log(`Cache with length ${cacheSize} cleaned`); + } + + console.log(`Calc ${key}`); + cache[key] = fn(...args); + return cache[key]; + }; + + func.clear = () => { + console.log('Cache cleared'); + cache = {}; + }; + + func.add = (key, value) => { + if (cache[key]) throw new Error('This key already exists'); + else cache[key] = value; + console.log(`${key} added`); + }; + + func.get = (key) => cache[key]; + + func.del = (key) => { + if (cache[key]) { + console.log(`${key} deleted`); + delete cache[key]; + return; + } + console.log(`There is no ${key}`); + }; + + func.on = (name, fn) => { + if (events[name]) throw new Error('Event already exists'); + if (!['clear', 'add', 'del'].find((el) => (el === name))) + throw new Error('Wrong event name'); + events[name] = fn; + }; + + func.emit = (name, data) => { + if (name === 'clear') { + events[name](cache); + func.clear(); + return true; + } + if (name === 'add') { + const res = data.map((el) => events[name](el)); + res.map((el, key) => func.add(key, el)); + return true; + } + if (name === 'del') { + const res = []; + res.push(events[name](...data, cache)); + res.map((key) => func.del(key)); + return true; + } + throw new Error('Frong event name'); + }; + + func.timeout = null; + func.maxSize = null; + func.maxCount = null; + + return func; +}; + +//USAGE + +const sum = (a, b) => a + b; +const sumM = memoizator(sum); +console.log(sumM(1, 1)); +sumM.maxCount = 3; +sumM.timeout = 100; +sumM.maxSize = 32; + +sumM.on('clear', (cache) => console.dir({ cache })); +sumM.emit('clear'); + +const fibbo = (n) => (n < 2 ? 1 : fibbo(n - 1) + fibbo(n - 2)); +sumM.on('add', fibbo); +sumM.emit('add', [1, 2, 3]); + +sumM(1, 2); +sumM.on('del', (el) => generateKey(el, el + 1)); +sumM.emit('del', [1]); diff --git a/README.md b/README.md index be5f0d4..cf14897 100644 --- a/README.md +++ b/README.md @@ -3,19 +3,19 @@ Memoization of synchronous and asynchronous functions Tasks: -- see examples -- implement time expiration cash -- implement memoize with max records count and removing least used -- implement memoize with max total stored data size -- implement universal memoize compatible with both sync and async function -- implement functional object with following properties methods and events: - - `memoized.clear()` - clear cache - - `memoized.add(key, value)` - add value to cach - - `memoized.del(key)` - remove value from cach - - `memoized.get(key)` - returns saved value - - `memoized.timeout: Number` - cache timout - - `memoized.maxSize: Number` - maximum cache size in bytes - - `memoized.maxCount: Number` - maximum cache size in item count - - `memoized.on('add', Function)` - - `memoized.on('del', Function)` - - `memoized.on('clear', Function)` ++ see examples ++ implement time expiration cash ++ implement memoize with max records count and removing least used ++ implement memoize with max total stored data size ++ implement universal memoize compatible with both sync and async function ++ implement functional object with following properties methods and events: + + `memoized.clear()` - clear cache + + `memoized.add(key, value)` - add value to cach + + `memoized.del(key)` - remove value from cach + + `memoized.get(key)` - returns saved value + + `memoized.timeout: Number` - cache timout + + `memoized.maxSize: Number` - maximum cache size in bytes + + `memoized.maxCount: Number` - maximum cache size in item count + + `memoized.on('add', Function)` + + `memoized.on('del', Function)` + + `memoized.on('clear', Function)` pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy