added several methods + docs...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2020-12-08 01:53:40 +03:00
parent e6441cb661
commit 332225e7d3
4 changed files with 283 additions and 50 deletions

View File

@ -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){

273
README.md
View File

@ -18,7 +18,8 @@ A library of JavaScript type extensions, types and type utilities.
- [`<array>.rol(..)`](#arrayrol)
- [`<array>.compact()`](#arraycompact)
- [`<array>.len`](#arraylen)
- [`<array>.unique(..)` / `<array>.tailUnique(..)`](#arrayunique--arraytailunique)
- [`<array>.unique()` / `<array>.tailUnique()`](#arrayunique--arraytailunique)
- [`<array>.trim()` / `<array>.trimStart()` / `<array>.trimEnd()`](#arraytrim--arraytrimstart--arraytrimend)
- [`<array>.cmp(..)`](#arraycmp)
- [`<array>.setCmp(..)`](#arraysetcmp)
- [`<array>.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)
- [`<array>.CHUNK_SIZE`](#arraychunk_size)
- [`<array>.mapChunks(..)`](#arraymapchunks)
- [`<array>.filterChunks(..)`](#arrayfilterchunks)
- [`<array>.reduceChunks(..)`](#arrayreducechunks)
- [`<array>.mapChunks(..)` / `<array>.filterChunks(..)` / `<array>.reduceChunks(..)`](#arraymapchunks--arrayfilterchunks--arrayreducechunks)
- [`Map`](#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)
- [`<queue>.state`](#queuestate)
- [`<queue>.start(..)`](#queuestart)
- [`<queue>.pause(..)`](#queuepause)
- [`<queue>.abort(..)`](#queueabort)
- [`<queue>.stop(..)`](#queuestop)
- [`<queue>.then(..)`](#queuethen)
- [`<queue>.runTask(..)`](#queueruntask)
- [`<queue>.tasksAdded(..)` (event)](#queuetasksadded-event)
- [`<queue>.taskStarting(..)` (event)](#queuetaskstarting-event)
- [`<queue>.taskFailed(..)` (event)](#queuetaskfailed-event)
- [`<queue>.taskCompleted(..)` (event)](#queuetaskcompleted-event)
- [`<queue>.queueEmpty(..)` (event)](#queuequeueempty-event)
- [Large task management](#large-task-management)
- [`runner.TaskManager(..)`](#runnertaskmanager)
- [`<task-manager>.Task(..)`](#task-managertask)
@ -173,9 +178,9 @@ require('ig-types/Object')
### `Object.deepKeys(..)`
```
```bnf
Object.deepKeys(<obj>)
-> <keys>
-> <keys>
```
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(<obj>)
-> <obj-copy>
-> <obj-copy>
```
Create a copy of `<obj>`
@ -217,9 +222,9 @@ _XXX not yet sure how useful this is._
### `Object.flatCopy(..)`
```
```bnf
Object.flatCopy(<obj>)
-> <new-obj>
-> <new-obj>
```
Copy all attributes from the prototype chain of `<obj>` into `<new-obj>`.
@ -231,7 +236,7 @@ Copy all attributes from the prototype chain of `<obj>` into `<new-obj>`.
### `<object>.run(..)`
```
```bnf
<object>.run(<func>)
-> <object>
-> <other>
@ -269,21 +274,21 @@ https://github.com/flynx/object-run.js
### `Object.sort(..)`
Sort `<obj>` attributes (same as `Array`'s `.sort(..)`)
```
```bnf
Object.sort(<obj>)
-> <obj>
-> <obj>
```
Sort `<obj>` attributes via `<cmp>` function.
```
Object.sort(<obj>, <cmp>)
-> <obj>
-> <obj>
```
Sort `<obj>` attributes to the same order of `<order-list>`.
```
```bnf
Object.sort(<obj>, <order-list>)
-> <obj>
-> <obj>
```
Note that this rewrites all the keys of `<obj>` thus for very large
@ -321,16 +326,16 @@ var array = require('ig-types/Array')
### `<array>.first(..)` / `<array>.last(..)`
Get the first/last items of `<array>`.
```
```bnf
<array>.first()
-> <item>
-> <item>
<array>.last()
-> <item>
-> <item>
```
Set the first/last items of `<array>`.
```
```bnf
<array>.first(<item>)
-> <array>
@ -345,13 +350,13 @@ an empty `<array>`.
### `<array>.rol(..)`
Roll `<array>` in-place left.
```
```bnf
<array>.rol()
<array>.rol(1)
-> <array>
-> <array>
<array>.rol(n)
-> <array>
-> <array>
```
To roll right pass a negative `n` to `.rol(..)`.
@ -359,9 +364,9 @@ To roll right pass a negative `n` to `.rol(..)`.
### `<array>.compact()`
```
```bnf
<array>.compact()
-> <compact-array>
-> <compact-array>
```
Generate a compact `<array>` from a sparse `<array>`, 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.
### `<array>.unique(..)` / `<array>.tailUnique(..)`
### `<array>.unique()` / `<array>.tailUnique()`
Generate an array with all duplicate elements removed.
```bnf
<array>.unique()
-> <array>
```
### `<array>.trim()` / `<array>.trimStart()` / `<array>.trimEnd()`
Copy array removing empty slots from array start, end or both.
```bnf
<array>.trim()
-> <array>
<array>.trimStart()
-> <array>
<array>.trimEnd()
-> <array>
```
### `<array>.cmp(..)`
```
Compare two arrays.
```bnf
<array>.cmp(<other>)
-> <bool>
-> <bool>
```
Compare `<array>` to `<other>`.
This will return `true` if:
- `<array>` === `<other>` or,
- lengths are the same and,
@ -405,16 +428,120 @@ This will return `true` if:
### `<array>.setCmp(..)`
Compare to arrays ignoring element order and count.
```bnf
<array>.setCmp(<other>)
-> <bool>
```
### `<array>.sortAs(..)`
Sort array as a different array.
```bnf
<array>.sortAs(<other>)
-> <array>
```
Elements not present in `<other>` 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]
```
### `<array>.inplaceSortAs(..)`
Sort array as a different array keeping positions of unsorted elements.
```bnf
<array>.inplaceSortAs(<other>)
-> <array>
```
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]
```
### `<array>.toKeys(..)`
Create an object with array values as keys and index as value.
```bnf
<array>.toKeys()
-> <object>
```
Normalize resulting `<object>` keys:
```bnf
<array>.toKeys(<normalize>)
-> <object>
<normalize>(<elem>, <index>)
-> <key>
```
If `<array>` contains the same value multiple times it will be written
to `<object>` 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.
### `<array>.toMap(..)`
Create a map with array values as keys and index as value.
```bnf
<array>.toMap()
-> <map>
```
Normalize resulting `<map>` keys:
```bnf
<array>.toMap(<normalize>)
-> <map>
<normalize>(<elem>, <index>)
-> <key>
```
Note that if `<array>` contains the same value multiple times it will be used
as key only once and retain the last occurrences' index.
### `Array.zip(..)` / `<array>.zip(..)`
_Zip_ input array items.
```bnf
Array.zip(<array>, <array>, ..)
-> <array>
<array>.zip(<array>, <array>, ..)
-> <array>
```
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(..)` / `<array>.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`
#### `<array>.mapChunks(..)`
#### `<array>.mapChunks(..)` / `<array>.filterChunks(..)` / `<array>.reduceChunks(..)`
```
The `.map(..)`, `.filter(..)` and `.reduce(..)` alternatives respectively:
```bnf
<array>.mapChunks(<func>)
<array>.mapChunks(<chunk-size>, <func>)
-> <promise>
@ -553,7 +681,26 @@ Default value: `50`
-> <new-item>
```
```bnf
<array>.filterChunks(<func>)
<array>.filterChunks(<chunk-size>, <func>)
-> <promise>
<func>(<item>, <index>, <array>)
-> <bool>
```
```bnf
<array>.reduceChunks(<func>, <state>)
<array>.mreduceChunks(<chunk-size>, <func>, <state>)
-> <promise>
<func>(<state>, <item>, <index>, <array>)
-> <state>
```
All three support chunk handlers in the same way (illustrated on `.mapChunks(..)`):
```bnf
<array>.mapChunks([<func>, <chunk-handler>])
<array>.mapChunks(<chunk-size>, [<func>, <chunk-handler>])
-> <promise>
@ -564,10 +711,9 @@ Default value: `50`
<chunk-handler>(<chunk>, <result>, <offset>)
```
The `<chunk-handler>` gets the completed chunk of data after it is computed
but before the timeout.
#### `<array>.filterChunks(..)`
#### `<array>.reduceChunks(..)`
## `Map`
@ -579,6 +725,7 @@ require('ig-types/Map')
### `<map>.sort(..)`
## `Set`
```javascript
@ -725,7 +872,7 @@ Promise.iter(<array>)
#### Advanced handler
```
```bnf
Promise.iter(<block-array>, <handler>)
-> <iterable-promise>
@ -913,7 +1060,7 @@ https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects
#### `<unique-key-map>.set(..)`
```
```bnf
<unique-key-map>.reset(<key>, <item>)
-> <unique-key-map>
@ -930,7 +1077,7 @@ Key updating is done via [`<unique-key-map>.__key_pattern__`](#unique-key-map__k
#### `<unique-key-map>.reset(..)`
```
```bnf
<unique-key-map>.reset(<key>, <item>)
-> <unique-key-map>
```
@ -939,7 +1086,7 @@ Explicitly write an `<item>` under `<key>` as-is, this is like `Map`'s `.set(..)
#### `<unique-key-map>.rename(..)`
```
```bnf
<unique-key-map>.rename(<from-key>, <to-key>)
-> <unique-key-map>
@ -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(<func>, ...<data>)
Queue.handle(<options>, <func>, ...<data>)
-> <queue>
```
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){ .. },
..
},
.. )
```
#### `<queue>.state`
#### `<queue>.start(..)`
#### `<queue>.pause(..)`
#### `<queue>.stop(..)`
#### `<queue>.abort(..)`
#### `<queue>.then(..)`
#### `<queue>.runTask(..)`
#### `<queue>.tasksAdded(..)` (event)
#### `<queue>.taskStarting(..)` (event)
#### `<queue>.taskFailed(..)` (event)
#### `<queue>.taskCompleted(..)` (event)
Event, triggered when a task is completed passing in its result.
#### `<queue>.queueEmpty(..)` (event)
### Large task management
#### `runner.TaskManager(..)`

View File

@ -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": {

View File

@ -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