<commit_before>//
//  ImageCache.swift
//  ImageCache
//
//  Created by <NAME> on 27/06/15.
//  Copyright © 2015 <NAME>. All rights reserved.
//

import DiskCache

/**
Caches images in memory and on disk
*/
public class ImageCache {

    //MARK: Properties

    private let memoryCache = NSCache()
    private let diskCache: DiskCache

    /**
    Images will be cached at this path, e.g. `Library/Caches/com.domain.App.ImageCache`
    */
    public let diskCachePath: String

    //MARK: Initialization

    public init(identifier: String) {
        diskCache = DiskCache(identifier: identifier)
        diskCachePath = diskCache.path

        memoryCache.name = identifier
    }

    public convenience init() {
        self.init(identifier: "ImageCache")
    }

    //MARK: Cache Image

    /**
    Cache image asynchronously
    
    - Parameter image: Image to cache
    - Parameter forKey: Key for image
    - Parameter onDisk: Whether to cache image on disk
    - Parameter completionHandler: Called on main thread after image is cached
    
    - Warning: Doesn't throw when error happens asynchronously. Check `.Success` or `.Failure` in `Result` parameter of `completionHandler` instead.
    */
    public func cacheImage(image: UIImage, forKey key: String, onDisk: Bool, completionHandler: (Result<Void> -> Void)?) throws {
        guard let imageData = UIImagePNGRepresentation(image) else {
            throw ImageCacheError.ImageDataError
        }

        if key.isEmpty {
            throw ImageCacheError.EmptyKey
        }

        memoryCache.setObject(image, forKey: key, cost: imageData.length)

        if onDisk {
            try diskCache.cacheData(imageData, forKey: key, completionHandler: completionHandler)
        } else {
            completionHandler?(.Success())
        }
    }

    //MARK: Retrieve image

    /**
    Retrieve image asynchronously

    - Parameter key: Key for image
    - Parameter completionHandler: Called on main thread with retrieved image or error as parameter
    
    - Note: Retrieves image with scale of device's screen.

    - Warning: Doesn't throw when error happens asynchronously. Check `.Success` or `.Failure` in `Result` parameter of `completionHandler` instead.
    */
    public func retrieveImageForKey(key: String, completionHandler: Result<UIImage> -> Void) throws {
        if key.isEmpty {
            throw ImageCacheError.EmptyKey
        }

        // try to retrieve image from memory cache first
        if let imageData = memoryCache.objectForKey(key) as? NSData, let image = UIImage(data: imageData, scale: UIScreen.mainScreen().scale) {
            completionHandler(.Success(image))
        } else {
            // if image couldn't be retrieved from memory cache, try to retrieve it from disk cache
            let dataCompletionHandler: Result<NSData> -> Void = { result in
                switch result {
                case .Success(let imageData):
                    if let image = UIImage(data: imageData, scale: UIScreen.mainScreen().scale) {
                        completionHandler(.Success(image))
                    } else {
                        completionHandler(.Failure(ImageCacheError.ImageDataError))
                    }

                case .Failure(let error):
                    completionHandler(.Failure(error))
                }
            }

            try diskCache.retrieveDataForKey(key, completionHandler: dataCompletionHandler)
        }
    }

    //MARK: Remove Image

    /**
    Remove all cached images asynchronously

    - Parameter fromDisk: If true, all cached images will not only be removed from the memory cache, but also from the disk cache
    - Parameter completionHandler: Called on main thread after all cached images got removed

    - Note: `Result` parameter of `completionHandler` contains `.Success` or `.Failure`.
    */
    public func removeAllImagesFromDisk(fromDisk: Bool, completionHandler: (Result<Void> -> Void)?) {
        memoryCache.removeAllObjects()

        if fromDisk {
            diskCache.removeAllData(completionHandler: completionHandler)
        } else {
            completionHandler?(.Success())
        }
    }

    /**
    Remove cached image for key asynchronously

    - Parameter key: Key for image
    - Parameter fromDisk: If true, cached image will not only be removed from the memory cache, but also from the disk cache
    - Parameter completionHandler: Called on main thread after cached image got removed

    - Warning: Doesn't throw when error happens asynchronously. Check `.Success` or `.Failure` in `Result` parameter of `completionHandler` instead.
    */
    public func removeImageForKey(key: String, fromDisk: Bool, completionHandler: (Result<Void> -> Void)?) throws {
        if key.isEmpty {
            throw ImageCacheError.EmptyKey
        }

        memoryCache.removeObjectForKey(key)

        if fromDisk {
            try diskCache.removeDataForKey(key, completionHandler: completionHandler)
        } else {
            completionHandler?(.Success())
        }
    }
}
<commit_msg>Add note explaining data format of cached images<commit_after>//
//  ImageCache.swift
//  ImageCache
//
//  Created by <NAME> on 27/06/15.
//  Copyright © 2015 <NAME>. All rights reserved.
//

import DiskCache

