diff --git a/Array.js b/Array.js index f485b93..a7566e5 100644 --- a/Array.js +++ b/Array.js @@ -289,6 +289,26 @@ object.Mixin('ArrayProtoMixin', 'soft', { return this .filter(function(){ return true }) }, + // Remove sprse slots form start/end/both ends of array... + // + trim: function(){ + var l = this.length + var i = 0 + while(!(i in this) && i < l){ i++ } + var j = 0 + while(!(l-j-1 in this) && j < l){ j++ } + return this.slice(i, j == 0 ? l : -j) }, + trimStart: function(){ + var l = this.length + var i = 0 + while(!(i in this) && i < l){ i++ } + return this.slice(i) }, + trimEnd: function(){ + var l = this.length + var j = 0 + while(!(l-j-1 in this) && j < l){ j++ } + return this.slice(0, j == 0 ? l : -j) }, + // like .length but for sparse arrays will return the element count... get len(){ // NOTE: if we don't do .slice() here this can count array @@ -297,7 +317,6 @@ object.Mixin('ArrayProtoMixin', 'soft', { // attributes from the count... return Object.keys(this.slice()).length }, - // Return a new array with duplicate elements removed... // // NOTE: order is preserved... @@ -409,7 +428,7 @@ object.Mixin('ArrayProtoMixin', 'soft', { toKeys: function(normalize){ return normalize ? this.reduce(function(r, e, i){ - r[normalize(e)] = i + r[normalize(e, i)] = i return r }, {}) : this.reduce(function(r, e, i){ r[e] = i @@ -432,7 +451,7 @@ object.Mixin('ArrayProtoMixin', 'soft', { return normalize ? this .reduce(function(m, e, i){ - m.set(normalize(e), i) + m.set(normalize(e, i), i) return m }, new Map()) : this .reduce(function(m, e, i){ diff --git a/README.md b/README.md index ace3b7a..a602e49 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,8 @@ A library of JavaScript type extensions, types and type utilities. - [`.rol(..)`](#arrayrol) - [`.compact()`](#arraycompact) - [`.len`](#arraylen) - - [`.unique(..)` / `.tailUnique(..)`](#arrayunique--arraytailunique) + - [`.unique()` / `.tailUnique()`](#arrayunique--arraytailunique) + - [`.trim()` / `.trimStart()` / `.trimEnd()`](#arraytrim--arraytrimstart--arraytrimend) - [`.cmp(..)`](#arraycmp) - [`.setCmp(..)`](#arraysetcmp) - [`.sortAs(..)`](#arraysortas) @@ -33,9 +34,7 @@ A library of JavaScript type extensions, types and type utilities. - [Large `Array` iteration (chunked)](#large-array-iteration-chunked) - [`array.STOP` / `array.STOP(..)`](#arraystop--arraystop-1) - [`.CHUNK_SIZE`](#arraychunk_size) - - [`.mapChunks(..)`](#arraymapchunks) - - [`.filterChunks(..)`](#arrayfilterchunks) - - [`.reduceChunks(..)`](#arrayreducechunks) + - [`.mapChunks(..)` / `.filterChunks(..)` / `.reduceChunks(..)`](#arraymapchunks--arrayfilterchunks--arrayreducechunks) - [`Map`](#map) - [`.sort(..)`](#mapsort) - [`Set`](#set) @@ -108,12 +107,18 @@ A library of JavaScript type extensions, types and type utilities. - [`event.EventMixin`](#eventeventmixin) - [Runner](#runner) - [Micro task queue](#micro-task-queue) - - [`runner.Queue(..)` / `runner.Queue.run(..)`](#runnerqueue--runnerqueuerun) + - [`Queue(..)` / `Queue.runTasks(..)`](#queue--queueruntasks) + - [`Queue.handle(..)`](#queuehandle) - [`.state`](#queuestate) - [`.start(..)`](#queuestart) - - [`.pause(..)`](#queuepause) - - [`.abort(..)`](#queueabort) + - [`.stop(..)`](#queuestop) + - [`.then(..)`](#queuethen) + - [`.runTask(..)`](#queueruntask) + - [`.tasksAdded(..)` (event)](#queuetasksadded-event) + - [`.taskStarting(..)` (event)](#queuetaskstarting-event) + - [`.taskFailed(..)` (event)](#queuetaskfailed-event) - [`.taskCompleted(..)` (event)](#queuetaskcompleted-event) + - [`.queueEmpty(..)` (event)](#queuequeueempty-event) - [Large task management](#large-task-management) - [`runner.TaskManager(..)`](#runnertaskmanager) - [`.Task(..)`](#task-managertask) @@ -173,9 +178,9 @@ require('ig-types/Object') ### `Object.deepKeys(..)` -``` +```bnf Object.deepKeys() - -> + -> ``` Get list of keys from all objects in the prototype chain. @@ -198,9 +203,9 @@ Object.deepKeys(b) // -> ['x', 'y'] ### `Object.copy(..)` (EXPERIMENTAL) -``` +```bnf Object.copy() - -> + -> ``` Create a copy of `` @@ -217,9 +222,9 @@ _XXX not yet sure how useful this is._ ### `Object.flatCopy(..)` -``` +```bnf Object.flatCopy() - -> + -> ``` Copy all attributes from the prototype chain of `` into ``. @@ -231,7 +236,7 @@ Copy all attributes from the prototype chain of `` into ``. ### `.run(..)` -``` +```bnf .run() -> -> @@ -269,21 +274,21 @@ https://github.com/flynx/object-run.js ### `Object.sort(..)` Sort `` attributes (same as `Array`'s `.sort(..)`) -``` +```bnf Object.sort() - -> + -> ``` Sort `` attributes via `` function. ``` Object.sort(, ) - -> + -> ``` Sort `` attributes to the same order of ``. -``` +```bnf Object.sort(, ) - -> + -> ``` Note that this rewrites all the keys of `` thus for very large @@ -321,16 +326,16 @@ var array = require('ig-types/Array') ### `.first(..)` / `.last(..)` Get the first/last items of ``. -``` +```bnf .first() - -> + -> .last() - -> + -> ``` Set the first/last items of ``. -``` +```bnf .first() -> @@ -345,13 +350,13 @@ an empty ``. ### `.rol(..)` Roll `` in-place left. -``` +```bnf .rol() .rol(1) - -> + -> .rol(n) - -> + -> ``` To roll right pass a negative `n` to `.rol(..)`. @@ -359,9 +364,9 @@ To roll right pass a negative `n` to `.rol(..)`. ### `.compact()` -``` +```bnf .compact() - -> + -> ``` Generate a compact `` from a sparse ``, i.e. removing all @@ -383,20 +388,38 @@ L.compact().length Note that this is different from `.length` in that writing to `.len` has no effect. -### `.unique(..)` / `.tailUnique(..)` +### `.unique()` / `.tailUnique()` Generate an array with all duplicate elements removed. +```bnf +.unique() + -> +``` + +### `.trim()` / `.trimStart()` / `.trimEnd()` + +Copy array removing empty slots from array start, end or both. +```bnf +.trim() + -> + +.trimStart() + -> + +.trimEnd() + -> +``` + ### `.cmp(..)` -``` +Compare two arrays. +```bnf .cmp() - -> + -> ``` -Compare `` to ``. - This will return `true` if: - `` === `` or, - lengths are the same and, @@ -405,16 +428,120 @@ This will return `true` if: ### `.setCmp(..)` +Compare to arrays ignoring element order and count. + +```bnf +.setCmp() + -> +``` + ### `.sortAs(..)` +Sort array as a different array. +```bnf +.sortAs() + -> +``` + +Elements not present in `` retain their relative order and are +placed after the sorted elements. + +Example: +```javascript +var L = [1, 2, 3, 4, 5, 6] +var O = [5, 3, 1, 0] + +L.sortAs(O) // -> [5, 3, 1, 2, 4, 6] +``` + + ### `.inplaceSortAs(..)` +Sort array as a different array keeping positions of unsorted elements. +```bnf +.inplaceSortAs() + -> +``` + +Example: +```javascript +var L = [1, 2, 3, 4, 5, 6] +var O = [5, 3, 1, 0] + +L.inplaceSortAs(O) // -> [5, 2, 3, 4, 1, 6] +``` + ### `.toKeys(..)` +Create an object with array values as keys and index as value. +```bnf +.toKeys() + -> +``` + +Normalize resulting `` keys: +```bnf +.toKeys() + -> + +(, ) + -> +``` + +If `` contains the same value multiple times it will be written +to `` only once with the last occurrences' index. + +Since `object` keys can only be `string`s array items that are not +strings will be converted to strings. If this is not desired use `.toMap(..)` +instead. + + ### `.toMap(..)` +Create a map with array values as keys and index as value. +```bnf +.toMap() + -> +``` + +Normalize resulting `` keys: +```bnf +.toMap() + -> + +(, ) + -> +``` + +Note that if `` contains the same value multiple times it will be used +as key only once and retain the last occurrences' index. + + ### `Array.zip(..)` / `.zip(..)` +_Zip_ input array items. +```bnf +Array.zip(, , ..) + -> + +.zip(, , ..) + -> +``` + +Example: +```javascript +var A = [1, 2, 3] +var B = ['a', 'b', 'c', 'd'] + +Array.zip(A, B) // -> [[1, 'a'], [2, 'b'], [3, 'c'], [, 'd']] +``` + +Array _sparseness_ is retained -- if one of the arrays has an empty slot, or is +not long enough, the corresponding spot in the result will be empty. + +Resulting array length is strictly equal to the longest input array length. + + ### `Array.iter(..)` / `.iter()` Return an iterator/generator from the current array. @@ -542,9 +669,10 @@ in UI applications but there is a small overhead added per chunk. Default value: `50` -#### `.mapChunks(..)` +#### `.mapChunks(..)` / `.filterChunks(..)` / `.reduceChunks(..)` -``` +The `.map(..)`, `.filter(..)` and `.reduce(..)` alternatives respectively: +```bnf .mapChunks() .mapChunks(, ) -> @@ -553,7 +681,26 @@ Default value: `50` -> ``` +```bnf +.filterChunks() +.filterChunks(, ) + -> + +(, , ) + -> ``` + +```bnf +.reduceChunks(, ) +.mreduceChunks(, , ) + -> + +(, , , ) + -> +``` + +All three support chunk handlers in the same way (illustrated on `.mapChunks(..)`): +```bnf .mapChunks([, ]) .mapChunks(, [, ]) -> @@ -564,10 +711,9 @@ Default value: `50` (, , ) ``` +The `` gets the completed chunk of data after it is computed +but before the timeout. -#### `.filterChunks(..)` - -#### `.reduceChunks(..)` ## `Map` @@ -579,6 +725,7 @@ require('ig-types/Map') ### `.sort(..)` + ## `Set` ```javascript @@ -725,7 +872,7 @@ Promise.iter() #### Advanced handler -``` +```bnf Promise.iter(, ) -> @@ -913,7 +1060,7 @@ https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects #### `.set(..)` -``` +```bnf .reset(, ) -> @@ -930,7 +1077,7 @@ Key updating is done via [`.__key_pattern__`](#unique-key-map__k #### `.reset(..)` -``` +```bnf .reset(, ) -> ``` @@ -939,7 +1086,7 @@ Explicitly write an `` under `` as-is, this is like `Map`'s `.set(..) #### `.rename(..)` -``` +```bnf .rename(, ) -> @@ -1019,22 +1166,58 @@ var runner = require('ig-types/runner') This includes [`event.EventMixin`](#eventeventmixin). -#### `runner.Queue(..)` / `runner.Queue.run(..)` +#### `Queue(..)` / `Queue.runTasks(..)` + +#### `Queue.handle(..)` + +Create a handler queue object. +```bnf +Queue.handle(, ...) +Queue.handle(, , ...) + -> +``` + +A handler queue is a queue that has a single handler function (`.handle(..)`) +that handles the queue data. + +This is a shorthand for: +```javascript +var handler_queue = Queue({ + handler: function(item){ .. }, + .. + }, + .. ) +``` #### `.state` + #### `.start(..)` -#### `.pause(..)` +#### `.stop(..)` -#### `.abort(..)` +#### `.then(..)` + + +#### `.runTask(..)` + + +#### `.tasksAdded(..)` (event) + +#### `.taskStarting(..)` (event) + +#### `.taskFailed(..)` (event) #### `.taskCompleted(..)` (event) Event, triggered when a task is completed passing in its result. +#### `.queueEmpty(..)` (event) + + + ### Large task management #### `runner.TaskManager(..)` diff --git a/package.json b/package.json index 55279c0..f0d8c16 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ig-types", - "version": "5.0.39", + "version": "5.0.40", "description": "Generic JavaScript types and type extensions...", "main": "main.js", "scripts": { diff --git a/runner.js b/runner.js index 705815b..ea5b359 100644 --- a/runner.js +++ b/runner.js @@ -59,8 +59,38 @@ var Queue = module.Queue = object.Constructor('Queue', Array, { // create a running queue... + // runTasks: function(...tasks){ - return this({ state: 'running' }, ...tasks) }, + if(typeof(tasks[0]) != 'function' + && !(tasks[0] instanceof Queue) + && typeof(tasks[0].finally) != 'function'){ + var [options, ...tasks] = arguments } + return this( + Object.assign({}, + options || {}, + { state: 'running' }), + ...tasks) }, + + // Create a handler queue... + // + // Queue.handle(func, ...data) + // Queue.handle(options, func, ...data) + // -> queue + // + // NOTE: func(..) should be compatible with .handler(..) instance method... + // NOTE: this is a shorthand for: + // Queue({handler: func, ...}, ...data) + handle: function(handler, ...data){ + // NOTE: this is a simpler test than in .runTasks(..) above because + // here we are expecting a function as the first arg in the + // general case while above a non-task is the exception.. + if(typeof(handler) != 'function'){ + var [options, handler, ...data] = arguments } + return this( + Object.assign({}, + options || {}, + {handler}), + ...data) }, }, events.EventMixin('flat', { // Config... @@ -470,6 +500,7 @@ object.Constructor('Queue', Array, { if(!(this[0] instanceof Queue) && this[0] instanceof Object && typeof(this[0]) != 'function' + // XXX do we need this test??? && typeof(this[0].finally) != 'function'){ Object.assign(this, this.shift()) } this.length > 0