-
Notifications
You must be signed in to change notification settings - Fork 10.5k
/
Copy pathOSLogFloatingPointTypes.swift
168 lines (152 loc) · 6.32 KB
/
OSLogFloatingPointTypes.swift
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
//===----------------- OSLogFloatingPointTypes.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 floating-point expressions
// into an OSLogMessage. It defines `appendInterpolation` functions for standard
// floating-point types. It also defines extensions for serializing floating-
// point types into the argument buffer passed to os_log ABIs.
//
// The `appendInterpolation` functions defined in this file accept privacy
// options along with the interpolated expression as shown below:
//
// "\(x, format: .fixed(precision: 10), privacy: .private\)"
import ObjectiveC
extension OSLogInterpolation {
/// Defines interpolation for expressions of type Float.
///
/// Do not call this function directly. It will be called automatically when interpolating
/// a value of type `Float` in the string interpolations passed to the log APIs.
///
/// - Parameters:
/// - number: The interpolated expression of type Float, which is autoclosured.
/// - format: A formatting option available for float types, defined by the
/// type`OSLogFloatFormatting`. The default is `.fixed`.
/// - 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 () -> Float,
format: OSLogFloatFormatting = .fixed,
align: OSLogStringAlignment = .none,
privacy: OSLogPrivacy = .auto
) {
appendInterpolation(
Double(number()),
format: format,
align: align,
privacy: privacy)
}
/// Define interpolation for expressions of type Double.
///
/// Do not call this function directly. It will be called automatically when interpolating
/// a value of type `Double` in the string interpolations passed to the log APIs.
///
/// - Parameters:
/// - number: The interpolated expression of type Double, which is autoclosured.
/// - format: A formatting option available for float types, defined by the
/// type`OSLogFloatFormatting`. The default is `.fixed`.
/// - 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 () -> Double,
format: OSLogFloatFormatting = .fixed,
align: OSLogStringAlignment = .none,
privacy: OSLogPrivacy = .auto
) {
guard argumentCount < maxOSLogArgumentCount else { return }
formatString +=
format.formatSpecifier(for: Double.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. %*f.
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: %.*f.
if let precision = format.precision {
appendPrecisionArgument(precision)
}
// Append the double.
addDoubleHeaders(privacy)
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 addDoubleHeaders(_ privacy: OSLogPrivacy) {
// Append argument header.
let argumentHeader = getArgumentHeader(privacy: privacy, type: .scalar)
arguments.append(argumentHeader)
// Append number of bytes needed to serialize the argument.
let byteCount = doubleSizeInBytes()
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)
}
}
extension OSLogArguments {
/// Append an (autoclosured) interpolated expression of Double type, passed to
/// `OSLogMessage.appendInterpolation`, to the array of closures tracked
/// by this instance.
@_semantics("constant_evaluable")
@inlinable
@_optimize(none)
internal mutating func append(_ value: @escaping () -> Double) {
argumentClosures.append({ (position, _, _) in
serialize(value(), at: &position)
})
}
}
/// Return the number of bytes needed for serializing a double argument as
/// specified by os_log. Note that this is marked transparent instead of
/// @inline(__always) as it is used in optimize(none) functions.
@_transparent
@_alwaysEmitIntoClient
internal func doubleSizeInBytes() -> Int {
return 8
}
/// Serialize a double at the buffer location that `position` points to and
/// increment `position` by the byte size of the double.
@_alwaysEmitIntoClient
@inline(__always)
internal func serialize(
_ value: Double,
at bufferPosition: inout ByteBufferPointer
) {
let byteCount = doubleSizeInBytes()
let dest =
UnsafeMutableRawBufferPointer(start: bufferPosition, count: byteCount)
withUnsafeBytes(of: value) { dest.copyMemory(from: $0) }
bufferPosition += byteCount
}