• Stars
    star
    144
  • Rank 255,590 (Top 6 %)
  • Language
    Common Lisp
  • License
    MIT License
  • Created about 12 years ago
  • Updated over 2 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Fast octet-vector/stream I/O for Common Lisp

fast-io

Now with static-vectors support!

(deftype octet '(unsigned-byte 8))
(deftype octet-vector '(simple-array octet (*)))

Fast-io is about improving performance to octet-vectors and octet streams (though primarily the former, while wrapping the latter). Imagine we're creating messages for the network. If we try and fill an octet-vector with 50 bytes, 50000 times, here are the results (SBCL 1.0.57):

vector-push-extend: flexi-streams: fast-io:
Time: 0.767s 2.545s 0.090s
Bytes consed: 104,778,352 274,452,768 18,373,904

(See t/benchmarks.lisp for the exact code used.)

It should be surprising that it takes a nontrivial effort to achieve relatively decent performance to octet-vectors, but probably isn't. However, fast-io provides a relatively straightforward interface for reading and writing either a stream or a vector:

;;; Write a byte or sequence, optionally to a stream:

(with-fast-output (buffer [STREAM | :vector | :static])
  (fast-write-byte BYTE buffer))

(with-fast-output (buffer [STREAM | :vector | :static])
  (fast-write-sequence OCTET-VECTOR buffer [START [END]]))

;;; Read from a vector or stream:

(with-fast-input (buffer VECTOR [STREAM])
  (fast-read-byte buffer))

(with-fast-input (buffer VECTOR [STREAM])
  (let ((vec (make-octet-vector N)))
    (fast-read-sequence vec buffer [START [END]])))

Multi-byte and Endianness

Fast-io provides a host of read and write functions for big- and little-endian reads. See the Dictionary below.

Static Vectors

You may now specify :static instead of a stream to WITH-OUTPUT-BUFFER. This returns an octet-vector created with static-vectors, which means that passing the buffered data directly to a foreign function is now that much more efficient:

(let ((data (with-fast-output (buffer :static)
              (buffer-some-data buffer))))
  (foreign-send (static-vectors:static-vector-pointer data))
  (static-vectors:free-static-vector data))

Note that the restriction for manually freeing the result remains. This avoids multiple inefficient (i.e., byte-by-byte) copies to foreign memory.

Streams

Obviously, the above API isn't built around Lisp streams, or even gray-streams. However, fast-io provides a small wrapper using trivial-gray-streams, and supports {WRITE,READ}-SEQUENCE:

(let ((stream (make-instance 'fast-io:fast-output-stream)))
  (write-sequence (fast-io:octets-from '(1 2 3 4)) stream))

Both fast-input-stream and fast-output-stream support backing a stream, much like using the plain fast-io buffers. However, using the gray-streams interface is a 3-4x as slow as using the buffers alone. Simple benchmarks show the gray-streams interface writing 1M 50-byte vectors in about 1.7s, whereas simply using buffers is about 0.8s. Consing remains similar between the two.

Dictionary

Octets

Most functions operate on or require octet-vectors, i.e.,

(deftype octet () '(unsigned-byte 8))
(deftype octet-vector '(simple-array octet (*)))

Which is exactly what is defined and exported from fast-io. Also:

  • make-octet-vector LEN
    Make an octet-vector of length LEN.
  • octets-from SEQUENCE
    Make an octet-vector from the contents of SEQUENCE.

Buffers

  • make-input-buffer &key VECTOR STREAM POS
    Create an input buffer for use with input functions. :vector specifies the vector to be read from. :stream specifies the stream to read from. :pos specifies the offset to start reading into VECTOR If both :vector and :stream is provided, the input buffer reads from the vector first, followed by the stream.

  • make-output-buffer &key OUTPUT
    Create an output buffer for use with output functions. :output specifies an output stream. If :output :static is specified, and static-vectors is supported, output will be to a static-vector.

  • finish-output-buffer BUFFER
    Finish the output and return the complete octet-vector.

  • buffer-position BUFFER
    Return the current read/write position for BUFFER.

  • with-fast-input (BUFFER VECTOR &optional STREAM (OFFSET 0)) &body body
    Create an input buffer called BUFFER, optionally reading from VECTOR, followed by reading from STREAM. If OFFSET is specified, start reading from this position in VECTOR.

  • with-fast-output (BUFFER &optional OUTPUT) &body BODY
    Create an output buffer named BUFFER, optionally writing to the stream OUTPUT. This will automatically FINISH-OUTPUT-BUFFER on BUFFER. Thus the with-fast-output form evaluates to the completed octet-vector.

Reading and Writing

  • fast-read-byte INPUT-BUFFER &optional (EOF-ERROR-P t) EOF-VALUE
    Read a byte from INPUT-BUFFER. If EOF-ERROR-P is t, reading past the end-of-file will signal CL:END-OF-FILE. Otherwise, it will return EOF-VALUE instead.
  • fast-write-byte BYTE OUTPUT-BUFFER
    Write a byte to OUTPUT-BUFFER.
  • fast-read-sequence SEQUENCE INPUT-BUFFER &optional (START 0) END
    Read from INPUT-BUFFER into SEQUENCE. Values will be written starting at position START and, if END is specified, ending at END. Otherwise values will be written until the length of the sequence, or until the input is exhausted.
  • fast-write-sequence SEQUENCE OUTPUT-BUFFER &optional (START 0) END
    Write SEQUENCE to OUTPUT-BUFFER, starting at position START in SEQUENCE. If END is specified, values will be written until END; otherwise, values will be written for the length of the sequence.

For multi-byte reads and writes requiring endianness, fast-io provides functions in the following forms:

  • write[u]{8,16,32,64,128}{-be,-le}: E.g., (write32-be VALUE BUFFER) will write the specified 32-bit value to the specified buffer with a big-endian layout. Likewise, (writeu16-le VALUE BUFFER) will write an unsigned 16-bit value in little-endian layout.
  • read[u]{8,16,32,64,128}{-be,-le}: Similarly, (read64-le BUFFER) will read a 64-bit value from the buffer with little-endian layout.

More Repositories

1

c2ffi

Clang-based FFI wrapper generator
C++
228
star
2

cl-autowrap

(c-include "file.h") => complete FFI wrapper
Python
210
star
3

ScriptL

Shell scripting made Lisp-like! Or, live-coding remote function calls for the shell.
Makefile
72
star
4

cl-cairo2

Cairo bindings for Common Lisp
Common Lisp
62
star
5

CheckL

Why write programs in Common Lisp but tests like Java? Meet CheckL!
Common Lisp
43
star
6

spatial-trees

spatial-trees is a set of dynamic index data structures for spatially-extended data.
Common Lisp
30
star
7

dynamic-mixins

Simple, dynamic class combination for CLOS.
Common Lisp
30
star
8

cl-freetype2

Common Lisp bindings for Freetype 2
Common Lisp
28
star
9

xleapmouse

LeapMotion mouse controller for Linux/X, with optional Qt GUI
C++
23
star
10

cl-interval

Intervals and interval trees for Common Lisp
Common Lisp
21
star
11

cl-xcb-xlib

CLX reimplementation on XCB/Xlib
Common Lisp
17
star
12

cmake-build.el

CMake building with multiple targets, run configurations, and interactive menu
Emacs Lisp
14
star
13

cl-gendoc

Simple modular documentation builder for with package reference generator
Common Lisp
13
star
14

defpackage-plus

DEFPACKAGE-PLUS is an *extensible* DEFPACKAGE variant with version support
Common Lisp
13
star
15

GameKernel

GameKernel is a command-driven "kernel" of game functionality. Its goal is to be a fast, portable, and language-friendly.
C++
10
star
16

c2ffi-cffi

Bridge for parsing c2ffi JSON into CFFI
Common Lisp
8
star
17

texatl

Texture atlas generation, including fonts
Common Lisp
7
star
18

buffer-buttons

Define, save, and load code-safe buttons in files for emacs
Emacs Lisp
7
star
19

ninja-sphere

Ninja Sphere ... Lisp Game Jam 2017 entry
Common Lisp
6
star
20

spell-and-dagger

Lisp Game Jam 2016 Q2 entry
Common Lisp
6
star
21

common-methods

A framework for managing method namespaces by working around generic function congruent lambda lists.
Common Lisp
5
star
22

c2ffi-ruby

Import C2FFI JSON to ruby/ffi
Ruby
5
star
23

trivial-channels

Very simple thread-safe channels with timeout
Common Lisp
5
star
24

ZMQ4L

Yet another Common Lisp ZMQ wrapper; this time for ZMQ 4.0.1, with autowrap
Common Lisp
5
star
25

cl-gamekernel

Common Lisp wrapper for GameKernel
Common Lisp
4
star
26

turipong

TuriPong .. PLTG Dec2012 challenge
Common Lisp
3
star
27

cl-named-values

Named values, VALUE protocols
Common Lisp
3
star
28

cl-observer

Trivial observer system
Common Lisp
3
star
29

consmsg

Message pool and threaded message pool, inspired by OSC
Common Lisp
3
star
30

make-util

Trivial way to generate a "util.lisp" files from your own loaded utilities.
Common Lisp
3
star
31

conspath

Regex/XPath like matching for Common Lisp lists.
Common Lisp
3
star
32

cpp-pipedream

for(auto s : "a,b,c" | split(","))
C++
3
star
33

cl-xcb-xlib-demos

Demos for XCB.CLX
Common Lisp
2
star
34

laconic

"Brevity" functions for very common operations.
Common Lisp
2
star
35

tasklist.el

Make a list of commands; pick one and run it in a dedicated frame or window
Emacs Lisp
2
star
36

archive-manager

Bash-based tar/zip/etc unified frontend
Shell
1
star
37

tileutil.js

Some handy tile processing utilities
JavaScript
1
star
38

nono

constexpr C++ nonogram game, played in source code
C++
1
star
39

util.rpav

My utilities for MAKE-UTIL
Common Lisp
1
star