File: idlarray.ml

package info (click to toggle)
camlidl 1.12-1
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 1,592 kB
  • sloc: ml: 5,238; ansic: 945; cpp: 908; makefile: 358; xml: 213; sh: 74
file content (276 lines) | stat: -rw-r--r-- 10,154 bytes parent folder | download | duplicates (2)
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
(***********************************************************************)
(*                                                                     *)
(*                              CamlIDL                                *)
(*                                                                     *)
(*            Xavier Leroy, projet Cristal, INRIA Rocquencourt         *)
(*                                                                     *)
(*  Copyright 1999 Institut National de Recherche en Informatique et   *)
(*  en Automatique.  All rights reserved.  This file is distributed    *)
(*  under the terms of the GNU Lesser General Public License LGPL v2.1 *)
(*                                                                     *)
(***********************************************************************)

(* $Id: array.ml,v 1.17 2002-01-16 09:42:00 xleroy Exp $ *)

(* Handling of arrays and bigarrays *)

open Printf
open Utils
open Variables
open Idltypes
open Cvttyp

(* Recognize float IDL types *)

let is_float_type =
  function Type_float -> true | Type_double -> true | _ -> false

(* Recognize IDL types whose conversion C -> ML performs no allocation.
   Due to the special treatment of float arrays, float and double
   are also treated as "no allocation". *)

let rec no_allocation_type = function
    Type_int(_, Iunboxed) -> true
  | Type_float -> true
  | Type_double -> true
  | Type_pointer(kind, ty) -> kind = Ref && no_allocation_type ty
  | Type_enum _ -> true
  | Type_const ty -> no_allocation_type ty
  | _ -> false  

(* Update dependent size variables *)

let update_size_variable svar oc pref size =
  match svar with
    None -> ()
  | Some re when Lexpr.is_identifier_deref re ->
    iprintf oc "%a = %s;\n" Lexpr.output (pref, re) size
  | Some re ->
    error "Array size expression too complex for ML -> C conversion"

(* Translation from an ML array [v] to a C array [c] *)

let array_ml_to_c ml_to_c oc onstack pref attr ty_elt v c =
  if attr.is_string || attr.is_bytes then begin
    match attr.bound with
    | None ->
        if onstack then
          iprintf oc "%s = (%a) String_val(%s);\n"
                  c
                  out_c_type (Type_pointer(Ptr, ty_elt))
                  v
        else begin
          iprintf oc "%s = camlidl_malloc_string(%s, _ctx);\n" c v;
          need_context := true
        end;
        begin match attr.size with
          None -> ()
        | Some re -> iprintf oc "%a = caml_string_length(%s);\n" 
                             Lexpr.output (pref, re) v
        end
    | Some n ->
        let size = new_c_variable (Type_named("", "mlsize_t")) in
        iprintf oc "%s = caml_string_length(%s);\n" size v;    
        iprintf oc
            "if (%s >= %d) caml_invalid_argument(\"%s\");\n"
            size (Lexpr.eval_int n) !current_function;
        iprintf oc "memcpy(%s, String_val(%s), %s + 1);\n" c v size;
        begin match attr.size with
          None -> ()
        | Some re -> iprintf oc "%a = %s;\n" 
                             Lexpr.output (pref, re) size
        end
  end else begin
    (* Determine actual size of ML array *)
    let size = new_c_variable (Type_named("", "mlsize_t")) in
    if is_float_type ty_elt
    then iprintf oc "%s = Wosize_val(%s) / Double_wosize;\n" size v
    else iprintf oc "%s = Wosize_val(%s);\n" size v;
    begin match attr.bound with
      None ->
        (* Allocate C array of same size as ML array *)
        iprintf oc "%s = camlidl_malloc(" c;
        if attr.null_terminated
        then fprintf oc "(%s + 1)" size
        else fprintf oc "%s" size;
        fprintf oc " * sizeof(%a), _ctx);\n" out_c_type ty_elt;
        need_context := true;
    | Some n ->
        (* Check compatibility of actual size w.r.t. expected size *)
        iprintf oc "if (%s %s %d) caml_invalid_argument(\"%s\");\n"
                (if attr.null_terminated then size ^ " + 1" else size)
                (if attr.size = None && not attr.null_terminated
                 then "!=" else ">")
                (Lexpr.eval_int n) !current_function
    end;
    (* Copy the array elements *)
    let idx = new_c_variable (Type_named("", "mlsize_t")) in
    begin match attr with
      {bound = Some n; size = None} ->
        iprintf oc "for (%s = 0; %s < %d; %s++) {\n"
                   idx idx (Lexpr.eval_int n) idx
    | _ ->
        iprintf oc "for (%s = 0; %s < %s; %s++) {\n"
                   idx idx size idx
    end;
    increase_indent();
    if is_float_type ty_elt then
      iprintf oc "%s[%s] = Double_field(%s, %s);\n" c idx v idx
    else begin
      let v' = new_ml_variable() in
      iprintf oc "%s = Field(%s, %s);\n" v' v idx;
      ml_to_c oc onstack pref ty_elt v' (sprintf "%s[%s]" c idx)
    end;
    decrease_indent();
    iprintf oc "}\n";
    (* Null-terminate the array if requested *)
    if attr.null_terminated then iprintf oc "%s[%s] = 0;\n" c size;
    update_size_variable attr.size oc pref size;
    update_size_variable attr.length oc pref size
  end

(* Translation from a C array [c] to an ML array [v] *)

