2014-07-27 6 views
5

के साथ क्लोजर में मूल्य के आधार पर structs प्राप्त करना और पास करना मेरे पास एक सी एपीआई है जिसे मैं जेएनए एपीआई के माध्यम से क्लोजर के भीतर उपयोग करने की कोशिश कर रहा हूं। मेरा मुद्दा निम्नलिखित उदाहरण के साथ सबसे अच्छा प्रदर्शन किया जा सकता है। मैं एक पुस्तकालय में इस सी कोड है कहते हैं:जेएनए

typedef struct { 
    int foo; 
    int bar; 
    double baz; 
} MyStruct; 

MyStruct createStruct() { 
    MyStruct myStruct; 
    myStruct.foo = 3; 
    myStruct.bar = 4; 
    myStruct.baz = 3.14; 

    return myStruct; 
} 

double addStruct(MyStruct myStruct) { 
    return myStruct.foo + myStruct.bar + myStruct.baz; 
} 

इस उदाहरण में, मैं createStruct कॉल करने के लिए, और फिर addStruct है कि परिणाम से पारित करना चाहते हैं। यहां महत्वपूर्ण बात यह है कि MyStructमूल्य द्वारा पारित प्रकार और एक तर्क दोनों के रूप में पारित किया गया है। मुझे किसी भी समय MyStruct में फ़ील्ड के मानों को वास्तव में पढ़ने की आवश्यकता नहीं है।

साथ ही, अपने सिस्टम में, देशी कार्यों इस तरह लिपटे रहे हैं:

; `quux` is defined in `some-lib` and returns an `int` 
(let [fn- (com.sun.jna.Function/getFunction "some-lib" "quux")] 
    (fn [& args] 
    (.invoke fn- Integer (to-array args)))) 

लक्ष्य है कि इसके बाद के संस्करण Integer के लिए स्थानापन्न करने के लिए एक मूल्य के रूप में MyStruct लपेटो जाएगा एक प्रकार प्राप्त करने के लिए है।

इस विषय को कवर करने वाला एकमात्र संसाधन this article है, लेकिन यह केवल चर्चा करता है कि संदर्भ द्वारा structs को कैसे पास किया जाए।

यह देखते हुए कि, यहाँ विभिन्न दृष्टिकोणों मैं इस समस्या को हल करने के लिए लेने के लिए कोशिश की है इस प्रकार हैं:

  1. एक वर्ग है, जो JNA के built-in mechanism for creating and using structs है कि Structure से विरासत बनाएँ। उस पृष्ठ पर जानकारी को देखते हुए, मैं सिर्फ Clojure का उपयोग कर निम्नलिखित वर्ग बनाने की कोशिश की:

    class MyStruct extends Structure implements Structure.ByValue { 
        int foo; 
        int bar; 
        double baz; 
    } 
    

    deftype इस परिदृश्य के लिए काम नहीं करता है, के बाद से वर्ग सार वर्ग Structure से विरासत की जरूरत है, और gen-class नहीं करता ' टी काम नहीं करता क्योंकि कक्षा में सार्वजनिक गैर स्थैतिक फ़ील्ड foo, bar और baz होना आवश्यक है।

    जो मैं बता सकता हूं, मानक क्लोजर जावा इंटरऑप सुविधाओं में से कोई भी उपरोक्त वर्ग नहीं बना सकता है।

  2. एक वर्ग है कि Structure से विरासत बनाएँ और struct क्षेत्र गेटर/सेटर तरीकों ओवरराइड। चूंकि gen-class (मुझे विश्वास है) केवल क्लोजर निर्माण है जो प्रत्यक्ष विरासत की अनुमति देता है, और यह कई सार्वजनिक गैर स्थैतिक क्षेत्रों का समर्थन नहीं करता है, अगला विकल्प केवल फ़ील्ड का उपयोग नहीं करना है। Looking at the Structure abstract class documentation, ऐसा लगता है कि 'आभासी' संरचना फ़ील्ड का उपयोग करने के लिए ओवरराइड का एक मिश्रण होता है, जैसे कि यह वास्तव में एक अलग स्रोत (such as the state field from gen-class) से डेटा प्राप्त करता है और सेट करता है। प्रलेखन के माध्यम से देखकर, यह readField, writeField ओवरराइड करने जैसा लगता है, और कुछ अन्य विधियों का इरादा प्रभाव हो सकता है, लेकिन मुझे अस्पष्ट था कि दस्तावेज़ को पढ़ने से ऐसा कैसे किया जाए, और मुझे ऑनलाइन कोई भी उदाहरण नहीं मिल सका।

  3. एक अलग भंडारण वर्ग का उपयोग करें। देशी प्रकारों को लपेटने के लिए जेएनए में कक्षाओं का असंख्य वर्ग है।मैं सोच रहा हूं कि Structure कक्षा को परिभाषित करने और उपयोग करने के बजाय, मैं एक और जेनेरिक क्लास का उपयोग कर सकता हूं जो बिट्स की मनमानी संख्या ले सकता है (जैसे Integer 4 बिट्स चौड़ा कुछ भी हो सकता है, इस पर ध्यान दिए बिना कि स्रोत 'वास्तव में' है)। उदाहरण के लिए, यह कहना संभव है कि एक फ़ंक्शन लंबाई 16 के बाइट्स की सरणी देता है (sizeof(MyStruct) 16 है)? NativeMapped लागू करने वाले कंटेनर क्लास में एक निश्चित-आकार सरणी को लपेटने के बारे में क्या? मुझे या तो कैसे करना है इसके उदाहरण नहीं मिल सका।

