<commit_before>//
//  RealmResultsCache.swift
//  redbooth-ios-sdk
//
//  Created by <NAME> on 4/8/15.
//  Copyright © 2015 Redbooth Inc.
//

import Foundation
import RealmSwift

enum RealmCacheUpdateType: String {
    case Move
    case Update
    case Insert
}

protocol RealmResultsCacheDelegate: class {
    func didInsertSection<T: Object>(section: Section<T>, index: Int)
    func didDeleteSection<T: Object>(section: Section<T>, index: Int)
    func didInsert<T: Object>(object: T, indexPath: NSIndexPath)
    func didUpdate<T: Object>(object: T, oldIndexPath: NSIndexPath, newIndexPath: NSIndexPath, changeType: RealmResultsChangeType)
    func didDelete<T: Object>(object: T, indexPath: NSIndexPath)
}

/**
The Cache is responsible to store a copy of the current objects used by the RRC obtained by the original request.
It has an Array of sections where the objects are stored, always filtered and sorted by the request.

The array of sections is constructed depending on the SectionKeyPath given in the RRC creation.

When interacting with the cache is important to do it always in this order:
Taking into account that a MOVE is not an update but a pair of delete/insert operations.

- Deletions
- Insertions
- Updates (Only for objects that won't change position)

:important: always call the three methods, the operations are commited at the end
so calling only `delete` will change the cache but not call the delegate.
*/
class RealmResultsCache<T: Object> {
    var request: RealmRequest<T>
    var sectionKeyPath: String? = ""
    var sections: [Section<T>] = []
    let defaultKeyPathValue = "default"
    weak var delegate: RealmResultsCacheDelegate?
    
    var temporalDeletions: [T] = []
    var temporalDeletionsIndexPath: [T: NSIndexPath] = [:]
    
    
    //MARK: Initializer
    init(request: RealmRequest<T>, sectionKeyPath: String?) {
        self.request = request
        self.sectionKeyPath = sectionKeyPath
    }
    

    //MARK: Population
    func populateSections(objects: [T]) {
        for object in objects {
            let section = getOrCreateSection(object)
            section.insertSorted(object)
        }
    }
    
    func reset(objects: [T]) {
        sections.removeAll()
        populateSections(objects)
    }
    
    //MARK: Actions
    
    func insert(objects: [T]) {
        let mirrorsArray = sortedMirrors(objects)
        for object in mirrorsArray {
            let section = getOrCreateSection(object) //Calls the delegate when there is an insertion
            let rowIndex = section.insertSorted(object)
            guard let sectionIndex = indexForSection(section) else { continue }
            let indexPath = NSIndexPath(forRow: rowIndex, inSection: sectionIndex)
            
            // If the object was not deleted previously, it is just an INSERT.
            if !temporalDeletions.contains(object) {
                delegate?.didInsert(object, indexPath: indexPath)
                continue
            }
            
            // If the object was already deleted, then is a MOVE, and the insert/deleted
            // should be wrapped in only one operation to the delegate
            guard let oldIndexPath = temporalDeletionsIndexPath[object] else { continue }
            delegate?.didUpdate(object, oldIndexPath: oldIndexPath, newIndexPath: indexPath, changeType: RealmResultsChangeType.Move)
            guard let index = temporalDeletions.indexOf(object) else { continue }
            temporalDeletions.removeAtIndex(index)
            temporalDeletionsIndexPath.removeValueForKey(object)
        }
        
        // The remaining objects, not MOVED or INSERTED, are DELETES, and must be deleted at the end
        for object in temporalDeletions {
            guard let oldIndexPath = temporalDeletionsIndexPath[object] else { continue }
            delegate?.didDelete(object, indexPath: oldIndexPath)
        }
        temporalDeletions.removeAll()
        temporalDeletionsIndexPath.removeAll()
    }
    
