Az Euclid programozási nyelv

Példakódok

Étkező filozófusok

Feladat:
Általában n=5 filozófusra fogalmazzák meg, mint a jelenlegi példában is. n filozófus ül körbe egy kerek asztalt, amelyen n db (azaz ugyanannyi) villa, illetve középen egy tál főtt tészta, amiből a filozófusok szedhetnek a tányérjukba (két villa segítségével).
Az alábbi megszorításoknak teljesülnie kell:

{ Dining Philosphers J.R. Cordy (after C. Lewis) Dec 1981 } var Diners : module { Random number generator } include '%RANDOM' pervasive type XCoord = 0 .. 79 pervasive type YCoord = 0 .. 23 pervasive const numberOfDiners := 5 { Position of each philosopher at the table } pervasive type Philosopher = 0 .. numberOfDiners - 1 pervasive const faceXPosition : array Philosopher of XCoord := (36, 56, 48, 24, 16) pervasive const faceYPosition : array Philosopher of YCoord := (2, 9, 18, 18, 9) { Positions of forks to left and right of each philosopher } pervasive type Fork = 0 .. numberOfDiners pervasive const forkXPosition : array Fork of XCoord := (25, 49, 57, 37, 19, 25) pervasive const forkYPosition : array Fork of YCoord:= (5, 5, 14, 21, 14, 5) { Meals eaten by each philosopher } pervasive const maxMeals := 50 var meals : array Philosopher of 0 .. maxMeals { Maximum eating and thinking times } pervasive const maxEatingTime := 10 pervasive const maxThinkingTime := 10 { Philospher's expressions } pervasive const contemplating := 0 pervasive const smiling := 1 pervasive const chewing := 2 pervasive const frowning := 3 { Philosopher's activities } pervasive const thinking := 0 pervasive const eating := 1 { Sides } pervasive const left := 0 pervasive const right := 1 var Draw : module exports (ChangeExpression, MoveFork, Finalize, Interrupt) { Terminal cursor handling library } include '%CURSES' procedure DrawFace (diner : Philosopher) = imports (var Curses) begin const x : XCoord := faceXPosition (diner) const y : YCoord := faceYPosition (diner) Curses.Move (y, x) Curses.AddStr ('MMMMMMM$E') Curses.Move (y + 1, x) Curses.AddStr ('| o,o |$E') Curses.Move (y + 2, x) Curses.AddStr ('| --- |$E') Curses.Move (y + 3, x) Curses.AddStr (' """""$E') Curses.Refresh end DrawFace procedure ChangeExpression (diner : Philosopher, newExpression : contemplating .. frowning) = imports (var Curses) begin const x : XCoord := faceXPosition (diner) const y : YCoord := faceYPosition (diner) Curses.Move (y + 2, x) if newExpression = contemplating then Curses.AddStr ('| --- |$E') elseif newExpression = smiling then Curses.AddStr ('| \_/ |$E') elseif newExpression = chewing then Curses.AddStr ('| (_) |$E') else Curses.AddStr ('| /-\ |$E') end if Curses.Refresh end ChangeExpression procedure DrawFork (diner : Philosopher, side : left .. right, activity : thinking .. eating) = imports (var Curses) begin var x : XCoord var y : YCoord if activity = thinking then x := forkXPosition (diner + side) y := forkYPosition (diner + side) else if side = left then x := faceXPosition (diner) - 7 else x := faceXPosition (diner) + 9 end if y := faceYPosition (diner) + 1 end if Curses.Move (y, x) Curses.AddStr ('|_|_|$E') Curses.Move (y + 1, x + 2) Curses.AddCh ($|) Curses.Move (y + 2, x + 2) Curses.AddCh ($|) Curses.Refresh end DrawFork procedure EraseFork (diner : Philosopher, side : left .. right, activity : thinking .. eating) = imports (var Curses) begin var x : XCoord var y : YCoord if activity = thinking then x := forkXPosition (diner + side) y := forkYPosition (diner + side) else if side = left then x := faceXPosition (diner) - 7 else x := faceXPosition (diner) + 9 end if y := faceYPosition (diner) + 1 end if Curses.Move (y, x) Curses.AddStr (' $E') Curses.Move (y + 1, x + 2) Curses.AddCh ($$S) Curses.Move (Y + 2, x + 2) Curses.AddCh ($$S) Curses.Refresh end EraseFork procedure MoveFork (diner : Philosopher, side : left .. right, newActivity : thinking .. eating) = imports (DrawFork, EraseFork) begin if newActivity = thinking then EraseFork (diner, side, eating) else EraseFork (diner, side, thinking) end if DrawFork (diner, side, newActivity) end MoveFork procedure Finalize = imports (var Curses) begin var c : Char Curses.Move (23, 0) Curses.CursorOn Curses.AddStr ('Hit return to continue.$E') loop exit when not Curses.HasCh Curses.GetCh (c) end loop Curses.GetCh (c) Curses.Clear Curses.Refresh Curses.Endwin end Finalize function Interrupt returns result : Boolean = imports (Curses) begin return (Curses.HasCh) end Interrupt initially imports (DrawFace, DrawFork, var Curses) begin var diner : Philosopher Curses.Clear Curses.Move (0, 3) Curses.CursorOff Curses.AddStr ('THE DINING PHILOSOPHERS$E') Curses.Move (1, 0) Curses.AddStr ('Processes in Concurrent Euclid$E') diner := 0 loop DrawFace (diner) DrawFork (diner, left, thinking) DrawFork (diner, right, thinking) exit when diner = numberOfDiners - 1 diner := diner + 1 end loop end end module var Forks : monitor imports (var meals, var Draw) exports (PickUp, PutDown, AllDone) function LeftDiner (diner : Philosopher) returns dinerToLeft : Philosopher = begin return ((diner + 1) mod numberOfDiners) end LeftDiner function RightDiner (diner : Philosopher) returns dinerToRight : Philosopher = begin return ((diner + numberOfDiners - 1) mod numberOfDiners) end RightDiner var forksAvail : array Philosopher of 0 .. 2 var okayToEat : array Philosopher of Condition var done : condition procedure PickUp (diner : Philosopher) = imports (var forksAvail, var okayToEat, meals, LeftDiner, RightDiner , var Draw) begin if forksAvail (diner) not= 2 then wait (okayToEat (diner)) end if forksAvail (LeftDiner (diner)) := forksAvail (LeftDiner (diner)) - 1 Draw.MoveFork (diner, left, eating) forksAvail (RightDiner (diner)) := forksAvail (RightDiner (diner )) - 1 Draw.MoveFork (diner, right, eating) Draw.ChangeExpression (diner, chewing) end PickUp procedure PutDown (diner : Philosopher) = imports (var forksAvail, var okayToEat, var meals, var done, LeftDiner, RightDiner, var Draw) begin Draw.ChangeExpression (diner, contemplating) Draw.MoveFork (diner, left, thinking) forksAvail (LeftDiner (diner)) := forksAvail (LeftDiner (diner)) + 1 Draw.MoveFork (diner, right, thinking) forksAvail (RightDiner (diner)) := forksAvail (RightDiner (diner )) + 1 if forksAvail (LeftDiner (diner)) = 2 then signal (okayToEat (LeftDiner (diner))) end if if forksAvail (RightDiner (diner)) = 2 then signal (okayToEat (RightDiner (diner))) end if meals (diner) := meals (diner) + 1 if meals (diner) = maxMeals then Draw.ChangeExpression (diner, smiling) signal (done) elseif Draw.Interrupt then meals (diner) := maxmeals Draw.ChangeExpression (diner, frowning) signal (done) end if end PutDown procedure AllDone = imports (var done) begin var numberDone : 0 .. numberOfDiners := 0 loop wait (done) numberDone := numberDone + 1 exit when numberDone = numberOfDiners end loop end AllDone initially imports (var forksAvail, var meals) begin var i : Philosopher i := 0 loop forksAvail (i) := 2 meals (i) := 0 i := i + 1 exit when i = numberOfDiners end loop end end monitor procedure Delay (time : SignedInt) = begin var i : SignedInt := time * 100 loop exit when i <= 0 i := i - 1 end loop end Delay procedure CommonPhilosopher (diner : Philosopher) = imports (var meals, var Forks, var Random, Delay) begin loop Forks.PickUp (diner) Random.Next busy (Random.Number mod maxEatingTime) Delay (Random.Number mod maxEatingTime) Forks.PutDown (diner) Random.Next busy (Random.Number mod maxThinkingTime) Delay (Random.Number mod maxThinkingTime) exit when meals (diner) = maxMeals end loop end CommonPhilosopher process Philosopher_0 (3000) imports (CommonPhilosopher) begin CommonPhilosopher (0) end Philosopher_0 process Philosopher_1 (3000) imports (CommonPhilosopher) begin CommonPhilosopher (1) end Philosopher_1 process Philosopher_2 (3000) imports (CommonPhilosopher) begin CommonPhilosopher (2) end Philosopher_2 process Philosopher_3 (3000) imports (CommonPhilosopher) begin CommonPhilosopher (3) end Philosopher_3 process Philosopher_4 (3000) imports (CommonPhilosopher) begin CommonPhilosopher (4) end Philosopher_4 process Cleanup (3000) imports (var Forks, var Draw) begin Forks.AllDone Draw.Finalize end Cleanup end Diners


