diff --git a/.gdbinit b/.gdbinit new file mode 100644 index 0000000..bdf921c --- /dev/null +++ b/.gdbinit @@ -0,0 +1,7 @@ +python +import sys +import os +sys.path.insert(0, os.path.join(os.getcwd(), 'debug')) +import gdbinit +print("GDB pretty-printer for original initialized.") +end \ No newline at end of file diff --git a/.github/workflows/basic-tests.yml b/.github/workflows/basic-tests.yml index cd7de7d..074599e 100644 --- a/.github/workflows/basic-tests.yml +++ b/.github/workflows/basic-tests.yml @@ -3,7 +3,7 @@ name: Test Branch CI - Basic Tests on: - push: + pull_request: branches: [ test ] jobs: diff --git a/.github/workflows/deploy-docs-existing-tags.yml b/.github/workflows/deploy-docs-existing-tags.yml deleted file mode 100644 index 2f942f5..0000000 --- a/.github/workflows/deploy-docs-existing-tags.yml +++ /dev/null @@ -1,116 +0,0 @@ -# .github/workflows/deploy-docs-existing-tags.yml -name: Deploy Documentation - Existing Tags - -on: - push: - branches: - - test # 监听 test 分支 push - -jobs: - build-and-deploy: - runs-on: ubuntu-latest - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Install dependencies - run: | - sudo apt-get update - sudo apt-get install -y doxygen graphviz plantuml jq - - - name: Set tags to deploy - id: tags - run: | - # 一次性部署的指定 tags - TAGS="v0.1.0 v0.1.2 v0.1.4" - echo "tags=$TAGS" >> $GITHUB_OUTPUT - echo "Deploying tags: $TAGS" - - - name: Build and deploy documentation - env: - GH_PAT: ${{ secrets.GH_PAT }} - TAGS: ${{ steps.tags.outputs.tags }} - run: | - git config --global user.name "github-actions[bot]" - git config --global user.email "github-actions[bot]@users.noreply.github.com" - - # 克隆文档仓库 - git clone -b master https://$GH_PAT@github.com/FrozenLemonTee/original_docs.git deploy-repo - - for TAG in $TAGS; do - echo "Processing tag: $TAG" - - # 检出 tag - git checkout $TAG || { echo "Tag $TAG not found"; continue; } - - # 提取版本号 - VERSION=${TAG#v} - - # 清理并创建文档目录 - mkdir -p ../original_docs/docs/html - doxygen Doxyfile > doxygen.log 2>&1 - - # 检查 HTML 是否生成 - if [ ! -d "../original_docs/docs/html" ]; then - echo "Warning: Documentation not generated for $TAG" - continue - fi - - # 创建版本信息文件 - echo '' > ../original_docs/docs/html/version.html - echo 'Version Info' >> ../original_docs/docs/html/version.html - echo "

Documentation Version

" >> ../original_docs/docs/html/version.html - echo "

Version: $VERSION

" >> ../original_docs/docs/html/version.html - echo "

Tag: $TAG

" >> ../original_docs/docs/html/version.html - echo "

Build Date: $(date -u)

" >> ../original_docs/docs/html/version.html - echo "

Commit: $(git rev-parse $TAG)

" >> ../original_docs/docs/html/version.html - echo '' >> ../original_docs/docs/html/version.html - - # 部署到文档仓库 - cd deploy-repo - mkdir -p versions - VERSION_DIR="versions/$VERSION" - rm -rf "$VERSION_DIR" - mkdir -p "$VERSION_DIR" - cp -r ../../original_docs/docs/html/* "$VERSION_DIR"/ - cd .. - done - - # 更新主 index.html 和 versions/index.html - cd deploy-repo - - echo '' > index.html - echo '' >> index.html - echo '

Redirecting to stable documentation...

' >> index.html - echo '

Available versions:

Recent tag versions:

' >> index.html - - # versions/index.html - echo '' > versions/index.html - echo 'Versioned Documentation' >> versions/index.html - echo '

Versioned Documentation

Select a version:

Stable (master branch)

' >> versions/index.html - echo '

Latest (test branch)

' >> versions/index.html - - # 提交推送 - git add . - if git diff-index --quiet HEAD --; then - echo "No changes to deploy" - else - git commit -m "Deploy documentation for tags $TAGS" - git push origin master - echo "✅ Documentation deployed successfully for tags $TAGS" - fi diff --git a/.github/workflows/deploy-docs-latest.yml b/.github/workflows/deploy-docs-latest.yml index a25ed8a..a136c01 100644 --- a/.github/workflows/deploy-docs-latest.yml +++ b/.github/workflows/deploy-docs-latest.yml @@ -4,10 +4,11 @@ name: Deploy Documentation - Latest on: push: - branches: [ master ] # Temporary change from test to master to avoid concurrency push + branches: [ test ] jobs: build-and-deploy: + if: github.repository == 'FrozenLemonTee/original' runs-on: ubuntu-latest steps: diff --git a/.github/workflows/deploy-docs-stable.yml b/.github/workflows/deploy-docs-stable.yml index 0b41a78..1b88f99 100644 --- a/.github/workflows/deploy-docs-stable.yml +++ b/.github/workflows/deploy-docs-stable.yml @@ -5,9 +5,12 @@ name: Deploy Documentation - Stable on: push: branches: [ master ] + tags: + - 'v*.*.*' jobs: build-and-deploy: + if: github.repository == 'FrozenLemonTee/original' runs-on: ubuntu-latest steps: @@ -45,7 +48,7 @@ jobs: echo '' >> ../original_docs/docs/html/version.html echo '

Documentation Version

' >> ../original_docs/docs/html/version.html echo '

Version: stable

' >> ../original_docs/docs/html/version.html - echo '

Branch: master

' >> index.html + echo '

Branch: master

' >> ../original_docs/docs/html/version.html echo "

Build Date: $(date -u)

" >> ../original_docs/docs/html/version.html echo "

Commit: ${{ github.sha }}

