Skip to content

Commit dcd0893

Browse files
Merge pull request #26815 from ravikandhadai/oslog-integer-types
[oslog][stdlib-private] Refactor and generalize interpolation of Int type in the new os_log APIs so as to extend to other integer types.
2 parents 08c943d + 8641dc7 commit dcd0893

File tree

5 files changed

+239
-134
lines changed

5 files changed

+239
-134
lines changed

stdlib/private/OSLog/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ add_swift_target_library(swiftOSLogPrototype
44

55
OSLog.swift
66
OSLogMessage.swift
7+
OSLogIntegerTypes.swift
78

89
SWIFT_MODULE_DEPENDS_IOS Darwin os
910
SWIFT_MODULE_DEPENDS_OSX Darwin os
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
//===----------------- OSLogIntegerTypes.swift ----------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2019 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 integer expressions into a
14+
// OSLogMesage. It defines `appendInterpolation` functions for standard integer
15+
// types. It also defines extensions for serializing integer types into the
16+
// argument buffer passed to os_log ABIs.
17+
//
18+
// The `appendInterpolation` functions defined in this file accept formatting
19+
// and privacy options along with the interpolated expression as shown below:
20+
//
21+
// "\(x, format: .hex, privacy: .private\)"
22+
23+
extension OSLogInterpolation {
24+
25+
/// Define interpolation for expressions of type Int.
26+
/// - Parameters:
27+
/// - number: the interpolated expression of type Int, which is autoclosured.
28+
/// - format: a formatting option available for integer types, defined by the
29+
/// enum `IntFormat`.
30+
/// - privacy: a privacy qualifier which is either private or public.
31+
/// The default is public.
32+
@_transparent
33+
@_optimize(none)
34+
public mutating func appendInterpolation(
35+
_ number: @autoclosure @escaping () -> Int,
36+
format: IntFormat = .decimal,
37+
privacy: Privacy = .public
38+
) {
39+
appendInteger(number, format: format, privacy: privacy)
40+
}
41+
42+
/// Define interpolation for expressions of type Int32.
43+
/// - Parameters:
44+
/// - number: the interpolated expression of type Int32, which is autoclosured.
45+
/// - format: a formatting option available for integer types, defined by the
46+
/// enum `IntFormat`.
47+
/// - privacy: a privacy qualifier which is either private or public.
48+
/// The default is public.
49+
@_transparent
50+
@_optimize(none)
51+
public mutating func appendInterpolation(
52+
_ number: @autoclosure @escaping () -> Int32,
53+
format: IntFormat = .decimal,
54+
privacy: Privacy = .public
55+
) {
56+
appendInteger(number, format: format, privacy: privacy)
57+
}
58+
59+
/// Given an integer, create and append a format specifier for the integer to the
60+
/// format string property. Also, append the integer along with necessary headers
61+
/// to the OSLogArguments property.
62+
@_transparent
63+
@_optimize(none)
64+
@usableFromInline
65+
internal mutating func appendInteger<T>(
66+
_ number: @escaping () -> T,
67+
format: IntFormat,
68+
privacy: Privacy
69+
) where T: FixedWidthInteger {
70+
guard argumentCount < maxOSLogArgumentCount else { return }
71+
72+
let isPrivateArgument = isPrivate(privacy)
73+
formatString +=
74+
getIntegerFormatSpecifier(
75+
T.self,
76+
format,
77+
isPrivateArgument)
78+
addIntHeaders(isPrivateArgument, sizeForEncoding(T.self))
79+
80+
arguments.append(number)
81+
argumentCount += 1
82+
}
83+
84+
/// Update preamble and append argument headers based on the parameters of
85+
/// the interpolation.
86+
@_transparent
87+
@_optimize(none)
88+
@usableFromInline
89+
internal mutating func addIntHeaders(_ isPrivate: Bool, _ byteCount: Int) {
90+
// Append argument header.
91+
let argumentHeader = getArgumentHeader(isPrivate: isPrivate, type: .scalar)
92+
arguments.append(argumentHeader)
93+
94+
// Append number of bytes needed to serialize the argument.
95+
arguments.append(UInt8(byteCount))
96+
97+
// Increment total byte size by the number of bytes needed for this
98+
// argument, which is the sum of the byte size of the argument and
99+
// two bytes needed for the headers.
100+
totalBytesForSerializingArguments += byteCount + 2
101+
102+
preamble = getUpdatedPreamble(isPrivate: isPrivate)
103+
}
104+
105+
/// Construct an os_log format specifier from the given parameters.
106+
/// This function must be constant evaluable and all its arguments
107+
/// must be known at compile time.
108+
@inlinable
109+
@_semantics("oslog.interpolation.getFormatSpecifier")
110+
@_effects(readonly)
111+
@_optimize(none)
112+
internal func getIntegerFormatSpecifier<T>(
113+
_ integerType: T.Type,
114+
_ format: IntFormat,
115+
_ isPrivate: Bool
116+
) -> String where T : FixedWidthInteger {
117+
var formatSpecifier: String = isPrivate ? "%{private}" : "%{public}"
118+
119+
// Add a length modifier to the specifier.
120+
// TODO: more length modifiers will be added.
121+
if (integerType.bitWidth == CLongLong.bitWidth) {
122+
formatSpecifier += "ll"
123+
}
124+
125+
// TODO: more format specifiers will be added.
126+
switch (format) {
127+
case .hex:
128+
formatSpecifier += "x"
129+
case .octal:
130+
formatSpecifier += "o"
131+
default:
132+
formatSpecifier += integerType.isSigned ? "d" : "u"
133+
}
134+
return formatSpecifier
135+
}
136+
}
137+
138+
extension OSLogArguments {
139+
/// Append an (autoclosured) interpolated expression of integer type, passed to
140+
/// `OSLogMessage.appendInterpolation`, to the array of closures tracked
141+
/// by this instance.
142+
@usableFromInline
143+
internal mutating func append<T>(
144+
_ value: @escaping () -> T
145+
) where T: FixedWidthInteger {
146+
argumentClosures!.append({ $0.serialize(value()) })
147+
}
148+
}
149+
150+
/// Return the number of bytes needed for serializing an integer argument as
151+
/// specified by os_log. This function must be constant evaluable.
152+
@inlinable
153+
@_semantics("oslog.integers.sizeForEncoding")
154+
@_effects(readonly)
155+
@_optimize(none)
156+
internal func sizeForEncoding<T>(
157+
_ type: T.Type
158+
) -> Int where T : FixedWidthInteger {
159+
return type.bitWidth &>> logBitsPerByte
160+
}
161+
162+
extension OSLogByteBufferBuilder {
163+
/// Serialize an integer at the buffer location pointed to by `position`.
164+
@usableFromInline
165+
internal mutating func serialize<T>(
166+
_ value: T
167+
) where T : FixedWidthInteger {
168+
let byteCount = sizeForEncoding(T.self)
169+
let dest = UnsafeMutableRawBufferPointer(start: position, count: byteCount)
170+
withUnsafeBytes(of: value) { dest.copyMemory(from: $0) }
171+
position += byteCount
172+
}
173+
}

stdlib/private/OSLog/OSLogMessage.swift

Lines changed: 4 additions & 130 deletions
Original file line numberDiff line numberDiff line change
@@ -202,68 +202,7 @@ public struct OSLogInterpolation : StringInterpolationProtocol {
202202
formatString += literal.percentEscapedString
203203
}
204204

205-
/// Define interpolation for expressions of type Int. This definition enables
206-
/// passing a formatting option and a privacy qualifier along with the
207-
/// interpolated expression as shown below:
208-
///
209-
/// "\(x, format: .hex, privacy: .private\)"
210-
///
211-
/// - Parameters:
212-
/// - number: the interpolated expression of type Int, which is autoclosured.
213-
/// - format: a formatting option available for Int types, defined by the
214-
/// enum `IntFormat`.
215-
/// - privacy: a privacy qualifier which is either private or public.
216-
/// The default is public.
217-
@_transparent
218-
@_optimize(none)
219-
public mutating func appendInterpolation(
220-
_ number: @autoclosure @escaping () -> Int,
221-
format: IntFormat = .decimal,
222-
privacy: Privacy = .public
223-
) {
224-
guard argumentCount < maxOSLogArgumentCount else { return }
225-
226-
addIntHeadersAndFormatSpecifier(
227-
format,
228-
isPrivate: isPrivate(privacy),
229-
bitWidth: Int.bitWidth,
230-
isSigned: true)
231-
arguments.append(number)
232-
argumentCount += 1
233-
}
234-
235-
/// Construct/update format string and headers from the parameters of the
236-
/// interpolation.
237-
@_transparent
238-
@_optimize(none)
239-
public mutating func addIntHeadersAndFormatSpecifier(
240-
_ format: IntFormat,
241-
isPrivate: Bool,
242-
bitWidth: Int,
243-
isSigned: Bool
244-
) {
245-
formatString += getIntegerFormatSpecifier(
246-
format,
247-
isPrivate: isPrivate,
248-
bitWidth: bitWidth,
249-
isSigned: isSigned)
250-
251-
// Append argument header.
252-
let argumentHeader =
253-
getArgumentHeader(isPrivate: isPrivate, bitWidth: bitWidth, type: .scalar)
254-
arguments.append(argumentHeader)
255-
256-
// Append number of bytes needed to serialize the argument.
257-
let argumentByteCount = OSLogSerializationInfo.sizeForEncoding(Int.self)
258-
arguments.append(UInt8(argumentByteCount))
259-
260-
// Increment total byte size by the number of bytes needed for this
261-
// argument, which is the sum of the byte size of the argument and
262-
// two bytes needed for the headers.
263-
totalBytesForSerializingArguments += argumentByteCount + 2
264-
265-
preamble = getUpdatedPreamble(isPrivate: isPrivate)
266-
}
205+
/// `appendInterpolation` conformances will be added by extensions to this type.
267206

268207
/// Return true if and only if the parameter is .private.
269208
/// This function must be constant evaluable.
@@ -280,7 +219,7 @@ public struct OSLogInterpolation : StringInterpolationProtocol {
280219
return false
281220
}
282221

283-
/// compute a byte-sized argument header consisting of flag and type.
222+
/// Compute a byte-sized argument header consisting of flag and type.
284223
/// Flag and type take up the least and most significant four bits
285224
/// of the header byte, respectively.
286225
/// This function should be constant evaluable.
@@ -290,7 +229,6 @@ public struct OSLogInterpolation : StringInterpolationProtocol {
290229
@_optimize(none)
291230
internal func getArgumentHeader(
292231
isPrivate: Bool,
293-
bitWidth: Int,
294232
type: ArgumentType
295233
) -> UInt8 {
296234
let flag: ArgumentFlag = isPrivate ? .privateFlag : .publicFlag
@@ -310,39 +248,6 @@ public struct OSLogInterpolation : StringInterpolationProtocol {
310248
}
311249
return preamble
312250
}
313-
314-
/// Construct an os_log format specifier from the given parameters.
315-
/// This function must be constant evaluable and all its arguments
316-
/// must be known at compile time.
317-
@inlinable
318-
@_semantics("oslog.interpolation.getFormatSpecifier")
319-
@_effects(readonly)
320-
@_optimize(none)
321-
internal func getIntegerFormatSpecifier(
322-
_ format: IntFormat,
323-
isPrivate: Bool,
324-
bitWidth: Int,
325-
isSigned: Bool
326-
) -> String {
327-
var formatSpecifier: String = isPrivate ? "%{private}" : "%{public}"
328-
329-
// Add a length modifier, if needed, to the specifier
330-
// TODO: more length modifiers will be added.
331-
if (bitWidth == CLongLong.bitWidth) {
332-
formatSpecifier += "ll"
333-
}
334-
335-
// TODO: more format specifiers will be added.
336-
switch (format) {
337-
case .hex:
338-
formatSpecifier += "x"
339-
case .octal:
340-
formatSpecifier += "o"
341-
default:
342-
formatSpecifier += isSigned ? "d" : "u"
343-
}
344-
return formatSpecifier
345-
}
346251
}
347252

348253
extension String {
@@ -430,38 +335,14 @@ internal struct OSLogArguments {
430335
argumentClosures!.append({ $0.serialize(header) })
431336
}
432337

433-
/// Append an (autoclosured) interpolated expression of type Int, passed to
434-
/// `OSLogMessage.appendInterpolation`, to the tracked array of closures.
435-
@usableFromInline
436-
internal mutating func append(_ value: @escaping () -> Int) {
437-
argumentClosures!.append({ $0.serialize(value()) })
438-
}
338+
/// `append` for other types must be implemented by extensions.
439339

440340
@usableFromInline
441341
internal func serialize(into bufferBuilder: inout OSLogByteBufferBuilder) {
442342
argumentClosures?.forEach { $0(&bufferBuilder) }
443343
}
444344
}
445345

446-
/// A struct that provides information regarding the serialization of types
447-
/// to a byte buffer as specified by the C os_log ABIs.
448-
@usableFromInline
449-
internal struct OSLogSerializationInfo {
450-
/// Return the number of bytes needed for serializing an UInt8 value.
451-
@usableFromInline
452-
@_transparent
453-
internal static func sizeForEncoding(_ type: UInt8.Type) -> Int {
454-
return 1
455-
}
456-
457-
/// Return the number of bytes needed for serializing an Int value.
458-
@usableFromInline
459-
@_transparent
460-
internal static func sizeForEncoding(_ type: Int.Type) -> Int {
461-
return Int.bitWidth &>> logBitsPerByte
462-
}
463-
}
464-
465346
/// A struct that manages serialization of instances of specific types to a
466347
/// byte buffer. The byte buffer is provided as an argument to the initializer
467348
/// so that its lifetime can be managed by the caller.
@@ -484,12 +365,5 @@ internal struct OSLogByteBufferBuilder {
484365
position += 1
485366
}
486367

487-
/// Serialize an Int at the buffer location pointed to by `position`.
488-
@usableFromInline
489-
internal mutating func serialize(_ value: Int) {
490-
let byteCount = OSLogSerializationInfo.sizeForEncoding(Int.self)
491-
let dest = UnsafeMutableRawBufferPointer(start: position, count: byteCount)
492-
withUnsafeBytes(of: value) { dest.copyMemory(from: $0) }
493-
position += byteCount
494-
}
368+
/// `serialize` for other other types must be implemented by extensions.
495369
}

0 commit comments

Comments
 (0)