String view of file

118 views
Skip to first unread message

Jesper Quorning

unread,
Nov 21, 2022, 3:30:02 AM11/21/22
to
I like to ask about

Is it possible to write something like this with ADA

```Ada
package my_rw_file is new file
(name => "whatever"
,mode => read_write
,implementation => standard -- or portable or fast
);
package as_string is new. xxx(from => my_rw_file);

-- parse (as_string);
package data is new parse (as_string, format => markdown); -- or whatever
```

Sorry, im new to ada


Jesper Q

G.B.

unread,
Nov 21, 2022, 8:01:04 AM11/21/22
to
Do you mean, gobble up a file into a string
and then parse that? Yes, that's possible
in a number of ways.

Jeffrey R.Carter

unread,
Nov 21, 2022, 8:48:52 AM11/21/22
to
On 2022-11-21 09:30, Jesper Quorning wrote:
>
> Is it possible to write something like this with ADA

"Ada" is a woman's name, not an acronymn.

> package my_rw_file is new file
> (name => "whatever"
> ,mode => read_write
> ,implementation => standard -- or portable or fast
> );
> package as_string is new. xxx(from => my_rw_file);
>
> -- parse (as_string);
> package data is new parse (as_string, format => markdown); -- or whatever

If I presume that the '.' in the declaration of As_String is a typo, what you
have here is a sequence of related generic pkg instantiations, so you can write
this in Ada if you have the corresponding generic pkgs. I have no idea what the
result would provide.

If you want to read the arbitrary contents of a file into a String, that's
easily done:

with Ada.Directories;

package String_A_File is
use type Ada.Directories.File_Size;

