-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtest-cinline.lisp
153 lines (132 loc) · 4.92 KB
/
test-cinline.lisp
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
(eval-when (:compile-toplevel :load-toplevel :execute)
(require 'asdf)
(asdf:operate 'asdf:load-op :cinline))
;;; Some standard C routines. Careful in slime, it redirects stdout
(defun system (cmd)
(let ((ret 0))
(cin:cinline ((int ret :out) (char* cmd :in))
"#include <unistd.h>"
"$ret = system ($cmd)")
ret))
(defun malloc (size)
(let ((p 0))
(cin:cinline ((void* p :out) (int size :in))
"#include <stdlib.h>"
"$p = malloc ($size)")
p))
(defun free (p)
(cin:cinline ((void* p :in)) "#include <stdlib.h>" "free ($p)"))
(defun fopen (file mode)
(let ((ret 0))
(cin:cinline ((void* ret :out)
(char* file :in)
(char* mode :in))
"#include <stdio.h>"
"$ret = fopen ($file, $mode)")
ret))
(defun popen (cmd mode)
(let ((ret 0))
(cin:cinline ((void* ret :out)
(char* cmd :in)
(char* mode :in))
"#include <stdio.h>"
"$ret = popen ($cmd, $mode)")
ret))
(defun fread (ptr size nitems fp)
(let ((ret 0))
(cin:cinline ((byte* ptr)
(uint size :in)
(uint nitems :in)
(void* fp :in)
(int ret :out))
"#include <stdio.h>"
"$ret = fread ($ptr, $size, $nitems, $fp)")
ret))
(defun fwrite (ptr size nitems fp)
(let ((ret 0))
(cin:cinline ((byte* ptr)
(uint size :in)
(uint nitems :in)
(void* fp :in)
(int ret :out))
"#include <stdio.h>"
"$ret = fwrite ($ptr, $size, $nitems, $fp)")
ret))
(defun pclose (fp)
(let ((ret 0))
(cin:cinline ((void* fp :in) (int ret :out))
"#include <stdio.h>"
"$ret = pclose ($fp)")
ret))
(defun fclose (fp)
(let ((ret 0))
(cin:cinline ((void* fp :in) (int ret :out))
"#include <stdio.h>"
"$ret = fclose ($fp)")
ret))
(defun perror (s)
(cin:cinline ((char* s :in)) "#include <stdio.h>" "perror ($s)"))
;;; Use fwrite and a lower level function (array->foreign)
(defun formatf (destfp control-string &rest format-args)
(let ((s (apply 'format `(nil ,control-string ,@format-args))))
(fwrite (cin:array->foreign s) 1 (length s) destfp)))
;;; A more involved example
(defun symm-eigenvals (matrix)
"Use GSL and BLAS to find the eigenvalues of a symmetric matrix
Usage: (symm-eigenvals
(make-array 4 :initial-contents '(1d0 2d0 2d0 1d0)
:element-type 'double-float))
==> #(3.0000000000000004d0 -1.0000000000000002d0)
"
(declare (type (simple-array double-float (*)) matrix))
(let* ((n^2 (length matrix))
(n-r (multiple-value-list (floor (sqrt n^2))))
(n (if (zerop (cadr n-r)) (car n-r) (error "matrix isn't square")))
(eivals (make-array n :element-type 'double-float)))
(cin:cinline ((double* matrix) (uint n) (double* eivals))
"""
#include <gsl/gsl_math.h>
#include <gsl/gsl_eigen.h>
"""
"""
gsl_matrix_view m = gsl_matrix_view_array ($matrix, $n, $n);
gsl_vector_view o = gsl_vector_view_array ($eivals, $n);
gsl_eigen_symm_workspace *w = gsl_eigen_symm_alloc ($n);
gsl_eigen_symm (&m.matrix, &o.vector, w);
gsl_eigen_symm_free (w);
"""
("gsl" "blas"))
eivals))
;;; Run a command, and process the output a line at a time
(defun process-by-line (fn cmd &optional (buf-size 1024))
(let ((fp (popen cmd "r"))
(line (make-string buf-size))
(read-err 0))
(if (zerop fp)
nil
; (unwind-protect
(progn
(loop while (zerop read-err) do
;; line is a byte* and not a char* because we're using it
;; as a buffer, so we don't need char* :in behavior and we
;; definitely don't want char* :out behavior: shrinking line
;; on the lisp side to strlen (line).
(cin:cinline ((void* fp :in)
(byte* line)
(int buf-size :in)
(int read-err :out))
"#include <stdio.h>"
"""
if (fgets ($line, $buf_size, $fp))
{
int len = strlen ($line);
if (len > 0 && $line[len-1] == '\n')
$line[len-1] = '\0';
}
else
$read_err = feof ($fp) ? 1 : -1;
""")
(when (zerop read-err)
(funcall fn (cin:char*->string line))))
(pclose fp)))
(> read-err 0)))