Az implementációról

A filozófusokat, villákat koordinátáik tömbjén keresztül reprezentálják. A progi karaktergrafikával ki is rajzolja őket: ehhez kellenek a bal felső sarkok koordinátái. A többi változó jelentése a kódban eléggé dokumentálva van :)

A Diners modul egy Draw modult és egy Forks monitort tartalmaz.
A Draw modul a filozófusok és villák kirajzolását, illetve a képernyő tisztítását, és az interaktivitás(a felhasználó és a program között) kontrollját végzi. Karaktergrafikát használó műveleteket tartalmaz, illetve lehetőséget ad arra, hogy tetszőleges billenytű lenyomására megzavarjunk egy (a max. adagját még el nem fogyasztott ) filozófust, és azt mondjuk neki, hogy "nem kapsz többet enni" - lásd 'Forks.PutDown'.
A Forks monitor pedig a villák használatát implementáló műveleteket felügyeli. Van egy inicializáló művelete: kezdetben V filozófus két villát érhet el, és még nem evett semmit. A PickUp - al egy filozófus villát vesz fel, egészen addig, amíg nem sikerül neki; A PutDown-al leteszi a villáit, és erre "udvariasan fehívja a többiek figyelmét"; az AllDone (és a Draw.Finalize) segítségével a CleanUp folyamat újra kiindulási helyzetbe hozza a programot.
Ezen kívül definiált benne a Delay (késleltető) és a CommonPhilosopher(a kajálást vezérlő fő eljárás) műveletek, valamint az ezt hívó filozófus-folyamatok,és egy "eltakarító" (a filozófusok hazamennek, az asztalt meg leszedik :) ) folyamat. A CommonPhilosopher-ben az éppen evő, illetve éppen gondolkodó filozófus tevékenyen várakozik (busy,Delay), de csak korlátozott ideig (maxEatingTime, maxThinkingTime).

A monitorbeli eljárások használta signal, wait és conditon-ok összefüggései:

SCAN merevlemez-elérést irányító ütemező algoritmus

Feladat: a merevlemezhez érkező írási és olvasási kérelmek kiszolgálása, a fej mozgatásának írányításával. Az algoritmusról lentebb.

{SCAN Disc Scheduling Algorithm} var Scan : module include '%IO' pervasive type cardinal = 0..32767 pervasive type tracknums=0..39 var disk:array tracknums of cardinal var curtrack:0..39 var scheduler : monitor imports (var curtrack, var IO, var disk) exports (request,finish) var tracks:array tracknums of condition var numreq:cardinal var prefdir:-1..1 procedure request(track:cardinal)= imports (var tracks, var numreq) begin numreq := numreq+1 if numreq>1 then wait(tracks(track)) end if end request procedure finish = imports(curtrack, var prefdir, var numreq, var tracks) begin var scanner:cardinal numreq := numreq-1 if numreq>0 then if not(empty(tracks(curtrack))) then signal(tracks(curtrack)) else scanner := curtrack loop scanner := scanner+prefdir if scanner=39 then prefdir := -1 else if scanner=0 then prefdir := 1 end if end if if not(empty(tracks(scanner))) then exit end if end loop signal(tracks(scanner)) end if end if end finish initially imports(var prefdir, var numreq, var curtrack, var disk) begin var i:cardinal prefdir := 1 curtrack := 0 numreq := 0 i := 0 loop disk(i) := 0 i := i+1 if i=40 then exit end if end loop end end monitor procedure positionhead(track:cardinal)= imports (var curtrack) begin curtrack := track end positionhead procedure read(procnum:cardinal,track:cardinal, var c:cardinal)= imports (curtrack, disk, var scheduler, positionhead, var IO) begin scheduler.request(track) positionhead(track) c := disk(curtrack) IO.PutString('Process number ') IO.PutInt(procnum,0) IO.PutString(' read ') IO.PutInt(c,0) IO.PutString(' from track ') IO.PutInt(track,0) IO.PutString('.$N') scheduler.finish() end read procedure write(procnum:cardinal,track:cardinal,c:cardinal)= imports (curtrack, var scheduler, positionhead, var disk, var IO) begin scheduler.request(track) positionhead(track) disk(curtrack) := c IO.PutString('Process number ') IO.PutInt(procnum,0) IO.PutString(' wrote ') IO.PutInt(disk(curtrack),0) IO.PutString(' on track ') IO.PutInt(track,0) IO.PutString('.$N') scheduler.finish() end write process p1 (5000) imports(read, write) begin var q:cardinal write(1,25,1) write(1,15,2) write(1,35,3) read (1,27,q) read (1, 2,q) write(1,34,4) write(1, 3,5) write(1,29,6) write(1, 5,7) write(1,39,8) end p1 process p2 (5000) imports(read, write) begin var q:cardinal write(2,27,9) write(2, 2,10) read (2,25,q) write(2,37,11) write(2,10,12) write(2,30,13) write(2,20,14) write(2,21,15) read (2,29,q) read (2,34,q) end p2 process p3 (5000) imports(read, write) begin var q:cardinal write(3,17,16) write(3, 8,17) write(3,24,18) read (3, 5,q) write(3,36,19) read (3,36,q) write(3, 9,20) write(3, 4,21) write(3,28,22) write(3,14,23) write(3,13,24) end p3 process p4 (5000) imports(read, write) begin var q:cardinal write(4,16,25) read (4, 8,q) read (4,17,q) read (4,24,q) write(4,11,26) write(4,12,27) write(4,18,28) write(4,19,29) read (4,16,q) read (4,14,q) end p4 process p5 (5000) imports(read, write) begin var q:cardinal write(5, 0,30) write(5,31,31) write(5,32,32) write(5,33,33) write(5,37,34) read (5,15,q) read (5,16,q) read (5,17,q) write(5,26,35) write(5,23,36) end p5 process p6 (5000) imports(read, write) begin var q:cardinal write(6, 1,37) write(6, 6,38) write(6, 7,39) write(6,22,40) write(6,38,41) read (6, 8,q) read (6,10,q) read (6,12,q) write(6,14,35) write(6,16,36) end p6 End Scan


