Skip to content

Commit

Permalink
Changed HSTRING projection to use WindowsPreallocateStringBuffer to s…
Browse files Browse the repository at this point in the history
…ave an allocation and copy.
  • Loading branch information
tristanlabelle committed Mar 5, 2024
1 parent c98f4ea commit 4794f3c
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 22 deletions.
23 changes: 18 additions & 5 deletions Support/Sources/WindowsRuntime/HSTRING+methods.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,25 @@ import COM

extension WindowsRuntime_ABI.SWRT_HString {
public static func create(_ value: String) throws -> WindowsRuntime_ABI.SWRT_HString? {
let chars = Array(value.utf16)
return try chars.withUnsafeBufferPointer {
var result: WindowsRuntime_ABI.SWRT_HString?
try HResult.throwIfFailed(WindowsRuntime_ABI.SWRT_WindowsCreateString($0.baseAddress!, UInt32(chars.count), &result))
return result
if value.isEmpty { return nil }

let codeUnitCount = value.utf16.count

// Preallocate and fill a UTF-16 HSTRING_BUFFER
var buffer: WindowsRuntime_ABI.SWRT_HStringBuffer? = nil
var pointer: UnsafeMutablePointer<UInt16>? = nil
try HResult.throwIfFailed(WindowsRuntime_ABI.SWRT_WindowsPreallocateStringBuffer(UInt32(codeUnitCount), &pointer, &buffer))
guard let pointer else { throw HResult.Error.pointer }
_ = UnsafeMutableBufferPointer(start: pointer, count: codeUnitCount).initialize(from: value.utf16)

var result: WindowsRuntime_ABI.SWRT_HString?
do { try HResult.throwIfFailed(WindowsRuntime_ABI.SWRT_WindowsPromoteStringBuffer(buffer, &result)) }
catch {
WindowsRuntime_ABI.SWRT_WindowsDeleteStringBuffer(buffer)
throw error
}

return result
}

public static func delete(_ value: WindowsRuntime_ABI.SWRT_HString?) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#include "WinRT.h"
#include "Functions.h"

#include <Windows.h>
Expand All @@ -21,14 +20,18 @@ uint32_t SWRT_SysStringLen(SWRT_BStr pbstr) {
}

#include <winstring.h>
SWRT_HResult SWRT_WindowsCreateString(const char16_t* sourceString, uint32_t length, SWRT_HString *string) {
SWRT_HResult SWRT_WindowsCreateString(const char16_t* sourceString, uint32_t length, SWRT_HString* string) {
return (SWRT_HResult)WindowsCreateString((PCNZWCH)sourceString, (UINT32)length, (HSTRING*)string);
}

SWRT_HResult SWRT_WindowsDeleteString(SWRT_HString string) {
return (SWRT_HResult)WindowsDeleteString((HSTRING)string);
}

SWRT_HResult SWRT_WindowsDeleteStringBuffer(SWRT_HStringBuffer bufferHandle) {
return (SWRT_HResult)WindowsDeleteStringBuffer((HSTRING_BUFFER)bufferHandle);
}

SWRT_HResult SWRT_WindowsDuplicateString(SWRT_HString string, SWRT_HString *newString) {
return (SWRT_HResult)WindowsDuplicateString((HSTRING)string, (HSTRING*)newString);
}
Expand All @@ -37,8 +40,16 @@ const char16_t* SWRT_WindowsGetStringRawBuffer(SWRT_HString string, uint32_t *le
return (const char16_t*)WindowsGetStringRawBuffer((HSTRING)string, (UINT32*)length);
}

SWRT_HResult SWRT_WindowsPreallocateStringBuffer(uint32_t length, char16_t** charBuffer, SWRT_HStringBuffer* bufferHandle) {
return (SWRT_HResult)WindowsPreallocateStringBuffer((UINT32)length, (PWSTR*)charBuffer, (HSTRING_BUFFER*)bufferHandle);
}

SWRT_HResult SWRT_WindowsPromoteStringBuffer(SWRT_HStringBuffer bufferHandle, SWRT_HString* string) {
return (SWRT_HResult)WindowsPromoteStringBuffer((HSTRING_BUFFER)bufferHandle, (HSTRING*)string);
}

#include <roapi.h>
SWRT_HResult SWRT_RoGetActivationFactory(SWRT_HString activatableClassId, SWRT_Guid* iid, void **factory) {
SWRT_HResult SWRT_RoGetActivationFactory(SWRT_HString activatableClassId, SWRT_Guid* iid, void** factory) {
return (SWRT_HResult)RoGetActivationFactory((HSTRING)activatableClassId, (IID*)iid, factory);
}

Expand Down
9 changes: 0 additions & 9 deletions Support/Sources/WindowsRuntime_ABI/include/CWinRTCore.h

This file was deleted.

11 changes: 7 additions & 4 deletions Support/Sources/WindowsRuntime_ABI/include/Functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,21 @@ void SWRT_SysFreeString(SWRT_BStr bstrString);
uint32_t SWRT_SysStringLen(SWRT_BStr pbstr);

// winstring.h
SWRT_HResult SWRT_WindowsCreateString(const char16_t* sourceString, uint32_t length, SWRT_HString *string);
SWRT_HResult SWRT_WindowsCreateString(const char16_t* sourceString, uint32_t length, SWRT_HString* string);
SWRT_HResult SWRT_WindowsDeleteString(SWRT_HString string);
SWRT_HResult SWRT_WindowsDuplicateString(SWRT_HString string, SWRT_HString *newString);
const char16_t* SWRT_WindowsGetStringRawBuffer(SWRT_HString string, uint32_t *length);
SWRT_HResult SWRT_WindowsDeleteStringBuffer(SWRT_HStringBuffer bufferHandle);
SWRT_HResult SWRT_WindowsDuplicateString(SWRT_HString string, SWRT_HString* newString);
const char16_t* SWRT_WindowsGetStringRawBuffer(SWRT_HString string, uint32_t* length);
SWRT_HResult SWRT_WindowsPreallocateStringBuffer(uint32_t length, char16_t** charBuffer, SWRT_HStringBuffer* bufferHandle);
SWRT_HResult SWRT_WindowsPromoteStringBuffer(SWRT_HStringBuffer bufferHandle, SWRT_HString* string);

// roapi.h
typedef enum SWRT_RO_INIT_TYPE {
SWRT_RO_INIT_SINGLETHREADED = 0,
SWRT_RO_INIT_MULTITHREADED = 1
} SWRT_RO_INIT_TYPE;

SWRT_HResult SWRT_RoGetActivationFactory(SWRT_HString activatableClassId, SWRT_Guid* iid, void **factory);
SWRT_HResult SWRT_RoGetActivationFactory(SWRT_HString activatableClassId, SWRT_Guid* iid, void** factory);
SWRT_HResult SWRT_RoInitialize(SWRT_RO_INIT_TYPE initType);
void SWRT_RoUninitialize();

Expand Down
4 changes: 3 additions & 1 deletion Support/Sources/WindowsRuntime_ABI/include/WinRT.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@

// HSTRING
struct SWRT_HString_ {};

typedef struct SWRT_HString_* SWRT_HString;

struct SWRT_HStringBuffer_ {};
typedef struct SWRT_HStringBuffer_* SWRT_HStringBuffer;

// TrustLevel
typedef int32_t SWRT_TrustLevel;

Expand Down
22 changes: 22 additions & 0 deletions Support/Tests/HStringTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import XCTest
import WindowsRuntime

internal final class HStringTests: XCTestCase {
func testEmptyString() throws {
XCTAssertNil(try HStringProjection.toABI(""))
XCTAssertEqual(HStringProjection.toSwift(nil), "")
}

func testRoundTrip() throws {
func assertRoundTrip(_ str: String) throws{
var abi = try HStringProjection.toABI(str)
let roundtripped = HStringProjection.toSwift(consuming: &abi)
XCTAssertEqual(str, roundtripped)
}

try assertRoundTrip("")
try assertRoundTrip("a")
try assertRoundTrip("à")
try assertRoundTrip("")
}
}

0 comments on commit 4794f3c

Please sign in to comment.