From 53e195884f4ddd5b99c2e395a4dd62e39440a24d Mon Sep 17 00:00:00 2001 From: ALEGATOR1209 Date: Sun, 4 Nov 2018 14:01:44 +0200 Subject: [PATCH 1/6] Done homework --- JavaScript/8-timer.js | 47 +++++++++++++ JavaScript/9-least.js | 48 ++++++++++++++ JavaScript/a-bytes.js | 86 ++++++++++++++++++++++++ JavaScript/b-universal.js | 54 +++++++++++++++ JavaScript/c-object.js | 134 ++++++++++++++++++++++++++++++++++++++ README.md | 32 ++++----- 6 files changed, 385 insertions(+), 16 deletions(-) create mode 100644 JavaScript/8-timer.js create mode 100644 JavaScript/9-least.js create mode 100644 JavaScript/a-bytes.js create mode 100644 JavaScript/b-universal.js create mode 100644 JavaScript/c-object.js diff --git a/JavaScript/8-timer.js b/JavaScript/8-timer.js new file mode 100644 index 0000000..601c712 --- /dev/null +++ b/JavaScript/8-timer.js @@ -0,0 +1,47 @@ +'use strict'; + +const memoize = (fn, msec = 100) => { + let cache = {}; + let timer = setTimeout(() => { + console.log('Cache cleaned'); + timer = null; + cache = {}; + }, msec); + + const setTimer = msec => { + timer = setTimeout(() => { + console.log('Cache cleaned'); + timer = null; + cache = {}; + }, msec); + }; + + const generateKey = (...args) => args.join('|'); + + return (...args) => { + if (!timer) setTimer(msec); + const key = generateKey(...args); + + if (cache[key]) { + console.log(`From cache: ${args} = ${cache[key]}`); + return cache[key]; + } + + console.log(`Calculate: ${args} = ${fn(...args)}`); + const res = fn(...args); + cache[key] = res; + console.log(cache); + return res; + }; +}; + +const sum = (a, b) => a + b; + +const sumM = memoize(sum, 2000); + +//USAGE +sumM(1, 2); +sumM(1, 2); +setTimeout(() => { + sumM(1, 2); +}, 2500); 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..7f830de --- /dev/null +++ b/JavaScript/a-bytes.js @@ -0,0 +1,86 @@ +'use strict'; + +const memoizeBytes = (fn, size) => { + let cache = {}; + + 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; + 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; + }; + + return (...args) => { + const key = generateKey(...args); + + if (cache[key]) { + console.log(`From cache: ${key}`); + return cache[key]; + } + + if (getSize(cache) >= sizeInBytes) { + console.log(`Cache with size ${getSize(cache)} bytes cleaned`); + cache = {}; + } + + console.log(`Calculating: ${key}`); + cache[key] = fn(...args); + console.dir(`Cache size: ${getSize(cache)}`); + return fn(...args); + }; +}; + +//USAGE + +const sum = (a, b) => a + b; +const sumB = memoizeBytes(sum, '32B'); +console.log(`sumB(1, 2) = ${sumB(1, 2)}`); +console.log(`sumB(1, 2) = ${sumB(1, 2)}`); +console.log(`sumB(2, 3) = ${sumB(2, 3)}`); +console.log(`sumB(3, 2) = ${sumB(3, 2)}`); +console.log(`sumB(4, 2) = ${sumB(4, 2)}`); +console.log(`sumB(2, 3) = ${sumB(2, 3)}`); +console.log(`sumB(1, 3) = ${sumB(1, 3)}`); +console.log(`sumB(4, 3) = ${sumB(4, 3)}`); +console.log(`sumB(9, 3) = ${sumB(9, 3)}`); +console.log(`sumB(8, 3) = ${sumB(8, 3)}`); + +const sumK = memoizeBytes(sum, '0.25K'); +const arr = []; +for (let i = 0; i < 100; i++) {; + arr[i] = sumK(i, i-1); +} \ No newline at end of file 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)` From 56fefe5f502bcf3db7ff7d1d35a8e6069a42aaa5 Mon Sep 17 00:00:00 2001 From: ALEGATOR1209 Date: Sun, 4 Nov 2018 14:05:14 +0200 Subject: [PATCH 2/6] a-bytes.js fixed --- JavaScript/a-bytes.js | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/JavaScript/a-bytes.js b/JavaScript/a-bytes.js index 7f830de..a1d34b9 100644 --- a/JavaScript/a-bytes.js +++ b/JavaScript/a-bytes.js @@ -76,11 +76,5 @@ console.log(`sumB(4, 2) = ${sumB(4, 2)}`); console.log(`sumB(2, 3) = ${sumB(2, 3)}`); console.log(`sumB(1, 3) = ${sumB(1, 3)}`); console.log(`sumB(4, 3) = ${sumB(4, 3)}`); -console.log(`sumB(9, 3) = ${sumB(9, 3)}`); +console.log(`sumB(9, 3) = ${sumB(1, 3)}`); console.log(`sumB(8, 3) = ${sumB(8, 3)}`); - -const sumK = memoizeBytes(sum, '0.25K'); -const arr = []; -for (let i = 0; i < 100; i++) {; - arr[i] = sumK(i, i-1); -} \ No newline at end of file From 7367d48fd38e51280d4e80883883091f7b322989 Mon Sep 17 00:00:00 2001 From: ALEGATOR1209 Date: Fri, 16 Nov 2018 21:06:20 +0200 Subject: [PATCH 3/6] Fixed small problems --- JavaScript/{8-timer.js => 8-timeout.js} | 33 +++++++++++++++---------- 1 file changed, 20 insertions(+), 13 deletions(-) rename JavaScript/{8-timer.js => 8-timeout.js} (56%) diff --git a/JavaScript/8-timer.js b/JavaScript/8-timeout.js similarity index 56% rename from JavaScript/8-timer.js rename to JavaScript/8-timeout.js index 601c712..b10de77 100644 --- a/JavaScript/8-timer.js +++ b/JavaScript/8-timeout.js @@ -2,34 +2,41 @@ const memoize = (fn, msec = 100) => { let cache = {}; - let timer = setTimeout(() => { - console.log('Cache cleaned'); - timer = null; - cache = {}; - }, msec); const setTimer = msec => { - timer = setTimeout(() => { + let timer = setTimeout(() => { console.log('Cache cleaned'); timer = null; cache = {}; }, msec); + + return timer; }; - const generateKey = (...args) => args.join('|'); + const hasKey = (key) => Object.keys(cache).includes(key); + + const timer = setTimer(msec); + + const generateKey = (args) => { + let key = ''; + for (const arg of args) + key += `${arg}~${typeof arg}|`; + return key; + }; return (...args) => { if (!timer) setTimer(msec); - const key = generateKey(...args); + const key = generateKey(args); - if (cache[key]) { + if (hasKey(key)) { console.log(`From cache: ${args} = ${cache[key]}`); return cache[key]; } console.log(`Calculate: ${args} = ${fn(...args)}`); const res = fn(...args); - cache[key] = res; + if (res !== undefined) + cache[key] = res; console.log(cache); return res; }; @@ -40,8 +47,8 @@ const sum = (a, b) => a + b; const sumM = memoize(sum, 2000); //USAGE -sumM(1, 2); -sumM(1, 2); +sumM(1, -1); +sumM(1, -1); setTimeout(() => { - sumM(1, 2); + sumM(1, -1); }, 2500); From c4a9f226da2cc446f82ac02c4f33c9802cc218e1 Mon Sep 17 00:00:00 2001 From: ALEGATOR1209 Date: Fri, 16 Nov 2018 23:50:46 +0200 Subject: [PATCH 4/6] timeout now deletes only keys which weren't used for some time --- JavaScript/8-timeout.js | 69 +++++++++++++++++++++++++++-------------- 1 file changed, 46 insertions(+), 23 deletions(-) diff --git a/JavaScript/8-timeout.js b/JavaScript/8-timeout.js index b10de77..79e4d4a 100644 --- a/JavaScript/8-timeout.js +++ b/JavaScript/8-timeout.js @@ -1,22 +1,9 @@ 'use strict'; const memoize = (fn, msec = 100) => { - let cache = {}; - - const setTimer = msec => { - let timer = setTimeout(() => { - console.log('Cache cleaned'); - timer = null; - cache = {}; - }, msec); - - return timer; - }; - + const cache = {}; + let timer; const hasKey = (key) => Object.keys(cache).includes(key); - - const timer = setTimer(msec); - const generateKey = (args) => { let key = ''; for (const arg of args) @@ -24,31 +11,67 @@ const memoize = (fn, msec = 100) => { return key; }; - return (...args) => { - if (!timer) setTimer(msec); + 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]}`); - return cache[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] = res; + cache[key] = { value: res, lastUse: new Date() }; console.log(cache); return res; }; + + return func; }; const sum = (a, b) => a + b; -const sumM = memoize(sum, 2000); +const sumM = memoize(sum, 250); //USAGE sumM(1, -1); -sumM(1, -1); +sumM(2, -1); setTimeout(() => { sumM(1, -1); -}, 2500); + setTimeout(() => sumM(2, -1), 100); + setTimeout(() => { + sumM(2, 3); + setTimeout(() => sumM(3, 4), 1000); + }, 500); +}, 200); From d28df6d7887fa4859d7ee55ab02d6e9766b8fd26 Mon Sep 17 00:00:00 2001 From: ALEGATOR1209 Date: Fri, 16 Nov 2018 23:56:15 +0200 Subject: [PATCH 5/6] Oops I've forgot about null --- JavaScript/8-timeout.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/JavaScript/8-timeout.js b/JavaScript/8-timeout.js index 79e4d4a..aa89832 100644 --- a/JavaScript/8-timeout.js +++ b/JavaScript/8-timeout.js @@ -2,7 +2,7 @@ const memoize = (fn, msec = 100) => { const cache = {}; - let timer; + let timer = null; const hasKey = (key) => Object.keys(cache).includes(key); const generateKey = (args) => { let key = ''; From d19d32683108b9495454c25d8a709d38b675fadd Mon Sep 17 00:00:00 2001 From: ALEGATOR1209 Date: Sat, 17 Nov 2018 10:52:44 +0200 Subject: [PATCH 6/6] Improved a-bytes.js --- JavaScript/a-bytes.js | 74 ++++++++++++++++++++----------------------- 1 file changed, 35 insertions(+), 39 deletions(-) diff --git a/JavaScript/a-bytes.js b/JavaScript/a-bytes.js index a1d34b9..8b25c0e 100644 --- a/JavaScript/a-bytes.js +++ b/JavaScript/a-bytes.js @@ -1,7 +1,7 @@ 'use strict'; -const memoizeBytes = (fn, size) => { - let cache = {}; +const memoizeBytes = (fn, size = '1K', logging = true) => { + let cache = new Map(); const generateKey = (...args) => args.join('|'); @@ -24,57 +24,53 @@ const memoizeBytes = (fn, size) => { 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.'); - } - } + 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 (cache[key]) { - console.log(`From cache: ${key}`); + if (record) { + if (logging) console.log(`From cache: ${key}`); return cache[key]; } - if (getSize(cache) >= sizeInBytes) { - console.log(`Cache with size ${getSize(cache)} bytes cleaned`); - cache = {}; + const sizeOfCache = getSize(cache); + if (sizeOfCache >= sizeInBytes) { + console.log(`Cache with size ${sizeOfCache} bytes cleaned`); + cache = new Map(); } - console.log(`Calculating: ${key}`); - cache[key] = fn(...args); - console.dir(`Cache size: ${getSize(cache)}`); - return fn(...args); + 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 sumB = memoizeBytes(sum, '32B'); -console.log(`sumB(1, 2) = ${sumB(1, 2)}`); -console.log(`sumB(1, 2) = ${sumB(1, 2)}`); -console.log(`sumB(2, 3) = ${sumB(2, 3)}`); -console.log(`sumB(3, 2) = ${sumB(3, 2)}`); -console.log(`sumB(4, 2) = ${sumB(4, 2)}`); -console.log(`sumB(2, 3) = ${sumB(2, 3)}`); -console.log(`sumB(1, 3) = ${sumB(1, 3)}`); -console.log(`sumB(4, 3) = ${sumB(4, 3)}`); -console.log(`sumB(9, 3) = ${sumB(1, 3)}`); -console.log(`sumB(8, 3) = ${sumB(8, 3)}`); +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)); 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