//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#if DEPLOYMENT_RUNTIME_SWIFT
    
#if os(OSX) || os(iOS)
import Darwin
#elseif os(Linux)
import Glibc
#endif
    
import CoreFoundation
    
internal func __NSDataInvokeDeallocatorUnmap(_ mem: UnsafeMutableRawPointer, _ length: Int) {
    munmap(mem, length)
}
    
internal func __NSDataInvokeDeallocatorFree(_ mem: UnsafeMutableRawPointer, _ length: Int) {
    free(mem)
}
    
#else
    
@_exported import Foundation // Clang module
import _SwiftFoundationOverlayShims
import _SwiftCoreFoundationOverlayShims
    
@_silgen_name("__NSDataWriteToURL")
internal func __NSDataWriteToURL(_ data: NSData, _ url: NSURL, _ options: UInt, _ error: NSErrorPointer) -> Bool
    
#endif

public final class _DataStorage {
    public enum Backing {
        // A mirror of the Objective-C implementation that is suitable to inline in Swift
        case swift
        
        // these two storage points for immutable and mutable data are reserved for references that are returned by "known"
        // cases from Foundation in which implement the backing of struct Data, these have signed up for the concept that
        // the backing bytes/mutableBytes pointer does not change per call (unless mutated) as well as the length is ok
        // to be cached, this means that as long as the backing reference is retained no further objc_msgSends need to be
        // dynamically dispatched out to the reference.
        case immutable(NSData) // This will most often (perhaps always) be NSConcreteData
        case mutable(NSMutableData) // This will often (perhaps always) be NSConcreteMutableData
        
        // These are reserved for foreign sources where neither Swift nor Foundation are fully certain whom they belong
        // to from an object inheritance standpoint, this means that all bets are off and the values of bytes, mutableBytes,
        // and length cannot be cached. This also means that all methods are expected to dynamically dispatch out to the
        // backing reference.
        case customReference(NSData) // tracks data references that are only known to be immutable
        case customMutableReference(NSMutableData) // tracks data references that are known to be mutable
    }
    
    public static let maxSize = Int.max >> 1
    public static let vmOpsThreshold = NSPageSize() * 4
    
    public static func allocate(_ size: Int, _ clear: Bool) -> UnsafeMutableRawPointer? {
        if clear {
            return calloc(1, size)
        } else {
            return malloc(size)
        }
    }
    
    
    public static func move(_ dest_: UnsafeMutableRawPointer, _ source_: UnsafeRawPointer?, _ num_: Int) {
        var dest = dest_
        var source = source_
        var num = num_
        if _DataStorage.vmOpsThreshold <= num && ((unsafeBitCast(source, to: Int.self) | Int(bitPattern: dest)) & (NSPageSize() - 1)) == 0 {
            let pages = NSRoundDownToMultipleOfPageSize(num)
            NSCopyMemoryPages(source!, dest, pages)
            source = source!.advanced(by: pages)
            dest = dest.advanced(by: pages)
            num -= pages
        }
        if num > 0 {
            memmove(dest, source!, num)
        }
    }
    
    public static func shouldAllocateCleared(_ size: Int) -> Bool {
        return (size > (128 * 1024))
    }
    
    public var _bytes: UnsafeMutableRawPointer?
    public var _length: Int
    public var _capacity: Int
    public var _needToZero: Bool
    public var _deallocator: ((UnsafeMutableRawPointer, Int) -> Void)?
    public var _backing: Backing = .swift
    
    public var bytes: UnsafeRawPointer? {
        @inline(__always)
        get {
            switch _backing {
            case .swift:
                return UnsafeRawPointer(_bytes)
            case .immutable:
                return UnsafeRawPointer(_bytes)
            case .mutable:
                return UnsafeRawPointer(_bytes)
            case .customReference(let d):
                return d.bytes
            case .customMutableReference(let d):
                return d.bytes
            }
        }
    }
    
    public var mutableBytes: UnsafeMutableRawPointer? {
        @inline(__always)
        get {
            switch _backing {
            case .swift:
                return _bytes
            case .immutable(let d):
                let data = d.mutableCopy() as! NSMutableData
                data.length = length
                _backing = .mutable(data)
                _bytes = data.mutableBytes
                return data.mutableBytes
            case .mutable:
                return _bytes
            case .customReference(let d):
                let data = d.mutableCopy() as! NSMutableData
                data.length = length
                _backing = .customMutableReference(data)
                _bytes = data.mutableBytes
                return data.mutableBytes
            case .customMutableReference(let d):
                return d.mutableBytes
            }
        }
    }
    
    public var length: Int {
        @inline(__always)
        get {
            switch _backing {
            case .swift:
                return _length
            case .immutable:
                return _length
            case .mutable:
                return _length
            case .customReference(let d):
                return d.length
            case .customMutableReference(let d):
                return d.length
            }
        }
        @inline(__always)
        set {
            setLength(newValue)
        }
    }
    
    
    public func _freeBytes() {
        if let bytes = _bytes {
            if let dealloc = _deallocator {
                dealloc(bytes, length)
            } else {
                free(bytes)
            }
        }
    }
    
    public func enumerateBytes(_ block: (_ buffer: UnsafeBufferPointer<UInt8>, _ byteIndex: Data.Index, _ stop: inout Bool) -> Void) {
        var stop: Bool = false
        switch _backing {
        case .swift:
            block(UnsafeBufferPointer<UInt8>(start: _bytes?.assumingMemoryBound(to: UInt8.self), count: _length), 0, &stop)
        case .immutable:
            block(UnsafeBufferPointer<UInt8>(start: _bytes?.assumingMemoryBound(to: UInt8.self), count: _length), 0, &stop)
        case .mutable:
            block(UnsafeBufferPointer<UInt8>(start: _bytes?.assumingMemoryBound(to: UInt8.self), count: _length), 0, &stop)
        case .customReference(let d):
            d.enumerateBytes { (ptr, range, stop) in
                var stopv = false
                let bytePtr = ptr.bindMemory(to: UInt8.self, capacity: range.length)
                block(UnsafeBufferPointer(start: bytePtr, count: range.length), range.location, &stopv)
                if stopv {
                    stop.pointee = true
                }
            }
        case .customMutableReference(let d):
            d.enumerateBytes { (ptr, range, stop) in
                var stopv = false
                let bytePtr = ptr.bindMemory(to: UInt8.self, capacity: range.length)
                block(UnsafeBufferPointer(start: bytePtr, count: range.length), range.location, &stopv)
                if stopv {
                    stop.pointee = true
                }
            }
        }
    }
    
    @inline(never)
    public func _grow(_ newLength: Int, _ clear: Bool) {
        let cap = _capacity
        var additionalCapacity = (newLength >> (_DataStorage.vmOpsThreshold <= newLength ? 2 : 1))
        if Int.max - additionalCapacity < newLength {
            additionalCapacity = 0
        }
        var newCapacity = Swift.max(cap, newLength + additionalCapacity)
        let origLength = _length
        var allocateCleared = clear && _DataStorage.shouldAllocateCleared(newCapacity)
        var newBytes: UnsafeMutableRawPointer? = nil
        if _bytes == nil {
            newBytes = _DataStorage.allocate(newCapacity, allocateCleared)
            if newBytes == nil {
                /* Try again with minimum length */
                allocateCleared = clear && _DataStorage.shouldAllocateCleared(newLength)
                newBytes = _DataStorage.allocate(newLength, allocateCleared)
            }
        } else {
            let tryCalloc = (origLength == 0 || (newLength / origLength) >= 4)
            if allocateCleared && tryCalloc {
                newBytes = _DataStorage.allocate(newCapacity, true)
                if newBytes != nil {
                    _DataStorage.move(newBytes!, _bytes!, origLength)
                    _freeBytes()
                }
            }
            /* Where calloc/memmove/free fails, realloc might succeed */
            if newBytes == nil {
                allocateCleared = false
                if _deallocator != nil {
                    newBytes = _DataStorage.allocate(newCapacity, true)
                    if newBytes != nil {
                        _DataStorage.move(newBytes!, _bytes!, origLength)
                        _freeBytes()
                        _deallocator = nil
                    }
                } else {
                    newBytes = realloc(_bytes!, newCapacity)
                }
            }
            
            /* Try again with minimum length */
            if newBytes == nil {
                newCapacity = newLength
                allocateCleared = clear && _DataStorage.shouldAllocateCleared(newCapacity)
                if allocateCleared && tryCalloc {
                    newBytes = _DataStorage.allocate(newCapacity, true)
                    if newBytes != nil {
                        _DataStorage.move(newBytes!, _bytes!, origLength)
                        _freeBytes()
                    }
                }
                if newBytes == nil {
                    allocateCleared = false
                    newBytes = realloc(_bytes!, newCapacity)
                }
            }
        }
        
        if newBytes == nil {
            /* Could not allocate bytes */
            // At this point if the allocation cannot occur the process is likely out of memory
            // and Bad-Things™ are going to happen anyhow
            fatalError("unable to allocate memory for length (\(newLength))")
        }
        
        if origLength < newLength && clear && !allocateCleared {
            memset(newBytes!.advanced(by: origLength), 0, newLength - origLength)
        }
        
        /* _length set by caller */
        _bytes = newBytes
        _capacity = newCapacity
        /* Realloc/memset doesn't zero out the entire capacity, so we must be safe and clear next time we grow the length */
        _needToZero = !allocateCleared
    }
    
