Skip to content

Instantly share code, notes, and snippets.

@BenziAhamed
Created May 17, 2017 13:27
Show Gist options
  • Save BenziAhamed/6b3e03c2462bf6b82f34174c4fac179d to your computer and use it in GitHub Desktop.
Save BenziAhamed/6b3e03c2462bf6b82f34174c4fac179d to your computer and use it in GitHub Desktop.
In-process, single thread safe memcache in Swift
import Foundation
public struct Memcache {
enum Expiration {
case never
case at(Double)
var expired: Bool {
switch self {
case .never: return false
case .at(let ttl): return Date.timeIntervalSinceReferenceDate > ttl
}
}
}
struct Entry {
let item: Any
let expiry: Expiration
var expired: Bool { return expiry.expired }
}
typealias Cache = [String: Entry]
var namespaceCache = [String: Cache]()
var cache = Cache()
public mutating func put(key: String, value: Any, namespace: String? = nil, ttl: Double = -1) {
// key - the cache entry key
// value - the item to be cached
// namespace - optional namespace associated with the key
// ttl - duration in seconds for entry to be valid, -1 means cache will never expire
let entry = Entry(
item: value,
expiry: ttl < 0 ? .never : .at(Date.timeIntervalSinceReferenceDate + ttl)
)
if let ns = namespace {
if namespaceCache[ns] == nil {
namespaceCache[ns] = [:]
}
namespaceCache[ns]![key] = entry
}
else {
cache[key] = entry
}
}
public func get(key: String, namespace: String? = nil) -> Any? {
guard let entry = getEntry(key, namespace), !entry.expired else { return nil }
return entry.item
}
private func getEntry(_ key: String, _ namespace: String?) -> Entry? {
if let ns = namespace {
return namespaceCache[ns]?[key]
}
return cache[key]
}
mutating public func clear(namespace: String? = nil) {
// if invoked with a namespace
// we will clear out all caches entries associated
// with that namespace
// else we clear out everything
if let ns = namespace {
namespaceCache[ns] = nil
}
else {
cache.removeAll()
namespaceCache.removeAll()
}
}
}
@BenziAhamed
Copy link
Author

BenziAhamed commented May 17, 2017

var mc = Memcache()

mc.put(key: "name", value: "john", ttl: 1) // will be available for 1 second
mc.get(key: "name") // john

mc.put(key: "name", value: "john", ttl: 0) // will never be available
mc.get(key: "name") // nil

mc.put(key: "name", value: "john") // will always be available
mc.get(key: "name") // john

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment