123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187 |
- //
- // 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)
-
- fileprivate 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 {
- #if swift(>=4.2)
- func hash(into hasher: inout Hasher) {
- hasher.combine(rawValue)
- }
- #else
- var hashValue: Int {
- return rawValue.hashValue
- }
- #endif
- }
- func ==(lhs: BagKey, rhs: BagKey) -> Bool {
- return lhs.rawValue == rhs.rawValue
- }
|