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

C++ 20: Move vnext to C++ 20 and C++ 20 coroutines #12331

Draft
wants to merge 12 commits into
base: main
Choose a base branch
from
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "C++ 20: Move vnext to C++ 20 and C++ 20 coroutines",
"packageName": "react-native-windows",
"email": "ngerlem@fb.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@
$(VCInstallDir)UnitTest\include;
%(AdditionalIncludeDirectories)
</AdditionalIncludeDirectories>
<AdditionalOptions>%(AdditionalOptions) /await</AdditionalOptions>
</ClCompile>
<Link>
<!--
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
<PreprocessorDefinitions>_CONSOLE;MSO_MOTIFCPP;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<WarningLevel>Level4</WarningLevel>
<AdditionalIncludeDirectories>$(MSBuildThisFileDirectory);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalOptions>/await %(AdditionalOptions) /bigobj</AdditionalOptions>
<AdditionalOptions>%(AdditionalOptions) /bigobj</AdditionalOptions>
<ConformanceMode>true</ConformanceMode>
<CallingConvention>Cdecl</CallingConvention>
</ClCompile>
Expand Down Expand Up @@ -165,4 +165,4 @@
<PackageReference Include="$(V8PackageName)" Version="$(V8Version)" Condition="'$(UseV8)' == 'true'" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
<PreprocessorDefinitions>_CONSOLE;MSO_MOTIFCPP;FOLLY_CFG_NO_COROUTINES;FOLLY_NO_CONFIG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<WarningLevel>Level4</WarningLevel>
<AdditionalIncludeDirectories>$(MSBuildThisFileDirectory);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<AdditionalOptions>/await %(AdditionalOptions) /bigobj</AdditionalOptions>
<AdditionalOptions>%(AdditionalOptions) /bigobj</AdditionalOptions>
<ConformanceMode>true</ConformanceMode>
<CallingConvention>Cdecl</CallingConvention>
<!-- We need RuntimeTypeInfo for JSI tests -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@
<PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>
<ForcedIncludeFiles>pch.h</ForcedIncludeFiles>
<WarningLevel>Level4</WarningLevel>
<AdditionalOptions>/await %(AdditionalOptions) /bigobj /ZH:SHA_256</AdditionalOptions>
<AdditionalOptions>%(AdditionalOptions) /bigobj /ZH:SHA_256</AdditionalOptions>
<AdditionalIncludeDirectories>
$(FmtDir)\include;
$(ReactNativeWindowsDir)Microsoft.ReactNative;
Expand Down
11 changes: 6 additions & 5 deletions vnext/Microsoft.ReactNative/Utils/LocalBundleReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ std::string GetBundleFromEmbeddedResource(const winrt::Windows::Foundation::Uri
return std::string(start, start + size);
}

std::future<std::string> LocalBundleReader::LoadBundleAsync(const std::wstring bundleUri) {
winrt::Windows::Foundation::IAsyncOperation<winrt::hstring> LocalBundleReader::LoadBundleAsync(
const std::wstring bundleUri) {
co_await winrt::resume_background();

winrt::Windows::Storage::StorageFile file{nullptr};
Expand All @@ -65,7 +66,7 @@ std::future<std::string> LocalBundleReader::LoadBundleAsync(const std::wstring b
file = co_await winrt::Windows::Storage::StorageFile::GetFileFromApplicationUriAsync(uri);
} else if (bundleUri._Starts_with(L"resource://")) {
winrt::Windows::Foundation::Uri uri(bundleUri);
co_return GetBundleFromEmbeddedResource(uri);
co_return winrt::to_hstring(GetBundleFromEmbeddedResource(uri));
} else {
file = co_await winrt::Windows::Storage::StorageFile::GetFileFromPathAsync(bundleUri);
}
Expand All @@ -86,10 +87,10 @@ std::future<std::string> LocalBundleReader::LoadBundleAsync(const std::wstring b
reinterpret_cast<uint8_t *>(&script[0]), reinterpret_cast<uint8_t *>(&script[script.length()])});
dataReader.Close();

co_return script;
co_return winrt::to_hstring(script);
}

