2017-07-22 60 views
0

我一直在努力解決這個小問題一段時間。我試圖創建我自己的內部JSON結構的實現。面臨的挑戰是,對於Ada,我必須使用訪問類型來遞歸,如果我沒有嚴格控制,訪問類型有泄漏的風險。爲了控制它,我將所有真正的活動保留爲私有,我爲節點類型提供了Get (Source:...)Set (Target:...; Value:...)函數/過程,它們將嘗試驗證和處理任何現有的Vector(json-array)或Map(json-object)元素。爲了進一步確保我使用Ada 2012的穩定功能,並在內容超出範圍時捕獲內容,我嘗試使用Protected_Controlled類型和「管理」Ada庫,但發現容器庫無法處理受保護的類型,所以我只用了Controlled。 Finalize (...)過程適用於任何Vector或Map類型,並遞歸釋放Node_Value.Reference。在Ada中,我如何遞歸映射和內存管理自己的類型

我的問題是如果我正確應用Ada 2012,或者如何創建一個可以是矢量/地圖或字符串/數字的內存管理遞歸?

private 

    ... 

    type Node_Access is access Node; 
    type Node_Value is new Ada.Finalization.Controlled with record 
     Reference : Node_Access; 
    end record; 
    overriding procedure Initialize (Item : in out Node_Value); 
    overriding procedure Adjust (Item : in out Node_Value); 
    overriding procedure Finalize (Item : in out Node_Value); 

    ... 

    package Of_Array is new Ada.Containers.Indefinite_Vectors (Natural, Node_Value); 
    package Of_Object is new Ada.Containers.Indefinite_Ordered_Maps (Wide_String, Node_Value); 

    type Node is record 
     ... 
     Vector : aliased Of_Array.Vector; 
     Object : aliased Of_Object.Map; 
    end record 
    with Size => 96; 

    procedure Free is new Ada.Unchecked_Deallocation (Node, Node_Access); 
+0

你看過['GNATCOLL.JSON'](https://docs.adacore.com/gnatcoll-docs/json.html)嗎? – trashgod

+0

如果判別式有默認值,你的節點[可以是可變的](https://en.wikibooks.org/wiki/Ada_Programming/Types/record#Mutable- and_immutable_variant_records) –

+0

@trashgod Thankyou,但正如任何_serious_ beginner I我希望能夠變得足夠好,我不必依賴GPL庫。我喜歡GCC修改的GPL,LGPL和其他各種。我更喜歡這種方式發佈我自己的代碼。我已經分析了情況,對我來說,GPL許可證問題太複雜了,有點像軟件專利,它往往會減緩實際進展。無論如何,這是_my_嘗試使JSON儘可能接近原生Ada的風格和功能。感謝大家的幫助! (特別是你西蒙賴特) –

回答

1

做(在我看來)的方法是使用OOP和有一個抽象元件作爲家族的代表不同類型的數據可以存儲類型的根節點。

然後,可以將元素數組實現爲以抽象元素類型爲根的類的向量。一個「對象」可以作爲一個帶有字符串鍵的哈希表來實現,並且這個類根據抽象元素類型作爲值來實現。

+0

在編輯/修剪到我現在呈現的內容之前,這正是我採用的方法。我也可以回到它,但因爲在堆中聲明的對象是不可變的,所以我離開了這個模型。我可以回過頭去看看,因爲我清楚地忽略了標準庫Maps和Vectors對象在新作業之前需要銷燬/釋放的事實,所以可變性不再重要了......感謝您的額外幫助。 –

+0

@MicahW這聽起來像你誤解了一些事情。不可變的,存儲在一個存儲池(相當於堆的Ada)不是以任何方式連接的概念。而且,用戶不必在標準庫中的地圖和矢量上調用任何「銷燬/釋放」操作。 –

+0

你在沒有預期的地方閱讀推理。粗糙的程序員不需要爲標準庫容器調用Free;我指的是在給定位置釋放組件的內部_邏輯_必要性(即SomeVector(3))。我很高興錯在這裏,但是我讀到的是,如果一個變量用**'new' **聲明,那麼存儲池中的實際是不可變的。這是唯一的關係(因此我的措辭「堆只」)。 –

1

沒有訪問類型的自引用類型是與無限容器結合使用的類型擴展的有效用法。一個簡單的例子是S表達式,或者性別。性別既可以是一個原子,也可以是一個零或更多的性別列表。能夠做到這一點的正確方法是

with Ada.Containers.Indefinite_Vectors; 
package Sexes is 
    type Sex is private; 
    -- Operations on Sex 
private -- Sexes 
    package Sex_List is new Ada.Containers.Indefinite_Vectors 
     (Index_Type => Positive, Element_Type => Sex); -- Illegal 

    type Sex (Is_Atom : Boolean := False) is record 
     case Is_Atom is 
     when False => 
     Value : Atom; 
     when True => 
     List : Sex_List.Vector; 
     end case; 
    end record; 
end Sexes; 

但是Ada不允許這樣做。我們可以使用類型擴展來解決這個問題:

private -- Sexes 
    type Root is tagged null record; 

    package Sex_List is new Ada.Containers.Indefinite_Vectors 
     (Index_Type => Positive, Element_Type => Root'Class); 

    type Sex (Is_Atom : Boolean := False) is new Root with record 
     case Is_Atom is 
     when False => 
     Value : Atom; 
     when True => 
     List : Sex_List.Vector; 
     end case; 
    end record; 
end Sexes; 

這是合法的。唯一的問題是你必須將List中的任何內容轉換爲Sex(或者你的情況下的節點)。

HTH;對於遲到的迴應感到抱歉。

+0

好答案。根據最初的計劃,我有一個有區別的記錄,但爲了避免任何不可變的麻煩,我將它作爲節點記錄(記錄中的記錄)的組成部分。我可能會重寫我目前的實驗,以包含您建議的類向量。利用當前使用的記錄中的記錄,適當的判別式不需要對庫用戶可見。在嘗試和評估這項技術後,我會回報... –

+0

只需要檢查。公平地說,您的解決方案似乎最好,但重新編寫庫三次之後,我仍未按預期工作 - 轉換類型時,似乎直接訪問組件是無效的。 Jacob Sparre Anderson也對我的理解做出了很好的貢獻。我的下一次嘗試將使用另一個單元素Vector或List作爲Value的內部包裝,這將通過轉換可見,希望這可以工作... –