Skip to content

Commit 7d33d3a

Browse files
committed
[PlaygroundLogger] Implemented support for normalizing type names.
The legacy PlaygroundLogger stripped out the standard library's module prefix (e.g. `Swift.`) from type names when displaying them. As a result, such support has been ported to the new PlaygroundLogger implementation. Since generating type names and normalizing them is a costly operation, this includes caching of the type names. To support this, a concurrent, lockless, insertion-only map implementation (based on the one used by the Swift runtime, but ported to Objective-C) has been added.
1 parent fcb0399 commit 7d33d3a

File tree

8 files changed

+278
-6
lines changed

8 files changed

+278
-6
lines changed

PlaygroundLogger/PlaygroundLogger.xcodeproj/project.pbxproj

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
objects = {
88

99
/* Begin PBXBuildFile section */
10+
5E184715202BB72700F01AD1 /* TypeName.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E184714202BB72700F01AD1 /* TypeName.swift */; };
11+
5E184718202BB80200F01AD1 /* PGLConcurrentMap.h in Headers */ = {isa = PBXBuildFile; fileRef = 5E184716202BB80200F01AD1 /* PGLConcurrentMap.h */; settings = {ATTRIBUTES = (Public, ); }; };
12+
5E184719202BB80200F01AD1 /* PGLConcurrentMap_MRR.m in Sources */ = {isa = PBXBuildFile; fileRef = 5E184717202BB80200F01AD1 /* PGLConcurrentMap_MRR.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
1013
5E2646311FB64876002DC6B6 /* PlaygroundLogger.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5E2646271FB64876002DC6B6 /* PlaygroundLogger.framework */; };
1114
5E2646381FB64876002DC6B6 /* PlaygroundLogger.h in Headers */ = {isa = PBXBuildFile; fileRef = 5E26462A1FB64876002DC6B6 /* PlaygroundLogger.h */; settings = {ATTRIBUTES = (Public, ); }; };
1215
5E2646431FB64B2A002DC6B6 /* LoggerEntrypoints.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E2646421FB64B2A002DC6B6 /* LoggerEntrypoints.swift */; };
@@ -71,6 +74,7 @@
7174
5E2756941FCF9CB000B69C83 /* SpriteKitOpaqueLoggable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E2756931FCF9CB000B69C83 /* SpriteKitOpaqueLoggable.swift */; };
7275
5E4AF1AD1FDDBDE400B7C9D9 /* Unimplemented.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E4AF1AC1FDDBDE400B7C9D9 /* Unimplemented.swift */; };
7376
5E4AF1AF1FDDC12A00B7C9D9 /* LegacyEntrypoints.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E4AF1AE1FDDC12A00B7C9D9 /* LegacyEntrypoints.swift */; };
77+
5E5FE50B202D13C800E28C3C /* PGLConcurrentMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5E5FE50A202D13C800E28C3C /* PGLConcurrentMap.swift */; };
7478
5ECE8F911FFCD2A70034D9BC /* LegacyPlaygroundLoggerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5ECE8F901FFCD2A70034D9BC /* LegacyPlaygroundLoggerTests.swift */; };
7579
/* End PBXBuildFile section */
7680

@@ -85,6 +89,9 @@
8589
/* End PBXContainerItemProxy section */
8690

