Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,23 @@ if (POLICY CMP0141) # MSVC hot-reload schenanigans
set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<IF:$<AND:$<C_COMPILER_ID:MSVC>,$<CXX_COMPILER_ID:MSVC>>,$<$<CONFIG:Debug,RelWithDebInfo>:EditAndContinue>,$<$<CONFIG:Debug,RelWithDebInfo>:ProgramDatabase>>")
endif()

if(POLICY CMP0092)
cmake_policy(SET CMP0092 NEW)
endif()

if(MSVC)
string(REPLACE "/EHsc" "" OLD_FLAGS "${CMAKE_CXX_FLAGS}")
set(CMAKE_CXX_FLAGS "${OLD_FLAGS}")
string(REPLACE "/RTC1" "" OLD_FLAGS "${CMAKE_CXX_FLAGS_DEBUG}")
set(CMAKE_CXX_FLAGS_DEBUG "${OLD_FLAGS}")
add_compile_options(/permissive- /Zc:preprocessor /JMC /std:c++latest /GR- /GS- /EHsc-)
add_compile_options(/permissive- /Zc:preprocessor /JMC /std:c++latest /GR- /GS- /Zc:throwingNew- /EHs-)
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-ffreestanding -nostdinc++ -fno-exceptions -fno-rtti)
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
add_compile_options(-ffreestanding -nostdinc++ -fno-exceptions -fno-rtti)
endif()

message(STATUS "CMAKE_CXX_FLAGS: ${CMAKE_CXX_FLAGS}")

add_subdirectory(starlib)
add_subdirectory(testing)
9 changes: 7 additions & 2 deletions starlib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,18 @@ add_library(starlib STATIC)
# Add module sources
target_sources(starlib
PUBLIC
FILE_SET cxx_modules TYPE CXX_MODULES FILES
FILE_SET CXX_MODULES TYPE CXX_MODULES FILES
starlib.ixx
process.ixx
print.ixx
native.ixx
printInternals.ixx
PRIVATE
starlib.cpp
process.cpp
"process.ixx")
print.cpp
printInternals.cpp
native.cpp)

