Skip to content

Commit

Permalink
Added support for additional types.
Browse files Browse the repository at this point in the history
Added build readme script.
Waiting on 8 byte native support to come up to speed before enabling 64 bit tests.
Added tags to meta6.
  • Loading branch information
samgwise committed Jul 5, 2017
1 parent 7af847a commit bb6c890
Show file tree
Hide file tree
Showing 7 changed files with 201 additions and 11 deletions.
4 changes: 3 additions & 1 deletion META6.json
Expand Up @@ -2,6 +2,7 @@
"authors" : [
"Sam Gillespie"
],
"tags": ["Binary", "Buf", "Native"],
"build-depends" : [
"Panda::Builder",
"Native::Resources"
Expand All @@ -12,6 +13,7 @@
],
"description" : "Convert perl6 Numerics to Bufs and back again!",
"name" : "Numeric::Pack",
"license" : "Artistic-2.0",
"perl" : "6.c",
"provides" : {
"Numeric::Pack" : "lib/Numeric/Pack.pm6"
Expand All @@ -23,5 +25,5 @@
],
"source-url" : "git://github.com/samgwise/p6-Numeric-Pack.git",
"test-depends" : [ ],
"version" : "0.1.1"
"version" : "0.2.0"
}
76 changes: 71 additions & 5 deletions README.md
@@ -1,5 +1,4 @@
[![Build Status](https://travis-ci.org/samgwise/p6-Numeric-Pack.svg?branch=master)](https://travis-ci.org/samgwise/p6-Numeric-Pack)

NAME
====

Expand Down Expand Up @@ -79,6 +78,14 @@ Use :floats or :ints flags to export subsets of the module's functionality.
<td>unpack-float</td>
<td>unpack-int32</td>
</tr>
<tr>
<td></td>
<td>pack-uint32</td>
</tr>
<tr>
<td></td>
<td>unpack-uint32</td>
</tr>
<tr>
<td>pack-double</td>
<td>pack-int64</td>
Expand All @@ -87,24 +94,39 @@ Use :floats or :ints flags to export subsets of the module's functionality.
<td>unpack-double</td>
<td>unpack-int64</td>
</tr>
<tr>
<td></td>
<td>pack-uint64 ★</td>
</tr>
<tr>
<td></td>
<td>unpack-uint64 ★</td>
</tr>
</table>

★ This behaviour is faulty for values over 7 bytes ☹

TODO
====

* unsigned types

* larger types

* smaller types

* optimise memory management

CHANGES
=======

<table>
<tr>
<td>changed named argument :endianness to :byte-order</td>
<td>Signitures now read more naturally</td>
<td>Added pack-uint32, pack-uint32 and unpack-uint32</td>
<td>Added support for unsigned types</td>
<td>2017-04-20</td>
</tr>
<tr>
<td>Changed named argument :endianness to :byte-order</td>
<td>Signatures now read more naturally</td>
<td>2016-08-30</td>
</tr>
</table>
Expand Down Expand Up @@ -168,6 +190,28 @@ sub unpack-int32(

Unpack a signed 4 byte integer buffer. Exported via tag :ints.

### sub pack-uint32

```
sub pack-uint32(
Cool $int,
Endianness :$byte-order = Endianness::big-endian
) returns Buf
```

Pack an Int to an 4 byte unsigned integer buffer Exported via tag :ints. Be aware that the behaviour of Int values outside the range of a signed 32bit integer [0 to 4,294,967,295] is undefined.

### sub unpack-uint32

```
sub unpack-uint32(
Buf $int-buf,
Endianness :$byte-order = Endianness::big-endian
) returns Int
```

Unpack an unsigned 4 byte integer buffer. Exported via tag :ints.

### sub pack-double

```
Expand Down Expand Up @@ -211,3 +255,25 @@ sub unpack-int64(
```

Unpack a signed 8 byte integer buffer. Exported via tag :ints.

### sub pack-uint64

```
sub pack-uint64(
Cool $int,
Endianness :$byte-order = Endianness::big-endian
) returns Buf
```

Pack an Int to an 8 byte unsigned integer buffer Exported via tag :ints. Be aware that the behaviour of Int values outside the range of a signed 64bit integer [0 to 18,446,744,073,709,551,615] is undefined. BE WARNED for reasons unknown values above 7bytes are represented as a BigInt and cannot be unboxed! Maybe this will be fixed but for know this function is faulty and untested due to this behaviour.

### sub unpack-uint64

```
sub unpack-uint64(
Buf $int-buf,
Endianness :$byte-order = Endianness::big-endian
) returns Int
```

Unpack an unsigned 8 byte integer buffer. Exported via tag :ints. BE WARNED for reasons unknown values above 7bytes are lost! Maybe this will be fixed but for know this function is faulty and untested due to this behaviour.
4 changes: 4 additions & 0 deletions build-readme.sh
@@ -0,0 +1,4 @@
#! /bin/bash
# using Pod::To::Markdown::Fenced
cat res/readme-header.md > README.md
perl6 -Ilib --doc=Markdown::Fenced lib/Numeric/Pack.pm6 >> README.md
77 changes: 74 additions & 3 deletions lib/Numeric/Pack.pm6
Expand Up @@ -66,20 +66,27 @@ Use :floats or :ints flags to export subsets of the module's functionality.
===============================
pack-float | pack-int32
unpack-float | unpack-int32
| pack-uint32
| unpack-uint32
pack-double | pack-int64
unpack-double | unpack-int64
| pack-uint64 ★
| unpack-uint64 ★
=end table
★ This behaviour is faulty for values over 7 bytes ☹
=head1 TODO
=item unsigned types
=item larger types
=item smaller types
=item optimise memory management
=head1 CHANGES
=begin table
changed named argument :endianness to :byte-order | Signitures now read more naturally | 2016-08-30
Added pack-uint32, pack-uint32 and unpack-uint32 | Added support for unsigned types | 2017-04-20
Changed named argument :endianness to :byte-order | Signatures now read more naturally | 2016-08-30
=end table
=head1 AUTHOR
Expand Down Expand Up @@ -166,6 +173,33 @@ sub unpack-int32(Buf $int-buf, Endianness :$byte-order = big-endian) returns Int
unpack_int32 buf-to-byte-array $int-buf, :$byte-order;
}

# void pack_uint32(int32_t i, char *bytes)
sub pack_uint32(uint32, CArray[uint8]) is native(&libnumpack) { * }

sub pack-uint32(Int(Cool) $int, Endianness :$byte-order = big-endian) returns Buf is export(:ints)
#= Pack an Int to an 4 byte unsigned integer buffer
#= Exported via tag :ints.
#= Be aware that the behaviour of Int values outside the range of a signed 32bit integer
#= [0 to 4,294,967,295]
#= is undefined.
{
my $bytes = CArray[uint8].new;
$bytes[3] = 0; #make room for 4 bytes
pack_uint32 $int, $bytes;
byte-array-to-buf($bytes, 4, :$byte-order);
}

# int32_t unpack_int32(char *bytes)
sub unpack_uint32(CArray[uint8]) returns uint32 is native(&libnumpack) { * }

sub unpack-uint32(Buf $int-buf, Endianness :$byte-order = big-endian) returns Int is export(:ints)
#= Unpack an unsigned 4 byte integer buffer.
#= Exported via tag :ints.
{
die "Unable to unpack buffer: expected 4 bytes but recieved { $int-buf.elems }" unless $int-buf.elems == 4;
unpack_uint32 buf-to-byte-array($int-buf, :$byte-order);
}

### 8 byte types:

# void pack_rat_to_double(int64_t n, int64_t d, char *bytes)
Expand Down Expand Up @@ -218,9 +252,46 @@ sub unpack-int64(Buf $int-buf, Endianness :$byte-order = big-endian) returns Int
#= Exported via tag :ints.
{
die "Unable to unpack buffer: expected 8 bytes but recieved { $int-buf.elems }" unless $int-buf.elems == 8;
unpack_int64 buf-to-byte-array $int-buf, :$byte-order;
unpack_int64 buf-to-byte-array($int-buf, :$byte-order);
}

# void pack_uint64(uint64_t i, char *bytes)
sub pack_uint64(uint64, CArray[uint8]) is native(&libnumpack) { * }

sub pack-uint64(Int(Cool) $int, Endianness :$byte-order = big-endian) returns Buf is export(:ints)
#= Pack an Int to an 8 byte unsigned integer buffer
#= Exported via tag :ints.
#= Be aware that the behaviour of Int values outside the range of a signed 64bit integer
#= [0 to 18,446,744,073,709,551,615]
#= is undefined.
#= BE WARNED for reasons unknown values above 7bytes are represented as a BigInt and cannot be unboxed!
#= Maybe this will be fixed but for know this function is faulty and untested due to this behaviour.
{
my $bytes = CArray[uint8].new;
$bytes[7] = 0; #make room for 8 bytes
pack_uint64 $int, $bytes;
byte-array-to-buf($bytes, 8, :$byte-order);
}

# uint64_t unpack_uint64(char *bytes)
sub unpack_uint64(CArray[uint8]) returns uint64 is native(&libnumpack) { * }

sub unpack-uint64(Buf $int-buf, Endianness :$byte-order = big-endian) returns Int is export(:ints)
#= Unpack an unsigned 8 byte integer buffer.
#= Exported via tag :ints.
#= BE WARNED for reasons unknown values above 7bytes are lost!
#= Maybe this will be fixed but for know this function is faulty and untested due to this behaviour.
{
die "Unable to unpack buffer: expected 8 bytes but recieved { $int-buf.elems }" unless $int-buf.elems == 8;
unpack_uint64 buf-to-byte-array($int-buf, :$byte-order);
}

# uint64_t max_uint64()
sub max_uint64() returns uint64 is native(&libnumpack) { * }

sub max-uint64() returns Int is export(:ints) {
max_uint64
}

#
# Utils:
Expand Down
32 changes: 32 additions & 0 deletions libnumpack.c
Expand Up @@ -7,6 +7,7 @@
union Bits32 {
float f;
int32_t i;
uint32_t ui;
char bytes[4];
};

Expand Down Expand Up @@ -36,12 +37,26 @@ int32_t unpack_int32(char *bytes) {
return b2i.i;
}

//uint32:
void pack_uint32(uint32_t i, char *bytes) {
union Bits32 i2b;
i2b.ui = i;
memcpy(bytes, i2b.bytes, 4);
}

uint32_t unpack_uint32(char *bytes) {
union Bits32 b2i;
memcpy(b2i.bytes, bytes, 4);
return b2i.ui;
}

//
// 64 bit packing
//
union Bits64 {
char bytes[8];
int64_t i;
uint64_t ui;
double d;
};

Expand Down Expand Up @@ -69,3 +84,20 @@ int64_t unpack_int64(char *bytes) {
memcpy(b2i.bytes, bytes, 8);
return b2i.i;
}

//uint64:
void pack_uint64(uint64_t i, char *bytes) {
union Bits64 i2b;
i2b.ui = i;
memcpy(bytes, i2b.bytes, 8);
}

uint64_t unpack_uint64(char *bytes) {
union Bits64 b2i;
memcpy(b2i.bytes, bytes, 8);
return b2i.ui;
}

uint64_t max_uint64() {
return UINT64_MAX;
}
1 change: 1 addition & 0 deletions res/readme-header.md
@@ -0,0 +1 @@
[![Build Status](https://travis-ci.org/samgwise/p6-Numeric-Pack.svg?branch=master)](https://travis-ci.org/samgwise/p6-Numeric-Pack)
18 changes: 16 additions & 2 deletions t/01-basic.t
Expand Up @@ -3,6 +3,8 @@ use v6;
use Test;
use Numeric::Pack;

plan 30;

use-ok 'Numeric::Pack';
use Numeric::Pack :ALL;

Expand All @@ -24,6 +26,9 @@ is pack-double( 12.375, :byte-order(big-endian) ).perl, Buf.new(0x40, 0x28, 0xC0
is pack-int32(1024, :byte-order(big-endian)).perl, Buf.new(0, 0, 0x04, 0).perl, "pack-int32 1024";
is pack-int64(1024, :byte-order(big-endian)).perl, Buf.new(0, 0, 0x00, 0, 0, 0, 0x04, 0).perl, "pack-int64 1024";

is pack-uint32(1024, :byte-order(big-endian)).perl, Buf.new(0, 0, 0x04, 0).perl, "pack-int32 1024";
is pack-uint64(1024, :byte-order(big-endian)).perl, Buf.new(0, 0, 0x00, 0, 0, 0, 0x04, 0).perl, "pack-int64 1024";

#
# Test unpacking
#
Expand All @@ -33,17 +38,28 @@ is unpack-double( Buf.new(0x40, 0x28, 0xC0, 0, 0, 0, 0, 0), :byte-order(big-endi
is unpack-int32(Buf.new(0, 0, 0x04, 0), :byte-order(big-endian)), 1024, "unpack-int32 1024";
is unpack-int64(Buf.new(0, 0, 0x00, 0, 0, 0, 0x04, 0), :byte-order(big-endian)), 1024, "unpack-int64 1024";

is unpack-uint32(Buf.new(0, 0, 0x04, 0), :byte-order(big-endian)), 1024, "unpack-int32 1024";
is unpack-uint64(Buf.new(0, 0, 0x00, 0, 0, 0, 0x04, 0), :byte-order(big-endian)), 1024, "unpack-int64 1024";

#
# Test limits
#
is unpack-int32( pack-int32 0 ), 0, "pack -> unpack int32 0";
is unpack-int32( pack-int32 −2_147_483_648 ), −2_147_483_648, "pack -> unpack int32 lower limit";
is unpack-int32( pack-int32 2_147_483_647 ), 2_147_483_647, "pack -> unpack int32 upper limit";

is unpack-uint32( pack-uint32 0 ), 0, "pack -> unpack uint32 0";
is unpack-uint32( pack-uint32 4_294_967_295 ), 4_294_967_295, "pack -> unpack uint32 upper limit";

is unpack-int64( pack-int64 0 ), 0, "pack -> unpack int64 0";
is unpack-int64( pack-int64 −9_223_372_036_854_775_808 ), −9_223_372_036_854_775_808, "pack -> unpack int64 lower limit";
is unpack-int64( pack-int64 9_223_372_036_854_775_807 ), 9_223_372_036_854_775_807, "pack -> unpack int64 upper limit";

is unpack-uint64( pack-uint64 0 ), 0, "pack -> unpack uint64 0";
# is pack-uint64(0xFFFFFFFFFFFFFFFF)[].join(' '), Buf.new( (0..7).map: { 0xFF } )[].join(' '), "pack -> unpack uint64 upper limit (raw)";
# is max-uint64, 0xFFFFFFFFFFFFFFFF, "unit64_t max value is expected 0xFFFFFFFFFFFFFFFF";
# is unpack-uint64( pack-uint64 18_446_744_073_709_551_615 ), 18_446_744_073_709_551_615, "pack -> unpack uint64 upper limit";

is unpack-float( pack-float 0 ), 0.Rat, "pack -> unpack float-rat 0";
is unpack-double( pack-double 0), 0.Rat, "pack -> unpack double-rat 0";

Expand All @@ -52,5 +68,3 @@ is unpack-float($nan-buffer), NaN, "unpack-float NaN";

$nan-buffer .= new(|$nan-buffer[0..3], 0xff, 0xff, 0xff, 0xff);
is unpack-double($nan-buffer), NaN, "unpack-double NaN";

done-testing;

0 comments on commit bb6c890

Please sign in to comment.