Concat separated fields in one

倖福魔咒の 提交于 2020-01-24 14:54:24

问题


I'm working in Ada, I have a very ugly type that I can't modify and I want to do something easy to use.

The type is something like this :

for T_Ugly_Type'Alignment use 4;
for T_Ugly_Type'Size use 48;
for T_Ugly_Type use record
    Value_Bits_00_07  at 16#00# range 0  .. 7;   -- 8 bits
    Field1            at 16#00# range 8  .. 15;  -- 8 bits

    Field2            at 16#02# range 0  .. 11;  -- 12 bits
    Value_Bits_08_11  at 16#02# range 12 .. 15;  -- 4 bits

    Value_Bits_12_15  at 16#03# range 0  .. 3;   -- 4 bits
    Field3            at 16#03# range 4 .. 15;   -- 12 bits
end record;

This structure is filled by a message and the addresses cant's be changed. But my Value is a 16 bits type divided in 3 parts. I don't want to concat all theses parts each type I want to use it.

Is there a way to use T_Ugly_Type.Value and get the result of Value_Bits_00_07 + 2 ** 8 * Value_Bits_08_12 + 2 ** 12 * Value_Bits_12_15 ?


回答1:


Well you can do something like this:

type T_Wrapper is tagged record
   Values : T_Ugly_Type;
end record;

function Value (Subject : T_Wrapper) return Uint16 is
  (Subject.Values.Value_Bits_00_07 * 2**8 +
          Subject.Values.Value_Bits_08_12 * 2**4 +
          Subject.Values.Vaule_Bits_13_15);

function Field1 (Subject : T_Wrapper) return Uint12 is
  (Subject.Values.Field1);

function Field2 (Subject : T_Wrapper) return Uint12 is
  (Subject.Values.Field2);

function Field3 (Subject : T_Wrapper) return Uint12 is
  (Subject.Values.Field3);

Being tagged enables you to use prefix syntax on the T_Wrapper functions:

declare
   -- assuming a T_Ugly_Type instance named Orig
   Wrapped : T_Wrapper := (Values => Orig);
begin
   Do_Something (Wrapped.Value);
   Do_Something_Elese (Wrapped.Field1);
end;

Note that since the original type is not tagged, you cannot declare a Value function on it you can call with prefix notation.

A maybe somewhat nicer way to do this would be to use an access value and some Ada 2012 features:

type Reference (Data : not null access T_Ugly_Type) is tagged limited null record
  with Implicit_Dereference => Data;

function Value (Subject : Reference) return Uint16 is
  (Subject.Data.Value_Bits_00_07 * 2**8 +
   Subject.Data.Value_Bits_08_12 * 2**4 +
   Subject.Data.Vaule_Bits_13_15);

Implicit_Dereference allows you to directly access the original fields, while you can use the Value function for the calculation.

declare
   Ref : Reference := (Data => Orig'Access);
begin
   Do_Something (Ref.Value); -- calls function
   Do_Something (Ref.Field1); -- accesses Field1 of the inner record
end;


来源:https://stackoverflow.com/questions/59198028/concat-separated-fields-in-one

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!