Quantcast
Channel: Designing ParaSail, a new programming language
Viewing all articles
Browse latest Browse all 48

Example of doubly linked list in ParaSail

$
0
0
A question was posted asking how you would create in a pointer-free language like ParaSail a doubly-linked list, with constant time addition on either end of the list, and constant time removal anywhere within the list.  One straightforward way to do this is to use a Vector to store the nodes, and then use indices into the vector to create the doubly linked list. Below is such an implementation.



// Illustration of a doubly-linked list implemented in ParaSail

// Copyright (C) 2012, AdaCore, New York, NY
// To be used only for Personal, Academic, or Evaluation Purposes;
// Not for Commercial Production Use.
// Report errors at http://groups.google.com/group/parasail-programming-language

// There are two modules here, plus two test programs.
// The first module, Doubly_Linked_Index, provides a doubly-linked
// list of indices, the indices being usable with another vector
// where the actual data can be stored.

// The second module, Doubly_Linked_List, uses the Doubly_Linked_Index
// to provide the "Elem_Id" type, which is used to identify nodes in the
// linked list. It also has a formal type "Element_Type" which is the
// type of the actual data to be stored in the linked list.

interface Doubly_Linked_Index<Max_Len : Univ_Integer := 100_000> is
// Doubly-linked list acting as index into a separate vector of data
type Elem_Id isnew Integer<1..Max_Len>;
op "[]"() -> Doubly_Linked_Index;
// Create an empty linked list

func Append(var DLI : Doubly_Linked_Index) -> Elem_Id;
// Add a new node onto end of linked list

func Prepend(var DLI : Doubly_Linked_Index) -> Elem_Id;
// Add a new node at beginning of linked list

func Insert_Before(var DLI : Doubly_Linked_Index; Elem_Id)
-> optional Elem_Id;
// Insert new node before given element Id

func Insert_After(var DLI : Doubly_Linked_Index; Elem_Id)
-> optional Elem_Id;
// Insert new node after given element Id

func Remove(var DLI : Doubly_Linked_Index; Elem_Id);
// Remove specified element from linked list (if present)

op "in"(Elem_Id; DLI : Doubly_Linked_Index) -> Boolean;
// Return True if given element is in linked list

func Remove_First(var DLI : Doubly_Linked_Index) -> optional Elem_Id;
// Remove first element from linked list

func Remove_Last(var DLI : Doubly_Linked_Index) -> optional Elem_Id;
// Remove last element from linked list

func Remove_Any(var DLI : Doubly_Linked_Index) -> optional Elem_Id;
// Remove arbitrary element from linked list

func Count(DLI : Doubly_Linked_Index) -> Univ_Integer;
// Return count of elements in linked list

func Max_Id_In_Use(DLI : Doubly_Linked_Index) -> optional Elem_Id;
// Return max Elem_Id in use
endinterface Doubly_Linked_Index;



interface Doubly_Linked_List
<Element_Type is Assignable<>;
Max_Len : Univ_Integer := 100_000> is

// Doubly-linked list

type DLI isnew Doubly_Linked_Index<Max_Len>;

type Elem_Id is DLI::Elem_Id;

op "[]"() -> Doubly_Linked_List;
// Create an empty linked list

func Append(var DLL : Doubly_Linked_List; Elem : Element_Type) -> Elem_Id;
// Add a new element onto end of linked list

func Prepend(var DLL : Doubly_Linked_List; Elem : Element_Type) -> Elem_Id;
// Add a new element at beginning of linked list

func Insert_Before
(var DLL : Doubly_Linked_List; Elem : Element_Type; Elem_Id)
-> optional Elem_Id;
// Insert new element before given element Id

func Insert_After
(var DLL : Doubly_Linked_List; Elem : Element_Type; Elem_Id)
-> optional Elem_Id;
// Insert new element after given element Id

func Remove(var DLL : Doubly_Linked_List; Elem_Id);
// Remove specified element from linked list (if present)

op "in"(Elem_Id; DLL : Doubly_Linked_List) -> Boolean;
// Return True if given element is in linked list

func Remove_First(var DLL : Doubly_Linked_List) -> optional Element_Type;
// Remove first element from linked list

func Remove_Last(var DLL : Doubly_Linked_List) -> optional Element_Type;
// Remove last element from linked list

func Remove_Any(var DLL : Doubly_Linked_List) -> optional Element_Type;
// Remove arbitrary element from linked list

func Count(DLL : Doubly_Linked_List) -> Univ_Integer;
// Return count of elements in linked list

func Max_Id_In_Use(DLL : Doubly_Linked_List) -> optional Elem_Id;
// Return max Elem_Id in use

op "indexing"(ref DLL : Doubly_Linked_List; Elem_Id)
-> refoptional Element_Type;
// Return a reference to specified element

endinterface Doubly_Linked_List;



// Here are the implementations of the above two modules

class Doubly_Linked_Index is
interface Node<> is
// Each node on list has next and prev Id
var Next : Elem_Id;
var Prev : Elem_Id;
endinterface Node;

var Links : ZVector<Node>; // zero-th element is header

var First_Free : Elem_Id;
var Num_Free : Univ_Integer;

func Add_Node(var DLI : Doubly_Linked_Index; Next, Prev : Elem_Id)
-> New_Id : Elem_Id is
// Add a node with given Next/Prev fields to Links vector
var New_Node for DLI := Node::(Next => Next, Prev => Prev);

if DLI.First_Free != 0 then
// Reuse a free node`
New_Id := DLI.First_Free;
DLI.First_Free := DLI.Links[New_Id].Next;
DLI.Num_Free -= 1;

DLI.Links[New_Id] <== New_Node;
else
// Add a new node at end of Links vector
New_Id := Length(DLI.Links);
DLI.Links <|= New_Node;
endif;

DLI.Links[Prev].Next := New_Id;
DLI.Links[Next].Prev := New_Id;
return New_Id;
endfunc Add_Node;

// {Num_Free < Length(Links); First_Free in 0..<Length(Links)}
// {(for all N of Links => N.Next in 0..<Length(Links) and then
// N.Prev in 0..<Length(Links)}
exports
op "[]"() -> Doubly_Linked_Index is
return (Links => [(Next => 0, Prev => 0)],
First_Free => 0, Num_Free => 0);
endop "[]";

func Append(var DLI : Doubly_Linked_Index) -> New_Id : Elem_Id is
// Add a new node onto end of linked list
return Add_Node(DLI,
Next => 0, Prev => DLI.Links[0].Prev);
endfunc Append;

func Prepend(var DLI : Doubly_Linked_Index) -> Elem_Id is
// Add a new node at beginning of linked list
return Add_Node(DLI,
Next => DLI.Links[0].Next, Prev => 0);
endfunc Prepend;

func Insert_Before(var DLI : Doubly_Linked_Index; Follower : Elem_Id)
-> New_Id : optional Elem_Id is
// Insert new node before given element Id
if Follower in DLI then
return Add_Node(DLI,
Next => Follower, Prev => DLI.Links[Follower].Prev);
else
// Follower not in linked list
returnnull;
endif;
endfunc Insert_Before;

func Insert_After(var DLI : Doubly_Linked_Index; Elem_Id)
-> optional Elem_Id is
// Insert new node after given element Id
if Elem_Id in DLI then
return Add_Node(DLI,
Next => DLI.Links[Elem_Id].Next, Prev => Elem_Id);
else
// Elem_Id not in linked list
returnnull;
endif;
endfunc Insert_After;

op "in"(Elem_Id; DLI : Doubly_Linked_Index) -> Boolean is
// Return #true if given element is in linked list
// NOTE: All elements on free list have Prev pointing to themselves
return Elem_Id in 1..<Length(DLI.Links) andthen
DLI.Links[Elem_Id].Prev != Elem_Id;
endop "in";

func Remove(var DLI : Doubly_Linked_Index; Elem_Id) is
// Remove specified element from linked list (if present)
if Elem_Id in DLI then
// Not on the free list, so OK to remove
ref Elem => DLI.Links[Elem_Id];
DLI.Links[Elem.Prev].Next := Elem.Next;
DLI.Links[Elem.Next].Prev := Elem.Prev;

// Mark as being on the free list
Elem.Prev := Elem_Id;

// Add to the free list
Elem.Next := DLI.First_Free;
DLI.First_Free := Elem_Id;
DLI.Num_Free += 1;
endif;
endfunc Remove;

func Remove_First(var DLI : Doubly_Linked_Index) -> optional Elem_Id is
// Remove first element from linked list
const First := DLI.Links[0].Next;

