From: Martin <martin@thedowies.com>
Subject: Re: String_Holder ?
Date: Mon, 19 Dec 2011 03:12:51 -0800 (PST)
Date: 2011-12-19T03:12:51-08:00 [thread overview]
Message-ID: <5076a388-0734-4bac-a726-bc92e4d813c2@q11g2000vbq.googlegroups.com> (raw)
In-Reply-To: slrnjerndj.1lme.lithiumcat@sigil.instinctive.eu
On Dec 18, 12:34 pm, Natasha Kerensikova <lithium...@gmail.com> wrote:
> Hello,
>
> in my few Ada projects so far, I have quite often encountered the need
> of storing a string along with other information in records. So I went
> for discriminants containing the string size, and putting the string
> directly in the record.
>
> This works well when there is only one or two strings, but with several
> of them, or in variant records, I find it quite heavy. So I was thinking
> about something like that:
>
> type String_Holder is still to be defined;
>
> function Hold (S : String) return String_Holder;
>
> function To_String (Holder : String_Holder) return String;
>
> procedure Query (Holder : String_Holder;
> Process : not null access procedure (S : String));
>
> I'm still unsure on what kind of type String_Holder should be (private,
> tagged private or interface). It would basically be a constant-size
> reference to an immutable string that is stored "somewhere".
>
> The simplest implementation would be an Unbounded_String, though if
> needed it could be improved reference counting to make assignments
> cheaper, or with a hash table to deduplicate identical strings, etc.
>
> So my question is, does it make sense to have such objects? Or am I
> getting blinded by my C past, where strings are always manipulated
> through a char* object?
>
> Assuming it does make sense, am I right in thinking it's better to have
> such a type, even if it's a thin wrapper around Unbounded_String,
> instead of using directly Unbounded_String?
>
> Assuming it does make sense to have a String_Holder, would it be better
> to have it private, tagged private or interface?
> My guess is that tagged private has no advantage over interface,
> especially with a default implementation around Unbounded_String, which
> doesn't need to be controlled, but then controlled extension would be
> heavier. Then the choice between private and interface amounts to
> whether or not it could be useful to use simultaneously several
> implementations of String_Holder in the same project. I cannot think of
> any project where it would be the case, so I would lean towards private,
> but maybe I'm lacking imagination here.
>
> Still under the same assumption, is the above specification sane, or am
> I missing something? Query procedure is probably not absolutely
> necessary, but I guess it can be occasionally useful to save a string
> copy compared to To_String, and it seems to be a very small
> implementation burden anyway.
>
> Still under the same assumption, can it be useful to provide unary "+"
> functions to tersely convert String_Holder to String, and maybe
> vice-versa, or would it do more harm (obfuscation) than good?
>
> And lastly, is there any trick to allow a String_Holder object or
> similar to be pre-elaborable?
>
> Thanks in advance for your insights,
> Natasha
Have you considered a "Flyweight"?
Here's an example in Ada2012 (which is soooo much easier to acheive
than in previous Ada versions).
The coffee flavour string is repeated in each order but only unique
strings are stored and each order context contains a reference to the
string.
In a real application, you'd want probably want to add finalization.
-- Martin
-- main.adb
with Applications; use Applications;
procedure Main is
App : Application := Create;
begin
App.Execute;
end Main;
-- applications.ads
private with Ada.Containers.Vectors;
private with Coffee_Orders.Flavours;
private with Coffee_Orders.Flavours.Factories;
limited private with Coffee_Order_Contexts;
package Applications is
type Application (<>) is tagged limited private;
function Create return Application;
procedure Execute (A : in out Application);
private
use Coffee_Orders.Flavours.Factories;
type Order is record
Context : access Coffee_Order_Contexts.Coffee_Order_Context;
Flavour : access Coffee_Orders.Flavours.Flavour;
end record;
package Order_Vectors is
new Ada.Containers.Vectors (Natural, Order);
type Application is tagged limited record
Orders : Order_Vectors.Vector;
Flavour_Factory : Coffee_Orders.Flavours.Factories.Factory;
end record;
procedure Take_Orders (A : in out Application;
Flavour : String;
Table : Integer);
end Applications;
-- applications.adb
with Ada.Text_IO; use Ada.Text_IO;
with Coffee_Order_Contexts; use Coffee_Order_Contexts;
with Coffee_Orders.Flavours; use Coffee_Orders.Flavours;
package body Applications is
function Create return Application is
begin
return Result : Application do
null;
end return;
end Create;
procedure Take_Orders (A : in out Application;
Flavour : String;
Table : Integer) is
begin
A.Orders.Append ((Context => new Coffee_Order_Context'(Create
(Table)),
Flavour =>
Flavour_Ref'(A.Flavour_Factory.Get_Flavour (Flavour))));
end Take_Orders;
procedure Execute (A : in out Application) is
begin
A.Take_Orders ("Cappuccino", 2);
A.Take_Orders ("Cappuccino", 2);
A.Take_Orders ("Frappe", 1);
A.Take_Orders ("Frappe", 1);
A.Take_Orders ("Xpresso", 1);
A.Take_Orders ("Frappe", 897);
A.Take_Orders ("Cappuccino", 97);
A.Take_Orders ("Cappuccino", 97);
A.Take_Orders ("Frappe", 3);
A.Take_Orders ("Xpresso", 3);
A.Take_Orders ("Cappuccino", 3);
A.Take_Orders ("Xpresso", 96);
A.Take_Orders ("Frappe", 552);
A.Take_Orders ("Cappuccino", 121);
A.Take_Orders ("Xpresso", 121);
for Order of A.Orders loop
Order.Flavour.Serve_Coffee (Order.Context.all);
end loop;
Put_Line ("Total Coffee_Flavor objects made:" & Integer'Image
(A.Flavour_Factory.Total_Flavours_Made));
end Execute;
end Applications;
-- coffee_order_contexts.ads
package Coffee_Order_Contexts is
type Coffee_Order_Context (<>) is tagged private;
function Create (Table : Integer) return Coffee_Order_Context;
function Table_No (COC : Coffee_Order_Context) return Integer;
private
type Coffee_Order_Context is tagged record
Table : Integer := 0;
end record;
end Coffee_Order_Contexts;
-- coffee_order_contexts.adb
package body Coffee_Order_Contexts is
function Create (Table : Integer) return Coffee_Order_Context is
begin
return Result : Coffee_Order_Context do
Result.Table := Table;
end return;
end Create;
function Table_No (COC : Coffee_Order_Context) return Integer is
begin
return COC.Table;
end Table_No;
end Coffee_Order_Contexts;
-- coffee_order_contexts-vectors.ads
with Ada.Containers.Indefinite_Vectors;
package Coffee_Order_Contexts.Vectors is
new Ada.Containers.Indefinite_Vectors (Natural,
Coffee_Order_Context);
-- coffee_orders.ads
with Coffee_Order_Contexts; use Coffee_Order_Contexts;
package Coffee_Orders is
type Coffee_Order is interface;
procedure Serve_Coffee (CO : Coffee_Order;
COC : Coffee_Order_Context) is abstract;
end Coffee_Orders;
-- coffee_orders-flavours.ads
private with Ada.Strings.Unbounded;
with Coffee_Order_Contexts; use Coffee_Order_Contexts;
package Coffee_Orders.Flavours is
type Flavour (<>) is new Coffee_Order with private;
type Flavour_Ref is access all Flavour'Class;
function Create (Name : String) return Flavour;
function "=" (L, R : Flavour) return Boolean;
overriding
procedure Serve_Coffee (F : Flavour;
COC : Coffee_Order_Context);
private
use Ada.Strings.Unbounded;
type Flavour is new Coffee_Order with record
Name : Unbounded_String;
end record;
end Coffee_Orders.Flavours;
-- coffee_orders-flavours.adb
with Ada.Strings.Equal_Case_Insensitive;
with Ada.Text_IO; use Ada.Text_IO;
package body Coffee_Orders.Flavours is
function Create (Name : String) return Flavour is
begin
return Result : Flavour do
Result.Name := To_Unbounded_String (Name);
end return;
end Create;
function "=" (L, R : Flavour) return Boolean is
begin
return Ada.Strings.Equal_Case_Insensitive (To_String (L.Name),
To_String (R.Name));
end "=";
procedure Serve_Coffee (F : Flavour;
COC : Coffee_Order_Context) is
begin
Put_Line ("Serving Coffee flavor " & To_String (F.Name)
& " to table number " & Integer'Image (COC.Table_No));
end Serve_Coffee;
end Coffee_Orders.Flavours;
-- coffee_orders-flavours-vectors.ads
with Ada.Containers.Vectors;
package Coffee_Orders.Flavours.Vectors is
new Ada.Containers.Vectors (Natural, Flavour_Ref);
-- coffee_orders-flavours-factories.ads
private with Ada.Containers.Indefinite_Hashed_Maps;
private with Ada.Strings.Equal_Case_Insensitive;
private with Ada.Strings.Hash_Case_Insensitive;
private with Ada.Strings.Unbounded;
package Coffee_Orders.Flavours.Factories is
type Factory is tagged private;
function Get_Flavour (F : in out Factory;
Name : String)
return not null access Flavour;
function Total_Flavours_Made (F : Factory) return Natural;
private
use Ada.Strings.Unbounded;
package Maps is
new Ada.Containers.Indefinite_Hashed_Maps (Key_Type =>
String,
Element_Type =>
Flavour,
Hash =>
Ada.Strings.Hash_Case_Insensitive,
Equivalent_Keys =>
Ada.Strings.Equal_Case_Insensitive);
type Factory is tagged record
Flavours : Maps.Map;
end record;
end Coffee_Orders.Flavours.Factories;
-- coffee_orders-flavours-factories.adb
package body Coffee_Orders.Flavours.Factories is
function Get_Flavour (F : in out Factory;
Name : String) return not null access
Flavour is
use type Maps.Cursor;
C : constant Maps.Cursor := F.Flavours.Find (Name);
begin
if C /= Maps.No_Element then
return F.Flavours.Constant_Reference (Name).Element;
end if;
F.Flavours.Insert (Name, Create (Name));
return F.Flavours.Constant_Reference (Name).Element;
end Get_Flavour;
function Total_Flavours_Made (F : Factory) return Natural is
begin
return Natural (F.Flavours.Length);
end Total_Flavours_Made;
end Coffee_Orders.Flavours.Factories;
next prev parent reply other threads:[~2011-12-19 11:14 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-12-18 12:34 String_Holder ? Natasha Kerensikova
2011-12-18 16:48 ` Brad Moore
2011-12-18 20:55 ` Jeffrey Carter
2011-12-18 23:08 ` Natasha Kerensikova
2011-12-19 12:14 ` Niklas Holsti
2011-12-19 11:12 ` Martin [this message]
2011-12-19 23:53 ` Randy Brukardt
2011-12-22 9:08 ` Natasha Kerensikova
2011-12-22 10:08 ` Niklas Holsti
2011-12-22 12:23 ` Simon Wright
2011-12-23 1:26 ` Randy Brukardt
2011-12-23 6:18 ` Jeffrey Carter
2011-12-22 11:40 ` AdaMagica
replies disabled
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox