4#include "Stroika/Foundation/StroikaPreComp.h"
11#if qStroika_Platform_POSIX
14#if qStroika_Platform_Linux
15#include <sys/sysinfo.h>
18#elif qStroika_Platform_Windows
21#include <VersionHelpers.h>
25#include "Stroika/Foundation/Characters/FloatConversion.h"
27#include "Stroika/Foundation/Characters/SDKString.h"
28#include "Stroika/Foundation/Characters/String2Int.h"
31#if qStroika_Platform_Windows
32#include "Stroika/Foundation/Common/Platform/Windows/Registry.h"
34#include "Stroika/Foundation/Containers/Sequence.h"
35#include "Stroika/Foundation/Containers/Set.h"
37#include "Stroika/Foundation/Cryptography/Digest/Digester.h"
38#include "Stroika/Foundation/Execution/Exceptions.h"
39#if qStroika_Platform_Windows
40#include "Stroika/Foundation/Execution/Platform/Windows/Exception.h"
49#if qStroika_Platform_POSIX
51#include "Stroika/Foundation/Execution/ProcessRunner.h"
52#include "Stroika/Foundation/Streams/iostream/FStreamSupport.h"
59using namespace Stroika::Foundation::Streams;
60using namespace Stroika::Foundation::Time;
72String SystemConfiguration::BootInformation::ToString ()
const
76 sb <<
"bootedAt: "sv << fBootedAt;
102String SystemConfiguration::CPU::ToString ()
const
106 sb <<
"cores: "sv << fCores;
116String SystemConfiguration::Memory::ToString ()
const
120 sb <<
"Page-Size: "sv << fPageSize;
121 sb <<
", Total-Physical-RAM: "sv << fTotalPhysicalRAM;
122 sb <<
", Total-Virtual-RAM: "sv << fTotalVirtualRAM;
136 sb <<
"Hostname: "sv << fHostname;
146String SystemConfiguration::OperatingSystem::ToString ()
const
150 sb <<
"tokenName: "sv + fTokenName;
151 sb <<
", shortPrettyName: "sv + fShortPrettyName;
152 sb <<
", prettyNameWithMajorVersion: "sv + fPrettyNameWithMajorVersion;
153 sb <<
", prettyNameWithVersionDetails: "sv + fPrettyNameWithVersionDetails;
154 sb <<
", majorMinorVersionString: "sv + fMajorMinorVersionString;
155 sb <<
", rfc1945CompatProductTokenWithVersion: "sv + fRFC1945CompatProductTokenWithVersion;
156 sb <<
", bits: "sv << fBits;
157 if (fPreferredInstallerTechnology) {
158 sb <<
", preferredInstallerTechnology: "sv << *fPreferredInstallerTechnology;
173 sb <<
"bootInformation: " << fBootInformation;
174 sb <<
", CPU: "sv << fCPU;
175 sb <<
", memory: "sv << fMemory;
178 sb <<
", computerNames: "sv << fComputerNames;
179 sb <<
", machineID: "sv << (
fMachineID ?
"(not shown: confidential)"sv :
"none"sv);
189unsigned int SystemConfiguration::CPU::GetNumberOfSockets ()
const
192 for (
const auto& i : fCores) {
193 socketIds.
Add (i.fSocketID);
195 return static_cast<unsigned int> (socketIds.
size ());
203SystemConfiguration::BootInformation Common::GetSystemConfiguration_BootInformation ()
206 static const SystemConfiguration::BootInformation kCachedResult_ = [] () {
207 SystemConfiguration::BootInformation result;
208#if qStroika_Platform_Linux
211 result.fBootedAt = DateTime::Now ().AddSeconds (-info.uptime);
212#elif qStroika_Platform_POSIX
215 bool succeeded{
false};
216 static const filesystem::path kProcUptimeFileName_{
"/proc/uptime"};
224 BinaryToText::Reader::New (IO::FileSystem::FileInputStream::New (kProcUptimeFileName_, IO::FileSystem::FileInputStream::eNotSeekable))
227 if (t.
size () >= 2) {
228 result.fBootedAt = DateTime::Now ().AddSeconds (-Characters::FloatConversion::ToFloat<double> (t[0]));
244 [[maybe_unused]]
auto&& cleanup =
Execution::Finally ([] ()
noexcept { ::endutxent (); });
246 for (
const utmpx* i = ::getutxent (); i !=
nullptr; i = ::getutxent ()) {
247 if (i->ut_type == BOOT_TIME) {
248 result.fBootedAt = DateTime{i->ut_tv};
255#elif qStroika_Platform_Windows
257#if _WIN32_WINNT >= 0x0600
258 result.fBootedAt = DateTime::Now ().AddSeconds (-
static_cast<int> (::GetTickCount64 () / 1000));
260 result.fBootedAt = DateTime::Now ().AddSeconds (-
static_cast<int> (::GetTickCount () / 1000));
267 return kCachedResult_;
275SystemConfiguration::CPU Common::GetSystemConfiguration_CPU ()
279 using CPU = SystemConfiguration::CPU;
281#if qStroika_Platform_Linux
284 static const filesystem::path kProcCPUInfoFileName_{
"/proc/cpuinfo"sv};
366 optional<String> foundProcessor;
367 optional<unsigned int> currentProcessorID;
368 optional<String> currentModelName;
369 optional<unsigned int> currentSocketID;
371 BinaryToText::Reader::New (IO::FileSystem::FileInputStream::New (kProcCPUInfoFileName_, IO::FileSystem::FileInputStream::eNotSeekable))
373#if USE_NOISY_TRACE_IN_THIS_MODULE_
374 DbgTrace (
"in Configuration::GetSystemConfiguration_CPU capture_ line={}"_f, line);
376 static const String kOldProcessorLabel_{
"Processor"sv};
377 static const String kProcessorIDLabel_{
"processor"sv};
378 static const String kModelNameLabel_{
"model name"sv};
379 static const String kSocketIDLabel_{
"physical id"sv};
380 if (not line.Trim ().empty ()) {
382 if (lineTokens.
size () >= 2) {
383 String firstTrimedToken = lineTokens[0].Trim ();
384 size_t afterColon = *line.
Find (
':') + 1;
385 if (firstTrimedToken == kOldProcessorLabel_) {
386 foundProcessor = line.SubString (afterColon).Trim ();
388 else if (firstTrimedToken == kProcessorIDLabel_) {
389 currentProcessorID = String2Int<unsigned int> (line.SubString (afterColon).Trim ());
391 else if (firstTrimedToken == kModelNameLabel_) {
392 currentModelName = line.SubString (afterColon).Trim ();
394 else if (firstTrimedToken == kSocketIDLabel_) {
395 currentSocketID = String2Int<unsigned int> (line.SubString (afterColon).Trim ());
400 if (currentProcessorID) {
401 String useModelName = Memory::NullCoalesce (foundProcessor);
402 Memory::CopyToIf (&useModelName, currentModelName);
403 result.fCores.Append (CPU::CoreDetails{Memory::NullCoalesce (currentSocketID), useModelName});
406 currentProcessorID = nullopt;
407 currentModelName = nullopt;
408 currentSocketID = nullopt;
411 if (currentProcessorID) {
412 String useModelName = Memory::NullCoalesce (foundProcessor);
413 Memory::CopyToIf (&useModelName, currentModelName);
414 result.fCores.Append (CPU::CoreDetails{Memory::NullCoalesce (currentSocketID), useModelName});
417#elif qStroika_Platform_Windows
424 DWORD logicalProcessorCount = 0;
425 DWORD processorCoreCount = 0;
426 DWORD processorPackageCount = 0;
428 auto countSetBits = [] (ULONG_PTR bitMask) -> DWORD {
429 DWORD LSHIFT =
sizeof (ULONG_PTR) * 8 - 1;
430 DWORD bitSetCount = 0;
431 ULONG_PTR bitTest = (ULONG_PTR)1 << LSHIFT;
432 for (DWORD i = 0; i <= LSHIFT; ++i) {
433 bitSetCount += ((bitMask & bitTest) ? 1 : 0);
438 typedef BOOL (WINAPI * LPFN_GLPI) (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD);
439 DISABLE_COMPILER_MSC_WARNING_START (6387)
440 LPFN_GLPI glpi = (LPFN_GLPI)::GetProcAddress (::GetModuleHandle (TEXT ("kernel32")), "GetLogicalProcessorInformation");
441 DISABLE_COMPILER_MSC_WARNING_END (6387)
443 StackBuffer<
byte> buffer{Memory::eUninitialized,
sizeof (PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)};
444 DWORD returnLength = 0;
446 DWORD rc = glpi (
reinterpret_cast<PSYSTEM_LOGICAL_PROCESSOR_INFORMATION
> (buffer.begin ()), &returnLength);
448 if (GetLastError () == ERROR_INSUFFICIENT_BUFFER) {
449 buffer.GrowToSize_uninitialized (returnLength);
459 PSYSTEM_LOGICAL_PROCESSOR_INFORMATION ptr =
reinterpret_cast<PSYSTEM_LOGICAL_PROCESSOR_INFORMATION
> (buffer.begin ());
460 DWORD byteOffset = 0;
461 while (byteOffset +
sizeof (SYSTEM_LOGICAL_PROCESSOR_INFORMATION) <= returnLength) {
462 switch (ptr->Relationship) {
463 case RelationNumaNode:
465 case RelationProcessorCore:
466 ++processorCoreCount;
468 logicalProcessorCount += countSetBits (ptr->ProcessorMask);
472 case RelationProcessorPackage:
474 ++processorPackageCount;
477 DbgTrace (
"Error: Unsupported LOGICAL_PROCESSOR_RELATIONSHIP value."_f);
480 byteOffset +=
sizeof (SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
485 static const String kProcessorType_ = [] () {
486 int CPUInfo[4] = {-1};
487 char CPUBrandString[0x40];
489 ::__cpuid (CPUInfo, 0x80000000);
490 uint32_t nExIds = CPUInfo[0];
491 for (uint32_t i = 0x80000000; i <= nExIds; ++i) {
492 ::__cpuid (CPUInfo, i);
495 (void)::memcpy (CPUBrandString, CPUInfo,
sizeof (CPUInfo));
496 else if (i == 0x80000003)
497 (void)::memcpy (CPUBrandString + 16, CPUInfo,
sizeof (CPUInfo));
498 else if (i == 0x80000004)
499 (void)::memcpy (CPUBrandString + 32, CPUInfo,
sizeof (CPUInfo));
501 return String{CPUBrandString};
505 ::SYSTEM_INFO sysInfo{};
506 ::GetNativeSystemInfo (&sysInfo);
507 Assert (sysInfo.dwNumberOfProcessors == logicalProcessorCount);
509 for (
unsigned int socketNum = 0; socketNum < processorPackageCount; ++socketNum) {
510 unsigned int logProcessorsPerSocket = logicalProcessorCount / processorPackageCount;
511 for (DWORD i = 0; i < logProcessorsPerSocket; ++i) {
512 result.fCores.Append (CPU::CoreDetails{socketNum, kProcessorType_});
525SystemConfiguration::Memory Common::GetSystemConfiguration_Memory ()
527 using Memory = SystemConfiguration::Memory;
529#if qStroika_Platform_POSIX
532 static const size_t kPageSize_{
static_cast<size_t> (::sysconf (_SC_PAGESIZE))};
533 result.fPageSize = kPageSize_;
534 result.fTotalPhysicalRAM = ::sysconf (_SC_PHYS_PAGES) * kPageSize_;
535#elif qStroika_Platform_Windows
536 ::SYSTEM_INFO sysInfo{};
537 ::GetNativeSystemInfo (&sysInfo);
538 result.fPageSize = sysInfo.dwPageSize;
540 ::MEMORYSTATUSEX memStatus{};
541 memStatus.dwLength =
sizeof (memStatus);
542 Verify (::GlobalMemoryStatusEx (&memStatus));
543 result.fTotalPhysicalRAM = memStatus.ullTotalPhys;
544 result.fTotalVirtualRAM = memStatus.ullTotalVirtual;
556 using OperatingSystem = SystemConfiguration::OperatingSystem;
557 static const OperatingSystem kCachedResult_ = [] () -> OperatingSystem {
559#if qStroika_Platform_POSIX
560 tmp.fTokenName =
"Unix"sv;
565 DbgTrace (
"Failure running uname"_f);
570 tmp.fShortPrettyName = p.fUnnamedSection.fProperties.LookupValue (
"NAME"sv);
571 tmp.fPrettyNameWithMajorVersion = p.fUnnamedSection.fProperties.LookupValue (
"PRETTY_NAME"sv);
572 tmp.fMajorMinorVersionString = p.fUnnamedSection.fProperties.LookupValue (
"VERSION_ID"sv);
575 DbgTrace (
"Failure reading /etc/os-release: {}"_f, current_exception ());
577 if (tmp.fShortPrettyName.empty ()) {
580 tmp.fShortPrettyName =
"Centos"sv;
581 tmp.fPrettyNameWithMajorVersion = n;
583 if (tokens.
size () >= 3) {
584 tmp.fMajorMinorVersionString = tokens[2];
588 DbgTrace (
"Failure reading /etc/centos-release {}"_f, current_exception ());
591 if (tmp.fShortPrettyName.empty ()) {
594 tmp.fShortPrettyName =
"RedHat"sv;
595 tmp.fPrettyNameWithMajorVersion = n;
597 if (tokens.
size () >= 3) {
598 tmp.fMajorMinorVersionString = tokens[2];
602 DbgTrace (
"Failure reading /etc/redhat-release {}"_f, current_exception ());
605 if (tmp.fShortPrettyName.empty ()) {
606 tmp.fShortPrettyName = tmp.fTokenName;
608 if (tmp.fPrettyNameWithMajorVersion.empty ()) {
609 tmp.fPrettyNameWithMajorVersion = tmp.fShortPrettyName;
611 if (tmp.fPrettyNameWithVersionDetails.empty ()) {
612 tmp.fPrettyNameWithVersionDetails = tmp.fPrettyNameWithMajorVersion;
614 if (tmp.fRFC1945CompatProductTokenWithVersion.empty ()) {
615 tmp.fRFC1945CompatProductTokenWithVersion = tmp.fShortPrettyName.Trim ().ReplaceAll (
" "sv,
"-"sv);
616 if (not tmp.fMajorMinorVersionString.empty ()) {
617 tmp.fRFC1945CompatProductTokenWithVersion = tmp.fRFC1945CompatProductTokenWithVersion +
"/"sv + tmp.fMajorMinorVersionString;
621#if defined(_POSIX_V6_LP64_OFF64)
629 tmp.fBits = ::sysconf (_SC_V6_LP64_OFF64) == _POSIX_V6_LP64_OFF64 ? 64 : 32;
630#elif defined(_V6_LP64_OFF64)
632 tmp.fBits = ::sysconf (_SC_V6_LP64_OFF64) == _V6_LP64_OFF64 ? 64 : 32;
636 DbgTrace (
"_SC_V6_LP64_OFF64/_POSIX_V6_LP64_OFF64 not available - so assuming 32-bit..."_f);
639 using Characters::CompareOptions;
642 if (not tmp.fPreferredInstallerTechnology.has_value ()) {
644 if (nameEqComparer (tmp.fShortPrettyName,
"Centos"sv) or nameEqComparer (tmp.fShortPrettyName,
"RedHat"sv)) {
645 tmp.fPreferredInstallerTechnology = SystemConfiguration::OperatingSystem::InstallerTechnology::eRPM;
647 else if (nameEqComparer (tmp.fShortPrettyName,
"Ubuntu"sv)) {
648 tmp.fPreferredInstallerTechnology = SystemConfiguration::OperatingSystem::InstallerTechnology::eDPKG;
652 if (not tmp.fPreferredInstallerTechnology.has_value ()) {
655 tmp.fPreferredInstallerTechnology = SystemConfiguration::OperatingSystem::InstallerTechnology::eDPKG;
660 if (not tmp.fPreferredInstallerTechnology.has_value ()) {
663 tmp.fPreferredInstallerTechnology = SystemConfiguration::OperatingSystem::InstallerTechnology::eRPM;
668#elif qStroika_Platform_Windows
669 tmp.fTokenName =
"Windows"sv;
682 String kernelOSBuildVersion;
693 const wchar_t* kkernel32_ = L
"kernel32.dll";
695 const auto cbInfo = ::GetFileVersionInfoSizeExW (FILE_VER_GET_NEUTRAL, kkernel32_, &dummy);
696 StackBuffer<char> buffer{Memory::eUninitialized, cbInfo};
697 Verify (::GetFileVersionInfoExW (FILE_VER_GET_NEUTRAL, kkernel32_, dummy,
static_cast<DWORD
> (buffer.size ()), &buffer[0]));
700 Verify (::VerQueryValueW (buffer.data (), L
"\\", &p, &size));
701 Assert (size >=
sizeof (VS_FIXEDFILEINFO));
702 Assert (p !=
nullptr);
703 auto pFixed =
static_cast<const VS_FIXEDFILEINFO*
> (p);
704 kernelVersion =
"{}.{}"_f(HIWORD (pFixed->dwFileVersionMS), LOWORD (pFixed->dwFileVersionMS));
705 kernelOSBuildVersion =
"{}.{}"_f(HIWORD (pFixed->dwFileVersionLS), LOWORD (pFixed->dwFileVersionLS));
715 optional<String> platformVersion;
716 optional<String> productName;
717 optional<String> currentVersion;
720 if (
auto o = kWinVersionInfo_.Lookup (
"ReleaseId"sv)) {
721 platformVersion = o.As<
String> ();
723 if (
auto o = kWinVersionInfo_.Lookup (
"ProductName"sv)) {
729 if (
auto oMajor = kWinVersionInfo_.Lookup (
"CurrentMajorVersionNumber"sv)) {
730 if (
auto oMinor = kWinVersionInfo_.Lookup (
"CurrentMinorVersionNumber"sv)) {
738 if (not currentVersion) {
739 if (
auto o = kWinVersionInfo_.Lookup (
"CurrentVersion"sv)) {
745 DbgTrace (
"Exception suppressed looking up windows version in registry: {}"_f, current_exception ());
749 if (currentVersion ==
"10.0"sv and Characters::FloatConversion::ToFloat<double> (kernelOSBuildVersion) >= 21996.0) {
750 currentVersion =
"11.0"sv;
751 if (productName and productName->StartsWith (
"Windows 10"sv)) {
752 productName =
"Windows 11"sv + productName->SubString (10);
754 platformVersion = nullopt;
757 if (tmp.fShortPrettyName.empty ()) {
758 tmp.fShortPrettyName = productName.value_or (
"Windows"sv);
760 tmp.fPrettyNameWithMajorVersion = tmp.fShortPrettyName;
764 if (platformVersion) {
765 sb <<
" Version "sv + *platformVersion;
767 if (not kernelVersion.empty ()) {
768 sb <<
" (OS Build "sv + kernelOSBuildVersion +
")"sv;
770 tmp.fPrettyNameWithVersionDetails = sb.
str ();
773 tmp.fMajorMinorVersionString = currentVersion.value_or (
"unknown"sv);
774 tmp.fRFC1945CompatProductTokenWithVersion =
"Windows/"sv + tmp.fMajorMinorVersionString;
775 if constexpr (
sizeof (
void*) == 4) {
780 typedef BOOL (WINAPI * LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
781 DISABLE_COMPILER_MSC_WARNING_START (6387)
782 LPFN_ISWOW64PROCESS isWow64Process =
783 (LPFN_ISWOW64PROCESS)::GetProcAddress (::GetModuleHandle (TEXT (
"kernel32")),
"IsWow64Process");
784 DISABLE_COMPILER_MSC_WARNING_END (6387)
785 if (
nullptr != isWow64Process) {
786 BOOL isWOW64 =
false;
787 (void)isWow64Process (::GetCurrentProcess (), &isWOW64);
795 Assert (
sizeof (
void*) == 8);
798 tmp.fPreferredInstallerTechnology = SystemConfiguration::OperatingSystem::InstallerTechnology::eMSI;
804 return kCachedResult_;
807#if qStroika_Platform_Windows
808#pragma comment(lib, "Mincore.lib")
812 using OperatingSystem = SystemConfiguration::OperatingSystem;
813 static const OperatingSystem kCachedResult_ = [] () -> OperatingSystem {
816#if qStroika_Platform_Windows
818 optional<String> winCompatibilityVersionName;
819 optional<String> winCompatibilityVersionNumber;
821 if (not winCompatibilityVersionName and IsWindows10OrGreater ()) {
822 winCompatibilityVersionName =
"10.0"sv;
823 winCompatibilityVersionNumber =
"10.0"sv;
825 if (not winCompatibilityVersionName and IsWindows8Point1OrGreater ()) {
826 winCompatibilityVersionName =
"8.1"sv;
827 winCompatibilityVersionNumber =
"6.3"sv;
829 if (not winCompatibilityVersionName and IsWindows8OrGreater ()) {
830 winCompatibilityVersionName =
"8.0"sv;
831 winCompatibilityVersionNumber =
"6.2"sv;
833 if (not winCompatibilityVersionName and IsWindows7SP1OrGreater ()) {
835 winCompatibilityVersionName =
"7.1"sv;
836 winCompatibilityVersionNumber =
"6.2"sv;
838 if (not winCompatibilityVersionName and IsWindows7OrGreater ()) {
839 winCompatibilityVersionName =
"7.0"sv;
840 winCompatibilityVersionNumber =
"6.1"sv;
843 String useWinMajorMinorVersionNameStr = winCompatibilityVersionName.value_or (
"unknown"sv);
844 String useWinMajorMinorVersionNumberStr = winCompatibilityVersionNumber.value_or (
"unknown"sv);
845 tmp.fShortPrettyName =
"Windows "sv + useWinMajorMinorVersionNameStr;
846 tmp.fPrettyNameWithMajorVersion = tmp.fShortPrettyName;
847 tmp.fPrettyNameWithVersionDetails = tmp.fShortPrettyName;
848 tmp.fMajorMinorVersionString = useWinMajorMinorVersionNumberStr;
849 tmp.fRFC1945CompatProductTokenWithVersion =
"Windows/"sv + useWinMajorMinorVersionNumberStr;
853 return kCachedResult_;
861#if 0 && qStroika_Platform_POSIX
865 struct addrinfo* res;
866 struct addrinfo hints {};
867 hints.ai_socktype = SOCK_STREAM;
868 hints.ai_flags = AI_CANONNAME;
869 int e = getaddrinfo(
nullptr,
nullptr, &hints, &res);
875 for (
struct addrinfo* r = res; r != NULL; r = r->ai_next) {
876 name = r->ai_canonname ;
886 ComputerNames result;
887#if qStroika_Platform_POSIX
888#if defined(HOST_NAME_MAX)
889 char nameBuf[HOST_NAME_MAX + 1];
894 nameBuf[std::size (nameBuf) - 1] =
'\0';
896#elif qStroika_Platform_Windows
897 constexpr COMPUTER_NAME_FORMAT kUseNameFormat_ = ComputerNameDnsHostname;
901 (void)::GetComputerNameEx (kUseNameFormat_,
nullptr, &dwSize);
902 StackBuffer<SDKChar> buf{Memory::eUninitialized, dwSize};
918 optional<Common::GUID> GUIDFromHexDigits_ (
const string& text)
920 array<std::byte, 16> bytes{};
922 for (
size_t i = 0; i < text.size () and not ::isspace (
static_cast<unsigned char> (text[i])); i += 2) {
923 if (n == bytes.size () or i + 1 >= text.size () or not ::isxdigit (
static_cast<unsigned char> (text[i])) or
924 not ::isxdigit (
static_cast<unsigned char> (text[i + 1]))) {
927 bytes[n++] =
static_cast<std::byte
> (std::stoi (text.substr (i, 2),
nullptr, 16));
929 if (n != bytes.size ()) {
939#if qStroika_Platform_Linux
941 for (
const char* path : {
"/etc/machine-id",
"/var/lib/dbus/machine-id"}) {
944 if (getline (in, line)) {
945 if (optional<Common::GUID>
id = GUIDFromHexDigits_ (line)) {
950#elif qStroika_Platform_MacOS
952 const timespec wait{5, 0};
953 if (::gethostuuid (
id, &wait) == 0) {
956#elif qStroika_Platform_Windows
959 if (
auto o = key.Lookup (
"MachineGuid"sv)) {
965 DbgTrace (
"GetSystemConfiguration_MachineID: none ({})"_f, current_exception ());
980 array<std::byte, 16> name = machineID->AsRFC9562Bytes ();
981 array<std::byte, 32> in{};
982 std::copy (ns.begin (), ns.end (), in.begin ());
983 std::copy (name.begin (), name.end (), in.begin () + ns.size ());
984 array<uint8_t, 16> h = Cryptography::Digest::ComputeDigest<Cryptography::Digest::Algorithm::MD5> (span<const std::byte>{in});
985 h[6] =
static_cast<uint8_t
> ((h[6] & 0x0f) | 0x30);
986 h[8] =
static_cast<uint8_t
> ((h[8] & 0x3f) | 0x80);
997 [[maybe_unused]]
static auto computeViaStdThreadHardwareConcurrency = [] () {
return std::thread::hardware_concurrency (); };
998 [[maybe_unused]]
static auto computeViaGetSystemConfiguration_CPU = [] () {
999 return Common::GetSystemConfiguration_CPU ().GetNumberOfLogicalCores ();
1001#if qStroika_Foundation_Debug_AssertionsChecked
1002 static auto compute = [=] () {
1003 unsigned int hc = computeViaStdThreadHardwareConcurrency ();
1004 unsigned int sysConfigLogCores = computeViaGetSystemConfiguration_CPU ();
1006 return sysConfigLogCores;
1009 auto compute = computeViaGetSystemConfiguration_CPU;
1013 static atomic<unsigned int> sCachedValue_ = compute ();
1015 if (now > sCachedAt_.load () + allowedStaleness) {
1016 sCachedValue_ = compute ();
1019 return sCachedValue_;
1030 GetSystemConfiguration_CPU (),
1031 GetSystemConfiguration_Memory (),
1034 GetSystemConfiguration_ComputerNames (),
#define AssertNotImplemented()
#define qStroika_Foundation_Debug_AssertionsChecked
The qStroika_Foundation_Debug_AssertionsChecked flag determines if assertions are checked and validat...
#define WeakAssert(c)
A WeakAssert() is for things that aren't guaranteed to be true, but are overwhelmingly likely to be t...
time_point< RealtimeClock, DurationSeconds > TimePointSeconds
TimePointSeconds is a simpler approach to chrono::time_point, which doesn't require using templates e...
Similar to String, but intended to more efficiently construct a String. Mutable type (String is large...
nonvirtual String str() const
String is like std::u32string, except it is much easier to use, often much more space efficient,...
static String FromSDKString(const SDKChar *from)
static String FromNarrowSDKString(const char *from)
nonvirtual String Trim(bool(*shouldBeTrimmed)(Character)=Character::IsWhitespace) const
nonvirtual Containers::Sequence< String > Tokenize() const
A generalization of a vector: a container whose elements are keyed by the natural numbers.
Set<T> is a container of T, where once an item is added, additionally adds () do nothing.
nonvirtual void Add(ArgByValueType< value_type > item)
Reader for INI format files.
nonvirtual Profile ReadProfile(const Streams::InputStream::Ptr< byte > &in) const
though can read directly as VariantValue, reading as a Profile object maybe handier for this type of ...
Run an external command, with stdin/stdout/stderr as strings or as streams - like perl backticks.
nonvirtual void Run(const Streams::InputStream::Ptr< byte > &in, const Streams::OutputStream::Ptr< byte > &out=nullptr, const Streams::OutputStream::Ptr< byte > &error=nullptr, Time::DurationSeconds timeout=Time::kInfinity)
Run the command synchronously, returning its output, and THROW on any failure.
Logically halfway between std::array and std::vector; Smart 'direct memory array' - which when needed...
nonvirtual Iterator< T > Find(THAT_FUNCTION &&that) const
Run the argument bool-returning function (or lambda) on the elements of the container,...
nonvirtual size_t size() const
Returns the number of items contained.
T String2Int(span< const CHAR_T > s)
SystemConfiguration::OperatingSystem GetSystemConfiguration_ActualOperatingSystem()
SystemConfiguration GetSystemConfiguration()
Get the System Configuration object - note not a system global - because the configuration can change...
optional< GUID > GetSystemConfiguration_MachineID()
The operating system's own ID for this machine - exactly as the OS keeps it, the same every time (it ...
SystemConfiguration::OperatingSystem GetSystemConfiguration_ApparentOperatingSystem()
unsigned int GetNumberOfLogicalCPUCores(const chrono::duration< double > &allowedStaleness=1min)
return the number of currently available CPU cores on this (virtual) machine
auto Finally(FUNCTION &&f) -> Private_::FinallySentry< FUNCTION >
INT_TYPE ThrowPOSIXErrNoIfNegative(INT_TYPE returnCode)
Ptr New(const InputStream::Ptr< byte > &src, optional< SeekableFlag > seekable={}, ReadAhead readAhead=eReadAheadAllowed)
Create an InputStream::Ptr<Character> from the arguments (usually binary source) - which can be used ...
constexpr array< byte, 16 > AsRFC9562Bytes() const noexcept
Its 16 bytes in RFC 9562's order - the order its text is written in (.
static constexpr GUID FromRFC9562Bytes(span< const byte, 16 > bytes) noexcept
From its 16 bytes in RFC 9562's order: network byte order, the order its text is written in - as a uu...
nonvirtual String ToString() const
nonvirtual String ToString() const
What can be told of the machine this runs on - GetSystemConfiguration () gets it all,...
nonvirtual String ToString() const
OperatingSystem fApparentOperatingSystem
optional< GUID > fMachineID
OperatingSystem fActualOperatingSystem