if First == 0 then
// List is empty
returnnull;
else
Remove(DLI, First);
return First;
endif;
endfunc Remove_First;

func Remove_Last(var DLI : Doubly_Linked_Index) -> optional Elem_Id is
// Remove last element from linked list
const Last := DLI.Links[0].Prev;

if Last == 0 then
// List is empty
returnnull;
else
Remove(DLI, Last);
return Last;
endif;
endfunc Remove_Last;

func Remove_Any(var DLI : Doubly_Linked_Index) -> optional Elem_Id is
// Remove arbitrary element from linked list
if Count(DLI) mod 2 == 0 then
// Remove First if Count is odd, Remove Last if Count is even
return Remove_Last(DLI);
else
return Remove_First(DLI);
endif;
endfunc Remove_Any;

func Count(DLI : Doubly_Linked_Index) -> Univ_Integer is
// Return count of elements in linked list
return Length(DLI.Links) - DLI.Num_Free - 1;
endfunc Count;

func Max_Id_In_Use(DLI : Doubly_Linked_Index) -> optional Elem_Id is
// Return max Elem_Id in use
return Length(DLI.Links) - 1;
endfunc Max_Id_In_Use;

endclass Doubly_Linked_Index;



class Doubly_Linked_List is
var Index : DLI;
var Data : ZVector<optional Element_Type>;
// zeroth element is used to represent a missing element
exports
op "[]"() -> Doubly_Linked_List is
// Create an empty linked list
return (Index => [], Data => [null]);
endop "[]";

func Append(var DLL : Doubly_Linked_List; Elem : Element_Type)
-> Result : Elem_Id is
// Add a new element onto end of linked list
Result := Append(DLL.Index);
DLL.Data[Result] := Elem;
endfunc Append;

func Prepend(var DLL : Doubly_Linked_List; Elem : Element_Type)
-> Result : Elem_Id is
// Add a new element at beginning of linked list
Result := Prepend(DLL.Index);
DLL.Data[Result] := Elem;
endfunc Prepend;

func Insert_Before
(var DLL : Doubly_Linked_List; Elem : Element_Type; Elem_Id)
-> Result : optional Elem_Id is
// Insert new element before given element Id
Result := Insert_Before(DLL.Index, Elem_Id);
if Result notnullthen
DLL.Data[Result] := Elem;
endif;
endfunc Insert_Before;

func Insert_After
(var DLL : Doubly_Linked_List; Elem : Element_Type; Elem_Id)
-> Result : optional Elem_Id is
// Insert new element after given element Id
Result := Insert_After(DLL.Index, Elem_Id);
if Result notnullthen
DLL.Data[Result] := Elem;
endif;
endfunc Insert_After;

func Remove(var DLL : Doubly_Linked_List; Elem_Id) is
// Remove specified element from linked list (if present)
Remove(DLL.Index, Elem_Id);
endfunc Remove;

op "in"(Elem_Id; DLL : Doubly_Linked_List) -> Boolean is
// Return True if given element is in linked list
return Elem_Id in DLL.Index;
endop "in";

func Remove_First(var DLL : Doubly_Linked_List)
-> Result : optional Element_Type is
// Remove first element from linked list
const Id := Remove_First(DLL.Index);
if Id notnullthen
// Remove element from Data vector
Result <== DLL.Data[Id];
else
// List is empty
Result := null;
endif;
endfunc Remove_First;

func Remove_Last(var DLL : Doubly_Linked_List)
-> Result : optional Element_Type is
// Remove last element from linked list
const Id := Remove_Last(DLL.Index);
if Id notnullthen
// Remove element from Data vector
Result <== DLL.Data[Id];
else
// List is empty
Result := null;
endif;
endfunc Remove_Last;

func Remove_Any(var DLL : Doubly_Linked_List)
-> Result : optional Element_Type is
// Remove arbitrary element from linked list
const Id := Remove_Any(DLL.Index);
if Id notnullthen
// Remove element from Data vector
Result <== DLL.Data[Id];
else
// List is empty
Result := null;
endif;
endfunc Remove_Any;

func Count(DLL : Doubly_Linked_List) -> Univ_Integer is
// Return count of elements in linked list
return Count(DLL.Index);
endfunc Count;

