From b754ae27d2dc8641b9c1a2b69a13c3b556a9a374 Mon Sep 17 00:00:00 2001 From: Falilah Date: Mon, 2 Dec 2024 08:52:12 +0100 Subject: [PATCH] variable length quantity (#311) * word search updated * word search * word search updated * word search requested changes made * word search requested changes made * word search requested changes made * word search requested changes made * word search requested changes made * Increase difficulty * isbn verifier updated * isbn-verifier changes updated * Fix panic message * vlq updated * vlq updated * vlq: requested changes updated * Update difficulty --------- Co-authored-by: Nenad --- config.json | 8 + .../.docs/instructions.md | 34 +++ .../.meta/config.json | 22 ++ .../.meta/example.cairo | 67 ++++ .../variable-length-quantity/.meta/tests.toml | 88 ++++++ .../variable-length-quantity/Scarb.toml | 7 + .../variable-length-quantity/src/lib.cairo | 7 + .../tests/variable_length_quantity.cairo | 285 ++++++++++++++++++ 8 files changed, 518 insertions(+) create mode 100644 exercises/practice/variable-length-quantity/.docs/instructions.md create mode 100644 exercises/practice/variable-length-quantity/.meta/config.json create mode 100644 exercises/practice/variable-length-quantity/.meta/example.cairo create mode 100644 exercises/practice/variable-length-quantity/.meta/tests.toml create mode 100644 exercises/practice/variable-length-quantity/Scarb.toml create mode 100644 exercises/practice/variable-length-quantity/src/lib.cairo create mode 100644 exercises/practice/variable-length-quantity/tests/variable_length_quantity.cairo diff --git a/config.json b/config.json index e13242f4..071775bd 100644 --- a/config.json +++ b/config.json @@ -867,6 +867,14 @@ "practices": [], "prerequisites": [], "difficulty": 4 + }, + { + "slug": "variable-length-quantity", + "name": "Variable Length Quantity", + "uuid": "66e4bb61-076a-4adb-b7a0-b216196e699e", + "practices": [], + "prerequisites": [], + "difficulty": 5 } ], "foregone": [ diff --git a/exercises/practice/variable-length-quantity/.docs/instructions.md b/exercises/practice/variable-length-quantity/.docs/instructions.md new file mode 100644 index 00000000..50125482 --- /dev/null +++ b/exercises/practice/variable-length-quantity/.docs/instructions.md @@ -0,0 +1,34 @@ +# Instructions + +Implement variable length quantity encoding and decoding. + +The goal of this exercise is to implement [VLQ][vlq] encoding/decoding. + +In short, the goal of this encoding is to encode integer values in a way that would save bytes. +Only the first 7 bits of each byte are significant (right-justified; sort of like an ASCII byte). +So, if you have a 32-bit value, you have to unpack it into a series of 7-bit bytes. +Of course, you will have a variable number of bytes depending upon your integer. +To indicate which is the last byte of the series, you leave bit #7 clear. +In all of the preceding bytes, you set bit #7. + +So, if an integer is between `0-127`, it can be represented as one byte. +Although VLQ can deal with numbers of arbitrary sizes, for this exercise we will restrict ourselves to only numbers that fit in a 32-bit unsigned integer. +Here are examples of integers as 32-bit values, and the variable length quantities that they translate to: + +```text + NUMBER VARIABLE QUANTITY +00000000 00 +00000040 40 +0000007F 7F +00000080 81 00 +00002000 C0 00 +00003FFF FF 7F +00004000 81 80 00 +00100000 C0 80 00 +001FFFFF FF FF 7F +00200000 81 80 80 00 +08000000 C0 80 80 00 +0FFFFFFF FF FF FF 7F +``` + +[vlq]: https://en.wikipedia.org/wiki/Variable-length_quantity diff --git a/exercises/practice/variable-length-quantity/.meta/config.json b/exercises/practice/variable-length-quantity/.meta/config.json new file mode 100644 index 00000000..becb23ed --- /dev/null +++ b/exercises/practice/variable-length-quantity/.meta/config.json @@ -0,0 +1,22 @@ +{ + "authors": [ + "Falilah" + ], + "files": { + "solution": [ + "src/lib.cairo" + ], + "test": [ + "tests/variable_length_quantity.cairo" + ], + "example": [ + ".meta/example.cairo" + ], + "invalidator": [ + "Scarb.toml" + ] + }, + "blurb": "Implement variable length quantity encoding and decoding.", + "source": "A poor Splice developer having to implement MIDI encoding/decoding.", + "source_url": "https://splice.com" +} diff --git a/exercises/practice/variable-length-quantity/.meta/example.cairo b/exercises/practice/variable-length-quantity/.meta/example.cairo new file mode 100644 index 00000000..ae063459 --- /dev/null +++ b/exercises/practice/variable-length-quantity/.meta/example.cairo @@ -0,0 +1,67 @@ +const EIGHT_BIT_MASK: u32 = 0x80; +const SEVEN_BIT_MASK: u32 = 0x7f; +const TWO_POW_7: u32 = 128; + +pub fn encode(integers: Array) -> Array { + let mut result = ArrayTrait::::new(); + + for integer in integers { + let mut value = integer; + let mut temp_result = ArrayTrait::::new(); + + if value == 0 { + temp_result.append(0); + } + while value > 0 { + // take the lower 7 bits + let mut tmp = value & SEVEN_BIT_MASK; + // remove them from the original value + value = value / TWO_POW_7; + + // set continuation bit + if !temp_result.is_empty() { + tmp = tmp | EIGHT_BIT_MASK; + } + + temp_result.append(tmp); + }; + + temp_result = reverse_array(temp_result); + result.append_span(temp_result.span()); + }; + result +} + +pub fn decode(integers: Array) -> Array { + let mut res = ArrayTrait::::new(); + let size = integers.len(); + let mut tmp = 0; + let mut i = 0; + for integer in integers { + tmp = (tmp * EIGHT_BIT_MASK) | (integer & SEVEN_BIT_MASK); + + if EIGHT_BIT_MASK & integer == 0 { + // continuation bit not set, number if complete + res.append(tmp); + tmp = 0; + } else { + // check for incomplete bytes + assert!(i + 1 != size, "incomplete sequence"); + } + i += 1; + }; + + res +} + +fn reverse_array(arr: Array) -> Array { + let mut reversed: Array = ArrayTrait::new(); + + let mut i = arr.len(); + while i > 0 { + i -= 1; + reversed.append(*arr[i]); + }; + + reversed +} diff --git a/exercises/practice/variable-length-quantity/.meta/tests.toml b/exercises/practice/variable-length-quantity/.meta/tests.toml new file mode 100644 index 00000000..c9af549f --- /dev/null +++ b/exercises/practice/variable-length-quantity/.meta/tests.toml @@ -0,0 +1,88 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[35c9db2e-f781-4c52-b73b-8e76427defd0] +description = "Encode a series of integers, producing a series of bytes. -> zero" + +[be44d299-a151-4604-a10e-d4b867f41540] +description = "Encode a series of integers, producing a series of bytes. -> arbitrary single byte" + +[ea399615-d274-4af6-bbef-a1c23c9e1346] +description = "Encode a series of integers, producing a series of bytes. -> largest single byte" + +[77b07086-bd3f-4882-8476-8dcafee79b1c] +description = "Encode a series of integers, producing a series of bytes. -> smallest double byte" + +[63955a49-2690-4e22-a556-0040648d6b2d] +description = "Encode a series of integers, producing a series of bytes. -> arbitrary double byte" + +[29da7031-0067-43d3-83a7-4f14b29ed97a] +description = "Encode a series of integers, producing a series of bytes. -> largest double byte" + +[3345d2e3-79a9-4999-869e-d4856e3a8e01] +description = "Encode a series of integers, producing a series of bytes. -> smallest triple byte" + +[5df0bc2d-2a57-4300-a653-a75ee4bd0bee] +description = "Encode a series of integers, producing a series of bytes. -> arbitrary triple byte" + +[f51d8539-312d-4db1-945c-250222c6aa22] +description = "Encode a series of integers, producing a series of bytes. -> largest triple byte" + +[da78228b-544f-47b7-8bfe-d16b35bbe570] +description = "Encode a series of integers, producing a series of bytes. -> smallest quadruple byte" + +[11ed3469-a933-46f1-996f-2231e05d7bb6] +description = "Encode a series of integers, producing a series of bytes. -> arbitrary quadruple byte" + +[d5f3f3c3-e0f1-4e7f-aad0-18a44f223d1c] +description = "Encode a series of integers, producing a series of bytes. -> largest quadruple byte" + +[91a18b33-24e7-4bfb-bbca-eca78ff4fc47] +description = "Encode a series of integers, producing a series of bytes. -> smallest quintuple byte" + +[5f34ff12-2952-4669-95fe-2d11b693d331] +description = "Encode a series of integers, producing a series of bytes. -> arbitrary quintuple byte" + +[7489694b-88c3-4078-9864-6fe802411009] +description = "Encode a series of integers, producing a series of bytes. -> maximum 32-bit integer input" + +[f9b91821-cada-4a73-9421-3c81d6ff3661] +description = "Encode a series of integers, producing a series of bytes. -> two single-byte values" + +[68694449-25d2-4974-ba75-fa7bb36db212] +description = "Encode a series of integers, producing a series of bytes. -> two multi-byte values" + +[51a06b5c-de1b-4487-9a50-9db1b8930d85] +description = "Encode a series of integers, producing a series of bytes. -> many multi-byte values" + +[baa73993-4514-4915-bac0-f7f585e0e59a] +description = "Decode a series of bytes, producing a series of integers. -> one byte" + +[72e94369-29f9-46f2-8c95-6c5b7a595aee] +description = "Decode a series of bytes, producing a series of integers. -> two bytes" + +[df5a44c4-56f7-464e-a997-1db5f63ce691] +description = "Decode a series of bytes, producing a series of integers. -> three bytes" + +[1bb58684-f2dc-450a-8406-1f3452aa1947] +description = "Decode a series of bytes, producing a series of integers. -> four bytes" + +[cecd5233-49f1-4dd1-a41a-9840a40f09cd] +description = "Decode a series of bytes, producing a series of integers. -> maximum 32-bit integer" + +[e7d74ba3-8b8e-4bcb-858d-d08302e15695] +description = "Decode a series of bytes, producing a series of integers. -> incomplete sequence causes error" + +[aa378291-9043-4724-bc53-aca1b4a3fcb6] +description = "Decode a series of bytes, producing a series of integers. -> incomplete sequence causes error, even if value is zero" + +[a91e6f5a-c64a-48e3-8a75-ce1a81e0ebee] +description = "Decode a series of bytes, producing a series of integers. -> multiple values" diff --git a/exercises/practice/variable-length-quantity/Scarb.toml b/exercises/practice/variable-length-quantity/Scarb.toml new file mode 100644 index 00000000..f835a8e7 --- /dev/null +++ b/exercises/practice/variable-length-quantity/Scarb.toml @@ -0,0 +1,7 @@ +[package] +name = "variable_length_quantity" +version = "0.1.0" +edition = "2024_07" + +[dev-dependencies] +cairo_test = "2.8.2" diff --git a/exercises/practice/variable-length-quantity/src/lib.cairo b/exercises/practice/variable-length-quantity/src/lib.cairo new file mode 100644 index 00000000..e67ae438 --- /dev/null +++ b/exercises/practice/variable-length-quantity/src/lib.cairo @@ -0,0 +1,7 @@ +pub fn encode(integers: Array) -> Array { + panic!("implement `encode`") +} + +pub fn decode(integers: Array) -> Array { + panic!("implemenent `decode`") +} diff --git a/exercises/practice/variable-length-quantity/tests/variable_length_quantity.cairo b/exercises/practice/variable-length-quantity/tests/variable_length_quantity.cairo new file mode 100644 index 00000000..6bb9627b --- /dev/null +++ b/exercises/practice/variable-length-quantity/tests/variable_length_quantity.cairo @@ -0,0 +1,285 @@ +use variable_length_quantity::{encode, decode}; + +#[test] +fn zero() { + let integers = array![0]; + let expected = array![0]; + + let result = encode(integers); + + assert_eq!(result, expected); +} + +#[test] +#[ignore] +fn arbitrary_single_byte() { + let integers = array![64]; + let expected = array![64]; + + let result = encode(integers); + + assert_eq!(result, expected); +} + +#[test] +#[ignore] +fn largest_single_byte() { + let integers = array![127]; + let expected = array![127]; + + let result = encode(integers); + + assert_eq!(result, expected); +} + +#[test] +#[ignore] +fn smallest_double_byte() { + let integers = array![128]; + let expected = array![129, 0]; + + let result = encode(integers); + + assert_eq!(result, expected); +} + + +#[test] +#[ignore] +fn arbitrary_double_byte() { + let integers = array![8192]; + let expected = array![192, 0]; + + let result = encode(integers); + + assert_eq!(result, expected); +} + + +#[test] +#[ignore] +fn largest_double_byte() { + let integers = array![16383]; + let expected = array![255, 127]; + + let result = encode(integers); + + assert_eq!(result, expected); +} + + +#[test] +#[ignore] +fn smallest_triple_byte() { + let integers = array![16384]; + let expected = array![129, 128, 0]; + + let result = encode(integers); + + assert_eq!(result, expected); +} + +#[test] +#[ignore] +fn arbitrary_triple_byte() { + let integers = array![1048576]; + let expected = array![192, 128, 0]; + + let result = encode(integers); + + assert_eq!(result, expected); +} + +#[test] +#[ignore] +fn largest_triple_byte() { + let integers = array![2097151]; + let expected = array![255, 255, 127]; + + let result = encode(integers); + + assert_eq!(result, expected); +} + +#[test] +#[ignore] +fn smallest_quadruple_byte() { + let integers = array![2097152]; + let expected = array![129, 128, 128, 0]; + + let result = encode(integers); + + assert_eq!(result, expected); +} + +#[test] +#[ignore] +fn arbitrary_quadruple_byte() { + let integers = array![134217728]; + let expected = array![192, 128, 128, 0]; + + let result = encode(integers); + + assert_eq!(result, expected); +} + +#[test] +#[ignore] +fn largest_quadruple_byte() { + let integers = array![268435455]; + let expected = array![255, 255, 255, 127]; + + let result = encode(integers); + + assert_eq!(result, expected); +} + +#[test] +#[ignore] +fn smallest_quintuple_byte() { + let integers = array![268435456]; + let expected = array![129, 128, 128, 128, 0]; + + let result = encode(integers); + + assert_eq!(result, expected); +} + +#[test] +#[ignore] +fn arbitrary_quintuple_byte() { + let integers = array![4278190080]; + let expected = array![143, 248, 128, 128, 0]; + + let result = encode(integers); + + assert_eq!(result, expected); +} + +#[test] +#[ignore] +fn maximum_32_bit_integer_input() { + let integers = array![4294967295]; + let expected = array![143, 255, 255, 255, 127]; + + let result = encode(integers); + + assert_eq!(result, expected); +} + + +#[test] +#[ignore] +fn two_single_byte_values() { + let integers = array![64, 127]; + let expected = array![64, 127]; + + let result = encode(integers); + + assert_eq!(result, expected); +} + +#[test] +#[ignore] +fn two_multi_byte_values() { + let integers = array![16384, 1193046]; + let expected = array![129, 128, 0, 200, 232, 86]; + + let result = encode(integers); + + assert_eq!(result, expected); +} + +#[test] +#[ignore] +fn many_multi_byte_values() { + let integers = array![8192, 1193046, 268435455, 0, 16383, 16384]; + let expected = array![192, 0, 200, 232, 86, 255, 255, 255, 127, 0, 255, 127, 129, 128, 0]; + + let result = encode(integers); + + assert_eq!(result, expected); +} + +#[test] +#[ignore] +fn one_byte() { + let integers = array![127]; + let expected = array![127]; + + let result = decode(integers); + + assert_eq!(result, expected); +} + +#[test] +#[ignore] +fn two_byte() { + let integers = array![192, 0]; + let expected = array![8192]; + + let result = decode(integers); + + assert_eq!(result, expected); +} + +#[test] +#[ignore] +fn three_byte() { + let integers = array![255, 255, 127]; + let expected = array![2097151]; + + let result = decode(integers); + + assert_eq!(result, expected); +} + +#[test] +#[ignore] +fn four_byte() { + let integers = array![129, 128, 128, 0]; + let expected = array![2097152]; + + let result = decode(integers); + + assert_eq!(result, expected); +} + +#[test] +#[ignore] +fn maximum_32_bit_integer() { + let integers = array![143, 255, 255, 255, 127]; + let expected = array![4294967295]; + + let result = decode(integers); + + assert_eq!(result, expected); +} + +#[test] +#[ignore] +#[should_panic(expected: ("incomplete sequence",))] +fn incomplete_sequence_causes_error() { + let integers = array![255]; + let _ = decode(integers); +} + +#[test] +#[ignore] +#[should_panic(expected: ("incomplete sequence",))] +fn incomplete_sequence_causes_error_even_if_value_is_zero() { + let integers = array![128]; + let _ = decode(integers); +} + + +#[test] +#[ignore] +fn multiple_values() { + let integers = array![192, 0, 200, 232, 86, 255, 255, 255, 127, 0, 255, 127, 129, 128, 0]; + let expected = array![8192, 1193046, 268435455, 0, 16383, 16384]; + + let result = decode(integers); + + assert_eq!(result, expected); +}