+0

JNA के रूप में ब्लॉक स्मृति आवंटन प्रदान करता है 'com.sun.jna.Memory'। वहां से, आप 'Pointer.getXXX()' विधियों का उपयोग करके स्मृति में मनमाने ढंग से ऑफसेट से मनमाने ढंग से प्रकार निकाल सकते हैं। – technomage

+0

@technomage 'createStruct' के लिए रिटर्न प्रकार के रूप में 'मेमोरी' का उपयोग करके' पॉइंटर 'लौटाता है, जिसका पता' 0x0000000400000003' है। दूसरे शब्दों में, यह एक सूचक के रूप में संरचना के कच्चे स्मृति मूल्य का इलाज करता है। जब dereferencing (किसी भी 'read' या' getXXX' विधियों के माध्यम से) के माध्यम से, यह वीएम दुर्घटनाग्रस्त हो जाता है। –

+1

समस्या यह है कि 'स्ट्रक्चर' पैरामीटर और रिटर्न वैल्यू सेमेन्टिक्स कंपाइलर द्वारा भिन्न होते हैं और 'स्ट्रक्चर' लेआउट वास्तव में मूल कोड द्वारा उपयोग किया जाता है ताकि यह निर्धारित किया जा सके कि स्टैक को सही तरीके से कैसे सेट किया जाए। मैं सुझाव दे रहा था कि आप मौजूदा 'संरचना। ByValue' उदाहरण में स्मृति के मनमाने ढंग से ब्लॉक को असाइन करने के लिए' मेमोरी 'का उपयोग करने में सक्षम हो सकते हैं। – technomage

उत्तर

5

Clojure वास्तव में जो पैदा करने और लोड हो रहा है JVM बाईटकोड के लिए प्रयोग किया जाता है ASM की एक काँटेदार संस्करण, एम्बेड करता है।

इस लाइब्रेरी के शीर्ष पर, मैंने छोटा डीएसएल बनाया (यह अधूरा और शायद टूटा हुआ है) जो जावा-जैसी वाक्यविन्यास के साथ मनमाने ढंग से जावा कक्षाएं बनाने की अनुमति देता है। वर्तमान में, यह सिर्फ GitHub gist है, और केवल कक्षाओं को विस्तारित करने, इंटरफेस को लागू करने, सुपरक्लस कन्स्ट्रक्टर और फ़ील्ड कॉल करने वाले रचनाकारों को जोड़ने का समर्थन करता है।

यहाँ, ऊपर सवाल का हल है इस डीएसएल का उपयोग कर:

(def-class MyStruct :extends com.sun.jna.Structure 
        :implements [com.sun.jna.Structure$ByValue] 
    ; Declare all the constructors, which just forward their 
    ; arguments to the constructors of com.sun.jna.Structure 
    (com.sun.jna.Structure []) 
    (com.sun.jna.Structure [com.sun.jna.TypeMapper]) 
    (com.sun.jna.Structure [Integer]) 
    (com.sun.jna.Structure [Integer com.sun.jna.TypeMapper]) 
    (com.sun.jna.Structure [com.sun.jna.Pointer]) 
    (com.sun.jna.Structure [com.sun.jna.Pointer Integer]) 
    (com.sun.jna.Structure [com.sun.jna.Pointer Integer com.sun.jna.TypeMapper]) 

    ; Declare the fields of the struct 
    ^Integer foo 
    ^Integer bar 
    ^Double baz) 

अब, मैं क्या कर सकते हैं निम्नलिखित:

(defn createStruct [& args] 
    (let [fn- (com.sun.jna.Function/getFunction "some-lib" "createStruct")] 
    (.invoke fn- MyStruct (to-array args)))) 

(defn addStruct [& args] 
    (let [fn- (com.sun.jna.Function/getFunction "some-lib" "addStruct")] 
    (.invoke fn- Double (to-array args)))) 

(addStruct (createStruct)) 
; => 10.14 
संबंधित मुद्दे