" >> ../original_docs/docs/html/version.html echo '' >> ../original_docs/docs/html/version.html @@ -64,12 +67,12 @@ jobs: cd deploy-repo - # Only update stable directory + # Update stable directory rm -rf stable mkdir -p stable cp -r ../../original_docs/docs/html/* stable/ - # Create index.html redirection + # Regenerate the main index.html to include the latest tag version echo '' > index.html echo '' >> index.html echo '' >> index.html @@ -82,16 +85,47 @@ jobs: echo '
  • Stable (master branch)
  • ' >> index.html echo '
  • Latest (test branch)
  • ' >> index.html echo '
  • Tag versions
  • ' >> index.html + echo ' ' >> index.html + echo '

    Recent tag versions:

    ' >> index.html + echo ' ' >> index.html echo '' >> index.html echo '' >> index.html + # Also update versions/index.html to ensure that the list of all versions is up to date + echo '' > versions/index.html + echo '' >> versions/index.html + echo '' >> versions/index.html + echo ' Versioned Documentation' >> versions/index.html + echo '' >> versions/index.html + echo '' >> versions/index.html + echo '

    Versioned Documentation

    ' >> versions/index.html + echo '

    Select a version:

    ' >> versions/index.html + echo ' ' >> versions/index.html + echo '

    Stable (master branch)

    ' >> versions/index.html + echo '

    Latest (test branch)

    ' >> versions/index.html + echo '' >> versions/index.html + echo '' >> versions/index.html + # Submit and push git add . if git diff-index --quiet HEAD --; then echo "No changes to deploy" else - git commit -m "Deploy ${{ steps.version.outputs.docs-version }} documentation from ${{ github.sha }}" + git commit -m "Deploy stable documentation from ${{ github.sha }} and update version lists" git push origin master - echo "✅ Stable documentation deployed successfully" + echo "✅ Stable documentation deployed successfully with updated version lists" fi \ No newline at end of file diff --git a/.github/workflows/deploy-docs-tags.yml b/.github/workflows/deploy-docs-tags.yml index c56feac..2666f9c 100644 --- a/.github/workflows/deploy-docs-tags.yml +++ b/.github/workflows/deploy-docs-tags.yml @@ -9,6 +9,7 @@ on: jobs: build-and-deploy: + if: github.repository == 'FrozenLemonTee/original' runs-on: ubuntu-latest steps: diff --git a/.github/workflows/full-tests.yml b/.github/workflows/full-tests.yml index 79ca7db..a175a66 100644 --- a/.github/workflows/full-tests.yml +++ b/.github/workflows/full-tests.yml @@ -56,7 +56,7 @@ jobs: - name: Run tests run: | - cd build && ctest --output-on-failure + cd build && ctest --verbose --output-on-failure windows-tests: runs-on: windows-latest @@ -75,4 +75,4 @@ jobs: - name: Run tests run: | - cd build && ctest -C ${{ matrix.build_type }} --output-on-failure \ No newline at end of file + cd build && ctest --verbose -C ${{ matrix.build_type }} --output-on-failure \ No newline at end of file diff --git a/.gitignore b/.gitignore index 5b69209..6792be8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,13 @@ -cmake-build-debug/ -.idea/ -test.exe -original.zip -original.rar +cmake-build-*/ +**/.idea/ build/ install/ .vs/ +.vscode/ out/ -original/ \ No newline at end of file +original/ +**/__pycache__/ + +test.exe +original.zip +original.rar \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index bcdefab..54f0e5a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,12 +1,48 @@ # CMakeLists.txt Main cmake_minimum_required(VERSION 3.31) +if(CMAKE_GENERATOR MATCHES "Visual Studio" OR CMAKE_GENERATOR MATCHES "Ninja Multi-Config") + set(CMAKE_GENERATOR_PLATFORM x64 CACHE STRING "Platform" FORCE) +endif() project(original LANGUAGES CXX) set(ORIGINAL_VERSION 0.1.5) set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD_REQUIRED True) +set(CMAKE_CXX_EXTENSIONS OFF) + +if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 13.0) + message(FATAL_ERROR "GCC version too old. Minimum required: 13.0. Current: ${CMAKE_CXX_COMPILER_VERSION}") + else() + message(STATUS "GCC version: ${CMAKE_CXX_COMPILER_VERSION} (>= 13.0 ✓)") + endif() +endif() + +if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 20.0) + message(FATAL_ERROR "Clang version too old. Minimum required: 20.0. Current: ${CMAKE_CXX_COMPILER_VERSION}") + else() + message(STATUS "Clang version: ${CMAKE_CXX_COMPILER_VERSION} (>= 20.0 ✓)") + endif() +endif() +if(MSVC) + if(MSVC_VERSION LESS 1944) + message(FATAL_ERROR "MSVC version too old. Minimum required: 14.44.35207 (VS2022 17.10+). Current: ${MSVC_VERSION}") + else() + message(STATUS "MSVC version: ${MSVC_VERSION} (>= 14.44 ✓)") + endif() + set(CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION "10.0" CACHE STRING "Windows Target Platform Version") +endif() +if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + include(CheckCXXCompilerFlag) + check_cxx_compiler_flag("-std=c++23" HAS_CXX23_FLAG) + if(NOT HAS_CXX23_FLAG) + message(WARNING "Compiler may not fully support C++23 standard") + endif() +endif() + if (NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE Debug CACHE STRING "Build type (default Debug)" FORCE) + set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type (default Release)" FORCE) endif() include(CMakePackageConfigHelpers) @@ -69,24 +105,12 @@ install(FILES DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/original ) +add_subdirectory(debug) + option(BUILD_TESTING "Build the testing directories" ON) if (BUILD_TESTING) include(CTest) - if(MSVC) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zi") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Zi") - else() - if (NOT CMAKE_SYSTEM_NAME STREQUAL "Windows") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -g") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -g") - else() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g") - endif() - endif() - - # test cases - add_subdirectory(test/other) - add_subdirectory(test/unit_test) + enable_testing() + add_subdirectory(test) endif () \ No newline at end of file diff --git a/debug/CMakeLists.txt b/debug/CMakeLists.txt new file mode 100644 index 0000000..2843c8d --- /dev/null +++ b/debug/CMakeLists.txt @@ -0,0 +1,42 @@ +# debug/CMakeLists.txt + +if(CMAKE_BUILD_TYPE MATCHES "Debug") + if(CMAKE_CXX_COMPILER_ID MATCHES "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "MinGW") + message(STATUS "[GDB CONFIG] Detected GNU/MinGW toolchain, setting up GDB auto-load permissions") + + if(WIN32) + file(TO_CMAKE_PATH "$ENV{USERPROFILE}" USER_HOME) + else() + file(TO_CMAKE_PATH "$ENV{HOME}" USER_HOME) + endif() + + set(GDB_GLOBAL_INIT "${USER_HOME}/.config/gdb/gdbinit") + if(NOT EXISTS "${GDB_GLOBAL_INIT}") + set(GDB_GLOBAL_INIT "${USER_HOME}/.gdbinit") + endif() + + set(PROJECT_GDBINIT "${CMAKE_SOURCE_DIR}/.gdbinit") + + set(GDB_CONFIG_LINES + "set auto-load local-gdbinit on +add-auto-load-safe-path ${PROJECT_GDBINIT}\n" + ) + + get_filename_component(GDB_CONFIG_DIR "${GDB_GLOBAL_INIT}" DIRECTORY) + file(MAKE_DIRECTORY "${GDB_CONFIG_DIR}") + + if(EXISTS "${GDB_GLOBAL_INIT}") + file(READ "${GDB_GLOBAL_INIT}" EXISTING_CONTENT) + string(FIND "${EXISTING_CONTENT}" "${PROJECT_GDBINIT}" ALREADY_ADDED) + else() + set(ALREADY_ADDED -1) + endif() + + if(ALREADY_ADDED EQUAL -1) + file(APPEND "${GDB_GLOBAL_INIT}" "\n# Added by Original CMake auto-config\n${GDB_CONFIG_LINES}") + message(STATUS "[GDB CONFIG] Added safe-path for ${PROJECT_GDBINIT} in ${GDB_GLOBAL_INIT}") + else() + message(STATUS "[GDB CONFIG] Safe-path already configured in ${GDB_GLOBAL_INIT}") + endif() + endif() +endif() diff --git a/debug/gdbinit.py b/debug/gdbinit.py new file mode 100644 index 0000000..c9a86d9 --- /dev/null +++ b/debug/gdbinit.py @@ -0,0 +1,58 @@ +# debug/gdbinit.py + +import gdb +import sys +import os +import importlib.util +import inspect + + +def load_printers_from_directory(pretty_printer_collection, directory): + """Load all pretty-printer scripts from the specified directory.""" + if not os.path.isdir(directory): + print(f"[WARN] Skipped non-existent directory: {directory}") + return + + for file_name in os.listdir(directory): + if not file_name.endswith("_printer.py"): + continue + + file_path = os.path.join(directory, file_name) + module_name = os.path.splitext(file_name)[0] + + try: + spec = importlib.util.spec_from_file_location(module_name, file_path) + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + + printer_class = None + for name, cls in inspect.getmembers(module, inspect.isclass): + if name == "Printer": + printer_class = cls + break + + if printer_class is None: + print(f"[SKIP] {module_name}: no 'Printer' class found") + continue + type_name = module_name.replace("_printer", "") + type_regex = f"^original::{type_name}(<.*>)?$" + + pretty_printer_collection.add_printer(module_name, type_regex, printer_class) + print(f"Registered pretty-printer: {type_name}") + + except Exception as e: + print(f"Failed to load {file_name}: {e}") + + +this_dir = os.path.dirname(__file__) +printers_dir = os.path.join(this_dir, "printers") +core_dir = os.path.join(printers_dir, "core") + +sys.path.insert(0, printers_dir) +sys.path.insert(0, core_dir) + +pp = gdb.printing.RegexpCollectionPrettyPrinter("original") +load_printers_from_directory(pp, core_dir) +gdb.printing.register_pretty_printer(None, pp) + +print("GDB pretty-printers for 'original' registered successfully.") \ No newline at end of file diff --git a/debug/printers/core/RBTree_printer.py b/debug/printers/core/RBTree_printer.py new file mode 100644 index 0000000..8db4a04 --- /dev/null +++ b/debug/printers/core/RBTree_printer.py @@ -0,0 +1,79 @@ +# debug/printers/core/RBTree_printer.py + +import gdb +import sys +import os +sys.path.insert(0, os.path.dirname(os.path.dirname(__file__))) +from utils import * + + +def get_successor_node(ptr): + if ptr == 0: + return 0 + node = ptr.dereference() + if node["right_"] != 0: + ptr = node["right_"] + node = ptr.dereference() + while node["left_"] != 0: + ptr = node["left_"] + node = ptr.dereference() + return ptr + + node = ptr.dereference() + ptr_parent = node["parent_"] + node = ptr_parent.dereference() + + while ptr_parent != 0 and ptr == node["right_"]: + ptr = ptr_parent + node = ptr_parent.dereference() + ptr_parent = node["parent_"] + return ptr_parent + + +class PrinterBase: + """Pretty printer for derived classes of RBTree in original""" + + def __init__(self, val): + self.val = val + + def class_name(self): + return "original::RBTree" + + def to_string(self): + size = int(call(self.val, "size")) + return f"{self.class_name()}(size={size}, {addr_str(self.val)})" + + def get_min_node(self): + p = self.val["root_"] + if p == 0: + return p + node = p.dereference() + while node["left_"] != 0: + p = node["left_"] + node = p.dereference() + return p + + def get_max_node(self): + p = self.val["root_"] + if p == 0: + return p + node = p.dereference() + while node["right_"] != 0: + p = node["right_"] + node = p.dereference() + return p + + def elem(self): + if self.val["root_"] == 0: + return + cur = self.get_min_node() + end = self.get_max_node() + while cur != end: + node = cur.dereference() + cp = node["data_"] + yield cp["first_"], cp["second_"] + cur = get_successor_node(cur) + if end != 0: + node = end.dereference() + cp = node["data_"] + yield cp["first_"], cp["second_"] diff --git a/debug/printers/core/array_printer.py b/debug/printers/core/array_printer.py new file mode 100644 index 0000000..5a85c91 --- /dev/null +++ b/debug/printers/core/array_printer.py @@ -0,0 +1,33 @@ +# debug/printers/core/array_printer.py + + +import gdb +import sys +import os +sys.path.insert(0, os.path.dirname(os.path.dirname(__file__))) +from utils import * + + +class Printer: + """Pretty printer for original::array""" + + def __init__(self, val): + self.val = val + + def to_string(self): + size = int(call(self.val, "size")) + return f"original::array(cap={size}, {addr_str(self.val)})" + + def children(self): + size = int(call(self.val, "size")) + for i in range(0, size): + v = call(self.val, "operator[]", f"{i}") + if v.type.code == gdb.TYPE_CODE_REF: + v = v.referenced_value() + yield f"[{i}]", v + if gdb.parameter('print pretty') > 0: + addr = addr_str(self.val["body"]) + yield "body", f"{addr}" + + def display_hint(self): + return "array" \ No newline at end of file diff --git a/debug/printers/core/autoPtr_printer.py b/debug/printers/core/autoPtr_printer.py new file mode 100644 index 0000000..623fdfe --- /dev/null +++ b/debug/printers/core/autoPtr_printer.py @@ -0,0 +1,59 @@ +# debug/printers/core/autoPtr_printer.py + +import gdb +import sys +import os +sys.path.insert(0, os.path.dirname(os.path.dirname(__file__))) +from utils import * + + +def is_array_ptr(val): + type_str = str(val.type) + + if "<" not in type_str or ">" not in type_str: + return False + + inner = type_str[type_str.find("<")+1:type_str.rfind(">")] + parts = [p.strip() for p in inner.split(",")] + if len(parts) < 2: + return False + deleter_param = parts[1] + return deleter_param.endswith("[]>") + + +class PrinterBase: + """Pretty printer for derived classes of autoPtr in original""" + + def __init__(self, val): + self.val = val + + def class_name(self): + return "original::autoPtr" + + def to_string(self): + ptr = int(call(self.val, "get")) + if ptr == 0: + return f"{self.class_name()}(nullptr)" + ref_count = self.val['ref_count'] + loaded_ptr = call(ref_count, "operator*") + ref_count_base = loaded_ptr.dereference() + strong_refs_atomic = ref_count_base['strong_refs'] + weak_refs_atomic = ref_count_base['weak_refs'] + strong_refs = call(strong_refs_atomic, "operator*") + weak_refs = call(weak_refs_atomic, "operator*") + strong_refs = to_int(strong_refs, U_INTEGER_SIZE) + weak_refs = to_int(weak_refs, U_INTEGER_SIZE) + return f"{self.class_name()}(strong refs={strong_refs}, weak refs={weak_refs}, {addr_str(ptr)})" + + def children(self): + ptr = call(self.val, "get") + ptr_val = int(ptr) + + if ptr_val != 0: + if is_array_ptr(self.val): + yield "array", f"@{ptr_val:#x}" + else: + yield "object", ptr.dereference() + if gdb.parameter('print pretty') > 0: + yield "ref count", self.val["ref_count"] + yield "alias ptr", self.val["alias_ptr"] \ No newline at end of file diff --git a/debug/printers/core/bitSet_printer.py b/debug/printers/core/bitSet_printer.py new file mode 100644 index 0000000..6393b52 --- /dev/null +++ b/debug/printers/core/bitSet_printer.py @@ -0,0 +1,30 @@ +# debug/printers/core/bitSet_printer.py + + +import gdb +import sys +import os +sys.path.insert(0, os.path.dirname(os.path.dirname(__file__))) +from utils import * + + +class Printer: + """Pretty printer for original::bitset""" + + def __init__(self, val): + self.val = val + + def to_string(self): + size = int(call(self.val, "size")) + cnt = int(call(self.val, "count")) + return f"original::bitset(count={cnt}, cap={size}, {addr_str(self.val)})" + + def children(self): + size = int(call(self.val, "size")) + for i in range(0, size): + yield f"[{i}]", call(self.val, "get", f"{i}") + if gdb.parameter('print pretty') > 0: + yield "map", self.val["map"] + + def display_hint(self): + return "array" \ No newline at end of file diff --git a/debug/printers/core/blocksList_printer.py b/debug/printers/core/blocksList_printer.py new file mode 100644 index 0000000..d5563d7 --- /dev/null +++ b/debug/printers/core/blocksList_printer.py @@ -0,0 +1,36 @@ +# debug/printers/core/blocksList_printer.py + + +import gdb +import sys +import os +sys.path.insert(0, os.path.dirname(os.path.dirname(__file__))) +from utils import * + + +class Printer: + """Pretty printer for original::blocksList""" + + def __init__(self, val): + self.val = val + + def to_string(self): + size = int(call(self.val, "size")) + capacity = int(call(self.val["map"], "size")) * 16 + return f"original::blocksList(size={size}, cap={capacity}, {addr_str(self.val)})" + + def children(self): + size = int(call(self.val, "size")) + for i in range(0, size): + v = call(self.val, "operator[]", f"{i}") + if v.type.code == gdb.TYPE_CODE_REF: + v = v.referenced_value() + yield f"[{i}]", v + if gdb.parameter('print pretty') > 0: + yield "first", self.val["first_"] + yield "last", self.val["last_"] + yield "first block", self.val["first_block"] + yield "last block", self.val["last_block"] + + def display_hint(self): + return "array" \ No newline at end of file diff --git a/debug/printers/core/chain_printer.py b/debug/printers/core/chain_printer.py new file mode 100644 index 0000000..4b3eed3 --- /dev/null +++ b/debug/printers/core/chain_printer.py @@ -0,0 +1,30 @@ +# debug/printers/core/chain_printer.py + + +import gdb +import sys +import os +sys.path.insert(0, os.path.dirname(os.path.dirname(__file__))) +from utils import * + + +class Printer: + """Pretty printer for original::chain""" + + def __init__(self, val): + self.val = val + + def to_string(self): + size = int(call(self.val, "size")) + return f"original::chain(size={size}, {addr_str(self.val)})" + + def children(self): + size = int(call(self.val, "size")) + p = self.val["begin_"] + for i in range(0, size): + node = p.dereference() + yield f"[{i}]", node["data_"] + p = node["next"] + if gdb.parameter('print pretty') > 0: + yield "begin", self.val["begin_"] + yield "end", self.val["end_"] \ No newline at end of file diff --git a/debug/printers/core/containerAdaptor_printer.py b/debug/printers/core/containerAdaptor_printer.py new file mode 100644 index 0000000..63bbcfd --- /dev/null +++ b/debug/printers/core/containerAdaptor_printer.py @@ -0,0 +1,23 @@ +# debug/printers/core/containerAdaptor_printer.py + +import gdb +import sys +import os +sys.path.insert(0, os.path.dirname(os.path.dirname(__file__))) +from utils import * + + +class PrinterBase: + """Pretty printer for derived classes of containerAdaptor in original""" + + def __init__(self, val): + self.val = val + + def class_name(self): + return "original::containerAdaptor" + + def to_string(self): + return f"{self.class_name()}({addr_str(self.val)})" + + def children(self): + yield "serial", self.val["serial_"] \ No newline at end of file diff --git a/debug/printers/core/couple_printer.py b/debug/printers/core/couple_printer.py new file mode 100644 index 0000000..2e62aa9 --- /dev/null +++ b/debug/printers/core/couple_printer.py @@ -0,0 +1,24 @@ +# debug/printers/core/couple_printer.py + +import gdb +import sys +import os +sys.path.insert(0, os.path.dirname(os.path.dirname(__file__))) +from utils import * + + +class Printer: + """Pretty printer for original::couple""" + + def __init__(self, val): + self.val = val + + def to_string(self): + return f"original::couple({addr_str(self.val)})" + + def children(self): + yield "[0]", self.val['first_'] + yield "[1]", self.val['second_'] + + def display_hint(self): + return "array" \ No newline at end of file diff --git a/debug/printers/core/deque_printerr.py b/debug/printers/core/deque_printerr.py new file mode 100644 index 0000000..9dc04dd --- /dev/null +++ b/debug/printers/core/deque_printerr.py @@ -0,0 +1,14 @@ +# debug/printers/core/deque_printer.py + +import gdb +from containerAdaptor_printer import PrinterBase as Base + + +class Printer(Base): + """Pretty printer for original::deque""" + + def __init__(self, val): + super().__init__(val) + + def class_name(self): + return "original::deque" \ No newline at end of file diff --git a/debug/printers/core/forwardChain_printer.py b/debug/printers/core/forwardChain_printer.py new file mode 100644 index 0000000..c428632 --- /dev/null +++ b/debug/printers/core/forwardChain_printer.py @@ -0,0 +1,28 @@ +# debug/printers/core/forwardChain_printer.py + + +import gdb +import sys +import os +sys.path.insert(0, os.path.dirname(os.path.dirname(__file__))) +from utils import * + + +class Printer: + """Pretty printer for original::forwardChain""" + + def __init__(self, val): + self.val = val + + def to_string(self): + return f"original::forwardChain({addr_str(self.val)})" + + def children(self): + size = int(call(self.val, "size")) + yield "size", size + p = self.val["begin_"] + for i in range(0, size): + node = p.dereference() + yield f"[{i}]", node["data_"] + p = node["next"] + yield "begin", self.val["begin_"] \ No newline at end of file diff --git a/debug/printers/core/hashMap_printer.py b/debug/printers/core/hashMap_printer.py new file mode 100644 index 0000000..7dc608f --- /dev/null +++ b/debug/printers/core/hashMap_printer.py @@ -0,0 +1,24 @@ +# debug/printers/core/hashMap_printer.py + +import gdb +from hashTable_printer import PrinterBase as Base + + +class Printer(Base): + """Pretty printer for original::hashMap""" + + def __init__(self, val): + super().__init__(val) + + def class_name(self): + return "original::hashMap" + + def children(self): + for i, cp in enumerate(self.elem()): + yield f"[{i}].key", cp[0] + yield f"[{i}].value", cp[1] + if gdb.parameter('print pretty') > 0: + yield "buckets", self.val["buckets"] + + def display_hint(self): + return "map" \ No newline at end of file diff --git a/debug/printers/core/hashSet_printer.py b/debug/printers/core/hashSet_printer.py new file mode 100644 index 0000000..1c97e88 --- /dev/null +++ b/debug/printers/core/hashSet_printer.py @@ -0,0 +1,23 @@ +# debug/printers/core/hashSet_printer.py + +import gdb +from hashTable_printer import PrinterBase as Base + + +class Printer(Base): + """Pretty printer for original::hashSet""" + + def __init__(self, val): + super().__init__(val) + + def class_name(self): + return "original::hashSet" + + def children(self): + for i, cp in enumerate(self.elem()): + yield f"[{i}]", cp[0] + if gdb.parameter('print pretty') > 0: + yield "buckets", self.val["buckets"] + + def display_hint(self): + return "array" diff --git a/debug/printers/core/hashTable_printer.py b/debug/printers/core/hashTable_printer.py new file mode 100644 index 0000000..fb8958c --- /dev/null +++ b/debug/printers/core/hashTable_printer.py @@ -0,0 +1,39 @@ +# debug/printers/core/hashTable_printer.py + +import gdb +import sys +import os +sys.path.insert(0, os.path.dirname(os.path.dirname(__file__))) +from utils import * + + +class PrinterBase: + """Pretty printer for derived classes of hashTable in original""" + + def __init__(self, val): + self.val = val + + def class_name(self): + return "original::hashTable" + + def to_string(self): + size = int(call(self.val, "size")) + return f"{self.class_name()}(size={size}, {addr_str(self.val)})" + + def elem(self): + size = int(call(self.val, "size")) + if size == 0: + return + cnt = 0 + buckets = self.val['buckets'] + length = int(call(buckets, "size")) + for i in range(length): + p = call(buckets, "operator[]", f"{i}") + while p != 0: + node = p.dereference() + cp = node["data_"] + yield cp["first_"], cp["second_"] + cnt += 1 + if cnt == size: + return + p = node["next_"] diff --git a/debug/printers/core/ownerPtr_printer.py b/debug/printers/core/ownerPtr_printer.py new file mode 100644 index 0000000..49d82f8 --- /dev/null +++ b/debug/printers/core/ownerPtr_printer.py @@ -0,0 +1,15 @@ +# debug/printers/core/ownerPtr_printer.py + +import gdb + +from autoPtr_printer import PrinterBase as Base +class Printer(Base): + """Pretty printer for original::ownerPtr""" + + + def __init__(self, val): + super().__init__(val) + + + def class_name(self): + return "original::ownerPtr" \ No newline at end of file diff --git a/debug/printers/core/prique_printer.py b/debug/printers/core/prique_printer.py new file mode 100644 index 0000000..4b95bf6 --- /dev/null +++ b/debug/printers/core/prique_printer.py @@ -0,0 +1,20 @@ +# debug/printers/core/prique_printer.py + +import gdb +from containerAdaptor_printer import PrinterBase as Base + + +class Printer(Base): + """Pretty printer for original::prique""" + + def __init__(self, val): + super().__init__(val) + + def class_name(self): + return "original::prique" + + def children(self): + for _, e in enumerate(super().children()): + yield e + if gdb.parameter('print pretty') > 0: + yield "compare", self.val["compare_"] \ No newline at end of file diff --git a/debug/printers/core/queue_printer.py b/debug/printers/core/queue_printer.py new file mode 100644 index 0000000..f9a6e45 --- /dev/null +++ b/debug/printers/core/queue_printer.py @@ -0,0 +1,14 @@ +# debug/printers/core/queue_printer.py + +import gdb +from containerAdaptor_printer import PrinterBase as Base + + +class Printer(Base): + """Pretty printer for original::queue""" + + def __init__(self, val): + super().__init__(val) + + def class_name(self): + return "original::queue" \ No newline at end of file diff --git a/debug/printers/core/stack_printer.py b/debug/printers/core/stack_printer.py new file mode 100644 index 0000000..7fcba7d --- /dev/null +++ b/debug/printers/core/stack_printer.py @@ -0,0 +1,14 @@ +# debug/printers/core/stack_printer.py + +import gdb +from containerAdaptor_printer import PrinterBase as Base + + +class Printer(Base): + """Pretty printer for original::stack""" + + def __init__(self, val): + super().__init__(val) + + def class_name(self): + return "original::stack" \ No newline at end of file diff --git a/debug/printers/core/strongPtr_printer.py b/debug/printers/core/strongPtr_printer.py new file mode 100644 index 0000000..629c30b --- /dev/null +++ b/debug/printers/core/strongPtr_printer.py @@ -0,0 +1,15 @@ +# debug/printers/core/strongPtr_printer.py + +import gdb + +from autoPtr_printer import PrinterBase as Base +class Printer(Base): + """Pretty printer for original::strongPtr""" + + + def __init__(self, val): + super().__init__(val) + + + def class_name(self): + return "original::strongPtr" \ No newline at end of file diff --git a/debug/printers/core/treeMap_printer.py b/debug/printers/core/treeMap_printer.py new file mode 100644 index 0000000..346f70c --- /dev/null +++ b/debug/printers/core/treeMap_printer.py @@ -0,0 +1,31 @@ +# debug/printers/core/treeMap_printer.py + +import gdb +from RBTree_printer import PrinterBase as Base +import sys +import os +sys.path.insert(0, os.path.dirname(os.path.dirname(__file__))) +from utils import * + + +class Printer(Base): + """Pretty printer for original::treeMap""" + + def __init__(self, val): + super().__init__(val) + + def class_name(self): + return "original::treeMap" + + def children(self): + for i, cp in enumerate(self.elem()): + yield f"[{i}].key", cp[0] + yield f"[{i}].value", cp[1] + if gdb.parameter('print pretty') > 0: + addr_root = addr_str(self.val["root_"]) + addr_cmp = addr_str(self.val["compare_"]) + yield "root", f"{addr_root}" + yield "compare", f"{addr_cmp}" + + def display_hint(self): + return "map" \ No newline at end of file diff --git a/debug/printers/core/treeSet_printer.py b/debug/printers/core/treeSet_printer.py new file mode 100644 index 0000000..df2bbd8 --- /dev/null +++ b/debug/printers/core/treeSet_printer.py @@ -0,0 +1,30 @@ +# debug/printers/core/treeSet_printer.py + +import gdb +from RBTree_printer import PrinterBase as Base +import sys +import os +sys.path.insert(0, os.path.dirname(os.path.dirname(__file__))) +from utils import * + + +class Printer(Base): + """Pretty printer for original::treeSet""" + + def __init__(self, val): + super().__init__(val) + + def class_name(self): + return "original::treeSet" + + def children(self): + for i, cp in enumerate(self.elem()): + yield f"[{i}]", cp[0] + if gdb.parameter('print pretty') > 0: + addr_root = addr_str(self.val["root_"]) + addr_cmp = addr_str(self.val["compare_"]) + yield "root", f"{addr_root}" + yield "compare", f"{addr_cmp}" + + def display_hint(self): + return "array" \ No newline at end of file diff --git a/debug/printers/core/tuple_printer.py b/debug/printers/core/tuple_printer.py new file mode 100644 index 0000000..88c1fff --- /dev/null +++ b/debug/printers/core/tuple_printer.py @@ -0,0 +1,46 @@ +# debug/printers/core/tuple_printer.py + +import gdb +import sys +import os +sys.path.insert(0, os.path.dirname(os.path.dirname(__file__))) +from utils import * + + +class Printer: + """Pretty printer for original::tuple""" + + def __init__(self, val): + self.val = val + self.size = 0 + try: + elems = val['elems'] + current = elems + while True: + try: + _ = current['cur_elem'] + self.size += 1 + current = current['next'] + except gdb.error: + break + except gdb.error: + self.size = 0 + + def to_string(self): + return f"original::tuple(size={self.size}, {addr_str(self.val)})" + + def children(self): + elems = self.val['elems'] + current = elems + index = 0 + while True: + try: + elem = current['cur_elem'] + yield f"[{index}]", elem + index += 1 + current = current['next'] + except gdb.error: + break + + def display_hint(self): + return "array" \ No newline at end of file diff --git a/debug/printers/core/vector_printer.py b/debug/printers/core/vector_printer.py new file mode 100644 index 0000000..cf69b0f --- /dev/null +++ b/debug/printers/core/vector_printer.py @@ -0,0 +1,34 @@ +# debug/printers/core/vector_printer.py + + +import gdb +import sys +import os +sys.path.insert(0, os.path.dirname(os.path.dirname(__file__))) +from utils import * + + +class Printer: + """Pretty printer for original::vector""" + + def __init__(self, val): + self.val = val + + def to_string(self): + size = int(call(self.val, "size")) + capacity = self.val["max_size"] + return f"original::vector(size={size}, cap={capacity}, {addr_str(self.val)})" + + def children(self): + size = int(call(self.val, "size")) + for i in range(0, size): + v = call(self.val, "operator[]", f"{i}") + if v.type.code == gdb.TYPE_CODE_REF: + v = v.referenced_value() + yield f"[{i}]", v + if gdb.parameter('print pretty') > 0: + yield "max size", self.val["max_size"] + yield "inner begin", self.val["inner_begin"] + + def display_hint(self): + return "array" \ No newline at end of file diff --git a/debug/printers/core/weakPtr_printer.py b/debug/printers/core/weakPtr_printer.py new file mode 100644 index 0000000..2333413 --- /dev/null +++ b/debug/printers/core/weakPtr_printer.py @@ -0,0 +1,15 @@ +# debug/printers/core/weakPtr_printer.py + +import gdb + +from autoPtr_printer import PrinterBase as Base +class Printer(Base): + """Pretty printer for original::weakPtr""" + + + def __init__(self, val): + super().__init__(val) + + + def class_name(self): + return "original::weakPtr" \ No newline at end of file diff --git a/debug/printers/utils.py b/debug/printers/utils.py new file mode 100644 index 0000000..f8e7da2 --- /dev/null +++ b/debug/printers/utils.py @@ -0,0 +1,37 @@ +# debug/printers/utils.py + +import gdb + + +U_INTEGER_SIZE = 4 + +def to_int(val, size = 8): + mask = (1 << (size * 8)) - 1 + v = int(val) + return v & mask + +def address(obj): + try: + return int(obj.address) if obj.address else None + except gdb.error: + return None + +def addr_str(item): + if isinstance(item, int) or isinstance(item, str): + return f"@{item:#x}" + return f"@{address(item):#x}" + +def type_name(obj): + return obj.type.name + +def call(obj, method_name, *args): + try: + if obj.type.code == gdb.TYPE_CODE_REF: + obj = obj.referenced_value() + args_str = ', '.join(str(arg) for arg in args) + addr = address(obj) + expr = f'(({type_name(obj)}*)({addr}))->{method_name}({args_str})' + return gdb.parse_and_eval(expr) + except Exception as e: + print(f"Error calling {method_name} on {obj}: {e}") + return None diff --git a/src/core/RBTree.h b/src/core/RBTree.h index 4e2d01b..713f737 100644 --- a/src/core/RBTree.h +++ b/src/core/RBTree.h @@ -38,7 +38,7 @@ namespace original { typename ALLOC = allocator, typename Compare = increaseComparator> class RBTree { - protected: + public: /** * @class RBNode @@ -200,10 +200,10 @@ namespace original { static void connect(RBNode* parent, RBNode* child, bool is_left); }; - using color = typename RBNode::color; ///< Color type alias + using color = RBNode::color; ///< Color type alias static constexpr color BLACK = color::BLACK; ///< Black color constant static constexpr color RED = color::RED; ///< Red color constant - using rebind_alloc_node = typename ALLOC::template rebind_alloc; ///< Rebound allocator type + using rebind_alloc_node = ALLOC::template rebind_alloc; ///< Rebound allocator type RBNode* root_; ///< Root node pointer u_integer size_; ///< Number of elements @@ -460,7 +460,7 @@ namespace original { * @brief Destructor * @details Cleans up all tree nodes and allocated memory */ - ~RBTree(); + virtual ~RBTree(); }; } @@ -476,7 +476,7 @@ original::RBTree::RBNode::RBNode(const RBNode &o } template -typename original::RBTree::RBNode& +original::RBTree::RBNode& original::RBTree::RBNode::operator=(const RBNode &other) { if (this == &other) return *this; @@ -539,38 +539,38 @@ void original::RBTree::RBNode::setValue(const V_ } template -typename original::RBTree::RBNode::color +original::RBTree::RBNode::color original::RBTree::RBNode::getColor() const { return this->color_; } template -typename original::RBTree::RBNode* +original::RBTree::RBNode* original::RBTree::RBNode::getPParent() const { return this->parent_; } template -typename original::RBTree::RBNode* +original::RBTree::RBNode* original::RBTree::RBNode::getPLeft() const { return this->left_; } template -typename original::RBTree::RBNode* +original::RBTree::RBNode* original::RBTree::RBNode::getPRight() const { return this->right_; } template -typename original::RBTree::RBNode*& +original::RBTree::RBNode*& original::RBTree::RBNode::getPLeftRef() { return this->left_; } template -typename original::RBTree::RBNode*& +original::RBTree::RBNode*& original::RBTree::RBNode::getPRightRef() { return this->right_; @@ -617,7 +617,7 @@ original::RBTree::Iterator::Iterator(const Itera } template -typename original::RBTree::Iterator& +original::RBTree::Iterator& original::RBTree::Iterator::operator=(const Iterator& other) { if (this == &other) @@ -704,7 +704,7 @@ bool original::RBTree::Iterator::isValid() const template -typename original::RBTree::RBNode* +original::RBTree::RBNode* original::RBTree::treeCopy() const { if (!this->root_) { return nullptr; @@ -740,7 +740,7 @@ original::RBTree::treeCopy() const { } template -typename original::RBTree::RBNode* +original::RBTree::RBNode* original::RBTree::getPrecursorNode(RBNode *cur) const { if (!cur) return nullptr; @@ -762,7 +762,7 @@ original::RBTree::getPrecursorNode(RBNode *cur) } template -typename original::RBTree::RBNode* +original::RBTree::RBNode* original::RBTree::getSuccessorNode(RBNode *cur) const { if (!cur) return nullptr; @@ -784,7 +784,7 @@ original::RBTree::getSuccessorNode(RBNode *cur) } template -typename original::RBTree::RBNode* +original::RBTree::RBNode* original::RBTree::getMinNode() const { if (!root_) return nullptr; @@ -797,7 +797,7 @@ original::RBTree::getMinNode() const } template -typename original::RBTree::RBNode* +original::RBTree::RBNode* original::RBTree::getMaxNode() const { if (!this->root_) { @@ -812,7 +812,7 @@ original::RBTree::getMaxNode() const } template -typename original::RBTree::RBNode* +original::RBTree::RBNode* original::RBTree::replaceNode(RBNode* src, RBNode* tar) { auto moved_src = this->createNode(std::move(*src)); @@ -829,7 +829,7 @@ original::RBTree::replaceNode(RBNode* src, RBNod } template -typename original::RBTree::RBNode* +original::RBTree::RBNode* original::RBTree::createNode(const K_TYPE &key, const V_TYPE &value, color color, RBNode* parent, RBNode* left, RBNode* right) const { @@ -839,7 +839,7 @@ original::RBTree::createNode(const K_TYPE &key, } template -typename original::RBTree::RBNode* +original::RBTree::RBNode* original::RBTree::createNode(RBNode&& other_node) const { auto node = this->rebind_alloc.allocate(1); @@ -870,7 +870,7 @@ bool original::RBTree::highPriority(const K_TYPE } template -typename original::RBTree::RBNode* +original::RBTree::RBNode* original::RBTree::rotateLeft(RBNode *cur) { RBNode* child_left = cur; RBNode* child_root = child_left->getPRight(); @@ -884,7 +884,7 @@ original::RBTree::rotateLeft(RBNode *cur) { } template -typename original::RBTree::RBNode* +original::RBTree::RBNode* original::RBTree::rotateRight(RBNode *cur) { RBNode* child_right = cur; RBNode* child_root = cur->getPLeft(); @@ -1117,7 +1117,7 @@ original::RBTree::RBTree(Compare compare) : root_(nullptr), size_(0), compare_(std::move(compare)) {} template -typename original::RBTree::RBNode* +original::RBTree::RBNode* original::RBTree::find(const K_TYPE &key) const { auto cur = this->root_; while (cur){ diff --git a/src/core/allocator.h b/src/core/allocator.h index 5d666f7..271c614 100644 --- a/src/core/allocator.h +++ b/src/core/allocator.h @@ -488,15 +488,15 @@ original::objPoolAllocator& original::objPoolAllocator::operator+=(o if (this == &other) return *this; - auto size_class_count_max = max(this->size_class_count, other.size_class_count); - auto chunk_count_init_max = max(this->chunk_count_init, other.chunk_count_init); + auto size_class_count_max = maximum(this->size_class_count, other.size_class_count); + auto chunk_count_init_max = maximum(this->chunk_count_init, other.chunk_count_init); auto chunk_count_max = allocators::malloc(size_class_count_max); auto free_list_head_max = allocators::malloc(size_class_count_max); auto chunks_available_max = allocators::malloc(size_class_count_max); for (u_integer i = 0; i < size_class_count_max; i++) { if (i < this->size_class_count && i < other.size_class_count) { - chunk_count_max[i] = max(this->chunk_count[i], other.chunk_count[i]); + chunk_count_max[i] = maximum(this->chunk_count[i], other.chunk_count[i]); chunks_available_max[i] = this->chunks_available[i] + other.chunks_available[i]; auto cur_list_head_i = other.free_list_head[i]; if (cur_list_head_i) { @@ -597,7 +597,7 @@ TYPE* original::objPoolAllocator::allocate(const u_integer size) } if (!this->free_list_head[index] || this->chunks_available[index] * (static_cast(1) << index) < size) { - this->chunkAllocate(max(1, this->chunk_count[index]), index); + this->chunkAllocate(maximum(1, this->chunk_count[index]), index); } auto cur_ptr = this->free_list_head[index]; diff --git a/src/core/bitSet.h b/src/core/bitSet.h index ed1216a..3cf4267 100644 --- a/src/core/bitSet.h +++ b/src/core/bitSet.h @@ -674,12 +674,12 @@ namespace std { auto* other_it = dynamic_cast(&other); if (other_it == nullptr) return this > &other ? - std::numeric_limits::max() : - std::numeric_limits::min(); + (std::numeric_limits::max)() : + (std::numeric_limits::min)(); if (this->container_ != other_it->container_) return this->container_ > other_it->container_ ? - std::numeric_limits::max() : - std::numeric_limits::min(); + (std::numeric_limits::max)() : + (std::numeric_limits::min)(); return toOuterIdx(this->cur_block, this->cur_bit) - toOuterIdx(other_it->cur_block, other_it->cur_bit); } @@ -800,7 +800,7 @@ namespace std { } auto nb = bitSet(new_size); - const u_integer blocks_min = min(nb.map.size(), + const u_integer blocks_min = minimum(nb.map.size(), this->map.size()); for (u_integer i = 0; i < blocks_min; i++) { nb.map.set(i, this->map.get(i)); diff --git a/src/core/blocksList.h b/src/core/blocksList.h index 06ff3ce..d7aba84 100644 --- a/src/core/blocksList.h +++ b/src/core/blocksList.h @@ -742,12 +742,12 @@ namespace std { auto* other_it = dynamic_cast(&other); if (other_it == nullptr) return this > &other ? - std::numeric_limits::max() : - std::numeric_limits::min(); + (std::numeric_limits::max)() : + (std::numeric_limits::min)(); if (this->container_ != other_it->container_) return this->container_ > other_it->container_ ? - std::numeric_limits::max() : - std::numeric_limits::min(); + (std::numeric_limits::max)() : + (std::numeric_limits::min)(); return static_cast(innerIdxToAbsIdx(this->cur_block, this->cur_pos)) - static_cast(innerIdxToAbsIdx(other_it->cur_block, other_it->cur_pos)); diff --git a/src/core/chain.h b/src/core/chain.h index 581ee41..b92083d 100644 --- a/src/core/chain.h +++ b/src/core/chain.h @@ -591,7 +591,12 @@ namespace std { } template - original::chain::chain(ALLOC alloc) : baseList(std::move(alloc)), size_(0), rebind_alloc(std::move(rebind_alloc_node{})) + original::chain::chain(ALLOC alloc) + : baseList(std::move(alloc)), + size_(0), + begin_(nullptr), + end_(nullptr), + rebind_alloc(std::move(rebind_alloc_node{})) { chainInit(); } diff --git a/src/core/config.h b/src/core/config.h index b373d2e..741358d 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -17,22 +17,37 @@ * @{ */ +// Initialize all platform macros to false +#define ORIGINAL_PLATFORM_WINDOWS 0 +#define ORIGINAL_PLATFORM_WINDOWS_32 0 +#define ORIGINAL_PLATFORM_WINDOWS_64 0 +#define ORIGINAL_PLATFORM_LINUX 0 +#define ORIGINAL_PLATFORM_MACOS 0 +#define ORIGINAL_PLATFORM_UNIX 0 +#define ORIGINAL_PLATFORM_UNKNOWN 0 + +// Override based on actual platform detection #if defined(_WIN32) || defined(_WIN64) -#define ORIGINAL_PLATFORM_WINDOWS 1 -#ifdef _WIN64 -#define ORIGINAL_PLATFORM_WINDOWS_64 1 -#elif -#define ORIGINAL_PLATFORM_WINDOWS_32 1 -#else - #define ORIGINAL_PLATFORM_WINDOWS 0 -#endif + #undef ORIGINAL_PLATFORM_WINDOWS + #define ORIGINAL_PLATFORM_WINDOWS 1 + #ifdef _WIN64 + #undef ORIGINAL_PLATFORM_WINDOWS_64 + #define ORIGINAL_PLATFORM_WINDOWS_64 1 + #else + #undef ORIGINAL_PLATFORM_WINDOWS_32 + #define ORIGINAL_PLATFORM_WINDOWS_32 1 + #endif #elif defined(__linux__) -#define ORIGINAL_PLATFORM_LINUX 1 + #undef ORIGINAL_PLATFORM_LINUX + #define ORIGINAL_PLATFORM_LINUX 1 #elif defined(__APPLE__) && defined(__MACH__) + #undef ORIGINAL_PLATFORM_MACOS #define ORIGINAL_PLATFORM_MACOS 1 #elif defined(__unix__) + #undef ORIGINAL_PLATFORM_UNIX #define ORIGINAL_PLATFORM_UNIX 1 #else + #undef ORIGINAL_PLATFORM_UNKNOWN #define ORIGINAL_PLATFORM_UNKNOWN 1 #endif /** @} */ // end of PlatformDetection group @@ -42,16 +57,28 @@ * @brief Macros for identifying the compiler being used * @{ */ + +// Initialize all compiler macros to false +#define ORIGINAL_COMPILER_CLANG 0 +#define ORIGINAL_COMPILER_GCC 0 +#define ORIGINAL_COMPILER_MSVC 0 +#define ORIGINAL_COMPILER_UNKNOWN 0 + +// Override based on actual compiler detection #if defined(__clang__) -#define ORIGINAL_COMPILER_CLANG 1 + #undef ORIGINAL_COMPILER_CLANG + #define ORIGINAL_COMPILER_CLANG 1 #define ORIGINAL_COMPILER_VERSION __clang_major__.__clang_minor__.__clang_patchlevel__ #elif defined(__GNUC__) || defined(__GNUG__) -#define ORIGINAL_COMPILER_GCC 1 -#define ORIGINAL_COMPILER_VERSION __GNUC__.__GNUC_MINOR__.__GNUC_PATCHLEVEL__ + #undef ORIGINAL_COMPILER_GCC + #define ORIGINAL_COMPILER_GCC 1 + #define ORIGINAL_COMPILER_VERSION __GNUC__.__GNUC_MINOR__.__GNUC_PATCHLEVEL__ #elif defined(_MSC_VER) -#define ORIGINAL_COMPILER_MSVC 1 + #undef ORIGINAL_COMPILER_MSVC + #define ORIGINAL_COMPILER_MSVC 1 #define ORIGINAL_COMPILER_VERSION _MSC_VER #else + #undef ORIGINAL_COMPILER_UNKNOWN #define ORIGINAL_COMPILER_UNKNOWN 1 #endif /** @} */ // end of CompilerDetection group @@ -228,50 +255,71 @@ namespace original { * @{ */ - /** - * @brief Unsigned 8-bit integer type (byte) - * @details Typically used for raw byte manipulation and binary data handling. - * @note Range: 0 to 255 - * @note Equivalent to std::uint8_t - */ - using byte = std::uint8_t; + #if ORIGINAL_COMPILER_GCC || ORIGINAL_COMPILER_CLANG + /** + * @brief Unsigned 8-bit integer type (byte) + * @details Typically used for raw byte manipulation and binary data handling. + * @note Range: 0 to 255 + * @note Equivalent to std::uint8_t + */ + using byte = std::uint8_t; + #elif ORIGINAL_COMPILER_MSVC + using byte = uint8_t; + #endif - /** - * @brief Signed 8-bit integer type - * @details Used for small signed numeric values. - * @note Range: -128 to 127 - * @note Equivalent to std::int8_t - */ - using s_byte = std::int8_t; - /** - * @brief 64-bit signed integer type for arithmetic operations - * @details Primary type for most arithmetic operations where large range is needed. - * @note Range: -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 - * @note Use this for calculations that may require large numbers - * @note Equivalent to std::int64_t - */ - using integer = std::int64_t; + #if ORIGINAL_COMPILER_GCC || ORIGINAL_COMPILER_CLANG + /** + * @brief Signed 8-bit integer type + * @details Used for small signed numeric values. + * @note Range: -128 to 127 + * @note Equivalent to std::int8_t + */ + using s_byte = std::int8_t; + #elif ORIGINAL_COMPILER_MSVC + using s_byte = int8_t; + #endif - /** - * @brief 32-bit unsigned integer type for sizes and indexes - * @details Used for array indexing, sizes, and counts where negative values are not needed. - * @note Range: 0 to 4,294,967,295 - * @warning Not suitable for very large containers (>4GB) - * @note Equivalent to std::uint32_t - */ - using u_integer = std::uint32_t; + #if ORIGINAL_COMPILER_GCC || ORIGINAL_COMPILER_CLANG + /** + * @brief 64-bit signed integer type for arithmetic operations + * @details Primary type for most arithmetic operations where large range is needed. + * @note Range: -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 + * @note Use this for calculations that may require large numbers + * @note Equivalent to std::int64_t + */ + using integer = std::int64_t; + #elif ORIGINAL_COMPILER_MSVC + using integer = int64_t; + #endif - /** - * @brief 64-bit unsigned integer type - * @details Large unsigned integer type for big sizes and counters. - * Guaranteed to be exactly 64 bits wide across all platforms. - * @note Range: 0 to 18,446,744,073,709,551,615 - * @note Preferred for: Large containers, filesystem sizes, big counters - * @see u_integer For smaller unsigned needs - * @note Equivalent to std::uint64_t - */ - using ul_integer = std::uint64_t; + #if ORIGINAL_COMPILER_GCC || ORIGINAL_COMPILER_CLANG + /** + * @brief 32-bit unsigned integer type for sizes and indexes + * @details Used for array indexing, sizes, and counts where negative values are not needed. + * @note Range: 0 to 4,294,967,295 + * @warning Not suitable for very large containers (>4GB) + * @note Equivalent to std::uint32_t + */ + using u_integer = std::uint32_t; + #elif ORIGINAL_COMPILER_MSVC + using u_integer = uint32_t; + #endif + + #if ORIGINAL_COMPILER_GCC || ORIGINAL_COMPILER_CLANG + /** + * @brief 64-bit unsigned integer type + * @details Large unsigned integer type for big sizes and counters. + * Guaranteed to be exactly 64 bits wide across all platforms. + * @note Range: 0 to 18,446,744,073,709,551,615 + * @note Preferred for: Large containers, filesystem sizes, big counters + * @see u_integer For smaller unsigned needs + * @note Equivalent to std::uint64_t + */ + using ul_integer = std::uint64_t; + #elif ORIGINAL_COMPILER_MSVC + using ul_integer = uint64_t; + #endif /** * @brief Double-precision floating-point type diff --git a/src/core/filterStream.h b/src/core/filterStream.h index b903183..0705e2e 100644 --- a/src/core/filterStream.h +++ b/src/core/filterStream.h @@ -26,14 +26,15 @@ namespace original{ template class filterStream { - ///< Null filter instance used as operator placeholder in stream processing - static const strongPtr> nullFilter; - + public: /// @internal Operator types for postfix conversion enum class opts{AND = 1, OR = 0, NOT = 2, LEFT_BRACKET = 3, RIGHT_BRACKET = 4}; + private: + ///< Null filter instance used as operator placeholder in stream processing + static const strongPtr> nullFilter; - mutable chain>> stream; ///< Filter operand chain - mutable chain ops; ///< Operator sequence storage + mutable chain>> stream{}; ///< Filter operand chain + mutable chain ops{}; ///< Operator sequence storage mutable bool flag; ///< Postfix conversion status flag protected: diff --git a/src/core/forwardChain.h b/src/core/forwardChain.h index a00e4ee..eee4eda 100644 --- a/src/core/forwardChain.h +++ b/src/core/forwardChain.h @@ -559,7 +559,10 @@ namespace original { template original::forwardChain::forwardChain(ALLOC alloc) - : baseList(std::move(alloc)), size_(0) , rebind_alloc(std::move(rebind_alloc_node{})) + : baseList(std::move(alloc)), + size_(0), + begin_(nullptr), + rebind_alloc(std::move(rebind_alloc_node{})) { this->chainInit(); } diff --git a/src/core/hashTable.h b/src/core/hashTable.h index 5b70e87..e9bc169 100644 --- a/src/core/hashTable.h +++ b/src/core/hashTable.h @@ -4,7 +4,6 @@ #include "allocator.h" #include "couple.h" #include "hash.h" -#include "singleDirectionIterator.h" #include "vector.h" #include "wrapper.h" @@ -53,7 +52,7 @@ namespace original { */ template, typename HASH = hash> class hashTable{ - protected: + public: /** * @class hashNode @@ -165,13 +164,13 @@ namespace original { * @typedef rebind_alloc_node * @brief Rebound allocator type for node storage */ - using rebind_alloc_node = typename ALLOC::template rebind_alloc; + using rebind_alloc_node = ALLOC::template rebind_alloc; /** * @typedef rebind_alloc_pointer * @brief Rebound allocator type for pointer storage */ - using rebind_alloc_pointer = typename ALLOC::template rebind_alloc; + using rebind_alloc_pointer = ALLOC::template rebind_alloc; /** * @typedef buckets_type @@ -492,7 +491,7 @@ namespace original { * @brief Destroys hashTable * @details Cleans up all nodes and buckets */ - ~hashTable(); + virtual ~hashTable(); }; } @@ -506,7 +505,7 @@ original::hashTable::hashNode::hashNode(const hashN } template -typename original::hashTable::hashNode& +original::hashTable::hashNode& original::hashTable::hashNode::operator=(const hashNode& other) { if (this == &other) return *this; @@ -553,13 +552,13 @@ void original::hashTable::hashNode::setValue(const } template -typename original::hashTable::hashNode* +original::hashTable::hashNode* original::hashTable::hashNode::getPPrev() const { throw unSupportedMethodError(); } template -typename original::hashTable::hashNode* +original::hashTable::hashNode* original::hashTable::hashNode::getPNext() const { return this->next_; } @@ -611,7 +610,7 @@ original::hashTable::Iterator::Iterator(const Itera } template -typename original::hashTable::Iterator& +original::hashTable::Iterator& original::hashTable::Iterator::operator=(const Iterator &other) { if (this == &other) return *this; @@ -689,7 +688,7 @@ bool original::hashTable::Iterator::isValid() const } template -typename original::hashTable::buckets_type +original::hashTable::buckets_type original::hashTable::bucketsCopy(const buckets_type& old_buckets) const { buckets_type new_buckets = buckets_type(old_buckets.size(), rebind_alloc_pointer{}, nullptr); @@ -714,7 +713,7 @@ original::hashTable::bucketsCopy(const buckets_type } template -typename original::hashTable::hashNode* +original::hashTable::hashNode* original::hashTable::createNode(const K_TYPE& key, const V_TYPE& value, hashNode* next) const { auto node = this->rebind_alloc.allocate(1); this->rebind_alloc.construct(node, key, value, next); @@ -740,7 +739,7 @@ original::hashTable::getBucketCount() const { } template -typename original::hashTable::hashNode* +original::hashTable::hashNode* original::hashTable::getBucket(const K_TYPE &key) const { u_integer code = this->getHashCode(key); return this->buckets[code]; @@ -812,7 +811,7 @@ original::hashTable::hashTable(HASH hash) } template -typename original::hashTable::hashNode* +original::hashTable::hashNode* original::hashTable::find(const K_TYPE& key) const { if (this->size_ == 0) return nullptr; diff --git a/src/core/maps.h b/src/core/maps.h index 33ba211..c06034c 100644 --- a/src/core/maps.h +++ b/src/core/maps.h @@ -830,8 +830,8 @@ namespace original { typename V_TYPE, typename Compare = increaseComparator, typename ALLOC = allocator>> - class JMap final : public skipList, - public map, + class JMap final : public map, + public skipList, public iterable>, public printable { @@ -1923,8 +1923,8 @@ original::JMap::Iterator::operator-( auto other_it = dynamic_cast(&other); if (other_it == nullptr) return this > &other ? - std::numeric_limits::max() : - std::numeric_limits::min(); + (std::numeric_limits::max)() : + (std::numeric_limits::min)(); return skipListType::Iterator::operator-(*other_it); } @@ -1993,8 +1993,7 @@ bool original::JMap::Iterator::isValid() const { template original::JMap::JMap(Compare comp, ALLOC alloc) - : skipListType(std::move(comp)) , - map(std::move(alloc)) {} + : map(std::move(alloc)), skipListType(std::move(comp)) {} template original::JMap::JMap(const JMap& other) : JMap() { diff --git a/src/core/maths.h b/src/core/maths.h index b5299d0..982b69c 100644 --- a/src/core/maths.h +++ b/src/core/maths.h @@ -79,7 +79,7 @@ TYPE abs(TYPE a); * @endcode */ template -TYPE max(TYPE a, TYPE b); +TYPE maximum(TYPE a, TYPE b); /** * @brief Returns the smaller of two given values. @@ -100,7 +100,7 @@ TYPE max(TYPE a, TYPE b); * @endcode */ template -TYPE min(TYPE a, TYPE b); +TYPE minimum(TYPE a, TYPE b); /** * @brief Returns the result of raising a base to an exponent. @@ -186,13 +186,13 @@ auto original::abs(TYPE a) -> TYPE } template -auto original::max(TYPE a, TYPE b) -> TYPE +auto original::maximum(TYPE a, TYPE b) -> TYPE { return a > b ? a : b; } template -auto original::min(TYPE a, TYPE b) -> TYPE +auto original::minimum(TYPE a, TYPE b) -> TYPE { return a < b ? a : b; } diff --git a/src/core/optional.h b/src/core/optional.h index 9726891..f86036c 100644 --- a/src/core/optional.h +++ b/src/core/optional.h @@ -8,7 +8,7 @@ * @file optional.h * @brief Type-safe optional value container * @details Provides an alternative class that can either contain a value of type 'TYPE' - * or be in an empty state (represented by original::none from types.h). This implementation + * or be in an empty state (represented by original::null from types.h). This implementation * provides: * - Value semantics with proper construction/destruction * - Safe access operations with error checking @@ -20,7 +20,7 @@ * Key features: * - Type-safe alternative to raw pointers for optional values * - No dynamic memory allocation (uses union storage) - * - Explicit empty state handling with original::none + * - Explicit empty state handling with original::null * - Exception-safe operations * - STL-compatible interface */ @@ -33,7 +33,7 @@ namespace original { * @tparam TYPE The type of value to store * @details This class provides a way to represent optional values without * using pointers. It can either contain a value of type TYPE or be empty. - * The empty state is represented using original::none from types.h. + * The empty state is represented using original::null from types.h. * * The implementation uses a union for storage to avoid dynamic allocation * and ensure optimal performance. All operations provide strong exception @@ -62,18 +62,18 @@ namespace original { class alternative { /** * @union storage - * @brief Internal storage for either TYPE or none - * @details Uses a union to store either the value type or none, + * @brief Internal storage for either TYPE or null + * @details Uses a union to store either the value type or null, * with proper construction/destruction handling. The union ensures * that only one member is active at any time, managed by the - * non_none_type_ flag. + * non_null_type_ flag. */ union storage { TYPE type_; ///< Storage for the contained value - none none_; ///< Storage for empty state (from types.h) + null null_; ///< Storage for empty state (from types.h) /** - * @brief Default constructor (initializes to none) + * @brief Default constructor (initializes to null) */ storage() noexcept; @@ -87,14 +87,14 @@ namespace original { ~storage(); }; - bool non_none_type_; ///< Flag indicating whether value is present (true = TYPE, false = none) + bool non_null_type_; ///< Flag indicating whether value is present (true = TYPE, false = null) storage val_; ///< The actual storage union /** * @brief Safely destroys the current contents * @note Properly calls destructor based on current state - * @details If non_none_type_ is true, calls TYPE destructor, - * otherwise calls none destructor. Ensures RAII compliance. + * @details If non_null_type_ is true, calls TYPE destructor, + * otherwise calls null destructor. Ensures RAII compliance. */ void destroy() noexcept; @@ -286,11 +286,11 @@ namespace original { explicit alternative(); /** - * @brief Constructs from none (empty state) - * @param n none value indicating empty state + * @brief Constructs from null (empty state) + * @param n null value indicating empty state * @post hasValue() == false */ - explicit alternative(none n); + explicit alternative(null n); /** * @brief Constructs with value present @@ -331,19 +331,19 @@ namespace original { alternative& operator=(std::in_place_t t) noexcept; /** - * @brief Assignment from none to reset to empty state - * @param n none value indicating empty state + * @brief Assignment from null to reset to empty state + * @param n null value indicating empty state * @return Reference to this alternative * @post hasValue() == false * @details Resets the alternative to the empty state. This operation * is equivalent to calling reset() but provides a more expressive syntax - * when working with none values. The assignment clears the "present" state + * when working with null values. The assignment clears the "present" state * and ensures the alternative is empty. * * Example usage: * @code * alternative flag(std::in_place); // Present state - * flag = original::none; // Now empty + * flag = original::null; // Now empty * * if (!flag) { * // This will execute since flag is now empty @@ -352,14 +352,14 @@ namespace original { * // In generic code: * template * void clearAlternative(alternative& opt) { - * opt = original::none; // Works for both alternative and alternative + * opt = original::null; // Works for both alternative and alternative * } * @endcode * * @note This operation is noexcept and always succeeds. * @see reset() */ - alternative& operator=(none n) noexcept; + alternative& operator=(null n) noexcept; /** * @brief Resets to empty state @@ -422,7 +422,7 @@ namespace std { template original::alternative::storage::storage() noexcept { - new(&this->none_) none{}; + new(&this->null_) null; } template @@ -430,33 +430,33 @@ original::alternative::storage::~storage() {} template void original::alternative::destroy() noexcept { - if (this->non_none_type_){ + if (this->non_null_type_){ this->val_.type_.~TYPE(); - this->non_none_type_ = false; + this->non_null_type_ = false; } else { - this->val_.none_.~none(); - this->non_none_type_ = true; + this->val_.null_.~null(); + this->non_null_type_ = true; } } template original::alternative::alternative() - : non_none_type_(false), val_() {} + : non_null_type_(false), val_() {} template template original::alternative::alternative(Args &&... args) - : non_none_type_(true), val_() { + : non_null_type_(true), val_() { new (&this->val_.type_) TYPE{ std::forward(args)... }; } template original::alternative::alternative(const alternative& other) { - this->non_none_type_ = other.non_none_type_; - if (other.non_none_type_) { + this->non_null_type_ = other.non_null_type_; + if (other.non_null_type_) { new (&val_.type_) TYPE{ other.val_.type_ }; } else { - new (&val_.none_) none{}; + new (&val_.null_) null; } } @@ -467,22 +467,22 @@ original::alternative::operator=(const alternative& other) { return *this; this->destroy(); - this->non_none_type_ = other.non_none_type_; - if (other.non_none_type_) { + this->non_null_type_ = other.non_null_type_; + if (other.non_null_type_) { new (&val_.type_) TYPE{ other.val_.type_ }; } else { - new (&val_.none_) none{}; + new (&val_.null_) null; } return *this; } template original::alternative::alternative(alternative&& other) noexcept { - this->non_none_type_ = other.non_none_type_; - if (this->non_none_type_){ + this->non_null_type_ = other.non_null_type_; + if (this->non_null_type_){ new (&val_.type_) TYPE{ std::move(other.val_.type_) }; } else{ - new (&val_.none_) none{}; + new (&val_.null_) null; } } @@ -493,11 +493,11 @@ original::alternative::operator=(alternative&& other) noexcept { return *this; this->destroy(); - this->non_none_type_ = other.non_none_type_; - if (this->non_none_type_){ + this->non_null_type_ = other.non_null_type_; + if (this->non_null_type_){ new (&val_.type_) TYPE{ std::move(other.val_.type_) }; } else{ - new (&val_.none_) none{}; + new (&val_.null_) null; } return *this; } @@ -508,15 +508,15 @@ void original::alternative::swap(alternative& other) noexcept if (this == &other) return; - std::swap(this->non_none_type_, other.non_none_type_); + std::swap(this->non_null_type_, other.non_null_type_); std::swap(this->val_, other.val_); } template const TYPE& original::alternative::operator*() const { - if (!this->non_none_type_) - throw valueError("Dereferencing a original::none value"); + if (!this->non_null_type_) + throw valueError("Dereferencing a original::null value"); return this->val_.type_; } @@ -524,8 +524,8 @@ original::alternative::operator*() const { template TYPE& original::alternative::operator*() { - if (!this->non_none_type_) - throw valueError("Dereferencing a original::none value"); + if (!this->non_null_type_) + throw valueError("Dereferencing a original::null value"); return this->val_.type_; } @@ -533,8 +533,8 @@ original::alternative::operator*() { template const TYPE* original::alternative::operator->() const { - if (!this->non_none_type_) - throw valueError("Accessing member of a original::none value"); + if (!this->non_null_type_) + throw valueError("Accessing member of a original::null value"); return &this->val_.type_; } @@ -542,20 +542,20 @@ original::alternative::operator->() const { template TYPE* original::alternative::operator->() { - if (!this->non_none_type_) - throw valueError("Accessing member of a original::none value"); + if (!this->non_null_type_) + throw valueError("Accessing member of a original::null value"); return &this->val_.type_; } template const TYPE* original::alternative::get() const { - return this->non_none_type_ ? &this->val_.type_ : nullptr; + return this->non_null_type_ ? &this->val_.type_ : nullptr; } template TYPE* original::alternative::get() { - return this->non_none_type_ ? &this->val_.type_ : nullptr; + return this->non_null_type_ ? &this->val_.type_ : nullptr; } template @@ -567,14 +567,14 @@ template template void original::alternative::emplace(Args &&... args) { this->destroy(); - this->non_none_type_ = true; + this->non_null_type_ = true; new (&val_.type_) TYPE{ std::forward(args)... }; } template void original::alternative::set(const TYPE &t) { this->destroy(); - this->non_none_type_ = true; + this->non_null_type_ = true; new (&val_.type_) TYPE{ t }; } @@ -588,7 +588,7 @@ original::alternative::operator=(const TYPE& t) template original::alternative::operator bool() const { - return this->non_none_type_; + return this->non_null_type_; } template @@ -604,7 +604,7 @@ original::alternative::~alternative() { inline original::alternative::alternative() = default; -inline original::alternative::alternative(none) {} +inline original::alternative::alternative(null) {} inline original::alternative::alternative(std::in_place_t) : has_value_(true) {} @@ -621,7 +621,7 @@ original::alternative::operator=(std::in_place_t) noexcept } inline original::alternative& -original::alternative::operator=(none) noexcept +original::alternative::operator=(null) noexcept { this->reset(); return *this; diff --git a/src/core/randomAccessIterator.h b/src/core/randomAccessIterator.h index fd7305a..3c79b60 100644 --- a/src/core/randomAccessIterator.h +++ b/src/core/randomAccessIterator.h @@ -260,12 +260,12 @@ namespace original { auto* other_it = dynamic_cast(&other); if (other_it == nullptr) return this > &other ? - std::numeric_limits::max() : - std::numeric_limits::min(); + (std::numeric_limits::max)() : + (std::numeric_limits::min)(); if (this->_container != other_it->_container) return this->_container > other_it->_container ? - std::numeric_limits::max() : - std::numeric_limits::min(); + (std::numeric_limits::max)() : + (std::numeric_limits::min)(); return this->_ptr - other_it->_ptr; } diff --git a/src/core/sets.h b/src/core/sets.h index a9d0db9..9c784fd 100644 --- a/src/core/sets.h +++ b/src/core/sets.h @@ -708,8 +708,8 @@ namespace original { template , typename ALLOC = allocator>> - class JSet final : public skipList, - public set, + class JSet final : public set, + public skipList, public iterable, public printable { using skipListType = skipList; @@ -1653,8 +1653,8 @@ original::JSet::Iterator::operator-( auto other_it = dynamic_cast(&other); if (other_it == nullptr) return this > &other ? - std::numeric_limits::max() : - std::numeric_limits::min(); + (std::numeric_limits::max)() : + (std::numeric_limits::min)(); return skipListType::Iterator::operator-(*other_it); } @@ -1723,8 +1723,8 @@ bool original::JSet::Iterator::isValid() const { template original::JSet::JSet(Compare comp, ALLOC alloc) - : skipListType(std::move(comp)), - set(std::move(alloc)) {} + : set(std::move(alloc)), + skipListType(std::move(comp)) {} template original::JSet::JSet(const JSet& other) : JSet() { diff --git a/src/core/skipList.h b/src/core/skipList.h index 08c5367..96fa80d 100644 --- a/src/core/skipList.h +++ b/src/core/skipList.h @@ -43,7 +43,7 @@ namespace original { typename ALLOC = allocator, typename Compare = increaseComparator> class skipList { - protected: + public: /** * @class skipListNode * @brief Internal node class for Skip List @@ -366,7 +366,7 @@ namespace original { * @brief Destructor * @details Cleans up all list nodes and allocated memory */ - ~skipList(); + virtual ~skipList(); }; } @@ -517,12 +517,12 @@ template original::integer original::skipList::Iterator::operator-(const Iterator& other) const { if (const integer pos_dis = ptrDistance(&other, this); - pos_dis != std::numeric_limits::max()) return pos_dis; + pos_dis != (std::numeric_limits::max)()) return pos_dis; if (const integer neg_dis = ptrDistance(this, &other); - neg_dis != std::numeric_limits::max()) return -neg_dis; + neg_dis != (std::numeric_limits::max)()) return -neg_dis; return this->cur_ > other.cur_ ? - std::numeric_limits::max() : - std::numeric_limits::min(); + (std::numeric_limits::max)() : + (std::numeric_limits::min)(); } template @@ -564,7 +564,7 @@ original::skipList::Iterator::ptrDistance(const s->next(); } if (e->isValid()){ - dis = std::numeric_limits::max(); + dis = (std::numeric_limits::max)(); } return dis; } @@ -672,7 +672,10 @@ original::skipList::findLastNode() const { template original::skipList::skipList(Compare compare) - : size_(0), head_(this->createNode()), compare_(std::move(compare)) {} + : size_(0), head_(nullptr), compare_(std::move(compare)) +{ + this->head_ = this->createNode(); +} template original::skipList::skipListNode* diff --git a/src/core/stepIterator.h b/src/core/stepIterator.h index 8b037a8..2ab1079 100644 --- a/src/core/stepIterator.h +++ b/src/core/stepIterator.h @@ -199,7 +199,7 @@ namespace original s->next(); } if (e->isValid()){ - dis = std::numeric_limits::max(); + dis = (std::numeric_limits::max)(); } return dis; } @@ -302,15 +302,15 @@ namespace original auto* other_it = dynamic_cast(&other); if (other_it == nullptr) return this > &other ? - std::numeric_limits::max() : - std::numeric_limits::min(); + (std::numeric_limits::max)() : + (std::numeric_limits::min)(); if (const integer pos_dis = ptrDistance(other_it, this); - pos_dis != std::numeric_limits::max()) return pos_dis; + pos_dis != (std::numeric_limits::max)()) return pos_dis; if (const integer neg_dis = ptrDistance(this, other_it); - neg_dis != std::numeric_limits::max()) return -neg_dis; + neg_dis != (std::numeric_limits::max)()) return -neg_dis; return this->_ptr > other_it->_ptr ? - std::numeric_limits::max() : - std::numeric_limits::min(); + (std::numeric_limits::max)() : + (std::numeric_limits::min)(); } template diff --git a/src/core/types.h b/src/core/types.h index 0a2f997..b3717dd 100644 --- a/src/core/types.h +++ b/src/core/types.h @@ -24,19 +24,19 @@ namespace original { // ==================== Fundamental Types ==================== /** - * @class none + * @class null * @brief A placeholder type representing the absence of a value. * @details This class provides consteval operations and can be converted to bool, * always returning false. Useful for template metaprogramming and * representing empty states. */ - class none { + class null { public: /// @brief Default constructor (consteval) - consteval explicit none() = default; + consteval explicit null() = default; /// @brief Default destructor (constexpr) - constexpr ~none() = default; + constexpr ~null() = default; /** * @brief Bool conversion operator @@ -516,6 +516,26 @@ namespace original { c.pop_back(); }; + template + class some; + + template + class some + { + public: + using type = MATCH_TYPE; + }; + + template + class some + { + public: + using type = OTHER_TYPE; + }; + + template + using some_t = some::type; + // ==================== Compile-time Index Sequences ==================== /** @@ -642,11 +662,11 @@ namespace original { } // namespace original -consteval original::none::operator bool() const { +consteval original::null::operator bool() const { return false; } -consteval bool original::none::operator!() const { +consteval bool original::null::operator!() const { return true; } diff --git a/src/vibrant/async.h b/src/vibrant/async.h index 5312a7c..7bc0e15 100644 --- a/src/vibrant/async.h +++ b/src/vibrant/async.h @@ -31,8 +31,8 @@ namespace original { class asyncWrapper { atomic ready_{makeAtomic(false)}; ///< Atomic flag indicating result readiness strongPtr result_; ///< Storage of asynchronous computation result - mutable pCondition cond_{}; ///< Condition variable for synchronization - mutable pMutex mutex_{}; ///< Mutex for thread safety + mutable condition cond_{}; ///< Condition variable for synchronization + mutable mutex mutex_{}; ///< Mutex for thread safety std::exception_ptr e_{}; ///< Exception pointer for error handling public: @@ -48,7 +48,7 @@ namespace original { * @brief Sets an exception and marks as ready * @param e Exception pointer to store */ - void setException(std::exception_ptr e); + void setException(const std::exception_ptr& e); /** * @brief Checks if the result is ready @@ -66,7 +66,7 @@ namespace original { * @param timeout Maximum time to wait * @return True if result is ready within timeout, false otherwise */ - bool waitFor(time::duration timeout) const; + [[nodiscard]] bool waitFor(time::duration timeout) const; /** * @brief Retrieves the result value (blocks until ready) @@ -86,7 +86,7 @@ namespace original { * @brief Gets a strong pointer to the result value * @return Strong pointer to the result */ - strongPtr getPtr() const; + [[nodiscard]] strongPtr getPtr() const; /** * @brief Throws stored exception if present @@ -487,7 +487,7 @@ namespace original { * @return A new future holding the result of the callback */ template - auto operator|(async::sharedFuture sf, Callback&& c); + auto operator|(const async::sharedFuture& sf, Callback&& c); /** * @brief Pipe operator specialization for sharedFuture @@ -501,7 +501,7 @@ namespace original { * @return A new future holding the result of the callback */ template - auto operator|(async::sharedFuture sf, Callback&& c); + auto operator|(const async::sharedFuture& sf, Callback&& c); /** * @brief Lazy pipe operator for chaining promise computations @@ -556,8 +556,8 @@ namespace original { class async::asyncWrapper { atomic ready_{makeAtomic(false)}; ///< Atomic flag indicating completion alternative result_; ///< Mark of asynchronous computation status - mutable pCondition cond_{}; ///< Condition variable for synchronization - mutable pMutex mutex_{}; ///< Mutex for thread safety + mutable condition cond_{}; ///< Condition variable for synchronization + mutable mutex mutex_{}; ///< Mutex for thread safety std::exception_ptr e_{}; ///< Exception pointer for error handling public: @@ -572,7 +572,7 @@ namespace original { * @brief Sets an exception and marks as completed * @param e Exception pointer to store */ - void setException(std::exception_ptr e); + void setException(const std::exception_ptr& e); /** * @brief Checks if the computation is completed @@ -590,7 +590,7 @@ namespace original { * @param timeout Maximum time to wait * @return True if result is ready within timeout, false otherwise */ - bool waitFor(const time::duration& timeout) const; + [[nodiscard]] bool waitFor(const time::duration& timeout) const; /** * @brief Waits for completion and checks for exceptions @@ -838,11 +838,11 @@ void original::async::asyncWrapper::setValue(TYPE&& v) } template -void original::async::asyncWrapper::setException(std::exception_ptr e) +void original::async::asyncWrapper::setException(const std::exception_ptr &e) { { uniqueLock lock{this->mutex_}; - this->e_ = std::move(e); + this->e_ = e; this->ready_.store(true); } this->cond_.notifyAll(); @@ -1194,7 +1194,7 @@ auto original::operator|(async::future f, Callback&& c) } template -auto original::operator|(async::sharedFuture sf, Callback&& c) +auto original::operator|(const async::sharedFuture& sf, Callback&& c) { using ResultType = std::invoke_result_t; return async::get([sf, c = std::forward(c)] mutable -> ResultType { @@ -1203,7 +1203,7 @@ auto original::operator|(async::sharedFuture sf, Callback&& c) } template -auto original::operator|(async::sharedFuture sf, Callback&& c) +auto original::operator|(const async::sharedFuture& sf, Callback&& c) { using ResultType = std::invoke_result_t; return async::get([sf, c = std::forward(c)]() mutable -> ResultType { @@ -1249,11 +1249,11 @@ inline void original::async::asyncWrapper::setValue() this->cond_.notifyAll(); } -inline void original::async::asyncWrapper::setException(std::exception_ptr e) +inline void original::async::asyncWrapper::setException(const std::exception_ptr& e) { { uniqueLock lock{this->mutex_}; - this->e_ = std::move(e); + this->e_ = e; this->ready_.store(true); } this->cond_.notifyAll(); diff --git a/src/vibrant/atomic.h b/src/vibrant/atomic.h index 37d482d..bebfd3b 100644 --- a/src/vibrant/atomic.h +++ b/src/vibrant/atomic.h @@ -1,10 +1,19 @@ #ifndef ORIGINAL_ATOMIC_H #define ORIGINAL_ATOMIC_H -#include +#include "config.h" + +#if ORIGINAL_COMPILER_GCC || ORIGINAL_COMPILER_CLANG #include +#elif ORIGINAL_COMPILER_MSVC +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#include +#endif + #include "optional.h" -#include "config.h" #include "mutex.h" namespace original { @@ -62,7 +71,7 @@ namespace original { */ template class atomicImpl { - alignas(TYPE) byte data_[sizeof(TYPE)]; ///< Properly aligned storage + alignas(TYPE) byte data_[sizeof(TYPE)]{}; ///< Properly aligned storage /** * @brief Default constructor (zero-initializes storage) @@ -126,7 +135,7 @@ namespace original { * @brief Assignment operator (atomically stores value) * @param value Value to store */ - void operator=(TYPE value) noexcept; + atomicImpl& operator=(TYPE value) noexcept; /** * @brief Atomic addition assignment @@ -246,7 +255,7 @@ namespace original { * @brief Assignment operator (atomically stores value) * @param value Value to store */ - void operator=(TYPE value) noexcept; + atomicImpl& operator=(TYPE value) noexcept; /** * @brief Atomic addition assignment @@ -289,7 +298,131 @@ namespace original { template friend auto makeAtomic(T value); }; +#elif ORIGINAL_COMPILER_MSVC + enum class memOrder { + RELAXED, + ACQUIRE, + RELEASE, + ACQ_REL, + SEQ_CST, + }; + + template + constexpr bool isLockFreeType() noexcept; + + template + class atomicImpl; + + template + using atomic = atomicImpl()>; + + template + class atomicImpl + { + using val_type = some_t; + + alignas(TYPE) volatile TYPE data_{}; + + template + static To atomicCastTo(From value); + + template + static To atomicCastBack(From value); + + atomicImpl(); + + explicit atomicImpl(TYPE value, memOrder order = SEQ_CST); + public: + static constexpr auto RELAXED = memOrder::RELAXED; + static constexpr auto ACQUIRE = memOrder::ACQUIRE; + static constexpr auto RELEASE = memOrder::RELEASE; + static constexpr auto ACQ_REL = memOrder::ACQ_REL; + static constexpr auto SEQ_CST = memOrder::SEQ_CST; + + atomicImpl(const atomicImpl&) = delete; + atomicImpl(atomicImpl&&) = delete; + atomicImpl& operator=(const atomicImpl&) = delete; + atomicImpl& operator=(atomicImpl&&) = delete; + + static constexpr bool isLockFree() noexcept; + + void store(TYPE value, memOrder order = SEQ_CST); + + TYPE load(memOrder order = SEQ_CST) const noexcept; + + TYPE operator*() const noexcept; + + explicit operator TYPE() const noexcept; + + atomicImpl& operator=(TYPE value) noexcept; + + atomicImpl& operator+=(TYPE value) noexcept; + + atomicImpl& operator-=(TYPE value) noexcept; + + TYPE exchange(TYPE value, memOrder order = SEQ_CST) noexcept; + + bool exchangeCmp(TYPE& expected, TYPE desired, memOrder order = SEQ_CST) noexcept; + + ~atomicImpl() = default; + + template + friend auto makeAtomic(); + + template + friend auto makeAtomic(T value); + }; + + template + class atomicImpl + { + mutable wMutex mutex_; + alternative data_; + + atomicImpl() = default; + + explicit atomicImpl(TYPE value, memOrder order = RELEASE); + public: + static constexpr auto RELAXED = memOrder::RELAXED; + static constexpr auto ACQUIRE = memOrder::ACQUIRE; + static constexpr auto RELEASE = memOrder::RELEASE; + static constexpr auto ACQ_REL = memOrder::ACQ_REL; + static constexpr auto SEQ_CST = memOrder::SEQ_CST; + + atomicImpl(const atomicImpl&) = delete; + atomicImpl(atomicImpl&&) = delete; + atomicImpl& operator=(const atomicImpl&) = delete; + atomicImpl& operator=(atomicImpl&&) = delete; + + static constexpr bool isLockFree() noexcept; + + void store(TYPE value, memOrder order = SEQ_CST); + + TYPE load(memOrder order = SEQ_CST) const noexcept; + + TYPE operator*() const noexcept; + explicit operator TYPE() const noexcept; + + atomicImpl& operator=(TYPE value) noexcept; + + atomicImpl& operator+=(TYPE value) noexcept; + + atomicImpl& operator-=(TYPE value) noexcept; + + TYPE exchange(const TYPE& value, memOrder order = SEQ_CST) noexcept; + + bool exchangeCmp(TYPE& expected, const TYPE& desired, memOrder order = SEQ_CST) noexcept; + + ~atomicImpl() = default; + + template + friend auto makeAtomic(); + + template + friend auto makeAtomic(T value); + }; +#endif // ==================== Factory Functions ==================== /** @@ -311,6 +444,7 @@ namespace original { } // namespace original +#if ORIGINAL_COMPILER_GCC || ORIGINAL_COMPILER_CLANG template original::atomicImpl::atomicImpl() { std::memset(this->data_, byte{}, sizeof(TYPE)); @@ -351,9 +485,10 @@ original::atomicImpl::operator TYPE() const noexcept } template -void original::atomicImpl::operator=(TYPE value) noexcept +original::atomicImpl& original::atomicImpl::operator=(TYPE value) noexcept { this->store(std::move(value)); + return *this; } template @@ -422,9 +557,271 @@ original::atomicImpl::operator TYPE() const noexcept } template -void original::atomicImpl::operator=(TYPE value) noexcept +original::atomicImpl& +original::atomicImpl::operator=(TYPE value) noexcept +{ + this->store(std::move(value)); + return *this; +} + +template +original::atomicImpl& original::atomicImpl::operator+=(TYPE value) noexcept +{ + uniqueLock lock{this->mutex_}; + TYPE result = *this->data_ + value; + this->data_.set(result); + return *this; +} + +template +original::atomicImpl& original::atomicImpl::operator-=(TYPE value) noexcept +{ + uniqueLock lock{this->mutex_}; + TYPE result = *this->data_ - value; + this->data_.set(result); + return *this; +} + +template +TYPE original::atomicImpl::exchange(const TYPE& value, memOrder) noexcept { + uniqueLock lock{this->mutex_}; + TYPE result = *this->data_; + this->data_.set(value); + return result; +} + +template +bool original::atomicImpl::exchangeCmp(TYPE& expected, const TYPE& desired, memOrder) noexcept { + uniqueLock lock{this->mutex_}; + if (*this->data_ == expected) { + this->data_.set(desired); + return true; + } + expected = *this->data_; + return false; +} +#elif ORIGINAL_COMPILER_MSVC + +template +constexpr bool original::isLockFreeType() noexcept { + return sizeof(TYPE) == 4 || sizeof(TYPE) == 8; +} + +template +template +To original::atomicImpl::atomicCastTo(From value) +{ + if constexpr (std::is_pointer_v) { + return reinterpret_cast(value); + } else { + return static_cast(value); + } +} + +template +template +To original::atomicImpl::atomicCastBack(From value) +{ + if constexpr (std::is_pointer_v) { + return reinterpret_cast(value); + } else { + return static_cast(value); + } +} + +template +original::atomicImpl::atomicImpl() +{ + std::memset(this->data_, byte{}, sizeof(TYPE)); +} + +template +original::atomicImpl::atomicImpl(TYPE value, const memOrder order) +{ + this->store(value, order); +} + +template +constexpr bool +original::atomicImpl::isLockFree() noexcept +{ + return true; +} + +template +void original::atomicImpl::store(TYPE value, const memOrder order) +{ + switch (order) { + case memOrder::RELAXED: + this->data_ = value; + break; + case memOrder::RELEASE: + _WriteBarrier(); + this->data_ = value; + break; + case memOrder::SEQ_CST: + default: + if constexpr (sizeof(TYPE) == 4) { + InterlockedExchange(reinterpret_cast(&this->data_), + atomicCastTo(value)); + } else { + InterlockedExchange64(reinterpret_cast(&this->data_), + atomicCastTo(value)); + } + break; + } +} + +template +TYPE original::atomicImpl::load(const memOrder order) const noexcept +{ + TYPE value; + switch (order) { + case memOrder::RELAXED: + value = this->data_; + break; + case memOrder::ACQUIRE: + value = this->data_; + _ReadBarrier(); + break; + case memOrder::SEQ_CST: + default: + if constexpr (sizeof(TYPE) == 4) { + return atomicCastBack( + InterlockedCompareExchange( + reinterpret_cast(const_cast(&this->data_)), + 0, 0)); + } else { + return atomicCastBack( + InterlockedCompareExchange64( + reinterpret_cast(const_cast(&this->data_)), + 0, 0)); + } + break; + } + return value; +} + +template +TYPE original::atomicImpl::operator*() const noexcept +{ + return this->load(); +} + +template +original::atomicImpl::operator TYPE() const noexcept +{ + return this->load(); +} + +template +original::atomicImpl& +original::atomicImpl::operator=(TYPE value) noexcept +{ + this->store(std::move(value)); + return *this; +} + +template +original::atomicImpl& +original::atomicImpl::operator+=(TYPE value) noexcept +{ + if constexpr (sizeof(TYPE) == 4) { + InterlockedAdd(reinterpret_cast(&this->data_), + atomicCastTo(value)); + } else { + InterlockedAdd64(reinterpret_cast(&this->data_), + atomicCastTo(value)); + } + return *this; +} + +template +original::atomicImpl& +original::atomicImpl::operator-=(TYPE value) noexcept +{ + return *this += -value; +} + +template +TYPE original::atomicImpl::exchange(TYPE value, memOrder) noexcept +{ + if constexpr (sizeof(TYPE) == 4) { + return atomicCastBack( + InterlockedExchange(reinterpret_cast(&this->data_), + atomicCastTo(value)) + ); + } else { + return atomicCastBack( + InterlockedExchange64(reinterpret_cast(&this->data_), + atomicCastTo(value)) + ); + } +} + +template +bool original::atomicImpl::exchangeCmp(TYPE& expected, TYPE desired, memOrder) noexcept +{ + if constexpr (sizeof(TYPE) == 4) { + val_type old = InterlockedCompareExchange( + reinterpret_cast(&this->data_), + atomicCastTo(desired), + atomicCastTo(expected)); + const bool success = old == atomicCastTo(expected); + if (!success) expected = atomicCastBack(old); + return success; + } else { + val_type old = InterlockedCompareExchange64( + reinterpret_cast(&this->data_), + atomicCastTo(desired), + atomicCastTo(expected)); + const bool success = old == atomicCastTo(expected); + if (!success) expected = atomicCastBack(old); + return success; + } +} + +template +original::atomicImpl::atomicImpl(TYPE value, memOrder) { + uniqueLock lock{this->mutex_}; + this->data_.set(value); +} + +template +constexpr bool original::atomicImpl::isLockFree() noexcept { + return false; +} + +template +void original::atomicImpl::store(TYPE value, memOrder) { + uniqueLock lock{this->mutex_}; + this->data_.set(value); +} + +template +TYPE original::atomicImpl::load(memOrder) const noexcept { + uniqueLock lock{this->mutex_}; + return *this->data_; +} + +template +TYPE original::atomicImpl::operator*() const noexcept +{ + return this->load(); +} + +template +original::atomicImpl::operator TYPE() const noexcept +{ + return this->load(); +} + +template +original::atomicImpl& +original::atomicImpl::operator=(TYPE value) noexcept { this->store(std::move(value)); + return *this; } template @@ -464,6 +861,8 @@ bool original::atomicImpl::exchangeCmp(TYPE& expected, const TYPE& d return false; } +#endif + template auto original::makeAtomic() { @@ -476,4 +875,3 @@ auto original::makeAtomic(TYPE value) return atomic{std::move(value)}; } #endif -#endif diff --git a/src/vibrant/condition.h b/src/vibrant/condition.h index 02309ec..fda5e63 100644 --- a/src/vibrant/condition.h +++ b/src/vibrant/condition.h @@ -1,5 +1,11 @@ #ifndef CONDITION_H #define CONDITION_H + +#if ORIGINAL_COMPILER_GCC || ORIGINAL_COMPILER_CLANG +#include +#elif ORIGINAL_COMPILER_MSVC +#endif + #include "mutex.h" #include "zeit.h" @@ -118,6 +124,7 @@ namespace original conditionBase& operator=(const conditionBase&) = delete; }; +#if ORIGINAL_COMPILER_GCC || ORIGINAL_COMPILER_CLANG /** * @class pCondition * @brief POSIX condition variable implementation @@ -176,8 +183,52 @@ namespace original */ ~pCondition() override; }; -} +#elif ORIGINAL_COMPILER_MSVC + class wCondition final : public conditionBase + { + CONDITION_VARIABLE cond_; + public: + using conditionBase::wait; + using conditionBase::waitFor; + + explicit wCondition(); + + void wait(mutexBase& mutex) override; + + bool waitFor(mutexBase& mutex, time::duration d) override; + + void notify() override; + + void notifyAll() override; + + ~wCondition() override; + }; +#endif + + class condition final : public conditionBase { + #if ORIGINAL_COMPILER_GCC || ORIGINAL_COMPILER_CLANG + pCondition cond_; + #elif ORIGINAL_COMPILER_MSVC + wCondition cond_; + #endif + + public: + using conditionBase::wait; + using conditionBase::waitFor; + + condition(); + + void wait(mutexBase& mutex) override; + + bool waitFor(mutexBase& mutex, time::duration d) override; + + void notify() override; + + void notifyAll() override; + }; + +} template void original::conditionBase::wait(mutexBase& mutex, Pred predicate) noexcept(noexcept(predicate())) { while (!predicate()){ @@ -211,6 +262,7 @@ inline void original::conditionBase::notifySome(const u_integer n) { } } +#if ORIGINAL_COMPILER_GCC || ORIGINAL_COMPILER_CLANG inline original::pCondition::pCondition() : cond_{} { if (const int code = pthread_cond_init(&this->cond_, nullptr); code != 0) @@ -221,12 +273,9 @@ inline original::pCondition::pCondition() : cond_{} inline void original::pCondition::wait(mutexBase& mutex) { - const auto p_mutex = dynamic_cast(&mutex); - if (!p_mutex) { - throw valueError("Invalid mutex type for condition variable: must be pMutex"); - } + staticError>::asserts(); - const auto handle = static_cast(p_mutex->nativeHandle()); + const auto handle = static_cast(mutex.nativeHandle()); if (const int code = pthread_cond_wait(&this->cond_, handle); code != 0) { throw sysError("Failed to wait on condition variable (pthread_cond_wait returned " + printable::formatString(code) + ")"); } @@ -234,14 +283,11 @@ inline void original::pCondition::wait(mutexBase& mutex) inline bool original::pCondition::waitFor(mutexBase& mutex, const time::duration d) { - const auto p_mutex = dynamic_cast(&mutex); - if (!p_mutex) { - throw valueError("Invalid mutex type for condition variable: must be pMutex"); - } + staticError>::asserts(); const auto deadline = time::point::now() + d; const auto ts = deadline.toTimespec(); - const auto handle = static_cast(p_mutex->nativeHandle()); + const auto handle = static_cast(mutex.nativeHandle()); const int code = pthread_cond_timedwait(&this->cond_, handle, &ts); if (code == 0) return true; if (code == ETIMEDOUT) return false; @@ -269,5 +315,69 @@ inline original::pCondition::~pCondition() << code << ")" << std::endl; } } +#elif ORIGINAL_COMPILER_MSVC +inline original::wCondition::wCondition() : cond_{} +{ + InitializeConditionVariable(&this->cond_); +} + +inline void original::wCondition::wait(mutexBase& mutex) +{ + if (const auto handle = static_cast(mutex.nativeHandle()); + !SleepConditionVariableSRW(&this->cond_, handle, INFINITE, 0)) { + throw sysError("Failed to wait on condition variable (SleepConditionVariableSRW returned error " + + printable::formatString(GetLastError())); + } +} + +inline bool original::wCondition::waitFor(mutexBase& mutex, const time::duration d) +{ + const auto handle = static_cast(mutex.nativeHandle()); + if (const auto timeout_ms = d.toDWMilliseconds(); + !SleepConditionVariableSRW(&this->cond_, handle, timeout_ms, 0)) { + const DWORD error = GetLastError(); + if (error == ERROR_TIMEOUT) { + return false; + } + throw sysError("Failed to timed wait on condition variable (SleepConditionVariableSRW returned error " + + printable::formatString(error)); + } + return true; +} + +inline void original::wCondition::notify() +{ + WakeConditionVariable(&this->cond_); +} + +inline void original::wCondition::notifyAll() +{ + WakeAllConditionVariable(&this->cond_); +} + +inline original::wCondition::~wCondition() = default; +#endif + +inline original::condition::condition() = default; + +inline void original::condition::wait(mutexBase& mutex) +{ + this->cond_.wait(mutex); +} + +inline bool original::condition::waitFor(mutexBase& mutex, time::duration d) +{ + return this->cond_.waitFor(mutex, d); +} + +inline void original::condition::notify() +{ + this->cond_.notify(); +} + +inline void original::condition::notifyAll() +{ + this->cond_.notifyAll(); +} #endif //CONDITION_H diff --git a/src/vibrant/coroutines.h b/src/vibrant/coroutines.h index ed28af6..108d302 100644 --- a/src/vibrant/coroutines.h +++ b/src/vibrant/coroutines.h @@ -55,6 +55,14 @@ namespace original { */ template class generator { + public: + struct promise_type; + private: + using handle = std::coroutine_handle; ///< Coroutine handle type + + handle handle_; ///< Underlying coroutine handle + + public: /** * @struct promise_type * @brief Implements the coroutine promise interface for generator @@ -168,14 +176,6 @@ namespace original { bool operator==(const iterator& other) const; }; - using handle = std::coroutine_handle; ///< Coroutine handle type - - handle handle_; ///< Underlying coroutine handle - - public: - using promise_type = promise_type; ///< Promise type for coroutine protocol - using iterator = iterator; ///< Iterator type for range operations - generator(const generator&) = delete; ///< Copy constructor deleted generator& operator=(const generator&) = delete; ///< Copy assignment deleted diff --git a/src/vibrant/generators.h b/src/vibrant/generators.h index f07bd81..14bd26a 100644 --- a/src/vibrant/generators.h +++ b/src/vibrant/generators.h @@ -3,6 +3,7 @@ #include "coroutines.h" #include "couple.h" #include "sets.h" +#include "vector.h" namespace original { @@ -26,45 +27,6 @@ namespace original { template coroutine::generator> enumerate(coroutine::generator gen); - /** - * @brief Collects generator elements into a set. - * @tparam TYPE The type of elements in the generator. - * @tparam SET The set type to collect into (default: hashSet). - * @param gen The generator to collect from. - * @return A set containing all unique elements from the generator. - * @details Transforms a generator sequence into a set container, removing duplicates - * and providing fast lookup capabilities. - * - * Example: - * @code - * auto vec = vector{1, 2, 2, 3, 3, 3}; - * auto gen = vec.generator(); - * auto set = collect(gen); // {1, 2, 3} - * @endcode - */ - template> - requires ExtendsOf>>, SET> - SET collect(coroutine::generator gen); - - /** - * @brief Collects generator elements into a list container. - * @tparam TYPE The type of elements in the generator. - * @tparam SERIAL The list container type (default: vector). - * @param gen The generator to collect from. - * @return A list container with all generator elements in order. - * @details Converts a generator sequence into a concrete list container, - * preserving element order and allowing random access. - * - * Example: - * @code - * auto gen = someContainer.generator(); - * auto vec = list(gen); // Creates vector with all elements - * @endcode - */ - template typename SERIAL = vector> - requires ExtendsOf>, SERIAL> - SERIAL list(coroutine::generator gen); - /** * @brief Transforms generator elements using a callable. * @tparam TYPE The input element type. @@ -644,42 +606,73 @@ namespace original { */ template auto find(F&& f); -} -template -original::coroutine::generator> -original::enumerate(coroutine::generator gen) -{ - u_integer i = 0; - for (auto elem : gen) + /** + * @brief Collects generator elements into a set. + * @tparam TYPE The type of elements in the generator. + * @tparam SET The set type to collect into (default: hashSet). + * @param gen The generator to collect from. + * @return A set containing all unique elements from the generator. + * @details Transforms a generator sequence into a set container, removing duplicates + * and providing fast lookup capabilities. + * + * Example: + * @code + * auto vec = vector{1, 2, 2, 3, 3, 3}; + * auto gen = vec.generator(); + * auto set = collect(gen); // {1, 2, 3} + * @endcode + */ + template> + requires original::ExtendsOf>>, SET> + SET collect(coroutine::generator gen) { - co_yield {i, elem}; - i += 1; + SET set; + for (auto elem : gen) + { + set.add(elem); + } + return set; } -} -template -requires original::ExtendsOf>>, SET> -SET original::collect(coroutine::generator gen) -{ - SET set; - for (auto elem : gen) + /** + * @brief Collects generator elements into a list container. + * @tparam TYPE The type of elements in the generator. + * @tparam SERIAL The list container type (default: vector). + * @param gen The generator to collect from. + * @return A list container with all generator elements in order. + * @details Converts a generator sequence into a concrete list container, + * preserving element order and allowing random access. + * + * Example: + * @code + * auto gen = someContainer.generator(); + * auto vec = list(gen); // Creates vector with all elements + * @endcode + */ + template typename SERIAL = vector> + requires original::ExtendsOf>, SERIAL> + SERIAL list(coroutine::generator gen) { - set.add(elem); + SERIAL list; + for (auto elem : gen) + { + list.pushEnd(elem); + } + return list; } - return set; } -template class SERIAL> -requires original::ExtendsOf>, SERIAL> -SERIAL original::list(coroutine::generator gen) +template +original::coroutine::generator> +original::enumerate(coroutine::generator gen) { - SERIAL list; + u_integer i = 0; for (auto elem : gen) { - list.pushEnd(elem); + co_yield {i, elem}; + i += 1; } - return list; } template diff --git a/src/vibrant/mutex.h b/src/vibrant/mutex.h index d280d61..c7306f9 100644 --- a/src/vibrant/mutex.h +++ b/src/vibrant/mutex.h @@ -1,9 +1,16 @@ #ifndef MUTEX_H #define MUTEX_H +#include "config.h" + +#if ORIGINAL_COMPILER_GCC || ORIGINAL_COMPILER_CLANG #include "pthread.h" +#elif ORIGINAL_COMPILER_MSVC +#endif + #include "error.h" #include "tuple.h" +#include "zeit.h" #include /** @@ -28,7 +35,7 @@ namespace original { * Derived classes must implement all pure virtual methods. */ class mutexBase { - protected: + public: /** * @brief Locks the mutex, blocking if necessary * @throws sysError if the lock operation fails @@ -54,7 +61,6 @@ namespace original { */ [[nodiscard]] virtual ul_integer id() const = 0; - public: /// Default constructor explicit mutexBase() = default; @@ -142,6 +148,7 @@ namespace original { virtual ~lockGuard() = default; }; +#if ORIGINAL_COMPILER_GCC || ORIGINAL_COMPILER_CLANG /** * @class pMutex * @brief POSIX thread mutex implementation @@ -151,7 +158,7 @@ namespace original { * and cleanup. */ class pMutex final : public mutexBase { - pthread_mutex_t mutex_; ///< Internal POSIX mutex handle + pthread_mutex_t mutex_{}; ///< Internal POSIX mutex handle public: /// Native handle type (pthread_mutex_t) using native_handle = pthread_mutex_t; @@ -205,6 +212,63 @@ namespace original { */ ~pMutex() override; }; +#elif ORIGINAL_COMPILER_MSVC + class wMutex final : public mutexBase { + SRWLOCK lock_; + public: + using native_handle = SRWLOCK; + + explicit wMutex(); + + wMutex(wMutex&&) = delete; + + wMutex& operator=(wMutex&&) = delete; + + [[nodiscard]] ul_integer id() const override; + + [[nodiscard]] void* nativeHandle() noexcept override; + + void lock() override; + + bool tryLock() override; + + void unlock() override; + + ~wMutex() override; + }; +#endif + + class mutex final : public mutexBase { + #if ORIGINAL_COMPILER_GCC || ORIGINAL_COMPILER_CLANG + pMutex mutex_; + #elif ORIGINAL_COMPILER_MSVC + wMutex mutex_; + #endif + + public: + using native_handle = + #if ORIGINAL_COMPILER_GCC || ORIGINAL_COMPILER_CLANG + pMutex::native_handle; + #elif ORIGINAL_COMPILER_MSVC + wMutex::native_handle; + #endif + + mutex(); + + mutex(mutex&&) = delete; + + mutex& operator=(mutex&) = delete; + + [[nodiscard]] ul_integer id() const override; + + [[nodiscard]] void* nativeHandle() noexcept override; + + void lock() override; + + bool tryLock() override; + + void unlock() override; + }; /** * @class uniqueLock @@ -214,17 +278,17 @@ namespace original { * with various locking policies. */ class uniqueLock final : public lockGuard { - pMutex& p_mutex_; ///< Reference to managed mutex + mutexBase& mutex_; ///< Reference to managed mutex bool is_locked; ///< Current lock state public: /** * @brief Constructs a uniqueLock with specified policy - * @param p_mutex Mutex to manage + * @param mutex Mutex to manage * @param policy Locking policy (default: AUTO_LOCK) * @throws sysError if locking fails */ - explicit uniqueLock(pMutex& p_mutex, lockPolicy policy = AUTO_LOCK); + explicit uniqueLock(mutexBase& mutex, lockPolicy policy = AUTO_LOCK); /// Deleted move constructor uniqueLock(uniqueLock&&) = delete; @@ -352,6 +416,7 @@ namespace original { }; } +#if ORIGINAL_COMPILER_GCC || ORIGINAL_COMPILER_CLANG inline original::pMutex::pMutex() : mutex_{} { if (const int code = pthread_mutex_init(&this->mutex_, nullptr); code != 0){ @@ -401,9 +466,70 @@ inline original::pMutex::~pMutex() { std::terminate(); } } +#elif ORIGINAL_COMPILER_MSVC +inline original::wMutex::wMutex() +{ + InitializeSRWLock(&this->lock_); +} + +inline original::ul_integer original::wMutex::id() const +{ + return reinterpret_cast(&this->lock_); +} + +inline void* original::wMutex::nativeHandle() noexcept +{ + return &this->lock_; +} + +inline void original::wMutex::lock() +{ + AcquireSRWLockExclusive(&this->lock_); +} + +inline bool original::wMutex::tryLock() +{ + return TryAcquireSRWLockExclusive(&this->lock_) != 0; +} + +inline void original::wMutex::unlock() +{ + ReleaseSRWLockExclusive(&this->lock_); +} + +inline original::wMutex::~wMutex() = default; + +#endif + +inline original::mutex::mutex() = default; + +inline original::ul_integer original::mutex::id() const +{ + return this->mutex_.id(); +} + +inline void* original::mutex::nativeHandle() noexcept +{ + return this->mutex_.nativeHandle(); +} + +inline void original::mutex::lock() +{ + this->mutex_.lock(); +} + +inline bool original::mutex::tryLock() +{ + return this->mutex_.tryLock(); +} + +inline void original::mutex::unlock() +{ + this->mutex_.unlock(); +} -inline original::uniqueLock::uniqueLock(pMutex& p_mutex, lockPolicy policy) - : p_mutex_(p_mutex), is_locked(false) { +inline original::uniqueLock::uniqueLock(mutexBase& mutex, const lockPolicy policy) + : mutex_(mutex), is_locked(false) { switch (policy) { case MANUAL_LOCK: break; @@ -426,7 +552,7 @@ inline void original::uniqueLock::lock() { if (this->is_locked) throw sysError("Cannot lock uniqueLock: already locked"); - this->p_mutex_.lock(); + this->mutex_.lock(); this->is_locked = true; } @@ -434,13 +560,13 @@ inline bool original::uniqueLock::tryLock() { if (this->is_locked) throw sysError("Cannot try-lock uniqueLock: already locked"); - this->is_locked = this->p_mutex_.tryLock(); + this->is_locked = this->mutex_.tryLock(); return this->is_locked; } inline void original::uniqueLock::unlock() { if (this->is_locked){ - this->p_mutex_.unlock(); + this->mutex_.unlock(); this->is_locked = false; } } diff --git a/src/vibrant/semaphores.h b/src/vibrant/semaphores.h index 437bbd0..9488fef 100644 --- a/src/vibrant/semaphores.h +++ b/src/vibrant/semaphores.h @@ -47,8 +47,8 @@ namespace original { template class semaphore { u_integer count_; ///< Current semaphore count - pMutex mutex_; ///< Mutex for synchronization - pCondition condition_; ///< Condition variable for waiting + mutex mutex_; ///< Mutex for synchronization + condition condition_; ///< Condition variable for waiting public: /** @@ -128,8 +128,8 @@ namespace original { template<> class semaphore<0> { u_integer count_; ///< Current semaphore count (unbounded) - pMutex mutex_; ///< Mutex for synchronization - pCondition condition_; ///< Condition variable for waiting + mutex mutex_; ///< Mutex for synchronization + condition condition_; ///< Condition variable for waiting public: /** diff --git a/src/vibrant/syncPoint.h b/src/vibrant/syncPoint.h index fd1c616..bb3b2a1 100644 --- a/src/vibrant/syncPoint.h +++ b/src/vibrant/syncPoint.h @@ -25,8 +25,8 @@ namespace original { const u_integer max_arrived_; ///< Maximum number of threads required for synchronization u_integer arrived_; ///< Current number of arrived threads u_integer round_; ///< Current synchronization round - mutable pMutex mutex_; ///< Mutex for thread synchronization - mutable pCondition condition_; ///< Condition variable for thread waiting + mutable mutex mutex_; ///< Mutex for thread synchronization + mutable condition condition_; ///< Condition variable for thread waiting std::function complete_func_; ///< Completion function called by last thread std::exception_ptr e_; ///< Exception pointer for propagating completion function errors @@ -111,7 +111,7 @@ inline void original::syncPoint::arrive() { lock.unlock(); this->condition_.notifyAll(); if (this->e_) { - throw this->e_; + std::rethrow_exception(this->e_); } } } diff --git a/src/vibrant/tasks.h b/src/vibrant/tasks.h index 4e9a7b4..588fdc0 100644 --- a/src/vibrant/tasks.h +++ b/src/vibrant/tasks.h @@ -47,6 +47,7 @@ namespace original { * manually activated or discarded on shutdown. */ class taskDelegator { + public: // ==================== Task Base Interface ==================== /** @@ -111,7 +112,6 @@ namespace original { async::future getFuture(); }; - public: // ==================== Task Priorities ==================== /** @@ -172,8 +172,8 @@ namespace original { priorityTaskQueue tasks_waiting_; ///< Waiting tasks queue> task_immediate_; ///< Immediate tasks queue> tasks_deferred_; ///< Deferred tasks - mutable pCondition condition_; ///< Synchronization - mutable pMutex mutex_; ///< Mutex for thread safety + mutable condition condition_; ///< Synchronization + mutable mutex mutex_; ///< Mutex for thread safety bool stopped_; ///< Stop flag u_integer active_threads_; ///< Count of active threads u_integer idle_threads_; ///< Count of idle threads diff --git a/src/vibrant/thread.h b/src/vibrant/thread.h index 7653a3d..e0cb3a6 100644 --- a/src/vibrant/thread.h +++ b/src/vibrant/thread.h @@ -1,9 +1,19 @@ #ifndef THREAD_H #define THREAD_H +#include "config.h" + +#if ORIGINAL_COMPILER_GCC || ORIGINAL_COMPILER_CLANG +#include "pthread.h" +#elif ORIGINAL_COMPILER_MSVC +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#endif + #include "error.h" #include "functional" -#include "pthread.h" +#include "hash.h" #include "ownerPtr.h" #include "zeit.h" @@ -140,6 +150,7 @@ namespace original { std::string toString(bool enter) const override; }; +#if ORIGINAL_COMPILER_GCC || ORIGINAL_COMPILER_CLANG /** * @class pThread * @brief POSIX thread implementation @@ -231,6 +242,39 @@ namespace original { */ ~pThread() override; }; +#elif ORIGINAL_COMPILER_MSVC + class wThread final : public threadBase { + HANDLE handle; + bool is_joinable; + + [[nodiscard]] bool valid() const override; + public: + explicit wThread(); + + template + explicit wThread(Callback c, ARGS&&... args...); + + wThread(wThread&& other) noexcept; + + wThread& operator=(wThread&& other) noexcept; + + [[nodiscard]] ul_integer id() const override; + + [[nodiscard]] bool joinable() const override; + + integer compareTo(const wThread &other) const override; + + u_integer toHash() const noexcept override; + + std::string className() const override; + + void join() override; + + void detach() override; + + ~wThread() override; + }; +#endif /** * @class thread @@ -261,7 +305,11 @@ namespace original { * @see original::thread::joinPolicy */ class thread final : public threadBase { + #if ORIGINAL_COMPILER_GCC || ORIGINAL_COMPILER_CLANG pThread thread_; ///< Underlying thread implementation + #elif ORIGINAL_COMPILER_MSVC + wThread thread_; + #endif bool will_join; ///< Join policy flag /** @@ -335,6 +383,7 @@ namespace original { template explicit thread(Callback c, joinPolicy policy, ARGS&&... args); +#if ORIGINAL_COMPILER_GCC || ORIGINAL_COMPILER_CLANG /** * @brief Construct a thread from an existing pThread with a join policy * @param p_thread The POSIX thread wrapper to take ownership of @@ -342,6 +391,9 @@ namespace original { * @post Takes ownership of the thread and applies the specified join policy */ explicit thread(pThread p_thread, joinPolicy policy = AUTO_JOIN); +#elif ORIGINAL_COMPILER_MSVC + explicit thread(wThread w_thread, joinPolicy policy = AUTO_JOIN); +#endif thread(const thread&) = delete; ///< Deleted copy constructor thread& operator=(const thread&) = delete; ///< Deleted copy assignment @@ -382,11 +434,11 @@ namespace original { */ [[nodiscard]] bool joinable() const override; - integer compareTo(const thread &other) const override; + [[nodiscard]] integer compareTo(const thread &other) const override; - u_integer toHash() const noexcept override; + [[nodiscard]] u_integer toHash() const noexcept override; - std::string className() const override; + [[nodiscard]] std::string className() const override; /** * @brief Wait for thread to complete @@ -457,7 +509,7 @@ std::string original::threadBase::toString(bool enter) const { ss << "\n"; return ss.str(); } - +#if ORIGINAL_COMPILER_GCC || ORIGINAL_COMPILER_CLANG inline original::pThread::pThread() : handle(), is_joinable() {} template @@ -567,6 +619,116 @@ inline original::pThread::~pThread() } } } +#elif ORIGINAL_COMPILER_MSVC +inline bool original::wThread::valid() const +{ + return this->handle != HANDLE{}; +} + +inline original::wThread::wThread() : handle(), is_joinable() {} + +template +original::wThread::wThread(Callback c, ARGS&&... args, ...) : handle(), is_joinable(true) +{ + auto bound_lambda = + [func = std::forward(c), ...lambda_args = std::forward(args)]() mutable { + std::invoke(std::move(func), std::move(lambda_args)...); + }; + + using bound_callback = decltype(bound_lambda); + using bound_thread_data = threadData; + + auto task = new bound_thread_data(std::move(bound_lambda)); + + static auto threadEntry = [](LPVOID param) -> DWORD { + bound_thread_data::run(param); + return 0; + }; + + this->handle = CreateThread(nullptr, 0, threadEntry, task, 0, nullptr); + if (this->handle == nullptr) { + delete task; + throw sysError("Failed to create thread (CreateThread returned null)"); + } +} + +inline original::wThread::wThread(wThread&& other) noexcept : wThread() +{ + this->operator=(std::move(other)); +} + +inline original::wThread& original::wThread::operator=(wThread&& other) noexcept +{ + if (this == &other) { + return *this; + } + + if (this->is_joinable && this->valid()) { + CloseHandle(this->handle); + } + + this->handle = other.handle; + other.handle = {}; + this->is_joinable = other.is_joinable; + other.is_joinable = false; + return *this; +} + +inline original::ul_integer original::wThread::id() const +{ + ul_integer id = 0; + std::memcpy(&id, &this->handle, sizeof(HANDLE)); + return id; +} + +inline bool original::wThread::joinable() const +{ + return this->is_joinable; +} + +inline original::integer original::wThread::compareTo(const wThread& other) const +{ + if (this->id() != other.id()) + return this->id() > other.id() ? 1 : -1; + return 0; +} + +inline original::u_integer original::wThread::toHash() const noexcept +{ + return hash::hashFunc(this->id()); +} + +inline std::string original::wThread::className() const +{ + return "wThread"; +} + +inline void original::wThread::join() +{ + WaitForSingleObject(this->handle, INFINITE); + this->is_joinable = false; + this->handle = {}; +} + +inline void original::wThread::detach() +{ + CloseHandle(this->handle); + this->is_joinable = false; + this->handle = {}; +} + +inline original::wThread::~wThread() +{ + if (this->is_joinable) { + try { + this->detach(); + } catch (...) { + std::cerr << "Fatal error in wThread destructor" << std::endl; + std::terminate(); + } + } +} +#endif inline bool original::thread::valid() const { @@ -576,9 +738,12 @@ inline bool original::thread::valid() const inline original::ul_integer original::thread::thisId() { ul_integer id = 0; -#ifdef ORIGINAL_COMPILER_GCC +#if ORIGINAL_COMPILER_GCC || ORIGINAL_COMPILER_CLANG auto handle = pthread_self(); std::memcpy(&id, &handle, sizeof(pthread_t)); +#elif ORIGINAL_COMPILER_MSVC + const auto handle = GetCurrentThreadId(); + std::memcpy(&id, &handle, sizeof(HANDLE)); #endif return id; } @@ -603,8 +768,8 @@ inline void original::thread::sleep(const time::duration& d) throw sysError("Failed to sleep thread (clock_nano-sleep returned " + formatString(ret) + ", errno: " + std::to_string(errno) + ")"); } -#else - ::Sleep(static_cast((d.value() + time::FACTOR_MILLISECOND - 1) / time::FACTOR_MILLISECOND)); +#elif ORIGINAL_COMPILER_MSVC + Sleep(d.toDWMilliseconds()); #endif } @@ -619,8 +784,13 @@ template original::thread::thread(Callback c, const joinPolicy policy, ARGS&&... args) : thread_(std::forward(c), std::forward(args)...), will_join(policy == AUTO_JOIN) {} +#if ORIGINAL_COMPILER_GCC || ORIGINAL_COMPILER_CLANG inline original::thread::thread(pThread p_thread, const joinPolicy policy) : thread_(std::move(p_thread)), will_join(policy == AUTO_JOIN) {} +#elif ORIGINAL_COMPILER_MSVC +inline original::thread::thread(wThread w_thread, const joinPolicy policy) + : thread_(std::move(w_thread)), will_join(policy == AUTO_JOIN) {} +#endif inline original::thread::thread(thread&& other) noexcept : thread_(std::move(other.thread_)), will_join(true) {} diff --git a/src/vibrant/zeit.h b/src/vibrant/zeit.h index bf23e97..5f70aee 100644 --- a/src/vibrant/zeit.h +++ b/src/vibrant/zeit.h @@ -1,15 +1,24 @@ #ifndef ORIGINAL_ZEIT_H #define ORIGINAL_ZEIT_H -#include + #include "config.h" + +#if ORIGINAL_COMPILER_GCC || ORIGINAL_COMPILER_CLANG +#include +#elif ORIGINAL_COMPILER_MSVC +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#include +#endif + +#include #include "comparable.h" #include "hash.h" #include "printable.h" #include "error.h" #include -#if ORIGINAL_COMPILER_GCC || ORIGINAL_COMPILER_CLANG -#include -#endif /** * @file zeit.h @@ -156,6 +165,8 @@ namespace original { * into a unified duration value in nanoseconds. */ explicit duration(const timespec& ts); +#elif ORIGINAL_COMPILER_MSVC + explicit duration(DWORD milliseconds); #endif /// Default copy constructor @@ -219,6 +230,10 @@ namespace original { explicit operator timespec() const; timespec toTimespec() const; +#elif ORIGINAL_COMPILER_MSVC + explicit operator DWORD() const; + + DWORD toDWMilliseconds() const; #endif /** @@ -403,6 +418,8 @@ namespace original { * @note The conversion computes the total nanoseconds from ts.tv_sec and ts.tv_nsec. */ explicit point(const timespec& ts); +#elif ORIGINAL_COMPILER_MSVC + explicit point(DWORD milliseconds); #endif /** @@ -447,6 +464,10 @@ namespace original { explicit operator timespec() const; timespec toTimespec() const; +#elif ORIGINAL_COMPILER_MSVC + explicit operator DWORD() const; + + DWORD toDWMilliseconds() const; #endif /** @@ -822,7 +843,7 @@ namespace original { * @warning When converting back to time::point, the time point will only * have second-level precision (sub-second components will be zero) */ - explicit operator point() const; + explicit operator original::time::point() const; point toPoint() const; @@ -1107,6 +1128,9 @@ inline original::time::duration::duration(const time_val_type val, const unit un #if ORIGINAL_COMPILER_GCC || ORIGINAL_COMPILER_CLANG inline original::time::duration::duration(const timespec& ts) : nano_seconds_(ts.tv_sec * FACTOR_SECOND + ts.tv_nsec) {} +#elif ORIGINAL_COMPILER_MSVC +inline original::time::duration::duration(const DWORD milliseconds) + : nano_seconds_(static_cast(milliseconds) * FACTOR_MILLISECOND) {} #endif inline original::time::duration::duration(duration&& other) noexcept : duration() { @@ -1191,6 +1215,16 @@ inline timespec original::time::duration::toTimespec() const { return static_cast(*this); } +#elif ORIGINAL_COMPILER_MSVC +inline original::time::duration::operator DWORD() const +{ + return static_cast(this->value()); +} + +inline DWORD original::time::duration::toDWMilliseconds() const +{ + return static_cast(*this); +} #endif inline original::time::duration& @@ -1359,10 +1393,21 @@ original::time::point::now() { gettimeofday(&tv, nullptr); time_val_type ns = tv.tv_sec * FACTOR_SECOND + tv.tv_usec * FACTOR_MICROSECOND; return point(ns, NANOSECOND); -#else - // Other implements not complete - return point(); +#elif ORIGINAL_COMPILER_MSVC + FILETIME file_time; + GetSystemTimePreciseAsFileTime(&file_time); + + ULARGE_INTEGER uli; + uli.LowPart = file_time.dwLowDateTime; + uli.HighPart = file_time.dwHighDateTime; + + constexpr time_val_type WINDOWS_TO_UNIX_EPOCH = 11644473600LL * FACTOR_SECOND; + + const time_val_type nanoseconds = uli.QuadPart * 100 - WINDOWS_TO_UNIX_EPOCH; + + return point{nanoseconds, NANOSECOND}; #endif + return point{}; } inline original::time::point::point(const time_val_type val, const unit unit) @@ -1374,6 +1419,9 @@ inline original::time::point::point(duration d) #if ORIGINAL_COMPILER_GCC || ORIGINAL_COMPILER_CLANG inline original::time::point::point(const timespec& ts) : nano_since_epoch_(ts) {} +#elif ORIGINAL_COMPILER_MSVC +inline original::time::point::point(const DWORD milliseconds) + : nano_since_epoch_(milliseconds) {} #endif inline original::time::time_val_type @@ -1414,6 +1462,16 @@ inline timespec original::time::point::toTimespec() const { return static_cast(*this); } +#elif ORIGINAL_COMPILER_MSVC +inline original::time::point::operator DWORD() const +{ + return static_cast(this->nano_since_epoch_); +} + +inline DWORD original::time::point::toDWMilliseconds() const +{ + return static_cast(*this); +} #endif inline original::time::point& @@ -1726,7 +1784,7 @@ original::time::UTCTime::value(const calendar calendar) const { } } -inline original::time::UTCTime::operator point() const { +inline original::time::UTCTime::operator original::time::point() const { time_val_type total_days = 0; for (integer year = EPOCH_YEAR; year < this->year_; ++year) { diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..8c06175 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,18 @@ +# test/CMakeLists.txt + +if(MSVC) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Zi") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Zi") +else() + if (NOT CMAKE_SYSTEM_NAME STREQUAL "Windows") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -g") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -g") + else() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g") + endif() +endif() + +# test cases +add_subdirectory(other) +add_subdirectory(unit_test) \ No newline at end of file diff --git a/test/other/test1.cpp b/test/other/test1.cpp index d3c62be..f0c6da7 100644 --- a/test/other/test1.cpp +++ b/test/other/test1.cpp @@ -11,7 +11,7 @@ int main(){ std::printf("%s", arr1.toString(true).c_str()); original::array arr2 = {1, 4, 5, 3, 8}; std::printf("%s", arr2.toString(true).c_str()); - std::printf("max(5,3):%d\n", original::max(5, 3)); + std::printf("maximum(5,3):%d\n", original::maximum(5, 3)); auto arr3 = arr2; std::printf("arr3:%p, arr2:%p\n", &arr3, &arr2); std::printf("arr3:%s\narr2:%s\n", arr3.toString(false).c_str(), arr2.toString(false).c_str()); diff --git a/test/other/test3.cpp b/test/other/test3.cpp index 158705d..b7c24fa 100644 --- a/test/other/test3.cpp +++ b/test/other/test3.cpp @@ -8,7 +8,6 @@ #include "chain.h" #include "vector.h" #include "algorithms.h" -#include "filter.h" int main(){ @@ -148,7 +147,7 @@ int main(){ std::cout << "p1 == p2: " << original::printable::formatString(p1 == p2) << std::endl; std::cout << "p1 < p2: " << original::printable::formatString(p1 < p2) << std::endl; auto cmp = p1 <=> p2; - std::cout << (cmp == nullptr) << std::endl; + std::cout << (cmp == 0) << std::endl; std::cout << "p1: " << p1 << std::endl; while (!p1.empty()) { diff --git a/test/other/test6.cpp b/test/other/test6.cpp index 75b5743..a2619e6 100644 --- a/test/other/test6.cpp +++ b/test/other/test6.cpp @@ -1,6 +1,8 @@ #include #include "atomic.h" +#include "array.h" +#include "allocator.h" #include "thread.h" #include "maps.h" #include "mutex.h" @@ -15,37 +17,24 @@ using namespace original::literals; int main() { std::cout << "id of main thread: " << original::thread::thisId() << std::endl; - original::pMutex print_mtx; - original::pCondition p; - - auto printErr = [&](const original::error& e){ - original::uniqueLock lock{print_mtx}; - std::cout << e << ": " << e.message() << std::endl; - p.notify(); - }; - - const auto err = original::valueError("Divided by zero"); - original::thread print_thread {printErr, std::cref(err)}; - p.wait(print_mtx); - - original::pMutex mutex; + original::mutex mutex; auto task1 = [&](const int a, const std::string& b) { original::uniqueLock lock{mutex}; std::cout << b << a << std::endl; }; - original::pThread t1{task1, 1, "show: "}; + original::thread t1{task1, 1, "show: "}; original::thread::sleep(100_ms); std::cout << "id t1: " << t1.id() << std::endl; t1.join(); - original::pThread t2{task1, 2, "show: "}; + original::thread t2{task1, 2, "show: "}; t2.join(); - original::pThread t3{task1, 3, "show: "}; + original::thread t3{task1, 3, "show: "}; auto t4 = std::move(t3); t4.join(); - original::pThread t5{task1, 4, "show: "}; - original::pThread t6{task1, 5, "show: "}; + original::thread t5{task1, 4, "show: "}; + original::thread t6{task1, 5, "show: "}; if (t5) { std::cout << "t5 is valid" << std::endl; } @@ -58,11 +47,11 @@ int main() original::thread t7{task1, 6, "show: "}; original::thread t8{task1, 7, "show: "}; - original::pThread t9{task1, 8, "show: "}; + original::thread t9{task1, 8, "show: "}; original::thread t10{std::move(t9), original::thread::AUTO_JOIN}; original::thread::sleep(100_ms); std::cout << "t10 id: " << t10.id() << std::endl; - original::pThread t11{task1, 9, "show: "}; + original::thread t11{task1, 9, "show: "}; original::thread t12{std::move(t11)}; original::thread t13; @@ -94,8 +83,8 @@ int main() std::cout << "On win64: " << original::printable::formatString(original::ON_WIN64()) << std::endl; std::cout << "Using GCC: " << original::printable::formatString(original::USING_GCC()) << std::endl; - original::pMutex m1; - original::pMutex m2; + original::mutex m1; + original::mutex m2; original::multiLock ml{m1, m2}; auto d1 = original::time::duration(100, original::time::MILLISECOND); diff --git a/test/other/test7.cpp b/test/other/test7.cpp index 264a965..5f83a96 100644 --- a/test/other/test7.cpp +++ b/test/other/test7.cpp @@ -3,12 +3,13 @@ #include "async.h" #include "singleton.h" #include "tasks.h" +#include "maths.h" #include "coroutines.h" #include "generators.h" original::array matrixAdd(const original::array& a, const original::array& b) { - const auto len = original::max(a.size(), b.size()); + const auto len = original::maximum(a.size(), b.size()); original::array result(len); for (original::integer i = 0; i < len; i++) { if (i < a.size()) diff --git a/test/unit_test/test_core/test_JMap.cpp b/test/unit_test/test_core/test_JMap.cpp index 78051c3..c59f4b3 100644 --- a/test/unit_test/test_core/test_JMap.cpp +++ b/test/unit_test/test_core/test_JMap.cpp @@ -23,6 +23,15 @@ class JMapTest : public testing::Test { JMap* stringMap{}; }; +namespace { + template + struct CustomCompare { + bool operator()(const int a, const int b) const { + return a > b; // Reverse order + } + }; +} + // Basic Functionality Tests TEST_F(JMapTest, InitialState) { EXPECT_EQ(intMap->size(), 0); @@ -209,13 +218,8 @@ EXPECT_EQ(intMap->size(), 0); // NOLINT(bugprone-use-after-move) // Custom Comparator Test TEST(JMapCustomCompareTest, CustomCompareFunction) { -struct CustomCompare { - bool operator()(const int a, const int b) const { - return a > b; // Reverse order - } -}; -JMap customMap; +JMap> customMap; customMap.add(1, 10); customMap.add(2, 20); customMap.add(3, 30); diff --git a/test/unit_test/test_core/test_JSet.cpp b/test/unit_test/test_core/test_JSet.cpp index ea04800..d5e3e83 100644 --- a/test/unit_test/test_core/test_JSet.cpp +++ b/test/unit_test/test_core/test_JSet.cpp @@ -22,6 +22,16 @@ class JSetTest : public testing::Test { JSet* stringSet{}; }; +namespace +{ + template + struct ReverseCompare { + bool operator()(int a, int b) const { + return a > b; + } + }; +} + // 基础功能测试 TEST_F(JSetTest, InitialState) { EXPECT_EQ(intSet->size(), 0); @@ -139,13 +149,7 @@ TEST_F(JSetTest, ToString) { // 自定义比较器测试(反向排序) TEST(JSetCustomCompareTest, CustomCompare) { - struct ReverseCompare { - bool operator()(int a, int b) const { - return a > b; - } - }; - - JSet set; + JSet> set; for (int i = 1; i <= 3; ++i) set.add(i); auto it = set.begins(); diff --git a/test/unit_test/test_core/test_algorithms.cpp b/test/unit_test/test_core/test_algorithms.cpp index 17b2542..376fd91 100644 --- a/test/unit_test/test_core/test_algorithms.cpp +++ b/test/unit_test/test_core/test_algorithms.cpp @@ -1,5 +1,6 @@ #include #include // std algorithm +#include #include "array.h" #include "vector.h" #include "algorithms.h" // original algorithm diff --git a/test/unit_test/test_core/test_hashMap.cpp b/test/unit_test/test_core/test_hashMap.cpp index c51c23b..b7b9192 100644 --- a/test/unit_test/test_core/test_hashMap.cpp +++ b/test/unit_test/test_core/test_hashMap.cpp @@ -232,15 +232,19 @@ TEST_F(HashMapTest, ToString) { EXPECT_TRUE(str.find("20") != std::string::npos); } -// Custom Hash Function Test -TEST(HashMapCustomHashTest, CustomHashFunction) { +namespace +{ + template struct CustomHash { u_integer operator()(const int key) const { return key % 10; // Simple hash for testing } }; +} - hashMap customMap; +// Custom Hash Function Test +TEST(HashMapCustomHashTest, CustomHashFunction) { + hashMap> customMap; for (int i = 0; i < 20; ++i) { customMap.add(i, i * 10); } diff --git a/test/unit_test/test_core/test_hashSet.cpp b/test/unit_test/test_core/test_hashSet.cpp index 0a061d5..50106f2 100644 --- a/test/unit_test/test_core/test_hashSet.cpp +++ b/test/unit_test/test_core/test_hashSet.cpp @@ -188,15 +188,19 @@ TEST_F(HashSetTest, ToString) { EXPECT_TRUE(str.find('2') != std::string::npos); } -// Custom Hash Function Test -TEST(HashSetCustomHashTest, CustomHashFunction) { +namespace +{ + template struct CustomHash { u_integer operator()(const int key) const { return key % 10; // Simple hash for testing } }; +} - hashSet customSet; +// Custom Hash Function Test +TEST(HashSetCustomHashTest, CustomHashFunction) { + hashSet> customSet; for (int i = 0; i < 20; ++i) { customSet.add(i); } diff --git a/test/unit_test/test_core/test_maths.cpp b/test/unit_test/test_core/test_maths.cpp index ea9da95..86476de 100644 --- a/test/unit_test/test_core/test_maths.cpp +++ b/test/unit_test/test_core/test_maths.cpp @@ -21,30 +21,30 @@ TEST(MathsTests, AbsDoubleNegative) { EXPECT_EQ(original::abs(-5.5), std::abs(-5.5)); } -// Tests for max +// Tests for maximum TEST(MathsTests, MaxInt) { - EXPECT_EQ(original::max(3, 5), std::max(3, 5)); + EXPECT_EQ(original::maximum(3, 5), std::max(3, 5)); } TEST(MathsTests, MaxDouble) { - EXPECT_EQ(original::max(3.5, 5.5), std::max(3.5, 5.5)); + EXPECT_EQ(original::maximum(3.5, 5.5), std::max(3.5, 5.5)); } TEST(MathsTests, MaxEqual) { - EXPECT_EQ(original::max(3, 3), std::max(3, 3)); + EXPECT_EQ(original::maximum(3, 3), std::max(3, 3)); } -// Tests for min +// Tests for minimum TEST(MathsTests, MinInt) { - EXPECT_EQ(original::min(3, 5), std::min(3, 5)); + EXPECT_EQ(original::minimum(3, 5), std::min(3, 5)); } TEST(MathsTests, MinDouble) { - EXPECT_EQ(original::min(3.5, 5.5), std::min(3.5, 5.5)); + EXPECT_EQ(original::minimum(3.5, 5.5), std::min(3.5, 5.5)); } TEST(MathsTests, MinEqual) { - EXPECT_EQ(original::min(3, 3), std::min(3, 3)); + EXPECT_EQ(original::minimum(3, 3), std::min(3, 3)); } // Tests for pow diff --git a/test/unit_test/test_core/test_printable.cpp b/test/unit_test/test_core/test_printable.cpp index 053b16b..e49e535 100644 --- a/test/unit_test/test_core/test_printable.cpp +++ b/test/unit_test/test_core/test_printable.cpp @@ -3,7 +3,7 @@ namespace original { // 创建一个继承 printable 的测试类 - class TestClass : public printable { + class TestClass final : public printable { public: std::string className() const override { return "TestClass"; @@ -21,12 +21,12 @@ TEST(PrintableTest, ClassNameTest) { // 测试 toString() 方法 TEST(PrintableTest, ToStringTest) { - original::TestClass obj; + const original::TestClass obj; // 测试 toString 传入 false,不带换行 std::string str = obj.toString(false); EXPECT_TRUE(str.find("TestClass") != std::string::npos); // 应该包含类名 - EXPECT_TRUE(str.find("0x") != std::string::npos); // 应该包含地址信息 + EXPECT_TRUE(str.find('@') != std::string::npos); // 应该包含地址信息 // 测试 toString 传入 true,带换行 str = obj.toString(true); @@ -35,7 +35,7 @@ TEST(PrintableTest, ToStringTest) { // 测试 toCString() 方法 TEST(PrintableTest, ToCStringTest) { - original::TestClass obj; + const original::TestClass obj; const char* c_str = obj.toCString(false); EXPECT_TRUE(std::string(c_str).find("TestClass") != std::string::npos); } @@ -84,9 +84,9 @@ TEST(PrintableTest, FormatEnumTest) { // 测试输出操作符 TEST(PrintableTest, OutputOperatorTest) { - original::TestClass obj; + const original::TestClass obj; std::ostringstream oss; oss << obj; EXPECT_TRUE(oss.str().find("TestClass") != std::string::npos); // 输出应包含类名 - EXPECT_TRUE(oss.str().find("0x") != std::string::npos); // 输出应包含对象地址 + EXPECT_TRUE(oss.str().find('@') != std::string::npos); // 输出应包含对象地址 } diff --git a/test/unit_test/test_core/test_treeMap.cpp b/test/unit_test/test_core/test_treeMap.cpp index c2a2758..02df525 100644 --- a/test/unit_test/test_core/test_treeMap.cpp +++ b/test/unit_test/test_core/test_treeMap.cpp @@ -230,15 +230,19 @@ TEST_F(TreeMapTest, MoveAssignment) { EXPECT_EQ(intMap->size(), 0); // NOLINT(bugprone-use-after-move) } -// Custom Comparator Test -TEST(TreeMapCustomCompareTest, CustomCompareFunction) { +namespace +{ + template struct CustomCompare { bool operator()(const int a, const int b) const { return a > b; // Reverse order } }; +} - treeMap customMap; +// Custom Comparator Test +TEST(TreeMapCustomCompareTest, CustomCompareFunction) { + treeMap> customMap; customMap.add(1, 10); customMap.add(2, 20); customMap.add(3, 30); diff --git a/test/unit_test/test_core/test_treeSet.cpp b/test/unit_test/test_core/test_treeSet.cpp index 8f40582..ed57f2f 100644 --- a/test/unit_test/test_core/test_treeSet.cpp +++ b/test/unit_test/test_core/test_treeSet.cpp @@ -187,15 +187,19 @@ TEST_F(TreeSetTest, MoveAssignment) { EXPECT_EQ(intSet->size(), 0); // NOLINT(bugprone-use-after-move) } -// Custom Comparator Test -TEST(TreeSetCustomCompareTest, CustomCompareFunction) { +namespace +{ + template struct CustomCompare { bool operator()(const int a, const int b) const { return a > b; // Reverse order } }; +} - treeSet customSet; +// Custom Comparator Test +TEST(TreeSetCustomCompareTest, CustomCompareFunction) { + treeSet> customSet; customSet.add(1); customSet.add(2); customSet.add(3); diff --git a/test/unit_test/test_vibrant/CMakeLists.txt b/test/unit_test/test_vibrant/CMakeLists.txt index 54225eb..fcc8d6d 100644 --- a/test/unit_test/test_vibrant/CMakeLists.txt +++ b/test/unit_test/test_vibrant/CMakeLists.txt @@ -6,6 +6,11 @@ file(GLOB VIBRANT_TESTS "test_*.cpp") add_executable(vibrant_test ${VIBRANT_TESTS}) +if(MSVC) + target_compile_options(vibrant_test PRIVATE "/bigobj") + target_compile_options(vibrant_test PRIVATE "/Zc:inline") +endif() + target_link_libraries(vibrant_test PRIVATE GTest::gtest GTest::gmock GTest::gmock_main GTest::gtest_main) target_link_libraries(vibrant_test PRIVATE original) diff --git a/test/unit_test/test_vibrant/test_async.cpp b/test/unit_test/test_vibrant/test_async.cpp index 9072cba..1906e2b 100644 --- a/test/unit_test/test_vibrant/test_async.cpp +++ b/test/unit_test/test_vibrant/test_async.cpp @@ -894,19 +894,26 @@ TEST(AsyncTest, SharedFutureWaitFor) { // 测试 sharedFuture 的 waitFor 方法 TEST(AsyncTest, SharedFutureVoidWaitFor) { - std::atomic executed{false}; + auto executed = std::make_shared>(false); - const auto sf = async::get([&executed] { + const auto sf = async::get([executed] { thread::sleep(milliseconds(100)); - executed = true; + executed->store(true); }).share(); // 等待足够长的时间 const bool success = sf.waitFor(milliseconds(150)); EXPECT_TRUE(success); EXPECT_TRUE(sf.ready()); - EXPECT_NO_THROW(sf.result()); - EXPECT_TRUE(executed); + + // 在检查result之前确保任务已完成 + if (sf.ready()) { + EXPECT_NO_THROW(sf.result()); + } + + EXPECT_TRUE(executed->load()); + + sf.wait(); } // 测试 futureBase 接口的 waitFor 方法 diff --git a/test/unit_test/test_vibrant/test_condition.cpp b/test/unit_test/test_vibrant/test_condition.cpp index d5081bf..0618ebc 100644 --- a/test/unit_test/test_vibrant/test_condition.cpp +++ b/test/unit_test/test_vibrant/test_condition.cpp @@ -11,8 +11,8 @@ using namespace original::literals; class pConditionTest : public testing::Test { protected: - pMutex mutex; - pCondition cond; + mutex mutex_; + condition cond_; bool ready = false; }; @@ -20,27 +20,27 @@ class ProducerConsumerTest : public testing::Test { protected: queue buffer; static constexpr std::size_t MAX_SIZE = 5; - pMutex mutex; - pCondition cond_full; // 消费者等待“非空” - pCondition cond_empty; // 生产者等待“非满” + mutex mutex_; + condition cond_full; // 消费者等待“非空” + condition cond_empty; // 生产者等待“非满” bool done = false; }; // 基本通知机制:等待一个条件,然后 notify 唤醒 TEST_F(pConditionTest, BasicNotifyTest) { thread t([&] { - uniqueLock lock(mutex); + uniqueLock lock(mutex_); while (!ready) { - cond.wait(mutex); + cond_.wait(mutex_); } }, thread::AUTO_JOIN); thread::sleep(50_ms); // 让线程进入 wait 状态 { - uniqueLock lock(mutex); + uniqueLock lock(mutex_); ready = true; - cond.notify(); + cond_.notify(); } t.join(); @@ -49,8 +49,8 @@ TEST_F(pConditionTest, BasicNotifyTest) { // 测试 waitFor 的超时行为 TEST_F(pConditionTest, TimedWaitTimeoutTest) { - uniqueLock lock(mutex); - const bool result = cond.waitFor(mutex, 200_ms); + uniqueLock lock(mutex_); + const bool result = cond_.waitFor(mutex_, 200_ms); EXPECT_FALSE(result); // 应超时 } @@ -58,15 +58,15 @@ TEST_F(pConditionTest, TimedWaitTimeoutTest) { TEST_F(pConditionTest, TimedWaitNotTimeoutTest) { thread t([&] { thread::sleep(50_ms); // 等待 50ms 再唤醒 - uniqueLock lock(mutex); + uniqueLock lock(mutex_); ready = true; - cond.notify(); + cond_.notify(); }, thread::AUTO_JOIN); bool result; { - uniqueLock lock(mutex); - result = cond.waitFor(mutex, 200_ms); + uniqueLock lock(mutex_); + result = cond_.waitFor(mutex_, 200_ms); } EXPECT_TRUE(result); @@ -78,23 +78,23 @@ TEST_F(pConditionTest, NotifyAllWakesAllWaiters) { ready = false; thread t1([&] { - uniqueLock lock(mutex); - while (!ready) cond.wait(mutex); + uniqueLock lock(mutex_); + while (!ready) cond_.wait(mutex_); wake_count++; }); thread t2([&] { - uniqueLock lock(mutex); - while (!ready) cond.wait(mutex); + uniqueLock lock(mutex_); + while (!ready) cond_.wait(mutex_); wake_count++; }); thread::sleep(50_ms); // 等待线程进入阻塞状态 { - uniqueLock lock(mutex); + uniqueLock lock(mutex_); ready = true; - cond.notifyAll(); + cond_.notifyAll(); } t1.join(); @@ -110,8 +110,8 @@ TEST_F(ProducerConsumerTest, ProducerConsumerWorkCorrectly) { // 消费者线程 thread consumer([&] { while (true) { - uniqueLock lock(mutex); - cond_full.wait(mutex, [&]{ + uniqueLock lock(mutex_); + cond_full.wait(mutex_, [&]{ return !buffer.empty() || done; }); if (done && buffer.empty()) @@ -129,8 +129,8 @@ TEST_F(ProducerConsumerTest, ProducerConsumerWorkCorrectly) { // 生产者线程 thread producer([&] { for (int i = 1; i <= total_count; ++i) { - uniqueLock lock(mutex); - cond_empty.wait(mutex, [&] { + uniqueLock lock(mutex_); + cond_empty.wait(mutex_, [&] { return buffer.size() < MAX_SIZE; }); buffer.push(i); // 生产 @@ -139,7 +139,7 @@ TEST_F(ProducerConsumerTest, ProducerConsumerWorkCorrectly) { // 设置完成标志并广播 { - uniqueLock lock(mutex); + uniqueLock lock(mutex_); done = true; cond_full.notifyAll(); } diff --git a/test/unit_test/test_vibrant/test_mutex.cpp b/test/unit_test/test_vibrant/test_mutex.cpp index 721acea..7337a85 100644 --- a/test/unit_test/test_vibrant/test_mutex.cpp +++ b/test/unit_test/test_vibrant/test_mutex.cpp @@ -6,19 +6,19 @@ using namespace original; TEST(MutexTest, LockUnlockDoesNotThrow) { - pMutex m; + mutex m; EXPECT_NO_THROW(m.lock()); EXPECT_NO_THROW(m.unlock()); } TEST(MutexTest, TryLockSuccess) { - pMutex m; + mutex m; EXPECT_NO_THROW(m.tryLock()); EXPECT_NO_THROW(m.unlock()); } TEST(MutexTest, TryLockContested) { - pMutex m; + mutex m; std::thread t( [&m] { @@ -39,7 +39,7 @@ TEST(MutexTest, PreventsDataRaceWithMultipleThreads) { constexpr int thread_count = 10; constexpr int iterations = 10000; int counter = 0; - pMutex m; + mutex m; auto increment = [&] { @@ -64,7 +64,7 @@ TEST(MutexTest, PreventsDataRaceWithMultipleThreads) { TEST(MutexTest, LockInConstructorAndUnlockInDestructor) { { - pMutex pm; + mutex pm; const uniqueLock m(pm); // 默认锁定 EXPECT_TRUE(m.isLocked()); } @@ -73,7 +73,7 @@ TEST(MutexTest, LockInConstructorAndUnlockInDestructor) { TEST(MutexTest, TryLockConstructor) { { - pMutex pm; + mutex pm; const uniqueLock m(pm, uniqueLock::TRY_LOCK); // 使用 tryLock EXPECT_TRUE(m.isLocked()); } @@ -81,22 +81,22 @@ TEST(MutexTest, TryLockConstructor) { } TEST(MutexTest, MutexIsNonCopyable) { - EXPECT_FALSE(std::is_copy_constructible_v); - EXPECT_FALSE(std::is_copy_assignable_v); + EXPECT_FALSE(std::is_copy_constructible_v); + EXPECT_FALSE(std::is_copy_assignable_v); EXPECT_FALSE(std::is_copy_constructible_v); EXPECT_FALSE(std::is_copy_assignable_v); } TEST(MutexTest, MutexIsNonMovable) { - EXPECT_FALSE(std::is_move_constructible_v); - EXPECT_FALSE(std::is_move_assignable_v); + EXPECT_FALSE(std::is_move_constructible_v); + EXPECT_FALSE(std::is_move_assignable_v); EXPECT_FALSE(std::is_move_constructible_v); EXPECT_FALSE(std::is_move_assignable_v); } // TryLock失败时,uniqueLock::isLocked() 应为 false TEST(MutexTest, TryLockFailsIsLockedFalse) { - pMutex pm; + mutex pm; pm.lock(); // 主线程先锁住 const uniqueLock s(pm, uniqueLock::TRY_LOCK); // 尝试获取失败 @@ -107,7 +107,7 @@ TEST(MutexTest, TryLockFailsIsLockedFalse) { // scopeLock析构后,mutex可以再次上锁 TEST(MutexTest, RAIIUnlocksCorrectly) { - pMutex pm; + mutex pm; { uniqueLock s(pm); EXPECT_TRUE(s.isLocked()); @@ -124,7 +124,7 @@ TEST(MutexTest, UniqueLockProtectsCriticalSection) { constexpr int thread_count = 10; constexpr int iterations = 10000; int counter = 0; - pMutex m; + mutex m; auto increment = [&] { @@ -148,7 +148,7 @@ TEST(MutexTest, UniqueLockProtectsCriticalSection) { // TryLock获取失败时不会 unlock TEST(MutexTest, TryLockFailDoesNotUnlock) { - pMutex pm; + mutex pm; pm.lock(); { @@ -162,7 +162,7 @@ TEST(MutexTest, TryLockFailDoesNotUnlock) { // TryLock获取成功后,锁应被释放 TEST(MutexTest, TryLockSuccessUnlocksOnDestruction) { - pMutex pm; + mutex pm; { if (const uniqueLock s(pm, uniqueLock::TRY_LOCK); s.isLocked()) { SUCCEED(); // 成功加锁 @@ -176,7 +176,7 @@ TEST(MutexTest, TryLockSuccessUnlocksOnDestruction) { // 测试解锁后可以再次加锁 TEST(MutexTest, CanRelockAfterUnlock) { - pMutex m; + mutex m; m.lock(); m.unlock(); EXPECT_NO_THROW(m.lock()); // 再次加锁不应抛出异常 @@ -185,7 +185,7 @@ TEST(MutexTest, CanRelockAfterUnlock) { // 测试uniqueLock解锁后可以再次加锁 TEST(MutexTest, UniqueLockCanRelockAfterUnlock) { - pMutex pm; + mutex pm; { uniqueLock lock(pm); lock.unlock(); @@ -198,7 +198,7 @@ TEST(MutexTest, UniqueLockCanRelockAfterUnlock) { // 测试多次加锁解锁循环 TEST(MutexTest, MultipleLockUnlockCycles) { - pMutex m; + mutex m; for (int i = 0; i < 100; ++i) { EXPECT_NO_THROW(m.lock()); EXPECT_NO_THROW(m.unlock()); @@ -207,7 +207,7 @@ TEST(MutexTest, MultipleLockUnlockCycles) { // 测试uniqueLock手动锁策略 TEST(MutexTest, ManualLockPolicy) { - pMutex pm; + mutex pm; { uniqueLock lock(pm, uniqueLock::MANUAL_LOCK); EXPECT_FALSE(lock.isLocked()); @@ -223,7 +223,7 @@ TEST(MutexTest, ManualLockPolicy) { // 测试跨线程的加锁解锁顺序 TEST(MutexTest, CrossThreadLockUnlockSequence) { - pMutex m; + mutex m; std::atomic thread_locked{false}; std::atomic main_proceed{false}; @@ -251,7 +251,7 @@ TEST(MultiLockTest, MultiLockLocksAndUnlocksInReverseOrder) { std::vector unlock_order; class Trackable { - pMutex mutex_; + mutex mutex_; std::vector& lock_record_; std::vector& unlock_record_; public: @@ -299,7 +299,7 @@ TEST(MultiLockTest, MultiLockLocksAndUnlocksInReverseOrder) { TEST(MultiLockTest, MultiLockProtectsMultipleResources) { constexpr int iterations = 1000; int x = 0, y = 0; - pMutex mx, my; + mutex mx, my; auto worker = [&]() { for (int i = 0; i < iterations; ++i) { @@ -319,7 +319,7 @@ TEST(MultiLockTest, MultiLockProtectsMultipleResources) { } TEST(MutexTest, AdoptLockPolicyAssumesLocked) { - pMutex m; + mutex m; m.lock(); // 手动加锁 { @@ -334,7 +334,7 @@ TEST(MutexTest, AdoptLockPolicyAssumesLocked) { } TEST(MultiLockTest, AdoptLockSkipsLocking) { - pMutex m1, m2; + mutex m1, m2; m1.lock(); m2.lock(); @@ -352,7 +352,7 @@ TEST(MultiLockTest, AdoptLockSkipsLocking) { } TEST(MultiLockTest, TryLockFailsWhenAnyMutexUnavailable) { - pMutex m1, m2; + mutex m1, m2; m1.lock(); // 抢占一个锁 const multiLock lock(lockGuard::TRY_LOCK, m1, m2); diff --git a/test/unit_test/test_vibrant/test_thread.cpp b/test/unit_test/test_vibrant/test_thread.cpp index 7bcfdca..8ff5c37 100644 --- a/test/unit_test/test_vibrant/test_thread.cpp +++ b/test/unit_test/test_vibrant/test_thread.cpp @@ -9,6 +9,12 @@ using namespace original::literals; using namespace std::literals; namespace { + using thread_type = +#if ORIGINAL_COMPILER_GCC || ORIGINAL_COMPILER_CLANG + pThread; +#elif ORIGINAL_COMPILER_MSVC + wThread; +#endif // Test class with member functions class Worker { public: @@ -52,7 +58,7 @@ namespace { // Function with delay for join/detach tests void delayedFunction(std::atomic& flag) { - std::this_thread::sleep_for(std::chrono::milliseconds(500)); + thread::sleep(milliseconds(500)); flag = true; } } @@ -155,7 +161,7 @@ TEST_F(ThreadTest, Detach) { ASSERT_FALSE(t); } // Give some time for the thread to complete - std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + thread::sleep(milliseconds(1000)); ASSERT_TRUE(flag); } @@ -177,7 +183,7 @@ TEST_F(ThreadTest, DestructorDetach) { // t will be detached when it goes out of scope } // Give some time for the thread to complete - std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + thread::sleep(milliseconds(1000)); ASSERT_TRUE(flag); } @@ -237,14 +243,14 @@ TEST_F(ThreadTest, WillJoinFlag) { // Will be detached on destruction } // Give some time for the thread to complete - std::this_thread::sleep_for(std::chrono::milliseconds(200)); + thread::sleep(microseconds(200)); ASSERT_TRUE(flag); } // Test thread ID uniqueness TEST_F(ThreadTest, ThreadIdUniqueness) { - thread t1([] { std::this_thread::sleep_for(std::chrono::milliseconds(100)); }); - thread t2([] { std::this_thread::sleep_for(std::chrono::milliseconds(100)); }); + thread t1([] { thread::sleep(microseconds(100)); }); + thread t2([] { thread::sleep(microseconds(100)); }); const ul_integer id1 = t1.id(); const ul_integer id2 = t2.id(); @@ -274,13 +280,13 @@ TEST_F(ThreadTest, ThreadIdAfterMove) { ASSERT_EQ(t2.id(), 0); // After joining, ID should be 0 } -// Test pThread ID functionality -TEST_F(ThreadTest, PThreadId) { - pThread pt([] {}); +// Test platform thread ID functionality +TEST_F(ThreadTest, PlatformThreadId) { + thread_type pt([] {}); const ul_integer id1 = pt.id(); ASSERT_NE(id1, 0); - pThread pt2(std::move(pt)); + thread_type pt2(std::move(pt)); ASSERT_EQ(pt2.id(), id1); // ID should be preserved after move ASSERT_EQ(pt.id(), 0); // Moved-from pThread should have ID 0 @@ -467,21 +473,23 @@ TEST_F(ThreadTest, PrintableInterface) { t2.join(); } -// Test pThread printable interface -TEST_F(ThreadTest, PThreadPrintableInterface) { - pThread pt1([] {}); - pThread pt2; +// Test platform thread printable interface +TEST_F(ThreadTest, PlatformThreadPrintableInterface) { + thread_type pt1([] {}); + thread_type pt2; + + const std::string platform_thread_name = USING_MSVC() ? "wThread": "pThread"; // Test className - ASSERT_EQ(pt1.className(), "pThread"); + ASSERT_EQ(pt1.className(), platform_thread_name); // Test toString const std::string str1 = pt1.toString(false); const std::string str2 = pt2.toString(false); - ASSERT_TRUE(str1.find("pThread") != std::string::npos); + ASSERT_TRUE(str1.find(platform_thread_name) != std::string::npos); ASSERT_TRUE(str1.find(std::to_string(pt1.id())) != std::string::npos); - ASSERT_TRUE(str2.find("pThread") != std::string::npos); + ASSERT_TRUE(str2.find(platform_thread_name) != std::string::npos); pt1.join(); } \ No newline at end of file