    @inline(__always)
    public func setLength(_ length: Int) {
        switch _backing {
        case .swift:
            let origLength = _length
            let newLength = length
            if _capacity < newLength || _bytes == nil {
                _grow(newLength, true)
            } else if origLength < newLength && _needToZero {
                memset(_bytes! + origLength, 0, newLength - origLength)
            } else if newLength < origLength {
                _needToZero = true
            }
            _length = newLength
        case .immutable(let d):
            let data = d.mutableCopy() as! NSMutableData
            data.length = length
            _backing = .mutable(data)
            _length = length
            _bytes = data.mutableBytes
        case .mutable(let d):
            d.length = length
            _length = length
            _bytes = d.mutableBytes
        case .customReference(let d):
            let data = d.mutableCopy() as! NSMutableData
            data.length = length
            _backing = .customMutableReference(data)
        case .customMutableReference(let d):
            d.length = length
        }
    }
    
    @inline(__always)
    public func append(_ bytes: UnsafeRawPointer, length: Int) {
        precondition(length >= 0, "Length of appending bytes must be positive")
        switch _backing {
        case .swift:
            let origLength = _length
            let newLength = origLength + length
            if _capacity < newLength || _bytes == nil {
                _grow(newLength, false)
            }
            _length = newLength
            _DataStorage.move(_bytes!.advanced(by: origLength), bytes, length)
        case .immutable(let d):
            let data = d.mutableCopy() as! NSMutableData
            data.append(bytes, length: length)
            _backing = .mutable(data)
            _length = data.length
            _bytes = data.mutableBytes
        case .mutable(let d):
            d.append(bytes, length: length)
            _length = d.length
            _bytes = d.mutableBytes
        case .customReference(let d):
            let data = d.mutableCopy() as! NSMutableData
            data.append(bytes, length: length)
            _backing = .customMutableReference(data)
        case .customMutableReference(let d):
            d.append(bytes, length: length)
        }
        
    }
    
    // fast-path for appending directly from another data storage
    @inline(__always)
    public func append(_ otherData: _DataStorage, startingAt start: Int, endingAt end: Int) {
        let otherLength = otherData.length
        if otherLength == 0 { return }
        if let bytes = otherData.bytes {
            append(bytes.advanced(by: start), length: end - start)
        }
    }
    
    @inline(__always)
    public func append(_ otherData: Data) {
        otherData.enumerateBytes { (buffer: UnsafeBufferPointer<UInt8>, _, _) in
            append(buffer.baseAddress!, length: buffer.count)
        }
    }
    
    @inline(__always)
    public func increaseLength(by extraLength: Int) {
        if extraLength == 0 { return }
        switch _backing {
        case .swift:
            let origLength = _length
            let newLength = origLength + extraLength
            if _capacity < newLength || _bytes == nil {
                _grow(newLength, true)
            } else if _needToZero {
                memset(_bytes!.advanced(by: origLength), 0, extraLength)
            }
            _length = newLength
        case .immutable(let d):
            let data = d.mutableCopy() as! NSMutableData
            data.increaseLength(by: extraLength)
            _backing = .mutable(data)
            _length += extraLength
            _bytes = data.mutableBytes
        case .mutable(let d):
            d.increaseLength(by: extraLength)
            _length += extraLength
            _bytes = d.mutableBytes
        case .customReference(let d):
            let data = d.mutableCopy() as! NSMutableData
            data.increaseLength(by: extraLength)
            _backing = .customReference(data)
        case .customMutableReference(let d):
            d.increaseLength(by: extraLength)
        }
        
    }
    
    @inline(__always)
    public func set(_ index: Int, to value: UInt8) {
        switch _backing {
        case .swift:
            fallthrough
        case .mutable:
            _bytes!.advanced(by: index).assumingMemoryBound(to: UInt8.self).pointee = value
        default:
            var theByte = value
            let range = NSRange(location: index, length: 1)
            replaceBytes(in: range, with: &theByte, length: 1)
        }
        
    }
    
    @inline(__always)
    public func replaceBytes(in range: NSRange, with bytes: UnsafeRawPointer?) {
        if range.length == 0 { return }
        switch _backing {
        case .swift:
            if _length < range.location + range.length {
                let newLength = range.location + range.length
                if _capacity < newLength {
                    
                    _grow(newLength, false)
                }
                _length = newLength
            }
            _DataStorage.move(_bytes!.advanced(by: range.location), bytes!, range.length)
        case .immutable(let d):
            let data = d.mutableCopy() as! NSMutableData
            data.replaceBytes(in: range, withBytes: bytes!)
            _backing = .mutable(data)
            _length = data.length
            _bytes = data.mutableBytes
        case .mutable(let d):
            d.replaceBytes(in: range, withBytes: bytes!)
            _length = d.length
            _bytes = d.mutableBytes
        case .customReference(let d):
            let data = d.mutableCopy() as! NSMutableData
            data.replaceBytes(in: range, withBytes: bytes!)
            _backing = .customMutableReference(data)
        case .customMutableReference(let d):
            d.replaceBytes(in: range, withBytes: bytes!)
        }
    }
    
    @inline(__always)
    public func replaceBytes(in range: NSRange, with replacementBytes: UnsafeRawPointer?, length replacementLength: Int) {
        let currentLength = _length
        let resultingLength = currentLength - range.length + replacementLength
        switch _backing {
        case .swift:
            let shift = resultingLength - currentLength
            var mutableBytes = _bytes
            if resultingLength > currentLength {
                setLength(resultingLength)
                mutableBytes = _bytes!
            }
            /* shift the trailing bytes */
            let start = range.location
            let length = range.length
            if shift != 0 {
                memmove(mutableBytes! + start + replacementLength, mutableBytes! + start + length, currentLength - start - length)
            }
            if replacementLength != 0 {
                if replacementBytes != nil {
                    memmove(mutableBytes! + start, replacementBytes!, replacementLength)
                } else {
                    memset(mutableBytes! + start, 0, replacementLength)
                }
            }
            
            if resultingLength < currentLength {
                setLength(resultingLength)
            }
        case .immutable(let d):
            let data = d.mutableCopy() as! NSMutableData
            data.replaceBytes(in: range, withBytes: replacementBytes, length: replacementLength)
            _backing = .mutable(data)
            _length = data.length
            _bytes = data.mutableBytes
        case .mutable(let d):
            d.replaceBytes(in: range, withBytes: replacementBytes, length: replacementLength)
            _backing = .mutable(d)
            _length = d.length
            _bytes = d.mutableBytes
        case .customReference(let d):
            let data = d.mutableCopy() as! NSMutableData
            data.replaceBytes(in: range, withBytes: replacementBytes, length: replacementLength)
            _backing = .customMutableReference(data)
        case .customMutableReference(let d):
            d.replaceBytes(in: range, withBytes: replacementBytes, length: replacementLength)
        }
    }
    
    @inline(__always)
    public func resetBytes(in range: NSRange) {
        if range.length == 0 { return }
        switch _backing {
        case .swift:
            if _length < range.location + range.length {
                let newLength = range.location + range.length
                if _capacity < newLength {
                    _grow(newLength, false)
                }
                _length = newLength
            }
            memset(_bytes!.advanced(by: range.location), 0, range.length)
        case .immutable(let d):
            let data = d.mutableCopy() as! NSMutableData
            data.resetBytes(in: range)
            _backing = .mutable(data)
            _length = data.length
            _bytes = data.mutableBytes
        case .mutable(let d):
            d.resetBytes(in: range)
            _length = d.length
            _bytes = d.mutableBytes
        case .customReference(let d):
            let data = d.mutableCopy() as! NSMutableData
            data.resetBytes(in: range)
            _backing = .customMutableReference(data)
        case .customMutableReference(let d):
            d.resetBytes(in: range)
        }
        
    }
    
    
    public convenience init() {
        self.init(capacity: 0)
    }
    
