This implements a key-value data store for RETRO. It's not an optimal solution, but works well enough for smaller data sets.

A store is setup as a linked list with three values:

0  pointer to previous entry 1  pointer to key (string) 2  pointer to value (string) or value (numeric)

This begins with words to access these fields.

~~~:kv:link  (D-a)       ; :kv:name  (D-a) n:inc ; :kv:value (D-a) #2 +  ; ~~~

Next is a word to make a new store. I create a dummy entry named (nil) as the root.

~~~:kv:new   (s-)   d:create here n:inc , #0 , '(nil) , #0 ,  ; ~~~

Searching the store for an entry is next. This is very inefficient due to the use of reorder. If the performance becomes an issue I will revisit it later.

~~~{{   :match?     (sD-sf)    kv:name fetch over s:eq? ;   :update     (abc-cbc)  'abc 'cbc reorder ;   :seek       (nsD-ns)     repeat fetch 0; &match? sip swap &update if again ; ---reveal---   :kv:lookup  (sD-a) #0 'abc 'cab reorder seek drop ; }} ~~~

To add or change an entry, I provide kv:set. This is even more inefficient as it scans the store twice when setting an existing entry.

This could be improved:

• only scan once
• factor out the update and add entry actions

~~~:kv:update-entry  (vsD-)  kv:lookup kv:value store ; :kv:add-entry     (vsD-)  here over [ [ fetch , , , ] dip ] dip store ;   :kv:set   (vsD-)   dup-pair kv:lookup n:-zero?   [ kv:update-entry ] [ kv:add-entry ] choose ; ~~~

The last word is kv:get, which returns the contents of the kv:value field.

~~~:kv:get (sD-v)   kv:lookup dup 0; drop kv:value fetch ; ~~~

And some tests:

```'Test kv:new   #1000 'FOO Test kv:set #1500 'BAR Test kv:set #4000 'FOOBAR Test kv:set 'FOOBAR Test kv:get n:put nl #5000 'FOOBAR Test kv:set 'FOOBAR Test kv:get n:put nl
~~~