Skip to content

Commit

Permalink
Merge branch 'circular-buffer'
Browse files Browse the repository at this point in the history
  • Loading branch information
loziniak committed Dec 19, 2021
2 parents 6a482e8 + 8912a1a commit 097916d
Show file tree
Hide file tree
Showing 11 changed files with 440 additions and 1 deletion.
5 changes: 5 additions & 0 deletions concepts/dsl/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"blurb": "It's about creating a language inside language. Red makes it easy.",
"authors": ["loziniak"],
"contributors": []
}
3 changes: 3 additions & 0 deletions concepts/dsl/about.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# About

> Provide more detailed information about the Concept for a student who has completed the corresponding Concept Exercise to learn from and refer back to.
3 changes: 3 additions & 0 deletions concepts/dsl/introduction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Introduction

> Provide a brief introduction to a student who has not yet completed the corresponding concept exercise.
2 changes: 2 additions & 0 deletions concepts/dsl/links.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[
]
20 changes: 19 additions & 1 deletion config.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@
"slug": "errors",
"name": "Handling Errors",
"uuid": "d33f88db-be6a-4868-b6c6-4dca70a47cc9"
},
{
"slug": "dsl",
"name": "Domain Specific Languages",
"uuid": "2a949ab5-9293-4d9a-9538-eeeda281a66e"
}
],
"tags": [
Expand Down Expand Up @@ -274,7 +279,7 @@
{
"slug": "largest-series-product",
"name": "Largest Series Product",
"status": "wip",
"status": "beta",
"uuid": "3bdc9858-390b-4d82-8669-663db97e6a0a",
"practices": [
"loops"
Expand Down Expand Up @@ -311,6 +316,19 @@
"strings"
],
"difficulty": 6
},
{
"slug": "circular-buffer",
"name": "Circular Buffer",
"status": "wip",
"uuid": "ab563cba-5556-4625-b1aa-971c01d3bead",
"practices": [
"dsl"
],
"prerequisites": [
"blocks"
],
"difficulty": 9
}
]
}
Expand Down
51 changes: 51 additions & 0 deletions exercises/practice/circular-buffer/.docs/instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Instructions

A circular buffer, cyclic buffer or ring buffer is a data structure that
uses a single, fixed-size buffer as if it were connected end-to-end.

A circular buffer first starts empty and of some predefined length. For
example, this is a 7-element buffer:
<!-- prettier-ignore -->
[ ][ ][ ][ ][ ][ ][ ]

Assume that a 1 is written into the middle of the buffer (exact starting
location does not matter in a circular buffer):
<!-- prettier-ignore -->
[ ][ ][ ][1][ ][ ][ ]

Then assume that two more elements are added — 2 & 3 — which get
appended after the 1:
<!-- prettier-ignore -->
[ ][ ][ ][1][2][3][ ]

If two elements are then removed from the buffer, the oldest values
inside the buffer are removed. The two elements removed, in this case,
are 1 & 2, leaving the buffer with just a 3:
<!-- prettier-ignore -->
[ ][ ][ ][ ][ ][3][ ]

If the buffer has 7 elements then it is completely full:
<!-- prettier-ignore -->
[5][6][7][8][9][3][4]

When the buffer is full an error will be raised, alerting the client
that further writes are blocked until a slot becomes free.

When the buffer is full, the client can opt to overwrite the oldest
data with a forced write. In this case, two more elements — A & B —
are added and they overwrite the 3 & 4:
<!-- prettier-ignore -->
[5][6][7][8][9][A][B]

3 & 4 have been replaced by A & B making 5 now the oldest data in the
buffer. Finally, if two elements are removed then what would be
returned is 5 & 6 yielding the buffer:
<!-- prettier-ignore -->
[ ][ ][7][8][9][A][B]

Because there is space available, if the client again uses overwrite
to store C & D then the space where 5 & 6 were stored previously will
be used not the location of 7 & 8. 7 is still the oldest element and
the buffer is once again full.
<!-- prettier-ignore -->
[C][D][7][8][9][A][B]
18 changes: 18 additions & 0 deletions exercises/practice/circular-buffer/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"blurb": "A data structure that uses a single, fixed-size buffer as if it were connected end-to-end.",
"authors": [
"loziniak"
],
"contributors": [],
"files": {
"solution": [
"circular-buffer.red"
],
"test": [
"circular-buffer-test.red"
],
"example": [
".meta/example.red"
]
}
}
98 changes: 98 additions & 0 deletions exercises/practice/circular-buffer/.meta/example.red
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
Red [
description: {"Circular Buffer" exercise solution for exercism platform}
author: "loziniak"
]

circular-buffer!: context [
buffer: none
results: none

start: 1
length: 0


full?: function [return: [logic!]] [
(length + 1) > length? buffer
]

write-end: function [item [integer!]] [
end: ((start - 1 + length) % length? buffer) + 1
buffer/(end): item
]

consume: function [] [
self/start: (self/start % length? buffer) + 1
]


read: function [
/extern start length
] [
append results either any [
none? buffer
length < 1
] [
'false
] [
result: buffer/(start)
consume
length: length - 1

result
]
]

write: function [
item [integer!]
/extern start length
] [
append results either any [
none? buffer
full?
] [
'false
] [
write-end item
length: length + 1

'true
]
]

clear: function [
/extern start length
] [
length: 0
]

overwrite: function [
item [integer!]
/extern start length
] [
unless none? buffer [
write-end item

either full? [
consume
] [
length: length + 1
]
]
]
]

run: function [
capacity [integer!]
operations [block!]
return: [block!]
] [
buf: make circular-buffer! [
buffer: append/dup copy [] none capacity
results: copy []
]

bind operations buf

do operations
buf/results
]
44 changes: 44 additions & 0 deletions exercises/practice/circular-buffer/.meta/tests.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
[canonical-tests]

# reading empty buffer should fail
"28268ed4-4ff3-45f3-820e-895b44d53dfa" = true

# can read an item just written
"2e6db04a-58a1-425d-ade8-ac30b5f318f3" = true

# each item may only be read once
"90741fe8-a448-45ce-be2b-de009a24c144" = true

# items are read in the order they are written
"be0e62d5-da9c-47a8-b037-5db21827baa7" = true

# full buffer can't be written to
"2af22046-3e44-4235-bfe6-05ba60439d38" = true

# a read frees up capacity for another write
"547d192c-bbf0-4369-b8fa-fc37e71f2393" = true

# read position is maintained even across multiple writes
"04a56659-3a81-4113-816b-6ecb659b4471" = true

# items cleared out of buffer can't be read
"60c3a19a-81a7-43d7-bb0a-f07242b1111f" = true

# clear frees up capacity for another write
"45f3ae89-3470-49f3-b50e-362e4b330a59" = true

# clear does nothing on empty buffer
"e1ac5170-a026-4725-bfbe-0cf332eddecd" = true

# overwrite acts like write on non-full buffer
"9c2d4f26-3ec7-453f-a895-7e7ff8ae7b5b" = true

# overwrite replaces the oldest item on full buffer
"880f916b-5039-475c-bd5c-83463c36a147" = true

# overwrite replaces the oldest item remaining in buffer following a read
"bfecab5b-aca1-4fab-a2b0-cd4af2b053c3" = true

# initial clear does not affect wrapping around
"9cebe63a-c405-437b-8b62-e3fdc1ecec5a" = true

Loading

0 comments on commit 097916d

Please sign in to comment.