let array_c_to_ml c_to_ml oc pref attr ty_elt c v =
  if attr.is_string || attr.is_bytes then
    iprintf oc "%s = caml_copy_string(%s);\n" v c
  else begin
    (* Determine size of ML array *)
    let (nsize, size) =
      match attr with
        {length = Some re} ->
          (max_int, Lexpr.tostring pref re)
      | {size = Some re} ->
          (max_int, Lexpr.tostring pref re)
      | {bound = Some le} ->
          let n = Lexpr.eval_int le in
          (n, string_of_int n)
      | {null_terminated = true} ->
          let sz = new_c_variable (Type_named("", "mlsize_t")) in
          iprintf oc "%s = camlidl_ptrarray_size((void **) %s);\n" sz c;
          (max_int, sz)
      | _ ->
          error "Cannot determine array size for C -> ML conversion" in
    (* Allocate ML array *)
    let alloc_function =
      if nsize < 64 && no_allocation_type ty_elt
      then "camlidl_alloc_small" else "camlidl_alloc" in
    if is_float_type ty_elt
    then iprintf oc "%s = %s(%s * Double_wosize, Double_array_tag);\n"
                  v alloc_function size
    else iprintf oc "%s = %s(%s, 0);\n" v alloc_function size;
    if not (no_allocation_type ty_elt) then begin
      iprintf oc "Begin_root(%s)\n" v;
      increase_indent()
    end;
    (* Copy elements of C array *)
    let idx = new_c_variable (Type_named("", "mlsize_t")) in
    iprintf oc "for (%s = 0; %s < %s; %s++) {\n" idx idx size idx;
    increase_indent();
    if is_float_type ty_elt then
      iprintf oc "Store_double_field(%s, %s, %s[%s]);\n" v idx c idx
    else if nsize < 64 && no_allocation_type ty_elt then
      c_to_ml oc pref ty_elt (sprintf "%s[%s]" c idx)
                             (sprintf "Field(%s, %s)" v idx)
    else begin
      let v' = new_ml_variable() in
      c_to_ml oc pref ty_elt (sprintf "%s[%s]" c idx) v';
      iprintf oc "caml_modify(&Field(%s, %s), %s);\n" v idx v'
    end;
    decrease_indent();
    iprintf oc "}\n";
    (* Pop root if needed *)
    if not (no_allocation_type ty_elt) then begin
      decrease_indent();    
      iprintf oc "End_roots()\n"
    end
  end

(* Determine the output size of an array *)

let array_output_size attr =
  match attr with
    {length = Some re} -> re
  | {size = Some re} -> re
  | {bound = Some le} -> le
  | _ -> error "Cannot determine array size for C -> ML conversion"

(* Allocate room for an out array *)

let array_allocate_output_space oc pref attr ty_elt c =
  if attr.bound = None then begin
    iprintf oc "%s = camlidl_malloc(%a * sizeof(%a), _ctx);\n"
               c Lexpr.output (pref, array_output_size attr)
               out_c_type ty_elt;
    need_context := true
  end

(* Translation from an ML bigarray [v] to a C array [c] *)

let bigarray_ml_to_c oc pref attr ty_elt v c =
  iprintf oc "%s = Caml_ba_data_val(%s);\n" c v;
  (* Update dependent size variables, if any *)
  iter_index
    (fun i attr ->
      match attr.size with
        None -> ()
      | Some re -> iprintf oc "%a = Caml_ba_array_val(%s)->dim[%d];\n" 
                           Lexpr.output (pref, re) v i)
    0 attr.dims

(* Return the flags to alloc_bigarray_dims corresponding to the given
   big array attributes *)

let bigarray_alloc_kind = function
    Type_int((Char | UChar | Byte), _) -> "CAML_BA_UINT8"
  | Type_int((SChar | Small), _) -> "CAML_BA_SINT8"
  | Type_int(Short, _) -> "CAML_BA_SINT16"
  | Type_int(UShort, _) -> "CAML_BA_UINT16"
  | Type_int((Int | UInt), _) -> "CAML_BA_INT32"
  | Type_int((Long | ULong), I64) -> "CAML_BA_INT64"
  | Type_int((Long | ULong), _) -> "CAML_BA_NATIVE_INT"
  | Type_int((Hyper | UHyper), _) -> "CAML_BA_INT64"
  | Type_float -> "CAML_BA_FLOAT32"
  | Type_double -> "CAML_BA_FLOAT64"
  | _ -> assert false

let bigarray_alloc_layout attr =
  if attr.fortran_layout
  then "CAML_BA_FORTRAN_LAYOUT"
  else "CAML_BA_C_LAYOUT"

let bigarray_alloc_managed attr =
  if attr.malloced
  then "CAML_BA_MANAGED"
  else "CAML_BA_EXTERNAL"

(* Translation from a C array [c] to an ML bigarray [v] *)

let bigarray_c_to_ml oc pref attr ty_elt c v =
  iprintf oc "%s = caml_ba_alloc_dims(\n" v;
  iprintf oc "        %s | %s | %s,\n"
             (bigarray_alloc_kind ty_elt)
             (bigarray_alloc_layout attr)
             (bigarray_alloc_managed attr);
  iprintf oc "        %d, %s" (List.length attr.dims) c;
  List.iter
    (fun attr ->
      let e = array_output_size attr in
      fprintf oc ", %a" Lexpr.output (pref, e))
    attr.dims;
  fprintf oc ");\n"

(* Allocate room for an out bigarray *)

let bigarray_allocate_output_space oc pref attr ty_elt c =
  (* Since the conversion to ML bigarray does not copy the data,
     we must allocate permanent space using stat_alloc
     (instead of transient space using camlidl_alloc),
     and we set the "malloced" attribute to true so that the
     ML bigarray will be managed by the Caml GC *)
  iprintf oc "%s = caml_stat_alloc(" c;
  List.iter
    (fun a -> fprintf oc "%a * " Lexpr.output (pref, array_output_size a))
    attr.dims;
  fprintf oc "sizeof(%a));\n" out_c_type ty_elt;
  attr.malloced <- true