Merge branch 'feature/c-layout' into develop
This commit is contained in:
commit
3709aab143
5 changed files with 72 additions and 4 deletions
|
|
@ -2,6 +2,9 @@
|
|||
All notable changes to this project will be documented in this file. This change log follows the conventions of [keepachangelog.com](http://keepachangelog.com/).
|
||||
|
||||
## [Unreleased]
|
||||
### Added
|
||||
- New `coffi.layout` namespace with support for forcing C layout rules on structs
|
||||
|
||||
### Fixed
|
||||
- C-characters were being read as UTF-16 rather than ASCII code points
|
||||
|
||||
|
|
|
|||
30
src/clj/coffi/layout.clj
Normal file
30
src/clj/coffi/layout.clj
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
(ns coffi.layout
|
||||
"Functions for adjusting the layout of structs."
|
||||
(:require
|
||||
[coffi.mem :as mem]))
|
||||
|
||||
(defn with-c-layout
|
||||
"Forces a struct specification to C layout rules.
|
||||
|
||||
This will add padding fields between fields to match C alignment
|
||||
requirements."
|
||||
[struct-spec]
|
||||
(let [aligned-fields
|
||||
(loop [offset 0
|
||||
aligned-fields []
|
||||
fields (nth struct-spec 1)]
|
||||
(if (seq fields)
|
||||
(let [[[_ type :as field] & fields] fields
|
||||
size (mem/size-of type)
|
||||
r (rem offset (mem/align-of type))]
|
||||
(recur (cond-> (+ offset size)
|
||||
(pos? r) (+ (- size r)))
|
||||
(cond-> aligned-fields
|
||||
(pos? r) (conj [::padding [::mem/padding (- size r)]])
|
||||
:always (conj field))
|
||||
fields))
|
||||
(let [strongest-alignment (mem/align-of struct-spec)
|
||||
r (rem offset strongest-alignment)]
|
||||
(cond-> aligned-fields
|
||||
(pos? r) (conj [::padding [::mem/padding (- strongest-alignment r)]])))))]
|
||||
(assoc struct-spec 1 aligned-fields)))
|
||||
|
|
@ -349,6 +349,11 @@
|
|||
[type]
|
||||
(.byteSize ^MemoryLayout (c-layout type)))
|
||||
|
||||
(defn align-of
|
||||
"The alignment in bytes of the given `type`."
|
||||
[type]
|
||||
(.byteAlignment ^MemoryLayout (c-layout type)))
|
||||
|
||||
(defn alloc-instance
|
||||
"Allocates a memory segment for the given `type`."
|
||||
([type] (alloc-instance type (connected-scope)))
|
||||
|
|
@ -776,7 +781,8 @@
|
|||
aliased type."
|
||||
{:style/indent [:defn]}
|
||||
[new-type aliased-type]
|
||||
(if (primitive-type aliased-type)
|
||||
(if (and (s/valid? ::type aliased-type)
|
||||
(primitive-type aliased-type))
|
||||
`(let [aliased# ~aliased-type]
|
||||
(defmethod primitive-type ~new-type
|
||||
[_type#]
|
||||
|
|
@ -799,4 +805,4 @@
|
|||
(deserialize-from segment# aliased#)))))
|
||||
(s/fdef defalias
|
||||
:args (s/cat :new-type qualified-keyword?
|
||||
:aliased-type ::type))
|
||||
:aliased-type any?))
|
||||
|
|
|
|||
|
|
@ -48,3 +48,18 @@ StringFactory get_downcall(int whichString) {
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct alignment_test {
|
||||
char a;
|
||||
double x;
|
||||
float y;
|
||||
} AlignmentTest;
|
||||
|
||||
AlignmentTest get_struct() {
|
||||
AlignmentTest ret = {};
|
||||
ret.a = 'x';
|
||||
ret.x = 3.14;
|
||||
ret.y = 42.0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
(ns coffi.ffi-test
|
||||
(:require
|
||||
[clojure.test :as t]
|
||||
[coffi.mem :as mem]
|
||||
[coffi.ffi :as ffi]))
|
||||
[coffi.ffi :as ffi]
|
||||
[coffi.layout :as layout]
|
||||
[coffi.mem :as mem]))
|
||||
|
||||
(ffi/load-library "target/ffi_test.so")
|
||||
|
||||
|
|
@ -30,3 +31,16 @@
|
|||
(t/is (= ((ffi/cfn "upcall_test" [[::ffi/fn [] ::mem/c-string]] ::mem/c-string)
|
||||
(fn [] "hello"))
|
||||
"hello")))
|
||||
|
||||
(mem/defalias ::alignment-test
|
||||
(layout/with-c-layout
|
||||
[::mem/struct
|
||||
[[:a ::mem/char]
|
||||
[:x ::mem/double]
|
||||
[:y ::mem/float]]]))
|
||||
|
||||
(t/deftest padding-matches
|
||||
(t/is (= (dissoc ((ffi/cfn "get_struct" [] ::alignment-test)) ::layout/padding)
|
||||
{:a \x
|
||||
:x 3.14
|
||||
:y 42.0})))
|
||||
|
|
|
|||
Loading…
Reference in a new issue