function File_As_String (Name : in String) return String with
Pre => Ada.Directories.Exists (Name) and then
Ada.Directories.Size (Name) <=
Ada.Directories.File_Size (Integer'Last),
Post => File_As_String'Result'First = 1 and
File_As_String'Result'Last =
Integer (Ada.Directories.Size (Name) );
end String_A_File;

with Ada.Sequential_IO;

package body String_A_File is
function File_As_String (Name : in String) return String is
subtype FAS is String (1 .. Integer (Ada.Directories.Size (Name) ) );

package FAS_IO is new Ada.Sequential_IO (Element_Type => FAS);

File : FAS_IO.File_Type;
Result : FAS;
begin -- File_As_String
FAS_IO.Open (File => File, Mode => FAS_IO.In_File, Name => Name);
FAS_IO.Read (File => File, Item => Result;
FAS_IO.Close (File => File);

return Result;
end File_As_String;
end String_A_File;

This presumes that Result will fit on the stack. If that's likely to be a
problem, then you will need to use Unbounded_String and read the file Character
by Character.

--
Jeff Carter
"I have a very small head and I had
better learn to live with it ..."
Edsger Dijkstra
158

Dmitry A. Kazakov

unread,
Nov 21, 2022, 10:18:50 AM11/21/22
to
On 2022-11-21 09:30, Jesper Quorning wrote:

> Is it possible to write something like this with ADA
>
> ```Ada
> package my_rw_file is new file
> (name => "whatever"
> ,mode => read_write
> ,implementation => standard -- or portable or fast
> );
> package as_string is new. xxx(from => my_rw_file);
>
> -- parse (as_string);
> package data is new parse (as_string, format => markdown); -- or whatever

It is difficult to guess what you want to achieve. What it looks to me
is a design opposite to the customary approach:

abstract code source (generic and/or tagged)
/ | \
/ | \
string text_file stream

Since string and file cannot be derived, in a tagged case some mix-in is
used.

The parser from simple-components has multi-line and single-line
sources. A single-line source can be set on a string. Multi-line source
is for files and streams.

--
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de

Niklas Holsti

unread,
Nov 21, 2022, 10:52:17 AM11/21/22
to
For the OP's benefit (Jeffrey of course knows this): an alternative to
Unbounded_String is to allocate the Result string on the heap, and
return an access to the heap string. With that method, you can still
read the entire string with one call of FAS_IO.Read instead of Character
by Character.

Marius Amado-Alves

unread,
Nov 21, 2022, 11:11:06 AM11/21/22
to
Use Ada.Sequential_IO (Character), load to an Unbounded_String, save from a String or Unbounded_String.

Jeffrey R.Carter

unread,
Nov 21, 2022, 11:43:02 AM11/21/22
to
On 2022-11-21 16:52, Niklas Holsti wrote:
>
> For the OP's benefit (Jeffrey of course knows this): an alternative to
> Unbounded_String is to allocate the Result string on the heap, and return an
> access to the heap string. With that method, you can still read the entire
> string with one call of FAS_IO.Read instead of Character by Character.

I know it, and I deliberately reject it. Having access types in a pkg spec is
poor design. Delegating the associated memory management and all its
opportunities for error to the pkg client is very poor design.

If access types are used, they should be hidden and encapsulated with their
memory management. This makes it easier to get the memory management correct.
Since this is what using Unbounded_String does for you, I think it's better to
use it than to expend extra effort doing something similar.

Niklas Holsti

unread,
Nov 21, 2022, 12:29:15 PM11/21/22
to
On 2022-11-21 18:42, Jeffrey R.Carter wrote:
> On 2022-11-21 16:52, Niklas Holsti wrote:
>>
>> For the OP's benefit (Jeffrey of course knows this): an alternative to
>> Unbounded_String is to allocate the Result string on the heap, and
>> return an access to the heap string. With that method, you can still
>> read the entire string with one call of FAS_IO.Read instead of
>> Character by Character.
>
> I know it, and I deliberately reject it. Having access types in a pkg
> spec is poor design. Delegating the associated memory management and all
> its opportunities for error to the pkg client is very poor design.


I agree in general, but there are design trade-offs that depend on
issues not made clear in the original question, such as the size of the
file and the performance requirements. So I thought that the OP should
know of the heap alternative, even if it has some poorer properties too.

Qunying

unread,
Nov 21, 2022, 12:29:51 PM11/21/22
to
If you are using gnat with gnatcoll, then you may try its mmap facility, https://docs.adacore.com/gnatcoll-docs/mmap.html

Gautier write-only address

unread,
Nov 21, 2022, 4:43:40 PM11/21/22
to
You may be interested by this:
https://github.com/zertovitch/zip-ada/blob/master/zip_lib/zip_streams.ads#L148
It can be actually used out of the context of Zip archives.

Jesper Quorning

unread,
Jan 1, 2023, 6:37:00 PMJan 1
to
The original post was a bit of a mess, and I am not quite new to Ada. But I lack some skills regarding software construction and software engineering.

What I want goes something like this:
- Zero copy access to a (read-only) file.
- Get lines of file one by one as a stream of lines.
- Use a package instance as file representation.
- Stretch goal: Multiple implementations of File Instance (Standard, Fast, Compatible ..)

Refined version:
```Ada
package File
is new File_Instance
(Filename => "whatever",
Implementation => Standard);
---
for Line of File.As_Line_Stream loop
Parse (Line);
end loop;
```

I think Dewar has written something about string view of some data. I saw some tricky tricks in the GNAT.Snobol implementation. Links to papers anyone?

Sorry for the late follow-up.


/Jesper

Stephen Leake

unread,
Jan 2, 2023, 1:57:16 PMJan 2
to
Jesper Quorning <jesper....@gmail.com> writes:

> The original post was a bit of a mess, and I am not quite new to Ada. But I lack some skills regarding software construction and software engineering.
>
> What I want goes something like this:
> - Zero copy access to a (read-only) file.

You can use gnatcoll mmap to get a memory-mapped view of a file. To get
a zero-copy string, you'll have to find the line boundaries yourself,
and use unchecked-conversion on a string pointer, or an address clause
on a local variable.

> - Get lines of file one by one as a stream of lines.

'stream' has a specific meaning in Ada; better say "collection of lines"
here.

You can define an iterator for your File type.

- Use a package instance as file representation.

Why do you want to do this? The alternative is to define your own File
type, and provide an Open; then you can reuse that package for multiple
files. Closer to Ada standard practice for files.

- Stretch goal: Multiple implementations of File Instance (Standard, Fast, Compatible ..)

If you want to choose the implementation at compile time, you can use
separate bodies in implementation-specific directories, and choose the
directory in the project file.

If you want to chose the implementation at run time, you have to make
File a dispatching type. Then you pick the implementation via the
package name:

My_File : Files.Implementation_1.File;

> for Line of File.As_Line_Stream loop
> Parse (Line);
> end loop;

You probably know that you can get close to this in standard Ada, at the
cost of a copy:

while not End_of_file (File) loop
declare
Line : get_line (file);
begin
Parse (line);
end;
end loop;

An really aggressive optimizing compiler could get rid of the local
variable Line to avoid the copy, but it's not very likely.

This violates your requirement, but it could easily be that the copy is
very cheap; have you measured it in your actual application, and is
eliminating it worth the bother?

--
-- Stephe

Jeffrey R.Carter

unread,
Jan 3, 2023, 11:37:36 AMJan 3
to
On 2023-01-02 00:36, Jesper Quorning wrote:
>
> - Zero copy access to a (read-only) file.

So far as I know, any access to a file involves copying information from the
external medium into memory, so this may be impossible.

--
Jeff Carter
"Any noun can be verbed."
Alan Perlis
"Verbing weirds language."
Calvin and Hobbes
206

Dmitry A. Kazakov

unread,
Jan 3, 2023, 12:02:57 PMJan 3
to
On 2023-01-03 17:37, Jeffrey R.Carter wrote:
> On 2023-01-02 00:36, Jesper Quorning wrote:
>>
>> - Zero copy access to a (read-only) file.
>
> So far as I know, any access to a file involves copying information from
> the external medium into memory, so this may be impossible.

... in many cases copying drastically improves performance, e.g.
caching, read ahead techniques etc.
Reply all
Reply to author
Forward
0 new messages