<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body text="#000000" bgcolor="#FFFFFF">
<div class="moz-cite-prefix">Am 05.07.2019 um 08:08 schrieb Sven
Barth:<br>
</div>
<blockquote type="cite"
cite="mid:CAFMUeB_Nq5Y5CmswK2qDBFH_VdqszZiBkoDMDS+GAydxxtrozg@mail.gmail.com">
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<div dir="auto">
<div>
<div class="gmail_quote">
<div dir="ltr" class="gmail_attr">Jonas Maebe <<a
href="mailto:jonas@freepascal.org"
moz-do-not-send="true">jonas@freepascal.org</a>>
schrieb am Do., 4. Juli 2019, 21:21:<br>
</div>
<blockquote class="gmail_quote" style="margin:0 0 0
.8ex;border-left:1px #ccc solid;padding-left:1ex">On
03/07/2019 09:26, Ondrej Pokorny wrote:<br>
> On 02.07.2019 23:34, Jonas Maebe wrote:<br>
>> Invalid data means undefined behaviour, always.
"is" is not a special<br>
>> case that is immune to this.<br>
> <br>
> Don't you really see the need to handle invalid data
with a /defined/<br>
> behavior?<br>
<br>
My point is that is impossible to do so, so trying to do
it in a way<br>
that works in some/most cases, is much more dangerous than
categorically<br>
refusing to try to do it, as it creates a false sense of
security.<br>
</blockquote>
</div>
</div>
<div dir="auto"><br>
</div>
<div dir="auto">Then how would you read data from e.g. a stream
into an enum or subrange if the stream may contain invalid
data? <br>
</div>
</div>
</blockquote>
I now did a proof of concept for that task myself:<br>
<br>
=== code begin ===<br>
<br>
program tptrhlp;<br>
<br>
{$mode objfpc}<br>
{$modeswitch typehelpers}<br>
<br>
uses<br>
 Classes, SysUtils;<br>
<br>
type<br>
 TStreamHelper = type helper for TStream<br>
 public<br>
   generic function ReadEnum<T>(out aEnum: T): Boolean;<br>
 end;<br>
<br>
generic function TStreamHelper.ReadEnum<T>(out aEnum: T):
Boolean;<br>
var<br>
 buf: array[0..SizeOf(T) - 1] of Byte absolute aEnum;<br>
 tmp: LongInt;<br>
begin<br>
 if Read(buf[0], SizeOf(buf)) <> SizeOf(buf) then<br>
   Exit(False)<br>
 else begin<br>
   case SizeOf(T) of<br>
     1:<br>
       tmp := PByte(@buf[0])^;<br>
     2:<br>
       tmp := PWord(@buf[0])^;<br>
     3:<br>
       tmp := LongWord(PWord(@buf[0])^) or
(LongInt(PByte(@buf[2])^) shl 16);<br>
     4:<br>
       tmp := PLongWord(@buf[0])^;<br>
   end;<br>
   Result := (tmp >= Ord(Low(T))) and (tmp <= Ord(High(T)));<br>
 end;<br>
end;<br>
<br>
type<br>
 {$PACKENUM 1}<br>
 TMyEnum = (<br>
   meOne,<br>
   meTwo,<br>
   meThree<br>
 );<br>
var<br>
 s: TMemoryStream;<br>
 e: TMyEnum;<br>
 b: Byte;<br>
begin<br>
 s := TMemoryStream.Create;<br>
 try<br>
   try<br>
     Writeln(SizeOf(TMyEnum));<br>
     b := 1;<br>
     s.Write(b, SizeOf(b));<br>
     b := 3;<br>
     s.Write(b, SizeOf(b));<br>
     s.Position := 0;<br>
     if not s.specialize ReadEnum<TMyEnum>(e) then<br>
       raise EStreamError.Create('Failed to read enum value');<br>
     Writeln('Read value: ', e);<br>
     if not s.specialize ReadEnum<TMyEnum>(e) then<br>
       raise EstreamError.CReate('Failed to read enum value');<br>
   except<br>
     on e: Exception do<br>
       Writeln(e.ClassName, ': ', e.Message);<br>
   end;<br>
 finally<br>
   s.Free;<br>
 end;<br>
end. <br>
<br>
=== code end ===<br>
<br>
Note 1: Needs today's trunk cause I fixed generic methods in helpers
in mode ObjFPC<br>
Note 2: Similar code can also be done for ranges (though there the
sizes 5 to 8 need to be handled as well)<br>
Note 3: I didn't test whether this works correctly on Big Endian
systems<br>
Note 4: The compiler will optimize away the unneeded case branches
:)<br>
<br>
Regards,<br>
Sven<br>
</body>
</html>