    public init(length: Int) {
        precondition(length < _DataStorage.maxSize)
        var capacity = (length < 1024 * 1024 * 1024) ? length + (length >> 2) : length
        if _DataStorage.vmOpsThreshold <= capacity {
            capacity = NSRoundUpToMultipleOfPageSize(capacity)
        }
        
        let clear = _DataStorage.shouldAllocateCleared(length)
        _bytes = _DataStorage.allocate(capacity, clear)!
        _capacity = capacity
        _needToZero = !clear
        _length = 0
        setLength(length)
    }
    
    
    public init(capacity capacity_: Int) {
        var capacity = capacity_
        precondition(capacity < _DataStorage.maxSize)
        if _DataStorage.vmOpsThreshold <= capacity {
            capacity = NSRoundUpToMultipleOfPageSize(capacity)
        }
        _length = 0
        _bytes = _DataStorage.allocate(capacity, false)!
        _capacity = capacity
        _needToZero = true
    }
    
    public init(bytes: UnsafeRawPointer?, length: Int) {
        precondition(length < _DataStorage.maxSize)
        if length == 0 {
            _capacity = 0
            _length = 0
            _needToZero = false
            _bytes = nil
        } else if _DataStorage.vmOpsThreshold <= length {
            _capacity = length
            _length = length
            _needToZero = true
            _bytes = _DataStorage.allocate(length, false)!
            _DataStorage.move(_bytes!, bytes, length)
        } else {
            var capacity = length
            if _DataStorage.vmOpsThreshold <= capacity {
                capacity = NSRoundUpToMultipleOfPageSize(capacity)
            }
            _length = length
            _bytes = _DataStorage.allocate(capacity, false)!
            _capacity = capacity
            _needToZero = true
            _DataStorage.move(_bytes!, bytes, length)
        }
    }
    
    public init(bytes: UnsafeMutableRawPointer?, length: Int, copy: Bool, deallocator: ((UnsafeMutableRawPointer, Int) -> Void)?) {
        precondition(length < _DataStorage.maxSize)
        if length == 0 {
            _capacity = 0
            _length = 0
            _needToZero = false
            _bytes = nil
            if let dealloc = deallocator,
               let bytes_ = bytes {
                dealloc(bytes_, length)
            }
        } else if !copy {
            _capacity = length
            _length = length
            _needToZero = false
            _bytes = bytes
            _deallocator = deallocator
        } else if _DataStorage.vmOpsThreshold <= length {
            _capacity = length
            _length = length
            _needToZero = true
            _bytes = _DataStorage.allocate(length, false)!
            _DataStorage.move(_bytes!, bytes, length)
            if let dealloc = deallocator {
                dealloc(bytes!, length)
            }
        } else {
            var capacity = length
            if _DataStorage.vmOpsThreshold <= capacity {
                capacity = NSRoundUpToMultipleOfPageSize(capacity)
            }
            _length = length
            _bytes = _DataStorage.allocate(capacity, false)!
            _capacity = capacity
            _needToZero = true
            _DataStorage.move(_bytes!, bytes, length)
            if let dealloc = deallocator {
                dealloc(bytes!, length)
            }
        }
    }
    
    public init(immutableReference: NSData) {
        _bytes = UnsafeMutableRawPointer(mutating: immutableReference.bytes)
        _capacity = 0
        _needToZero = false
        _length = immutableReference.length
        _backing = .immutable(immutableReference)
    }
    
    public init(mutableReference: NSMutableData) {
        _bytes = mutableReference.mutableBytes
        _capacity = 0
        _needToZero = false
        _length = mutableReference.length
        _backing = .mutable(mutableReference)
    }
    
    public init(customReference: NSData) {
        _bytes = nil
        _capacity = 0
        _needToZero = false
        _length = 0
        _backing = .customReference(customReference)
    }
    
    public init(customMutableReference: NSMutableData) {
        _bytes = nil
        _capacity = 0
        _needToZero = false
        _length = 0
        _backing = .customMutableReference(customMutableReference)
    }
    
    deinit {
        switch _backing {
        case .swift:
            _freeBytes()
        default:
            break
        }
    }
    
    @inline(__always)
    public func mutableCopy(_ range: Range<Int>) -> _DataStorage {
        switch _backing {
        case .swift:
            return _DataStorage(bytes: _bytes?.advanced(by: range.lowerBound), length: range.count, copy: true, deallocator: nil)
        case .immutable(let d):
            if range.lowerBound == 0 && range.upperBound == _length {
                return _DataStorage(mutableReference: d.mutableCopy() as! NSMutableData)
            } else {
                return _DataStorage(mutableReference: d.subdata(with: NSRange(location: range.lowerBound, length: range.count))._bridgeToObjectiveC().mutableCopy() as! NSMutableData)
            }
        case .mutable(let d):
            if range.lowerBound == 0 && range.upperBound == _length {
                return _DataStorage(mutableReference: d.mutableCopy() as! NSMutableData)
            } else {
                return _DataStorage(mutableReference: d.subdata(with: NSRange(location: range.lowerBound, length: range.count))._bridgeToObjectiveC().mutableCopy() as! NSMutableData)
            }
        case .customReference(let d):
            if range.lowerBound == 0 && range.upperBound == _length {
                return _DataStorage(mutableReference: d.mutableCopy() as! NSMutableData)
            } else {
                return _DataStorage(mutableReference: d.subdata(with: NSRange(location: range.lowerBound, length: range.count))._bridgeToObjectiveC().mutableCopy() as! NSMutableData)
            }
        case .customMutableReference(let d):
            if range.lowerBound == 0 && range.upperBound == _length {
                return _DataStorage(mutableReference: d.mutableCopy() as! NSMutableData)
            } else {
                return _DataStorage(mutableReference: d.subdata(with: NSRange(location: range.lowerBound, length: range.count))._bridgeToObjectiveC().mutableCopy() as! NSMutableData)
            }
        }
    }
    
    public func withInteriorPointerReference<T>(_ range: Range<Int>, _ work: (NSData) throws -> T) rethrows -> T {
        if range.count == 0 {
            return try work(NSData()) // zero length data can be optimized as a singleton
        }
        
        switch _backing {
        case .swift:
            return try work(NSData(bytesNoCopy: _bytes!.advanced(by: range.lowerBound), length: range.count, freeWhenDone: false))
        case .immutable(let d):
            guard range.lowerBound == 0 && range.upperBound == _length else {
                return try work(NSData(bytesNoCopy: _bytes!.advanced(by: range.lowerBound), length: range.count, freeWhenDone: false))
            }
            return try work(d)
        case .mutable(let d):
            guard range.lowerBound == 0 && range.upperBound == _length else {
                return try work(NSData(bytesNoCopy: _bytes!.advanced(by: range.lowerBound), length: range.count, freeWhenDone: false))
            }
            return try work(d)
        case .customReference(let d):
            guard range.lowerBound == 0 && range.upperBound == _length else {
                
                return try work(NSData(bytesNoCopy: UnsafeMutableRawPointer(mutating: d.bytes.advanced(by: range.lowerBound)), length: range.count, freeWhenDone: false))
            }
            return try work(d)
        case .customMutableReference(let d):
            guard range.lowerBound == 0 && range.upperBound == _length else {
                return try work(NSData(bytesNoCopy: UnsafeMutableRawPointer(mutating: d.bytes.advanced(by: range.lowerBound)), length: range.count, freeWhenDone: false))
            }
            return try work(d)
        }
    }
    
    public func bridgedReference(_ range: Range<Int>) -> NSData {
        if range.count == 0 {
            return NSData() // zero length data can be optimized as a singleton
        }
        
        switch _backing {
        case .swift:
            return _NSSwiftData(backing: self, range: range)
        case .immutable(let d):
            guard range.lowerBound == 0 && range.upperBound == _length else {
                return _NSSwiftData(backing: self, range: range)
            }
            return d
        case .mutable(let d):
            guard range.lowerBound == 0 && range.upperBound == _length else {
                return _NSSwiftData(backing: self, range: range)
            }
            return d
        case .customReference(let d):
            guard range.lowerBound == 0 && range.upperBound == d.length else {
                return _NSSwiftData(backing: self, range: range)
            }
            return d
        case .customMutableReference(let d):
            guard range.lowerBound == 0 && range.upperBound == d.length else {
                return d.subdata(with: NSRange(location: range.lowerBound, length: range.count))._bridgeToObjectiveC()
            }
            return d.copy() as! NSData
        }
    }
    
    public var hashValue: Int {
        switch _backing {
        case .customReference(let d):
            return d.hash
        case .customMutableReference(let d):
            return d.hash
        default:
            let len = _length
            return Int(bitPattern: CFHashBytes(_bytes?.assumingMemoryBound(to: UInt8.self), Swift.min(len, 80)))
        }
    }
    
