comp.lang.ada
 help / color / mirror / Atom feed
* User defined type conversion
@ 2013-05-09 14:07 Vinícius Franchini
  2013-05-09 14:50 ` Adam Beneschan
                   ` (4 more replies)
  0 siblings, 5 replies; 12+ messages in thread
From: Vinícius Franchini @ 2013-05-09 14:07 UTC (permalink / raw)


Hi Folks,
 I have a problem with a type conversion. Hereby is what I'm trying to do:

type AB is tagged
  record
    A : Unsigned_16;
    B : Unsigned_16;
  end record;

type abcde is tagged
  record
    a: Unsigned_8;
    b: Unsigned_8;
    c: Unsigned_8;
    d: Unsigned_8;
  end record;

X : AB;
Y : abcd;

X := Y;

I'd like to do a direct conversion without creating a method for it.



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: User defined type conversion
  2013-05-09 14:07 User defined type conversion Vinícius Franchini
@ 2013-05-09 14:50 ` Adam Beneschan
  2013-05-09 16:12 ` Shark8
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 12+ messages in thread
From: Adam Beneschan @ 2013-05-09 14:50 UTC (permalink / raw)


On Thursday, May 9, 2013 7:07:33 AM UTC-7, Vinícius Franchini wrote:
> Hi Folks,
> 
>  I have a problem with a type conversion. Hereby is what I'm trying to do:
> 
> type AB is tagged
>   record
>     A : Unsigned_16;
>     B : Unsigned_16;
>   end record;
> 
> type abcde is tagged
>   record
>     a: Unsigned_8;
>     b: Unsigned_8;
>     c: Unsigned_8;
>     d: Unsigned_8; 
>   end record; 
> 
> X : AB;
> Y : abcd;
> 
> X := Y;
> 
> I'd like to do a direct conversion without creating a method for it.

Yes, I'd often like the program to do what I want done without having to write any code.  Unfortunately, Ada is not expected to have mind-reading capabilities until at least Ada 2030.

I don't know what you mean by "direct conversion".  Whatever you're doing, it's not all that direct.  Obviously, using Unchecked_Conversion on the entire record type is a very bad idea since these are tagged records.  There's going to be at least one piece of data in Y that is not the same as any data in X, i.e whatever data the compiler sets aside for "tag" information.  So you'll have to define your own function

    function To_AB (Source : ABCD) return AB is ...

How you write it depends on what you're trying to do.  If the Unsigned_* types are the ones defined in Interfaces, and you're trying to combine Source.a and Source.b into an A field, and Source.c and Source.d into a B field, I'd probably just use the "or" operator and Shift_Left to produce the results, something like

    begin
        return (A => Shift_Left(Unsigned_16(Source.a), 8) or 
                     Unsigned_16(Source.b),
                B => Shift_Left(Unsigned_16(Source.c), 8) or 
                     Unsigned_16(Source.d));
    end;

or something similar depending on exactly what you're trying to do.  I haven't tested the above.

                        -- Adam  




^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: User defined type conversion
  2013-05-09 14:07 User defined type conversion Vinícius Franchini
  2013-05-09 14:50 ` Adam Beneschan
@ 2013-05-09 16:12 ` Shark8
  2013-05-09 16:50   ` Adam Beneschan
  2013-05-09 18:24 ` Jeffrey Carter
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 12+ messages in thread
From: Shark8 @ 2013-05-09 16:12 UTC (permalink / raw)


