From: dsc Date: Sun, 19 Feb 2012 22:32:53 +0000 (-0800) Subject: Adds utility modules. X-Git-Url: http://git.less.ly:3516/?a=commitdiff_plain;h=b6fd2b90a70086864f3cf7e423d41a7d71b91972;p=limn.git Adds utility modules. --- diff --git a/lib/util/bitstring.co b/lib/util/bitstring.co new file mode 100644 index 0000000..a5be754 --- /dev/null +++ b/lib/util/bitstring.co @@ -0,0 +1,247 @@ +SEEK_ABSOLUTE = 0 +SEEK_RELATIVE = 1 +SEEK_FROM_EOF = 2 + + +# Binary representation of the number +bin = (n) -> + do + s = (if n % 2 then '1' else '0') + (s or '') + n >>= 1 + while n + s + +# Number of bits needed to represent the absolute value of n. +binlen = (n) -> + bin Math.abs n .length + +# Returns a run of 1s of size n. +mask = (n) -> + (1 << n) - 1 + +chr = -> String.fromCharCode it +ord = -> String(it).charCodeAt 0 + + + + +/** + * File-like object for reading/writing bits. + * @class + */ +class BitString + # Array + buf : null + + # Byte position of read/write cursor (-1 for end). + _pos : -1 + + # Spill cache for bits smaller than a byte waiting to write. + _spill : 0 + + # Number of bits in the spill cache. + _spillen : 0 + + # Peek cache for read requests smaller than a byte. + _peek : 0 + + # Number of bits in the peek cache. + _peeklen : 0 + + + + (source='', buf=[]) -> + @buf = buf.slice() + for i til source.length + @_bufwrite source.charCodeAt i + + size: -> + @buf.length + if @_spillen then 1 else 0 + + bitsize: -> + @buf.length*8 + @_spillen + + _bufwrite: (b) -> + if @_pos is -1 + @buf.push b + else + @buf[@_pos] = b + @_pos = -1 if ++@_pos >= @buf.length + this + + # Writes bits to the stream; bits must be supplied as a number. Supplying n=0 will write one bit. + # Supplying the optional parameter length treats the bits as a field with the given length. + writebits: (n, size) -> + size = size or binlen n + bits = (@_spill << size) | n + size += @_spillen # handles _spill=0 but _spillen > 0 + while size >= 8 + size -= 8 + b = bits >> size + bits &= mask size + @_bufwrite b + @_spill = bits + @_spillen = size + this + + # Flushes any pending bits to the stream. + flush: -> + b = @_spill + if @_spillen + b <<= 8 - @_spillen + @_bufwrite b + @_spill = 0 + @_spillen = 0 + this + + # Truncates the stream to zero bits. + truncate: -> + @buf = [] + @_pos = -1 + @_spill = 0 + @_spillen = 0 + @_peek = 0 + @_peeklen = 0 + this + + # Move buffer cursor to given byte-offset. mode: 0 = absolute, 1 = relative, 2 = relative EOF + _bufseek: (n, mode=SEEK_ABSOLUTE) -> + switch mode + case 1 # relative + pos = @_pos + n + case 2 + pos = @buf.length + n + default # absolute + pos = n + @_pos = if pos >= @buf.length then -1 else Math.max 0, pos + this + + # Flushes the bit-buffer and moves to the given byte-offset. mode: 0 = absolute, 1 = relative, 2 = relative EOF + seek: (n, mode=SEEK_ABSOLUTE) -> + @flush() + @_peek = 0 + @_peeklen = 0 + @_bufseek n, mode + this + + # Returns the current position of the cursor as a *byte* offset from the start of the stream. + tell: -> + if @_pos is -1 then @buf.length else @_pos + + + _nextbyte: -> + return null if @_pos is -1 + byte = @buf[ @_pos++ ] + @_pos = -1 if @_pos >= @buf.length + byte + + + # Reads n bits from the stream. + readbits: (n) -> + return 0 if n == 0 + + size = @_peeklen + bits = @_peek + + while size < n + byte = @_nextbyte() + break unless byte? + size += 8 + bits = (bits << 8) | byte + + if size > n + @_peeklen = size - n + @_peek = bits & mask(@_peeklen) + bits >>= @_peeklen + else + @_peeklen = 0 + @_peek = 0 + + return if size then bits else null + + + # Reads the next n bits without moving the cursor. + peek: (n) -> + offset = 0 + size = @_peeklen + bits = @_peek + + while size < n + byte = @_nextbyte() + break unless byte? + offset += 1 + size += 8 + bits = (bits << 8) | byte + + if size == 0 + return null + + if size > n + bits >>= size - n + + if offset + @_bufseek -offset, SEEK_RELATIVE + bits + + + # True if there is more data to read. + hasMore: -> + @peek(1)? + + + ### XXX: Should .each(), .map(), .reduce() flush? + + # forEach of bytes + each: (fn, cxt=this) -> + @buf.forEach fn, cxt + + # map over bytes + map: (fn, cxt=this) -> + @buf.map fn, cxt + + # reduce over bytes + reduce: (fn, acc, cxt=this) -> + fn .= bind this + @buf.reduce fn, acc + + + # Returns the stream as a bytearray. + bytearray: -> + @flush().buf.slice() + + # Dumps the stream as a binary string. Unlike __index__(), bin() will not cause int overflow. + bin: (byte_sep='') -> + @flush().buf.map(bin).join(byte_sep) + + # Returns the stream as a hex string. + hex: -> + @flush().buf.map(hex).join('') + + # Returns the buffer as a number. Use this with obvious caution. Called by builtins bin(), int(), long(), etc. + number: -> + @flush() + @reduce (n, byte) -> (n << 8) | byte + + + # Dumps the stream as a string; does not flush or change cursor position. + dump: -> + @buf.map(chr).join('') + if @_spillen then chr @_spill << (8 - @_spillen) else '' + + repr: (dump_buf=true) -> + s = if dump_buf then "buf=#{@dump()}" else "len(buf)=#{@buf.length}" + return "BitString(#s, + spill[#{@_spillen}]=#{bin @_spill}, + tell=#{@tell()}, + peek[#{@_peeklen}]=#{bin @_peek}) + " + + # Dumps the stream as a string; flushes the bit-buffer but leaves cursor position unchanged. + toString: -> + @flush().dump() + + +exports = module.exports = BitString + +exports.SEEK_ABSOLUTE = SEEK_ABSOLUTE +exports.SEEK_RELATIVE = SEEK_RELATIVE +exports.SEEK_FROM_EOF = SEEK_FROM_EOF diff --git a/lib/util/crc.co b/lib/util/crc.co new file mode 100644 index 0000000..056b090 --- /dev/null +++ b/lib/util/crc.co @@ -0,0 +1,58 @@ + +crc32 = exports.crc32 = (s, last_crc=0) -> + s = utf8Encode s + crc = last_crc ^ (-1) + for i til s.length + y = (crc ^ s.charCodeAt i) & 0xFF + x = "0x" + TABLE.substr y*9, 8 + crc = (crc >>> 8) ^ x + crc ^ (-1) + + +utf8Encode = exports.utf8Encode = (s) -> + s = s.replace /\r\n/g, '\n' + u = '' + for n til s.length + c = s.charCodeAt n + if c < 128 + u += String.fromCharCode c + else if 127 < c < 2048 + u += String.fromCharCode (c >> 6) | 192 + u += String.fromCharCode (c & 63) | 128 + else + u += String.fromCharCode (c >> 12) | 224 + u += String.fromCharCode ((c >> 6) & 63) | 128 + u += String.fromCharCode (c & 63) | 128 + u + + +# static precompiled hashes +TABLE = ''' + 00000000 77073096 EE0E612C 990951BA 076DC419 706AF48F E963A535 9E6495A3 0EDB8832 79DCB8A4 + E0D5E91E 97D2D988 09B64C2B 7EB17CBD E7B82D07 90BF1D91 1DB71064 6AB020F2 F3B97148 84BE41DE + 1ADAD47D 6DDDE4EB F4D4B551 83D385C7 136C9856 646BA8C0 FD62F97A 8A65C9EC 14015C4F 63066CD9 + FA0F3D63 8D080DF5 3B6E20C8 4C69105E D56041E4 A2677172 3C03E4D1 4B04D447 D20D85FD A50AB56B + 35B5A8FA 42B2986C DBBBC9D6 ACBCF940 32D86CE3 45DF5C75 DCD60DCF ABD13D59 26D930AC 51DE003A + C8D75180 BFD06116 21B4F4B5 56B3C423 CFBA9599 B8BDA50F 2802B89E 5F058808 C60CD9B2 B10BE924 + 2F6F7C87 58684C11 C1611DAB B6662D3D 76DC4190 01DB7106 98D220BC EFD5102A 71B18589 06B6B51F + 9FBFE4A5 E8B8D433 7807C9A2 0F00F934 9609A88E E10E9818 7F6A0DBB 086D3D2D 91646C97 E6635C01 + 6B6B51F4 1C6C6162 856530D8 F262004E 6C0695ED 1B01A57B 8208F4C1 F50FC457 65B0D9C6 12B7E950 + 8BBEB8EA FCB9887C 62DD1DDF 15DA2D49 8CD37CF3 FBD44C65 4DB26158 3AB551CE A3BC0074 D4BB30E2 + 4ADFA541 3DD895D7 A4D1C46D D3D6F4FB 4369E96A 346ED9FC AD678846 DA60B8D0 44042D73 33031DE5 + AA0A4C5F DD0D7CC9 5005713C 270241AA BE0B1010 C90C2086 5768B525 206F85B3 B966D409 CE61E49F + 5EDEF90E 29D9C998 B0D09822 C7D7A8B4 59B33D17 2EB40D81 B7BD5C3B C0BA6CAD EDB88320 9ABFB3B6 + 03B6E20C 74B1D29A EAD54739 9DD277AF 04DB2615 73DC1683 E3630B12 94643B84 0D6D6A3E 7A6A5AA8 + E40ECF0B 9309FF9D 0A00AE27 7D079EB1 F00F9344 8708A3D2 1E01F268 6906C2FE F762575D 806567CB + 196C3671 6E6B06E7 FED41B76 89D32BE0 10DA7A5A 67DD4ACC F9B9DF6F 8EBEEFF9 17B7BE43 60B08ED5 + D6D6A3E8 A1D1937E 38D8C2C4 4FDFF252 D1BB67F1 A6BC5767 3FB506DD 48B2364B D80D2BDA AF0A1B4C + 36034AF6 41047A60 DF60EFC3 A867DF55 316E8EEF 4669BE79 CB61B38C BC66831A 256FD2A0 5268E236 + CC0C7795 BB0B4703 220216B9 5505262F C5BA3BBE B2BD0B28 2BB45A92 5CB36A04 C2D7FFA7 B5D0CF31 + 2CD99E8B 5BDEAE1D 9B64C2B0 EC63F226 756AA39C 026D930A 9C0906A9 EB0E363F 72076785 05005713 + 95BF4A82 E2B87A14 7BB12BAE 0CB61B38 92D28E9B E5D5BE0D 7CDCEFB7 0BDBDF21 86D3D2D4 F1D4E242 + 68DDB3F8 1FDA836E 81BE16CD F6B9265B 6FB077E1 18B74777 88085AE6 FF0F6A70 66063BCA 11010B5C + 8F659EFF F862AE69 616BFFD3 166CCF45 A00AE278 D70DD2EE 4E048354 3903B3C2 A7672661 D06016F7 + 4969474D 3E6E77DB AED16A4A D9D65ADC 40DF0B66 37D83BF0 A9BCAE53 DEBB9EC5 47B2CF7F 30B5FFE9 + BDBDF21C CABAC28A 53B39330 24B4A3A6 BAD03605 CDD70693 54DE5729 23D967BF B3667A2E C4614AB8 + 5D681B02 2A6F2B94 B40BBE37 C30C8EA1 5A05DF1B 2D02EF8D +''' + diff --git a/lib/util/hashset.co b/lib/util/hashset.co new file mode 100644 index 0000000..0c99bef --- /dev/null +++ b/lib/util/hashset.co @@ -0,0 +1,418 @@ +_ = require 'underscore' + + +/** + * A Set class, implemented using the `__id__` property on non-primitive objects it is passed. + * Arrays are hashed based on their contents. If an object lacks `__id__`, an exception will be + * thrown. This class does not keep values in sorted order. + * + * Underscore provides an easy way to generate unique IDs with the (surprise!) `_.uniqueId()` + * function. + * @see http://documentcloud.github.com/underscore/#uniqueId + * + * @class + */ +class HashSet + /** + * Objects by Id. + * @private + */ + _byId : {} + + /** + * Set contents. + * @private + */ + _o : [] + + /** + * Number of elements in the set. + * @property {Number} + */ + length : 0 + + + /** + * Accepts any number of collections to be added to the set. + * @constructor + */ + -> + @_byId = {} + @_o = [] + @update ...arguments if arguments.length + + + + /** + * Determine unique identifier for the given value. + * @private + * @returns {String} Id for this value. + */ + _getIdSafe : (v) -> + t = typeof v + + switch t + case 'undefined' + return 'u' + case 'boolean' 'string' 'number' + return "#{t.charAt 0}:#v" + if v is null + return 'n' + if '__id__' in v + return 'o:' + v.__id__ + if _.isArray v + return 'a:' + v.map @_getIdSafe, this .join ',' + + /** + * Determine unique identifier for the given value, throwing an exception otherwise. + * @private + * @returns {String} Id for this value. + */ + _getId : (v) -> + id = @_getIdSafe v + unless id? + throw new Error "HashSet elements must be hashable (#v)" + id + + + + /** + * Aliases: HashSet#has + * @param {Any} v Value to test. + * @returns {Boolean} Whether HashSet contains value. + */ + contains : (v) -> + @_getIdSafe(v) in @_byId + + + /** + * @private + * @returns {this} + */ + _addOne : (v) -> + id = @_getId v + unless id in @_byId + @_byId[id] = v + @_o.push(v) + @length = @_o.length + this + + + /** + * Add values to the HashSet. + * Aliases: HashSet#push HashSet#unshift + * @param {Any} values... Values to add. + * @returns {this} + */ + add : (...values) -> + _.each arguments, @_addOne, this + this + + /** + * @private + * @returns {this} + */ + _removeOne : (v) -> + id = @_getId v + if id in @_byId + delete @_byId[id] + @_o.splice @_o.indexOf(v), 1 + @length = @_o.length + this + + + /** + * Remove values from the HashSet. + * Aliases: HashSet#without + * @param {Any} values... Values to remove. + * @returns {this} + */ + remove : (...values) -> + _.each arguments, @_removeOne, this + this + + + /** + * Update this HashSet (in-place) with other collections. + * Aliases: HashSet#extend HashSet#concat + * @param {Array|Object} it... Collection to add. + * @returns {this} + */ + update : (vs) -> + _.each arguments, ~> _.each it, @_addOne, this + this + + + /** + * Remove and return an element from the set. + * Aliases: HashSet#shift + * @returns {Any} An element from the set. + */ + pop : -> + return unless @_o.length + v = @_o.shift() + id = @_getIdSafe v + delete @_byId[id] + return v + + + /** + * Returns but does not remove the an element from the set. + * @returns {Any} An element from the set. + */ + element : -> + @_o[0] + + + /** + * Clones the set, returning a new object. + * @returns {HashSet} + */ + clone : -> + new HashSet @_o + + + /** + * Removes all elements from the set. + * Aliases: HashSet#empty + * @returns {this} + */ + clear: -> + @_byId = {} + @_o = [] + @length = 0 + this + + + + ### Collection Operations + + /** + * Transforms the collection into a single value, front-to-back. + * Aliases: HashSet#inject HashSet#fold HashSet#foldl HashSet#foldr + * @param {Function} fn Reducer function. + * @param {Any} [acc] Starting accumulator value. + * @param {Object} [cxt=this] Context; defaults to this HashSet. + * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/reduce + * @returns {Any} + */ + reduce: (fn, acc, cxt) -> + _.reduce @_o, fn, acc, cxt or this + + /** + * Applies a function to each element. + * Aliases: HashSet#each + * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/forEach + * @returns {this} + */ + forEach: (fn, cxt) -> + _.forEach @_o, fn, cxt or this + this + + /** + * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/map + * @return {HashSet} A new HashSet of elements produced by applying the transform across each element. + */ + map: (fn, cxt) -> + new HashSet _.map @_o, fn, cxt or this + + + /** + * Aliases: HashSet#select + * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/filter + * @return {HashSet} A new HashSet of only the elements passing the filter. + */ + filter: (fn, cxt) -> + new HashSet _.filter @_o, fn, cxt or this + + /** + * Like `HashSet.filter()`, but instead keeps values for which the filter returns false. + * @see HashSet#filter + * @return {HashSet} A new HashSet of only the elements for which the filter returns false. + */ + reject: (fn, cxt) -> + new HashSet _.reject @_o, fn, cxt or this + + + /** + * Aliases: HashSet#any + * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/some + * @return {Boolean} + */ + some: (fn, cxt) -> + _.some @_o, fn, cxt or this + + /** + * Aliases: HashSet#all + * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/every + * @return {Boolean} + */ + every: (fn, cxt) -> + _.every @_o, fn, cxt or this + + + /** + * Iterates through the HashSet, returning the first value for which `fn` returns truth-y. + * Aliases: HashSet#detect + * @returns {Any} + */ + find: (fn, cxt) -> + _.find @_o, fn, cxt or this + + + /** + * @returns {Array} List of all values at property `prop`. + */ + pluck : (prop) -> + _.pluck @_o, prop + + + /** + * Invokes the named method on each element in the set, returning a list of the results. + * @param {String} methodName Name of the method on each element to call. + * @param {Any...} [args...] Optional arguments to call pass to method call. + * @returns {Array} List of results. + */ + invoke : (methodName) -> + _.invoke @_o, ...arguments + + + /** + * @returns {Array} List of the unique identifiers for each element of the set. + */ + keys : -> + _.keys @_byId + + /** + * Converts this HashSet to an Array. + * Aliases: HashSet#toArray + * @returns {Array} + */ + values : -> + @_o.slice() + + + + ### Comparators and HashSet Operations + + /** + * Tests if `a` is a Collection and has all elements in common with the set. + * Sets are equal if and only if their intersection has the same size as both sets. + * @param {Collection} a + * @returns {Boolean} + */ + equals : (a) -> + return false unless a + L = @_o.length + return L is a.length and L is @intersect(a).length + + + /** + * Tests if the set has no elements in common with `a`. + * Sets are disjoint if and only if their intersection is the empty set. + * @param {Collection} a + * @returns {Boolean} + */ + isDisjoint : (a) -> + return true unless a + return not _.some a, @contains, this + + + /** + * Test whether every element in the set is in `a`. + * @param {Collection} a + * @returns {Boolean} + */ + isSubset : (a) -> + return false unless a + A = _ if _.isArray a then a else _.values a + @every A.contains, A + + + /** + * Test whether every element in `a` is in the set. + * @param {Array|Object} a + * @returns {Boolean} + */ + isSuperset : (a) -> + return false unless a + _.every a, @contains, this + + + /** + * HashSet Intersection (A ^ B) + * Intersects this YArray with another collection, returning a new YArray. + * The membership test uses _(a).contains(), so it is possible to intersect collections of different types. + * For YArray and YObject, .contains() uses strict equality (is) via .indexOf(). + * + * @param {Array|Object} a Comparison collection. + * @returns {HashSet} A new YArray of all elements of {this} found in the supplied collection. + * + * @example + * foo = /foo/ + * A = [foo, 'A', 1, 2, 3, 'C', /foo/] + * B = [foo, 'B', 3, 'A', 1, /foo/] + * ins = _(A).intersect(B) + * ins.toString() is "HashSet([/foo/,A,1,3])"; # true + * ins.get(0) is foo; # true + */ + intersect : (a) -> + new HashSet _.intersect @_o, _.map arguments, _.values + + + /** + * HashSet Union (A v B) + * Aliases: HashSet#extend HashSet#concat + * @param {Array|Object} a Other collection(s). + * @returns {HashSet} A new HashSet of all elements of both collections, without duplicates. + */ + union : (a) -> + _.reduce arguments, ((out, it) -> out.update it), @clone() + + + /** + * HashSet Difference (A - B) + * @param {Array|Object} a Comparison collection(s). + * @returns {HashSet} A new HashSet of only elements of this HashSet not in supplied collection(s). + */ + difference : (a) -> + new HashSet _.difference @_o, _.map arguments, _.values + + + /** + * Symmetric Difference (A - B) v (B - A) + * @returns {HashSet} + */ + xor : (a) -> + a = _.values a + @difference a .union _.difference a, @_o + + + toString : -> + "HashSet([#{@_o}])" + + + +### Aliases + +pt = HashSet:: + +pt.push = pt.unshift = pt.add +pt.shift = pt.pop +pt.without = pt.remove +pt.empty = pt.clear +pt.has = pt.include = pt.contains + +pt.fold = pt.foldl = pt.foldr = pt.inject = pt.reduce +pt.each = pt.forEach +pt.select = pt.filter +pt.all = pt.every +pt.any = pt.some + +pt.detect = pt.find +pt.toArray = pt.values +pt.extend = pt.concat = pt.union + + +exports = module.exports = HashSet + diff --git a/lib/util/index.co b/lib/util/index.co new file mode 100644 index 0000000..30d12d9 --- /dev/null +++ b/lib/util/index.co @@ -0,0 +1,18 @@ +_ = require 'kraken/underscore' + +root = do -> this +root.console or= _ <[ log info warn error dir table group groupCollapsed groupEnd ]> .synthesize -> [it, nop] + +root.jQuery?.fn.invoke = (method, ...args) -> + for el, idx of this + el = jQuery(el) + el[method] ...args + +op = require 'kraken/util/op' +# HashSet = require 'kraken/util/hashset' +# BitString = require 'kraken/util/bitstring' +# {crc32} = require 'kraken/util/crc' + + +exports import { root, _, op, } +# exports import { root, _, op, HashSet, BitString, crc32, } diff --git a/lib/util/op.co b/lib/util/op.co new file mode 100644 index 0000000..83a75bc --- /dev/null +++ b/lib/util/op.co @@ -0,0 +1,122 @@ + +FALSEY = /^\s*(?:no|off|false)\s*$/i +parseBool = (s) -> + i = parseInt(s or 0) + !! if isNaN(i) then not FALSEY.test(s) else i + +module.exports = op = + + I : (x) -> x + K : (k) -> -> k + nop : -> + kThis : -> this + kObject : -> {} + kArray : -> [] + + # values + val : (def,o) -> o ? def + ok : (o) -> o? + + first : (a) -> a + second : (_,a) -> a + nth : (n) -> + switch n + case 0 then op.first + case 1 then op.second + default -> arguments[n] + + flip : (fn) -> + (a, b) -> + arguments[0] = b + arguments[1] = a + fn.apply this, arguments + + # reduce-ordered values & accessors + khas : (k,o) -> k in o + kget : (k,o) -> o[k] + defkget : (def,k,o) -> if k in o then o[k] else def + thisget : (k) -> this[k] + vkset : (o,v,k) -> o[k] = v if o and k?; o + + # curry-ordered values & accessors + has : (o,k) -> k in o + get : (o,k) -> o[k] + getdef : (o,k,def) -> if k in o then o[k] else def + kvset : (o,k,v) -> o[k] = v if o and k?; o + thiskvset : (k,v) -> @[k] = v if k?; this + + prop : (k) -> (o) -> o[k] + method : (name, ...args) -> + (obj, ..._args) -> + obj[name] ...args.concat(_args) if obj?[name] + isK : (k) -> (v) -> v is k + + # type coercion (w/ limited parameters for mapping) + parseBool : parseBool + toBool : (v) -> !! v + toInt : (v) -> parseInt v + toFloat : (v) -> parseFloat v + toStr : (v) -> String v + + # comparison + cmp : (x,y) -> if x < y then -1 else (if x > y then 1 else 0) + eq : (x,y) -> x == y + ne : (x,y) -> x != y + gt : (x,y) -> x > y + ge : (x,y) -> x >= y + lt : (x,y) -> x < y + le : (x,y) -> x <= y + + # math + add : (x,y) -> x + y + sub : (x,y) -> x - y + mul : (x,y) -> x * y + div : (x,y) -> x / y + flrdiv : (x,y) -> Math.floor(x / y) + mod : (x,y) -> x % y + neg : (x) -> -x + log2 : (n) -> Math.log n / Math.LN2 + + + # logic + is : (x,y) -> x is y + isnt : (x,y) -> x is not y + and : (x,y) -> x and y + or : (x,y) -> x or y + not : (x) -> not x + + # bitwise + bitnot : (x) -> ~x + bitand : (x,y) -> x & y + bitor : (x,y) -> x | y + bitxor : (x,y) -> x ^ y + lshift : (x,y) -> x << y + rshift : (x,y) -> x >> y + # zrshift : (x,y) -> x >>> y + + # binary + + # Binary representation of the number. + bin : (n) -> + do + s = (if n % 2 then '1' else '0') + (s or '') + n >>= 1 + while n + s + + # Number of bits needed to represent the absolute value of n. + binlen : (n) -> + bin Math.abs n .length + + # Returns a run of 1s of size n. + mask : (n) -> + (1 << n) - 1 + + # strings + chr : -> String.fromCharCode it + ord : -> String(it).charCodeAt 0 + encode : -> it and $ "
#it
" .html().replace /"/g, '"' + decode : -> it and $ "
#it
" .text() + + + diff --git a/www/modules.yaml b/www/modules.yaml index 1027fa8..618dc36 100644 --- a/www/modules.yaml +++ b/www/modules.yaml @@ -28,8 +28,11 @@ all: - underscore.array - underscore.object - index - # - scaffold - # - graph + - util: + - op + - index + - scaffold + - graph # - suffix: .js # paths: