Skip to content

Instantly share code, notes, and snippets.

@hooman
Last active April 30, 2016 01:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hooman/2b74d9756976a43330c1acfcfba699f3 to your computer and use it in GitHub Desktop.
Save hooman/2b74d9756976a43330c1acfcfba699f3 to your computer and use it in GitHub Desktop.
An API for storing arbitrary key/value pairs. Supporting this API enables extensions to add their properties to our type.
//
// KeyValueStore.swift
// FoundationNG
//
// Created by Hooman Mehr on 4/27/16.
// Copyright © 2016 Hooman Mehr. See the MIT license at the bottom.
//
//==============================================================================================
//MARK: Common API for a Key Value Store
//==============================================================================================
/// An API for a value type that can store arbitrary key/value pairs.
///
/// As in any key/value system, the key needs to be `Hashable`.
///
/// A type that supports this API provides means for extensions to add their properties to the instance of a value type.
public protocol KeyValueStore {
/// Adds/updates a (key,value) pair.
mutating func set<K: Hashable,V>(key: K, to value: V)
/// Removes a (key,value) pair; if the key exists.
mutating func unset<K: Hashable>(key: K)
/// Returns the value corresponding to key; if the key exists.
func get<K: Hashable,V>(key: K) -> V?
}
/// An API for an object that can store arbitrary key/value pairs.
///
/// As in any key/value system, the key needs to be `Hashable`.
///
/// A class that supports this API provides means for extensions to add their properties to the instances of this class.
public protocol KeyValueStoreObject: class, KeyValueStore {}
//==============================================================================================
//MARK: A Key Value Store using Dictionary for Storage
//==============================================================================================
/// A protocol to facilitate support of Key Value Store API.
///
/// Any value type that implements this protocol, gets Key Value Store API for free.
public protocol AnyDictionaryStore {
/// Provides storage for heterogenous (key,value) pairs.
var anyDictionaryStore: [AnyKey:Any] {get set}
}
/// A Protocol to Facilitate Support of Key Value Store API.
///
/// Any value type that implements this protocols, gets Key Value Store API for free.
public protocol AnyDictionaryStoreObject: class, AnyDictionaryStore {}
/// A wrapper type that erases the type of any hashable key.
public struct AnyKey: Hashable {
/// Function/arguments selector used as the input parameter of `AnyKey` core function.
private enum Selector {
case key
case hash
case equals(AnyKey)
}
/// The original key behind this `AnyKey`.
public var key: Any { return function(.key) }
/// The hash value for `Hashable` support.
public var hashValue: Int { return function(.hash) as! Int }
/// The core function that captures/encapsulates all data/functionality of this type.
private let function: (Selector)->Any
/// Initializer of `AnyKey`.
public init<T: Hashable>(_ key: T) {
function = { arg in switch arg {
case .key: return key
case .hash: return key.hashValue
case let .equals(other):
guard let otherKey = other.key as? T else { return false }
return key == otherKey
}}
}
}
/// Equality test operator for `Hashable` support of `AnyKey`.
public func ==(lhs: AnyKey, rhs:AnyKey) -> Bool {
return lhs.function(.equals(rhs)) as! Bool
}
//==============================================================================================
//MARK: Implementation of Key Value Store using Heterogenous Dictionary for storage
//==============================================================================================
/// Default Implementation of `KeyValueStore` for any type that has an `anyDictionaryStore`.
public extension KeyValueStore where Self: AnyDictionaryStore {
/// Adds/updates a (key,value) pair.
mutating func set<K: Hashable,V>(key: K, to value: V) { anyDictionaryStore[AnyKey(key)] = value }
/// Removes a (key,value) pair; if the key exists.
mutating func unset<K: Hashable>(key: K) { anyDictionaryStore[AnyKey(key)] = nil }
/// Returns the value corresponding to key; if the key exists.
func get<K: Hashable,V>(key: K) -> V? { return anyDictionaryStore[AnyKey(key)] as? V }
}
/// Default Implementation of `KeyValueStoreObject` for any type that has an `anyDictionaryStore`.
public extension KeyValueStoreObject where Self: AnyDictionaryStoreObject {
/// Adds/updates a (key,value) pair.
func set<K: Hashable,V>(key: K, to value: V) { anyDictionaryStore[AnyKey(key)] = value } //FIXME: Cannot assign through subscript: ‘self’ is immutable
/// Removes a (key,value) pair; if the key exists.
func unset<K: Hashable>(key: K) { anyDictionaryStore[AnyKey(key)] = nil } //FIXME: Cannot assign through subscript: ‘self’ is immutable
/// Returns the value corresponding to key; if the key exists.
func get<K: Hashable,V>(key: K) -> V? { return anyDictionaryStore[AnyKey(key)] as? V }
}
// Copyright (c) 2016 Hooman Mehr (hooman@mac.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment