File: _HashNode%2BStructural%20mapValues.swift

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (90 lines) | stat: -rw-r--r-- 2,747 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift Collections open source project
//
// Copyright (c) 2022 - 2024 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
//
//===----------------------------------------------------------------------===//

#if !COLLECTIONS_SINGLE_MODULE
import InternalCollectionsUtilities
#endif

extension _HashNode {
  @inlinable
  internal func mapValues<T>(
    _ transform: (Element) throws -> T
  ) rethrows -> _HashNode<Key, T> {
    let c = self.count
    return try read { source in
      var result: _HashNode<Key, T>
      if isCollisionNode {
        result = _HashNode<Key, T>.allocateCollision(
          count: c, source.collisionHash,
          initializingWith: { _ in }
        ).node
      } else {
        result = _HashNode<Key, T>.allocate(
          itemMap: source.itemMap,
          childMap: source.childMap,
          count: c,
          initializingWith: { _, _ in }
        ).node
      }
      try result.update { target in
        let sourceItems = source.reverseItems
        let targetItems = target.reverseItems
        assert(sourceItems.count == targetItems.count)

        let sourceChildren = source.children
        let targetChildren = target.children
        assert(sourceChildren.count == targetChildren.count)

        var i = 0
        var j = 0

        var success = false

        defer {
          if !success {
            targetItems.prefix(i).deinitialize()
            targetChildren.prefix(j).deinitialize()
            target.clear()
          }
        }

        while i < targetItems.count {
          let key = sourceItems[i].key
          let value = try transform(sourceItems[i])
          targetItems.initializeElement(at: i, to: (key, value))
          i += 1
        }
        while j < targetChildren.count {
          let child = try sourceChildren[j].mapValues(transform)
          targetChildren.initializeElement(at: j, to: child)
          j += 1
        }
        success = true
      }
      result._invariantCheck()
      return result
    }
  }

  @inlinable
  internal func mapValuesToVoid(
    copy: Bool = false, extraBytes: Int = 0
  ) -> _HashNode<Key, Void> {
    if Value.self == Void.self {
      let node = unsafeBitCast(self, to: _HashNode<Key, Void>.self)
      guard copy || !node.hasFreeSpace(extraBytes) else { return node }
      return node.copy(withFreeSpace: extraBytes)
    }
    let node = mapValues { _ in () }
    guard !node.hasFreeSpace(extraBytes) else { return node }
    return node.copy(withFreeSpace: extraBytes)
  }
}