* S'Write and How To Count Bytes @ 2000-09-30 0:00 Marin David Condic 2000-10-01 0:00 ` David C. Hoos, Sr. ` (2 more replies) 0 siblings, 3 replies; 29+ messages in thread From: Marin David Condic @ 2000-09-30 0:00 UTC (permalink / raw) Suppose I have a type something like this: type My_Record is record A_String : Unbounded_String := Null_Unbounded_String ; end record ; In theory, I should be able to create an object that is derived from Ada.Streams.Root_Stream_Type which has a Read and Write procedure that will allow me to create a call such as: My_Record'Write (Ptr, A_Record) ; where Ptr is a pointer to my derived Root_Stream_Type object. Now here's where it gets fun: The object derived from Root_Stream_Type is going to contain some version of a Stream_Element_Array. Possibly dynamically allocated. The Write procedure that I create for the Root_Stream_Type is going to get automagically called with a Stream_Element_Array parameter, from which you could determine the size, allocate what you need for a buffer and attach it to the Root_Stream_Type. That buffer can then be sent somewhere or used in some other manner. The problem is this: What if you want the record to contain the number of bytes that it converts to so that the number ends up in the stream? You can't easily determine how many bytes there will be in the record nor can you determine what the 'Write is really going to produce. You could possibly retain the size information in your Root_Stream_Type after the conversion, but by then its too late. You already converted it and if you had a "Count" field in the record, its value is probably dead wrong. You could convert it to the stream once, interrogate the Root_Stream_Type you built to determine the number of bytes in it, then include that byte count in your record and convert it all over again. That seems a little inefficient. Is there any good way of determining in advance how many bytes you are going to get when converting an object to a stream? MDC -- ====================================================================== Marin David Condic - Quadrus Corporation - http://www.quadruscorp.com/ Send Replies To: m c o n d i c @ q u a d r u s c o r p . c o m Visit my web site at: http://www.mcondic.com/ "Giving money and power to Government is like giving whiskey and car keys to teenage boys." -- P. J. O'Rourke ====================================================================== ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: S'Write and How To Count Bytes 2000-09-30 0:00 S'Write and How To Count Bytes Marin David Condic @ 2000-10-01 0:00 ` David C. Hoos, Sr. 2000-10-02 0:00 ` Dr. Joachim Schr�er 2000-10-02 0:00 ` Marin David Condic 2000-10-02 0:00 ` David C. Hoos, Sr. 2000-10-02 6:58 ` tmoran 2 siblings, 2 replies; 29+ messages in thread From: David C. Hoos, Sr. @ 2000-10-01 0:00 UTC (permalink / raw) If your record contains an unbounded string, I would in the My_Record'Write procedure convert the unbounded string to a Standard.String, and write its length to the stream with Natural'Write, followed by a call to String'Write. This will put the length of the string on the stream, followed by the string itself. Then, the My_Record'Read procedure would read the length from the stream, using Natural'Read, use that length to declare a string of the proper size (in a declare block), then read the string with String'Read. Finally, you would convert the string to the unbounded string component in your My_Record'Read's out parameter of type My_Record. Marin David Condic <mcondic.nospam@acm.org> wrote in message news:39D6891A.7DC448B6@acm.org... > Suppose I have a type something like this: > > type My_Record is record > A_String : Unbounded_String := Null_Unbounded_String ; > end record ; > > In theory, I should be able to create an object that is derived from > Ada.Streams.Root_Stream_Type which has a Read and Write procedure that > will allow me to create a call such as: > > My_Record'Write (Ptr, A_Record) ; > > where Ptr is a pointer to my derived Root_Stream_Type object. Now here's > where it gets fun: > > The object derived from Root_Stream_Type is going to contain some > version of a Stream_Element_Array. Possibly dynamically allocated. The > Write procedure that I create for the Root_Stream_Type is going to get > automagically called with a Stream_Element_Array parameter, from which > you could determine the size, allocate what you need for a buffer and > attach it to the Root_Stream_Type. That buffer can then be sent > somewhere or used in some other manner. > > The problem is this: What if you want the record to contain the number > of bytes that it converts to so that the number ends up in the stream? > You can't easily determine how many bytes there will be in the record > nor can you determine what the 'Write is really going to produce. You > could possibly retain the size information in your Root_Stream_Type > after the conversion, but by then its too late. You already converted it > and if you had a "Count" field in the record, its value is probably dead > wrong. You could convert it to the stream once, interrogate the > Root_Stream_Type you built to determine the number of bytes in it, then > include that byte count in your record and convert it all over again. > That seems a little inefficient. > > Is there any good way of determining in advance how many bytes you are > going to get when converting an object to a stream? > > MDC > -- > ====================================================================== > Marin David Condic - Quadrus Corporation - http://www.quadruscorp.com/ > Send Replies To: m c o n d i c @ q u a d r u s c o r p . c o m > Visit my web site at: http://www.mcondic.com/ > > "Giving money and power to Government is like giving whiskey > and car keys to teenage boys." > > -- P. J. O'Rourke > ====================================================================== > > ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: S'Write and How To Count Bytes 2000-10-01 0:00 ` David C. Hoos, Sr. @ 2000-10-02 0:00 ` Dr. Joachim Schr�er 2000-10-02 0:00 ` Marin David Condic 2000-10-02 0:00 ` Marin David Condic 1 sibling, 1 reply; 29+ messages in thread From: Dr. Joachim Schr�er @ 2000-10-02 0:00 UTC (permalink / raw) I have not thought about the original question but there is a more elegant solution for your description. The 'read, 'write attributes are for constrained types. For unconstrained types (including tagged types/classwide types) there exist the 'input, 'output attributes. Note, that 'input is a function. If you want to overwrite 'input, 'output you just have to overwrite 'read, 'write cause they are used by the former. For this and input/output of access objects/linked datastructures you should look into the relevant chapter of Norman Cohens Ada95 version of "Ada as a second language" or into the Rationale, chapter A.4.1. J. Schroer David C. Hoos, Sr. <david.c.hoos.sr@ada95.com> schrieb in im Newsbeitrag: <hXTB5.64979$Ao1.5807473@newsrump.sjc.telocity.net>... > If your record contains an unbounded string, I would in the My_Record'Write > procedure convert the unbounded string to a Standard.String, and write its > length to the stream with Natural'Write, followed by a call to String'Write. > This will put the length of the string on the stream, followed by the > string itself. > > Then, the My_Record'Read procedure would read the length from the stream, > using Natural'Read, use that length to declare a string of the proper size > (in a declare block), then read the string with String'Read. > Finally, you would convert the string to the unbounded string component in > your My_Record'Read's out parameter of type My_Record. > > > Marin David Condic <mcondic.nospam@acm.org> wrote in message > news:39D6891A.7DC448B6@acm.org snip ... ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: S'Write and How To Count Bytes 2000-10-02 0:00 ` Dr. Joachim Schr�er @ 2000-10-02 0:00 ` Marin David Condic 2000-10-06 0:00 ` Charles Hixson 0 siblings, 1 reply; 29+ messages in thread From: Marin David Condic @ 2000-10-02 0:00 UTC (permalink / raw) "Dr. Joachim Schr�er" wrote: > The 'read, 'write attributes are for constrained types. > For unconstrained types (including tagged types/classwide types) > there exist the 'input, 'output attributes. Note, that 'input > is a function. If you want to overwrite 'input, 'output you just > have to overwrite 'read, 'write cause they are used by the former. I've used the 'Input and 'Output in the process of saving and reloading things from a file. It works nicely. However, in this case, I can't have all the dope information in the output. See some of the other posts in this thread where I explain it in a little more detail. Also, even with the 'Input and 'Output, you don't seem to have any means of determining in advance how big a stream of bytes you will produce from the operation. I don't see an obvious answer and perhaps no good one exists. Probably you would have to convert the data to get the size, then convert it again to get the size into the output. MDC -- ====================================================================== Marin David Condic - Quadrus Corporation - http://www.quadruscorp.com/ Send Replies To: m c o n d i c @ q u a d r u s c o r p . c o m Visit my web site at: http://www.mcondic.com/ "Giving money and power to Government is like giving whiskey and car keys to teenage boys." -- P. J. O'Rourke ====================================================================== ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: S'Write and How To Count Bytes 2000-10-02 0:00 ` Marin David Condic @ 2000-10-06 0:00 ` Charles Hixson 0 siblings, 0 replies; 29+ messages in thread From: Charles Hixson @ 2000-10-06 0:00 UTC (permalink / raw) [-- Attachment #1: Type: text/plain, Size: 2382 bytes --] In this special case it seems to me that you could write a long 0, divide your string into fixed length blocks, writing them as you created them, figure the total block count, go back to the beginning, and write the length there, (and then, probably, move back to the eof). Since you are returning an unconstrained string, you know ahead of time the type that you are returning. The more general case, where you don't know ahead of time the KIND of value being returned, is more difficult. I don't know of any decent way to do this in a statically bound language, though Lisp, Smalltalk, Python, etc. can handle this by having a run-time interpreter manage the variable assignments. And I guess I have to add Visual Basic into this list, also, out of fairness. Marin David Condic wrote: > "Dr. Joachim Schr�er" wrote: > > > The 'read, 'write attributes are for constrained types. > > For unconstrained types (including tagged types/classwide types) > > there exist the 'input, 'output attributes. Note, that 'input > > is a function. If you want to overwrite 'input, 'output you just > > have to overwrite 'read, 'write cause they are used by the former. > > I've used the 'Input and 'Output in the process of saving and reloading things > from a file. It works nicely. However, in this case, I can't have all the dope > information in the output. See some of the other posts in this thread where I > explain it in a little more detail. Also, even with the 'Input and 'Output, you > don't seem to have any means of determining in advance how big a stream of bytes > you will produce from the operation. I don't see an obvious answer and perhaps > no good one exists. Probably you would have to convert the data to get the size, > then convert it again to get the size into the output. > > MDC > -- > ====================================================================== > Marin David Condic - Quadrus Corporation - http://www.quadruscorp.com/ > Send Replies To: m c o n d i c @ q u a d r u s c o r p . c o m > Visit my web site at: http://www.mcondic.com/ > > "Giving money and power to Government is like giving whiskey > and car keys to teenage boys." > > -- P. J. O'Rourke > ====================================================================== -- (c) Charles Hixson -- Addition of advertisements or hyperlinks to products specifically prohibited [-- Attachment #2: Card for Charles Hixson --] [-- Type: text/x-vcard, Size: 145 bytes --] begin:vcard n:Hixson;Charles x-mozilla-html:FALSE adr:;;;;;; version:2.1 email;internet:charleshixson@earthling.net fn:Charles Hixson end:vcard ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: S'Write and How To Count Bytes 2000-10-01 0:00 ` David C. Hoos, Sr. 2000-10-02 0:00 ` Dr. Joachim Schr�er @ 2000-10-02 0:00 ` Marin David Condic 2000-10-02 0:00 ` Ted Dennison 1 sibling, 1 reply; 29+ messages in thread From: Marin David Condic @ 2000-10-02 0:00 UTC (permalink / raw) "David C. Hoos, Sr." wrote: > If your record contains an unbounded string, I would in the My_Record'Write > procedure convert the unbounded string to a Standard.String, and write its > length to the stream with Natural'Write, followed by a call to String'Write. > This will put the length of the string on the stream, followed by the > string itself. > > Then, the My_Record'Read procedure would read the length from the stream, > using Natural'Read, use that length to declare a string of the proper size > (in a declare block), then read the string with String'Read. > Finally, you would convert the string to the unbounded string component in > your My_Record'Read's out parameter of type My_Record. Well, there are a couple of questions here. One if which is "How does 'Write" normally handle an Unbounded_String or any other private type for that matter?" The ARM says they are defined for any non-limited type (ARM 13.13.2{36}) but I could easily see a private type (or any type) containing Access variables - no mention of that. It mentions Elementary types, Array types, Record types, but not Access types. (Or is Access an Elementary type? If so, its still a special case) Obviously, transmitting Access variables is *not* a good idea. (What if I store an unbounded string using Stream_IO? Is it going to come back properly, or will I have just stored a now-useless access variable that used to point to the string?) The other question is: "What if you extended the type and still wanted to handle the general case with dispatching => T'Class'Write?" That's really what I want to do - not so much a specific case of Unbounded_Strings. In other words, I need to somehow get the number of bytes I'm transmitting into the stream and I can't count on the listener at the other end to be using Ada or anything else. (The device expects one of several messages with varying lengths - it needs the number of bytes as the first datum to correctly read all the data for the message before attempting to process it.) I believe I can use the 'Read and 'Write attributes to correctly get the individual data pieces into the stream, but I need to know how many bytes that is going to be before putting it in the stream. So far as I can tell, there is no way to do this except convert it to a stream, count the bytes that turned into, insert the byte count in the record, then convert it to a stream again. Awfully wasteful! Maybe for Ada0x, there should be an attribute T'Stream_Size and/or T'Class'Stream_Size. Not sure that this would not simply have to degenerate to converting everything and counting it in the background though. Thanks for the help. MDC -- ====================================================================== Marin David Condic - Quadrus Corporation - http://www.quadruscorp.com/ Send Replies To: m c o n d i c @ q u a d r u s c o r p . c o m Visit my web site at: http://www.mcondic.com/ "Giving money and power to Government is like giving whiskey and car keys to teenage boys." -- P. J. O'Rourke ====================================================================== ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: S'Write and How To Count Bytes 2000-10-02 0:00 ` Marin David Condic @ 2000-10-02 0:00 ` Ted Dennison 2000-10-02 0:00 ` tmoran 2000-10-03 0:00 ` Robert A Duff 0 siblings, 2 replies; 29+ messages in thread From: Ted Dennison @ 2000-10-02 0:00 UTC (permalink / raw) In article <39D88ACE.92DF8897@acm.org>, Marin David Condic <mcondic.nospam@acm.org> wrote: > Well, there are a couple of questions here. One if which is "How does > 'Write" normally handle an Unbounded_String or any other private type > for that matter?" The ARM says they are defined for any non-limited If they are non-composite types, they get their bit pattern written out. If they are compositie types, 'Write gets called for each component. This can be kinda nasty when you've got a big array and 'Write for that stream is not entirely trivial. > type (ARM 13.13.2{36}) but I could easily see a private type (or any > type) containing Access variables - no mention of that. It mentions The value of the access type (not what it points to) gets written. This is almost certianly *not* what you want. In that case the author of the private type needs to make their own 'Write for that type which does something more sensible (eg: 'Write on Object.all). > Obviously, transmitting Access variables is *not* a good idea. (What > if I store an unbounded string using Stream_IO? Is it going to come > back properly, or will I have just stored a now-useless access > variable that used to point to the string?) I'm not sure if implementors are required to make 'Write on unbounded strings (or bounded ones for that matter) do anything sensible. I don't see anything in the LRM about it, so I'd guess not. You should probably convert them to strings and do a String'Write (or 'Output). > > Unbounded_Strings. In other words, I need to somehow get the number of > bytes I'm transmitting into the stream and I can't count on the > listener at the other end to be using Ada or anything else. (The > device expects one of several messages with varying lengths - it needs > the number of bytes as the first datum to correctly read all the data > for the message before attempting to process it.) I believe I can use > the 'Read and 'Write attributes to correctly get the individual data > pieces into the stream, but I need to know how many bytes that is > going to be before putting it in the stream. So far as I can tell, > there is no way to do this except convert it to a stream, count the > bytes that turned into, insert the byte count in the record, then > convert it to a stream again. Awfully wasteful! I had a similar need. What I did is made my custom stream require an "Open" and "Close" (primitives on the stream type) around a series of writes. This isn't that heinous; Ada.Streams.Text_IO has a similar restriction. Open leaves a 4 byte (I guess 2 would probably suffice) space at the front of the buffer for a count. Close calculates the number of bytes between the count bytes and the end of the stream data, and puts that value into the count bytes. > Maybe for Ada0x, there should be an attribute T'Stream_Size and/or > T'Class'Stream_Size. Not sure that this would not simply have to > degenerate to converting everything and counting it in the background > though. The problem with this is that since users can make their own 'Write attribute routines, there is no way to calculate this short of actually performing the writes. You might as well just do it yourself. -- T.E.D. http://www.telepath.com/~dennison/Ted/TED.html Sent via Deja.com http://www.deja.com/ Before you buy. ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: S'Write and How To Count Bytes 2000-10-02 0:00 ` Ted Dennison @ 2000-10-02 0:00 ` tmoran 2000-10-02 0:00 ` tmoran 2000-10-02 0:00 ` Marin David Condic 2000-10-03 0:00 ` Robert A Duff 1 sibling, 2 replies; 29+ messages in thread From: tmoran @ 2000-10-02 0:00 UTC (permalink / raw) You can of course have two different "new Root_Stream_Type"s, one of which merely adds to a counter without actually copying data, and the other actually does the data copy. This is certainly faster for simple but wide things. But >The problem with this is that since users can make their own 'Write >attribute routines, there is no way to calculate this short of actually >performing the writes. So a complex composite structure necessarily makes many subroutine calls, adding up to a lot of time even if each call itself is fast. >You see the double-conversion of the record to a stream. That's got to be >inefficient. If there were some way of knowing in advance how many bytes the >record was going to take up in the stream, we could save that >double-conversion. I still don't understand. Is each Integer'Write generating a call to the IO routine, or is it writing into a buffer, which will be passed to the IO routine when it contains the entire composite record? In the latter case, which I assume to be what you mean, keep a running total of the number of bytes in the buffer, then Send(Byte_Count, The_Resulting_Stream_Element_Array) or do an Integer'Write(S, Byte_Count) to Byte_Count_Header : Stream_Element_Array(1 .. 4); and replace a junk initial integer with Buffer(1 .. 4) := Byte_Count_Header; Another option of course would be to figure out the maximum size, write into that size buffer, possibly leaving unfilled junk on the end, and pass the fixed size buffer to your output routine. It knows the size so it can checksum and send the whole fixed size block. The reader will use 'Read and get the actual data back and never even notice the trailing pads. >You can't really use the 'Write in that case because you're counting on your >representation to handle how it looks in the stream. (You might get there by >accident, but when you're building a communication link to the outside world, >you've *really* got to be sure it gets into that stream *exactly* the way you >said it would or you're going to have some really upset people at the other end >of the wire. Compiler changes could really mess you up there.) It seems to me this indicates that Stream_IO may simply be inappropriate for such an application. The only way you can really know where the bytes are is via record rep clauses, or by writing your own 'Writes to handle everything in your records. If you depend on the compiler, even for Integer'Write, some compiler might some day decide to write integers in Roman numeral form, or in some error-correcting code expanded form, or whatever, and there goes your app. My understanding is that the only thing you can depend on from the compiler is the *sequence* of 'Write calls. ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: S'Write and How To Count Bytes 2000-10-02 0:00 ` tmoran @ 2000-10-02 0:00 ` tmoran 2000-10-02 0:00 ` Ted Dennison 2000-10-02 0:00 ` Marin David Condic 2000-10-02 0:00 ` Marin David Condic 1 sibling, 2 replies; 29+ messages in thread From: tmoran @ 2000-10-02 0:00 UTC (permalink / raw) How about dropping the initial byte count and use an end-of-record indicator instead, like LF in Text_IO? ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: S'Write and How To Count Bytes 2000-10-02 0:00 ` tmoran @ 2000-10-02 0:00 ` Ted Dennison 2000-10-02 0:00 ` Marin David Condic 1 sibling, 0 replies; 29+ messages in thread From: Ted Dennison @ 2000-10-02 0:00 UTC (permalink / raw) In article <ls5C5.275608$i5.3821851@news1.frmt1.sfba.home.com>, tmoran@bix.com wrote: > How about dropping the initial byte count and use an end-of-record > indicator instead, like LF in Text_IO? > I believe he had an external hardware device whose command spec he had to match. Of course that's a whole other can of worms. You have no control over how the various 'Write's in your system represent their objects (unless you use only ones that you wrote yourself). -- T.E.D. http://www.telepath.com/~dennison/Ted/TED.html Sent via Deja.com http://www.deja.com/ Before you buy. ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: S'Write and How To Count Bytes 2000-10-02 0:00 ` tmoran 2000-10-02 0:00 ` Ted Dennison @ 2000-10-02 0:00 ` Marin David Condic 2000-10-11 0:00 ` Nick Roberts 1 sibling, 1 reply; 29+ messages in thread From: Marin David Condic @ 2000-10-02 0:00 UTC (permalink / raw) tmoran@bix.com wrote: > How about dropping the initial byte count and use an end-of-record > indicator instead, like LF in Text_IO? Clearly, one could do that. You could build your whole protocol as if it were trading lines of text. The bad news is that for the particular app I'm looking at, I've got an already defined set of messages. What I am hoping to do is find a nice, tidy way of using Ada95 to get at that message catalog and build support tools that connect to the existing system. If the answer is really good, I might even be able to sell the notion of changing the existing system and eliminate some really butt-ugly code. MDC -- ====================================================================== Marin David Condic - Quadrus Corporation - http://www.quadruscorp.com/ Send Replies To: m c o n d i c @ q u a d r u s c o r p . c o m Visit my web site at: http://www.mcondic.com/ "Giving money and power to Government is like giving whiskey and car keys to teenage boys." -- P. J. O'Rourke ====================================================================== ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: S'Write and How To Count Bytes 2000-10-02 0:00 ` Marin David Condic @ 2000-10-11 0:00 ` Nick Roberts 2000-10-11 0:00 ` Marin David Condic 0 siblings, 1 reply; 29+ messages in thread From: Nick Roberts @ 2000-10-11 0:00 UTC (permalink / raw) I would honestly suggest you abandon the use of Ada's streams totally (except, at least, within the internals of a small package), and define your own package which formalises the entire message protocol. E.g. (inventing fictitious commands etc.): package SCSI is type Device_Type is tagged limited private; type Device_Status is (Ready, Busy, Spun_Down, Down); function Status (Device: in Device_Type) return Device_Status; procedure Reset (Device: in out Device_Type); ... type Block_List is array (Positive range <>) of Block_Number; procedure Get_Bad_Sector_Map ( Device: in out Device_Type; Map: out Block_List; Last: out Natural); ... Operation_Not_Supported: exception; private ... end SCSI; package body SCSI is ... type Byte_List is array (Positive range <>) of Unsigned_8; procedure Send_Bytes (Device: in out Device_Type; Bytes: in Byte_Array) is begin ... end; procedure Read_Bytes (Device: in out Device_Type; Bytes: out Byte_Array) is begin ... end; ... procedure Get_Bad_Sector_Map ( Device: in out Device_Type; Map: out Block_List; Last: out Natural) is Prelude: Byte_Array(1..1); Data: Byte_Array(1..4); begin Send_Bytes(Device,(1=>16#0A#)); -- fictitious code for 'GETBSMAP' Read_Bytes(Device,Prelude); -- TBD: check Prelude(1) byte Last := Map'First-1; loop Read_Bytes(Device,Data); if Data = (0,0,0,0) then return; end if; Last := Last+1; Map(Last) := ( Head_Number(Data(1)), Cylinder_Number(Integer(Data(2))*256+Integer(Data(3))), Sector_Number(Data(4))); end loop; end Get_Bad_Sector_Map; ... end SCSI; You can then allocate memory at exactly the points that make the best sense. The message protocol itself will determine how efficiently this can be done. Note how I've illustrated a solution to the unknown length problem similar to that adopted by Ada.Text_IO.Get_Line on a String. Also note how SCSI.Device_Type operations can be overridden and extended, neatly accommodating irregular devices. (Not quite so butt-ugly? ;-) -- Nick Roberts http://www.AdaOS.org ----- Original Message ----- From: "Marin David Condic" <mcondic.nospam@acm.org> Newsgroups: comp.lang.ada Sent: Monday, October 02, 2000 9:26 PM Subject: Re: S'Write and How To Count Bytes > tmoran@bix.com wrote: > > > How about dropping the initial byte count and use an end-of-record > > indicator instead, like LF in Text_IO? > > Clearly, one could do that. You could build your whole protocol as if it > were trading lines of text. > > The bad news is that for the particular app I'm looking at, I've got an > already defined set of messages. What I am hoping to do is find a nice, > tidy way of using Ada95 to get at that message catalog and build support > tools that connect to the existing system. If the answer is really good, > I might even be able to sell the notion of changing the existing system > and eliminate some really butt-ugly code. ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: S'Write and How To Count Bytes 2000-10-11 0:00 ` Nick Roberts @ 2000-10-11 0:00 ` Marin David Condic 0 siblings, 0 replies; 29+ messages in thread From: Marin David Condic @ 2000-10-11 0:00 UTC (permalink / raw) I'd agree that Streams are not really the best way to accommodate this because of representation issues. However, I've had representation problems with tagged records when trying to use byte overlays on them instead of streams. I don't think your approach addresses quite what I'd like to do. I want a way of treating the message catalog I've got as if it was a class of related things with certain kinds of common characteristics. I don't think what you're proposing below allows me to do that. It looks like you'd just be overlaying your version of a byte stream on top of some record definitions and calling that the message system. I could have done that with the standard Stream_Element_Array and a bunch of plain-vanilla records. However, what I want is the *elegant*abstraction* of the problem instead of the bit-twiddler answer that I've always seen resorted to with Ada because of fighting rigorous type checking or representation problems. If I have to abandon tagged records, I lose all the nice features of dispatching and class-wide operations. Its not that you can't build something that will work - you just can't do it with grace and pinache. The tagged record and OOP is at least intellectually speaking the "right" approach because a message catalog is a kind of "class" with common operations and common data - but with divergent extensions. The collision seems to occur in that unlike most OO Classes, I've got to a) absolutely control the representation internally and outside of the box and b) I've got to get around strict type checking to be able to alternately treat the messages as either a structured, well-defined record or simply a string of bytes of known length. This is one problem wherein Ada does not seem to give me the ability to get what I want out of it and have to resort to some form of compromise. MDC Nick Roberts wrote: > I would honestly suggest you abandon the use of Ada's streams totally > (except, at least, within the internals of a small package), and define your > own package which formalises the entire message protocol. E.g. (inventing > fictitious commands etc.): > > package SCSI is > > type Device_Type is tagged limited private; > > type Device_Status is (Ready, Busy, Spun_Down, Down); > > function Status (Device: in Device_Type) return Device_Status; > > procedure Reset (Device: in out Device_Type); > > ... > > type Block_List is array (Positive range <>) of Block_Number; > > procedure Get_Bad_Sector_Map ( > Device: in out Device_Type; > Map: out Block_List; > Last: out Natural); > > ... > > Operation_Not_Supported: exception; > > private > > ... > > end SCSI; > > package body SCSI is > > ... > > type Byte_List is array (Positive range <>) of Unsigned_8; > > procedure Send_Bytes (Device: in out Device_Type; Bytes: in Byte_Array) > is > begin > ... > end; > > procedure Read_Bytes (Device: in out Device_Type; Bytes: out Byte_Array) > is > begin > ... > end; > > ... > > procedure Get_Bad_Sector_Map ( > Device: in out Device_Type; > Map: out Block_List; > Last: out Natural) is > > Prelude: Byte_Array(1..1); > Data: Byte_Array(1..4); > > begin > Send_Bytes(Device,(1=>16#0A#)); -- fictitious code for 'GETBSMAP' > Read_Bytes(Device,Prelude); > -- TBD: check Prelude(1) byte > Last := Map'First-1; > loop > Read_Bytes(Device,Data); > if Data = (0,0,0,0) then return; end if; > Last := Last+1; > Map(Last) := ( > Head_Number(Data(1)), > Cylinder_Number(Integer(Data(2))*256+Integer(Data(3))), > Sector_Number(Data(4))); > end loop; > end Get_Bad_Sector_Map; > > ... > > end SCSI; > > You can then allocate memory at exactly the points that make the best sense. > The message protocol itself will determine how efficiently this can be done. > Note how I've illustrated a solution to the unknown length problem similar > to that adopted by Ada.Text_IO.Get_Line on a String. Also note how > SCSI.Device_Type operations can be overridden and extended, neatly > accommodating irregular devices. (Not quite so butt-ugly? ;-) > > -- > Nick Roberts > http://www.AdaOS.org -- ====================================================================== Marin David Condic - Quadrus Corporation - http://www.quadruscorp.com/ Send Replies To: m c o n d i c @ q u a d r u s c o r p . c o m Visit my web site at: http://www.mcondic.com/ "Giving money and power to Government is like giving whiskey and car keys to teenage boys." -- P. J. O'Rourke ====================================================================== ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: S'Write and How To Count Bytes 2000-10-02 0:00 ` tmoran 2000-10-02 0:00 ` tmoran @ 2000-10-02 0:00 ` Marin David Condic 1 sibling, 0 replies; 29+ messages in thread From: Marin David Condic @ 2000-10-02 0:00 UTC (permalink / raw) tmoran@bix.com wrote: > I still don't understand. Is each Integer'Write generating a call to > the IO routine, or is it writing into a buffer, which will be passed > to the IO routine when it contains the entire composite record? In > Having tested this in the past by putting Text_IO calls into the stream code, you appear to get a call for each elementary data object. This will be, of course, compiler dependent. Granted, its just a memory-to-menory operation rather than an actual I/O (up to you to do the I/O and you can wait for the buffer to fill.) so the cost is not extraordinary. But still, all those subprogram calls and memory moves add up if the structure gets big or you simply do a lot of them. I'd consider it ill-advised on a hard-realtime project with limited CPU. > It seems to me this indicates that Stream_IO may simply be > inappropriate for such an application. The only way you can really know > where the bytes are is via record rep clauses, or by writing your own > 'Writes to handle everything in your records. If you depend on the > compiler, even for Integer'Write, some compiler might some day decide to > write integers in Roman numeral form, or in some error-correcting code > expanded form, or whatever, and there goes your app. My understanding > is that the only thing you can depend on from the compiler is the > *sequence* of 'Write calls. Well, you don't get any absolute guarantees. Look at ARM 13.13.2 {17} and the surrounding stuff. It seems to imply that if I don't put anything wierd into the record that I will get out what I expect. In other words, make the record elements out of things you've defined and controlled representation on such as your own integers, etc., of known sizes. If I had something like: type X is record Int1 : SInt_32 ; Int2 : SInt_16 ; Flt1 : Float_96 ; end record ; Even if the compiler puts in padding to longword align everything, when I do the 'Write, I should get back what I expect - barring perverse implementations. As you note, I could create my own 'Write for everything and be certain of what I get. A perfect solution would be controlled representation of the (tagged) record types and a fast overlay of a Stream_Element_Array. If you had all the attributes you needed and could get the representation you wanted, you could very rapidly shove the bytes down the hose, complete with checksums and byte counts and all the stuff you want. You'd preserve dispatching and all the high level stuff that made extending the messages painless, preserved information hiding, let you have all the type abstractions you wanted and kept the callers from doing any sort of bit-twiddling. Only problem is, I've tried very hard to make that work and can't get there without ugly compromises. MDC -- ====================================================================== Marin David Condic - Quadrus Corporation - http://www.quadruscorp.com/ Send Replies To: m c o n d i c @ q u a d r u s c o r p . c o m Visit my web site at: http://www.mcondic.com/ "Giving money and power to Government is like giving whiskey and car keys to teenage boys." -- P. J. O'Rourke ====================================================================== ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: S'Write and How To Count Bytes 2000-10-02 0:00 ` Ted Dennison 2000-10-02 0:00 ` tmoran @ 2000-10-03 0:00 ` Robert A Duff 2000-10-06 0:00 ` Randy Brukardt 1 sibling, 1 reply; 29+ messages in thread From: Robert A Duff @ 2000-10-03 0:00 UTC (permalink / raw) Ted Dennison <dennison@telepath.com> writes: > I'm not sure if implementors are required to make 'Write on unbounded > strings (or bounded ones for that matter) do anything sensible. I don't > see anything in the LRM about it, so I'd guess not. I think there's an AI on this. - Bob ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: S'Write and How To Count Bytes 2000-10-03 0:00 ` Robert A Duff @ 2000-10-06 0:00 ` Randy Brukardt 2000-10-07 0:11 ` Ted Dennison 0 siblings, 1 reply; 29+ messages in thread From: Randy Brukardt @ 2000-10-06 0:00 UTC (permalink / raw) Robert A Duff wrote in message ... >Ted Dennison <dennison@telepath.com> writes: > >> I'm not sure if implementors are required to make 'Write on unbounded >> strings (or bounded ones for that matter) do anything sensible. I don't >> see anything in the LRM about it, so I'd guess not. > >I think there's an AI on this. Indeed, it is in the Technical Corrigendum. See 13.13.2(36.1/1) in the revised ARM. Randy. (Wondering about that paragraph number? The ".1" means it is the first inserted paragraph after paragraph 36; the "/1" means that it is from revision 1 [i.e. Technical Corrigendum 1]) ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: S'Write and How To Count Bytes 2000-10-06 0:00 ` Randy Brukardt @ 2000-10-07 0:11 ` Ted Dennison 2000-10-06 0:00 ` Randy Brukardt 2000-10-07 0:00 ` Marin David Condic 0 siblings, 2 replies; 29+ messages in thread From: Ted Dennison @ 2000-10-07 0:11 UTC (permalink / raw) Randy Brukardt wrote: > Robert A Duff wrote in message ... > >Ted Dennison <dennison@telepath.com> writes: > > > >> I'm not sure if implementors are required to make 'Write on unbounded > >> strings (or bounded ones for that matter) do anything sensible. I > don't > >> see anything in the LRM about it, so I'd guess not. > > > >I think there's an AI on this. > > Indeed, it is in the Technical Corrigendum. See 13.13.2(36.1/1) in the > revised ARM. OK. I went and checked out the nifty new ARM in PDF form (html doesn't have page numbers, presumably due to the formatting limitations of html). Here's what it says: {8652/0040} For every subtype S of a language-defined nonlimited specific type T, the output generated by S'Output or S'Write shall be readable by S'Input or S'Read, respectively. This rule applies across partitions if the implementation conforms to the Distributed Systems Annex. 36.1/1 Now just reading this cold, I would have figured that "language-defined type" meant types defined by the language itself (eg: Integer), rather than defined in a package (eg: System.Address or Ada.Strings.Unbounded.Unbounded_String). Thus this passage really wouldn't have anything to say about the workability of Unbounded_String'Write. BTW: Good job to everyone involved. -- T.E.D. Home - mailto:dennison@telepath.com Work - mailto:dennison@ssd.fsi.com WWW - http://www.telepath.com/dennison/Ted/TED.html ICQ - 10545591 ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: S'Write and How To Count Bytes 2000-10-07 0:11 ` Ted Dennison @ 2000-10-06 0:00 ` Randy Brukardt 2000-10-07 0:00 ` Marin David Condic 1 sibling, 0 replies; 29+ messages in thread From: Randy Brukardt @ 2000-10-06 0:00 UTC (permalink / raw) Ted Dennison wrote in message <3A061E9A.B8F76112@telepath.com>... >OK. I went and checked out the nifty new ARM in PDF form (html doesn't have >page numbers, presumably due to the formatting limitations of html). Here's >what it says: > > {8652/0040} For every subtype S of a language-defined nonlimited > specific type T, the output generated by S'Output or S'Write shall > be readable by S'Input or S'Read, respectively. This rule applies > across partitions if the implementation conforms to the > Distributed Systems Annex. > 36.1/1 > >Now just reading this cold, I would have figured that "language-defined >type" meant types defined by the language itself (eg: Integer), rather than >defined in a package (eg: System.Address or >Ada.Strings.Unbounded.Unbounded_String). Thus this passage really wouldn't >have anything to say about the workability of Unbounded_String'Write. Of course, "language-defined" means anything defined by the standard, and thus includes the contents of any of the language-defined packages. This rule is just trying to say that these things will work, even if the native implementation wouldn't work naturally. But that's hard to say in Reference Manual terms. Randy. ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: S'Write and How To Count Bytes 2000-10-07 0:11 ` Ted Dennison 2000-10-06 0:00 ` Randy Brukardt @ 2000-10-07 0:00 ` Marin David Condic 2000-10-08 0:00 ` Jean-Pierre Rosen 1 sibling, 1 reply; 29+ messages in thread From: Marin David Condic @ 2000-10-07 0:00 UTC (permalink / raw) Ted Dennison wrote: > OK. I went and checked out the nifty new ARM in PDF form (html doesn't have > page numbers, presumably due to the formatting limitations of html). Here's > what it says: > > {8652/0040} For every subtype S of a language-defined nonlimited > specific type T, the output generated by S'Output or S'Write shall > be readable by S'Input or S'Read, respectively. This rule applies > across partitions if the implementation conforms to the > Distributed Systems Annex. > 36.1/1 > > Now just reading this cold, I would have figured that "language-defined > type" meant types defined by the language itself (eg: Integer), rather than > defined in a package (eg: System.Address or > Ada.Strings.Unbounded.Unbounded_String). Thus this passage really wouldn't > have anything to say about the workability of Unbounded_String'Write. > That's not the way I would read it if I were the Judge in Language Court. (Idea for a new T.V. series? Move over Judge Judy!) If I were the Judge, my legislating from the bench would go like this: "You guys wrote this ARM. The ARM defines the Ada language. The packages in the annexes are thus part of the Ada Language. Unbounded_String is a non-limited type in a language defined package (same as standard). Hence 36.1/1 implies that when 'Output is called, you can't just dump 32 bits of pointer into the stream - you've got to implement a 'Output that will write the contents of the Unbounded_String into the stream such that on 'Input you get back the string. Your unfunded mandate is to now go off and change your compilers." But of course, one must now ask what the implications are for 'Read and 'Write? Would they have to output the contents of the Unbounded_String? (Granted, you're on your own with respect to the length, but would it be required to treat the string properly?) MDC -- ====================================================================== Marin David Condic - Quadrus Corporation - http://www.quadruscorp.com/ Send Replies To: m c o n d i c @ q u a d r u s c o r p . c o m Visit my web site at: http://www.mcondic.com/ "Giving money and power to Government is like giving whiskey and car keys to teenage boys." -- P. J. O'Rourke ====================================================================== ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: S'Write and How To Count Bytes 2000-10-07 0:00 ` Marin David Condic @ 2000-10-08 0:00 ` Jean-Pierre Rosen 2000-10-09 0:00 ` Randy Brukardt 2000-10-11 0:00 ` Marin David Condic 0 siblings, 2 replies; 29+ messages in thread From: Jean-Pierre Rosen @ 2000-10-08 0:00 UTC (permalink / raw) [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #1: Type: text/plain, Size: 766 bytes --] "Marin David Condic" <mcondic.nospam@acm.org> a �crit dans le message news: 39DF3347.38C82563@acm.org... > If I were the Judge, my legislating from the bench would go like this: "You > guys wrote this ARM. The ARM defines the Ada language. The packages in the > annexes are thus part of the Ada Language. Well, the cover says: "Ada : the language. The standard libraries". One could argue that everything after the cardboard page belongs to the standard libraries and not the language... Picky lawyer hat off: Of course, "language defined types" applies to all types defined in the LRM. :-) -- --------------------------------------------------------- J-P. Rosen (Rosen.Adalog@wanadoo.fr) Visit Adalog's web site at http://pro.wanadoo.fr/adalog ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: S'Write and How To Count Bytes 2000-10-08 0:00 ` Jean-Pierre Rosen @ 2000-10-09 0:00 ` Randy Brukardt 2000-10-11 0:00 ` Marin David Condic 1 sibling, 0 replies; 29+ messages in thread From: Randy Brukardt @ 2000-10-09 0:00 UTC (permalink / raw) [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #1: Type: text/plain, Size: 1002 bytes --] Jean-Pierre Rosen wrote in message <8rt642$g5r$1@wanadoo.fr>... > >"Marin David Condic" <mcondic.nospam@acm.org> a �crit dans le message news: 39DF3347.38C82563@acm.org... >> If I were the Judge, my legislating from the bench would go like this: "You >> guys wrote this ARM. The ARM defines the Ada language. The packages in the >> annexes are thus part of the Ada Language. >Well, the cover says: "Ada : the language. The standard libraries". One could argue that everything after the cardboard page belongs >to the standard libraries and not the language... > >Picky lawyer hat off: Of course, "language defined types" applies to all types defined in the LRM. :-) If you look in the index, you'll find, indexed under "language-defined types", a list of all of the language defined types. It includes Unbounded_String and all of the other things declared in those packages. While the index isn't normative, its pretty clear what the intent of the language designers was. Randy. ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: S'Write and How To Count Bytes 2000-10-08 0:00 ` Jean-Pierre Rosen 2000-10-09 0:00 ` Randy Brukardt @ 2000-10-11 0:00 ` Marin David Condic 1 sibling, 0 replies; 29+ messages in thread From: Marin David Condic @ 2000-10-11 0:00 UTC (permalink / raw) Jean-Pierre Rosen wrote: > Well, the cover says: "Ada : the language. The standard libraries". One could argue that everything after the cardboard page belongs > to the standard libraries and not the language... > Ahhhh. But I said "if I were the judge" - so "Overruled!" :-) > > Picky lawyer hat off: Of course, "language defined types" applies to all types defined in the LRM. :-) Well, if you were to exclude Ada.Strings.Unbounded.Unbounded_String as not being a language defined type, on what basis might you say that Standard.String *was* a language defined type? They are both defined in packages specified by the ARM and they appear in appendices. The only difference would be names. That's why I figured it would have to apply. Of course this is not necessarily the thinking that might be applied by a compiler vendor with a non-compliant compiler and no inexpensive fix available. That's when the lawyers come onto the scene and start bayonetting the wounded. :-) MDC -- ====================================================================== Marin David Condic - Quadrus Corporation - http://www.quadruscorp.com/ Send Replies To: m c o n d i c @ q u a d r u s c o r p . c o m Visit my web site at: http://www.mcondic.com/ "Giving money and power to Government is like giving whiskey and car keys to teenage boys." -- P. J. O'Rourke ====================================================================== ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: S'Write and How To Count Bytes 2000-09-30 0:00 S'Write and How To Count Bytes Marin David Condic 2000-10-01 0:00 ` David C. Hoos, Sr. @ 2000-10-02 0:00 ` David C. Hoos, Sr. 2000-10-02 6:58 ` tmoran 2 siblings, 0 replies; 29+ messages in thread From: David C. Hoos, Sr. @ 2000-10-02 0:00 UTC (permalink / raw) In my original answer, I gave a solution specific to your example, but there is another technique I use for more general cases. This technique uses a package I call Stream_Element_array_Streams, which reads or writes to a region of memory defined by two parameters of System.Address type. The package has a procedure called Allow_Access which defines the two address parameters, and whether the operation for which access is allowed is Read or Write. This package maintains an index (initialized to 1 by the Allow_Access procedure), pointing to the next element on which the allowed operation would take place. Thus, after writing to this memory stream, the Index function of the package can be called to ascertain the number of bytes written. The actual write to the file or communications channel, can be done with Stream_Element_Array'Write, having been preceded by a call to Natural'Write to put the size on the stream first. One situation for which I use this technique is the reading of DIS PDUs from a UDP port, where the Ada type has discriminants whose values are defined by the values of octets at a fixed offset from the start of the PDU. Thus, I read the PDU using a package which delivers me a stream_element_array containing all of the octets of the UDP packet. Then, I declare the object with the discriminant obtained from the appropriate elements of that array, and finally read from the raw memory array into the Ada (tagged) type, using my Stream_Element_Array_Streams package. The reason I did not suggest the use of 'Input and 'Output (as suggested by Dr. Schroer) is that you indicated only that you wanted the _length_ of the stream of bytes produced by the 'Write, whereas 'Input and 'Output write the 'First and 'Last for arrays, and in general insert all discriminants and/or bounds into the stream. I know this has been wordy, but I hope it helps. > ----- Original Message ----- > From: "Marin David Condic" <mcondic.nospam@acm.org> > To: "David C. Hoos, Sr." <david.c.hoos.sr@ada95.com> > Sent: Monday, October 02, 2000 7:37 AM > Subject: RE: S'Write and How To Count Bytes > Well, there are a couple of questions here. One if which is "How does > 'Write" normally handle an Unbounded_String or any other private type for > that matter?" The ARM says they are defined for any non-limited type (ARM > 13.13.2{36}) but I could easily see a private type (or any type) containing > Access variables - no mention of that. It mentions Elementary types, Array > types, Record types, but not Access types. (Or is Access an Elementary type? > If so, its still a special case) Obviously, transmitting Access variables is > *not* a good idea. (What if I store an unbounded string using Stream_IO? Is > it going to come back properly, or will I have just stored a now-useless > access variable that used to point to the string?) > The other question is: "What if you extended the type and still wanted to > handle the general case with dispatching => T'Class'Write?" That's really > what I want to do - not so much a specific case of Unbounded_Strings. In > other words, I need to somehow get the number of bytes I'm transmitting into > the stream and I can't count on the listener at the other end to be using > Ada or anything else. (The device expects one of several messages with > varying lengths - it needs the number of bytes as the first datum to > correctly read all the data for the message before attempting to process > it.) I believe I can use the 'Read and 'Write attributes to correctly get > the individual data pieces into the stream, but I need to know how many > bytes that is going to be before putting it in the stream. So far as I can > tell, there is no way to do this except convert it to a stream, count the > bytes that turned into, insert the byte count in the record, then convert it > to a stream again. Awfully wasteful! > Maybe for Ada0x, there should be an attribute T'Stream_Size and/or > T'Class'Stream_Size. Not sure that this would not simply have to degenerate > to converting everything and counting it in the background though. > > Thanks for the help. > MDC >> -----Original Message----- >> From: David C. Hoos, Sr. [mailto:david.c.hoos.sr@ada95.com] >> Sent: Monday, October 02, 2000 12:15 AM >> To: mcondic.nospam@acm.org >> Subject: Re: S'Write and How To Count Bytes >> If your record contains an unbounded string, I would in the My_Record'Write >> procedure convert the unbounded string to a Standard.String, and write its >> length to the stream with Natural'Write, followed by a call to String'Write. >> This will put the length of the string on the stream, followed by the >> string itself. >> Then, the My_Record'Read procedure would read the length from the stream, >> using Natural'Read, use that length to declare a string of the proper size >> (in a declare block), then read the string with String'Read. >> Finally, you would convert the string to the unbounded string component in >> your My_Record'Read's out parameter of type My_Record. "Marin David Condic" <mcondic.nospam@acm.org> wrote in message news:39D6891A.7DC448B6@acm.org... >>> Suppose I have a type something like this: >>> >>> type My_Record is record >>> A_String : Unbounded_String := Null_Unbounded_String ; >>> end record ; >>> >>> In theory, I should be able to create an object that is derived from >>> Ada.Streams.Root_Stream_Type which has a Read and Write procedure that >>> will allow me to create a call such as: >>> >>> My_Record'Write (Ptr, A_Record) ; >>> >>> where Ptr is a pointer to my derived Root_Stream_Type object. Now here's >>> where it gets fun: >>> >>> The object derived from Root_Stream_Type is going to contain some >>> version of a Stream_Element_Array. Possibly dynamically allocated. The >>> Write procedure that I create for the Root_Stream_Type is going to get >>> automagically called with a Stream_Element_Array parameter, from which >>> you could determine the size, allocate what you need for a buffer and >>> attach it to the Root_Stream_Type. That buffer can then be sent >>> somewhere or used in some other manner. >>> >>> The problem is this: What if you want the record to contain the number >>> of bytes that it converts to so that the number ends up in the stream? >>> You can't easily determine how many bytes there will be in the record >>> nor can you determine what the 'Write is really going to produce. You >>> could possibly retain the size information in your Root_Stream_Type >>> after the conversion, but by then its too late. You already converted it >>> and if you had a "Count" field in the record, its value is probably dead >>> wrong. You could convert it to the stream once, interrogate the >>> Root_Stream_Type you built to determine the number of bytes in it, then >>> include that byte count in your record and convert it all over again. >>> That seems a little inefficient. >>> >>> Is there any good way of determining in advance how many bytes you are >>> going to get when converting an object to a stream? >>> >>> MDC >>> -- >>> ====================================================================== >>> Marin David Condic - Quadrus Corporation - http://www.quadruscorp.com/ >>> Send Replies To: m c o n d i c @ q u a d r u s c o r p . c o m >>> Visit my web site at: http://www.mcondic.com/ >>> >>> "Giving money and power to Government is like giving whiskey >>> and car keys to teenage boys." >>> >>> -- P. J. O'Rourke >>> ====================================================================== >>> >>> ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: S'Write and How To Count Bytes 2000-09-30 0:00 S'Write and How To Count Bytes Marin David Condic 2000-10-01 0:00 ` David C. Hoos, Sr. 2000-10-02 0:00 ` David C. Hoos, Sr. @ 2000-10-02 6:58 ` tmoran 2000-10-02 0:00 ` Marin David Condic 2 siblings, 1 reply; 29+ messages in thread From: tmoran @ 2000-10-02 6:58 UTC (permalink / raw) > Is there any good way of determining in advance how many bytes you are > going to get when converting an object to a stream? I don't think I understand. Why not type Buffer_Type is new Root_Stream_Type with record Last : Natural := 0; Data : Stream_Element_Array(1 .. 1000); end record; Then each 'write can append its stuff to Data and increment Last and when they have all finished you have a count and a Stream_Element_Array to pass to your IO output routine. ----------------- The experienced programmer knows that work performed after midnight is likely to be negatively useful. ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: S'Write and How To Count Bytes 2000-10-02 6:58 ` tmoran @ 2000-10-02 0:00 ` Marin David Condic 0 siblings, 0 replies; 29+ messages in thread From: Marin David Condic @ 2000-10-02 0:00 UTC (permalink / raw) tmoran@bix.com wrote: > > Is there any good way of determining in advance how many bytes you are > > going to get when converting an object to a stream? > I don't think I understand. Why not > type Buffer_Type is new Root_Stream_Type with record > Last : Natural := 0; > Data : Stream_Element_Array(1 .. 1000); > end record; > Then each 'write can append its stuff to Data and increment Last > and when they have all finished you have a count and a Stream_Element_Array > to pass to your IO output routine. > ----------------- Well, that's pretty much what I said was one possible solution. Convert it to a stream, counting the bytes as you go. But suppose your record type looks a little more like this: type Some_Rec is tagged record Number_Of_Bytes_To_Pick_Up_Off_The_Wire : Natural ; Some_Piece_Of_Data : Any_Type_You_Like ; end record ; In the application at hand, I've got a listener at the other end of the wire expecting to see a count of how many bytes to pick up before processing. Before sending down the wire, I've got to fill in that number. I'd also like to do it in such a way that I can manage it for Some_Rec'Class so that by dispatching, all the other types derived from it are correctly handled. Now with your Buffer_Type I could do Some_Rec'Class'Write (Buff_Ptr, My_Rec); Then, (if you were a really swell guy and gave me all the right calls) I could go: My_Rec.Number_Of_Bytes_To_Pick_Up_Off_The_Wire := Toms_Pack.Bytes_In_Buffer ; Toms_Pack.Discard_Buffer (Buffer_Object) ; Some_Rec'Class'Write (Buff_Ptr, My_Rec) ; Toms_Pack.Go_Ahead_And_Send_It_Now (Buffer_Object) ; Did I explain that better this time? Hope so. You see the double-conversion of the record to a stream. That's got to be inefficient. If there were some way of knowing in advance how many bytes the record was going to take up in the stream, we could save that double-conversion. I'd like to be able to do this with some version of My_Rec'Size but I've been up and down this direction a thousand times and can never arrive at a satisfactory answer. You've got to be able to control representation, alignment of type extensions and remove the tag in the process of converting to a stream. You can't really use the 'Write in that case because you're counting on your representation to handle how it looks in the stream. (You might get there by accident, but when you're building a communication link to the outside world, you've *really* got to be sure it gets into that stream *exactly* the way you said it would or you're going to have some really upset people at the other end of the wire. Compiler changes could really mess you up there.) If you can't get there with representation clauses, you could conceivably get there with 'Write and making sure you control the sizes of the elementary types. I think I've got enough guarantees from the ARM with respect to elementary types that if I stick to things like UInt_16 and SInt_32 and other things that never pack down below the size of a byte, that the 'Write attribute will give you all this stuff packed end-to-end, pretty much like you'd anticipate. Hence your message representation is controlled by the 'Write. This is, of course, inherently slow in comparison to using a representation clause controlled record and a byte array overlay, but for this app, I'm not on a tiny little processor with no memory and 90% CPU utilization and I've got maybe 500mSec to get the job done. So I can eat the overhead of a bazillion tiny little subprogram calls to get the data in the stream. But I'd sure hate to have to eat that overhead *twice*! Thanks for the input. MDC -- ====================================================================== Marin David Condic - Quadrus Corporation - http://www.quadruscorp.com/ Send Replies To: m c o n d i c @ q u a d r u s c o r p . c o m Visit my web site at: http://www.mcondic.com/ "Giving money and power to Government is like giving whiskey and car keys to teenage boys." -- P. J. O'Rourke ====================================================================== ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: S'Write and How To Count Bytes @ 2000-10-02 0:00 tmoran 2000-10-03 5:21 ` Marin David Condic 0 siblings, 1 reply; 29+ messages in thread From: tmoran @ 2000-10-02 0:00 UTC (permalink / raw) >... I will get out what I expect. type Temperature is new Integer range 60 .. 80; for Temperature'size use 8; -- or 7 Is a Temperature'Write going to produce one byte, because that's how big Temperature is, or 4 bytes, because that's how big Integer is? type R is record Speed : Long_Integer; end record; for R use record S at 0 range 0 .. 7; end record; Will an R'Write produce one byte for S, or 8 or what? >A perfect solution would be controlled representation of the (tagged) >record types and a fast overlay of a Stream_Element_Array. I remember this discussion, but not the bottom line. What's wrong with TAG_SIZE : constant := 4; ... type This_Buffer is new Buffer with record Speed : Integer; T : Temperature; end record; for This_Buffer use record Speed at TAG_SIZE range 0 .. 7; T at Tag_Size+1 range 0 .. 7; end record; and then overlay a Stream_Element_Array? (Or a System.Storage_Elements.Storage_Array?) I'd rather trust to TAG_SIZE being 4, or at least a single thing to change, as I move between compilers, rather than trusting Stream stuff. ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: S'Write and How To Count Bytes 2000-10-02 0:00 tmoran @ 2000-10-03 5:21 ` Marin David Condic 0 siblings, 0 replies; 29+ messages in thread From: Marin David Condic @ 2000-10-03 5:21 UTC (permalink / raw) tmoran@bix.com wrote: > >... I will get out what I expect. > type Temperature is new Integer range 60 .. 80; > for Temperature'size use 8; -- or 7 > Is a Temperature'Write going to produce one byte, because that's how > big Temperature is, or 4 bytes, because that's how big Integer is? > type R is record > Speed : Long_Integer; > end record; > for R use record > S at 0 range 0 .. 7; > end record; > Will an R'Write produce one byte for S, or 8 or what? > Didn't say you couldn't create cases that would be tough to make work consistently. Said that if I used my head and declared my own primitive types that I would likely get what I wanted. It isn't that often that someone can't manage to live with "for X'Size use 8" > > >A perfect solution would be controlled representation of the (tagged) > >record types and a fast overlay of a Stream_Element_Array. > I remember this discussion, but not the bottom line. What's wrong > with > TAG_SIZE : constant := 4; > ... > type This_Buffer is new Buffer with record > Speed : Integer; > T : Temperature; > end record; > for This_Buffer use record > Speed at TAG_SIZE range 0 .. 7; > T at Tag_Size+1 range 0 .. 7; > end record; > and then overlay a Stream_Element_Array? (Or a > System.Storage_Elements.Storage_Array?) > I'd rather trust to TAG_SIZE being 4, or at least a single thing to > change, as I move between compilers, rather than trusting Stream stuff. Oh, you get part way there with that. There's a slew of other problems that come up and I'd just as soon not start that whole mess again. A lot of it involves being able to get a representation clause on the record elements and have the compiler give you what you want instead of what it wants. Problems with freezing rules. Problems with alignments when you extend the type, and so on. It really would be the elegant solution, but there doesn't seem to be a good way to make it happen in such a way that Ada will guarantee a compiler must do what you want it to do. I got tired of fighting the compiler, so I put it on the shelf until a later language revision. :-) If you're really curious, we could discuss it off-line. MDC -- ====================================================================== Marin David Condic - Quadrus Corporation - http://www.quadruscorp.com/ Send Replies To: m c o n d i c @ q u a d r u s c o r p . c o m Visit my web site at: http://www.mcondic.com/ "Giving money and power to Government is like giving whiskey and car keys to teenage boys." -- P. J. O'Rourke ====================================================================== ^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: S'Write and How To Count Bytes
@ 2000-10-03 0:00 Mario Amado Alves
2000-10-03 0:00 ` Marin David Condic
0 siblings, 1 reply; 29+ messages in thread
From: Mario Amado Alves @ 2000-10-03 0:00 UTC (permalink / raw)
To: comp.lang.ada
The "bottom line" was very simple: you may define the representation in
primary storage but not in secondary. This is what the ARM prescribes. I
also would like to see this changed in Ada20XX.
On Mon, 2 Oct 2000 tmoran@bix.com wrote:
> >... I will get out what I expect.
> type Temperature is new Integer range 60 .. 80;
> for Temperature'size use 8; -- or 7
> Is a Temperature'Write going to produce one byte, because that's how
> big Temperature is, or 4 bytes, because that's how big Integer is?
> type R is record
> Speed : Long_Integer;
> end record;
> for R use record
> S at 0 range 0 .. 7;
> end record;
> Will an R'Write produce one byte for S, or 8 or what?
>
> >A perfect solution would be controlled representation of the (tagged)
> >record types and a fast overlay of a Stream_Element_Array.
> I remember this discussion, but not the bottom line. What's wrong
> with
> TAG_SIZE : constant := 4;
> ...
> type This_Buffer is new Buffer with record
> Speed : Integer;
> T : Temperature;
> end record;
> for This_Buffer use record
> Speed at TAG_SIZE range 0 .. 7;
> T at Tag_Size+1 range 0 .. 7;
> end record;
> and then overlay a Stream_Element_Array? (Or a
> System.Storage_Elements.Storage_Array?)
> I'd rather trust to TAG_SIZE being 4, or at least a single thing to
> change, as I move between compilers, rather than trusting Stream stuff.
>
| |,| | | |RuaFranciscoTaborda24RcD 2815-249CharnecaCaparica 351+939354002
|M|A|R|I|O|
|A|M|A|D|O|DepartmentoDeInformaticaFCT/UNL 2825-114 Caparica 351+212958536
|A|L|V|E|S| fax 212948541
| | | | | | maa@di.fct.unl.pt FCT 212948300
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: S'Write and How To Count Bytes 2000-10-03 0:00 Mario Amado Alves @ 2000-10-03 0:00 ` Marin David Condic 0 siblings, 0 replies; 29+ messages in thread From: Marin David Condic @ 2000-10-03 0:00 UTC (permalink / raw) Mario Amado Alves wrote: > The "bottom line" was very simple: you may define the representation in > primary storage but not in secondary. This is what the ARM prescribes. I > also would like to see this changed in Ada20XX. Not quite. You can get around the whole mess very simply by creating a Stream_Element_Array of the appropriate size (minus the tag) and overloaying it on the object of your record type 'class. With the overlay you can compute checksums and whatever else you need, then blip the overlay down the wire. It could all be done in a class-wide operation so that it will handle all descendent types and avoids all the overhead of moving stuff around in memory and calling a bunch of small subprograms to convert the elementary objects to stream elements. You're guaranteed that your representation of data in memory is what you blipped down the wire because you just overlayed memory with a byte interpretation of it. The problem comes in when you try to start slamming representation clauses on tagged record types. You encounter a) problems with freezing rules. b) problems with alignments on descendent types, c) compiler bugs, d) no attributes for determining the size/placement of the tag within the record (implementation dependence is about all this causes) e) compiler obstinance in refusing to give you what you want. IMHO, it would work much nicer and more efficiently than relying on the stream attributes, but you just can't seem to get it to work all the way through. MDC -- ====================================================================== Marin David Condic - Quadrus Corporation - http://www.quadruscorp.com/ Send Replies To: m c o n d i c @ q u a d r u s c o r p . c o m Visit my web site at: http://www.mcondic.com/ "Giving money and power to Government is like giving whiskey and car keys to teenage boys." -- P. J. O'Rourke ====================================================================== ^ permalink raw reply [flat|nested] 29+ messages in thread
end of thread, other threads:[~2000-10-11 0:00 UTC | newest] Thread overview: 29+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2000-09-30 0:00 S'Write and How To Count Bytes Marin David Condic 2000-10-01 0:00 ` David C. Hoos, Sr. 2000-10-02 0:00 ` Dr. Joachim Schr�er 2000-10-02 0:00 ` Marin David Condic 2000-10-06 0:00 ` Charles Hixson 2000-10-02 0:00 ` Marin David Condic 2000-10-02 0:00 ` Ted Dennison 2000-10-02 0:00 ` tmoran 2000-10-02 0:00 ` tmoran 2000-10-02 0:00 ` Ted Dennison 2000-10-02 0:00 ` Marin David Condic 2000-10-11 0:00 ` Nick Roberts 2000-10-11 0:00 ` Marin David Condic 2000-10-02 0:00 ` Marin David Condic 2000-10-03 0:00 ` Robert A Duff 2000-10-06 0:00 ` Randy Brukardt 2000-10-07 0:11 ` Ted Dennison 2000-10-06 0:00 ` Randy Brukardt 2000-10-07 0:00 ` Marin David Condic 2000-10-08 0:00 ` Jean-Pierre Rosen 2000-10-09 0:00 ` Randy Brukardt 2000-10-11 0:00 ` Marin David Condic 2000-10-02 0:00 ` David C. Hoos, Sr. 2000-10-02 6:58 ` tmoran 2000-10-02 0:00 ` Marin David Condic -- strict thread matches above, loose matches on Subject: below -- 2000-10-02 0:00 tmoran 2000-10-03 5:21 ` Marin David Condic 2000-10-03 0:00 Mario Amado Alves 2000-10-03 0:00 ` Marin David Condic
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox