frozen-cub 0.1.12
A set of C and Python implementations of immutable, hashable, and performant frozen objects.
Requires Python: >=3.12

# Frozen Cub

[![pypi version](https://img.shields.io/pypi/v/frozen-cub.svg)](https://pypi.org/project/frozen-cub/)

A high-performance library for immutable, hashable data structures in Python. Built with Cython for speed.

**Supports Python 3.12, 3.13, and 3.14**

## Features

- **FrozenDict**: An immutable dictionary that can be used as a dict key or in sets
- **freeze()**: Recursively freeze nested data structures (dicts, lists, tuples, sets)
- **LRUCache**: A fast LRU cache with O(1) operations
- **CacheKey**: A lightweight hashable key for caching based on two values

## Installation

```bash
pip install frozen-cub
```

With [`uv`](https://docs.astral.sh/uv/):

```bash
uv add frozen-cub
```

## Quick Start

### Freezing Data Structures

```python
from frozen_cub.frozen import freeze, FrozenDict

# Freeze a nested dictionary
data = {
    "user": "bear",
    "settings": {"theme": "dark", "notifications": True},
    "tags": ["python", "cython"],
}
frozen = freeze(data)

# Now it's hashable - use as dict key or in sets
cache = {frozen: "some_result"}
unique_configs = {frozen}
```

### FrozenDict

```python
from frozen_cub.frozen import FrozenDict

# Create directly from items
fd = FrozenDict([("a", 1), ("b", 2)])

# Or from a dict
fd = FrozenDict({"a": 1, "b": 2})

# Access like a regular dict
print(fd["a"])  # 1
print(fd.get("c", "default"))  # "default"
print(list(fd.keys()))  # ["a", "b"]

# Use as a dict key (it's hashable!)
lookup = {fd: "found it"}
```

### LRU Cache

```python
from frozen_cub.lru_cache import LRUCache

# Create a cache with max 100 items
cache: LRUCache[str, dict] = LRUCache(capacity=100)

# Basic operations
cache["key"] = {"data": "value"}
result = cache.get("key")  # Returns {"data": "value"}
result = cache.get("missing", "default")  # Returns "default"

# Dict-like interface
"key" in cache  # True
del cache["key"]
len(cache)  # 0
```

### CacheKey

```python
from frozen_cub.utils import CacheKey

# Create a hashable key from two values
key = CacheKey(int, 42)

# Use as dict key or in sets
cache = {key: "cached_value"}

# For more than two values, use tuples
key = CacheKey("my_cache", (arg1, arg2, arg3))
```

## Cython API

For maximum performance in other Cython code, you can use the inlined C functions directly:

```cython
from frozen_cub.frozen cimport inline_freeze, FrozenDict

# inline_freeze is inlined at compile time - zero function call overhead
cdef object frozen = inline_freeze(my_dict)
```

## API Reference

### `freeze(obj)`

Recursively converts mutable objects to immutable equivalents:

| Input Type | Output Type  |
| ---------- | ------------ |
| `dict`     | `FrozenDict` |
| `list`     | `tuple`      |
| `set`      | `frozenset`  |


### `FrozenDict`

An immutable, hashable dictionary.

**Methods:**
- `get(key, default=None)` - Get value with optional default
- `keys()` - Return list of keys
- `values()` - Return list of values
- `items()` - Return list of (key, value) tuples
- `__getitem__(key)` - Get value, raises `KeyError` if missing
- `__contains__(key)` - Check if key exists
- `__hash__()` - Returns cached hash value
- `__len__()` - Return number of items

### `LRUCache[K, V]`

A generic LRU cache with configurable capacity.

**Constructor:**
- `LRUCache(capacity=512)` - Create cache with max capacity

**Methods:**
- `get(key, default=None)` - Get value with optional default
- `set(key, value)` - Set value (alias for `__setitem__`)
- `pop(key, default=None)` - Remove and return value
- `clear()` - Remove all items
- `__getitem__(key)` - Get value, raises `KeyError` if missing
- `__setitem__(key, value)` - Set value
- `__delitem__(key)` - Delete key, raises `KeyError` if missing
- `__contains__(key)` - Check if key exists
- `__len__()` - Return number of items

### `CacheKey`

A lightweight, hashable key for caching based on two values.

**Constructor:**
- `CacheKey(value1, value2)` - Create a cache key from two hashable values

**Methods:**
- `__hash__()` - Returns cached hash value
- `__eq__(other)` - Compare equality with another CacheKey