├── .gitignore ├── LICENSE ├── README.md ├── demo.html └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # nyc test coverage 18 | .nyc_output 19 | 20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 21 | .grunt 22 | 23 | # node-waf configuration 24 | .lock-wscript 25 | 26 | # Compiled binary addons (http://nodejs.org/api/addons.html) 27 | build/Release 28 | 29 | # Dependency directories 30 | node_modules 31 | jspm_packages 32 | 33 | # Optional npm cache directory 34 | .npm 35 | 36 | # Optional REPL history 37 | .node_repl_history 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 luobotang 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # simply-lazy 2 | 3 | A simple [Lazy.js](http://danieltao.com/lazy.js) implementation, to show the core of lazy evaluation. 4 | 5 | ## demo 6 | 7 | See: [demo](http://www.luobotang.cn/simply-lazy/demo.html). 8 | -------------------------------------------------------------------------------- /demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | simply-lazy 6 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 163 | 164 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | (function(root, factory) { 2 | if (typeof define === 'function' && define.amd) { 3 | define(factory); 4 | } else if (typeof exports === 'object') { 5 | module.exports = factory(); 6 | } else { 7 | root.Lazy = factory(); 8 | } 9 | })(this, function() { 10 | 11 | function Lazy(source) { 12 | if (source instanceof Array) { 13 | return ArrayWrapper(source); 14 | } 15 | throw new Error('Sorry, only array is supported in simply-lazy.') 16 | } 17 | 18 | /* Sequence */ 19 | 20 | function Sequence() { } 21 | 22 | Sequence.prototype.get = function get(i) { 23 | var element; 24 | this.each(function(e, index) { 25 | if (index === i) { 26 | element = e; 27 | return false; 28 | } 29 | }); 30 | return element; 31 | } 32 | 33 | Sequence.prototype.each = function each(fn) { 34 | var iterator = this.getIterator() 35 | var i = -1 36 | 37 | while (iterator.moveNext()) { 38 | if (fn(iterator.current(), ++i) === false) { 39 | return false; 40 | } 41 | } 42 | 43 | return true; 44 | } 45 | 46 | Sequence.prototype.map = function (mapFn) { 47 | return MappedSequence(this, mapFn) 48 | } 49 | 50 | Sequence.prototype.take = function (count) { 51 | return TakeSequence(this, count || 1) 52 | } 53 | 54 | /* MappedSequence */ 55 | 56 | function MappedSequence(parent, mapFn) { 57 | var seq = new Sequence() 58 | seq.getIterator = () => { 59 | var iterator = parent.getIterator() 60 | var index = -1 61 | return { 62 | current() { return mapFn(iterator.current(), index) }, 63 | moveNext() { 64 | if (iterator.moveNext()) { 65 | ++index 66 | return true 67 | } 68 | return false 69 | } 70 | } 71 | } 72 | seq.each = fn => parent.each((e, i) => fn(mapFn(e, i), i)) 73 | return seq 74 | } 75 | 76 | /* FilteredSequence */ 77 | 78 | function FilteredSequence(parent, filterFn) { 79 | var seq = new Sequence() 80 | seq.getIterator = () => { 81 | var iterator = parent.getIterator() 82 | var index = 0 83 | var value 84 | return { 85 | current() { return value }, 86 | moveNext() { 87 | var _val 88 | while (iterator.moveNext()) { 89 | _val = iterator.current() 90 | if (filterFn(_val, index++)) { 91 | value = _val 92 | return true 93 | } 94 | } 95 | value = undefined 96 | return false 97 | } 98 | } 99 | } 100 | seq.each = fn => { 101 | var j = 0; 102 | return parent.each((e, i) => { 103 | if (filterFn(e, i)) { 104 | return fn(e, j++); 105 | } 106 | }) 107 | } 108 | return seq 109 | } 110 | 111 | /* TakeSequence */ 112 | 113 | function TakeSequence(parent, count) { 114 | var seq = new Sequence() 115 | seq.getIterator = () => { 116 | var iterator = parent.getIterator() 117 | var _count = count 118 | return { 119 | current() { return iterator.current() }, 120 | moveNext() { return (--_count >= 0) && iterator.moveNext() } 121 | } 122 | } 123 | seq.each = (fn) => { 124 | var _count = count 125 | var i = 0 126 | var result 127 | parent.each(e => { 128 | if (i < count) { result = fn(e, i++); } 129 | if (i >= count) { return false; } 130 | return result 131 | }) 132 | return i === count && result !== false 133 | } 134 | return seq 135 | } 136 | 137 | /* ArrayLikeSequence */ 138 | 139 | function ArrayLikeSequence() { 140 | var seq = new Sequence() 141 | seq.length = () => seq.parent.length() 142 | seq.map = mapFn => IndexedMappedSequence(seq, mapFn) 143 | seq.filter = filterFn => IndexedFilteredSequence(seq, filterFn) 144 | return seq 145 | } 146 | 147 | /* IndexedMappedSequence */ 148 | 149 | function IndexedMappedSequence(parent, mapFn) { 150 | var seq = ArrayLikeSequence() 151 | seq.parent = parent 152 | seq.get = (i) => { 153 | if (i < 0 || i >= parent.length()) { 154 | return undefined; 155 | } 156 | return mapFn(parent.get(i), i); 157 | } 158 | return seq 159 | } 160 | 161 | /* IndexedFilteredSequence */ 162 | 163 | function IndexedFilteredSequence(parent, filterFn) { 164 | var seq = FilteredSequence(parent, filterFn) 165 | seq.parent = parent 166 | seq.each = (fn) => { 167 | var length = parent.length() 168 | var i = -1 169 | var j = 0 170 | var e 171 | while (++i < length) { 172 | e = parent.get(i) 173 | if (filterFn(e, i) && fn(e, j++) === false) { 174 | return false 175 | } 176 | } 177 | return true 178 | } 179 | return seq 180 | } 181 | 182 | /* ArrayWrapper */ 183 | 184 | function ArrayWrapper(source) { 185 | var seq = ArrayLikeSequence() 186 | seq.source = source 187 | seq.get = i => source[i] 188 | seq.length = () => source.length 189 | seq.each = fn => { 190 | var i = -1 191 | var len = source.length 192 | while (++i < len) { 193 | if (fn(source[i], i) === false) { 194 | return false 195 | } 196 | } 197 | return true 198 | } 199 | seq.map = mapFn => MappedArrayWrapper(seq, mapFn) 200 | seq.filter = filterFn => FilteredArrayWrapper(seq, filterFn) 201 | return seq 202 | } 203 | 204 | /* MappedArrayWrapper */ 205 | 206 | function MappedArrayWrapper(parent, mapFn) { 207 | var source = parent.source 208 | var length = source.length 209 | var seq = ArrayLikeSequence() 210 | seq.parent = parent 211 | seq.get = i => (i < 0 || i >= length) ? undefined : mapFn(source[i]) 212 | seq.length = () => length 213 | seq.each = fn => { 214 | var i = -1; 215 | while (++i < length) { 216 | if (fn(mapFn(source[i], i), i) === false) { 217 | return false 218 | } 219 | } 220 | return true 221 | } 222 | return seq 223 | } 224 | 225 | /* FilteredArrayWrapper */ 226 | 227 | function FilteredArrayWrapper(parent, filterFn) { 228 | var seq = FilteredSequence(parent, filterFn) 229 | seq.each = fn => { 230 | var source = parent.source 231 | var length = source.length 232 | var i = -1 233 | var j = 0 234 | var e 235 | 236 | while (++i < length) { 237 | e = source[i] 238 | if (filterFn(e, i) && fn(e, j++) === false) { 239 | return false 240 | } 241 | } 242 | 243 | return true 244 | } 245 | return seq 246 | } 247 | 248 | return Lazy 249 | }) --------------------------------------------------------------------------------