svghmi/pythonic.js
changeset 3484 32eaba9cf30e
child 3485 5f417d3c2d03
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/svghmi/pythonic.js	Wed May 11 12:12:16 2022 +0200
@@ -0,0 +1,206 @@
+/*
+
+From https://github.com/keyvan-m-sadeghi/pythonic
+
+Slightly modified in order to be usable in browser (i.e. not as a node.js module)
+
+The MIT License (MIT)
+
+Copyright (c) 2016 Assister.Ai
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+class Iterator {
+    constructor(generator) {
+        this[Symbol.iterator] = generator;
+    }
+
+    async * [Symbol.asyncIterator]() {
+        for (const element of this) {
+            yield await element;
+        }
+    }
+
+    map(callback) {
+        const result = [];
+        for (const element of this) {
+            result.push(callback(element));
+        }
+
+        return result;
+    }
+
+    filter(callback) {
+        const result = [];
+        for (const element of this) {
+            if (callback(element)) {
+                result.push(element);
+            }
+        }
+
+        return result;
+    }
+
+    reduce(callback, initialValue) {
+        let empty = typeof initialValue === 'undefined';
+        let accumulator = initialValue;
+        let index = 0;
+        for (const currentValue of this) {
+            if (empty) {
+                accumulator = currentValue;
+                empty = false;
+                continue;
+            }
+
+            accumulator = callback(accumulator, currentValue, index, this);
+            index++;
+        }
+
+        if (empty) {
+            throw new TypeError('Reduce of empty Iterator with no initial value');
+        }
+
+        return accumulator;
+    }
+
+    some(callback) {
+        for (const element of this) {
+            if (callback(element)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    every(callback) {
+        for (const element of this) {
+            if (!callback(element)) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    static fromIterable(iterable) {
+        return new Iterator(function * () {
+            for (const element of iterable) {
+                yield element;
+            }
+        });
+    }
+
+    toArray() {
+        return Array.from(this);
+    }
+
+    next() {
+        if (!this.currentInvokedGenerator) {
+            this.currentInvokedGenerator = this[Symbol.iterator]();
+        }
+
+        return this.currentInvokedGenerator.next();
+    }
+
+    reset() {
+        delete this.currentInvokedGenerator;
+    }
+}
+
+function rangeSimple(stop) {
+    return new Iterator(function * () {
+        for (let i = 0; i < stop; i++) {
+            yield i;
+        }
+    });
+}
+
+function rangeOverload(start, stop, step = 1) {
+    return new Iterator(function * () {
+        for (let i = start; i < stop; i += step) {
+            yield i;
+        }
+    });
+}
+
+function range(...args) {
+    if (args.length < 2) {
+        return rangeSimple(...args);
+    }
+
+    return rangeOverload(...args);
+}
+
+function enumerate(iterable) {
+    return new Iterator(function * () {
+        let index = 0;
+        for (const element of iterable) {
+            yield [index, element];
+            index++;
+        }
+    });
+}
+
+const _zip = longest => (...iterables) => {
+    if (iterables.length < 2) {
+        throw new TypeError("zip takes 2 iterables at least, "+iterables.length+" given");
+    }
+
+    return new Iterator(function * () {
+        const iterators = iterables.map(iterable => Iterator.fromIterable(iterable));
+        while (true) {
+            const row = iterators.map(iterator => iterator.next());
+            const check = longest ? row.every.bind(row) : row.some.bind(row);
+            if (check(next => next.done)) {
+                return;
+            }
+
+            yield row.map(next => next.value);
+        }
+    });
+};
+
+const zip = _zip(false), zipLongest= _zip(true);
+
+function items(obj) {
+    let {keys, get} = obj;
+    if (obj instanceof Map) {
+        keys = keys.bind(obj);
+        get = get.bind(obj);
+    } else {
+        keys = function () {
+            return Object.keys(obj);
+        };
+
+        get = function (key) {
+            return obj[key];
+        };
+    }
+
+    return new Iterator(function * () {
+        for (const key of keys()) {
+            yield [key, get(key)];
+        }
+    });
+}
+
+/*
+module.exports = {Iterator, range, enumerate, zip: _zip(false), zipLongest: _zip(true), items};
+*/