func Max_Id_In_Use(DLL : Doubly_Linked_List) -> optional Elem_Id is
// Return max Elem_Id in use
return Max_Id_In_Use(DLL.Index);
endfunc Max_Id_In_Use;

op "indexing"(ref DLL : Doubly_Linked_List; Elem_Id)
-> refoptional Element_Type is
// Return a reference to specified element
if Elem_Id in DLL.Index andthen
Elem_Id in 1..<Length(DLL.Data) then
return DLL.Data[Elem_Id];
else
// return reference to null value stored in zeroth element
return DLL.Data[0];
endif;
endop "indexing";

endclass Doubly_Linked_List;



// Two test programs, one for the Doubly_Linked_Index module
// and one for the Doubly_Linked_List module.


func Test_DLI() is
var DLI : Doubly_Linked_Index := [];

Println("Append three times");
const Id1 := Append(DLI);
const Id2 := Append(DLI);
const Id3 := Append(DLI);

for Id in DLI forwardloop
Println("Found Elem_Id = " | Id);
endloop;

Println("Prepend twice");
const Id4 := Prepend(DLI);
const Id5 := Prepend(DLI);

Println("Count = " | Count(DLI));

for Id in DLI forwardloop
Println("Found Elem_Id = " | Id);
endloop;

Println("Insert before original second append");
const Id6 := Insert_Before(DLI, Id2);

Println("Count = " | Count(DLI));

for Id in DLI forwardloop
Println("Found Elem_Id = " | Id);
endloop;

Println("Remove " | Id1 | " and " | Id4);

Remove(DLI, Id1);
Remove(DLI, Id4);

Println("Count = " | Count(DLI));

for Id in DLI forwardloop
Println("Found Elem_Id = " | Id);
endloop;

Println("Reverse loop");

for Id in DLI reverseloop
Println("Found Elem_Id = " | Id);
endloop;

Println("Append one and prepend two");

const Id7 := Append(DLI);
const Id8 := Prepend(DLI);
const Id9 := Prepend(DLI);

Println("Count = " | Count(DLI));

for Id in DLI forwardloop
Println("Found Elem_Id = " | Id);
endloop;

Println("Reverse loop");

for Id in DLI reverseloop
Println("Found Elem_Id = " | Id);
endloop;

Println("Unordered loop");
for Id in DLI loop
Println("Found Elem_Id = " | Id);
endloop;

endfunc Test_DLI;



func Test_DLL() is
var DLL : Doubly_Linked_List<Univ_Enumeration> := [];

Println("Append three times");
const Id1 := Append(DLL, #one);
const Id2 := Append(DLL, #two);
const Id3 := Append(DLL, #three);

Println("Count = " | Count(DLL));

Println("Item 2 = " | DLL[Id2]);
Println("Item 3 = " | DLL[Id3]);

var I := 0;
for Elem in DLL forwardloop
Println("Found Elem = " | Elem);
I += 1;
if I > 5 then
exitloop;
endif;
endloop;

Println("Prepend twice");
const Id4 := Prepend(DLL, #four);
const Id5 := Prepend(DLL, #five);

Println("Count = " | Count(DLL));

for Elem in DLL forwardloop
Println("Found Elem = " | Elem);
endloop;

Println("Insert before original second append");
const Id6 := Insert_Before(DLL, #six, Id2);

Println("Count = " | Count(DLL));

for Elem in DLL forwardloop
Println("Found Elem = " | Elem);
endloop;

Println("Remove " | Id1 | " and " | Id4);

Remove(DLL, Id1);
Remove(DLL, Id4);

Println("Count = " | Count(DLL));

for Elem in DLL forwardloop
Println("Found Elem = " | Elem);
endloop;

Println("Reverse loop");

for Elem in DLL reverseloop
Println("Found Elem = " | Elem);
endloop;

Println("Append one and prepend two");

const Id7 := Append(DLL, #seven);
const Id8 := Prepend(DLL, #eight);
const Id9 := Prepend(DLL, #nine);

Println("Count = " | Count(DLL));

for Elem in DLL forwardloop
Println("Found Elem = " | Elem);
endloop;

Println("Reverse loop");

for Elem in DLL reverseloop
Println("Found Elem = " | Elem);
endloop;

Println("Unordered loop");
for Elem in DLL loop
Println("Found Elem = " | Elem);
endloop;

endfunc Test_DLL;

Viewing all articles
Browse latest Browse all 48

Trending Articles