File: OSLogIntegerTypes.swift

package info (click to toggle)
swiftlang 6.1.3-4
  • links: PTS, VCS
  • area: main
  • in suites: forky
  • size: 2,791,644 kB
  • sloc: cpp: 9,901,738; ansic: 2,201,433; asm: 1,091,827; python: 308,252; objc: 82,166; f90: 80,126; lisp: 38,358; pascal: 25,559; sh: 20,429; ml: 5,058; perl: 4,745; makefile: 4,484; awk: 3,535; javascript: 3,018; xml: 918; fortran: 664; cs: 573; ruby: 396
file content (262 lines) | stat: -rw-r--r-- 9,996 bytes parent folder | download | duplicates (3)
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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
//===----------------- OSLogIntegerTypes.swift ----------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2020 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
//
//===----------------------------------------------------------------------===//

// This file defines extensions for interpolating integer expressions into an
// OSLogMessage. It defines `appendInterpolation` functions for standard integer
// types. It also defines extensions for serializing integer types into the
// argument buffer passed to os_log ABIs.
//
// The `appendInterpolation` functions defined in this file accept formatting,
// privacy and alignment options along with the interpolated expression as
// shown below:
//
//  1.  "\(x, format: .hex, privacy: .private, align: .right\)"
//  2.  "\(x, format: .hex(minDigits: 10), align: .right(columns: 10)\)"

import ObjectiveC

extension OSLogInterpolation {

  /// Defines interpolation for expressions of type Int.
  ///
  /// Do not call this function directly. It will be called automatically when interpolating
  /// a value of type `Int` in the string interpolations passed to the log APIs.
  ///
  /// - Parameters:
  ///   - number: The interpolated expression of type Int, which is autoclosured.
  ///   - format: A formatting option available for integer types, defined by the
  ///     type: `OSLogIntegerFormatting`. The default is `.decimal`.
  ///   - align: Left or right alignment with the minimum number of columns as
  ///     defined by the type `OSLogStringAlignment`.
  ///   - privacy: A privacy qualifier which is either private or public.
  ///     It is auto-inferred by default.
  @_semantics("constant_evaluable")
  @inlinable
  @_optimize(none)
  @_semantics("oslog.requires_constant_arguments")
  public mutating func appendInterpolation(
    _ number: @autoclosure @escaping () -> Int,
    format: OSLogIntegerFormatting = .decimal,
    align: OSLogStringAlignment = .none,
    privacy: OSLogPrivacy = .auto
  ) {
    appendInteger(number, format: format, align: align, privacy: privacy)
  }

  // Define appendInterpolation overloads for fixed-size integers.

  @_semantics("constant_evaluable")
  @inlinable
  @_optimize(none)
  @_semantics("oslog.requires_constant_arguments")
  public mutating func appendInterpolation(
    _ number: @autoclosure @escaping () -> Int32,
    format: OSLogIntegerFormatting = .decimal,
    align: OSLogStringAlignment = .none,
    privacy: OSLogPrivacy = .auto
  ) {
    appendInteger(number, format: format, align: align, privacy: privacy)
  }

  /// Defines interpolation for expressions of type UInt.
  ///
  /// Do not call this function directly. It will be called automatically when interpolating
  /// a value of type `Int` in the string interpolations passed to the log APIs.
  ///
  /// - Parameters:
  ///   - number: The interpolated expression of type UInt, which is autoclosured.
  ///   - format: A formatting option available for integer types, defined by the
  ///     type `OSLogIntegerFormatting`.
  ///   - align: Left or right alignment with the minimum number of columns as
  ///     defined by the type `OSLogStringAlignment`.
  ///   - privacy: A privacy qualifier which is either private or public.
  ///     It is auto-inferred by default.
  @_semantics("constant_evaluable")
  @inlinable
  @_optimize(none)
  @_semantics("oslog.requires_constant_arguments")
  public mutating func appendInterpolation(
    _ number: @autoclosure @escaping () -> UInt,
    format: OSLogIntegerFormatting = .decimal,
    align: OSLogStringAlignment = .none,
    privacy: OSLogPrivacy = .auto
  ) {
    appendInteger(number, format: format, align: align, privacy: privacy)
  }

  /// Given an integer, create and append a format specifier for the integer to the
  /// format string property. Also, append the integer along with necessary headers
  /// to the OSLogArguments property.
  @_semantics("constant_evaluable")
  @inlinable
  @_optimize(none)
  internal mutating func appendInteger<T>(
    _ number: @escaping () -> T,
    format: OSLogIntegerFormatting,
    align: OSLogStringAlignment,
    privacy: OSLogPrivacy
  ) where T: FixedWidthInteger {
    guard argumentCount < maxOSLogArgumentCount else { return }
    formatString +=
      format.formatSpecifier(for: T.self, align: align, privacy: privacy)

    // If minimum column width is specified, append this value first. Note that
    // the format specifier would use a '*' for width e.g. %*d.
    if let minColumns = align.minimumColumnWidth {
      appendAlignmentArgument(minColumns)
    }

    // If the privacy has a mask, append the mask argument, which is a constant payload.
    // Note that this should come after the width but before the precision.
    if privacy.hasMask {
      appendMaskArgument(privacy)
    }

    // If minimum number of digits (precision) is specified, append the
    // precision before the argument. Note that the format specifier would use
    // a '*' for precision: %.*d.
    if let minDigits = format.minDigits {
      appendPrecisionArgument(minDigits)
    }

    // Append the integer.
    addIntHeaders(privacy, sizeForEncoding(T.self))
    arguments.append(number)
    argumentCount += 1
  }