Here's two ways to do it:

    type AB is tagged
	record
	    A, B : Unsigned_16;
	end record;

    type abcd is tagged
	record
	    a,b,c,d: Unsigned_8;
	end record;

    ----------------------------------------------
    
    Function Convert(Input : AB) Return abcd is
	-- Note, these records could have dummy variables and layout
	-- clauses to exactly match the tagged-record's fields.
	type ut_AB is record
	    A, B : Unsigned_16;
	end record;

	type ut_abcd is record
	    a,b,c,d: Unsigned_8;
	end record;
	
	Function Convert is new unchecked_conversion
	  ( source => ut_AB, target => ut_abcd);
	
	-- Here we overlay the non-tagged record atop the tagged 
	-- record's fields.
	Working : ut_ab
	  with import, convention => Ada, address => input.A'Address;
    begin
	Return Result : abcd do
	    declare
		Result_Subsection : ut_abcd
		  with Import, Convention => Ada, Address => Result.A'Address;
	    begin
		-- Apply the conversion.
		Result_Subsection:= Convert(working);
	    end;
	end return;
    end Convert;

    -- This is safer than the above.
    Function Convert_Fields(Input : AB) Return abcd is
	Function High( Input : Unsigned_16 ) Return Unsigned_8 is
	begin
	    Return Unsigned_8(Shift_Right(Input, 8));
	end High;
	
	Function Low( Input : Unsigned_16 ) Return Unsigned_8 is
	begin
	    Return Unsigned_8( 16#00FF# and Input );
	End Low;
	
	A : Unsigned_8 renames High	( Input.A );
	B : Unsigned_8 renames Low	( Input.A );
	C : Unsigned_8 renames High	( Input.B );
	D : Unsigned_8 renames Low	( Input.B );
	
    begin
	Return ( A, B, C, D );
    End Convert_Fields;



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: User defined type conversion
  2013-05-09 16:12 ` Shark8
@ 2013-05-09 16:50   ` Adam Beneschan
  0 siblings, 0 replies; 12+ messages in thread
From: Adam Beneschan @ 2013-05-09 16:50 UTC (permalink / raw)


On Thursday, May 9, 2013 9:12:41 AM UTC-7, Shark8 wrote:
> Here's two ways to do it:
> 
>     type AB is tagged
> 	record
> 	    A, B : Unsigned_16;
> 	end record;
> 
>     type abcd is tagged
> 	record
> 	    a,b,c,d: Unsigned_8;
> 	end record;
> 
>     ----------------------------------------------
> 
>     Function Convert(Input : AB) Return abcd is
> 	-- Note, these records could have dummy variables and layout
> 	-- clauses to exactly match the tagged-record's fields.
> 	type ut_AB is record
> 	    A, B : Unsigned_16;
> 	end record;
> 
> 
> 	type ut_abcd is record
> 	    a,b,c,d: Unsigned_8;
> 	end record;
> 
> 	Function Convert is new unchecked_conversion
> 	  ( source => ut_AB, target => ut_abcd);
> 
> 	-- Here we overlay the non-tagged record atop the tagged 
> 	-- record's fields.
> 
> 	Working : ut_ab
> 	  with import, convention => Ada, address => input.A'Address;
>     begin
> 	Return Result : abcd do
> 	    declare
> 		Result_Subsection : ut_abcd
> 		  with Import, Convention => Ada, Address => Result.A'Address;
> 	    begin
> 		-- Apply the conversion.
> 		Result_Subsection:= Convert(working);
> 	    end;
> 	end return;
>     end Convert;

I definitely do not recommend this approach, because it makes some assumptions about how the original tagged records are laid out.  The assumption here is that aside from whatever data is set aside for tagged records, that the remaining fields will be arranged in order, with no gaps between the fields.  Maybe you've found that this is true when using your favorite compiler on your favorite processor.  But Ada was designed to be portable, and it saddens me a bit that so many of its fans think it's OK to write code that works only for one specific platform, especially when we don't know whether that's the platform that the OP is using.

There are two reasons why these assumptions aren't valid:

(1) There are some processors out there that are not byte-addressable.  Not a lot, but there are some.  Analog Devices' ADI 21xxx series comes to mind.  When targeting a processor like that, it's entirely possible that the Unsigned_8 fields in ABCD will be allocated one byte per 32-bit word.

(2) The compiler vendor may have decided to impose additional alignment requirements on fields in tagged types.  This one's a stretch, I know.  But I do have vague recollections that the additional semantics of tagged types, type extensions, and dispatching, sometimes does have an effect on record layout.

Anyway, one should **not** make assumptions about how fields are laid out unless there's a representation clause laying everything out.  And it's normally not a good idea to put a representation clause on a tagged type, in code that's supposed to be portable, because you really don't know what a particular implementation may require when it comes to setting aside fields for tagged types.  

If the OP needs efficiency so badly that some sort of copy operation is absolutely needed, then I'd recommend defining *untagged* record types with these fields and with representation clauses, and redefining the tagged types to have one component whose type is one of these untagged record types.  Only then would I trust an Unchecked_Conversion or overlay to work correctly.

                             -- Adam



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: User defined type conversion
  2013-05-09 14:07 User defined type conversion Vinícius Franchini
  2013-05-09 14:50 ` Adam Beneschan
  2013-05-09 16:12 ` Shark8
@ 2013-05-09 18:24 ` Jeffrey Carter
  2013-05-09 18:39   ` Vinícius Franchini
  2013-05-12  7:04 ` ldries46
  2013-05-12 15:02 ` anon
  4 siblings, 1 reply; 12+ messages in thread
From: Jeffrey Carter @ 2013-05-09 18:24 UTC (permalink / raw)


On 05/09/2013 07:07 AM, Vin�cius Franchini wrote:
>
> type AB is tagged
>    record
>      A : Unsigned_16;
>      B : Unsigned_16;
>    end record;
>
> type abcde is tagged
>    record
>      a: Unsigned_8;
>      b: Unsigned_8;
>      c: Unsigned_8;
>      d: Unsigned_8;
>    end record;
>
> X : AB;
> Y : abcd;
>
> X := Y;

The type of Y (Abcd) is undefined, so it's impossible to tell what you're trying 
to do. Also, types Unsigned_16 and Unsigned_8 are undefined.

Even if we presume that you meant Y to be of type Abcde, and the Unsigned_* 
types to be those in package Interfaces, it's still unclear what you're trying 
to do. Which parts of Y do you expect to be combined into which parts of X, and 
in what way? Since you haven't specified this, other responses you've received 
that presume that certain parts of Y are specific bytes of parts of X may not be 
correct.

Are you striving, as a good software engineer, to accomplish your goal in a 
portable way? Bear in mind that some platforms are big endian and others little 
endian, some byte addressable and others not. Since these are tagged records 
(why?), bear in mind that they contain a tag field, and the language does not 
specify where that field is located in objects of the type, nor where the other 
fields are located. All these factors make the solution using similar untagged 
records with representation clauses and Unchecked_Conversion non-portable.

When you answer these questions, we can suggest ways to accomplish the task.

-- 
Jeff Carter
"There's no messiah here. There's a mess all right, but no messiah."
Monty Python's Life of Brian
84



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: User defined type conversion
  2013-05-09 18:24 ` Jeffrey Carter
@ 2013-05-09 18:39   ` Vinícius Franchini
  2013-05-09 19:15     ` Adam Beneschan
  2013-05-09 20:19     ` Jeffrey Carter
  0 siblings, 2 replies; 12+ messages in thread
From: Vinícius Franchini @ 2013-05-09 18:39 UTC (permalink / raw)


Thanks all for the answers. 

I see I should be more clear about my problem. What I mean a "direct conversion" is like copy all bits, in the same positions they are in the original variable to the destination variable.

I'm programming an ATMEGA2560. I doing it in a way to optimize the code and I did not want to create a method for that.

Now I'm thinking something with Union structure. It could solve.  



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: User defined type conversion
  2013-05-09 18:39   ` Vinícius Franchini
@ 2013-05-09 19:15     ` Adam Beneschan
  2013-05-09 20:00       ` Vinícius Franchini
  2013-05-09 20:19     ` Jeffrey Carter
  1 sibling, 1 reply; 12+ messages in thread
From: Adam Beneschan @ 2013-05-09 19:15 UTC (permalink / raw)


On Thursday, May 9, 2013 11:39:06 AM UTC-7, Vinícius Franchini wrote:
> Thanks all for the answers. 
> 
> I see I should be more clear about my problem. What I mean a "direct conversion" is like copy all bits, in the same positions they are in the original variable to the destination variable.

To reiterate what I said before: you do not want to copy in "all bits", since tagged types have special data that you definitely do not want to copy.  Why did you make the types tagged?  Did someone tell you that all record types should be tagged?  Are you coming from a language where all types are automatically "classes"?  Regardless, when you're dealing with a low-level type where the exact representation is very important and you need to be aware of where all the individual bits are, you probably do *not* want to make it tagged. 


> I'm programming an ATMEGA2560. I doing it in a way to optimize the code and I did not want to create a method for that.

I'm still not clear on what you mean by "did not want to create a method".  What, exactly, did you want to create? 


> Now I'm thinking something with Union structure. It could solve.

In my opinion this is worse.  The only "union" in Ada is Unchecked_Union.  The only real purpose of Unchecked_Union is so that you can define structures that you want imported C code to work with.  You should not use it for the kind of purpose you're looking for.

I think what you really want to do is: get rid of "tagged" and declare two untagged record types, add record representation clauses to them to make sure the compiler puts the fields at the correct bit locations, and use Unchecked_Conversion to convert from one record type to the other.

                            -- Adam 



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: User defined type conversion
  2013-05-09 19:15     ` Adam Beneschan
@ 2013-05-09 20:00       ` Vinícius Franchini
  0 siblings, 0 replies; 12+ messages in thread
From: Vinícius Franchini @ 2013-05-09 20:00 UTC (permalink / raw)


On Thursday, May 9, 2013 4:15:17 PM UTC-3, Adam Beneschan wrote:
> On Thursday, May 9, 2013 11:39:06 AM UTC-7, Vinícius Franchini wrote:
> 
> > Thanks all for the answers. 
> 
> > 
> 
> > I see I should be more clear about my problem. What I mean a "direct conversion" is like copy all bits, in the same positions they are in the original variable to the destination variable.
> 
> 
> 
> To reiterate what I said before: you do not want to copy in "all bits", since tagged types have special data that you definitely do not want to copy.  Why did you make the types tagged?  Did someone tell you that all record types should be tagged?  Are you coming from a language where all types are automatically "classes"?  Regardless, when you're dealing with a low-level type where the exact representation is very important and you need to be aware of where all the individual bits are, you probably do *not* want to make it tagged. 
> 
> 
> 
> 
> 
> > I'm programming an ATMEGA2560. I doing it in a way to optimize the code and I did not want to create a method for that.
> 
> 
> 
> I'm still not clear on what you mean by "did not want to create a method".  What, exactly, did you want to create? 
> 
> 
> 
> 
> 
> > Now I'm thinking something with Union structure. It could solve.
> 
> 
> 
> In my opinion this is worse.  The only "union" in Ada is Unchecked_Union.  The only real purpose of Unchecked_Union is so that you can define structures that you want imported C code to work with.  You should not use it for the kind of purpose you're looking for.
> 
> 
> 
> I think what you really want to do is: get rid of "tagged" and declare two untagged record types, add record representation clauses to them to make sure the compiler puts the fields at the correct bit locations, and use Unchecked_Conversion to convert from one record type to the other.
> 
> 
> 
>                             -- Adam

After you insist in the "tagged", I think I did not pay the proper attention to this. Sorry. I put it because I planned to use inheritance, but I did not. I really do not need this and I will remove. The tip about Union is very good. I will use the Unchecked_Conversion to conversions.
Any more tip ?

Thanks for your attention



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: User defined type conversion
  2013-05-09 18:39   ` Vinícius Franchini
  2013-05-09 19:15     ` Adam Beneschan
@ 2013-05-09 20:19     ` Jeffrey Carter
  1 sibling, 0 replies; 12+ messages in thread
From: Jeffrey Carter @ 2013-05-09 20:19 UTC (permalink / raw)


On 05/09/2013 11:39 AM, Vin�cius Franchini wrote:
>
> I see I should be more clear about my problem. What I mean a "direct
> conversion" is like copy all bits, in the same positions they are in the
> original variable to the destination variable.

Since you do not know what bits are where in either of the 2 types (the compiler 
may put the fields in any order, and may put unused space between fields), you 
have no idea what you'll end up with. This is exacerbated by the implicit tag 
fields, since these are tagged types, which the compiler may put anywhere in the 
representation, and may separate them from other fields with unused space. 
Unless you've investigated exactly how your compiler lays out these records and 
are sure that copying the bits gives you what you want, and are never going to 
use another processor or compiler (including a different version of the same 
compiler) without reinvestigating and possibly rewriting the code, this is not a 
good idea. (If those conditions apply, then you can simply use 
Unchecked_Conversion between the 2 types.)

> I'm programming an ATMEGA2560. I doing it in a way to optimize the code and I
> did not want to create a method for that.

Premature optimization, and all that. Doing it portably will no doubt meet your 
timing requirements and be a much better choice.

> Now I'm thinking something with Union structure. It could solve.

Not a good idea.

-- 
Jeff Carter
"There's no messiah here. There's a mess all right, but no messiah."
Monty Python's Life of Brian
84



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: User defined type conversion
  2013-05-09 14:07 User defined type conversion Vinícius Franchini
                   ` (2 preceding siblings ...)
  2013-05-09 18:24 ` Jeffrey Carter
@ 2013-05-12  7:04 ` ldries46
  2013-05-12 14:13   ` AdaMagica
  2013-05-12 15:02 ` anon
  4 siblings, 1 reply; 12+ messages in thread
From: ldries46 @ 2013-05-12  7:04 UTC (permalink / raw)


Is a variant record perhaps the solution for your problem.

type Rec = (bit16, bit 8);
type ABC is
   record
      Option : Rec;
      case Option
         when bit16 =>
              A16 : Unsigned_16;
              B16 : Unsigned_16;
        when bit8 =>
              A8 : Unsigned_8;
              B8 : Unsigned_8;
              C8 : Unsigned_8;
              D8 : Unsigned_8;
      end case;
   end record;
It seems to me yhat changing Option will change the output of the record.

L. Dries

"Vin�cius Franchini"  schreef in bericht 
news:c9c8b269-fb9e-4715-b48c-40047fff1658@googlegroups.com...

Hi Folks,
I have a problem with a type conversion. Hereby is what I'm trying to do:

type AB is tagged
  record
    A : Unsigned_16;
    B : Unsigned_16;
  end record;

type abcde is tagged
  record
    a: Unsigned_8;
    b: Unsigned_8;
    c: Unsigned_8;
    d: Unsigned_8;
  end record;

X : AB;
Y : abcd;

X := Y;

I'd like to do a direct conversion without creating a method for it. 




^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: User defined type conversion
  2013-05-12  7:04 ` ldries46
@ 2013-05-12 14:13   ` AdaMagica
  0 siblings, 0 replies; 12+ messages in thread
From: AdaMagica @ 2013-05-12 14:13 UTC (permalink / raw)


On Sunday, May 12, 2013 9:04:36 AM UTC+2, ldries46 wrote:
> Is a variant record perhaps the solution for your problem.
>
> type Rec = (bit16, bit 8);
>
> type ABC is
>    record
>       Option : Rec;
>       case Option
>          when bit16 =>
>               A16 : Unsigned_16;

That doesn't compile. Option must be a discriminant and then you can't change the view by just changing the discriminant.
You might think that Unchecked_Union is the solution, but the program is erroneous if the record is read with the wrong discriminant.

The correct way is Unchecked_Conversion, as has been said before.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: User defined type conversion
  2013-05-09 14:07 User defined type conversion Vinícius Franchini
                   ` (3 preceding siblings ...)
  2013-05-12  7:04 ` ldries46
@ 2013-05-12 15:02 ` anon
  4 siblings, 0 replies; 12+ messages in thread
From: anon @ 2013-05-12 15:02 UTC (permalink / raw)


with Interfaces ;
with Text_IO ;

with Unchecked_Conversion ;

procedure RTest is

  use Interfaces ;
  use Text_IO ;

  -- Method One: Use pragma Unchecked_Union

  type Type_08 is record 
                    A8 : Unsigned_8 ;
                    B8 : Unsigned_8 ;
                    C8 : Unsigned_8 ;
                    D8 : Unsigned_8 ;
                  end record ;

  type Type_16 is record 
                    A16 : Unsigned_16 ;
                    B16 : Unsigned_16 ;
                  end record ;

  type Rec is ( bit32, bit16, bit8 ) ;

  type ABC ( Option : Rec := bit32 ) is record
                                   case Option is
                                       when bit8 =>
                                           Data_08 : Type_08 ;
                                       when bit16 =>
                                           Data_16 : Type_16 ;
                                       when bit32 =>
                                           Data_32 : Unsigned_32 ;
                                   end case;
                               end record;

    pragma Unchecked_Union ( ABC ) ;

  Test : ABC ;


  -- Method Two: Use arrays with Unchecked_Conversion function

  type Array_08 is array ( 0 .. 3 ) of Unsigned_8 ;
  type Array_16 is array ( 0 .. 1 ) of Unsigned_16 ;

  Data_08 : Array_08 ;
  Data_16 : Array_16 ;

  function Convert is new Unchecked_Conversion 
                                      ( Source => Array_08,
                                        Target => Array_16 ) ;

  function Convert is new Unchecked_Conversion 
                                      ( Source => Array_16,
                                        Target => Array_08 ) ;

begin
  ----------------------------------------------
  --  Method One: Use pragma Unchecked_Union  --
  ----------------------------------------------

  --
  -- To access 32 bit variables
  --
  Test.Data_32 := 0 ;
  --
  -- To access 16 bit variables
  --
  Test.Data_16.A16 := 0 ;
  Test.Data_16.B16 := 1023 ;

  --
  -- To access 8 bit variables
  --
  Put ( Unsigned_8 ' Image ( Test.Data_08.A8 ) ) ;
  Put ( Unsigned_8 ' Image ( Test.Data_08.B8 ) ) ;
  Put ( Unsigned_8 ' Image ( Test.Data_08.C8 ) ) ;
  Put ( Unsigned_8 ' Image ( Test.Data_08.D8 ) ) ;
  New_Line ;

  -----------------------------------------------------------------
  --  Method Two: Use arrays with Unchecked_Conversion function  --
  -----------------------------------------------------------------
  Data_08 := ( 16#FE#, 16#FF#, 16#FF#, 16#FE# ) ; 

  Data_16 := Convert ( Data_08 ) ;

  Put ( Unsigned_16 ' Image ( Data_16 ( 0 ) ) ) ;
  Put ( Unsigned_16 ' Image ( Data_16 ( 1 ) ) ) ;
  New_Line ;

end ;

In <c9c8b269-fb9e-4715-b48c-40047fff1658@googlegroups.com>, =?ISO-8859-1?Q?Vin=EDcius_Franchini?= <viniciusnf@gmail.com> writes:
>Hi Folks,
> I have a problem with a type conversion. Hereby is what I'm trying to do:
>
>type AB is tagged
>  record
>    A : Unsigned_16;
>    B : Unsigned_16;
>  end record;
>
>type abcde is tagged
>  record
>    a: Unsigned_8;
>    b: Unsigned_8;
>    c: Unsigned_8;
>    d: Unsigned_8;
>  end record;
>
>X : AB;
>Y : abcd;
>
>X := Y;
>
>I'd like to do a direct conversion without creating a method for it.



^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2013-05-12 15:02 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-05-09 14:07 User defined type conversion Vinícius Franchini
2013-05-09 14:50 ` Adam Beneschan
2013-05-09 16:12 ` Shark8
2013-05-09 16:50   ` Adam Beneschan
2013-05-09 18:24 ` Jeffrey Carter
2013-05-09 18:39   ` Vinícius Franchini
2013-05-09 19:15     ` Adam Beneschan
2013-05-09 20:00       ` Vinícius Franchini
2013-05-09 20:19     ` Jeffrey Carter
2013-05-12  7:04 ` ldries46
2013-05-12 14:13   ` AdaMagica
2013-05-12 15:02 ` anon

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox