Maps & Sets Examples
Real-world examples of working with Maps and Sets in Pura.
Cache Management
LRU Cache with Map
typescript
import { produceFast } from '@sylphx/pura'
interface CacheEntry<T> {
value: T
timestamp: number
hits: number
}
class LRUCache<K, V> {
private cache: Map<K, CacheEntry<V>>
private maxSize: number
constructor(maxSize = 100) {
this.cache = new Map()
this.maxSize = maxSize
}
get(key: K): V | undefined {
const entry = this.cache.get(key)
if (!entry) return undefined
// Update hits and timestamp immutably
this.cache = produceFast(this.cache, $ => {
$.set(key, {
...entry,
hits: entry.hits + 1,
timestamp: Date.now()
})
})
return entry.value
}
set(key: K, value: V): void {
this.cache = produceFast(this.cache, $ => {
$.set(key, {
value,
timestamp: Date.now(),
hits: 0
})
// Evict oldest if over capacity
if (this.cache.size > this.maxSize) {
const oldest = Array.from(this.cache.entries())
.sort((a, b) => a[1].timestamp - b[1].timestamp)[0]
if (oldest) {
$.delete(oldest[0])
}
}
})
}
}Simple Cache
typescript
import { produceFast } from '@sylphx/pura'
interface Cache {
data: Map<string, any>
timestamps: Map<string, number>
ttl: number
}
const cache: Cache = {
data: new Map(),
timestamps: new Map(),
ttl: 60000 // 1 minute
}
// Set cache entry
function setCacheEntry(cache: Cache, key: string, value: any): Cache {
return produceFast(cache, $ => {
$.set(['data'], produceFast(cache.data, d => d.set(key, value)))
$.set(['timestamps'], produceFast(cache.timestamps, t => t.set(key, Date.now())))
})
}
// Get cache entry (with expiration)
function getCacheEntry(cache: Cache, key: string): any | undefined {
const timestamp = cache.timestamps.get(key)
if (!timestamp) return undefined
const age = Date.now() - timestamp
if (age > cache.ttl) {
// Expired - remove
return undefined
}
return cache.data.get(key)
}
// Cleanup expired
function cleanupCache(cache: Cache): Cache {
const now = Date.now()
const expired: string[] = []
for (const [key, timestamp] of cache.timestamps) {
if (now - timestamp > cache.ttl) {
expired.push(key)
}
}
if (expired.length === 0) return cache
return produceFast(cache, $ => {
$.set(['data'], produceFast(cache.data, d => {
for (const key of expired) d.delete(key)
}))
$.set(['timestamps'], produceFast(cache.timestamps, t => {
for (const key of expired) t.delete(key)
}))
})
}User Permissions
Permission Set
typescript
import { produceFast } from '@sylphx/pura'
type Permission = 'read' | 'write' | 'delete' | 'admin'
interface User {
id: number
name: string
permissions: Set<Permission>
}
const user: User = {
id: 1,
name: 'Alice',
permissions: new Set(['read', 'write'])
}
// Grant permission
function grantPermission(user: User, permission: Permission): User {
return produceFast(user, $ => {
$.set(['permissions'], produceFast(user.permissions, p => {
p.add(permission)
}))
})
}
// Revoke permission
function revokePermission(user: User, permission: Permission): User {
return produceFast(user, $ => {
$.set(['permissions'], produceFast(user.permissions, p => {
p.delete(permission)
}))
})
}
// Check permission
function hasPermission(user: User, permission: Permission): boolean {
return user.permissions.has(permission)
}Role-Based Access Control
typescript
import { produceFast } from '@sylphx/pura'
interface RBAC {
roles: Map<string, Set<Permission>>
userRoles: Map<number, Set<string>>
}
const rbac: RBAC = {
roles: new Map([
['viewer', new Set(['read'])],
['editor', new Set(['read', 'write'])],
['admin', new Set(['read', 'write', 'delete', 'admin'])]
]),
userRoles: new Map([
[1, new Set(['viewer'])],
[2, new Set(['editor'])]
])
}
// Assign role to user
function assignRole(rbac: RBAC, userId: number, role: string): RBAC {
return produceFast(rbac, $ => {
const userRoles = rbac.userRoles.get(userId) || new Set()
$.set(['userRoles'], produceFast(rbac.userRoles, m => {
m.set(userId, produceFast(userRoles, s => s.add(role)))
}))
})
}
// Get user permissions (aggregated from roles)
function getUserPermissions(rbac: RBAC, userId: number): Set<Permission> {
const userRoles = rbac.userRoles.get(userId)
if (!userRoles) return new Set()
const permissions = new Set<Permission>()
for (const role of userRoles) {
const rolePerms = rbac.roles.get(role)
if (rolePerms) {
for (const perm of rolePerms) {
permissions.add(perm)
}
}
}
return permissions
}Tag Management
Document Tags
typescript
import { produceFast } from '@sylphx/pura'
interface Document {
id: string
title: string
content: string
tags: Set<string>
}
const doc: Document = {
id: '1',
title: 'Getting Started',
content: '...',
tags: new Set(['tutorial', 'beginner'])
}
// Add tag
function addTag(doc: Document, tag: string): Document {
return produceFast(doc, $ => {
$.set(['tags'], produceFast(doc.tags, s => s.add(tag)))
})
}
// Remove tag
function removeTag(doc: Document, tag: string): Document {
return produceFast(doc, $ => {
$.set(['tags'], produceFast(doc.tags, s => s.delete(tag)))
})
}
// Replace all tags
function setTags(doc: Document, tags: string[]): Document {
return produceFast(doc, $ => {
$.set(['tags'], new Set(tags))
})
}Tag Indexing
typescript
import { produceFast } from '@sylphx/pura'
interface TagIndex {
tagToDocIds: Map<string, Set<string>>
docIdToTags: Map<string, Set<string>>
}
const index: TagIndex = {
tagToDocIds: new Map(),
docIdToTags: new Map()
}
// Add document tags to index
function indexDocument(index: TagIndex, docId: string, tags: Set<string>): TagIndex {
return produceFast(index, $ => {
// Add to docIdToTags
$.set(['docIdToTags'], produceFast(index.docIdToTags, m => {
m.set(docId, tags)
}))
// Add to tagToDocIds
$.set(['tagToDocIds'], produceFast(index.tagToDocIds, m => {
for (const tag of tags) {
const docIds = m.get(tag) || new Set()
m.set(tag, produceFast(docIds, s => s.add(docId)))
}
}))
})
}
// Find documents by tag
function findByTag(index: TagIndex, tag: string): Set<string> {
return index.tagToDocIds.get(tag) || new Set()
}Session Management
Active Sessions
typescript
import { produceFast } from '@sylphx/pura'
interface Session {
id: string
userId: number
createdAt: number
lastActive: number
}
interface SessionStore {
sessions: Map<string, Session>
userSessions: Map<number, Set<string>>
}
const store: SessionStore = {
sessions: new Map(),
userSessions: new Map()
}
// Create session
function createSession(store: SessionStore, userId: number): SessionStore {
const sessionId = crypto.randomUUID()
const session: Session = {
id: sessionId,
userId,
createdAt: Date.now(),
lastActive: Date.now()
}
return produceFast(store, $ => {
// Add session
$.set(['sessions'], produceFast(store.sessions, m => {
m.set(sessionId, session)
}))
// Add to user sessions
const userSessions = store.userSessions.get(userId) || new Set()
$.set(['userSessions'], produceFast(store.userSessions, m => {
m.set(userId, produceFast(userSessions, s => s.add(sessionId)))
}))
})
}
// Update session activity
function updateSessionActivity(store: SessionStore, sessionId: string): SessionStore {
const session = store.sessions.get(sessionId)
if (!session) return store
return produceFast(store, $ => {
$.set(['sessions'], produceFast(store.sessions, m => {
m.set(sessionId, { ...session, lastActive: Date.now() })
}))
})
}
// Delete session
function deleteSession(store: SessionStore, sessionId: string): SessionStore {
const session = store.sessions.get(sessionId)
if (!session) return store
return produceFast(store, $ => {
// Remove session
$.set(['sessions'], produceFast(store.sessions, m => {
m.delete(sessionId)
}))
// Remove from user sessions
const userSessions = store.userSessions.get(session.userId)
if (userSessions) {
$.set(['userSessions'], produceFast(store.userSessions, m => {
m.set(session.userId, produceFast(userSessions, s => s.delete(sessionId)))
}))
}
})
}Graph Data
Simple Graph
typescript
import { produceFast } from '@sylphx/pura'
interface Graph {
nodes: Set<string>
edges: Map<string, Set<string>>
}
const graph: Graph = {
nodes: new Set(['A', 'B', 'C']),
edges: new Map([
['A', new Set(['B', 'C'])],
['B', new Set(['C'])]
])
}
// Add node
function addNode(graph: Graph, node: string): Graph {
return produceFast(graph, $ => {
$.set(['nodes'], produceFast(graph.nodes, s => s.add(node)))
})
}
// Add edge
function addEdge(graph: Graph, from: string, to: string): Graph {
return produceFast(graph, $ => {
// Ensure nodes exist
$.set(['nodes'], produceFast(graph.nodes, s => {
s.add(from)
s.add(to)
}))
// Add edge
const neighbors = graph.edges.get(from) || new Set()
$.set(['edges'], produceFast(graph.edges, m => {
m.set(from, produceFast(neighbors, s => s.add(to)))
}))
})
}
// Get neighbors
function getNeighbors(graph: Graph, node: string): Set<string> {
return graph.edges.get(node) || new Set()
}Event Tracking
Event Listeners
typescript
import { produceFast } from '@sylphx/pura'
type EventHandler = (data: any) => void
interface EventEmitter {
listeners: Map<string, Set<EventHandler>>
}
const emitter: EventEmitter = {
listeners: new Map()
}
// Add listener
function addEventListener(
emitter: EventEmitter,
event: string,
handler: EventHandler
): EventEmitter {
return produceFast(emitter, $ => {
const handlers = emitter.listeners.get(event) || new Set()
$.set(['listeners'], produceFast(emitter.listeners, m => {
m.set(event, produceFast(handlers, s => s.add(handler)))
}))
})
}
// Remove listener
function removeEventListener(
emitter: EventEmitter,
event: string,
handler: EventHandler
): EventEmitter {
const handlers = emitter.listeners.get(event)
if (!handlers) return emitter
return produceFast(emitter, $ => {
$.set(['listeners'], produceFast(emitter.listeners, m => {
m.set(event, produceFast(handlers, s => s.delete(handler)))
}))
})
}
// Emit event (read-only - no produceFast needed)
function emit(emitter: EventEmitter, event: string, data: any): void {
const handlers = emitter.listeners.get(event)
if (handlers) {
for (const handler of handlers) {
handler(data)
}
}
}Performance Note
For Maps and Sets larger than 512 entries, Pura uses HAMT (Hash Array Mapped Trie) for:
- O(log₃₂ n) operations (≈ constant time for practical sizes)
- Structural sharing (99% memory savings for single updates)
- 12-105× faster than Immer
See Understanding Adaptive Strategy for details.
Next Steps
- Array Examples - Working with arrays
- Object Examples - Nested objects
- Real-World Examples - Redux, React, Zustand