  /// Update preamble and append argument headers based on the parameters of
  /// the interpolation.
  @_semantics("constant_evaluable")
  @inlinable
  @_optimize(none)
  internal mutating func addIntHeaders(
    _ privacy: OSLogPrivacy,
    _ byteCount: Int
  ) {
    // Append argument header.
    let argumentHeader = getArgumentHeader(privacy: privacy, type: .scalar)
    arguments.append(argumentHeader)

    // Append number of bytes needed to serialize the argument.
    arguments.append(UInt8(byteCount))

    // Increment total byte size by the number of bytes needed for this
    // argument, which is the sum of the byte size of the argument and
    // two bytes needed for the headers.
    totalBytesForSerializingArguments += byteCount + 2

    preamble = getUpdatedPreamble(privacy: privacy, isScalar: true)
  }

  // Append argument indicating precision or width of a format specifier to the buffer.
  // These specify the value of the '*' in a format specifier like: %*.*ld.
  @_semantics("constant_evaluable")
  @inlinable
  @_optimize(none)
  internal mutating func appendPrecisionArgument(_ count: @escaping () -> Int) {
    appendPrecisionAlignCount(
      count,
      getArgumentHeader(privacy: .auto, type: .count))
  }

  @_semantics("constant_evaluable")
  @inlinable
  @_optimize(none)
  internal mutating func appendAlignmentArgument(_ count: @escaping () -> Int) {
    appendPrecisionAlignCount(
      count,
      getArgumentHeader(privacy: .auto, type: .scalar))
  }

  // This is made transparent to minimize compile time overheads. The function's
  // implementation also uses literals whenever possible for the same reason.
  @_transparent
  @inlinable
  internal mutating func appendPrecisionAlignCount(
    _ count: @escaping () -> Int,
    _ argumentHeader: UInt8
  ) {
    arguments.append(argumentHeader)
    // Append number of bytes needed to serialize the argument.
    arguments.append(4)
    // Increment total byte size by the number of bytes needed for this
    // argument, which is the sum of the byte size of the argument and
    // two bytes needed for the headers.
    totalBytesForSerializingArguments += 6
    // The count is expected to be a CInt.
    arguments.append({ CInt(count()) })
    argumentCount += 1
    // Note that we don't have to update the preamble here.
  }

  @_semantics("constant_evaluable")
  @inlinable
  @_optimize(none)
  internal mutating func appendMaskArgument(_ privacy: OSLogPrivacy) {
    arguments.append(getArgumentHeader(privacy: .auto, type: .mask))
    // Append number of bytes needed to serialize the mask. Mask is 64 bit payload.
    arguments.append(8)
    // Increment total byte size by the number of bytes needed for this
    // argument, which is the sum of the byte size of the argument and
    // two bytes needed for the headers.
    totalBytesForSerializingArguments += 10
    // Append the mask value. This is a compile-time constant.
    let maskValue = privacy.maskValue
    arguments.append({ maskValue })
    argumentCount += 1
    // Note that we don't have to update the preamble here.
  }
}

extension OSLogArguments {
  /// Append an (autoclosured) interpolated expression of integer type, passed to
  /// `OSLogMessage.appendInterpolation`, to the array of closures tracked
  /// by this instance.
  @_semantics("constant_evaluable")
  @inlinable
  @_optimize(none)
  internal mutating func append<T>(
    _ value: @escaping () -> T
  ) where T: FixedWidthInteger {
    argumentClosures.append({ (position, _, _) in
      serialize(value(), at: &position)
    })
  }
}

/// Return the number of bytes needed for serializing an integer argument as
/// specified by os_log. This function must be constant evaluable. Note that
/// it is marked transparent instead of @inline(__always) as it is used in
/// optimize(none) functions.
@_transparent
@_alwaysEmitIntoClient
internal func sizeForEncoding<T>(
  _ type: T.Type
) -> Int where T : FixedWidthInteger  {
  return type.bitWidth &>> logBitsPerByte
}

/// Serialize an integer at the buffer location that `position` points to and
/// increment `position` by the byte size of `T`.
@_alwaysEmitIntoClient
@inline(__always)
internal func serialize<T>(
  _ value: T,
  at bufferPosition: inout ByteBufferPointer
) where T : FixedWidthInteger {
  let byteCount = sizeForEncoding(T.self)
  let dest =
    UnsafeMutableRawBufferPointer(start: bufferPosition, count: byteCount)
  withUnsafeBytes(of: value) { dest.copyMemory(from: $0) }
  bufferPosition += byteCount
}