<commit_before>//
//  Bag.swift
//  ReactiveCocoa
//
//  Created by <NAME> on 2014-07-10.
//  Copyright (c) 2014 GitHub. All rights reserved.
//

/// A uniquely identifying token for removing a value that was inserted into a
/// Bag.
internal final class RemovalToken {
	private var identifier: UInt?

	private init(identifier: UInt) {
		self.identifier = identifier
	}
}

/// An unordered, non-unique collection of values of type `Element`.
/// This is a class to improve memory pressure.
/// Atomicity can be ensured by using `Atomic<Bag>`.
internal class Bag<Element> {
	private var elements: [BagElement<Element>] = []
	private var currentIdentifier: UInt = 0

	init() { }

	/// Inserts the given value in the collection, and returns a token that can
	/// later be passed to removeValueForToken().
	func insert(value: Element) -> RemovalToken {
		let nextIdentifier = currentIdentifier &+ 1
		if nextIdentifier == 0 {
			reindex()
		}

		let token = RemovalToken(identifier: currentIdentifier)
		let element = BagElement(value: value, identifier: currentIdentifier, token: token)

		elements.append(element)
		currentIdentifier++

		return token
	}

	/// Removes a value, given the token returned from insert().
	///
	/// If the value has already been removed, nothing happens.
	func removeValueForToken(token: RemovalToken) {
		if let identifier = token.identifier {
			// Removal is more likely for recent objects than old ones.
			for i in (0..<elements.endIndex).reverse() {
				if elements[i].identifier == identifier {
					elements.removeAtIndex(i)
					token.identifier = nil
					break
				}
			}
		}
	}

	/// In the event of an identifier overflow (highly, highly unlikely), this
	/// will reset all current identifiers to reclaim a contiguous set of
	/// available identifiers for the future.
	private func reindex() {
		for i in 0..<elements.endIndex {
			currentIdentifier = UInt(i)

			elements[i].identifier = currentIdentifier
			elements[i].token.identifier = currentIdentifier
		}
	}
}

extension Bag: SequenceType {
	func generate() -> AnyGenerator<Element> {
		var index = 0
		let elements = self.elements
		let count = elements.count

		return anyGenerator {
			if index < count {
				return elements[index++].value
			} else {
				return nil
			}
		}
	}
}

extension Bag: CollectionType {
	typealias Index = Array<Element>.Index

	var startIndex: Index {
		return 0
	}
	
	var endIndex: Index {
		return elements.count
	}

	subscript(index: Index) -> Element {
		return elements[index].value
	}
}

private struct BagElement<Value> {
	let value: Value
	var identifier: UInt
	let token: RemovalToken
}<commit_msg>Revert "Bag.generate: copying elements to make generator thread-safe"<commit_after>//
//  Bag.swift
//  ReactiveCocoa
//
//  Created by <NAME> on 2014-07-10.
//  Copyright (c) 2014 GitHub. All rights reserved.
//

/// A uniquely identifying token for removing a value that was inserted into a
/// Bag.
internal final class RemovalToken {
	private var identifier: UInt?

	private init(identifier: UInt) {
		self.identifier = identifier
	}
}

/// An unordered, non-unique collection of values of type `Element`.
/// This is a class to improve memory pressure.
/// Atomicity can be ensured by using `Atomic<Bag>`.
internal class Bag<Element> {
	private var elements: [BagElement<Element>] = []
	private var currentIdentifier: UInt = 0

	init() { }

	/// Inserts the given value in the collection, and returns a token that can
	/// later be passed to removeValueForToken().
	func insert(value: Element) -> RemovalToken {
		let nextIdentifier = currentIdentifier &+ 1
		if nextIdentifier == 0 {
			reindex()
		}

		let token = RemovalToken(identifier: currentIdentifier)
		let element = BagElement(value: value, identifier: currentIdentifier, token: token)

		elements.append(element)
		currentIdentifier++

		return token
	}

	/// Removes a value, given the token returned from insert().
	///
	/// If the value has already been removed, nothing happens.
	func removeValueForToken(token: RemovalToken) {
		if let identifier = token.identifier {
			// Removal is more likely for recent objects than old ones.
			for i in (0..<elements.endIndex).reverse() {
				if elements[i].identifier == identifier {
					elements.removeAtIndex(i)
					token.identifier = nil
					break
				}
			}
		}
	}

	/// In the event of an identifier overflow (highly, highly unlikely), this
	/// will reset all current identifiers to reclaim a contiguous set of
	/// available identifiers for the future.
	private func reindex() {
		for i in 0..<elements.endIndex {
			currentIdentifier = UInt(i)

			elements[i].identifier = currentIdentifier
			elements[i].token.identifier = currentIdentifier
		}
	}
}

extension Bag: SequenceType {
	func generate() -> AnyGenerator<Element> {
		var index = 0
		let count = elements.count

		return anyGenerator {
			if index < count {
				return self.elements[index++].value
			} else {
				return nil
			}
		}
	}
}

extension Bag: CollectionType {
	typealias Index = Array<Element>.Index

	var startIndex: Index {
		return 0
	}
	
	var endIndex: Index {
		return elements.count
	}

	subscript(index: Index) -> Element {
		return elements[index].value
	}
}

private struct BagElement<Value> {
	let value: Value
	var identifier: UInt
	let token: RemovalToken
}
{'fraction_non_alphanumeric': 0.10298000754432289, 'fraction_numerical': 0.007167106752168993, 'mean_word_length': 3.3396072013093288, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6247915', 'n_tokens_mistral': 1731, 'n_tokens_neox': 1515, 'n_words': 542}