packages feed

idris-0.9.13: libs/base/Data/Buffer.idr

module Data.Buffer

%default total

-- !!! TODO: Open issues:
-- 1. It may be theoretically nice to represent Buffer size as
--    Fin (2 ^ WORD_BITS) instead of Nat
-- 2. Primitives take Bits64 when really they should take the
--    equivalent of C's size_t (ideally unboxed)
-- 3. If we had access to host system information, we could reduce
--    the needed primitives by implementing the LE/BE variants on
--    top of the native variant plus a possible swab function
-- 4. Would be nice to be able to peek/append Int, Char, and Float,
--    all have fixed (though possibly implementation-dependent) widths.
--    Currently not in place due to lack of host system introspection.
-- 5. Would be nice to be able to peek/append the vector types, but
--    for now I'm only touching the C backend which AFAICT doesn't
--    support them.
-- 6. Conversion from Fin to Bits64 (which, re 2, should eventually
--    be a fixed-width implementation-dependent type) is likely
--    inefficient relative to conversion from Nat to Bits64
-- 7. We may want to have a separate type that is a product of Buffer
--    and offset rather than storing the offset in Buffer itself, which
--    would require exposing the offset argument of prim__appendBuffer

||| A contiguous chunk of n bytes
abstract
record Buffer : Nat -> Type where
  MkBuffer : ( offset : Nat ) -> ( realBuffer : prim__UnsafeBuffer ) -> Buffer n

bitsFromNat : Nat -> Bits64
bitsFromNat Z     = 0
bitsFromNat (S k) = 1 + bitsFromNat k

bitsFromFin : Fin n -> Bits64
bitsFromFin fZ     = 0
bitsFromFin (fS k) = 1 + bitsFromFin k

||| Allocate an empty Buffer. The size hint can be used to avoid
||| unnecessary reallocations and copies under the hood if the
||| approximate ultimate size of the Buffer is known. Users can assume
||| the new Buffer is word-aligned.
public
allocate : ( hint : Nat ) -> Buffer Z
allocate = MkBuffer Z . prim__allocate . bitsFromNat

||| Append count repetitions of a Buffer to another Buffer
%assert_total
public
appendBuffer : Buffer n        ->
               ( count : Nat ) ->
               Buffer m        ->
               Buffer ( n + count * m )
appendBuffer { n } { m } ( MkBuffer o1 r1 ) c ( MkBuffer o2 r2 ) =
  MkBuffer o1 $ prim__appendBuffer r1 size1 count size2 off r2
  where
    size1 : Bits64
    size1 = bitsFromNat ( n + o1 )
    size2 : Bits64
    size2 = bitsFromNat m
    count : Bits64
    count = bitsFromNat c
    off : Bits64
    off = bitsFromNat o2

||| Copy a buffer, potentially allowing the (potentially large) space it
||| pointed to to be freed
public
copy : Buffer n -> Buffer n
copy { n } = replace ( plusZeroRightNeutral n ) . appendBuffer ( allocate n ) 1

||| Create a view over a buffer
public
peekBuffer : { n : Nat } -> { offset : Nat } -> Buffer ( n + offset ) -> ( offset : Nat ) -> Buffer n
peekBuffer ( MkBuffer o r ) off = MkBuffer ( o + off ) r

peekBits : ( prim__UnsafeBuffer -> Bits64 -> a ) ->
           Buffer ( m + n )   ->
           ( offset : Fin ( S n ) ) ->
           a
peekBits prim ( MkBuffer o r ) = prim r . bitsFromNat . plus o . finToNat

appendBits : ( prim__UnsafeBuffer ->
               Bits64             ->
               Bits64             ->
               a                  ->
               prim__UnsafeBuffer ) ->
             Buffer n               ->
             ( count : Nat)         ->
             a                      ->
             Buffer ( n + count * size )
appendBits { n } prim ( MkBuffer o r ) count =
  MkBuffer o . prim r ( bitsFromNat $ n + o ) ( bitsFromNat count )


||| Read a Bits8 from a Buffer starting at offset
%assert_total
public
peekBits8 : Buffer ( 1 + n )           ->
            ( offset : Fin ( S n ) ) ->
            Bits8
peekBits8 = peekBits { m = 1 } prim__peekB8Native

||| Append count repetitions of a Bits8 to a Buffer
%assert_total
public
appendBits8 : Buffer n        ->
              ( count : Nat ) ->
              Bits8           ->
              Buffer ( n + count * 1 )
appendBits8 = appendBits prim__appendB8Native

||| Read a Bits16 in native byte order from a Buffer starting at offset
%assert_total
public
peekBits16Native : Buffer ( 2 + n )           ->
                   ( offset : Fin ( S n ) ) ->
                   Bits16
peekBits16Native = peekBits { m = 2 } prim__peekB16Native

