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/).
|
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]
|
## [Unreleased]
|
||||||
|
### Added
|
||||||
|
- New `coffi.layout` namespace with support for forcing C layout rules on structs
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- C-characters were being read as UTF-16 rather than ASCII code points
|
- 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]
|
[type]
|
||||||
(.byteSize ^MemoryLayout (c-layout 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
|
(defn alloc-instance
|
||||||
"Allocates a memory segment for the given `type`."
|
"Allocates a memory segment for the given `type`."
|
||||||
([type] (alloc-instance type (connected-scope)))
|
([type] (alloc-instance type (connected-scope)))
|
||||||
|
|
@ -776,7 +781,8 @@
|
||||||
aliased type."
|
aliased type."
|
||||||
{:style/indent [:defn]}
|
{:style/indent [:defn]}
|
||||||
[new-type aliased-type]
|
[new-type aliased-type]
|
||||||
(if (primitive-type aliased-type)
|
(if (and (s/valid? ::type aliased-type)
|
||||||
|
(primitive-type aliased-type))
|
||||||
`(let [aliased# ~aliased-type]
|
`(let [aliased# ~aliased-type]
|
||||||
(defmethod primitive-type ~new-type
|
(defmethod primitive-type ~new-type
|
||||||
[_type#]
|
[_type#]
|
||||||
|
|
@ -799,4 +805,4 @@
|
||||||
(deserialize-from segment# aliased#)))))
|
(deserialize-from segment# aliased#)))))
|
||||||
(s/fdef defalias
|
(s/fdef defalias
|
||||||
:args (s/cat :new-type qualified-keyword?
|
:args (s/cat :new-type qualified-keyword?
|
||||||
:aliased-type ::type))
|
:aliased-type any?))
|
||||||
|
|
|
||||||
|
|
@ -48,3 +48,18 @@ StringFactory get_downcall(int whichString) {
|
||||||
return 0;
|
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
|
(ns coffi.ffi-test
|
||||||
(:require
|
(:require
|
||||||
[clojure.test :as t]
|
[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")
|
(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)
|
(t/is (= ((ffi/cfn "upcall_test" [[::ffi/fn [] ::mem/c-string]] ::mem/c-string)
|
||||||
(fn [] "hello"))
|
(fn [] "hello"))
|
||||||
"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