Coverage report: /home/luis/src/cffi/src/utils.lisp
Kind | Covered | All | % |
expression | 123 | 152 | 80.9 |
branch | 29 | 36 | 80.6 |
Key
Not instrumented
Executed
Not executed
Both branches taken
One branch taken
Neither branch taken
1
;;;; -*- Mode: lisp; indent-tabs-mode: nil -*-
3
;;; utils.lisp --- Various utilities.
5
;;; Copyright (C) 2005-2006, Luis Oliveira <loliveira(@)common-lisp.net>
7
;;; Permission is hereby granted, free of charge, to any person
8
;;; obtaining a copy of this software and associated documentation
9
;;; files (the "Software"), to deal in the Software without
10
;;; restriction, including without limitation the rights to use, copy,
11
;;; modify, merge, publish, distribute, sublicense, and/or sell copies
12
;;; of the Software, and to permit persons to whom the Software is
13
;;; furnished to do so, subject to the following conditions:
15
;;; The above copyright notice and this permission notice shall be
16
;;; included in all copies or substantial portions of the Software.
18
;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
;;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
;;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21
;;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22
;;; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23
;;; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
;;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25
;;; DEALINGS IN THE SOFTWARE.
28
(in-package #:cl-user)
30
(defpackage #:cffi-utils
32
(:export #:discard-docstring
44
#:warn-if-kw-or-belongs-to-cl))
46
(in-package #:cffi-utils)
48
;;;# General Utilities
50
;;; frodef's, see: http://paste.lisp.org/display/2771#1
51
(defmacro post-incf (place &optional (delta 1) &environment env)
52
"Increment PLACE by DELTA and return its previous value."
53
(multiple-value-bind (dummies vals new setter getter)
54
(get-setf-expansion place env)
55
`(let* (,@(mapcar #'list dummies vals) (,(car new) ,getter))
57
(setq ,(car new) (+ ,(car new) ,delta))
60
(defun ensure-list (x)
61
"Make into list if atom."
62
(if (listp x) x (list x)))
64
(defmacro discard-docstring (body-var)
65
"Discards the first element of the list in body-var if it's a
66
string and the only element."
67
`(when (and (stringp (car ,body-var)) (cdr ,body-var))
70
;;; Parse a body of code, removing an optional documentation string
71
;;; and declaration forms. Returns the actual body, docstring, and
72
;;; declarations as three multiple values.
73
(defun parse-body (body)
76
(when (and (stringp (car body)) (cdr body))
77
(setf docstring (pop body)))
78
(loop while (and (consp (car body)) (eql (caar body) 'cl:declare))
79
do (push (pop body) declarations))
80
(values body docstring (nreverse declarations))))
82
;;; LET-IF (renamed to BIF) and LET-WHEN taken from KMRCL
83
(defmacro let-when ((var test-form) &body body)
84
`(let ((,var ,test-form))
87
(defmacro bif ((var test-form) if-true &optional if-false)
88
`(let ((,var ,test-form))
89
(if ,var ,if-true ,if-false)))
91
;;; ONCE-ONLY macro taken from PAIP
92
(defun starts-with (list x)
93
"Is x a list whose first element is x?"
94
(and (consp list) (eql (first list) x)))
96
(defun side-effect-free? (exp)
97
"Is exp a constant, variable, or function,
98
or of the form (THE type x) where x is side-effect-free?"
99
(or (atom exp) (constantp exp)
100
(starts-with exp 'function)
101
(and (starts-with exp 'the)
102
(side-effect-free? (third exp)))))
104
(defmacro once-only (variables &rest body)
105
"Returns the code built by BODY. If any of VARIABLES
106
might have side effects, they are evaluated once and stored
107
in temporary variables that are then passed to BODY."
108
(assert (every #'symbolp variables))
110
(dotimes (i (length variables)) (push (gensym "ONCE") temps))
111
`(if (every #'side-effect-free? (list .,variables))
114
,`(list ,@(mapcar #'(lambda (tmp var)
117
(let ,(mapcar #'(lambda (var tmp) `(,var ',tmp))
121
;;;; The following utils were taken from SBCL's
122
;;;; src/code/*-extensions.lisp
124
;;; Automate an idiom often found in macros:
125
;;; (LET ((FOO (GENSYM "FOO"))
126
;;; (MAX-INDEX (GENSYM "MAX-INDEX-")))
129
;;; "Good notation eliminates thought." -- Eric Siggia
131
;;; Incidentally, this is essentially the same operator which
132
;;; _On Lisp_ calls WITH-GENSYMS.
133
(defmacro with-unique-names (symbols &body body)
134
`(let ,(mapcar (lambda (symbol)
135
(let* ((symbol-name (symbol-name symbol))
136
(stem (if (every #'alpha-char-p symbol-name)
138
(concatenate 'string symbol-name "-"))))
139
`(,symbol (gensym ,stem))))
143
(defun make-gensym-list (n)
144
"Return a list of N gensyms."
145
(loop repeat n collect (gensym)))
147
(defun symbolicate (&rest things)
148
"Concatenate together the names of some strings and symbols,
149
producing a symbol in the current package."
150
(let* ((strings (mapcar (lambda (x)
152
(number (write-to-string x))
155
(length (reduce #'+ strings :key #'length))
156
(name (make-array length :element-type 'character)))
158
(dolist (string strings (values (intern name)))
159
(let ((len (length string)))
160
(replace name string :start1 index)
161
(incf index len))))))
163
(defun keywordify (&rest things)
164
(let ((*package* (find-package '#:keyword)))
165
(apply #'symbolicate things)))
167
(defun single-bit-p (integer)
168
"Answer whether INTEGER, which must be an integer, is a single
169
set twos-complement bit."
171
nil ;infinite set bits for negatives
172
(loop until (logbitp 0 integer)
173
do (setf integer (ash integer -1))
174
finally (return (zerop (ash integer -1))))))
176
;;; This function is here because it needs to be defined early.
178
;;; This function is used by DEFINE-PARSE-METHOD and DEFCTYPE to warn
179
;;; users when they're defining types whose names belongs to the
180
;;; KEYWORD or CL packages. CFFI itself gets to use keywords without
181
;;; a warning though.
182
(defun warn-if-kw-or-belongs-to-cl (name)
183
(let ((package (symbol-package name)))
184
(when (or (eq package (find-package '#:cl))
185
(and (not (eq *package* (find-package '#:cffi)))
186
(eq package (find-package '#:keyword))))
187
(warn "Defining a foreign type named ~S. This symbol belongs to the ~A ~
188
package and that may interfere with other code using CFFI."
189
name (package-name package)))))
191
;(defun deprecation-warning (bad-name &optional good-name)
192
; (warn "using deprecated ~S~@[, should use ~S instead~]"
197
;(defmacro awhen (test &body body)
201
;(defmacro acond (&rest clauses)
204
; (destructuring-bind ((test &body body) &rest rest) clauses
207
; (let ((it ,test)) (declare (ignorable it)),@body)
208
; (acond ,@rest))))))