8791
/* Begin PBXFileReference section */
92+
5E184714202BB72700F01AD1 /* TypeName.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TypeName.swift; sourceTree = "<group>"; };
93+
5E184716202BB80200F01AD1 /* PGLConcurrentMap.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PGLConcurrentMap.h; sourceTree = "<group>"; };
94+
5E184717202BB80200F01AD1 /* PGLConcurrentMap_MRR.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PGLConcurrentMap_MRR.m; sourceTree = "<group>"; };
8895
5E2646271FB64876002DC6B6 /* PlaygroundLogger.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = PlaygroundLogger.framework; sourceTree = BUILT_PRODUCTS_DIR; };
8996
5E26462A1FB64876002DC6B6 /* PlaygroundLogger.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PlaygroundLogger.h; sourceTree = "<group>"; };
9097
5E26462B1FB64876002DC6B6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
@@ -152,6 +159,7 @@
152159
5E2756931FCF9CB000B69C83 /* SpriteKitOpaqueLoggable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpriteKitOpaqueLoggable.swift; sourceTree = "<group>"; };
153160
5E4AF1AC1FDDBDE400B7C9D9 /* Unimplemented.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Unimplemented.swift; sourceTree = "<group>"; };
154161
5E4AF1AE1FDDC12A00B7C9D9 /* LegacyEntrypoints.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyEntrypoints.swift; sourceTree = "<group>"; };
162+
5E5FE50A202D13C800E28C3C /* PGLConcurrentMap.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PGLConcurrentMap.swift; sourceTree = "<group>"; };
155163
5ECE8F901FFCD2A70034D9BC /* LegacyPlaygroundLoggerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyPlaygroundLoggerTests.swift; sourceTree = "<group>"; };
156164
/* End PBXFileReference section */
157165

