String+Extensions.swift 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. /*
  2. * Copyright 2023, gRPC Authors All rights reserved.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. //===----------------------------------------------------------------------===//
  17. //
  18. // This source file is part of the SwiftNIO open source project
  19. //
  20. // Copyright (c) 2017-2023 Apple Inc. and the SwiftNIO project authors
  21. // Licensed under Apache License v2.0
  22. //
  23. // See LICENSE.txt for license information
  24. // See CONTRIBUTORS.txt for the list of SwiftNIO project authors
  25. //
  26. // SPDX-License-Identifier: Apache-2.0
  27. //
  28. //===----------------------------------------------------------------------===//
  29. extension UInt8 {
  30. @inlinable
  31. var isASCII: Bool {
  32. return self <= 127
  33. }
  34. }
  35. extension String.UTF8View {
  36. /// Compares two UTF8 strings as case insensitive ASCII bytes.
  37. ///
  38. /// - Parameter bytes: The string constant in the form of a collection of `UInt8`
  39. /// - Returns: Whether the collection contains **EXACTLY** this array or no, but by ignoring case.
  40. @inlinable
  41. func compareCaseInsensitiveASCIIBytes(to other: String.UTF8View) -> Bool {
  42. // fast path: we can get the underlying bytes of both
  43. let maybeMaybeResult = self.withContiguousStorageIfAvailable { lhsBuffer -> Bool? in
  44. other.withContiguousStorageIfAvailable { rhsBuffer in
  45. if lhsBuffer.count != rhsBuffer.count {
  46. return false
  47. }
  48. for idx in 0 ..< lhsBuffer.count {
  49. // let's hope this gets vectorised ;)
  50. if lhsBuffer[idx] & 0xdf != rhsBuffer[idx] & 0xdf && lhsBuffer[idx].isASCII {
  51. return false
  52. }
  53. }
  54. return true
  55. }
  56. }
  57. if let maybeResult = maybeMaybeResult, let result = maybeResult {
  58. return result
  59. } else {
  60. return self._compareCaseInsensitiveASCIIBytesSlowPath(to: other)
  61. }
  62. }
  63. @inlinable
  64. @inline(never)
  65. func _compareCaseInsensitiveASCIIBytesSlowPath(to other: String.UTF8View) -> Bool {
  66. return self.elementsEqual(other, by: { return (($0 & 0xdf) == ($1 & 0xdf) && $0.isASCII) })
  67. }
  68. }
  69. extension String {
  70. @inlinable
  71. func isEqualCaseInsensitiveASCIIBytes(to: String) -> Bool {
  72. return self.utf8.compareCaseInsensitiveASCIIBytes(to: to.utf8)
  73. }
  74. }