diff --git a/docs/API.md b/docs/API.md index 3069ff7b..cd15d330 100644 --- a/docs/API.md +++ b/docs/API.md @@ -32,19 +32,22 @@ This section of the Cyclone API is based on the [R7RS Scheme Specific Cyclone supports the following [Scheme Requests for Implementation (SRFI)](http://srfi.schemers.org/) libraries. Detailed information is available in the linked SRFI page as well as the provided Cyclone API: -- [`srfi 1`](api/srfi/1.md) - [List Library](http://srfi.schemers.org/srfi-1/srfi-1.html) +- [`srfi 1`](api/srfi/1.md) - [List library](http://srfi.schemers.org/srfi-1/srfi-1.html) - [`srfi 2`](api/srfi/2.md) - [`and-let*`](http://srfi.schemers.org/srfi-2/srfi-2.html) - [`srfi 8`](api/srfi/8.md) - [`receive`: Binding to multiple values](http://srfi.schemers.org/srfi-8/srfi-8.html) - Included as part of `scheme base`. - [`srfi 18`](api/srfi/18.md) - [Multithreading support](http://srfi.schemers.org/srfi-18/srfi-18.html) - [`srfi 27`](api/srfi/27.md) - [Sources of random bits](http://srfi.schemers.org/srfi-27/srfi-27.html) +- [`srfi 28`](api/srfi/28.md) - [Basic format strings](http://srfi.schemers.org/srfi-28/srfi-28.html) +- [`srfi 60`](api/srfi/60.md) - [Integers as bits](http://srfi.schemers.org/srfi-60/srfi-60.html) - [`srfi 69`](api/srfi/69.md) - [Basic hash tables](http://srfi.schemers.org/srfi-69/srfi-69.html) - [`srfi 106`](api/srfi/106.md) - [Basic socket interface](http://srfi.schemers.org/srfi-106/srfi-106.html) - [`srfi 111`](api/srfi/111.md) - [Boxes](http://srfi.schemers.org/srfi-111/srfi-111.html) - [`srfi 113`](api/srfi/113.md) - [Sets and bags](http://srfi.schemers.org/srfi-113/srfi-113.html) - [`srfi 117`](api/srfi/117.md) - [Mutable queues](http://srfi.schemers.org/srfi-117/srfi-117.html) +- [`srfi 121`](api/srfi/121.md) - [Generators](http://srfi.schemers.org/srfi-121/srfi-121.html) - [`srfi 128`](api/srfi/128.md) - [Comparators](http://srfi.schemers.org/srfi-128/srfi-128.html) -- [`srfi 132`](api/srfi/132.md) - [Sort Libraries](http://srfi.schemers.org/srfi-132/srfi-132.html) -- [`srfi 133`](api/srfi/133.md) - [Vector Library (R7RS-compatible)](http://srfi.schemers.org/srfi-133/srfi-133.html) +- [`srfi 132`](api/srfi/132.md) - [Sort libraries](http://srfi.schemers.org/srfi-132/srfi-132.html) +- [`srfi 133`](api/srfi/133.md) - [Vector library (R7RS-compatible)](http://srfi.schemers.org/srfi-133/srfi-133.html) # Cyclone Libraries diff --git a/docs/api/srfi/121.md b/docs/api/srfi/121.md new file mode 100644 index 00000000..e1843743 --- /dev/null +++ b/docs/api/srfi/121.md @@ -0,0 +1,458 @@ +# SRFI 121 - Generators + +Defines utility procedures that create, transform and consume generators. A +'generator' is a procedure with no arguments (a 'thunk') that works as a source +of values. Every time a generator is called, it yields a value. + +Generators may be finite or infinite; a finite generator returns an end-of-file +object to indicate that it is exhausted (has no more values to give). For +example, ``read-char``, ``read-line`` and ``read`` are generators that produce +characters, lines and objects from the current input port. + +This library is designed to provide lightweight laziness. + +See the [SRFI document][1] for more information. + +## Definitions + +Generators can be divided into two classes: *finite* and *infinite*. Both kinds +of generator can be invoked an indefinite number of times. After a finite +generator has produced all of its values, it will return an end-of-file object +for all subsequent calls. A generator is said to be *exhausted* if calling it +will return an end-of-file object. By definition, an infinite generator can +never be exhausted. + +A generator is said to be in an *undefined state* if it cannot be determined how +many values it has produced. This arises because it is impossible to tell by +inspection whether a generator is exhausted or not. For example, +``(generator-fold + 0 (generator 1 2 3) (generator 1 2))`` will compute 0 + 1 + +1 + 2 + 2 = 6, at which time the second generator will be exhausted. If the +first generator is invoked, however, it may return either 3 or an end-of-file +object, depending on whether the implementation of ``generator-fold`` invoked it +or not. Therefore, the first generator is said to be in an undefined state. + +Functions provided under [generator operations](#generator-operations) do not +consume elements from their input generators. In general, they produce finite +generators if their inputs are finite. + +Functions provided udner [consuming generated +values](#consuming-generated-values) consume all values from any generator +passed to them, and will not return if any of their arguments are infinite. + +## Generator constructors +[`generator`](#generator) +[`make-iota-generator`](#make-iota-generator) +[`make-range-generator`](#make-range-generator) +[`make-coroutine-generator`](#make-coroutine-generator) +[`list->generator'](#list-generator) +[`vector->generator'](#vector-generator) +[`reverse-vector->generator'](#reverse-vector-generator) +[`string->generator`](#string-generator) +[`bytevector->generator`](#bytevector-generator) +[`make-for-each-generator`](#make-for-each-generator) +[`make-unfold-generator`](#make-unfold-generator) + +## Generator operations +[`gcons*`](#gcons) +[`gappend`](#gappend) +[`gcombine`](#gcombine) +[`gfilter`](#gfilter) +[`gremove`](#gremove) +[`gtake`](#gtake) +[`gdrop`](#gdrop) +[`gtake-while`](#gtake-while) +[`gdrop-while`](#gdrop-while) +[`gdelete`](#gdelete) +[`gdelete-neighbor-dups`](#gdelete-neighbor-dups) +[`gindex`](#gindex) +[`gselect`](#gselect) + +## Consuming generated values +[`generator->list`](#generator-list) +[`generator->reverse-list`](#generator-reverse-list) +[`generator->vector`](#generator-vector) +[`generator->vector!`](#generator-vector!) +[`generator->string`](#generator-string) +[`generator-fold`](#generator-fold) +[`generator-for-each`](#generator-for-each) +[`generator-find`](#generator-find) +[`generator-count`](#generator-count) +[`generator-any`](#generator-any) +[`generator-every`](#generator-every) +[`generator-unfold`](#generator-unfold) + +# generator + + (generator arg ...) + +Returns a generator which produces each of this function's arguments in turn. +When given no arguments, returns an empty generator which provides no values. + +# make-iota-generator + + (make-iota-generator count) + (make-iota-generator count start) + (make-iota-generator count start step) + +Returns a finite generator which produces a sequence of ``count`` numbers. The +sequence begins with ``start`` (default 0) and increases by ``step`` (default +1). If both ``start`` and ``step`` are exact, the generator produces exact +values; otherwise, it produces inexact ones. The exactness of ``count`` does not +affect the exactness of results. + +Example: ``(generator->list (make-iota-generator 3 8))`` => (8 9 10)`` + +# make-range-generator + + (make-range-generator start) + (make-range-generator start end) + (make-range-generator start end step) + +Returns a generator which produces a sequence of numbers. The sequence begins +with ``start``, increases by ``step`` (default 1), and continues while the +number is less than ``end``, or forever if ``end`` is not provided. If both +``start`` and ``step`` are exact, the generator produces exact values; +otherwise, it produces inexact ones. The exactness of ``end`` does not affect +the exactness of the results. + +Example: ``(generator->list (make-range-generator 3) 4) => (3 4 5 6)`` + +# make-coroutine-generator + + (make-coroutine-generator proc) + +Creates a generator from a coroutine. The ``proc`` argument should be a +procedure that takes a single argument ``yield``. When called, +``make-coroutine-generator`` immediately returns a generator ``g``. When ``g`` +is called, ``proc`` runs until it calls ``yield``. Calling ``yield`` causes the +execution of ``proc`` to be suspended, and ``g`` returns the value passed to +``yield``. + +Whether ``g`` is finite or infinite depends on the behaviour of ``proc``: if +``proc`` returns, it is the end of the sequence, and ``g`` will return an +end-of-file object from then on. The return value of ``proc`` is ignored. + +# list->generator + + (list->generator lis) + +Returns a generator that produces each element of the list ``lis`` in turn. +Mutating ``lis`` will affect the results of the generator. + +``list->generator`` and ``generator->list`` (when given no arguments) are +inverses up to ``equal?``; thus, for any list ``x``, +``(equal? x (generator->list (list->generator x))) => #t``. + +# vector->generator + + (vector->generator vec) + (vector->generator vec start) + (vector->generator vec start end) + +Returns a generator that produces elements of ``vec``, in turn, from the index +``start`` (inclusive, default 0) to ``end`` (exclusive, default +``(vector-length vec)``). Mutating ``vec`` will affect the results of the +generator. + +When given no arguments, ``vector->generator`` and ``generator->vector`` are +inverses up to ``equal?``; thus, for any vector ``x``, ``(equal? x +(generator->vector (vector->generator x))) => #t``. + +# reverse-vector->generator + + (reverse-vector->generator vec) + (reverse-vector->generator vec start) + (reverse-vector->generator vec start end) + +Returns a generator that produces elements of ``vec``, in turn, from ``end`` +(exclusive, default ``(vector-length vec)``) to ``start`` (inclusive, default +0), in reverse order of indices. Mutating ``vec`` will affect the results of the +generator. + +# string->generator + + (string->generator str) + (string->generator str start) + (string->generator str start end) + +Returns a generator that produces characters of ``str``, in turn, from ``start`` +(inclusive, default 0) to ``end`` (exclusive, default ``(string-length str)``). +Mutating ``str`` will affect the results of the generator. + +When given no arguments, ``string->generator`` and ``generator->string`` are +inverses up to ``string=?``; thus, for any string ``s``, ``(string=? s +(generator->string (string->generator s))) => #t``. + +# bytevector->generator + + (bytevector->generator bv) + (bytevector->generator bv start) + (bytevector->generator bv start end) + +Returns a generator that produces bytes of ``bv``, in turn, from ``start`` +(inclusive, default 0) to ``end`` (exclusive, default ``(bytevector-length +bv)``). Mutating ``bv`` will affect the results of the generator. + +# make-for-each-generator + + (make-for-each-generator for-each obj) + +Constructs a generator over any collection ``obj``, using a ``for-each`` +procedure appropriate to ``obj``. This must be a procedure that, when called as +``(for-each proc obj)`` calls ``proc`` on each element of ``obj``. Examples of +such procedures are ``for-each``, ``string-for-each`` and ``vector-for-each``. +The value returned by ``for-each`` is ignored. The generator is finite if the +collection is finite. + +``obj`` need not be a conventional one (such as a string, list, etc), as long as +``for-each`` can invoke a procedure on everything that counts as a member. + +# make-unfold-generator + + (make-unfold-generator stop? mapper successor seed) + +A generator similar to [SRFI 1][2]'s ``unfold``. + +The ``stop?`` predicate takes a seed value and determines whether to stop. The +``mapper`` procedure calculates a value to be returned by the generator from a +seed value. The ``successor`` procedure calculates the next seed value from +the current seed value. + +For each call of the resulting generator, ``stop?`` is called with the current +seed value. If it returns true, then the generator returns an end-of-file +object. Otherwise, it applies ``mapper`` to the current seed value to get the +value to return, and uses ``successor`` to update the seed value. + +The generator is finite unless ``stop?`` is a constant function returning +``#f``. + +# gcons\* + + (gcons\* item ... gen) + +Returns a generator that adds ``item ...`` in front of ``gen``. Once each of +``item ...`` has been produced, the generator is guaranteed to tail-call +``gen``. + +# gappend + + (gappend gen ...) + +Returns a generator that yields the items from the first argument generator, and +once it is exhausted, the second generator, and so forth. + +If any of the argument generators are infinite, subsequent argument generators +will never be asked to produce any values. + +# gcombine + + (gcombine proc seed gen gen2 ...) + +Returns a generator for mapping with state. It produces a sequence of sub-folds +over ``proc``. + +The ``proc`` argument is a procedure that takes as many arguments as there are +argument generators, plus one. It is called as ``(proc v1 v2 ... seed)``, where +``v1 v2 ...`` are the values produced by the argument generators, and ``seed`` +is the current seed value. It must return two values: the produced value and the +next seed. The generator is exhausted when any of its argument generators are +exhausted, at which time, the remaining argument generators are in an undefined +state. + +# gfilter + + (gfilter pred gen) + +Returns a generator that produces items from ``gen``, except those for which +``pred`` would return ``#f``. + +# gremove + + (gremove pred gen) + +Equivalent to ``(gfilter (lambda (x) (not (pred x))) gen)``. + +# gtake + + (gtake gen k) + (gtake gen k padding) + +A generator analogue to [SRFI 1][2]'s ``take``. Returns a generator that +produces (at most) the first ``k`` items of ``gen``. If ``gen`` is exhausted +before it can produce ``k`` items, the rest will be made up by producing the +``padding`` value. + +# gdrop + + (gdrop gen k) + +A generator analogue to [SRFI 1][2]'s ``drop``. Returns a generator that +skips the first (at most) ``k`` items of ``gen``, then produces the rest. If +``k`` is greater than, or equal to, the total number of items ``gen`` could +produce, an empty generator is produced instead. + +# gtake-while + + (gtake-while pred gen) + +A generator analogue to [SRFI 1][2]'s ``take-while``. Returns a generator that +produces values from ``gen`` until ``pred`` returns ``#f`` on a value. + +# gdrop-while + + (gdrop-while pred gen) + +A generator analogue to [SRFI 1][2]'s ``drop-while``. Returns a generator that +discards values from ``gen`` until ``pred`` returns ``#t`` for a value, and then +produces values from ``gen``. + +# gdelete + + (gdelete item gen) + (gdelete item gen =) + +Returns a generator which produces the same items as ``gen``, except any items +that are the same as ``item`` up to ``=``, which defaults to ``equal?``. ``=`` +is passed exactly two arguments, one of which is the value produced by ``gen``. + +# gdelete-neighbor-dups + + (gdelete-neighbor-dups gen) + (gdelete-neighbor-dups gen =) + +Returns a generator which produces the same items as ``gen``, except any items +that are the same as the preceding items up to ``=``, which defaults to +``equal?``. ``=`` is passed exactly two arguments; the first of which is +produced by ``gen`` before the second. + +# gindex + + (gindex value-gen index-gen) + +Returns a generator that produces elements of ``value-gen`` specified by the +indices (non-negative exact integers) produced by ``index-gen``. It is an error +if the indices are not strictly increasing, or if any index exceeds the number +of elements produced by ``value-gen``. The generator is exhausted when either of +``value-gen`` or ``index-gen`` is exhausted, at which time the other is in an +undefined state. + +# gselect + + (gselect value-gen truth-gen) + +Returns a generator that produces elements of ``value-gen`` that correspond to +the values produced by ``truth-gen``. If the current value of ``truth-gen`` is +true, the current value of ``value-gen`` is produced; otherwise, the value is +skipped. The generator is exhausted when either of ``value-gen`` or +``truth-gen`` is exhausted, at which time the other is in an undefined state. + +# generator->list + + (generator->list gen) + (generator->list gen k) + +Calls ``gen`` repeatedly to produce its values, then collects them into a list +and returns them. If ``k`` is omitted, ``gen`` will be asked to produce values +until it is exhausted; otherwise, only at most ``k``-many values will be +requested. It is an error for ``k`` to be anything other than a non-negative +integer. + +# generator->reverse-list + + (generator->reverse-list gen) + (generator->reverse-list gen k) + +As ``generator->list``, but the returned list is in reverse order. + +# generator->vector + + (generator->vector gen) + (generator->vector gen k) + +As ``generator->list``, but the returned result is a vector. + +# generator->vector! + + (generator->vector! vec at gen) + +Calls ``gen`` repeatedly to produce its values, and puts them into ``vec``, +starting at index ``at``, until ``vec`` is full or ``gen`` is exhausted. Returns +the number of elements produced from ``gen``. + +# generator->string + + (generator->string gen) + (generator->string gen k) + +Calls ``gen`` repeatedly to produce characters, and returns a newly-allocated +string of them. It is an error if ``gen`` does not produce only characters. If +``k`` is omitted, the generator will be asked to produce characters until it is +exhausted; otherwise, at most ``k`` characters will be requested. It is an error +for ``k`` to be anything other than a non-negative integer. + +# generator-fold + + (generator-fold proc seed gen1 gen2 ...) + +An analogue of [SRFI 1][2]'s ``fold`` on values produced by the generator +arguments. + +When one generator argument ``gen`` is given, for each value ``v`` produced by +``gen``, ``proc`` is called as ``(proc v r)``, where ``r`` is the current +accumulated result; the initial value of ``r`` is ``seed``, and the return value +from ``proc`` becomes the new accumulated result. When ``gen`` is exhausted, the +accumulated result at the time is returned. + +When more than one generator argument is given, ``proc`` is called on all the +values produced by all the generator arguments, followed by the current +accumulated result. The procedure returns when any of the generator arguments is +exhausted, at which time the others are in an undefined state. + +# generator-for-each + + (generator-for-each proc gen1 gen2 ...) + +A generator analogue of ``for-each`` that consumes produced values with side +effects. ``proc`` is repeatedly applied to values produced by all the generator +arguments, until any of them is exhausted. The values returned by ``proc`` are +discarded. The procedure terminates when any of the argument generators is +exhausted, at which time the others are in an undefined state. + +# generator-find + + (generator-find pred gen) + +Returns the first value produced by ``gen`` that satisfies the predicate +``pred``, or ``#f`` if no such value exists. If ``gen`` is infinite, this +procedure will not return if it cannot find an appropriate item. + +# generator-count + + (generator-count pred gen) + +Returns the number of values that gen can produce which satisfy the predicate +``pred``. This procedure will not return if ``gen`` is infinite. + +# generator-any + + (generator-any pred gen) + +Applies ``pred`` to each item produced by ``gen``. As soon as ``pred`` returns a +true value, the value is returned without consuming the rest of ``gen``. If +``gen`` is exhausted, returns ``#f``. + +# generator-every + + (generator-every pred gen) + +Equivalent to ``(not (generator-any (lambda (x) (not (pred x))) gen))``. + +# generator-unfold + + (generator-unfold gen unfold arg ...) + +Equivalent to ``(unfold eof-object? (lambda (x) x) (lambda (x) (gen)) arg +...)``, where ``unfold`` is the [SRFI 1][2] procedure of the same name. + +[1]: http://srfi.schemers.org/srfi-121/srfi-121.html +[2]: http://srfi.schemers.org/srfi-1/srfi-1.html diff --git a/docs/api/srfi/18.md b/docs/api/srfi/18.md index 28bda540..7d81b319 100644 --- a/docs/api/srfi/18.md +++ b/docs/api/srfi/18.md @@ -4,6 +4,12 @@ The `(srfi 18)` library provides multithreading support. See the [Multithreading support SRFI documentation](http://srfi.schemers.org/srfi-18/srfi-18.html) for more information. +## Limitations + +Currently, ``thread-join!`` is not provided. While this is not an essential +primitive and can be worked around, code that relies on ``thread-join!`` being +present in this implementation will fail to compile. + - [`thread?`](#thread) - [`make-thread`](#make-thread) - [`thread-name`](#thread-name) diff --git a/docs/api/srfi/28.md b/docs/api/srfi/28.md new file mode 100644 index 00000000..7ba65952 --- /dev/null +++ b/docs/api/srfi/28.md @@ -0,0 +1,47 @@ +# SRFI 28 - Basic format strings + +Specifies a method of interpreting a Scheme string which contains a number of +escape sequences, into which other data is interpolated according to the +semantics of each sequence. + +See the [SRFI document][1] for more information. + +## Limitations + +Currently, this translates newline escape sequences into LF. This may cause +issues if this is ever used on Windows (which expects CRLF instead). Given that +Cyclone does not currently support Windows, this issue should not arise in +practice. + +## Interface + +# format + + (format format-string [obj ...]) + +Processes ``format-string``, replacing any escape sequences in order with one or +more characters. These characters depend on the semantics of the escape +sequence. + +An 'escape sequence' is a two-character sequence in ``format-string``, where the +first character is a tilde ('~'). The following are all of the valid escape +codes, as well as their semantics: + +- ``~a``: The corresponding value is inserted into the string as if printed by + ``display``. +- ``~s``: The corresponding value is inserted into the string as if printed by + ``write``. +- ``~%``: A newline is inserted. +- ``~~``: A literal tilde is inserted. + +``~a`` and ``~s``, when encountered, require a corresponding Scheme value to be +present as an argument to ``format``. The values provided in ``obj ...`` are +used by the escape sequences in order. It is an error if fewer values are +provided than escape sequences which require them. ``~%`` and ``~~`` do not need +a corresponding value. + +Example: The call ``(format "This is the ~ast example: ~s~%" 1 '(foo bar 17))`` +would produce the string ``"This is the 1st example: (foo bar 17) +"`` (note the newline). + +[1]: http://srfi.schemers.org/srfi-28/srfi-28.html diff --git a/docs/api/srfi/60.md b/docs/api/srfi/60.md new file mode 100644 index 00000000..24b44ae6 --- /dev/null +++ b/docs/api/srfi/60.md @@ -0,0 +1,247 @@ +# SRFI 60 - Integers as bits + +Various operations designed to work on integers as strings of bits efficiently. + +See the [SRFI document][1] for more information. + +## Bitwise operations +[`logand`](#logand) +[`logior`](#logior) +[`logxor`](#logxor) +[`lognot`](#lognot) +[`logtest`](#logtest) +[`bitwise-and`](#bitwise-and) +[`bitwise-ior`](#bitwise-ior) +[`bitwise-xor`](#bitwise-xor) +[`bitwise-not`](#bitwise-not) +[`bitwise-if`](#bitwise-if) +[`bitwise-merge`](#bitwise-merge) +[`any-bits-set?`](#any-bits-set) + +## Integer properties +[`logcount`](#logcount) +[`log2-binary-factors`](#log2-binary-factors) +[`bit-count`](#bit-count) +[`integer-length`](#integer-length) +[`first-set-bit`](#first-set-bit) + +## Bit within word +[`logbit?`](#logbit) +[`bit-set?`](#bit-set) +[`copy-bit`](#copy-bit) + +## Field of bits +[`bit-field`](#bit-field) +[`copy-bit-field`](#copy-bit-field) +[`ash`](#ash) +[`arithmetic-shift`](#ash) +[`rotate-bit-field`](#rotate-bit-field) + +## Bits as booleans +[`integer->list`](#integer-list) +[`list->integer`](#list-integer) +[`booleans->integer`](#booleans-integer) + +# logand + + (logand n1 ...) + +Returns the integer which is the bitwise-AND of the arguments. + +Example: ``(number->string (logand #b1100 #b1010) 2) => "1000"`` + +# bitwise-and + +Synonym for ``logand``. + +# logior + + (logior n1 ...) + +Returns the integer which is the bitwise-OR of the arguments. + +Example: ``(number->string (logior #b1100 #b1010) 2) => "1110"`` + +# bitwise-ior + +Synonym for ``logior``. + +# logxor + + (logxor n1 ...) + +Returns the integer which is the bitwise-XOR of the arguments. + +Example: ``(number->string (logxor #b1100 #b1010) 2) => "110"`` + +# bitwise-xor + +Synonym for ``logxor``. + +# lognot + + (lognot n) + +Returns the integer which is the one's-complement of the argument. + +# bitwise-not + +Synonym for ``lognot``. + +# bitwise-if + + (bitwise-if mask n0 n1) + +Returns an integer composed of some bits from ``n0`` and some bits from ``n1``. +A bit of the result is taken from ``n0`` if the corresponding bit of ``mask`` is +1, and from ``n1`` otherwise. + +# bitwise-merge + +Synonym for ``bitwise-if``. + +# logtest + + (logtest j k) + +Equivalent to ``(not (zero? (logand j k)))``. + +Example: ``(logtest #b0100 #b1011) => #f`` + +# any-bits-set? + +Synonym for ``logtest``. + +# logcount + + (logcount n) + +Returns the number of bits in ``n``. If ``n`` is positive, the 1-bits in its +binary representation are counted. If negative, the 0-bits in its +two's-complement binary representation are counted. If 0, then 0 is returned. + +Example: ``(logcount #b10101010) => 4`` + +# bit-count + +Synonym for ``logcount``. + +# integer-length + + (integer-length n) + +Returns the number of bits necessary to represent ``n``. + +Example: ``(integer-length #b1011) => 4`` + +# log2-binary-factors + + (log2-binary-factors n) + +Returns the bit-index of the least-significant 1-bit in ``n``. If ``n`` contains +no 1-bits, -1 is returned. + +Example: ``(log2-binary-factors 4) => 2`` + +# first-set-bit + +Synonym for ``log2-binary-factors`` + +# logbit? + + (logbit? index n) + +Equivalent to ``(logtest (exact (expt 2 index)) n)``. + +Example: ``(logbit? 1 #b1101) => #f`` + +# bit-set? + +Synonym for ``logbit?``. + +# copy-bit + + (copy-bit index from bit) + +Returns ``from``, except in the ``index``th bit, which is 1 if ``bit`` is #t, +and 0 if ``bit`` is #f. + +Example: ``(number->string (copy-bit 2 #b1111 #f) 2) => "1011"`` + +# bit-field + + (bit-field n start end) + +Returns the integer composed of the ``start`` (inclusive) through ``end`` +(exclusive) bits of ``n``. The ``start``th bit becomes the 0th bit in the +result. + +Example: ``(number->string (bit-field #b1101101010 0 4) 2) => "1010"`` + +# copy-bit-field + + (copy-bit-field to from start end) + +Returns ``to``, except possibly in the ``start`` (inclusive) through ``end`` +(exclusive) bits, which are the same as those of ``from``. The 0th bit of +``from`` becomes the ``start``th bit of the result. + +Example: ``(number->string (copy-bit-field #b1101101010 0 0 4) 2) => +"1101100000"`` + +# ash + + (ash n count) + +Equivalent to ``(exact (floor (* n (expt 2 count))))``. + +Example: ``(number->string (ash #b1010 -1) 2) => "101"`` + +# arithmetic-shift + +Synonym for ``ash``. + +# rotate-bit-field + + (rotate-bit-field n count start end) + +Returns ``n`` with the bit-field from ``start`` to ``end`` cyclically permuted +by ``count`` bits towards high-order. + +Example: ``(number->string (rotate-bit-field #b0100 3 0 4) 2) => "10"`` + +# reverse-bit-field + + (reverse-bit-field n start end) + +Returns ``n`` with the order of bits ``start`` to ``end`` reversed. + +Example: ``(number->string (reverse-bit-field #b10100111 0 8) 2) => +"11100101")`` + +# integer->list + + (integer->list k) + + (integer->list k len) + +Returns a list of ``len`` booleans corresponding to each bit of the non-negative +integer ``k``. ``#t`` is coded for each 1; ``#f`` for each 0. ``len`` defaults +to ``(integer-length k)``. + +# list->integer + + (list->integer list) + +Returns an integer formed from the booleans in ``list``, which must consist only +of booleans. A 1 bit is coded for each ``#t``; a 0 bit for each ``#f``. +``integer->list`` and ``list->integer`` are inverses up to ``equal?``: thus, for +any ``x``, ``(equal x (integer->list (list->integer x))) => #t``. + +# booleans->integer + + (booleans->integer b1 ...) + +Equivalent to ``(list->integer (list b1 ...))``. + +[1]: http://srfi.schemers.org/srfi-60/srfi-60.html diff --git a/docs/api/srfi/69.md b/docs/api/srfi/69.md index 93ce8201..b530139a 100644 --- a/docs/api/srfi/69.md +++ b/docs/api/srfi/69.md @@ -11,6 +11,18 @@ Hash tables are widely recognised as a fundamental data structure for a wide var See the [SRFI document](http://srfi.schemers.org/srfi-69/srfi-69.html) for more information. +## Limitations + +Hash table size must be strictly less than 536,870,909. + +The default implementation of record hashing is severely suboptimal - if you +want to store records in a hash table, use a custom hashing function. + +This implementation does not distinguish ``hash`` and ``hash-by-identity``. +Additionally, symbol hashing is done by string-hashing the result of +``symbol->string`` on the symbol, making symbols identical to strings for the +purpose of hash table key performance. + ## Type constructors and predicate [`make-hash-table`](#make-hash-table) [`hash-table?`](#hash-table) diff --git a/srfi/60.scm b/srfi/60.scm index 49713776..80fe92d7 100644 --- a/srfi/60.scm +++ b/srfi/60.scm @@ -1,23 +1,32 @@ -;;; "60.scm", bit access and operations for integers for Scheme -;;; Copyright (C) 1991, 1993, 2001, 2003, 2005 Aubrey Jaffer -;;; Copyright (C) 2017 Koz Ross -; -;Permission to copy this software, to modify it, to redistribute it, -;to distribute modified versions, and to use it for any purpose is -;granted, subject to the following restrictions and understandings. -; -;1. Any copy made of this software must include this copyright notice -;in full. -; -;2. I have made no warranty or representation that the operation of -;this software will be error-free, and I am under no obligation to -;provide any services, by way of maintenance, update, or otherwise. -; -;3. In conjunction with products arising from the use of this -;material, there shall be no use of my name in any advertising, -;promotional, or sales literature without prior written consent in -;each case. - +#| + | Copyright (c) 1991, 1993, 2001, 2003, 2005 Aubrey Jaffer + | Copyright (c) 2017, Koz Ross + | + | All rights reserved. + | + | Redistribution and use in source and binary forms, with or without + | modification, are permitted provided that the following conditions are met: + | * Redistributions of source code must retain the above copyright + | notice, this list of conditions and the following disclaimer. + | * Redistributions in binary form must reproduce the above copyright + | notice, this list of conditions and the following disclaimer in the + | documentation and/or other materials provided with the distribution. + | * Neither the name of Cyclone nor the + | names of its contributors may be used to endorse or promote products + | derived from this software without specific prior written permission. + | + | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + |# + (define-c raw-logand "(void* data, int argc, closure _, object k, object x, object y)" "Cyc_check_int(data, x); @@ -99,16 +108,24 @@ (define bit-count logcount) -(define (integer-length x) - (exact (ceiling (log (+ x 1) 2)))) +(define-c integer-length + "(void* data, int argc, closure _, object k, object x)" + "Cyc_check_int(data, x); + int input = (int)unbox_number(x); + int res = 0; + while (input) { + res++; + input >>= 1; + }; + return_closcall1(data, k, obj_int2obj(res));") (define (log2-binary-factors n) - (- (integer-length (logand n (- n))) 1)) + (- (integer-length (raw-logand n (- n))) 1)) (define first-set-bit log2-binary-factors) (define (logbit? index n) - (logtest (exact (expt 2 index)) n)) + (logtest (ash 1 index) n)) (define bit-set? logbit?) @@ -126,8 +143,22 @@ (ash from start) to)) -(define (ash x y) - (exact (floor (* x (expt 2 y))))) +(define-c ash + "(void* data, int argc, closure _, object k, object x, object y)" + "Cyc_check_int(data, x); + Cyc_check_int(data,y); + int bf = (int)unbox_number(x); + int shift = (int)unbox_number(y); + if (shift > 0) { + for (int i = 0; i < shift; i++) { + bf *= 2; + } + } else { + for (int i = 0; i < abs(shift); i++) { + bf /= 2; + } + } + return_closcall1(data, k, obj_int2obj(bf))") (define arithmetic-shift ash) diff --git a/srfi/60.sld b/srfi/60.sld index 8ab61128..52f018a4 100644 --- a/srfi/60.sld +++ b/srfi/60.sld @@ -10,8 +10,8 @@ ;;;; doesn't have them yet. This will need to be modified accordingly once ;;;; this support is provided. (define-library (srfi 60) - (import (scheme base) - (scheme inexact)) + (import + (scheme base)) (export any-bits-set? arithmetic-shift ash bit-count bit-field bit-set? bitwise-and bitwise-if bitwise-ior