@@ -207,6 +215,7 @@
207215
5E2755D01FB6619800B69C83 /* LogPacket.swift */,
208216
5E2755D41FB6807F00B69C83 /* LogPacket+Encoding.swift */,
209217
5E2755D21FB672DC00B69C83 /* SendData.swift */,
218+
5E184714202BB72700F01AD1 /* TypeName.swift */,
210219
5E27561B1FC4854C00B69C83 /* Opaque Representations */,
211220
5E2756511FC4EC4100B69C83 /* Custom Loggable */,
212221
5E27564D1FC4E54A00B69C83 /* Legacy Support */,
@@ -415,6 +424,9 @@
415424
isa = PBXGroup;
416425
children = (
417426
5E4AF1AC1FDDBDE400B7C9D9 /* Unimplemented.swift */,
427+
5E184716202BB80200F01AD1 /* PGLConcurrentMap.h */,
428+
5E184717202BB80200F01AD1 /* PGLConcurrentMap_MRR.m */,
429+
5E5FE50A202D13C800E28C3C /* PGLConcurrentMap.swift */,
418430
);
419431
path = Utilities;
420432
sourceTree = "<group>";
@@ -426,6 +438,7 @@
426438
isa = PBXHeadersBuildPhase;
427439
buildActionMask = 2147483647;
428440
files = (
441+
5E184718202BB80200F01AD1 /* PGLConcurrentMap.h in Headers */,
429442
5E2646381FB64876002DC6B6 /* PlaygroundLogger.h in Headers */,
430443
);
431444
runOnlyForDeploymentPostprocessing = 0;
@@ -481,7 +494,7 @@
481494
TargetAttributes = {
482495
5E2646261FB64876002DC6B6 = {
483496
CreatedOnToolsVersion = 9.1;
484-
LastSwiftMigration = 0910;
497+
LastSwiftMigration = 0920;
485498
ProvisioningStyle = Automatic;
486499
};
487500
5E26462F1FB64876002DC6B6 = {
@@ -547,6 +560,7 @@
547560
5E4AF1AF1FDDC12A00B7C9D9 /* LegacyEntrypoints.swift in Sources */,
548561
5E27568F1FCF964400B69C83 /* NSBitmapImageRep+CustomOpaqueLoggable.swift in Sources */,
549562
5E27568D1FCF45AE00B69C83 /* UIView+CustomOpaqueLoggable.swift in Sources */,
563+
5E184719202BB80200F01AD1 /* PGLConcurrentMap_MRR.m in Sources */,
550564
5E27566B1FC51D2B00B69C83 /* NSAttributedString+CustomOpaqueLoggable.swift in Sources */,
551565
5E2755D71FB682DE00B69C83 /* LogEntry+Encoding.swift in Sources */,
552566
5E2755DB1FB7069300B69C83 /* LogEntry+Reflection.swift in Sources */,
@@ -560,6 +574,7 @@
560574
5E2756771FCF3C9700B69C83 /* CIColor+CustomOpaqueLoggable.swift in Sources */,
561575
5E2756941FCF9CB000B69C83 /* SpriteKitOpaqueLoggable.swift in Sources */,
562576
5E2756911FCF967300B69C83 /* NSBitmapImageRep+OpaqueImageRepresentable.swift in Sources */,
577+
5E5FE50B202D13C800E28C3C /* PGLConcurrentMap.swift in Sources */,
563578
5E2756891FCF454D00B69C83 /* UIColor+CustomOpaqueLoggable.swift in Sources */,
564579
5E4AF1AD1FDDBDE400B7C9D9 /* Unimplemented.swift in Sources */,
565580
5E27566E1FC51F7E00B69C83 /* CGGeometry+CustomOpaqueLoggable.swift in Sources */,
@@ -574,6 +589,7 @@
574589
5E27567C1FCF423400B69C83 /* NSColor+CustomOpaqueLoggable.swift in Sources */,
575590
5E2756821FCF439D00B69C83 /* NSImage+CustomOpaqueLoggable.swift in Sources */,
576591
5E2755D91FB6836800B69C83 /* LogEncoder.swift in Sources */,
592+
5E184715202BB72700F01AD1 /* TypeName.swift in Sources */,
577593
5E2756791FCF3D3200B69C83 /* CIImage+CustomOpaqueLoggable.swift in Sources */,
578594
5E2756871FCF451900B69C83 /* UIBezierPath+CustomOpaqueLoggable.swift in Sources */,
579595
5E2756841FCF43DD00B69C83 /* NSView+CustomOpaqueLoggable.swift in Sources */,
@@ -750,6 +766,7 @@
750766
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
751767
SKIP_INSTALL = YES;
752768
SUPPORTED_PLATFORMS = "macosx iphonesimulator iphoneos appletvsimulator appletvos";
769+
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
753770
SWIFT_VERSION = 4.0;
754771
};
755772
name = Debug;

PlaygroundLogger/PlaygroundLogger/LogEntry+Reflection.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ extension LogEntry {
2828
// TODO: need to handle optionals better (e.g. implicitly unwrap optionality, I think)
2929

3030
// Returns either the passed-in type name/summary or the type name/summary of `instance`.
31-
var typeName: String { return passedInTypeName ?? _typeName(type(of: instance)) }
31+
var typeName: String { return passedInTypeName ?? normalizedName(of: type(of: instance)) }
3232
var summary: String { return passedInSummary ?? String(describing: instance) }
3333

3434
// For types which conform to the `CustomOpaqueLoggable` protocol, get their custom representation and construct an opaque log entry. (This is checked *second* so that user implementations of `CustomPlaygroundRepresentable` are honored over this framework's implementations of `CustomOpaqueLoggable`.)
@@ -91,7 +91,7 @@ extension LogEntry {
9191

9292
// If our Mirror has a superclassMirror, then we need to include that as the first "child" (and include it in the total children count).
9393
if let superclassMirror = mirror.superclassMirror {
94-
let superclassTypeName = _typeName(superclassMirror.subjectType)
94+
let superclassTypeName = normalizedName(of: superclassMirror.subjectType)
9595
childEntries.append(LogEntry(structureFrom: superclassMirror, name: LogEntry.superclassLogEntryName, typeName: superclassTypeName, summary: superclassTypeName))
9696

9797
totalChildrenCount = Int(mirror.children.count) + 1

PlaygroundLogger/PlaygroundLogger/LogPacket.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// This source file is part of the Swift.org open source project
44
//
5-
// Copyright (c) 2017 Apple Inc. and the Swift project authors
5+
// Copyright (c) 2017-2018 Apple Inc. and the Swift project authors
66
// Licensed under Apache License v2.0 with Runtime Library Exception
77
//
88
// See http://swift.org/LICENSE.txt for license information
@@ -23,7 +23,7 @@ struct LogPacket {
2323
var logEntry: LogEntry
2424
}
2525

26-
private let stringTypeName = _typeName(String.self)
26+
private let stringTypeName = normalizedName(of: String.self)
2727

2828
extension LogPacket {
2929
private init(logEntry: LogEntry, startLine: Int, endLine: Int, startColumn: Int, endColumn: Int, threadID: String?) {

PlaygroundLogger/PlaygroundLogger/PlaygroundLogger.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//
33
// This source file is part of the Swift.org open source project
44
//
5-
// Copyright (c) 2017 Apple Inc. and the Swift project authors
5+
// Copyright (c) 2017-2018 Apple Inc. and the Swift project authors
66
// Licensed under Apache License v2.0 with Runtime Library Exception
77
//
88
// See http://swift.org/LICENSE.txt for license information
@@ -17,3 +17,5 @@ FOUNDATION_EXPORT double PlaygroundLoggerVersionNumber;
1717

1818
//! Project version string for PlaygroundLogger.
1919
FOUNDATION_EXPORT const unsigned char PlaygroundLoggerVersionString[];
20+
21+
#import <PlaygroundLogger/PGLConcurrentMap.h>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//===--- TypeName.swift ---------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014-2018 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See http://swift.org/LICENSE.txt for license information
9+
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
fileprivate let typeNameCache = PGLConcurrentMap()
14+
15+
private let swiftStdlibModuleNameRegex = try! NSRegularExpression(pattern: "(?<!\\.)\\b(Swift\\.)", options: [.useUnicodeWordBoundaries])
16+
17+
fileprivate func normalizeTypeName(_ typeName: String) -> String {
18+
return swiftStdlibModuleNameRegex.stringByReplacingMatches(in: typeName, options: [], range: NSRange(location: 0, length: typeName.utf16.count), withTemplate: "")
19+
}
20+
21+
/// Returns the normalized name of the given `Any.Type`.
22+
///
23+
/// - note: This function caches type names, as normalization (and type name generation in general) can be expensive.
24+
func normalizedName(of type: Any.Type) -> String {
25+
let key = Int(bitPattern: ObjectIdentifier(type))
26+
let (object, _) = typeNameCache.object(forKey: key, insertingIfNecessary: normalizeTypeName(_typeName(type)))
27+
return object as! String
28+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//===--- PGLConcurrentMap.h -----------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2018 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See http://swift.org/LICENSE.txt for license information
9+
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// PGLConcurrentMap provides an insertion-only map which allows for concurrent
14+
// accesses with minimal overhead. Since this is extremely limited, the keys
15+
// into this map are integers. (The values are arbitrary objects.)
16+
//
17+
//===----------------------------------------------------------------------===//
18+
19+
#import <Foundation/Foundation.h>
20+
21+
NS_ASSUME_NONNULL_BEGIN
22+
23+
@interface PGLConcurrentMap : NSObject
24+
25+
- (instancetype)init NS_DESIGNATED_INITIALIZER;
26+
27+
- (BOOL)containsObjectForKey:(NSInteger)key;
28+
29+
- (nullable id)objectForKey:(NSInteger)key;
30+
31+
- (id)objectForKey:(NSInteger)key insertingObjectProvidedByBlockIfNotPresent:(id(^ NS_NOESCAPE)(void))objectProvider didInsert:(BOOL *)outDidInsert NS_REFINED_FOR_SWIFT;
32+
33+
- (id)objectForKey:(NSInteger)key insertingObjectIfNotPresent:(id)object didInsert:(BOOL *)outDidInsert NS_REFINED_FOR_SWIFT;
34+
35+
@end
36+
37+
NS_ASSUME_NONNULL_END
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//===--- PGLConcurrentMap.swift -------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2018 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See http://swift.org/LICENSE.txt for license information
9+
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
extension PGLConcurrentMap {
14+
func object(forKey key: Int, insertingIfNecessary object: @autoclosure () -> Any) -> (Any, didInsert: Bool) {
15+
var didInsert: ObjCBool = false
16+
let returnedObject = self.__object(forKey: key, insertingObjectProvidedByBlockIfNotPresent: object, didInsert: &didInsert)
17+
return (returnedObject, didInsert: didInsert.boolValue)
18+
}
19+
}

0 commit comments

Comments
 (0)