std::string LocalBundleReader::LoadBundle(const std::wstring &bundlePath) {
winrt::hstring LocalBundleReader::LoadBundle(const std::wstring &bundlePath) {
return LoadBundleAsync(bundlePath).get();
}

Expand All @@ -113,7 +114,7 @@ size_t StorageFileBigString::size() const {

void StorageFileBigString::ensure() const {
if (m_string.empty()) {
m_string = m_futureBuffer.get();
m_string = winrt::to_string(m_futureBuffer.get());
}
}

Expand Down
8 changes: 4 additions & 4 deletions vnext/Microsoft.ReactNative/Utils/LocalBundleReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@

#pragma once
#include <cxxreact/JSBigString.h>
#include <future>
#include <winrt/Windows.Foundation.h>
#include <string>

namespace Microsoft::ReactNative {

class LocalBundleReader {
public:
static std::future<std::string> LoadBundleAsync(const std::wstring bundlePath);
static std::string LoadBundle(const std::wstring &bundlePath);
static winrt::Windows::Foundation::IAsyncOperation<winrt::hstring> LoadBundleAsync(const std::wstring bundleUri);
static winrt::hstring LoadBundle(const std::wstring &bundlePath);
};

class StorageFileBigString : public facebook::react::JSBigString {
Expand All @@ -24,7 +24,7 @@ class StorageFileBigString : public facebook::react::JSBigString {
void ensure() const;

private:
mutable std::future<std::string> m_futureBuffer;
mutable winrt::Windows::Foundation::IAsyncOperation<winrt::hstring> m_futureBuffer;
mutable std::string m_string;
};

Expand Down
3 changes: 2 additions & 1 deletion vnext/Microsoft.ReactNative/Utils/UwpScriptStore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ facebook::jsi::ScriptVersion_t UwpScriptStore::getScriptVersion(const std::strin
return version;
}

std::future<facebook::jsi::ScriptVersion_t> UwpScriptStore::getScriptVersionAsync(const std::string &bundleUri) {
winrt::Windows::Foundation::IAsyncOperation<facebook::jsi::ScriptVersion_t> UwpScriptStore::getScriptVersionAsync(
const std::string &bundleUri) {
co_await winrt::resume_background();

const winrt::hstring fileUrl(Microsoft::Common::Unicode::Utf8ToUtf16("ms-appx:///Bundle/" + bundleUri + ".bundle"));
Expand Down
5 changes: 3 additions & 2 deletions vnext/Microsoft.ReactNative/Utils/UwpScriptStore.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#pragma once
#include <JSI/ScriptStore.h>
#include <future>
#include <winrt/Windows.Foundation.h>

namespace Microsoft::ReactNative {

Expand All @@ -16,7 +16,8 @@ class UwpScriptStore : public facebook::jsi::ScriptStore {
static facebook::jsi::ScriptVersion_t GetFileVersion(const std::wstring &filePath);

private:
std::future<facebook::jsi::ScriptVersion_t> getScriptVersionAsync(const std::string &bundleUri);
winrt::Windows::Foundation::IAsyncOperation<facebook::jsi::ScriptVersion_t> getScriptVersionAsync(
const std::string &bundleUri);
};

} // namespace Microsoft::ReactNative
4 changes: 2 additions & 2 deletions vnext/Mso.UnitTests/Mso.UnitTests.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
<PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>
<PreprocessorDefinitions>_CONSOLE;MS_TARGET_WINDOWS;MSO_MOTIFCPP;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<WarningLevel>Level4</WarningLevel>
<AdditionalOptions>/await %(AdditionalOptions) /bigobj</AdditionalOptions>
<AdditionalOptions>%(AdditionalOptions) /bigobj</AdditionalOptions>
<ConformanceMode>true</ConformanceMode>
<CallingConvention>Cdecl</CallingConvention>
</ClCompile>
Expand Down Expand Up @@ -148,4 +148,4 @@
<PackageReference Include="Microsoft.Windows.CppWinRT" Version="$(CppWinRTVersion)" PrivateAssets="all" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
</Project>
</Project>
2 changes: 1 addition & 1 deletion vnext/PropertySheets/React.Cpp.props
Original file line number Diff line number Diff line change
Expand Up @@ -152,4 +152,4 @@
</Link>
</ItemDefinitionGroup>

</Project>
</Project>
21 changes: 13 additions & 8 deletions vnext/Shared/DevSupportManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "Utilities.h"

#include <Utils/CppWinrtLessExceptions.h>
#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Storage.Streams.h>
#include <winrt/Windows.Web.Http.Filters.h>
Expand All @@ -30,7 +31,6 @@
#include <cxxreact/MessageQueueThread.h>
#pragma warning(pop)

#include <future>
#include <mutex>

#include <AppModel.h>
Expand All @@ -44,7 +44,9 @@ using namespace facebook::react;

namespace Microsoft::ReactNative {

std::future<std::pair<std::string, bool>> GetJavaScriptFromServerAsync(const std::string &url) {
winrt::Windows::Foundation::IAsyncOperation<
winrt::Windows::Foundation::Collections::IKeyValuePair<winrt::hstring, bool>>
GetJavaScriptFromServerAsync(const std::string &url) {
winrt::Windows::Web::Http::Filters::HttpBaseProtocolFilter filter;
filter.CacheControl().ReadBehavior(winrt::Windows::Web::Http::Filters::HttpCacheReadBehavior::NoCache);
winrt::Windows::Web::Http::HttpClient httpClient(filter);
Expand All @@ -58,8 +60,9 @@ std::future<std::pair<std::string, bool>> GetJavaScriptFromServerAsync(const std
try {
winrt::Windows::Web::Http::HttpResponseMessage response = co_await asyncRequest;
} catch (winrt::hresult_error const &e) {
co_return std::make_pair(
Microsoft::Common::Unicode::Utf16ToUtf8(e.message().c_str(), e.message().size()).c_str(), false);
co_return winrt::pair<winrt::hstring, bool>(
winrt::to_hstring(Microsoft::Common::Unicode::Utf16ToUtf8(e.message().c_str(), e.message().size()).c_str()),
false);
}
#else
co_await lessthrow_await_adapter<winrt::Windows::Foundation::IAsyncOperationWithProgress<
Expand All @@ -74,7 +77,7 @@ std::future<std::pair<std::string, bool>> GetJavaScriptFromServerAsync(const std
} else {
error = fmt::format("Error 0x{:x} downloading {}.", static_cast<int>(asyncRequest.ErrorCode()), url);
}
co_return std::make_pair(error, false);
co_return winrt::pair<winrt::hstring, bool>(winrt::to_hstring(error), false);
}

winrt::Windows::Web::Http::HttpResponseMessage response = asyncRequest.GetResults();
Expand All @@ -98,7 +101,7 @@ std::future<std::pair<std::string, bool>> GetJavaScriptFromServerAsync(const std
result = fmt::format("HTTP Error {} downloading {}.", static_cast<int>(response.StatusCode()), url);
}

co_return std::make_pair(std::move(result), response.IsSuccessStatusCode());
co_return winrt::pair<winrt::hstring, bool>(winrt::to_hstring(std::move(result)), response.IsSuccessStatusCode());
}

void LaunchDevTools(const facebook::react::DevSettings &settings) {
Expand Down Expand Up @@ -171,7 +174,8 @@ bool IsIgnorablePollHResult(HRESULT hr) {
return hr == WININET_E_INVALID_SERVER_RESPONSE;
}

std::future<winrt::Windows::Web::Http::HttpStatusCode> PollForLiveReload(const std::string &url) {
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Web::Http::HttpStatusCode> PollForLiveReload(
const std::string url) {
winrt::Windows::Web::Http::HttpClient httpClient;
winrt::Windows::Foundation::Uri uri(Microsoft::Common::Unicode::Utf8ToUtf16(url));
httpClient.DefaultRequestHeaders().Connection().TryParseAdd(L"keep-alive");
Expand Down Expand Up @@ -290,7 +294,8 @@ std::pair<std::string, bool> GetJavaScriptFromServer(
inlineSourceMap,
hermesBytecodeVersion);
try {
return GetJavaScriptFromServerAsync(bundleUrl).get();
auto result = GetJavaScriptFromServerAsync(bundleUrl).get();
return std::make_pair(winrt::to_string(result.Key()), result.Value());
} catch (winrt::hresult_error const &e) {
return std::make_pair(
"Error: " + Microsoft::Common::Unicode::Utf16ToUtf8(e.message().c_str(), e.message().size()), false);
Expand Down
24 changes: 24 additions & 0 deletions vnext/Shared/DevSupportManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#include <DevServerHelper.h>

#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.Networking.Sockets.h>
#include <atomic>
#include <functional>
Expand All @@ -22,6 +23,29 @@ struct DevSettings;
}
} // namespace facebook

namespace winrt {

template <typename K, typename V>
struct pair_impl : implements<pair_impl<K, V>, Windows::Foundation::Collections::IKeyValuePair<K, V>> {
pair_impl(K k, V v) : m_k(k), m_v(v) {}
K Key() {
return m_k;
}
V Value() {
return m_v;
}

private:
K m_k;
V m_v;
};

template <typename K, typename V>
Windows::Foundation::Collections::IKeyValuePair<K, V> pair(K key, V value) {
return make<pair_impl<K, V>>(key, value);
}
} // namespace winrt

namespace Microsoft::ReactNative {

std::pair<std::string, bool> GetJavaScriptFromServer(
Expand Down
11 changes: 4 additions & 7 deletions vnext/Shared/HermesSamplingProfiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

#include <hermes/hermes_api.h>
#include <chrono>
#include <future>
#include <coroutine>

#include "HermesRuntimeHolder.h"
#include "HermesSamplingProfiler.h"
Expand All @@ -32,10 +32,8 @@ auto resume_in_dispatcher(const IReactDispatcher &dispatcher) noexcept {

void await_resume() const noexcept {}

void await_suspend(std::experimental::coroutine_handle<> resume) noexcept {
callback_ = [context = resume.address()]() noexcept {
std::experimental::coroutine_handle<>::from_address(context)();
};
void await_suspend(std::coroutine_handle<> resume) noexcept {
callback_ = [context = resume.address()]() noexcept { std::coroutine_handle<>::from_address(context)(); };
dispatcher_.Post(std::move(callback_));
}

Expand All @@ -54,8 +52,7 @@ IAsyncOperation<winrt::hstring> getTraceFilePath() noexcept {
.count();

os << hermesDataPath.c_str() << L"\\cpu_" << now << L".cpuprofile";
// TODO: Use C++ 20 `os.view()` to avoid a copy
co_return winrt::hstring(os.str());
co_return winrt::hstring(os.view());
}

} // namespace
Expand Down
7 changes: 3 additions & 4 deletions vnext/Shared/Networking/WinRTWebSocketResource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <winrt/Windows.Security.Cryptography.h>

// Standard Library
#include <coroutine>
#include <sstream>

using Microsoft::Common::Utilities::CheckedReinterpretCast;
Expand Down Expand Up @@ -67,10 +68,8 @@ auto resume_in_queue(const Mso::DispatchQueue &queue) noexcept {

void await_resume() const noexcept {}

void await_suspend(std::experimental::coroutine_handle<> resume) noexcept {
m_callback = [context = resume.address()]() noexcept {
std::experimental::coroutine_handle<>::from_address(context)();
};
void await_suspend(std::coroutine_handle<> resume) noexcept {
m_callback = [context = resume.address()]() noexcept { std::coroutine_handle<>::from_address(context)(); };
m_queue.Post(std::move(m_callback));
}

Expand Down
5 changes: 3 additions & 2 deletions vnext/Shared/Utils/CppWinrtLessExceptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#define SHARED_UTILS_CPPWINRTLESSEXCEPTIONS_H_

#include <winrt/base.h>
#include <coroutine>

// #define DEFAULT_CPPWINRT_EXCEPTIONS
#ifndef DEFAULT_CPPWINRT_EXCEPTIONS
Expand All @@ -35,15 +36,15 @@ struct lessthrow_await_adapter {
return async.Status() == winrt::Windows::Foundation::AsyncStatus::Completed;
}

void await_suspend(std::experimental::coroutine_handle<> handle) const {
void await_suspend(std::coroutine_handle<> handle) const {
auto context = winrt::capture<winrt::impl::IContextCallback>(WINRT_IMPL_CoGetObjectContext);

async.Completed([handle, context = std::move(context)](auto const &, winrt::Windows::Foundation::AsyncStatus) {
winrt::impl::com_callback_args args{};
args.data = handle.address();

auto callback = [](winrt::impl::com_callback_args *args) noexcept -> int32_t {
std::experimental::coroutine_handle<>::from_address(args->data)();
std::coroutine_handle<>::from_address(args->data)();
return S_OK;
};

Expand Down
Loading