Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SR-12126] String(decoding:as:) allocates if passed an ArraySlice<UInt8> #54561

Closed
weissi opened this issue Feb 4, 2020 · 3 comments
Closed
Assignees
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. performance standard library Area: Standard library umbrella

Comments

@weissi
Copy link
Member

weissi commented Feb 4, 2020

Previous ID SR-12126
Radar rdar://problem/59148407
Original Reporter @weissi
Type Bug
Status Resolved
Resolution Done

Attachment: Download

Additional Detail from JIRA
Votes 1
Component/s Standard Library
Labels Bug, Performance
Assignee @milseman
Priority Medium

md5: c7940400704e1e3f7f98b4767867e9a0

Issue Description:

String(decoding: arraySlice, as: Unicode.UTF8.self)

allocates (unless the arraySlice is the whole Array).

Consider the following program

func makeString<Bytes: Collection>(_ bytes: Bytes) -> String  where Bytes.Element == UInt8 {
    return String(decoding: bytes, as: Unicode.UTF8.self)
}

func testArraySlice(_ array: ArraySlice<UInt8>) -> String {
    return makeString(array)
}

@inline(never)
func doArraySlice() {
    let array: ArraySlice<UInt8> = Array(repeating: UInt8(ascii: "X"), count: 15)[2...]

    for _ in 0..<10000 {
        precondition(testArraySlice(array) == "XXXXXXXXXXXXX")
    }
}

doArraySlice()

which when run as

swiftc -O test.swift && sudo ~/devel/swift-nio/dev/malloc-aggregation.d -c ./test

prints

[...]
              libsystem_malloc.dylib`malloc
              libswiftCore.dylib`swift_slowAlloc+0x19
              libswiftCore.dylib`swift_allocObject+0x27
              test`specialized _ContiguousArrayBuffer.init(_uninitializedCount:minimumCapacity:)+0x39
              test`specialized Array.init<A>(_:)+0x45
              test`specialized makeString<A>(_:)+0x162
              test`doArraySlice()+0xc0
              test`main+0x9
              libdyld.dylib`start+0x1
              test`0x1
            10000

that's totally unnecessary and can be worked around with

func makeStringFast<Bytes: Collection>(_ bytes: Bytes) -> String  where Bytes.Element == UInt8 {
    if let string = bytes.withContiguousStorageIfAvailable({
        return String(decoding: $0, as: Unicode.UTF8.self)
    }) {
        return string
    } else {
        return String(decoding: bytes, as: Unicode.UTF8.self)
    }
}
@weissi
Copy link
Member Author

weissi commented Feb 4, 2020

@swift-ci create

@weissi
Copy link
Member Author

weissi commented Feb 4, 2020

CC @milseman

@CodaFi
Copy link
Member

CodaFi commented Aug 1, 2020

This has since been resolved by #30729

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. performance standard library Area: Standard library umbrella
Projects
None yet
Development

No branches or pull requests

2 participants