    func delete(objects: [T]) {
        var outdated: [T] = []
        for object in objects {
            guard let section = sectionForOutdateObject(object) else { continue }
            let index = section.indexForOutdatedObject(object)
            guard index != -1,
                let object = section.objects.objectAtIndex(index) as? T else { continue }
            outdated.append(object)
        }
        
        let mirrorsArray = sortedMirrors(outdated).reverse() as [T]
        
        for object in mirrorsArray {
            guard let section = sectionForOutdateObject(object),
                let sectionIndex = indexForSection(section) else { continue }
            let index = section.deleteOutdatedObject(object)
            let indexPath = NSIndexPath(forRow: index, inSection: sectionIndex)
            
            temporalDeletions.append(object)
            temporalDeletionsIndexPath[object] = indexPath
            
            if section.objects.count == 0 {
                sections.removeAtIndex(indexPath.section)
                delegate?.didDeleteSection(section, index: indexPath.section)
            }
        }
    }
    
    
    func update(objects: [T]) {
        for object in objects {
            guard let oldSection = sectionForOutdateObject(object),<commit_msg>Defending against section.deleteOutdatedObject returning a -1<commit_after>//
//  RealmResultsCache.swift
//  redbooth-ios-sdk
//
//  Created by <NAME> on 4/8/15.
//  Copyright © 2015 Redbooth Inc.
//

import Foundation
import RealmSwift

enum RealmCacheUpdateType: String {
    case Move
    case Update
    case Insert
}

protocol RealmResultsCacheDelegate: class {
    func didInsertSection<T: Object>(section: Section<T>, index: Int)
    func didDeleteSection<T: Object>(section: Section<T>, index: Int)
    func didInsert<T: Object>(object: T, indexPath: NSIndexPath)
    func didUpdate<T: Object>(object: T, oldIndexPath: NSIndexPath, newIndexPath: NSIndexPath, changeType: RealmResultsChangeType)
    func didDelete<T: Object>(object: T, indexPath: NSIndexPath)
}

/**
The Cache is responsible to store a copy of the current objects used by the RRC obtained by the original request.
It has an Array of sections where the objects are stored, always filtered and sorted by the request.

The array of sections is constructed depending on the SectionKeyPath given in the RRC creation.

When interacting with the cache is important to do it always in this order:
Taking into account that a MOVE is not an update but a pair of delete/insert operations.

- Deletions
- Insertions
- Updates (Only for objects that won't change position)

:important: always call the three methods, the operations are commited at the end
so calling only `delete` will change the cache but not call the delegate.
*/
class RealmResultsCache<T: Object> {
    var request: RealmRequest<T>
    var sectionKeyPath: String? = ""
    var sections: [Section<T>] = []
    let defaultKeyPathValue = "default"
    weak var delegate: RealmResultsCacheDelegate?
    
    var temporalDeletions: [T] = []
    var temporalDeletionsIndexPath: [T: NSIndexPath] = [:]
    
    
    //MARK: Initializer
    init(request: RealmRequest<T>, sectionKeyPath: String?) {
        self.request = request
        self.sectionKeyPath = sectionKeyPath
    }
    

    //MARK: Population
    func populateSections(objects: [T]) {
        for object in objects {
            let section = getOrCreateSection(object)
            section.insertSorted(object)
        }
    }
    
    func reset(objects: [T]) {
        sections.removeAll()
        populateSections(objects)
    }
    
    //MARK: Actions
    
    func insert(objects: [T]) {
        let mirrorsArray = sortedMirrors(objects)
        for object in mirrorsArray {
            let section = getOrCreateSection(object) //Calls the delegate when there is an insertion
            let rowIndex = section.insertSorted(object)
            guard let sectionIndex = indexForSection(section) else { continue }
            let indexPath = NSIndexPath(forRow: rowIndex, inSection: sectionIndex)
            
            // If the object was not deleted previously, it is just an INSERT.
            if !temporalDeletions.contains(object) {
                delegate?.didInsert(object, indexPath: indexPath)
                continue
            }
            
            // If the object was already deleted, then is a MOVE, and the insert/deleted
            // should be wrapped in only one operation to the delegate
            guard let oldIndexPath = temporalDeletionsIndexPath[object] else { continue }
            delegate?.didUpdate(object, oldIndexPath: oldIndexPath, newIndexPath: indexPath, changeType: RealmResultsChangeType.Move)
            guard let index = temporalDeletions.indexOf(object) else { continue }
            temporalDeletions.removeAtIndex(index)
            temporalDeletionsIndexPath.removeValueForKey(object)
        }
        
        // The remaining objects, not MOVED or INSERTED, are DELETES, and must be deleted at the end
        for object in temporalDeletions {
            guard let oldIndexPath = temporalDeletionsIndexPath[object] else { continue }
            delegate?.didDelete(object, indexPath: oldIndexPath)
        }
        temporalDeletions.removeAll()
        temporalDeletionsIndexPath.removeAll()
    }
    
    func delete(objects: [T]) {
        var outdated: [T] = []
        for object in objects {
            guard let section = sectionForOutdateObject(object) else { continue }
            let index = section.indexForOutdatedObject(object)
            guard index != -1,
                let object = section.objects.objectAtIndex(index) as? T else { continue }
            outdated.append(object)
        }
        
        let mirrorsArray = sortedMirrors(outdated).reverse() as [T]
        
        for object in mirrorsArray {
            guard let section = sectionForOutdateObject(object),
                let sectionIndex = indexForSection(section) else { continue }
            let index = section.deleteOutdatedObject(object)
            guard index != -1 else { continue }
            let indexPath = NSIndexPath(forRow: index, inSection: sectionIndex)
            
            temporalDeletions.append(object)
            temporalDeletionsIndexPath[object] = indexPath
            
            if section.objects.count == 0 {
                sections.removeAtIndex(indexPath.section)
                delegate?.didDeleteSection(section, index: indexPath.section)
            }
        }
    }
    
    
    func update(objects: [T]) {
        for object in objects {
            guard let oldSection = sectionForOutdateObject(object),
{'fraction_non_alphanumeric': 0.07588202352062721, 'fraction_numerical': 0.002053388090349076, 'mean_word_length': 2.537471112578409, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 27, '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': '2860593', 'n_tokens_mistral': 2842, 'n_tokens_neox': 2767, 'n_words': 901}