Skip to content

Commit 3c7f6d8

Browse files
committed
[stdlib/private][OSLog] Add basic support for interpolating floating-point
types without formatting options, add an auto-inferred privacy mode and make it the default privacy mode, add support for aligning string arguments.
1 parent 02f0170 commit 3c7f6d8

14 files changed

+545
-116
lines changed

stdlib/private/OSLog/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ add_swift_target_library(swiftOSLogPrototype
99
OSLogIntegerTypes.swift
1010
OSLogStringTypes.swift
1111
OSLogNSObjectType.swift
12+
OSLogFloatingPointTypes.swift
1213

1314
SWIFT_MODULE_DEPENDS_IOS Darwin os ObjectiveC
1415
SWIFT_MODULE_DEPENDS_OSX Darwin os ObjectiveC

stdlib/private/OSLog/OSLog.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22
//
33
// This source file is part of the Swift.org open source project
44
//
5-
// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
5+
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
66
// Licensed under Apache License v2.0 with Runtime Library Exception
77
//
88
// See https://swift.org/LICENSE.txt for license information
99
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
1010
//
11-
//===-----------------------------------------------------------------------===//
11+
//===----------------------------------------------------------------------===//
1212

1313
// This file contains the new swift APIs for OS log that accept string
1414
// interpolations. This is a prototype meant for experimentation and testing.
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
//===----------------- OSLogFloatingPointTypes.swift ----------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
// This file defines extensions for interpolating floating-point expressions
14+
// into an OSLogMesage. It defines `appendInterpolation` functions for standard
15+
// floating-point types. It also defines extensions for serializing floating-
16+
// point types into the argument buffer passed to os_log ABIs.
17+
//
18+
// The `appendInterpolation` functions defined in this file accept privacy
19+
// options along with the interpolated expression as shown below:
20+
// TODO: support floating-point formatting options.
21+
//
22+
// "\(x, privacy: .private\)"
23+
24+
extension OSLogInterpolation {
25+
26+
/// Define interpolation for expressions of type Float.
27+
/// - Parameters:
28+
/// - number: the interpolated expression of type Float, which is autoclosured.
29+
/// - privacy: a privacy qualifier which is either private or public.
30+
/// It is auto-inferred by default.
31+
@_semantics("constant_evaluable")
32+
@inlinable
33+
@_optimize(none)
34+
public mutating func appendInterpolation(
35+
_ number: @autoclosure @escaping () -> Float,
36+
privacy: OSLogPrivacy = .auto
37+
) {
38+
appendInterpolation(Double(number()), privacy: privacy)
39+
}
40+
41+
/// Define interpolation for expressions of type Double.
42+
/// - Parameters:
43+
/// - number: the interpolated expression of type Double, which is autoclosured.
44+
/// - privacy: a privacy qualifier which is either private or public.
45+
/// It is auto-inferred by default.
46+
@_semantics("constant_evaluable")
47+
@inlinable
48+
@_optimize(none)
49+
public mutating func appendInterpolation(
50+
_ number: @autoclosure @escaping () -> Double,
51+
privacy: OSLogPrivacy = .auto
52+
) {
53+
guard argumentCount < maxOSLogArgumentCount else { return }
54+
55+
formatString += getDoubleFormatSpecifier(privacy: privacy)
56+
addDoubleHeaders(privacy)
57+
58+
arguments.append(number)
59+
argumentCount += 1
60+
}
61+
62+
/// Update preamble and append argument headers based on the parameters of
63+
/// the interpolation.
64+
@_semantics("constant_evaluable")
65+
@inlinable
66+
@_optimize(none)
67+
internal mutating func addDoubleHeaders(_ privacy: OSLogPrivacy) {
68+
// Append argument header.
69+
let argumentHeader = getArgumentHeader(privacy: privacy, type: .scalar)
70+
arguments.append(argumentHeader)
71+
72+
// Append number of bytes needed to serialize the argument.
73+
let byteCount = doubleSizeInBytes()
74+
arguments.append(UInt8(byteCount))
75+
76+
// Increment total byte size by the number of bytes needed for this
77+
// argument, which is the sum of the byte size of the argument and
78+
// two bytes needed for the headers.
79+
totalBytesForSerializingArguments += byteCount + 2
80+
81+
preamble = getUpdatedPreamble(privacy: privacy, isScalar: true)
82+
}
83+
84+
/// Construct an os_log format specifier from the given parameters.
85+
/// This function must be constant evaluable and all its arguments
86+
/// must be known at compile time.
87+
@inlinable
88+
@_semantics("constant_evaluable")
89+
@_effects(readonly)
90+
@_optimize(none)
91+
internal func getDoubleFormatSpecifier(privacy: OSLogPrivacy) -> String {
92+
// TODO: this will become more sophisticated when floating-point formatting
93+
// options are supported.
94+
var specifier = "%"
95+
switch privacy {
96+
case .private:
97+
specifier += "{private}"
98+
case .public:
99+
specifier += "{public}"
100+
default:
101+
break
102+
}
103+
specifier += "f"
104+
return specifier
105+
}
106+
}
107+
108+
extension OSLogArguments {
109+
/// Append an (autoclosured) interpolated expression of Double type, passed to
110+
/// `OSLogMessage.appendInterpolation`, to the array of closures tracked
111+
/// by this instance.
112+
@_semantics("constant_evaluable")
113+
@inlinable
114+
@_optimize(none)
115+
internal mutating func append(_ value: @escaping () -> Double) {
116+
argumentClosures.append({ (position, _) in
117+
serialize(value(), at: &position)
118+
})
119+
}
120+
}
121+
122+
/// Return the number of bytes needed for serializing a double argument as
123+
/// specified by os_log. Note that this is marked transparent instead of
124+
/// @inline(__always) as it is used in optimize(none) functions.
125+
@_transparent
126+
@usableFromInline
127+
internal func doubleSizeInBytes() -> Int {
128+
return 8
129+
}
130+
131+
/// Serialize a double at the buffer location that `position` points to and
132+
/// increment `position` by the byte size of the double.
133+
@inlinable
134+
@_alwaysEmitIntoClient
135+
@inline(__always)
136+
internal func serialize(
137+
_ value: Double,
138+
at bufferPosition: inout ByteBufferPointer
139+
) {
140+
let byteCount = doubleSizeInBytes()
141+
let dest =
142+
UnsafeMutableRawBufferPointer(start: bufferPosition, count: byteCount)
143+
withUnsafeBytes(of: value) { dest.copyMemory(from: $0) }
144+
bufferPosition += byteCount
145+
}

stdlib/private/OSLog/OSLogIntegerFormatting.swift

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,18 @@
1+
//===----------------- OSLogIntegerFormatting.swift -----------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
// This file defines types and functions for specifying formatting of
14+
// integer-valued interpolations passed to the os log APIs.
15+
116
@frozen
217
public struct OSLogIntegerFormatting: Equatable {
318
/// The base to use for the string representation. `radix` must be at least 2
@@ -261,11 +276,8 @@ extension OSLogIntegerFormatting {
261276
// IEEE: `-` The result of the conversion shall be left-justified within
262277
// the field. The conversion is right-justified if this flag is not
263278
// specified.
264-
switch align.anchor {
265-
case OSLogCollectionBound.start:
266-
specification += "-"
267-
default:
268-
break
279+
if case .start = align.anchor {
280+
specification += "-"
269281
}
270282

271283
// 2. Minimumn field width

stdlib/private/OSLog/OSLogIntegerTypes.swift

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,41 +2,45 @@
22
//
33
// This source file is part of the Swift.org open source project
44
//
5-
// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
5+
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
66
// Licensed under Apache License v2.0 with Runtime Library Exception
77
//
88
// See https://swift.org/LICENSE.txt for license information
99
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13-
// This file defines extensions for interpolating integer expressions into a
13+
// This file defines extensions for interpolating integer expressions into an
1414
// OSLogMesage. It defines `appendInterpolation` functions for standard integer
1515
// types. It also defines extensions for serializing integer types into the
1616
// argument buffer passed to os_log ABIs.
1717
//
18-
// The `appendInterpolation` functions defined in this file accept formatting
19-
// and privacy options along with the interpolated expression as shown below:
18+
// The `appendInterpolation` functions defined in this file accept formatting,
19+
// privacy and alignment options along with the interpolated expression as
20+
// shown below:
2021
//
21-
// "\(x, format: .hex, privacy: .private\)"
22+
// 1. "\(x, format: .hex, privacy: .private, align: .right\)"
23+
// 2. "\(x, format: .hex(minDigits: 10), align: .right(columns: 10)\)"
2224

2325
extension OSLogInterpolation {
2426

2527
/// Define interpolation for expressions of type Int.
2628
/// - Parameters:
2729
/// - number: the interpolated expression of type Int, which is autoclosured.
2830
/// - format: a formatting option available for integer types, defined by the
29-
/// enum `OSLogIntegerFormatting`.
31+
/// type`OSLogIntegerFormatting`. The default is .decimal.
32+
/// - align: left or right alignment with the minimum number of columns as
33+
/// defined by the type `OSLogStringAlignment`.
3034
/// - privacy: a privacy qualifier which is either private or public.
31-
/// The default is public.
35+
/// It is auto-inferred by default.
3236
@_semantics("constant_evaluable")
3337
@inlinable
3438
@_optimize(none)
3539
public mutating func appendInterpolation(
3640
_ number: @autoclosure @escaping () -> Int,
3741
format: OSLogIntegerFormatting = .decimal,
3842
align: OSLogStringAlignment = .none,
39-
privacy: OSLogPrivacy = .public
43+
privacy: OSLogPrivacy = .auto
4044
) {
4145
appendInteger(number, format: format, align: align, privacy: privacy)
4246
}
@@ -45,17 +49,19 @@ extension OSLogInterpolation {
4549
/// - Parameters:
4650
/// - number: the interpolated expression of type Int32, which is autoclosured.
4751
/// - format: a formatting option available for integer types, defined by the
48-
/// enum `OSLogIntegerFormatting`.
52+
/// type `OSLogIntegerFormatting`.
53+
/// - align: left or right alignment with the minimum number of columns as
54+
/// defined by the type `OSLogStringAlignment`.
4955
/// - privacy: a privacy qualifier which is either private or public.
50-
/// The default is public.
56+
/// It is auto-inferred by default.
5157
@_semantics("constant_evaluable")
5258
@inlinable
5359
@_optimize(none)
5460
public mutating func appendInterpolation(
5561
_ number: @autoclosure @escaping () -> Int32,
5662
format: OSLogIntegerFormatting = .decimal,
5763
align: OSLogStringAlignment = .none,
58-
privacy: OSLogPrivacy = .public
64+
privacy: OSLogPrivacy = .auto
5965
) {
6066
appendInteger(number, format: format, align: align, privacy: privacy)
6167
}
@@ -64,17 +70,19 @@ extension OSLogInterpolation {
6470
/// - Parameters:
6571
/// - number: the interpolated expression of type UInt, which is autoclosured.
6672
/// - format: a formatting option available for integer types, defined by the
67-
/// enum `OSLogIntegerFormatting`.
73+
/// type `OSLogIntegerFormatting`.
74+
/// - align: left or right alignment with the minimum number of columns as
75+
/// defined by the type `OSLogStringAlignment`.
6876
/// - privacy: a privacy qualifier which is either private or public.
69-
/// The default is public.
77+
/// It is auto-inferred by default.
7078
@_semantics("constant_evaluable")
7179
@inlinable
7280
@_optimize(none)
7381
public mutating func appendInterpolation(
7482
_ number: @autoclosure @escaping () -> UInt,
7583
format: OSLogIntegerFormatting = .decimal,
7684
align: OSLogStringAlignment = .none,
77-
privacy: OSLogPrivacy = .public
85+
privacy: OSLogPrivacy = .auto
7886
) {
7987
appendInteger(number, format: format, align: align, privacy: privacy)
8088
}
@@ -94,9 +102,7 @@ extension OSLogInterpolation {
94102
guard argumentCount < maxOSLogArgumentCount else { return }
95103
formatString +=
96104
format.formatSpecifier(for: T.self, align: align, privacy: privacy)
97-
98-
let isPrivateArgument = isPrivate(privacy)
99-
addIntHeaders(isPrivateArgument, sizeForEncoding(T.self))
105+
addIntHeaders(privacy, sizeForEncoding(T.self))
100106

101107
arguments.append(number)
102108
argumentCount += 1
@@ -107,9 +113,12 @@ extension OSLogInterpolation {
107113
@_semantics("constant_evaluable")
108114
@inlinable
109115
@_optimize(none)
110-
internal mutating func addIntHeaders(_ isPrivate: Bool, _ byteCount: Int) {
116+
internal mutating func addIntHeaders(
117+
_ privacy: OSLogPrivacy,
118+
_ byteCount: Int
119+
) {
111120
// Append argument header.
112-
let argumentHeader = getArgumentHeader(isPrivate: isPrivate, type: .scalar)
121+
let argumentHeader = getArgumentHeader(privacy: privacy, type: .scalar)
113122
arguments.append(argumentHeader)
114123

115124
// Append number of bytes needed to serialize the argument.
@@ -120,7 +129,7 @@ extension OSLogInterpolation {
120129
// two bytes needed for the headers.
121130
totalBytesForSerializingArguments += byteCount + 2
122131

123-
preamble = getUpdatedPreamble(isPrivate: isPrivate, isScalar: true)
132+
preamble = getUpdatedPreamble(privacy: privacy, isScalar: true)
124133
}
125134
}
126135

0 commit comments

Comments
 (0)