target_include_directories(starlib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

Expand Down
27 changes: 27 additions & 0 deletions starlib/native.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
module;
#ifdef _WIN32
#include <Windows.h>
#else

#endif

#include <cstddef>

module nativeAPI;

void* __cdecl operator new(std::size_t size) noexcept
{
return HeapAlloc(GetProcessHeap(), 0, size);
}
void __cdecl operator delete(void* lpMemory) noexcept
{
HeapFree(GetProcessHeap(), 0, lpMemory);
}
void* __cdecl operator new[](std::size_t size) noexcept
{
return HeapAlloc(GetProcessHeap(), 0, size);
}
void __cdecl operator delete[](void* lpMemory) noexcept
{
HeapFree(GetProcessHeap(), 0, lpMemory);
}
20 changes: 20 additions & 0 deletions starlib/native.ixx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// This module provides interface for native system APIs (at least tries to make it universal)

module;

#include <cstdint>
#include <bit>

export module nativeAPI;

static_assert(std::bit_cast<std::uintptr_t>(nullptr) == 0, "Null pointer is not all-zero bits. While this is conforming, this library requires the bit pattern of nullptr to be the same as the bit pattern of 0");

namespace starlib::detail
{
export enum struct NativeHandle : std::uintptr_t { Null = 0 };
export template <typename T>
NativeHandle PointerToHandle(T* pointer) noexcept
{
return static_cast<NativeHandle>(reinterpret_cast<std::underlying_type_t<NativeHandle>>(pointer));
}
}
34 changes: 34 additions & 0 deletions starlib/print.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
module;

#include <cstddef>

module print;

import :internal;

void starlib::Print(const char* szString, std::size_t dwSize)
{
detail::PrintString(szString, dwSize);
}

void starlib::Print(const wchar_t* szString, std::size_t dwSize)
{
detail::PrintString(szString, dwSize);
}

void starlib::Print(const char8_t* szString, std::size_t dwSize)
{
const auto converted = detail::Utf8ToCP(szString, dwSize);
Print(converted.get(), dwSize);
}

void starlib::Print(const char16_t* szString, std::size_t dwSize)
{
const auto converted = detail::Utf16ToCP(szString, dwSize);
Print(converted.get(), dwSize);
}
void starlib::Print(const char32_t* szString, std::size_t dwSize)
{
const auto converted = detail::Utf32ToCP(szString, dwSize);
Print(converted.get(), dwSize);
}
37 changes: 37 additions & 0 deletions starlib/print.ixx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
module;

#include <cstddef>
#include <type_traits>
#include <concepts>

export module print;

namespace starlib
{
export template<typename T>
concept IsCharacter = std::disjunction_v<
std::is_same<T, char>,
std::is_same<T, wchar_t>,
std::is_same<T, char8_t>,
std::is_same<T, char16_t>,
std::is_same<T, char32_t>
>;

export void Print(const char* szString, std::size_t dwSize);
export void Print(const wchar_t* szString, std::size_t dwSize);
export void Print(const char8_t* szString, std::size_t dwSize);
export void Print(const char16_t* szString, std::size_t dwSize);
export void Print(const char32_t* szString, std::size_t dwSize);

// templates
export template <std::size_t N, IsCharacter TChar>
void Print(const TChar(&string)[N])
{
Print(string, N - 1);
}

export void Print(std::integral auto integral)
{

}
}
139 changes: 139 additions & 0 deletions starlib/printInternals.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
module;
#ifdef _WIN32
#include <Windows.h>
#else
// no includes here
#endif

#include <cstddef>
#include <utility>
#include <memory>

module print;

import :internal;
import nativeAPI;

using starlib::detail::NativeHandle;

static NativeHandle g_hStandardOutput{};

void starlib::detail::InitialisePrintBuffers(void)
{
if (g_hStandardOutput != NativeHandle::Null)
return;

#ifdef _WIN32
g_hStandardOutput = starlib::detail::PointerToHandle(GetStdHandle(STD_OUTPUT_HANDLE));
SetConsoleCP(CP_UTF8); // Ensure UTF-8
SetConsoleOutputCP(CP_UTF8);
const auto hConsole = reinterpret_cast<HANDLE>(std::to_underlying(g_hStandardOutput));

DWORD mode{};
if (GetConsoleMode(hConsole, &mode))
{
mode |= ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING;
SetConsoleMode(hConsole, mode);
}
#else
#endif
}
void starlib::detail::PrintString(const char* szBuffer, std::size_t dwLength)
{
InitialisePrintBuffers();

#ifdef _WIN32
DWORD dwWritten{};
const auto hConsole = reinterpret_cast<HANDLE>(std::to_underlying(g_hStandardOutput));
WriteConsoleA(hConsole, szBuffer, dwLength, &dwWritten, nullptr);
#else
#endif
}
void starlib::detail::PrintString(const wchar_t* szBuffer, std::size_t dwLength)
{
InitialisePrintBuffers();

#ifdef _WIN32
DWORD dwWritten{};
WriteConsoleW(reinterpret_cast<HANDLE>(std::to_underlying(g_hStandardOutput)), szBuffer, dwLength, &dwWritten, nullptr);
#else
#endif
}

std::unique_ptr<char[]> starlib::detail::Utf8ToCP(const char8_t* szInput, std::size_t& dwLength)
{
#ifdef _WIN32
if (szInput == nullptr || dwLength == 0)
return nullptr;

const auto wideSize = MultiByteToWideChar(CP_UTF8, 0, reinterpret_cast<const char*>(szInput), dwLength, nullptr, 0);

std::unique_ptr<wchar_t[]> wideBuffer = std::make_unique_for_overwrite<wchar_t[]>(wideSize);

wideBuffer[MultiByteToWideChar(CP_UTF8, 0, reinterpret_cast<const char*>(szInput), dwLength, wideBuffer.get(), wideSize)] = 0;

const auto convertedSize = WideCharToMultiByte(CP_ACP, 0, wideBuffer.get(), wideSize, nullptr, 0, nullptr, nullptr);

std::unique_ptr<char[]> converted = std::make_unique_for_overwrite<char[]>(convertedSize + 1);

WideCharToMultiByte(CP_ACP, 0, wideBuffer.get(), wideSize, converted.get(), convertedSize, nullptr, nullptr);
converted[convertedSize] = 0;
dwLength = convertedSize;
return converted;
#else
#error Unsupported platform
#endif
}

std::unique_ptr<char[]> starlib::detail::Utf16ToCP(const char16_t* szInput, std::size_t& dwLength)
{
#ifdef _WIN32
if (szInput == nullptr || dwLength == 0)
return nullptr;

static_assert(sizeof(wchar_t) == 2);

const wchar_t* wideInput = reinterpret_cast<const wchar_t*>(szInput);
std::unique_ptr<wchar_t[]> temporaryBuffer{};

const int requiredSize = WideCharToMultiByte(CP_ACP, 0, wideInput, dwLength, nullptr, 0, nullptr, nullptr);

if (requiredSize <= 0) return nullptr;

std::unique_ptr<char[]> output = std::make_unique_for_overwrite<char[]>(requiredSize + 1);
WideCharToMultiByte(CP_ACP, 0, wideInput, dwLength, output.get(), requiredSize, nullptr, nullptr);
output[requiredSize] = 0;
dwLength = static_cast<std::size_t>(requiredSize);
return output;
#else
#error Unsupported platform
#endif
}

std::unique_ptr<char[]> starlib::detail::Utf32ToCP(const char32_t* szInput, std::size_t& dwLength)
{
#ifdef _WIN32
std::unique_ptr<char16_t[]> utf16String = std::make_unique_for_overwrite<char16_t[]>(dwLength * 2);
std::size_t utf16Length{};

for (std::size_t i = 0; i < dwLength; ++i)
{
char32_t codepoint = szInput[i];
if (codepoint <= 0xFFFF)
{
utf16String[utf16Length++] = static_cast<char16_t>(codepoint);
}
else if (codepoint <= 0x10FFFF)
{
codepoint -= 0x10000;
utf16String[utf16Length++] = static_cast<char16_t>((codepoint >> 10) + 0xD800);
utf16String[utf16Length++] = static_cast<char16_t>((codepoint & 0x3FF) + 0xDC00);
}
else return nullptr;
}
dwLength = utf16Length;
return starlib::detail::Utf16ToCP(utf16String.get(), dwLength);
#else
#error Unsupported platform
#endif
}
17 changes: 17 additions & 0 deletions starlib/printInternals.ixx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module;

#include <cstddef>
#include <memory>

export module print:internal;

namespace starlib::detail
{
void InitialisePrintBuffers(void);
export void PrintString(const char* szBuffer, std::size_t dwLength);
export void PrintString(const wchar_t* szBuffer, std::size_t dwLength);

export std::unique_ptr<char[]> Utf8ToCP(const char8_t* szInput, std::size_t& dwLength);
export std::unique_ptr<char[]> Utf16ToCP(const char16_t* szInput, std::size_t& dwLength);
export std::unique_ptr<char[]> Utf32ToCP(const char32_t* szInput, std::size_t& dwLength);
}
2 changes: 1 addition & 1 deletion starlib/starlib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ module starlib;

extern "C" void DefaultMain(void)
{
starlib::process::Exit(1);
starlib::process::Exit(Program::Main());
}

7 changes: 7 additions & 0 deletions starlib/starlib.ixx
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
export module starlib;

export import process;
export import print;

export class Program
{
public:
static int Main(void);
};
9 changes: 9 additions & 0 deletions testing/main.cpp
Original file line number Diff line number Diff line change
@@ -1,2 +1,11 @@
import starlib;

int Program::Main(void)
{
starlib::Print("Meow ordinary character\n");
starlib::Print(L"Meow wide character\n");
starlib::Print(u8"Meow UTF-8\n");
starlib::Print(u"Meow UTF-16\n");
starlib::Print(U"Meow UTF-32\n");
return 0;
}
Loading