/**
Caches images in memory and on disk
*/
public class ImageCache {

    //MARK: Properties

    private let memoryCache = NSCache()
    private let diskCache: DiskCache

    /**
    Images will be cached at this path, e.g. `Library/Caches/com.domain.App.ImageCache`
    */
    public let diskCachePath: String

    //MARK: Initialization

    public init(identifier: String) {
        diskCache = DiskCache(identifier: identifier)
        diskCachePath = diskCache.path

        memoryCache.name = identifier
    }

    public convenience init() {
        self.init(identifier: "ImageCache")
    }

    //MARK: Cache Image

    /**
    Cache image asynchronously
    
    - Parameter image: Image to cache
    - Parameter forKey: Key for image
    - Parameter onDisk: Whether to cache image on disk
    - Parameter completionHandler: Called on main thread after image is cached
    
    - Note: Caches image in it's PNG representation. See [`UIImagePNGRepresentation(_:)`](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIKitFunctionReference/#//apple_ref/c/func/UIImagePNGRepresentation) for more information.
    
    - Warning: Doesn't throw when error happens asynchronously. Check `.Success` or `.Failure` in `Result` parameter of `completionHandler` instead.
    */
    public func cacheImage(image: UIImage, forKey key: String, onDisk: Bool, completionHandler: (Result<Void> -> Void)?) throws {
        guard let imageData = UIImagePNGRepresentation(image) else {
            throw ImageCacheError.ImageDataError
        }

        if key.isEmpty {
            throw ImageCacheError.EmptyKey
        }

        memoryCache.setObject(image, forKey: key, cost: imageData.length)

        if onDisk {
            try diskCache.cacheData(imageData, forKey: key, completionHandler: completionHandler)
        } else {
            completionHandler?(.Success())
        }
    }

    //MARK: Retrieve image

    /**
    Retrieve image asynchronously

    - Parameter key: Key for image
    - Parameter completionHandler: Called on main thread with retrieved image or error as parameter
    
    - Note: Retrieves image with scale of device's screen.

    - Warning: Doesn't throw when error happens asynchronously. Check `.Success` or `.Failure` in `Result` parameter of `completionHandler` instead.
    */
    public func retrieveImageForKey(key: String, completionHandler: Result<UIImage> -> Void) throws {
        if key.isEmpty {
            throw ImageCacheError.EmptyKey
        }

        // try to retrieve image from memory cache first
        if let imageData = memoryCache.objectForKey(key) as? NSData, let image = UIImage(data: imageData, scale: UIScreen.mainScreen().scale) {
            completionHandler(.Success(image))
        } else {
            // if image couldn't be retrieved from memory cache, try to retrieve it from disk cache
            let dataCompletionHandler: Result<NSData> -> Void = { result in
                switch result {
                case .Success(let imageData):
                    if let image = UIImage(data: imageData, scale: UIScreen.mainScreen().scale) {
                        completionHandler(.Success(image))
                    } else {
                        completionHandler(.Failure(ImageCacheError.ImageDataError))
                    }

                case .Failure(let error):
                    completionHandler(.Failure(error))
                }
            }

            try diskCache.retrieveDataForKey(key, completionHandler: dataCompletionHandler)
        }
    }

    //MARK: Remove Image

    /**
    Remove all cached images asynchronously

    - Parameter fromDisk: If true, all cached images will not only be removed from the memory cache, but also from the disk cache
    - Parameter completionHandler: Called on main thread after all cached images got removed

    - Note: `Result` parameter of `completionHandler` contains `.Success` or `.Failure`.
    */
    public func removeAllImagesFromDisk(fromDisk: Bool, completionHandler: (Result<Void> -> Void)?) {
        memoryCache.removeAllObjects()

        if fromDisk {
            diskCache.removeAllData(completionHandler: completionHandler)
        } else {
            completionHandler?(.Success())
        }
    }

    /**
    Remove cached image for key asynchronously

    - Parameter key: Key for image
    - Parameter fromDisk: If true, cached image will not only be removed from the memory cache, but also from the disk cache
    - Parameter completionHandler: Called on main thread after cached image got removed

    - Warning: Doesn't throw when error happens asynchronously. Check `.Success` or `.Failure` in `Result` parameter of `completionHandler` instead.
    */
    public func removeImageForKey(key: String, fromDisk: Bool, completionHandler: (Result<Void> -> Void)?) throws {
        if key.isEmpty {
            throw ImageCacheError.EmptyKey
        }

        memoryCache.removeObjectForKey(key)

        if fromDisk {
            try diskCache.removeDataForKey(key, completionHandler: completionHandler)
        } else {
            completionHandler?(.Success())
        }
    }
}

{'fraction_non_alphanumeric': 0.0837396042443361, 'fraction_numerical': 0.001911863110601281, 'mean_word_length': 2.4290396591281547, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 27, 'https://': 1, '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': '922276', 'n_tokens_mistral': 2755, 'n_tokens_neox': 2575, 'n_words': 883}