X-Git-Url: http://git.annexia.org/?a=blobdiff_plain;f=bitstring_c.c;h=5570f0506356edf1bfd30c9c3c53ae42a5fc0354;hb=ec13c41509db2b7fae9138cde2a8ea0b6d3b3699;hp=6faba8b214a4bd615bcc77af0c6333aa9ddd7b98;hpb=05e4823231b911aa103ebb0339a9d3519606a028;p=ocaml-bitstring.git diff --git a/bitstring_c.c b/bitstring_c.c index 6faba8b..5570f05 100644 --- a/bitstring_c.c +++ b/bitstring_c.c @@ -23,20 +23,94 @@ * certain very frequently used functions. */ +#include + #include #include +#include +#include #include #include -/* Return a mask of 0-31 bits wide. */ -CAMLprim value -ocaml_bitstring_I_mask (value bitsv) -{ - int bits = Int_val (bitsv); - - if (bits <= 31) - return Val_int ((1 << bits) - 1); - else - caml_invalid_argument ("Bitstring.I.mask"); -} +/* Fastpath functions. These are used in the common case for reading + * ints where the following conditions are known to be true: + * (a) the int size is a whole number of bytes (eg. 16, 24, 32, etc bits) + * (b) the access in the match is byte-aligned + * (c) the access in the underlying bitstring is byte-aligned + * + * These functions are all "noalloc" meaning they must not perform + * any OCaml allocations. For this reason, when the function returns + * an int32 or int64, the OCaml code passes in the pre-allocated pointer + * to the return value. + * + * The final offset in the string is calculated by the OCaml (caller) + * code. All we need to do is to read the string+offset and byteswap, + * sign-extend as necessary. + * + * There is one function for every combination of: + * (i) int size: 16, 32, 64 bits + * (ii) endian: bigendian, littleendian, nativeendian + * (iii) signed and unsigned + * + * XXX Future work: Expand this to 24, 40, 48, 56 bits. This + * requires some extra work because sign-extension won't "just happen". + */ + +#ifdef WORDS_BIGENDIAN +#define swap_be(size,v) +#define swap_le(size,v) v = bswap_##size (v) +#define swap_ne(size,v) +#else +#define swap_be(size,v) v = bswap_##size (v) +#define swap_le(size,v) +#define swap_ne(size,v) +#endif + +#define fastpath1(size,endian,signed,type) \ + CAMLprim value \ + ocaml_bitstring_extract_fastpath_int##size##_##endian##_##signed \ + (value strv, value offv) \ + { \ + type *ptr = (type *) ((void *) String_val (strv) + Int_val (offv)); \ + type r; \ + r = *ptr; \ + swap_##endian(size,r); \ + return Val_int (r); \ + } + +fastpath1(16,be,unsigned,uint16_t) +fastpath1(16,le,unsigned,uint16_t) +fastpath1(16,ne,unsigned,uint16_t) +fastpath1(16,be,signed,int16_t) +fastpath1(16,le,signed,int16_t) +fastpath1(16,ne,signed,int16_t) + +/* XXX This probably doesn't work on ARCH_ALIGN_INT64 platforms. */ + +#define fastpath2(size,endian,signed,type,rval) \ + CAMLprim value \ + ocaml_bitstring_extract_fastpath_int##size##_##endian##_##signed \ + (value strv, value offv, value rv) \ + { \ + type *ptr = (type *) ((void *) String_val (strv) + Int_val (offv)); \ + type r; \ + r = *ptr; \ + swap_##endian(size,r); \ + rval(rv) = r; \ + return rv; \ + } + +fastpath2(32,be,unsigned,uint32_t,Int32_val) +fastpath2(32,le,unsigned,uint32_t,Int32_val) +fastpath2(32,ne,unsigned,uint32_t,Int32_val) +fastpath2(32,be,signed,int32_t,Int32_val) +fastpath2(32,le,signed,int32_t,Int32_val) +fastpath2(32,ne,signed,int32_t,Int32_val) + +fastpath2(64,be,unsigned,uint64_t,Int64_val) +fastpath2(64,le,unsigned,uint64_t,Int64_val) +fastpath2(64,ne,unsigned,uint64_t,Int64_val) +fastpath2(64,be,signed,int64_t,Int64_val) +fastpath2(64,le,signed,int64_t,Int64_val) +fastpath2(64,ne,signed,int64_t,Int64_val)