Merge branch 'feature/c-layout' into develop

This commit is contained in:
Joshua Suskalo 2022-01-10 14:55:59 -06:00
commit 3709aab143
5 changed files with 72 additions and 4 deletions

View file

@ -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
View 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)))

View file

@ -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?))

View file

@ -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;
}

View file

@ -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})))