You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
|
|
// // Bag.swift // Platform // // Created by Krunoslav Zaher on 2/28/15. // Copyright © 2015 Krunoslav Zaher. All rights reserved. //
import Swift
let arrayDictionaryMaxSize = 30
struct BagKey { /**
Unique identifier for object added to `Bag`. It's underlying type is UInt64. If we assume there in an idealized CPU that works at 4GHz, it would take ~150 years of continuous running time for it to overflow. */ fileprivate let rawValue: UInt64 }
/**
Data structure that represents a bag of elements typed `T`.
Single element can be stored multiple times.
Time and space complexity of insertion and deletion is O(n).
It is suitable for storing small number of elements. */ struct Bag<T> : CustomDebugStringConvertible { /// Type of identifier for inserted elements. typealias KeyType = BagKey typealias Entry = (key: BagKey, value: T) private var _nextKey: BagKey = BagKey(rawValue: 0)
// data
// first fill inline variables var _key0: BagKey? var _value0: T?
// then fill "array dictionary" var _pairs = ContiguousArray<Entry>()
// last is sparse dictionary var _dictionary: [BagKey: T]?
var _onlyFastPath = true
/// Creates new empty `Bag`. init() { } /**
Inserts `value` into bag. - parameter element: Element to insert. - returns: Key that can be used to remove element from bag. */ mutating func insert(_ element: T) -> BagKey { let key = _nextKey
_nextKey = BagKey(rawValue: _nextKey.rawValue &+ 1)
if _key0 == nil { _key0 = key _value0 = element return key }
_onlyFastPath = false
if _dictionary != nil { _dictionary![key] = element return key }
if _pairs.count < arrayDictionaryMaxSize { _pairs.append((key: key, value: element)) return key } _dictionary = [key: element] return key } /// - returns: Number of elements in bag. var count: Int { let dictionaryCount: Int = _dictionary?.count ?? 0 return (_value0 != nil ? 1 : 0) + _pairs.count + dictionaryCount } /// Removes all elements from bag and clears capacity. mutating func removeAll() { _key0 = nil _value0 = nil
_pairs.removeAll(keepingCapacity: false) _dictionary?.removeAll(keepingCapacity: false) } /**
Removes element with a specific `key` from bag. - parameter key: Key that identifies element to remove from bag. - returns: Element that bag contained, or nil in case element was already removed. */ mutating func removeKey(_ key: BagKey) -> T? { if _key0 == key { _key0 = nil let value = _value0! _value0 = nil return value }
if let existingObject = _dictionary?.removeValue(forKey: key) { return existingObject }
for i in 0 ..< _pairs.count where _pairs[i].key == key { let value = _pairs[i].value _pairs.remove(at: i) return value }
return nil } }
extension Bag { /// A textual representation of `self`, suitable for debugging. var debugDescription : String { return "\(self.count) elements in Bag" } }
extension Bag { /// Enumerates elements inside the bag. /// /// - parameter action: Enumeration closure. func forEach(_ action: (T) -> Void) { if _onlyFastPath { if let value0 = _value0 { action(value0) } return }
let value0 = _value0 let dictionary = _dictionary
if let value0 = value0 { action(value0) }
for i in 0 ..< _pairs.count { action(_pairs[i].value) }
if dictionary?.count ?? 0 > 0 { for element in dictionary!.values { action(element) } } } }
extension BagKey: Hashable { func hash(into hasher: inout Hasher) { hasher.combine(rawValue) } }
func ==(lhs: BagKey, rhs: BagKey) -> Bool { return lhs.rawValue == rhs.rawValue }
|