Az implementációról

A SCAN modul tartalmazza a 'scheduler' nevű monitort, fejpozicionálást, olvasását, írást végző műveleteket, végül 6 folyamatot, azonosítószámukkal(1..6) és azzal hogy hova/honnan és mit írnak/olvasnak. Ezek a folyamtok a 0..39 -ig számozott cilindereken végeznek író-olvasó műveleteket. A scheduler nevű monitor műveletei az (írás/olvasás)kéréseket, illetve a következő kiszolgálandó kérés keresését(scan) koordinálják.

A monitorbeli eljárások használta signal, wait és conditon-ok összefüggései:

Ebben a feladatban már az 'empty' konstrukciónak is szerep jutott. Az algoritmus már ismerős (lehet) 'operációs rendszerek'-órákról : de azért röviden leírom, hogyan működik.
Kezdetben (lsd. a monitor initially műveletét) a mozgás iránya 1 (kifelé), az aktuális cilinder a legelső (a 0.), nincs kérés se írásra, se olvasásra, és a lemez(itt ebben a példában, az egyszerűség kedvéért) üres.
A folyamatok kéréseit (akár írás, akár olvasás), először belülről kifelé (a kiindulási pozícióból, ami most a 0. cilinder) folyamatosan haladva teljesíti, majd ha a legszélső (a 39.) cilinderhez ért, visszafordul, és kívülről befelé mozgatja a fejet, és ha talál kérést egy cilindernél, akkor azt teljesíti. Természetesen csak egyet egyszerre: ha egy cilinderre több kérés is befutott már, mire a fej odaért, akkor a cilinder várakozási sorából csak 1 folyamatot ébreszt fel. Ha ott van még további kérés, akkor ezek a kérések láncban, meg nem határozott sorrendben teljesülnek. Ezután továbbmegy befelé(a kéréseket az előbb látott módon szolgálva ki), és ha elérte az első (a 0.) cilindert,megint visszafordul.
A továbbiakban oda-vissza végigpásztázza a cilindereket, és ha egyiken kérés(eke)t talál, kiszolgálja az(oka)t. Az algoritmus holtpontmentes, és megelőzi a kiéheztetést.

"Concurrent Worms"

Feladat: 3 kukac mozog egy fix téglalap alakú területen, a határra érve ellenkező irányra váltanak, nem ütközhetnek magukba, sem egymásba.

{ Concurrent Worms V1.00 J.R. Cordy 29 April 1982 } var Worms: module include '%CURSES' pervasive const nWorms := 3 var Its: monitor exports (YourTurn, MyTurn, WormDone, AllDone) { Monitor to synchronize unit actions on the terminal screen; Its.MyTurn insures that the process may manipulate the screen until it calls Its.YourTurn } var mine: Boolean := false var yours: condition { not mine } var done : condition procedure MyTurn = imports (var mine, var yours) begin if mine then { Someone else already has it } wait (yours) end if mine := true end MyTurn procedure YourTurn = imports (var mine, var yours) begin mine := false signal (yours) end YourTurn procedure WormDone = imports (var done) begin signal (done) end WormDone procedure AllDone = imports (var done) begin var numberDone : 0 .. nWorms := 0 loop wait (done) numberDone := numberDone + 1 exit when numberDone = nWorms end loop end AllDone end monitor { Screen parameters } pervasive const minX := 0 pervasive const maxX := 79 pervasive const minY := 0 pervasive const maxY := 23 { Worm parameters } pervasive const wormLength := 11 pervasive const wormX0: array 1..nWorms of minX..maxX-1 := (0,38,72) pervasive const wormY0: array 1..nWorms of minY..maxY-1 := (0,11,22) pervasive const wormString: array 0..nWorms*wormLength-1 of Char := ($C,$o,$n,$c,$u,$r,$r,$e,$n,$t,$$S, $E,$u,$c,$l,$i,$d,$$S,$$S,$$S,$$S,$$S, $P,$r,$o,$c,$e,$s,$s,$e,$s,$$S,$$S) pervasive const wormWiggle: array 0..wormLength-1 of -1..1 := (1,1,1,1,1,0,0,-1,-1,-1,0) { Worm algorithm } procedure Worm (w: 1..nWorms) = imports (var Its, var Curses) begin { Segments of the worm } var segment: array 0..wormLength-1 of record var x: minX..maxX var y: minY..maxY end record { Present direction of motion } var xdir: -1..1 := 1 var ydir: -1..1 := 1 { Turning parameters } const maxCount := 1024 var count: 0..maxCount-1 := 0 const xturn: 0..maxCount := w * 117 const yturn: 0..maxCount := w * 37 { Head and tail segments } var head: 0..wormLength-1 := 0 var tail: 0..wormLength-1 var i: 0..wormLength var j: 0..nWorms*wormLength-1 { Initialize } i := 0 loop exit when i = wormLength segment(i).x := wormX0(w) segment(i).y := wormY0(w) i := i + 1 end loop loop exit when Curses.HasCh tail := (head + 1) mod wormLength { Compute new head position } if segment(head).x >= maxX-1 then xdir := -1 elseif segment(head).x <= minX+1 then xdir := 1 end if segment(tail).x := segment(head).x + xdir + xdir * wormWiggle(tail) assert (segment(tail).x >= minX and segment(tail).x <= maxX) if segment(head).y = maxY then ydir := -1 elseif segment(head).y = minY then ydir := 1 end if segment(tail).y := segment(head).y + ydir assert (segment(tail).y >= minY and segment(tail).y <= maxY) head := tail { Redraw worm } Its.MyTurn i := head j := (w-1) * wormLength loop Curses.Move (segment(i).y, segment(i).x) Curses.AddCh (wormString(j)) exit when wormString(j) = $$S i := (i + wormLength - 1) mod wormLength j := j + 1 end loop Curses.Refresh Its.YourTurn { Decide if it's time to turn around } if count mod xturn = 0 then xdir := -xdir end if if count mod yturn = 0 then ydir := -ydir end if count := (count + 1) mod maxCount end loop Its.WormDone end Worm procedure Finalize = imports (var Curses) begin var c : Char Curses.Move (23, 0) Curses.CursorOn loop exit when not Curses.HasCh Curses.GetCh (c) end loop Curses.Clear Curses.Refresh Curses.Endwin end Finalize initially imports (var Curses) begin Curses.Clear Curses.CursorOff end process Worm1 imports (Worm) begin Worm (1) end Worm1 process Worm2 imports (Worm) begin Worm (2) end Worm2 process Worm3 imports (Worm) begin Worm (3) end Worm3 process Cleanup imports (var Its, Finalize) begin Its.AllDone Finalize end Cleanup end module


Az implementációról

Ez egy kedves kis program egymással párhuzamosan mozgó 3 kukaccal a képernyőn, amelyek a 'Concurrent','Euclid','Processes' feliratokból állnak. A program működése alatt a giliszták a 'képernyő' szélénél ellenkező irányba váltanak, és mielőtt egymásba ütköznének, el/megfordulnak.
A monitor MyTurn, YourTurn metódusai biztosítják a kölcsönös kizárást a képernyőre, mint kritikus erőforrásra vonatkozólag (lásd Worm - algoritmus 'Redraw worm' része.) A WormDone művelet segít "eltüntetni a gilisztákat" a képernyőről: billentyű-leütéskor sóbálvánnyá válik egy -egy giliszta. A program jólnevelt és az összes megmerevedett gilisztát eltakarítja a képernyőről, mielőtt befejeződne (Its.AllDone, Finalize).

Lineáris hashelés egy implementációja(Euclid nyelven)

Szerző : B. W. Lampson, J. Horning, R. L. London, J. G. Mitchell and G. L. Popek - Sigplan Notices, Vol.12, Nr. 2, February 1977
Feladat: valósítsuk meg számoknak tábláját, (pl. frissen nyitott bankszámláknak), mint egy asszociatív memóriát.

type NumberTable = module exports( Search, Delete, Insert ) {This modu1e implements a tab1e of numbers, e.g., currently open accounts, as an associative memory} pervasive const tableSize :=763; { Ez a tabla merete } pervasive type TableIndex = 1..tableSize pervasive type CyclicScan ( item : signedInt ) = {a generator for a for loop} module exports ( Next, value, stop ) const start := (item mod tableSize)+1 var value : TableIndex := start var stop : Boolean := False procedure Next = imports ( var value, start, var stop ) begin if value = tableSize then value := 1 else value := value+1 end if stop := (value not= start) end Next end CyclicScan type State = (fresh, full, deleted) type TableEntry( flag :State) = record case flag of full => var key :signedInt end full otherwise => end case end TableEntry var table :array TableIndex of TableEntry(any) {any: fresh,full,deleted} function Search( key :signedInt) returns Boolean = imports(table) begin {any tipusertekei itt az 1..tableSize intervallum-típus ertekei lehetnek :) } for i in CyclicScan(any) loop with entry := table(i) case flag of fresh => return False end fresh full => return True when entry.key = key; end full; otherwise => end case; end loop; return False; end Search; procedure Delete( key :signedInt) = imports(var table) begin const deletedEntry : TableEntry(deleted) := (); for i in CyclicScan(key) loop with entry := table(i) case flag of full => if entry.key = key then table(i) := deletedEntry; return end if end full fresh => return end fresh otherwise => end case end loop end Delete procedure Insert( key :signedInt) = imports(var table, Search) begin return when Search(key) {if already there}; for i in CyclicScan(key) loop case table(i).flag of fresh, deleted => var t: TableEntry(full) t.key := key table(i) := t; {az alabbi aprosagot veletlenul nem szedte a nyomdagep, pedig fontos :) } return end fresh otherwise => end case end loop assert False {table never be full} end Insert const freshEntry : TableEntry(fresh) := () initially begin for i in table.IndexType loop table(i) := freshEntry end loop end end NumberTable


Segítség a kód olvasásához :
A CyclicScan a for-ciklus számára generálja a ciklusváltozó típusának lehetséges értékeit. Itt most épp előjeles egészeket, amik fix lépésközzel (most =1) követik egymást, növekvő sorrendben. Mindez a Next műveletből derül ki. A TableEntry típus megmondja, mi az aktuális kulcs állapota.
Kezdetben minden entry (kulcs) üres. Az assert, mivel(valószínűleg) a táblaméret úgy lett optimálisan beállítva, hogy soha ne teljen meg a tábla (és az értékek is signedInt -ek), jogos.