||| Read a little-endian Bits16 from a Buffer starting at offset
%assert_total
public
peekBits16LE : Buffer ( 2 + n ) -> ( offset : Fin ( S n ) ) -> Bits16
peekBits16LE = peekBits { m = 2 } prim__peekB16LE

||| Read a big-endian Bits16 from a Buffer starting at offset
%assert_total
public
peekBits16BE : Buffer ( 2 + n ) -> ( offset : Fin ( S n ) ) -> Bits16
peekBits16BE = peekBits { m = 2 } prim__peekB16BE

||| Append count repetitions of a Bits16 in native byte order to a Buffer
%assert_total
public
appendBits16Native : Buffer n        ->
                     ( count : Nat ) ->
                     Bits16          ->
                     Buffer ( n + count * 2 )
appendBits16Native = appendBits prim__appendB16Native

||| Append count repetitions of a little-endian Bits16 to a Buffer
%assert_total
public
appendBits16LE : Buffer n        ->
                 ( count : Nat ) ->
                 Bits16          ->
                 Buffer ( n + count * 2 )
appendBits16LE = appendBits prim__appendB16LE

||| Append count repetitions of a big-endian Bits16 to a Buffer
%assert_total
public
appendBits16BE : Buffer n        ->
                 ( count : Nat ) ->
                 Bits16          ->
                 Buffer ( n + count * 2 )
appendBits16BE = appendBits prim__appendB16BE

||| Read a Bits32 in native byte order from a Buffer starting at offset
%assert_total
public
peekBits32Native : Buffer ( 4 + n )           ->
                   ( offset : Fin ( S n ) ) ->
                   Bits32
peekBits32Native = peekBits { m = 4 } prim__peekB32Native

||| Read a little-endian Bits32 from a Buffer starting at offset
%assert_total
public
peekBits32LE : Buffer ( 4 + n ) -> ( offset : Fin ( S n ) ) -> Bits32
peekBits32LE = peekBits { m = 4 } prim__peekB32LE

||| Read a big-endian Bits32 from a Buffer starting at offset
%assert_total
public
peekBits32BE : Buffer ( 4 + n ) -> ( offset : Fin ( S n ) ) -> Bits32
peekBits32BE = peekBits { m = 4 } prim__peekB32BE

||| Append count repetitions of a Bits32 in native byte order to a Buffer
%assert_total
public
appendBits32Native : Buffer n        ->
                     ( count : Nat ) ->
                     Bits32          ->
                     Buffer ( n + count * 4 )
appendBits32Native = appendBits prim__appendB32Native

||| Append count repetitions of a little-endian Bits32 to a Buffer
%assert_total
public
appendBits32LE : Buffer n        ->
                 ( count : Nat ) ->
                 Bits32          ->
                 Buffer ( n + count * 4 )
appendBits32LE = appendBits prim__appendB32LE

||| Append count repetitions of a big-endian Bits32 to a Buffer
%assert_total
public
appendBits32BE : Buffer n        ->
                 ( count : Nat ) ->
                 Bits32          ->
                 Buffer ( n + count * 4 )
appendBits32BE = appendBits prim__appendB32BE

||| Read a Bits64 in native byte order from a Buffer starting at offset
%assert_total
public
peekBits64Native : Buffer ( 8 + n )           ->
                   ( offset : Fin ( S n ) ) ->
                   Bits64
peekBits64Native = peekBits { m = 8 } prim__peekB64Native

||| Read a little-endian Bits64 from a Buffer starting at offset
%assert_total
public
peekBits64LE : Buffer ( 8 + n ) -> ( offset : Fin ( S n ) ) -> Bits64
peekBits64LE = peekBits { m = 8 } prim__peekB64LE

||| Read a big-endian Bits64 from a Buffer starting at offset
%assert_total
public
peekBits64BE : Buffer ( 8 + n ) -> ( offset : Fin ( S n ) ) -> Bits64
peekBits64BE = peekBits { m = 8 } prim__peekB64BE

||| Append count repetitions of a Bits64 in native byte order to a Buffer
%assert_total
public
appendBits64Native : Buffer n        ->
                     ( count : Nat ) ->
                     Bits64          ->
                     Buffer ( n + count * 8 )
appendBits64Native = appendBits prim__appendB64Native

||| Append count repetitions of a little-endian Bits64 to a Buffer
%assert_total
public
appendBits64LE : Buffer n        ->
                 ( count : Nat ) ->
                 Bits64          ->
                 Buffer ( n + count * 8 )
appendBits64LE = appendBits prim__appendB64LE

||| Append count repetitions of a big-endian Bits64 to a Buffer
%assert_total
public
appendBits64BE : Buffer n        ->
                 ( count : Nat ) ->
                 Bits64          ->
                 Buffer ( n + count * 8 )
appendBits64BE = appendBits prim__appendB64BE