    public func subdata(in range: Range<Data.Index>) -> Data {
        switch _backing {
        case .customReference(let d):
            return d.subdata(with: NSRange(location: range.lowerBound, length: range.count))
        case .customMutableReference(let d):
            return d.subdata(with: NSRange(location: range.lowerBound, length: range.count))
        default:
            return Data(bytes: _bytes!.advanced(by: range.lowerBound), count: range.count)
        }
    }
}

internal class _NSSwiftData : NSData {
    var _backing: _DataStorage!
    var _range: Range<Data.Index>!
    
    convenience init(backing: _DataStorage, range: Range<Data.Index>) {
        self.init()
        _backing = backing
        _range = range
    }
    override var length: Int {
        return _range.count
    }
    
    override var bytes: UnsafeRawPointer {
        // NSData's byte pointer methods are not annotated for nullability correctly
        // (but assume non-null by the wrapping macro guards). This placeholder value
        // is to work-around this bug. Any indirection to the underlying bytes of an NSData
        // with a length of zero would have been a programmer error anyhow so the actual
        // return value here is not needed to be an allocated value. This is specifically
        // needed to live like this to be source compatible with Swift3. Beyond that point
        // this API may be subject to correction.
        guard let bytes = _backing.bytes else {
            return UnsafeRawPointer(bitPattern: 0xBAD0)!
        }
        
        return bytes.advanced(by: _range.lowerBound)
    }
    
    override func copy(with zone: NSZone? = nil) -> Any {
        return self
    }
    
    override func mutableCopy(with zone: NSZone? = nil) -> Any {
        return NSMutableData(bytes: bytes, length: length)
    }
    
#if !DEPLOYMENT_RUNTIME_SWIFT
    @objc
    func _isCompact() -> Bool {
        return true
    }
#endif
    
#if DEPLOYMENT_RUNTIME_SWIFT
    override func _providesConcreteBacking() -> Bool {
        return true
    }
#else
    @objc(_providesConcreteBacking)
    func _providesConcreteBacking() -> Bool {
        return true
    }
#endif
}

