Generated: 2026-02-16T12:12:48.696813
/* Simple hash map implementation - fundamental data structure */
#include <stdlib.h>
#include <string.h>
#define HASHMAP_INITIAL_CAPACITY 16
typedef struct HashMapEntry {
char* key;
void* value;
struct HashMapEntry* next;
} HashMapEntry;
typedef struct {
HashMapEntry** buckets;
size_t capacity;
size_t size;
} HashMap;
/**
* Simple hash function (djb2)
*/
static unsigned long hash_string(const char* str) {
unsigned long hash = 5381;
int c;
while ((c = *str++)) {
hash = ((hash << 5) + hash) + c;
}
return hash;
}
/**
* Create a new hash map
*/
HashMap* hashmap_new(void) {
HashMap* map = (HashMap*)malloc(sizeof(HashMap));
if (!map) return NULL;
map->capacity = HASHMAP_INITIAL_CAPACITY;
map->size = 0;
map->buckets = (HashMapEntry**)calloc(map->capacity, sizeof(HashMapEntry*));
if (!map->buckets) {
free(map);
return NULL;
}
return map;
}
/**
* Insert or update a key-value pair
*/
int hashmap_put(HashMap* map, const char* key, void* value) {
if (!map || !key) return -1;
unsigned long hash = hash_string(key);
size_t index = hash % map->capacity;
// Check if key exists
HashMapEntry* entry = map->buckets[index];
while (entry) {
if (strcmp(entry->key, key) == 0) {
entry->value = value;
return 0;
}
entry = entry->next;
}
// Create new entry
HashMapEntry* new_entry = (HashMapEntry*)malloc(sizeof(HashMapEntry));
if (!new_entry) return -1;
new_entry->key = strdup(key);
if (!new_entry->key) {
free(new_entry);
return -1;
}
new_entry->value = value;
new_entry->next = map->buckets[index];
map->buckets[index] = new_entry;
map->size++;
return 0;
}
/**
* Get value for a key
*/
void* hashmap_get(HashMap* map, const char* key) {
if (!map || !key) return NULL;
unsigned long hash = hash_string(key);
size_t index = hash % map->capacity;
HashMapEntry* entry = map->buckets[index];
while (entry) {
if (strcmp(entry->key, key) == 0) {
return entry->value;
}
entry = entry->next;
}
return NULL;
}
/**
* Remove a key-value pair
*/
int hashmap_remove(HashMap* map, const char* key) {
if (!map || !key) return -1;
unsigned long hash = hash_string(key);
size_t index = hash % map->capacity;
HashMapEntry** indirect = &map->buckets[index];
HashMapEntry* entry = *indirect;
while (entry) {
if (strcmp(entry->key, key) == 0) {
*indirect = entry->next;
free(entry->key);
free(entry);
map->size--;
return 0;
}
indirect = &entry->next;
entry = entry->next;
}
return -1;
}
/**
* Free hash map and all entries
*/
void hashmap_free(HashMap* map) {
if (!map) return;
for (size_t i = 0; i < map->capacity; i++) {
HashMapEntry* entry = map->buckets[i];
while (entry) {
HashMapEntry* next = entry->next;
free(entry->key);
free(entry);
entry = next;
}
}
free(map->buckets);
free(map);
}
| Dimension | Score | Max | Details |
|---|---|---|---|
| Compilation | 0 | 25 | ✗ Compilation errors: warning: unused import: `std::collections::hash_map::DefaultHasher` --> /var/folders/hd/dlntwdzx0rg8g8z7x52tdkp80000gn/T/tmpnhftkqi6/lib.rs:1:5 | 1 | use std::collections::hash_map::DefaultHasher; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `#[warn(unused_imports)]` (part of `#[warn(unused)]`) on by default warning: unused imports: `Hash` and `Hasher` --> /var/folders/hd/dlntwdzx0rg8g8z7x52tdkp80000gn/T/tmpnhftkqi6/lib.rs:2:17 | 2 | use std::hash::{Hash, Hasher}; | ^^^^ ^^^^^^ error[E0506]: cannot assign to `*current` because it is borrowed --> /var/folders/hd/dlntwdzx0rg8g8z7x52tdkp80000gn/T/tmpnhftkqi6/lib.rs:118:25 | 116 | Some(entry) => { | ----- `*current` is borrowed here 117 | if entry.key == key { 118 | *current = entry.next.take(); | ^^^^^^^^ | | | `*current` is assigned to here but it was already borrowed | borrow later used here error: aborting due to 1 previous error; 2 warnings emitted For more information about this error, try `rustc --explain E0506`. |
| Safety | 20 | 20 | ✓ No unsafe blocks | ✓ Uses Result for error handling | ✓ Uses Option for nullable values | ✓ Smart pointer usage |
| Quality | 15 | 20 | ✓ Snake_case naming | ✓ Well documented (10 doc comments) | ✓ Functional programming patterns | ✓ Proper type definitions |
| Correctness | 3 | 15 | ✓ Pattern matching |
| Maintainability | 5 | 10 | ✓ Clear public API (8 items) | ✓ Uses constants |
| Performance | 10 | 10 | ✓ Minimal cloning | ✓ Reference usage |
❌ Compilation: FAILED
✗ Compilation errors: warning: unused import: `std::collections::hash_map::DefaultHasher`
--> /var/folders/hd/dlntwdzx0rg8g8z7x52tdkp80000gn/T/tmpnhftkqi6/lib.rs:1:5
|
1 | use std::collections::hash_map::DefaultHasher;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[warn(unused_imports)]` (part of `#[warn(unused)]`) on by default
warning: unused imports: `Hash` and `Hasher`
--> /var/folders/hd/dlntwdzx0rg8g8z7x52tdkp80000gn/T/tmpnhftkqi6/lib.rs:2:17
|
2 | use std::hash::{Hash, Hasher};
| ^^^^ ^^^^^^
error[E0506]: cannot assign to `*current` because it is borrowed
--> /var/folders/hd/dlntwdzx0rg8g8z7x52tdkp80000gn/T/tmpnhftkqi6/lib.rs:118:25
|
116 | Some(entry) => {
| ----- `*current` is borrowed here
117 | if entry.key == key {
118 | *current = entry.next.take();
| ^^^^^^^^
| |
| `*current` is assigned to here but it was already borrowed
| borrow later used here
error: aborting due to 1 previous error; 2 warnings emitted
For more information about this error, try `rustc --explain E0506`.
Error Type: E0506: Borrow Checker Violation
Summary: Cannot assign to a variable because it is borrowed
Location: Line 1: `use std::collections::hash_map::DefaultHasher;`
Rust's borrow checker prevents you from modifying a variable while you have an active borrow of it. In this case, the code tries to assign to a mutable reference (`*current`) while `entry` still borrows it. This is a classic pattern when working with self-referential data structures like linked lists.
The LLM translated C's pointer manipulation patterns directly to Rust, but didn't account for Rust's ownership rules. C allows you to modify pointers freely, but Rust tracks borrows statically and prevents simultaneous aliasing + mutation.
Use `std::mem::replace()` or restructure the code to avoid borrowing and mutating simultaneously: ```rust // Instead of: *current = entry.next.take(); // Use: let next = std::mem::replace(current, None); *current = next.and_then(|mut e| e.next.take()); ``` Or use `Option::take()` earlier to move ownership before the borrow.
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
const HASHMAP_INITIAL_CAPACITY: usize = 16;
/// Entry in the hash map containing a key-value pair and pointer to next entry
struct HashMapEntry<T> {
key: String,
value: T,
next: Option<Box<HashMapEntry<T>>>,
}
/// Simple hash map implementation using separate chaining
pub struct HashMap<T> {
buckets: Vec<Option<Box<HashMapEntry<T>>>>,
capacity: usize,
size: usize,
}
/// Simple hash function (djb2)
fn hash_string(s: &str) -> u64 {
let mut hash: u64 = 5381;
for c in s.bytes() {
hash = hash.wrapping_shl(5).wrapping_add(hash).wrapping_add(c as u64);
}
hash
}
impl<T> HashMap<T> {
/// Create a new hash map
pub fn new() -> Self {
HashMap {
buckets: (0..HASHMAP_INITIAL_CAPACITY).map(|_| None).collect(),
capacity: HASHMAP_INITIAL_CAPACITY,
size: 0,
}
}
/// Insert or update a key-value pair
pub fn put(&mut self, key: &str, value: T) -> Result<(), String> {
let hash = hash_string(key);
let index = (hash % self.capacity as u64) as usize;
let mut current = &mut self.buckets[index];
// Check if key exists and update
loop {
match current {
Some(entry) => {
if entry.key == key {
entry.value = value;
return Ok(());
}
current = &mut entry.next;
}
None => break,
}
}
// Create new entry
let new_entry = Box::new(HashMapEntry {
key: key.to_string(),
value,
next: self.buckets[index].take(),
});
self.buckets[index] = Some(new_entry);
self.size += 1;
Ok(())
}
/// Get value for a key
pub fn get(&self, key: &str) -> Option<&T> {
let hash = hash_string(key);
let index = (hash % self.capacity as u64) as usize;
let mut current = &self.buckets[index];
while let Some(entry) = current {
if entry.key == key {
return Some(&entry.value);
}
current = &entry.next;
}
None
}
/// Get mutable value for a key
pub fn get_mut(&mut self, key: &str) -> Option<&mut T> {
let hash = hash_string(key);
let index = (hash % self.capacity as u64) as usize;
let mut current = &mut self.buckets[index];
while let Some(entry) = current {
if entry.key == key {
return Some(&mut entry.value);
}
current = &mut entry.next;
}
None
}
/// Remove a key-value pair
pub fn remove(&mut self, key: &str) -> Result<(), String> {
let hash = hash_string(key);
let index = (hash % self.capacity as u64) as usize;
let mut current = &mut self.buckets[index];
loop {
match current {
Some(entry) => {
if entry.key == key {
*current = entry.next.take();
self.size -= 1;
return Ok(());
}
current = &mut entry.next;
}
None => return Err("Key not found".to_string()),
}
}
}
/// Get the number of entries in the map
pub fn size(&self) -> usize {
self.size
}
/// Get the capacity of the map
pub fn capacity(&self) -> usize {
self.capacity
}
}
impl<T> Default for HashMap<T> {
fn default() -> Self {
Self::new()
}
}
| Dimension | Score | Max | Details |
|---|---|---|---|
| Compilation | 0 | 25 | ✗ Compilation errors: warning: unused import: `std::ptr` --> /var/folders/hd/dlntwdzx0rg8g8z7x52tdkp80000gn/T/tmpcg0kgcfd/lib.rs:5:5 | 5 | use std::ptr; | ^^^^^^^^ | = note: `#[warn(unused_imports)]` (part of `#[warn(unused)]`) on by default error[E0277]: the trait bound `Box<HashMapEntry<K, V>>: Clone` is not satisfied --> /var/folders/hd/dlntwdzx0rg8g8z7x52tdkp80000gn/T/tmpcg0kgcfd/lib.rs:43:28 | 43 | let buckets = vec![None; capacity]; | -----^^^^----------- | | | | | the trait `Clone` is not implemented for `Box<HashMapEntry<K, V>>` | required by a bound introduced by this call | = note: required for `Box<HashMapEntry<K, V>>` to implement `Clone` = note: 1 redundant requirement hidden = note: required for `Option<Box<HashMapEntry<K, V>>>` to implement `Clone` note: required by a bound in `from_elem` --> /rustc/01f6ddf7588f42ae2d7eb0a2f21d44e8e96674cf/library/alloc/src/vec/mod.rs:3509:1 help: consider borrowing here | 43 | let buckets = vec![&None; capacity]; | + error[E0506]: cannot assign to `current.next` because it is borrowed --> /var/folders/hd/dlntwdzx0rg8g8z7x52tdkp80000gn/T/tmpcg0kgcfd/lib.rs:86:17 | 71 | match &mut current.next { | ----------------- `current.next` is borrowed here ... 86 | current.next = Some(Box::new(new_entry)); | ^^^^^^^^^^^^ | | | `current.next` is assigned to here but it was already borrowed | borrow later used here error[E0506]: cannot assign to `current.next` because it is borrowed --> /var/folders/hd/dlntwdzx0rg8g8z7x52tdkp80000gn/T/tmpcg0kgcfd/lib.rs:138:29 | 136 | while let Some(next_entry) = &mut current.next { | ----------------- `current.next` is borrowed here 137 | if next_entry.key == *key { 138 | current.next = next_entry.next.take(); | ^^^^^^^^^^^^ | | | `current.next` is assigned to here but it was already borrowed | borrow later used here error: aborting due to 3 previous errors; 1 warning emitted Some errors have detailed explanations: E0277, E0506. For more information about an error, try `rustc --explain E0277`. |
| Safety | 20 | 20 | ✓ No unsafe blocks | ✓ Uses Result for error handling | ✓ Uses Option for nullable values | ✓ Smart pointer usage |
| Quality | 17 | 20 | ✓ Snake_case naming | ✓ Well documented (5 doc comments) | ✓ Uses ? operator | ✓ Proper type definitions | ✓ Implementation blocks |
| Correctness | 3 | 15 | ✓ Pattern matching |
| Maintainability | 4 | 10 | ✓ Uses constants | ✓ Type aliases |
| Performance | 8 | 10 | ✓ Minimal cloning |
❌ Compilation: FAILED
✗ Compilation errors: warning: unused import: `std::ptr`
--> /var/folders/hd/dlntwdzx0rg8g8z7x52tdkp80000gn/T/tmpcg0kgcfd/lib.rs:5:5
|
5 | use std::ptr;
| ^^^^^^^^
|
= note: `#[warn(unused_imports)]` (part of `#[warn(unused)]`) on by default
error[E0277]: the trait bound `Box<HashMapEntry<K, V>>: Clone` is not satisfied
--> /var/folders/hd/dlntwdzx0rg8g8z7x52tdkp80000gn/T/tmpcg0kgcfd/lib.rs:43:28
|
43 | let buckets = vec![None; capacity];
| -----^^^^-----------
| | |
| | the trait `Clone` is not implemented for `Box<HashMapEntry<K, V>>`
| required by a bound introduced by this call
|
= note: required for `Box<HashMapEntry<K, V>>` to implement `Clone`
= note: 1 redundant requirement hidden
= note: required for `Option<Box<HashMapEntry<K, V>>>` to implement `Clone`
note: required by a bound in `from_elem`
--> /rustc/01f6ddf7588f42ae2d7eb0a2f21d44e8e96674cf/library/alloc/src/vec/mod.rs:3509:1
help: consider borrowing here
|
43 | let buckets = vec![&None; capacity];
| +
error[E0506]: cannot assign to `current.next` because it is borrowed
--> /var/folders/hd/dlntwdzx0rg8g8z7x52tdkp80000gn/T/tmpcg0kgcfd/lib.rs:86:17
|
71 | match &mut current.next {
| ----------------- `current.next` is borrowed here
...
86 | current.next = Some(Box::new(new_entry));
| ^^^^^^^^^^^^
| |
| `current.next` is assigned to here but it was already borrowed
| borrow later used here
error[E0506]: cannot assign to `current.next` because it is borrowed
--> /var/folders/hd/dlntwdzx0rg8g8z7x52tdkp80000gn/T/tmpcg0kgcfd/lib.rs:138:29
|
136 | while let Some(next_entry) = &mut current.next {
| ----------------- `current.next` is borrowed here
137 | if next_entry.key == *key {
138 | current.next = next_entry.next.take();
| ^^^^^^^^^^^^
| |
| `current.next` is assigned to here but it was already borrowed
| borrow later used here
error: aborting due to 3 previous errors; 1 warning emitted
Some errors have detailed explanations: E0277, E0506.
For more information about an error, try `rustc --explain E0277`.
Error Type: E0506: Borrow Checker Violation
Summary: Cannot assign to a variable because it is borrowed
Location: Line 5: `use std::ptr;`
Rust's borrow checker prevents you from modifying a variable while you have an active borrow of it. In this case, the code tries to assign to a mutable reference (`*current`) while `entry` still borrows it. This is a classic pattern when working with self-referential data structures like linked lists.
The LLM translated C's pointer manipulation patterns directly to Rust, but didn't account for Rust's ownership rules. C allows you to modify pointers freely, but Rust tracks borrows statically and prevents simultaneous aliasing + mutation.
Use `std::mem::replace()` or restructure the code to avoid borrowing and mutating simultaneously: ```rust // Instead of: *current = entry.next.take(); // Use: let next = std::mem::replace(current, None); *current = next.and_then(|mut e| e.next.take()); ``` Or use `Option::take()` earlier to move ownership before the borrow.
use std::collections::hash_map::DefaultHasher;
use std::error::Error;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::ptr;
const HASHMAP_INITIAL_CAPACITY: usize = 16;
#[derive(Debug)]
struct HashMapError(String);
impl fmt::Display for HashMapError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "HashMapError: {}", self.0)
}
}
impl Error for HashMapError {}
type Result<T> = std::result::Result<T, HashMapError>;
#[derive(Debug)]
struct HashMapEntry<K, V> {
key: K,
value: V,
next: Option<Box<HashMapEntry<K, V>>>,
}
#[derive(Debug)]
struct HashMap<K, V> {
buckets: Vec<Option<Box<HashMapEntry<K, V>>>>,
capacity: usize,
size: usize,
}
impl<K, V> HashMap<K, V>
where
K: Eq + Hash + Clone,
{
/// Creates a new hash map with the initial capacity.
fn new() -> Self {
let capacity = HASHMAP_INITIAL_CAPACITY;
let buckets = vec![None; capacity];
HashMap {
buckets,
capacity,
size: 0,
}
}
/// Generates a hash value for the given key.
fn hash_string(key: &K) -> u64 {
let mut hasher = DefaultHasher::new();
key.hash(&mut hasher);
hasher.finish()
}
/// Inserts a key-value pair into the hash map.
fn put(&mut self, key: K, value: V) -> Result<()> {
let hash = Self::hash_string(&key);
let index = (hash % self.capacity as u64) as usize;
match &mut self.buckets[index] {
Some(entry) => {
let mut current = entry;
loop {
if current.key == key {
current.value = value;
return Ok(());
}
match &mut current.next {
Some(next_entry) => {
current = next_entry;
}
None => {
break;
}
}
}
let new_entry = HashMapEntry {
key: key.clone(),
value,
next: None,
};
current.next = Some(Box::new(new_entry));
}
None => {
let new_entry = HashMapEntry {
key: key.clone(),
value,
next: None,
};
self.buckets[index] = Some(Box::new(new_entry));
}
}
self.size += 1;
Ok(())
}
/// Retrieves the value associated with the given key.
fn get(&self, key: &K) -> Option<&V> {
let hash = Self::hash_string(key);
let index = (hash % self.capacity as u64) as usize;
let mut current = self.buckets[index].as_ref()?;
loop {
if current.key == *key {
return Some(¤t.value);
}
match ¤t.next {
Some(next_entry) => {
current = next_entry;
}
None => {
return None;
}
}
}
}
/// Removes a key-value pair from the hash map.
fn remove(&mut self, key: &K) -> Result<()> {
let hash = Self::hash_string(key);
let index = (hash % self.capacity as u64) as usize;
match &mut self.buckets[index] {
Some(entry) => {
if entry.key == *key {
self.buckets[index] = entry.next.take();
self.size -= 1;
return Ok(());
} else {
let mut current = entry;
while let Some(next_entry) = &mut current.next {
if next_entry.key == *key {
current.next = next_entry.next.take();
self.size -= 1;
return Ok(());
}
current = next_entry;
}
}
}
None => {
return Err(HashMapError("Key not found".to_string()));
}
}
Err(HashMapError("Key not found".to_string()))
}
}
| Model | Total | Compilation | Safety | Quality | Correctness | Maintainability | Performance |
|---|---|---|---|---|---|---|---|
| CLAUDE | 53/100 | 0/25 | 20/20 | 15/20 | 3/15 | 5/10 | 10/10 |
| GEMINI | 52/100 | 0/25 | 20/20 | 17/20 | 3/15 | 4/10 | 8/10 |
CELLO evaluates transpilation quality across 6 dimensions:
Total possible score: 100 points