tzBytes_c.c
// Open Source License
// Copyright (c) 2022 DaiLambda, Inc. <contact@dailambda,jp>
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#include <string.h>
#include <caml/mlvalues.h>
#include <caml/memory.h>
#include <caml/alloc.h>
#include <caml/fail.h>
#define SWAP(ty, a, b) ({ \
ty tmp = (a); \
(a) = (b); \
(b) = (tmp); \
})
CAMLprim value bytes_logand(value a, value b)
{
// <------ l ---->
// <diff>
// a |aaaaaaaaaaaaaaaaaaaaaa|
// b |bbbbbbbbbbbbbbb|
// r |rrrrrrrrrrrrrrr|
CAMLparam2(a, b);
CAMLlocal1(r);
mlsize_t la = caml_string_length(a);
mlsize_t lb = caml_string_length(b);
// make [a] always longer than (or same length as) [b]
if ( la < lb ) {
SWAP(mlsize_t, la, lb);
SWAP(value, a, b);
}
mlsize_t diff = la - lb;
r = caml_alloc_string(lb);
unsigned char *pa = Bytes_val(a);
unsigned char *pb = Bytes_val(b);
unsigned char *pr = Bytes_val(r);
pa += diff;
for(mlsize_t i = 0; i < lb; i++, pr++, pa++, pb++){
*pr = *pa & *pb;
}
CAMLreturn(r);
}
CAMLprim value bytes_logor(value a, value b)
{
// <---------len-------->
// <diff>
// a |aaaaaaaaaaaaaaaaaaaaaa|
// b |bbbbbbbbbbbbbbb|
// r |aaaaaa|rrrrrrrrrrrrrrr|
CAMLparam2(a, b);
CAMLlocal1(r);
mlsize_t la = caml_string_length(a);
mlsize_t lb = caml_string_length(b);
// make [a] always longer than (or same length as) [b]
if ( la < lb ) {
SWAP(mlsize_t, la, lb);
SWAP(value, a, b);
}
mlsize_t diff = la - lb;
r = caml_alloc_string(la);
unsigned char *pa = Bytes_val(a);
unsigned char *pb = Bytes_val(b);
unsigned char *pr = Bytes_val(r);
// diff part
memcpy(pr, pa, diff);
// the rest
pr += diff;
pa += diff;
for(mlsize_t i = diff; i < la; i++, pr++, pa++, pb++){
*pr = *pa | *pb;
}
CAMLreturn(r);
}
CAMLprim value bytes_logxor(value a, value b)
{
// <---------len-------->
// <diff>
// a |aaaaaaaaaaaaaaaaaaaaaa|
// b |bbbbbbbbbbbbbbb|
// r |aaaaaa|rrrrrrrrrrrrrrr|
CAMLparam2(a, b);
CAMLlocal1(r);
mlsize_t la = caml_string_length(a);
mlsize_t lb = caml_string_length(b);
// make [a] always longer than (or same length as) [b]
if ( la < lb ) {
SWAP(mlsize_t, la, lb);
SWAP(value, a, b);
}
mlsize_t diff = la - lb;
r = caml_alloc_string(la);
unsigned char *pa = Bytes_val(a);
unsigned char *pb = Bytes_val(b);
unsigned char *pr = Bytes_val(r);
// diff part
memcpy(pr, pa, diff);
// the rest
pr += diff;
pa += diff;
for(mlsize_t i = diff; i < la; i++, pr++, pa++, pb++){
*pr = *pa ^ *pb;
}
CAMLreturn(r);
}
CAMLprim value bytes_lognot(value a)
{
CAMLparam1(a);
CAMLlocal1(r);
mlsize_t l = caml_string_length(a);
r = caml_alloc_string(l);
unsigned char *pa = Bytes_val(a);
unsigned char *pr = Bytes_val(r);
for(mlsize_t i = 0; i < l; i++){
*pr++ = ~*pa++;
}
CAMLreturn(r);
}
CAMLprim value bytes_shift_left(value a, value vn)
{
CAMLparam2(a, vn);
CAMLlocal1(r);
mlsize_t n = Long_val(vn);
if (n < 0) caml_invalid_argument("bytes_shift_left");
int shift = n % 8;
mlsize_t nbytes = n / 8;
mlsize_t len_a = caml_string_length(a);
if ( shift == 0 ) {
// <----- len_a ---->
// a |aaaaaaaaaaaaaaaaaa|
// r |aaaaaaaaaaaaaaaaaa|0000000000|
// <-nbytes->
// <--------- len_r ----------->
mlsize_t len_r = len_a + nbytes;
r = caml_alloc_string(len_r);
unsigned char *pa = Bytes_val(a);
unsigned char *pr = Bytes_val(r);
memcpy(pr, pa, len_a);
bzero(pr + len_a, nbytes);
} else {
mlsize_t len_r = len_a + nbytes + 1;
int shift_right = 8 - shift;
// <---- len_a ----->
// a |aaaaaaaaaaaaaaaaaa|
// <--------- len_r------------------>
// r |000|aaaaaaaaaaaaaaaaaa|000|00000000|
// ^ ^ <nbytes>
// | |
// shift_right bits shift bits
r = caml_alloc_string(len_r);
unsigned char *pa = Bytes_val(a);
unsigned char *pr = Bytes_val(r);
// first byte
*pr++ = *pa >> shift_right;
// middle
for(mlsize_t i = 1; i < len_a; i++, pa++){
*pr++ = (((*pa << 8) + *(pa+1)) >> shift_right) & 255;
}
// last byte before 0s
*pr++ = (*pa << shift) & 255;
// 0s
bzero(pr, len_r - len_a - 1);
}
CAMLreturn(r);
}
CAMLprim value bytes_shift_right(value a, value vn)
{
CAMLparam2(a, vn);
CAMLlocal1(r);
mlsize_t n = Long_val(vn);
if ( n < 0 ) caml_invalid_argument("bytes_shift_right");
int shift = n % 8;
mlsize_t nbytes = n / 8;
mlsize_t len_a = caml_string_length(a);
if ( len_a <= nbytes ) {
r = caml_alloc_string(0);
CAMLreturn(r);
}
mlsize_t len_r = len_a - nbytes;
r = caml_alloc_string(len_r);
unsigned char *pa = Bytes_val(a);
unsigned char *pr = Bytes_val(r);
if ( shift == 0 ) {
// <---- len_a ------------>
// a |aaaaaaaaaaaaaaaaaaaaaaaaa|
// r |aaaaaaaaaaaaaa|<-nbytes->
// <--- len_r -->
memcpy(pr, pa, len_r);
} else {
// <---- len_a ----------->
// a |aaaaaaaaaaaaaaa|aaaaaaaa|
// <--- len_r----> <nbytes>
// r |000|aaaaaaaaaaa|
// ^
// |
// shift bits
// first byte
*pr++ = *pa >> shift;
// the rest
for(mlsize_t i = 1; i < len_r; i++, pa++, pr++){
*pr = (((*pa << 8) + *(pa+1)) >> shift) & 255;
}
}
CAMLreturn(r);
}