Repository: Alairion/not-enough-standards
Branch: master
Commit: 9013a68ab88d
Files: 20
Total size: 189.7 KB
Directory structure:
gitextract_vd_i4h3q/
├── .clang-format
├── .github/
│ └── workflows/
│ └── common.yml
├── .gitignore
├── CMakeLists.txt
├── LICENSE
├── README.md
├── cmake/
│ └── NotEnoughStandards.cmake.in
├── include/
│ └── nes/
│ ├── named_mutex.hpp
│ ├── named_semaphore.hpp
│ ├── pipe.hpp
│ ├── process.hpp
│ ├── semaphore.hpp
│ ├── shared_library.hpp
│ ├── shared_memory.hpp
│ └── thread_pool.hpp
└── tests/
├── common.hpp
├── library.cpp
├── process.cpp
├── process_other.cpp
└── thread_pool_test.cpp
================================================
FILE CONTENTS
================================================
================================================
FILE: .clang-format
================================================
Language: Cpp
AccessModifierOffset: -4
AlignAfterOpenBracket: DontAlign
AlignArrayOfStructures: Left
AlignConsecutiveAssignments: None
AlignConsecutiveBitFields: None
AlignConsecutiveDeclarations: None
AlignConsecutiveMacros: None
AlignEscapedNewlines: Left
AlignOperands: Align
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortEnumsOnASingleLine: false
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortLambdasOnASingleLine: None
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: MultiLine
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterCaseLabel: true
AfterClass: true
AfterControlStatement: Always
AfterEnum: true
AfterFunction: true
AfterNamespace: true
AfterObjCDeclaration: true
AfterStruct: true
AfterUnion: true
AfterExternBlock: true
BeforeCatch: true
BeforeElse: true
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeConceptDeclarations: Always
BreakBeforeBraces: Allman
BreakBeforeInheritanceComma: false
BreakInheritanceList: AfterColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeComma
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 0
CommentPragmas: '^ IWYU pragma: '
QualifierAlignment: Leave
CompactNamespaces: false
ConstructorInitializerIndentWidth: 0
ContinuationIndentWidth: 0
Cpp11BracedListStyle: true
DeriveLineEnding: true
DerivePointerAlignment: false
DisableFormat: false
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: LogicalBlock
ExperimentalAutoDetectBinPacking: false
PackConstructorInitializers: NextLine
BasedOnStyle: ''
ConstructorInitializerAllOnOneLineOrOnePerLine: false
AllowAllConstructorInitializersOnNextLine: true
FixNamespaceComments: false
IncludeBlocks: Preserve
IndentAccessModifiers: false
IndentCaseLabels: false
IndentCaseBlocks: false
IndentGotoLabels: true
IndentPPDirectives: BeforeHash
IndentExternBlock: AfterExternBlock
IndentRequiresClause: true
IndentWidth: 4
IndentWrappedFunctionNames: false
InsertBraces: true
InsertTrailingCommas: None
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
LambdaBodyIndentation: OuterScope
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakOpenParenthesis: 0
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PenaltyIndentedWhitespace: 0
PointerAlignment: Left
PPIndentWidth: -1
ReferenceAlignment: Pointer
ReflowComments: true
RemoveBracesLLVM: false
RequiresClausePosition: OwnLine
SeparateDefinitionBlocks: Leave
ShortNamespaceLines: 1
SortIncludes: Never
SortUsingDeclarations: false
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: false
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: Never
SpaceBeforeParensOptions:
AfterControlStatements: true
AfterForeachMacros: true
AfterFunctionDefinitionName: false
AfterFunctionDeclarationName: false
AfterIfMacros: true
AfterOverloadedOperator: false
AfterRequiresInClause: false
AfterRequiresInExpression: false
BeforeNonEmptyParentheses: false
SpaceAroundPointerQualifiers: Default
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: Never
SpacesInConditionalStatement: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInLineCommentPrefix:
Minimum: 1
Maximum: -1
SpacesInParentheses: false
SpacesInSquareBrackets: false
SpaceBeforeSquareBrackets: false
BitFieldColonSpacing: Both
Standard: Latest
TabWidth: 4
UseCRLF: false
UseTab: Never
================================================
FILE: .github/workflows/common.yml
================================================
name: CI
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
env:
BUILD_TYPE: Debug
jobs:
build-linux:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Configure CMake
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE:STRING=${{env.BUILD_TYPE}} -DBUILD_TESTING:BOOL=ON
- name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
- name: Test
working-directory: ${{github.workspace}}/build${{ matrix.subdir }}
run: ctest -VV -C ${{env.BUILD_TYPE}}
build-windows:
runs-on: windows-latest
steps:
- uses: actions/checkout@v3
- name: Configure CMake
run: cmake -B ${{github.workspace}}/build -DCMAKE_CONFIGURATION_TYPES:STRING=${{env.BUILD_TYPE}} -DBUILD_TESTING:BOOL=ON
- name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
- name: Test
working-directory: ${{github.workspace}}/build
run: |
Add-Content $env:GITHUB_PATH "${{github.workspace}}\build\Debug"
ctest -VV -C ${{env.BUILD_TYPE}}
================================================
FILE: .gitignore
================================================
# Prerequisites
*.d
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Fortran module files
*.mod
*.smod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app
# IDEs
.vs
*.user
out
bin
build
================================================
FILE: CMakeLists.txt
================================================
cmake_minimum_required(VERSION 3.23) # required for file sets
project(NotEnoughStandards VERSION 1.1.0)
if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR})
option(BUILD_TESTING "Build Not Enough Standards' tests" OFF)
else() # don't use caller cache
set(BUILD_TESTING OFF)
endif()
add_library(NotEnoughStandards INTERFACE)
target_compile_features(NotEnoughStandards INTERFACE cxx_std_20)
target_sources(NotEnoughStandards INTERFACE
FILE_SET HEADERS
BASE_DIRS include
FILES
include/nes/shared_library.hpp
include/nes/shared_memory.hpp
include/nes/named_mutex.hpp
include/nes/semaphore.hpp
include/nes/named_semaphore.hpp
include/nes/pipe.hpp
include/nes/process.hpp
include/nes/thread_pool.hpp
)
if(UNIX)
target_link_libraries(NotEnoughStandards INTERFACE dl)
if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL ANDROID)
target_link_libraries(NotEnoughStandards INTERFACE pthread rt)
endif()
endif()
if(BUILD_TESTING OR NOT_ENOUGH_STANDARDS_BUILD_TESTS)
include(CTest)
get_property(multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
add_executable(NotEnoughStandardsTest tests/common.hpp tests/process.cpp)
target_link_libraries(NotEnoughStandardsTest PRIVATE NotEnoughStandards)
add_executable(NotEnoughStandardsTestOther tests/common.hpp tests/process_other.cpp)
target_link_libraries(NotEnoughStandardsTestOther PRIVATE NotEnoughStandards)
add_library(NotEnoughStandardsTestLib SHARED tests/common.hpp tests/library.cpp)
set_target_properties(NotEnoughStandardsTestLib PROPERTIES PREFIX "")
target_link_libraries(NotEnoughStandardsTestLib PRIVATE NotEnoughStandards)
add_test(NAME NotEnoughStandardsTest COMMAND NotEnoughStandardsTest)
if(multi_config)
set_tests_properties(NotEnoughStandardsTest PROPERTIES WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>)
endif()
add_executable(NotEnoughStandardsThreadPoolTest tests/common.hpp tests/thread_pool_test.cpp)
target_link_libraries(NotEnoughStandardsThreadPoolTest PRIVATE NotEnoughStandards)
add_test(NAME NotEnoughStandardsThreadPoolTest COMMAND NotEnoughStandardsThreadPoolTest)
endif()
include(CMakePackageConfigHelpers)
configure_package_config_file(
${CMAKE_CURRENT_SOURCE_DIR}/cmake/NotEnoughStandards.cmake.in
${CMAKE_CURRENT_BINARY_DIR}/NotEnoughStandardsConfig.cmake
INSTALL_DESTINATION lib/cmake/NotEnoughStandards
)
write_basic_package_version_file(
${CMAKE_CURRENT_BINARY_DIR}/NotEnoughStandardsConfigVersion.cmake
VERSION ${PROJECT_VERSION}
COMPATIBILITY SameMajorVersion
)
install(TARGETS NotEnoughStandards
EXPORT NotEnoughStandardsTargets
FILE_SET HEADERS DESTINATION include
)
install(EXPORT NotEnoughStandardsTargets
DESTINATION lib/cmake/NotEnoughStandards
NAMESPACE NotEnoughStandards::
)
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/NotEnoughStandardsConfigVersion.cmake
${CMAKE_CURRENT_BINARY_DIR}/NotEnoughStandardsConfig.cmake
DESTINATION lib/cmake/NotEnoughStandards
)
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2019 Alexy Pellegrini
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
# Not Enough Standards
Not Enough Standards is a modern header-only C++17 and C++20 library that provides platform-independent utilities. The goal of this library is to extend the standard library with recurent features, such as process management, shared library loading or thread pools. To reach that goal the library is written in a very standard compliant way, from the coding-style to the naming convention.
## Features
Not Enough Standards works on any posix-compliant system and also on Windows.
* [Shared library loading](https://github.com/Alairion/not-enough-standards/wiki/shared_library.hpp)
* [Process management](https://github.com/Alairion/not-enough-standards/wiki/process.hpp)
* Inter-process communication ([pipes](https://github.com/Alairion/not-enough-standards/wiki/pipe.hpp), [shared memory](https://github.com/Alairion/not-enough-standards/wiki/shared_memory.hpp))
* Inter-process synchronization ([named mutexes](https://github.com/Alairion/not-enough-standards/wiki/named_mutex.hpp), [named semaphores](https://github.com/Alairion/not-enough-standards/wiki/names_semaphore.hpp))
* Synchronization primitives ([semaphores](https://github.com/Alairion/not-enough-standards/wiki/semaphore.hpp))
* [Thread pools](https://github.com/Alairion/not-enough-standards/wiki/thread_pool.hpp)
Check out the [Wiki](https://github.com/Alairion/not-enough-standards/wiki) for more informations.
## Installation
Not Enough Standards requires a C++17 compiler, and a C++20 compiler for thread pools.
As any header only library, Not Enough Standards is designed to be directly included in your project, by copying the files you need in your project's directory.
You may also use it as a CMake subproject using `add_subdirectory`, or by find package, and use it as any other library:
```
target_link_libraries(xxx PRIVATE NotEnoughStandards::NotEnoughStandards)
```
The files of the library are independent from each others, so if you only need one specific feature, you can use only the header that contains it.
Actually the only file with a dependency is `process.hpp` which defines more features if `pipe.hpp` is available.
## Usage
Here is a short example using Not Enough Standards:
#### main.cpp
```cpp
#include <iostream>
#include <nes/process.hpp>
int main()
{
//nes::this_process namespace can be used to modify current process or get informations about it.
std::cout << "Current process has id " << nes::this_process::get_id() << std::endl;
std::cout << "Its current directory is \"" << nes::this_process::working_directory() << "\"" << std::endl;
//Create a child process
nes::process other{"other_process", {"Hey!", "\\\"12\"\"\\\\", "\\42\\", "It's \"me\"!"}, nes::process_options::grab_stdout};
//Read the entire standard output of the child process. (nes::process_options::grab_stdout must be specified on process creation)
std::cout << other.stdout_stream().rdbuf() << std::endl;
//As a std::thread, a nes::process must be joined if it is not detached.
if(other.joinable())
other.join();
//Once joined, we can check its return code.
std::cout << "Other process ended with code: " << other.return_code() << std::endl;
}
```
#### other.cpp
```cpp
#include <iostream>
#include <nes/process.hpp>
int main(int argc, char** argv)
{
//Output some informations about this process
std::cout << "Hello world! I'm Other!\n";
std::cout << "You gave me " << argc << " arguments:";
for(int i{}; i < argc; ++i)
std::cout << "[" << argv[i] << "] ";
std::cout << '\n';
std::cout << "My working directory is \"" << nes::this_process::working_directory() << "\"" << std::endl;
}
```
#### Output
```
Current process has id 3612
Its current directory is "/..."
Hello world! I'm Other!
You gave me 5 arguments:[not_enough_standards_other.exe] [Hey!] [\"12""\\\] [\42\] [It's "me"!]
My working directory is "/..."
Other process ended with code: 0
```
## License
Not Enough Standards use the [MIT license](https://opensource.org/licenses/MIT).
================================================
FILE: cmake/NotEnoughStandards.cmake.in
================================================
@PACKAGE_INIT@
include("${CMAKE_CURRENT_LIST_DIR}/NotEnoughStandardsTargets.cmake")
check_required_components("@PROJECT_NAME@")
================================================
FILE: include/nes/named_mutex.hpp
================================================
///////////////////////////////////////////////////////////
/// Copyright 2019 Alexy Pellegrini
///
/// Permission is hereby granted, free of charge,
/// to any person obtaining a copy of this software
/// and associated documentation files (the "Software"),
/// to deal in the Software without restriction,
/// including without limitation the rights to use,
/// copy, modify, merge, publish, distribute, sublicense,
/// and/or sell copies of the Software, and to permit
/// persons to whom the Software is furnished to do so,
/// subject to the following conditions:
///
/// The above copyright notice and this permission notice
/// shall be included in all copies or substantial portions
/// of the Software.
///
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
/// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
/// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
/// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
/// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
/// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
/// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
/// OR OTHER DEALINGS IN THE SOFTWARE.
///////////////////////////////////////////////////////////
#ifndef NOT_ENOUGH_STANDARDS_NAMED_MUTEX
#define NOT_ENOUGH_STANDARDS_NAMED_MUTEX
#if defined(_WIN32)
#define NES_WIN32_NAMED_MUTEX
#ifndef NOMINMAX
#define NOMINMAX
#endif
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <Windows.h>
#elif defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))
#define NES_POSIX_NAMED_MUTEX
#include <unistd.h>
#include <pthread.h>
#include <time.h>
#include <fcntl.h>
#include <string.h>
#include <sys/mman.h>
#else
#error "Not enough standards does not support this environment."
#endif
#ifdef NES_INLINE_NAMESPACE
#define NES_INLINE_NAMESPACE_BEGIN \
inline namespace NES_INLINE_NAMESPACE \
{
#define NES_INLINE_NAMESPACE_END }
#else
#define NES_INLINE_NAMESPACE_BEGIN
#define NES_INLINE_NAMESPACE_END
#endif
#include <string>
#include <utility>
#include <stdexcept>
#include <cassert>
#include <chrono>
#if defined(NES_WIN32_NAMED_MUTEX)
namespace nes
{
NES_INLINE_NAMESPACE_BEGIN
inline constexpr const char named_mutex_root[] = "Local\\";
namespace impl
{
struct named_mutex_base
{
HANDLE create_or_open(const std::string& name)
{
const auto native_name{to_wide(named_mutex_root + name)};
HANDLE handle{CreateMutexW(nullptr, FALSE, std::data(native_name))};
if(!handle)
{
if(GetLastError() == ERROR_ACCESS_DENIED)
{
handle = OpenMutexW(SYNCHRONIZE, FALSE, std::data(native_name));
if(!handle)
{
throw std::runtime_error{"Failed to open named mutex. " + get_error_message()};
}
}
else
{
throw std::runtime_error{"Failed to create named mutex. " + get_error_message()};
}
}
return handle;
}
std::wstring to_wide(const std::string& path)
{
assert(std::size(path) < 0x7FFFFFFFu && "Wrong path.");
if(std::empty(path))
{
return {};
}
std::wstring out_path{};
out_path.resize(static_cast<std::size_t>(MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, std::data(path), static_cast<int>(std::size(path)), nullptr, 0)));
if(!MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, std::data(path), static_cast<int>(std::size(path)), std::data(out_path), static_cast<int>(std::size(out_path))))
{
throw std::runtime_error{"Failed to convert the path to wide."};
}
return out_path;
}
std::string get_error_message() const
{
return "#" + std::to_string(GetLastError());
}
};
}
class named_mutex : impl::named_mutex_base
{
public:
using native_handle_type = HANDLE;
public:
explicit named_mutex(const std::string& name)
: m_handle{create_or_open(name)}
{
}
~named_mutex()
{
CloseHandle(m_handle);
}
named_mutex(const named_mutex&) = delete;
named_mutex& operator=(const named_mutex&) = delete;
named_mutex(named_mutex&&) noexcept = delete;
named_mutex& operator=(named_mutex&&) noexcept = delete;
void lock()
{
if(WaitForSingleObject(m_handle, INFINITE) == WAIT_FAILED)
{
throw std::runtime_error{"Failed to lock mutex. " + get_error_message()};
}
}
bool try_lock()
{
return WaitForSingleObject(m_handle, 0) == WAIT_OBJECT_0;
}
void unlock()
{
ReleaseMutex(m_handle);
}
native_handle_type native_handle() const noexcept
{
return m_handle;
}
private:
native_handle_type m_handle{};
};
class timed_named_mutex : impl::named_mutex_base
{
public:
using native_handle_type = HANDLE;
public:
explicit timed_named_mutex(const std::string& name)
: m_handle{create_or_open(name)}
{
}
~timed_named_mutex()
{
CloseHandle(m_handle);
}
timed_named_mutex(const timed_named_mutex&) = delete;
timed_named_mutex& operator=(const timed_named_mutex&) = delete;
timed_named_mutex(timed_named_mutex&&) noexcept = delete;
timed_named_mutex& operator=(timed_named_mutex&&) noexcept = delete;
void lock()
{
if(WaitForSingleObject(m_handle, INFINITE) == WAIT_FAILED)
{
throw std::runtime_error{"Failed to lock mutex. " + get_error_message()};
}
}
bool try_lock()
{
return WaitForSingleObject(m_handle, 0) == WAIT_OBJECT_0;
}
template<class Rep, class Period>
bool try_lock_for(const std::chrono::duration<Rep, Period>& timeout)
{
return WaitForSingleObject(m_handle, static_cast<DWORD>(std::chrono::duration_cast<std::chrono::milliseconds>(timeout).count())) == WAIT_OBJECT_0;
}
template<class Clock, class Duration>
bool try_lock_until(const std::chrono::time_point<Clock, Duration>& time_point)
{
const auto current_time{Clock::now()};
if(time_point < current_time)
{
return try_lock();
}
return try_lock_for(time_point - current_time);
}
void unlock()
{
ReleaseMutex(m_handle);
}
native_handle_type native_handle() const noexcept
{
return m_handle;
}
private:
native_handle_type m_handle{};
};
class recursive_named_mutex : public named_mutex
{
};
class recursive_timed_named_mutex : public timed_named_mutex
{
};
NES_INLINE_NAMESPACE_END
}
#elif defined(NES_POSIX_NAMED_MUTEX)
namespace nes
{
NES_INLINE_NAMESPACE_BEGIN
inline constexpr const char named_mutex_root[] = "/";
namespace impl
{
struct mutex_data
{
std::uint64_t opened{};
pthread_mutex_t mutex{};
};
struct mutex_base
{
int memory{-1};
mutex_data* data{};
};
inline mutex_base create_or_open_mutex(const std::string& name, bool recursive)
{
const auto native_name{named_mutex_root + name};
int shm_handle{shm_open(std::data(native_name), O_RDWR | O_CREAT, 0660)};
if(shm_handle == -1)
{
throw std::runtime_error{"Failed to allocate space for named mutex. " + std::string{strerror(errno)}};
}
if(ftruncate(shm_handle, sizeof(mutex_data)) == -1)
{
close(shm_handle);
throw std::runtime_error{"Failed to truncate shared memory for named mutex. " + std::string{strerror(errno)}};
}
auto* ptr{reinterpret_cast<mutex_data*>(mmap(nullptr, sizeof(mutex_data), PROT_READ | PROT_WRITE, MAP_SHARED, shm_handle, 0))};
if(ptr == MAP_FAILED)
{
close(shm_handle);
throw std::runtime_error{"Failed to map shared memory for named mutex. " + std::string{strerror(errno)}};
}
if(!ptr->opened)
{
pthread_mutexattr_t attr{};
pthread_mutexattr_init(&attr);
auto clean_and_throw = [ptr, shm_handle, &attr](const std::string& error_str, int error)
{
munmap(ptr, sizeof(mutex_data));
close(shm_handle);
pthread_mutexattr_destroy(&attr);
throw std::runtime_error{error_str + std::string{strerror(error)}};
};
if(auto error = pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED); error != 0)
{
clean_and_throw("Failed to set process shared attribute of mutex. ", error);
}
if(auto error = pthread_mutexattr_setrobust(&attr, PTHREAD_MUTEX_ROBUST); error != 0)
{
clean_and_throw("Failed to set robust attribute of mutex. ", error);
}
if(recursive)
{
if(auto error = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); error != 0)
{
clean_and_throw("Failed to set recursive attribute of mutex. ", error);
}
}
if(auto error = pthread_mutex_init(&ptr->mutex, &attr); error != 0)
{
clean_and_throw("Failed to init mutex. ", error);
}
pthread_mutexattr_destroy(&attr);
ptr->opened = 1;
}
return mutex_base{shm_handle, ptr};
}
inline void close_mutex(mutex_base& mutex)
{
if(mutex.data)
{
munmap(std::exchange(mutex.data, nullptr), sizeof(mutex_data));
}
if(mutex.memory != -1)
{
close(std::exchange(mutex.memory, -1));
}
}
inline void lock_mutex(mutex_base& mutex)
{
auto error{pthread_mutex_lock(&mutex.data->mutex)};
if(error == EOWNERDEAD)
{
pthread_mutex_consistent(&mutex.data->mutex);
}
else if(error != 0)
{
throw std::runtime_error{"Failed to lock mutex. " + std::string{strerror(error)}};
}
}
inline bool try_lock_mutex(mutex_base& mutex)
{
auto error{pthread_mutex_trylock(&mutex.data->mutex)};
if(error == EOWNERDEAD)
{
pthread_mutex_consistent(&mutex.data->mutex);
return true;
}
return !error;
}
inline bool try_lock_mutex_until(mutex_base& mutex, const timespec& time)
{
auto error{pthread_mutex_timedlock(&mutex.data->mutex, &time)};
if(error == EOWNERDEAD)
{
pthread_mutex_consistent(&mutex.data->mutex);
return true;
}
return !error;
}
}
class named_mutex
{
public:
using native_handle_type = pthread_mutex_t*;
public:
explicit named_mutex(const std::string& name)
: m_handle{impl::create_or_open_mutex(name, false)}
{
}
~named_mutex()
{
impl::close_mutex(m_handle);
}
named_mutex(const named_mutex&) = delete;
named_mutex& operator=(const named_mutex&) = delete;
named_mutex(named_mutex&&) noexcept = delete;
named_mutex& operator=(named_mutex&&) noexcept = delete;
void lock()
{
impl::lock_mutex(m_handle);
}
bool try_lock()
{
return impl::try_lock_mutex(m_handle);
}
void unlock()
{
pthread_mutex_unlock(&m_handle.data->mutex);
}
native_handle_type native_handle() const noexcept
{
return &m_handle.data->mutex;
}
private:
impl::mutex_base m_handle{};
};
class timed_named_mutex
{
public:
using native_handle_type = pthread_mutex_t*;
public:
explicit timed_named_mutex(const std::string& name)
: m_handle{impl::create_or_open_mutex(name, false)}
{
}
~timed_named_mutex()
{
impl::close_mutex(m_handle);
}
timed_named_mutex(const timed_named_mutex&) = delete;
timed_named_mutex& operator=(const timed_named_mutex&) = delete;
timed_named_mutex(timed_named_mutex&&) noexcept = delete;
timed_named_mutex& operator=(timed_named_mutex&&) noexcept = delete;
void lock()
{
impl::lock_mutex(m_handle);
}
bool try_lock()
{
return impl::try_lock_mutex(m_handle);
}
template<class Rep, class Period>
bool try_lock_for(const std::chrono::duration<Rep, Period>& timeout)
{
return try_lock_until(std::chrono::system_clock::now() + timeout);
}
template<class Clock, class Duration>
bool try_lock_until(const std::chrono::time_point<Clock, Duration>& time_point)
{
const auto seconds{std::chrono::time_point_cast<std::chrono::seconds>(time_point)};
const auto nanoseconds{std::chrono::duration_cast<std::chrono::nanoseconds>(time_point - seconds)};
timespec time{};
time.tv_sec = static_cast<std::time_t>(seconds.time_since_epoch().count());
time.tv_nsec = static_cast<long>(nanoseconds.count());
return impl::try_lock_mutex_until(m_handle, time);
}
void unlock()
{
pthread_mutex_unlock(&m_handle.data->mutex);
}
native_handle_type native_handle() const noexcept
{
return &m_handle.data->mutex;
}
private:
impl::mutex_base m_handle{};
};
class recursive_named_mutex
{
public:
using native_handle_type = pthread_mutex_t*;
public:
explicit recursive_named_mutex(const std::string& name)
: m_handle{impl::create_or_open_mutex(name, true)}
{
}
~recursive_named_mutex()
{
impl::close_mutex(m_handle);
}
recursive_named_mutex(const recursive_named_mutex&) = delete;
recursive_named_mutex& operator=(const recursive_named_mutex&) = delete;
recursive_named_mutex(recursive_named_mutex&&) noexcept = delete;
recursive_named_mutex& operator=(recursive_named_mutex&&) noexcept = delete;
void lock()
{
impl::lock_mutex(m_handle);
}
bool try_lock()
{
return impl::try_lock_mutex(m_handle);
}
void unlock()
{
pthread_mutex_unlock(&m_handle.data->mutex);
}
native_handle_type native_handle() const noexcept
{
return &m_handle.data->mutex;
}
private:
impl::mutex_base m_handle{};
};
class recursive_timed_named_mutex
{
public:
using native_handle_type = pthread_mutex_t*;
public:
explicit recursive_timed_named_mutex(const std::string& name)
: m_handle{impl::create_or_open_mutex(name, true)}
{
}
~recursive_timed_named_mutex()
{
impl::close_mutex(m_handle);
}
recursive_timed_named_mutex(const recursive_timed_named_mutex&) = delete;
recursive_timed_named_mutex& operator=(const recursive_timed_named_mutex&) = delete;
recursive_timed_named_mutex(recursive_timed_named_mutex&&) noexcept = delete;
recursive_timed_named_mutex& operator=(recursive_timed_named_mutex&&) noexcept = delete;
void lock()
{
impl::lock_mutex(m_handle);
}
bool try_lock()
{
return impl::try_lock_mutex(m_handle);
}
template<class Rep, class Period>
bool try_lock_for(const std::chrono::duration<Rep, Period>& timeout)
{
return try_lock_until(std::chrono::system_clock::now() + timeout);
}
template<class Clock, class Duration>
bool try_lock_until(const std::chrono::time_point<Clock, Duration>& time_point)
{
const auto seconds{std::chrono::time_point_cast<std::chrono::seconds>(time_point)};
const auto nanoseconds{std::chrono::duration_cast<std::chrono::nanoseconds>(time_point - seconds)};
timespec time{};
time.tv_sec = static_cast<std::time_t>(seconds.time_since_epoch().count());
time.tv_nsec = static_cast<long>(nanoseconds.count());
return impl::try_lock_mutex_until(m_handle, time);
}
void unlock()
{
pthread_mutex_unlock(&m_handle.data->mutex);
}
native_handle_type native_handle() const noexcept
{
return &m_handle.data->mutex;
}
private:
impl::mutex_base m_handle{};
};
NES_INLINE_NAMESPACE_END
}
#endif
#endif
================================================
FILE: include/nes/named_semaphore.hpp
================================================
///////////////////////////////////////////////////////////
/// Copyright 2019 Alexy Pellegrini
///
/// Permission is hereby granted, free of charge,
/// to any person obtaining a copy of this software
/// and associated documentation files (the "Software"),
/// to deal in the Software without restriction,
/// including without limitation the rights to use,
/// copy, modify, merge, publish, distribute, sublicense,
/// and/or sell copies of the Software, and to permit
/// persons to whom the Software is furnished to do so,
/// subject to the following conditions:
///
/// The above copyright notice and this permission notice
/// shall be included in all copies or substantial portions
/// of the Software.
///
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
/// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
/// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
/// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
/// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
/// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
/// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
/// OR OTHER DEALINGS IN THE SOFTWARE.
///////////////////////////////////////////////////////////
#ifndef NOT_ENOUGH_STANDARDS_NAMED_SEMAPHORE
#define NOT_ENOUGH_STANDARDS_NAMED_SEMAPHORE
#if defined(_WIN32)
#define NES_WIN32_NAMED_SEMAPHORE
#ifndef NOMINMAX
#define NOMINMAX
#endif
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <Windows.h>
#elif defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))
#define NES_POSIX_NAMED_SEMAPHORE
#include <unistd.h>
#include <string.h>
#include <semaphore.h>
#include <fcntl.h>
#else
#error "Not enough standards does not support this environment."
#endif
#ifdef NES_INLINE_NAMESPACE
#define NES_INLINE_NAMESPACE_BEGIN \
inline namespace NES_INLINE_NAMESPACE \
{
#define NES_INLINE_NAMESPACE_END }
#else
#define NES_INLINE_NAMESPACE_BEGIN
#define NES_INLINE_NAMESPACE_END
#endif
#include <cassert>
#include <string>
#include <chrono>
#include <limits>
#include <utility>
#include <stdexcept>
#if defined(NES_WIN32_NAMED_SEMAPHORE)
namespace nes
{
NES_INLINE_NAMESPACE_BEGIN
inline constexpr const char named_semaphore_root[] = "Local\\";
class named_semaphore
{
public:
using native_handle_type = HANDLE;
public:
explicit named_semaphore(const std::string& name, std::size_t initial_count = 0)
{
const auto native_name{to_wide(named_semaphore_root + name)};
m_handle = CreateSemaphoreW(nullptr, static_cast<LONG>(initial_count), std::numeric_limits<LONG>::max(), std::data(native_name));
if(!m_handle)
{
if(GetLastError() == ERROR_ACCESS_DENIED)
{
m_handle = OpenSemaphoreW(SYNCHRONIZE, FALSE, std::data(native_name));
if(!m_handle)
{
throw std::runtime_error{"Failed to open semaphore. " + get_error_message()};
}
}
else
{
throw std::runtime_error{"Failed to create semaphore. " + get_error_message()};
}
}
}
~named_semaphore()
{
CloseHandle(m_handle);
}
named_semaphore(const named_semaphore&) = delete;
named_semaphore& operator=(const named_semaphore&) = delete;
named_semaphore(named_semaphore&& other) noexcept = delete;
named_semaphore& operator=(named_semaphore&& other) noexcept = delete;
void acquire()
{
if(WaitForSingleObject(m_handle, INFINITE))
{
throw std::runtime_error{"Failed to decrement semaphore count. " + get_error_message()};
}
}
bool try_acquire()
{
return WaitForSingleObject(m_handle, 0) == WAIT_OBJECT_0;
}
void release()
{
if(!ReleaseSemaphore(m_handle, 1, nullptr))
{
throw std::runtime_error{"Failed to increment semaphore count. " + get_error_message()};
}
}
native_handle_type native_handle() const noexcept
{
return m_handle;
}
private:
std::wstring to_wide(const std::string& path)
{
assert(std::size(path) < 0x7FFFFFFFu && "Wrong path.");
if(std::empty(path))
{
return {};
}
std::wstring out_path{};
out_path.resize(static_cast<std::size_t>(MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, std::data(path), static_cast<int>(std::size(path)), nullptr, 0)));
if(!MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, std::data(path), static_cast<int>(std::size(path)), std::data(out_path), static_cast<int>(std::size(out_path))))
{
throw std::runtime_error{"Failed to convert the path to wide."};
}
return out_path;
}
std::string get_error_message() const
{
return "#" + std::to_string(GetLastError());
}
private:
native_handle_type m_handle{};
};
class timed_named_semaphore
{
public:
using native_handle_type = HANDLE;
public:
explicit timed_named_semaphore(const std::string& name, std::size_t initial_count = 0)
{
const auto native_name{to_wide(named_semaphore_root + name)};
m_handle = CreateSemaphoreW(nullptr, static_cast<LONG>(initial_count), std::numeric_limits<LONG>::max(), std::data(native_name));
if(!m_handle)
{
if(GetLastError() == ERROR_ACCESS_DENIED)
{
m_handle = OpenSemaphoreW(SYNCHRONIZE, FALSE, std::data(native_name));
if(!m_handle)
{
throw std::runtime_error{"Failed to open semaphore. " + get_error_message()};
}
}
else
{
throw std::runtime_error{"Failed to create semaphore. " + get_error_message()};
}
}
}
~timed_named_semaphore()
{
CloseHandle(m_handle);
}
timed_named_semaphore(const timed_named_semaphore&) = delete;
timed_named_semaphore& operator=(const timed_named_semaphore&) = delete;
timed_named_semaphore(timed_named_semaphore&& other) noexcept = delete;
timed_named_semaphore& operator=(timed_named_semaphore&& other) noexcept = delete;
void acquire()
{
if(WaitForSingleObject(m_handle, INFINITE))
{
throw std::runtime_error{"Failed to decrement semaphore count. " + get_error_message()};
}
}
bool try_acquire()
{
return WaitForSingleObject(m_handle, 0) == WAIT_OBJECT_0;
}
template<class Rep, class Period>
bool try_acquire_for(const std::chrono::duration<Rep, Period>& timeout)
{
return WaitForSingleObject(m_handle, std::chrono::duration_cast<std::chrono::milliseconds>(timeout).count()) == WAIT_OBJECT_0;
}
template<class Clock, class Duration>
bool try_acquire_until(const std::chrono::time_point<Clock, Duration>& time_point)
{
const auto current_time{Clock::now()};
if(time_point < current_time)
{
return try_acquire();
}
return try_acquire_for(time_point - current_time);
}
void release()
{
if(!ReleaseSemaphore(m_handle, 1, nullptr))
{
throw std::runtime_error{"Failed to increment semaphore count. " + get_error_message()};
}
}
native_handle_type native_handle() const noexcept
{
return m_handle;
}
private:
std::wstring to_wide(const std::string& path)
{
assert(std::size(path) < 0x7FFFFFFFu && "Wrong path.");
if(std::empty(path))
{
return {};
}
std::wstring out_path{};
out_path.resize(static_cast<std::size_t>(MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, std::data(path), static_cast<int>(std::size(path)), nullptr, 0)));
if(!MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, std::data(path), static_cast<int>(std::size(path)), std::data(out_path), static_cast<int>(std::size(out_path))))
{
throw std::runtime_error{"Failed to convert the path to wide."};
}
return out_path;
}
std::string get_error_message() const
{
return "#" + std::to_string(GetLastError());
}
private:
native_handle_type m_handle{};
};
NES_INLINE_NAMESPACE_END
}
#elif defined(NES_POSIX_NAMED_SEMAPHORE)
namespace nes
{
NES_INLINE_NAMESPACE_BEGIN
inline constexpr const char named_semaphore_root[] = "/";
class named_semaphore
{
public:
using native_handle_type = sem_t*;
public:
explicit named_semaphore(const std::string& name, std::size_t initial_count = 0)
{
const auto native_name{named_semaphore_root + name};
m_handle = sem_open(std::data(native_name), O_CREAT, 0660, initial_count);
if(m_handle == SEM_FAILED)
{
throw std::runtime_error{"Failed to create semaphore. " + std::string{strerror(errno)}};
}
}
~named_semaphore()
{
sem_close(m_handle);
}
named_semaphore(const named_semaphore&) = delete;
named_semaphore& operator=(const named_semaphore&) = delete;
named_semaphore(named_semaphore&& other) noexcept = delete;
named_semaphore& operator=(named_semaphore&& other) noexcept = delete;
void acquire()
{
if(sem_wait(m_handle) == -1)
{
throw std::runtime_error{"Failed to decrement semaphore count. " + std::string{strerror(errno)}};
}
}
bool try_acquire()
{
return !sem_trywait(m_handle);
}
void release()
{
if(sem_post(m_handle) == -1)
{
throw std::runtime_error{"Failed to increment semaphore count. " + std::string{strerror(errno)}};
}
}
native_handle_type native_handle() const noexcept
{
return m_handle;
}
private:
native_handle_type m_handle{};
};
class timed_named_semaphore
{
public:
using native_handle_type = sem_t*;
public:
explicit timed_named_semaphore(const std::string& name, std::size_t initial_count = 0)
{
const auto native_name{named_semaphore_root + name};
m_handle = sem_open(std::data(native_name), O_CREAT, 0660, initial_count);
if(m_handle == SEM_FAILED)
{
throw std::runtime_error{"Failed to create semaphore. " + std::string{strerror(errno)}};
}
}
~timed_named_semaphore()
{
sem_close(m_handle);
}
timed_named_semaphore(const timed_named_semaphore&) = delete;
timed_named_semaphore& operator=(const timed_named_semaphore&) = delete;
timed_named_semaphore(timed_named_semaphore&& other) noexcept = delete;
timed_named_semaphore& operator=(timed_named_semaphore&& other) noexcept = delete;
void acquire()
{
if(sem_wait(m_handle) == -1)
{
throw std::runtime_error{"Failed to decrement semaphore count. " + std::string{strerror(errno)}};
}
}
bool try_acquire()
{
return !sem_trywait(m_handle);
}
template<class Rep, class Period>
bool try_lock_for(const std::chrono::duration<Rep, Period>& timeout)
{
return try_lock_until(std::chrono::system_clock::now() + timeout);
}
template<class Clock, class Duration>
bool try_lock_until(const std::chrono::time_point<Clock, Duration>& time_point)
{
const auto seconds{std::chrono::time_point_cast<std::chrono::seconds>(time_point)};
const auto nanoseconds{std::chrono::duration_cast<std::chrono::nanoseconds>(time_point - seconds)};
timespec time{};
time.tv_sec = static_cast<std::time_t>(seconds.time_since_epoch().count());
time.tv_nsec = static_cast<long>(nanoseconds.count());
return !sem_timedwait(m_handle, &time);
}
void release()
{
if(sem_post(m_handle) == -1)
{
throw std::runtime_error{"Failed to increment semaphore count. " + std::string{strerror(errno)}};
}
}
native_handle_type native_handle() const noexcept
{
return m_handle;
}
private:
native_handle_type m_handle{};
};
NES_INLINE_NAMESPACE_END
}
#endif
#endif
================================================
FILE: include/nes/pipe.hpp
================================================
///////////////////////////////////////////////////////////
/// Copyright 2019 Alexy Pellegrini
///
/// Permission is hereby granted, free of charge,
/// to any person obtaining a copy of this software
/// and associated documentation files (the "Software"),
/// to deal in the Software without restriction,
/// including without limitation the rights to use,
/// copy, modify, merge, publish, distribute, sublicense,
/// and/or sell copies of the Software, and to permit
/// persons to whom the Software is furnished to do so,
/// subject to the following conditions:
///
/// The above copyright notice and this permission notice
/// shall be included in all copies or substantial portions
/// of the Software.
///
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
/// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
/// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
/// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
/// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
/// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
/// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
/// OR OTHER DEALINGS IN THE SOFTWARE.
///////////////////////////////////////////////////////////
#ifndef NOT_ENOUGH_STANDARDS_PIPE
#define NOT_ENOUGH_STANDARDS_PIPE
#if defined(_WIN32)
#define NES_WIN32_PIPE
#ifndef NOMINMAX
#define NOMINMAX
#endif
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <Windows.h>
#elif defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))
#define NES_POSIX_PIPE
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#else
#error "Not enough standards does not support this environment."
#endif
#ifdef NES_INLINE_NAMESPACE
#define NES_INLINE_NAMESPACE_BEGIN \
inline namespace NES_INLINE_NAMESPACE \
{
#define NES_INLINE_NAMESPACE_END }
#else
#define NES_INLINE_NAMESPACE_BEGIN
#define NES_INLINE_NAMESPACE_END
#endif
#include <vector>
#include <algorithm>
#include <streambuf>
#include <istream>
#include <ostream>
#include <memory>
#include <cassert>
#include <utility>
#if defined(NES_WIN32_PIPE)
namespace nes
{
NES_INLINE_NAMESPACE_BEGIN
inline constexpr const char pipe_root[] = "\\\\.\\pipe\\";
template<typename CharT, typename Traits>
class basic_pipe_istream;
template<typename CharT, typename Traits>
class basic_pipe_ostream;
template<typename CharT = char, typename Traits = std::char_traits<CharT>>
std::pair<basic_pipe_istream<CharT, Traits>, basic_pipe_ostream<CharT, Traits>> make_anonymous_pipe();
template<typename CharT, typename Traits = std::char_traits<CharT>>
class basic_pipe_streambuf : public std::basic_streambuf<CharT, Traits>
{
private:
using parent_type = std::basic_streambuf<CharT, Traits>;
public:
using char_type = CharT;
using traits_type = Traits;
using int_type = typename Traits::int_type;
using pos_type = typename Traits::pos_type;
using off_type = typename Traits::off_type;
public:
static constexpr std::size_t buf_size{1024};
public:
basic_pipe_streambuf() = default;
explicit basic_pipe_streambuf(const std::string& name, std::ios_base::openmode mode)
{
open(name, mode);
}
virtual ~basic_pipe_streambuf()
{
close();
}
basic_pipe_streambuf(const basic_pipe_streambuf&) = delete;
basic_pipe_streambuf& operator=(const basic_pipe_streambuf&) = delete;
basic_pipe_streambuf(basic_pipe_streambuf&& other) noexcept
: parent_type{other}
, m_buffer{std::move(other.m_buffer)}
, m_handle{std::exchange(other.m_handle, INVALID_HANDLE_VALUE)}
, m_mode{std::exchange(other.m_mode, std::ios_base::openmode{})}
{
}
basic_pipe_streambuf& operator=(basic_pipe_streambuf&& other) noexcept
{
parent_type::operator=(other);
m_buffer = std::move(other.m_buffer);
m_handle = std::exchange(other.m_handle, m_handle);
m_mode = std::exchange(other.m_mode, m_mode);
return *this;
}
bool open(const std::string& name, std::ios_base::openmode mode)
{
assert(!((mode & std::ios_base::in) && (mode & std::ios_base::out)) && "nes::basic_pipe_streambuf::open called with mode = std::ios_base::in | std::ios_base::out.");
close();
const auto native_name{to_wide(pipe_root + name)};
DWORD native_mode{mode & std::ios_base::in ? GENERIC_READ : GENERIC_WRITE};
HANDLE handle = CreateFileW(std::data(native_name), native_mode, 0, nullptr, OPEN_EXISTING, 0, nullptr);
if(handle == INVALID_HANDLE_VALUE)
{
if(GetLastError() == ERROR_FILE_NOT_FOUND)
{
native_mode = mode & std::ios_base::in ? PIPE_ACCESS_INBOUND : PIPE_ACCESS_OUTBOUND;
handle = CreateNamedPipeW(std::data(native_name), native_mode, PIPE_READMODE_BYTE | PIPE_WAIT, 1, buf_size, buf_size, 0, nullptr);
if(handle == INVALID_HANDLE_VALUE)
{
return false;
}
if(!ConnectNamedPipe(handle, nullptr))
{
CloseHandle(handle);
return false;
}
}
}
m_buffer.resize(buf_size);
parent_type::setp(std::data(m_buffer), std::data(m_buffer) + buf_size);
m_handle = handle;
m_mode = mode;
return true;
}
bool is_open() const noexcept
{
return m_handle != INVALID_HANDLE_VALUE;
}
void close()
{
if(is_open())
{
sync();
m_mode = std::ios_base::openmode{};
CloseHandle(std::exchange(m_handle, INVALID_HANDLE_VALUE));
parent_type::setp(nullptr, nullptr);
parent_type::setg(nullptr, nullptr, nullptr);
}
}
private:
friend class process;
friend std::pair<basic_pipe_istream<char_type, traits_type>, basic_pipe_ostream<char_type, traits_type>> make_anonymous_pipe<char_type, traits_type>();
basic_pipe_streambuf(HANDLE handle, std::ios_base::openmode mode)
: m_handle{handle}
, m_mode{mode}
{
m_buffer.resize(buf_size);
parent_type::setp(std::data(m_buffer), std::data(m_buffer) + buf_size);
}
protected:
virtual int sync() override
{
if(m_mode & std::ios_base::out)
{
const std::ptrdiff_t count{parent_type::pptr() - parent_type::pbase()};
DWORD written{};
if(!WriteFile(m_handle, reinterpret_cast<const CHAR*>(std::data(m_buffer)), static_cast<DWORD>(count) * sizeof(char_type), &written, nullptr))
{
return -1;
}
parent_type::setp(std::data(m_buffer), std::data(m_buffer) + buf_size);
}
return 0;
}
virtual int_type overflow(int_type c = traits_type::eof()) override
{
assert(m_mode & std::ios_base::out && "Write operation on a read only pipe.");
if(traits_type::eq_int_type(c, traits_type::eof()))
{
DWORD written{};
if(!WriteFile(m_handle, reinterpret_cast<const CHAR*>(std::data(m_buffer)), static_cast<DWORD>(buf_size) * sizeof(char_type), &written, nullptr))
{
return traits_type::eof();
}
parent_type::setp(std::data(m_buffer), std::data(m_buffer) + buf_size);
}
else
{
*parent_type::pptr() = traits_type::to_char_type(c);
parent_type::pbump(1);
}
return traits_type::not_eof(c);
}
virtual std::streamsize xsputn(const char_type* s, std::streamsize count) override
{
assert(m_mode & std::ios_base::out && "Write operation on a read only pipe.");
sync(); // empty putarea before performing a write
DWORD written{};
if(!WriteFile(m_handle, reinterpret_cast<const CHAR*>(s), static_cast<DWORD>(count) * sizeof(char_type), &written, nullptr))
{
return 0;
}
return static_cast<std::streamsize>(written);
}
virtual int_type underflow() override
{
assert(m_mode & std::ios_base::in && "Read operation on a write only pipe.");
if(parent_type::gptr() == parent_type::egptr())
{
DWORD read{};
if(!ReadFile(m_handle, reinterpret_cast<CHAR*>(std::data(m_buffer)), static_cast<DWORD>(buf_size * sizeof(char_type)), &read, nullptr) || read == 0)
{
return traits_type::eof();
}
parent_type::setg(std::data(m_buffer), std::data(m_buffer), std::data(m_buffer) + (read / sizeof(char_type)));
}
return traits_type::to_int_type(*parent_type::gptr());
}
virtual std::streamsize xsgetn(char_type* s, std::streamsize count) override
{
assert(m_mode & std::ios_base::in && "Read operation on a write only pipe.");
// to support mixing formatted and unformatted input, we have to flush the get buffer
const std::ptrdiff_t available = parent_type::egptr() - parent_type::gptr();
if(available > 0)
{
std::copy_n(parent_type::gptr(), (std::min)(available, count), s);
// if we still have buffered input update gptr
if(available > count)
{
parent_type::setg(parent_type::eback(), parent_type::gptr() + count, parent_type::egptr());
return count;
}
// resets get buffer, this will force an underflow on next formatted input
parent_type::setg(nullptr, nullptr, nullptr);
if(count == available)
{
return count;
}
// perform a read to fulfill the requested count if possible
count -= available;
s += available;
}
DWORD read{};
if(!ReadFile(m_handle, reinterpret_cast<CHAR*>(s), static_cast<DWORD>(count) * sizeof(char_type), &read, nullptr))
{
return 0;
}
return static_cast<std::streamsize>(read / sizeof(char_type)) + available;
}
private:
std::wstring to_wide(std::string path)
{
assert(std::size(path) < 0x7FFFFFFFu && "Wrong path.");
if(std::empty(path))
{
return {};
}
std::transform(std::begin(path), std::end(path), std::begin(path), [](char c)
{
return c == '/' ? '\\' : c;
});
std::wstring out_path{};
out_path.resize(static_cast<std::size_t>(MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, std::data(path), static_cast<int>(std::size(path)), nullptr, 0)));
if(!MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, std::data(path), static_cast<int>(std::size(path)), std::data(out_path), static_cast<int>(std::size(out_path))))
{
throw std::runtime_error{"Failed to convert the path to wide."};
}
return out_path;
}
private:
std::vector<CharT> m_buffer{};
HANDLE m_handle{INVALID_HANDLE_VALUE};
std::ios_base::openmode m_mode{};
};
template<typename CharT, typename Traits = std::char_traits<CharT>>
class basic_pipe_istream : public std::basic_istream<CharT, Traits>
{
private:
using parent_type = std::basic_istream<CharT, Traits>;
public:
using char_type = CharT;
using traits_type = Traits;
using int_type = typename Traits::int_type;
using pos_type = typename Traits::pos_type;
using off_type = typename Traits::off_type;
public:
basic_pipe_istream() = default;
explicit basic_pipe_istream(const std::string& name, std::ios_base::openmode mode = std::ios_base::in)
: parent_type{nullptr}
{
parent_type::rdbuf(m_buffer.get());
open(name, mode);
}
virtual ~basic_pipe_istream() = default;
basic_pipe_istream(const basic_pipe_istream&) = delete;
basic_pipe_istream& operator=(const basic_pipe_istream&) = delete;
basic_pipe_istream(basic_pipe_istream&& other) noexcept
: parent_type{std::move(other)}
{
std::swap(m_buffer, other.m_buffer);
parent_type::rdbuf(m_buffer.get());
}
basic_pipe_istream& operator=(basic_pipe_istream&& other) noexcept
{
parent_type::operator=(std::move(other));
std::swap(m_buffer, other.m_buffer);
parent_type::rdbuf(m_buffer.get());
return *this;
}
void open(const std::string& name, std::ios_base::openmode mode = std::ios_base::in)
{
m_buffer->open(name, mode);
parent_type::clear(m_buffer->is_open() ? std::ios_base::goodbit : std::ios_base::failbit);
}
bool is_open() const noexcept
{
return m_buffer->is_open();
}
void close()
{
m_buffer->close();
}
basic_pipe_streambuf<char_type, traits_type>* rdbuf() const noexcept
{
return m_buffer.get();
}
private:
friend class process;
friend std::pair<basic_pipe_istream<char_type, traits_type>, basic_pipe_ostream<char_type, traits_type>> make_anonymous_pipe<char_type, traits_type>();
basic_pipe_istream(basic_pipe_streambuf<char_type, traits_type> buffer)
: parent_type{nullptr}
, m_buffer{std::make_unique<basic_pipe_streambuf<char_type, traits_type>>(std::move(buffer))}
{
parent_type::rdbuf(m_buffer.get());
}
private:
std::unique_ptr<basic_pipe_streambuf<char_type, traits_type>> m_buffer{std::make_unique<basic_pipe_streambuf<char_type, traits_type>>()};
};
template<typename CharT, typename Traits = std::char_traits<CharT>>
class basic_pipe_ostream : public std::basic_ostream<CharT, Traits>
{
private:
using parent_type = std::basic_ostream<CharT, Traits>;
public:
using char_type = CharT;
using traits_type = Traits;
using int_type = typename Traits::int_type;
using pos_type = typename Traits::pos_type;
using off_type = typename Traits::off_type;
public:
basic_pipe_ostream() = default;
explicit basic_pipe_ostream(const std::string& name, std::ios_base::openmode mode = std::ios_base::out)
: parent_type{nullptr}
{
parent_type::rdbuf(m_buffer.get());
open(name, mode);
}
virtual ~basic_pipe_ostream() = default;
basic_pipe_ostream(const basic_pipe_ostream&) = delete;
basic_pipe_ostream& operator=(const basic_pipe_ostream&) = delete;
basic_pipe_ostream(basic_pipe_ostream&& other) noexcept
: parent_type{std::move(other)}
{
std::swap(m_buffer, other.m_buffer);
parent_type::rdbuf(m_buffer.get());
}
basic_pipe_ostream& operator=(basic_pipe_ostream&& other) noexcept
{
parent_type::operator=(std::move(other));
std::swap(m_buffer, other.m_buffer);
parent_type::rdbuf(m_buffer.get());
return *this;
}
void open(const std::string& name, std::ios_base::openmode mode = std::ios_base::out)
{
m_buffer->open(name, mode);
parent_type::clear(m_buffer->is_open() ? std::ios_base::goodbit : std::ios_base::failbit);
}
bool is_open() const noexcept
{
return m_buffer->is_open();
}
void close()
{
m_buffer->close();
}
basic_pipe_streambuf<char_type, traits_type>* rdbuf() const noexcept
{
return m_buffer.get();
}
private:
friend class process;
friend std::pair<basic_pipe_istream<char_type, traits_type>, basic_pipe_ostream<char_type, traits_type>> make_anonymous_pipe<char_type, traits_type>();
basic_pipe_ostream(basic_pipe_streambuf<char_type, traits_type> buffer)
: parent_type{nullptr}
, m_buffer{std::make_unique<basic_pipe_streambuf<char_type, traits_type>>(std::move(buffer))}
{
parent_type::rdbuf(m_buffer.get());
}
private:
std::unique_ptr<basic_pipe_streambuf<char_type, traits_type>> m_buffer{std::make_unique<basic_pipe_streambuf<char_type, traits_type>>()};
};
template<typename CharT, typename Traits>
std::pair<basic_pipe_istream<CharT, Traits>, basic_pipe_ostream<CharT, Traits>> make_anonymous_pipe()
{
HANDLE input{};
HANDLE output{};
if(!CreatePipe(&input, &output, nullptr, 0))
{
throw std::runtime_error{"Failed to create pipe"};
}
// clang-format off
return std::make_pair(
basic_pipe_istream<CharT, Traits>{basic_pipe_streambuf<CharT, Traits>{input, std::ios_base::in}},
basic_pipe_ostream<CharT, Traits>{basic_pipe_streambuf<CharT, Traits>{output, std::ios_base::out}});
// clang-format on
}
using pipe_streambuf = basic_pipe_streambuf<char>;
using pipe_istream = basic_pipe_istream<char>;
using pipe_ostream = basic_pipe_ostream<char>;
NES_INLINE_NAMESPACE_END
}
#elif defined(NES_POSIX_PIPE)
namespace nes
{
NES_INLINE_NAMESPACE_BEGIN
inline constexpr const char pipe_root[] = "/tmp/";
template<typename CharT, typename Traits>
class basic_pipe_istream;
template<typename CharT, typename Traits>
class basic_pipe_ostream;
template<typename CharT = char, typename Traits = std::char_traits<CharT>>
std::pair<basic_pipe_istream<CharT, Traits>, basic_pipe_ostream<CharT, Traits>> make_anonymous_pipe();
template<typename CharT, typename Traits = std::char_traits<CharT>>
class basic_pipe_streambuf : public std::basic_streambuf<CharT, Traits>
{
private:
using parent_type = std::basic_streambuf<CharT, Traits>;
public:
using char_type = CharT;
using traits_type = Traits;
using int_type = typename Traits::int_type;
using pos_type = typename Traits::pos_type;
using off_type = typename Traits::off_type;
public:
static constexpr std::size_t buf_size{1024};
public:
basic_pipe_streambuf() = default;
explicit basic_pipe_streambuf(const std::string& name, std::ios_base::openmode mode)
: parent_type{nullptr}
{
open(name, mode);
}
virtual ~basic_pipe_streambuf()
{
close();
}
basic_pipe_streambuf(const basic_pipe_streambuf&) = delete;
basic_pipe_streambuf& operator=(const basic_pipe_streambuf&) = delete;
basic_pipe_streambuf(basic_pipe_streambuf&& other) noexcept
: parent_type{std::move(other)}
, m_buffer{std::move(other.m_buffer)}
, m_handle{std::exchange(other.m_handle, 0)}
, m_mode{std::exchange(other.m_mode, std::ios_base::openmode{})}
{
}
basic_pipe_streambuf& operator=(basic_pipe_streambuf&& other) noexcept
{
parent_type::operator=(std::move(other));
m_buffer = std::move(other.m_buffer);
m_handle = std::exchange(other.m_handle, m_handle);
m_mode = std::exchange(other.m_mode, m_mode);
return *this;
}
bool open(const std::string& name, std::ios_base::openmode mode)
{
assert(!((mode & std::ios_base::in) && (mode & std::ios_base::out)) && "nes::basic_pipe_streambuf::open called with mode = std::ios_base::in | std::ios_base::out.");
close();
const auto native_name{pipe_root + name};
if(mkfifo(std::data(native_name), 0660) != 0 && errno != EEXIST)
{
return false;
}
const int native_mode{mode & std::ios_base::in ? O_RDONLY : O_WRONLY};
int handle = ::open(std::data(native_name), native_mode);
if(handle < 0)
{
return false;
}
m_buffer.resize(buf_size);
parent_type::setp(std::data(m_buffer), std::data(m_buffer) + buf_size);
m_handle = handle;
m_mode = mode;
return true;
}
bool is_open() const noexcept
{
return m_handle;
}
void close()
{
if(is_open())
{
sync();
m_mode = std::ios_base::openmode{};
::close(std::exchange(m_handle, 0));
parent_type::setp(nullptr, nullptr);
parent_type::setg(nullptr, nullptr, nullptr);
}
}
private:
friend class process;
friend std::pair<basic_pipe_istream<char_type, traits_type>, basic_pipe_ostream<char_type, traits_type>> make_anonymous_pipe<char_type, traits_type>();
basic_pipe_streambuf(int handle, std::ios_base::openmode mode)
: m_handle{handle}
, m_mode{mode}
{
m_buffer.resize(buf_size);
parent_type::setp(std::data(m_buffer), std::data(m_buffer) + buf_size);
}
protected:
virtual int sync() override
{
if(m_mode & std::ios_base::out)
{
const std::ptrdiff_t count{parent_type::pptr() - parent_type::pbase()};
if(write(m_handle, reinterpret_cast<const char*>(std::data(m_buffer)), count * sizeof(char_type)) < 0)
{
return -1;
}
parent_type::setp(std::data(m_buffer), std::data(m_buffer) + buf_size);
}
return 0;
}
virtual int_type overflow(int_type c = traits_type::eof()) override
{
assert(m_mode & std::ios_base::out && "Write operation on a read only pipe.");
if(traits_type::eq_int_type(c, traits_type::eof()))
{
if(write(m_handle, reinterpret_cast<const char*>(std::data(m_buffer)), std::size(m_buffer) * sizeof(char_type)))
{
return traits_type::eof();
}
parent_type::setp(std::data(m_buffer), std::data(m_buffer) + buf_size);
}
else
{
*parent_type::pptr() = traits_type::to_char_type(c);
parent_type::pbump(1);
}
return traits_type::not_eof(c);
}
virtual std::streamsize xsputn(const char_type* s, std::streamsize count) override
{
assert(m_mode & std::ios_base::out && "Write operation on a read only pipe.");
sync(); // empty putarea before performing a write
const auto written = write(m_handle, reinterpret_cast<const char*>(s), count * sizeof(char_type));
if(written < 0)
{
return 0;
}
return static_cast<std::streamsize>(written);
}
virtual int_type underflow() override
{
assert(m_mode & std::ios_base::in && "Read operation on a write only pipe.");
if(parent_type::gptr() == parent_type::egptr())
{
const auto _read = read(m_handle, reinterpret_cast<char*>(std::data(m_buffer)), buf_size * sizeof(char_type));
if(_read <= 0)
{
return traits_type::eof();
}
parent_type::setg(std::data(m_buffer), std::data(m_buffer), std::data(m_buffer) + (_read / sizeof(char_type)));
}
return traits_type::to_int_type(*parent_type::gptr());
}
virtual std::streamsize xsgetn(char_type* s, std::streamsize count) override
{
assert(m_mode & std::ios_base::in && "Read operation on a write only pipe.");
// to support mixing formatted and unformatted input, we have to flush the get buffer
const std::ptrdiff_t available = parent_type::egptr() - parent_type::gptr();
if(available > 0)
{
std::copy_n(parent_type::gptr(), (std::min)(available, count), s);
// if we still have buffered input update gptr
if(available > count)
{
parent_type::setg(parent_type::eback(), parent_type::gptr() + count, parent_type::egptr());
return count;
}
// resets get buffer, this will force an underflow on next formatted input
parent_type::setg(nullptr, nullptr, nullptr);
if(count == available)
{
return count;
}
// perform a read to fulfill the requested count if possible
count -= available;
s += available;
}
const auto _read = read(m_handle, reinterpret_cast<char*>(s), count * sizeof(char_type));
if(_read < 0)
{
return 0;
}
return static_cast<std::streamsize>(_read / sizeof(char_type)) + available;
}
private:
std::vector<CharT> m_buffer{};
int m_handle{};
std::ios_base::openmode m_mode{};
};
template<typename CharT, typename Traits = std::char_traits<CharT>>
class basic_pipe_istream : public std::basic_istream<CharT, Traits>
{
private:
using parent_type = std::basic_istream<CharT, Traits>;
public:
using char_type = CharT;
using traits_type = Traits;
using int_type = typename Traits::int_type;
using pos_type = typename Traits::pos_type;
using off_type = typename Traits::off_type;
public:
basic_pipe_istream() = default;
explicit basic_pipe_istream(const std::string& name, std::ios_base::openmode mode = std::ios_base::in)
: parent_type{nullptr}
{
parent_type::rdbuf(m_buffer.get());
open(name, mode);
}
virtual ~basic_pipe_istream() = default;
basic_pipe_istream(const basic_pipe_istream&) = delete;
basic_pipe_istream& operator=(const basic_pipe_istream&) = delete;
basic_pipe_istream(basic_pipe_istream&& other) noexcept
: parent_type{std::move(other)}
{
std::swap(m_buffer, other.m_buffer);
parent_type::rdbuf(m_buffer.get());
}
basic_pipe_istream& operator=(basic_pipe_istream&& other) noexcept
{
parent_type::operator=(std::move(other));
std::swap(m_buffer, other.m_buffer);
parent_type::rdbuf(m_buffer.get());
return *this;
}
void open(const std::string& name, std::ios_base::openmode mode = std::ios_base::in)
{
m_buffer->open(name, mode);
parent_type::clear(m_buffer->is_open() ? std::ios_base::goodbit : std::ios_base::failbit);
}
bool is_open() const noexcept
{
return m_buffer->is_open();
}
void close()
{
m_buffer->close();
}
basic_pipe_streambuf<char_type, traits_type>* rdbuf() const noexcept
{
return m_buffer.get();
}
private:
friend class process;
friend std::pair<basic_pipe_istream<char_type, traits_type>, basic_pipe_ostream<char_type, traits_type>> make_anonymous_pipe<char_type, traits_type>();
basic_pipe_istream(basic_pipe_streambuf<char_type, traits_type> buffer)
: parent_type{nullptr}
, m_buffer{std::make_unique<basic_pipe_streambuf<char_type, traits_type>>(std::move(buffer))}
{
parent_type::rdbuf(m_buffer.get());
}
private:
std::unique_ptr<basic_pipe_streambuf<char_type, traits_type>> m_buffer{std::make_unique<basic_pipe_streambuf<char_type, traits_type>>()};
};
template<typename CharT, typename Traits = std::char_traits<CharT>>
class basic_pipe_ostream : public std::basic_ostream<CharT, Traits>
{
private:
using parent_type = std::basic_ostream<CharT, Traits>;
public:
using char_type = CharT;
using traits_type = Traits;
using int_type = typename Traits::int_type;
using pos_type = typename Traits::pos_type;
using off_type = typename Traits::off_type;
public:
basic_pipe_ostream() = default;
explicit basic_pipe_ostream(const std::string& name, std::ios_base::openmode mode = std::ios_base::out)
: parent_type{nullptr}
{
parent_type::rdbuf(m_buffer.get());
open(name, mode);
}
virtual ~basic_pipe_ostream() = default;
basic_pipe_ostream(const basic_pipe_ostream&) = delete;
basic_pipe_ostream& operator=(const basic_pipe_ostream&) = delete;
basic_pipe_ostream(basic_pipe_ostream&& other) noexcept
: parent_type{std::move(other)}
{
std::swap(m_buffer, other.m_buffer);
parent_type::rdbuf(m_buffer.get());
}
basic_pipe_ostream& operator=(basic_pipe_ostream&& other) noexcept
{
parent_type::operator=(std::move(other));
std::swap(m_buffer, other.m_buffer);
parent_type::rdbuf(m_buffer.get());
return *this;
}
void open(const std::string& name, std::ios_base::openmode mode = std::ios_base::out)
{
m_buffer->open(name, mode);
parent_type::clear(m_buffer->is_open() ? std::ios_base::goodbit : std::ios_base::failbit);
}
bool is_open() const noexcept
{
return m_buffer->is_open();
}
void close()
{
m_buffer->close();
}
basic_pipe_streambuf<char_type, traits_type>* rdbuf() const noexcept
{
return m_buffer.get();
}
private:
friend class process;
friend std::pair<basic_pipe_istream<char_type, traits_type>, basic_pipe_ostream<char_type, traits_type>> make_anonymous_pipe<char_type, traits_type>();
basic_pipe_ostream(basic_pipe_streambuf<char_type, traits_type> buffer)
: parent_type{nullptr}
, m_buffer{std::make_unique<basic_pipe_streambuf<char_type, traits_type>>(std::move(buffer))}
{
parent_type::rdbuf(m_buffer.get());
}
private:
std::unique_ptr<basic_pipe_streambuf<char_type, traits_type>> m_buffer{std::make_unique<basic_pipe_streambuf<char_type, traits_type>>()};
};
template<typename CharT, typename Traits>
std::pair<basic_pipe_istream<CharT, Traits>, basic_pipe_ostream<CharT, Traits>> make_anonymous_pipe()
{
int fd[2];
if(pipe(fd))
{
throw std::runtime_error{"Failed to create pipe"};
}
// clang-format off
return std::make_pair(
basic_pipe_istream<CharT, Traits>{basic_pipe_streambuf<CharT, Traits>{fd[0], std::ios_base::in}},
basic_pipe_ostream<CharT, Traits>{basic_pipe_streambuf<CharT, Traits>{fd[1], std::ios_base::out}});
// clang-format on
}
using pipe_streambuf = basic_pipe_streambuf<char>;
using pipe_istream = basic_pipe_istream<char>;
using pipe_ostream = basic_pipe_ostream<char>;
NES_INLINE_NAMESPACE_END
}
#endif
#endif
================================================
FILE: include/nes/process.hpp
================================================
///////////////////////////////////////////////////////////
/// Copyright 2019 Alexy Pellegrini
///
/// Permission is hereby granted, free of charge,
/// to any person obtaining a copy of this software
/// and associated documentation files (the "Software"),
/// to deal in the Software without restriction,
/// including without limitation the rights to use,
/// copy, modify, merge, publish, distribute, sublicense,
/// and/or sell copies of the Software, and to permit
/// persons to whom the Software is furnished to do so,
/// subject to the following conditions:
///
/// The above copyright notice and this permission notice
/// shall be included in all copies or substantial portions
/// of the Software.
///
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
/// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
/// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
/// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
/// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
/// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
/// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
/// OR OTHER DEALINGS IN THE SOFTWARE.
///////////////////////////////////////////////////////////
#ifndef NOT_ENOUGH_STANDARDS_PROCESS
#define NOT_ENOUGH_STANDARDS_PROCESS
#if defined(_WIN32)
#define NES_WIN32_PROCESS
#ifndef NOMINMAX
#define NOMINMAX
#endif
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <Windows.h>
#elif defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))
#define NES_POSIX_PROCESS
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
#include <string.h>
#include <limits.h>
#else
#error "Not enough standards does not support this environment."
#endif
#if __has_include("pipe.hpp")
#define NES_PROCESS_PIPE_EXTENSION
#include "pipe.hpp"
#endif
#ifdef NES_INLINE_NAMESPACE
#define NES_INLINE_NAMESPACE_BEGIN \
inline namespace NES_INLINE_NAMESPACE \
{
#define NES_INLINE_NAMESPACE_END }
#else
#define NES_INLINE_NAMESPACE_BEGIN
#define NES_INLINE_NAMESPACE_END
#endif
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <memory>
#include <functional>
#include <cassert>
#include <utility>
#if defined(NES_WIN32_PROCESS)
namespace nes
{
NES_INLINE_NAMESPACE_BEGIN
class process;
namespace impl
{
enum class id_t : DWORD
{
};
constexpr bool operator==(id_t lhs, id_t rhs) noexcept
{
return static_cast<DWORD>(lhs) == static_cast<DWORD>(rhs);
}
constexpr bool operator!=(id_t lhs, id_t rhs) noexcept
{
return static_cast<DWORD>(lhs) != static_cast<DWORD>(rhs);
}
constexpr bool operator<(id_t lhs, id_t rhs) noexcept
{
return static_cast<DWORD>(lhs) < static_cast<DWORD>(rhs);
}
constexpr bool operator<=(id_t lhs, id_t rhs) noexcept
{
return static_cast<DWORD>(lhs) <= static_cast<DWORD>(rhs);
}
constexpr bool operator>(id_t lhs, id_t rhs) noexcept
{
return static_cast<DWORD>(lhs) > static_cast<DWORD>(rhs);
}
constexpr bool operator>=(id_t lhs, id_t rhs) noexcept
{
return static_cast<DWORD>(lhs) >= static_cast<DWORD>(rhs);
}
struct auto_handle
{
public:
constexpr auto_handle() = default;
auto_handle(HANDLE h)
: m_handle{h}
{
}
~auto_handle()
{
if(m_handle != INVALID_HANDLE_VALUE)
{
CloseHandle(m_handle);
}
}
auto_handle(const auto_handle&) = delete;
auto_handle& operator=(const auto_handle&) = delete;
auto_handle(auto_handle&& other) noexcept
: m_handle{std::exchange(other.m_handle, INVALID_HANDLE_VALUE)}
{
}
auto_handle& operator=(auto_handle&& other) noexcept
{
m_handle = std::exchange(other.m_handle, m_handle);
return *this;
}
HANDLE release() noexcept
{
return std::exchange(m_handle, INVALID_HANDLE_VALUE);
}
operator HANDLE() const noexcept
{
return m_handle;
}
HANDLE* operator&() noexcept
{
return &m_handle;
}
const HANDLE* operator&() const noexcept
{
return &m_handle;
}
operator bool() const noexcept
{
return m_handle != INVALID_HANDLE_VALUE;
}
private:
HANDLE m_handle{INVALID_HANDLE_VALUE};
};
}
enum class process_options : std::uint32_t
{
none = 0x00,
#ifdef NES_PROCESS_PIPE_EXTENSION
grab_stdout = 0x10,
grab_stderr = 0x20,
grab_stdin = 0x40
#endif
};
constexpr process_options operator&(process_options left, process_options right) noexcept
{
return static_cast<process_options>(static_cast<std::uint32_t>(left) & static_cast<std::uint32_t>(right));
}
constexpr process_options& operator&=(process_options& left, process_options right) noexcept
{
left = left & right;
return left;
}
constexpr process_options operator|(process_options left, process_options right) noexcept
{
return static_cast<process_options>(static_cast<std::uint32_t>(left) | static_cast<std::uint32_t>(right));
}
constexpr process_options& operator|=(process_options& left, process_options right) noexcept
{
left = left | right;
return left;
}
constexpr process_options operator^(process_options left, process_options right) noexcept
{
return static_cast<process_options>(static_cast<std::uint32_t>(left) ^ static_cast<std::uint32_t>(right));
}
constexpr process_options& operator^=(process_options& left, process_options right) noexcept
{
left = left ^ right;
return left;
}
constexpr process_options operator~(process_options value) noexcept
{
return static_cast<process_options>(~static_cast<std::uint32_t>(value));
}
class process
{
public:
using native_handle_type = HANDLE;
using return_code_type = DWORD;
using id = impl::id_t;
public:
constexpr process() noexcept = default;
explicit process(const std::string& path, const std::string& working_directory)
: process{path, {}, working_directory, {}}
{
}
explicit process(const std::string& path, process_options options)
: process{path, {}, {}, options}
{
}
explicit process(const std::string& path, const std::vector<std::string>& args, process_options options)
: process{path, args, {}, options}
{
}
explicit process(const std::string& path, const std::string& working_directory, process_options options)
: process{path, {}, working_directory, options}
{
}
explicit process(const std::string& path, std::vector<std::string> args = std::vector<std::string>{}, const std::string& working_directory = std::string{}, process_options options [[maybe_unused]] = process_options{})
{
assert(!std::empty(path) && "nes::process::process called with empty path.");
SECURITY_ATTRIBUTES security_attributes{};
security_attributes.nLength = sizeof(SECURITY_ATTRIBUTES);
security_attributes.bInheritHandle = TRUE;
security_attributes.lpSecurityDescriptor = nullptr;
#ifdef NES_PROCESS_PIPE_EXTENSION
impl::auto_handle stdin_rd{};
impl::auto_handle stdout_rd{};
impl::auto_handle stderr_rd{};
impl::auto_handle stdin_wr{};
impl::auto_handle stdout_wr{};
impl::auto_handle stderr_wr{};
if(static_cast<bool>(options & process_options::grab_stdin))
{
if(!CreatePipe(&stdin_rd, &stdin_wr, &security_attributes, 0) || !SetHandleInformation(stdin_wr, HANDLE_FLAG_INHERIT, 0))
{
throw std::runtime_error{"Failed to create stdin pipe. " + get_error_message()};
}
}
if(static_cast<bool>(options & process_options::grab_stdout))
{
if(!CreatePipe(&stdout_rd, &stdout_wr, &security_attributes, 0) || !SetHandleInformation(stdout_rd, HANDLE_FLAG_INHERIT, 0))
{
throw std::runtime_error{"Failed to create stdout pipe. " + get_error_message()};
}
}
if(static_cast<bool>(options & process_options::grab_stderr))
{
if(!CreatePipe(&stderr_rd, &stderr_wr, &security_attributes, 0) || !SetHandleInformation(stderr_rd, HANDLE_FLAG_INHERIT, 0))
{
throw std::runtime_error{"Failed to create stderr pipe. " + get_error_message()};
}
}
#endif
args.insert(std::begin(args), path);
auto format_arg = [](const std::wstring& arg) -> std::wstring
{
if(arg.find_first_of(L" \t\n\v\"") == std::wstring::npos)
{
return arg;
}
std::wstring out{L"\""};
for(auto it = std::cbegin(arg); it != std::cend(arg); ++it)
{
if(*it == L'\\')
{
std::size_t count{1};
while(++it != std::cend(arg) && *it == L'\\')
{
++count;
}
if(it == std::cend(arg))
{
out.append(count * 2, L'\\');
break;
}
else if(*it == L'\"')
{
out.append(count * 2 + 1, L'\\');
out.push_back(L'\"');
}
else
{
out.append(count, L'\\');
out.push_back(*it);
}
}
else if(*it == L'\"')
{
out.push_back(L'\\');
out.push_back(*it);
}
else
{
out.push_back(*it);
}
}
out.push_back(L'\"');
return out;
};
std::wstring args_str{};
for(auto&& arg : args)
{
args_str += format_arg(to_wide(arg)) + L" ";
}
const std::wstring native_working_directory{to_wide(working_directory)};
const std::wstring native_path{to_wide(path)};
STARTUPINFOW startup_info{};
startup_info.cb = sizeof(STARTUPINFOW);
#ifdef NES_PROCESS_PIPE_EXTENSION
startup_info.hStdInput = stdin_rd;
startup_info.hStdOutput = stdout_wr;
startup_info.hStdError = stderr_wr;
if(static_cast<std::uint32_t>(options) != 0)
{
startup_info.dwFlags = STARTF_USESTDHANDLES;
}
#endif
PROCESS_INFORMATION process_info{};
if(!CreateProcessW(std::data(native_path), null_or_data(args_str), nullptr, nullptr, TRUE, 0, nullptr, null_or_data(native_working_directory), &startup_info, &process_info))
{
throw std::runtime_error{"Failed to create process. " + get_error_message()};
}
m_id = static_cast<id>(process_info.dwProcessId);
m_handle = process_info.hProcess;
m_thread_handle = process_info.hThread;
#ifdef NES_PROCESS_PIPE_EXTENSION
if(static_cast<bool>(options & process_options::grab_stdin))
{
pipe_streambuf buffer{stdin_wr.release(), std::ios_base::out};
m_stdin_stream.reset(new pipe_ostream{std::move(buffer)});
}
if(static_cast<bool>(options & process_options::grab_stdout))
{
pipe_streambuf buffer{stdout_rd.release(), std::ios_base::in};
m_stdout_stream.reset(new pipe_istream{std::move(buffer)});
}
if(static_cast<bool>(options & process_options::grab_stderr))
{
pipe_streambuf buffer{stderr_rd.release(), std::ios_base::in};
m_stderr_stream.reset(new pipe_istream{std::move(buffer)});
}
#endif
}
~process()
{
assert(!joinable() && "nes::process::~process() called with joinable() returning true.");
if(joinable())
{
std::terminate();
}
}
process(const process&) = delete;
process& operator=(const process&) = delete;
process(process&& other) noexcept
: m_id{std::exchange(other.m_id, id{})}
, m_return_code{std::exchange(other.m_return_code, return_code_type{})}
, m_handle{std::move(other.m_handle)}
, m_thread_handle{std::move(other.m_thread_handle)}
#ifdef NES_PROCESS_PIPE_EXTENSION
, m_stdin_stream{std::move(other.m_stdin_stream)}
, m_stdout_stream{std::move(other.m_stdout_stream)}
, m_stderr_stream{std::move(other.m_stderr_stream)}
#endif
{
}
process& operator=(process&& other) noexcept
{
if(joinable())
{
std::terminate();
}
m_id = std::exchange(other.m_id, m_id);
m_return_code = std::exchange(other.m_return_code, m_return_code);
m_handle = std::move(other.m_handle);
m_thread_handle = std::move(other.m_thread_handle);
#ifdef NES_PROCESS_PIPE_EXTENSION
m_stdin_stream = std::move(other.m_stdin_stream);
m_stdout_stream = std::move(other.m_stdout_stream);
m_stderr_stream = std::move(other.m_stderr_stream);
#endif
return *this;
}
void join()
{
assert(joinable() && "nes::process::join() called with joinable() returning false.");
if(WaitForSingleObject(m_handle, INFINITE))
{
throw std::runtime_error{"Failed to join the process. " + get_error_message()};
}
if(!GetExitCodeProcess(m_handle, reinterpret_cast<DWORD*>(&m_return_code)))
{
throw std::runtime_error{"Failed to get the return code of the process. " + get_error_message()};
}
close_process();
}
bool joinable() const noexcept
{
return m_handle;
}
bool active() const
{
if(!m_handle)
{
return false;
}
DWORD result = WaitForSingleObject(m_handle, 0);
if(result == WAIT_FAILED)
{
throw std::runtime_error{"Failed to get the state of the process. " + get_error_message()};
}
return result == WAIT_TIMEOUT;
}
void detach()
{
assert(joinable() && "nes::process::detach() called with joinable() returning false.");
close_process();
}
bool kill()
{
assert(joinable() && "nes::process::kill() called with joinable() returning false.");
if(!TerminateProcess(m_handle, 1))
{
return false;
}
join();
return true;
}
return_code_type return_code() const noexcept
{
assert(!joinable() && "nes::process::return_code() called with joinable() returning true.");
return m_return_code;
}
native_handle_type native_handle() const noexcept
{
return m_handle;
}
id get_id() const noexcept
{
return m_id;
}
#ifdef NES_PROCESS_PIPE_EXTENSION
pipe_ostream& stdin_stream() noexcept
{
return *m_stdin_stream;
}
pipe_istream& stdout_stream() noexcept
{
return *m_stdout_stream;
}
pipe_istream& stderr_stream() noexcept
{
return *m_stderr_stream;
}
#endif
private:
std::wstring to_wide(const std::string& path)
{
assert(std::size(path) < 0x7FFFFFFFu && "Wrong path.");
if(std::empty(path))
{
return {};
}
std::wstring out_path{};
out_path.resize(static_cast<std::size_t>(MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, std::data(path), static_cast<int>(std::size(path)), nullptr, 0)));
if(!MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, std::data(path), static_cast<int>(std::size(path)), std::data(out_path), static_cast<int>(std::size(out_path))))
{
throw std::runtime_error{"Failed to convert the path to wide."};
}
return out_path;
}
std::string get_error_message() const
{
return "#" + std::to_string(GetLastError());
}
void close_process()
{
m_id = id{};
CloseHandle(m_handle.release());
CloseHandle(m_thread_handle.release());
}
wchar_t* null_or_data(std::wstring& str)
{
return std::empty(str) ? nullptr : std::data(str);
}
const wchar_t* null_or_data(const std::wstring& str)
{
return std::empty(str) ? nullptr : std::data(str);
}
private:
id m_id{};
return_code_type m_return_code{};
impl::auto_handle m_handle{};
impl::auto_handle m_thread_handle{};
#ifdef NES_PROCESS_PIPE_EXTENSION
std::unique_ptr<pipe_ostream> m_stdin_stream{};
std::unique_ptr<pipe_istream> m_stdout_stream{};
std::unique_ptr<pipe_istream> m_stderr_stream{};
#endif
};
namespace this_process
{
inline process::id get_id() noexcept
{
return process::id{GetCurrentProcessId()};
}
inline std::string working_directory()
{
const DWORD size{GetCurrentDirectoryW(0, nullptr)};
std::wstring native_path{};
native_path.resize(static_cast<std::size_t>(size));
GetCurrentDirectoryW(size, std::data(native_path));
native_path.pop_back(); // Because GetCurrentDirectoryW adds a null terminator
std::transform(std::begin(native_path), std::end(native_path), std::begin(native_path), [](wchar_t c)
{
return c == L'\\' ? L'/' : c;
});
std::string path{};
path.resize(static_cast<std::size_t>(WideCharToMultiByte(CP_UTF8, 0, std::data(native_path), static_cast<int>(std::size(native_path)), nullptr, 0, nullptr, nullptr)));
if(!WideCharToMultiByte(CP_UTF8, 0, std::data(native_path), static_cast<int>(std::size(native_path)), std::data(path), static_cast<int>(std::size(path)), nullptr, nullptr))
{
throw std::runtime_error{"Failed to convert the path to UTF-8."};
}
return path;
}
inline bool change_working_directory(const std::string& path)
{
std::wstring native_path{};
native_path.resize(static_cast<std::size_t>(MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, std::data(path), static_cast<int>(std::size(path)), nullptr, 0)));
if(!MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, std::data(path), static_cast<int>(std::size(path)), std::data(native_path), static_cast<int>(std::size(native_path))))
{
throw std::runtime_error{"Failed to convert the path to wide."};
}
return SetCurrentDirectoryW(std::data(native_path));
}
}
NES_INLINE_NAMESPACE_END
}
template<typename CharT, typename Traits>
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, nes::process::id id)
{
return os << static_cast<DWORD>(id);
}
namespace std
{
template<>
struct hash<nes::process::id>
{
using argument_type = nes::process::id;
using result_type = std::size_t;
result_type operator()(const argument_type& s) const noexcept
{
return std::hash<DWORD>{}(static_cast<DWORD>(s));
}
};
}
#elif defined(NES_POSIX_PROCESS)
namespace nes
{
NES_INLINE_NAMESPACE_BEGIN
class process;
namespace impl
{
enum class id_t : pid_t
{
};
constexpr bool operator==(id_t lhs, id_t rhs) noexcept
{
return static_cast<pid_t>(lhs) == static_cast<pid_t>(rhs);
}
constexpr bool operator!=(id_t lhs, id_t rhs) noexcept
{
return static_cast<pid_t>(lhs) != static_cast<pid_t>(rhs);
}
constexpr bool operator<(id_t lhs, id_t rhs) noexcept
{
return static_cast<pid_t>(lhs) < static_cast<pid_t>(rhs);
}
constexpr bool operator<=(id_t lhs, id_t rhs) noexcept
{
return static_cast<pid_t>(lhs) <= static_cast<pid_t>(rhs);
}
constexpr bool operator>(id_t lhs, id_t rhs) noexcept
{
return static_cast<pid_t>(lhs) > static_cast<pid_t>(rhs);
}
constexpr bool operator>=(id_t lhs, id_t rhs) noexcept
{
return static_cast<pid_t>(lhs) >= static_cast<pid_t>(rhs);
}
#ifdef NES_PROCESS_PIPE_EXTENSION
struct auto_handle
{
constexpr auto_handle() = default;
auto_handle(int h)
: m_handle{h}
{
}
~auto_handle()
{
if(m_handle)
{
close(m_handle);
}
}
auto_handle(const auto_handle&) = delete;
auto_handle& operator=(const auto_handle&) = delete;
auto_handle(auto_handle&& other) noexcept
: m_handle{std::exchange(other.m_handle, -1)}
{
}
auto_handle& operator=(auto_handle&& other) noexcept
{
m_handle = std::exchange(other.m_handle, m_handle);
return *this;
}
int release() noexcept
{
return std::exchange(m_handle, -1);
}
operator int() noexcept
{
return m_handle;
}
operator int() const noexcept
{
return m_handle;
}
int* operator&() noexcept
{
return &m_handle;
}
const int* operator&() const noexcept
{
return &m_handle;
}
operator bool() const noexcept
{
return m_handle != -1;
}
int m_handle{-1};
};
#endif
}
enum class process_options : std::uint32_t
{
none = 0x00,
#ifdef NES_PROCESS_PIPE_EXTENSION
grab_stdout = 0x10,
grab_stderr = 0x20,
grab_stdin = 0x40
#endif
};
constexpr process_options operator&(process_options left, process_options right) noexcept
{
return static_cast<process_options>(static_cast<std::uint32_t>(left) & static_cast<std::uint32_t>(right));
}
constexpr process_options& operator&=(process_options& left, process_options right) noexcept
{
left = left & right;
return left;
}
constexpr process_options operator|(process_options left, process_options right) noexcept
{
return static_cast<process_options>(static_cast<std::uint32_t>(left) | static_cast<std::uint32_t>(right));
}
constexpr process_options& operator|=(process_options& left, process_options right) noexcept
{
left = left | right;
return left;
}
constexpr process_options operator^(process_options left, process_options right) noexcept
{
return static_cast<process_options>(static_cast<std::uint32_t>(left) ^ static_cast<std::uint32_t>(right));
}
constexpr process_options& operator^=(process_options& left, process_options right) noexcept
{
left = left ^ right;
return left;
}
constexpr process_options operator~(process_options value) noexcept
{
return static_cast<process_options>(~static_cast<std::uint32_t>(value));
}
class process
{
public:
using native_handle_type = pid_t;
using return_code_type = int;
using id = impl::id_t;
public:
constexpr process() noexcept = default;
explicit process(const std::string& path, const std::string& working_directory)
: process{path, {}, working_directory, {}}
{
}
explicit process(const std::string& path, process_options options)
: process{path, {}, {}, options}
{
}
explicit process(const std::string& path, const std::vector<std::string>& args, process_options options)
: process{path, args, {}, options}
{
}
explicit process(const std::string& path, const std::string& working_directory, process_options options)
: process{path, {}, working_directory, options}
{
}
explicit process(const std::string& path, std::vector<std::string> args = std::vector<std::string>{}, const std::string& working_directory = std::string{}, process_options options [[maybe_unused]] = process_options{})
{
assert(!std::empty(path) && "nes::process::process called with empty path.");
args.insert(std::begin(args), path);
std::vector<char*> native_args{};
native_args.resize(std::size(args) + 1);
for(std::size_t i{}; i < std::size(args); ++i)
{
native_args[i] = std::data(args[i]);
}
#ifdef NES_PROCESS_PIPE_EXTENSION
impl::auto_handle stdin_fd[2]{};
impl::auto_handle stdout_fd[2]{};
impl::auto_handle stderr_fd[2]{};
if(static_cast<bool>(options & process_options::grab_stdin) && pipe(reinterpret_cast<int*>(stdin_fd)))
{
throw std::runtime_error{"Failed to create stdin pipe. " + std::string{strerror(errno)}};
}
if(static_cast<bool>(options & process_options::grab_stdout) && pipe(reinterpret_cast<int*>(stdout_fd)))
{
throw std::runtime_error{"Failed to create stdout pipe. " + std::string{strerror(errno)}};
}
if(static_cast<bool>(options & process_options::grab_stderr) && pipe(reinterpret_cast<int*>(stderr_fd)))
{
throw std::runtime_error{"Failed to create stderr pipe. " + std::string{strerror(errno)}};
}
const bool standard_streams{static_cast<bool>(options & process_options::grab_stdin) || static_cast<bool>(options & process_options::grab_stdout) || static_cast<bool>(options & process_options::grab_stderr)};
#else
constexpr bool standard_streams{false};
#endif
const pid_t id{fork()};
if(id < 0)
{
throw std::runtime_error{"Failed to create process. " + std::string{strerror(errno)}};
}
else if(id == 0)
{
#ifdef NES_PROCESS_PIPE_EXTENSION
if(static_cast<bool>(options & process_options::grab_stdin))
{
if(dup2(stdin_fd[0], 0) == -1)
{
_exit(EXIT_FAILURE);
}
}
if(static_cast<bool>(options & process_options::grab_stdout))
{
if(dup2(stdout_fd[1], 1) == -1)
{
_exit(EXIT_FAILURE);
}
}
if(static_cast<bool>(options & process_options::grab_stderr))
{
if(dup2(stderr_fd[1], 2) == -1)
{
_exit(EXIT_FAILURE);
}
}
#endif
if(!std::empty(working_directory))
{
if(chdir(std::data(working_directory)))
{
_exit(EXIT_FAILURE);
}
}
execv(std::data(path), std::data(native_args));
_exit(EXIT_FAILURE);
}
m_id = id;
#ifdef NES_PROCESS_PIPE_EXTENSION
if(static_cast<bool>(options & process_options::grab_stdin))
{
pipe_streambuf buf{stdin_fd[1].release(), std::ios_base::out};
m_stdin_stream.reset(new pipe_ostream{std::move(buf)});
}
if(static_cast<bool>(options & process_options::grab_stdout))
{
pipe_streambuf buf{stdout_fd[0].release(), std::ios_base::in};
m_stdout_stream.reset(new pipe_istream{std::move(buf)});
}
if(static_cast<bool>(options & process_options::grab_stderr))
{
pipe_streambuf buf{stderr_fd[0].release(), std::ios_base::in};
m_stderr_stream.reset(new pipe_istream{std::move(buf)});
}
#endif
}
~process()
{
assert(!joinable() && "nes::process::~process() called with joinable() returning true.");
if(joinable())
{
std::terminate();
}
}
process(const process&) = delete;
process& operator=(const process&) = delete;
process(process&& other) noexcept
: m_id{std::exchange(other.m_id, -1)}
, m_return_code{std::exchange(other.m_return_code, return_code_type{})}
#ifdef NES_PROCESS_PIPE_EXTENSION
, m_stdin_stream{std::move(other.m_stdin_stream)}
, m_stdout_stream{std::move(other.m_stdout_stream)}
, m_stderr_stream{std::move(other.m_stderr_stream)}
#endif
{
}
process& operator=(process&& other) noexcept
{
if(joinable())
{
std::terminate();
}
m_id = std::exchange(other.m_id, m_id);
m_return_code = std::exchange(other.m_return_code, m_return_code);
#ifdef NES_PROCESS_PIPE_EXTENSION
m_stdin_stream = std::move(other.m_stdin_stream);
m_stdout_stream = std::move(other.m_stdout_stream);
m_stderr_stream = std::move(other.m_stderr_stream);
#endif
return *this;
}
void join()
{
assert(joinable() && "nes::process::join() called with joinable() returning false.");
int return_code{};
if(waitpid(m_id, &return_code, 0) == -1)
{
throw std::runtime_error{"Failed to join the process. " + std::string{strerror(errno)}};
}
m_id = -1;
m_return_code = WEXITSTATUS(return_code);
}
bool joinable() const noexcept
{
return m_id != -1;
}
bool active() const
{
return ::kill(m_id, 0) != ESRCH;
}
void detach()
{
assert(joinable() && "nes::process::detach() called with joinable() returning false.");
m_id = -1;
}
bool kill()
{
assert(joinable() && "nes::process::kill() called with joinable() returning false.");
if(::kill(m_id, SIGTERM))
{
return false;
}
join();
return true;
}
return_code_type return_code() const noexcept
{
assert(!joinable() && "nes::process::return_code() called with joinable() returning true.");
return m_return_code;
}
native_handle_type native_handle() const noexcept
{
return m_id;
}
id get_id() const noexcept
{
return static_cast<impl::id_t>(m_id);
}
#ifdef NES_PROCESS_PIPE_EXTENSION
pipe_ostream& stdin_stream() noexcept
{
return *m_stdin_stream;
}
pipe_istream& stdout_stream() noexcept
{
return *m_stdout_stream;
}
pipe_istream& stderr_stream() noexcept
{
return *m_stderr_stream;
}
#endif
private:
native_handle_type m_id{};
return_code_type m_return_code{};
#ifdef NES_PROCESS_PIPE_EXTENSION
std::unique_ptr<pipe_ostream> m_stdin_stream{};
std::unique_ptr<pipe_istream> m_stdout_stream{};
std::unique_ptr<pipe_istream> m_stderr_stream{};
#endif
};
namespace this_process
{
inline process::id get_id() noexcept
{
return process::id{getpid()};
}
inline std::string working_directory()
{
std::string path{};
path.resize(256);
while(!getcwd(std::data(path), std::size(path)))
{
if(errno == ERANGE)
{
path.resize(std::size(path) * 2);
}
else
{
throw std::runtime_error{"Failed to get the current working directory. " + std::string{strerror(errno)}};
}
}
path.resize(path.find_first_of('\0'));
return path;
}
inline bool change_working_directory(const std::string& path)
{
return chdir(std::data(path)) == 0;
}
}
NES_INLINE_NAMESPACE_END
}
template<typename CharT, typename Traits>
std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& os, nes::process::id id)
{
return os << static_cast<int>(id);
}
namespace std
{
template<>
struct hash<nes::process::id>
{
using argument_type = nes::process::id;
using result_type = std::size_t;
result_type operator()(const argument_type& s) const noexcept
{
return std::hash<int>{}(static_cast<int>(s));
}
};
}
#endif
#endif
================================================
FILE: include/nes/semaphore.hpp
================================================
///////////////////////////////////////////////////////////
/// Copyright 2019 Alexy Pellegrini
///
/// Permission is hereby granted, free of charge,
/// to any person obtaining a copy of this software
/// and associated documentation files (the "Software"),
/// to deal in the Software without restriction,
/// including without limitation the rights to use,
/// copy, modify, merge, publish, distribute, sublicense,
/// and/or sell copies of the Software, and to permit
/// persons to whom the Software is furnished to do so,
/// subject to the following conditions:
///
/// The above copyright notice and this permission notice
/// shall be included in all copies or substantial portions
/// of the Software.
///
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
/// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
/// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
/// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
/// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
/// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
/// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
/// OR OTHER DEALINGS IN THE SOFTWARE.
///////////////////////////////////////////////////////////
#ifndef NOT_ENOUGH_STANDARDS_SEMAPHORE
#define NOT_ENOUGH_STANDARDS_SEMAPHORE
#if defined(_WIN32)
#define NES_WIN32_SEMAPHORE
#ifndef NOMINMAX
#define NOMINMAX
#endif
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <Windows.h>
#elif defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))
#define NES_POSIX_SEMAPHORE
#include <unistd.h>
#include <string.h>
#include <semaphore.h>
#else
#error "Not enough standards does not support this environment."
#endif
#ifdef NES_INLINE_NAMESPACE
#define NES_INLINE_NAMESPACE_BEGIN \
inline namespace NES_INLINE_NAMESPACE \
{
#define NES_INLINE_NAMESPACE_END }
#else
#define NES_INLINE_NAMESPACE_BEGIN
#define NES_INLINE_NAMESPACE_END
#endif
#include <string>
#include <chrono>
#include <limits>
#include <utility>
#include <stdexcept>
#include <memory>
#if defined(NES_WIN32_SEMAPHORE)
namespace nes
{
NES_INLINE_NAMESPACE_BEGIN
class semaphore
{
public:
using native_handle_type = HANDLE;
public:
explicit semaphore(std::size_t initial_count = 0)
{
m_handle = CreateSemaphoreW(nullptr, static_cast<LONG>(initial_count), std::numeric_limits<LONG>::max(), nullptr);
if(!m_handle)
{
throw std::runtime_error{"Failed to create semaphore. " + get_error_message()};
}
}
~semaphore()
{
if(m_handle)
{
CloseHandle(m_handle);
}
}
semaphore(const semaphore&) = delete;
semaphore& operator=(const semaphore&) = delete;
semaphore(semaphore&& other) noexcept = delete;
semaphore& operator=(semaphore&& other) noexcept = delete;
void acquire()
{
if(WaitForSingleObject(m_handle, INFINITE))
{
throw std::runtime_error{"Failed to decrement semaphore count. " + get_error_message()};
}
}
bool try_acquire()
{
return WaitForSingleObject(m_handle, 0) == WAIT_OBJECT_0;
}
void release()
{
if(!ReleaseSemaphore(m_handle, 1, nullptr))
{
throw std::runtime_error{"Failed to increment semaphore count. " + get_error_message()};
}
}
native_handle_type native_handle() const noexcept
{
return m_handle;
}
private:
std::string get_error_message() const
{
return "#" + std::to_string(GetLastError());
}
private:
native_handle_type m_handle{};
};
class timed_semaphore
{
public:
using native_handle_type = HANDLE;
public:
explicit timed_semaphore(std::size_t initial_count = 0)
{
m_handle = CreateSemaphoreW(nullptr, static_cast<LONG>(initial_count), std::numeric_limits<LONG>::max(), nullptr);
if(!m_handle)
{
throw std::runtime_error{"Failed to create semaphore. " + get_error_message()};
}
}
~timed_semaphore()
{
CloseHandle(m_handle);
}
timed_semaphore(const timed_semaphore&) = delete;
timed_semaphore& operator=(const timed_semaphore&) = delete;
timed_semaphore(timed_semaphore&& other) noexcept = delete;
timed_semaphore& operator=(timed_semaphore&& other) noexcept = delete;
void acquire()
{
if(WaitForSingleObject(m_handle, INFINITE))
{
throw std::runtime_error{"Failed to decrement semaphore count. " + get_error_message()};
}
}
bool try_acquire()
{
return WaitForSingleObject(m_handle, 0) == WAIT_OBJECT_0;
}
template<class Rep, class Period>
bool try_acquire_for(const std::chrono::duration<Rep, Period>& timeout)
{
return WaitForSingleObject(m_handle, std::chrono::duration_cast<std::chrono::milliseconds>(timeout).count()) == WAIT_OBJECT_0;
}
template<class Clock, class Duration>
bool try_acquire_until(const std::chrono::time_point<Clock, Duration>& time_point)
{
const auto current_time{Clock::now()};
if(time_point < current_time)
{
return try_acquire();
}
return try_acquire_for(time_point - current_time);
}
void release()
{
if(!ReleaseSemaphore(m_handle, 1, nullptr))
{
throw std::runtime_error{"Failed to increment semaphore count. " + get_error_message()};
}
}
native_handle_type native_handle() const noexcept
{
return m_handle;
}
private:
std::string get_error_message() const
{
return "#" + std::to_string(GetLastError());
}
private:
native_handle_type m_handle{};
};
NES_INLINE_NAMESPACE_END
}
#elif defined(NES_POSIX_SEMAPHORE)
namespace nes
{
NES_INLINE_NAMESPACE_BEGIN
class semaphore
{
public:
using native_handle_type = sem_t*;
public:
explicit semaphore(std::size_t initial_count = 0)
{
if(sem_init(m_handle.get(), 0, initial_count) != 0)
{
throw std::runtime_error{"Failed to create semaphore. " + std::string{strerror(errno)}};
}
}
~semaphore()
{
sem_destroy(m_handle.get());
}
semaphore(const semaphore&) = delete;
semaphore& operator=(const semaphore&) = delete;
semaphore(semaphore&& other) noexcept = delete;
semaphore& operator=(semaphore&& other) noexcept = delete;
void acquire()
{
if(sem_wait(m_handle.get()) == -1)
{
throw std::runtime_error{"Failed to decrement semaphore count. " + std::string{strerror(errno)}};
}
}
bool try_acquire()
{
return !sem_trywait(m_handle.get());
}
void release()
{
if(sem_post(m_handle.get()) == -1)
{
throw std::runtime_error{"Failed to increment semaphore count. " + std::string{strerror(errno)}};
}
}
native_handle_type native_handle() const noexcept
{
return m_handle.get();
}
private:
std::unique_ptr<sem_t> m_handle{std::make_unique<sem_t>()};
};
class timed_semaphore
{
public:
using native_handle_type = sem_t*;
public:
explicit timed_semaphore(std::size_t initial_count = 0)
{
if(sem_init(m_handle.get(), 0, initial_count) != 0)
{
throw std::runtime_error{"Failed to create timed_semaphore. " + std::string{strerror(errno)}};
}
}
~timed_semaphore()
{
sem_destroy(m_handle.get());
}
timed_semaphore(const timed_semaphore&) = delete;
timed_semaphore& operator=(const timed_semaphore&) = delete;
timed_semaphore(timed_semaphore&& other) noexcept = delete;
timed_semaphore& operator=(timed_semaphore&& other) noexcept = delete;
void acquire()
{
if(sem_wait(m_handle.get()) == -1)
{
throw std::runtime_error{"Failed to decrement semaphore count. " + std::string{strerror(errno)}};
}
}
bool try_acquire()
{
return !sem_trywait(m_handle.get());
}
template<class Rep, class Period>
bool try_lock_for(const std::chrono::duration<Rep, Period>& timeout)
{
return try_lock_until(std::chrono::system_clock::now() + timeout);
}
template<class Clock, class Duration>
bool try_lock_until(const std::chrono::time_point<Clock, Duration>& time_point)
{
const auto seconds{std::chrono::time_point_cast<std::chrono::seconds>(time_point)};
const auto nanoseconds{std::chrono::duration_cast<std::chrono::nanoseconds>(time_point - seconds)};
timespec time{};
time.tv_sec = static_cast<std::time_t>(seconds.time_since_epoch().count());
time.tv_nsec = static_cast<long>(nanoseconds.count());
return !sem_timedwait(m_handle.get(), &time);
}
void release()
{
if(sem_post(m_handle.get()) == -1)
{
throw std::runtime_error{"Failed to increment semaphore count. " + std::string{strerror(errno)}};
}
}
native_handle_type native_handle() const noexcept
{
return m_handle.get();
}
private:
std::unique_ptr<sem_t> m_handle{std::make_unique<sem_t>()};
};
NES_INLINE_NAMESPACE_END
}
#endif
#endif
================================================
FILE: include/nes/shared_library.hpp
================================================
///////////////////////////////////////////////////////////
/// Copyright 2019 Alexy Pellegrini
///
/// Permission is hereby granted, free of charge,
/// to any person obtaining a copy of this software
/// and associated documentation files (the "Software"),
/// to deal in the Software without restriction,
/// including without limitation the rights to use,
/// copy, modify, merge, publish, distribute, sublicense,
/// and/or sell copies of the Software, and to permit
/// persons to whom the Software is furnished to do so,
/// subject to the following conditions:
///
/// The above copyright notice and this permission notice
/// shall be included in all copies or substantial portions
/// of the Software.
///
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
/// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
/// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
/// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
/// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
/// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
/// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
/// OR OTHER DEALINGS IN THE SOFTWARE.
///////////////////////////////////////////////////////////
#ifndef NOT_ENOUGH_STANDARDS_SHARED_LIBRARY
#define NOT_ENOUGH_STANDARDS_SHARED_LIBRARY
#if defined(_WIN32)
#define NES_WIN32_SHARED_LIBRARY
#ifndef NOMINMAX
#define NOMINMAX
#endif
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <Windows.h>
#elif defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))
#define NES_POSIX_SHARED_LIBRARY
#include <dlfcn.h>
#else
#error "Not enough standards does not support this environment."
#endif
#ifdef NES_INLINE_NAMESPACE
#define NES_INLINE_NAMESPACE_BEGIN \
inline namespace NES_INLINE_NAMESPACE \
{
#define NES_INLINE_NAMESPACE_END }
#else
#define NES_INLINE_NAMESPACE_BEGIN
#define NES_INLINE_NAMESPACE_END
#endif
#include <string>
#include <algorithm>
#include <cassert>
#include <stdexcept>
#include <utility>
#if defined(NES_WIN32_SHARED_LIBRARY)
namespace nes
{
NES_INLINE_NAMESPACE_BEGIN
struct load_current_t
{
};
inline constexpr load_current_t load_current{};
class shared_library
{
public:
using native_handle_type = HINSTANCE;
public:
constexpr shared_library() noexcept = default;
explicit shared_library(load_current_t)
{
m_handle = GetModuleHandleW(nullptr);
if(!m_handle)
{
throw std::runtime_error{"Failed to load current binary file. " + get_error_message()};
}
}
explicit shared_library(const std::string& path)
{
assert(!std::empty(path) && "nes::shared_library::shared_library called with empty path.");
m_handle = LoadLibraryW(to_wide(path).c_str());
if(!m_handle)
{
throw std::runtime_error{"Failed to load binary file \"" + path + "\". " + get_error_message()};
}
m_need_free = true;
}
~shared_library()
{
if(m_handle && m_need_free)
{
FreeLibrary(m_handle);
}
}
shared_library(const shared_library&) = delete;
shared_library& operator=(const shared_library&) = delete;
shared_library(shared_library&& other) noexcept
: m_handle{std::exchange(other.m_handle, native_handle_type{})}
, m_need_free{std::exchange(other.m_need_free, false)}
{
}
shared_library& operator=(shared_library&& other) noexcept
{
m_handle = std::exchange(other.m_handle, m_handle);
m_need_free = std::exchange(other.m_need_free, m_need_free);
return *this;
}
template<typename Func, typename = std::enable_if_t<std::is_pointer_v<Func> && std::is_function_v<std::remove_pointer_t<Func>>>>
Func load(const std::string& symbol) const noexcept
{
assert(!std::empty(symbol) && "nes::shared_library::load called with an empty symbol name.");
assert(m_handle && "nes::shared_library::load called with invalid handle.");
return reinterpret_cast<Func>(reinterpret_cast<void (*)()>(GetProcAddress(m_handle, std::data(symbol))));
}
template<typename Func, typename = std::enable_if_t<std::is_function_v<Func>>>
Func* load(const std::string& symbol) const noexcept
{
return load<Func*>(symbol);
}
native_handle_type native_handle() const noexcept
{
return m_handle;
}
private:
std::wstring to_wide(std::string path)
{
assert(std::size(path) < 0x7FFFFFFFu && "Wrong path.");
std::transform(std::begin(path), std::end(path), std::begin(path), [](char c)
{
return c == '/' ? '\\' : c;
});
std::wstring out_path{};
out_path.resize(static_cast<std::size_t>(MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, std::data(path), static_cast<int>(std::size(path)), nullptr, 0)));
if(!MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, std::data(path), static_cast<int>(std::size(path)), std::data(out_path), static_cast<int>(std::size(out_path))))
{
throw std::runtime_error{"Failed to convert the path to wide."};
}
return out_path;
}
std::string get_error_message() const
{
return "#" + std::to_string(GetLastError());
}
native_handle_type m_handle{};
bool m_need_free{};
};
NES_INLINE_NAMESPACE_END
}
#elif defined(NES_POSIX_SHARED_LIBRARY)
namespace nes
{
NES_INLINE_NAMESPACE_BEGIN
struct load_current_t
{
};
inline constexpr load_current_t load_current{};
class shared_library
{
public:
using native_handle_type = void*;
public:
constexpr shared_library() noexcept = default;
explicit shared_library(load_current_t)
{
m_handle = dlopen(nullptr, RTLD_NOW);
if(!m_handle)
{
throw std::runtime_error{"Failed to load current binary file. " + std::string{dlerror()}};
}
}
explicit shared_library(const std::string& path)
{
assert(!std::empty(path) && "nes::shared_library::shared_library called with empty path.");
m_handle = dlopen(std::data(path), RTLD_NOW);
if(!m_handle)
{
throw std::runtime_error{"Failed to load binary file \"" + path + "\". " + std::string{dlerror()}};
}
}
~shared_library()
{
if(m_handle)
{
dlclose(m_handle);
}
}
shared_library(const shared_library&) = delete;
shared_library& operator=(const shared_library&) = delete;
shared_library(shared_library&& other) noexcept
: m_handle{std::exchange(other.m_handle, native_handle_type{})}
{
}
shared_library& operator=(shared_library&& other) noexcept
{
m_handle = std::exchange(other.m_handle, m_handle);
return *this;
}
template<typename Func, typename = std::enable_if_t<std::is_pointer_v<Func> && std::is_function_v<std::remove_pointer_t<Func>>>>
Func load(const std::string& symbol) const noexcept
{
assert(!std::empty(symbol) && "nes::shared_library::load called with an empty symbol name.");
assert(m_handle && "nes::shared_library::load called with invalid handle.");
return reinterpret_cast<Func>(dlsym(m_handle, std::data(symbol)));
}
template<typename Func, typename = std::enable_if_t<std::is_function_v<Func>>>
Func* load(const std::string& symbol) const noexcept
{
return load<Func*>(symbol);
}
native_handle_type native_handle() const noexcept
{
return m_handle;
}
private:
native_handle_type m_handle{};
};
NES_INLINE_NAMESPACE_END
}
#endif
#endif
================================================
FILE: include/nes/shared_memory.hpp
================================================
///////////////////////////////////////////////////////////
/// Copyright 2019 Alexy Pellegrini
///
/// Permission is hereby granted, free of charge,
/// to any person obtaining a copy of this software
/// and associated documentation files (the "Software"),
/// to deal in the Software without restriction,
/// including without limitation the rights to use,
/// copy, modify, merge, publish, distribute, sublicense,
/// and/or sell copies of the Software, and to permit
/// persons to whom the Software is furnished to do so,
/// subject to the following conditions:
///
/// The above copyright notice and this permission notice
/// shall be included in all copies or substantial portions
/// of the Software.
///
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
/// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
/// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
/// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
/// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
/// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
/// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
/// OR OTHER DEALINGS IN THE SOFTWARE.
///////////////////////////////////////////////////////////
#ifndef NOT_ENOUGH_STANDARDS_SHARED_MEMORY
#define NOT_ENOUGH_STANDARDS_SHARED_MEMORY
#if defined(_WIN32)
#define NES_WIN32_SHARED_MEMORY
#ifndef NOMINMAX
#define NOMINMAX
#endif
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <Windows.h>
#elif defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))
#define NES_POSIX_SHARED_MEMORY
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#else
#error "Not enough standards does not support this environment."
#endif
#include <string>
#include <utility>
#include <stdexcept>
#include <memory>
#include <cassert>
#if defined(NES_WIN32_SHARED_MEMORY)
namespace nes
{
inline constexpr const char shared_memory_root[] = "Local\\";
enum class shared_memory_options : std::uint32_t
{
none = 0x00,
constant = 0x01
};
constexpr shared_memory_options operator&(shared_memory_options left, shared_memory_options right) noexcept
{
return static_cast<shared_memory_options>(static_cast<std::uint32_t>(left) & static_cast<std::uint32_t>(right));
}
constexpr shared_memory_options& operator&=(shared_memory_options& left, shared_memory_options right) noexcept
{
left = left & right;
return left;
}
constexpr shared_memory_options operator|(shared_memory_options left, shared_memory_options right) noexcept
{
return static_cast<shared_memory_options>(static_cast<std::uint32_t>(left) | static_cast<std::uint32_t>(right));
}
constexpr shared_memory_options& operator|=(shared_memory_options& left, shared_memory_options right) noexcept
{
left = left | right;
return left;
}
constexpr shared_memory_options operator^(shared_memory_options left, shared_memory_options right) noexcept
{
return static_cast<shared_memory_options>(static_cast<std::uint32_t>(left) ^ static_cast<std::uint32_t>(right));
}
constexpr shared_memory_options& operator^=(shared_memory_options& left, shared_memory_options right) noexcept
{
left = left ^ right;
return left;
}
constexpr shared_memory_options operator~(shared_memory_options value) noexcept
{
return static_cast<shared_memory_options>(~static_cast<std::uint32_t>(value));
}
namespace impl
{
inline std::uintptr_t get_allocation_granularity() noexcept
{
SYSTEM_INFO info{};
GetSystemInfo(&info);
return info.dwAllocationGranularity;
}
static const std::uintptr_t allocation_granularity_mask{~(get_allocation_granularity() - 1)};
template<class T>
struct is_unbounded_array : std::false_type
{
};
template<class T>
struct is_unbounded_array<T[]> : std::true_type
{
};
template<class T>
struct is_bounded_array : std::false_type
{
};
template<class T, std::size_t N>
struct is_bounded_array<T[N]> : std::true_type
{
};
}
template<typename T>
struct map_deleter
{
void operator()(T* ptr) const noexcept
{
if(ptr)
{
UnmapViewOfFile(reinterpret_cast<void*>(reinterpret_cast<std::uintptr_t>(ptr) & impl::allocation_granularity_mask));
}
}
};
template<typename T>
struct map_deleter<T[]>
{
void operator()(T* ptr) const noexcept
{
if(ptr)
{
UnmapViewOfFile(reinterpret_cast<void*>(reinterpret_cast<std::uintptr_t>(ptr) & impl::allocation_granularity_mask));
}
}
};
template<typename T>
using unique_map_t = std::unique_ptr<T, map_deleter<T>>;
template<typename T>
using shared_map_t = std::shared_ptr<T>;
template<typename T>
using weak_map_t = std::weak_ptr<T>;
class shared_memory
{
public:
using native_handle_type = HANDLE;
public:
constexpr shared_memory() noexcept = default;
explicit shared_memory(const std::string& name, std::uint64_t size)
{
assert(!std::empty(name) && "nes::shared_memory::shared_memory called with empty name.");
assert(size != 0 && "nes::shared_memory::shared_memory called with size == 0.");
const auto native_name{to_wide(shared_memory_root + name)};
m_handle = CreateFileMappingW(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, static_cast<DWORD>(size >> 32), static_cast<DWORD>(size), std::data(native_name));
if(!m_handle || GetLastError() == ERROR_ALREADY_EXISTS)
{
throw std::runtime_error{"Failed to create shared memory. " + get_error_message()};
}
}
explicit shared_memory(const std::string& name, shared_memory_options options = shared_memory_options::none)
{
assert(!std::empty(name) && "nes::shared_memory::shared_memory called with empty name.");
const auto native_name{to_wide(shared_memory_root + name)};
const DWORD access = static_cast<bool>(options & shared_memory_options::constant) ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS;
m_handle = OpenFileMappingW(access, FALSE, std::data(native_name));
if(!m_handle)
{
throw std::runtime_error{"Failed to open shared memory. " + get_error_message()};
}
}
~shared_memory()
{
if(m_handle)
{
CloseHandle(m_handle);
}
}
shared_memory(const shared_memory&) = delete;
shared_memory& operator=(const shared_memory&) = delete;
shared_memory(shared_memory&& other) noexcept
: m_handle{std::exchange(other.m_handle, nullptr)}
{
}
shared_memory& operator=(shared_memory&& other) noexcept
{
m_handle = std::exchange(other.m_handle, m_handle);
return *this;
}
template<typename T>
unique_map_t<T> map(std::uint64_t offset, shared_memory_options options = (std::is_const<T>::value ? shared_memory_options::constant : shared_memory_options::none)) const
{
static_assert(std::is_trivial<T>::value, "Behaviour is undefined if T is not a trivial type.");
static_assert(!impl::is_unbounded_array<T>::value, "T can not be an unbounded array type, i.e. T[]. Specify the size, or use the second overload if you don't know it at compile-time");
assert(m_handle && "nes::shared_memory::map called with an invalid handle.");
const DWORD access = static_cast<bool>(options & shared_memory_options::constant) ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS;
const auto aligned_offset{offset & impl::allocation_granularity_mask};
const auto real_size{static_cast<std::size_t>((offset - aligned_offset) + sizeof(T))};
auto* ptr{MapViewOfFile(m_handle, access, static_cast<DWORD>(aligned_offset >> 32), static_cast<DWORD>(aligned_offset), real_size)};
if(!ptr)
{
throw std::runtime_error{"Failed to map shared memory. " + get_error_message()};
}
ptr = reinterpret_cast<void*>(reinterpret_cast<std::uintptr_t>(ptr) + (offset - aligned_offset));
return unique_map_t<T>{static_cast<T*>(ptr)};
}
template<typename T>
shared_map_t<T> shared_map(std::uint64_t offset, shared_memory_options options = (std::is_const<T>::value ? shared_memory_options::constant : shared_memory_options::none)) const
{
return shared_map_t<T>{map<T>(offset, options)};
}
template<typename T, typename ValueType = typename std::remove_extent<T>::type>
unique_map_t<T> map(std::uint64_t offset, std::size_t count, shared_memory_options options = (std::is_const<ValueType>::value ? shared_memory_options::constant : shared_memory_options::none)) const
{
static_assert(std::is_trivial<ValueType>::value, "Behaviour is undefined if ValueType is not a trivial type.");
static_assert(!impl::is_bounded_array<T>::value, "T is an statically sized array, use the other overload of map instead of this one (remove the second parameter).");
static_assert(impl::is_unbounded_array<T>::value, "T must be an array type, i.e. T[].");
assert(m_handle && "nes::shared_memory::map called with an invalid handle.");
const DWORD access = static_cast<bool>(options & shared_memory_options::constant) ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS;
const auto aligned_offset{offset & impl::allocation_granularity_mask};
const auto real_size{static_cast<std::size_t>((offset - aligned_offset) + (sizeof(ValueType) * count))};
auto* ptr{MapViewOfFile(m_handle, access, static_cast<DWORD>(aligned_offset >> 32), static_cast<DWORD>(aligned_offset), real_size)};
if(!ptr)
{
throw std::runtime_error{"Failed to map shared memory. " + get_error_message()};
}
ptr = reinterpret_cast<void*>(reinterpret_cast<std::uintptr_t>(ptr) + (offset - aligned_offset));
return unique_map_t<T>{static_cast<ValueType*>(ptr)};
}
template<typename T, typename ValueType = typename std::remove_extent<T>::type>
shared_map_t<T> shared_map(std::uint64_t offset, std::size_t count, shared_memory_options options = (std::is_const<ValueType>::value ? shared_memory_options::constant : shared_memory_options::none)) const
{
return shared_map_t<T>{map<T>(offset, count, options)};
}
native_handle_type native_handle() const noexcept
{
return m_handle;
}
private:
std::wstring to_wide(const std::string& path)
{
assert(std::size(path) < 0x7FFFFFFFu && "Wrong path.");
if(std::empty(path))
{
return {};
}
std::wstring out_path{};
out_path.resize(static_cast<std::size_t>(MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, std::data(path), static_cast<int>(std::size(path)), nullptr, 0)));
if(!MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, std::data(path), static_cast<int>(std::size(path)), std::data(out_path), static_cast<int>(std::size(out_path))))
{
throw std::runtime_error{"Failed to convert the path to wide."};
}
return out_path;
}
std::string get_error_message() const
{
return "#" + std::to_string(GetLastError());
}
private:
native_handle_type m_handle{};
};
}
#elif defined(NES_POSIX_SHARED_MEMORY)
namespace nes
{
inline constexpr const char shared_memory_root[] = "/";
enum class shared_memory_options : std::uint32_t
{
none = 0x00,
constant = 0x01
};
constexpr shared_memory_options operator&(shared_memory_options left, shared_memory_options right) noexcept
{
return static_cast<shared_memory_options>(static_cast<std::uint32_t>(left) & static_cast<std::uint32_t>(right));
}
constexpr shared_memory_options& operator&=(shared_memory_options& left, shared_memory_options right) noexcept
{
left = left & right;
return left;
}
constexpr shared_memory_options operator|(shared_memory_options left, shared_memory_options right) noexcept
{
return static_cast<shared_memory_options>(static_cast<std::uint32_t>(left) | static_cast<std::uint32_t>(right));
}
constexpr shared_memory_options& operator|=(shared_memory_options& left, shared_memory_options right) noexcept
{
left = left | right;
return left;
}
constexpr shared_memory_options operator^(shared_memory_options left, shared_memory_options right) noexcept
{
return static_cast<shared_memory_options>(static_cast<std::uint32_t>(left) ^ static_cast<std::uint32_t>(right));
}
constexpr shared_memory_options& operator^=(shared_memory_options& left, shared_memory_options right) noexcept
{
left = left ^ right;
return left;
}
constexpr shared_memory_options operator~(shared_memory_options value) noexcept
{
return static_cast<shared_memory_options>(~static_cast<std::uint32_t>(value));
}
namespace impl
{
inline std::uintptr_t get_allocation_granularity() noexcept
{
return static_cast<std::uintptr_t>(sysconf(_SC_PAGE_SIZE));
}
static const std::uintptr_t allocation_granularity_mask{~(get_allocation_granularity() - 1)};
template<class T>
struct is_unbounded_array : std::false_type
{
};
template<class T>
struct is_unbounded_array<T[]> : std::true_type
{
};
template<class T>
struct is_bounded_array : std::false_type
{
};
template<class T, std::size_t N>
struct is_bounded_array<T[N]> : std::true_type
{
};
}
template<typename T>
struct map_deleter
{
void operator()(T* ptr) const noexcept
{
if(ptr)
{
const auto base_address{reinterpret_cast<std::uintptr_t>(ptr) & impl::allocation_granularity_mask};
munmap(reinterpret_cast<void*>(base_address), static_cast<std::size_t>(reinterpret_cast<std::uintptr_t>(ptr) - base_address) + sizeof(T));
}
}
};
template<typename T>
struct map_deleter<T[]>
{
void operator()(T* ptr) const noexcept
{
if(ptr)
{
const auto base_address{reinterpret_cast<std::uintptr_t>(ptr) & impl::allocation_granularity_mask};
munmap(reinterpret_cast<void*>(base_address), static_cast<std::size_t>(reinterpret_cast<std::uintptr_t>(ptr) - base_address) + (sizeof(T) * count));
}
}
std::size_t count{};
};
template<typename T>
using unique_map_t = std::unique_ptr<T, map_deleter<T>>;
template<typename T>
using shared_map_t = std::shared_ptr<T>;
template<typename T>
using weak_map_t = std::weak_ptr<T>;
class shared_memory
{
public:
using native_handle_type = int;
public:
constexpr shared_memory() noexcept = default;
explicit shared_memory(const std::string& name, std::uint64_t size)
{
assert(!std::empty(name) && "nes::shared_memory::shared_memory called with empty name.");
assert(size != 0 && "nes::shared_memory::shared_memory called with size == 0.");
const auto native_name{shared_memory_root + name};
m_handle = shm_open(std::data(native_name), O_RDWR | O_CREAT | O_TRUNC, 0660);
if(m_handle == -1)
{
throw std::runtime_error{"Failed to create shared memory. " + std::string{strerror(errno)}};
}
if(ftruncate(m_handle, static_cast<off_t>(size)) == -1)
{
close(m_handle);
throw std::runtime_error{"Failed to set shared memory size. " + std::string{strerror(errno)}};
}
}
explicit shared_memory(const std::string& name, shared_memory_options options = shared_memory_options::none)
{
assert(!std::empty(name) && "nes::shared_memory::shared_memory called with empty name.");
const auto native_name{shared_memory_root + name};
const auto access = static_cast<bool>(options & shared_memory_options::constant) ? O_RDONLY : O_RDWR;
m_handle = shm_open(std::data(native_name), access, 0660);
if(m_handle == -1)
{
throw std::runtime_error{"Failed to open shared memory. " + std::string{strerror(errno)}};
}
}
~shared_memory()
{
if(m_handle != -1)
{
close(m_handle);
}
}
shared_memory(const shared_memory&) = delete;
shared_memory& operator=(const shared_memory&) = delete;
shared_memory(shared_memory&& other) noexcept
: m_handle{std::exchange(other.m_handle, -1)}
{
}
shared_memory& operator=(shared_memory&& other) noexcept
{
m_handle = std::exchange(other.m_handle, m_handle);
return *this;
}
template<typename T>
unique_map_t<T> map(std::uint64_t offset, shared_memory_options options = (std::is_const<T>::value ? shared_memory_options::constant : shared_memory_options::none)) const
{
static_assert(std::is_trivial<T>::value, "Behaviour is undefined if T is not a trivial type.");
static_assert(!impl::is_unbounded_array<T>::value, "T can not be an unbounded array type, i.e. T[]. Specify the size, or use the second overload if you don't know it at compile-time");
assert(m_handle != -1 && "nes::shared_memory::map called with an invalid handle.");
const auto access = static_cast<bool>(options & shared_memory_options::constant) ? PROT_READ : PROT_READ | PROT_WRITE;
const auto aligned_offset{offset & impl::allocation_granularity_mask};
const auto real_size{static_cast<std::size_t>((offset - aligned_offset) + sizeof(T))};
auto* ptr{mmap(nullptr, real_size, access, MAP_SHARED, m_handle, static_cast<off_t>(aligned_offset))};
if(ptr == MAP_FAILED)
{
throw std::runtime_error{"Failed to map shared memory. " + std::string{strerror(errno)}};
}
ptr = reinterpret_cast<void*>(reinterpret_cast<std::uintptr_t>(ptr) + (offset - aligned_offset));
return unique_map_t<T>{reinterpret_cast<T*>(ptr)};
}
template<typename T>
shared_map_t<T> shared_map(std::uint64_t offset, shared_memory_options options = (std::is_const<T>::value ? shared_memory_options::constant : shared_memory_options::none)) const
{
return shared_map_t<T>{map<T>(offset, options)};
}
template<typename T, typename ValueType = typename std::remove_extent<T>::type>
unique_map_t<T> map(std::uint64_t offset, std::size_t count, shared_memory_options options = (std::is_const<ValueType>::value ? shared_memory_options::constant : shared_memory_options::none)) const
{
static_assert(std::is_trivial<ValueType>::value, "Behaviour is undefined if ValueType is not a trivial type.");
static_assert(!impl::is_bounded_array<T>::value, "T is an statically sized array, use the other overload of map instead of this one (remove the second parameter).");
static_assert(impl::is_unbounded_array<T>::value, "T must be an array type, i.e. T[].");
assert(m_handle != -1 && "nes::shared_memory::map called with an invalid handle.");
const auto access = static_cast<bool>(options & shared_memory_options::constant) ? PROT_READ : PROT_READ | PROT_WRITE;
const auto aligned_offset{offset & impl::allocation_granularity_mask};
const auto real_size{static_cast<std::size_t>((offset - aligned_offset) + (sizeof(ValueType) * count))};
auto* ptr{mmap(nullptr, real_size, access, MAP_SHARED, m_handle, static_cast<off_t>(aligned_offset))};
if(ptr == MAP_FAILED)
{
throw std::runtime_error{"Failed to map shared memory. " + std::string{strerror(errno)}};
}
ptr = reinterpret_cast<void*>(reinterpret_cast<std::uintptr_t>(ptr) + (offset - aligned_offset));
return unique_map_t<T>{reinterpret_cast<ValueType*>(ptr), map_deleter<T>{count}};
}
template<typename T, typename ValueType = typename std::remove_extent<T>::type>
shared_map_t<T> shared_map(std::uint64_t offset, std::size_t count, shared_memory_options options = (std::is_const<ValueType>::value ? shared_memory_options::constant : shared_memory_options::none)) const
{
return shared_map_t<T>{map<T>(offset, count, options)};
}
native_handle_type native_handle() const noexcept
{
return m_handle;
}
private:
native_handle_type m_handle{-1};
};
}
#endif
#endif
================================================
FILE: include/nes/thread_pool.hpp
================================================
///////////////////////////////////////////////////////////
/// Copyright 2020 Alexy Pellegrini
///
/// Permission is hereby granted, free of charge,
/// to any person obtaining a copy of this software
/// and associated documentation files (the "Software"),
/// to deal in the Software without restriction,
/// including without limitation the rights to use,
/// copy, modify, merge, publish, distribute, sublicense,
/// and/or sell copies of the Software, and to permit
/// persons to whom the Software is furnished to do so,
/// subject to the following conditions:
///
/// The above copyright notice and this permission notice
/// shall be included in all copies or substantial portions
/// of the Software.
///
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
/// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
/// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
/// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
/// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
/// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
/// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
/// OR OTHER DEALINGS IN THE SOFTWARE.
///////////////////////////////////////////////////////////
#ifndef NOT_ENOUGH_STANDARDS_THREAD_POOL
#define NOT_ENOUGH_STANDARDS_THREAD_POOL
#ifdef NES_INLINE_NAMESPACE
#define NES_INLINE_NAMESPACE_BEGIN \
inline namespace NES_INLINE_NAMESPACE \
{
#define NES_INLINE_NAMESPACE_END }
#else
#define NES_INLINE_NAMESPACE_BEGIN
#define NES_INLINE_NAMESPACE_END
#endif
#include <vector>
#include <atomic>
#include <thread>
#include <future>
#include <condition_variable>
#include <mutex>
#include <functional>
#include <iterator>
#include <variant>
#include <cassert>
#include <span>
#include <utility>
namespace nes
{
NES_INLINE_NAMESPACE_BEGIN
namespace impl
{
class checkpoint_holder_base
{
public:
checkpoint_holder_base(bool barrier)
: m_barrier{barrier}
{
}
virtual ~checkpoint_holder_base() = default;
checkpoint_holder_base(const checkpoint_holder_base&) = delete;
checkpoint_holder_base& operator=(const checkpoint_holder_base&) = delete;
checkpoint_holder_base(checkpoint_holder_base&&) = delete;
checkpoint_holder_base& operator=(checkpoint_holder_base&&) = delete;
virtual void set_reset_value(std::size_t value) noexcept = 0;
virtual void reset() = 0;
virtual bool count_down() noexcept = 0;
virtual bool check_barrier() const noexcept = 0;
bool is_barrier() const noexcept
{
return m_barrier;
}
private:
bool m_barrier{};
};
template<typename T>
class checkpoint_holder final : public checkpoint_holder_base
{
public:
explicit checkpoint_holder(bool barrier, std::future<T>*& user_reference)
: checkpoint_holder_base{barrier}
{
user_reference = &m_future;
}
~checkpoint_holder() = default;
checkpoint_holder(const checkpoint_holder&) = delete;
checkpoint_holder& operator=(const checkpoint_holder&) = delete;
checkpoint_holder(checkpoint_holder&&) = delete;
checkpoint_holder& operator=(checkpoint_holder&&) = delete;
void set_reset_value(std::size_t value) noexcept override
{
m_reset_value = value;
}
void reset() override
{
m_promise = std::promise<void>{};
m_future = m_promise.get_future();
m_counter.store(m_reset_value, std::memory_order_release);
}
bool count_down() noexcept override
{
const bool last{--(m_counter) == 0};
if(last)
{
m_promise.set_value();
}
return last;
}
bool check_barrier() const noexcept override
{
return m_counter.load(std::memory_order_acquire) == 1;
}
private:
std::promise<T> m_promise{};
std::future<T> m_future{};
std::atomic<std::size_t> m_counter{};
std::size_t m_reset_value{};
};
class checkpoint // checkpoints and barriers type
{
public:
template<typename T>
checkpoint(bool barrier, std::future<T>*& user_reference)
: m_checkpoint{std::make_unique<checkpoint_holder<T>>(barrier, user_reference)}
{
}
~checkpoint() = default;
checkpoint(const checkpoint&) = delete;
checkpoint& operator=(const checkpoint&) = delete;
checkpoint(checkpoint&&) = default;
checkpoint& operator=(checkpoint&&) = default;
void set_reset_value(std::size_t value) noexcept
{
m_checkpoint->set_reset_value(value);
}
void reset()
{
m_checkpoint->reset();
}
bool count_down() noexcept
{
return m_checkpoint->count_down();
}
bool check_barrier() const noexcept
{
return m_checkpoint->check_barrier();
}
bool is_barrier() const noexcept
{
return m_checkpoint->is_barrier();
}
checkpoint_holder_base* base() const noexcept
{
return m_checkpoint.get();
}
private:
std::unique_ptr<checkpoint_holder_base> m_checkpoint{};
};
using checkpoint_range = std::span<checkpoint_holder_base*>;
class task_holder_base // base class for type erasing in task
{
public:
task_holder_base() = default;
virtual ~task_holder_base() = default;
task_holder_base(const task_holder_base&) = delete;
task_holder_base& operator=(const task_holder_base&) = delete;
task_holder_base(task_holder_base&&) = delete;
task_holder_base& operator=(task_holder_base&&) = delete;
virtual void reset() = 0;
virtual void execute() = 0;
// checkpoints to count down once this task is done
void set_checkpoint_range(checkpoint_range checkpoints)
{
m_checkpoints = checkpoints;
}
protected:
void trigger_checkpoints()
{
for(auto& checkpoint : m_checkpoints)
{
checkpoint->count_down();
}
}
private:
checkpoint_range m_checkpoints{};
};
// task holder that not returns a value, used for execute function
template<typename Func>
class task_holder final : public task_holder_base
{
public:
task_holder(Func&& func)
: m_func{std::move(func)}
{
}
~task_holder() = default;
task_holder(const task_holder&) = delete;
task_holder& operator=(const task_holder&) = delete;
task_holder(task_holder&&) = delete;
task_holder& operator=(task_holder&&) = delete;
void execute() override
{
m_func();
trigger_checkpoints();
}
void reset() override
{
}
private:
Func m_func;
};
// task holder that returns a value, used for invoke function
template<typename Func, typename Ret>
class return_task_holder final : public task_holder_base
{
public:
return_task_holder(Func&& func, std::future<Ret>*& user_reference)
: m_func{std::move(func)}
{
user_reference = &m_future;
}
~return_task_holder() = default;
return_task_holder(const return_task_holder&) = delete;
return_task_holder& operator=(const return_task_holder&) = delete;
return_task_holder(return_task_holder&&) = delete;
return_task_holder& operator=(return_task_holder&&) = delete;
void execute() override
{
if constexpr(std::is_same_v<Ret, void>)
{
m_func();
m_promise.set_value();
}
else
{
m_promise.set_value(m_func());
}
trigger_checkpoints();
}
void reset() override
{
m_promise = std::promise<Ret>{};
m_future = m_promise.get_future();
}
private:
Func m_func;
std::promise<Ret> m_promise{};
std::future<Ret> m_future{};
};
class task // actual execution unit
{
public:
template<typename Func>
task(Func&& func)
: m_holder{std::make_unique<task_holder<Func>>(std::forward<Func>(func))}
{
}
template<typename Func, typename Ret>
task(Func&& func, std::future<Ret>*& user_reference)
: m_holder{std::make_unique<return_task_holder<Func, Ret>>(std::forward<Func>(func), user_reference)}
{
}
~task() = default;
task(const task&) = delete;
task& operator=(const task&) = delete;
task(task&&) = default;
task& operator=(task&&) = default;
void set_checkpoint_range(checkpoint_range checkpoints)
{
m_holder->set_checkpoint_range(checkpoints);
}
void execute()
{
m_holder->execute();
}
void reset()
{
m_holder->reset();
}
task_holder_base* holder() const noexcept
{
return m_holder.get();
}
private:
std::unique_ptr<task_holder_base> m_holder{};
};
class fence_holder
{
public:
fence_holder() = default;
~fence_holder() = default;
fence_holder(const fence_holder&) = delete;
fence_holder& operator=(const fence_holder&) = delete;
fence_holder(fence_holder&&) = delete;
fence_holder& operator=(fence_holder&&) = delete;
void set_condition(std::condition_variable& condition) noexcept
{
m_condition = &condition;
}
void reset() noexcept
{
m_signaled.store(false, std::memory_order_release);
}
void signal() noexcept
{
m_signaled.store(true, std::memory_order_release);
m_condition->notify_one();
}
bool is_signaled() const noexcept
{
return m_signaled.load(std::memory_order_acquire);
}
private:
std::condition_variable* m_condition{};
std::atomic<bool> m_signaled{};
};
class fence
{
public:
fence()
: m_holder{std::make_unique<fence_holder>()}
{
}
~fence() = default;
fence(const fence&) = delete;
fence& operator=(const fence&) = delete;
fence(fence&&) = default;
fence& operator=(fence&&) = default;
void set_condition(std::condition_variable& condition) noexcept
{
m_holder->set_condition(condition);
}
void reset() noexcept
{
m_holder->reset();
}
void signal() noexcept
{
m_holder->signal();
}
bool is_signaled() const noexcept
{
return m_holder->is_signaled();
}
fence_holder* holder() const noexcept
{
return m_holder.get();
}
private:
std::unique_ptr<fence_holder> m_holder{};
};
using task_type = std::variant<checkpoint, task, fence>;
}
template<typename T>
class task_result
{
friend class task_builder;
public:
task_result() = default;
~task_result() = default;
task_result(const task_result&) = delete;
task_result& operator=(const task_result&) = delete;
task_result(task_result&& other) noexcept
: m_state{std::exchange(other.m_state, nullptr)}
{
}
task_result& operator=(task_result&& other) noexcept
{
m_state = std::exchange(other.m_state, nullptr);
return *this;
}
T get()
{
return m_state->get();
}
bool valid() const noexcept
{
return m_state->valid();
}
void wait() const
{
m_state->wait();
}
template<class Rep, class Period>
bool wait_for(const std::chrono::duration<Rep, Period>& timeout) const
{
return m_state->wait_for(timeout) == std::future_status::ready;
}
template<class Rep, class Period>
bool wait_until(const std::chrono::duration<Rep, Period>& timeout) const
{
return m_state->wait_until(timeout) == std::future_status::ready;
}
private:
std::future<T>* m_state{};
};
using task_checkpoint = task_result<void>;
class task_fence
{
friend class task_builder;
public:
task_fence() = default;
~task_fence() = default;
task_fence(const task_fence&) = delete;
task_fence& operator=(const task_fence&) = delete;
task_fence(task_fence&& other) noexcept
: m_holder{std::exchange(other.m_holder, nullptr)}
{
}
task_fence& operator=(task_fence&& other) noexcept
{
m_holder = std::exchange(other.m_holder, nullptr);
return *this;
}
void signal() noexcept
{
m_holder->signal();
}
private:
impl::fence_holder* m_holder{};
};
class task_list
{
friend class thread_pool;
friend class task_builder;
public:
constexpr task_list() = default;
~task_list() = default;
task_list(const task_list&) = delete;
task_list& operator=(const task_list&) = delete;
task_list(task_list&&) = default;
task_list& operator=(task_list&&) = default;
private:
void reset(std::condition_variable& condition)
{
for(auto& task : m_tasks)
{
std::visit([&condition](auto&& task)
{
using alternative_type = std::decay_t<decltype(task)>;
if constexpr(std::is_same_v<alternative_type, impl::fence>)
{
task.set_condition(condition);
}
task.reset();
},
task);
}
m_current = std::begin(m_tasks);
}
// bool: is the task_list done after that ?
// count: number of task executable at call time
// outputit: outputis to store the tasks
template<typename OutputIt>
std::pair<bool, std::size_t> next(OutputIt output)
{
std::size_t count{};
while(m_current != std::end(m_tasks))
{
if(std::holds_alternative<impl::checkpoint>(*m_current))
{
auto& checkpoint{std::get<impl::checkpoint>(*m_current)};
if(checkpoint.is_barrier() && !checkpoint.check_barrier())
{
return std::make_pair(false, count);
}
checkpoint.count_down();
}
else if(std::holds_alternative<impl::task>(*m_current))
{
auto& task{std::get<impl::task>(*m_current)};
*output++ = task.holder();
++count;
}
else
{
auto& fence{std::get<impl::fence>(*m_current)};
if(!fence.is_signaled())
{
return std::make_pair(false, count);
}
}
++m_current;
}
return std::make_pair(true, count);
}
private:
std::vector<impl::task_type> m_tasks{};
std::vector<impl::task_type>::iterator m_current{};
std::vector<impl::checkpoint_holder_base*> m_checkpoints{};
};
class task_builder
{
public:
explicit task_builder(std::uint32_t thread_count = std::thread::hardware_concurrency())
: m_thread_count{thread_count != 0 ? thread_count : 8}
{
m_tasks.reserve(32);
}
~task_builder() = default;
task_builder(const task_builder&) = delete;
task_builder& operator=(const task_builder&) = delete;
task_builder(task_builder&&) = default;
task_builder& operator=(task_builder&&) = default;
template<typename Func, typename... Args>
void execute(Func&& func, Args&&... args)
{
push_task([func = std::forward<Func>(func), ... args = std::forward<Args>(args)]() mutable
{
std::invoke(func, args...);
});
}
template<typename Func, typename... Args>
[[nodiscard("Use execute instead of invoke when the returned future is not needed")]]
auto invoke(Func&& func, Args&&... args)
{
using func_return_type = std::invoke_result_t<Func, Args...>;
using result_type = task_result<func_return_type>;
result_type output{};
push_task([func = std::forward<Func>(func), ... args = std::forward<Args>(args)]() mutable
{
return std::invoke(func, args...);
},
output.m_state);
return output;
}
template<typename Func, typename... Args>
void dispatch(std::uint32_t x, std::uint32_t y, std::uint32_t z, Func&& func, Args&&... args)
{
dispatch(x, y, z, std::numeric_limits<std::uint32_t>::max(), std::forward<Func>(func), std::forward<Args>(args)...);
}
template<typename Func, typename... Args>
void dispatch(std::uint32_t x, std::uint32_t y, std::uint32_t z, std::uint32_t max_invoke_per_task, Func&& func, Args&&... args)
{
assert(x != 0 && "nes::task_builder::dispatch called with x == 0");
assert(y != 0 && "nes::task_builder::dispatch called with y == 0");
assert(z != 0 && "nes::task_builder::dispatch called with z == 0");
assert(max_invoke_per_task != 0 && "nes::task_builder::dispatch called with max_invoke_per_task == 0");
const std::uint64_t total_calls{static_cast<std::uint64_t>(x) * y * z};
if(total_calls < m_thread_count) // one invocation per thread
{
for(std::uint32_t current_z{}; current_z < z; ++current_z)
{
for(std::uint32_t current_y{}; current_y < y; ++current_y)
{
for(std::uint32_t current_x{}; current_x < x; ++current_x)
{
push_task([current_x, current_y, current_z, func = std::forward<Func>(func), ... args = std::forward<Args>(args)]() mutable
{
std::invoke(func, current_x, current_y, current_z, args...);
});
}
}
}
}
else if(total_calls <= static_cast<std::uint64_t>(max_invoke_per_task) * m_thread_count) // max_invoke_per_task or less invocations per thread
{
const std::uint64_t calls_per_thread{total_calls / m_thread_count};
std::uint64_t remainder{total_calls % m_thread_count};
std::uint64_t calls{};
while(calls < total_calls)
{
std::uint64_t count{calls_per_thread};
if(remainder > 0)
{
++count;
--remainder;
}
push_task([calls, count, x, y, z_factor = (x * y), func = std::forward<Func>(func), ... args = std::forward<Args>(args)]() mutable
{
for(std::uint64_t i{calls}; i < calls + count; ++i)
{
const auto current_x{static_cast<std::uint32_t>(i % x)};
const auto current_y{static_cast<std::uint32_t>((i / x) % y)};
const auto current_z{static_cast<std::uint32_t>(i / z_factor)};
std::invoke(func, current_x, current_y, current_z, args...);
}
});
calls += count;
}
}
else // create tasks that perform max_invoke_per_task invocations each, until we reach the total number of invocations
{
std::uint64_t calls{};
while(calls < total_calls)
{
std::uint64_t count{std::min(static_cast<std::size_t>(max_invoke_per_task), total_calls - calls)};
push_task([calls, count, x, y, z_factor = (x * y), func = std::forward<Func>(func), ... args = std::forward<Args>(args)]() mutable
{
for(std::uint64_t i{calls}; i < calls + count; ++i)
{
const auto current_x{static_cast<std::uint32_t>(i % x)};
const auto current_y{static_cast<std::uint32_t>((i / x) % y)};
const auto current_z{static_cast<std::uint32_t>(i / z_factor)};
std::invoke(func, current_x, current_y, current_z, args...);
}
});
calls += count;
}
}
}
task_checkpoint barrier()
{
task_result<void> output{};
m_tasks.emplace_back(std::in_place_type<impl::checkpoint>, true, output.m_state);
return output;
}
[[nodiscard]] task_checkpoint checkpoint()
{
task_result<void> output{};
m_tasks.emplace_back(std::in_place_type<impl::checkpoint>, false, output.m_state);
return output;
}
[[nodiscard]] task_fence fence()
{
task_fence output{};
output.m_holder = std::get<impl::fence>(m_tasks.emplace_back(std::in_place_type<impl::fence>)).holder();
return output;
}
task_list build()
{
barrier(); // this barrier is used by the pool to know when all the tasks are done and the list can be returned to user
task_list output{};
output.m_tasks.reserve(std::size(m_tasks));
output.m_checkpoints.reserve(count_checkpoints());
auto begin{std::begin(m_tasks)};
auto current{begin};
std::size_t checkpoints_begin{};
std::size_t checkpoints_size{};
while(current != std::end(m_tasks))
{
if(std::holds_alternative<impl::checkpoint>(*current))
{
auto& checkpoint{std::get<impl::checkpoint>(*current)};
output.m_checkpoints.emplace_back(checkpoint.base());
++checkpoints_size;
if(checkpoint.is_barrier())
{
const auto checkpoints_it{std::begin(output.m_checkpoints) + checkpoints_begin};
flush(output.m_tasks, checkpoints_it, checkpoints_it + checkpoints_size, begin, current + 1);
checkpoints_begin += checkpoints_size;
checkpoints_size = 0;
begin = current + 1;
}
}
++current;
}
m_tasks.clear();
return output;
}
private:
template<typename... Args>
void push_task(Args&&... args)
{
m_tasks.emplace_back(std::in_place_type<impl::task>, std::forward<Args>(args)...);
}
template<typename InputIt, typename CheckpointIt>
void flush(std::vector<impl::task_type>& output, CheckpointIt checkpoints_begin, CheckpointIt checkpoints_end, InputIt begin, InputIt end)
{
std::size_t checkpoint_counter{};
while(begin != end)
{
if(std::holds_alternative<impl::checkpoint>(*begin))
{
auto checkpoint{std::get<impl::checkpoint>(std::move(*begin))};
checkpoint.set_reset_value(checkpoint_counter + 1); //+ 1 for the caller
output.emplace_back(std::in_place_type<impl::checkpoint>, std::move(checkpoint));
++checkpoints_begin;
}
else if(std::holds_alternative<impl::task>(*begin))
{
auto task{std::get<impl::task>(std::move(*begin))};
task.set_checkpoint_range(impl::checkpoint_range{checkpoints_begin, checkpoints_end});
output.emplace_back(std::in_place_type<impl::task>, std::move(task));
++checkpoint_counter;
}
else
{
auto fence{std::get<impl::fence>(std::move(*begin))};
output.emplace_back(std::in_place_type<impl::fence>, std::move(fence));
}
++begin;
}
}
std::size_t count_checkpoints() const noexcept
{
return std::count_if(std::begin(m_tasks), std::end(m_tasks), [](auto&& task)
{
return std::holds_alternative<impl::checkpoint>(task);
});
}
private:
std::uint32_t m_thread_count{};
std::vector<impl::task_type> m_tasks{};
};
class thread_pool
{
public:
explicit thread_pool(std::size_t thread_count = std::thread::hardware_concurrency())
{
const auto worker_base = [this]()
{
worker_main();
};
thread_count = thread_count != 0 ? thread_count : 8;
m_threads.reserve(thread_count);
for(std::size_t i{}; i < thread_count; ++i)
{
m_threads.emplace_back(worker_base);
}
m_tasks.reserve(4 * thread_count);
m_task_lists.reserve(4 * thread_count);
}
~thread_pool()
{
std::unique_lock lock{m_mutex};
m_wait_condition.wait(lock, [this]
{
return std::empty(m_tasks) && std::empty(m_task_lists);
});
m_running = false;
lock.unlock();
m_worker_condition.notify_all();
for(auto&& thread : m_threads)
{
if(thread.joinable())
{
thread.join();
}
}
}
thread_pool(const thread_pool&) = delete;
thread_pool& operator=(const thread_pool&) = delete;
thread_pool(thread_pool&&) = delete;
thread_pool& operator=(thread_pool&&) = delete;
template<typename Func, typename... Args>
void execute(Func&& func, Args&&... args)
{
push_impl([func = std::forward<Func>(func), ... args = std::forward<Args>(args)]() mutable
{
std::invoke(std::forward<Func>(func), std::forward<Args>(args)...);
});
m_worker_condition.notify_one();
}
template<typename Func, typename... Args>
[[nodiscard("Use execute instead of invoke when the returned future is not needed")]]
auto invoke(Func&& func, Args&&... args)
{
using return_type = std::invoke_result_t<Func, Args...>;
using promise_type = std::promise<return_type>;
using future_type = std::future<return_type>;
promise_type promise{};
future_type future{promise.get_future()};
if constexpr(std::is_same_v<return_type, void>)
{
push_impl([promise = std::move(promise), func = std::forward<Func>(func), ... args = std::forward<Args>(args)]() mutable
{
std::invoke(std::forward<Func>(func), std::forward<Args>(args)...);
promise.set_value();
});
}
else
{
push_impl([promise = std::move(promise), func = std::forward<Func>(func), ... args = std::forward<Args>(args)]() mutable
{
promise.set_value(std::invoke(std::forward<Func>(func), std::forward<Args>(args)...));
});
}
m_worker_condition.notify_one();
return future;
}
std::future<task_list> push(task_list&& list)
{
list.reset(m_worker_condition);
std::unique_lock lock{m_mutex};
auto& data{m_task_lists.emplace_back()};
data.list = std::move(list);
auto future{data.promise.get_future()};
const auto notify_count{update_task_lists()};
lock.unlock();
for(std::size_t i{}; i < std::min(notify_count, std::size(m_threads)); ++i)
{
m_worker_condition.notify_one();
}
return future;
}
void wait_idle()
{
std::unique_lock lock{m_mutex};
m_wait_condition.wait(lock, [this]
{
return std::empty(m_tasks) && std::empty(m_task_lists);
});
}
std::size_t thread_count() const noexcept
{
return std::size(m_threads);
}
private:
void worker_main()
{
while(true)
{
std::unique_lock lock{m_mutex};
m_worker_condition.wait(lock, [this]
{
if(std::empty(m_tasks) && !std::empty(m_task_lists))
{
const auto notify_count{update_task_lists()};
for(std::size_t i{}; i < std::min(notify_count, std::size(m_threads)); ++i)
{
m_worker_condition.notify_one();
}
}
if(std::empty(m_tasks) && std::empty(m_task_lists))
{
m_wait_condition.notify_all();
}
return !m_running || !std::empty(m_tasks);
});
if(!m_running)
{
break;
}
auto task{std::move(m_tasks.front())};
m_tasks.erase(std::begin(m_tasks));
lock.unlock();
if(std::holds_alternative<impl::task>(task))
{
std::get<impl::task>(task).execute();
}
else
{
std::get<impl::task_holder_base*>(task)->execute();
}
}
}
template<typename Func>
void push_impl(Func&& func)
{
std::lock_guard lock{m_mutex};
m_tasks.emplace_back(std::in_place_type<impl::task>, std::forward<Func>(func));
}
std::size_t update_task_lists()
{
std::size_t notify_count{};
bool need_free{};
for(auto& list : m_task_lists)
{
const auto [end, count] = list.list.next(std::back_inserter(m_tasks));
if(end && count == 0)
{
list.promise.set_value(std::move(list.list));
list.need_free = true;
need_free = true;
}
notify_count += count;
}
if(need_free)
{
const auto predicate = [](const task_list_data& list)
{
return list.need_free;
};
m_task_lists.erase(std::remove_if(std::begin(m_task_lists), std::end(m_task_lists), predicate), std::end(m_task_lists));
}
return notify_count;
}
private:
struct task_list_data
{
task_list list{};
std::promise<task_list> promise{};
bool need_free{};
};
private:
std::vector<std::thread> m_threads{};
std::vector<std::variant<impl::task, impl::task_holder_base*>> m_tasks{};
std::vector<task_list_data> m_task_lists{};
std::condition_variable m_worker_condition{};
std::condition_variable m_wait_condition{};
std::mutex m_mutex{};
bool m_running{true};
};
NES_INLINE_NAMESPACE_END
}
#endif
================================================
FILE: tests/common.hpp
================================================
///////////////////////////////////////////////////////////
/// Copyright 2019 Alexy Pellegrini
///
/// Permission is hereby granted, free of charge,
/// to any person obtaining a copy of this software
/// and associated documentation files (the "Software"),
/// to deal in the Software without restriction,
/// including without limitation the rights to use,
/// copy, modify, merge, publish, distribute, sublicense,
/// and/or sell copies of the Software, and to permit
/// persons to whom the Software is furnished to do so,
/// subject to the following conditions:
///
/// The above copyright notice and this permission notice
/// shall be included in all copies or substantial portions
/// of the Software.
///
/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
/// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
/// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
/// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
/// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
/// ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
/// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
/// OR OTHER DEALINGS IN THE SOFTWARE.
///////////////////////////////////////////////////////////
#ifndef NOT_ENOUGH_STANDARDS_TESTS_COMMON
#define NOT_ENOUGH_STANDARDS_TESTS_COMMON
#include <cstdlib>
#include <cstdint>
#include <iostream>
#define CHECK(expr, message) \
do \
{ \
if(!(expr)) \
{ \
std::cerr << "Error: Test failed at " << __FILE__ << " L." << __LINE__ << ":\n" \
<< message << std::endl; \
std::exit(1); \
} \
} while(0)
enum class data_type : std::uint32_t
{
uint32 = 1,
float64,
string
};
inline std::string data_type_to_string(data_type type)
{
switch(type)
{
case data_type::uint32: return "uint32";
case data_type::float64: return "float64";
case data_type::string: return "string";
}
return "Wrong type";
}
#endif
================================================
FILE: tests/library.cpp
================================================
#include <cstdint>
#ifdef _WIN32
#define NES_EXPORT __declspec(dllexport)
#else
#define NES_EXPORT
#endif
extern "C" NES_EXPORT std::int32_t nes_lib_func();
extern "C" NES_EXPORT std::int32_t nes_lib_func()
{
return 42;
}
================================================
FILE: tests/process.cpp
================================================
#include <iostream>
#include <thread>
#include <mutex>
#include <shared_mutex>
#include <iterator>
#include <iomanip>
#include <array>
#include <cassert>
#include <cstdlib>
#include <random>
#include <nes/pipe.hpp>
#include <nes/shared_library.hpp>
#include <nes/process.hpp>
#include <nes/shared_memory.hpp>
#include <nes/named_mutex.hpp>
#include <nes/semaphore.hpp>
#include <nes/named_semaphore.hpp>
#include "common.hpp"
#if defined(NES_WIN32_PROCESS)
constexpr const char* other_path{"NotEnoughStandardsTestOther.exe"};
constexpr const char* lib_path{"NotEnoughStandardsTestLib.dll"};
#elif defined(NES_POSIX_PROCESS)
constexpr const char* other_path{"./NotEnoughStandardsTestOther"};
constexpr const char* lib_path{"./NotEnoughStandardsTestLib.so"};
#endif
static void shared_library_test()
{
nes::shared_library lib{lib_path};
auto func = lib.load<std::int32_t()>("nes_lib_func");
CHECK(func, "Can not load library \"" << lib_path << "\"");
const auto value{func()};
CHECK(value == 42, "Function returned wrong value " << value);
}
static void a_thread(nes::basic_pipe_istream<char>& is) noexcept
{
data_type type{};
is.read(reinterpret_cast<char*>(&type), sizeof(data_type));
CHECK(type == data_type::uint32, "Wrong data type, expected uint32 got " << data_type_to_string(type));
std::uint32_t uint_value{};
is.read(reinterpret_cast<char*>(&uint_value), sizeof(std::uint32_t));
CHECK(uint_value == 42, "Wrong value, expected 42 got " << uint_value);
is.read(reinterpret_cast<char*>(&type), sizeof(data_type));
CHECK(type == data_type::float64, "Wrong data type, expected float64 got " << data_type_to_string(type));
double float_value{};
is.read(reinterpret_cast<char*>(&float_value), sizeof(double));
CHECK(float_value > 3.139 && float_value < 3.141, "Wrong value, expected 3.14 got " << float_value);
is.read(reinterpret_cast<char*>(&type), sizeof(data_type));
CHECK(type == data_type::string, "Wrong data type, expected string got " << data_type_to_string(type));
std::uint64_t str_size{};
is.read(reinterpret_cast<char*>(&str_size), sizeof(std::uint64_t));
std::string str_value{};
str_value.resize(str_size);
is.read(std::data(str_value), static_cast<std::streamsize>(str_size));
is.read(reinterpret_cast<char*>(&type), sizeof(data_type));
CHECK(type == data_type::string, "Wrong data type, expected string got " << data_type_to_string(type));
is.read(reinterpret_cast<char*>(&str_size), sizeof(std::uint64_t));
str_value.clear();
is >> str_value;
CHECK(str_value == "Hello", "Wrong value, expected \"Hello\" got \"" << str_value << "\"");
str_value.clear();
str_value.resize(3);
is.read(std::data(str_value), 3);
CHECK(str_value == " wo", "Wrong value, expected \" wo\" got \"" << str_value << "\"");
is >> str_value;
CHECK(str_value == "rld!", "Wrong value, expected \"rld!\" got \"" << str_value << "\"");
}
static void pipe_test()
{
auto [is, os] = nes::make_anonymous_pipe();
std::thread thread{a_thread, std::ref(is)};
const data_type uint_type{data_type::uint32};
const std::uint32_t uint_value{42};
os.write(reinterpret_cast<const char*>(&uint_type), sizeof(data_type));
os.write(reinterpret_cast<const char*>(&uint_value), sizeof(std::uint32_t));
const data_type float_type{data_type::float64};
const double float_value{3.14};
os.write(reinterpret_cast<const char*>(&float_type), sizeof(data_type));
os.write(reinterpret_cast<const char*>(&float_value), sizeof(double));
const data_type str_type{data_type::string};
const std::string str_value{"Hello world!"};
const std::uint64_t size_size{std::size(str_value)};
os.write(reinterpret_cast<const char*>(&str_type), sizeof(data_type));
os.write(reinterpret_cast<const char*>(&size_size), sizeof(std::uint64_t));
os.write(std::data(str_value), static_cast<std::streamsize>(size_size));
// send it twice to test formatted input too
os.write(reinterpret_cast<const char*>(&str_type), sizeof(data_type));
os.write(reinterpret_cast<const char*>(&size_size), sizeof(std::uint64_t));
os.put(str_value[0]);
os.write(str_value.data() + 1, str_value.size() - 1);
os.close();
if(thread.joinable())
{
thread.join();
}
}
static void another_thread(const std::array<std::uint32_t, 8>& data, nes::semaphore& semaphore)
{
for(std::uint32_t i{}; i < 8; ++i)
{
semaphore.acquire();
CHECK(data[i] == i, "Wrong value expected " << i << " got " << data[i]);
}
}
static void semaphore_test()
{
std::array<std::uint32_t, 8> data{0, 1};
nes::semaphore semaphore{2};
std::thread thread{another_thread, std::cref(data), std::ref(semaphore)};
for(std::uint32_t i{2}; i < 8; ++i)
{
data[i] = i;
semaphore.release();
}
if(thread.joinable())
{
thread.join();
}
}
static void named_pipe_test()
{
nes::process other{other_path, std::vector<std::string>{"named pipe"}, nes::process_options::grab_stdout};
nes::pipe_ostream os{"nes_test_pipe"};
CHECK(os, "Failed to open pipe.");
const data_type uint_type{data_type::uint32};
const std::uint32_t uint_value{42};
os.write(reinterpret_cast<const char*>(&uint_type), sizeof(data_type));
os.write(reinterpret_cast<const char*>(&uint_value), sizeof(std::uint32_t));
const data_type float_type{data_type::float64};
const double float_value{3.14};
os.write(reinterpret_cast<const char*>(&float_type), sizeof(data_type));
os.write(reinterpret_cast<const char*>(&float_value), sizeof(double));
const data_type str_type{data_type::string};
const std::string str_value{"Hello world!"};
const std::uint64_t size_size{std::size(str_value)};
os.write(reinterpret_cast<const char*>(&str_type), sizeof(data_type));
os.write(reinterpret_cast<const char*>(&size_size), sizeof(std::uint64_t));
os.write(std::data(str_value), static_cast<std::streamsize>(size_size));
os.close();
CHECK(other.joinable(), "Process is not joinable");
other.join();
CHECK(other.return_code() == 0, "Other process failed with code " << other.return_code() << ":\n"
<< other.stdout_stream().rdbuf());
}
static void process_test()
{
nes::process other{
other_path, {"Hey!", "\\\"12\"\"\\\\\\", "\\42\\", "It's \"me\"!"},
nes::process_options::grab_stdout
};
std::cout << other.stdout_stream().rdbuf() << std::endl;
CHECK(other.joinable(), "Process is not joinable");
other.join();
CHECK(other.return_code() == 0, "Other process failed with code " << other.return_code() << ":\n"
<< other.stdout_stream().rdbuf());
}
static void process_kill_test()
{
nes::process other{other_path, std::vector<std::string>{"process kill"}, nes::process_options::grab_stdout};
std::this_thread::sleep_for(std::chrono::milliseconds{200});
CHECK(other.kill(), "Failed to kill other process");
CHECK(!other.joinable(), "Other is still joinable");
}
static void shared_memory_test()
{
nes::shared_memory memory{"nes_test_shared_memory", sizeof(std::uint64_t)};
auto value{memory.map<std::uint64_t>(0)};
CHECK(value, "Failed to map shared memory");
*value = 42;
CHECK(*value == 42, "Failed to write shared memory");
nes::process other{other_path, std::vector<std::string>{"shared memory"}, nes::process_options::grab_stdout};
CHECK(other.joinable(), "Process is not joinable");
other.join();
CHECK(other.return_code() == 0, "Other process failed with code " << other.return_code() << ":\n"
<< other.stdout_stream().rdbuf());
CHECK(*value == 16777216, "Wrong value in shared memory, expected 16777216 got " << *value);
other = nes::process{other_path, std::vector<std::string>{"shared memory bad"}, nes::process_options::grab_stdout};
CHECK(other.joinable(), "Process is not joinable");
other.join();
CHECK(other.return_code() != 0, "Other process must return an error");
CHECK(*value == 16777216, "Wrong value in shared memory, expected 16777216 got " << *value);
}
static void named_mutex_test()
{
nes::named_mutex mutex{"nes_test_named_mutex"};
std::unique_lock lock{mutex};
nes::process other{other_path, std::vector<std::string>{"named mutex"}, nes::process_options::grab_stdout};
lock.unlock();
CHECK(other.joinable(), "Process is not joinable");
other.join();
CHECK(other.return_code() == 0, "Other process failed with code " << other.return_code() << ":\n"
<< other.stdout_stream().rdbuf());
}
static void timed_named_mutex_test()
{
nes::timed_named_mutex mutex{"nes_test_timed_named_mutex"};
std::unique_lock lock{mutex};
nes::process other{other_path, std::vector<std::string>{"timed named mutex"}, nes::process_options::grab_stdout};
lock.unlock();
CHECK(other.joinable(), "Process is not joinable");
other.join();
CHECK(other.return_code() == 0, "Other process failed with code " << other.return_code() << ":\n"
<< other.stdout_stream().rdbuf());
}
static void named_semaphore_test()
{
nes::named_semaphore semaphore{"nes_test_named_semaphore"};
nes::process other{other_path, std::vector<std::string>{"named semaphore"}, nes::process_options::grab_stdout};
for(std::size_t i{}; i < 8; ++i)
{
semaphore.release();
}
CHECK(other.joinable(), "Process is not joinable");
other.join();
CHECK(other.return_code() == 0, "Other process failed with code " << other.return_code() << ":\n"
<< other.stdout_stream().rdbuf());
}
int main()
{
try
{
shared_library_test();
pipe_test();
semaphore_test();
process_test();
process_kill_test();
named_pipe_test();
shared_memory_test();
named_mutex_test();
timed_named_mutex_test();
named_semaphore_test();
}
catch(const std::exception& e)
{
CHECK(false, e.what());
return 1;
}
}
================================================
FILE: tests/process_other.cpp
================================================
#include <iostream>
#include <mutex>
#include <thread>
#include <nes/process.hpp>
#include <nes/shared_memory.hpp>
#include <nes/named_mutex.hpp>
#include <nes/named_semaphore.hpp>
#include "common.hpp"
[[noreturn]] static void to_infinity_and_beyond()
{
while(true)
{
std::this_thread::sleep_for(std::chrono::milliseconds{10});
}
}
static void named_pipe()
{
nes::pipe_istream is{"nes_test_pipe"};
CHECK(is, "Failed to open pipe.");
data_type type{};
std::uint32_t uint_value{};
double float_value{};
std::string str_value{};
std::uint64_t str_size{};
is.read(reinterpret_cast<char*>(&type), sizeof(data_type));
CHECK(type == data_type::uint32, "Wrong data type, expected uint32 got " << data_type_to_string(type));
is.read(reinterpret_cast<char*>(&uint_value), sizeof(std::uint32_t));
CHECK(uint_value == 42, "Wrong value, expected 42 got " << uint_value);
is.read(reinterpret_cast<char*>(&type), sizeof(data_type));
CHECK(type == data_type::float64, "Wrong data type, expected float64 got " << data_type_to_string(type));
is.read(reinterpret_cast<char*>(&float_value), sizeof(double));
CHECK(float_value > 3.139 && float_value < 3.141, "Wrong value, expected 3.14 got " << float_value);
is.read(reinterpret_cast<char*>(&type), sizeof(data_type));
CHECK(type == data_type::string, "Wrong data type, expected string got " << data_type_to_string(type));
is.read(reinterpret_cast<char*>(&str_size), sizeof(std::uint64_t));
str_value.resize(str_size);
is.read(std::data(str_value), static_cast<std::streamsize>(str_size));
CHECK(str_value == "Hello world!", "Wrong value, expected \"Hello world!\" got \"" << str_value << "\"");
}
static void shared_memory()
{
{
nes::shared_memory memory{"nes_test_shared_memory", nes::shared_memory_options::constant};
const auto value{*memory.map<const std::uint64_t>(0)};
CHECK(value == 42, "Wrong value, expected 42 got " << value);
}
{
nes::shared_memory new_memory{"nes_test_shared_memory"};
*new_memory.map<std::uint64_t>(0) = 16777216;
}
}
static void shared_memory_bad()
{
nes::shared_memory memory{"nes_test_shared_memory", nes::shared_memory_options::constant};
*memory.map<std::uint64_t>(0) = 12;
// theorically unreachable
}
static void named_mutex()
{
nes::named_mutex mutex{"nes_test_named_mutex"};
std::lock_guard lock{mutex}; // will throw in case of error
}
static void timed_named_mutex()
{
nes::timed_named_mutex mutex{"nes_test_timed_named_mutex"};
std::unique_lock lock{mutex, std::defer_lock};
while(!lock.try_lock_for(std::chrono::milliseconds{10}))
; // will throw in case of error
}
static void named_semaphore()
{
nes::named_semaphore semaphore{"nes_test_named_semaphore"};
for(std::size_t i{}; i < 8; ++i)
{
semaphore.acquire(); // will throw in case of error
}
}
int main(int argc, char** argv)
{
for(int i{}; i < argc; ++i)
{
try
{
using namespace std::string_view_literals;
if(argv[i] == "process kill"sv)
{
to_infinity_and_beyond();
}
else if(argv[i] == "named pipe"sv)
{
named_pipe();
}
else if(argv[i] == "shared memory"sv)
{
shared_memory();
}
else if(argv[i] == "shared memory bad"sv)
{
shared_memory_bad();
}
else if(argv[i] == "named mutex"sv)
{
named_mutex();
}
else if(argv[i] == "timed named mutex"sv)
{
timed_named_mutex();
}
else if(argv[i] == "named semaphore"sv)
{
named_semaphore();
}
}
catch(const std::exception& e)
{
std::cout << e.what() << std::endl;
return 1;
}
}
}
================================================
FILE: tests/thread_pool_test.cpp
================================================
#include <array>
#include <nes/thread_pool.hpp>
#include "common.hpp"
static void smoke_test()
{
static constexpr std::size_t buffer_size{8};
// Some buffers
std::array<std::uint32_t, buffer_size> input{32, 543, 4329, 12, 542, 656, 523, 98473};
std::array<std::uint32_t, buffer_size> temp{};
std::array<std::uint32_t, buffer_size> output{};
// The task builder
nes::task_builder builder{};
builder.dispatch(buffer_size, 1, 1, [&input, &temp](std::uint32_t x, std::uint32_t y [[maybe_unused]], std::uint32_t z [[maybe_unused]] )
{
temp[x] = input[x] * 2u;
});
nes::task_checkpoint checkpoint{builder.checkpoint()};
nes::task_fence fence{builder.fence()};
builder.dispatch(buffer_size, 1, 1, [&input, &temp, &output](std::uint32_t x, std::uint32_t y [[maybe_unused]], std::uint32_t z [[maybe_unused]] )
{
for(auto value : temp)
{
output[x] += (value + input[x]);
}
});
// Create a thread pool to run our task list.
nes::thread_pool thread_pool{};
std::future<nes::task_list> future{thread_pool.push(builder.build())};
checkpoint.wait();
constexpr std::array<std::uint32_t, buffer_size> temp_expected{64, 1086, 8658, 24, 1084, 1312, 1046, 196946};
CHECK(temp == temp_expected, "Wrong array values");
fence.signal();
future.wait();
constexpr std::array<std::uint32_t, buffer_size> output_expected{210476, 214564, 244852, 210316, 214556, 215468, 214404, 998004};
CHECK(output == output_expected, "Wrong array values");
}
int main()
{
try
{
smoke_test();
}
catch(const std::exception& e)
{
CHECK(false, e.what());
return 1;
}
}
gitextract_vd_i4h3q/
├── .clang-format
├── .github/
│ └── workflows/
│ └── common.yml
├── .gitignore
├── CMakeLists.txt
├── LICENSE
├── README.md
├── cmake/
│ └── NotEnoughStandards.cmake.in
├── include/
│ └── nes/
│ ├── named_mutex.hpp
│ ├── named_semaphore.hpp
│ ├── pipe.hpp
│ ├── process.hpp
│ ├── semaphore.hpp
│ ├── shared_library.hpp
│ ├── shared_memory.hpp
│ └── thread_pool.hpp
└── tests/
├── common.hpp
├── library.cpp
├── process.cpp
├── process_other.cpp
└── thread_pool_test.cpp
SYMBOL INDEX (530 symbols across 13 files)
FILE: include/nes/named_mutex.hpp
type nes (line 71) | namespace nes
type impl (line 78) | namespace impl
type named_mutex_base (line 81) | struct named_mutex_base
method HANDLE (line 83) | HANDLE create_or_open(const std::string& name)
method to_wide (line 107) | std::wstring to_wide(const std::string& path)
method get_error_message (line 127) | std::string get_error_message() const
type mutex_data (line 273) | struct mutex_data
type mutex_base (line 279) | struct mutex_base
function mutex_base (line 285) | inline mutex_base create_or_open_mutex(const std::string& name, bool...
function close_mutex (line 352) | inline void close_mutex(mutex_base& mutex)
function lock_mutex (line 365) | inline void lock_mutex(mutex_base& mutex)
function try_lock_mutex (line 378) | inline bool try_lock_mutex(mutex_base& mutex)
function try_lock_mutex_until (line 390) | inline bool try_lock_mutex_until(mutex_base& mutex, const timespec& ...
class named_mutex (line 135) | class named_mutex : impl::named_mutex_base
method named_mutex (line 141) | explicit named_mutex(const std::string& name)
method named_mutex (line 151) | named_mutex(const named_mutex&) = delete;
method named_mutex (line 152) | named_mutex& operator=(const named_mutex&) = delete;
method named_mutex (line 153) | named_mutex(named_mutex&&) noexcept = delete;
method named_mutex (line 154) | named_mutex& operator=(named_mutex&&) noexcept = delete;
method lock (line 156) | void lock()
method try_lock (line 164) | bool try_lock()
method unlock (line 169) | void unlock()
method native_handle_type (line 174) | native_handle_type native_handle() const noexcept
method named_mutex (line 410) | explicit named_mutex(const std::string& name)
method named_mutex (line 420) | named_mutex(const named_mutex&) = delete;
method named_mutex (line 421) | named_mutex& operator=(const named_mutex&) = delete;
method named_mutex (line 422) | named_mutex(named_mutex&&) noexcept = delete;
method named_mutex (line 423) | named_mutex& operator=(named_mutex&&) noexcept = delete;
method lock (line 425) | void lock()
method try_lock (line 430) | bool try_lock()
method unlock (line 435) | void unlock()
method native_handle_type (line 440) | native_handle_type native_handle() const noexcept
class timed_named_mutex (line 183) | class timed_named_mutex : impl::named_mutex_base
method timed_named_mutex (line 189) | explicit timed_named_mutex(const std::string& name)
method timed_named_mutex (line 199) | timed_named_mutex(const timed_named_mutex&) = delete;
method timed_named_mutex (line 200) | timed_named_mutex& operator=(const timed_named_mutex&) = delete;
method timed_named_mutex (line 201) | timed_named_mutex(timed_named_mutex&&) noexcept = delete;
method timed_named_mutex (line 202) | timed_named_mutex& operator=(timed_named_mutex&&) noexcept = delete;
method lock (line 204) | void lock()
method try_lock (line 212) | bool try_lock()
method try_lock_for (line 218) | bool try_lock_for(const std::chrono::duration<Rep, Period>& timeout)
method try_lock_until (line 224) | bool try_lock_until(const std::chrono::time_point<Clock, Duration>& ...
method unlock (line 235) | void unlock()
method native_handle_type (line 240) | native_handle_type native_handle() const noexcept
method timed_named_mutex (line 455) | explicit timed_named_mutex(const std::string& name)
method timed_named_mutex (line 465) | timed_named_mutex(const timed_named_mutex&) = delete;
method timed_named_mutex (line 466) | timed_named_mutex& operator=(const timed_named_mutex&) = delete;
method timed_named_mutex (line 467) | timed_named_mutex(timed_named_mutex&&) noexcept = delete;
method timed_named_mutex (line 468) | timed_named_mutex& operator=(timed_named_mutex&&) noexcept = delete;
method lock (line 470) | void lock()
method try_lock (line 475) | bool try_lock()
method try_lock_for (line 481) | bool try_lock_for(const std::chrono::duration<Rep, Period>& timeout)
method try_lock_until (line 487) | bool try_lock_until(const std::chrono::time_point<Clock, Duration>& ...
method unlock (line 499) | void unlock()
method native_handle_type (line 504) | native_handle_type native_handle() const noexcept
class recursive_named_mutex (line 249) | class recursive_named_mutex : public named_mutex
method recursive_named_mutex (line 519) | explicit recursive_named_mutex(const std::string& name)
method recursive_named_mutex (line 529) | recursive_named_mutex(const recursive_named_mutex&) = delete;
method recursive_named_mutex (line 530) | recursive_named_mutex& operator=(const recursive_named_mutex&) = del...
method recursive_named_mutex (line 531) | recursive_named_mutex(recursive_named_mutex&&) noexcept = delete;
method recursive_named_mutex (line 532) | recursive_named_mutex& operator=(recursive_named_mutex&&) noexcept =...
method lock (line 534) | void lock()
method try_lock (line 539) | bool try_lock()
method unlock (line 544) | void unlock()
method native_handle_type (line 549) | native_handle_type native_handle() const noexcept
class recursive_timed_named_mutex (line 253) | class recursive_timed_named_mutex : public timed_named_mutex
method recursive_timed_named_mutex (line 564) | explicit recursive_timed_named_mutex(const std::string& name)
method recursive_timed_named_mutex (line 574) | recursive_timed_named_mutex(const recursive_timed_named_mutex&) = de...
method recursive_timed_named_mutex (line 575) | recursive_timed_named_mutex& operator=(const recursive_timed_named_m...
method recursive_timed_named_mutex (line 576) | recursive_timed_named_mutex(recursive_timed_named_mutex&&) noexcept ...
method recursive_timed_named_mutex (line 577) | recursive_timed_named_mutex& operator=(recursive_timed_named_mutex&&...
method lock (line 579) | void lock()
method try_lock (line 584) | bool try_lock()
method try_lock_for (line 590) | bool try_lock_for(const std::chrono::duration<Rep, Period>& timeout)
method try_lock_until (line 596) | bool try_lock_until(const std::chrono::time_point<Clock, Duration>& ...
method unlock (line 608) | void unlock()
method native_handle_type (line 613) | native_handle_type native_handle() const noexcept
type impl (line 270) | namespace impl
type named_mutex_base (line 81) | struct named_mutex_base
method HANDLE (line 83) | HANDLE create_or_open(const std::string& name)
method to_wide (line 107) | std::wstring to_wide(const std::string& path)
method get_error_message (line 127) | std::string get_error_message() const
type mutex_data (line 273) | struct mutex_data
type mutex_base (line 279) | struct mutex_base
function mutex_base (line 285) | inline mutex_base create_or_open_mutex(const std::string& name, bool...
function close_mutex (line 352) | inline void close_mutex(mutex_base& mutex)
function lock_mutex (line 365) | inline void lock_mutex(mutex_base& mutex)
function try_lock_mutex (line 378) | inline bool try_lock_mutex(mutex_base& mutex)
function try_lock_mutex_until (line 390) | inline bool try_lock_mutex_until(mutex_base& mutex, const timespec& ...
class named_mutex (line 404) | class named_mutex
method named_mutex (line 141) | explicit named_mutex(const std::string& name)
method named_mutex (line 151) | named_mutex(const named_mutex&) = delete;
method named_mutex (line 152) | named_mutex& operator=(const named_mutex&) = delete;
method named_mutex (line 153) | named_mutex(named_mutex&&) noexcept = delete;
method named_mutex (line 154) | named_mutex& operator=(named_mutex&&) noexcept = delete;
method lock (line 156) | void lock()
method try_lock (line 164) | bool try_lock()
method unlock (line 169) | void unlock()
method native_handle_type (line 174) | native_handle_type native_handle() const noexcept
method named_mutex (line 410) | explicit named_mutex(const std::string& name)
method named_mutex (line 420) | named_mutex(const named_mutex&) = delete;
method named_mutex (line 421) | named_mutex& operator=(const named_mutex&) = delete;
method named_mutex (line 422) | named_mutex(named_mutex&&) noexcept = delete;
method named_mutex (line 423) | named_mutex& operator=(named_mutex&&) noexcept = delete;
method lock (line 425) | void lock()
method try_lock (line 430) | bool try_lock()
method unlock (line 435) | void unlock()
method native_handle_type (line 440) | native_handle_type native_handle() const noexcept
class timed_named_mutex (line 449) | class timed_named_mutex
method timed_named_mutex (line 189) | explicit timed_named_mutex(const std::string& name)
method timed_named_mutex (line 199) | timed_named_mutex(const timed_named_mutex&) = delete;
method timed_named_mutex (line 200) | timed_named_mutex& operator=(const timed_named_mutex&) = delete;
method timed_named_mutex (line 201) | timed_named_mutex(timed_named_mutex&&) noexcept = delete;
method timed_named_mutex (line 202) | timed_named_mutex& operator=(timed_named_mutex&&) noexcept = delete;
method lock (line 204) | void lock()
method try_lock (line 212) | bool try_lock()
method try_lock_for (line 218) | bool try_lock_for(const std::chrono::duration<Rep, Period>& timeout)
method try_lock_until (line 224) | bool try_lock_until(const std::chrono::time_point<Clock, Duration>& ...
method unlock (line 235) | void unlock()
method native_handle_type (line 240) | native_handle_type native_handle() const noexcept
method timed_named_mutex (line 455) | explicit timed_named_mutex(const std::string& name)
method timed_named_mutex (line 465) | timed_named_mutex(const timed_named_mutex&) = delete;
method timed_named_mutex (line 466) | timed_named_mutex& operator=(const timed_named_mutex&) = delete;
method timed_named_mutex (line 467) | timed_named_mutex(timed_named_mutex&&) noexcept = delete;
method timed_named_mutex (line 468) | timed_named_mutex& operator=(timed_named_mutex&&) noexcept = delete;
method lock (line 470) | void lock()
method try_lock (line 475) | bool try_lock()
method try_lock_for (line 481) | bool try_lock_for(const std::chrono::duration<Rep, Period>& timeout)
method try_lock_until (line 487) | bool try_lock_until(const std::chrono::time_point<Clock, Duration>& ...
method unlock (line 499) | void unlock()
method native_handle_type (line 504) | native_handle_type native_handle() const noexcept
class recursive_named_mutex (line 513) | class recursive_named_mutex
method recursive_named_mutex (line 519) | explicit recursive_named_mutex(const std::string& name)
method recursive_named_mutex (line 529) | recursive_named_mutex(const recursive_named_mutex&) = delete;
method recursive_named_mutex (line 530) | recursive_named_mutex& operator=(const recursive_named_mutex&) = del...
method recursive_named_mutex (line 531) | recursive_named_mutex(recursive_named_mutex&&) noexcept = delete;
method recursive_named_mutex (line 532) | recursive_named_mutex& operator=(recursive_named_mutex&&) noexcept =...
method lock (line 534) | void lock()
method try_lock (line 539) | bool try_lock()
method unlock (line 544) | void unlock()
method native_handle_type (line 549) | native_handle_type native_handle() const noexcept
class recursive_timed_named_mutex (line 558) | class recursive_timed_named_mutex
method recursive_timed_named_mutex (line 564) | explicit recursive_timed_named_mutex(const std::string& name)
method recursive_timed_named_mutex (line 574) | recursive_timed_named_mutex(const recursive_timed_named_mutex&) = de...
method recursive_timed_named_mutex (line 575) | recursive_timed_named_mutex& operator=(const recursive_timed_named_m...
method recursive_timed_named_mutex (line 576) | recursive_timed_named_mutex(recursive_timed_named_mutex&&) noexcept ...
method recursive_timed_named_mutex (line 577) | recursive_timed_named_mutex& operator=(recursive_timed_named_mutex&&...
method lock (line 579) | void lock()
method try_lock (line 584) | bool try_lock()
method try_lock_for (line 590) | bool try_lock_for(const std::chrono::duration<Rep, Period>& timeout)
method try_lock_until (line 596) | bool try_lock_until(const std::chrono::time_point<Clock, Duration>& ...
method unlock (line 608) | void unlock()
method native_handle_type (line 613) | native_handle_type native_handle() const noexcept
type nes (line 263) | namespace nes
type impl (line 78) | namespace impl
type named_mutex_base (line 81) | struct named_mutex_base
method HANDLE (line 83) | HANDLE create_or_open(const std::string& name)
method to_wide (line 107) | std::wstring to_wide(const std::string& path)
method get_error_message (line 127) | std::string get_error_message() const
type mutex_data (line 273) | struct mutex_data
type mutex_base (line 279) | struct mutex_base
function mutex_base (line 285) | inline mutex_base create_or_open_mutex(const std::string& name, bool...
function close_mutex (line 352) | inline void close_mutex(mutex_base& mutex)
function lock_mutex (line 365) | inline void lock_mutex(mutex_base& mutex)
function try_lock_mutex (line 378) | inline bool try_lock_mutex(mutex_base& mutex)
function try_lock_mutex_until (line 390) | inline bool try_lock_mutex_until(mutex_base& mutex, const timespec& ...
class named_mutex (line 135) | class named_mutex : impl::named_mutex_base
method named_mutex (line 141) | explicit named_mutex(const std::string& name)
method named_mutex (line 151) | named_mutex(const named_mutex&) = delete;
method named_mutex (line 152) | named_mutex& operator=(const named_mutex&) = delete;
method named_mutex (line 153) | named_mutex(named_mutex&&) noexcept = delete;
method named_mutex (line 154) | named_mutex& operator=(named_mutex&&) noexcept = delete;
method lock (line 156) | void lock()
method try_lock (line 164) | bool try_lock()
method unlock (line 169) | void unlock()
method native_handle_type (line 174) | native_handle_type native_handle() const noexcept
method named_mutex (line 410) | explicit named_mutex(const std::string& name)
method named_mutex (line 420) | named_mutex(const named_mutex&) = delete;
method named_mutex (line 421) | named_mutex& operator=(const named_mutex&) = delete;
method named_mutex (line 422) | named_mutex(named_mutex&&) noexcept = delete;
method named_mutex (line 423) | named_mutex& operator=(named_mutex&&) noexcept = delete;
method lock (line 425) | void lock()
method try_lock (line 430) | bool try_lock()
method unlock (line 435) | void unlock()
method native_handle_type (line 440) | native_handle_type native_handle() const noexcept
class timed_named_mutex (line 183) | class timed_named_mutex : impl::named_mutex_base
method timed_named_mutex (line 189) | explicit timed_named_mutex(const std::string& name)
method timed_named_mutex (line 199) | timed_named_mutex(const timed_named_mutex&) = delete;
method timed_named_mutex (line 200) | timed_named_mutex& operator=(const timed_named_mutex&) = delete;
method timed_named_mutex (line 201) | timed_named_mutex(timed_named_mutex&&) noexcept = delete;
method timed_named_mutex (line 202) | timed_named_mutex& operator=(timed_named_mutex&&) noexcept = delete;
method lock (line 204) | void lock()
method try_lock (line 212) | bool try_lock()
method try_lock_for (line 218) | bool try_lock_for(const std::chrono::duration<Rep, Period>& timeout)
method try_lock_until (line 224) | bool try_lock_until(const std::chrono::time_point<Clock, Duration>& ...
method unlock (line 235) | void unlock()
method native_handle_type (line 240) | native_handle_type native_handle() const noexcept
method timed_named_mutex (line 455) | explicit timed_named_mutex(const std::string& name)
method timed_named_mutex (line 465) | timed_named_mutex(const timed_named_mutex&) = delete;
method timed_named_mutex (line 466) | timed_named_mutex& operator=(const timed_named_mutex&) = delete;
method timed_named_mutex (line 467) | timed_named_mutex(timed_named_mutex&&) noexcept = delete;
method timed_named_mutex (line 468) | timed_named_mutex& operator=(timed_named_mutex&&) noexcept = delete;
method lock (line 470) | void lock()
method try_lock (line 475) | bool try_lock()
method try_lock_for (line 481) | bool try_lock_for(const std::chrono::duration<Rep, Period>& timeout)
method try_lock_until (line 487) | bool try_lock_until(const std::chrono::time_point<Clock, Duration>& ...
method unlock (line 499) | void unlock()
method native_handle_type (line 504) | native_handle_type native_handle() const noexcept
class recursive_named_mutex (line 249) | class recursive_named_mutex : public named_mutex
method recursive_named_mutex (line 519) | explicit recursive_named_mutex(const std::string& name)
method recursive_named_mutex (line 529) | recursive_named_mutex(const recursive_named_mutex&) = delete;
method recursive_named_mutex (line 530) | recursive_named_mutex& operator=(const recursive_named_mutex&) = del...
method recursive_named_mutex (line 531) | recursive_named_mutex(recursive_named_mutex&&) noexcept = delete;
method recursive_named_mutex (line 532) | recursive_named_mutex& operator=(recursive_named_mutex&&) noexcept =...
method lock (line 534) | void lock()
method try_lock (line 539) | bool try_lock()
method unlock (line 544) | void unlock()
method native_handle_type (line 549) | native_handle_type native_handle() const noexcept
class recursive_timed_named_mutex (line 253) | class recursive_timed_named_mutex : public timed_named_mutex
method recursive_timed_named_mutex (line 564) | explicit recursive_timed_named_mutex(const std::string& name)
method recursive_timed_named_mutex (line 574) | recursive_timed_named_mutex(const recursive_timed_named_mutex&) = de...
method recursive_timed_named_mutex (line 575) | recursive_timed_named_mutex& operator=(const recursive_timed_named_m...
method recursive_timed_named_mutex (line 576) | recursive_timed_named_mutex(recursive_timed_named_mutex&&) noexcept ...
method recursive_timed_named_mutex (line 577) | recursive_timed_named_mutex& operator=(recursive_timed_named_mutex&&...
method lock (line 579) | void lock()
method try_lock (line 584) | bool try_lock()
method try_lock_for (line 590) | bool try_lock_for(const std::chrono::duration<Rep, Period>& timeout)
method try_lock_until (line 596) | bool try_lock_until(const std::chrono::time_point<Clock, Duration>& ...
method unlock (line 608) | void unlock()
method native_handle_type (line 613) | native_handle_type native_handle() const noexcept
type impl (line 270) | namespace impl
type named_mutex_base (line 81) | struct named_mutex_base
method HANDLE (line 83) | HANDLE create_or_open(const std::string& name)
method to_wide (line 107) | std::wstring to_wide(const std::string& path)
method get_error_message (line 127) | std::string get_error_message() const
type mutex_data (line 273) | struct mutex_data
type mutex_base (line 279) | struct mutex_base
function mutex_base (line 285) | inline mutex_base create_or_open_mutex(const std::string& name, bool...
function close_mutex (line 352) | inline void close_mutex(mutex_base& mutex)
function lock_mutex (line 365) | inline void lock_mutex(mutex_base& mutex)
function try_lock_mutex (line 378) | inline bool try_lock_mutex(mutex_base& mutex)
function try_lock_mutex_until (line 390) | inline bool try_lock_mutex_until(mutex_base& mutex, const timespec& ...
class named_mutex (line 404) | class named_mutex
method named_mutex (line 141) | explicit named_mutex(const std::string& name)
method named_mutex (line 151) | named_mutex(const named_mutex&) = delete;
method named_mutex (line 152) | named_mutex& operator=(const named_mutex&) = delete;
method named_mutex (line 153) | named_mutex(named_mutex&&) noexcept = delete;
method named_mutex (line 154) | named_mutex& operator=(named_mutex&&) noexcept = delete;
method lock (line 156) | void lock()
method try_lock (line 164) | bool try_lock()
method unlock (line 169) | void unlock()
method native_handle_type (line 174) | native_handle_type native_handle() const noexcept
method named_mutex (line 410) | explicit named_mutex(const std::string& name)
method named_mutex (line 420) | named_mutex(const named_mutex&) = delete;
method named_mutex (line 421) | named_mutex& operator=(const named_mutex&) = delete;
method named_mutex (line 422) | named_mutex(named_mutex&&) noexcept = delete;
method named_mutex (line 423) | named_mutex& operator=(named_mutex&&) noexcept = delete;
method lock (line 425) | void lock()
method try_lock (line 430) | bool try_lock()
method unlock (line 435) | void unlock()
method native_handle_type (line 440) | native_handle_type native_handle() const noexcept
class timed_named_mutex (line 449) | class timed_named_mutex
method timed_named_mutex (line 189) | explicit timed_named_mutex(const std::string& name)
method timed_named_mutex (line 199) | timed_named_mutex(const timed_named_mutex&) = delete;
method timed_named_mutex (line 200) | timed_named_mutex& operator=(const timed_named_mutex&) = delete;
method timed_named_mutex (line 201) | timed_named_mutex(timed_named_mutex&&) noexcept = delete;
method timed_named_mutex (line 202) | timed_named_mutex& operator=(timed_named_mutex&&) noexcept = delete;
method lock (line 204) | void lock()
method try_lock (line 212) | bool try_lock()
method try_lock_for (line 218) | bool try_lock_for(const std::chrono::duration<Rep, Period>& timeout)
method try_lock_until (line 224) | bool try_lock_until(const std::chrono::time_point<Clock, Duration>& ...
method unlock (line 235) | void unlock()
method native_handle_type (line 240) | native_handle_type native_handle() const noexcept
method timed_named_mutex (line 455) | explicit timed_named_mutex(const std::string& name)
method timed_named_mutex (line 465) | timed_named_mutex(const timed_named_mutex&) = delete;
method timed_named_mutex (line 466) | timed_named_mutex& operator=(const timed_named_mutex&) = delete;
method timed_named_mutex (line 467) | timed_named_mutex(timed_named_mutex&&) noexcept = delete;
method timed_named_mutex (line 468) | timed_named_mutex& operator=(timed_named_mutex&&) noexcept = delete;
method lock (line 470) | void lock()
method try_lock (line 475) | bool try_lock()
method try_lock_for (line 481) | bool try_lock_for(const std::chrono::duration<Rep, Period>& timeout)
method try_lock_until (line 487) | bool try_lock_until(const std::chrono::time_point<Clock, Duration>& ...
method unlock (line 499) | void unlock()
method native_handle_type (line 504) | native_handle_type native_handle() const noexcept
class recursive_named_mutex (line 513) | class recursive_named_mutex
method recursive_named_mutex (line 519) | explicit recursive_named_mutex(const std::string& name)
method recursive_named_mutex (line 529) | recursive_named_mutex(const recursive_named_mutex&) = delete;
method recursive_named_mutex (line 530) | recursive_named_mutex& operator=(const recursive_named_mutex&) = del...
method recursive_named_mutex (line 531) | recursive_named_mutex(recursive_named_mutex&&) noexcept = delete;
method recursive_named_mutex (line 532) | recursive_named_mutex& operator=(recursive_named_mutex&&) noexcept =...
method lock (line 534) | void lock()
method try_lock (line 539) | bool try_lock()
method unlock (line 544) | void unlock()
method native_handle_type (line 549) | native_handle_type native_handle() const noexcept
class recursive_timed_named_mutex (line 558) | class recursive_timed_named_mutex
method recursive_timed_named_mutex (line 564) | explicit recursive_timed_named_mutex(const std::string& name)
method recursive_timed_named_mutex (line 574) | recursive_timed_named_mutex(const recursive_timed_named_mutex&) = de...
method recursive_timed_named_mutex (line 575) | recursive_timed_named_mutex& operator=(const recursive_timed_named_m...
method recursive_timed_named_mutex (line 576) | recursive_timed_named_mutex(recursive_timed_named_mutex&&) noexcept ...
method recursive_timed_named_mutex (line 577) | recursive_timed_named_mutex& operator=(recursive_timed_named_mutex&&...
method lock (line 579) | void lock()
method try_lock (line 584) | bool try_lock()
method try_lock_for (line 590) | bool try_lock_for(const std::chrono::duration<Rep, Period>& timeout)
method try_lock_until (line 596) | bool try_lock_until(const std::chrono::time_point<Clock, Duration>& ...
method unlock (line 608) | void unlock()
method native_handle_type (line 613) | native_handle_type native_handle() const noexcept
FILE: include/nes/named_semaphore.hpp
type nes (line 70) | namespace nes
class named_semaphore (line 77) | class named_semaphore
method named_semaphore (line 83) | explicit named_semaphore(const std::string& name, std::size_t initia...
method named_semaphore (line 110) | named_semaphore(const named_semaphore&) = delete;
method named_semaphore (line 111) | named_semaphore& operator=(const named_semaphore&) = delete;
method named_semaphore (line 112) | named_semaphore(named_semaphore&& other) noexcept = delete;
method named_semaphore (line 113) | named_semaphore& operator=(named_semaphore&& other) noexcept = delete;
method acquire (line 115) | void acquire()
method try_acquire (line 123) | bool try_acquire()
method release (line 128) | void release()
method native_handle_type (line 136) | native_handle_type native_handle() const noexcept
method to_wide (line 142) | std::wstring to_wide(const std::string& path)
method get_error_message (line 162) | std::string get_error_message() const
method named_semaphore (line 302) | explicit named_semaphore(const std::string& name, std::size_t initia...
method named_semaphore (line 318) | named_semaphore(const named_semaphore&) = delete;
method named_semaphore (line 319) | named_semaphore& operator=(const named_semaphore&) = delete;
method named_semaphore (line 320) | named_semaphore(named_semaphore&& other) noexcept = delete;
method named_semaphore (line 321) | named_semaphore& operator=(named_semaphore&& other) noexcept = delete;
method acquire (line 323) | void acquire()
method try_acquire (line 331) | bool try_acquire()
method release (line 336) | void release()
method native_handle_type (line 344) | native_handle_type native_handle() const noexcept
class timed_named_semaphore (line 171) | class timed_named_semaphore
method timed_named_semaphore (line 177) | explicit timed_named_semaphore(const std::string& name, std::size_t ...
method timed_named_semaphore (line 204) | timed_named_semaphore(const timed_named_semaphore&) = delete;
method timed_named_semaphore (line 205) | timed_named_semaphore& operator=(const timed_named_semaphore&) = del...
method timed_named_semaphore (line 206) | timed_named_semaphore(timed_named_semaphore&& other) noexcept = delete;
method timed_named_semaphore (line 207) | timed_named_semaphore& operator=(timed_named_semaphore&& other) noex...
method acquire (line 209) | void acquire()
method try_acquire (line 217) | bool try_acquire()
method try_acquire_for (line 223) | bool try_acquire_for(const std::chrono::duration<Rep, Period>& timeout)
method try_acquire_until (line 229) | bool try_acquire_until(const std::chrono::time_point<Clock, Duration...
method release (line 240) | void release()
method native_handle_type (line 248) | native_handle_type native_handle() const noexcept
method to_wide (line 254) | std::wstring to_wide(const std::string& path)
method get_error_message (line 274) | std::string get_error_message() const
method timed_named_semaphore (line 359) | explicit timed_named_semaphore(const std::string& name, std::size_t ...
method timed_named_semaphore (line 375) | timed_named_semaphore(const timed_named_semaphore&) = delete;
method timed_named_semaphore (line 376) | timed_named_semaphore& operator=(const timed_named_semaphore&) = del...
method timed_named_semaphore (line 377) | timed_named_semaphore(timed_named_semaphore&& other) noexcept = delete;
method timed_named_semaphore (line 378) | timed_named_semaphore& operator=(timed_named_semaphore&& other) noex...
method acquire (line 380) | void acquire()
method try_acquire (line 388) | bool try_acquire()
method try_lock_for (line 394) | bool try_lock_for(const std::chrono::duration<Rep, Period>& timeout)
method try_lock_until (line 400) | bool try_lock_until(const std::chrono::time_point<Clock, Duration>& ...
method release (line 412) | void release()
method native_handle_type (line 420) | native_handle_type native_handle() const noexcept
class named_semaphore (line 296) | class named_semaphore
method named_semaphore (line 83) | explicit named_semaphore(const std::string& name, std::size_t initia...
method named_semaphore (line 110) | named_semaphore(const named_semaphore&) = delete;
method named_semaphore (line 111) | named_semaphore& operator=(const named_semaphore&) = delete;
method named_semaphore (line 112) | named_semaphore(named_semaphore&& other) noexcept = delete;
method named_semaphore (line 113) | named_semaphore& operator=(named_semaphore&& other) noexcept = delete;
method acquire (line 115) | void acquire()
method try_acquire (line 123) | bool try_acquire()
method release (line 128) | void release()
method native_handle_type (line 136) | native_handle_type native_handle() const noexcept
method to_wide (line 142) | std::wstring to_wide(const std::string& path)
method get_error_message (line 162) | std::string get_error_message() const
method named_semaphore (line 302) | explicit named_semaphore(const std::string& name, std::size_t initia...
method named_semaphore (line 318) | named_semaphore(const named_semaphore&) = delete;
method named_semaphore (line 319) | named_semaphore& operator=(const named_semaphore&) = delete;
method named_semaphore (line 320) | named_semaphore(named_semaphore&& other) noexcept = delete;
method named_semaphore (line 321) | named_semaphore& operator=(named_semaphore&& other) noexcept = delete;
method acquire (line 323) | void acquire()
method try_acquire (line 331) | bool try_acquire()
method release (line 336) | void release()
method native_handle_type (line 344) | native_handle_type native_handle() const noexcept
class timed_named_semaphore (line 353) | class timed_named_semaphore
method timed_named_semaphore (line 177) | explicit timed_named_semaphore(const std::string& name, std::size_t ...
method timed_named_semaphore (line 204) | timed_named_semaphore(const timed_named_semaphore&) = delete;
method timed_named_semaphore (line 205) | timed_named_semaphore& operator=(const timed_named_semaphore&) = del...
method timed_named_semaphore (line 206) | timed_named_semaphore(timed_named_semaphore&& other) noexcept = delete;
method timed_named_semaphore (line 207) | timed_named_semaphore& operator=(timed_named_semaphore&& other) noex...
method acquire (line 209) | void acquire()
method try_acquire (line 217) | bool try_acquire()
method try_acquire_for (line 223) | bool try_acquire_for(const std::chrono::duration<Rep, Period>& timeout)
method try_acquire_until (line 229) | bool try_acquire_until(const std::chrono::time_point<Clock, Duration...
method release (line 240) | void release()
method native_handle_type (line 248) | native_handle_type native_handle() const noexcept
method to_wide (line 254) | std::wstring to_wide(const std::string& path)
method get_error_message (line 274) | std::string get_error_message() const
method timed_named_semaphore (line 359) | explicit timed_named_semaphore(const std::string& name, std::size_t ...
method timed_named_semaphore (line 375) | timed_named_semaphore(const timed_named_semaphore&) = delete;
method timed_named_semaphore (line 376) | timed_named_semaphore& operator=(const timed_named_semaphore&) = del...
method timed_named_semaphore (line 377) | timed_named_semaphore(timed_named_semaphore&& other) noexcept = delete;
method timed_named_semaphore (line 378) | timed_named_semaphore& operator=(timed_named_semaphore&& other) noex...
method acquire (line 380) | void acquire()
method try_acquire (line 388) | bool try_acquire()
method try_lock_for (line 394) | bool try_lock_for(const std::chrono::duration<Rep, Period>& timeout)
method try_lock_until (line 400) | bool try_lock_until(const std::chrono::time_point<Clock, Duration>& ...
method release (line 412) | void release()
method native_handle_type (line 420) | native_handle_type native_handle() const noexcept
type nes (line 289) | namespace nes
class named_semaphore (line 77) | class named_semaphore
method named_semaphore (line 83) | explicit named_semaphore(const std::string& name, std::size_t initia...
method named_semaphore (line 110) | named_semaphore(const named_semaphore&) = delete;
method named_semaphore (line 111) | named_semaphore& operator=(const named_semaphore&) = delete;
method named_semaphore (line 112) | named_semaphore(named_semaphore&& other) noexcept = delete;
method named_semaphore (line 113) | named_semaphore& operator=(named_semaphore&& other) noexcept = delete;
method acquire (line 115) | void acquire()
method try_acquire (line 123) | bool try_acquire()
method release (line 128) | void release()
method native_handle_type (line 136) | native_handle_type native_handle() const noexcept
method to_wide (line 142) | std::wstring to_wide(const std::string& path)
method get_error_message (line 162) | std::string get_error_message() const
method named_semaphore (line 302) | explicit named_semaphore(const std::string& name, std::size_t initia...
method named_semaphore (line 318) | named_semaphore(const named_semaphore&) = delete;
method named_semaphore (line 319) | named_semaphore& operator=(const named_semaphore&) = delete;
method named_semaphore (line 320) | named_semaphore(named_semaphore&& other) noexcept = delete;
method named_semaphore (line 321) | named_semaphore& operator=(named_semaphore&& other) noexcept = delete;
method acquire (line 323) | void acquire()
method try_acquire (line 331) | bool try_acquire()
method release (line 336) | void release()
method native_handle_type (line 344) | native_handle_type native_handle() const noexcept
class timed_named_semaphore (line 171) | class timed_named_semaphore
method timed_named_semaphore (line 177) | explicit timed_named_semaphore(const std::string& name, std::size_t ...
method timed_named_semaphore (line 204) | timed_named_semaphore(const timed_named_semaphore&) = delete;
method timed_named_semaphore (line 205) | timed_named_semaphore& operator=(const timed_named_semaphore&) = del...
method timed_named_semaphore (line 206) | timed_named_semaphore(timed_named_semaphore&& other) noexcept = delete;
method timed_named_semaphore (line 207) | timed_named_semaphore& operator=(timed_named_semaphore&& other) noex...
method acquire (line 209) | void acquire()
method try_acquire (line 217) | bool try_acquire()
method try_acquire_for (line 223) | bool try_acquire_for(const std::chrono::duration<Rep, Period>& timeout)
method try_acquire_until (line 229) | bool try_acquire_until(const std::chrono::time_point<Clock, Duration...
method release (line 240) | void release()
method native_handle_type (line 248) | native_handle_type native_handle() const noexcept
method to_wide (line 254) | std::wstring to_wide(const std::string& path)
method get_error_message (line 274) | std::string get_error_message() const
method timed_named_semaphore (line 359) | explicit timed_named_semaphore(const std::string& name, std::size_t ...
method timed_named_semaphore (line 375) | timed_named_semaphore(const timed_named_semaphore&) = delete;
method timed_named_semaphore (line 376) | timed_named_semaphore& operator=(const timed_named_semaphore&) = del...
method timed_named_semaphore (line 377) | timed_named_semaphore(timed_named_semaphore&& other) noexcept = delete;
method timed_named_semaphore (line 378) | timed_named_semaphore& operator=(timed_named_semaphore&& other) noex...
method acquire (line 380) | void acquire()
method try_acquire (line 388) | bool try_acquire()
method try_lock_for (line 394) | bool try_lock_for(const std::chrono::duration<Rep, Period>& timeout)
method try_lock_until (line 400) | bool try_lock_until(const std::chrono::time_point<Clock, Duration>& ...
method release (line 412) | void release()
method native_handle_type (line 420) | native_handle_type native_handle() const noexcept
class named_semaphore (line 296) | class named_semaphore
method named_semaphore (line 83) | explicit named_semaphore(const std::string& name, std::size_t initia...
method named_semaphore (line 110) | named_semaphore(const named_semaphore&) = delete;
method named_semaphore (line 111) | named_semaphore& operator=(const named_semaphore&) = delete;
method named_semaphore (line 112) | named_semaphore(named_semaphore&& other) noexcept = delete;
method named_semaphore (line 113) | named_semaphore& operator=(named_semaphore&& other) noexcept = delete;
method acquire (line 115) | void acquire()
method try_acquire (line 123) | bool try_acquire()
method release (line 128) | void release()
method native_handle_type (line 136) | native_handle_type native_handle() const noexcept
method to_wide (line 142) | std::wstring to_wide(const std::string& path)
method get_error_message (line 162) | std::string get_error_message() const
method named_semaphore (line 302) | explicit named_semaphore(const std::string& name, std::size_t initia...
method named_semaphore (line 318) | named_semaphore(const named_semaphore&) = delete;
method named_semaphore (line 319) | named_semaphore& operator=(const named_semaphore&) = delete;
method named_semaphore (line 320) | named_semaphore(named_semaphore&& other) noexcept = delete;
method named_semaphore (line 321) | named_semaphore& operator=(named_semaphore&& other) noexcept = delete;
method acquire (line 323) | void acquire()
method try_acquire (line 331) | bool try_acquire()
method release (line 336) | void release()
method native_handle_type (line 344) | native_handle_type native_handle() const noexcept
class timed_named_semaphore (line 353) | class timed_named_semaphore
method timed_named_semaphore (line 177) | explicit timed_named_semaphore(const std::string& name, std::size_t ...
method timed_named_semaphore (line 204) | timed_named_semaphore(const timed_named_semaphore&) = delete;
method timed_named_semaphore (line 205) | timed_named_semaphore& operator=(const timed_named_semaphore&) = del...
method timed_named_semaphore (line 206) | timed_named_semaphore(timed_named_semaphore&& other) noexcept = delete;
method timed_named_semaphore (line 207) | timed_named_semaphore& operator=(timed_named_semaphore&& other) noex...
method acquire (line 209) | void acquire()
method try_acquire (line 217) | bool try_acquire()
method try_acquire_for (line 223) | bool try_acquire_for(const std::chrono::duration<Rep, Period>& timeout)
method try_acquire_until (line 229) | bool try_acquire_until(const std::chrono::time_point<Clock, Duration...
method release (line 240) | void release()
method native_handle_type (line 248) | native_handle_type native_handle() const noexcept
method to_wide (line 254) | std::wstring to_wide(const std::string& path)
method get_error_message (line 274) | std::string get_error_message() const
method timed_named_semaphore (line 359) | explicit timed_named_semaphore(const std::string& name, std::size_t ...
method timed_named_semaphore (line 375) | timed_named_semaphore(const timed_named_semaphore&) = delete;
method timed_named_semaphore (line 376) | timed_named_semaphore& operator=(const timed_named_semaphore&) = del...
method timed_named_semaphore (line 377) | timed_named_semaphore(timed_named_semaphore&& other) noexcept = delete;
method timed_named_semaphore (line 378) | timed_named_semaphore& operator=(timed_named_semaphore&& other) noex...
method acquire (line 380) | void acquire()
method try_acquire (line 388) | bool try_acquire()
method try_lock_for (line 394) | bool try_lock_for(const std::chrono::duration<Rep, Period>& timeout)
method try_lock_until (line 400) | bool try_lock_until(const std::chrono::time_point<Clock, Duration>& ...
method release (line 412) | void release()
method native_handle_type (line 420) | native_handle_type native_handle() const noexcept
FILE: include/nes/pipe.hpp
type nes (line 72) | namespace nes
class basic_pipe_istream (line 80) | class basic_pipe_istream
method basic_pipe_istream (line 361) | basic_pipe_istream() = default;
method basic_pipe_istream (line 363) | explicit basic_pipe_istream(const std::string& name, std::ios_base::...
method basic_pipe_istream (line 372) | basic_pipe_istream(const basic_pipe_istream&) = delete;
method basic_pipe_istream (line 373) | basic_pipe_istream& operator=(const basic_pipe_istream&) = delete;
method basic_pipe_istream (line 375) | basic_pipe_istream(basic_pipe_istream&& other) noexcept
method basic_pipe_istream (line 382) | basic_pipe_istream& operator=(basic_pipe_istream&& other) noexcept
method open (line 392) | void open(const std::string& name, std::ios_base::openmode mode = st...
method is_open (line 398) | bool is_open() const noexcept
method close (line 403) | void close()
method basic_pipe_istream (line 417) | basic_pipe_istream(basic_pipe_streambuf<char_type, traits_type> buffer)
method basic_pipe_istream (line 788) | basic_pipe_istream() = default;
method basic_pipe_istream (line 790) | explicit basic_pipe_istream(const std::string& name, std::ios_base::...
method basic_pipe_istream (line 799) | basic_pipe_istream(const basic_pipe_istream&) = delete;
method basic_pipe_istream (line 800) | basic_pipe_istream& operator=(const basic_pipe_istream&) = delete;
method basic_pipe_istream (line 802) | basic_pipe_istream(basic_pipe_istream&& other) noexcept
method basic_pipe_istream (line 809) | basic_pipe_istream& operator=(basic_pipe_istream&& other) noexcept
method open (line 819) | void open(const std::string& name, std::ios_base::openmode mode = st...
method is_open (line 825) | bool is_open() const noexcept
method close (line 830) | void close()
method basic_pipe_istream (line 844) | basic_pipe_istream(basic_pipe_streambuf<char_type, traits_type> buffer)
class basic_pipe_ostream (line 82) | class basic_pipe_ostream
method basic_pipe_ostream (line 442) | basic_pipe_ostream() = default;
method basic_pipe_ostream (line 444) | explicit basic_pipe_ostream(const std::string& name, std::ios_base::...
method basic_pipe_ostream (line 453) | basic_pipe_ostream(const basic_pipe_ostream&) = delete;
method basic_pipe_ostream (line 454) | basic_pipe_ostream& operator=(const basic_pipe_ostream&) = delete;
method basic_pipe_ostream (line 456) | basic_pipe_ostream(basic_pipe_ostream&& other) noexcept
method basic_pipe_ostream (line 463) | basic_pipe_ostream& operator=(basic_pipe_ostream&& other) noexcept
method open (line 473) | void open(const std::string& name, std::ios_base::openmode mode = st...
method is_open (line 479) | bool is_open() const noexcept
method close (line 484) | void close()
method basic_pipe_ostream (line 498) | basic_pipe_ostream(basic_pipe_streambuf<char_type, traits_type> buffer)
method basic_pipe_ostream (line 869) | basic_pipe_ostream() = default;
method basic_pipe_ostream (line 871) | explicit basic_pipe_ostream(const std::string& name, std::ios_base::...
method basic_pipe_ostream (line 880) | basic_pipe_ostream(const basic_pipe_ostream&) = delete;
method basic_pipe_ostream (line 881) | basic_pipe_ostream& operator=(const basic_pipe_ostream&) = delete;
method basic_pipe_ostream (line 883) | basic_pipe_ostream(basic_pipe_ostream&& other) noexcept
method basic_pipe_ostream (line 890) | basic_pipe_ostream& operator=(basic_pipe_ostream&& other) noexcept
method open (line 900) | void open(const std::string& name, std::ios_base::openmode mode = st...
method is_open (line 906) | bool is_open() const noexcept
method close (line 911) | void close()
method basic_pipe_ostream (line 925) | basic_pipe_ostream(basic_pipe_streambuf<char_type, traits_type> buffer)
class basic_pipe_streambuf (line 87) | class basic_pipe_streambuf : public std::basic_streambuf<CharT, Traits>
method basic_pipe_streambuf (line 103) | basic_pipe_streambuf() = default;
method basic_pipe_streambuf (line 105) | explicit basic_pipe_streambuf(const std::string& name, std::ios_base...
method basic_pipe_streambuf (line 115) | basic_pipe_streambuf(const basic_pipe_streambuf&) = delete;
method basic_pipe_streambuf (line 116) | basic_pipe_streambuf& operator=(const basic_pipe_streambuf&) = delete;
method basic_pipe_streambuf (line 118) | basic_pipe_streambuf(basic_pipe_streambuf&& other) noexcept
method basic_pipe_streambuf (line 126) | basic_pipe_streambuf& operator=(basic_pipe_streambuf&& other) noexcept
method open (line 136) | bool open(const std::string& name, std::ios_base::openmode mode)
method is_open (line 174) | bool is_open() const noexcept
method close (line 179) | void close()
method basic_pipe_streambuf (line 196) | basic_pipe_streambuf(HANDLE handle, std::ios_base::openmode mode)
method sync (line 205) | virtual int sync() override
method int_type (line 223) | virtual int_type overflow(int_type c = traits_type::eof()) override
method xsputn (line 246) | virtual std::streamsize xsputn(const char_type* s, std::streamsize c...
method int_type (line 260) | virtual int_type underflow() override
method xsgetn (line 278) | virtual std::streamsize xsgetn(char_type* s, std::streamsize count) ...
method to_wide (line 316) | std::wstring to_wide(std::string path)
method basic_pipe_streambuf (line 568) | basic_pipe_streambuf() = default;
method basic_pipe_streambuf (line 570) | explicit basic_pipe_streambuf(const std::string& name, std::ios_base...
method basic_pipe_streambuf (line 581) | basic_pipe_streambuf(const basic_pipe_streambuf&) = delete;
method basic_pipe_streambuf (line 582) | basic_pipe_streambuf& operator=(const basic_pipe_streambuf&) = delete;
method basic_pipe_streambuf (line 584) | basic_pipe_streambuf(basic_pipe_streambuf&& other) noexcept
method basic_pipe_streambuf (line 592) | basic_pipe_streambuf& operator=(basic_pipe_streambuf&& other) noexcept
method open (line 602) | bool open(const std::string& name, std::ios_base::openmode mode)
method is_open (line 629) | bool is_open() const noexcept
method close (line 634) | void close()
method basic_pipe_streambuf (line 651) | basic_pipe_streambuf(int handle, std::ios_base::openmode mode)
method sync (line 660) | virtual int sync() override
method int_type (line 677) | virtual int_type overflow(int_type c = traits_type::eof()) override
method xsputn (line 699) | virtual std::streamsize xsputn(const char_type* s, std::streamsize c...
method int_type (line 713) | virtual int_type underflow() override
method xsgetn (line 731) | virtual std::streamsize xsgetn(char_type* s, std::streamsize count) ...
class basic_pipe_istream (line 348) | class basic_pipe_istream : public std::basic_istream<CharT, Traits>
method basic_pipe_istream (line 361) | basic_pipe_istream() = default;
method basic_pipe_istream (line 363) | explicit basic_pipe_istream(const std::string& name, std::ios_base::...
method basic_pipe_istream (line 372) | basic_pipe_istream(const basic_pipe_istream&) = delete;
method basic_pipe_istream (line 373) | basic_pipe_istream& operator=(const basic_pipe_istream&) = delete;
method basic_pipe_istream (line 375) | basic_pipe_istream(basic_pipe_istream&& other) noexcept
method basic_pipe_istream (line 382) | basic_pipe_istream& operator=(basic_pipe_istream&& other) noexcept
method open (line 392) | void open(const std::string& name, std::ios_base::openmode mode = st...
method is_open (line 398) | bool is_open() const noexcept
method close (line 403) | void close()
method basic_pipe_istream (line 417) | basic_pipe_istream(basic_pipe_streambuf<char_type, traits_type> buffer)
method basic_pipe_istream (line 788) | basic_pipe_istream() = default;
method basic_pipe_istream (line 790) | explicit basic_pipe_istream(const std::string& name, std::ios_base::...
method basic_pipe_istream (line 799) | basic_pipe_istream(const basic_pipe_istream&) = delete;
method basic_pipe_istream (line 800) | basic_pipe_istream& operator=(const basic_pipe_istream&) = delete;
method basic_pipe_istream (line 802) | basic_pipe_istream(basic_pipe_istream&& other) noexcept
method basic_pipe_istream (line 809) | basic_pipe_istream& operator=(basic_pipe_istream&& other) noexcept
method open (line 819) | void open(const std::string& name, std::ios_base::openmode mode = st...
method is_open (line 825) | bool is_open() const noexcept
method close (line 830) | void close()
method basic_pipe_istream (line 844) | basic_pipe_istream(basic_pipe_streambuf<char_type, traits_type> buffer)
class basic_pipe_ostream (line 429) | class basic_pipe_ostream : public std::basic_ostream<CharT, Traits>
method basic_pipe_ostream (line 442) | basic_pipe_ostream() = default;
method basic_pipe_ostream (line 444) | explicit basic_pipe_ostream(const std::string& name, std::ios_base::...
method basic_pipe_ostream (line 453) | basic_pipe_ostream(const basic_pipe_ostream&) = delete;
method basic_pipe_ostream (line 454) | basic_pipe_ostream& operator=(const basic_pipe_ostream&) = delete;
method basic_pipe_ostream (line 456) | basic_pipe_ostream(basic_pipe_ostream&& other) noexcept
method basic_pipe_ostream (line 463) | basic_pipe_ostream& operator=(basic_pipe_ostream&& other) noexcept
method open (line 473) | void open(const std::string& name, std::ios_base::openmode mode = st...
method is_open (line 479) | bool is_open() const noexcept
method close (line 484) | void close()
method basic_pipe_ostream (line 498) | basic_pipe_ostream(basic_pipe_streambuf<char_type, traits_type> buffer)
method basic_pipe_ostream (line 869) | basic_pipe_ostream() = default;
method basic_pipe_ostream (line 871) | explicit basic_pipe_ostream(const std::string& name, std::ios_base::...
method basic_pipe_ostream (line 880) | basic_pipe_ostream(const basic_pipe_ostream&) = delete;
method basic_pipe_ostream (line 881) | basic_pipe_ostream& operator=(const basic_pipe_ostream&) = delete;
method basic_pipe_ostream (line 883) | basic_pipe_ostream(basic_pipe_ostream&& other) noexcept
method basic_pipe_ostream (line 890) | basic_pipe_ostream& operator=(basic_pipe_ostream&& other) noexcept
method open (line 900) | void open(const std::string& name, std::ios_base::openmode mode = st...
method is_open (line 906) | bool is_open() const noexcept
method close (line 911) | void close()
method basic_pipe_ostream (line 925) | basic_pipe_ostream(basic_pipe_streambuf<char_type, traits_type> buffer)
function make_anonymous_pipe (line 510) | std::pair<basic_pipe_istream<CharT, Traits>, basic_pipe_ostream<CharT,...
class basic_pipe_istream (line 545) | class basic_pipe_istream
method basic_pipe_istream (line 361) | basic_pipe_istream() = default;
method basic_pipe_istream (line 363) | explicit basic_pipe_istream(const std::string& name, std::ios_base::...
method basic_pipe_istream (line 372) | basic_pipe_istream(const basic_pipe_istream&) = delete;
method basic_pipe_istream (line 373) | basic_pipe_istream& operator=(const basic_pipe_istream&) = delete;
method basic_pipe_istream (line 375) | basic_pipe_istream(basic_pipe_istream&& other) noexcept
method basic_pipe_istream (line 382) | basic_pipe_istream& operator=(basic_pipe_istream&& other) noexcept
method open (line 392) | void open(const std::string& name, std::ios_base::openmode mode = st...
method is_open (line 398) | bool is_open() const noexcept
method close (line 403) | void close()
method basic_pipe_istream (line 417) | basic_pipe_istream(basic_pipe_streambuf<char_type, traits_type> buffer)
method basic_pipe_istream (line 788) | basic_pipe_istream() = default;
method basic_pipe_istream (line 790) | explicit basic_pipe_istream(const std::string& name, std::ios_base::...
method basic_pipe_istream (line 799) | basic_pipe_istream(const basic_pipe_istream&) = delete;
method basic_pipe_istream (line 800) | basic_pipe_istream& operator=(const basic_pipe_istream&) = delete;
method basic_pipe_istream (line 802) | basic_pipe_istream(basic_pipe_istream&& other) noexcept
method basic_pipe_istream (line 809) | basic_pipe_istream& operator=(basic_pipe_istream&& other) noexcept
method open (line 819) | void open(const std::string& name, std::ios_base::openmode mode = st...
method is_open (line 825) | bool is_open() const noexcept
method close (line 830) | void close()
method basic_pipe_istream (line 844) | basic_pipe_istream(basic_pipe_streambuf<char_type, traits_type> buffer)
class basic_pipe_ostream (line 547) | class basic_pipe_ostream
method basic_pipe_ostream (line 442) | basic_pipe_ostream() = default;
method basic_pipe_ostream (line 444) | explicit basic_pipe_ostream(const std::string& name, std::ios_base::...
method basic_pipe_ostream (line 453) | basic_pipe_ostream(const basic_pipe_ostream&) = delete;
method basic_pipe_ostream (line 454) | basic_pipe_ostream& operator=(const basic_pipe_ostream&) = delete;
method basic_pipe_ostream (line 456) | basic_pipe_ostream(basic_pipe_ostream&& other) noexcept
method basic_pipe_ostream (line 463) | basic_pipe_ostream& operator=(basic_pipe_ostream&& other) noexcept
method open (line 473) | void open(const std::string& name, std::ios_base::openmode mode = st...
method is_open (line 479) | bool is_open() const noexcept
method close (line 484) | void close()
method basic_pipe_ostream (line 498) | basic_pipe_ostream(basic_pipe_streambuf<char_type, traits_type> buffer)
method basic_pipe_ostream (line 869) | basic_pipe_ostream() = default;
method basic_pipe_ostream (line 871) | explicit basic_pipe_ostream(const std::string& name, std::ios_base::...
method basic_pipe_ostream (line 880) | basic_pipe_ostream(const basic_pipe_ostream&) = delete;
method basic_pipe_ostream (line 881) | basic_pipe_ostream& operator=(const basic_pipe_ostream&) = delete;
method basic_pipe_ostream (line 883) | basic_pipe_ostream(basic_pipe_ostream&& other) noexcept
method basic_pipe_ostream (line 890) | basic_pipe_ostream& operator=(basic_pipe_ostream&& other) noexcept
method open (line 900) | void open(const std::string& name, std::ios_base::openmode mode = st...
method is_open (line 906) | bool is_open() const noexcept
method close (line 911) | void close()
method basic_pipe_ostream (line 925) | basic_pipe_ostream(basic_pipe_streambuf<char_type, traits_type> buffer)
class basic_pipe_streambuf (line 552) | class basic_pipe_streambuf : public std::basic_streambuf<CharT, Traits>
method basic_pipe_streambuf (line 103) | basic_pipe_streambuf() = default;
method basic_pipe_streambuf (line 105) | explicit basic_pipe_streambuf(const std::string& name, std::ios_base...
method basic_pipe_streambuf (line 115) | basic_pipe_streambuf(const basic_pipe_streambuf&) = delete;
method basic_pipe_streambuf (line 116) | basic_pipe_streambuf& operator=(const basic_pipe_streambuf&) = delete;
method basic_pipe_streambuf (line 118) | basic_pipe_streambuf(basic_pipe_streambuf&& other) noexcept
method basic_pipe_streambuf (line 126) | basic_pipe_streambuf& operator=(basic_pipe_streambuf&& other) noexcept
method open (line 136) | bool open(const std::string& name, std::ios_base::openmode mode)
method is_open (line 174) | bool is_open() const noexcept
method close (line 179) | void close()
method basic_pipe_streambuf (line 196) | basic_pipe_streambuf(HANDLE handle, std::ios_base::openmode mode)
method sync (line 205) | virtual int sync() override
method int_type (line 223) | virtual int_type overflow(int_type c = traits_type::eof()) override
method xsputn (line 246) | virtual std::streamsize xsputn(const char_type* s, std::streamsize c...
method int_type (line 260) | virtual int_type underflow() override
method xsgetn (line 278) | virtual std::streamsize xsgetn(char_type* s, std::streamsize count) ...
method to_wide (line 316) | std::wstring to_wide(std::string path)
method basic_pipe_streambuf (line 568) | basic_pipe_streambuf() = default;
method basic_pipe_streambuf (line 570) | explicit basic_pipe_streambuf(const std::string& name, std::ios_base...
method basic_pipe_streambuf (line 581) | basic_pipe_streambuf(const basic_pipe_streambuf&) = delete;
method basic_pipe_streambuf (line 582) | basic_pipe_streambuf& operator=(const basic_pipe_streambuf&) = delete;
method basic_pipe_streambuf (line 584) | basic_pipe_streambuf(basic_pipe_streambuf&& other) noexcept
method basic_pipe_streambuf (line 592) | basic_pipe_streambuf& operator=(basic_pipe_streambuf&& other) noexcept
method open (line 602) | bool open(const std::string& name, std::ios_base::openmode mode)
method is_open (line 629) | bool is_open() const noexcept
method close (line 634) | void close()
method basic_pipe_streambuf (line 651) | basic_pipe_streambuf(int handle, std::ios_base::openmode mode)
method sync (line 660) | virtual int sync() override
method int_type (line 677) | virtual int_type overflow(int_type c = traits_type::eof()) override
method xsputn (line 699) | virtual std::streamsize xsputn(const char_type* s, std::streamsize c...
method int_type (line 713) | virtual int_type underflow() override
method xsgetn (line 731) | virtual std::streamsize xsgetn(char_type* s, std::streamsize count) ...
class basic_pipe_istream (line 775) | class basic_pipe_istream : public std::basic_istream<CharT, Traits>
method basic_pipe_istream (line 361) | basic_pipe_istream() = default;
method basic_pipe_istream (line 363) | explicit basic_pipe_istream(const std::string& name, std::ios_base::...
method basic_pipe_istream (line 372) | basic_pipe_istream(const basic_pipe_istream&) = delete;
method basic_pipe_istream (line 373) | basic_pipe_istream& operator=(const basic_pipe_istream&) = delete;
method basic_pipe_istream (line 375) | basic_pipe_istream(basic_pipe_istream&& other) noexcept
method basic_pipe_istream (line 382) | basic_pipe_istream& operator=(basic_pipe_istream&& other) noexcept
method open (line 392) | void open(const std::string& name, std::ios_base::openmode mode = st...
method is_open (line 398) | bool is_open() const noexcept
method close (line 403) | void close()
method basic_pipe_istream (line 417) | basic_pipe_istream(basic_pipe_streambuf<char_type, traits_type> buffer)
method basic_pipe_istream (line 788) | basic_pipe_istream() = default;
method basic_pipe_istream (line 790) | explicit basic_pipe_istream(const std::string& name, std::ios_base::...
method basic_pipe_istream (line 799) | basic_pipe_istream(const basic_pipe_istream&) = delete;
method basic_pipe_istream (line 800) | basic_pipe_istream& operator=(const basic_pipe_istream&) = delete;
method basic_pipe_istream (line 802) | basic_pipe_istream(basic_pipe_istream&& other) noexcept
method basic_pipe_istream (line 809) | basic_pipe_istream& operator=(basic_pipe_istream&& other) noexcept
method open (line 819) | void open(const std::string& name, std::ios_base::openmode mode = st...
method is_open (line 825) | bool is_open() const noexcept
method close (line 830) | void close()
method basic_pipe_istream (line 844) | basic_pipe_istream(basic_pipe_streambuf<char_type, traits_type> buffer)
class basic_pipe_ostream (line 856) | class basic_pipe_ostream : public std::basic_ostream<CharT, Traits>
method basic_pipe_ostream (line 442) | basic_pipe_ostream() = default;
method basic_pipe_ostream (line 444) | explicit basic_pipe_ostream(const std::string& name, std::ios_base::...
method basic_pipe_ostream (line 453) | basic_pipe_ostream(const basic_pipe_ostream&) = delete;
method basic_pipe_ostream (line 454) | basic_pipe_ostream& operator=(const basic_pipe_ostream&) = delete;
method basic_pipe_ostream (line 456) | basic_pipe_ostream(basic_pipe_ostream&& other) noexcept
method basic_pipe_ostream (line 463) | basic_pipe_ostream& operator=(basic_pipe_ostream&& other) noexcept
method open (line 473) | void open(const std::string& name, std::ios_base::openmode mode = st...
method is_open (line 479) | bool is_open() const noexcept
method close (line 484) | void close()
method basic_pipe_ostream (line 498) | basic_pipe_ostream(basic_pipe_streambuf<char_type, traits_type> buffer)
method basic_pipe_ostream (line 869) | basic_pipe_ostream() = default;
method basic_pipe_ostream (line 871) | explicit basic_pipe_ostream(const std::string& name, std::ios_base::...
method basic_pipe_ostream (line 880) | basic_pipe_ostream(const basic_pipe_ostream&) = delete;
method basic_pipe_ostream (line 881) | basic_pipe_ostream& operator=(const basic_pipe_ostream&) = delete;
method basic_pipe_ostream (line 883) | basic_pipe_ostream(basic_pipe_ostream&& other) noexcept
method basic_pipe_ostream (line 890) | basic_pipe_ostream& operator=(basic_pipe_ostream&& other) noexcept
method open (line 900) | void open(const std::string& name, std::ios_base::openmode mode = st...
method is_open (line 906) | bool is_open() const noexcept
method close (line 911) | void close()
method basic_pipe_ostream (line 925) | basic_pipe_ostream(basic_pipe_streambuf<char_type, traits_type> buffer)
function make_anonymous_pipe (line 937) | std::pair<basic_pipe_istream<CharT, Traits>, basic_pipe_ostream<CharT,...
type nes (line 537) | namespace nes
class basic_pipe_istream (line 80) | class basic_pipe_istream
method basic_pipe_istream (line 361) | basic_pipe_istream() = default;
method basic_pipe_istream (line 363) | explicit basic_pipe_istream(const std::string& name, std::ios_base::...
method basic_pipe_istream (line 372) | basic_pipe_istream(const basic_pipe_istream&) = delete;
method basic_pipe_istream (line 373) | basic_pipe_istream& operator=(const basic_pipe_istream&) = delete;
method basic_pipe_istream (line 375) | basic_pipe_istream(basic_pipe_istream&& other) noexcept
method basic_pipe_istream (line 382) | basic_pipe_istream& operator=(basic_pipe_istream&& other) noexcept
method open (line 392) | void open(const std::string& name, std::ios_base::openmode mode = st...
method is_open (line 398) | bool is_open() const noexcept
method close (line 403) | void close()
method basic_pipe_istream (line 417) | basic_pipe_istream(basic_pipe_streambuf<char_type, traits_type> buffer)
method basic_pipe_istream (line 788) | basic_pipe_istream() = default;
method basic_pipe_istream (line 790) | explicit basic_pipe_istream(const std::string& name, std::ios_base::...
method basic_pipe_istream (line 799) | basic_pipe_istream(const basic_pipe_istream&) = delete;
method basic_pipe_istream (line 800) | basic_pipe_istream& operator=(const basic_pipe_istream&) = delete;
method basic_pipe_istream (line 802) | basic_pipe_istream(basic_pipe_istream&& other) noexcept
method basic_pipe_istream (line 809) | basic_pipe_istream& operator=(basic_pipe_istream&& other) noexcept
method open (line 819) | void open(const std::string& name, std::ios_base::openmode mode = st...
method is_open (line 825) | bool is_open() const noexcept
method close (line 830) | void close()
method basic_pipe_istream (line 844) | basic_pipe_istream(basic_pipe_streambuf<char_type, traits_type> buffer)
class basic_pipe_ostream (line 82) | class basic_pipe_ostream
method basic_pipe_ostream (line 442) | basic_pipe_ostream() = default;
method basic_pipe_ostream (line 444) | explicit basic_pipe_ostream(const std::string& name, std::ios_base::...
method basic_pipe_ostream (line 453) | basic_pipe_ostream(const basic_pipe_ostream&) = delete;
method basic_pipe_ostream (line 454) | basic_pipe_ostream& operator=(const basic_pipe_ostream&) = delete;
method basic_pipe_ostream (line 456) | basic_pipe_ostream(basic_pipe_ostream&& other) noexcept
method basic_pipe_ostream (line 463) | basic_pipe_ostream& operator=(basic_pipe_ostream&& other) noexcept
method open (line 473) | void open(const std::string& name, std::ios_base::openmode mode = st...
method is_open (line 479) | bool is_open() const noexcept
method close (line 484) | void close()
method basic_pipe_ostream (line 498) | basic_pipe_ostream(basic_pipe_streambuf<char_type, traits_type> buffer)
method basic_pipe_ostream (line 869) | basic_pipe_ostream() = default;
method basic_pipe_ostream (line 871) | explicit basic_pipe_ostream(const std::string& name, std::ios_base::...
method basic_pipe_ostream (line 880) | basic_pipe_ostream(const basic_pipe_ostream&) = delete;
method basic_pipe_ostream (line 881) | basic_pipe_ostream& operator=(const basic_pipe_ostream&) = delete;
method basic_pipe_ostream (line 883) | basic_pipe_ostream(basic_pipe_ostream&& other) noexcept
method basic_pipe_ostream (line 890) | basic_pipe_ostream& operator=(basic_pipe_ostream&& other) noexcept
method open (line 900) | void open(const std::string& name, std::ios_base::openmode mode = st...
method is_open (line 906) | bool is_open() const noexcept
method close (line 911) | void close()
method basic_pipe_ostream (line 925) | basic_pipe_ostream(basic_pipe_streambuf<char_type, traits_type> buffer)
class basic_pipe_streambuf (line 87) | class basic_pipe_streambuf : public std::basic_streambuf<CharT, Traits>
method basic_pipe_streambuf (line 103) | basic_pipe_streambuf() = default;
method basic_pipe_streambuf (line 105) | explicit basic_pipe_streambuf(const std::string& name, std::ios_base...
method basic_pipe_streambuf (line 115) | basic_pipe_streambuf(const basic_pipe_streambuf&) = delete;
method basic_pipe_streambuf (line 116) | basic_pipe_streambuf& operator=(const basic_pipe_streambuf&) = delete;
method basic_pipe_streambuf (line 118) | basic_pipe_streambuf(basic_pipe_streambuf&& other) noexcept
method basic_pipe_streambuf (line 126) | basic_pipe_streambuf& operator=(basic_pipe_streambuf&& other) noexcept
method open (line 136) | bool open(const std::string& name, std::ios_base::openmode mode)
method is_open (line 174) | bool is_open() const noexcept
method close (line 179) | void close()
method basic_pipe_streambuf (line 196) | basic_pipe_streambuf(HANDLE handle, std::ios_base::openmode mode)
method sync (line 205) | virtual int sync() override
method int_type (line 223) | virtual int_type overflow(int_type c = traits_type::eof()) override
method xsputn (line 246) | virtual std::streamsize xsputn(const char_type* s, std::streamsize c...
method int_type (line 260) | virtual int_type underflow() override
method xsgetn (line 278) | virtual std::streamsize xsgetn(char_type* s, std::streamsize count) ...
method to_wide (line 316) | std::wstring to_wide(std::string path)
method basic_pipe_streambuf (line 568) | basic_pipe_streambuf() = default;
method basic_pipe_streambuf (line 570) | explicit basic_pipe_streambuf(const std::string& name, std::ios_base...
method basic_pipe_streambuf (line 581) | basic_pipe_streambuf(const basic_pipe_streambuf&) = delete;
method basic_pipe_streambuf (line 582) | basic_pipe_streambuf& operator=(const basic_pipe_streambuf&) = delete;
method basic_pipe_streambuf (line 584) | basic_pipe_streambuf(basic_pipe_streambuf&& other) noexcept
method basic_pipe_streambuf (line 592) | basic_pipe_streambuf& operator=(basic_pipe_streambuf&& other) noexcept
method open (line 602) | bool open(const std::string& name, std::ios_base::openmode mode)
method is_open (line 629) | bool is_open() const noexcept
method close (line 634) | void close()
method basic_pipe_streambuf (line 651) | basic_pipe_streambuf(int handle, std::ios_base::openmode mode)
method sync (line 660) | virtual int sync() override
method int_type (line 677) | virtual int_type overflow(int_type c = traits_type::eof()) override
method xsputn (line 699) | virtual std::streamsize xsputn(const char_type* s, std::streamsize c...
method int_type (line 713) | virtual int_type underflow() override
method xsgetn (line 731) | virtual std::streamsize xsgetn(char_type* s, std::streamsize count) ...
class basic_pipe_istream (line 348) | class basic_pipe_istream : public std::basic_istream<CharT, Traits>
method basic_pipe_istream (line 361) | basic_pipe_istream() = default;
method basic_pipe_istream (line 363) | explicit basic_pipe_istream(const std::string& name, std::ios_base::...
method basic_pipe_istream (line 372) | basic_pipe_istream(const basic_pipe_istream&) = delete;
method basic_pipe_istream (line 373) | basic_pipe_istream& operator=(const basic_pipe_istream&) = delete;
method basic_pipe_istream (line 375) | basic_pipe_istream(basic_pipe_istream&& other) noexcept
method basic_pipe_istream (line 382) | basic_pipe_istream& operator=(basic_pipe_istream&& other) noexcept
method open (line 392) | void open(const std::string& name, std::ios_base::openmode mode = st...
method is_open (line 398) | bool is_open() const noexcept
method close (line 403) | void close()
method basic_pipe_istream (line 417) | basic_pipe_istream(basic_pipe_streambuf<char_type, traits_type> buffer)
method basic_pipe_istream (line 788) | basic_pipe_istream() = default;
method basic_pipe_istream (line 790) | explicit basic_pipe_istream(const std::string& name, std::ios_base::...
method basic_pipe_istream (line 799) | basic_pipe_istream(const basic_pipe_istream&) = delete;
method basic_pipe_istream (line 800) | basic_pipe_istream& operator=(const basic_pipe_istream&) = delete;
method basic_pipe_istream (line 802) | basic_pipe_istream(basic_pipe_istream&& other) noexcept
method basic_pipe_istream (line 809) | basic_pipe_istream& operator=(basic_pipe_istream&& other) noexcept
method open (line 819) | void open(const std::string& name, std::ios_base::openmode mode = st...
method is_open (line 825) | bool is_open() const noexcept
method close (line 830) | void close()
method basic_pipe_istream (line 844) | basic_pipe_istream(basic_pipe_streambuf<char_type, traits_type> buffer)
class basic_pipe_ostream (line 429) | class basic_pipe_ostream : public std::basic_ostream<CharT, Traits>
method basic_pipe_ostream (line 442) | basic_pipe_ostream() = default;
method basic_pipe_ostream (line 444) | explicit basic_pipe_ostream(const std::string& name, std::ios_base::...
method basic_pipe_ostream (line 453) | basic_pipe_ostream(const basic_pipe_ostream&) = delete;
method basic_pipe_ostream (line 454) | basic_pipe_ostream& operator=(const basic_pipe_ostream&) = delete;
method basic_pipe_ostream (line 456) | basic_pipe_ostream(basic_pipe_ostream&& other) noexcept
method basic_pipe_ostream (line 463) | basic_pipe_ostream& operator=(basic_pipe_ostream&& other) noexcept
method open (line 473) | void open(const std::string& name, std::ios_base::openmode mode = st...
method is_open (line 479) | bool is_open() const noexcept
method close (line 484) | void close()
method basic_pipe_ostream (line 498) | basic_pipe_ostream(basic_pipe_streambuf<char_type, traits_type> buffer)
method basic_pipe_ostream (line 869) | basic_pipe_ostream() = default;
method basic_pipe_ostream (line 871) | explicit basic_pipe_ostream(const std::string& name, std::ios_base::...
method basic_pipe_ostream (line 880) | basic_pipe_ostream(const basic_pipe_ostream&) = delete;
method basic_pipe_ostream (line 881) | basic_pipe_ostream& operator=(const basic_pipe_ostream&) = delete;
method basic_pipe_ostream (line 883) | basic_pipe_ostream(basic_pipe_ostream&& other) noexcept
method basic_pipe_ostream (line 890) | basic_pipe_ostream& operator=(basic_pipe_ostream&& other) noexcept
method open (line 900) | void open(const std::string& name, std::ios_base::openmode mode = st...
method is_open (line 906) | bool is_open() const noexcept
method close (line 911) | void close()
method basic_pipe_ostream (line 925) | basic_pipe_ostream(basic_pipe_streambuf<char_type, traits_type> buffer)
function make_anonymous_pipe (line 510) | std::pair<basic_pipe_istream<CharT, Traits>, basic_pipe_ostream<CharT,...
class basic_pipe_istream (line 545) | class basic_pipe_istream
method basic_pipe_istream (line 361) | basic_pipe_istream() = default;
method basic_pipe_istream (line 363) | explicit basic_pipe_istream(const std::string& name, std::ios_base::...
method basic_pipe_istream (line 372) | basic_pipe_istream(const basic_pipe_istream&) = delete;
method basic_pipe_istream (line 373) | basic_pipe_istream& operator=(const basic_pipe_istream&) = delete;
method basic_pipe_istream (line 375) | basic_pipe_istream(basic_pipe_istream&& other) noexcept
method basic_pipe_istream (line 382) | basic_pipe_istream& operator=(basic_pipe_istream&& other) noexcept
method open (line 392) | void open(const std::string& name, std::ios_base::openmode mode = st...
method is_open (line 398) | bool is_open() const noexcept
method close (line 403) | void close()
method basic_pipe_istream (line 417) | basic_pipe_istream(basic_pipe_streambuf<char_type, traits_type> buffer)
method basic_pipe_istream (line 788) | basic_pipe_istream() = default;
method basic_pipe_istream (line 790) | explicit basic_pipe_istream(const std::string& name, std::ios_base::...
method basic_pipe_istream (line 799) | basic_pipe_istream(const basic_pipe_istream&) = delete;
method basic_pipe_istream (line 800) | basic_pipe_istream& operator=(const basic_pipe_istream&) = delete;
method basic_pipe_istream (line 802) | basic_pipe_istream(basic_pipe_istream&& other) noexcept
method basic_pipe_istream (line 809) | basic_pipe_istream& operator=(basic_pipe_istream&& other) noexcept
method open (line 819) | void open(const std::string& name, std::ios_base::openmode mode = st...
method is_open (line 825) | bool is_open() const noexcept
method close (line 830) | void close()
method basic_pipe_istream (line 844) | basic_pipe_istream(basic_pipe_streambuf<char_type, traits_type> buffer)
class basic_pipe_ostream (line 547) | class basic_pipe_ostream
method basic_pipe_ostream (line 442) | basic_pipe_ostream() = default;
method basic_pipe_ostream (line 444) | explicit basic_pipe_ostream(const std::string& name, std::ios_base::...
method basic_pipe_ostream (line 453) | basic_pipe_ostream(const basic_pipe_ostream&) = delete;
method basic_pipe_ostream (line 454) | basic_pipe_ostream& operator=(const basic_pipe_ostream&) = delete;
method basic_pipe_ostream (line 456) | basic_pipe_ostream(basic_pipe_ostream&& other) noexcept
method basic_pipe_ostream (line 463) | basic_pipe_ostream& operator=(basic_pipe_ostream&& other) noexcept
method open (line 473) | void open(const std::string& name, std::ios_base::openmode mode = st...
method is_open (line 479) | bool is_open() const noexcept
method close (line 484) | void close()
method basic_pipe_ostream (line 498) | basic_pipe_ostream(basic_pipe_streambuf<char_type, traits_type> buffer)
method basic_pipe_ostream (line 869) | basic_pipe_ostream() = default;
method basic_pipe_ostream (line 871) | explicit basic_pipe_ostream(const std::string& name, std::ios_base::...
method basic_pipe_ostream (line 880) | basic_pipe_ostream(const basic_pipe_ostream&) = delete;
method basic_pipe_ostream (line 881) | basic_pipe_ostream& operator=(const basic_pipe_ostream&) = delete;
method basic_pipe_ostream (line 883) | basic_pipe_ostream(basic_pipe_ostream&& other) noexcept
method basic_pipe_ostream (line 890) | basic_pipe_ostream& operator=(basic_pipe_ostream&& other) noexcept
method open (line 900) | void open(const std::string& name, std::ios_base::openmode mode = st...
method is_open (line 906) | bool is_open() const noexcept
method close (line 911) | void close()
method basic_pipe_ostream (line 925) | basic_pipe_ostream(basic_pipe_streambuf<char_type, traits_type> buffer)
class basic_pipe_streambuf (line 552) | class basic_pipe_streambuf : public std::basic_streambuf<CharT, Traits>
method basic_pipe_streambuf (line 103) | basic_pipe_streambuf() = default;
method basic_pipe_streambuf (line 105) | explicit basic_pipe_streambuf(const std::string& name, std::ios_base...
method basic_pipe_streambuf (line 115) | basic_pipe_streambuf(const basic_pipe_streambuf&) = delete;
method basic_pipe_streambuf (line 116) | basic_pipe_streambuf& operator=(const basic_pipe_streambuf&) = delete;
method basic_pipe_streambuf (line 118) | basic_pipe_streambuf(basic_pipe_streambuf&& other) noexcept
method basic_pipe_streambuf (line 126) | basic_pipe_streambuf& operator=(basic_pipe_streambuf&& other) noexcept
method open (line 136) | bool open(const std::string& name, std::ios_base::openmode mode)
method is_open (line 174) | bool is_open() const noexcept
method close (line 179) | void close()
method basic_pipe_streambuf (line 196) | basic_pipe_streambuf(HANDLE handle, std::ios_base::openmode mode)
method sync (line 205) | virtual int sync() override
method int_type (line 223) | virtual int_type overflow(int_type c = traits_type::eof()) override
method xsputn (line 246) | virtual std::streamsize xsputn(const char_type* s, std::streamsize c...
method int_type (line 260) | virtual int_type underflow() override
method xsgetn (line 278) | virtual std::streamsize xsgetn(char_type* s, std::streamsize count) ...
method to_wide (line 316) | std::wstring to_wide(std::string path)
method basic_pipe_streambuf (line 568) | basic_pipe_streambuf() = default;
method basic_pipe_streambuf (line 570) | explicit basic_pipe_streambuf(const std::string& name, std::ios_base...
method basic_pipe_streambuf (line 581) | basic_pipe_streambuf(const basic_pipe_streambuf&) = delete;
method basic_pipe_streambuf (line 582) | basic_pipe_streambuf& operator=(const basic_pipe_streambuf&) = delete;
method basic_pipe_streambuf (line 584) | basic_pipe_streambuf(basic_pipe_streambuf&& other) noexcept
method basic_pipe_streambuf (line 592) | basic_pipe_streambuf& operator=(basic_pipe_streambuf&& other) noexcept
method open (line 602) | bool open(const std::string& name, std::ios_base::openmode mode)
method is_open (line 629) | bool is_open() const noexcept
method close (line 634) | void close()
method basic_pipe_streambuf (line 651) | basic_pipe_streambuf(int handle, std::ios_base::openmode mode)
method sync (line 660) | virtual int sync() override
method int_type (line 677) | virtual int_type overflow(int_type c = traits_type::eof()) override
method xsputn (line 699) | virtual std::streamsize xsputn(const char_type* s, std::streamsize c...
method int_type (line 713) | virtual int_type underflow() override
method xsgetn (line 731) | virtual std::streamsize xsgetn(char_type* s, std::streamsize count) ...
class basic_pipe_istream (line 775) | class basic_pipe_istream : public std::basic_istream<CharT, Traits>
method basic_pipe_istream (line 361) | basic_pipe_istream() = default;
method basic_pipe_istream (line 363) | explicit basic_pipe_istream(const std::string& name, std::ios_base::...
method basic_pipe_istream (line 372) | basic_pipe_istream(const basic_pipe_istream&) = delete;
method basic_pipe_istream (line 373) | basic_pipe_istream& operator=(const basic_pipe_istream&) = delete;
method basic_pipe_istream (line 375) | basic_pipe_istream(basic_pipe_istream&& other) noexcept
method basic_pipe_istream (line 382) | basic_pipe_istream& operator=(basic_pipe_istream&& other) noexcept
method open (line 392) | void open(const std::string& name, std::ios_base::openmode mode = st...
method is_open (line 398) | bool is_open() const noexcept
method close (line 403) | void close()
method basic_pipe_istream (line 417) | basic_pipe_istream(basic_pipe_streambuf<char_type, traits_type> buffer)
method basic_pipe_istream (line 788) | basic_pipe_istream() = default;
method basic_pipe_istream (line 790) | explicit basic_pipe_istream(const std::string& name, std::ios_base::...
method basic_pipe_istream (line 799) | basic_pipe_istream(const basic_pipe_istream&) = delete;
method basic_pipe_istream (line 800) | basic_pipe_istream& operator=(const basic_pipe_istream&) = delete;
method basic_pipe_istream (line 802) | basic_pipe_istream(basic_pipe_istream&& other) noexcept
method basic_pipe_istream (line 809) | basic_pipe_istream& operator=(basic_pipe_istream&& other) noexcept
method open (line 819) | void open(const std::string& name, std::ios_base::openmode mode = st...
method is_open (line 825) | bool is_open() const noexcept
method close (line 830) | void close()
method basic_pipe_istream (line 844) | basic_pipe_istream(basic_pipe_streambuf<char_type, traits_type> buffer)
class basic_pipe_ostream (line 856) | class basic_pipe_ostream : public std::basic_ostream<CharT, Traits>
method basic_pipe_ostream (line 442) | basic_pipe_ostream() = default;
method basic_pipe_ostream (line 444) | explicit basic_pipe_ostream(const std::string& name, std::ios_base::...
method basic_pipe_ostream (line 453) | basic_pipe_ostream(const basic_pipe_ostream&) = delete;
method basic_pipe_ostream (line 454) | basic_pipe_ostream& operator=(const basic_pipe_ostream&) = delete;
method basic_pipe_ostream (line 456) | basic_pipe_ostream(basic_pipe_ostream&& other) noexcept
method basic_pipe_ostream (line 463) | basic_pipe_ostream& operator=(basic_pipe_ostream&& other) noexcept
method open (line 473) | void open(const std::string& name, std::ios_base::openmode mode = st...
method is_open (line 479) | bool is_open() const noexcept
method close (line 484) | void close()
method basic_pipe_ostream (line 498) | basic_pipe_ostream(basic_pipe_streambuf<char_type, traits_type> buffer)
method basic_pipe_ostream (line 869) | basic_pipe_ostream() = default;
method basic_pipe_ostream (line 871) | explicit basic_pipe_ostream(const std::string& name, std::ios_base::...
method basic_pipe_ostream (line 880) | basic_pipe_ostream(const basic_pipe_ostream&) = delete;
method basic_pipe_ostream (line 881) | basic_pipe_ostream& operator=(const basic_pipe_ostream&) = delete;
method basic_pipe_ostream (line 883) | basic_pipe_ostream(basic_pipe_ostream&& other) noexcept
method basic_pipe_ostream (line 890) | basic_pipe_ostream& operator=(basic_pipe_ostream&& other) noexcept
method open (line 900) | void open(const std::string& name, std::ios_base::openmode mode = st...
method is_open (line 906) | bool is_open() const noexcept
method close (line 911) | void close()
method basic_pipe_ostream (line 925) | basic_pipe_ostream(basic_pipe_streambuf<char_type, traits_type> buffer)
function make_anonymous_pipe (line 937) | std::pair<basic_pipe_istream<CharT, Traits>, basic_pipe_ostream<CharT,...
FILE: include/nes/process.hpp
type nes (line 78) | namespace nes
type impl (line 85) | namespace impl
type id_t (line 88) | enum class id_t : DWORD
type auto_handle (line 122) | struct auto_handle
method auto_handle (line 125) | constexpr auto_handle() = default;
method auto_handle (line 126) | auto_handle(HANDLE h)
method auto_handle (line 139) | auto_handle(const auto_handle&) = delete;
method auto_handle (line 140) | auto_handle& operator=(const auto_handle&) = delete;
method auto_handle (line 142) | auto_handle(auto_handle&& other) noexcept
method auto_handle (line 147) | auto_handle& operator=(auto_handle&& other) noexcept
method HANDLE (line 154) | HANDLE release() noexcept
method HANDLE (line 164) | HANDLE* operator&() noexcept
method HANDLE (line 169) | const HANDLE* operator&() const noexcept
method auto_handle (line 724) | constexpr auto_handle() = default;
method auto_handle (line 725) | auto_handle(int h)
method auto_handle (line 738) | auto_handle(const auto_handle&) = delete;
method auto_handle (line 739) | auto_handle& operator=(const auto_handle&) = delete;
method auto_handle (line 741) | auto_handle(auto_handle&& other) noexcept
method auto_handle (line 746) | auto_handle& operator=(auto_handle&& other) noexcept
method release (line 753) | int release() noexcept
type id_t (line 687) | enum class id_t : pid_t
type auto_handle (line 722) | struct auto_handle
method auto_handle (line 125) | constexpr auto_handle() = default;
method auto_handle (line 126) | auto_handle(HANDLE h)
method auto_handle (line 139) | auto_handle(const auto_handle&) = delete;
method auto_handle (line 140) | auto_handle& operator=(const auto_handle&) = delete;
method auto_handle (line 142) | auto_handle(auto_handle&& other) noexcept
method auto_handle (line 147) | auto_handle& operator=(auto_handle&& other) noexcept
method HANDLE (line 154) | HANDLE release() noexcept
method HANDLE (line 164) | HANDLE* operator&() noexcept
method HANDLE (line 169) | const HANDLE* operator&() const noexcept
method auto_handle (line 724) | constexpr auto_handle() = default;
method auto_handle (line 725) | auto_handle(int h)
method auto_handle (line 738) | auto_handle(const auto_handle&) = delete;
method auto_handle (line 739) | auto_handle& operator=(const auto_handle&) = delete;
method auto_handle (line 741) | auto_handle(auto_handle&& other) noexcept
method auto_handle (line 746) | auto_handle& operator=(auto_handle&& other) noexcept
method release (line 753) | int release() noexcept
type process_options (line 185) | enum class process_options : std::uint32_t
function process_options (line 195) | constexpr process_options operator&(process_options left, process_opti...
function process_options (line 200) | constexpr process_options& operator&=(process_options& left, process_o...
function process_options (line 206) | constexpr process_options operator|(process_options left, process_opti...
function process_options (line 211) | constexpr process_options& operator|=(process_options& left, process_o...
function process_options (line 217) | constexpr process_options operator^(process_options left, process_opti...
function process_options (line 222) | constexpr process_options& operator^=(process_options& left, process_o...
function process_options (line 228) | constexpr process_options operator~(process_options value) noexcept
class process (line 233) | class process
method process (line 241) | constexpr process() noexcept = default;
method process (line 243) | explicit process(const std::string& path, const std::string& working...
method process (line 248) | explicit process(const std::string& path, process_options options)
method process (line 253) | explicit process(const std::string& path, const std::vector<std::str...
method process (line 258) | explicit process(const std::string& path, const std::string& working...
method process (line 263) | explicit process(const std::string& path, std::vector<std::string> a...
method process (line 418) | process(const process&) = delete;
method process (line 419) | process& operator=(const process&) = delete;
method process (line 421) | process(process&& other) noexcept
method process (line 434) | process& operator=(process&& other) noexcept
method join (line 454) | void join()
method joinable (line 471) | bool joinable() const noexcept
method active (line 476) | bool active() const
method detach (line 492) | void detach()
method kill (line 499) | bool kill()
method return_code_type (line 513) | return_code_type return_code() const noexcept
method native_handle_type (line 520) | native_handle_type native_handle() const noexcept
method id (line 525) | id get_id() const noexcept
method pipe_ostream (line 531) | pipe_ostream& stdin_stream() noexcept
method pipe_istream (line 536) | pipe_istream& stdout_stream() noexcept
method pipe_istream (line 541) | pipe_istream& stderr_stream() noexcept
method to_wide (line 548) | std::wstring to_wide(const std::string& path)
method get_error_message (line 568) | std::string get_error_message() const
method close_process (line 573) | void close_process()
method wchar_t (line 580) | wchar_t* null_or_data(std::wstring& str)
method wchar_t (line 585) | const wchar_t* null_or_data(const std::wstring& str)
method process (line 845) | constexpr process() noexcept = default;
method process (line 847) | explicit process(const std::string& path, const std::string& working...
method process (line 852) | explicit process(const std::string& path, process_options options)
method process (line 857) | explicit process(const std::string& path, const std::vector<std::str...
method process (line 862) | explicit process(const std::string& path, const std::string& working...
method process (line 867) | explicit process(const std::string& path, std::vector<std::string> a...
method process (line 984) | process(const process&) = delete;
method process (line 985) | process& operator=(const process&) = delete;
method process (line 987) | process(process&& other) noexcept
method process (line 998) | process& operator=(process&& other) noexcept
method join (line 1016) | void join()
method joinable (line 1030) | bool joinable() const noexcept
method active (line 1035) | bool active() const
method detach (line 1040) | void detach()
method kill (line 1046) | bool kill()
method return_code_type (line 1060) | return_code_type return_code() const noexcept
method native_handle_type (line 1067) | native_handle_type native_handle() const noexcept
method id (line 1072) | id get_id() const noexcept
method pipe_ostream (line 1078) | pipe_ostream& stdin_stream() noexcept
method pipe_istream (line 1083) | pipe_istream& stdout_stream() noexcept
method pipe_istream (line 1088) | pipe_istream& stderr_stream() noexcept
type this_process (line 602) | namespace this_process
function get_id (line 605) | inline process::id get_id() noexcept
function working_directory (line 610) | inline std::string working_directory()
function change_working_directory (line 635) | inline bool change_working_directory(const std::string& path)
function get_id (line 1107) | inline process::id get_id() noexcept
function working_directory (line 1112) | inline std::string working_directory()
function change_working_directory (line 1134) | inline bool change_working_directory(const std::string& path)
type impl (line 684) | namespace impl
type id_t (line 88) | enum class id_t : DWORD
type auto_handle (line 122) | struct auto_handle
method auto_handle (line 125) | constexpr auto_handle() = default;
method auto_handle (line 126) | auto_handle(HANDLE h)
method auto_handle (line 139) | auto_handle(const auto_handle&) = delete;
method auto_handle (line 140) | auto_handle& operator=(const auto_handle&) = delete;
method auto_handle (line 142) | auto_handle(auto_handle&& other) noexcept
method auto_handle (line 147) | auto_handle& operator=(auto_handle&& other) noexcept
method HANDLE (line 154) | HANDLE release() noexcept
method HANDLE (line 164) | HANDLE* operator&() noexcept
method HANDLE (line 169) | const HANDLE* operator&() const noexcept
method auto_handle (line 724) | constexpr auto_handle() = default;
method auto_handle (line 725) | auto_handle(int h)
method auto_handle (line 738) | auto_handle(const auto_handle&) = delete;
method auto_handle (line 739) | auto_handle& operator=(const auto_handle&) = delete;
method auto_handle (line 741) | auto_handle(auto_handle&& other) noexcept
method auto_handle (line 746) | auto_handle& operator=(auto_handle&& other) noexcept
method release (line 753) | int release() noexcept
type id_t (line 687) | enum class id_t : pid_t
type auto_handle (line 722) | struct auto_handle
method auto_handle (line 125) | constexpr auto_handle() = default;
method auto_handle (line 126) | auto_handle(HANDLE h)
method auto_handle (line 139) | auto_handle(const auto_handle&) = delete;
method auto_handle (line 140) | auto_handle& operator=(const auto_handle&) = delete;
method auto_handle (line 142) | auto_handle(auto_handle&& other) noexcept
method auto_handle (line 147) | auto_handle& operator=(auto_handle&& other) noexcept
method HANDLE (line 154) | HANDLE release() noexcept
method HANDLE (line 164) | HANDLE* operator&() noexcept
method HANDLE (line 169) | const HANDLE* operator&() const noexcept
method auto_handle (line 724) | constexpr auto_handle() = default;
method auto_handle (line 725) | auto_handle(int h)
method auto_handle (line 738) | auto_handle(const auto_handle&) = delete;
method auto_handle (line 739) | auto_handle& operator=(const auto_handle&) = delete;
method auto_handle (line 741) | auto_handle(auto_handle&& other) noexcept
method auto_handle (line 746) | auto_handle& operator=(auto_handle&& other) noexcept
method release (line 753) | int release() noexcept
type process_options (line 789) | enum class process_options : std::uint32_t
function process_options (line 799) | constexpr process_options operator&(process_options left, process_opti...
function process_options (line 804) | constexpr process_options& operator&=(process_options& left, process_o...
function process_options (line 810) | constexpr process_options operator|(process_options left, process_opti...
function process_options (line 815) | constexpr process_options& operator|=(process_options& left, process_o...
function process_options (line 821) | constexpr process_options operator^(process_options left, process_opti...
function process_options (line 826) | constexpr process_options& operator^=(process_options& left, process_o...
function process_options (line 832) | constexpr process_options operator~(process_options value) noexcept
class process (line 837) | class process
method process (line 241) | constexpr process() noexcept = default;
method process (line 243) | explicit process(const std::string& path, const std::string& working...
method process (line 248) | explicit process(const std::string& path, process_options options)
method process (line 253) | explicit process(const std::string& path, const std::vector<std::str...
method process (line 258) | explicit process(const std::string& path, const std::string& working...
method process (line 263) | explicit process(const std::string& path, std::vector<std::string> a...
method process (line 418) | process(const process&) = delete;
method process (line 419) | process& operator=(const process&) = delete;
method process (line 421) | process(process&& other) noexcept
method process (line 434) | process& operator=(process&& other) noexcept
method join (line 454) | void join()
method joinable (line 471) | bool joinable() const noexcept
method active (line 476) | bool active() const
method detach (line 492) | void detach()
method kill (line 499) | bool kill()
method return_code_type (line 513) | return_code_type return_code() const noexcept
method native_handle_type (line 520) | native_handle_type native_handle() const noexcept
method id (line 525) | id get_id() const noexcept
method pipe_ostream (line 531) | pipe_ostream& stdin_stream() noexcept
method pipe_istream (line 536) | pipe_istream& stdout_stream() noexcept
method pipe_istream (line 541) | pipe_istream& stderr_stream() noexcept
method to_wide (line 548) | std::wstring to_wide(const std::string& path)
method get_error_message (line 568) | std::string get_error_message() const
method close_process (line 573) | void close_process()
method wchar_t (line 580) | wchar_t* null_or_data(std::wstring& str)
method wchar_t (line 585) | const wchar_t* null_or_data(const std::wstring& str)
method process (line 845) | constexpr process() noexcept = default;
method process (line 847) | explicit process(const std::string& path, const std::string& working...
method process (line 852) | explicit process(const std::string& path, process_options options)
method process (line 857) | explicit process(const std::string& path, const std::vector<std::str...
method process (line 862) | explicit process(const std::string& path, const std::string& working...
method process (line 867) | explicit process(const std::string& path, std::vector<std::string> a...
method process (line 984) | process(const process&) = delete;
method process (line 985) | process& operator=(const process&) = delete;
method process (line 987) | process(process&& other) noexcept
method process (line 998) | process& operator=(process&& other) noexcept
method join (line 1016) | void join()
method joinable (line 1030) | bool joinable() const noexcept
method active (line 1035) | bool active() const
method detach (line 1040) | void detach()
method kill (line 1046) | bool kill()
method return_code_type (line 1060) | return_code_type return_code() const noexcept
method native_handle_type (line 1067) | native_handle_type native_handle() const noexcept
method id (line 1072) | id get_id() const noexcept
method pipe_ostream (line 1078) | pipe_ostream& stdin_stream() noexcept
method pipe_istream (line 1083) | pipe_istream& stdout_stream() noexcept
method pipe_istream (line 1088) | pipe_istream& stderr_stream() noexcept
type this_process (line 1104) | namespace this_process
function get_id (line 605) | inline process::id get_id() noexcept
function working_directory (line 610) | inline std::string working_directory()
function change_working_directory (line 635) | inline bool change_working_directory(const std::string& path)
function get_id (line 1107) | inline process::id get_id() noexcept
function working_directory (line 1112) | inline std::string working_directory()
function change_working_directory (line 1134) | inline bool change_working_directory(const std::string& path)
type std (line 660) | namespace std
type hash<nes::process::id> (line 663) | struct hash<nes::process::id>
method result_type (line 668) | result_type operator()(const argument_type& s) const noexcept
method result_type (line 1159) | result_type operator()(const argument_type& s) const noexcept
type hash<nes::process::id> (line 1154) | struct hash<nes::process::id>
method result_type (line 668) | result_type operator()(const argument_type& s) const noexcept
method result_type (line 1159) | result_type operator()(const argument_type& s) const noexcept
type nes (line 677) | namespace nes
type impl (line 85) | namespace impl
type id_t (line 88) | enum class id_t : DWORD
type auto_handle (line 122) | struct auto_handle
method auto_handle (line 125) | constexpr auto_handle() = default;
method auto_handle (line 126) | auto_handle(HANDLE h)
method auto_handle (line 139) | auto_handle(const auto_handle&) = delete;
method auto_handle (line 140) | auto_handle& operator=(const auto_handle&) = delete;
method auto_handle (line 142) | auto_handle(auto_handle&& other) noexcept
method auto_handle (line 147) | auto_handle& operator=(auto_handle&& other) noexcept
method HANDLE (line 154) | HANDLE release() noexcept
method HANDLE (line 164) | HANDLE* operator&() noexcept
method HANDLE (line 169) | const HANDLE* operator&() const noexcept
method auto_handle (line 724) | constexpr auto_handle() = default;
method auto_handle (line 725) | auto_handle(int h)
method auto_handle (line 738) | auto_handle(const auto_handle&) = delete;
method auto_handle (line 739) | auto_handle& operator=(const auto_handle&) = delete;
method auto_handle (line 741) | auto_handle(auto_handle&& other) noexcept
method auto_handle (line 746) | auto_handle& operator=(auto_handle&& other) noexcept
method release (line 753) | int release() noexcept
type id_t (line 687) | enum class id_t : pid_t
type auto_handle (line 722) | struct auto_handle
method auto_handle (line 125) | constexpr auto_handle() = default;
method auto_handle (line 126) | auto_handle(HANDLE h)
method auto_handle (line 139) | auto_handle(const auto_handle&) = delete;
method auto_handle (line 140) | auto_handle& operator=(const auto_handle&) = delete;
method auto_handle (line 142) | auto_handle(auto_handle&& other) noexcept
method auto_handle (line 147) | auto_handle& operator=(auto_handle&& other) noexcept
method HANDLE (line 154) | HANDLE release() noexcept
method HANDLE (line 164) | HANDLE* operator&() noexcept
method HANDLE (line 169) | const HANDLE* operator&() const noexcept
method auto_handle (line 724) | constexpr auto_handle() = default;
method auto_handle (line 725) | auto_handle(int h)
method auto_handle (line 738) | auto_handle(const auto_handle&) = delete;
method auto_handle (line 739) | auto_handle& operator=(const auto_handle&) = delete;
method auto_handle (line 741) | auto_handle(auto_handle&& other) noexcept
method auto_handle (line 746) | auto_handle& operator=(auto_handle&& other) noexcept
method release (line 753) | int release() noexcept
type process_options (line 185) | enum class process_options : std::uint32_t
function process_options (line 195) | constexpr process_options operator&(process_options left, process_opti...
function process_options (line 200) | constexpr process_options& operator&=(process_options& left, process_o...
function process_options (line 206) | constexpr process_options operator|(process_options left, process_opti...
function process_options (line 211) | constexpr process_options& operator|=(process_options& left, process_o...
function process_options (line 217) | constexpr process_options operator^(process_options left, process_opti...
function process_options (line 222) | constexpr process_options& operator^=(process_options& left, process_o...
function process_options (line 228) | constexpr process_options operator~(process_options value) noexcept
class process (line 233) | class process
method process (line 241) | constexpr process() noexcept = default;
method process (line 243) | explicit process(const std::string& path, const std::string& working...
method process (line 248) | explicit process(const std::string& path, process_options options)
method process (line 253) | explicit process(const std::string& path, const std::vector<std::str...
method process (line 258) | explicit process(const std::string& path, const std::string& working...
method process (line 263) | explicit process(const std::string& path, std::vector<std::string> a...
method process (line 418) | process(const process&) = delete;
method process (line 419) | process& operator=(const process&) = delete;
method process (line 421) | process(process&& other) noexcept
method process (line 434) | process& operator=(process&& other) noexcept
method join (line 454) | void join()
method joinable (line 471) | bool joinable() const noexcept
method active (line 476) | bool active() const
method detach (line 492) | void detach()
method kill (line 499) | bool kill()
method return_code_type (line 513) | return_code_type return_code() const noexcept
method native_handle_type (line 520) | native_handle_type native_handle() const noexcept
method id (line 525) | id get_id() const noexcept
method pipe_ostream (line 531) | pipe_ostream& stdin_stream() noexcept
method pipe_istream (line 536) | pipe_istream& stdout_stream() noexcept
method pipe_istream (line 541) | pipe_istream& stderr_stream() noexcept
method to_wide (line 548) | std::wstring to_wide(const std::string& path)
method get_error_message (line 568) | std::string get_error_message() const
method close_process (line 573) | void close_process()
method wchar_t (line 580) | wchar_t* null_or_data(std::wstring& str)
method wchar_t (line 585) | const wchar_t* null_or_data(const std::wstring& str)
method process (line 845) | constexpr process() noexcept = default;
method process (line 847) | explicit process(const std::string& path, const std::string& working...
method process (line 852) | explicit process(const std::string& path, process_options options)
method process (line 857) | explicit process(const std::string& path, const std::vector<std::str...
method process (line 862) | explicit process(const std::string& path, const std::string& working...
method process (line 867) | explicit process(const std::string& path, std::vector<std::string> a...
method process (line 984) | process(const process&) = delete;
method process (line 985) | process& operator=(const process&) = delete;
method process (line 987) | process(process&& other) noexcept
method process (line 998) | process& operator=(process&& other) noexcept
method join (line 1016) | void join()
method joinable (line 1030) | bool joinable() const noexcept
method active (line 1035) | bool active() const
method detach (line 1040) | void detach()
method kill (line 1046) | bool kill()
method return_code_type (line 1060) | return_code_type return_code() const noexcept
method native_handle_type (line 1067) | native_handle_type native_handle() const noexcept
method id (line 1072) | id get_id() const noexcept
method pipe_ostream (line 1078) | pipe_ostream& stdin_stream() noexcept
method pipe_istream (line 1083) | pipe_istream& stdout_stream() noexcept
method pipe_istream (line 1088) | pipe_istream& stderr_stream() noexcept
type this_process (line 602) | namespace this_process
function get_id (line 605) | inline process::id get_id() noexcept
function working_directory (line 610) | inline std::string working_directory()
function change_working_directory (line 635) | inline bool change_working_directory(const std::string& path)
function get_id (line 1107) | inline process::id get_id() noexcept
function working_directory (line 1112) | inline std::string working_directory()
function change_working_directory (line 1134) | inline bool change_working_directory(const std::string& path)
type impl (line 684) | namespace impl
type id_t (line 88) | enum class id_t : DWORD
type auto_handle (line 122) | struct auto_handle
method auto_handle (line 125) | constexpr auto_handle() = default;
method auto_handle (line 126) | auto_handle(HANDLE h)
method auto_handle (line 139) | auto_handle(const auto_handle&) = delete;
method auto_handle (line 140) | auto_handle& operator=(const auto_handle&) = delete;
method auto_handle (line 142) | auto_handle(auto_handle&& other) noexcept
method auto_handle (line 147) | auto_handle& operator=(auto_handle&& other) noexcept
method HANDLE (line 154) | HANDLE release() noexcept
method HANDLE (line 164) | HANDLE* operator&() noexcept
method HANDLE (line 169) | const HANDLE* operator&() const noexcept
method auto_handle (line 724) | constexpr auto_handle() = default;
method auto_handle (line 725) | auto_handle(int h)
method auto_handle (line 738) | auto_handle(const auto_handle&) = delete;
method auto_handle (line 739) | auto_handle& operator=(const auto_handle&) = delete;
method auto_handle (line 741) | auto_handle(auto_handle&& other) noexcept
method auto_handle (line 746) | auto_handle& operator=(auto_handle&& other) noexcept
method release (line 753) | int release() noexcept
type id_t (line 687) | enum class id_t : pid_t
type auto_handle (line 722) | struct auto_handle
method auto_handle (line 125) | constexpr auto_handle() = default;
method auto_handle (line 126) | auto_handle(HANDLE h)
method auto_handle (line 139) | auto_handle(const auto_handle&) = delete;
method auto_handle (line 140) | auto_handle& operator=(const auto_handle&) = delete;
method auto_handle (line 142) | auto_handle(auto_handle&& other) noexcept
method auto_handle (line 147) | auto_handle& operator=(auto_handle&& other) noexcept
method HANDLE (line 154) | HANDLE release() noexcept
method HANDLE (line 164) | HANDLE* operator&() noexcept
method HANDLE (line 169) | const HANDLE* operator&() const noexcept
method auto_handle (line 724) | constexpr auto_handle() = default;
method auto_handle (line 725) | auto_handle(int h)
method auto_handle (line 738) | auto_handle(const auto_handle&) = delete;
method auto_handle (line 739) | auto_handle& operator=(const auto_handle&) = delete;
method auto_handle (line 741) | auto_handle(auto_handle&& other) noexcept
method auto_handle (line 746) | auto_handle& operator=(auto_handle&& other) noexcept
method release (line 753) | int release() noexcept
type process_options (line 789) | enum class process_options : std::uint32_t
function process_options (line 799) | constexpr process_options operator&(process_options left, process_opti...
function process_options (line 804) | constexpr process_options& operator&=(process_options& left, process_o...
function process_options (line 810) | constexpr process_options operator|(process_options left, process_opti...
function process_options (line 815) | constexpr process_options& operator|=(process_options& left, process_o...
function process_options (line 821) | constexpr process_options operator^(process_options left, process_opti...
function process_options (line 826) | constexpr process_options& operator^=(process_options& left, process_o...
function process_options (line 832) | constexpr process_options operator~(process_options value) noexcept
class process (line 837) | class process
method process (line 241) | constexpr process() noexcept = default;
method process (line 243) | explicit process(const std::string& path, const std::string& working...
method process (line 248) | explicit process(const std::string& path, process_options options)
method process (line 253) | explicit process(const std::string& path, const std::vector<std::str...
method process (line 258) | explicit process(const std::string& path, const std::string& working...
method process (line 263) | explicit process(const std::string& path, std::vector<std::string> a...
method process (line 418) | process(const process&) = delete;
method process (line 419) | process& operator=(const process&) = delete;
method process (line 421) | process(process&& other) noexcept
method process (line 434) | process& operator=(process&& other) noexcept
method join (line 454) | void join()
method joinable (line 471) | bool joinable() const noexcept
method active (line 476) | bool active() const
method detach (line 492) | void detach()
method kill (line 499) | bool kill()
method return_code_type (line 513) | return_code_type return_code() const noexcept
method native_handle_type (line 520) | native_handle_type native_handle() const noexcept
method id (line 525) | id get_id() const noexcept
method pipe_ostream (line 531) | pipe_ostream& stdin_stream() noexcept
method pipe_istream (line 536) | pipe_istream& stdout_stream() noexcept
method pipe_istream (line 541) | pipe_istream& stderr_stream() noexcept
method to_wide (line 548) | std::wstring to_wide(const std::string& path)
method get_error_message (line 568) | std::string get_error_message() const
method close_process (line 573) | void close_process()
method wchar_t (line 580) | wchar_t* null_or_data(std::wstring& str)
method wchar_t (line 585) | const wchar_t* null_or_data(const std::wstring& str)
method process (line 845) | constexpr process() noexcept = default;
method process (line 847) | explicit process(const std::string& path, const std::string& working...
method process (line 852) | explicit process(const std::string& path, process_options options)
method process (line 857) | explicit process(const std::string& path, const std::vector<std::str...
method process (line 862) | explicit process(const std::string& path, const std::string& working...
method process (line 867) | explicit process(const std::string& path, std::vector<std::string> a...
method process (line 984) | process(const process&) = delete;
method process (line 985) | process& operator=(const process&) = delete;
method process (line 987) | process(process&& other) noexcept
method process (line 998) | process& operator=(process&& other) noexcept
method join (line 1016) | void join()
method joinable (line 1030) | bool joinable() const noexcept
method active (line 1035) | bool active() const
method detach (line 1040) | void detach()
method kill (line 1046) | bool kill()
method return_code_type (line 1060) | return_code_type return_code() const noexcept
method native_handle_type (line 1067) | native_handle_type native_handle() const noexcept
method id (line 1072) | id get_id() const noexcept
method pipe_ostream (line 1078) | pipe_ostream& stdin_stream() noexcept
method pipe_istream (line 1083) | pipe_istream& stdout_stream() noexcept
method pipe_istream (line 1088) | pipe_istream& stderr_stream() noexcept
type this_process (line 1104) | namespace this_process
function get_id (line 605) | inline process::id get_id() noexcept
function working_directory (line 610) | inline std::string working_directory()
function change_working_directory (line 635) | inline bool change_working_directory(const std::string& path)
function get_id (line 1107) | inline process::id get_id() noexcept
function working_directory (line 1112) | inline std::string working_directory()
function change_working_directory (line 1134) | inline bool change_working_directory(const std::string& path)
type std (line 1151) | namespace std
type hash<nes::process::id> (line 663) | struct hash<nes::process::id>
method result_type (line 668) | result_type operator()(const argument_type& s) const noexcept
method result_type (line 1159) | result_type operator()(const argument_type& s) const noexcept
type hash<nes::process::id> (line 1154) | struct hash<nes::process::id>
method result_type (line 668) | result_type operator()(const argument_type& s) const noexcept
method result_type (line 1159) | result_type operator()(const argument_type& s) const noexcept
FILE: include/nes/semaphore.hpp
type nes (line 69) | namespace nes
function NES_INLINE_NAMESPACE_BEGIN (line 72) | NES_INLINE_NAMESPACE_BEGIN
function semaphore (line 97) | semaphore(const semaphore&) = delete;
function semaphore (line 99) | semaphore(semaphore&& other) noexcept = delete;
function acquire (line 102) | void acquire()
function try_acquire (line 110) | bool try_acquire()
function release (line 115) | void release()
function native_handle_type (line 123) | native_handle_type native_handle() const noexcept
function NES_INLINE_NAMESPACE_BEGIN (line 226) | NES_INLINE_NAMESPACE_BEGIN
class timed_semaphore (line 282) | class timed_semaphore
method timed_semaphore (line 288) | explicit timed_semaphore(std::size_t initial_count = 0)
method timed_semaphore (line 301) | timed_semaphore(const timed_semaphore&) = delete;
method timed_semaphore (line 302) | timed_semaphore& operator=(const timed_semaphore&) = delete;
method timed_semaphore (line 303) | timed_semaphore(timed_semaphore&& other) noexcept = delete;
method timed_semaphore (line 304) | timed_semaphore& operator=(timed_semaphore&& other) noexcept = delete;
method acquire (line 306) | void acquire()
method try_acquire (line 314) | bool try_acquire()
method try_lock_for (line 320) | bool try_lock_for(const std::chrono::duration<Rep, Period>& timeout)
method try_lock_until (line 326) | bool try_lock_until(const std::chrono::time_point<Clock, Duration>& ...
method release (line 338) | void release()
method native_handle_type (line 346) | native_handle_type native_handle() const noexcept
class timed_semaphore (line 138) | class timed_semaphore
method timed_semaphore (line 144) | explicit timed_semaphore(std::size_t initial_count = 0)
method timed_semaphore (line 158) | timed_semaphore(const timed_semaphore&) = delete;
method timed_semaphore (line 159) | timed_semaphore& operator=(const timed_semaphore&) = delete;
method timed_semaphore (line 160) | timed_semaphore(timed_semaphore&& other) noexcept = delete;
method timed_semaphore (line 161) | timed_semaphore& operator=(timed_semaphore&& other) noexcept = delete;
method acquire (line 163) | void acquire()
method try_acquire (line 171) | bool try_acquire()
method try_acquire_for (line 177) | bool try_acquire_for(const std::chrono::duration<Rep, Period>& timeout)
method try_acquire_until (line 183) | bool try_acquire_until(const std::chrono::time_point<Clock, Duration>&...
method release (line 194) | void release()
method native_handle_type (line 202) | native_handle_type native_handle() const noexcept
method get_error_message (line 208) | std::string get_error_message() const
type nes (line 223) | namespace nes
function NES_INLINE_NAMESPACE_BEGIN (line 72) | NES_INLINE_NAMESPACE_BEGIN
function semaphore (line 97) | semaphore(const semaphore&) = delete;
function semaphore (line 99) | semaphore(semaphore&& other) noexcept = delete;
function acquire (line 102) | void acquire()
function try_acquire (line 110) | bool try_acquire()
function release (line 115) | void release()
function native_handle_type (line 123) | native_handle_type native_handle() const noexcept
function NES_INLINE_NAMESPACE_BEGIN (line 226) | NES_INLINE_NAMESPACE_BEGIN
class timed_semaphore (line 282) | class timed_semaphore
method timed_semaphore (line 288) | explicit timed_semaphore(std::size_t initial_count = 0)
method timed_semaphore (line 301) | timed_semaphore(const timed_semaphore&) = delete;
method timed_semaphore (line 302) | timed_semaphore& operator=(const timed_semaphore&) = delete;
method timed_semaphore (line 303) | timed_semaphore(timed_semaphore&& other) noexcept = delete;
method timed_semaphore (line 304) | timed_semaphore& operator=(timed_semaphore&& other) noexcept = delete;
method acquire (line 306) | void acquire()
method try_acquire (line 314) | bool try_acquire()
method try_lock_for (line 320) | bool try_lock_for(const std::chrono::duration<Rep, Period>& timeout)
method try_lock_until (line 326) | bool try_lock_until(const std::chrono::time_point<Clock, Duration>& ...
method release (line 338) | void release()
method native_handle_type (line 346) | native_handle_type native_handle() const noexcept
FILE: include/nes/shared_library.hpp
type nes (line 66) | namespace nes
class shared_library (line 77) | class shared_library
method shared_library (line 83) | constexpr shared_library() noexcept = default;
method shared_library (line 85) | explicit shared_library(load_current_t)
method shared_library (line 94) | explicit shared_library(const std::string& path)
method shared_library (line 115) | shared_library(const shared_library&) = delete;
method shared_library (line 116) | shared_library& operator=(const shared_library&) = delete;
method shared_library (line 118) | shared_library(shared_library&& other) noexcept
method shared_library (line 124) | shared_library& operator=(shared_library&& other) noexcept
method Func (line 133) | Func load(const std::string& symbol) const noexcept
method Func (line 142) | Func* load(const std::string& symbol) const noexcept
method native_handle_type (line 147) | native_handle_type native_handle() const noexcept
method to_wide (line 153) | std::wstring to_wide(std::string path)
method get_error_message (line 173) | std::string get_error_message() const
method shared_library (line 205) | constexpr shared_library() noexcept = default;
method shared_library (line 207) | explicit shared_library(load_current_t)
method shared_library (line 216) | explicit shared_library(const std::string& path)
method shared_library (line 235) | shared_library(const shared_library&) = delete;
method shared_library (line 236) | shared_library& operator=(const shared_library&) = delete;
method shared_library (line 238) | shared_library(shared_library&& other) noexcept
method shared_library (line 243) | shared_library& operator=(shared_library&& other) noexcept
method Func (line 250) | Func load(const std::string& symbol) const noexcept
method Func (line 259) | Func* load(const std::string& symbol) const noexcept
method native_handle_type (line 264) | native_handle_type native_handle() const noexcept
class shared_library (line 199) | class shared_library
method shared_library (line 83) | constexpr shared_library() noexcept = default;
method shared_library (line 85) | explicit shared_library(load_current_t)
method shared_library (line 94) | explicit shared_library(const std::string& path)
method shared_library (line 115) | shared_library(const shared_library&) = delete;
method shared_library (line 116) | shared_library& operator=(const shared_library&) = delete;
method shared_library (line 118) | shared_library(shared_library&& other) noexcept
method shared_library (line 124) | shared_library& operator=(shared_library&& other) noexcept
method Func (line 133) | Func load(const std::string& symbol) const noexcept
method Func (line 142) | Func* load(const std::string& symbol) const noexcept
method native_handle_type (line 147) | native_handle_type native_handle() const noexcept
method to_wide (line 153) | std::wstring to_wide(std::string path)
method get_error_message (line 173) | std::string get_error_message() const
method shared_library (line 205) | constexpr shared_library() noexcept = default;
method shared_library (line 207) | explicit shared_library(load_current_t)
method shared_library (line 216) | explicit shared_library(const std::string& path)
method shared_library (line 235) | shared_library(const shared_library&) = delete;
method shared_library (line 236) | shared_library& operator=(const shared_library&) = delete;
method shared_library (line 238) | shared_library(shared_library&& other) noexcept
method shared_library (line 243) | shared_library& operator=(shared_library&& other) noexcept
method Func (line 250) | Func load(const std::string& symbol) const noexcept
method Func (line 259) | Func* load(const std::string& symbol) const noexcept
method native_handle_type (line 264) | native_handle_type native_handle() const noexcept
type nes (line 188) | namespace nes
class shared_library (line 77) | class shared_library
method shared_library (line 83) | constexpr shared_library() noexcept = default;
method shared_library (line 85) | explicit shared_library(load_current_t)
method shared_library (line 94) | explicit shared_library(const std::string& path)
method shared_library (line 115) | shared_library(const shared_library&) = delete;
method shared_library (line 116) | shared_library& operator=(const shared_library&) = delete;
method shared_library (line 118) | shared_library(shared_library&& other) noexcept
method shared_library (line 124) | shared_library& operator=(shared_library&& other) noexcept
method Func (line 133) | Func load(const std::string& symbol) const noexcept
method Func (line 142) | Func* load(const std::string& symbol) const noexcept
method native_handle_type (line 147) | native_handle_type native_handle() const noexcept
method to_wide (line 153) | std::wstring to_wide(std::string path)
method get_error_message (line 173) | std::string get_error_message() const
method shared_library (line 205) | constexpr shared_library() noexcept = default;
method shared_library (line 207) | explicit shared_library(load_current_t)
method shared_library (line 216) | explicit shared_library(const std::string& path)
method shared_library (line 235) | shared_library(const shared_library&) = delete;
method shared_library (line 236) | shared_library& operator=(const shared_library&) = delete;
method shared_library (line 238) | shared_library(shared_library&& other) noexcept
method shared_library (line 243) | shared_library& operator=(shared_library&& other) noexcept
method Func (line 250) | Func load(const std::string& symbol) const noexcept
method Func (line 259) | Func* load(const std::string& symbol) const noexcept
method native_handle_type (line 264) | native_handle_type native_handle() const noexcept
class shared_library (line 199) | class shared_library
method shared_library (line 83) | constexpr shared_library() noexcept = default;
method shared_library (line 85) | explicit shared_library(load_current_t)
method shared_library (line 94) | explicit shared_library(const std::string& path)
method shared_library (line 115) | shared_library(const shared_library&) = delete;
method shared_library (line 116) | shared_library& operator=(const shared_library&) = delete;
method shared_library (line 118) | shared_library(shared_library&& other) noexcept
method shared_library (line 124) | shared_library& operator=(shared_library&& other) noexcept
method Func (line 133) | Func load(const std::string& symbol) const noexcept
method Func (line 142) | Func* load(const std::string& symbol) const noexcept
method native_handle_type (line 147) | native_handle_type native_handle() const noexcept
method to_wide (line 153) | std::wstring to_wide(std::string path)
method get_error_message (line 173) | std::string get_error_message() const
method shared_library (line 205) | constexpr shared_library() noexcept = default;
method shared_library (line 207) | explicit shared_library(load_current_t)
method shared_library (line 216) | explicit shared_library(const std::string& path)
method shared_library (line 235) | shared_library(const shared_library&) = delete;
method shared_library (line 236) | shared_library& operator=(const shared_library&) = delete;
method shared_library (line 238) | shared_library(shared_library&& other) noexcept
method shared_library (line 243) | shared_library& operator=(shared_library&& other) noexcept
method Func (line 250) | Func load(const std::string& symbol) const noexcept
method Func (line 259) | Func* load(const std::string& symbol) const noexcept
method native_handle_type (line 264) | native_handle_type native_handle() const noexcept
FILE: include/nes/shared_memory.hpp
type nes (line 60) | namespace nes
type shared_memory_options (line 65) | enum class shared_memory_options : std::uint32_t
function shared_memory_options (line 71) | constexpr shared_memory_options operator&(shared_memory_options left, ...
function shared_memory_options (line 76) | constexpr shared_memory_options& operator&=(shared_memory_options& lef...
function shared_memory_options (line 82) | constexpr shared_memory_options operator|(shared_memory_options left, ...
function shared_memory_options (line 87) | constexpr shared_memory_options& operator|=(shared_memory_options& lef...
function shared_memory_options (line 93) | constexpr shared_memory_options operator^(shared_memory_options left, ...
function shared_memory_options (line 98) | constexpr shared_memory_options& operator^=(shared_memory_options& lef...
function shared_memory_options (line 104) | constexpr shared_memory_options operator~(shared_memory_options value)...
type impl (line 109) | namespace impl
function get_allocation_granularity (line 112) | inline std::uintptr_t get_allocation_granularity() noexcept
type is_unbounded_array (line 122) | struct is_unbounded_array : std::false_type
type is_unbounded_array<T[]> (line 127) | struct is_unbounded_array<T[]> : std::true_type
type is_bounded_array (line 132) | struct is_bounded_array : std::false_type
type is_bounded_array<T[N]> (line 137) | struct is_bounded_array<T[N]> : std::true_type
function get_allocation_granularity (line 381) | inline std::uintptr_t get_allocation_granularity() noexcept
type is_unbounded_array (line 389) | struct is_unbounded_array : std::false_type
type is_unbounded_array<T[]> (line 394) | struct is_unbounded_array<T[]> : std::true_type
type is_bounded_array (line 399) | struct is_bounded_array : std::false_type
type is_bounded_array<T[N]> (line 404) | struct is_bounded_array<T[N]> : std::true_type
type map_deleter (line 144) | struct map_deleter
type map_deleter<T[]> (line 156) | struct map_deleter<T[]>
class shared_memory (line 174) | class shared_memory
method shared_memory (line 180) | constexpr shared_memory() noexcept = default;
method shared_memory (line 182) | explicit shared_memory(const std::string& name, std::uint64_t size)
method shared_memory (line 196) | explicit shared_memory(const std::string& name, shared_memory_option...
method shared_memory (line 218) | shared_memory(const shared_memory&) = delete;
method shared_memory (line 219) | shared_memory& operator=(const shared_memory&) = delete;
method shared_memory (line 221) | shared_memory(shared_memory&& other) noexcept
method shared_memory (line 226) | shared_memory& operator=(shared_memory&& other) noexcept
method map (line 234) | unique_map_t<T> map(std::uint64_t offset, shared_memory_options opti...
method shared_map (line 256) | shared_map_t<T> shared_map(std::uint64_t offset, shared_memory_optio...
method map (line 262) | unique_map_t<T> map(std::uint64_t offset, std::size_t count, shared_...
method shared_map (line 285) | shared_map_t<T> shared_map(std::uint64_t offset, std::size_t count, ...
method native_handle_type (line 290) | native_handle_type native_handle() const noexcept
method to_wide (line 296) | std::wstring to_wide(const std::string& path)
method get_error_message (line 316) | std::string get_error_message() const
method shared_memory (line 453) | constexpr shared_memory() noexcept = default;
method shared_memory (line 455) | explicit shared_memory(const std::string& name, std::uint64_t size)
method shared_memory (line 475) | explicit shared_memory(const std::string& name, shared_memory_option...
method shared_memory (line 497) | shared_memory(const shared_memory&) = delete;
method shared_memory (line 498) | shared_memory& operator=(const shared_memory&) = delete;
method shared_memory (line 500) | shared_memory(shared_memory&& other) noexcept
method shared_memory (line 505) | shared_memory& operator=(shared_memory&& other) noexcept
method map (line 513) | unique_map_t<T> map(std::uint64_t offset, shared_memory_options opti...
method shared_map (line 535) | shared_map_t<T> shared_map(std::uint64_t offset, shared_memory_optio...
method map (line 541) | unique_map_t<T> map(std::uint64_t offset, std::size_t count, shared_...
method shared_map (line 564) | shared_map_t<T> shared_map(std::uint64_t offset, std::size_t count, ...
method native_handle_type (line 569) | native_handle_type native_handle() const noexcept
type shared_memory_options (line 334) | enum class shared_memory_options : std::uint32_t
function shared_memory_options (line 340) | constexpr shared_memory_options operator&(shared_memory_options left, ...
function shared_memory_options (line 345) | constexpr shared_memory_options& operator&=(shared_memory_options& lef...
function shared_memory_options (line 351) | constexpr shared_memory_options operator|(shared_memory_options left, ...
function shared_memory_options (line 356) | constexpr shared_memory_options& operator|=(shared_memory_options& lef...
function shared_memory_options (line 362) | constexpr shared_memory_options operator^(shared_memory_options left, ...
function shared_memory_options (line 367) | constexpr shared_memory_options& operator^=(shared_memory_options& lef...
function shared_memory_options (line 373) | constexpr shared_memory_options operator~(shared_memory_options value)...
type impl (line 378) | namespace impl
function get_allocation_granularity (line 112) | inline std::uintptr_t get_allocation_granularity() noexcept
type is_unbounded_array (line 122) | struct is_unbounded_array : std::false_type
type is_unbounded_array<T[]> (line 127) | struct is_unbounded_array<T[]> : std::true_type
type is_bounded_array (line 132) | struct is_bounded_array : std::false_type
type is_bounded_array<T[N]> (line 137) | struct is_bounded_array<T[N]> : std::true_type
function get_allocation_granularity (line 381) | inline std::uintptr_t get_allocation_granularity() noexcept
type is_unbounded_array (line 389) | struct is_unbounded_array : std::false_type
type is_unbounded_array<T[]> (line 394) | struct is_unbounded_array<T[]> : std::true_type
type is_bounded_array (line 399) | struct is_bounded_array : std::false_type
type is_bounded_array<T[N]> (line 404) | struct is_bounded_array<T[N]> : std::true_type
type map_deleter (line 411) | struct map_deleter
type map_deleter<T[]> (line 425) | struct map_deleter<T[]>
class shared_memory (line 447) | class shared_memory
method shared_memory (line 180) | constexpr shared_memory() noexcept = default;
method shared_memory (line 182) | explicit shared_memory(const std::string& name, std::uint64_t size)
method shared_memory (line 196) | explicit shared_memory(const std::string& name, shared_memory_option...
method shared_memory (line 218) | shared_memory(const shared_memory&) = delete;
method shared_memory (line 219) | shared_memory& operator=(const shared_memory&) = delete;
method shared_memory (line 221) | shared_memory(shared_memory&& other) noexcept
method shared_memory (line 226) | shared_memory& operator=(shared_memory&& other) noexcept
method map (line 234) | unique_map_t<T> map(std::uint64_t offset, shared_memory_options opti...
method shared_map (line 256) | shared_map_t<T> shared_map(std::uint64_t offset, shared_memory_optio...
method map (line 262) | unique_map_t<T> map(std::uint64_t offset, std::size_t count, shared_...
method shared_map (line 285) | shared_map_t<T> shared_map(std::uint64_t offset, std::size_t count, ...
method native_handle_type (line 290) | native_handle_type native_handle() const noexcept
method to_wide (line 296) | std::wstring to_wide(const std::string& path)
method get_error_message (line 316) | std::string get_error_message() const
method shared_memory (line 453) | constexpr shared_memory() noexcept = default;
method shared_memory (line 455) | explicit shared_memory(const std::string& name, std::uint64_t size)
method shared_memory (line 475) | explicit shared_memory(const std::string& name, shared_memory_option...
method shared_memory (line 497) | shared_memory(const shared_memory&) = delete;
method shared_memory (line 498) | shared_memory& operator=(const shared_memory&) = delete;
method shared_memory (line 500) | shared_memory(shared_memory&& other) noexcept
method shared_memory (line 505) | shared_memory& operator=(shared_memory&& other) noexcept
method map (line 513) | unique_map_t<T> map(std::uint64_t offset, shared_memory_options opti...
method shared_map (line 535) | shared_map_t<T> shared_map(std::uint64_t offset, shared_memory_optio...
method map (line 541) | unique_map_t<T> map(std::uint64_t offset, std::size_t count, shared_...
method shared_map (line 564) | shared_map_t<T> shared_map(std::uint64_t offset, std::size_t count, ...
method native_handle_type (line 569) | native_handle_type native_handle() const noexcept
type nes (line 329) | namespace nes
type shared_memory_options (line 65) | enum class shared_memory_options : std::uint32_t
function shared_memory_options (line 71) | constexpr shared_memory_options operator&(shared_memory_options left, ...
function shared_memory_options (line 76) | constexpr shared_memory_options& operator&=(shared_memory_options& lef...
function shared_memory_options (line 82) | constexpr shared_memory_options operator|(shared_memory_options left, ...
function shared_memory_options (line 87) | constexpr shared_memory_options& operator|=(shared_memory_options& lef...
function shared_memory_options (line 93) | constexpr shared_memory_options operator^(shared_memory_options left, ...
function shared_memory_options (line 98) | constexpr shared_memory_options& operator^=(shared_memory_options& lef...
function shared_memory_options (line 104) | constexpr shared_memory_options operator~(shared_memory_options value)...
type impl (line 109) | namespace impl
function get_allocation_granularity (line 112) | inline std::uintptr_t get_allocation_granularity() noexcept
type is_unbounded_array (line 122) | struct is_unbounded_array : std::false_type
type is_unbounded_array<T[]> (line 127) | struct is_unbounded_array<T[]> : std::true_type
type is_bounded_array (line 132) | struct is_bounded_array : std::false_type
type is_bounded_array<T[N]> (line 137) | struct is_bounded_array<T[N]> : std::true_type
function get_allocation_granularity (line 381) | inline std::uintptr_t get_allocation_granularity() noexcept
type is_unbounded_array (line 389) | struct is_unbounded_array : std::false_type
type is_unbounded_array<T[]> (line 394) | struct is_unbounded_array<T[]> : std::true_type
type is_bounded_array (line 399) | struct is_bounded_array : std::false_type
type is_bounded_array<T[N]> (line 404) | struct is_bounded_array<T[N]> : std::true_type
type map_deleter (line 144) | struct map_deleter
type map_deleter<T[]> (line 156) | struct map_deleter<T[]>
class shared_memory (line 174) | class shared_memory
method shared_memory (line 180) | constexpr shared_memory() noexcept = default;
method shared_memory (line 182) | explicit shared_memory(const std::string& name, std::uint64_t size)
method shared_memory (line 196) | explicit shared_memory(const std::string& name, shared_memory_option...
method shared_memory (line 218) | shared_memory(const shared_memory&) = delete;
method shared_memory (line 219) | shared_memory& operator=(const shared_memory&) = delete;
method shared_memory (line 221) | shared_memory(shared_memory&& other) noexcept
method shared_memory (line 226) | shared_memory& operator=(shared_memory&& other) noexcept
method map (line 234) | unique_map_t<T> map(std::uint64_t offset, shared_memory_options opti...
method shared_map (line 256) | shared_map_t<T> shared_map(std::uint64_t offset, shared_memory_optio...
method map (line 262) | unique_map_t<T> map(std::uint64_t offset, std::size_t count, shared_...
method shared_map (line 285) | shared_map_t<T> shared_map(std::uint64_t offset, std::size_t count, ...
method native_handle_type (line 290) | native_handle_type native_handle() const noexcept
method to_wide (line 296) | std::wstring to_wide(const std::string& path)
method get_error_message (line 316) | std::string get_error_message() const
method shared_memory (line 453) | constexpr shared_memory() noexcept = default;
method shared_memory (line 455) | explicit shared_memory(const std::string& name, std::uint64_t size)
method shared_memory (line 475) | explicit shared_memory(const std::string& name, shared_memory_option...
method shared_memory (line 497) | shared_memory(const shared_memory&) = delete;
method shared_memory (line 498) | shared_memory& operator=(const shared_memory&) = delete;
method shared_memory (line 500) | shared_memory(shared_memory&& other) noexcept
method shared_memory (line 505) | shared_memory& operator=(shared_memory&& other) noexcept
method map (line 513) | unique_map_t<T> map(std::uint64_t offset, shared_memory_options opti...
method shared_map (line 535) | shared_map_t<T> shared_map(std::uint64_t offset, shared_memory_optio...
method map (line 541) | unique_map_t<T> map(std::uint64_t offset, std::size_t count, shared_...
method shared_map (line 564) | shared_map_t<T> shared_map(std::uint64_t offset, std::size_t count, ...
method native_handle_type (line 569) | native_handle_type native_handle() const noexcept
type shared_memory_options (line 334) | enum class shared_memory_options : std::uint32_t
function shared_memory_options (line 340) | constexpr shared_memory_options operator&(shared_memory_options left, ...
function shared_memory_options (line 345) | constexpr shared_memory_options& operator&=(shared_memory_options& lef...
function shared_memory_options (line 351) | constexpr shared_memory_options operator|(shared_memory_options left, ...
function shared_memory_options (line 356) | constexpr shared_memory_options& operator|=(shared_memory_options& lef...
function shared_memory_options (line 362) | constexpr shared_memory_options operator^(shared_memory_options left, ...
function shared_memory_options (line 367) | constexpr shared_memory_options& operator^=(shared_memory_options& lef...
function shared_memory_options (line 373) | constexpr shared_memory_options operator~(shared_memory_options value)...
type impl (line 378) | namespace impl
function get_allocation_granularity (line 112) | inline std::uintptr_t get_allocation_granularity() noexcept
type is_unbounded_array (line 122) | struct is_unbounded_array : std::false_type
type is_unbounded_array<T[]> (line 127) | struct is_unbounded_array<T[]> : std::true_type
type is_bounded_array (line 132) | struct is_bounded_array : std::false_type
type is_bounded_array<T[N]> (line 137) | struct is_bounded_array<T[N]> : std::true_type
function get_allocation_granularity (line 381) | inline std::uintptr_t get_allocation_granularity() noexcept
type is_unbounded_array (line 389) | struct is_unbounded_array : std::false_type
type is_unbounded_array<T[]> (line 394) | struct is_unbounded_array<T[]> : std::true_type
type is_bounded_array (line 399) | struct is_bounded_array : std::false_type
type is_bounded_array<T[N]> (line 404) | struct is_bounded_array<T[N]> : std::true_type
type map_deleter (line 411) | struct map_deleter
type map_deleter<T[]> (line 425) | struct map_deleter<T[]>
class shared_memory (line 447) | class shared_memory
method shared_memory (line 180) | constexpr shared_memory() noexcept = default;
method shared_memory (line 182) | explicit shared_memory(const std::string& name, std::uint64_t size)
method shared_memory (line 196) | explicit shared_memory(const std::string& name, shared_memory_option...
method shared_memory (line 218) | shared_memory(const shared_memory&) = delete;
method shared_memory (line 219) | shared_memory& operator=(const shared_memory&) = delete;
method shared_memory (line 221) | shared_memory(shared_memory&& other) noexcept
method shared_memory (line 226) | shared_memory& operator=(shared_memory&& other) noexcept
method map (line 234) | unique_map_t<T> map(std::uint64_t offset, shared_memory_options opti...
method shared_map (line 256) | shared_map_t<T> shared_map(std::uint64_t offset, shared_memory_optio...
method map (line 262) | unique_map_t<T> map(std::uint64_t offset, std::size_t count, shared_...
method shared_map (line 285) | shared_map_t<T> shared_map(std::uint64_t offset, std::size_t count, ...
method native_handle_type (line 290) | native_handle_type native_handle() const noexcept
method to_wide (line 296) | std::wstring to_wide(const std::string& path)
method get_error_message (line 316) | std::string get_error_message() const
method shared_memory (line 453) | constexpr shared_memory() noexcept = default;
method shared_memory (line 455) | explicit shared_memory(const std::string& name, std::uint64_t size)
method shared_memory (line 475) | explicit shared_memory(const std::string& name, shared_memory_option...
method shared_memory (line 497) | shared_memory(const shared_memory&) = delete;
method shared_memory (line 498) | shared_memory& operator=(const shared_memory&) = delete;
method shared_memory (line 500) | shared_memory(shared_memory&& other) noexcept
method shared_memory (line 505) | shared_memory& operator=(shared_memory&& other) noexcept
method map (line 513) | unique_map_t<T> map(std::uint64_t offset, shared_memory_options opti...
method shared_map (line 535) | shared_map_t<T> shared_map(std::uint64_t offset, shared_memory_optio...
method map (line 541) | unique_map_t<T> map(std::uint64_t offset, std::size_t count, shared_...
method shared_map (line 564) | shared_map_t<T> shared_map(std::uint64_t offset, std::size_t count, ...
method native_handle_type (line 569) | native_handle_type native_handle() const noexcept
FILE: include/nes/thread_pool.hpp
type nes (line 55) | namespace nes
function NES_INLINE_NAMESPACE_BEGIN (line 58) | NES_INLINE_NAMESPACE_BEGIN
class task_result (line 430) | class task_result
method task_result (line 435) | task_result() = default;
method task_result (line 437) | task_result(const task_result&) = delete;
method task_result (line 438) | task_result& operator=(const task_result&) = delete;
method task_result (line 440) | task_result(task_result&& other) noexcept
method task_result (line 445) | task_result& operator=(task_result&& other) noexcept
method T (line 452) | T get()
method valid (line 457) | bool valid() const noexcept
method wait (line 462) | void wait() const
method wait_for (line 468) | bool wait_for(const std::chrono::duration<Rep, Period>& timeout) const
method wait_until (line 474) | bool wait_until(const std::chrono::duration<Rep, Period>& timeout) c...
class task_fence (line 485) | class task_fence
method task_fence (line 490) | task_fence() = default;
method task_fence (line 492) | task_fence(const task_fence&) = delete;
method task_fence (line 493) | task_fence& operator=(const task_fence&) = delete;
method task_fence (line 495) | task_fence(task_fence&& other) noexcept
method task_fence (line 500) | task_fence& operator=(task_fence&& other) noexcept
method signal (line 507) | void signal() noexcept
class task_list (line 516) | class task_list
method task_list (line 522) | constexpr task_list() = default;
method task_list (line 524) | task_list(const task_list&) = delete;
method task_list (line 525) | task_list& operator=(const task_list&) = delete;
method task_list (line 526) | task_list(task_list&&) = default;
method task_list (line 527) | task_list& operator=(task_list&&) = default;
method reset (line 530) | void reset(std::condition_variable& condition)
method next (line 555) | std::pair<bool, std::size_t> next(OutputIt output)
class task_builder (line 601) | class task_builder
method task_builder (line 604) | explicit task_builder(std::uint32_t thread_count = std::thread::hard...
method task_builder (line 611) | task_builder(const task_builder&) = delete;
method task_builder (line 612) | task_builder& operator=(const task_builder&) = delete;
method task_builder (line 613) | task_builder(task_builder&&) = default;
method task_builder (line 614) | task_builder& operator=(task_builder&&) = default;
method execute (line 617) | void execute(Func&& func, Args&&... args)
method invoke (line 626) | [[nodiscard("Use execute instead of invoke when the returned future ...
method dispatch (line 644) | void dispatch(std::uint32_t x, std::uint32_t y, std::uint32_t z, Fun...
method dispatch (line 650) | void dispatch(std::uint32_t x, std::uint32_t y, std::uint32_t z, std...
method task_checkpoint (line 731) | task_checkpoint barrier()
method task_checkpoint (line 739) | [[nodiscard]] task_checkpoint checkpoint()
method task_fence (line 747) | [[nodiscard]] task_fence fence()
method task_list (line 755) | task_list build()
method push_task (line 801) | void push_task(Args&&... args)
method flush (line 807) | void flush(std::vector<impl::task_type>& output, CheckpointIt checkp...
method count_checkpoints (line 842) | std::size_t count_checkpoints() const noexcept
class thread_pool (line 855) | class thread_pool
method thread_pool (line 858) | explicit thread_pool(std::size_t thread_count = std::thread::hardwar...
method thread_pool (line 900) | thread_pool(const thread_pool&) = delete;
method thread_pool (line 901) | thread_pool& operator=(const thread_pool&) = delete;
method thread_pool (line 902) | thread_pool(thread_pool&&) = delete;
method thread_pool (line 903) | thread_pool& operator=(thread_pool&&) = delete;
method execute (line 906) | void execute(Func&& func, Args&&... args)
method invoke (line 917) | [[nodiscard("Use execute instead of invoke when the returned future ...
method push (line 948) | std::future<task_list> push(task_list&& list)
method wait_idle (line 971) | void wait_idle()
method thread_count (line 980) | std::size_t thread_count() const noexcept
method worker_main (line 986) | void worker_main()
method push_impl (line 1033) | void push_impl(Func&& func)
method update_task_lists (line 1040) | std::size_t update_task_lists()
type task_list_data (line 1074) | struct task_list_data
FILE: tests/common.hpp
type data_type (line 48) | enum class data_type : std::uint32_t
function data_type_to_string (line 55) | inline std::string data_type_to_string(data_type type)
FILE: tests/library.cpp
function NES_EXPORT (line 10) | NES_EXPORT std::int32_t nes_lib_func()
FILE: tests/process.cpp
function shared_library_test (line 30) | static void shared_library_test()
function a_thread (line 41) | static void a_thread(nes::basic_pipe_istream<char>& is) noexcept
function pipe_test (line 83) | static void pipe_test()
function another_thread (line 123) | static void another_thread(const std::array<std::uint32_t, 8>& data, nes...
function semaphore_test (line 133) | static void semaphore_test()
function named_pipe_test (line 152) | static void named_pipe_test()
function process_test (line 187) | static void process_test()
function process_kill_test (line 201) | static void process_kill_test()
function shared_memory_test (line 209) | static void shared_memory_test()
function named_mutex_test (line 236) | static void named_mutex_test()
function timed_named_mutex_test (line 251) | static void timed_named_mutex_test()
function named_semaphore_test (line 266) | static void named_semaphore_test()
function main (line 283) | int main()
FILE: tests/process_other.cpp
function to_infinity_and_beyond (line 12) | [[noreturn]] static void to_infinity_and_beyond()
function named_pipe (line 20) | static void named_pipe()
function shared_memory (line 53) | static void shared_memory()
function shared_memory_bad (line 67) | static void shared_memory_bad()
function named_mutex (line 74) | static void named_mutex()
function timed_named_mutex (line 80) | static void timed_named_mutex()
function named_semaphore (line 89) | static void named_semaphore()
function main (line 99) | int main(int argc, char** argv)
FILE: tests/thread_pool_test.cpp
function smoke_test (line 7) | static void smoke_test()
function main (line 51) | int main()
Condensed preview — 20 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (207K chars).
[
{
"path": ".clang-format",
"chars": 4541,
"preview": "Language: Cpp\nAccessModifierOffset: -4\nAlignAfterOpenBracket: DontAlign\nAlignArrayOfStructures: Left\nAlignConsecutiveAss"
},
{
"path": ".github/workflows/common.yml",
"chars": 1139,
"preview": "name: CI\n\non:\n push:\n branches: [ \"master\" ]\n pull_request:\n branches: [ \"master\" ]\n\nenv:\n BUILD_TYPE: Debug\n\nj"
},
{
"path": ".gitignore",
"chars": 302,
"preview": "# Prerequisites\n*.d\n\n# Compiled Object files\n*.slo\n*.lo\n*.o\n*.obj\n\n# Precompiled Headers\n*.gch\n*.pch\n\n# Compiled Dynamic"
},
{
"path": "CMakeLists.txt",
"chars": 3181,
"preview": "cmake_minimum_required(VERSION 3.23) # required for file sets\r\n\r\nproject(NotEnoughStandards VERSION 1.1.0)\r\n\r\nif(${CMAKE"
},
{
"path": "LICENSE",
"chars": 1073,
"preview": "MIT License\n\nCopyright (c) 2019 Alexy Pellegrini\n\nPermission is hereby granted, free of charge, to any person obtaining "
},
{
"path": "README.md",
"chars": 4060,
"preview": "# Not Enough Standards\n\nNot Enough Standards is a modern header-only C++17 and C++20 library that provides platform-inde"
},
{
"path": "cmake/NotEnoughStandards.cmake.in",
"chars": 129,
"preview": "@PACKAGE_INIT@\n\ninclude(\"${CMAKE_CURRENT_LIST_DIR}/NotEnoughStandardsTargets.cmake\")\ncheck_required_components(\"@PROJECT"
},
{
"path": "include/nes/named_mutex.hpp",
"chars": 16507,
"preview": "///////////////////////////////////////////////////////////\r\n/// Copyright 2019 Alexy Pellegrini\r\n///\r\n/// Permission is"
},
{
"path": "include/nes/named_semaphore.hpp",
"chars": 12797,
"preview": "///////////////////////////////////////////////////////////\r\n/// Copyright 2019 Alexy Pellegrini\r\n///\r\n/// Permission is"
},
{
"path": "include/nes/pipe.hpp",
"chars": 30701,
"preview": "///////////////////////////////////////////////////////////\r\n/// Copyright 2019 Alexy Pellegrini\r\n///\r\n/// Permission is"
},
{
"path": "include/nes/process.hpp",
"chars": 32373,
"preview": "///////////////////////////////////////////////////////////\r\n/// Copyright 2019 Alexy Pellegrini\r\n///\r\n/// Permission is"
},
{
"path": "include/nes/semaphore.hpp",
"chars": 9776,
"preview": "///////////////////////////////////////////////////////////\r\n/// Copyright 2019 Alexy Pellegrini\r\n///\r\n/// Permission is"
},
{
"path": "include/nes/shared_library.hpp",
"chars": 8090,
"preview": "///////////////////////////////////////////////////////////\r\n/// Copyright 2019 Alexy Pellegrini\r\n///\r\n/// Permission is"
},
{
"path": "include/nes/shared_memory.hpp",
"chars": 20707,
"preview": "///////////////////////////////////////////////////////////\r\n/// Copyright 2019 Alexy Pellegrini\r\n///\r\n/// Permission is"
},
{
"path": "include/nes/thread_pool.hpp",
"chars": 29739,
"preview": "///////////////////////////////////////////////////////////\n/// Copyright 2020 Alexy Pellegrini\n///\n/// Permission is he"
},
{
"path": "tests/common.hpp",
"chars": 2623,
"preview": "///////////////////////////////////////////////////////////\n/// Copyright 2019 Alexy Pellegrini\n///\n/// Permission is he"
},
{
"path": "tests/library.cpp",
"chars": 236,
"preview": "#include <cstdint>\n\n#ifdef _WIN32\n #define NES_EXPORT __declspec(dllexport)\n#else\n #define NES_EXPORT\n#endif\n\nexte"
},
{
"path": "tests/process.cpp",
"chars": 10475,
"preview": "#include <iostream>\n#include <thread>\n#include <mutex>\n#include <shared_mutex>\n#include <iterator>\n#include <iomanip>\n#i"
},
{
"path": "tests/process_other.cpp",
"chars": 4056,
"preview": "#include <iostream>\n#include <mutex>\n#include <thread>\n\n#include <nes/process.hpp>\n#include <nes/shared_memory.hpp>\n#inc"
},
{
"path": "tests/thread_pool_test.cpp",
"chars": 1727,
"preview": "#include <array>\n\n#include <nes/thread_pool.hpp>\n\n#include \"common.hpp\"\n\nstatic void smoke_test()\n{\n static constexpr"
}
]
About this extraction
This page contains the full source code of the Alairion/not-enough-standards GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 20 files (189.7 KB), approximately 45.0k tokens, and a symbol index with 530 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.