File: bitstring_c.c

package info (click to toggle)
ocaml-bitstring 2.0.4-2
  • links: PTS, VCS
  • area: main
  • in suites: buster, jessie, jessie-kfreebsd, sid, stretch
  • size: 1,516 kB
  • ctags: 546
  • sloc: ml: 3,470; sh: 343; makefile: 335; ansic: 114
file content (138 lines) | stat: -rw-r--r-- 4,709 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/* Bitstring library.
 * Copyright (C) 2008 Red Hat Inc., Richard W.M. Jones
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version,
 * with the OCaml linking exception described in COPYING.LIB.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 *
 * $Id: bitstring.ml 146 2008-08-20 16:58:33Z richard.wm.jones $
 */

/* This file contains hand-coded, optimized C implementations of
 * certain very frequently used functions.
 */

#include <config.h>

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <byteswap.h>
#include <string.h>

#include <caml/mlvalues.h>
#include <caml/fail.h>

/* 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;								\
    memcpy(&r, ptr, sizeof(r));					\
    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)

#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;								\
    memcpy(&r, ptr, sizeof(r));					\
    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)

/* Special care needs to be taken on ARCH_ALIGN_INT64 platforms
   (hppa and sparc in Debian). */

#ifdef ARCH_ALIGN_INT64
#include <caml/memory.h>
#include <caml/alloc.h>
#define fastpath3(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;								\
    memcpy(&r, ptr, sizeof(r));					\
    swap_##endian(size,r);						\
    memcpy(Data_custom_val(rv), &r, sizeof(r));			\
    return rv;								\
  }

#else
#define fastpath3 fastpath2
#endif

fastpath3(64,be,unsigned,uint64_t,Int64_val)
fastpath3(64,le,unsigned,uint64_t,Int64_val)
fastpath3(64,ne,unsigned,uint64_t,Int64_val)
fastpath3(64,be,signed,int64_t,Int64_val)
fastpath3(64,le,signed,int64_t,Int64_val)
fastpath3(64,ne,signed,int64_t,Int64_val)