Skip to content

Commit 2f4cf57

Browse files
authored
Add circular-buffer (#809)
1 parent 020de6e commit 2f4cf57

File tree

8 files changed

+340
-20
lines changed

8 files changed

+340
-20
lines changed

config.json

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,11 @@
4141
"slug": "basics",
4242
"name": "Lucians Luscious Lasagna",
4343
"uuid": "ea9ee1b7-26e4-4612-839d-fc6a9ecc2e7c",
44-
"status": "wip",
45-
"concepts": ["basics"],
46-
"prerequisites": []
44+
"concepts": [
45+
"basics"
46+
],
47+
"prerequisites": [],
48+
"status": "wip"
4749
}
4850
],
4951
"practice": [
@@ -273,8 +275,7 @@
273275
"uuid": "2be75924-fce4-49fa-b52e-6cdcf222b283",
274276
"practices": [],
275277
"prerequisites": [],
276-
"difficulty": 3,
277-
"topics": []
278+
"difficulty": 3
278279
},
279280
{
280281
"slug": "pascals-triangle",
@@ -423,8 +424,7 @@
423424
"uuid": "e6e88c52-b984-479d-8b9c-047d25f2aa47",
424425
"practices": [],
425426
"prerequisites": [],
426-
"difficulty": 9,
427-
"topics": []
427+
"difficulty": 9
428428
},
429429
{
430430
"slug": "binary-search",
@@ -686,7 +686,6 @@
686686
"practices": [],
687687
"prerequisites": [],
688688
"difficulty": 2,
689-
"topics": null,
690689
"status": "deprecated"
691690
},
692691
{
@@ -696,7 +695,6 @@
696695
"practices": [],
697696
"prerequisites": [],
698697
"difficulty": 2,
699-
"topics": null,
700698
"status": "deprecated"
701699
},
702700
{
@@ -706,7 +704,6 @@
706704
"practices": [],
707705
"prerequisites": [],
708706
"difficulty": 2,
709-
"topics": null,
710707
"status": "deprecated"
711708
},
712709
{
@@ -716,7 +713,6 @@
716713
"practices": [],
717714
"prerequisites": [],
718715
"difficulty": 2,
719-
"topics": null,
720716
"status": "deprecated"
721717
},
722718
{
@@ -1278,10 +1274,17 @@
12781274
"optional_values",
12791275
"trees"
12801276
]
1277+
},
1278+
{
1279+
"slug": "circular-buffer",
1280+
"name": "Circular Buffer",
1281+
"uuid": "23df18c8-5fd6-4148-9f69-364d46a911b0",
1282+
"practices": [],
1283+
"prerequisites": [],
1284+
"difficulty": 3
12811285
}
12821286
]
12831287
},
1284-
"concepts": [],
12851288
"key_features": [
12861289
{
12871290
"title": "Modern",
@@ -1315,19 +1318,19 @@
13151318
}
13161319
],
13171320
"tags": [
1318-
"runtime/jvm",
1319-
"platform/windows",
1321+
"execution_mode/compiled",
1322+
"paradigm/functional",
1323+
"paradigm/imperative",
1324+
"paradigm/object_oriented",
13201325
"platform/linux",
13211326
"platform/mac",
13221327
"platform/web",
1323-
"paradigm/imperative",
1324-
"paradigm/functional",
1325-
"paradigm/object_oriented",
1328+
"platform/windows",
1329+
"runtime/jvm",
13261330
"typing/static",
13271331
"typing/strong",
1328-
"execution_mode/compiled",
13291332
"used_for/backends",
1330-
"used_for/frontends",
1331-
"used_for/financial_systems"
1333+
"used_for/financial_systems",
1334+
"used_for/frontends"
13321335
]
13331336
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Instructions
2+
3+
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.
4+
5+
A circular buffer first starts empty and of some predefined length.
6+
For example, this is a 7-element buffer:
7+
8+
```text
9+
[ ][ ][ ][ ][ ][ ][ ]
10+
```
11+
12+
Assume that a 1 is written into the middle of the buffer (exact starting location does not matter in a circular buffer):
13+
14+
```text
15+
[ ][ ][ ][1][ ][ ][ ]
16+
```
17+
18+
Then assume that two more elements are added — 2 & 3 — which get appended after the 1:
19+
20+
```text
21+
[ ][ ][ ][1][2][3][ ]
22+
```
23+
24+
If two elements are then removed from the buffer, the oldest values inside the buffer are removed.
25+
The two elements removed, in this case, are 1 & 2, leaving the buffer with just a 3:
26+
27+
```text
28+
[ ][ ][ ][ ][ ][3][ ]
29+
```
30+
31+
If the buffer has 7 elements then it is completely full:
32+
33+
```text
34+
[5][6][7][8][9][3][4]
35+
```
36+
37+
When the buffer is full an error will be raised, alerting the client that further writes are blocked until a slot becomes free.
38+
39+
When the buffer is full, the client can opt to overwrite the oldest data with a forced write.
40+
In this case, two more elements — A & B — are added and they overwrite the 3 & 4:
41+
42+
```text
43+
[5][6][7][8][9][A][B]
44+
```
45+
46+
3 & 4 have been replaced by A & B making 5 now the oldest data in the buffer.
47+
Finally, if two elements are removed then what would be returned is 5 & 6 yielding the buffer:
48+
49+
```text
50+
[ ][ ][7][8][9][A][B]
51+
```
52+
53+
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.
54+
7 is still the oldest element and the buffer is once again full.
55+
56+
```text
57+
[C][D][7][8][9][A][B]
58+
```
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
class EmptyBufferException() extends Exception {}
2+
3+
class FullBufferException() extends Exception {}
4+
5+
class CircularBuffer(var capacity: Int) {
6+
private var data = List[Int]()
7+
8+
def write(value: Int): Unit = {
9+
if (isFull()) {
10+
throw new FullBufferException
11+
}
12+
data = value :: data
13+
}
14+
15+
def read(): Int = {
16+
if (data.isEmpty) {
17+
throw new EmptyBufferException
18+
}
19+
20+
val last = data.last
21+
data = data.init
22+
last
23+
}
24+
25+
def overwrite(value: Int): Unit = {
26+
if (isFull()) {
27+
read()
28+
}
29+
30+
write(value)
31+
}
32+
33+
def clear(): Unit = {
34+
data = List[Int]()
35+
}
36+
37+
def isFull() = data.size == capacity
38+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"authors": [
3+
"BNAndras"
4+
],
5+
"files": {
6+
"solution": [
7+
"src/main/scala/CircularBuffer.scala"
8+
],
9+
"test": [
10+
"src/test/scala/CircularBufferTest.scala"
11+
],
12+
"example": [
13+
".meta/Example.scala"
14+
]
15+
},
16+
"blurb": "A data structure that uses a single, fixed-size buffer as if it were connected end-to-end.",
17+
"source": "Wikipedia",
18+
"source_url": "https://en.wikipedia.org/wiki/Circular_buffer"
19+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# This is an auto-generated file.
2+
#
3+
# Regenerating this file via `configlet sync` will:
4+
# - Recreate every `description` key/value pair
5+
# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications
6+
# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion)
7+
# - Preserve any other key/value pair
8+
#
9+
# As user-added comments (using the # character) will be removed when this file
10+
# is regenerated, comments can be added via a `comment` key.
11+
12+
[28268ed4-4ff3-45f3-820e-895b44d53dfa]
13+
description = "reading empty buffer should fail"
14+
15+
[2e6db04a-58a1-425d-ade8-ac30b5f318f3]
16+
description = "can read an item just written"
17+
18+
[90741fe8-a448-45ce-be2b-de009a24c144]
19+
description = "each item may only be read once"
20+
21+
[be0e62d5-da9c-47a8-b037-5db21827baa7]
22+
description = "items are read in the order they are written"
23+
24+
[2af22046-3e44-4235-bfe6-05ba60439d38]
25+
description = "full buffer can't be written to"
26+
27+
[547d192c-bbf0-4369-b8fa-fc37e71f2393]
28+
description = "a read frees up capacity for another write"
29+
30+
[04a56659-3a81-4113-816b-6ecb659b4471]
31+
description = "read position is maintained even across multiple writes"
32+
33+
[60c3a19a-81a7-43d7-bb0a-f07242b1111f]
34+
description = "items cleared out of buffer can't be read"
35+
36+
[45f3ae89-3470-49f3-b50e-362e4b330a59]
37+
description = "clear frees up capacity for another write"
38+
39+
[e1ac5170-a026-4725-bfbe-0cf332eddecd]
40+
description = "clear does nothing on empty buffer"
41+
42+
[9c2d4f26-3ec7-453f-a895-7e7ff8ae7b5b]
43+
description = "overwrite acts like write on non-full buffer"
44+
45+
[880f916b-5039-475c-bd5c-83463c36a147]
46+
description = "overwrite replaces the oldest item on full buffer"
47+
48+
[bfecab5b-aca1-4fab-a2b0-cd4af2b053c3]
49+
description = "overwrite replaces the oldest item remaining in buffer following a read"
50+
51+
[9cebe63a-c405-437b-8b62-e3fdc1ecec5a]
52+
description = "initial clear does not affect wrapping around"
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
scalaVersion := "2.13.6"
2+
3+
libraryDependencies += "org.scalatest" %% "scalatest" % "3.2.10" % "test"
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
class EmptyBufferException() extends Exception {}
2+
3+
class FullBufferException() extends Exception {}
4+
5+
class CircularBuffer(var capacity: Int) {
6+
7+
def write(value: Int) = ???
8+
9+
def read(): Int = ???
10+
11+
def overwrite(value: Int) = ???
12+
13+
def clear() = ???
14+
}

0 commit comments

Comments
 (0)