public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessCollection, MutableCollection, RangeReplaceableCollection {
    public typealias ReferenceType = NSData
    
    public typealias ReadingOptions = NSData.ReadingOptions
    public typealias WritingOptions = NSData.WritingOptions
    public typealias SearchOptions = NSData.SearchOptions
    public typealias Base64EncodingOptions = NSData.Base64EncodingOptions
    public typealias Base64DecodingOptions = NSData.Base64DecodingOptions
    
    public typealias Index = Int
    public typealias Indices = CountableRange<Int>
    
    @_versioned internal var _backing : _DataStorage
    @_versioned internal var _sliceRange: Range<Index>
    
    
    // A standard or custom deallocator for `Data`.
    ///
    /// When creating a `Data` with the no-copy initializer, you may specify a `Data.Deallocator` to customize the behavior of how the backing store is deallocated.
    public enum Deallocator {
        /// Use a virtual memory deallocator.
#if !DEPLOYMENT_RUNTIME_SWIFT
        case virtualMemory
#endif
        
        /// Use `munmap`.
        case unmap
        
        /// Use `free`.
        case free
        
        /// Do nothing upon deallocation.
        case none
        
        /// A custom deallocator.
        case custom((UnsafeMutableRawPointer, Int) -> Void)
        
        fileprivate var _deallocator : ((UnsafeMutableRawPointer, Int) -> Void) {
#if DEPLOYMENT_RUNTIME_SWIFT
            switch self {
            case .unmap:
                return { __NSDataInvokeDeallocatorUnmap($0, $1) }
            case .free:
                return { __NSDataInvokeDeallocatorFree($0, $1) }
            case .none:
                return { _, _ in }
            case .custom(let b):
                return { (ptr, len) in
                    b(ptr, len)
                }
            }
#else
            switch self {
            case .virtualMemory:
                return { NSDataDeallocatorVM($0, $1) }
            case .unmap:
                return { NSDataDeallocatorUnmap($0, $1) }
            case .free:
                return { NSDataDeallocatorFree($0, $1) }
            case .none:
                return { _, _ in }
            case .custom(let b):
                return { (ptr, len) in
                    b(ptr, len)
                }
            }
#endif
        }
    }
    
    // MARK: -
    // MARK: Init methods
    
    /// Initialize a `Data` with copied memory content.
    ///
    /// - parameter bytes: A pointer to the memory. It will be copied.
    /// - parameter count: The number of bytes to copy.
    public init(bytes: UnsafeRawPointer, count: Int) {
        _backing = _DataStorage(bytes: bytes, length: count)
        _sliceRange = 0..<count
    }
    
    /// Initialize a `Data` with copied memory content.
    ///
    /// - parameter buffer: A buffer pointer to copy. The size is calculated from `SourceType` and `buffer.count`.
    public init<SourceType>(buffer: UnsafeBufferPointer<SourceType>) {
        let count = MemoryLayout<SourceType>.stride * buffer.count
        _backing = _DataStorage(bytes: buffer.baseAddress, length: count)
        _sliceRange = 0..<count
    }
    
    /// Initialize a `Data` with copied memory content.
    ///
    /// - parameter buffer: A buffer pointer to copy. The size is calculated from `SourceType` and `buffer.count`.
    public init<SourceType>(buffer: UnsafeMutableBufferPointer<SourceType>) {
        let count = MemoryLayout<SourceType>.stride * buffer.count
        _backing = _DataStorage(bytes: buffer.baseAddress, length: count)
        _sliceRange = 0..<count
    }
    
    /// Initialize a `Data` with the contents of an Array.
    ///
    /// - parameter bytes: An array of bytes to copy.
    public init(bytes: Array<UInt8>) {
        let count = bytes.count
        _backing = bytes.withUnsafeBufferPointer {
            return _DataStorage(bytes: $0.baseAddress, length: count)
        }
        _sliceRange = 0..<count
    }
    
    /// Initialize a `Data` with the contents of an Array.
    ///
    /// - parameter bytes: An array of bytes to copy.
    public init(bytes: ArraySlice<UInt8>) {
        let count = bytes.count
        _backing = bytes.withUnsafeBufferPointer {
            return _DataStorage(bytes: $0.baseAddress, length: count)
        }
        _sliceRange = 0..<count
    }
    
    /// Initialize a `Data` with a repeating byte pattern
    ///
    /// - parameter repeatedValue: A byte to initialize the pattern
    /// - parameter count: The number of bytes the data initially contains initialized to the repeatedValue
    public init(repeating repeatedValue: UInt8, count: Int) {
        self.init(count: count)
        withUnsafeMutableBytes { (bytes: UnsafeMutablePointer<UInt8>) -> Void in
            memset(bytes, Int32(repeatedValue), count)
        }
    }
    
    /// Initialize a `Data` with the specified size.
    ///
    /// This initializer doesn't necessarily allocate the requested memory right away. `Data` allocates additional memory as needed, so `capacity` simply establishes the initial capacity. When it does allocate the initial memory, though, it allocates the specified amount.
    ///
    /// This method sets the `count` of the data to 0.
    ///
    /// If the capacity specified in `capacity` is greater than four memory pages in size, this may round the amount of requested memory up to the nearest full page.
    ///
    /// - parameter capacity: The size of the data.
    public init(capacity: Int) {
        _backing = _DataStorage(capacity: capacity)
        _sliceRange = 0..<0
    }
    
    /// Initialize a `Data` with the specified count of zeroed bytes.
    ///
    /// - parameter count: The number of bytes the data initially contains.
    public init(count: Int) {
        _backing = _DataStorage(length: count)
        _sliceRange = 0..<count
    }
    
    /// Initialize an empty `Data`.
    public init() {
        _backing = _DataStorage(length: 0)
        _sliceRange = 0..<0
    }
    
    
    /// Initialize a `Data` without copying the bytes.
    ///
    /// If the result is mutated and is not a unique reference, then the `Data` will still follow copy-on-write semantics. In this case, the copy will use its own deallocator. Therefore, it is usually best to only use this initializer when you either enforce immutability with `let` or ensure that no other references to the underlying data are formed.
    /// - parameter bytes: A pointer to the bytes.
    /// - parameter count: The size of the bytes.
    /// - parameter deallocator: Specifies the mechanism to free the indicated buffer, or `.none`.
    public init(bytesNoCopy bytes: UnsafeMutableRawPointer, count: Int, deallocator: Deallocator) {
        let whichDeallocator = deallocator._deallocator
        _backing = _DataStorage(bytes: bytes, length: count, copy: false, deallocator: whichDeallocator)
        _sliceRange = 0..<count
    }
    
    /// Initialize a `Data` with the contents of a `URL`.
    ///
    /// - parameter url: The `URL` to read.
    /// - parameter options: Options for the read operation. Default value is `[]`.
    /// - throws: An error in the Cocoa domain, if `url` cannot be read.
    public init(contentsOf url: URL, options: Data.ReadingOptions = []) throws {
        let d = try NSData(contentsOf: url, options: ReadingOptions(rawValue: options.rawValue))
        _backing = _DataStorage(immutableReference: d)
        _sliceRange = 0..<d.length
    }
    
    /// Initialize a `Data` from a Base-64 encoded String using the given options.
    ///
    /// Returns nil when the input is not recognized as valid Base-64.
    /// - parameter base64String: The string to parse.
    /// - parameter options: Encoding options. Default value is `[]`.
    public init?(base64Encoded base64String: String, options: Data.Base64DecodingOptions = []) {
        if let d = NSData(base64Encoded: base64String, options: Base64DecodingOptions(rawValue: options.rawValue)) {
            _backing = _DataStorage(immutableReference: d)
            _sliceRange = 0..<d.length
        } else {
            return nil
        }
    }
    
    /// Initialize a `Data` from a Base-64, UTF-8 encoded `Data`.
    ///
    /// Returns nil when the input is not recognized as valid Base-64.
    ///
    /// - parameter base64Data: Base-64, UTF-8 encoded input data.
    /// - parameter options: Decoding options. Default value is `[]`.
    public init?(base64Encoded base64Data: Data, options: Data.Base64DecodingOptions = []) {
        if let d = NSData(base64Encoded: base64Data, options: Base64DecodingOptions(rawValue: options.rawValue)) {
            _backing = _DataStorage(immutableReference: d)
            _sliceRange = 0..<d.length
        } else {
            return nil
        }
    }
    
    /// Initialize a `Data` by adopting a reference type.
    ///
    /// You can use this initializer to create a `struct Data` that wraps a `class NSData`. `struct Data` will use the `class NSData` for all operations. Other initializers (including casting using `as Data`) may choose to hold a reference or not, based on a what is the most efficient representation.
    ///
    /// If the resulting value is mutated, then `Data` will invoke the `mutableCopy()` function on the reference to copy the contents. You may customize the behavior of that function if you wish to return a specialized mutable subclass.
    ///
    /// - parameter reference: The instance of `NSData` that you wish to wrap. This instance will be copied by `struct Data`.
    public init(referencing reference: NSData) {
#if DEPLOYMENT_RUNTIME_SWIFT
        let providesConcreteBacking = reference._providesConcreteBacking()
#else
        let providesConcreteBacking = (reference as AnyObject)._providesConcreteBacking?() ?? false
#endif
        if providesConcreteBacking {
            _backing = _DataStorage(immutableReference: reference.copy() as! NSData)
            _sliceRange = 0..<reference.length
        } else {
            _backing = _DataStorage(customReference: reference.copy() as! NSData)
            _sliceRange = 0..<reference.length
        }
        
    }
    
    // slightly faster paths for common sequences
    
    public init<S: Sequence>(_ elements: S) where S.Iterator.Element == UInt8 {
        if elements is Array<UInt8> {
            self.init(bytes: _identityCast(elements, to: Array<UInt8>.self))
        } else if elements is ArraySlice<UInt8> {
            self.init(bytes: _identityCast(elements, to: ArraySlice<UInt8>.self))
        } else if elements is UnsafeBufferPointer<UInt8> {
            self.init(buffer: _identityCast(elements, to: UnsafeBufferPointer<UInt8>.self))
        } else if let buffer = elements as? UnsafeMutableBufferPointer<UInt8> {
            self.init(buffer: buffer)
        } else if let data = elements as? Data {
            self.init(backing: data._backing.mutableCopy(data._sliceRange), range: 0..<data.count)
        } else {
            let underestimatedCount = elements.underestimatedCount
            self.init(count: underestimatedCount)
            
            let (endIterator, _) = UnsafeMutableBufferPointer(start: _backing._bytes?.assumingMemoryBound(to: UInt8.self), count: underestimatedCount).initialize(from: elements)
            var iter = endIterator
            while let byte = iter.next() { self.append(byte) }
        }
    }

    @_versioned
    internal init(backing: _DataStorage, range: Range<Index>) {
        _backing = backing
        _sliceRange = range
    }
    
    @_versioned
    internal func _validateIndex(_ index: Int, message: String? = nil) {
        precondition(_sliceRange.contains(index), message ?? "Index \(index) is out of bounds of range \(_sliceRange)")
    }
    
    @_versioned
    internal func _validateRange<R: RangeExpression>(_ range: R) where R.Bound == Int {
        let lower = R.Bound(_sliceRange.lowerBound)
        let upper = R.Bound(_sliceRange.upperBound)
        let r = range.relative(to: lower..<upper)
        precondition(r.lowerBound >= _sliceRange.lowerBound && r.lowerBound <= _sliceRange.upperBound, "Range \(r) is out of bounds of range \(_sliceRange)")
        precondition(r.upperBound >= _sliceRange.lowerBound && r.upperBound <= _sliceRange.upperBound, "Range \(r) is out of bounds of range \(_sliceRange)")
    }
    
    // -----------------------------------
    // MARK: - Properties and Functions
    
    /// The number of bytes in the data.
    
    public var count: Int {
        @inline(__always)
        get {
            return _sliceRange.count
        }
        @inline(__always)
        set {
            precondition(count >= 0, "count must be positive")
            if !isKnownUniquelyReferenced(&_backing) {
                _backing = _backing.mutableCopy(_sliceRange)
            }
            _backing.length = newValue
            _sliceRange = _sliceRange.lowerBound..<(_sliceRange.lowerBound + newValue)
        }
    }
    
    /// Access the bytes in the data.
    ///
    /// - warning: The byte pointer argument should not be stored and used outside of the lifetime of the call to the closure.
    @inline(__always)
    public func withUnsafeBytes<ResultType, ContentType>(_ body: (UnsafePointer<ContentType>) throws -> ResultType) rethrows -> ResultType {
        let bytes =  _backing.bytes?.advanced(by: _sliceRange.lowerBound) ?? UnsafeRawPointer(bitPattern: 0xBAD0)!
        let contentPtr = bytes.bindMemory(to: ContentType.self, capacity: count / MemoryLayout<ContentType>.stride)
        return try body(contentPtr)
    }
    
    
    /// Mutate the bytes in the data.
    ///
    /// This function assumes that you are mutating the contents.
    /// - warning: The byte pointer argument should not be stored and used outside of the lifetime of the call to the closure.
    @inline(__always)
    public mutating func withUnsafeMutableBytes<ResultType, ContentType>(_ body: (UnsafeMutablePointer<ContentType>) throws -> ResultType) rethrows -> ResultType {
        if !isKnownUniquelyReferenced(&_backing) {
            _backing = _backing.mutableCopy(_sliceRange)
        }
        let mutableBytes = _backing.mutableBytes?.advanced(by: _sliceRange.lowerBound) ?? UnsafeMutableRawPointer(bitPattern: 0xBAD0)!
        let contentPtr = mutableBytes.bindMemory(to: ContentType.self, capacity: count / MemoryLayout<ContentType>.stride)
        return try body(UnsafeMutablePointer(contentPtr))
    }
    
    // MARK: -
    // MARK: Copy Bytes
    
    /// Copy the contents of the data to a pointer.
    ///
    /// - parameter pointer: A pointer to the buffer you wish to copy the bytes into.
    /// - parameter count: The number of bytes to copy.
    /// - warning: This method does not verify that the contents at pointer have enough space to hold `count` bytes.
    @inline(__always)
    public func copyBytes(to pointer: UnsafeMutablePointer<UInt8>, count: Int) {
        precondition(count >= 0, "count of bytes to copy must be positive")
        if count == 0 { return }
        memcpy(UnsafeMutableRawPointer(pointer), _backing.bytes!.advanced(by: _sliceRange.lowerBound), Swift.min(count, _sliceRange.count))
    }
    
    @inline(__always)
    private func _copyBytesHelper(to pointer: UnsafeMutableRawPointer, from range: NSRange) {
        if range.length == 0 { return }
        memcpy(UnsafeMutableRawPointer(pointer), _backing.bytes!.advanced(by: range.location), Swift.min(range.length, _sliceRange.count))
    }
    
    /// Copy a subset of the contents of the data to a pointer.
    ///
    /// - parameter pointer: A pointer to the buffer you wish to copy the bytes into.
    /// - parameter range: The range in the `Data` to copy.
    /// - warning: This method does not verify that the contents at pointer have enough space to hold the required number of bytes.
    public func copyBytes(to pointer: UnsafeMutablePointer<UInt8>, from range: Range<Index>) {
        _copyBytesHelper(to: pointer, from: NSRange(range))
    }
    
    // Copy the contents of the data into a buffer.
    ///
    /// This function copies the bytes in `range` from the data into the buffer. If the count of the `range` is greater than `MemoryLayout<DestinationType>.stride * buffer.count` then the first N bytes will be copied into the buffer.
    /// - precondition: The range must be within the bounds of the data. Otherwise `fatalError` is called.
    /// - parameter buffer: A buffer to copy the data into.
    /// - parameter range: A range in the data to copy into the buffer. If the range is empty, this function will return 0 without copying anything. If the range is nil, as much data as will fit into `buffer` is copied.
    /// - returns: Number of bytes copied into the destination buffer.
    public func copyBytes<DestinationType>(to buffer: UnsafeMutableBufferPointer<DestinationType>, from range: Range<Index>? = nil) -> Int {
        let cnt = count
        guard cnt > 0 else { return 0 }
        
        let copyRange : Range<Index>
        if let r = range {
            guard !r.isEmpty else { return 0 }
            copyRange = r.lowerBound..<(r.lowerBound + Swift.min(buffer.count * MemoryLayout<DestinationType>.stride, r.count))
        } else {
            copyRange = 0..<Swift.min(buffer.count * MemoryLayout<DestinationType>.stride, cnt)
        }
        _validateRange(copyRange)
        
        guard !copyRange.isEmpty else { return 0 }
        
        let nsRange = NSMakeRange(copyRange.lowerBound, copyRange.upperBound - copyRange.lowerBound)
        _copyBytesHelper(to: buffer.baseAddress!, from: nsRange)
        return copyRange.count
    }
    
    // MARK: -
#if !DEPLOYMENT_RUNTIME_SWIFT
    @inline(__always)
    private func _shouldUseNonAtomicWriteReimplementation(options: Data.WritingOptions = []) -> Bool {
    
        // Avoid a crash that happens on OS X 10.11.x and iOS 9.x or before when writing a bridged Data non-atomically with Foundation's standard write() implementation.
        if !options.contains(.atomic) {
            #if os(OSX)
                return NSFoundationVersionNumber <= Double(NSFoundationVersionNumber10_11_Max)
            #else
                return NSFoundationVersionNumber <= Double(NSFoundationVersionNumber_iOS_9_x_Max)
            #endif
        } else {
            return false
        }
    }
#endif
    
    /// Write the contents of the `Data` to a location.
    ///
    /// - parameter url: The location to write the data into.
    /// - parameter options: Options for writing the data. Default value is `[]`.
    /// - throws: An error in the Cocoa domain, if there is an error writing to the `URL`.
    public func write(to url: URL, options: Data.WritingOptions = []) throws {
        try _backing.withInteriorPointerReference(_sliceRange) {
#if DEPLOYMENT_RUNTIME_SWIFT
            try $0.write(to: url, options: WritingOptions(rawValue: options.rawValue))
#else
            if _shouldUseNonAtomicWriteReimplementation(options: options) {
                var error: NSError? = nil
                guard __NSDataWriteToURL($0, url as NSURL, options.rawValue, &error) else { throw error! }
            } else {
                try $0.write(to: url, options: WritingOptions(rawValue: options.rawValue))
            }
#endif
        }
    }
    
    // MARK: -
    
    /// Find the given `Data` in the content of this `Data`.
    ///
    /// - parameter dataToFind: The data to be searched for.
    /// - parameter options: Options for the search. Default value is `[]`.
    /// - parameter range: The range of this data in which to perform the search. Default value is `nil`, which means the entire content of this data.
    /// - returns: A `Range` specifying the location of the found data, or nil if a match could not be found.
    /// - precondition: `range` must be in the bounds of the Data.
    public func range(of dataToFind: Data, options: Data.SearchOptions = [], in range: Range<Index>? = nil) -> Range<Index>? {
        let nsRange : NSRange
        if let r = range {
            _validateRange(r)
            nsRange = NSMakeRange(r.lowerBound, r.upperBound - r.lowerBound)
        } else {
            nsRange = NSMakeRange(0, _backing.length)
        }
        let result = _backing.withInteriorPointerReference(_sliceRange) {
            $0.range(of: dataToFind, options: options, in: nsRange)
        }
        if result.location == NSNotFound {
            return nil
        }
        return result.location..<(result.location + result.length)
    }
    
    /// Enumerate the contents of the data.
    ///
    /// In some cases, (for example, a `Data` backed by a `dispatch_data_t`, the bytes may be stored discontiguously. In those cases, this function invokes the closure for each contiguous region of bytes.
    /// - parameter block: The closure to invoke for each region of data. You may stop the enumeration by setting the `stop` parameter to `true`.
    public func enumerateBytes(_ block: (_ buffer: UnsafeBufferPointer<UInt8>, _ byteIndex: Index, _ stop: inout Bool) -> Void) {
        _backing.enumerateBytes(block)
    }
    
    @inline(__always)
    public mutating func append(_ bytes: UnsafePointer<UInt8>, count: Int) {
        precondition(count >= 0, "count must be positive")
        if count == 0 { return }
        if !isKnownUniquelyReferenced(&_backing) {
            _backing = _backing.mutableCopy(_sliceRange)
        }
        _backing.append(bytes, length: count)
        _sliceRange = _sliceRange.lowerBound..<(_sliceRange.upperBound + count)
    }
    
    @inline(__always)
    public mutating func append(_ other: Data) {
        if !isKnownUniquelyReferenced(&_backing) {
            _backing = _backing.mutableCopy(_sliceRange)
        }
        _backing.append(other._backing, startingAt: other._sliceRange.lowerBound, endingAt: other._sliceRange.upperBound)
        _sliceRange = _sliceRange.lowerBound..<(_sliceRange.upperBound + other.count)
    }
    
    /// Append a buffer of bytes to the data.
    ///
    /// - parameter buffer: The buffer of bytes to append. The size is calculated from `SourceType` and `buffer.count`.
    @inline(__always)
    public mutating func append<SourceType>(_ buffer : UnsafeBufferPointer<SourceType>) {
        if buffer.count == 0 { return }
        if !isKnownUniquelyReferenced(&_backing) {
            _backing = _backing.mutableCopy(_sliceRange)
        }
        _backing.append(buffer.baseAddress!, length: buffer.count * MemoryLayout<SourceType>.stride)
        _sliceRange = _sliceRange.lowerBound..<(_sliceRange.upperBound + buffer.count * MemoryLayout<SourceType>.stride)
    }
    
    @inline(__always)
    public mutating func append<S : Sequence>(contentsOf newElements: S) where S.Iterator.Element == Iterator.Element {
        let estimatedCount = newElements.underestimatedCount
        var idx = count
        count += estimatedCount
        for byte in newElements {
            let newIndex = idx + 1
            if newIndex > count {
                count = newIndex
            }
            self[idx] = byte
            idx = newIndex
        }
    }
    
    @inline(__always)
    public mutating func append(contentsOf bytes: [UInt8]) {
        bytes.withUnsafeBufferPointer { (buffer: UnsafeBufferPointer<UInt8>) -> Void in
            append(buffer)
        }
    }
    
    // MARK: -
    
    /// Set a region of the data to `0`.
    ///
    /// If `range` exceeds the bounds of the data, then the data is resized to fit.
    /// - parameter range: The range in the data to set to `0`.
    @inline(__always)
    public mutating func resetBytes(in range: Range<Index>) {
        // it is worth noting that the range here may be out of bounds of the Data itself (which triggers a growth)
        precondition(range.lowerBound >= 0, "Ranges must be positive bounds")
        precondition(range.upperBound >= 0, "Ranges must be positive bounds")
        let range = NSMakeRange(range.lowerBound, range.upperBound - range.lowerBound)
        if !isKnownUniquelyReferenced(&_backing) {
            _backing = _backing.mutableCopy(_sliceRange)
        }
        _backing.resetBytes(in: range)
        if _sliceRange.count < range.location + range.length {
            let newLength = range.location + range.length
            _sliceRange = _sliceRange.lowerBound..<(_sliceRange.lowerBound + newLength)
        }
    }
    
    /// Replace a region of bytes in the data with new data.
    ///
    /// This will resize the data if required, to fit the entire contents of `data`.
    ///
    /// - precondition: The bounds of `subrange` must be valid indices of the collection.
    /// - parameter subrange: The range in the data to replace. If `subrange.lowerBound == data.count && subrange.count == 0` then this operation is an append.
    /// - parameter data: The replacement data.
    @inline(__always)
    public mutating func replaceSubrange(_ subrange: Range<Index>, with data: Data) {
        _validateRange(subrange)
        let nsRange = NSMakeRange(subrange.lowerBound, subrange.upperBound - subrange.lowerBound)
        let cnt = data.count
        if !isKnownUniquelyReferenced(&_backing) {
            _backing = _backing.mutableCopy(_sliceRange)
        }
        let resultingLength = data.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) -> Int in
            let currentLength = _backing.length
            _backing.replaceBytes(in: nsRange, with: bytes, length: cnt)
            return currentLength - nsRange.length + cnt
        }
        _sliceRange = _sliceRange.lowerBound..<(_sliceRange.lowerBound + resultingLength)
    }
    
    @inline(__always)
    public mutating func replaceSubrange(_ subrange: CountableRange<Index>, with data: Data) {
        _validateRange(subrange)
        let nsRange = NSMakeRange(subrange.lowerBound, subrange.upperBound - subrange.lowerBound)
        let cnt = data.count
        if !isKnownUniquelyReferenced(&_backing) {
            _backing = _backing.mutableCopy(_sliceRange)
        }
        let resultingLength = data.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) -> Int in
            let currentLength = _backing.length
            _backing.replaceBytes(in: nsRange, with: bytes, length: cnt)
            return currentLength - nsRange.length + cnt
        }
        _sliceRange = _sliceRange.lowerBound..<(_sliceRange.lowerBound + resultingLength)
    }
    
    /// Replace a region of bytes in the data with new bytes from a buffer.
    ///
    /// This will resize the data if required, to fit the entire contents of `buffer`.
    ///
    /// - precondition: The bounds of `subrange` must be valid indices of the collection.
    /// - parameter subrange: The range in the data to replace.
    /// - parameter buffer: The replacement bytes.
    @inline(__always)
    public mutating func replaceSubrange<SourceType>(_ subrange: Range<Index>, with buffer: UnsafeBufferPointer<SourceType>) {
        _validateRange(subrange)
        let nsRange = NSMakeRange(subrange.lowerBound, subrange.upperBound - subrange.lowerBound)
        let bufferCount = buffer.count * MemoryLayout<SourceType>.stride
        
        if !isKnownUniquelyReferenced(&_backing) {
            _backing = _backing.mutableCopy(_sliceRange)
        }
        let currentLength = _backing.length
        _backing.replaceBytes(in: nsRange, with: buffer.baseAddress, length: bufferCount)
        let resultingLength = currentLength - nsRange.length + bufferCount
        _sliceRange = _sliceRange.lowerBound..<(_sliceRange.lowerBound + resultingLength)
    }
    
    /// Replace a region of bytes in the data with new bytes from a collection.
    ///
    /// This will resize the data if required, to fit the entire contents of `newElements`.
    ///
    /// - precondition: The bounds of `subrange` must be valid indices of the collection.
    /// - parameter subrange: The range in the data to replace.
    /// - parameter newElements: The replacement bytes.
    @inline(__always)
    public mutating func replaceSubrange<ByteCollection : Collection>(_ subrange: Range<Index>, with newElements: ByteCollection)
        where ByteCollection.Iterator.Element == Data.Iterator.Element {
            _validateRange(subrange)
            // Calculate this once, it may not be O(1)
            let replacementCount: Int = numericCast(newElements.count)
            let currentCount = self.count
            let subrangeCount = subrange.count
            
            _validateRange(subrange)
            
            let resultCount = currentCount - subrangeCount + replacementCount
            if resultCount != currentCount {
                // This may realloc.
                // In the future, if we keep the malloced pointer and count inside this struct/ref instead of deferring to NSData, we may be able to do this more efficiently.
                self.count = resultCount
            }
            
            let shift = resultCount - currentCount
            let start = subrange.lowerBound
            
            self.withUnsafeMutableBytes { (bytes : UnsafeMutablePointer<UInt8>) -> Void in
                if shift != 0 {
                    let destination = bytes + start + replacementCount
                    let source = bytes + start + subrangeCount
                    memmove(destination, source, currentCount - start - subrangeCount)
                }
                
                if replacementCount != 0 {
                    let buf = UnsafeMutableBufferPointer(start: bytes + start, count: replacementCount)
                    var (it,idx) = newElements._copyContents(initializing: buf)
                    precondition(it.next() == nil && idx == buf.endIndex, "newElements iterator returned different count to newElements.count")
                }
            }
    }
    
    @inline(__always)
    public mutating func replaceSubrange(_ subrange: Range<Index>, with bytes: UnsafeRawPointer, count cnt: Int) {
        _validateRange(subrange)
        let nsRange = NSMakeRange(subrange.lowerBound, subrange.upperBound - subrange.lowerBound)
        if !isKnownUniquelyReferenced(&_backing) {
            _backing = _backing.mutableCopy(_sliceRange)
        }
        let currentLength = _backing.length
        _backing.replaceBytes(in: nsRange, with: bytes, length: cnt)
        let resultingLength = currentLength - nsRange.length + cnt
        _sliceRange = _sliceRange.lowerBound..<(_sliceRange.lowerBound + resultingLength)
    }
    
    /// Return a new copy of the data in a specified range.
    ///
    /// - parameter range: The range to copy.
    @inline(__always)
    public func subdata(in range: Range<Index>) -> Data {
        _validateRange(range)
        let length = count
        if count == 0 {
            return Data()
        }
        return _backing.subdata(in: range)
    }
    
    // MARK: -
    //
    
    /// Returns a Base-64 encoded string.
    ///
    /// - parameter options: The options to use for the encoding. Default value is `[]`.
    /// - returns: The Base-64 encoded string.
    public func base64EncodedString(options: Data.Base64EncodingOptions = []) -> String {
        return _backing.withInteriorPointerReference(_sliceRange) {
            return $0.base64EncodedString(options: options)
        }
    }
    
    /// Returns a Base-64 encoded `Data`.
    ///
    /// - parameter options: The options to use for the encoding. Default value is `[]`.
    /// - returns: The Base-64 encoded data.
    public func base64EncodedData(options: Data.Base64EncodingOptions = []) -> Data {
        return _backing.withInteriorPointerReference(_sliceRange) {
            return $0.base64EncodedData(options: options)
        }
    }
    
    // MARK: -
    //
    
    /// The hash value for the data.
    public var hashValue: Int {
        return _backing.hashValue
    }
    
    @inline(__always)
    public func advanced(by amount: Int) -> Data {
        _validateIndex(startIndex + amount)
        let length = count - amount
        precondition(length > 0)
        return withUnsafeBytes { (ptr: UnsafePointer<UInt8>) -> Data in
            return Data(bytes: ptr.advanced(by: amount), count: length)
        }
    }
    
    // MARK: -
    
    // MARK: -
    // MARK: Index and Subscript
    
    /// Sets or returns the byte at the specified index.
    public subscript(index: Index) -> UInt8 {
        @inline(__always)
        get {
            _validateIndex(index)
            return _backing.bytes!.advanced(by: index).assumingMemoryBound(to: UInt8.self).pointee
        }
        @inline(__always)
        set {
            _validateIndex(index)
            if !isKnownUniquelyReferenced(&_backing) {
                _backing = _backing.mutableCopy(_sliceRange)
            }
            _backing.set(index, to: newValue)
        }
    }
    
    public subscript(bounds: Range<Index>) -> Data {
        @inline(__always)
        get {
            _validateRange(bounds)
            return Data(backing: _backing, range: bounds)
        }
        @inline(__always)
        set {
            replaceSubrange(bounds, with: newValue)
        }
    }
    
    public subscript<R: RangeExpression>(_ rangeExpression: R) -> Data
        where R.Bound: FixedWidthInteger, R.Bound.Stride : SignedInteger {
        @inline(__always)
        get {
            let lower = R.Bound(_sliceRange.lowerBound)
            let upper = R.Bound(_sliceRange.upperBound)
            let range = rangeExpression.relative(to: lower..<upper)
            let start: Int = numericCast(range.lowerBound)
            let end: Int = numericCast(range.upperBound)
            let r: Range<Int> = start..<end
            _validateRange(r)
            return Data(backing: _backing, range: r)
        }
        @inline(__always)
        set {
            let lower = R.Bound(_sliceRange.lowerBound)
            let upper = R.Bound(_sliceRange.upperBound)
            let range = rangeExpression.relative(to: lower..<upper)
            let start: Int = numericCast(range.lowerBound)
            let end: Int = numericCast(range.upperBound)
            let r: Range<Int> = start..<end
            _validateRange(r)
            replaceSubrange(r, with: newValue)
        }
        
    }
    
    /// The start `Index` in the data.
    public var startIndex: Index {
        @inline(__always)
        get {
            return _sliceRange.lowerBound
        }
    }
    
    /// The end `Index` into the data.
    ///
    /// This is the "one-past-the-end" position, and will always be equal to the `count`.
    public var endIndex: Index {
        @inline(__always)
        get {
            return _sliceRange.upperBound
        }
    }
    
    @inline(__always)
    public func index(before i: Index) -> Index {
        return i - 1
    }
    
    @inline(__always)
    public func index(after i: Index) -> Index {
        return i + 1
    }
    
    public var indices: CountableRange<Int> {
        @inline(__always)
        get {
            return startIndex..<endIndex
        }
    }
    
    public func _copyContents(initializing buffer: UnsafeMutableBufferPointer<UInt8>) -> (Iterator, UnsafeMutableBufferPointer<UInt8>.Index) {
        guard !isEmpty else { return (makeIterator(), buffer.startIndex) }
        guard let p = buffer.baseAddress else {
            preconditionFailure("Attempt to copy contents into nil buffer pointer")
        }
        let cnt = count
        precondition(cnt <= buffer.count, "Insufficient space allocated to copy Data contents")
        
        withUnsafeBytes { p.initialize(from: $0, count: cnt) }
        
        return (Iterator(endOf: self), buffer.index(buffer.startIndex, offsetBy: cnt))
    }
    
    /// An iterator over the contents of the data.
    ///
    /// The iterator will increment byte-by-byte.
    public func makeIterator() -> Data.Iterator {
        return Iterator(self)
    }
    
    public struct Iterator : IteratorProtocol {
        private let _data: Data
        private var _buffer: (
        UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8,
        UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8,
        UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8,
        UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8)
        private var _idx: Data.Index
        private let _endIdx: Data.Index
        
        fileprivate init(_ data: Data) {
            _data = data
            _buffer = (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
            _idx = data.startIndex
            _endIdx = data.endIndex
        }
        
        fileprivate init(endOf data: Data) {
            self._data = data
            _buffer = (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
            _idx = data.endIndex
            _endIdx = data.endIndex
        }
        
        public mutating func next() -> UInt8? {
            guard _idx < _endIdx else { return nil }
            defer { _idx += 1 }
            let bufferSize = MemoryLayout.size(ofValue: _buffer)
            return withUnsafeMutablePointer(to: &_buffer) { ptr_ in
                let ptr = UnsafeMutableRawPointer(ptr_).assumingMemoryBound(to: UInt8.self)
                let bufferIdx = (_idx - _data.startIndex) % bufferSize
                if bufferIdx == 0 {
                    // populate the buffer
                    _data.copyBytes(to: ptr, from: _idx..<(_endIdx - _idx > bufferSize ? _idx + bufferSize : _endIdx))
                }
                return ptr[bufferIdx]
            }
        }
    }
    
    // MARK: -
    //
    
    @available(*, unavailable, renamed: "count")
    public var length: Int {
        get { fatalError() }
        set { fatalError() }
    }
    
    @available(*, unavailable, message: "use withUnsafeBytes instead")
    public var bytes: UnsafeRawPointer { fatalError() }
    
    @available(*, unavailable, message: "use withUnsafeMutableBytes instead")
    public var mutableBytes: UnsafeMutableRawPointer { fatalError() }
    
    /// Returns `true` if the two `Data` arguments are equal.
    public static func ==(d1 : Data, d2 : Data) -> Bool {
        let backing1 = d1._backing
        let backing2 = d2._backing
        if backing1 === backing2 {
            if d1._sliceRange == d2._sliceRange {
                return true
            }
        }
        let length1 = d1.count
        if length1 != d2.count {
            return false
        }
        if backing1.bytes == backing2.bytes {
            if d1._sliceRange == d2._sliceRange {
                return true
            }
        }
        if length1 > 0 {
            return d1.withUnsafeBytes { (b1) in
                return d2.withUnsafeBytes { (b2) in
                    return memcmp(b1, b2, length1) == 0
                }
            }
        }
        return true
    }
}


extension Data : CustomStringConvertible, CustomDebugStringConvertible, CustomReflectable {
    /// A human-readable description for the data.
    public var description: String {
        return "\(self.count) bytes"
    }
    
    /// A human-readable debug description for the data.
    public var debugDescription: String {
        return self.description
    }
    
    public var customMirror: Mirror {
        let nBytes = self.count
        var children: [(label: String?, value: Any)] = []
        children.append((label: "count", value: nBytes))
        
        self.withUnsafeBytes { (bytes : UnsafePointer<UInt8>) in
            children.append((label: "pointer", value: bytes))
        }
        
        // Minimal size data is output as an array
        if nBytes < 64 {
            children.append((label: "bytes", value: Array(self[0..<nBytes])))
        }
        
        let m = Mirror(self, children:children, displayStyle: Mirror.DisplayStyle.struct)
        return m
    }
}

extension Data {
    @available(*, unavailable, renamed: "copyBytes(to:count:)")
    public func getBytes<UnsafeMutablePointerVoid: _Pointer>(_ buffer: UnsafeMutablePointerVoid, length: Int) { }
    
    @available(*, unavailable, renamed: "copyBytes(to:from:)")
    public func getBytes<UnsafeMutablePointerVoid: _Pointer>(_ buffer: UnsafeMutablePointerVoid, range: NSRange) { }
}

/// Provides bridging functionality for struct Data to class NSData and vice-versa.

#if DEPLOYMENT_RUNTIME_SWIFT
internal typealias DataBridgeType = _ObjectTypeBridgeable
#else
internal typealias DataBridgeType = _ObjectiveCBridgeable
#endif

extension Data : DataBridgeType {
    @_semantics("convertToObjectiveC")
    public func _bridgeToObjectiveC() -> NSData {
        return _backing.bridgedReference(_sliceRange)
    }
    
    public static func _forceBridgeFromObjectiveC(_ input: NSData, result: inout Data?) {
        // We must copy the input because it might be mutable; just like storing a value type in ObjC
        result = Data(referencing: input)
    }
    
    public static func _conditionallyBridgeFromObjectiveC(_ input: NSData, result: inout Data?) -> Bool {
        // We must copy the input because it might be mutable; just like storing a value type in ObjC
        result = Data(referencing: input)
        return true
    }
    
    public static func _unconditionallyBridgeFromObjectiveC(_ source: NSData?) -> Data {
        guard let src = source else { return Data() }
        return Data(referencing: src)
    }
}

extension NSData : _HasCustomAnyHashableRepresentation {
    // Must be @nonobjc to avoid infinite recursion during bridging.
    @nonobjc
    public func _toCustomAnyHashable() -> AnyHashable? {
        return AnyHashable(Data._unconditionallyBridgeFromObjectiveC(self))
    }
}

extension Data : Codable {
    public init(from decoder: Decoder) throws {
        // FIXME: This is a hook for bypassing a conditional conformance implementation to apply a strategy (see SR-5206). Remove this once conditional conformance is available.
        do {
            let singleValueContainer = try decoder.singleValueContainer()
            if let decoder = singleValueContainer as? _JSONDecoder {
                switch decoder.options.dataDecodingStrategy {
                case .deferredToData:
                    break /* fall back to default implementation below; this would recurse */

                default:
                    // _JSONDecoder has a hook for Datas; this won't recurse since we're not going to defer back to Data in _JSONDecoder.
                    self = try singleValueContainer.decode(Data.self)
                    return
                }
            }
        } catch { /* fall back to default implementation below */ }

        var container = try decoder.unkeyedContainer()
        
        // It's more efficient to pre-allocate the buffer if we can.
        if let count = container.count {
            self = Data(count: count)
            
            // Loop only until count, not while !container.isAtEnd, in case count is underestimated (this is misbehavior) and we haven't allocated enough space.
            // We don't want to write past the end of what we allocated.
            for i in 0 ..< count {
                let byte = try container.decode(UInt8.self)
                self[i] = byte
            }
        } else {
            self = Data()
        }
        
        while !container.isAtEnd {
            var byte = try container.decode(UInt8.self)
            self.append(&byte, count: 1)
        }
    }
    
    public func encode(to encoder: Encoder) throws {
        // FIXME: This is a hook for bypassing a conditional conformance implementation to apply a strategy (see SR-5206). Remove this once conditional conformance is available.
        // We are allowed to request this container as long as we don't encode anything through it when we need the unkeyed container below.
        var singleValueContainer = encoder.singleValueContainer()
        if let encoder = singleValueContainer as? _JSONEncoder {
            switch encoder.options.dataEncodingStrategy {
            case .deferredToData:
                break /* fall back to default implementation below; this would recurse */

            default:
                // _JSONEncoder has a hook for Datas; this won't recurse since we're not going to defer back to Data in _JSONEncoder.
                try singleValueContainer.encode(self)
                return
            }
        }

        var container = encoder.unkeyedContainer()
        
        // Since enumerateBytes does not rethrow, we need to catch the error, stow it away, and rethrow if we stopped.
        var caughtError: Error? = nil
        self.enumerateBytes { (buffer: UnsafeBufferPointer<UInt8>, byteIndex: Data.Index, stop: inout Bool) in
            do {
                try container.encode(contentsOf: buffer)
            } catch {
                caughtError = error
                stop = true
            }
        }
        
        if let error = caughtError {
            throw error
        }
    }
}

