Skip to content

Commit

Permalink
Add Cairo LoC (#204)
Browse files Browse the repository at this point in the history
* Add Cairo LoC

* Fix multiple-files expected values
  • Loading branch information
0xNeshi authored Jul 23, 2024
1 parent 7614516 commit ec4351b
Show file tree
Hide file tree
Showing 9 changed files with 290 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
node_modules/
tests/**/response.json
tests/**/.tokeignore
tests/**/Scarb.lock
4 changes: 4 additions & 0 deletions tests/cairo/multiple-files/Scarb.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[package]
name = "anagram"
version = "0.1.0"
edition = "2023_11"
9 changes: 9 additions & 0 deletions tests/cairo/multiple-files/expected_response.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"statusCode": 200,
"statusDescription": "200 OK",
"headers": {
"Content-Type": "application/json"
},
"isBase64Encoded": false,
"body": "{\"counts\":{\"code\":111,\"blanks\":17,\"comments\":4},\"files\":[\"src/helper.cairo\",\"src/lib.cairo\"]}"
}
65 changes: 65 additions & 0 deletions tests/cairo/multiple-files/src/helper.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
pub impl IgnoreCase of PartialEq<ByteArray> {
fn eq(lhs: @ByteArray, rhs: @ByteArray) -> bool {
let len = lhs.len();
if len != rhs.len() {
return false;
}
let mut i = 0;
loop {
if i == len {
break true;
}
if lowercase(@lhs[i]) != lowercase(@rhs[i]) {
break false;
}
i += 1;
}
}

fn ne(lhs: @ByteArray, rhs: @ByteArray) -> bool {
!IgnoreCase::eq(lhs, rhs)
}
}

pub fn sort_ignore_case(word: @ByteArray) -> ByteArray {
// count the number each of the alphabet ASCII characters appears
let mut ascii_chars: Felt252Dict<u8> = Default::default();
let mut i = word.len();
while i != 0 {
i -= 1;
let char: felt252 = word[i].into();
ascii_chars.insert(char, ascii_chars.get(char) + 1);
};

let mut sorted_word: ByteArray = "";

// append each appearing alphabet ASCII character
let mut alphabet_char: u8 = 65; // char 'A'
while alphabet_char <= 90 { // char 'Z'
// process uppercase char
let mut count = ascii_chars.get(alphabet_char.into());
while count != 0 {
sorted_word.append_byte(alphabet_char);
count -= 1;
};
// process lowercase char
let lowercase_char = alphabet_char + 32;
let mut count = ascii_chars.get(lowercase_char.into());
while count != 0 {
sorted_word.append_byte(lowercase_char);
count -= 1;
};

alphabet_char += 1;
};

sorted_word
}

fn lowercase(char: @u8) -> u8 {
if *char < 97 {
*char + 32
} else {
*char
}
}
67 changes: 67 additions & 0 deletions tests/cairo/multiple-files/src/lib.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
use anagram::helper::{IgnoreCase, sort_ignore_case};

#[derive(Drop, Debug)]
struct Set {
values: Array<ByteArray>
}

#[generate_trait]
pub impl SetImpl of SetTrait {
fn new(values: Array<ByteArray>) -> Set {
Set { values }
}
}

impl SetEq of PartialEq<Set> {
fn eq(lhs: @Set, rhs: @Set) -> bool {
let len = lhs.values.len();
if len != rhs.values.len() {
return false;
}
let mut i = 0;
loop {
if i == len {
break true;
}
let l_item = lhs.values.at(i);
let mut j = 0;
while j != len {
if IgnoreCase::eq(l_item, rhs.values.at(j)) {
break;
}
j += 1;
};
if j == len {
break false;
}
i += 1;
}
}

fn ne(lhs: @Set, rhs: @Set) -> bool {
!(lhs == rhs)
}
}

pub fn anagrams_for(word: @ByteArray, inputs: @Set) -> Set {
let mut word_sorted = @sort_ignore_case(word);
let mut anagrams = Set { values: array![] };
let mut i = inputs.values.len();

while i != 0 {
i -= 1;
let candidate = inputs.values[i];

let is_anagram = word.len() == candidate.len()
&& IgnoreCase::ne(word, candidate)
&& IgnoreCase::eq(word_sorted, @sort_ignore_case(candidate));

if is_anagram {
anagrams.values.append(format!("{candidate}"));
}
};

anagrams
}

mod helper;
4 changes: 4 additions & 0 deletions tests/cairo/single-file/Scarb.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[package]
name = "anagram"
version = "0.1.0"
edition = "2023_11"
9 changes: 9 additions & 0 deletions tests/cairo/single-file/expected_response.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"statusCode": 200,
"statusDescription": "200 OK",
"headers": {
"Content-Type": "application/json"
},
"isBase64Encoded": false,
"body": "{\"counts\":{\"code\":109,\"blanks\":16,\"comments\":4},\"files\":[\"src/lib.cairo\"]}"
}
129 changes: 129 additions & 0 deletions tests/cairo/single-file/src/lib.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
#[derive(Drop, Debug)]
struct Set {
values: Array<ByteArray>
}

#[generate_trait]
pub impl SetImpl of SetTrait {
fn new(values: Array<ByteArray>) -> Set {
Set { values }
}
}

impl SetEq of PartialEq<Set> {
fn eq(lhs: @Set, rhs: @Set) -> bool {
let len = lhs.values.len();
if len != rhs.values.len() {
return false;
}
let mut i = 0;
loop {
if i == len {
break true;
}
let l_item = lhs.values.at(i);
let mut j = 0;
while j != len {
if IgnoreCase::eq(l_item, rhs.values.at(j)) {
break;
}
j += 1;
};
if j == len {
break false;
}
i += 1;
}
}

fn ne(lhs: @Set, rhs: @Set) -> bool {
!(lhs == rhs)
}
}

pub fn anagrams_for(word: @ByteArray, inputs: @Set) -> Set {
let mut word_sorted = @sort_ignore_case(word);
let mut anagrams = Set { values: array![] };
let mut i = inputs.values.len();

while i != 0 {
i -= 1;
let candidate = inputs.values[i];

let is_anagram = word.len() == candidate.len()
&& IgnoreCase::ne(word, candidate)
&& IgnoreCase::eq(word_sorted, @sort_ignore_case(candidate));

if is_anagram {
anagrams.values.append(format!("{candidate}"));
}
};

anagrams
}

impl IgnoreCase of PartialEq<ByteArray> {
fn eq(lhs: @ByteArray, rhs: @ByteArray) -> bool {
let len = lhs.len();
if len != rhs.len() {
return false;
}
let mut i = 0;
loop {
if i == len {
break true;
}
if lowercase(@lhs[i]) != lowercase(@rhs[i]) {
break false;
}
i += 1;
}
}

fn ne(lhs: @ByteArray, rhs: @ByteArray) -> bool {
!IgnoreCase::eq(lhs, rhs)
}
}

fn sort_ignore_case(word: @ByteArray) -> ByteArray {
// count the number each of the alphabet ASCII characters appears
let mut ascii_chars: Felt252Dict<u8> = Default::default();
let mut i = word.len();
while i != 0 {
i -= 1;
let char: felt252 = word[i].into();
ascii_chars.insert(char, ascii_chars.get(char) + 1);
};

let mut sorted_word: ByteArray = "";

// append each appearing alphabet ASCII character
let mut alphabet_char: u8 = 65; // char 'A'
while alphabet_char <= 90 { // char 'Z'
// process uppercase char
let mut count = ascii_chars.get(alphabet_char.into());
while count != 0 {
sorted_word.append_byte(alphabet_char);
count -= 1;
};
// process lowercase char
let lowercase_char = alphabet_char + 32;
let mut count = ascii_chars.get(lowercase_char.into());
while count != 0 {
sorted_word.append_byte(lowercase_char);
count -= 1;
};

alphabet_char += 1;
};

sorted_word
}

fn lowercase(char: @u8) -> u8 {
if *char < 97 {
*char + 32
} else {
*char
}
}
2 changes: 2 additions & 0 deletions tracks/cairo.ignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Scarb.toml
Scarb.lock

0 comments on commit ec4351b

Please sign in to comment.