diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..5a9f2789 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +*.h text eol=lf +*.c text eol=lf +*.S text eol=lf +*.cmake text eol=lf +*.md text eol=lf +*.svg text eol=lf +.gitignore text eol=lf +CMakeLists.txt text eol=lf diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 00000000..6d5f178b --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,40 @@ +name: analyse on codeql + +on: + repository_dispatch: + workflow_dispatch: + push: + pull_request: + schedule: + - cron: '43 23 * * 4' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + strategy: + fail-fast: false + matrix: + language: [ 'cpp' ] + + steps: + - name: checkout + uses: actions/checkout@v3 + - name: install dependencies + run: | + sudo apt update + sudo apt install cmake make clang + - name: initialize codeql + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + - name: autobuild + uses: github/codeql-action/autobuild@v2 + - name: perform analysis + uses: github/codeql-action/analyze@v2 + with: + category: "/language:${{matrix.language}}" diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml new file mode 100644 index 00000000..a4407dcd --- /dev/null +++ b/.github/workflows/macos.yml @@ -0,0 +1,42 @@ +name: build default on macos + +on: + repository_dispatch: + workflow_dispatch: + push: + pull_request: + schedule: + - cron: '0 */2 * * *' + +env: + BUILD_TYPE: Release + +jobs: + build: + name: Test on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [macos-latest] + + steps: + - name: checkout + uses: actions/checkout@v3 + - name: install dependencies + run: | + brew update + brew install cmake make ccache + - name: configure cmake + run: | + cmake -B ${{github.workspace}}/build \ + -D CMAKE_INSTALL_PREFIX=${{github.workspace}}/build/install \ + -D CMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} \ + -D CMAKE_C_COMPILER=/usr/local/opt/ccache/libexec/clang \ + -D BFDEV_DEVEL=ON + - name: make + run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} + - name: install + run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -- install + - name: ctest + working-directory: ${{github.workspace}}/build + run: ctest -C ${{env.BUILD_TYPE}} -V diff --git a/.github/workflows/ubuntu-clang.yml b/.github/workflows/ubuntu-clang.yml new file mode 100644 index 00000000..28fa94d1 --- /dev/null +++ b/.github/workflows/ubuntu-clang.yml @@ -0,0 +1,43 @@ +name: build default on ubuntu clang + +on: + repository_dispatch: + workflow_dispatch: + push: + pull_request: + schedule: + - cron: '0 */2 * * *' + +env: + BUILD_TYPE: Release + +jobs: + build: + name: Test on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest] + + steps: + - name: checkout + uses: actions/checkout@v3 + - name: install dependencies + run: | + sudo apt update + sudo apt install cmake make clang ccache + - name: configure cmake + run: | + cmake -B ${{github.workspace}}/build \ + -D CMAKE_INSTALL_PREFIX=${{github.workspace}}/build/install \ + -D CMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} \ + -D CMAKE_C_COMPILER=/usr/lib/ccache/clang \ + -D BFDEV_DEVEL=ON + - name: make + run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} + - name: install + working-directory: ${{github.workspace}}/build + run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -- install + - name: ctest + working-directory: ${{github.workspace}}/build + run: ctest -C ${{env.BUILD_TYPE}} -V diff --git a/.github/workflows/ubuntu-gcc.yml b/.github/workflows/ubuntu-gcc.yml new file mode 100644 index 00000000..19204721 --- /dev/null +++ b/.github/workflows/ubuntu-gcc.yml @@ -0,0 +1,43 @@ +name: build default on ubuntu gcc + +on: + repository_dispatch: + workflow_dispatch: + push: + pull_request: + schedule: + - cron: '0 */2 * * *' + +env: + BUILD_TYPE: Release + +jobs: + build: + name: Test on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest] + + steps: + - name: checkout + uses: actions/checkout@v3 + - name: install dependencies + run: | + sudo apt update + sudo apt install cmake make gcc ccache + - name: configure cmake + run: | + cmake -B ${{github.workspace}}/build \ + -D CMAKE_INSTALL_PREFIX=${{github.workspace}}/build/install \ + -D CMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} \ + -D CMAKE_C_COMPILER=/usr/lib/ccache/gcc \ + -D BFDEV_DEVEL=ON + - name: make + run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} + - name: install + working-directory: ${{github.workspace}}/build + run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -- install + - name: ctest + working-directory: ${{github.workspace}}/build + run: ctest -C ${{env.BUILD_TYPE}} -V diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml new file mode 100644 index 00000000..953ba450 --- /dev/null +++ b/.github/workflows/windows.yml @@ -0,0 +1,46 @@ +name: build default on windows + +on: + repository_dispatch: + workflow_dispatch: + push: + pull_request: + schedule: + - cron: '0 */2 * * *' + +env: + BUILD_TYPE: Debug + +jobs: + build: + name: Test on ${{ matrix.os }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [windows-latest] + defaults: + run: + shell: msys2 {0} + + steps: + - name: checkout + uses: actions/checkout@v3 + - name: install dependencies + uses: msys2/setup-msys2@v2 + with: + msystem: UCRT64 + update: true + install: cmake make gcc + - name: configure cmake + run: | + cmake -B build \ + -D CMAKE_INSTALL_PREFIX=build/install \ + -D CMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} \ + -D BFDEV_EXAMPLES=ON + - name: make + run: cmake --build build --config ${{env.BUILD_TYPE}} + - name: install + run: cmake --build build --config ${{env.BUILD_TYPE}} -- install + - name: ctest + working-directory: ${{github.workspace}}/build + run: ctest -C ${{env.BUILD_TYPE}} -V diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..b217b044 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +CMakeFiles/ +generated/ +CMakeCache.txt +CTestTestfile.cmake +cmake_install.cmake +Makefile +libbfdev.* diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 00000000..b1ddf016 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,15 @@ + This is the people who participate in the development + of the project, and they have made great contributions + to the development of the project. + Thanks + +----------- +Bfdev Designer Group + +Name : ffashion +Email : helloworldffashion@gmail.com +Represent : global + +Name : John Sanpe +Email : sanpeqf@gmail.com +Represent : global diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..f5a2895f --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,276 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright(c) 2023 ffashion +# Copyright(c) 2023 John Sanpe +# + +cmake_minimum_required(VERSION 3.12) +project(bfdev VERSION 1.0.0 LANGUAGES C) + +include(GNUInstallDirs) +include(CheckIncludeFiles) +include(CheckCXXSymbolExists) +include(CheckFunctionExists) +include(CheckCSourceCompiles) + +set(BFDEV_ARCH dummy) +set(BFDEV_NAME sirius) + +set(BFDEV_EXTREVERSION -devel) +set(BFDEV_VERSION ${PROJECT_VERSION}) + +if(BFDEV_EXTREVERSION) + string(APPEND BFDEV_VERSION ${BFDEV_EXTREVERSION}) +endif() + +set(BFDEV_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) +set(BFDEV_HEADER_PATH ${PROJECT_SOURCE_DIR}/include) +set(BFDEV_SOURCE_PATH ${PROJECT_SOURCE_DIR}/src) +set(BFDEV_DOCUMENT_PATH ${PROJECT_SOURCE_DIR}/docs) +set(BFDEV_GENERATED_PATH ${PROJECT_BINARY_DIR}/generated) + +set(BFDEV_ARCH_PATH ${PROJECT_SOURCE_DIR}/arch/${BFDEV_ARCH}) +set(BFDEV_ARCH_HEADER_PATH ${BFDEV_ARCH_PATH}/include) +set(BFDEV_CONFIGURE ${BFDEV_GENERATED_PATH}/bfdev-config.cmake) + +include(scripts/asm-generic.cmake) +include(scripts/hostrule.cmake) +include(scripts/packed-header.cmake) +include(scripts/commit.cmake) + +commit_hash(BFDEV_COMMITID) +commit_branch(BFDEV_BRANCH) + +option(BFDEV_DEVEL "Enable development mode" OFF) +option(BFDEV_EXAMPLES "Build examples" OFF) +option(BFDEV_STRICT "Enable strict compilation" ON) +option(BFDEV_ASAN "Enable Address Sanitizer" OFF) +option(BFDEV_UBSAN "Enable Undefined Behaviour Sanitizer" OFF) + +option(BFDEV_DBGLIST "Dynamic debug list" ON) +option(BFDEV_DBGSLIST "Dynamic debug slist" ON) +option(BFDEV_DBGHLIST "Dynamic debug hlist" ON) +option(BFDEV_DBGILIST "Dynamic debug ilist" ON) +option(BFDEV_DBGRBTREE "Dynamic debug rbtree" ON) +option(BFDEV_DBGHEAP "Dynamic debug heap" ON) +option(BFDEV_DBGREFCNT "Dynamic debug refcnt" ON) + +if(BFDEV_DEVEL) + set(BFDEV_EXAMPLES ON) + set(BFDEV_ASAN ON) + set(BFDEV_UBSAN ON) +endif() + +if(BFDEV_DBGLIST) + set(BFDEV_DEBUG_LIST ON) +endif() + +if(BFDEV_DBGSLIST) + set(BFDEV_DEBUG_SLIST ON) +endif() + +if(BFDEV_DBGHLIST) + set(BFDEV_DEBUG_HLIST ON) +endif() + +if(BFDEV_DBGILIST) + set(BFDEV_DEBUG_ILIST ON) +endif() + +if(BFDEV_DBGRBTREE) + set(BFDEV_DEBUG_RBTREE ON) +endif() + +if(BFDEV_DBGHEAP) + set(BFDEV_DEBUG_HEAP ON) +endif() + +if(BFDEV_DBGREFCNT) + set(BFDEV_DEBUG_REFCNT ON) +endif() + +asm_generic( + bfdev/asm-generic/ + ${BFDEV_GENERATED_PATH}/bfdev/asm + ${BFDEV_ARCH_HEADER_PATH}/bfdev/asm + ${BFDEV_HEADER_PATH}/bfdev/asm-generic +) + +packed_header( + bfdev/ + _BFDEV_H_ + ${BFDEV_GENERATED_PATH}/bfdev.h + ${BFDEV_HEADER_PATH}/bfdev +) + +configure_file( + ${BFDEV_MODULE_PATH}/config.h.in + ${BFDEV_GENERATED_PATH}/bfdev/config.h +) + +configure_file( + ${BFDEV_MODULE_PATH}/bfdev-config.cmake.in + ${BFDEV_CONFIGURE} +) + +file(GLOB BFDEV_HEADER + ${BFDEV_HEADER_PATH}/bfdev/*.h +) + +file(GLOB BFDEV_ASM_HEADER + ${BFDEV_HEADER_PATH}/bfdev/asm-generic/*.h +) + +file(GLOB BFDEV_ARCH_ASM_HEADER + ${BFDEV_ARCH_HEADER_PATH}/bfdev/asm/*.h +) + +file(GLOB BFDEV_GENERATED_HEADER + ${BFDEV_GENERATED_PATH}/*.h +) + +add_compile_options( + -std=gnu11 + -Wall + -Wextra + -Wno-override-init + -Wno-unused-parameter + -Wno-sign-compare + -Wno-pointer-sign + -Wno-null-pointer-arithmetic + -fvisibility=hidden +) + +if(BFDEV_STRICT) + set(CMAKE_C_FLAGS + "${CMAKE_C_FLAGS} \ + -Werror" + ) +endif() + +if(BFDEV_ASAN) + set(CMAKE_C_FLAGS + "${CMAKE_C_FLAGS} \ + -fsanitize=address \ + -fsanitize=undefined \ + -fsanitize-recover=all \ + -fno-omit-frame-pointer \ + -fno-stack-protector" + ) + if(NOT APPLE) + set(CMAKE_C_FLAGS + "${CMAKE_C_FLAGS} \ + -fsanitize=leak" + ) + endif() +endif() + +if(BFDEV_UBSAN) + set(CMAKE_C_FLAGS + "${CMAKE_C_FLAGS} \ + -fsanitize=alignment \ + -fsanitize=bounds \ + -fsanitize=shift \ + -fsanitize=integer-divide-by-zero \ + -fsanitize=unreachable \ + -fsanitize=bool \ + -fsanitize=enum \ + -fsanitize-undefined-trap-on-error" + ) +endif() + +include_directories(${PROJECT_SOURCE_DIR}/include) +include_directories(${PROJECT_BINARY_DIR}/generated) + +add_subdirectory(${PROJECT_SOURCE_DIR}/scripts) +include(${PROJECT_SOURCE_DIR}/build.cmake) + +set(BFDEV_LIBRARY + ${BFDEV_HEADER} + ${BFDEV_ASM_HEADER} + ${BFDEV_ARCH_ASM_HEADER} + ${BFDEV_GENERATED_HEADER} + ${BFDEV_INCLUDE} + ${BFDEV_SOURCE} + ${BFDEV_ARCH_SOURCE} +) + +macro(bfdev_dependencies target) + add_dependencies( + ${target} + gen-crc8 + gen-crc16 + gen-crc16be + gen-crc32 + gen-crc32be + gen-crc64 + gen-crc64be + ) +endmacro() + +add_library(bfdev_object OBJECT ${BFDEV_LIBRARY}) +bfdev_dependencies(bfdev_object) +add_library(bfdev ALIAS bfdev_object) + +if(BFDEV_EXAMPLES) + enable_testing() + add_subdirectory(examples) +endif() + +if(${CMAKE_PROJECT_NAME} STREQUAL "bfdev") + add_library(bfdev_static STATIC ${BFDEV_LIBRARY}) + add_library(bfdev_shared SHARED ${BFDEV_LIBRARY}) + + bfdev_dependencies(bfdev_static) + bfdev_dependencies(bfdev_shared) + + set_target_properties(bfdev_static + PROPERTIES + OUTPUT_NAME ${PROJECT_NAME} + LINKER_LANGUAGE C + ) + + set_target_properties(bfdev_shared + PROPERTIES + OUTPUT_NAME ${PROJECT_NAME} + VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_VERSION_MAJOR} + LINKER_LANGUAGE C + MACOSX_RPATH ON + ) + + install(FILES + ${BFDEV_GENERATED_PATH}/bfdev.h + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + ) + + install(FILES + ${CMAKE_SOURCE_DIR}/README.md + ${CMAKE_SOURCE_DIR}/AUTHORS + ${CMAKE_SOURCE_DIR}/COPYING + DESTINATION ${CMAKE_INSTALL_DOCDIR} + ) + + install(FILES + ${BFDEV_CONFIGURE} + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/bfdev + ) + + install(DIRECTORY + ${BFDEV_HEADER_PATH}/bfdev + ${BFDEV_GENERATED_PATH}/bfdev + ${BFDEV_ARCH_HEADER_PATH}/bfdev + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + ) + + install(DIRECTORY + ${BFDEV_DOCUMENT_PATH} + DESTINATION ${CMAKE_INSTALL_DOCDIR} + ) + + install(TARGETS + bfdev_static bfdev_shared + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ) +endif() diff --git a/COPYING b/COPYING new file mode 100644 index 00000000..6d45519c --- /dev/null +++ b/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/README b/README deleted file mode 100644 index 2863ee69..00000000 --- a/README +++ /dev/null @@ -1,2 +0,0 @@ -bfdev stand for brief dev or base fast dev. -this is a c lang base algo lib. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100755 index 00000000..9ed18620 --- /dev/null +++ b/README.md @@ -0,0 +1,93 @@ +# BFDEV Introduce + +bfdev is a high-performance, aesthetically pleasing, and portable infrastructure provisioning library. Its goal is to provide a comprehensive and streamlined development environment. + +![logo](docs/images/logo.png) + +## Continuous Integration Status + +| Status (master) | Status (devel) | Description | +| :----------------------------------------------------------: | :----------------------------------------------------------: | :----------------------------------: | +| [![build status](https://github.com/openbfdev/bfdev/actions/workflows/ubuntu-gcc.yml/badge.svg?branch=master)](https://github.com/openbfdev/bfdev/actions/workflows/ubuntu-gcc.yml?query=branch%3Amaster) | [![build status](https://github.com/openbfdev/bfdev/actions/workflows/ubuntu-gcc.yml/badge.svg?branch=devel)](https://github.com/openbfdev/bfdev/actions/workflows/ubuntu-gcc.yml?query=branch%3Adevel) | Build default config on Ubuntu gcc | +| [![build status](https://github.com/openbfdev/bfdev/actions/workflows/ubuntu-clang.yml/badge.svg?branch=master)](https://github.com/openbfdev/bfdev/actions/workflows/ubuntu-clang.yml?query=branch%3Amaster) | [![build status](https://github.com/openbfdev/bfdev/actions/workflows/ubuntu-clang.yml/badge.svg?branch=devel)](https://github.com/openbfdev/bfdev/actions/workflows/ubuntu-clang.yml?query=branch%3Adevel) | Build default config on Ubuntu clang | +| [![build status](https://github.com/openbfdev/bfdev/actions/workflows/macos.yml/badge.svg?branch=master)](https://github.com/openbfdev/bfdev/actions/workflows/macos.yml?query=branch%3Amaster) | [![build status](https://github.com/openbfdev/bfdev/actions/workflows/macos.yml/badge.svg?branch=devel)](https://github.com/openbfdev/bfdev/actions/workflows/macos.yml?query=branch%3Adevel) | Build default config on Macos | +| [![build status](https://github.com/openbfdev/bfdev/actions/workflows/windows.yml/badge.svg?branch=master)](https://github.com/openbfdev/bfdev/actions/workflows/windows.yml?query=branch%3Amaster) | [![build status](https://github.com/openbfdev/bfdev/actions/workflows/windows.yml/badge.svg?branch=devel)](https://github.com/openbfdev/bfdev/actions/workflows/windows.yml?query=branch%3Adevel) | Build default config on Windows | +| [![build status](https://github.com/openbfdev/bfdev/actions/workflows/codeql.yml/badge.svg?branch=master)](https://github.com/openbfdev/bfdev/actions/workflows/codeql.yml?query=branch%3Amaster) | [![build status](https://github.com/openbfdev/bfdev/actions/workflows/codeql.yml/badge.svg?branch=devel)](https://github.com/openbfdev/bfdev/actions/workflows/codeql.yml?query=branch%3Adevel) | Code analyse on codeql | + +## Why Choose + +- The library provides common data structures, eliminating the need to reinvent the wheel. +- Supports dynamic checking of data structures. +- Designed with an object-oriented approach, providing compatibility with various project. +- Offers a rich and well-organized set of APIs for users. +- Conforms to the GNUC standard, ensuring strong cross-platform compatibility. + +### WARNING + +This project is not yet fully completed, so it is not recommended for use in a production environment. + +View supported components: [Docs](docs/components.md) + +## Directory Structure + +``` +. +├── arch +├── cmake +├── docs +├── examples +├── include +├── scripts +└── src +``` + +| Directory | Description | +| :-------: | :----------------------: | +| arch | ISA related code | +| cmake | cmake configuration file | +| docs | doc for guiding | +| exampes | unit testing and case | +| include | include path | +| scripts | build scripts | +| src | core code path | + +## Reference Path + +```mermaid +graph LR + include[include] + include/asm-generic[asm-generic] + arch/asm[asm] + arch/asm-generated{exist} + + subgraph target[User Installation] + include/bfdev[bfdev] + include/bfdev/asm-generic[bfdev:asm-generic] + arch/bfdev/asm[bfdev:asm] + arch/bfdev/asm-generated{exist} + end + + include --> arch/asm-generated + arch/asm-generated --Y--> arch/asm + arch/asm -.-> include/asm-generic + arch/asm-generated --N--> include/asm-generic + include/bfdev --> arch/bfdev/asm-generated + arch/bfdev/asm-generated --Y--> arch/bfdev/asm + arch/bfdev/asm-generated --N--> include/bfdev/asm-generic + arch/bfdev/asm -.-> include/bfdev/asm-generic + include --> include/bfdev + arch/asm --> arch/bfdev/asm + include/asm-generic --> arch/bfdev/asm +``` + +## Documentation Tutorial + +Quickly start, API manual, see [Bfdev Documentation Tutorial](https://openbfdev.github.io/bfdev-docs) + +## License + +This is free software: you can redistribute it and/or modify it under the terms of the latest GNU General Public License as published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/. diff --git a/arch/dummy/build.cmake b/arch/dummy/build.cmake new file mode 100644 index 00000000..e94bbed1 --- /dev/null +++ b/arch/dummy/build.cmake @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright(c) 2023 John Sanpe +# + +# +# Nothing +# diff --git a/arch/dummy/include/bfdev/.gitkeep b/arch/dummy/include/bfdev/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/build.cmake b/build.cmake new file mode 100644 index 00000000..2ef3d509 --- /dev/null +++ b/build.cmake @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright(c) 2023 John Sanpe +# + +include(${BFDEV_ARCH_PATH}/build.cmake) +include(${BFDEV_SOURCE_PATH}/build.cmake) diff --git a/cmake/bfdev-config.cmake.in b/cmake/bfdev-config.cmake.in new file mode 100644 index 00000000..e96e1f96 --- /dev/null +++ b/cmake/bfdev-config.cmake.in @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright(c) 2023 ffashion +# + +@PACKAGE_INIT@ + +set(BFDEV_VERSION "@BFDEV_VERSION@") +set(BFDEV_INCLUDE_DIR "@CMAKE_INSTALL_PREFIX@/include") +set(BFDEV_LIBRARY_DIR "@CMAKE_INSTALL_PREFIX@/lib") +set(BFDEV_FOUND true) diff --git a/cmake/config.h.in b/cmake/config.h.in new file mode 100644 index 00000000..5e1d6cdf --- /dev/null +++ b/cmake/config.h.in @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 ffashion + * Copyright(c) 2023 John Sanpe + */ + +#ifndef _BFDEV_CONFIG_H_ +#define _BFDEV_CONFIG_H_ + +#include +#include +#include + +BFDEV_BEGIN_DECLS + +#define BFDEV_VERSION_MAJOR ${CMAKE_PROJECT_VERSION_MAJOR} +#define BFDEV_VERSION_MINOR ${CMAKE_PROJECT_VERSION_MINOR} +#define BFDEV_VERSION_PATCH ${CMAKE_PROJECT_VERSION_PATCH} +#define BFDEV_VERSION_TWEAK ${CMAKE_PROJECT_VERSION_TWEAK} +#define BFDEV_EXTREVERSION ${BFDEV_EXTREVERSION} + +#define BFDEV_ARCH ${BFDEV_ARCH} +#define BFDEV_NAME ${BFDEV_NAME} +#define BFDEV_VERSION ${BFDEV_VERSION} + +#define BFDEV_COMMITID ${BFDEV_COMMITID} +#define BFDEV_BRANCH ${BFDEV_BRANCH} + +#cmakedefine BFDEV_DEBUG_LIST +#cmakedefine BFDEV_DEBUG_SLIST +#cmakedefine BFDEV_DEBUG_HLIST +#cmakedefine BFDEV_DEBUG_ILIST +#cmakedefine BFDEV_DEBUG_RBTREE +#cmakedefine BFDEV_DEBUG_HEAP +#cmakedefine BFDEV_DEBUG_REFCNT + +#define BFDEV_VERSION_CHECK(major, minor, patch) ( \ + ((major) == BFDEV_VERSION_MAJOR) && \ + (((minor) < BFDEV_VERSION_MINOR) || \ + ((minor) == BFDEV_VERSION_MINOR && \ + (patch) <= BFDEV_VERSION_PATCH)) \ +) + +static inline int +bfdev_version_major(void) +{ + return BFDEV_VERSION_MAJOR; +} + +static inline int +bfdev_version_minor(void) +{ + return BFDEV_VERSION_MINOR; +} + +static inline int +bfdev_version_patch(void) +{ + return BFDEV_VERSION_PATCH; +} + +BFDEV_END_DECLS + +#endif /*_BFDEV_CONFIG_H_*/ diff --git a/docs/components.md b/docs/components.md new file mode 100644 index 00000000..b90a483a --- /dev/null +++ b/docs/components.md @@ -0,0 +1,93 @@ +# Supporting Components + +## Data Structures + +- array +- bloom +- btree +- fifo +- hashmap +- hashtbl +- heap +- hlist +- ilist +- list +- llist +- radix +- rbtree +- ringbuf +- segtree +- skiplist +- slist + +## Algorithms + +- ascii85 +- base64 +- base64 +- bsearch +- crc +- hash +- prandom +- stringhash + +## Bit Operation + +- bcd +- bitfied +- bitmap +- bitops +- bitrev +- bitwalk +- popcount + +## Architecture + +- atomic +- byteorder +- cmpxchg +- overflow +- swab +- unaligned + +## Memory Allocator + +- allocator +- allocpool +- minpool + +## String Process + +- argv +- fsm +- levenshtein +- snprintf + +## Mathematics + +- align +- log2 +- math +- minmax +- uplower + +## Cache + +- lfu +- lru + +## Textsearch + +- bm +- kmp +- sunday + +## Miscellaneous + +- action +- callback +- container +- guards +- log +- notifier +- once diff --git a/docs/images/logo.png b/docs/images/logo.png new file mode 100755 index 00000000..f0c5d459 Binary files /dev/null and b/docs/images/logo.png differ diff --git a/docs/images/logo.svg b/docs/images/logo.svg new file mode 100644 index 00000000..67bd5bd5 --- /dev/null +++ b/docs/images/logo.svg @@ -0,0 +1,99 @@ + +bfdevbfdev diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 00000000..e1aba467 --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1,35 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright(c) 2023 ffashion +# + +add_subdirectory(allocator) +add_subdirectory(array) +add_subdirectory(base32) +add_subdirectory(base64) +add_subdirectory(bfdev) +add_subdirectory(bloom) +add_subdirectory(btree) +add_subdirectory(cache) +add_subdirectory(crc) +add_subdirectory(fifo) +add_subdirectory(fsm) +add_subdirectory(guards) +add_subdirectory(hashmap) +add_subdirectory(hashtbl) +add_subdirectory(heap) +add_subdirectory(hlist) +add_subdirectory(ilist) +add_subdirectory(levenshtein) +add_subdirectory(list) +add_subdirectory(log) +add_subdirectory(log2) +add_subdirectory(matrix) +add_subdirectory(once) +add_subdirectory(radix) +add_subdirectory(rbtree) +add_subdirectory(ringbuf) +add_subdirectory(segtree) +add_subdirectory(skiplist) +add_subdirectory(slist) +add_subdirectory(textsearch) diff --git a/examples/allocator/.gitignore b/examples/allocator/.gitignore new file mode 100644 index 00000000..409970b0 --- /dev/null +++ b/examples/allocator/.gitignore @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +/allocator-simple diff --git a/examples/allocator/CMakeLists.txt b/examples/allocator/CMakeLists.txt new file mode 100755 index 00000000..99f7a7a1 --- /dev/null +++ b/examples/allocator/CMakeLists.txt @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright(c) 2023 John Sanpe +# + +add_executable(allocator-simple simple.c) +target_link_libraries(allocator-simple bfdev) +add_test(allocator-simple allocator-simple) + +if(${CMAKE_PROJECT_NAME} STREQUAL "bfdev") + install(FILES + simple.c + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/examples/allocator + ) + + install(TARGETS + allocator-simple + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/bin + ) +endif() diff --git a/examples/allocator/simple.c b/examples/allocator/simple.c new file mode 100644 index 00000000..2020e9a8 --- /dev/null +++ b/examples/allocator/simple.c @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#include +#include + +static void * +test_alloc(size_t size, void *pdata) +{ + return malloc(size); +} + +static void * +test_realloc(void *block, size_t resize, void *pdata) +{ + return realloc((void *)block, resize); +} + +static void +test_free(void *block, void *pdata) +{ + return free((void *)block); +} + +BFDEV_DEFINE_ALLOC( + test_ops, + test_alloc, + test_realloc, + test_free, + NULL +); + +int main(int argc, char const *argv[]) +{ + int *block; + + block = bfdev_malloc(&test_ops, sizeof(*block)); + if (!block) + return 1; + bfdev_free(&test_ops, block); + + block = bfdev_zalloc(&test_ops, sizeof(*block)); + if (!block) + return 1; + block = bfdev_realloc(&test_ops, block, sizeof(*block) * 2); + if (!block) + return 1; + bfdev_free(&test_ops, block); + + return 0; +} diff --git a/examples/array/.gitignore b/examples/array/.gitignore new file mode 100644 index 00000000..e18d4665 --- /dev/null +++ b/examples/array/.gitignore @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +/array-simple diff --git a/examples/array/CMakeLists.txt b/examples/array/CMakeLists.txt new file mode 100644 index 00000000..3f90958f --- /dev/null +++ b/examples/array/CMakeLists.txt @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright(c) 2023 ffashion +# + +add_executable(array-simple simple.c) +target_link_libraries(array-simple bfdev) +add_test(array-simple array-simple) + +if(${CMAKE_PROJECT_NAME} STREQUAL "bfdev") + install(FILES + simple.c + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/examples/array + ) + + install(TARGETS + array-simple + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/bin + ) +endif() diff --git a/examples/array/simple.c b/examples/array/simple.c new file mode 100644 index 00000000..d4a54098 --- /dev/null +++ b/examples/array/simple.c @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#include +#include +#include +#include + +#define TEST_LOOP 100 +#define TEST_SIZE 64 +BFDEV_DEFINE_ARRAY(test_array, NULL, TEST_SIZE); + +int main(int argc, const char *argv[]) +{ + unsigned int count; + void *array; + + for (count = 0; count < TEST_LOOP; ++count) { + unsigned int num; + + num = rand() % TEST_SIZE; + array = bfdev_array_push(&test_array, num); + memset(array, 0, TEST_SIZE * num); + + printf("array bfdev_array_push test: %02u: %u\n", + count, num); + } + + bfdev_array_release(&test_array); + return 0; +} diff --git a/examples/base32/.gitignore b/examples/base32/.gitignore new file mode 100644 index 00000000..a779548f --- /dev/null +++ b/examples/base32/.gitignore @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +/base32-bandwidth diff --git a/examples/base32/CMakeLists.txt b/examples/base32/CMakeLists.txt new file mode 100755 index 00000000..fa0ac4fd --- /dev/null +++ b/examples/base32/CMakeLists.txt @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright(c) 2023 John Sanpe +# + +add_executable(base32-bandwidth bandwidth.c) +target_link_libraries(base32-bandwidth bfdev) +add_test(base32-bandwidth base32-bandwidth) + +if(${CMAKE_PROJECT_NAME} STREQUAL "bfdev") + install(FILES + bandwidth.c + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/examples/base32 + ) + + install(TARGETS + base32-bandwidth + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/bin + ) +endif() diff --git a/examples/base32/bandwidth.c b/examples/base32/bandwidth.c new file mode 100644 index 00000000..ad80a9e3 --- /dev/null +++ b/examples/base32/bandwidth.c @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#define MODULE_NAME "base32-bandwidth" +#define bfdev_log_fmt(fmt) MODULE_NAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include "../time.h" + +#define TEST_SIZE BFDEV_SZ_1MiB +#define TEST_LOOP 3 + +int main(int argc, char const *argv[]) +{ + unsigned int count, loop; + uint8_t *dbuff, *sbuff; + size_t dlen, slen, index; + uint32_t cksum, check; + + slen = bfdev_base32_encode_length(TEST_SIZE); + sbuff = malloc(slen); + if (!sbuff) + return 1; + + dlen = bfdev_base32_decode_length(slen); + dbuff = malloc(dlen); + if (!dbuff) + return 1; + + srand(time(NULL)); + for (index = 0; index < TEST_SIZE; ++index) + dbuff[index] = (uint8_t)rand(); + + cksum = bfdev_crc32(dbuff, dlen, (uint32_t)~0UL); + bfdev_log_info("start checksum: %#010x\n", cksum); + + for (count = 0; count < TEST_LOOP; ++count) { + EXAMPLE_TIME_LOOP(&loop, 1000, + bfdev_base32_encode(sbuff, dbuff, TEST_SIZE); + 0; + ); + bfdev_log_info("encode bandwidth %u: %uMiB/s\n", count, loop); + + EXAMPLE_TIME_LOOP(&loop, 1000, + bfdev_base32_decode(dbuff, sbuff, slen); + 0; + ); + bfdev_log_info("decode bandwidth %u: %uMiB/s\n", count, loop); + } + + check = bfdev_crc32(dbuff, dlen, (uint32_t)~0UL); + if (cksum != check) { + bfdev_log_err("verification failed\n"); + return 1; + } + bfdev_log_info("verification pass\n"); + + free(sbuff); + free(dbuff); + + return 0; +} diff --git a/examples/base64/.gitignore b/examples/base64/.gitignore new file mode 100644 index 00000000..4d626c27 --- /dev/null +++ b/examples/base64/.gitignore @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +/base64-bandwidth diff --git a/examples/base64/CMakeLists.txt b/examples/base64/CMakeLists.txt new file mode 100755 index 00000000..2aff05e3 --- /dev/null +++ b/examples/base64/CMakeLists.txt @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright(c) 2023 John Sanpe +# + +add_executable(base64-bandwidth bandwidth.c) +target_link_libraries(base64-bandwidth bfdev) +add_test(base64-bandwidth base64-bandwidth) + +if(${CMAKE_PROJECT_NAME} STREQUAL "bfdev") + install(FILES + bandwidth.c + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/examples/base64 + ) + + install(TARGETS + base64-bandwidth + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/bin + ) +endif() diff --git a/examples/base64/bandwidth.c b/examples/base64/bandwidth.c new file mode 100644 index 00000000..607e43a8 --- /dev/null +++ b/examples/base64/bandwidth.c @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#define MODULE_NAME "base64-bandwidth" +#define bfdev_log_fmt(fmt) MODULE_NAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include "../time.h" + +#define TEST_SIZE BFDEV_SZ_1MiB +#define TEST_LOOP 3 + +int main(int argc, char const *argv[]) +{ + unsigned int count, loop; + uint8_t *dbuff, *sbuff; + size_t dlen, slen, index; + uint32_t cksum, check; + + slen = bfdev_base64_encode_length(TEST_SIZE); + sbuff = malloc(slen); + if (!sbuff) + return 1; + + dlen = bfdev_base64_decode_length(slen); + dbuff = malloc(dlen); + if (!dbuff) + return 1; + + srand(time(NULL)); + for (index = 0; index < TEST_SIZE; ++index) + dbuff[index] = (uint8_t)rand(); + + cksum = bfdev_crc32(dbuff, dlen, (uint32_t)~0UL); + bfdev_log_info("start checksum: %#010x\n", cksum); + + for (count = 0; count < TEST_LOOP; ++count) { + EXAMPLE_TIME_LOOP(&loop, 1000, + bfdev_base64_encode(sbuff, dbuff, TEST_SIZE); + 0; + ); + bfdev_log_info("encode bandwidth %u: %uMiB/s\n", count, loop); + + EXAMPLE_TIME_LOOP(&loop, 1000, + bfdev_base64_decode(dbuff, sbuff, slen); + 0; + ); + bfdev_log_info("decode bandwidth %u: %uMiB/s\n", count, loop); + } + + check = bfdev_crc32(dbuff, dlen, (uint32_t)~0UL); + if (cksum != check) { + bfdev_log_err("verification failed\n"); + return 1; + } + bfdev_log_info("verification pass\n"); + + free(sbuff); + free(dbuff); + + return 0; +} diff --git a/examples/bfdev/.gitignore b/examples/bfdev/.gitignore new file mode 100644 index 00000000..b253ef84 --- /dev/null +++ b/examples/bfdev/.gitignore @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +/bfdev-version diff --git a/examples/bfdev/CMakeLists.txt b/examples/bfdev/CMakeLists.txt new file mode 100755 index 00000000..94f178c4 --- /dev/null +++ b/examples/bfdev/CMakeLists.txt @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright(c) 2023 John Sanpe +# + +add_executable(bfdev-version version.c) +target_link_libraries(bfdev-version bfdev) +add_test(bfdev-version bfdev-version) + +if(${CMAKE_PROJECT_NAME} STREQUAL "bfdev") + install(FILES + version.c + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/examples/bfdev + ) + + install(TARGETS + bfdev-version + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/bin + ) +endif() diff --git a/examples/bfdev/version.c b/examples/bfdev/version.c new file mode 100755 index 00000000..840d0070 --- /dev/null +++ b/examples/bfdev/version.c @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#include +#include + +int main(int argc, const char *argv[]) +{ + printf("arch: %s\n", __bfdev_stringify(BFDEV_ARCH)); + printf("name: %s\n", __bfdev_stringify(BFDEV_NAME)); + printf("version: %s\n", __bfdev_stringify(BFDEV_VERSION)); + printf("commitid: %s\n", __bfdev_stringify(BFDEV_COMMITID)); + printf("branch: %s\n", __bfdev_stringify(BFDEV_BRANCH)); + return 0; +} diff --git a/examples/bloom/.gitignore b/examples/bloom/.gitignore new file mode 100644 index 00000000..acfa7643 --- /dev/null +++ b/examples/bloom/.gitignore @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +/bloom-simple diff --git a/examples/bloom/CMakeLists.txt b/examples/bloom/CMakeLists.txt new file mode 100644 index 00000000..f184ae15 --- /dev/null +++ b/examples/bloom/CMakeLists.txt @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright(c) 2023 ffashion +# + +add_executable(bloom-simple simple.c) +target_link_libraries(bloom-simple bfdev) +add_test(bloom-simple bloom-simple) + +if(${CMAKE_PROJECT_NAME} STREQUAL "bfdev") + install(FILES + simple.c + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/examples/bloom + ) + + install(TARGETS + bloom-simple + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/bin + ) +endif() diff --git a/examples/bloom/simple.c b/examples/bloom/simple.c new file mode 100644 index 00000000..db3a2294 --- /dev/null +++ b/examples/bloom/simple.c @@ -0,0 +1,68 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#include +#include +#include +#include +#include +#include +#include + +#define TEST_LOOP 50 +#define TEST_SIZE 100 + +static unsigned int +bloom_hash(unsigned int func, const void *key, void *pdata) +{ + unsigned int hash; + + switch (func) { + case 0: + hash = bfdev_pjwhash(key); + break; + + case 1: + hash = (unsigned int)(uintptr_t)key; + break; + + default: + abort(); + } + + return hash; +} + +int main(int argc, const char *argv[]) +{ + struct bfdev_bloom *bloom; + char buffer[TEST_SIZE][32]; + unsigned int count; + bool retval; + + bloom = bfdev_bloom_create(NULL, TEST_SIZE, bloom_hash, 2, NULL); + if (!bloom) + err(errno, "bfdev_bloom_create"); + + for (count = 0; count < TEST_LOOP; ++count) { + snprintf(buffer[count], sizeof(*buffer), "%d", rand()); + retval = bfdev_bloom_push(bloom, buffer[count]); + printf("push %u: %s (%s)\n", count, buffer[count], + retval ? "clash" : "none"); + } + + for (count = 0; count < TEST_LOOP; ++count) { + retval = bfdev_bloom_peek(bloom, buffer[count]); + printf("peek %u: %s (%s)\n", count, buffer[count], + retval ? "passed" : "failed"); + if (!retval) + return 1; + } + + bfdev_bloom_flush(bloom); + bfdev_bloom_destory(bloom); + + return 0; +} diff --git a/examples/btree/.gitignore b/examples/btree/.gitignore new file mode 100644 index 00000000..d949011a --- /dev/null +++ b/examples/btree/.gitignore @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +/btree-benchmark +/btree-selftest diff --git a/examples/btree/CMakeLists.txt b/examples/btree/CMakeLists.txt new file mode 100644 index 00000000..f7508d6c --- /dev/null +++ b/examples/btree/CMakeLists.txt @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright(c) 2023 ffashion +# + +add_executable(btree-benchmark benchmark.c) +target_link_libraries(btree-benchmark bfdev) +add_test(btree-benchmark btree-benchmark) + +add_executable(btree-selftest selftest.c) +target_link_libraries(btree-selftest bfdev) +add_test(btree-selftest btree-selftest) + +if(${CMAKE_PROJECT_NAME} STREQUAL "bfdev") + install(FILES + benchmark.c + selftest.c + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/examples/btree + ) + + install(TARGETS + btree-benchmark + btree-selftest + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/bin + ) +endif() diff --git a/examples/btree/benchmark.c b/examples/btree/benchmark.c new file mode 100644 index 00000000..74d1a147 --- /dev/null +++ b/examples/btree/benchmark.c @@ -0,0 +1,104 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2021 John Sanpe + */ + +#define MODULE_NAME "btree-benchmark" +#define bfdev_log_fmt(fmt) MODULE_NAME ": " fmt + +#include +#include +#include +#include +#include "../time.h" + +#define BTREE_DEBUG 0 +#define TEST_LEN 1000000 + +struct bench_node { + unsigned int num; + uintptr_t data; +}; + +#if BTREE_DEBUG +static void +node_dump(struct bench_node *node) +{ + bfdev_log_info("\t%04d: ", node->num); + bfdev_log_info("data %#018lx ", node->data); + bfdev_log_info("\n"); +} +#else +# define node_dump(node) ((void)(node)) +#endif + +static const struct bfdev_btree_ops +bench_ops = { + .alloc = bfdev_btree_alloc, + .free = bfdev_btree_free, + .find = bfdev_btree_key_find, +}; + +int main(int argc, const char *argv[]) +{ + struct bench_node *node; + unsigned int count; + uintptr_t key; + void *block; + + BFDEV_BTREE_ROOT( + bench_root, &bfdev_btree_layoutptr, + &bench_ops, NULL + ); + + node = block = malloc(sizeof(*node) * TEST_LEN); + if (!block) { + bfdev_log_err("Insufficient memory!\n"); + return 1; + } + + srand(time(NULL)); + bfdev_log_info("Generate %u node:\n", TEST_LEN); + for (count = 0; count < TEST_LEN; ++count) { + node[count].num = count + 1; + node[count].data = ((uint64_t)rand() << 32) | rand(); +#if BTREE_DEBUG + bfdev_log_info("\t%08d: 0x%016lx\n", node->num, node->data); +#endif + } + + bfdev_log_info("Insert nodes:\n"); + EXAMPLE_TIME_STATISTICAL( + for (count = 0; count < TEST_LEN; ++count) + bfdev_btree_insert(&bench_root, &node[count].data, node); + 0; + ); + + count = 0; + bfdev_log_info("Btree iteration:\n"); + EXAMPLE_TIME_STATISTICAL( + bfdev_btree_for_each(&bench_root, &key, node) { + node_dump(node); + count++; + } + 0; + ); + bfdev_log_info("\ttotal num: %u\n", count); + + count = 0; + bfdev_log_info("Btree reverse iteration:\n"); + EXAMPLE_TIME_STATISTICAL( + bfdev_btree_for_each_reverse(&bench_root, &key, node) { + node_dump(node); + count++; + } + 0; + ); + bfdev_log_info("\ttotal num: %u\n", count); + + bfdev_log_info("Done.\n"); + bfdev_btree_destroy(&bench_root); + free(block); + + return 0; +} diff --git a/examples/btree/selftest.c b/examples/btree/selftest.c new file mode 100644 index 00000000..759f7ce2 --- /dev/null +++ b/examples/btree/selftest.c @@ -0,0 +1,194 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2022 John Sanpe + */ + +#include +#include +#include +#include +#include +#include + +#define TEST_LOOP 100 + +struct test_node { + struct bfdev_list_head list; + union { + uintptr_t key; + char uuid[11]; + }; +}; + +static int +test_clash(struct bfdev_btree_root *root, void *value, void *clash) +{ + struct test_node *vnode = value; + struct test_node *cnode = clash; + bfdev_list_add(&vnode->list, &cnode->list); + return 0; +} + +static void * +test_remove(struct bfdev_btree_root *root, void *value) +{ + struct test_node *vnode = value; + struct test_node *remove; + + if (bfdev_list_check_empty(&vnode->list)) + return NULL; + + remove = bfdev_list_first_entry(&vnode->list, struct test_node, list); + bfdev_list_del(&remove->list); + + return remove; +} + +static long +test_strfind(struct bfdev_btree_root *root, uintptr_t *node, uintptr_t *key) +{ + const char *nstring = (void *)*node ?: ""; + const char *kstring = (void *)*key ?: ""; + return strcmp(nstring, kstring); +} + +static const struct bfdev_btree_ops +test_value_ops = { + .alloc = bfdev_btree_alloc, + .free = bfdev_btree_free, + .find = bfdev_btree_key_find, + .clash = test_clash, + .remove = test_remove, + +}; + +static const struct bfdev_btree_ops +test_string_ops = { + .alloc = bfdev_btree_alloc, + .free = bfdev_btree_free, + .find = test_strfind, + .clash = test_clash, + .remove = test_remove, +}; + +static int +test_testing(struct test_node *nodes) +{ + struct test_node *lookup; + unsigned int count; + uintptr_t insert; + void *value; + int retval; + + BFDEV_BTREE_ROOT( + root32, &bfdev_btree_layout32, + &test_value_ops, NULL + ); + + srand(time(NULL)); + for (count = 0; count < TEST_LOOP; ++count) { + bfdev_list_head_init(&nodes[count].list); + nodes[count].key = (uintptr_t)rand(); + } + + for (count = 0; count < TEST_LOOP; ++count) { + retval = bfdev_btree_insert(&root32, &nodes[count].key, &nodes[count]); + printf("btree random insert test%d: %#010lx retval %d\n", count, + (unsigned long)nodes[count].key, retval); + if (retval) + return retval; + } + + for (count = 0; count < TEST_LOOP; ++count) { + lookup = bfdev_btree_lookup(&root32, &nodes[count].key); + printf("btree random lookup test%d: ", count); + if (!lookup || (lookup != &nodes[count] && bfdev_list_check_empty(&lookup->list))) { + printf("failed\n"); + return 1; + } + printf("pass\n"); + } + + bfdev_btree_for_each(&root32, &insert, value) { + printf("btree random for each: %#010lx = %p\n", + (unsigned long)insert, value); + } + + bfdev_btree_for_each_reverse(&root32, &insert, value) { + printf("btree random for each reverse: %#010lx = %p\n", + (unsigned long)insert, value); + } + + for (count = 0; count < TEST_LOOP; ++count) { + lookup = bfdev_btree_remove(&root32, &nodes[count].key); + printf("btree random remove test%d\n", count); + } + + bfdev_btree_destroy(&root32); + + BFDEV_BTREE_ROOT( + rootstr, &bfdev_btree_layout32, + &test_string_ops, NULL + ); + + for (count = 0; count < TEST_LOOP; ++count) { + bfdev_list_head_init(&nodes[count].list); + snprintf(nodes[count].uuid, sizeof(nodes->uuid), + "%#010x", (unsigned int)rand()); + } + + for (count = 0; count < TEST_LOOP; ++count) { + insert = (uintptr_t)&nodes[count].uuid; + retval = bfdev_btree_insert(&rootstr, &insert, &nodes[count]); + printf("btree string insert test%d: %s retval %d\n", count, + nodes[count].uuid, retval); + if (retval) + return retval; + } + + for (count = 0; count < TEST_LOOP; ++count) { + insert = (uintptr_t)&nodes[count].uuid; + lookup = bfdev_btree_lookup(&rootstr, &insert); + printf("btree string lookup test%d: ", count); + if (!lookup || (lookup != &nodes[count] && bfdev_list_check_empty(&lookup->list))) { + printf("failed\n"); + return 1; + } + printf("pass\n"); + } + + bfdev_btree_for_each(&rootstr, &insert, value) { + printf("btree string for each: %s = %p\n", + (char *)insert, value); + } + + bfdev_btree_for_each_reverse(&rootstr, &insert, value) { + printf("btree string for each reverse: %s = %p\n", + (char *)insert, value); + } + + for (count = 0; count < TEST_LOOP; ++count) { + insert = (uintptr_t)&nodes[count].uuid; + lookup = bfdev_btree_remove(&rootstr, &insert); + printf("btree string remove test%d\n", count); + } + + bfdev_btree_destroy(&rootstr); + + return 0; +} + +int main(int argc, const char *argv[]) +{ + struct test_node *bdata; + int retval; + + bdata = malloc(sizeof(*bdata) * TEST_LOOP); + if (!bdata) + return 1; + + retval = test_testing(bdata); + free(bdata); + + return retval; +} diff --git a/examples/cache/.gitignore b/examples/cache/.gitignore new file mode 100644 index 00000000..884a92be --- /dev/null +++ b/examples/cache/.gitignore @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +/cache-simple diff --git a/examples/cache/CMakeLists.txt b/examples/cache/CMakeLists.txt new file mode 100755 index 00000000..666eccc5 --- /dev/null +++ b/examples/cache/CMakeLists.txt @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright(c) 2023 John Sanpe +# + +add_executable(cache-simple simple.c) +target_link_libraries(cache-simple bfdev) +add_test(cache-simple cache-simple) + +if(${CMAKE_PROJECT_NAME} STREQUAL "bfdev") + install(FILES + simple.c + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/examples/cache + ) + + install(TARGETS + cache-simple + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/bin + ) +endif() diff --git a/examples/cache/simple.c b/examples/cache/simple.c new file mode 100644 index 00000000..f58971b4 --- /dev/null +++ b/examples/cache/simple.c @@ -0,0 +1,63 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#define MODULE_NAME "cache-simple" +#define bfdev_log_fmt(fmt) MODULE_NAME ": " fmt + +#include +#include +#include +#include +#include +#include + +#define TEST_LOOP 100 +#define TEST_SIZE 10 +#define TEST_MASK 30 + +int main(int argc, const char *argv[]) +{ + struct bfdev_cache_head *cache; + unsigned int count; + + cache = bfdev_cache_create("lfu", NULL, TEST_SIZE, 1); + if (!cache) + return 1; + + srand(time(NULL)); + for (count = 0; count < TEST_LOOP; ++count) { + struct bfdev_cache_node *node; + unsigned int value, verify; + + value = (unsigned int)rand() % TEST_MASK; + node = bfdev_cache_get(cache, value); + if (!node) + return 1; + + if (node->status == BFDEV_CACHE_PENDING) { + bfdev_log_info("test%u cache miss: %u\n", count, value); + node->pdata = (void *)(uintptr_t)value; + bfdev_cache_committed(cache); + } else { + verify = (uintptr_t)node->pdata; + if (value == verify) + bfdev_log_info("test%u cache hit: %u passed\n", count, verify); + else { + bfdev_log_err("test%u cache hit: %u failed\n", count, verify); + return 1; + } + } + + bfdev_cache_put(cache, node); + } + + bfdev_log_notice("cache changed = %lu\n", cache->changed); + bfdev_log_notice("cache starve = %lu\n", cache->starve); + bfdev_log_notice("cache hits = %lu\n", cache->hits); + bfdev_log_notice("cache misses = %lu\n", cache->misses); + bfdev_cache_destroy(cache); + + return 0; +} diff --git a/examples/crc/.gitignore b/examples/crc/.gitignore new file mode 100644 index 00000000..3de19f33 --- /dev/null +++ b/examples/crc/.gitignore @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +/crc-bandwidth diff --git a/examples/crc/CMakeLists.txt b/examples/crc/CMakeLists.txt new file mode 100755 index 00000000..87e082ad --- /dev/null +++ b/examples/crc/CMakeLists.txt @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright(c) 2023 John Sanpe +# + +add_executable(crc-bandwidth bandwidth.c) +target_link_libraries(crc-bandwidth bfdev) +add_test(crc-bandwidth crc-bandwidth) + +if(${CMAKE_PROJECT_NAME} STREQUAL "bfdev") + install(FILES + bandwidth.c + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/examples/crc + ) + + install(TARGETS + crc-bandwidth + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/bin + ) +endif() diff --git a/examples/crc/bandwidth.c b/examples/crc/bandwidth.c new file mode 100644 index 00000000..3f285f1e --- /dev/null +++ b/examples/crc/bandwidth.c @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#define MODULE_NAME "crc-bandwidth" +#define bfdev_log_fmt(fmt) MODULE_NAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include "../time.h" + +#define TEST_SIZE BFDEV_SZ_1MiB +#define TEST_LOOP 3 + +#define GENERIC_CRC_BANDWIDTH(func, name, size) \ +for (count = 0; count < TEST_LOOP; ++count) { \ + EXAMPLE_TIME_LOOP(&loop, 1000, \ + func(buff, size, 0); \ + 0; \ + ); \ + bfdev_log_info( \ + name " bandwidth %u: %uMiB/s\n", \ + count, loop \ + ); \ +} + +int main(int argc, char const *argv[]) +{ + unsigned int count, loop; + uint8_t *buff; + size_t index; + + buff = malloc(TEST_SIZE); + if (!buff) + return 1; + + srand(time(NULL)); + for (index = 0; index < TEST_SIZE; ++index) + buff[index] = (uint8_t)rand(); + + GENERIC_CRC_BANDWIDTH(bfdev_crc4, "crc4", TEST_SIZE * BFDEV_BITS_PER_BYTE) + GENERIC_CRC_BANDWIDTH(bfdev_crc7, "crc7", TEST_SIZE) + GENERIC_CRC_BANDWIDTH(bfdev_crc8, "crc8", TEST_SIZE) + GENERIC_CRC_BANDWIDTH(bfdev_crc16, "crc16", TEST_SIZE) + GENERIC_CRC_BANDWIDTH(bfdev_crc32, "crc32", TEST_SIZE) + GENERIC_CRC_BANDWIDTH(bfdev_crc64, "crc64", TEST_SIZE) + + GENERIC_CRC_BANDWIDTH(bfdev_crc_ccitt, "crc-ccitt", TEST_SIZE) + GENERIC_CRC_BANDWIDTH(bfdev_crc_itut, "crc-itut", TEST_SIZE) + GENERIC_CRC_BANDWIDTH(bfdev_crc_t10dif, "crc-t10dif", TEST_SIZE) + GENERIC_CRC_BANDWIDTH(bfdev_crc_rocksoft, "crc-rocksoft", TEST_SIZE) + + free(buff); + return 0; +} diff --git a/examples/fifo/.gitignore b/examples/fifo/.gitignore new file mode 100644 index 00000000..ebb431a7 --- /dev/null +++ b/examples/fifo/.gitignore @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +/fifo-selftest +/fifo-simple diff --git a/examples/fifo/CMakeLists.txt b/examples/fifo/CMakeLists.txt new file mode 100644 index 00000000..f6a310d7 --- /dev/null +++ b/examples/fifo/CMakeLists.txt @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright(c) 2023 ffashion +# + +add_executable(fifo-selftest selftest.c) +target_link_libraries(fifo-selftest bfdev) +add_test(fifo-selftest fifo-selftest) + +add_executable(fifo-simple simple.c) +target_link_libraries(fifo-simple bfdev pthread) +add_test(fifo-simple fifo-simple) + +if(${CMAKE_PROJECT_NAME} STREQUAL "bfdev") + install(FILES + selftest.c + simple.c + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/examples/fifo + ) + + install(TARGETS + fifo-selftest + fifo-simple + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/bin + ) +endif() diff --git a/examples/fifo/selftest.c b/examples/fifo/selftest.c new file mode 100644 index 00000000..9b1fd5dd --- /dev/null +++ b/examples/fifo/selftest.c @@ -0,0 +1,474 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2022 John Sanpe + */ + +#include +#include +#include +#include + +#define TEST_LOOP 16 + +struct test_pdata { + BFDEV_DECLARE_FIFO(normal_bytetest, char, TEST_LOOP); + BFDEV_DECLARE_FIFO(normal_longtest, long, TEST_LOOP); + BFDEV_DECLARE_FIFO_RECORD(record_bytetest, char, TEST_LOOP, 1); + BFDEV_DECLARE_FIFO_RECORD(record_longtest, long, TEST_LOOP, 1); + BFDEV_DECLARE_FIFO_DYNAMIC(dynamic_bytetest, char); + BFDEV_DECLARE_FIFO_DYNAMIC(dynamic_longtest, long); + BFDEV_DECLARE_FIFO_DYNAMIC_RECORD(dynamic_record_bytetest, char, 1); + BFDEV_DECLARE_FIFO_DYNAMIC_RECORD(dynamic_record_longtest, long, 1); +}; + +static const char +bytetest_table[TEST_LOOP] = { + 'o', 'p', 'e', 'n', 'b', 'f', 'd', 'e', + 'v', ',', 'h', 'e', 'l', 'l', 'l', 'o', +}; + +static const long +longtest_table[TEST_LOOP] = { + (long)0x0000000000000000ULL, (long)0x1111111111111111ULL, + (long)0x2222222222222222ULL, (long)0x3333333333333333ULL, + (long)0x4444444444444444ULL, (long)0x5555555555555555ULL, + (long)0x6666666666666666ULL, (long)0x7777777777777777ULL, + (long)0x8888888888888888ULL, (long)0x9999999999999999ULL, + (long)0xaaaaaaaaaaaaaaaaULL, (long)0xbbbbbbbbbbbbbbbbULL, + (long)0xccccccccccccccccULL, (long)0xddddddddddddddddULL, + (long)0xeeeeeeeeeeeeeeeeULL, (long)0xffffffffffffffffULL, +}; + +static int +fifo_testing(struct test_pdata *pdata) +{ + char bytevalue[TEST_LOOP]; + long longvalue[TEST_LOOP]; + unsigned int count; + unsigned long retval; + + for (count = 0; count < TEST_LOOP; ++count) { + retval = bfdev_fifo_put(&pdata->normal_bytetest, bytetest_table[count]); + printf("fifo normal_bytetest %u put '%c': ", count, bytetest_table[count]); + if (!retval || bfdev_fifo_len(&pdata->normal_bytetest) != count + 1) { + printf("failed\n"); + return 1; + } + printf("pass\n"); + } + + printf("fifo normal_bytetest check full: "); + if (!bfdev_fifo_check_full(&pdata->normal_bytetest)) { + printf("failed\n"); + return 1; + } + printf("pass\n"); + + for (count = 0; count < TEST_LOOP; ++count) { + retval = bfdev_fifo_peek(&pdata->normal_bytetest, bytevalue); + printf("fifo normal_bytetest %u peek '%c': ", count, *bytevalue); + if (!retval || *bytevalue != bytetest_table[count]) { + printf("failed\n"); + return 1; + } + printf("pass\n"); + + retval = bfdev_fifo_get(&pdata->normal_bytetest, bytevalue); + printf("fifo normal_bytetest %u get '%c': ", count, *bytevalue); + if (!retval || *bytevalue != bytetest_table[count]) { + printf("failed\n"); + return 1; + } + printf("pass\n"); + } + + printf("fifo normal_bytetest copy in: "); + retval = bfdev_fifo_in(&pdata->normal_bytetest, bytetest_table, TEST_LOOP); + if (retval != TEST_LOOP) { + printf("failed\n"); + return 1; + } + printf("pass\n"); + + printf("fifo normal_bytetest copy peek out: "); + retval = bfdev_fifo_out_peek(&pdata->normal_bytetest, bytevalue, TEST_LOOP); + if (retval != TEST_LOOP) { + printf("failed\n"); + return 1; + } + printf("pass\n"); + + printf("fifo normal_bytetest check peek out: "); + if (memcmp(bytevalue, bytetest_table, sizeof(bytetest_table))) { + printf("failed\n"); + return 1; + } + printf("pass\n"); + + printf("fifo normal_bytetest copy out: "); + retval = bfdev_fifo_out(&pdata->normal_bytetest, bytevalue, TEST_LOOP); + if (retval != TEST_LOOP) { + printf("failed\n"); + return 1; + } + printf("pass\n"); + + printf("fifo normal_bytetest check out: "); + if (memcmp(bytevalue, bytetest_table, sizeof(bytetest_table))) { + printf("failed\n"); + return 1; + } + printf("pass\n"); + + for (count = 0; count < TEST_LOOP; ++count) { + bfdev_fifo_put(&pdata->normal_longtest, longtest_table[count]); + printf("fifo normal_longtest %u put %#lx: ", count, longtest_table[count]); + if (bfdev_fifo_len(&pdata->normal_longtest) != count + 1) { + printf("failed\n"); + return 1; + } + printf("pass\n"); + } + + printf("fifo normal_longtest check full: "); + if (!bfdev_fifo_check_full(&pdata->normal_longtest)) { + printf("failed\n"); + return 1; + } + printf("pass\n"); + + for (count = 0; count < TEST_LOOP; ++count) { + retval = bfdev_fifo_peek(&pdata->normal_longtest, longvalue); + printf("fifo normal_longtest %u peek %#lx: ", count, *longvalue); + if (!retval || *longvalue != longtest_table[count]) { + printf("failed\n"); + return 1; + } + printf("pass\n"); + + retval = bfdev_fifo_get(&pdata->normal_longtest, longvalue); + printf("fifo normal_longtest %u get %#lx: ", count, *longvalue); + if (!retval || *longvalue != longtest_table[count]) { + printf("failed\n"); + return 1; + } + printf("pass\n"); + } + + printf("fifo normal_longtest copy in: "); + retval = bfdev_fifo_in(&pdata->normal_longtest, longtest_table, TEST_LOOP); + if (retval != TEST_LOOP) { + printf("failed\n"); + return 1; + } + printf("pass\n"); + + printf("fifo normal_longtest copy peek out: "); + retval = bfdev_fifo_out_peek(&pdata->normal_longtest, longvalue, TEST_LOOP); + if (retval != TEST_LOOP) { + printf("failed\n"); + return 1; + } + printf("pass\n"); + + printf("fifo normal_longtest check peek out: "); + if (memcmp(longvalue, longtest_table, sizeof(longtest_table))) { + printf("failed\n"); + return 1; + } + printf("pass\n"); + + printf("fifo normal_longtest copy out: "); + retval = bfdev_fifo_out(&pdata->normal_longtest, longvalue, TEST_LOOP); + if (retval != TEST_LOOP) { + printf("failed\n"); + return 1; + } + printf("pass\n"); + + printf("fifo normal_longtest check out: "); + if (memcmp(longvalue, longtest_table, sizeof(longtest_table))) { + printf("failed\n"); + return 1; + } + printf("pass\n"); + + for (count = 0; count < TEST_LOOP; ++count) { + retval = bfdev_fifo_put(&pdata->dynamic_bytetest, bytetest_table[count]); + printf("fifo dynamic_bytetest %u put '%c': ", count, bytetest_table[count]); + if (!retval || bfdev_fifo_len(&pdata->dynamic_bytetest) != count + 1) { + printf("failed\n"); + return 1; + } + printf("pass\n"); + } + + printf("fifo dynamic_bytetest check full: "); + if (!bfdev_fifo_check_full(&pdata->dynamic_bytetest)) { + printf("failed\n"); + return 1; + } + printf("pass\n"); + + for (count = 0; count < TEST_LOOP; ++count) { + retval = bfdev_fifo_peek(&pdata->dynamic_bytetest, bytevalue); + printf("fifo dynamic_bytetest %u peek '%c': ", count, *bytevalue); + if (!retval || *bytevalue != bytetest_table[count]) { + printf("failed\n"); + return 1; + } + printf("pass\n"); + + retval = bfdev_fifo_get(&pdata->dynamic_bytetest, bytevalue); + printf("fifo dynamic_bytetest %u get '%c': ", count, *bytevalue); + if (!retval || *bytevalue != bytetest_table[count]) { + printf("failed\n"); + return 1; + } + printf("pass\n"); + } + + printf("fifo dynamic_bytetest copy in: "); + retval = bfdev_fifo_in(&pdata->dynamic_bytetest, bytetest_table, TEST_LOOP); + if (retval != TEST_LOOP) { + printf("failed\n"); + return 1; + } + printf("pass\n"); + + printf("fifo dynamic_bytetest copy peek out: "); + retval = bfdev_fifo_out_peek(&pdata->dynamic_bytetest, bytevalue, TEST_LOOP); + if (retval != TEST_LOOP) { + printf("failed\n"); + return 1; + } + printf("pass\n"); + + printf("fifo dynamic_bytetest check peek out: "); + if (memcmp(bytetest_table, bytetest_table, sizeof(bytetest_table))) { + printf("failed\n"); + return 1; + } + printf("pass\n"); + + printf("fifo dynamic_bytetest copy out: "); + retval = bfdev_fifo_out(&pdata->dynamic_bytetest, bytevalue, TEST_LOOP); + if (retval != TEST_LOOP) + return 1; + printf("pass\n"); + + printf("fifo dynamic_bytetest check out: "); + if (memcmp(bytevalue, bytetest_table, sizeof(bytetest_table))) { + printf("failed\n"); + return 1; + } + printf("pass\n"); + + for (count = 0; count < TEST_LOOP; ++count) { + bfdev_fifo_put(&pdata->dynamic_longtest, longtest_table[count]); + printf("fifo dynamic_longtest %u put %#lx: ", count, longtest_table[count]); + if (bfdev_fifo_len(&pdata->dynamic_longtest) != count + 1) { + printf("failed\n"); + return 1; + } + printf("pass\n"); + } + + printf("fifo dynamic_longtest check full: "); + if (!bfdev_fifo_check_full(&pdata->dynamic_longtest)) { + printf("failed\n"); + return 1; + } + printf("pass\n"); + + for (count = 0; count < TEST_LOOP; ++count) { + retval = bfdev_fifo_peek(&pdata->dynamic_longtest, longvalue); + printf("fifo dynamic_longtest %u peek %#lx: ", count, *longvalue); + if (!retval || *longvalue != longtest_table[count]) { + printf("failed\n"); + return 1; + } + printf("pass\n"); + + retval = bfdev_fifo_get(&pdata->dynamic_longtest, longvalue); + printf("fifo dynamic_longtest %u get %#lx: ", count, *longvalue); + if (!retval || *longvalue != longtest_table[count]) { + printf("failed\n"); + return 1; + } + printf("pass\n"); + } + + printf("fifo dynamic_longtest copy in: "); + retval = bfdev_fifo_in(&pdata->dynamic_longtest, longtest_table, TEST_LOOP); + if (retval != TEST_LOOP) { + printf("failed\n"); + return 1; + } + printf("pass\n"); + + printf("fifo dynamic_longtest copy peek out: "); + retval = bfdev_fifo_out_peek(&pdata->dynamic_longtest, longvalue, TEST_LOOP); + if (retval != TEST_LOOP) { + printf("failed\n"); + return 1; + } + printf("pass\n"); + + printf("fifo dynamic_longtest check peek out: "); + if (memcmp(longvalue, longtest_table, sizeof(longtest_table))) { + printf("failed\n"); + return 1; + } + printf("pass\n"); + + printf("fifo dynamic_longtest copy out: "); + retval = bfdev_fifo_out(&pdata->dynamic_longtest, longvalue, TEST_LOOP); + if (retval != TEST_LOOP) { + printf("failed\n"); + return 1; + } + printf("pass\n"); + + printf("fifo normal_longtest check out: "); + if (memcmp(longvalue, longtest_table, sizeof(longtest_table))) { + printf("failed\n"); + return 1; + } + printf("pass\n"); + + for (count = 1; count < TEST_LOOP; ++count) { + printf("fifo record_bytetest copy %u in: ", count); + retval = bfdev_fifo_in(&pdata->record_bytetest, bytetest_table, count); + if (retval != count) { + printf("failed\n"); + return 1; + } + printf("pass\n"); + + printf("fifo record_bytetest copy %u out: ", count); + retval = bfdev_fifo_out(&pdata->record_bytetest, bytevalue, count); + if (retval != count) { + printf("failed\n"); + return 1; + } + printf("pass\n"); + + printf("fifo record_bytetest check %u copy: ", count); + if (memcmp(bytevalue, bytetest_table, count)) { + printf("failed\n"); + return 1; + } + printf("pass\n"); + } + + for (count = 1; count < TEST_LOOP; ++count) { + printf("fifo record_longtest copy %u in: ", count); + retval = bfdev_fifo_in(&pdata->record_longtest, longtest_table, count); + if (retval != count) { + printf("failed\n"); + return 1; + } + printf("pass\n"); + + printf("fifo record_longtest copy %u out: ", count); + retval = bfdev_fifo_out(&pdata->record_longtest, longvalue, count); + if (retval != count) { + printf("failed\n"); + return 1; + } + printf("pass\n"); + + printf("fifo record_longtest check %u copy: ", count); + if (memcmp(longvalue, longtest_table, count)) { + printf("failed\n"); + return 1; + } + printf("pass\n"); + } + + for (count = 1; count < TEST_LOOP; ++count) { + printf("fifo dynamic_record_bytetest copy %u in: ", count); + retval = bfdev_fifo_in(&pdata->dynamic_record_bytetest, bytetest_table, count); + if (retval != count) { + printf("failed\n"); + return 1; + } + printf("pass\n"); + + printf("fifo dynamic_record_bytetest copy %u out: ", count); + retval = bfdev_fifo_out(&pdata->dynamic_record_bytetest, bytevalue, count); + if (retval != count) { + printf("failed\n"); + return 1; + } + printf("pass\n"); + + printf("fifo dynamic_record_bytetest check %u copy: ", count); + if (memcmp(bytevalue, bytetest_table, count)) { + printf("failed\n"); + return 1; + } + printf("pass\n"); + } + + for (count = 1; count < TEST_LOOP; ++count) { + printf("fifo dynamic_record_longtest copy %u in: ", count); + retval = bfdev_fifo_in(&pdata->dynamic_record_longtest, longtest_table, count); + if (retval != count) { + printf("failed\n"); + return 1; + } + printf("pass\n"); + + printf("fifo dynamic_record_longtest copy %u out: ", count); + retval = bfdev_fifo_out(&pdata->dynamic_record_longtest, longvalue, count); + if (retval != count) { + printf("failed\n"); + return 1; + } + printf("pass\n"); + + printf("fifo dynamic_record_longtest check %u copy: ", count); + if (memcmp(longvalue, longtest_table, count)) { + printf("failed\n"); + return 1; + } + printf("pass\n"); + } + + return 0; +} + +int main(int argc, const char *argv[]) +{ + struct test_pdata *pdata; + int retval; + + pdata = malloc(sizeof(struct test_pdata)); + if (!pdata) + return 1; + + pdata->normal_bytetest = BFDEV_FIFO_INIT(pdata->normal_bytetest); + pdata->normal_longtest = BFDEV_FIFO_INIT(pdata->normal_longtest); + pdata->record_bytetest = BFDEV_FIFO_INIT(pdata->record_bytetest); + pdata->record_longtest = BFDEV_FIFO_INIT(pdata->record_longtest); + + if ((retval = bfdev_fifo_alloc(&pdata->dynamic_bytetest, NULL, TEST_LOOP)) || + (retval = bfdev_fifo_alloc(&pdata->dynamic_longtest, NULL, TEST_LOOP)) || + (retval = bfdev_fifo_alloc(&pdata->dynamic_record_bytetest, NULL, TEST_LOOP)) || + (retval = bfdev_fifo_alloc(&pdata->dynamic_record_longtest, NULL, TEST_LOOP))) + return 1; + + retval = fifo_testing(pdata); + if (retval) + return retval; + + bfdev_fifo_free(&pdata->dynamic_bytetest); + bfdev_fifo_free(&pdata->dynamic_longtest); + bfdev_fifo_free(&pdata->dynamic_record_bytetest); + bfdev_fifo_free(&pdata->dynamic_record_longtest); + free(pdata); + + return 0; +} diff --git a/examples/fifo/simple.c b/examples/fifo/simple.c new file mode 100644 index 00000000..85073ea3 --- /dev/null +++ b/examples/fifo/simple.c @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2022 John Sanpe + */ + +#include +#include +#include +#include + +static const char test_table[] = { + 'b', 'f', 'd', 'e', 'v', '-', 'f', 'i', + 'f', 'o', '-', 't', 'e', 's', 't', '\n', +}; + +#define TEST_LOOP 64 +BFDEV_DEFINE_FIFO(normal_bytetest, char, BFDEV_ARRAY_SIZE(test_table)); + +static void * +fifo_production(void *unused) +{ + unsigned int count, index; + char ch; + + for (count = 0; count < TEST_LOOP; ++count) { + for (index = 0; index < BFDEV_ARRAY_SIZE(test_table); ++index) { + while (bfdev_fifo_check_full(&normal_bytetest)) + sched_yield(); + ch = test_table[index]; + bfdev_fifo_put(&normal_bytetest, ch); + } + } + + while (bfdev_fifo_check_full(&normal_bytetest)) + sched_yield(); + bfdev_fifo_put(&normal_bytetest, 0); + + return NULL; +} + +int main(int argc, const char *argv[]) +{ + pthread_t thread; + char ch; + + pthread_create(&thread, NULL, fifo_production, NULL); + for (;;) { + while (bfdev_fifo_check_empty(&normal_bytetest)) + sched_yield(); + bfdev_fifo_get(&normal_bytetest, &ch); + if (!ch) { + printf("exit\n"); + break; + } + printf("%c", ch); + } + + return 0; +} diff --git a/examples/fsm/.gitignore b/examples/fsm/.gitignore new file mode 100644 index 00000000..3492addf --- /dev/null +++ b/examples/fsm/.gitignore @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +/fsm-console diff --git a/examples/fsm/CMakeLists.txt b/examples/fsm/CMakeLists.txt new file mode 100644 index 00000000..75ce8c32 --- /dev/null +++ b/examples/fsm/CMakeLists.txt @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright(c) 2023 ffashion +# + +add_executable(fsm-console console.c) +target_link_libraries(fsm-console bfdev) + +if(${CMAKE_PROJECT_NAME} STREQUAL "bfdev") + install(FILES + console.c + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/examples/fsm + ) + + install(TARGETS + fsm-console + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/bin + ) +endif() diff --git a/examples/fsm/console.c b/examples/fsm/console.c new file mode 100644 index 00000000..42e1078a --- /dev/null +++ b/examples/fsm/console.c @@ -0,0 +1,194 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#include +#include +#include + +enum { + TEST_IDLE = 0, + TEST_CHECK, + TEST_EXIT, + TEST_HSTATE, + TEST_ISTATE, + TEST_STACK, + TEST_ASTATE, +}; + +static int +enter_print(struct bfdev_fsm_event *event, void *data) +{ + printf( "Enter: %s\n", (char *)data); + return 0; +} + +static int +exit_print(struct bfdev_fsm_event *event, void *data) +{ + printf( "Exit: %s\n", (char *)data); + return 0; +} + +static long +trans_guard(struct bfdev_fsm_event *event, const void *cond) +{ + return event->pdata - cond; +} + +static int +trans_active(struct bfdev_fsm_event *event, void *data, + void *curr, void *next) +{ + printf("Active: %s\n", (char *)data); + return 0; +} + +static struct bfdev_fsm_state +test_state[] = { + [TEST_IDLE] = { + .parent = &test_state[TEST_CHECK], + .data = "idle", + .tnum = 2, + .trans = (struct bfdev_fsm_transition[]) { + { + .cond = (void *)(intptr_t)'h', + .next = &test_state[TEST_HSTATE], + .guard = trans_guard, + }, + { + .cond = (void *)(intptr_t)'e', + .next = &test_state[TEST_EXIT], + .guard = trans_guard, + }, + }, + .enter = enter_print, + .exit = exit_print, + }, + [TEST_HSTATE] = { + .parent = &test_state[TEST_CHECK], + .data = "h-state", + .tnum = 2, + .trans = (struct bfdev_fsm_transition[]) { + { + .cond = (void *)(intptr_t)'i', + .next = &test_state[TEST_ISTATE], + .guard = trans_guard, + }, + { + .cond = (void *)(intptr_t)'a', + .next = &test_state[TEST_ASTATE], + .guard = trans_guard, + }, + }, + .enter = enter_print, + .exit = exit_print, + }, + [TEST_ISTATE] = { + .parent = &test_state[TEST_CHECK], + .data = "i-state", + .tnum = 2, + .trans = (struct bfdev_fsm_transition[]) { + { + .cond = (void *)(intptr_t)'\n', + .next = &test_state[TEST_IDLE], + .guard = trans_guard, + .action = trans_active, + .data = "hello", + }, + { + .cond = (void *)(intptr_t)'.', + .next = &test_state[TEST_STACK], + .guard = trans_guard, + .stack = +1, + }, + }, + .enter = enter_print, + .exit = exit_print, + }, + [TEST_ASTATE] = { + .parent = &test_state[TEST_CHECK], + .data = "a-state", + .tnum = 2, + .trans = (struct bfdev_fsm_transition[]) { + { + .cond = (void *)(intptr_t)'\n', + .next = &test_state[TEST_IDLE], + .guard = trans_guard, + .action = trans_active, + .data = "haha", + }, + { + .cond = (void *)(intptr_t)'.', + .next = &test_state[TEST_STACK], + .guard = trans_guard, + .stack = +1, + }, + }, + .enter = enter_print, + .exit = exit_print, + }, + [TEST_STACK] = { + .parent = &test_state[TEST_CHECK], + .data = "stack", + .tnum = 1, + .trans = (struct bfdev_fsm_transition[]) { + { + .action = trans_active, + .data = "state pop", + .cross = true, + .stack = -1, + }, + }, + .enter = enter_print, + .exit = exit_print, + }, + [TEST_CHECK] = { + .entry = &test_state[TEST_IDLE], + .data = "check", + .tnum = 2, + .trans = (struct bfdev_fsm_transition[]) { + { + .cond = (void *)(intptr_t)'!', + .next = &test_state[TEST_IDLE], + .guard = trans_guard, + .action = trans_active, + .data = "reset", + }, + { + .next = &test_state[TEST_IDLE], + .action = trans_active, + .data = "ignore", + }, + }, + .enter = enter_print, + .exit = exit_print, + }, + [TEST_EXIT] = { + .data = "exit", + .enter = enter_print, + }, +}; + +BFDEV_DEFINE_FSM(test_fsm, NULL, + &test_state[TEST_IDLE], + &test_state[TEST_EXIT] +); + +int main(int argc, const char *argv[]) +{ + int ch, retval; + + while ((ch = getc(stdin)) != EOF) { + retval = bfdev_fsm_handle(&test_fsm, + &(struct bfdev_fsm_event) { + .pdata = (void *)(intptr_t)ch, + } + ); + if (retval) + break; + } + + return 0; +} diff --git a/examples/guards/.gitignore b/examples/guards/.gitignore new file mode 100644 index 00000000..b5a0ea0f --- /dev/null +++ b/examples/guards/.gitignore @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +/guards-cleanup diff --git a/examples/guards/CMakeLists.txt b/examples/guards/CMakeLists.txt new file mode 100644 index 00000000..e3da55f9 --- /dev/null +++ b/examples/guards/CMakeLists.txt @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright(c) 2023 ffashion +# + +add_executable(guards-cleanup cleanup.c) +target_link_libraries(guards-cleanup bfdev) +add_test(guards-cleanup guards-cleanup) + +if(${CMAKE_PROJECT_NAME} STREQUAL "bfdev") + install(FILES + cleanup.c + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/examples/guards + ) + + install(TARGETS + guards-cleanup + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/bin + ) +endif() diff --git a/examples/guards/cleanup.c b/examples/guards/cleanup.c new file mode 100644 index 00000000..83358599 --- /dev/null +++ b/examples/guards/cleanup.c @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#include +#include +#include + +BFDEV_CLEAN_TEMPLATE(malloc, void *, + if (_T) { + printf("cleanup %p\n", _T); + free(_T); + } +) + +static void +test_gc_cleanup(void) +{ + bfdev_clean(malloc) void *block; + block = malloc(8); + (void)block; +} + +static void * +test_gc_lasting(void) +{ + bfdev_clean(malloc) void *block; + block = malloc(8); + bfdev_clean_return(block); +} + +int main(int argc, const char *argv[]) +{ + void *block; + + test_gc_cleanup(); + block = test_gc_lasting(); + free(block); + + return 0; +} diff --git a/examples/hashmap/.gitignore b/examples/hashmap/.gitignore new file mode 100644 index 00000000..9c538dfc --- /dev/null +++ b/examples/hashmap/.gitignore @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +/hashmap-simple diff --git a/examples/hashmap/CMakeLists.txt b/examples/hashmap/CMakeLists.txt new file mode 100644 index 00000000..29a2d806 --- /dev/null +++ b/examples/hashmap/CMakeLists.txt @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright(c) 2023 ffashion +# + +add_executable(hashmap-simple simple.c) +target_link_libraries(hashmap-simple bfdev) +add_test(hashmap-simple hashmap-simple) + +if(${CMAKE_PROJECT_NAME} STREQUAL "bfdev") + install(FILES + simple.c + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/examples/hashmap + ) + + install(TARGETS + hashmap-simple + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/bin + ) +endif() diff --git a/examples/hashmap/simple.c b/examples/hashmap/simple.c new file mode 100644 index 00000000..4eb67780 --- /dev/null +++ b/examples/hashmap/simple.c @@ -0,0 +1,110 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#include +#include +#include +#include +#include + +#define TEST_LOOP 100 + +struct test_node { + struct bfdev_hlist_node node; + unsigned long value; +}; + +#define node_to_test(ptr) \ + bfdev_container_of(ptr, struct test_node, node) + +static inline unsigned long +hashmap_hash_key(const void *key, void *pdata) +{ + return (unsigned long)key; +} + +static inline unsigned long +hashmap_hash_node(const struct bfdev_hlist_node *node, void *pdata) +{ + const struct test_node *tnode = node_to_test(node); + return tnode->value; +} + +static inline long +hashmap_equal(const struct bfdev_hlist_node *node1, + const struct bfdev_hlist_node *nodeb, void *pdata) +{ + const struct test_node *tnode1 = node_to_test(node1); + const struct test_node *tnodeb = node_to_test(nodeb); + return tnode1->value - tnodeb->value; +} + +static inline long +hashmap_find(const struct bfdev_hlist_node *node, const void *key, void *pdata) +{ + const struct test_node *tnode = node_to_test(node); + return tnode->value - (unsigned long)key; +} + +static struct bfdev_hashmap_ops +test_ops = { + .hash_key = hashmap_hash_key, + .hash_node = hashmap_hash_node, + .equal = hashmap_equal, + .find = hashmap_find, +}; + +int main(int argc, const char *argv[]) +{ + struct test_node *nodes, *find; + struct bfdev_hlist_node *hnode; + unsigned long value; + unsigned int count; + int retval; + + BFDEV_DEFINE_HASHMAP(test_map, NULL, &test_ops, NULL); + nodes = malloc(sizeof(*nodes) * TEST_LOOP); + if (!nodes) + return 1; + + printf("hashmap 'bfdev_hashmap_add':\n"); + srand(time(NULL)); + for (count = 0; count < TEST_LOOP; ++count) { + value = ((uint64_t)rand() << 32) | rand(); + nodes[count].value = value; + + printf("\ttest %02u: value %lu\n", count, value); + retval = bfdev_hashmap_add(&test_map, &nodes[count].node); + if (retval) + return retval; + } + + printf("hashmap 'bfdev_hashmap_find':\n"); + for (count = 0; count < TEST_LOOP; ++count) { + value = nodes[count].value; + hnode = bfdev_hashmap_find(&test_map, (void *)value); + if (!hnode) + return 1; + + find = node_to_test(hnode); + printf("\ttest %02u: value %lu\n", count, find->value); + } + + printf("hashmap 'bfdev_hashmap_del':\n"); + for (count = 0; count < TEST_LOOP; ++count) { + value = nodes[count].value; + retval = bfdev_hashmap_del(&test_map, (void *)value, &hnode); + if (retval) + return retval; + + find = node_to_test(hnode); + printf("\ttest %02u: value %lu\n", count, find->value); + } + + bfdev_hashmap_release(&test_map); + free(nodes); + + return 0; +} diff --git a/examples/hashtbl/.gitignore b/examples/hashtbl/.gitignore new file mode 100644 index 00000000..3cb6d3b2 --- /dev/null +++ b/examples/hashtbl/.gitignore @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +/hashtbl-simple diff --git a/examples/hashtbl/CMakeLists.txt b/examples/hashtbl/CMakeLists.txt new file mode 100644 index 00000000..d6177f02 --- /dev/null +++ b/examples/hashtbl/CMakeLists.txt @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright(c) 2023 ffashion +# + +add_executable(hashtbl-simple simple.c) +target_link_libraries(hashtbl-simple bfdev) +add_test(hashtbl-simple hashtbl-simple) + +if(${CMAKE_PROJECT_NAME} STREQUAL "bfdev") + install(FILES + simple.c + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/examples/hashtbl + ) + + install(TARGETS + hashtbl-simple + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/bin + ) +endif() diff --git a/examples/hashtbl/simple.c b/examples/hashtbl/simple.c new file mode 100644 index 00000000..fb691b4a --- /dev/null +++ b/examples/hashtbl/simple.c @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2021 John Sanpe + */ + +#include +#include +#include +#include + +#define TEST_SIZE 16 +#define TEST_LOOP 100 + +BFDEV_DEFINE_HASHTBL(test_table, TEST_SIZE); + +struct test_node { + struct bfdev_hlist_node node; + unsigned int value; +}; + +int main(int argc, const char *argv[]) +{ + struct test_node *nodes, *walk; + unsigned int count, value; + + nodes = malloc(sizeof(*nodes) * TEST_LOOP); + if (!nodes) + return 1; + + printf("hashtbl 'bfdev_hashtbl_add':\n"); + srand(time(NULL)); + for (count = 0; count < TEST_LOOP; ++count) { + value = (unsigned int)rand(); + nodes[count].value = value; + printf("\ttest %02u: value %u\n", count, value); + bfdev_hashtbl_add(test_table, TEST_SIZE, &nodes[count].node, value); + } + + printf("hashtbl 'bfdev_hashtbl_for_each_entry':\n"); + bfdev_hashtbl_for_each_entry(walk, test_table, TEST_SIZE, node, count) { + value = walk->value; + printf("\tindex %02u: value %u\n", count, value); + } + + free(nodes); + return 0; +} diff --git a/examples/heap/.gitignore b/examples/heap/.gitignore new file mode 100644 index 00000000..6179f463 --- /dev/null +++ b/examples/heap/.gitignore @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +/heap-benchmark +/heap-selftest diff --git a/examples/heap/CMakeLists.txt b/examples/heap/CMakeLists.txt new file mode 100644 index 00000000..76df7662 --- /dev/null +++ b/examples/heap/CMakeLists.txt @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright(c) 2023 ffashion +# + +add_executable(heap-benchmark benchmark.c) +target_link_libraries(heap-benchmark bfdev) +add_test(heap-benchmark heap-benchmark) + +add_executable(heap-selftest selftest.c) +target_link_libraries(heap-selftest bfdev) +add_test(heap-selftest heap-selftest) + +if(${CMAKE_PROJECT_NAME} STREQUAL "bfdev") + install(FILES + benchmark.c + selftest.c + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/examples/heap + ) + + install(TARGETS + heap-benchmark + heap-selftest + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/bin + ) +endif() diff --git a/examples/heap/benchmark.c b/examples/heap/benchmark.c new file mode 100644 index 00000000..ddf6aeed --- /dev/null +++ b/examples/heap/benchmark.c @@ -0,0 +1,127 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2021 John Sanpe + */ + +#define MODULE_NAME "heap-benchmark" +#define bfdev_log_fmt(fmt) MODULE_NAME ": " fmt + +#include +#include +#include +#include +#include "../time.h" + +#define HEAP_DEBUG 0 +#define TEST_LEN 1000000 + +struct bench_node { + struct bfdev_heap_node node; + unsigned int num; + unsigned int data; +}; + +#define bfdev_heap_to_bench(ptr) \ + bfdev_heap_entry_safe(ptr, struct bench_node, node) + +#if HEAP_DEBUG +static void +node_dump(struct bench_node *node) +{ + bfdev_log_info("\t%04d: ", node[count].num); + bfdev_log_info("parent %-4d ", node[count].node.parent ? bfdev_heap_to_bench(node[count].node.parent)->num : 0); + bfdev_log_info("left %-4d ", node[count].node.left ? bfdev_heap_to_bench(node[count].node.left)->num : 0); + bfdev_log_info("right %-4d ", node[count].node.right ? bfdev_heap_to_bench(node[count].node.right)->num : 0); + bfdev_log_info("data 0x%8x ", node[count].data); + bfdev_log_info("\n"); +} +#else +# define node_dump(node) ((void)(node)) +#endif + +static unsigned int +test_deepth(struct bfdev_heap_node *node) +{ + unsigned int left_deepth, right_deepth; + + if (!node) + return 0; + + left_deepth = test_deepth(node->left); + right_deepth = test_deepth(node->right); + + return left_deepth > right_deepth ? (left_deepth + 1) : (right_deepth + 1); +} + +static long +bench_cmp(const struct bfdev_heap_node *hpa, + const struct bfdev_heap_node *hpb, void *pdata) +{ + struct bench_node *node1, *node2; + + node1 = bfdev_heap_to_bench(hpa); + node2 = bfdev_heap_to_bench(hpb); + + if (node1->data == node2->data) + return 0; + + return node1->data < node2->data ? -1 : 1; +} + +int main(int argc, const char *argv[]) +{ + struct bench_node *bnode; + unsigned int count; + unsigned long index; + void *block; + + BFDEV_HEAP_ROOT(bench_root); + + block = bnode = malloc(sizeof(*bnode) * TEST_LEN); + if (!bnode) { + bfdev_log_err("Insufficient memory!\n"); + return 1; + } + + srand(time(NULL)); + bfdev_log_info("Generate %u node:\n", TEST_LEN); + for (count = 0; count < TEST_LEN; ++count) { + bnode[count].num = count + 1; + bnode[count].data = rand(); +#if HEAP_DEBUG + bfdev_log_info("\t%08d: 0x%8x\n", bnode[count].num, bnode[count].data); +#endif + } + + bfdev_log_info("Insert nodes:\n"); + EXAMPLE_TIME_STATISTICAL( + for (count = 0; count < TEST_LEN; ++count) + bfdev_heap_insert(&bench_root, &bnode[count].node, bench_cmp, NULL); + 0; + ); + count = test_deepth(bench_root.node); + bfdev_log_info("\theap deepth: %u\n", count); + + count = 0; + bfdev_log_info("Level-order iteration:\n"); + EXAMPLE_TIME_STATISTICAL( + bfdev_heap_for_each_entry(bnode, &index, &bench_root, node) { + node_dump(bnode); + count++; + } + 0; + ); + bfdev_log_info("\ttotal num: %u\n", count); + + bfdev_log_info("Deletion all nodes...\n"); + while (bench_root.count) { + bnode = bfdev_heap_to_bench(bench_root.node); + node_dump(bnode); + bfdev_heap_delete(&bench_root, &bnode->node, bench_cmp, NULL); + } + + bfdev_log_info("Done.\n"); + free(block); + + return 0; +} diff --git a/examples/heap/selftest.c b/examples/heap/selftest.c new file mode 100644 index 00000000..6de4f2b9 --- /dev/null +++ b/examples/heap/selftest.c @@ -0,0 +1,241 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2022 John Sanpe + */ + +#define MODULE_NAME "heap-selftest" +#define bfdev_log_fmt(fmt) MODULE_NAME ": " fmt + +#include +#include +#include +#include +#include + +#define TEST_LOOP 100 + +struct test_node { + struct bfdev_heap_node node; + unsigned short num; +}; + +struct test_pdata { + struct test_node nodes[TEST_LOOP]; +}; + +#define hpnode_to_test(ptr) \ + bfdev_heap_entry(ptr, struct test_node, node) + +static long +bfdev_heap_test_cmp(const struct bfdev_heap_node *node1, + const struct bfdev_heap_node *node2, void *pdata) +{ + struct test_node *tnode1, *tnode2; + + tnode1 = hpnode_to_test(node1); + tnode2 = hpnode_to_test(node2); + + if (tnode1->num == tnode2->num) + return 0; + + return tnode1->num < tnode2->num ? -1 : 1; +} + +static int +bfdev_heap_testing(struct test_pdata *hdata) +{ + struct test_node *node, *nnode, *tnode; + struct bfdev_heap_node *hpnode, *nhpnode, *thpnode; + unsigned long count, index, tindex; + + BFDEV_HEAP_ROOT(root); + + for (count = 0; count < TEST_LOOP; ++count) + bfdev_heap_insert(&root, &hdata->nodes[count].node, bfdev_heap_test_cmp, NULL); + + count = 0; + bfdev_heap_for_each(hpnode, &index, &root) { + node = hpnode_to_test(hpnode); + bfdev_log_info("'heap_for_each' test: %u\n", node->num); + if (count++ == TEST_LOOP / 2) + break; + } + + thpnode = hpnode; + tindex = index; + bfdev_heap_for_each_continue(hpnode, &index, &root) { + node = hpnode_to_test(hpnode); + bfdev_log_info("'heap_for_each_continue' test: %u\n", node->num); + count++; + } + + hpnode = thpnode; + index = tindex; + bfdev_heap_for_each_from(hpnode, &index, &root) { + node = hpnode_to_test(hpnode); + bfdev_log_info("'heap_for_each_from' test: %u\n", node->num); + count++; + } + + if (count != TEST_LOOP + (TEST_LOOP / 2)) { + bfdev_log_err("count verification failed: %lu\n", count); + return 1; + } + + count = 0; + bfdev_heap_for_each_entry(node, &index, &root, node) { + bfdev_log_info("'heap_for_each_entry' test: %u\n", node->num); + if (count++ == TEST_LOOP / 2) + break; + } + + tnode = node; + tindex = index; + bfdev_heap_for_each_entry_continue(node, &index, &root, node) { + bfdev_log_info("'heap_for_each_entry_continue' test: %u\n", node->num); + count++; + } + + node = tnode; + index = tindex; + bfdev_heap_for_each_entry_from(node, &index, &root, node) { + bfdev_log_info("'heap_for_each_entry_from' test: %u\n", node->num); + count++; + } + + if (count != TEST_LOOP + (TEST_LOOP / 2)) { + bfdev_log_err("count verification failed: %lu\n", count); + return 1; + } + + count = 0; + bfdev_heap_post_for_each(hpnode, &root) { + node = hpnode_to_test(hpnode); + bfdev_log_info("'heap_post_for_each' test: %u\n", node->num); + if (count++ == TEST_LOOP / 2) + break; + } + + thpnode = hpnode; + bfdev_heap_post_for_each_continue(hpnode) { + node = hpnode_to_test(hpnode); + bfdev_log_info("'heap_post_for_each_continue' test: %u\n", node->num); + count++; + } + + hpnode = thpnode; + bfdev_heap_post_for_each_from(hpnode) { + node = hpnode_to_test(hpnode); + bfdev_log_info("'heap_post_for_each_from' test: %u\n", node->num); + count++; + } + + if (count != TEST_LOOP + (TEST_LOOP / 2)) { + bfdev_log_err("count verification failed: %lu\n", count); + return 1; + } + + count = 0; + bfdev_heap_post_for_each_safe(hpnode, nhpnode, &root) { + node = hpnode_to_test(hpnode); + bfdev_log_info("'heap_post_for_each_safe' test: %u\n", node->num); + if (count++ == TEST_LOOP / 2) + break; + } + + thpnode = hpnode; + bfdev_heap_post_for_each_safe_continue(hpnode, nhpnode) { + node = hpnode_to_test(hpnode); + bfdev_log_info("'heap_post_for_each_safe_continue' test: %u\n", node->num); + count++; + } + + hpnode = thpnode; + bfdev_heap_post_for_each_safe_from(hpnode, nhpnode) { + node = hpnode_to_test(hpnode); + bfdev_log_info("'heap_post_for_each_safe_from' test: %u\n", node->num); + count++; + } + + if (count != TEST_LOOP + (TEST_LOOP / 2)) { + bfdev_log_err("count verification failed: %lu\n", count); + return 1; + } + + count = 0; + bfdev_heap_post_for_each_entry(node, &root, node) { + bfdev_log_info("'heap_post_for_each_entry' test: %u\n", node->num); + if (count++ == TEST_LOOP / 2) + break; + } + + tnode = node; + bfdev_heap_post_for_each_entry_continue(node, node) { + bfdev_log_info("'heap_post_for_each_entry_continue' test: %u\n", node->num); + count++; + } + + node = tnode; + bfdev_heap_post_for_each_entry_from(node, node) { + bfdev_log_info("'heap_post_for_each_entry_from' test: %u\n", node->num); + count++; + } + + if (count != TEST_LOOP + (TEST_LOOP / 2)) { + bfdev_log_err("count verification failed: %lu\n", count); + return 1; + } + + count = 0; + bfdev_heap_post_for_each_entry_safe(node, nnode, &root, node) { + bfdev_log_info("'heap_post_for_each_entry_safe' test: %u\n", node->num); + if (count++ == TEST_LOOP / 2) + break; + } + + tnode = node; + bfdev_heap_post_for_each_entry_continue_safe(node, nnode, node) { + bfdev_log_info("'heap_post_for_each_entry_continue_safe' test: %u\n", node->num); + count++; + } + + node = tnode; + bfdev_heap_post_for_each_entry_from_safe(node, nnode, node) { + bfdev_log_info("'heap_post_for_each_entry_from_safe' test: %u\n", node->num); + count++; + } + + if (count != TEST_LOOP + (TEST_LOOP / 2)) { + bfdev_log_err("count verification failed: %lu\n", count); + return 1; + } + + for (count = 0; count < TEST_LOOP; ++count) { + node = hpnode_to_test(root.node); + bfdev_log_info("'heap_delete' test: %u\n", node->num); + bfdev_heap_delete(&root, &node->node, bfdev_heap_test_cmp, NULL); + } + + return 0; +} + +int main(int argc, const char *argv[]) +{ + struct test_pdata *rdata; + unsigned int count; + int retval; + + rdata = malloc(sizeof(struct test_pdata)); + if (!rdata) + return 1; + + srand(time(NULL)); + for (count = 0; count < TEST_LOOP; ++count) + rdata->nodes[count].num = rand(); + + retval = bfdev_heap_testing(rdata); + bfdev_log_notice("heap test: %s\n", retval ? "failed" : "passed"); + free(rdata); + + return retval; +} diff --git a/examples/hlist/.gitignore b/examples/hlist/.gitignore new file mode 100644 index 00000000..7f7e4e0f --- /dev/null +++ b/examples/hlist/.gitignore @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +/hlist-selftest +/hlist-simple diff --git a/examples/hlist/CMakeLists.txt b/examples/hlist/CMakeLists.txt new file mode 100644 index 00000000..5e2ef655 --- /dev/null +++ b/examples/hlist/CMakeLists.txt @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright(c) 2023 ffashion +# + +add_executable(hlist-selftest selftest.c) +target_link_libraries(hlist-selftest bfdev) +add_test(hlist-selftest hlist-selftest) + +add_executable(hlist-simple simple.c) +target_link_libraries(hlist-simple bfdev) +add_test(hlist-simple hlist-simple) + +if(${CMAKE_PROJECT_NAME} STREQUAL "bfdev") + install(FILES + selftest.c + simple.c + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/examples/hlist + ) + + install(TARGETS + hlist-selftest + hlist-simple + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/bin + ) +endif() diff --git a/examples/hlist/selftest.c b/examples/hlist/selftest.c new file mode 100644 index 00000000..fc783503 --- /dev/null +++ b/examples/hlist/selftest.c @@ -0,0 +1,130 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2021 John Sanpe + */ + +#include +#include +#include +#include + +#define TEST_LOOP 10 + +struct test_node { + struct bfdev_hlist_node list; + unsigned long num; +}; + +struct test_pdata { + struct test_node nodes[TEST_LOOP]; +}; + +#define bfdev_hlist_to_test(ptr) \ + bfdev_hlist_entry(ptr, struct test_node, list) + +static int +bfdev_hlist_selftest(struct test_pdata *hdata) +{ + struct test_node *node, *nnode, *tnode; + struct bfdev_hlist_node *list, *nlist, *tlist; + unsigned int count; + + BFDEV_HLIST_HEAD(test_head); + + for (count = 0; count < BFDEV_ARRAY_SIZE(hdata->nodes); ++count) { + bfdev_hlist_head_add(&test_head, &hdata->nodes[count].list); + } + + bfdev_hlist_for_each(list, &test_head) { + node = bfdev_hlist_to_test(list); + printf("hlist 'bfdev_hlist_for_each' test: %lu\n", node->num); + if (node->num == TEST_LOOP / 2) + break; + } + + tlist = list; + bfdev_hlist_for_each_continue(list) { + node = bfdev_hlist_to_test(list); + printf("hlist 'bfdev_hlist_for_each_continue' test: %lu\n", node->num); + } + + list = tlist; + bfdev_hlist_for_each_from(list) { + node = bfdev_hlist_to_test(list); + printf("hlist 'bfdev_hlist_for_each_from' test: %lu\n", node->num); + } + + bfdev_hlist_for_each_safe(list, nlist, &test_head) { + node = bfdev_hlist_to_test(list); + printf("hlist 'bfdev_hlist_for_each_safe' test: %lu\n", node->num); + if (node->num == TEST_LOOP / 2) + break; + } + + tlist = list; + bfdev_hlist_for_each_continue_safe(list, nlist) { + node = bfdev_hlist_to_test(list); + printf("hlist 'bfdev_hlist_for_each_continue_safe' test: %lu\n", node->num); + } + + list = tlist; + bfdev_hlist_for_each_from_safe(list, nlist) { + node = bfdev_hlist_to_test(list); + printf("hlist 'bfdev_hlist_for_each_from_safe' test: %lu\n", node->num); + } + + bfdev_hlist_for_each_entry(node, &test_head, list) { + printf("hlist 'bfdev_hlist_for_each_entry' test: %lu\n", node->num); + if (node->num == TEST_LOOP / 2) + break; + } + + tnode = node; + bfdev_hlist_for_each_entry_continue(node, list) { + printf("hlist 'bfdev_hlist_for_each_entry_continue' test: %lu\n", node->num); + } + + node = tnode; + bfdev_hlist_for_each_entry_from(node, list) { + printf("hlist 'bfdev_hlist_for_each_entry_from' test: %lu\n", node->num); + } + + bfdev_hlist_for_each_entry_safe(node, nnode, &test_head, list) { + printf("hlist 'bfdev_hlist_for_each_entry_safe' test: %lu\n", node->num); + if (node->num == TEST_LOOP / 2) + break; + bfdev_hlist_del(&node->list); + } + + tnode = node; + bfdev_hlist_for_each_entry_continue_safe(node, nnode, list) { + printf("hlist 'bfdev_hlist_for_each_entry_continue_safe' test: %lu\n", node->num); + } + + node = tnode; + bfdev_hlist_for_each_entry_from_safe(node, nnode, list) { + printf("hlist 'bfdev_hlist_for_each_entry_from_safe' test: %lu\n", node->num); + bfdev_hlist_del(&node->list); + } + + return 0; +} + +int main(int argc, const char *argv[]) +{ + struct test_pdata *hdata; + unsigned int count; + int retval; + + hdata = malloc(sizeof(struct test_pdata)); + if ((retval = !hdata)) + return retval; + + for (count = 0; count < BFDEV_ARRAY_SIZE(hdata->nodes); ++count) + hdata->nodes[count].num = TEST_LOOP - count - 1; + + retval = bfdev_hlist_selftest(hdata); + free(hdata); + + return retval; +} diff --git a/examples/hlist/simple.c b/examples/hlist/simple.c new file mode 100644 index 00000000..c9f8e3e6 --- /dev/null +++ b/examples/hlist/simple.c @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2021 John Sanpe + */ + +#include +#include +#include +#include +#include + +#define TEST_LEN 100 +static BFDEV_HLIST_HEAD(demo_list); + +struct hlist_simple { + struct bfdev_hlist_node list; + unsigned int num; + unsigned long data; +}; + +#define hlist_to_simple(node) \ + bfdev_hlist_entry(node, struct hlist_simple, list) + +int main(int argc, const char *argv[]) +{ + struct hlist_simple *node, *tmp; + unsigned int count; + int retval = 0; + + printf("Generate %d Node:\n", TEST_LEN); + srand(time(NULL)); + for (count = 0; count < TEST_LEN; ++count) { + node = malloc(sizeof(*node)); + if ((retval = !node)) { + printf("insufficient memory\n"); + return 1; + } + + node->num = count; + node->data = ((uint64_t)rand() << 32) | rand(); + bfdev_hlist_head_add(&demo_list, &node->list); + } + + bfdev_hlist_for_each_entry(node, &demo_list, list) + printf("\t%04u: 0x%016lx\n", node->num, node->data); + + printf("Deletion All Node...\n"); + bfdev_hlist_for_each_entry_safe(node, tmp, &demo_list, list) { + bfdev_hlist_del(&node->list); + free(node); + } + + return retval; +} diff --git a/examples/ilist/.gitignore b/examples/ilist/.gitignore new file mode 100755 index 00000000..00b55b3e --- /dev/null +++ b/examples/ilist/.gitignore @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +/ilist-selftest diff --git a/examples/ilist/CMakeLists.txt b/examples/ilist/CMakeLists.txt new file mode 100644 index 00000000..c2368f25 --- /dev/null +++ b/examples/ilist/CMakeLists.txt @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright(c) 2023 ffashion +# + +add_executable(ilist-selftest selftest.c) +target_link_libraries(ilist-selftest bfdev) +add_test(ilist-selftest ilist-selftest) + +if(${CMAKE_PROJECT_NAME} STREQUAL "bfdev") + install(FILES + selftest.c + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/examples/ilist + ) + + install(TARGETS + ilist-selftest + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/bin + ) +endif() diff --git a/examples/ilist/selftest.c b/examples/ilist/selftest.c new file mode 100644 index 00000000..9b9f7bfc --- /dev/null +++ b/examples/ilist/selftest.c @@ -0,0 +1,86 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2021 John Sanpe + */ + +#include +#include +#include + +#define TEST_LOOP 10 + +struct test_node { + struct bfdev_ilist_node ilist; + unsigned long num; +}; + +struct test_pdata { + struct test_node nodes[TEST_LOOP]; +}; + +#define ilist_to_test(ptr) \ + bfdev_ilist_entry(ptr, struct test_node, ilist) + +static inline long +ilist_cmp(const struct bfdev_ilist_node *node1, + const struct bfdev_ilist_node *node2, void *pdata) +{ + struct test_node *tnode1, *tnode2; + + tnode1 = ilist_to_test(node1); + tnode2 = ilist_to_test(node2); + + if (tnode1->num == tnode2->num) + return 0; + + return tnode1->num < tnode2->num ? -1 : 1; +} + +static int +ilist_selftest(struct test_pdata *idata) +{ + unsigned int count, count2; + + BFDEV_ILIST_HEAD(test_head); + + for (count = 0; count < TEST_LOOP; ++count) { + printf("ilist 'bfdev_ilist_add' test%u single\n", count); + idata->nodes[count].num = count; + bfdev_ilist_node_init(&idata->nodes[count].ilist); + bfdev_ilist_add(&test_head, &idata->nodes[count].ilist, + ilist_cmp, NULL); + } + + for (count = 0; count < TEST_LOOP; ++count) + bfdev_ilist_del(&test_head, &idata->nodes[count].ilist); + + for (count = 0; count < TEST_LOOP / 2; ++count) { + for (count2 = 0; count2 < 2; ++count2) { + printf("ilist 'bfdev_ilist_add' test%u multi%u\n", count * 2 + count2, count2); + idata->nodes[count].num = count; + bfdev_ilist_node_init(&idata->nodes[count * 2 + count2].ilist); + bfdev_ilist_add(&test_head, &idata->nodes[count * 2 + count2].ilist, + ilist_cmp, NULL); + } + } + + for (count = 0; count < TEST_LOOP; ++count) + bfdev_ilist_del(&test_head, &idata->nodes[count].ilist); + + return 0; +} + +int main(int argc, const char *argv[]) +{ + struct test_pdata *idata; + int retval; + + idata = malloc(sizeof(*idata)); + if (!idata) + return 1; + + retval = ilist_selftest(idata); + free(idata); + + return retval; +} diff --git a/examples/levenshtein/.gitignore b/examples/levenshtein/.gitignore new file mode 100644 index 00000000..759dbf0d --- /dev/null +++ b/examples/levenshtein/.gitignore @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +/levenshtein-simple diff --git a/examples/levenshtein/CMakeLists.txt b/examples/levenshtein/CMakeLists.txt new file mode 100644 index 00000000..aa387ed2 --- /dev/null +++ b/examples/levenshtein/CMakeLists.txt @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright(c) 2023 ffashion +# + +add_executable(levenshtein-simple simple.c) +target_link_libraries(levenshtein-simple bfdev) +add_test(levenshtein-simple levenshtein-simple) + +if(${CMAKE_PROJECT_NAME} STREQUAL "bfdev") + install(FILES + simple.c + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/examples/levenshtein + ) + + install(TARGETS + levenshtein-simple + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/bin + ) +endif() diff --git a/examples/levenshtein/simple.c b/examples/levenshtein/simple.c new file mode 100644 index 00000000..794b42df --- /dev/null +++ b/examples/levenshtein/simple.c @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#include +#include +#include + +int main(int argc, const char *argv[]) +{ + unsigned int diff; + + /* substitution distance reward */ + diff = bfdev_levenshtein(NULL, "aaa", "bbb", 1, 0, 1, 1); + printf("levenshtein substitution: %u (aaa -> bbb)\n", diff); + + /* swap distance reward */ + diff = bfdev_levenshtein(NULL, "abcdef", "badcfe", 1, 1, 1, 1); + printf("levenshtein swap: %u (abcdef -> badcfe)\n", diff); + + /* addition distance reward */ + diff = bfdev_levenshtein(NULL, "hello", "helloworld", 0, 0, 1, 0); + printf("levenshtein addition: %u (hello -> helloworld)\n", diff); + + /* deletion distance reward */ + diff = bfdev_levenshtein(NULL, "popcat", "pop", 0, 0, 0, 1); + printf("levenshtein deletion: %u (popcat -> pop)\n", diff); + + return 0; +} diff --git a/examples/list/.gitignore b/examples/list/.gitignore new file mode 100644 index 00000000..d938e3d7 --- /dev/null +++ b/examples/list/.gitignore @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +/list-benchmark +/list-selftest diff --git a/examples/list/CMakeLists.txt b/examples/list/CMakeLists.txt new file mode 100644 index 00000000..479a8522 --- /dev/null +++ b/examples/list/CMakeLists.txt @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright(c) 2023 ffashion +# + +add_executable(list-benchmark benchmark.c) +target_link_libraries(list-benchmark bfdev) +add_test(list-benchmark list-benchmark) + +add_executable(list-selftest selftest.c) +target_link_libraries(list-selftest bfdev) +add_test(list-selftest list-selftest) + +if(${CMAKE_PROJECT_NAME} STREQUAL "bfdev") + install(FILES + benchmark.c + selftest.c + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/examples/list + ) + + install(TARGETS + list-benchmark + list-selftest + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/bin + ) +endif() diff --git a/examples/list/benchmark.c b/examples/list/benchmark.c new file mode 100644 index 00000000..7bb6c87d --- /dev/null +++ b/examples/list/benchmark.c @@ -0,0 +1,102 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2021 John Sanpe + */ + +#define MODULE_NAME "list-benchmark" +#define bfdev_log_fmt(fmt) MODULE_NAME ": " fmt + +#include +#include +#include +#include +#include "../time.h" + +#define LIST_DEBUG 0 +#define TEST_LEN 1000000 +static BFDEV_LIST_HEAD(demo_list); + +struct benchmark { + struct bfdev_list_head list; + unsigned int num; + unsigned long data; +}; + +#define list_to_demo(node) \ + bfdev_list_entry(node, struct benchmark, list) + +#if LIST_DEBUG +static void +node_dump(struct benchmark *node) +{ + bfdev_log_info("\t%08d: data 0x%016lx\n", node->num, node->data); +} +#else +# define node_dump(node) ((void)(node)) +#endif + +static long +demo_cmp(const struct bfdev_list_head *node1, + const struct bfdev_list_head *node2, void *pdata) +{ + struct benchmark *test1, *test2; + + test1 = list_to_demo(node1); + test2 = list_to_demo(node2); + + if (test1->num == test2->num) + return 0; + + return test1->num < test2->num ? -1 : 1; +} + +int main(int argc, const char *argv[]) +{ + struct benchmark *node, *tmp; + unsigned int count; + void *block; + + node = block = malloc(sizeof(*node) * TEST_LEN); + if (!block) { + bfdev_log_err("insufficient memory!\n"); + return 1; + } + + srand(time(NULL)); + bfdev_log_info("Generate %u node:\n", TEST_LEN); + for (count = 0; count < TEST_LEN; ++count) { + node[count].num = count; + node[count].data = ((uint64_t)rand() << 32) | rand(); + } + + bfdev_log_info("Insert nodes:\n"); + EXAMPLE_TIME_STATISTICAL( + for (count = 0; count < TEST_LEN; ++count) { + bfdev_list_add(&demo_list, &node[count].list); + node_dump(node); + } + 0; + ); + + bfdev_log_info("Sort nodes:\n"); + EXAMPLE_TIME_STATISTICAL( + bfdev_list_sort(&demo_list, demo_cmp, NULL); + 0; + ); + + bfdev_log_info("List for each:\n"); + EXAMPLE_TIME_STATISTICAL( + bfdev_list_for_each_entry(node, &demo_list, list) + node_dump(node); + 0; + ); + + bfdev_log_info("Deletion all node...\n"); + bfdev_list_for_each_entry_safe(node, tmp, &demo_list, list) + bfdev_list_del(&node->list); + + bfdev_log_info("Done.\n"); + free(block); + + return 0; +} diff --git a/examples/list/selftest.c b/examples/list/selftest.c new file mode 100644 index 00000000..001777e2 --- /dev/null +++ b/examples/list/selftest.c @@ -0,0 +1,220 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2021 John Sanpe + */ + +#include +#include +#include +#include + +#define TEST_LOOP 10 + +struct test_node { + struct bfdev_list_head list; + unsigned long num; +}; + +struct test_pdata { + struct test_node nodes[TEST_LOOP]; +}; + +#define list_to_test(ptr) \ + bfdev_list_entry(ptr, struct test_node, list) + +static long +list_test_sort(const struct bfdev_list_head *node1, + const struct bfdev_list_head *node2, void *pdata) +{ + struct test_node *tnode1, *tnode2; + + tnode1 = list_to_test(node1); + tnode2 = list_to_test(node2); + + if (tnode1->num == tnode2->num) + return 0; + + return tnode1->num < tnode2->num ? -1 : 1; +} + +static int +list_selftest(struct test_pdata *ldata) +{ + struct test_node *node, *nnode, *tnode; + struct bfdev_list_head *list, *nlist, *tlist; + unsigned int count; + + BFDEV_LIST_HEAD(test_head); + + for (count = 0; count < BFDEV_ARRAY_SIZE(ldata->nodes); ++count) { + if (count % 1) + bfdev_list_add_prev(&test_head, &ldata->nodes[count].list); + else + bfdev_list_add(&test_head, &ldata->nodes[count].list); + } + + bfdev_list_sort(&test_head, list_test_sort, NULL); + + bfdev_list_for_each(list, &test_head) { + node = list_to_test(list); + printf("list 'list_for_each' test: %lu\n", node->num); + if (node->num == TEST_LOOP / 2) + break; + } + + tlist = list; + bfdev_list_for_each_continue(list, &test_head) { + node = list_to_test(list); + printf("list 'list_for_each_continue' test: %lu\n", node->num); + } + + list = tlist; + bfdev_list_for_each_from(list, &test_head) { + node = list_to_test(list); + printf("list 'list_for_each_from' test: %lu\n", node->num); + } + + bfdev_list_for_each_reverse(list, &test_head) { + node = list_to_test(list); + printf("list 'list_for_each_reverse' test: %lu\n", node->num); + if (node->num == TEST_LOOP / 2) + break; + } + + tlist = list; + bfdev_list_for_each_reverse_continue(list, &test_head) { + node = list_to_test(list); + printf("list 'list_for_each_reverse_continue' test: %lu\n", node->num); + } + + list = tlist; + bfdev_list_for_each_reverse_from(list, &test_head) { + node = list_to_test(list); + printf("list 'list_for_each_reverse_from' test: %lu\n", node->num); + } + + bfdev_list_for_each_safe(list, nlist, &test_head) { + node = list_to_test(list); + printf("list 'list_for_each_safe' test: %lu\n", node->num); + if (node->num == TEST_LOOP / 2) + break; + } + + tlist = list; + bfdev_list_for_each_continue_safe(list, nlist, &test_head) { + node = list_to_test(list); + printf("list 'list_for_each_continue_safe' test: %lu\n", node->num); + } + + list = tlist; + bfdev_list_for_each_from_safe(list, nlist, &test_head) { + node = list_to_test(list); + printf("list 'list_for_each_from_safe' test: %lu\n", node->num); + } + + bfdev_list_for_each_reverse_safe(list, nlist, &test_head) { + node = list_to_test(list); + printf("list 'list_for_each_reverse_safe' test: %lu\n", node->num); + if (node->num == TEST_LOOP / 2) + break; + } + + tlist = list; + bfdev_list_for_each_reverse_continue_safe(list, nlist, &test_head) { + node = list_to_test(list); + printf("list 'list_for_each_reverse_continue_safe' test: %lu\n", node->num); + } + + list = tlist; + bfdev_list_for_each_reverse_from_safe(list, nlist, &test_head) { + node = list_to_test(list); + printf("list 'list_for_each_reverse_from_safe' test: %lu\n", node->num); + } + + bfdev_list_for_each_entry(node, &test_head, list) { + printf("list 'list_for_each_entry' test: %lu\n", node->num); + if (node->num == TEST_LOOP / 2) + break; + } + + tnode = node; + bfdev_list_for_each_entry_continue(node, &test_head, list) { + printf("list 'list_for_each_entry_continue' test: %lu\n", node->num); + } + + node = tnode; + bfdev_list_for_each_entry_from(node, &test_head, list) { + printf("list 'list_for_each_entry_from' test: %lu\n", node->num); + } + + bfdev_list_for_each_entry_reverse(node, &test_head, list) { + printf("list 'list_for_each_entry_reverse' test: %lu\n", node->num); + if (node->num == TEST_LOOP / 2) + break; + } + + tnode = node; + bfdev_list_for_each_entry_reverse_continue(node, &test_head, list) { + printf("list 'list_for_each_entry_reverse_continue' test: %lu\n", node->num); + } + + node = tnode; + bfdev_list_for_each_entry_reverse_from(node, &test_head, list) { + printf("list 'list_for_each_entry_reverse_from' test: %lu\n", node->num); + } + + bfdev_list_for_each_entry_safe(node, nnode, &test_head, list) { + printf("list 'list_for_each_entry_safe' test: %lu\n", node->num); + if (node->num == TEST_LOOP / 2) + break; + } + + tnode = node; + bfdev_list_for_each_entry_continue_safe(node, nnode, &test_head, list) { + printf("list 'list_for_each_entry_continue_safe' test: %lu\n", node->num); + } + + node = tnode; + bfdev_list_for_each_entry_from_safe(node, nnode, &test_head, list) { + printf("list 'list_for_each_entry_form_safe' test: %lu\n", node->num); + } + + bfdev_list_for_each_entry_reverse_safe(node, nnode, &test_head, list) { + printf("list 'list_for_each_entry_reverse_safe' test: %lu\n", node->num); + if (node->num == TEST_LOOP / 2) + break; + bfdev_list_del(&node->list); + } + + tnode = node; + bfdev_list_for_each_entry_reverse_continue_safe(node, nnode, &test_head, list) { + printf("list 'list_for_each_entry_reverse_continue_safe' test: %lu\n", node->num); + } + + node = tnode; + bfdev_list_for_each_entry_reverse_from_safe(node, nnode, &test_head, list) { + printf("list 'list_for_each_entry_reverse_form_safe' test: %lu\n", node->num); + bfdev_list_del(&node->list); + } + + return 0; +} + +int main(int argc, const char *argv[]) +{ + struct test_pdata *ldata; + unsigned int count; + int retval; + + ldata = malloc(sizeof(struct test_pdata)); + if (!ldata) + return -1; + + for (count = 0; count < BFDEV_ARRAY_SIZE(ldata->nodes); ++count) + ldata->nodes[count].num = count; + + retval = list_selftest(ldata); + free(ldata); + + return retval; +} diff --git a/examples/log/.gitignore b/examples/log/.gitignore new file mode 100755 index 00000000..20227489 --- /dev/null +++ b/examples/log/.gitignore @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +/log-simple diff --git a/examples/log/CMakeLists.txt b/examples/log/CMakeLists.txt new file mode 100755 index 00000000..9e8d0477 --- /dev/null +++ b/examples/log/CMakeLists.txt @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright(c) 2023 John Sanpe +# + +add_executable(log-simple simple.c) +target_link_libraries(log-simple bfdev) +add_test(log-simple log-simple) + +if(${CMAKE_PROJECT_NAME} STREQUAL "bfdev") + install(FILES + simple.c + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/examples/log + ) + + install(TARGETS + log-simple + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/bin + ) +endif() diff --git a/examples/log/simple.c b/examples/log/simple.c new file mode 100644 index 00000000..047f7c36 --- /dev/null +++ b/examples/log/simple.c @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#define MODULE_NAME "log-simple" +#define bfdev_log_fmt(fmt) MODULE_NAME ": " fmt + +#include + +int main(int argc, const char *argv[]) +{ + bfdev_log_emerg("helloworld\n"); + bfdev_log_alert("helloworld\n"); + bfdev_log_crit("helloworld\n"); + bfdev_log_err("helloworld\n"); + bfdev_log_warn("helloworld\n"); + bfdev_log_notice("helloworld\n"); + bfdev_log_info("helloworld\n"); + bfdev_log_debug("helloworld\n"); + bfdev_log_print("helloworld\n"); + + return 0; +} diff --git a/examples/log2/.gitignore b/examples/log2/.gitignore new file mode 100755 index 00000000..cff308db --- /dev/null +++ b/examples/log2/.gitignore @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +/log2-selftest diff --git a/examples/log2/CMakeLists.txt b/examples/log2/CMakeLists.txt new file mode 100755 index 00000000..42df8480 --- /dev/null +++ b/examples/log2/CMakeLists.txt @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright(c) 2023 John Sanpe +# + +add_executable(log2-selftest selftest.c) +target_link_libraries(log2-selftest bfdev) +add_test(log2-selftest log2-selftest) + +if(${CMAKE_PROJECT_NAME} STREQUAL "bfdev") + install(FILES + selftest.c + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/examples/log2 + ) + + install(TARGETS + log2-selftest + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/bin + ) +endif() diff --git a/examples/log2/selftest.c b/examples/log2/selftest.c new file mode 100755 index 00000000..04602784 --- /dev/null +++ b/examples/log2/selftest.c @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#include +#include +#include + +int main(int argc, const char *argv[]) +{ + unsigned int count, result; + + for (count = 0; count < 32; ++count) { + uint32_t value; + + value = 1UL << count; + result = bfdev_ilog2(value); + + printf("log2 'bfdev_ilog2' u32 test: %u -> %u ", count, result); + if (result != count) { + printf("failed\n"); + return 1; + } + printf("passed\n"); + } + + for (count = 0; count < 64; ++count) { + uint64_t value; + + value = 1ULL << count; + result = bfdev_ilog2(value); + + printf("log2 'bfdev_ilog2' u64 test: %u -> %u ", count, result); + if (result != count) { + printf("failed\n"); + return 1; + } + printf("passed\n"); + } + + return 0; +} diff --git a/examples/matrix/.gitignore b/examples/matrix/.gitignore new file mode 100644 index 00000000..8ebe58fc --- /dev/null +++ b/examples/matrix/.gitignore @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +/matrix-benchmark +/matrix-fibonacci diff --git a/examples/matrix/CMakeLists.txt b/examples/matrix/CMakeLists.txt new file mode 100644 index 00000000..344eaf56 --- /dev/null +++ b/examples/matrix/CMakeLists.txt @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright(c) 2023 ffashion +# + +add_executable(matrix-fibonacci fibonacci.c) +target_link_libraries(matrix-fibonacci bfdev) +add_test(matrix-fibonacci matrix-fibonacci) + +add_executable(matrix-benchmark benchmark.c) +target_link_libraries(matrix-benchmark bfdev) +add_test(matrix-benchmark matrix-benchmark) + +if(${CMAKE_PROJECT_NAME} STREQUAL "bfdev") + install(FILES + fibonacci.c + benchmark.c + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/examples/matrix + ) + + install(TARGETS + matrix-fibonacci + matrix-benchmark + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/bin + ) +endif() diff --git a/examples/matrix/benchmark.c b/examples/matrix/benchmark.c new file mode 100644 index 00000000..86c2964d --- /dev/null +++ b/examples/matrix/benchmark.c @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#define MODULE_NAME "matrix-benchmark" +#define bfdev_log_fmt(fmt) MODULE_NAME ": " fmt + +#include +#include +#include +#include "../time.h" + +#define TEST_SIZE 40 +#define TEST_LOOP 3 + +#define GENERIC_MATRIX_BENCHMARK(func, name) \ +for (count = 0; count < TEST_LOOP; ++count) { \ + EXAMPLE_TIME_LOOP(&loop, 1000, \ + result = func(NULL, vara, varb); \ + bfdev_matrix_destory(NULL, result); \ + 0; \ + ); \ + bfdev_log_info( \ + name " %u: %uops/s\n", \ + count, loop \ + ); \ +} + +int main(int argc, char const *argv[]) +{ + unsigned int count, loop; + struct bfdev_matrix *vara, *varb; + struct bfdev_matrix *result; + + vara = bfdev_matrix_create(NULL, TEST_SIZE, TEST_SIZE); + if (!vara) + return 1; + + varb = bfdev_matrix_create(NULL, TEST_SIZE, TEST_SIZE); + if (!varb) + return 1; + + srand(time(NULL)); + for (count = 0; count < TEST_SIZE * TEST_SIZE; ++count) { + vara->values[count] = (uint16_t)rand(); + varb->values[count] = (uint16_t)rand(); + } + + GENERIC_MATRIX_BENCHMARK(bfdev_matrix_add, "adding") + GENERIC_MATRIX_BENCHMARK(bfdev_matrix_sub, "subtracting") + GENERIC_MATRIX_BENCHMARK(bfdev_matrix_mul, "multiplying") + + bfdev_matrix_destory(NULL, vara); + bfdev_matrix_destory(NULL, varb); + + return 0; +} diff --git a/examples/matrix/fibonacci.c b/examples/matrix/fibonacci.c new file mode 100644 index 00000000..c763761b --- /dev/null +++ b/examples/matrix/fibonacci.c @@ -0,0 +1,75 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#include +#include +#include + +#define TEST_BASE 1 +#define TEST_MAXN 46 + +static struct bfdev_matrix +matrix_power = { + .row = 2, .col = 2, + .values = { + 0, 1, + 1, 0, + }, +}; + +static struct bfdev_matrix +matrix_fibonacci = { + .row = 2, .col = 2, + .values = { + 1, 1, + 1, 0, + }, +}; + +static struct bfdev_matrix * +power(const struct bfdev_matrix *var, unsigned int pow) +{ + struct bfdev_matrix *result; + struct bfdev_matrix *tmp; + + result = bfdev_matrix_copy(NULL, &matrix_power); + var = bfdev_matrix_copy(NULL, var); + + while (pow) { + if (pow & 1) { + tmp = bfdev_matrix_mul(NULL, result, var); + if (bfdev_unlikely(!tmp)) + return NULL; + + bfdev_matrix_destory(NULL, result); + result = tmp; + } + + tmp = bfdev_matrix_mul(NULL, var, var); + if (bfdev_unlikely(!tmp)) + return NULL; + + bfdev_matrix_destory(NULL, var); + var = tmp; + pow >>= 1; + } + + bfdev_matrix_destory(NULL, var); + return result; +} + +int main(int argc, const char *argv[]) +{ + struct bfdev_matrix *result; + unsigned int count; + + for (count = TEST_BASE; count <= TEST_MAXN; ++count) { + result = power(&matrix_fibonacci, count); + printf("matrix fibonacci %02u: %ld\n", count, result->values[0]); + bfdev_matrix_destory(NULL, result); + } + + return 0; +} diff --git a/examples/once/.gitignore b/examples/once/.gitignore new file mode 100644 index 00000000..048f4f4c --- /dev/null +++ b/examples/once/.gitignore @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +/once-simple diff --git a/examples/once/CMakeLists.txt b/examples/once/CMakeLists.txt new file mode 100644 index 00000000..b4370124 --- /dev/null +++ b/examples/once/CMakeLists.txt @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright(c) 2023 ffashion +# + +add_executable(once-simple simple.c) +target_link_libraries(once-simple bfdev) +add_test(once-simple once-simple) + +if(${CMAKE_PROJECT_NAME} STREQUAL "bfdev") + install(FILES + simple.c + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/examples/once + ) + + install(TARGETS + once-simple + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/bin + ) +endif() diff --git a/examples/once/simple.c b/examples/once/simple.c new file mode 100644 index 00000000..1b0c3ef1 --- /dev/null +++ b/examples/once/simple.c @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#include +#include +#include + +static void +test_once(const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + printf("once test_once: "); + vprintf(fmt, args); + va_end(args); +} + +static void +test_once_on(const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + printf("once test_once_on: "); + vprintf(fmt, args); + va_end(args); +} + +static void +test_once_done(const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + printf("once test_once_done: "); + vprintf(fmt, args); + va_end(args); +} + +int main(int argc, const char *argv[]) +{ + unsigned int count; + + for (count = 0; count < 10; ++count) + BFDEV_DO_ONCE(test_once, "%d\n", count); + + for (count = 0; count < 10; ++count) + BFDEV_DO_ONCE_ON(count == 1, test_once_on, "%d\n", count); + + for (count = 0; count < 10; ++count) { + if (BFDEV_DO_ONCE_DONE(count == 2)) + test_once_done("%d\n", count); + } + + return 0; +} diff --git a/examples/radix/.gitignore b/examples/radix/.gitignore new file mode 100644 index 00000000..bdeff4cf --- /dev/null +++ b/examples/radix/.gitignore @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +/radix-benchmark +/radix-simple diff --git a/examples/radix/CMakeLists.txt b/examples/radix/CMakeLists.txt new file mode 100644 index 00000000..f5695078 --- /dev/null +++ b/examples/radix/CMakeLists.txt @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright(c) 2023 John Sanpe +# + +add_executable(radix-simple simple.c) +target_link_libraries(radix-simple bfdev) +add_test(radix-simple radix-simple) + +add_executable(radix-benchmark benchmark.c) +target_link_libraries(radix-benchmark bfdev) +add_test(radix-benchmark radix-benchmark) + +if(${CMAKE_PROJECT_NAME} STREQUAL "bfdev") + install(FILES + simple.c + benchmark.c + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/examples/radix + ) + + install(TARGETS + radix-simple + radix-benchmark + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/bin + ) +endif() diff --git a/examples/radix/benchmark.c b/examples/radix/benchmark.c new file mode 100644 index 00000000..3c26f5a4 --- /dev/null +++ b/examples/radix/benchmark.c @@ -0,0 +1,87 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#define MODULE_NAME "radix-benchmark" +#define bfdev_log_fmt(fmt) MODULE_NAME ": " fmt + +#include +#include +#include +#include +#include "../time.h" + +#define TEST_LOOP 1000000 +BFDEV_RADIX_ROOT(bench_root, unsigned int, NULL); + +int main(int argc, const char *argv[]) +{ + unsigned int count, *data; + int retval; + + bfdev_log_info("Generate %u node:\n", TEST_LOOP); + data = malloc(sizeof(*data) * TEST_LOOP); + if (!data) { + bfdev_log_err("Insufficient memory!\n"); + return 1; + } + + srand(time(NULL)); + for (count = 0; count < TEST_LOOP; ++count) + data[count] = rand(); + + retval = bfdev_radix_charge(&bench_root, 0, TEST_LOOP); + if (retval) { + bfdev_log_err("Insufficient memory!\n"); + return retval; + } + + bfdev_log_info("Alloc Nodes:\n"); + EXAMPLE_TIME_STATISTICAL( + for (count = 0; count < TEST_LOOP; ++count) { + unsigned int *block; + block = bfdev_radix_alloc(&bench_root, count); + *block = data[count]; + } + 0; + ); + + bfdev_log_info("Find Nodes:\n"); + EXAMPLE_TIME_STATISTICAL( + for (count = 0; count < TEST_LOOP; ++count) { + unsigned int *block; + block = bfdev_radix_find(&bench_root, count); + if (!block || *block != data[count]) { + bfdev_log_info("Data verification failed!\n"); + return 1; + } + } + 0; + ); + + bfdev_log_info("Free Nodes:\n"); + EXAMPLE_TIME_STATISTICAL( + for (count = 0; count < TEST_LOOP; ++count) { + retval = bfdev_radix_free(&bench_root, count); + if (retval) { + bfdev_log_info("Sequence error!\n"); + return 1; + } + } + 0; + ); + + count = bench_root.tree.level; + bfdev_log_info("\tradix level: %u\n", count); + if (count) { + bfdev_log_info("Pruning error!\n"); + return 1; + } + + bfdev_log_info("Done.\n"); + bfdev_radix_destory(&bench_root); + free(data); + + return 0; +} diff --git a/examples/radix/simple.c b/examples/radix/simple.c new file mode 100644 index 00000000..06d25372 --- /dev/null +++ b/examples/radix/simple.c @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#include +#include +#include + +#define TEST_LOOP 128 +BFDEV_RADIX_ROOT(simple_root, unsigned int, NULL); + +int main(int argc, const char *argv[]) +{ + unsigned int count, *block; + int retval; + + for (count = 0; count < TEST_LOOP; ++count) { + block = bfdev_radix_alloc(&simple_root, count); + printf("radix 'bfdev_radix_insert' test%02u: ", count); + if (!block) { + printf("failed\n"); + return 1; + } + *block = count; + printf("passed\n"); + } + + for (count = 0; count < TEST_LOOP; ++count) { + block = bfdev_radix_find(&simple_root, count); + printf("radix 'bfdev_radix_find' test%02u: ", count); + if (!block || count != *block) { + printf("failed\n"); + return 1; + } + printf("passed\n"); + } + + for (count = 0; count < TEST_LOOP; ++count) { + retval = bfdev_radix_free(&simple_root, count); + printf("radix 'bfdev_radix_delete' test%02u: ", count); + if (retval) { + printf("failed\n"); + return retval; + } + printf("passed\n"); + } + + bfdev_radix_destory(&simple_root); + return 0; +} diff --git a/examples/rbtree/.gitignore b/examples/rbtree/.gitignore new file mode 100644 index 00000000..bbe75818 --- /dev/null +++ b/examples/rbtree/.gitignore @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +/rbtree-benchmark +/rbtree-selftest +/rbtree-simple diff --git a/examples/rbtree/CMakeLists.txt b/examples/rbtree/CMakeLists.txt new file mode 100644 index 00000000..4fe60432 --- /dev/null +++ b/examples/rbtree/CMakeLists.txt @@ -0,0 +1,34 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright(c) 2023 ffashion +# + +add_executable(rbtree-benchmark benchmark.c) +target_link_libraries(rbtree-benchmark bfdev) +add_test(rbtree-benchmark rbtree-benchmark) + +add_executable(rbtree-selftest selftest.c) +target_link_libraries(rbtree-selftest bfdev) +add_test(rbtree-selftest rbtree-selftest) + +add_executable(rbtree-simple simple.c) +target_link_libraries(rbtree-simple bfdev) +add_test(rbtree-simple rbtree-simple) + +if(${CMAKE_PROJECT_NAME} STREQUAL "bfdev") +install(FILES + benchmark.c + selftest.c + simple.c + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/examples/rbtree +) + +install(TARGETS + rbtree-benchmark + rbtree-selftest + rbtree-simple + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/bin +) +endif() diff --git a/examples/rbtree/benchmark.c b/examples/rbtree/benchmark.c new file mode 100644 index 00000000..40f21e5b --- /dev/null +++ b/examples/rbtree/benchmark.c @@ -0,0 +1,158 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2021-2022 John Sanpe + */ + +#define MODULE_NAME "rbtree-benchmark" +#define bfdev_log_fmt(fmt) MODULE_NAME ": " fmt + +#include +#include +#include +#include +#include "../time.h" + +#define RB_DEBUG 0 +#define RB_CACHED 1 +#define TEST_LEN 1000000 + +struct bench_node { + struct bfdev_rb_node node; + unsigned int num; + unsigned long data; +}; + +#define rb_to_bench(ptr) \ + bfdev_rb_entry_safe(ptr, struct bench_node, node) + +#if RB_DEBUG +static void +node_dump(struct bench_node *node) +{ + bfdev_log_info("\t%04d: ", node->num); + bfdev_log_info("parent %-4d ", node->node.parent ? rb_to_bench(node->node.parent)->num : 0); + bfdev_log_info("left %-4d ", node->node.left ? rb_to_bench(node->node.left)->num : 0); + bfdev_log_info("right %-4d ", node->node.right ? rb_to_bench(node->node.right)->num : 0); + bfdev_log_info("data 0x%16lx ", node->data); + bfdev_log_info("color'%s' ", node->node.color ? "black" : "red"); + bfdev_log_info("\n"); +} +#else +# define node_dump(node) ((void)(node)) +#endif + +#if RB_CACHED +static BFDEV_RB_ROOT_CACHED(bench_root); +# define bc_insert bfdev_rb_cached_insert +# define bc_delete bfdev_rb_cached_delete +# define bc_for_each_entry bfdev_rb_cached_for_each_entry +# define bc_post_for_each_entry bfdev_rb_cached_post_for_each_entry +# define bc_post_for_each_entry_safe bfdev_rb_cached_post_for_each_entry_safe +# define bc_deepth(cached) test_deepth((cached)->root.node) +#else +static BFDEV_RB_ROOT(bench_root); +# define bc_insert bfdev_rb_insert +# define bc_delete bfdev_rb_delete +# define bc_for_each_entry bfdev_rb_for_each_entry +# define bc_post_for_each_entry bfdev_rb_post_for_each_entry +# define bc_post_for_each_entry_safe bfdev_rb_post_for_each_entry_safe +# define bc_deepth(root) test_deepth((root)->node) +#endif + +static unsigned int +test_deepth(struct bfdev_rb_node *node) +{ + unsigned int left_deepth, right_deepth; + + if (!node) + return 0; + + left_deepth = test_deepth(node->left); + right_deepth = test_deepth(node->right); + return left_deepth > right_deepth ? (left_deepth + 1) : (right_deepth + 1); +} + +static long +demo_cmp(const struct bfdev_rb_node *node1, + const struct bfdev_rb_node *node2, void *pdata) +{ + struct bench_node *test1, *test2; + + test1 = rb_to_bench(node1); + test2 = rb_to_bench(node2); + + if (test1->data == test2->data) + return 0; + + return test1->data < test2->data ? -1 : 1; +} + +int main(int argc, const char *argv[]) +{ + struct bench_node *node, *tmp; + unsigned int count; + void *block; + + node = block = malloc(sizeof(*node) * TEST_LEN); + if (!block) { + bfdev_log_err("Insufficient memory!\n"); + return 1; + } + + srand(time(NULL)); + bfdev_log_info("Generate %u node:\n", TEST_LEN); + for (count = 0; count < TEST_LEN; ++count) { + node[count].data = ((uint64_t)rand() << 32) | rand(); +#if RB_DEBUG + node[count].num = count + 1; + bfdev_log_info("\t%08d: 0x%016lx\n", node->num, node->data); +#endif + } + + bfdev_log_info("Insert nodes:\n"); + EXAMPLE_TIME_STATISTICAL( + for (count = 0; count < TEST_LEN; ++count) + bc_insert(&bench_root, &node[count].node, demo_cmp, NULL); + 0; + ); + count = bc_deepth(&bench_root); + bfdev_log_info("\trb deepth: %u\n", count); + + count = 0; + bfdev_log_info("Middle iteration:\n"); + EXAMPLE_TIME_STATISTICAL( + bc_for_each_entry(node, &bench_root, node) { + node_dump(node); + count++; + } + 0; + ); + bfdev_log_info("\ttotal num: %u\n", count); + + count = 0; + bfdev_log_info("Postorder iteration:\n"); + EXAMPLE_TIME_STATISTICAL( + bc_post_for_each_entry(node, &bench_root, node) { + node_dump(node); + count++; + } + 0; + ); + bfdev_log_info("\ttotal num: %u\n", count); + + count = 0; + bfdev_log_info("Postorder safe iteration:\n"); + EXAMPLE_TIME_STATISTICAL( + bc_post_for_each_entry_safe(node, tmp, &bench_root, node) { + node_dump(node); + count++; + } + 0; + ); + bfdev_log_info("\ttotal num: %u\n", count); + + bfdev_log_info("Done.\n"); + free(block); + + return 0; +} diff --git a/examples/rbtree/selftest.c b/examples/rbtree/selftest.c new file mode 100644 index 00000000..4f01d7ff --- /dev/null +++ b/examples/rbtree/selftest.c @@ -0,0 +1,473 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2022 John Sanpe + */ + +#include +#include +#include +#include + +#define TEST_LOOP 100 + +struct rbtree_test_node { + struct bfdev_rb_node node; + unsigned long data; +}; + +struct rbtree_test_pdata { + struct rbtree_test_node nodes[TEST_LOOP]; +}; + +#define rbnode_to_test(ptr) \ + bfdev_rb_entry(ptr, struct rbtree_test_node, node) + +#define rbnode_to_test_safe(ptr) \ + bfdev_rb_entry_safe(ptr, struct rbtree_test_node, node) + +static long +rbtest_rb_cmp(const struct bfdev_rb_node *rba, const struct bfdev_rb_node *rbb, void *pdata) +{ + struct rbtree_test_node *node1, *node2; + + node1 = rbnode_to_test(rba); + node2 = rbnode_to_test(rbb); + + if (node1->data== node2->data) + return 0; + + return node1->data < node2->data ? -1 : 1; +} + +static long +rbtest_rb_find(const struct bfdev_rb_node *rb, void *key) +{ + struct rbtree_test_node *node; + + node = rbnode_to_test(rb); + if (node->data == (unsigned long)key) + return 0; + + return node->data < (unsigned long)key ? -1 : 1; +} + +static int +rbtree_testing(struct rbtree_test_pdata *sdata) +{ + struct rbtree_test_node *node, *nnode, *tnode; + struct bfdev_rb_node *rbnode, *nrbnode, *trbnode; + unsigned long count; + + BFDEV_RB_ROOT_CACHED(test_root); + + for (count = 0; count < TEST_LOOP; ++count) + bfdev_rb_cached_insert(&test_root, &sdata->nodes[count].node, rbtest_rb_cmp, NULL); + + for (count = 0; count < TEST_LOOP; ++count) { + rbnode = bfdev_rb_find(&test_root.root, (void *)sdata->nodes[count].data, rbtest_rb_find); + if (!(node = rbnode_to_test_safe(rbnode))) + return 1; + printf("rbtree 'rb_cached' test: %lu\n", node->data); + } + + for (count = 0; count < TEST_LOOP; ++count) { + rbnode = bfdev_rb_cached_find(&test_root, (void *)sdata->nodes[count].data, rbtest_rb_find); + if (!(node = rbnode_to_test_safe(rbnode))) + return 1; + printf("rbtree 'rb_cached_find' test: %lu\n", node->data); + } + + count = 0; + bfdev_rb_for_each(rbnode, &test_root.root) { + node = rbnode_to_test(rbnode); + printf("rbtree 'rb_for_each' test: %lu\n", node->data); + if (count++ == TEST_LOOP / 2) + break; + } + + trbnode = rbnode; + bfdev_rb_for_each_continue(rbnode) { + node = rbnode_to_test(rbnode); + printf("rbtree 'rb_for_each_continue' test: %lu\n", node->data); + count++; + } + + rbnode = trbnode; + bfdev_rb_for_each_from(rbnode) { + node = rbnode_to_test(rbnode); + printf("rbtree 'rb_for_each_from' test: %lu\n", node->data); + count++; + } + + if (count != TEST_LOOP + (TEST_LOOP / 2)) + return 1; + + count = 0; + bfdev_rb_for_each_reverse(rbnode, &test_root.root) { + node = rbnode_to_test(rbnode); + printf("rbtree 'rb_for_each_reverse' test: %lu\n", node->data); + if (count++ == TEST_LOOP / 2) + break; + } + + trbnode = rbnode; + bfdev_rb_for_each_reverse_continue(rbnode) { + node = rbnode_to_test(rbnode); + printf("rbtree 'rb_for_each_reverse_continue' test: %lu\n", node->data); + count++; + } + + rbnode = trbnode; + bfdev_rb_for_each_reverse_from(rbnode) { + node = rbnode_to_test(rbnode); + printf("rbtree 'rb_for_each_reverse_from' test: %lu\n", node->data); + count++; + } + + if (count != TEST_LOOP + (TEST_LOOP / 2)) + return 1; + + count = 0; + bfdev_rb_post_for_each(rbnode, &test_root.root) { + node = rbnode_to_test(rbnode); + printf("rbtree 'rb_post_for_each' test: %lu\n", node->data); + if (count++ == TEST_LOOP / 2) + break; + } + + trbnode = rbnode; + bfdev_rb_post_for_each_continue(rbnode) { + node = rbnode_to_test(rbnode); + printf("rbtree 'rb_post_for_each_continue' test: %lu\n", node->data); + count++; + } + + rbnode = trbnode; + bfdev_rb_post_for_each_from(rbnode) { + node = rbnode_to_test(rbnode); + printf("rbtree 'rb_post_for_each_from' test: %lu\n", node->data); + count++; + } + + if (count != TEST_LOOP + (TEST_LOOP / 2)) + return 1; + + count = 0; + bfdev_rb_post_for_each_safe(rbnode, nrbnode, &test_root.root) { + node = rbnode_to_test(rbnode); + printf("rbtree 'rb_post_for_each_safe' test: %lu\n", node->data); + if (count++ == TEST_LOOP / 2) + break; + } + + trbnode = rbnode; + bfdev_rb_post_for_each_safe_continue(rbnode, nrbnode) { + node = rbnode_to_test(rbnode); + printf("rbtree 'rb_post_for_each_safe_continue' test: %lu\n", node->data); + count++; + } + + rbnode = trbnode; + bfdev_rb_post_for_each_safe_from(rbnode, nrbnode) { + node = rbnode_to_test(rbnode); + printf("rbtree 'rb_post_for_each_safe_from' test: %lu\n", node->data); + count++; + } + + if (count != TEST_LOOP + (TEST_LOOP / 2)) + return 1; + + count = 0; + bfdev_rb_for_each_entry(node, &test_root.root, node) { + printf("rbtree 'rb_for_each_entry' test: %lu\n", node->data); + if (count++ == TEST_LOOP / 2) + break; + } + + tnode = node; + bfdev_rb_for_each_entry_continue(node, node) { + printf("rbtree 'rb_for_each_entry_continue' test: %lu\n", node->data); + count++; + } + + node = tnode; + bfdev_rb_for_each_entry_from(node, node) { + printf("rbtree 'rb_for_each_entry_from' test: %lu\n", node->data); + count++; + } + + if (count != TEST_LOOP + (TEST_LOOP / 2)) + return 1; + + count = 0; + bfdev_rb_for_each_entry_reverse(node, &test_root.root, node) { + printf("rbtree 'rb_for_each_entry_reverse' test: %lu\n", node->data); + if (count++ == TEST_LOOP / 2) + break; + } + + tnode = node; + bfdev_rb_for_each_entry_reverse_continue(node, node) { + printf("rbtree 'rb_for_each_entry_reverse_continue' test: %lu\n", node->data); + count++; + } + + node = tnode; + bfdev_rb_for_each_entry_reverse_from(node, node) { + printf("rbtree 'rb_for_each_entry_reverse_from' test: %lu\n", node->data); + count++; + } + + if (count != TEST_LOOP + (TEST_LOOP / 2)) + return 1; + + count = 0; + bfdev_rb_post_for_each_entry(node, &test_root.root, node) { + printf("rbtree 'rb_post_for_each_entry' test: %lu\n", node->data); + if (count++ == TEST_LOOP / 2) + break; + } + + tnode = node; + bfdev_rb_post_for_each_entry_continue(node, node) { + printf("rbtree 'rb_post_for_each_entry_continue' test: %lu\n", node->data); + count++; + } + + node = tnode; + bfdev_rb_post_for_each_entry_from(node, node) { + printf("rbtree 'rb_post_for_each_entry_from' test: %lu\n", node->data); + count++; + } + + if (count != TEST_LOOP + (TEST_LOOP / 2)) + return 1; + + count = 0; + bfdev_rb_pre_for_each(rbnode, &test_root.root) { + node = rbnode_to_test(rbnode); + printf("rbtree 'rb_pre_for_each' test: %lu\n", node->data); + if (count++ == TEST_LOOP / 2) + break; + } + + trbnode = rbnode; + bfdev_rb_pre_for_each_continue(rbnode) { + node = rbnode_to_test(rbnode); + printf("rbtree 'rb_pre_for_each_continue' test: %lu\n", node->data); + count++; + } + + rbnode = trbnode; + bfdev_rb_pre_for_each_from(rbnode) { + node = rbnode_to_test(rbnode); + printf("rbtree 'rb_pre_for_each_from' test: %lu\n", node->data); + count++; + } + + if (count != TEST_LOOP + (TEST_LOOP / 2)) + return 1; + + count = 0; + bfdev_rb_pre_for_each_entry(node, &test_root.root, node) { + printf("rbtree 'rb_pre_for_each_entry' test: %lu\n", node->data); + if (count++ == TEST_LOOP / 2) + break; + } + + tnode = node; + bfdev_rb_pre_for_each_entry_continue(node, node) { + printf("rbtree 'rb_pre_for_each_entry_continue' test: %lu\n", node->data); + count++; + } + + node = tnode; + bfdev_rb_pre_for_each_entry_from(node, node) { + printf("rbtree 'rb_pre_for_each_entry_from' test: %lu\n", node->data); + count++; + } + + if (count != TEST_LOOP + (TEST_LOOP / 2)) + return 1; + + count = 0; + bfdev_rb_post_for_each(rbnode, &test_root.root) { + node = rbnode_to_test(rbnode); + printf("rbtree 'rb_post_for_each' test: %lu\n", node->data); + if (count++ == TEST_LOOP / 2) + break; + } + + tnode = node; + bfdev_rb_post_for_each_entry_continue(node, node) { + printf("rbtree 'rb_post_for_each_entry_continue' test: %lu\n", node->data); + count++; + } + + node = tnode; + bfdev_rb_post_for_each_entry_from(node, node) { + printf("rbtree 'rb_post_for_each_entry_from' test: %lu\n", node->data); + count++; + } + + if (count != TEST_LOOP + (TEST_LOOP / 2)) + return 1; + + count = 0; + bfdev_rb_post_for_each_entry_safe(node, nnode, &test_root.root, node) { + printf("rbtree 'rb_post_for_each_entry_safe' test: %lu\n", node->data); + if (count++ == TEST_LOOP / 2) + break; + } + + tnode = node; + bfdev_rb_post_for_each_entry_continue_safe(node, nnode, node) { + printf("rbtree 'rb_post_for_each_entry_continue_safe' test: %lu\n", node->data); + count++; + } + + node = tnode; + bfdev_rb_post_for_each_entry_from_safe(node, nnode, node) { + printf("rbtree 'rb_post_for_each_entry_from_safe' test: %lu\n", node->data); + count++; + } + + if (count != TEST_LOOP + (TEST_LOOP / 2)) + return 1; + + count = 0; + bfdev_rb_cached_for_each(rbnode, &test_root) { + node = rbnode_to_test(rbnode); + printf("rbtree 'rb_cached_for_each' test: %lu\n", node->data); + count++; + } + + if (count != TEST_LOOP) + return 1; + + count = 0; + bfdev_rb_cached_for_each_reverse(rbnode, &test_root) { + node = rbnode_to_test(rbnode); + printf("rbtree 'rb_cached_for_each_reverse' test: %lu\n", node->data); + count++; + } + + if (count != TEST_LOOP) + return 1; + + count = 0; + bfdev_rb_cached_for_each_entry(node, &test_root, node) { + printf("rbtree 'rb_cached_for_each_entry' test: %lu\n", node->data); + count++; + } + + if (count != TEST_LOOP) + return 1; + + count = 0; + bfdev_rb_cached_for_each_entry_reverse(node, &test_root, node) { + printf("rbtree 'rb_cached_for_each_entry_reverse' test: %lu\n", node->data); + count++; + } + + if (count != TEST_LOOP) + return 1; + + count = 0; + bfdev_rb_cached_pre_for_each(rbnode, &test_root) { + node = rbnode_to_test(rbnode); + printf("rbtree 'rb_cached_pre_for_each' test: %lu\n", node->data); + count++; + } + + if (count != TEST_LOOP) + return 1; + + count = 0; + bfdev_rb_cached_pre_for_each_entry(node, &test_root, node) { + printf("rbtree 'rb_cached_pre_for_each_entry' test: %lu\n", node->data); + count++; + } + + if (count != TEST_LOOP) + return 1; + + count = 0; + bfdev_rb_cached_post_for_each(rbnode, &test_root) { + node = rbnode_to_test(rbnode); + printf("rbtree 'rb_cached_post_for_each' test: %lu\n", node->data); + count++; + } + + if (count != TEST_LOOP) + return 1; + + count = 0; + bfdev_rb_cached_post_for_each_safe(rbnode, nrbnode, &test_root) { + node = rbnode_to_test(rbnode); + printf("rbtree 'rb_cached_post_for_each_safe' test: %lu\n", node->data); + count++; + } + + if (count != TEST_LOOP) + return 1; + + count = 0; + bfdev_rb_cached_post_for_each_entry(node, &test_root, node) { + printf("rbtree 'rb_cached_post_for_each_entry' test: %lu\n", node->data); + count++; + } + + if (count != TEST_LOOP) + return 1; + + count = 0; + bfdev_rb_cached_post_for_each_entry_safe(node, nnode, &test_root, node) { + printf("rbtree 'rb_cached_post_for_each_entry_safe' test: %lu\n", node->data); + count++; + } + + if (count != TEST_LOOP) + return 1; + + return 0; +} + +int main(int argc, const char *argv[]) +{ + struct rbtree_test_pdata *rdata; + unsigned int count; + int retval; + + rdata = malloc(sizeof(struct rbtree_test_pdata)); + if (!rdata) + return -1; + + printf("Sequence Test...\n"); + for (count = 0; count < TEST_LOOP; ++count) + rdata->nodes[count].data = count; + + retval = rbtree_testing(rdata); + if (retval) { + printf("Abort1.\n"); + free(rdata); + return retval; + } + + printf("Random Test...\n"); + srand(time(NULL)); + for (count = 0; count < TEST_LOOP; ++count) + rdata->nodes[count].data = rand(); + + retval = rbtree_testing(rdata); + if (retval) { + printf("Abort2.\n"); + free(rdata); + return retval; + } + + printf("Done.\n"); + free(rdata); + + return 0; +} diff --git a/examples/rbtree/simple.c b/examples/rbtree/simple.c new file mode 100644 index 00000000..044ef7a7 --- /dev/null +++ b/examples/rbtree/simple.c @@ -0,0 +1,61 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2021-2022 John Sanpe + */ + +#include +#include +#include +#include +#include + +#define TEST_LEN 10 +static BFDEV_RB_ROOT(simple_root); + +struct simple_node { + struct bfdev_rb_node node; + unsigned long data; +}; + +#define rb_to_simple(ptr) \ + bfdev_rb_entry_safe(ptr, struct simple_node, node) + +static long +demo_cmp(const struct bfdev_rb_node *a, const struct bfdev_rb_node *b, void *pdata) +{ + struct simple_node *demo_a = rb_to_simple(a); + struct simple_node *demo_b = rb_to_simple(b); + return demo_a->data - demo_b->data; +} + +int main(int argc, const char *argv[]) +{ + struct simple_node *node, *tmp; + unsigned int count; + + srand(time(NULL)); + for (count = 0; count < TEST_LEN; ++count) { + node = malloc(sizeof(*node)); + if (!node) { + printf("Abort.\n"); + return 1; + } + + node->data = ((uint64_t)rand() << 32) | rand(); + bfdev_rb_insert(&simple_root, &node->node, demo_cmp, NULL); + } + + printf("Middle Iteration:\n"); + bfdev_rb_for_each_entry(node, &simple_root, node) + printf("\t0x%16lx\n", node->data); + + printf("Postorder Iteration:\n"); + bfdev_rb_post_for_each_entry(node, &simple_root, node) + printf("\t0x%16lx\n", node->data); + + bfdev_rb_post_for_each_entry_safe(node, tmp, &simple_root, node) + free(node); + + printf("Done.\n"); + return 0; +} diff --git a/examples/ringbuf/.gitignore b/examples/ringbuf/.gitignore new file mode 100644 index 00000000..aa1a9a69 --- /dev/null +++ b/examples/ringbuf/.gitignore @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +/ringbuf-simple diff --git a/examples/ringbuf/CMakeLists.txt b/examples/ringbuf/CMakeLists.txt new file mode 100644 index 00000000..8f50e8e4 --- /dev/null +++ b/examples/ringbuf/CMakeLists.txt @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright(c) 2023 ffashion +# + +add_executable(ringbuf-simple simple.c) +target_link_libraries(ringbuf-simple bfdev pthread) +add_test(ringbuf-simple ringbuf-simple) + +if(${CMAKE_PROJECT_NAME} STREQUAL "bfdev") + install(FILES + simple.c + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/examples/ringbuf + ) + + install(TARGETS + ringbuf-simple + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/bin + ) +endif() diff --git a/examples/ringbuf/simple.c b/examples/ringbuf/simple.c new file mode 100644 index 00000000..7e73ad8e --- /dev/null +++ b/examples/ringbuf/simple.c @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2022 John Sanpe + */ + +#include +#include +#include +#include + +static const char test_table[32] = { + 'b', 'f', 'd', 'e', 'v', '-', 'r', 'i', + 'n', 'g', '-', 't', 'e', 's', 't', '\n', + 'b', 'f', 'd', 'e', 'v', '-', 'r', 'i', + 'n', 'g', '-', 't', 'e', 's', 't', '\n', +}; + +static const char warn_table[16] = { + '=', '=', '=', '=', '=', '=', '=', '=', + '=', '=', '=', '=', '=', '=', '=', '\n', +}; + +#define TEST_SIZE 16 +#define TEST_LOOP 64 +BFDEV_DEFINE_RINGBUF(normal_bytetest, char, TEST_SIZE); + +static void +ringbuf_warnup(void) +{ + unsigned int count; + + bfdev_ringbuf_homing(&normal_bytetest); + for (count = 0; count < TEST_SIZE; ++count) + bfdev_ringbuf_put(&normal_bytetest, warn_table[count]); +} + +int main(int argc, const char *argv[]) +{ + unsigned int count, index; + char ch = 0; + + ringbuf_warnup(); + for (count = 0; count < TEST_LOOP; ++count) { + bfdev_ringbuf_peek(&normal_bytetest, &ch); + if (!ch) + return 1; + printf("%c", ch); + index = count % TEST_SIZE; + bfdev_ringbuf_put(&normal_bytetest, test_table[index]); + } + + return 0; +} diff --git a/examples/segtree/.gitignore b/examples/segtree/.gitignore new file mode 100644 index 00000000..49297502 --- /dev/null +++ b/examples/segtree/.gitignore @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +/segtree-selftest diff --git a/examples/segtree/CMakeLists.txt b/examples/segtree/CMakeLists.txt new file mode 100644 index 00000000..17b4ab31 --- /dev/null +++ b/examples/segtree/CMakeLists.txt @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright(c) 2023 ffashion +# + +add_executable(segtree-selftest selftest.c) +target_link_libraries(segtree-selftest bfdev) +add_test(segtree-selftest segtree-selftest) + +if(${CMAKE_PROJECT_NAME} STREQUAL "bfdev") + install(FILES + selftest.c + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/examples/segtree + ) + + install(TARGETS + segtree-selftest + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/bin + ) +endif() diff --git a/examples/segtree/selftest.c b/examples/segtree/selftest.c new file mode 100644 index 00000000..8fd1df87 --- /dev/null +++ b/examples/segtree/selftest.c @@ -0,0 +1,117 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#include +#include +#include +#include +#include + +#define TEST_LOOP 10 + +struct test_node { + struct bfdev_segtree_node node; + unsigned int num; +}; + +struct test_pdata { + struct test_node nodes[TEST_LOOP]; + unsigned int queries[TEST_LOOP]; +}; + +#define segtree_to_test(ptr) \ + bfdev_segtree_entry(ptr, struct test_node, node) + +static int +segtree_testing(struct test_pdata *sdata) +{ + struct test_node *node, *tnode; + struct bfdev_segtree_node *snode, *tsnode; + unsigned int count; + + BFDEV_RB_ROOT_CACHED(segtree_root); + + for (count = 0; count < TEST_LOOP; ++count) + bfdev_segtree_insert(&segtree_root, &sdata->nodes[count].node); + + for (count = 0; count < TEST_LOOP; ++count) { + bfdev_segtree_for_each_entry(node, 0, sdata->queries[count], &segtree_root, node) { + printf("srgtree search %u: %lu - %lu\n", sdata->queries[count], + node->node.start, node->node.end); + } + } + + count = 0; + bfdev_segtree_for_each(snode, 0, ~0UL, &segtree_root) { + node = segtree_to_test(snode); + printf("srgtree 'segtree_for_each' test: %lu - %lu\n", + node->node.start, node->node.end); + if (count++ == TEST_LOOP / 2) + break; + } + + tsnode = snode; + bfdev_segtree_for_each_form(snode, 0, ~0UL) { + node = segtree_to_test(snode); + printf("srgtree 'segtree_for_each_form' test: %lu - %lu\n", + node->node.start, node->node.end); + } + + snode = tsnode; + bfdev_segtree_for_each_continue(snode, 0, ~0UL) { + node = segtree_to_test(snode); + printf("srgtree 'segtree_for_each_continue' test: %lu - %lu\n", + node->node.start, node->node.end); + } + + count = 0; + bfdev_segtree_for_each_entry(node, 0, ~0UL, &segtree_root, node) { + printf("srgtree 'segtree_for_each_entry' test: %lu - %lu\n", + node->node.start, node->node.end); + if (count++ == TEST_LOOP / 2) + break; + } + + tnode = node; + bfdev_segtree_for_each_entry_from(node, 0, ~0UL, node) { + printf("srgtree 'segtree_for_each_entry_from' test: %lu - %lu\n", + node->node.start, node->node.end); + } + + node = tnode; + bfdev_segtree_for_each_entry_continue(node, 0, ~0UL, node) { + printf("srgtree 'segtree_for_each_entry_continue' test: %lu - %lu\n", + node->node.start, node->node.end); + } + + for (count = 0; count < TEST_LOOP; ++count) + bfdev_segtree_delete(&segtree_root, &sdata->nodes[count].node); + + return 0; +} + +int main(int argc, const char *argv[]) +{ + struct test_pdata *sdata; + unsigned long random; + unsigned int count; + int retval; + + sdata = malloc(sizeof(struct test_pdata)); + if (!sdata) + return -1; + + srand(time(NULL)); + for (count = 0; count < BFDEV_ARRAY_SIZE(sdata->nodes); ++count) { + sdata->queries[count] = rand(); + sdata->nodes[count].node.end = (random = rand()); + sdata->nodes[count].node.start = rand() % random; + } + + retval = segtree_testing(sdata); + free(sdata); + + return retval; +} diff --git a/examples/skiplist/.gitignore b/examples/skiplist/.gitignore new file mode 100644 index 00000000..e5c6068e --- /dev/null +++ b/examples/skiplist/.gitignore @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +/skiplist-benchmark +/skiplist-selftest diff --git a/examples/skiplist/CMakeLists.txt b/examples/skiplist/CMakeLists.txt new file mode 100644 index 00000000..ea93ec31 --- /dev/null +++ b/examples/skiplist/CMakeLists.txt @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright(c) 2023 ffashion +# + +add_executable(skiplist-benchmark benchmark.c) +target_link_libraries(skiplist-benchmark bfdev) +add_test(skiplist-benchmark skiplist-benchmark) + +add_executable(skiplist-selftest selftest.c) +target_link_libraries(skiplist-selftest bfdev) +add_test(skiplist-selftest skiplist-selftest) + +if(${CMAKE_PROJECT_NAME} STREQUAL "bfdev") + install(FILES + benchmark.c + selftest.c + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/examples/skiplist + ) + + install(TARGETS + skiplist-benchmark + skiplist-selftest + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/bin + ) +endif() diff --git a/examples/skiplist/benchmark.c b/examples/skiplist/benchmark.c new file mode 100644 index 00000000..06babc0b --- /dev/null +++ b/examples/skiplist/benchmark.c @@ -0,0 +1,89 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2022 John Sanpe + */ + +#define MODULE_NAME "skiplist-benchmark" +#define bfdev_log_fmt(fmt) MODULE_NAME ": " fmt + +#include +#include +#include +#include +#include "../time.h" + +#define TEST_DEPTH 32 +#define TEST_LEN 1000000 + +static long +test_cmp(const void *node1, const void *node2, void *pdata) +{ + uintptr_t valuea, valueb; + + valuea = (uintptr_t)node1; + valueb = (uintptr_t)node2; + + if (valuea == valueb) + return 0; + + return valuea > valueb ? 1 : -1; +} + +static long +test_find(const void *node, void *pdata) +{ + uintptr_t valuea, valueb; + + valuea = (uintptr_t)node; + valueb = (uintptr_t)pdata; + + if (valuea == valueb) + return 0; + + return valuea > valueb ? 1 : -1; +} + +int main(int argc, const char *argv[]) +{ + struct bfdev_skip_head *head; + struct bfdev_skip_node *node; + uintptr_t value, *record; + unsigned int count; + + record = malloc(TEST_LEN * sizeof(*record)); + if (!record) + return 1; + + head = bfdev_skiplist_create(NULL, TEST_DEPTH); + if (!head) + return 1; + + srand(time(NULL)); + bfdev_log_info("Insert %u node:\n", TEST_LEN); + EXAMPLE_TIME_STATISTICAL( + for (count = 0; count < TEST_LEN; ++count) { + value = ((uint64_t)rand() << 32) | rand(); + record[count] = value; + retval = bfdev_skiplist_insert(head, (void *)value, test_cmp, NULL); + if (retval) + return 1; + } + 0; + ); + + bfdev_log_info("Find %u node:\n", TEST_LEN); + EXAMPLE_TIME_STATISTICAL( + for (count = 0; count < TEST_LEN; ++count) { + value = record[(unsigned long)rand() % TEST_LEN]; + node = bfdev_skiplist_find(head, test_find, (void *)value); + if (!node) + return 1; + } + 0; + ); + + bfdev_skiplist_destroy(head, NULL); + free(record); + + return 0; +} diff --git a/examples/skiplist/selftest.c b/examples/skiplist/selftest.c new file mode 100644 index 00000000..866f585f --- /dev/null +++ b/examples/skiplist/selftest.c @@ -0,0 +1,111 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2022 John Sanpe + */ + +#include +#include +#include +#include + +#define TEST_LOOP 100 +#define TEST_LEVEL 32 + +struct test_node { + struct bfdev_skip_head *head; + uintptr_t values[TEST_LOOP]; +}; + +static long +test_cmp(const void *node1, const void *node2, void *pdata) +{ + uintptr_t valuea, valueb; + + valuea = (uintptr_t)node1; + valueb = (uintptr_t)node2; + + if (valuea == valueb) + return 0; + + return valuea > valueb ? 1 : -1; +} + +static long +test_find(const void *node, void *pdata) +{ + uintptr_t valuea, valueb; + + valuea = (uintptr_t)node; + valueb = (uintptr_t)pdata; + + if (valuea == valueb) + return 0; + + return valuea > valueb ? 1 : -1; +} + +static int +skiplist_testing(struct test_node *test) +{ + unsigned int count; + uintptr_t value; + int retval; + + bfdev_skiplist_reset(test->head, NULL); + for (count = 0; count < TEST_LOOP; ++count) + test->values[count] = rand() | 1; + + for (count = 0; count < TEST_LOOP; ++count) { + retval = bfdev_skiplist_insert( + test->head, (void *)test->values[count], + test_cmp, NULL + ); + printf("skiplist insert test%02d: %#010lx retval %d\n", + count, (unsigned long)test->values[count], retval); + if (retval) + return retval; + } + + for (count = 0; count < TEST_LOOP; ++count) { + value = (uintptr_t)bfdev_skiplist_find( + test->head, + test_find, (void *)test->values[count] + ); + printf("skiplist find test%02d: %#010lx retval %#010lx\n", + count, (unsigned long)test->values[count], (unsigned long)value); + if (!value) + return -BFDEV_ENOENT; + } + + for (count = 0; count < TEST_LOOP; ++count) { + bfdev_skiplist_delete( + test->head, + test_find, (void *)test->values[count] + ); + printf("skiplist delete test%02d\n", count); + } + + return 0; +} + +int main(int argc, const char *argv[]) +{ + struct test_node *test; + int retval; + + test = malloc(sizeof(struct test_node)); + if (!test) + return -BFDEV_ENOMEM; + + test->head = bfdev_skiplist_create(NULL, TEST_LEVEL); + if (!test->head) { + free(test); + return -BFDEV_ENOMEM; + } + + retval = skiplist_testing(test); + bfdev_skiplist_destroy(test->head, NULL); + free(test); + + return retval; +} diff --git a/examples/slist/.gitignore b/examples/slist/.gitignore new file mode 100644 index 00000000..a78e6719 --- /dev/null +++ b/examples/slist/.gitignore @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +/slist-selftest +/slist-simple diff --git a/examples/slist/CMakeLists.txt b/examples/slist/CMakeLists.txt new file mode 100644 index 00000000..fd2282d9 --- /dev/null +++ b/examples/slist/CMakeLists.txt @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright(c) 2023 ffashion +# + +add_executable(slist-selftest selftest.c) +target_link_libraries(slist-selftest bfdev) +add_test(slist-selftest slist-selftest) + +add_executable(slist-simple simple.c) +target_link_libraries(slist-simple bfdev) +add_test(slist-simple slist-simple) + +if(${CMAKE_PROJECT_NAME} STREQUAL "bfdev") + install(FILES + selftest.c + simple.c + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/examples/slist + ) + + install(TARGETS + slist-selftest + slist-simple + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/bin + ) +endif() diff --git a/examples/slist/selftest.c b/examples/slist/selftest.c new file mode 100644 index 00000000..f32555fe --- /dev/null +++ b/examples/slist/selftest.c @@ -0,0 +1,129 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#include +#include +#include +#include + +#define TEST_LOOP 10 + +struct test_node { + struct bfdev_slist_head list; + unsigned long num; +}; + +struct test_pdata { + struct test_node nodes[TEST_LOOP]; +}; + +#define slist_to_test(ptr) \ + bfdev_slist_entry(ptr, struct test_node, list) + +static int bfdev_slist_selftest(struct test_pdata *sdata) +{ + struct test_node *node, *nnode, *tnode; + struct bfdev_slist_head *list, *nlist, *tlist; + unsigned int count; + + BFDEV_SLIST_HEAD(test_head); + + for (count = 0; count < BFDEV_ARRAY_SIZE(sdata->nodes); ++count) { + bfdev_slist_add(&test_head, &sdata->nodes[count].list); + } + + bfdev_slist_for_each(list, &test_head) { + node = slist_to_test(list); + printf("slist 'bfdev_slist_for_each' test: %lu\n", node->num); + if (node->num == TEST_LOOP / 2) + break; + } + + tlist = list; + bfdev_slist_for_each_continue(list) { + node = slist_to_test(list); + printf("slist 'bfdev_slist_for_each_continue' test: %lu\n", node->num); + } + + list = tlist; + bfdev_slist_for_each_from(list) { + node = slist_to_test(list); + printf("slist 'bfdev_slist_for_each_from' test: %lu\n", node->num); + } + + bfdev_slist_for_each_safe(list, nlist, &test_head) { + node = slist_to_test(list); + printf("slist 'bfdev_slist_for_each_safe' test: %lu\n", node->num); + if (node->num == TEST_LOOP / 2) + break; + } + + tlist = list; + bfdev_slist_for_each_continue_safe(list, nlist) { + node = slist_to_test(list); + printf("slist 'bfdev_slist_for_each_continue_safe' test: %lu\n", node->num); + } + + list = tlist; + bfdev_slist_for_each_from_safe(list, nlist) { + node = slist_to_test(list); + printf("slist 'bfdev_slist_for_each_from_safe' test: %lu\n", node->num); + } + + bfdev_slist_for_each_entry(node, &test_head, list) { + printf("slist 'bfdev_slist_for_each_entry' test: %lu\n", node->num); + if (node->num == TEST_LOOP / 2) + break; + } + + tnode = node; + bfdev_slist_for_each_entry_continue(node, list) { + printf("slist 'bfdev_slist_for_each_entry_continue' test: %lu\n", node->num); + } + + node = tnode; + bfdev_slist_for_each_entry_from(node, list) { + printf("slist 'bfdev_slist_for_each_entry_from' test: %lu\n", node->num); + } + + bfdev_slist_for_each_entry_safe(node, nnode, &test_head, list) { + printf("slist 'bfdev_slist_for_each_entry_safe' test: %lu\n", node->num); + if (node->num == TEST_LOOP / 2) + break; + bfdev_slist_del(&test_head, &node->list); + } + + tnode = node; + bfdev_slist_for_each_entry_continue_safe(node, nnode, list) { + printf("slist 'bfdev_slist_for_each_entry_continue_safe' test: %lu\n", node->num); + } + + node = tnode; + bfdev_slist_for_each_entry_from_safe(node, nnode, list) { + printf("slist 'bfdev_slist_for_each_entry_from_safe' test: %lu\n", node->num); + bfdev_slist_del(&test_head, &node->list); + } + + return 0; +} + +int main(int argc, const char *argv[]) +{ + struct test_pdata *sdata; + unsigned int count; + int retval; + + sdata = malloc(sizeof(struct test_pdata)); + if (!sdata) + return -1; + + for (count = 0; count < BFDEV_ARRAY_SIZE(sdata->nodes); ++count) + sdata->nodes[count].num = TEST_LOOP - count - 1; + + retval = bfdev_slist_selftest(sdata); + free(sdata); + + return retval; +} diff --git a/examples/slist/simple.c b/examples/slist/simple.c new file mode 100644 index 00000000..f3549fb7 --- /dev/null +++ b/examples/slist/simple.c @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#include +#include +#include +#include +#include + +#define TEST_LEN 100 +static BFDEV_SLIST_HEAD(demo_list); + +struct list_simple { + struct bfdev_slist_head list; + unsigned int num; + unsigned long data; +}; + +#define list_to_simple(node) \ + bfdev_slist_entry(node, struct list_simple, slist) + +int main(int argc, const char *argv[]) +{ + struct list_simple *node, *tmp; + unsigned int count; + int retval = 0; + + printf("Generate %d Node:\n", TEST_LEN); + srand(time(NULL)); + for (count = 0; count < TEST_LEN; ++count) { + node = malloc(sizeof(*node)); + if ((retval = !node)) { + printf("insufficient memory\n"); + return 1; + } + + node->num = count; + node->data = ((uint64_t)rand() << 32) | rand(); + bfdev_slist_add(&demo_list, &node->list); + } + + bfdev_slist_for_each_entry(node, &demo_list, list) + printf("\t%04u: 0x%016lx\n", node->num, node->data); + + printf("Deletion All Node...\n"); + bfdev_slist_for_each_entry_safe(node, tmp, &demo_list, list) { + bfdev_slist_del(&demo_list, &node->list); + free(node); + } + + return retval; +} diff --git a/examples/textsearch/.gitignore b/examples/textsearch/.gitignore new file mode 100644 index 00000000..5cb92f02 --- /dev/null +++ b/examples/textsearch/.gitignore @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +/textsearch-simple diff --git a/examples/textsearch/CMakeLists.txt b/examples/textsearch/CMakeLists.txt new file mode 100644 index 00000000..4d6ed99c --- /dev/null +++ b/examples/textsearch/CMakeLists.txt @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Copyright(c) 2023 ffashion +# + +add_executable(textsearch-simple simple.c) +target_link_libraries(textsearch-simple bfdev) +add_test(textsearch-simple textsearch-simple) + +if(${CMAKE_PROJECT_NAME} STREQUAL "bfdev") + install(FILES + simple.c + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/examples/textsearch + ) + + install(TARGETS + textsearch-simple + DESTINATION + ${CMAKE_INSTALL_DOCDIR}/bin + ) +endif() diff --git a/examples/textsearch/simple.c b/examples/textsearch/simple.c new file mode 100644 index 00000000..e49e1fd4 --- /dev/null +++ b/examples/textsearch/simple.c @@ -0,0 +1,85 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2022 John Sanpe + */ + +#include +#include + +#define TEST_STRING "abcceabcaabcd" +#define TEST_PATTERN "abcd" +#define TEST_OFFSET 9 + +int main(int argc, const char *argv[]) +{ + struct bfdev_ts_context *context; + struct bfdev_ts_linear linear; + unsigned int offset; + + printf("test bm algorithm: "); + context = bfdev_textsearch_create( + NULL, "bm", TEST_PATTERN, + sizeof(TEST_PATTERN) - 1, 0 + ); + if (!context) { + printf("failed\n"); + return 1; + } + + offset = bfdev_textsearch_linear_find( + context, &linear, TEST_STRING, + sizeof(TEST_STRING) - 1 + ); + if (offset != TEST_OFFSET) { + printf("failed\n"); + return 1; + } + + printf("passed\n"); + bfdev_textsearch_destroy(context); + + printf("test kmp algorithm: "); + context = bfdev_textsearch_create( + NULL, "kmp", TEST_PATTERN, + sizeof(TEST_PATTERN) - 1, 0 + ); + if (!context) { + printf("failed\n"); + return 1; + } + + offset = bfdev_textsearch_linear_find( + context, &linear, TEST_STRING, + sizeof(TEST_STRING) - 1 + ); + if (offset != TEST_OFFSET) { + printf("failed\n"); + return 1; + } + + printf("passed\n"); + bfdev_textsearch_destroy(context); + + printf("test sunday algorithm: "); + context = bfdev_textsearch_create( + NULL, "sunday", TEST_PATTERN, + sizeof(TEST_PATTERN) - 1, 0 + ); + if (!context) { + printf("failed\n"); + return 1; + } + + offset = bfdev_textsearch_linear_find( + context, &linear, TEST_STRING, + sizeof(TEST_STRING) - 1 + ); + if (offset != TEST_OFFSET) { + printf("failed\n"); + return 1; + } + printf("passed\n"); + bfdev_textsearch_destroy(context); + + return 0; +} diff --git a/examples/time.h b/examples/time.h new file mode 100644 index 00000000..a874f6fd --- /dev/null +++ b/examples/time.h @@ -0,0 +1,63 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#include +#include +#include +#include +#include +#include + +static inline void +time_dump(double ticks, clock_t start, clock_t end, struct tms *stms, struct tms *etms) +{ + bfdev_log_info("\treal time: %lf\n", (end - start) / ticks); + bfdev_log_info("\tuser time: %lf\n", (etms->tms_utime - stms->tms_utime) / ticks); + bfdev_log_info("\tkern time: %lf\n", (etms->tms_stime - stms->tms_stime) / ticks); +} + +#define EXAMPLE_TIME_STATISTICAL(codeblock...) ({ \ + struct tms start_tms, stop_tms; \ + clock_t start, stop; \ + unsigned int ticks; \ + int retval; \ + \ + ticks = sysconf(_SC_CLK_TCK); \ + start = times(&start_tms); \ + \ + retval = ({ \ + codeblock \ + }); \ + \ + stop = times(&stop_tms); \ + time_dump((double)ticks, start, stop, \ + &start_tms, &stop_tms); \ + \ + retval; \ +}) + +#define EXAMPLE_TIME_LOOP(loop, time, codeblock...) ({ \ + struct timeval curr_timval, stop_timval; \ + int retval; \ + \ + gettimeofday(&stop_timval, NULL); \ + stop_timval.tv_sec += (time) / 1000; \ + stop_timval.tv_usec += ((time) % 1000) * 1000; \ + *(loop) = 0; \ + \ + do { \ + retval = ({ \ + codeblock \ + }); \ + \ + if (retval) \ + break; \ + \ + ++*(loop); \ + gettimeofday(&curr_timval, NULL); \ + } while (timercmp(&curr_timval, &stop_timval, <)); \ + \ + retval; \ +}) diff --git a/include/base.h b/include/base.h new file mode 100644 index 00000000..ae139221 --- /dev/null +++ b/include/base.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#ifndef _LOCAL_BASE_H_ +#define _LOCAL_BASE_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#endif /* _LOCAL_BASE_H_ */ diff --git a/include/bfdev/action.h b/include/bfdev/action.h new file mode 100644 index 00000000..c3210d7d --- /dev/null +++ b/include/bfdev/action.h @@ -0,0 +1,82 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#ifndef _BFDEV_ACTION_H_ +#define _BFDEV_ACTION_H_ + +#include +#include +#include +#include + +BFDEV_BEGIN_DECLS + +typedef int +(*bfdev_action_func_t)(void *data); + +struct bfdev_action { + bfdev_action_func_t func; + const void *data; +}; + +#define BFDEV_ACTION_STATIC(FUNC, DATA) { \ + .func = (FUNC), .data = (DATA), \ +} + +#define BFDEV_ACTION_INIT(func, data) \ + (struct bfdev_action) BFDEV_ACTION_STATIC(func, data) + +#define BFDEV_DEFINE_ACTION(name, func, data) \ + struct bfdev_action name = BFDEV_ACTION_INIT(func, data) + +/** + * bfdev_action_init - initialize action. + * @action: the action pointer. + * @func: function to callback. + * @data: callback data of @func. + */ +static inline void +bfdev_action_init(struct bfdev_action *action, + bfdev_action_func_t func, const void *data) +{ + *action = BFDEV_ACTION_INIT(func, data); +} + +/** + * bfdev_action_update - update action data. + * @action: the action pointer. + * @data: the data to update. + */ +static inline void +bfdev_action_update(struct bfdev_action *action, const void *data) +{ + action->data = data; +} + +/** + * bfdev_action_clear - clear action callback. + * @action: the action pointer. + */ +static inline void +bfdev_action_clear(struct bfdev_action *action) +{ + action->func = NULL; +} + +/** + * bfdev_action_call - callback an action. + * @action: the action pointer. + */ +static inline int +bfdev_action_call(struct bfdev_action *action) +{ + if (bfdev_likely(action->func)) + return action->func((void *)action->data); + return -BFDEV_ENODATA; +} + +BFDEV_END_DECLS + +#endif /* _BFDEV_ACTION_H_ */ diff --git a/include/bfdev/align.h b/include/bfdev/align.h new file mode 100644 index 00000000..74bd2c58 --- /dev/null +++ b/include/bfdev/align.h @@ -0,0 +1,63 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#ifndef _BFDEV_ALIGN_H_ +#define _BFDEV_ALIGN_H_ + +#include +#include +#include + +BFDEV_BEGIN_DECLS + +/** + * align_low/high - aligned value. + * @size: value to aligned. + * @align: alignment size. + */ +#define bfdev_align_low(size, align) ({ \ + (size) & ~((align) - 1); \ +}) + +#define bfdev_align_high(size, align) ({ \ + typeof(align) _align = (align); \ + ((size) + (_align - 1)) & ~(_align - 1); \ +}) + +#define bfdev_align_ptr_low(ptr, align) ({ \ + (typeof(ptr))bfdev_align_low((uintptr_t)(ptr), align); \ +}) + +#define bfdev_align_ptr_high(ptr, align) ({ \ + (typeof(ptr))bfdev_align_high((uintptr_t)(ptr), align); \ +}) + +#define bfdev_align_low_adj(size, align) ({ \ + (size) = bfdev_align_low(size, align); \ +}) + +#define bfdev_align_high_adj(size, align) ({ \ + (size) = bfdev_align_high(size, align); \ +}) + +#define bfdev_align_ptr_low_adj(ptr, align) ({ \ + (ptr) = bfdev_align_ptr_low(ptr, align); \ +}) + +#define bfdev_align_ptr_high_adj(ptr, align) ({ \ + (ptr) = bfdev_align_ptr_high(ptr, align); \ +}) + +#define bfdev_align_check(size, align) ( \ + !((size) & ((align) - 1)) \ +) + +#define bfdev_align_ptr_check(ptr, align) ( \ + bfdev_align_check((uintptr_t)(ptr), align) \ +) + +BFDEV_END_DECLS + +#endif /* _BFDEV_ALIGN_H_ */ diff --git a/include/bfdev/alloca.h b/include/bfdev/alloca.h new file mode 100644 index 00000000..89718b22 --- /dev/null +++ b/include/bfdev/alloca.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#ifndef _BFDEV_ALLOCA_H_ +#define _BFDEV_ALLOCA_H_ + +#include +#include + +BFDEV_BEGIN_DECLS + +#define bfdev_alloca __builtin_alloca +extern __bfdev_malloc void *bfdev_alloca(unsigned long size); + +BFDEV_END_DECLS + +#endif /* _BFDEV_ALLOCA_H_ */ diff --git a/include/bfdev/allocator.h b/include/bfdev/allocator.h new file mode 100644 index 00000000..8243fe48 --- /dev/null +++ b/include/bfdev/allocator.h @@ -0,0 +1,104 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 ffashion + * Copyright(c) 2023 John Sanpe + */ + +#ifndef _BFDEV_ALLOCATOR_H_ +#define _BFDEV_ALLOCATOR_H_ + +#include +#include +#include +#include + +BFDEV_BEGIN_DECLS + +struct bfdev_alloc { + const struct bfdev_alloc_ops *ops; + void *pdata; +}; + +struct bfdev_alloc_ops { + bfdev_alloc_t alloc; + bfdev_realloc_t realloc; + bfdev_free_t free; +}; + +#define BFDEV_ALLOC_OPS_STATIC(ALLOC, REALLOC, FREE) \ + {.alloc = (ALLOC), .realloc = (REALLOC), .free = (FREE)} + +#define BFDEV_ALLOC_OPS_INIT(alloc, realloc, free) \ + (struct bfdev_alloc_ops) BFDEV_ALLOC_OPS_STATIC(alloc, realloc, free) + +#define BFDEV_DEFINE_ALLOC_OPS(name, alloc, realloc, free) \ + struct bfdev_alloc_ops name = BFDEV_ALLOC_OPS_INIT(alloc, realloc, free) + +#define BFDEV_ALLOC_STATIC(ALLOC, REALLOC, FREE, PDATA) \ + {.ops = &BFDEV_ALLOC_OPS_INIT(ALLOC, REALLOC, FREE), .pdata = (PDATA)} + +#define BFDEV_ALLOC_INIT(alloc, realloc, free, pdata) \ + (struct bfdev_alloc) BFDEV_ALLOC_STATIC(alloc, realloc, free, pdata) + +#define BFDEV_DEFINE_ALLOC(name, alloc, realloc, free, pdata) \ + struct bfdev_alloc name = BFDEV_ALLOC_INIT(alloc, realloc, free, pdata) + +static inline void +bfdev_alloc_init(struct bfdev_alloc *allocator, bfdev_alloc_t alloc, + bfdev_realloc_t realloc, bfdev_free_t free, void *pdata) +{ + *allocator = BFDEV_ALLOC_INIT(alloc, realloc, free, pdata); +} + +extern __bfdev_malloc void * +bfdev_malloc(const struct bfdev_alloc *alloc, size_t size); + +extern __bfdev_malloc void * +bfdev_zalloc(const struct bfdev_alloc *alloc, size_t size); + +extern __bfdev_malloc void * +bfdev_realloc(const struct bfdev_alloc *alloc, const void *block, size_t resize); + +extern void +bfdev_free(const struct bfdev_alloc *alloc, const void *block); + +/** + * bfdev_malloc_array - allocate memory for an array. + * @nr: number of elements. + * @size: single element size. + */ +static __bfdev_always_inline __bfdev_malloc void * +bfdev_malloc_array(const struct bfdev_alloc *alloc, + size_t nr, size_t size) +{ + return bfdev_malloc(alloc, size * nr); +} + +/** + * bfdev_zalloc_array - zero allocate memory for an array. + * @nr: number of elements. + * @size: single element size. + */ +static __bfdev_always_inline __bfdev_malloc void * +bfdev_zalloc_array(const struct bfdev_alloc *alloc, + size_t nr, size_t size) +{ + return bfdev_zalloc(alloc, size * nr); +} + +/** + * bfdev_realloc_array - reallocate memory for an array. + * @block: number of elements. + * @nr: number of elements. + * @size: single element size. + */ +static __bfdev_always_inline __bfdev_malloc void * +bfdev_realloc_array(const struct bfdev_alloc *alloc, + void *block, size_t nr, size_t size) +{ + return bfdev_realloc(alloc, block, size * nr); +} + +BFDEV_END_DECLS + +#endif /* _BFDEV_ALLOCATOR_H_ */ diff --git a/include/bfdev/allocpool.h b/include/bfdev/allocpool.h new file mode 100644 index 00000000..1012f912 --- /dev/null +++ b/include/bfdev/allocpool.h @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#ifndef _BFDEV_ALLOCPOOL_H_ +#define _BFDEV_ALLOCPOOL_H_ + +#include +#include +#include + +BFDEV_BEGIN_DECLS + +struct bfdev_allocpool { + void *block; + size_t size; + uintptr_t last; + unsigned long count; +}; + +#define BFDEV_ALLOCPOOL_STATIC(BLOCK, SIZE) \ + {.block = (BLOCK), .size = (SIZE)} + +#define BFDEV_ALLOCPOOL_INIT(block, size) \ + (struct bfdev_allocpool) BFDEV_ALLOCPOOL_STATIC(block, size) + +#define BFDEV_DEFINE_ALLOCPOOL(name, block, size) \ + struct bfdev_allocpool name = BFDEV_ALLOCPOOL_INIT(block, size) + +/** + * bfdev_allocpool_init() - Allocation mempool initialize. + * @pool: minimum mempool to initialize. + * @array: mempool array address. + * @size: mempool array size. + */ +static inline void +bfdev_allocpool_init(struct bfdev_allocpool *pool, void *block, size_t size) +{ + *pool = BFDEV_ALLOCPOOL_INIT(block, size); +} + +/** + * bfdev_allocpool_alloc() - Allocation mempool allocation. + * @pool: minimum mempool to alloc. + * @size: size to allocation. + * @align: align to allocation. + */ +extern void * +bfdev_allocpool_alloc(struct bfdev_allocpool *pool, size_t size, size_t align); + +/** + * bfdev_allocpool_free() - Allocation mempool free. + * @pool: minimum mempool to free. + * @block: memory block to free. + */ +extern void +bfdev_allocpool_free(struct bfdev_allocpool *pool, const char *block); + +BFDEV_END_DECLS + +#endif /* _BFDEV_ALLOCPOOL_H_ */ diff --git a/include/bfdev/argv.h b/include/bfdev/argv.h new file mode 100644 index 00000000..867eec2a --- /dev/null +++ b/include/bfdev/argv.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#ifndef _BFDEV_ARGV_H_ +#define _BFDEV_ARGV_H_ + +#include +#include + +BFDEV_BEGIN_DECLS + +extern unsigned int +bfdev_argv_count(const char *string); + +/** + * bfdev_argv_split() - split a string at whitespace, returning an argv. + * @alloc: the allocator used to allocate memory. + * @string: the string to be split. + * @argcp: returned argument count. + */ +extern char ** +bfdev_argv_split(const struct bfdev_alloc *alloc, + const char *string, unsigned int *argcp); + +/** + * bfdev_argv_destory() - destory an argv. + * @alloc: the allocator used to free memory. + * @argv: the argument vector to be freed. + */ +extern void +bfdev_argv_destory(const struct bfdev_alloc *alloc, + char **argv); + +BFDEV_END_DECLS + +#endif /* _BFDEV_ARGV_H_ */ diff --git a/include/bfdev/array.h b/include/bfdev/array.h new file mode 100644 index 00000000..2814c304 --- /dev/null +++ b/include/bfdev/array.h @@ -0,0 +1,88 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 ffashion + * Copyright(c) 2023 John Sanpe + */ + +#ifndef _BFDEV_ARRAY_H_ +#define _BFDEV_ARRAY_H_ + +#include +#include +#include +#include + +BFDEV_BEGIN_DECLS + +#ifndef BFDEV_ARRAY_MSIZE +# define BFDEV_ARRAY_MSIZE 32 +#endif + +struct bfdev_array { + const struct bfdev_alloc *alloc; + unsigned int capacity; + unsigned int index; + size_t cells; + void *data; +}; + +#define BFDEV_ARRAY_STATIC(ALLOC, CELLS) \ + {.alloc = (ALLOC), .cells = (CELLS)} + +#define BFDEV_ARRAY_INIT(alloc, cells) \ + (struct bfdev_array) BFDEV_ARRAY_STATIC(alloc, cells) + +#define BFDEV_DEFINE_ARRAY(name, alloc, cells) \ + struct bfdev_array name = BFDEV_ARRAY_INIT(alloc, cells) + +static inline void +bfdev_array_init(struct bfdev_array *array, const struct bfdev_alloc *alloc, + size_t cells) +{ + *array = BFDEV_ARRAY_INIT(alloc, cells); +} + +static inline void +bfdev_array_reset(struct bfdev_array *array) +{ + array->index = 0; +} + +static inline unsigned int +bfdev_array_index(struct bfdev_array *array) +{ + return array->index; +} + +static inline size_t +bfdev_array_size(struct bfdev_array *array) +{ + return array->cells * array->index; +} + +static inline uintptr_t +bfdev_array_offset(struct bfdev_array *array, unsigned int index) +{ + return array->cells * index; +} + +static inline void * +bfdev_array_data(struct bfdev_array *array, unsigned int index) +{ + if (bfdev_unlikely(index >= array->index)) + return NULL; + return array->data + bfdev_array_offset(array, index); +} + +extern void * +bfdev_array_push(struct bfdev_array *array, unsigned int num); + +extern void * +bfdev_array_pop(struct bfdev_array *array, unsigned int num); + +extern void +bfdev_array_release(struct bfdev_array *array); + +BFDEV_END_DECLS + +#endif /*_BFDEV_ARRAY_H_*/ diff --git a/include/bfdev/ascii.h b/include/bfdev/ascii.h new file mode 100644 index 00000000..f14d5a28 --- /dev/null +++ b/include/bfdev/ascii.h @@ -0,0 +1,43 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#ifndef _BFDEV_ASCII_H_ +#define _BFDEV_ASCII_H_ + +#define BFDEV_ASCII_NUL 0x00 /* Null Char */ +#define BFDEV_ASCII_SOH 0x01 /* Start Of Heading */ +#define BFDEV_ASCII_STX 0x02 /* Start Of Text */ +#define BFDEV_ASCII_ETX 0x03 /* End Of Text */ +#define BFDEV_ASCII_EOT 0x04 /* End Of Transmission */ +#define BFDEV_ASCII_ENQ 0x05 /* Enquiry */ +#define BFDEV_ASCII_ACK 0x06 /* Acknowledgment */ +#define BFDEV_ASCII_BEL 0x07 /* Bell */ +#define BFDEV_ASCII_BS 0x08 /* Back Space */ +#define BFDEV_ASCII_HT 0x09 /* Horizontal Tab */ +#define BFDEV_ASCII_LF 0x0a /* Line Feed */ +#define BFDEV_ASCII_VT 0x0b /* Vertical Tab */ +#define BFDEV_ASCII_FF 0x0c /* Form Feed */ +#define BFDEV_ASCII_CR 0x0d /* Carriage Return */ +#define BFDEV_ASCII_SO 0x0e /* Shift Out / X-On */ +#define BFDEV_ASCII_SI 0x0f /* Shift In / X-Off */ +#define BFDEV_ASCII_DLE 0x10 /* Data Line Escape */ +#define BFDEV_ASCII_DC1 0x11 /* Device Control 1 (Oft. Xon) */ +#define BFDEV_ASCII_DC2 0x12 /* Device Control 2 */ +#define BFDEV_ASCII_DC3 0x13 /* Device Control 3 (Oft. Xoff) */ +#define BFDEV_ASCII_DC4 0x14 /* Device Control 4 */ +#define BFDEV_ASCII_NAK 0x15 /* Negative Acknowledgement */ +#define BFDEV_ASCII_SYN 0x16 /* Synchronous Idle */ +#define BFDEV_ASCII_ETB 0x17 /* End Of Transmit Block */ +#define BFDEV_ASCII_CAN 0x18 /* Cancel */ +#define BFDEV_ASCII_EM 0x19 /* End Of Medium */ +#define BFDEV_ASCII_SUB 0x1a /* Substitute */ +#define BFDEV_ASCII_ESC 0x1b /* Escape */ +#define BFDEV_ASCII_FS 0x1c /* File Separator */ +#define BFDEV_ASCII_GS 0x1d /* Group Separator */ +#define BFDEV_ASCII_RS 0x1e /* Record Separator */ +#define BFDEV_ASCII_US 0x1f /* Unit Separator */ +#define BFDEV_ASCII_DEL 0x7f /* Delete */ + +#endif /* _BFDEV_ASCII_H_ */ diff --git a/include/bfdev/ascii85.h b/include/bfdev/ascii85.h new file mode 100644 index 00000000..e79a014a --- /dev/null +++ b/include/bfdev/ascii85.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#ifndef _BFDEV_ASCII85_H_ +#define _BFDEV_ASCII85_H_ + +#include +#include +#include +#include + +BFDEV_BEGIN_DECLS + +extern void +bfdev_ascii85_encode(void *buff, const void *data, size_t size); + +extern int +bfdev_ascii85_decode(void *buff, const void *data, size_t size); + +extern size_t +bfdev_ascii85_encode_length(const void *data, size_t size); + +extern size_t +bfdev_ascii85_decode_length(const void *data, size_t size); + +BFDEV_END_DECLS + +#endif /* _CRYPTO_ASCII85_H_ */ diff --git a/include/bfdev/asm-generic/atomic.h b/include/bfdev/asm-generic/atomic.h new file mode 100644 index 00000000..c1358716 --- /dev/null +++ b/include/bfdev/asm-generic/atomic.h @@ -0,0 +1,81 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#ifndef _BFDEV_ASM_GENERIC_ATOMIC_H_ +#define _BFDEV_ASM_GENERIC_ATOMIC_H_ + +#include +#include +#include + +BFDEV_BEGIN_DECLS + +#define bfdev_arch_atomic_read bfdev_arch_atomic_read +static __bfdev_always_inline bfdev_atomic_t +bfdev_arch_atomic_read(const bfdev_atomic_t *atomic) +{ + return BFDEV_READ_ONCE(*atomic); +} + +#define bfdev_arch_atomic_write bfdev_arch_atomic_write +static __bfdev_always_inline void +bfdev_arch_atomic_write(bfdev_atomic_t *atomic, bfdev_atomic_t value) +{ + BFDEV_WRITE_ONCE(*atomic, value); +} + +#define BFDEV_GENERIC_ATOMIC(name, func) \ +static __bfdev_always_inline void \ +bfdev_arch_atomic_##name(bfdev_atomic_t *atomic, bfdev_atomic_t value) \ +{ \ + (void)func(atomic, value); \ +} + +#define BFDEV_GENERIC_ATOMIC_FETCH(name, func) \ +static __bfdev_always_inline bfdev_atomic_t \ +bfdev_arch_atomic_##name(bfdev_atomic_t *atomic, bfdev_atomic_t value) \ +{ \ + return func(atomic, value); \ +} + +#define bfdev_arch_atomic_add bfdev_arch_atomic_add +#define bfdev_arch_atomic_sub bfdev_arch_atomic_sub +#define bfdev_arch_atomic_and bfdev_arch_atomic_and +#define bfdev_arch_atomic_or bfdev_arch_atomic_or +#define bfdev_arch_atomic_xor bfdev_arch_atomic_xor + +BFDEV_GENERIC_ATOMIC(add, __sync_fetch_and_add) +BFDEV_GENERIC_ATOMIC(sub, __sync_fetch_and_sub) +BFDEV_GENERIC_ATOMIC(and, __sync_fetch_and_and) +BFDEV_GENERIC_ATOMIC(or, __sync_fetch_and_or) +BFDEV_GENERIC_ATOMIC(xor, __sync_fetch_and_xor) + +#define bfdev_arch_atomic_fetch_add bfdev_arch_atomic_fetch_add +#define bfdev_arch_atomic_fetch_sub bfdev_arch_atomic_fetch_sub +#define bfdev_arch_atomic_fetch_and bfdev_arch_atomic_fetch_and +#define bfdev_arch_atomic_fetch_or bfdev_arch_atomic_fetch_or +#define bfdev_arch_atomic_fetch_xor bfdev_arch_atomic_fetch_xor + +BFDEV_GENERIC_ATOMIC_FETCH(fetch_add, __sync_fetch_and_add) +BFDEV_GENERIC_ATOMIC_FETCH(fetch_sub, __sync_fetch_and_sub) +BFDEV_GENERIC_ATOMIC_FETCH(fetch_and, __sync_fetch_and_and) +BFDEV_GENERIC_ATOMIC_FETCH(fetch_or, __sync_fetch_and_or) +BFDEV_GENERIC_ATOMIC_FETCH(fetch_xor, __sync_fetch_and_xor) + +#define bfdev_arch_atomic_add_fetch bfdev_arch_atomic_add_fetch +#define bfdev_arch_atomic_sub_fetch bfdev_arch_atomic_sub_fetch +#define bfdev_arch_atomic_and_fetch bfdev_arch_atomic_and_fetch +#define bfdev_arch_atomic_or_fetch bfdev_arch_atomic_or_fetch +#define bfdev_arch_atomic_xor_fetch bfdev_arch_atomic_xor_fetch + +BFDEV_GENERIC_ATOMIC_FETCH(add_fetch, __sync_add_and_fetch) +BFDEV_GENERIC_ATOMIC_FETCH(sub_fetch, __sync_sub_and_fetch) +BFDEV_GENERIC_ATOMIC_FETCH(and_fetch, __sync_and_and_fetch) +BFDEV_GENERIC_ATOMIC_FETCH(or_fetch, __sync_or_and_fetch) +BFDEV_GENERIC_ATOMIC_FETCH(xor_fetch, __sync_xor_and_fetch) + +BFDEV_END_DECLS + +#endif /* _BFDEV_ASM_GENERIC_ATOMIC_H_ */ diff --git a/include/bfdev/asm-generic/bitops.h b/include/bfdev/asm-generic/bitops.h new file mode 100644 index 00000000..b4658fe3 --- /dev/null +++ b/include/bfdev/asm-generic/bitops.h @@ -0,0 +1,582 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#ifndef _BFDEV_ASM_GENERIC_BITOPS_H_ +#define _BFDEV_ASM_GENERIC_BITOPS_H_ + +#include +#include +#include +#include +#include + +BFDEV_BEGIN_DECLS + +#ifndef bfdev_arch_bit_clr +static __bfdev_always_inline void +bfdev_arch_bit_clr(volatile unsigned long *addr, unsigned int bit) +{ + addr += BFDEV_BITS_WORD(bit); + *addr &= ~BFDEV_BIT(bit); +} +#endif + +#ifndef bfdev_arch_bit_set +static __bfdev_always_inline void +bfdev_arch_bit_set(volatile unsigned long *addr, unsigned int bit) +{ + addr += BFDEV_BITS_WORD(bit); + *addr |= BFDEV_BIT(bit); +} +#endif + +#ifndef bfdev_arch_bit_flip +static __bfdev_always_inline void +bfdev_arch_bit_flip(volatile unsigned long *addr, unsigned int bit) +{ + addr += BFDEV_BITS_WORD(bit); + *addr ^= BFDEV_BIT(bit); +} +#endif + +#ifndef bfdev_arch_bit_change +static __bfdev_always_inline void +bfdev_arch_bit_change(volatile unsigned long *addr, unsigned int bit, bool val) +{ + addr += BFDEV_BITS_WORD(bit); + if (val) + *addr |= BFDEV_BIT(bit); + else + *addr &= ~BFDEV_BIT(bit); +} +#endif + +#ifndef bfdev_arch_bit_test +static __bfdev_always_inline bool +bfdev_arch_bit_test(const volatile unsigned long *addr, unsigned int bit) +{ + addr += BFDEV_BITS_WORD(bit); + return !!(*addr & BFDEV_BIT(bit)); +} +#endif + +#ifndef bfdev_arch_bit_test_clr +static __bfdev_always_inline bool +bfdev_arch_bit_test_clr(volatile unsigned long *addr, unsigned int bit) +{ + unsigned long old; + addr += BFDEV_BITS_WORD(bit); + old = *addr; + *addr &= ~BFDEV_BIT(bit); + return !!(old & BFDEV_BIT(bit)); +} +#endif + +#ifndef bfdev_arch_bit_test_set +static __bfdev_always_inline bool +bfdev_arch_bit_test_set(volatile unsigned long *addr, unsigned int bit) +{ + unsigned long old; + addr += BFDEV_BITS_WORD(bit); + old = *addr; + *addr |= BFDEV_BIT(bit); + return !!(old & BFDEV_BIT(bit)); +} +#endif + +#ifndef bfdev_arch_bit_test_flip +static __bfdev_always_inline bool +bfdev_arch_bit_test_flip(volatile unsigned long *addr, unsigned int bit) +{ + unsigned long old; + addr += BFDEV_BITS_WORD(bit); + old = *addr; + *addr ^= BFDEV_BIT(bit); + return !!(old & BFDEV_BIT(bit)); +} +#endif + +#ifndef bfdev_arch_bit_test_change +static __bfdev_always_inline bool +bfdev_arch_bit_test_change(volatile unsigned long *addr, unsigned int bit, bool val) +{ + unsigned long old; + addr += BFDEV_BITS_WORD(bit); + old = *addr; + if (val) + *addr |= BFDEV_BIT(bit); + else + *addr &= ~BFDEV_BIT(bit); + return !!(old & BFDEV_BIT(bit)); +} +#endif + +#ifndef bfdev_arch_bit_atomic_clr +static __bfdev_always_inline void +bfdev_arch_bit_atomic_clr(volatile unsigned long *addr, unsigned int bit) +{ + addr += BFDEV_BITS_WORD(bit); + bfdev_arch_atomic_and((bfdev_atomic_t *)addr, ~BFDEV_BIT(bit)); +} +#endif + +#ifndef bfdev_arch_bit_atomic_set +static __bfdev_always_inline void +bfdev_arch_bit_atomic_set(volatile unsigned long *addr, unsigned int bit) +{ + addr += BFDEV_BITS_WORD(bit); + bfdev_arch_atomic_or((bfdev_atomic_t *)addr, BFDEV_BIT(bit)); +} +#endif + +#ifndef bfdev_arch_bit_atomic_flip +static __bfdev_always_inline void +bfdev_arch_bit_atomic_flip(volatile unsigned long *addr, unsigned int bit) +{ + addr += BFDEV_BITS_WORD(bit); + bfdev_arch_atomic_xor((bfdev_atomic_t *)addr, BFDEV_BIT(bit)); +} +#endif + +#ifndef bfdev_arch_bit_atomic_change +static __bfdev_always_inline void +bfdev_arch_bit_atomic_change(volatile unsigned long *addr, unsigned int bit, bool val) +{ + addr += BFDEV_BITS_WORD(bit); + if (val) + bfdev_arch_atomic_or((bfdev_atomic_t *)addr, BFDEV_BIT(bit)); + else + bfdev_arch_atomic_and((bfdev_atomic_t *)addr, ~BFDEV_BIT(bit)); +} +#endif + +#ifndef bfdev_arch_bit_atomic_test +static __bfdev_always_inline bool +bfdev_arch_bit_atomic_test(const volatile unsigned long *addr, unsigned int bit) +{ + addr += BFDEV_BITS_WORD(bit); + return !!(bfdev_arch_atomic_read((bfdev_atomic_t *)addr) & BFDEV_BIT(bit)); +} +#endif + +#ifndef bfdev_arch_bit_atomic_test_clr +static __bfdev_always_inline bool +bfdev_arch_bit_atomic_test_clr(volatile unsigned long *addr, unsigned int bit) +{ + unsigned long old; + + addr += BFDEV_BITS_WORD(bit); + if ((BFDEV_READ_ONCE(*addr) & BFDEV_BIT(bit)) == 0) + return 0; + + old = bfdev_arch_atomic_fetch_and((bfdev_atomic_t *)addr, ~BFDEV_BIT(bit)); + return !!(old & BFDEV_BIT(bit)); +} +#endif + +#ifndef bfdev_arch_bit_atomic_test_set +static __bfdev_always_inline bool +bfdev_arch_bit_atomic_test_set(volatile unsigned long *addr, unsigned int bit) +{ + unsigned long old; + + addr += BFDEV_BITS_WORD(bit); + if ((BFDEV_READ_ONCE(*addr) & BFDEV_BIT(bit)) != 0) + return 1; + + old = bfdev_arch_atomic_fetch_or((bfdev_atomic_t *)addr, BFDEV_BIT(bit)); + return !!(old & BFDEV_BIT(bit)); +} +#endif + +#ifndef bfdev_arch_bit_atomic_test_flip +static __bfdev_always_inline bool +bfdev_arch_bit_atomic_test_flip(volatile unsigned long *addr, unsigned int bit) +{ + unsigned long old; + addr += BFDEV_BITS_WORD(bit); + old = bfdev_arch_atomic_fetch_xor((bfdev_atomic_t *)addr, BFDEV_BIT(bit)); + return !!(old & BFDEV_BIT(bit)); +} +#endif + +#ifndef bfdev_arch_bit_atomic_test_change +static __bfdev_always_inline bool +bfdev_arch_bit_atomic_test_change(volatile unsigned long *addr, unsigned int bit, bool val) +{ + unsigned long old; + addr += BFDEV_BITS_WORD(bit); + if (val) + old = bfdev_arch_atomic_fetch_or((bfdev_atomic_t *)addr, BFDEV_BIT(bit)); + else + old = bfdev_arch_atomic_fetch_and((bfdev_atomic_t *)addr, ~BFDEV_BIT(bit)); + return !!(old & BFDEV_BIT(bit)); +} +#endif + +/** + * bfdev_arch_rol8 - rotate an 8-bit value left. + * @value: value to rotate. + * @shift: bits to roll. + */ +#ifndef bfdev_arch_rol8 +static __bfdev_always_inline uint8_t +bfdev_arch_rol8(uint8_t value, unsigned int shift) +{ + return (value << (shift & 7)) | (value >> ((-shift) & 7)); +} +#endif + +/** + * bfdev_arch_ror8 - rotate an 8-bit value right. + * @value: value to rotate. + * @shift: bits to roll. + */ +#ifndef bfdev_arch_ror8 +static __bfdev_always_inline uint8_t +bfdev_arch_ror8(uint8_t value, unsigned int shift) +{ + return (value >> (shift & 7)) | (value << ((-shift) & 7)); +} +#endif + +/** + * bfdev_arch_rol16 - rotate a 16-bit value left. + * @value: value to rotate. + * @shift: bits to roll. + */ +#ifndef bfdev_arch_rol16 +static __bfdev_always_inline uint16_t +bfdev_arch_rol16(uint16_t value, unsigned int shift) +{ + return (value << (shift & 15)) | (value >> ((-shift) & 15)); +} +#endif + +/** + * bfdev_arch_ror16 - rotate a 16-bit value right. + * @value: value to rotate. + * @shift: bits to roll. + */ +#ifndef bfdev_arch_ror16 +static __bfdev_always_inline uint16_t +bfdev_arch_ror16(uint16_t value, unsigned int shift) +{ + return (value >> (shift & 15)) | (value << ((-shift) & 15)); +} +#endif + +/** + * bfdev_arch_rol32 - rotate a 32-bit value left. + * @value: value to rotate. + * @shift: bits to roll. + */ +#ifndef bfdev_arch_rol32 +static __bfdev_always_inline uint32_t +bfdev_arch_rol32(uint32_t value, unsigned int shift) +{ + return (value << (shift & 31)) | (value >> ((-shift) & 31)); +} +#endif + +/** + * bfdev_arch_ror32 - rotate a 32-bit value right. + * @value: value to rotate. + * @shift: bits to roll. + */ +#ifndef bfdev_arch_ror32 +static __bfdev_always_inline uint32_t +bfdev_arch_ror32(uint32_t value, unsigned int shift) +{ + return (value >> (shift & 31)) | (value << ((-shift) & 31)); +} +#endif + +/** + * bfdev_arch_rol64 - rotate a 64-bit value left. + * @value: value to rotate. + * @shift: bits to roll. + */ +#ifndef bfdev_arch_rol64 +static __bfdev_always_inline uint64_t +bfdev_arch_rol64(uint64_t value, unsigned int shift) +{ + return (value << (shift & 63)) | (value >> ((-shift) & 63)); +} +#endif + +/** + * bfdev_arch_ror64 - rotate a 64-bit value right. + * @value: value to rotate. + * @shift: bits to roll. + */ +#ifndef bfdev_arch_ror64 +static __bfdev_always_inline uint64_t +bfdev_arch_ror64(uint64_t value, unsigned int shift) +{ + return (value >> (shift & 63)) | (value << ((-shift) & 63)); +} +#endif + +/** + * bfdev_arch_ffsuf - find first set bit in word (unsafe). + * @val: The word to search. + * Undefined if no bit exists, so code should check against 0 first.. + */ +#ifndef bfdev_arch_ffsuf +static __bfdev_always_inline unsigned int +bfdev_arch_ffsuf(unsigned long value) +{ + unsigned int shift = 0; + +#if BFDEV_BITS_PER_LONG == 64 + if ((value & 0xffffffff) == 0) { + shift += 32; + value >>= 32; + } +#endif + + if ((value & 0xffff) == 0) { + shift += 16; + value >>= 16; + } + + if ((value & 0xff) == 0) { + shift += 8; + value >>= 8; + } + + if ((value & 0xf) == 0) { + shift += 4; + value >>= 4; + } + + if ((value & 0x3) == 0) { + shift += 2; + value >>= 2; + } + + if ((value & 0x1) == 0) { + shift += 1; + } + + return shift; +} +#endif + +/* + * bfdev_arch_flsuf: find last set bit in word (unsafe). + * @val: The word to search. + * Undefined if no set bit exists, so code should check against 0 first.. + */ +#ifndef bfdev_arch_flsuf +static __bfdev_always_inline unsigned int +bfdev_arch_flsuf(unsigned long value) +{ + unsigned int shift = BFDEV_BITS_PER_LONG - 1; + +#if BFDEV_BITS_PER_LONG == 64 + if (!(value & (~0ul << 32))) { + shift -= 32; + value <<= 32; + } +#endif + + if (!(value & (~0ul << (BFDEV_BITS_PER_LONG - 16)))) { + shift -= 16; + value <<= 16; + } + if (!(value & (~0ul << (BFDEV_BITS_PER_LONG - 8)))) { + shift -= 8; + value <<= 8; + } + if (!(value & (~0ul << (BFDEV_BITS_PER_LONG - 4)))) { + shift -= 4; + value <<= 4; + } + if (!(value & (~0ul << (BFDEV_BITS_PER_LONG - 2)))) { + shift -= 2; + value <<= 2; + } + if (!(value & (~0ul << (BFDEV_BITS_PER_LONG - 1)))) + shift -= 1; + + return shift; +} +#endif + +/* + * bfdev_arch_ffzuf - find first zero in word (unsafe). + * @word: The word to search. + * Undefined if no zero exists, so code should check against ~0UL first.. + */ +#ifndef bfdev_arch_ffzuf +static __bfdev_always_inline unsigned int +bfdev_arch_ffzuf(unsigned long value) +{ + return bfdev_arch_ffsuf(~value); +} +#endif + +/* + * bfdev_arch_flzuf - find last zero in word (unsafe). + * @word: The word to search. + * Undefined if no zero exists, so code should check against ~0UL first.. + */ +#ifndef bfdev_arch_flzuf +static __bfdev_always_inline unsigned int +bfdev_arch_flzuf(unsigned long value) +{ + return bfdev_arch_flsuf(~value); +} +#endif + +/** + * bfdev_arch_ffs - find first bit set. + * @value: the word to search. + */ +#ifndef bfdev_arch_ffs +static __bfdev_always_inline unsigned int +bfdev_arch_ffs(unsigned long value) +{ + if (!value) + return 0; + return bfdev_arch_ffsuf(value) + 1; +} +#endif + +/** + * bfdev_arch_fls - find last zero in word. + * @value: the word to search. + */ +#ifndef bfdev_arch_fls +static __bfdev_always_inline unsigned int +bfdev_arch_fls(unsigned long value) +{ + if (!value) + return 0; + return bfdev_arch_flsuf(value) + 1; +} +#endif + +/* + * bfdev_arch_ffz - find first zero in word. + * @value: The word to search. + */ +#ifndef bfdev_arch_ffz +static __bfdev_always_inline unsigned int +bfdev_arch_ffz(unsigned long value) +{ + if (value == ULONG_MAX) + return 0; + return bfdev_arch_ffs(~value); +} +#endif + +/* + * bfdev_arch_flz - find last zero in word. + * @value: The word to search. + */ +#ifndef bfdev_arch_flz +static __bfdev_always_inline unsigned int +bfdev_arch_flz(unsigned long value) +{ + if (value == ULONG_MAX) + return 0; + return bfdev_arch_fls(~value); +} +#endif + +/* + * bfdev_arch_ctz - returns the number of trailing 0-bits in value. + * @value: The word to search. + */ +#ifndef bfdev_arch_ctz +static __bfdev_always_inline unsigned int +bfdev_arch_ctz(unsigned long value) +{ + if (value == ULONG_MAX) + return 0; + if (!value) + return BFDEV_BITS_PER_LONG; + return bfdev_arch_ffsuf(value); +} +#endif + +/* + * bfdev_arch_clz - returns the number of leading 0-bits in value. + * @value: The word to search. + */ +#ifndef bfdev_arch_clz +static __bfdev_always_inline unsigned int +bfdev_arch_clz(unsigned long value) +{ + if (value == ULONG_MAX) + return 0; + if (!value) + return BFDEV_BITS_PER_LONG; + return BFDEV_BITS_PER_LONG - 1 - bfdev_arch_flsuf(value); +} +#endif + +#ifndef bfdev_arch_ffns +static __bfdev_always_inline unsigned int +bfdev_arch_ffnsp(unsigned long word, unsigned int *nr) +{ + unsigned int bit; + + if (word == ULONG_MAX) + return *nr; + + while (word) { + bit = bfdev_arch_ffsuf(word); + if (!(*nr)--) + return bit; + bfdev_arch_bit_clr(&word, bit); + } + + return BFDEV_BITS_PER_LONG; +} +#endif + +#ifndef bfdev_arch_flns +static __bfdev_always_inline unsigned int +bfdev_arch_flnsp(unsigned long word, unsigned int *nr) +{ + unsigned int bit; + + if (word == ULONG_MAX) + return *nr; + + while (word) { + bit = bfdev_arch_flsuf(word); + if (!(*nr)--) + return bit; + bfdev_arch_bit_clr(&word, bit); + } + + return BFDEV_BITS_PER_LONG; +} +#endif + +#ifndef bfdev_arch_ffnz +static __bfdev_always_inline unsigned int +bfdev_arch_ffnzp(unsigned long word, unsigned int *nr) +{ + return bfdev_arch_ffnsp(~word, nr); +} +#endif + +#ifndef bfdev_arch_flnz +static __bfdev_always_inline unsigned int +bfdev_arch_flnzp(unsigned long word, unsigned int *nr) +{ + return bfdev_arch_flnsp(~word, nr); +} +#endif + +BFDEV_END_DECLS + +#endif /* _BFDEV_ASM_GENERIC_BITOPS_H_ */ diff --git a/include/bfdev/asm-generic/builtin-clz.h b/include/bfdev/asm-generic/builtin-clz.h new file mode 100644 index 00000000..3125e7c3 --- /dev/null +++ b/include/bfdev/asm-generic/builtin-clz.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#ifndef _BFDEV_ASM_GENERIC_BUILTIN_CLZ_H_ +#define _BFDEV_ASM_GENERIC_BUILTIN_CLZ_H_ + +#include +#include + +BFDEV_BEGIN_DECLS + +#define bfdev_arch_clz bfdev_arch_clz +static __bfdev_always_inline unsigned int +bfdev_arch_clz(unsigned long value) +{ + return __builtin_clzl(value); +} + +BFDEV_END_DECLS + +#endif /* _BFDEV_ASM_GENERIC_BUILTIN_CLZ_H_ */ diff --git a/include/bfdev/asm-generic/builtin-ctz.h b/include/bfdev/asm-generic/builtin-ctz.h new file mode 100644 index 00000000..e01d8772 --- /dev/null +++ b/include/bfdev/asm-generic/builtin-ctz.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#ifndef _BFDEV_ASM_GENERIC_BUILTIN_CTZ_H_ +#define _BFDEV_ASM_GENERIC_BUILTIN_CTZ_H_ + +#include +#include + +BFDEV_BEGIN_DECLS + +#define bfdev_arch_ctz bfdev_arch_ctz +static __bfdev_always_inline unsigned int +bfdev_arch_ctz(unsigned long value) +{ + return __builtin_ctzl(value); +} + +BFDEV_END_DECLS + +#endif /* _BFDEV_ASM_GENERIC_BUILTIN_CTZ_H_ */ diff --git a/include/bfdev/asm-generic/builtin-ffs.h b/include/bfdev/asm-generic/builtin-ffs.h new file mode 100644 index 00000000..626239f1 --- /dev/null +++ b/include/bfdev/asm-generic/builtin-ffs.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#ifndef _BFDEV_ASM_GENERIC_BUILTIN_FFS_H_ +#define _BFDEV_ASM_GENERIC_BUILTIN_FFS_H_ + +#include +#include + +BFDEV_BEGIN_DECLS + +#define bfdev_arch_ffs bfdev_arch_ffs +static __bfdev_always_inline unsigned int +bfdev_arch_ffs(unsigned long value) +{ + return __builtin_ffsl(value); +} + +BFDEV_END_DECLS + +#endif /* _BFDEV_ASM_GENERIC_BUILTIN_FFS_H_ */ diff --git a/include/bfdev/asm-generic/builtin-ffsuf.h b/include/bfdev/asm-generic/builtin-ffsuf.h new file mode 100644 index 00000000..11b7f36e --- /dev/null +++ b/include/bfdev/asm-generic/builtin-ffsuf.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#ifndef _BFDEV_ASM_GENERIC_BUILTIN_FFSUF_H_ +#define _BFDEV_ASM_GENERIC_BUILTIN_FFSUF_H_ + +#include +#include + +BFDEV_BEGIN_DECLS + +#define bfdev_arch_ffsuf bfdev_arch_ffsuf +static __bfdev_always_inline unsigned int +bfdev_arch_ffsuf(unsigned long value) +{ + return __builtin_ctzl(value); +} + +BFDEV_END_DECLS + +#endif /* _BFDEV_ASM_GENERIC_BUILTIN_FFSUF_H_ */ diff --git a/include/bfdev/asm-generic/builtin-fls.h b/include/bfdev/asm-generic/builtin-fls.h new file mode 100644 index 00000000..67cc4ae6 --- /dev/null +++ b/include/bfdev/asm-generic/builtin-fls.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#ifndef _BFDEV_ASM_GENERIC_BUILTIN_FLS_H_ +#define _BFDEV_ASM_GENERIC_BUILTIN_FLS_H_ + +#include +#include + +BFDEV_BEGIN_DECLS + +#define bfdev_arch_fls bfdev_arch_fls +static __bfdev_always_inline unsigned int +bfdev_arch_fls(unsigned long value) +{ + return value ? BFDEV_BITS_PER_LONG - __builtin_clzl(value) : 0; +} + +BFDEV_END_DECLS + +#endif /* _BFDEV_ASM_GENERIC_BUILTIN_FLS_H_ */ diff --git a/include/bfdev/asm-generic/builtin-flsuf.h b/include/bfdev/asm-generic/builtin-flsuf.h new file mode 100644 index 00000000..8ff10077 --- /dev/null +++ b/include/bfdev/asm-generic/builtin-flsuf.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#ifndef _BFDEV_ASM_GENERIC_BUILTIN_FLSUF_H_ +#define _BFDEV_ASM_GENERIC_BUILTIN_FLSUF_H_ + +#include +#include + +BFDEV_BEGIN_DECLS + +#define bfdev_arch_flsuf bfdev_arch_flsuf +static __bfdev_always_inline unsigned int +bfdev_arch_flsuf(unsigned long value) +{ + return BFDEV_BITS_PER_LONG - 1 - __builtin_clzl(value); +} + +BFDEV_END_DECLS + +#endif /* _BFDEV_ASM_GENERIC_BUILTIN_FLSUF_H_ */ diff --git a/include/bfdev/asm-generic/byteorder.h b/include/bfdev/asm-generic/byteorder.h new file mode 100644 index 00000000..0942ae85 --- /dev/null +++ b/include/bfdev/asm-generic/byteorder.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#ifndef _BFDEV_ASM_GENERIC_BYTEORDER_H_ +#define _BFDEV_ASM_GENERIC_BYTEORDER_H_ + +#include + +#endif /* _BFDEV_ASM_GENERIC_BYTEORDER_H_ */ diff --git a/include/bfdev/asm-generic/cmpxchg.h b/include/bfdev/asm-generic/cmpxchg.h new file mode 100644 index 00000000..10318ab5 --- /dev/null +++ b/include/bfdev/asm-generic/cmpxchg.h @@ -0,0 +1,58 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#ifndef _BFDEV_ASM_GENERIC_CMPXCHG_H_ +#define _BFDEV_ASM_GENERIC_CMPXCHG_H_ + +#include +#include +#include +#include + +BFDEV_BEGIN_DECLS + +#ifndef bfdev_arch_cmpxchg +# define bfdev_arch_cmpxchg bfdev_arch_cmpxchg +static __bfdev_always_inline bfdev_atomic_t +bfdev_arch_cmpxchg(bfdev_atomic_t *atomic, bfdev_atomic_t old, bfdev_atomic_t value) +{ + return __sync_val_compare_and_swap(atomic, old, value); +} +#endif + +#ifndef bfdev_arch_xchg +# define bfdev_arch_xchg bfdev_arch_xchg +static __bfdev_always_inline bfdev_atomic_t +bfdev_arch_xchg(bfdev_atomic_t *atomic, bfdev_atomic_t value) +{ + bfdev_atomic_t prev; + + do { + prev = *atomic; + } while (!bfdev_arch_cmpxchg(atomic, prev, value)); + + return prev; +} +#endif + +#ifndef bfdev_arch_try_cmpxchg +# define bfdev_arch_try_cmpxchg bfdev_arch_try_cmpxchg +static __bfdev_always_inline bool +bfdev_arch_try_cmpxchg(bfdev_atomic_t *atomic, bfdev_atomic_t *old, bfdev_atomic_t value) +{ + bfdev_atomic_t result, prev; + + prev = *old; + result = bfdev_arch_cmpxchg(atomic, prev, value); + if (bfdev_unlikely(result != prev)) + *old = result; + + return bfdev_likely(result == prev); +} +#endif + +BFDEV_END_DECLS + +#endif /* _BFDEV_ASM_GENERIC_CMPXCHG_H_ */ diff --git a/include/bfdev/asm-generic/rwonce.h b/include/bfdev/asm-generic/rwonce.h new file mode 100644 index 00000000..befec78f --- /dev/null +++ b/include/bfdev/asm-generic/rwonce.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#ifndef _BFDEV_ASM_GENERIC_RWONCE_H_ +#define _BFDEV_ASM_GENERIC_RWONCE_H_ + +#include + +BFDEV_BEGIN_DECLS + +#define BFDEV_READ_ONCE(x) ({ \ + *(volatile typeof(x) *)&(x); \ +}) + +#define BFDEV_WRITE_ONCE(x, val) ({ \ + *(volatile typeof(x) *)&(x) = (val); \ +}) + +BFDEV_END_DECLS + +#endif /* _BFDEV_ASM_GENERIC_RWONCE_H_ */ diff --git a/include/bfdev/asm-generic/swab.h b/include/bfdev/asm-generic/swab.h new file mode 100644 index 00000000..ac6b9242 --- /dev/null +++ b/include/bfdev/asm-generic/swab.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#ifndef _BFDEV_ASM_GENERIC_SWAB_H_ +#define _BFDEV_ASM_GENERIC_SWAB_H_ + +#include + +BFDEV_BEGIN_DECLS + +/* Nothing */ + +BFDEV_END_DECLS + +#endif /* _BFDEV_ASM_GENERIC_SWAB_H_ */ diff --git a/include/bfdev/asm-generic/unaligned.h b/include/bfdev/asm-generic/unaligned.h new file mode 100644 index 00000000..659fb395 --- /dev/null +++ b/include/bfdev/asm-generic/unaligned.h @@ -0,0 +1,219 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#ifndef _BFDEV_ASM_GENERIC_UNALIGNED_H_ +#define _BFDEV_ASM_GENERIC_UNALIGNED_H_ + +#include +#include +#include + +BFDEV_BEGIN_DECLS + +#ifndef bfdev_arch_unaligned_get_type +# define bfdev_arch_unaligned_get_type(type, ptr) ({ \ + const struct { type val; } __bfdev_packed \ + *_pptr = (typeof(_pptr))(ptr); \ + _pptr->val; \ +}) +#endif + +#ifndef bfdev_arch_unaligned_set_type +# define bfdev_arch_unaligned_set_type(type, ptr, value) ({ \ + struct { type val; } __bfdev_packed \ + *_pptr = (typeof(_pptr))(ptr); \ + _pptr->val = (value); \ +}) +#endif + +#ifndef bfdev_arch_unaligned_get +# define bfdev_arch_unaligned_get(ptr) \ + bfdev_arch_unaligned_get_type(typeof(*(ptr)), (ptr)) +#endif + +#ifndef bfdev_arch_unaligned_set +# define bfdev_arch_unaligned_set(ptr, val) \ + bfdev_arch_unaligned_set_type(typeof(*(ptr)), (ptr), (val)) +#endif + +#ifndef bfdev_arch_unaligned_get_uint +static __bfdev_always_inline unsigned int +bfdev_arch_unaligned_get_uint(const void *p) +{ + return bfdev_arch_unaligned_get_type(unsigned int, p); +} +#endif + +#ifndef bfdev_arch_unaligned_get_ulong +static __bfdev_always_inline unsigned long +bfdev_arch_unaligned_get_ulong(const void *p) +{ + return bfdev_arch_unaligned_get_type(unsigned long, p); +} +#endif + +#ifndef bfdev_arch_unaligned_set_uint +static __bfdev_always_inline void +bfdev_arch_unaligned_set_uint(void *p, unsigned int val) +{ + bfdev_arch_unaligned_set_type(unsigned int, p, val); +} +#endif + +#ifndef bfdev_arch_unaligned_set_ulong +static __bfdev_always_inline void +bfdev_arch_unaligned_set_ulong(void *p, unsigned long val) +{ + bfdev_arch_unaligned_set_type(unsigned long, p, val); +} +#endif + +#ifndef bfdev_arch_unaligned_get_u16 +static __bfdev_always_inline uint16_t +bfdev_arch_unaligned_get_u16(const void *p) +{ + return bfdev_arch_unaligned_get_type(uint16_t, p); +} +#endif + +#ifndef bfdev_arch_unaligned_get_u32 +static __bfdev_always_inline uint32_t +bfdev_arch_unaligned_get_u32(const void *p) +{ + return bfdev_arch_unaligned_get_type(uint32_t, p); +} +#endif + +#ifndef bfdev_arch_unaligned_get_u64 +static __bfdev_always_inline uint64_t +bfdev_arch_unaligned_get_u64(const void *p) +{ + return bfdev_arch_unaligned_get_type(uint64_t, p); +} +#endif + +#ifndef bfdev_arch_unaligned_set_u16 +static __bfdev_always_inline void +bfdev_arch_unaligned_set_u16(void *p, uint16_t val) +{ + bfdev_arch_unaligned_set_type(uint16_t, p, val); +} +#endif + +#ifndef bfdev_arch_unaligned_set_u32 +static __bfdev_always_inline void +bfdev_arch_unaligned_set_u32(void *p, uint32_t val) +{ + bfdev_arch_unaligned_set_type(uint32_t, p, val); +} +#endif + +#ifndef bfdev_arch_unaligned_set_u64 +static __bfdev_always_inline void +bfdev_arch_unaligned_set_u64(void *p, uint64_t val) +{ + bfdev_arch_unaligned_set_type(uint64_t, p, val); +} +#endif + +#ifndef bfdev_arch_unaligned_get_le16 +static __bfdev_always_inline uint16_t +bfdev_arch_unaligned_get_le16(const void *p) +{ + return bfdev_le16_to_cpu(bfdev_arch_unaligned_get_type(bfdev_le16, p)); +} +#endif + +#ifndef bfdev_arch_unaligned_get_le32 +static __bfdev_always_inline uint32_t +bfdev_arch_unaligned_get_le32(const void *p) +{ + return bfdev_le32_to_cpu(bfdev_arch_unaligned_get_type(bfdev_le32, p)); +} +#endif + +#ifndef bfdev_arch_unaligned_get_le64 +static __bfdev_always_inline uint64_t +bfdev_arch_unaligned_get_le64(const void *p) +{ + return bfdev_le64_to_cpu(bfdev_arch_unaligned_get_type(bfdev_le64, p)); +} +#endif + +#ifndef bfdev_arch_unaligned_set_le16 +static __bfdev_always_inline void +bfdev_arch_unaligned_set_le16(void *p, uint16_t val) +{ + bfdev_arch_unaligned_set_type(bfdev_le16, p, bfdev_cpu_to_le16(val)); +} +#endif + +#ifndef bfdev_arch_unaligned_set_le32 +static __bfdev_always_inline void +bfdev_arch_unaligned_set_le32(void *p, uint32_t val) +{ + bfdev_arch_unaligned_set_type(bfdev_le32, p, bfdev_cpu_to_le32(val)); +} +#endif + +#ifndef bfdev_arch_unaligned_set_le64 +static __bfdev_always_inline void +bfdev_arch_unaligned_set_le64(void *p, uint64_t val) +{ + bfdev_arch_unaligned_set_type(bfdev_le64, p, bfdev_cpu_to_le64(val)); +} +#endif + +#ifndef bfdev_arch_unaligned_get_be16 +static __bfdev_always_inline uint16_t +bfdev_arch_unaligned_get_be16(const void *p) +{ + return bfdev_be16_to_cpu(bfdev_arch_unaligned_get_type(bfdev_be16, p)); +} +#endif + +#ifndef bfdev_arch_unaligned_get_be32 +static __bfdev_always_inline uint32_t +bfdev_arch_unaligned_get_be32(const void *p) +{ + return bfdev_be32_to_cpu(bfdev_arch_unaligned_get_type(bfdev_be32, p)); +} +#endif + +#ifndef bfdev_arch_unaligned_get_be64 +static __bfdev_always_inline uint64_t +bfdev_arch_unaligned_get_be64(const void *p) +{ + return bfdev_be64_to_cpu(bfdev_arch_unaligned_get_type(bfdev_be64, p)); +} +#endif + +#ifndef bfdev_arch_unaligned_set_be16 +static __bfdev_always_inline void +bfdev_arch_unaligned_set_be16(void *p, uint16_t val) +{ + bfdev_arch_unaligned_set_type(bfdev_be16, p, bfdev_cpu_to_be16(val)); +} +#endif + +#ifndef bfdev_arch_unaligned_set_be32 +static __bfdev_always_inline void +bfdev_arch_unaligned_set_be32(void *p, uint32_t val) +{ + bfdev_arch_unaligned_set_type(bfdev_be32, p, bfdev_cpu_to_be32(val)); +} +#endif + +#ifndef bfdev_arch_unaligned_set_be64 +static __bfdev_always_inline void +bfdev_arch_unaligned_set_be64(void *p, uint64_t val) +{ + bfdev_arch_unaligned_set_type(bfdev_be64, p, bfdev_cpu_to_be64(val)); +} +#endif + +BFDEV_END_DECLS + +#endif /* _BFDEV_ASM_GENERIC_UNALIGNED_H_ */ diff --git a/include/bfdev/atomic.h b/include/bfdev/atomic.h new file mode 100644 index 00000000..d3b719c9 --- /dev/null +++ b/include/bfdev/atomic.h @@ -0,0 +1,236 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#ifndef _BFDEV_ATOMIC_H_ +#define _BFDEV_ATOMIC_H_ + +#include +#include + +BFDEV_BEGIN_DECLS + +/** + * bfdev_atomic_read - atomic read variable. + * @atomic: pointer of type atomic_t. + */ +#ifndef bfdev_atomic_read +static __bfdev_always_inline bfdev_atomic_t +bfdev_atomic_read(const bfdev_atomic_t *atomic) +{ + return bfdev_arch_atomic_read(atomic); +} +#endif + +/** + * bfdev_atomic_write - atomic write variable. + * @atomic: pointer of type atomic_t. + * @value: required value. + */ +#ifndef bfdev_atomic_write +static __bfdev_always_inline void +bfdev_atomic_write(bfdev_atomic_t *atomic, bfdev_atomic_t value) +{ + bfdev_arch_atomic_write(atomic, value); +} +#endif + +/** + * bfdev_atomic_add - atomic add variable. + * @atomic: pointer of type atomic_t. + * @value: required value. + */ +#ifndef bfdev_atomic_add +static __bfdev_always_inline void +bfdev_atomic_add(bfdev_atomic_t *atomic, bfdev_atomic_t value) +{ + bfdev_arch_atomic_add(atomic, value); +} +#endif + +/** + * bfdev_atomic_sub - atomic subtract variable. + * @atomic: pointer of type atomic_t. + * @value: required value. + */ +#ifndef bfdev_atomic_sub +static __bfdev_always_inline void +bfdev_atomic_sub(bfdev_atomic_t *atomic, bfdev_atomic_t value) +{ + bfdev_arch_atomic_sub(atomic, value); +} +#endif + +/** + * bfdev_atomic_and - atomic and variable. + * @atomic: pointer of type atomic_t. + * @value: required value. + */ +#ifndef bfdev_atomic_and +static __bfdev_always_inline void +bfdev_atomic_and(bfdev_atomic_t *atomic, bfdev_atomic_t value) +{ + bfdev_arch_atomic_and(atomic, value); +} +#endif + +/** + * bfdev_atomic_or - atomic or variable. + * @atomic: pointer of type atomic_t. + * @value: required value. + */ +#ifndef bfdev_atomic_or +static __bfdev_always_inline void +bfdev_atomic_or(bfdev_atomic_t *atomic, bfdev_atomic_t value) +{ + bfdev_arch_atomic_or(atomic, value); +} +#endif + +/** + * bfdev_atomic_xor - atomic xor variable. + * @atomic: pointer of type atomic_t. + * @value: required value. + */ +#ifndef bfdev_atomic_xor +static __bfdev_always_inline void +bfdev_atomic_xor(bfdev_atomic_t *atomic, bfdev_atomic_t value) +{ + bfdev_arch_atomic_xor(atomic, value); +} +#endif + +/** + * bfdev_atomic_fetch_add - fetch and atomic add variable. + * @atomic: pointer of type atomic_t. + * @value: required value. + */ +#ifndef bfdev_atomic_fetch_add +static __bfdev_always_inline bfdev_atomic_t +bfdev_atomic_fetch_add(bfdev_atomic_t *atomic, bfdev_atomic_t value) +{ + return bfdev_arch_atomic_fetch_add(atomic, value); +} +#endif + +/** + * bfdev_atomic_fetch_sub - fetch and atomic subtract variable. + * @atomic: pointer of type atomic_t. + * @value: required value. + */ +#ifndef bfdev_atomic_fetch_sub +static __bfdev_always_inline bfdev_atomic_t +bfdev_atomic_fetch_sub(bfdev_atomic_t *atomic, bfdev_atomic_t value) +{ + return bfdev_arch_atomic_fetch_sub(atomic, value); +} +#endif + +/** + * bfdev_atomic_fetch_and - fetch and atomic and variable. + * @atomic: pointer of type atomic_t. + * @value: required value. + */ +#ifndef bfdev_atomic_fetch_and +static __bfdev_always_inline bfdev_atomic_t +bfdev_atomic_fetch_and(bfdev_atomic_t *atomic, bfdev_atomic_t value) +{ + return bfdev_arch_atomic_fetch_and(atomic, value); +} +#endif + +/** + * bfdev_atomic_fetch_or - fetch and atomic or variable. + * @atomic: pointer of type atomic_t. + * @value: required value. + */ +#ifndef bfdev_atomic_fetch_or +static __bfdev_always_inline bfdev_atomic_t +bfdev_atomic_fetch_or(bfdev_atomic_t *atomic, bfdev_atomic_t value) +{ + return bfdev_arch_atomic_fetch_or(atomic, value); +} +#endif + +/** + * bfdev_atomic_fetch_xor - fetch and atomic xor variable. + * @atomic: pointer of type atomic_t. + * @value: required value. + */ +#ifndef bfdev_atomic_fetch_xor +static __bfdev_always_inline bfdev_atomic_t +bfdev_atomic_fetch_xor(bfdev_atomic_t *atomic, bfdev_atomic_t value) +{ + return bfdev_arch_atomic_fetch_xor(atomic, value); +} +#endif + +/** + * bfdev_atomic_add_fetch - atomic add variable and fetch. + * @atomic: pointer of type atomic_t. + * @value: required value. + */ +#ifndef bfdev_atomic_add_fetch +static __bfdev_always_inline bfdev_atomic_t +bfdev_atomic_add_fetch(bfdev_atomic_t *atomic, bfdev_atomic_t value) +{ + return bfdev_arch_atomic_add_fetch(atomic, value); +} +#endif + +/** + * bfdev_atomic_sub_fetch - atomic subtract variable and fetch. + * @atomic: pointer of type atomic_t. + * @value: required value. + */ +#ifndef bfdev_atomic_sub_fetch +static __bfdev_always_inline bfdev_atomic_t +bfdev_atomic_sub_fetch(bfdev_atomic_t *atomic, bfdev_atomic_t value) +{ + return bfdev_arch_atomic_sub_fetch(atomic, value); +} +#endif + +/** + * bfdev_atomic_and_fetch - atomic and variable and fetch. + * @atomic: pointer of type atomic_t. + * @value: required value. + */ +#ifndef bfdev_atomic_and_fetch +static __bfdev_always_inline bfdev_atomic_t +bfdev_atomic_and_fetch(bfdev_atomic_t *atomic, bfdev_atomic_t value) +{ + return bfdev_arch_atomic_and_fetch(atomic, value); +} +#endif + +/** + * bfdev_atomic_or_fetch - atomic or variable and fetch. + * @atomic: pointer of type atomic_t. + * @value: required value. + */ +#ifndef bfdev_atomic_or_fetch +static __bfdev_always_inline bfdev_atomic_t +bfdev_atomic_or_fetch(bfdev_atomic_t *atomic, bfdev_atomic_t value) +{ + return bfdev_arch_atomic_or_fetch(atomic, value); +} +#endif + +/** + * bfdev_atomic_xor_fetch - atomic xor variable and fetch. + * @atomic: pointer of type atomic_t. + * @value: required value. + */ +#ifndef bfdev_atomic_xor_fetch +static __bfdev_always_inline bfdev_atomic_t +bfdev_atomic_xor_fetch(bfdev_atomic_t *atomic, bfdev_atomic_t value) +{ + return bfdev_arch_atomic_xor_fetch(atomic, value); +} +#endif + +BFDEV_END_DECLS + +#endif /* _BFDEV_ATOMIC_H_ */ diff --git a/include/bfdev/base32.h b/include/bfdev/base32.h new file mode 100644 index 00000000..dee84f16 --- /dev/null +++ b/include/bfdev/base32.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2022 John Sanpe + */ + +#ifndef _BFDEV_BASE32_H_ +#define _BFDEV_BASE32_H_ + +#include +#include +#include +#include + +BFDEV_BEGIN_DECLS + +static inline size_t +bfdev_base32_encode_length(size_t size) +{ + return BFDEV_DIV_ROUND_UP(size, 5) * 8 + 1; +} + +static inline size_t +bfdev_base32_decode_length(size_t size) +{ + return BFDEV_DIV_ROUND_UP(size, 8) * 5; +} + +extern void +bfdev_base32_encode(void *buff, const void *data, size_t size); + +extern int +bfdev_base32_decode(void *buff, const void *data, size_t size); + +BFDEV_END_DECLS + +#endif /* _BFDEV_BASE32_H_ */ diff --git a/include/bfdev/base64.h b/include/bfdev/base64.h new file mode 100644 index 00000000..51adf168 --- /dev/null +++ b/include/bfdev/base64.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2022 John Sanpe + */ + +#ifndef _BFDEV_BASE64_H_ +#define _BFDEV_BASE64_H_ + +#include +#include +#include +#include + +BFDEV_BEGIN_DECLS + +static inline size_t +bfdev_base64_encode_length(size_t size) +{ + return BFDEV_DIV_ROUND_UP(size, 3) * 4 + 1; +} + +static inline size_t +bfdev_base64_decode_length(size_t size) +{ + return BFDEV_DIV_ROUND_UP(size, 4) * 3; +} + +extern void +bfdev_base64_encode(void *buff, const void *data, size_t size); + +extern int +bfdev_base64_decode(void *buff, const void *data, size_t size); + +BFDEV_END_DECLS + +#endif /* _BFDEV_BASE64_H_ */ diff --git a/include/bfdev/bcd.h b/include/bfdev/bcd.h new file mode 100644 index 00000000..9ce658fc --- /dev/null +++ b/include/bfdev/bcd.h @@ -0,0 +1,73 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#ifndef _BFDEV_BCD_H_ +#define _BFDEV_BCD_H_ + +#include +#include +#include + +BFDEV_BEGIN_DECLS + +/* + * Interface for known constant arguments + */ + +#define bfdev_bcd2bin_const(bcd) ( \ + ((bcd) & 0x0f) + ((bcd) >> 4) * 10 \ +) + +#define bfdev_bin2bcd_const(bin) ( \ + (((bin) / 10) << 4) + (bin) % 10 \ +) + +/* + * Interface for known dynamic arguments + */ + +extern const uint8_t +bfdev_bcd2bin_table[256]; + +extern const uint8_t +bfdev_bin2bcd_table[256]; + +static __bfdev_attribute_const inline +uint8_t bfdev_bcd2bin_dynamic(uint8_t bcd) +{ + return bfdev_bcd2bin_table[bcd]; +} + +static inline __bfdev_attribute_const +uint8_t bfdev_bin2bcd_dynamic(uint8_t bin) +{ + return bfdev_bin2bcd_table[bin]; +} + +/** + * bfdev_bcd2bin - convert bcd to bin. + * @bcd: the bcd to convert. + */ +#define bfdev_bcd2bin(bcd) ({ \ + uint8_t __bcd = (uint8_t)(bcd); \ + __builtin_constant_p(__bcd) \ + ? bfdev_bcd2bin_const(__bcd) \ + : bfdev_bcd2bin_dynamic(__bcd); \ +}) + +/** + * bfdev_bin2bcd - convert bin to bcd. + * @bin: the bin to convert. + */ +#define bfdev_bin2bcd(bin) ({ \ + uint8_t __bin = (uint8_t)(bin); \ + __builtin_constant_p(__bin) \ + ? bfdev_bin2bcd_const(__bin) \ + : bfdev_bin2bcd_dynamic(__bin); \ +}) + +BFDEV_END_DECLS + +#endif /* _BFDEV_BCD_H_ */ diff --git a/include/bfdev/bitfield.h b/include/bfdev/bitfield.h new file mode 100644 index 00000000..95866e5c --- /dev/null +++ b/include/bfdev/bitfield.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#ifndef _BFDEV_BITFIELD_H_ +#define _BFDEV_BITFIELD_H_ + +#include +#include + +BFDEV_BEGIN_DECLS + +/** + * BFDEV_FIELD_GET() - extract a bitfield element. + * @mask: shifted mask defining the field's length and position. + * @reg: value of entire bitfield. + */ +#define BFDEV_FIELD_GET(mask, reg) ({ \ + (typeof(mask))(((reg) & (mask)) >> bfdev_ffs(mask)); \ +}) + +/** + * BFDEV_FIELD_PREP() - prepare a bitfield element. + * @mask: shifted mask defining the field's length and position. + * @val: value to put in the field. + */ +#define BFDEV_FIELD_PREP(mask, val) ({ \ + ((typeof(mask))(val) << bfdev_ffs(mask)) & (mask); \ +}) + +/** + * BFDEV_FIELD_FIT() - check if value fits in the field. + * @_mask: shifted mask defining the field's length and position. + * @_val: value to test against the field. + */ +#define BFDEV_FIELD_FIT(mask, val) ({ \ + !((((typeof(mask))(val)) << bfdev_ffs(mask)) & ~(mask)); \ +}) + +/** + * BFDEV_FIELD_MAX() - produce the maximum value representable by a field. + * @_mask: shifted mask defining the field's length and position. + */ +#define BFDEV_FIELD_MAX(mask) ({ \ + (typeof(mask))((mask) >> bfdev_ffs(mask)); \ +}) + +BFDEV_END_DECLS + +#endif /* _BFDEV_BITFIELD_H_ */ diff --git a/include/bfdev/bitflags.h b/include/bfdev/bitflags.h new file mode 100644 index 00000000..ea8d69db --- /dev/null +++ b/include/bfdev/bitflags.h @@ -0,0 +1,178 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#ifndef _BFDEV_BITFLAGS_H_ +#define _BFDEV_BITFLAGS_H_ + +#include +#include + +BFDEV_BEGIN_DECLS + +#define BFDEV_BITFLAGS_STRUCT(name, type, member) \ +static __bfdev_always_inline void \ +name##_##member##_clr(type *ptr, unsigned int bit) \ +{ \ + bfdev_bit_clr(&ptr->member, bit); \ +} \ + \ +static __bfdev_always_inline void \ +name##_##member##_set(type *ptr, unsigned int bit) \ +{ \ + bfdev_bit_set(&ptr->member, bit); \ +} \ + \ +static __bfdev_always_inline void \ +name##_##member##_flip(type *ptr, unsigned int bit) \ +{ \ + bfdev_bit_flip(&ptr->member, bit); \ +} \ + \ +static __bfdev_always_inline bool \ +name##_##member##_test(const type *ptr, unsigned int bit) \ +{ \ + return bfdev_bit_test(&ptr->member, bit); \ +} \ + \ +static __bfdev_always_inline bool \ +name##_##member##_test_clr(type *ptr, unsigned int bit) \ +{ \ + return bfdev_bit_test_clr(&ptr->member, bit); \ +} \ + \ +static __bfdev_always_inline bool \ +name##_##member##_test_set(type *ptr, unsigned int bit) \ +{ \ + return bfdev_bit_test_set(&ptr->member, bit); \ +} \ + \ +static __bfdev_always_inline bool \ +name##_##member##_test_flip(type *ptr, unsigned int bit) \ +{ \ + return bfdev_bit_test_flip(&ptr->member, bit); \ +} + +#define BFDEV_BITFLAGS_STRUCT_ATOMIC(name, type, member) \ +static __bfdev_always_inline void \ +name##_##member##_atomic_clr(type *ptr, unsigned int bit) \ +{ \ + bfdev_bit_atomic_clr(&ptr->member, bit); \ +} \ + \ +static __bfdev_always_inline void \ +name##_##member##_atomic_set(type *ptr, unsigned int bit) \ +{ \ + bfdev_bit_atomic_set(&ptr->member, bit); \ +} \ + \ +static __bfdev_always_inline void \ +name##_##member##_atomic_flip(type *ptr, unsigned int bit) \ +{ \ + bfdev_bit_atomic_flip(&ptr->member, bit); \ +} \ + \ +static __bfdev_always_inline bool \ +name##_##member##_atomic_test(const type *ptr, unsigned int bit) \ +{ \ + return bfdev_bit_atomic_test(&ptr->member, bit); \ +} \ + \ +static __bfdev_always_inline bool \ +name##_##member##_atomic_test_clr(type *ptr, unsigned int bit) \ +{ \ + return bfdev_bit_atomic_test_clr(&ptr->member, bit); \ +} \ + \ +static __bfdev_always_inline bool \ +name##_##member##_atomic_test_set(type *ptr, unsigned int bit) \ +{ \ + return bfdev_bit_atomic_test_set(&ptr->member, bit); \ +} \ + \ +static __bfdev_always_inline bool \ +name##_##member##_atomic_test_flip(type *ptr, unsigned int bit) \ +{ \ + return bfdev_bit_atomic_test_flip(&ptr->member, bit); \ +} + +#define BFDEV_BITFLAGS_STRUCT_FLAG(name, type, member, \ + flag, index) \ +static __bfdev_always_inline void \ +name##_clr_##flag(type *ptr) \ +{ \ + name##_##member##_clr(ptr, index); \ +} \ + \ +static __bfdev_always_inline void \ +name##_set_##flag(type *ptr) \ +{ \ + name##_##member##_set(ptr, index); \ +} \ + \ +static __bfdev_always_inline bool \ +name##_test_##flag(const type *ptr) \ +{ \ + return name##_##member##_test(ptr, index); \ +} \ + \ +static __bfdev_always_inline bool \ +name##_test_clr_##flag(type *ptr) \ +{ \ + return name##_##member##_test_clr(ptr, index); \ +} \ + \ +static __bfdev_always_inline bool \ +name##_test_set_##flag(type *ptr) \ +{ \ + return name##_##member##_test_set(ptr, index); \ +} \ + \ +static __bfdev_always_inline bool \ +name##_test_flip_##flag(type *ptr) \ +{ \ + return name##_##member##_test_flip(ptr, index); \ +} + +#define BFDEV_BITFLAGS_STRUCT_ATOMIC_FLAG(name, type, member, \ + flag, index) \ +static __bfdev_always_inline void \ +name##_atomic_clr_##flag(type *ptr) \ +{ \ + name##_##member##_atomic_clr(ptr, index); \ +} \ + \ +static __bfdev_always_inline void \ +name##_atomic_set_##flag(type *ptr) \ +{ \ + name##_##member##_atomic_set(ptr, index); \ +} \ + \ +static __bfdev_always_inline bool \ +name##_atomic_test_##flag(const type *ptr) \ +{ \ + return name##_##member##_atomic_test(ptr, index); \ +} \ + \ +static __bfdev_always_inline bool \ +name##_atomic_test_clr_##flag(type *ptr) \ +{ \ + return name##_##member##_atomic_test_clr(ptr, index); \ +} \ + \ +static __bfdev_always_inline bool \ +name##_atomic_test_set_##flag(type *ptr) \ +{ \ + return name##_##member##_atomic_test_set(ptr, index); \ +} \ + \ +static __bfdev_always_inline bool \ +name##_atomic_test_flip_##flag(type *ptr) \ +{ \ + return name##_##member##_atomic_test_flip(ptr, index); \ +} + +BFDEV_END_DECLS + +#endif /* _BFDEV_BITFLAGS_H_ */ diff --git a/include/bfdev/bitmap.h b/include/bfdev/bitmap.h new file mode 100644 index 00000000..05873176 --- /dev/null +++ b/include/bfdev/bitmap.h @@ -0,0 +1,245 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#ifndef _BFDEV_BITMAP_H_ +#define _BFDEV_BITMAP_H_ + +#include +#include +#include +#include +#include +#include +#include + +BFDEV_BEGIN_DECLS + +#ifdef CONFIG_ARCH_LITTLE_ENDIAN +# define BFDEV_BITMAP_MEM_ALIGNMENT BFDEV_BITS_PER_BYTE +#else +# define BFDEV_BITMAP_MEM_ALIGNMENT (BFDEV_BITS_PER_BYTE * BFDEV_BYTES_PER_LONG) +#endif +#define BFDEV_BITMAP_MEM_MASK (BFDEV_BITMAP_MEM_ALIGNMENT - 1) + +#define BFDEV_DEFINE_BITMAP(name, bits) \ + unsigned long name[BFDEV_BITS_TO_LONG(bits)]; + +extern bool +bfdev_bitmap_comp_equal(const unsigned long *src1, const unsigned long *src2, + unsigned int bits); + +extern bool +bfdev_bitmap_comp_or_equal(const unsigned long *src1, const unsigned long *src2, + const unsigned long *src3, unsigned int bits); + +extern bool +bfdev_bitmap_comp_intersects(const unsigned long *src1, const unsigned long *src2, + unsigned int bits); + +extern bool +bfdev_bitmap_comp_and(unsigned long *dest, const unsigned long *src1, + const unsigned long *src2, unsigned int bits); + +extern bool +bfdev_bitmap_comp_andnot(unsigned long *dest, const unsigned long *src1, + const unsigned long *src2, unsigned int bits); + +extern void +bfdev_bitmap_comp_or(unsigned long *dest, const unsigned long *src1, + const unsigned long *src2, unsigned int bits); + +extern void +bfdev_bitmap_comp_xor(unsigned long *dest, const unsigned long *src1, + const unsigned long *src2, unsigned int bits); + +extern void +bfdev_bitmap_comp_complement(unsigned long *dest, const unsigned long *src, + unsigned int bits); + +extern void +bfdev_bitmap_comp_replace(unsigned long *bitmap, const unsigned long *oldp, + const unsigned long *newp, const unsigned long *mask, + unsigned int bits); + +extern void +bfdev_bitmap_comp_set(unsigned long *bitmap, unsigned int start, + unsigned int bits); + +extern void +bfdev_bitmap_comp_clr(unsigned long *bitmap, unsigned int start, + unsigned int bits); + +static __bfdev_always_inline bool +bfdev_bitmap_empty(const unsigned long *src, unsigned int bits) +{ + if (bfdev_const_small_nbits(bits)) + return !(*src & BFDEV_BIT_LOW_MASK(bits)); + else if (__builtin_constant_p(bits & BFDEV_BITMAP_MEM_MASK) && + bfdev_align_check(bits, BFDEV_BITMAP_MEM_ALIGNMENT)) + return !bfdev_memdiff(src, BFDEV_UINT_MIN, bits / BFDEV_BITS_PER_BYTE); + else + return bfdev_find_first_bit(src, bits) >= bits; +} + +static __bfdev_always_inline bool +bfdev_bitmap_full(const unsigned long *src, unsigned int bits) +{ + if (bfdev_const_small_nbits(bits)) + return !(~(*src) & BFDEV_BIT_LOW_MASK(bits)); + else if (__builtin_constant_p(bits & BFDEV_BITMAP_MEM_MASK) && + bfdev_align_check(bits, BFDEV_BITMAP_MEM_ALIGNMENT)) + return !bfdev_memdiff(src, BFDEV_UINT_MAX, bits / BFDEV_BITS_PER_BYTE); + else + return bfdev_find_first_zero(src, bits) >= bits; +} + +static __bfdev_always_inline bool +bfdev_bitmap_equal(const unsigned long *src1, const unsigned long *src2, + unsigned int bits) +{ + if (bfdev_const_small_nbits(bits)) + return !!((*src1 ^ *src2) & BFDEV_BIT_LOW_MASK(bits)); + else if (__builtin_constant_p(bits & BFDEV_BITMAP_MEM_MASK) && + bfdev_align_check(bits, BFDEV_BITMAP_MEM_ALIGNMENT)) + return memcmp(src1, src2, bits / BFDEV_BITS_PER_BYTE); + else + return bfdev_bitmap_comp_equal(src1, src2, bits); +} + +static __bfdev_always_inline bool +bfdev_bitmap_or_equal(const unsigned long *src1, const unsigned long *src2, + const unsigned long *src3, unsigned int bits) +{ + if (bfdev_const_small_nbits(bits)) + return !!(((*src1 | *src2) ^ *src3) & BFDEV_BIT_LOW_MASK(bits)); + else + return bfdev_bitmap_comp_or_equal(src1, src2, src3, bits); +} + +static __bfdev_always_inline bool +bfdev_bitmap_intersects(const unsigned long *src1, const unsigned long *src2, + unsigned int bits) +{ + if (bfdev_const_small_nbits(bits)) + return !!((*src1 & *src2) & BFDEV_BIT_LOW_MASK(bits)); + else + return bfdev_bitmap_comp_intersects(src1, src2, bits); +} + +static __bfdev_always_inline bool +bfdev_bitmap_and(unsigned long *dest, const unsigned long *src1, + const unsigned long *src2, unsigned int bits) +{ + if (bfdev_const_small_nbits(bits)) + return !!(*dest = *src1 & *src2 & BFDEV_BIT_LOW_MASK(bits)); + else + return bfdev_bitmap_comp_and(dest, src1, src2, bits); +} + +static __bfdev_always_inline void +bfdev_bitmap_or(unsigned long *dest, const unsigned long *src1, + const unsigned long *src2, unsigned int bits) +{ + if (bfdev_const_small_nbits(bits)) + *dest = *src1 | *src2; + else + bfdev_bitmap_comp_or(dest, src1, src2, bits); +} + +static __bfdev_always_inline void +bfdev_bitmap_xor(unsigned long *dest, const unsigned long *src1, + const unsigned long *src2, unsigned int bits) +{ + if (bfdev_const_small_nbits(bits)) + *dest = *src1 ^ *src2; + else + bfdev_bitmap_comp_xor(dest, src1, src2, bits); +} + +static __bfdev_always_inline void +bfdev_bitmap_complement(unsigned long *dest, const unsigned long *src, + unsigned int bits) +{ + if (bfdev_const_small_nbits(bits)) + *dest = ~(*src); + else + bfdev_bitmap_comp_complement(dest, src, bits); +} + +static __bfdev_always_inline void +bfdev_bitmap_set(unsigned long *bitmap, unsigned int start, unsigned int bits) +{ + if (__builtin_constant_p(bits) && bits == 1) + bfdev_bit_set(bitmap, start); + else if (__builtin_constant_p(start & BFDEV_BITMAP_MEM_MASK) && + bfdev_align_check(start, BFDEV_BITMAP_MEM_ALIGNMENT) && + __builtin_constant_p(bits & BFDEV_BITMAP_MEM_MASK) && + bfdev_align_check(bits, BFDEV_BITMAP_MEM_ALIGNMENT)) + memset((char *)bitmap + start / BFDEV_BITS_PER_BYTE, 0xff, bits / BFDEV_BITS_PER_BYTE); + else + bfdev_bitmap_comp_set(bitmap, start, bits); +} + +static __bfdev_always_inline void +bfdev_bitmap_clr(unsigned long *bitmap, unsigned int start, unsigned int bits) +{ + if (__builtin_constant_p(bits) && bits == 1) + bfdev_bit_clr(bitmap, start); + else if (__builtin_constant_p(start & BFDEV_BITMAP_MEM_MASK) && + bfdev_align_check(start, BFDEV_BITMAP_MEM_ALIGNMENT) && + __builtin_constant_p(bits & BFDEV_BITMAP_MEM_MASK) && + bfdev_align_check(bits, BFDEV_BITMAP_MEM_ALIGNMENT)) + memset((char *)bitmap + start / BFDEV_BITS_PER_BYTE, 0x00, bits / BFDEV_BITS_PER_BYTE); + else + bfdev_bitmap_comp_clr(bitmap, start, bits); +} + +static __bfdev_always_inline void +bfdev_bitmap_zero(unsigned long *bitmap, unsigned int bits) +{ + unsigned int len = BFDEV_BITS_TO_U8(bits); + memset(bitmap, 0, len); +} + +static __bfdev_always_inline void +bfdev_bitmap_fill(unsigned long *bitmap, unsigned int bits) +{ + unsigned int len = BFDEV_BITS_TO_U8(bits); + memset(bitmap, UINT8_MAX, len); +} + +static __bfdev_always_inline void +bfdev_bitmap_copy(unsigned long *dest, unsigned long *src, unsigned int bits) +{ + unsigned int len = BFDEV_BITS_TO_U8(bits); + memcpy(dest, src, len); +} + +/** + * bfdev_bitmap_alloc - alloc a bitmap. + * @bits: number of bits in the bitmap. + * @flags: allocate flags. + */ +extern unsigned long * +bfdev_bitmap_alloc(const struct bfdev_alloc *alloc, unsigned int bits); + +/** + * bfdev_bitmap_zalloc - alloc and zeroed a bitmap. + * @bits: number of bits in the bitmap. + * @flags: allocate flags. + */ +extern unsigned long * +bfdev_bitmap_zalloc(const struct bfdev_alloc *alloc, unsigned int bits); + +/** + * bfdev_bitmap_free - free a bitmap. + * @bitmap: bitmap to free. + */ +extern void +bfdev_bitmap_free(const struct bfdev_alloc *alloc, const unsigned long *bitmap); + +BFDEV_END_DECLS + +#endif /* _BFDEV_BITMAP_H_ */ diff --git a/include/bfdev/bitops-endian.h b/include/bfdev/bitops-endian.h new file mode 100644 index 00000000..fa0252f4 --- /dev/null +++ b/include/bfdev/bitops-endian.h @@ -0,0 +1,236 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#ifndef _BFDEV_BITOPS_ENDIAN_H_ +#define _BFDEV_BITOPS_ENDIAN_H_ + +#include +#include +#include +#include + +BFDEV_BEGIN_DECLS + +#if defined(__BFDEV_LITTLE_ENDIAN__) +# define BFDEV_BITOPS_LE_SWIZZLE 0 +# define BFDEV_BITOPS_BE_SWIZZLE ((BFDEV_BITS_PER_LONG - 1) & ~0x7) +#elif defined(__BFDEV_BIG_ENDIAN__) +# define BFDEV_BITOPS_LE_SWIZZLE ((BFDEV_BITS_PER_LONG - 1) & ~0x7) +# define BFDEV_BITOPS_BE_SWIZZLE 0 +#endif + +static inline void +bfdev_bit_clr_le(void *addr, unsigned int bit) +{ + bfdev_bit_clr(addr, bit ^ BFDEV_BITOPS_LE_SWIZZLE); +} + +static inline void +bfdev_bit_set_le(void *addr, unsigned int bit) +{ + bfdev_bit_set(addr, bit ^ BFDEV_BITOPS_LE_SWIZZLE); +} + +static inline void +bfdev_bit_flip_le(void *addr, unsigned int bit) +{ + bfdev_bit_flip(addr, bit ^ BFDEV_BITOPS_LE_SWIZZLE); +} + +static inline void +bfdev_bit_change_le(void *addr, unsigned int bit, bool val) +{ + bfdev_bit_change(addr, bit ^ BFDEV_BITOPS_LE_SWIZZLE, val); +} + +static inline bool +bfdev_bit_test_le(const void *addr, unsigned int bit) +{ + return bfdev_bit_test(addr, bit ^ BFDEV_BITOPS_LE_SWIZZLE); +} + +static inline bool +bfdev_bit_test_clr_le(void *addr, unsigned int bit) +{ + return bfdev_bit_test_clr(addr, bit ^ BFDEV_BITOPS_LE_SWIZZLE); +} + +static inline bool +bfdev_bit_test_set_le(void *addr, unsigned int bit) +{ + return bfdev_bit_test_set(addr, bit ^ BFDEV_BITOPS_LE_SWIZZLE); +} + +static inline bool +bfdev_bit_test_flip_le(void *addr, unsigned int bit) +{ + return bfdev_bit_test_flip(addr, bit ^ BFDEV_BITOPS_LE_SWIZZLE); +} + +static inline void +bfdev_bit_atomic_clr_le(void *addr, unsigned int bit) +{ + bfdev_bit_atomic_clr(addr, bit ^ BFDEV_BITOPS_LE_SWIZZLE); +} + +static inline void +bfdev_bit_atomic_set_le(void *addr, unsigned int bit) +{ + bfdev_bit_atomic_set(addr, bit ^ BFDEV_BITOPS_LE_SWIZZLE); +} + +static inline void +bfdev_bit_atomic_flip_le(void *addr, unsigned int bit) +{ + bfdev_bit_atomic_flip(addr, bit ^ BFDEV_BITOPS_LE_SWIZZLE); +} + +static inline void +bfdev_bit_atomic_change_le(void *addr, unsigned int bit, bool val) +{ + bfdev_bit_atomic_change(addr, bit ^ BFDEV_BITOPS_LE_SWIZZLE, val); +} + +static inline bool +bfdev_bit_atomic_test_le(const void *addr, unsigned int bit) +{ + return bfdev_bit_atomic_test(addr, bit ^ BFDEV_BITOPS_LE_SWIZZLE); +} + +static inline bool +bfdev_bit_atomic_test_clr_le(void *addr, unsigned int bit) +{ + return bfdev_bit_atomic_test_clr(addr, bit ^ BFDEV_BITOPS_LE_SWIZZLE); +} + +static inline bool +bfdev_bit_atomic_test_set_le(void *addr, unsigned int bit) +{ + return bfdev_bit_atomic_test_set(addr, bit ^ BFDEV_BITOPS_LE_SWIZZLE); +} + +static inline bool +bfdev_bit_atomic_test_flip_le(void *addr, unsigned int bit) +{ + return bfdev_bit_atomic_test_flip(addr, bit ^ BFDEV_BITOPS_LE_SWIZZLE); +} + +static inline bool +bfdev_bit_atomic_test_change_le(void *addr, unsigned int bit, bool val) +{ + return bfdev_bit_atomic_test_change(addr, bit ^ BFDEV_BITOPS_LE_SWIZZLE, val); +} + +static inline void +bfdev_bit_clr_be(void *addr, unsigned int bit) +{ + bfdev_bit_clr(addr, bit ^ BFDEV_BITOPS_BE_SWIZZLE); +} + +static inline void +bfdev_bit_set_be(void *addr, unsigned int bit) +{ + bfdev_bit_set(addr, bit ^ BFDEV_BITOPS_BE_SWIZZLE); +} + +static inline void +bfdev_bit_flip_be(void *addr, unsigned int bit) +{ + bfdev_bit_flip(addr, bit ^ BFDEV_BITOPS_BE_SWIZZLE); +} + +static inline void +bfdev_bit_change_be(void *addr, unsigned int bit, bool val) +{ + bfdev_bit_change(addr, bit ^ BFDEV_BITOPS_BE_SWIZZLE, val); +} + +static inline bool +bfdev_bit_test_be(const void *addr, unsigned int bit) +{ + return bfdev_bit_test(addr, bit ^ BFDEV_BITOPS_BE_SWIZZLE); +} + +static inline bool +bfdev_bit_test_clr_be(void *addr, unsigned int bit) +{ + return bfdev_bit_test_clr(addr, bit ^ BFDEV_BITOPS_BE_SWIZZLE); +} + +static inline bool +bfdev_bit_test_set_be(void *addr, unsigned int bit) +{ + return bfdev_bit_test_set(addr, bit ^ BFDEV_BITOPS_BE_SWIZZLE); +} + +static inline bool +bfdev_bit_test_flip_be(void *addr, unsigned int bit) +{ + return bfdev_bit_test_flip(addr, bit ^ BFDEV_BITOPS_BE_SWIZZLE); +} + +static inline bool +bfdev_bit_test_change_be(void *addr, unsigned int bit, bool val) +{ + return bfdev_bit_test_change(addr, bit ^ BFDEV_BITOPS_BE_SWIZZLE, val); +} + +static inline void +bfdev_bit_atomic_clr_be(void *addr, unsigned int bit) +{ + bfdev_bit_atomic_clr(addr, bit ^ BFDEV_BITOPS_BE_SWIZZLE); +} + +static inline void +bfdev_bit_atomic_set_be(void *addr, unsigned int bit) +{ + bfdev_bit_atomic_set(addr, bit ^ BFDEV_BITOPS_BE_SWIZZLE); +} + +static inline void +bfdev_bit_atomic_flip_be(void *addr, unsigned int bit) +{ + bfdev_bit_atomic_flip(addr, bit ^ BFDEV_BITOPS_BE_SWIZZLE); +} + +static inline void +bfdev_bit_atomic_change_be(void *addr, unsigned int bit, bool val) +{ + bfdev_bit_atomic_change(addr, bit ^ BFDEV_BITOPS_BE_SWIZZLE, val); +} + +static inline bool +bfdev_bit_atomic_test_be(const void *addr, unsigned int bit) +{ + return bfdev_bit_atomic_test(addr, bit ^ BFDEV_BITOPS_BE_SWIZZLE); +} + +static inline bool +bfdev_bit_atomic_test_clr_be(void *addr, unsigned int bit) +{ + return bfdev_bit_atomic_test_clr(addr, bit ^ BFDEV_BITOPS_BE_SWIZZLE); +} + +static inline bool +bfdev_bit_atomic_test_set_be(void *addr, unsigned int bit) +{ + return bfdev_bit_atomic_test_set(addr, bit ^ BFDEV_BITOPS_BE_SWIZZLE); +} + +static inline bool +bfdev_bit_atomic_test_flip_be(void *addr, unsigned int bit) +{ + return bfdev_bit_atomic_test_flip(addr, bit ^ BFDEV_BITOPS_BE_SWIZZLE); +} + +static inline bool +bfdev_bit_atomic_test_change_be(void *addr, unsigned int bit, bool val) +{ + return bfdev_bit_atomic_test_change(addr, bit ^ BFDEV_BITOPS_BE_SWIZZLE, val); +} + +BFDEV_END_DECLS + +#endif /* _BFDEV_BITOPS_ENDIAN_H_ */ diff --git a/include/bfdev/bitops.h b/include/bfdev/bitops.h new file mode 100644 index 00000000..8bda4bca --- /dev/null +++ b/include/bfdev/bitops.h @@ -0,0 +1,659 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#ifndef _BFDEV_BITOPS_H_ +#define _BFDEV_BITOPS_H_ + +#include +#include +#include +#include +#include + +BFDEV_BEGIN_DECLS + +#define BFDEV_BITS_DIV_U8(nr) ((nr) / BFDEV_BITS_PER_U8) +#define BFDEV_BITS_DIV_U16(nr) ((nr) / BFDEV_BITS_PER_U16) +#define BFDEV_BITS_DIV_U32(nr) ((nr) / BFDEV_BITS_PER_U32) +#define BFDEV_BITS_DIV_U64(nr) ((nr) / BFDEV_BITS_PER_U64) +#define BFDEV_BITS_DIV_CHAR(nr) ((nr) / BFDEV_BITS_PER_CHAR) +#define BFDEV_BITS_DIV_SHORT(nr) ((nr) / BFDEV_BITS_PER_SHORT) +#define BFDEV_BITS_DIV_INT(nr) ((nr) / BFDEV_BITS_PER_INT) +#define BFDEV_BITS_DIV_LONG(nr) ((nr) / BFDEV_BITS_PER_LONG) +#define BFDEV_BITS_DIV_LONG_LONG(nr) ((nr) / BFDEV_BITS_PER_LONG_LONG) + +#define BFDEV_BITS_MOD_U8(nr) ((nr) % BFDEV_BITS_PER_U8) +#define BFDEV_BITS_MOD_U16(nr) ((nr) % BFDEV_BITS_PER_U16) +#define BFDEV_BITS_MOD_U32(nr) ((nr) % BFDEV_BITS_PER_U32) +#define BFDEV_BITS_MOD_U64(nr) ((nr) % BFDEV_BITS_PER_U64) +#define BFDEV_BITS_MOD_CHAR(nr) ((nr) % BFDEV_BITS_PER_CHAR) +#define BFDEV_BITS_MOD_SHORT(nr) ((nr) % BFDEV_BITS_PER_SHORT) +#define BFDEV_BITS_MOD_INT(nr) ((nr) % BFDEV_BITS_PER_INT) +#define BFDEV_BITS_MOD_LONG(nr) ((nr) % BFDEV_BITS_PER_LONG) +#define BFDEV_BITS_MOD_LONG_LONG(nr) ((nr) % BFDEV_BITS_PER_LONG_LONG) + +#define BFDEV_BITS_TO_U8(nr) BFDEV_DIV_ROUND_UP(nr, BFDEV_BITS_PER_U8) +#define BFDEV_BITS_TO_U16(nr) BFDEV_DIV_ROUND_UP(nr, BFDEV_BITS_PER_U16) +#define BFDEV_BITS_TO_U32(nr) BFDEV_DIV_ROUND_UP(nr, BFDEV_BITS_PER_U32) +#define BFDEV_BITS_TO_U64(nr) BFDEV_DIV_ROUND_UP(nr, BFDEV_BITS_PER_U64) +#define BFDEV_BITS_TO_CHAR(nr) BFDEV_DIV_ROUND_UP(nr, BFDEV_BITS_PER_CHAR) +#define BFDEV_BITS_TO_SHORT(nr) BFDEV_DIV_ROUND_UP(nr, BFDEV_BITS_PER_SHORT) +#define BFDEV_BITS_TO_INT(nr) BFDEV_DIV_ROUND_UP(nr, BFDEV_BITS_PER_INT) +#define BFDEV_BITS_TO_LONG(nr) BFDEV_DIV_ROUND_UP(nr, BFDEV_BITS_PER_LONG) +#define BFDEV_BITS_TO_LONG_LONG(nr) BFDEV_DIV_ROUND_UP(nr, BFDEV_BITS_PER_LONG_LONG) + +#ifndef bfdev_bit_clr +static __bfdev_always_inline void +bfdev_bit_clr(volatile unsigned long *addr, unsigned int bit) +{ + bfdev_arch_bit_clr(addr, bit); +} +#endif + +#ifndef bfdev_bit_set +static __bfdev_always_inline void +bfdev_bit_set(volatile unsigned long *addr, unsigned int bit) +{ + bfdev_arch_bit_set(addr, bit); +} +#endif + +#ifndef bfdev_bit_flip +static __bfdev_always_inline void +bfdev_bit_flip(volatile unsigned long *addr, unsigned int bit) +{ + bfdev_arch_bit_flip(addr, bit); +} +#endif + +#ifndef bfdev_bit_change +static __bfdev_always_inline void +bfdev_bit_change(volatile unsigned long *addr, unsigned int bit, bool val) +{ + bfdev_arch_bit_change(addr, bit, val); +} +#endif + +#ifndef bfdev_bit_test +static __bfdev_always_inline bool +bfdev_bit_test(const volatile unsigned long *addr, unsigned int bit) +{ + return bfdev_arch_bit_test(addr, bit); +} +#endif + +#ifndef bfdev_bit_test_clr +static __bfdev_always_inline bool +bfdev_bit_test_clr(volatile unsigned long *addr, unsigned int bit) +{ + return bfdev_arch_bit_test_clr(addr, bit); +} +#endif + +#ifndef bfdev_bit_test_set +static __bfdev_always_inline bool +bfdev_bit_test_set(volatile unsigned long *addr, unsigned int bit) +{ + return bfdev_arch_bit_test_set(addr, bit); +} +#endif + +#ifndef bfdev_bit_test_flip +static __bfdev_always_inline bool +bfdev_bit_test_flip(volatile unsigned long *addr, unsigned int bit) +{ + return bfdev_arch_bit_test_flip(addr, bit); +} +#endif + +#ifndef bfdev_bit_test_change +static __bfdev_always_inline bool +bfdev_bit_test_change(volatile unsigned long *addr, unsigned int bit, bool val) +{ + return bfdev_arch_bit_test_change(addr, bit, val); +} +#endif + +#ifndef bfdev_bit_atomic_clr +static __bfdev_always_inline void +bfdev_bit_atomic_clr(volatile unsigned long *addr, unsigned int bit) +{ + bfdev_arch_bit_atomic_clr(addr, bit); +} +#endif + +#ifndef bfdev_bit_atomic_set +static __bfdev_always_inline void +bfdev_bit_atomic_set(volatile unsigned long *addr, unsigned int bit) +{ + bfdev_arch_bit_atomic_set(addr, bit); +} +#endif + +#ifndef bfdev_bit_atomic_flip +static __bfdev_always_inline void +bfdev_bit_atomic_flip(volatile unsigned long *addr, unsigned int bit) +{ + bfdev_arch_bit_atomic_flip(addr, bit); +} +#endif + +#ifndef bfdev_bit_atomic_change +static __bfdev_always_inline void +bfdev_bit_atomic_change(volatile unsigned long *addr, unsigned int bit, bool val) +{ + bfdev_arch_bit_atomic_change(addr, bit, val); +} +#endif + +#ifndef bfdev_bit_atomic_test +static __bfdev_always_inline bool +bfdev_bit_atomic_test(const volatile unsigned long *addr, unsigned int bit) +{ + return bfdev_arch_bit_atomic_test(addr, bit); +} +#endif + +#ifndef bfdev_bit_atomic_test_clr +static __bfdev_always_inline bool +bfdev_bit_atomic_test_clr(volatile unsigned long *addr, unsigned int bit) +{ + return bfdev_arch_bit_atomic_test_clr(addr, bit); +} +#endif + +#ifndef bfdev_bit_atomic_test_set +static __bfdev_always_inline bool +bfdev_bit_atomic_test_set(volatile unsigned long *addr, unsigned int bit) +{ + return bfdev_arch_bit_atomic_test_set(addr, bit); +} +#endif + +#ifndef bfdev_bit_atomic_test_flip +static __bfdev_always_inline bool +bfdev_bit_atomic_test_flip(volatile unsigned long *addr, unsigned int bit) +{ + return bfdev_arch_bit_atomic_test_flip(addr, bit); +} +#endif + +#ifndef bfdev_bit_atomic_test_change +static __bfdev_always_inline bool +bfdev_bit_atomic_test_change(volatile unsigned long *addr, unsigned int bit, bool val) +{ + return bfdev_arch_bit_atomic_test_change(addr, bit, val); +} +#endif + +#ifndef bfdev_rol8 +static __bfdev_always_inline uint8_t +bfdev_rol8(uint8_t value, unsigned int shift) +{ + return bfdev_arch_rol8(value, shift); +} +#endif + +#ifndef bfdev_ror8 +static __bfdev_always_inline uint8_t +bfdev_ror8(uint8_t value, unsigned int shift) +{ + return bfdev_arch_ror8(value, shift); +} +#endif + +#ifndef bfdev_rol16 +static __bfdev_always_inline uint16_t +bfdev_rol16(uint16_t value, unsigned int shift) +{ + return bfdev_arch_rol16(value, shift); +} +#endif + +#ifndef bfdev_ror16 +static __bfdev_always_inline uint16_t +bfdev_ror16(uint16_t value, unsigned int shift) +{ + return bfdev_arch_ror16(value, shift); +} +#endif + +#ifndef bfdev_rol32 +static __bfdev_always_inline uint32_t +bfdev_rol32(uint32_t value, unsigned int shift) +{ + return bfdev_arch_rol32(value, shift); +} +#endif + +#ifndef bfdev_ror32 +static __bfdev_always_inline uint32_t +bfdev_ror32(uint32_t value, unsigned int shift) +{ + return bfdev_arch_ror32(value, shift); +} +#endif + +#ifndef bfdev_rol64 +static __bfdev_always_inline uint64_t +bfdev_rol64(uint64_t value, unsigned int shift) +{ + return bfdev_arch_rol64(value, shift); +} +#endif + +#ifndef bfdev_ror64 +static __bfdev_always_inline uint64_t +bfdev_ror64(uint64_t value, unsigned int shift) +{ + return bfdev_arch_ror64(value, shift); +} +#endif + +#ifndef bfdev_ffsuf +static __bfdev_always_inline unsigned int +bfdev_ffsuf(unsigned long value) +{ + return bfdev_arch_ffsuf(value); +} +#endif + +#ifndef bfdev_flsuf +static __bfdev_always_inline unsigned int +bfdev_flsuf(unsigned long value) +{ + return bfdev_arch_flsuf(value); +} +#endif + +#ifndef bfdev_ffzuf +static __bfdev_always_inline unsigned int +bfdev_ffzuf(unsigned long value) +{ + return bfdev_arch_ffzuf(value); +} +#endif + +#ifndef bfdev_flzuf +static __bfdev_always_inline unsigned int +bfdev_flzuf(unsigned long value) +{ + return bfdev_arch_flzuf(value); +} +#endif + +#ifndef bfdev_ffs +static __bfdev_always_inline unsigned int +bfdev_ffs(unsigned long value) +{ + return bfdev_arch_ffs(value); +} +#endif + +#ifndef bfdev_fls +static __bfdev_always_inline unsigned int +bfdev_fls(unsigned long value) +{ + return bfdev_arch_fls(value); +} +#endif + +#ifndef bfdev_ffz +static __bfdev_always_inline unsigned int +bfdev_ffz(unsigned long value) +{ + return bfdev_arch_ffz(value); +} +#endif + +#ifndef bfdev_flz +static __bfdev_always_inline unsigned int +bfdev_flz(unsigned long value) +{ + return bfdev_arch_flz(value); +} +#endif + +#ifndef bfdev_ctz +static __bfdev_always_inline unsigned int +bfdev_ctz(unsigned long value) +{ + return bfdev_arch_ctz(value); +} +#endif + +#ifndef bfdev_clz +static __bfdev_always_inline unsigned int +bfdev_clz(unsigned long value) +{ + return bfdev_arch_clz(value); +} +#endif + +#ifndef bfdev_ffns +static __bfdev_always_inline unsigned int +bfdev_ffnsp(unsigned long word, unsigned int *nr) +{ + return bfdev_arch_ffnsp(word, nr); +} +#endif + +#ifndef bfdev_flns +static __bfdev_always_inline unsigned int +bfdev_flnsp(unsigned long word, unsigned int *nr) +{ + return bfdev_arch_flnsp(word, nr); +} +#endif + +#ifndef bfdev_ffnz +static __bfdev_always_inline unsigned int +bfdev_ffnzp(unsigned long word, unsigned int *nr) +{ + return bfdev_arch_ffnzp(word, nr); +} +#endif + +#ifndef bfdev_fznz +static __bfdev_always_inline unsigned int +bfdev_flnzp(unsigned long word, unsigned int *nr) +{ + return bfdev_arch_flnzp(word, nr); +} +#endif + +#ifndef bfdev_ffns +static __bfdev_always_inline unsigned int +bfdev_ffns(unsigned long word, unsigned int nr) +{ + return bfdev_ffnsp(word, &nr); +} +#endif + +#ifndef bfdev_flns +static __bfdev_always_inline unsigned int +bfdev_flns(unsigned long word, unsigned int nr) +{ + return bfdev_flnsp(word, &nr); +} +#endif + +#ifndef bfdev_ffnz +static __bfdev_always_inline unsigned int +bfdev_ffnz(unsigned long word, unsigned int nr) +{ + return bfdev_ffnzp(word, &nr); +} +#endif + +#ifndef bfdev_fznz +static __bfdev_always_inline unsigned int +bfdev_flnz(unsigned long word, unsigned int nr) +{ + return bfdev_flnzp(word, &nr); +} +#endif + +#if BFDEV_BITS_PER_LONG == 32 +static __bfdev_always_inline unsigned int +bfdev_ffsuf64(uint64_t value) +{ + uint32_t hi = value >> 32; + + if ((uint32_t)value) + return bfdev_ffsuf((uint32_t)value); + + return bfdev_ffsuf(hi) + 32; +} +#else +# define bfdev_ffsuf64 bfdev_ffsuf +#endif + +#if BFDEV_BITS_PER_LONG == 32 +static __bfdev_always_inline unsigned int +bfdev_flsuf64(uint64_t value) +{ + uint32_t hi = value >> 32; + + if (hi) + return bfdev_flsuf(hi) + 32; + + return bfdev_flsuf((uint32_t)value); +} +#else +# define bfdev_flsuf64 bfdev_flsuf +#endif + +#if BFDEV_BITS_PER_LONG == 32 +static __bfdev_always_inline unsigned int +bfdev_ffzuf64(uint64_t value) +{ + uint32_t hi = value >> 32; + + if ((uint32_t)value) + return bfdev_ffzuf((uint32_t)value); + + return bfdev_ffzuf(hi) + 32; +} +#else +# define bfdev_ffzuf64 bfdev_ffzuf +#endif + +#if BFDEV_BITS_PER_LONG == 32 +static __bfdev_always_inline unsigned int +bfdev_flzuf64(uint64_t value) +{ + uint32_t hi = value >> 32; + + if (hi) + return bfdev_flzuf(hi) + 32; + + return bfdev_flzuf((uint32_t)value); +} +#else +# define bfdev_flzuf64 bfdev_flzuf +#endif + +#if BFDEV_BITS_PER_LONG == 32 +static __bfdev_always_inline unsigned int +bfdev_ffs64(uint64_t value) +{ + uint32_t hi = value >> 32; + + if ((uint32_t)value) + return bfdev_ffs((uint32_t)value); + + return bfdev_ffs(hi) + 32; +} +#else +# define bfdev_ffs64 bfdev_ffs +#endif + +#if BFDEV_BITS_PER_LONG == 32 +static __bfdev_always_inline unsigned int +bfdev_fls64(uint64_t value) +{ + uint32_t hi = value >> 32; + + if (hi) + return bfdev_fls(hi) + 32; + + return bfdev_fls((uint32_t)value); +} +#else +# define bfdev_fls64 bfdev_fls +#endif + +#if BFDEV_BITS_PER_LONG == 32 +static __bfdev_always_inline unsigned int +bfdev_ffz64(uint64_t value) +{ + uint32_t hi = value >> 32; + + if ((uint32_t)value) + return bfdev_ffz((uint32_t)value); + + return bfdev_ffz(hi) + 32; +} +#else +# define bfdev_ffz64 bfdev_ffz +#endif + +#if BFDEV_BITS_PER_LONG == 32 +static __bfdev_always_inline unsigned int +bfdev_flz64(uint64_t value) +{ + uint32_t hi = value >> 32; + + if (hi) + return bfdev_flz(hi) + 32; + + return bfdev_flz((uint32_t)value); +} +#else +# define bfdev_flz64 bfdev_flz +#endif + +#if BFDEV_BITS_PER_LONG == 32 +static __bfdev_always_inline unsigned int +bfdev_ctz64(uint64_t value) +{ + uint32_t hi = value >> 32; + + if ((uint32_t)value) + return bfdev_ctz(value); + + return bfdev_ctz(hi) + 32; +} +#else +# define bfdev_ctz64 bfdev_ctz +#endif + +#if BFDEV_BITS_PER_LONG == 32 +static __bfdev_always_inline unsigned int +bfdev_clz64(uint64_t value) +{ + uint32_t hi = value >> 32; + + if (hi) + return bfdev_clz(hi); + + return bfdev_clz((uint32_t)value) + 32; +} +#else +# define bfdev_clz64 bfdev_clz +#endif + +#if BFDEV_BITS_PER_LONG == 32 +static __bfdev_always_inline unsigned int +bfdev_ffnsp64(uint64_t word, unsigned int *nr) +{ + uint32_t hi = word >> 32; + unsigned int bit; + + bit = bfdev_ffnsp((uint32_t)word, nr); + if (bit < BFDEV_BITS_PER_LONG) + return bit; + + return bfdev_ffnsp(hi, nr) + 32; +} +#else +# define bfdev_ffnsp64 bfdev_ffnsp +#endif + +#if BFDEV_BITS_PER_LONG == 32 +static __bfdev_always_inline unsigned int +bfdev_flnsp64(uint64_t word, unsigned int *nr) +{ + uint32_t hi = word >> 32; + unsigned int bit; + + bit = bfdev_flnsp(hi, nr); + if (bit < BFDEV_BITS_PER_LONG) + return bit + 32; + + return bfdev_flnsp((uint32_t)word, nr); +} +#else +# define bfdev_flnsp64 bfdev_flns +#endif + +#if BFDEV_BITS_PER_LONG == 32 +static __bfdev_always_inline unsigned int +bfdev_ffnzp64(uint64_t word, unsigned int *nr) +{ + uint32_t hi = word >> 32; + unsigned int bit; + + bit = bfdev_ffnzp((uint32_t)word, nr); + if (bit < BFDEV_BITS_PER_LONG) + return bit; + + return bfdev_ffnzp(hi, nr) + 32; +} +#else +# define bfdev_ffnzp64 bfdev_ffnzp +#endif + +#if BFDEV_BITS_PER_LONG == 32 +static __bfdev_always_inline unsigned int +bfdev_flnzp64(uint64_t word, unsigned int *nr) +{ + uint32_t hi = word >> 32; + unsigned int bit; + + bit = bfdev_flnzp(hi, nr); + if (bit < BFDEV_BITS_PER_LONG) + return bit + 32; + + return bfdev_flnzp((uint32_t)word, nr); +} +#else +# define bfdev_flnzp64 bfdev_flnzp +#endif + +#if BFDEV_BITS_PER_LONG == 32 +static __bfdev_always_inline unsigned int +bfdev_ffns64(uint64_t word, unsigned int nr) +{ + return bfdev_ffnsp64(word, &nr); +} +#else +# define bfdev_ffns64 bfdev_ffns +#endif + +#if BFDEV_BITS_PER_LONG == 32 +static __bfdev_always_inline unsigned int +bfdev_flns64(uint64_t word, unsigned int nr) +{ + return bfdev_flnsp64(word, &nr); +} +#else +# define bfdev_flns64 bfdev_flns +#endif + +#if BFDEV_BITS_PER_LONG == 32 +static __bfdev_always_inline unsigned int +bfdev_ffnz64(uint64_t word, unsigned int nr) +{ + return bfdev_ffnzp64(word, &nr); +} +#else +# define bfdev_ffnz64 bfdev_ffnz +#endif + +#if BFDEV_BITS_PER_LONG == 32 +static __bfdev_always_inline unsigned int +bfdev_flnz64(uint64_t word, unsigned int nr) +{ + return bfdev_flnzp64(word, &nr); +} +#else +# define bfdev_flnz64 bfdev_flnz +#endif + +BFDEV_END_DECLS + +#endif /* _BFDEV_BITOPS_H_ */ diff --git a/include/bfdev/bitrev.h b/include/bfdev/bitrev.h new file mode 100644 index 00000000..575303c0 --- /dev/null +++ b/include/bfdev/bitrev.h @@ -0,0 +1,210 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#ifndef _BFDEV_BITREV_H_ +#define _BFDEV_BITREV_H_ + +#include +#include + +BFDEV_BEGIN_DECLS + +/* + * Interface for known constant arguments + */ + +#define bfdev_bitrev8_const(value) ( \ + (((uint8_t)(value) & (uint8_t)0x01UL) << 7) | \ + (((uint8_t)(value) & (uint8_t)0x02UL) << 5) | \ + (((uint8_t)(value) & (uint8_t)0x04UL) << 3) | \ + (((uint8_t)(value) & (uint8_t)0x08UL) << 1) | \ + (((uint8_t)(value) & (uint8_t)0x10UL) >> 1) | \ + (((uint8_t)(value) & (uint8_t)0x20UL) >> 3) | \ + (((uint8_t)(value) & (uint8_t)0x40UL) >> 5) | \ + (((uint8_t)(value) & (uint8_t)0x80UL) >> 7)) + +#define bfdev_bitrev16_const(value) ( \ + (((uint16_t)(value) & (uint16_t)0x0001UL) << 15) | \ + (((uint16_t)(value) & (uint16_t)0x0002UL) << 13) | \ + (((uint16_t)(value) & (uint16_t)0x0004UL) << 11) | \ + (((uint16_t)(value) & (uint16_t)0x0008UL) << 9) | \ + (((uint16_t)(value) & (uint16_t)0x0010UL) << 7) | \ + (((uint16_t)(value) & (uint16_t)0x0020UL) << 5) | \ + (((uint16_t)(value) & (uint16_t)0x0040UL) << 3) | \ + (((uint16_t)(value) & (uint16_t)0x0080UL) << 1) | \ + (((uint16_t)(value) & (uint16_t)0x0100UL) >> 1) | \ + (((uint16_t)(value) & (uint16_t)0x0200UL) >> 3) | \ + (((uint16_t)(value) & (uint16_t)0x0400UL) >> 5) | \ + (((uint16_t)(value) & (uint16_t)0x0800UL) >> 7) | \ + (((uint16_t)(value) & (uint16_t)0x1000UL) >> 9) | \ + (((uint16_t)(value) & (uint16_t)0x2000UL) >> 11) | \ + (((uint16_t)(value) & (uint16_t)0x4000UL) >> 13) | \ + (((uint16_t)(value) & (uint16_t)0x8000UL) >> 15)) + +#define bfdev_bitrev32_const(value) ( \ + (((uint32_t)(value) & (uint32_t)0x00000001UL) << 31) | \ + (((uint32_t)(value) & (uint32_t)0x00000002UL) << 29) | \ + (((uint32_t)(value) & (uint32_t)0x00000004UL) << 27) | \ + (((uint32_t)(value) & (uint32_t)0x00000008UL) << 25) | \ + (((uint32_t)(value) & (uint32_t)0x00000010UL) << 23) | \ + (((uint32_t)(value) & (uint32_t)0x00000020UL) << 21) | \ + (((uint32_t)(value) & (uint32_t)0x00000040UL) << 19) | \ + (((uint32_t)(value) & (uint32_t)0x00000080UL) << 17) | \ + (((uint32_t)(value) & (uint32_t)0x00000100UL) << 15) | \ + (((uint32_t)(value) & (uint32_t)0x00000200UL) << 13) | \ + (((uint32_t)(value) & (uint32_t)0x00000400UL) << 11) | \ + (((uint32_t)(value) & (uint32_t)0x00000800UL) << 9) | \ + (((uint32_t)(value) & (uint32_t)0x00001000UL) << 7) | \ + (((uint32_t)(value) & (uint32_t)0x00002000UL) << 5) | \ + (((uint32_t)(value) & (uint32_t)0x00004000UL) << 3) | \ + (((uint32_t)(value) & (uint32_t)0x00008000UL) << 1) | \ + (((uint32_t)(value) & (uint32_t)0x00010000UL) >> 1) | \ + (((uint32_t)(value) & (uint32_t)0x00020000UL) >> 3) | \ + (((uint32_t)(value) & (uint32_t)0x00040000UL) >> 5) | \ + (((uint32_t)(value) & (uint32_t)0x00080000UL) >> 7) | \ + (((uint32_t)(value) & (uint32_t)0x00100000UL) >> 9) | \ + (((uint32_t)(value) & (uint32_t)0x00200000UL) >> 11) | \ + (((uint32_t)(value) & (uint32_t)0x00400000UL) >> 13) | \ + (((uint32_t)(value) & (uint32_t)0x00800000UL) >> 15) | \ + (((uint32_t)(value) & (uint32_t)0x01000000UL) >> 17) | \ + (((uint32_t)(value) & (uint32_t)0x02000000UL) >> 19) | \ + (((uint32_t)(value) & (uint32_t)0x04000000UL) >> 21) | \ + (((uint32_t)(value) & (uint32_t)0x08000000UL) >> 25) | \ + (((uint32_t)(value) & (uint32_t)0x10000000UL) >> 23) | \ + (((uint32_t)(value) & (uint32_t)0x20000000UL) >> 27) | \ + (((uint32_t)(value) & (uint32_t)0x40000000UL) >> 29) | \ + (((uint32_t)(value) & (uint32_t)0x80000000UL) >> 31)) + +#define bfdev_bitrev64_const(value) ( \ + (((uint64_t)(value) & (uint64_t)0x0000000000000001ULL) << 63) | \ + (((uint64_t)(value) & (uint64_t)0x0000000000000002ULL) << 61) | \ + (((uint64_t)(value) & (uint64_t)0x0000000000000004ULL) << 59) | \ + (((uint64_t)(value) & (uint64_t)0x0000000000000008ULL) << 57) | \ + (((uint64_t)(value) & (uint64_t)0x0000000000000010ULL) << 55) | \ + (((uint64_t)(value) & (uint64_t)0x0000000000000020ULL) << 53) | \ + (((uint64_t)(value) & (uint64_t)0x0000000000000040ULL) << 51) | \ + (((uint64_t)(value) & (uint64_t)0x0000000000000080ULL) << 49) | \ + (((uint64_t)(value) & (uint64_t)0x0000000000000100ULL) << 47) | \ + (((uint64_t)(value) & (uint64_t)0x0000000000000200ULL) << 45) | \ + (((uint64_t)(value) & (uint64_t)0x0000000000000400ULL) << 43) | \ + (((uint64_t)(value) & (uint64_t)0x0000000000000800ULL) << 41) | \ + (((uint64_t)(value) & (uint64_t)0x0000000000001000ULL) << 39) | \ + (((uint64_t)(value) & (uint64_t)0x0000000000002000ULL) << 37) | \ + (((uint64_t)(value) & (uint64_t)0x0000000000004000ULL) << 35) | \ + (((uint64_t)(value) & (uint64_t)0x0000000000008000ULL) << 33) | \ + (((uint64_t)(value) & (uint64_t)0x0000000000010000ULL) << 31) | \ + (((uint64_t)(value) & (uint64_t)0x0000000000020000ULL) << 29) | \ + (((uint64_t)(value) & (uint64_t)0x0000000000040000ULL) << 27) | \ + (((uint64_t)(value) & (uint64_t)0x0000000000080000ULL) << 25) | \ + (((uint64_t)(value) & (uint64_t)0x0000000000100000ULL) << 23) | \ + (((uint64_t)(value) & (uint64_t)0x0000000000200000ULL) << 21) | \ + (((uint64_t)(value) & (uint64_t)0x0000000000400000ULL) << 19) | \ + (((uint64_t)(value) & (uint64_t)0x0000000000800000ULL) << 17) | \ + (((uint64_t)(value) & (uint64_t)0x0000000001000000ULL) << 15) | \ + (((uint64_t)(value) & (uint64_t)0x0000000002000000ULL) << 13) | \ + (((uint64_t)(value) & (uint64_t)0x0000000004000000ULL) << 11) | \ + (((uint64_t)(value) & (uint64_t)0x0000000008000000ULL) << 9) | \ + (((uint64_t)(value) & (uint64_t)0x0000000010000000ULL) << 7) | \ + (((uint64_t)(value) & (uint64_t)0x0000000020000000ULL) << 5) | \ + (((uint64_t)(value) & (uint64_t)0x0000000040000000ULL) << 3) | \ + (((uint64_t)(value) & (uint64_t)0x0000000080000000ULL) << 1) | \ + (((uint64_t)(value) & (uint64_t)0x0000000100000000ULL) >> 1) | \ + (((uint64_t)(value) & (uint64_t)0x0000000200000000ULL) >> 3) | \ + (((uint64_t)(value) & (uint64_t)0x0000000400000000ULL) >> 5) | \ + (((uint64_t)(value) & (uint64_t)0x0000000800000000ULL) >> 7) | \ + (((uint64_t)(value) & (uint64_t)0x0000001000000000ULL) >> 9) | \ + (((uint64_t)(value) & (uint64_t)0x0000002000000000ULL) >> 11) | \ + (((uint64_t)(value) & (uint64_t)0x0000004000000000ULL) >> 13) | \ + (((uint64_t)(value) & (uint64_t)0x0000008000000000ULL) >> 15) | \ + (((uint64_t)(value) & (uint64_t)0x0000010000000000ULL) >> 17) | \ + (((uint64_t)(value) & (uint64_t)0x0000020000000000ULL) >> 19) | \ + (((uint64_t)(value) & (uint64_t)0x0000040000000000ULL) >> 21) | \ + (((uint64_t)(value) & (uint64_t)0x0000080000000000ULL) >> 25) | \ + (((uint64_t)(value) & (uint64_t)0x0000100000000000ULL) >> 23) | \ + (((uint64_t)(value) & (uint64_t)0x0000200000000000ULL) >> 27) | \ + (((uint64_t)(value) & (uint64_t)0x0000400000000000ULL) >> 29) | \ + (((uint64_t)(value) & (uint64_t)0x0000800000000000ULL) >> 31) | \ + (((uint64_t)(value) & (uint64_t)0x0001000000000000ULL) >> 33) | \ + (((uint64_t)(value) & (uint64_t)0x0002000000000000ULL) >> 35) | \ + (((uint64_t)(value) & (uint64_t)0x0004000000000000ULL) >> 37) | \ + (((uint64_t)(value) & (uint64_t)0x0008000000000000ULL) >> 39) | \ + (((uint64_t)(value) & (uint64_t)0x0010000000000000ULL) >> 41) | \ + (((uint64_t)(value) & (uint64_t)0x0020000000000000ULL) >> 43) | \ + (((uint64_t)(value) & (uint64_t)0x0040000000000000ULL) >> 45) | \ + (((uint64_t)(value) & (uint64_t)0x0080000000000000ULL) >> 47) | \ + (((uint64_t)(value) & (uint64_t)0x0100000000000000ULL) >> 49) | \ + (((uint64_t)(value) & (uint64_t)0x0200000000000000ULL) >> 51) | \ + (((uint64_t)(value) & (uint64_t)0x0400000000000000ULL) >> 53) | \ + (((uint64_t)(value) & (uint64_t)0x0800000000000000ULL) >> 55) | \ + (((uint64_t)(value) & (uint64_t)0x1000000000000000ULL) >> 57) | \ + (((uint64_t)(value) & (uint64_t)0x2000000000000000ULL) >> 59) | \ + (((uint64_t)(value) & (uint64_t)0x4000000000000000ULL) >> 61) | \ + (((uint64_t)(value) & (uint64_t)0x8000000000000000ULL) >> 63)) + +/* + * Interface for known dynamic arguments + */ + +extern const uint8_t +bfdev_bitrev_byte_table[256]; + +static inline uint8_t +bfdev_bitrev8_dynamic(uint8_t value) +{ + return bfdev_bitrev_byte_table[value]; +} + +static inline uint16_t +bfdev_bitrev16_dynamic(uint16_t value) +{ + return ((uint16_t)bfdev_bitrev8_dynamic(value & 0xff) << 8) | + bfdev_bitrev8_dynamic(value >> 8); +} + +static inline uint32_t +bfdev_bitrev32_dynamic(uint32_t value) +{ + return ((uint32_t)bfdev_bitrev16_dynamic(value & 0xffff) << 16) | + bfdev_bitrev16_dynamic(value >> 16); +} + +static inline uint64_t +bfdev_bitrev64_dynamic(uint64_t value) +{ + return ((uint64_t)bfdev_bitrev32_dynamic(value & 0xffffffff) << 32) | + bfdev_bitrev32_dynamic(value >> 32); +} + +#define bfdev_bitrev8(value) ({ \ + uint8_t __value = (uint8_t)(value); \ + __builtin_constant_p(__value) \ + ? bfdev_bitrev8_const(__value) \ + : bfdev_bitrev8_dynamic(__value); \ +}) + +#define bfdev_bitrev16(value) ({ \ + uint16_t __value = (uint16_t)(value); \ + __builtin_constant_p(__value) \ + ? bfdev_bitrev16_const(__value) \ + : bfdev_bitrev16_dynamic(__value); \ +}) + +#define bfdev_bitrev32(value) ({ \ + uint32_t __value = (uint32_t)(value); \ + __builtin_constant_p(__value) \ + ? bfdev_bitrev32_const(__value) \ + : bfdev_bitrev32_dynamic(__value); \ +}) + +#define bfdev_bitrev64(value) ({ \ + uint64_t __value = (uint64_t)(value); \ + __builtin_constant_p(__value) \ + ? bfdev_bitrev64_const(__value) \ + : bfdev_bitrev64_dynamic(__value); \ +}) + +BFDEV_END_DECLS + +#endif /* _BFDEV_BITREV_H_ */ diff --git a/include/bfdev/bits.h b/include/bfdev/bits.h new file mode 100644 index 00000000..53433843 --- /dev/null +++ b/include/bfdev/bits.h @@ -0,0 +1,107 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#ifndef _BFDEV_BITS_H_ +#define _BFDEV_BITS_H_ + +#include +#include +#include +#include + +BFDEV_BEGIN_DECLS + +#define BFDEV_BITS_PER_BYTE __CHAR_BIT__ +#define BFDEV_BITS_PER_TYPE(type) (sizeof(type) * BFDEV_BITS_PER_BYTE) +#define BFDEV_BITS_WORD(bit) ((bit) / BFDEV_BITS_PER_LONG) + +#define BFDEV_BITS_PER_U8 BFDEV_BITS_PER_TYPE(uint8_t) +#define BFDEV_BITS_PER_U16 BFDEV_BITS_PER_TYPE(uint16_t) +#define BFDEV_BITS_PER_U32 BFDEV_BITS_PER_TYPE(uint32_t) +#define BFDEV_BITS_PER_U64 BFDEV_BITS_PER_TYPE(uint64_t) + +#define BFDEV_BITS_PER_SHORT BFDEV_BITS_PER_TYPE(short) +#define BFDEV_BITS_PER_INT BFDEV_BITS_PER_TYPE(int) +#define BFDEV_BITS_PER_LONG_LONG BFDEV_BITS_PER_TYPE(long long) + +/** + * BFDEV_BIT_LOW_MASK - create a low position mask. + * @nbits: mask length. + * For example: + * BFDEV_BIT_LOW_MASK(8) gives us the vector 0x000000ff. + */ +#define BFDEV_BIT_LOW_MASK(nbits) ( \ + ULONG_MAX >> \ + (-(nbits) & (BFDEV_BITS_PER_LONG - 1)) \ +) + +/** + * BFDEV_BIT_HIGH_MASK - create a high position mask. + * @nbits: mask length. + * For example: + * BFDEV_BIT_HIGH_MASK(8) gives us the vector 0xffffff00. + */ +#define BFDEV_BIT_HIGH_MASK(nbits) ( \ + ULONG_MAX << \ + ((nbits) & (BFDEV_BITS_PER_LONG - 1)) \ +) + +/** + * BFDEV_BIT - create a bitmask (long). + * @nr: bit position. + */ +#define BFDEV_BIT(nr) ( \ + (1UL) << ((nr) % BFDEV_BITS_PER_LONG) \ +) + +/** + * BFDEV_BIT_ULL - create a bitmask (long long). + * @nr: bit position. + */ +#define BFDEV_BIT_ULL(nr) ( \ + (1ULL) << ((nr) % BFDEV_BITS_PER_LONG_LONG) \ +) + +/** + * BFDEV_BIT_SHIFT - create a shifted bitmask (long). + * @shift: bitmask position + * @val: bitmask value. + */ +#define BFDEV_BIT_SHIFT(shift, val) ( \ + (val) << ((shift) % BFDEV_BITS_PER_LONG) \ +) + +/** + * BFDEV_BIT_SHIFT_ULL - create a shifted bitmask (long long). + * @shift: bitmask position. + * @val: bitmask value. + */ +#define BFDEV_BIT_SHIFT_ULL(shift, val) ( \ + (val) << ((shift) % BFDEV_BITS_PER_LONG_LONG) \ +) + +/** + * BFDEV_BIT_RANGE - create a contiguous bitmask (long) + * @hi: ending position + * @lo: starting position + */ +#define BFDEV_BIT_RANGE(hi, lo) ( \ + ((~0UL) - (1UL << (lo)) + 1) & \ + (~0UL >> (BFDEV_BITS_PER_LONG - 1 - (hi))) \ +) + +/** + * BFDEV_BIT_RANGE_ULL - create a contiguous bitmask (long long) + * @hi: ending position + * @lo: starting position + */ +#define BFDEV_BIT_RANGE_ULL(hi, lo) ( \ + ((~0ULL) - (1ULL << (lo)) + 1) & \ + (~0ULL >> (BFDEV_BITS_PER_LONG_LONG - 1 - (hi))) \ +) + +BFDEV_END_DECLS + +#endif /* _BFDEV_BITS_H_ */ diff --git a/include/bfdev/bitsperlong.h b/include/bfdev/bitsperlong.h new file mode 100644 index 00000000..5612a3a5 --- /dev/null +++ b/include/bfdev/bitsperlong.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#ifndef _BFDEV_BITSPERLONG_H_ +#define _BFDEV_BITSPERLONG_H_ + +#include + +BFDEV_BEGIN_DECLS + +#if __SIZEOF_POINTER__ == 4 +# define BFDEV_BITS_PER_LONG 32 +#else /* __SIZEOF_POINTER__ == 8 */ +# define BFDEV_BITS_PER_LONG 64 +#endif /* __SIZEOF_POINTER__ == 8 */ + +#define bfdev_const_small_nbits(nbits) ( \ + __builtin_constant_p(nbits) && (nbits) <= \ + BFDEV_BITS_PER_LONG && (nbits) > 0 \ +) + +BFDEV_END_DECLS + +#endif /* _BFDEV_BITSPERLONG_H_ */ diff --git a/include/bfdev/bitwalk.h b/include/bfdev/bitwalk.h new file mode 100644 index 00000000..6f5688b5 --- /dev/null +++ b/include/bfdev/bitwalk.h @@ -0,0 +1,223 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#ifndef _BFDEV_BITWALK_H_ +#define _BFDEV_BITWALK_H_ + +#include +#include +#include + +BFDEV_BEGIN_DECLS + +/** + * bfdev_comp_find_first_bit - complex find first bit in a region. + * @block: the block to find. + * @bits: number of bits in the block. + * @swap: byte swap in the block. + */ +extern unsigned int +bfdev_comp_find_first_bit(const unsigned long *block, unsigned int bits, bool swap); + +/** + * bfdev_comp_find_last_bit - complex find last bit in a region. + * @block: the block to find. + * @bits: number of bits in the block. + * @swap: byte swap in the block. + */ +extern unsigned int +bfdev_comp_find_last_bit(const unsigned long *block, unsigned int bits, bool swap); + +/** + * bfdev_comp_find_first_zero - complex find first zero in a region. + * @block: the block to find. + * @bits: number of bits in the block. + * @swap: byte swap in the block. + */ +extern unsigned int +bfdev_comp_find_first_zero(const unsigned long *block, unsigned int bits, bool swap); + +/** + * bfdev_comp_find_last_zero - complex find last zero in a region. + * @block: the block to find. + * @bits: number of bits in the block. + * @swap: byte swap in the block. + */ +extern unsigned int +bfdev_comp_find_last_zero(const unsigned long *block, unsigned int bits, bool swap); + +/** + * bfdev_comp_find_last_zero - complex find last zero in a region. + * @block: the block to find. + * @bits: number of bits in the block. + * @swap: byte swap in the block. + */ +extern unsigned int +bfdev_comp_find_next_bit(const unsigned long *addr1, const unsigned long *addr2, + unsigned int bits, unsigned int start, + unsigned long invert, bool swap); + +extern unsigned int +bfdev_comp_find_prev_bit(const unsigned long *addr1, const unsigned long *addr2, + unsigned int bits, unsigned int start, + unsigned long invert, bool swap); + +#ifndef bfdev_find_first_bit +static inline unsigned int +bfdev_find_first_bit(const unsigned long *addr, unsigned int bits) +{ + if (bfdev_const_small_nbits(bits)) + return *addr ? bfdev_ffsuf(*addr & BFDEV_BIT_LOW_MASK(bits)) : bits; + else + return bfdev_comp_find_first_bit(addr, bits, false); +} +#endif + +#ifndef bfdev_find_last_bit +static inline unsigned int +bfdev_find_last_bit(const unsigned long *addr, unsigned int bits) +{ + if (bfdev_const_small_nbits(bits)) + return *addr ? bfdev_ffsuf(*addr & BFDEV_BIT_LOW_MASK(bits)) : bits; + else + return bfdev_comp_find_last_bit(addr, bits, false); +} +#endif + +#ifndef bfdev_find_first_zero +static inline unsigned int +bfdev_find_first_zero(const unsigned long *addr, unsigned int bits) +{ + if (bfdev_const_small_nbits(bits)) + return *addr ? bfdev_ffz(*addr | BFDEV_BIT_HIGH_MASK(bits)) : bits; + else + return bfdev_comp_find_first_zero(addr, bits, false); +} +#endif + +#ifndef bfdev_find_last_zero +static inline unsigned int +bfdev_find_last_zero(const unsigned long *addr, unsigned int bits) +{ + if (bfdev_const_small_nbits(bits)) + return *addr ? bfdev_flz(*addr | BFDEV_BIT_HIGH_MASK(bits)) : bits; + else + return bfdev_comp_find_last_zero(addr, bits, false); +} +#endif + +#ifndef bfdev_find_next_bit +static inline unsigned int +bfdev_find_next_bit(const unsigned long *addr, unsigned int bits, unsigned int offset) +{ + if (bfdev_const_small_nbits(bits)) { + unsigned long val; + + if (bfdev_unlikely(offset >= bits)) + return bits; + + val = *addr & BFDEV_BIT_RANGE(bits - 1, offset); + return val ? bfdev_ffsuf(val) : bits; + } + + return bfdev_comp_find_next_bit(addr, NULL, bits, offset, 0UL, false); +} +#endif + +#ifndef bfdev_find_prev_bit +static inline unsigned int +bfdev_find_prev_bit(const unsigned long *addr, unsigned int bits, unsigned int offset) +{ + if (bfdev_const_small_nbits(bits)) { + unsigned long val; + + if (bfdev_unlikely(offset >= bits)) + return bits; + + val = *addr & BFDEV_BIT_RANGE(bits - 1, offset); + return val ? bfdev_flsuf(val) : bits; + } + + return bfdev_comp_find_prev_bit(addr, NULL, bits, offset, 0UL, false); +} +#endif + +#ifndef bfdev_find_next_zero +static inline unsigned int +bfdev_find_next_zero(const unsigned long *addr, unsigned int bits, unsigned int offset) +{ + if (bfdev_const_small_nbits(bits)) { + unsigned long val; + + if (bfdev_unlikely(offset >= bits)) + return bits; + + val = *addr | ~BFDEV_BIT_RANGE(bits - 1, offset); + return val ? bfdev_ffzuf(val) : bits; + } + + return bfdev_comp_find_next_bit(addr, NULL, bits, offset, ~0UL, false); +} +#endif + +#ifndef bfdev_find_prev_zero +static inline unsigned int +bfdev_find_prev_zero(const unsigned long *addr, unsigned int bits, unsigned int offset) +{ + if (bfdev_const_small_nbits(bits)) { + unsigned long val; + + if (bfdev_unlikely(offset >= bits)) + return bits; + + val = *addr | ~BFDEV_BIT_RANGE(bits - 1, offset); + return val ? bfdev_flzuf(val) : bits; + } + + return bfdev_comp_find_prev_bit(addr, NULL, bits, offset, ~0UL, false); +} +#endif + +#ifndef bfdev_find_next_and_bit +static inline unsigned int +bfdev_find_next_and_bit(const unsigned long *addr1, const unsigned long *addr2, + unsigned int bits, unsigned int offset) +{ + if (bfdev_const_small_nbits(bits)) { + unsigned long val; + + if (bfdev_unlikely(offset >= bits)) + return bits; + + val = *addr1 & *addr2 & BFDEV_BIT_RANGE(bits - 1, offset); + return val ? bfdev_ffsuf(val) : bits; + } + + return bfdev_comp_find_next_bit(addr1, addr2, bits, offset, 0UL, false); +} +#endif + +#ifndef bfdev_find_prev_and_bit +static inline unsigned int +bfdev_find_prev_and_bit(const unsigned long *addr1, const unsigned long *addr2, + unsigned int bits, unsigned int offset) +{ + if (bfdev_const_small_nbits(bits)) { + unsigned long val; + + if (bfdev_unlikely(offset >= bits)) + return bits; + + val = *addr1 & *addr2 & BFDEV_BIT_RANGE(bits - 1, offset); + return val ? bfdev_flsuf(val) : bits; + } + + return bfdev_comp_find_prev_bit(addr1, addr2, bits, offset, 0UL, false); +} +#endif + +BFDEV_END_DECLS + +#endif /* _BFDEV_BITWALK_H_ */ diff --git a/include/bfdev/bloom.h b/include/bfdev/bloom.h new file mode 100644 index 00000000..8003fb2d --- /dev/null +++ b/include/bfdev/bloom.h @@ -0,0 +1,76 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#ifndef _BFDEV_BLOOM_H_ +#define _BFDEV_BLOOM_H_ + +#include +#include +#include +#include + +BFDEV_BEGIN_DECLS + +typedef unsigned int (*bfdev_bloom_hash_t) +(unsigned int func, const void *key, void *pdata); + +struct bfdev_bloom { + const struct bfdev_alloc *alloc; + bfdev_bloom_hash_t hash; + unsigned int funcs; + void *pdata; + + unsigned int capacity; + unsigned long bitmap[]; +}; + +/** + * bfdev_bloom_peek() - peek an object from a bloom filter. + * @bloom: bloom filter pointer. + * @key: object pointer. + * + * @return: object value. + */ +extern bool +bfdev_bloom_peek(struct bfdev_bloom *bloom, void *key); + +/** + * bfdev_bloom_push() - push an object from a bloom filter. + * @bloom: bloom filter pointer. + * @key: object pointer to push. + * + * @return: object value before push. + */ +extern bool +bfdev_bloom_push(struct bfdev_bloom *bloom, void *key); + +/** + * bfdev_bloom_flush() - flush the entire bloom filter. + * @bloom: bloom filter pointer. + */ +extern void +bfdev_bloom_flush(struct bfdev_bloom *bloom); + +/** + * bfdev_bloom_create() - creat a bloom filter. + * @capacity: capacity size of bloom filter. + * @hash: object hash callback function. + * @funcs: number of supported hash algorithms. + * @pdata: private data pointer of @hash. + */ +extern struct bfdev_bloom * +bfdev_bloom_create(const struct bfdev_alloc *alloc, unsigned int capacity, + bfdev_bloom_hash_t hash, unsigned int funcs, void *pdata); + +/** + * bfdev_bloom_destory() - destory a bloom filter. + * @bloom: bloom filter pointer. + */ +extern void +bfdev_bloom_destory(struct bfdev_bloom *bloom); + +BFDEV_END_DECLS + +#endif /* _BFDEV_BLOOM_H_ */ diff --git a/include/bfdev/bsearch.h b/include/bfdev/bsearch.h new file mode 100644 index 00000000..609aa5b1 --- /dev/null +++ b/include/bfdev/bsearch.h @@ -0,0 +1,54 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#ifndef _BFDEV_BSEARCH_H_ +#define _BFDEV_BSEARCH_H_ + +#include +#include +#include + +BFDEV_BEGIN_DECLS + +static inline void * +bfdev_bsearch_inline(const void *base, size_t num, size_t esize, + bfdev_find_t find, void *pdata) +{ + const void *pivot; + long result; + + while (num) { + pivot = base + (num >> 1) * esize; + result = find(pivot, pdata); + + if (!result) + return (void *)pivot; + + if (result < 0) { + base = pivot + esize; + num--; + } + + num >>= 1; + } + + return NULL; +} + +/** + * bfdev_bsearch() - binary search an array of elements. + * @base: pointer to first element to search. + * @num: number of elements. + * @esize: size of each element. + * @cmp: pointer to comparison function. + * @pdata: pointer to item being searched for. + */ +extern void * +bfdev_bsearch(const void *base, size_t num, size_t esize, + bfdev_find_t find, void *pdata); + +BFDEV_END_DECLS + +#endif /* _BFDEV_BSEARCH_H_ */ diff --git a/include/bfdev/btree.h b/include/bfdev/btree.h new file mode 100644 index 00000000..8d6707e0 --- /dev/null +++ b/include/bfdev/btree.h @@ -0,0 +1,268 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2022 John Sanpe + */ + +#ifndef _BFDEV_BTREE_H_ +#define _BFDEV_BTREE_H_ + +#include +#include +#include +#include +#include + +BFDEV_BEGIN_DECLS + +struct bfdev_btree_layout { + unsigned int keylen; + unsigned int keynum; + unsigned int ptrindex; + size_t nodesize; +}; + +struct bfdev_btree_node { + uintptr_t block[0]; +}; + +struct bfdev_btree_root { + const struct bfdev_alloc *alloc; + struct bfdev_btree_layout *layout; + struct bfdev_btree_node *node; + unsigned int height; + + const struct bfdev_btree_ops *ops; + void *pdata; +}; + +struct bfdev_btree_ops { + void *(*alloc)(struct bfdev_btree_root *root); + void (*free)(struct bfdev_btree_root *root, void *block); + long (*find)(struct bfdev_btree_root *root, uintptr_t *node, uintptr_t *key); + int (*clash)(struct bfdev_btree_root *root, void *clash, void *value); + void *(*remove)(struct bfdev_btree_root *root, void *value); +}; + +#define BFDEV_BTREE_STATIC(LAYOUT, OPS, PDATA) \ + {.layout = (LAYOUT), .ops = (OPS), .pdata = (PDATA)} + +#define BFDEV_BTREE_INIT(layout, ops, pdata) \ + (struct bfdev_btree_root) BFDEV_BTREE_STATIC(layout, ops, pdata) + +#define BFDEV_BTREE_ROOT(name, layout, ops, pdata) \ + struct bfdev_btree_root name = BFDEV_BTREE_INIT(layout, ops, pdata) + +extern struct bfdev_btree_layout +bfdev_btree_layout32; + +extern struct bfdev_btree_layout +bfdev_btree_layout64; + +extern struct bfdev_btree_layout +bfdev_btree_layoutptr; + +static inline void +bfdev_btree_init(struct bfdev_btree_root *root, + struct bfdev_btree_layout *layout, + struct bfdev_btree_ops *ops, void *pdata) +{ + *root = BFDEV_BTREE_INIT(layout, ops, pdata); +} + +extern long +bfdev_btree_key_find(struct bfdev_btree_root *root, + uintptr_t *node, uintptr_t *key); + +extern void * +bfdev_btree_alloc(struct bfdev_btree_root *root); + +extern void +bfdev_btree_free(struct bfdev_btree_root *root, void *node); + +extern void * +bfdev_btree_lookup(struct bfdev_btree_root *root, uintptr_t *key); + +extern int +bfdev_btree_update(struct bfdev_btree_root *root, + uintptr_t *key, void *value); + +extern int +bfdev_btree_insert(struct bfdev_btree_root *root, + uintptr_t *key, void *value); + +extern void * +bfdev_btree_remove(struct bfdev_btree_root *root, + uintptr_t *key); + +extern void +bfdev_btree_destroy(struct bfdev_btree_root *root); + +extern void +bfdev_btree_key_copy(struct bfdev_btree_root *root, + uintptr_t *dest, uintptr_t *src); + +extern void * +bfdev_btree_first(struct bfdev_btree_root *root, + uintptr_t *key); + +extern void * +bfdev_btree_last(struct bfdev_btree_root *root, + uintptr_t *key); + +extern void * +bfdev_btree_next(struct bfdev_btree_root *root, + uintptr_t *key); + +extern void * +bfdev_btree_prev(struct bfdev_btree_root *root, + uintptr_t *key); + +/** + * bfdev_btree_for_each - iterate over a btree. + * @root: the root for your btree. + * @key: the &key to use as a loop cursor. + * @value: the value of current loop cursor. + */ +#define bfdev_btree_for_each(root, key, value) \ + for (value = bfdev_btree_first(root, key); \ + value; value = bfdev_btree_next(root, key)) + +/** + * bfdev_btree_for_each_reverse - iterate over a btree backwards. + * @root: the root for your btree. + * @key: the &key to use as a loop cursor. + * @value: the value of current loop cursor. + */ +#define bfdev_btree_for_each_reverse(root, key, value) \ + for (value = bfdev_btree_last(root, key); \ + value; value = bfdev_btree_prev(root, key)) + +/** + * bfdev_btree_for_each_from - iterate over a btree from the current point. + * @root: the root for your btree. + * @key: the &key to use as a loop cursor. + * @value: the value of current loop cursor. + */ +#define bfdev_btree_for_each_from(root, key, value) \ + for (; value; value = bfdev_btree_next(root, key)) + +/** + * bfdev_btree_for_each_reverse_from - iterate over a btree backwards from the current point. + * @root: the root for your btree. + * @key: the &key to use as a loop cursor. + * @value: the value of current loop cursor. + */ +#define bfdev_btree_for_each_reverse_from(root, key, value) \ + for (; value; value = bfdev_btree_prev(root, key)) + +/** + * bfdev_btree_for_each_continue - continue iteration over a btree. + * @root: the root for your btree. + * @key: the &key to use as a loop cursor. + * @value: the value of current loop cursor. + */ +#define bfdev_btree_for_each_continue(root, key, value) \ + for (value = bfdev_btree_next(root, key); \ + value; value = bfdev_btree_next(root, key)) + +/** + * bfdev_btree_for_each_reverse_continue - continue iteration over a btree backwards. + * @root: the root for your btree. + * @key: the &key to use as a loop cursor. + * @value: the value of current loop cursor. + */ +#define bfdev_btree_for_each_reverse_continue(root, key, value) \ + for (value = bfdev_btree_prev(root, key); \ + value; value = bfdev_btree_prev(root, key)) + +/** + * bfdev_btree_for_each_safe - iterate over btree safe against removal. + * @root: the root for your btree. + * @key: the &key to use as a loop cursor. + * @value: the value of current loop cursor. + * @tkey: another &key to use as temporary storage. + * @tval: another value to use as temporary storage. + */ +#define bfdev_btree_for_each_safe(root, key, value, tkey, tval) \ + for ((void)((value = bfdev_btree_first(root, key)) && \ + (bfdev_btree_key_copy(root, tkey, key), \ + tval = bfdev_btree_next(root, tkey))); value; \ + bfdev_btree_key_copy(root, key, tkey), \ + value = tval, tval = bfdev_btree_next(root, tkey)) + +/** + * bfdev_btree_for_each_reverse_safe - iterate backwards over btree safe against removal. + * @root: the root for your btree. + * @key: the &key to use as a loop cursor. + * @value: the value of current loop cursor. + * @tkey: another &key to use as temporary storage. + * @tval: another value to use as temporary storage. + */ +#define bfdev_btree_for_each_reverse_safe(root, key, value, tkey, tval) \ + for ((void)((value = bfdev_btree_last(root, key)) && \ + (bfdev_btree_key_copy(root, tkey, key), \ + tval = bfdev_btree_prev(root, tkey))); value; \ + bfdev_btree_key_copy(root, key, tkey), \ + value = tval, tval = bfdev_btree_prev(root, tkey)) + +/** + * bfdev_btree_for_each_from_safe - iterate over btree from current point safe against removal. + * @root: the root for your btree. + * @key: the &key to use as a loop cursor. + * @value: the value of current loop cursor. + * @tkey: another &key to use as temporary storage. + * @tval: another value to use as temporary storage. + */ +#define bfdev_btree_for_each_from_safe(root, key, value, tkey, tval) \ + for (btree_key_copy(root, tkey, key), \ + tval = bfdev_btree_next(root, tkey); value; \ + bfdev_btree_key_copy(root, key, tkey), \ + value = tval, tval = bfdev_btree_next(root, tkey)) + +/** + * bfdev_btree_for_each_reverse_from_safe - iterate backwards over btree from current point safe against removal. + * @root: the root for your btree. + * @key: the &key to use as a loop cursor. + * @value: the value of current loop cursor. + * @tkey: another &key to use as temporary storage. + * @tval: another value to use as temporary storage. + */ +#define bfdev_btree_for_each_reverse_from_safe(root, key, value, tkey, tval) \ + for (btree_key_copy(root, tkey, key), \ + tval = bfdev_btree_prev(root, tkey); value; \ + bfdev_btree_key_copy(root, key, tkey), \ + value = tval, tval = bfdev_btree_prev(root, tkey)) + +/** + * bfdev_btree_for_each_continue_safe - continue btree iteration safe against removal. + * @root: the root for your btree. + * @key: the &key to use as a loop cursor. + * @value: the value of current loop cursor. + * @tkey: another &key to use as temporary storage. + * @tval: another value to use as temporary storage. + */ +#define bfdev_btree_for_each_continue_safe(root, key, value, tkey, tval) \ + for ((void)((value = bfdev_btree_next(root, key)) && \ + (bfdev_btree_key_copy(root, tkey, key), \ + tval = bfdev_btree_next(root, tkey))); value; \ + bfdev_btree_key_copy(root, key, tkey), \ + value = tval, tval = bfdev_btree_next(root, tkey)) + +/** + * bfdev_btree_for_each_reverse_continue_safe - continue backwards over btree iteration safe against removal. + * @root: the root for your btree. + * @key: the &key to use as a loop cursor. + * @value: the value of current loop cursor. + * @tkey: another &key to use as temporary storage. + * @tval: another value to use as temporary storage. + */ +#define bfdev_btree_for_each_reverse_continue_safe(root, key, value, tkey, tval) \ + for ((void)((value = bfdev_btree_prev(root, key)) && \ + (bfdev_btree_key_copy(root, tkey, key), \ + tval = bfdev_btree_prev(root, tkey))); value; \ + bfdev_btree_key_copy(root, key, tkey), \ + value = tval, tval = bfdev_btree_prev(root, tkey)) + +BFDEV_END_DECLS + +#endif /* _BFDEV_BTREE_H_ */ diff --git a/include/bfdev/byteorder.h b/include/bfdev/byteorder.h new file mode 100644 index 00000000..4f247933 --- /dev/null +++ b/include/bfdev/byteorder.h @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#ifndef _BFDEV_BYTEORDER_H_ +#define _BFDEV_BYTEORDER_H_ + +#include +#include +#include + +BFDEV_BEGIN_DECLS + +#define _bfdev_cpu_to_le_type(type) bfdev_cpu_to_le##type +#define bfdev_cpu_to_le_type(type) _bfdev_cpu_to_le_type(type) +#define _bfdev_cpu_to_be_type(type) bfdev_cpu_to_be##type +#define bfdev_cpu_to_be_type(type) _bfdev_cpu_to_be_type(type) +#define _bfdev_le_type_to_cpu(type) bfdev_le##type##_to_cpu +#define bfdev_le_type_to_cpu(type) _bfdev_le_type_to_cpu(type) +#define _bfdev_be_type_to_cpu(type) bfdev_be##type##_to_cpu +#define bfdev_be_type_to_cpu(type) _bfdev_be_type_to_cpu(type) + +#define bfdev_cpu_to_le_short(val) bfdev_cpu_to_le_type(BFDEV_BITS_PER_SHORT)(val) +#define bfdev_cpu_to_le_int(val) bfdev_cpu_to_le_type(BFDEV_BITS_PER_INT)(val) +#define bfdev_cpu_to_le_long(val) bfdev_cpu_to_le_type(BFDEV_BITS_PER_LONG)(val) +#define bfdev_cpu_to_le_long_long(val) bfdev_cpu_to_le_type(BFDEV_BITS_PER_LONG_LONG)(val) + +#define bfdev_cpu_to_be_short(val) bfdev_cpu_to_be_type(BFDEV_BITS_PER_SHORT)(val) +#define bfdev_cpu_to_be_int(val) bfdev_cpu_to_be_type(BFDEV_BITS_PER_INT)(val) +#define bfdev_cpu_to_be_long(val) bfdev_cpu_to_be_type(BFDEV_BITS_PER_LONG)(val) +#define bfdev_cpu_to_be_long_long(val) bfdev_cpu_to_be_type(BFDEV_BITS_PER_LONG_LONG)(val) + +#define bfdev_le_short_to_cpu(val) bfdev_le_type_to_cpu(BFDEV_BITS_PER_SHORT)(val) +#define bfdev_le_int_to_cpu(val) bfdev_le_type_to_cpu(BFDEV_BITS_PER_INT)(val) +#define bfdev_le_long_to_cpu(val) bfdev_le_type_to_cpu(BFDEV_BITS_PER_LONG)(val) +#define bfdev_le_long_long_to_cpu(val) bfdev_le_type_to_cpu(BFDEV_BITS_PER_LONG_LONG)(val) + +#define bfdev_be_short_to_cpu(val) bfdev_be_type_to_cpu(BFDEV_BITS_PER_SHORT)(val) +#define bfdev_be_int_to_cpu(val) bfdev_be_type_to_cpu(BFDEV_BITS_PER_INT)(val) +#define bfdev_be_long_to_cpu(val) bfdev_be_type_to_cpu(BFDEV_BITS_PER_LONG)(val) +#define bfdev_be_long_long_to_cpu(val) bfdev_be_type_to_cpu(BFDEV_BITS_PER_LONG_LONG)(val) + +BFDEV_END_DECLS + +#endif /* _BFDEV_BYTEORDER_H_ */ diff --git a/include/bfdev/byteorder/big_endian.h b/include/bfdev/byteorder/big_endian.h new file mode 100644 index 00000000..5111fac3 --- /dev/null +++ b/include/bfdev/byteorder/big_endian.h @@ -0,0 +1,140 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#ifndef _BFDEV_BYTEORDER_LITTLE_ENDIAN_H_ +#define _BFDEV_BYTEORDER_LITTLE_ENDIAN_H_ + +#ifndef __BFDEV_BIG_ENDIAN__ +# define __BFDEV_BIG_ENDIAN__ +#endif + +#include +#include +#include + +BFDEV_BEGIN_DECLS + +#define bfdev_htons_const(x) ((bfdev_be16)(uint16_t)(x)) +#define bfdev_htonl_const(x) ((bfdev_be32)(uint32_t)(x)) +#define bfdev_ntohl_const(x) ((uint32_t)(bfdev_be32)(x)) +#define bfdev_ntohs_const(x) ((uint16_t)(bfdev_be16)(x)) + +#define bfdev_cpu_to_le16_const(x) ((bfdev_le16)bfdev_swab16_const((x))) +#define bfdev_cpu_to_le32_const(x) ((bfdev_le32)bfdev_swab32_const((x))) +#define bfdev_cpu_to_le64_const(x) ((bfdev_le64)bfdev_swab64_const((x))) +#define bfdev_le16_to_cpu_const(x) bfdev_swab16_const((uint16_t)(bfdev_le16)(x)) +#define bfdev_le32_to_cpu_const(x) bfdev_swab32_const((uint32_t)(bfdev_le32)(x)) +#define bfdev_le64_to_cpu_const(x) bfdev_swab64_const((uint64_t)(bfdev_le64)(x)) + +#define bfdev_cpu_to_be16_const(x) ((bfdev_be16)(uint16_t)(x)) +#define bfdev_cpu_to_be32_const(x) ((bfdev_be32)(uint32_t)(x)) +#define bfdev_cpu_to_be64_const(x) ((bfdev_be64)(uint64_t)(x)) +#define bfdev_be16_to_cpu_const(x) ((uint16_t)(bfdev_be16)(x)) +#define bfdev_be32_to_cpu_const(x) ((uint32_t)(bfdev_be32)(x)) +#define bfdev_be64_to_cpu_const(x) ((uint64_t)(bfdev_be64)(x)) + +#define bfdev_cpu_to_le16(x) ((bfdev_le16)bfdev_swab16((x))) +#define bfdev_cpu_to_le32(x) ((bfdev_le32)bfdev_swab32((x))) +#define bfdev_cpu_to_le64(x) ((bfdev_le64)bfdev_swab64((x))) +#define bfdev_le16_to_cpu(x) bfdev_swab16((uint16_t)(bfdev_le16)(x)) +#define bfdev_le32_to_cpu(x) bfdev_swab32((uint32_t)(bfdev_le32)(x)) +#define bfdev_le64_to_cpu(x) bfdev_swab64((uint64_t)(bfdev_le64)(x)) + +#define bfdev_be16_to_cpu(x) ((uint16_t)(bfdev_be16)(x)) +#define bfdev_be32_to_cpu(x) ((uint32_t)(bfdev_be32)(x)) +#define bfdev_be64_to_cpu(x) ((uint64_t)(bfdev_be64)(x)) +#define bfdev_cpu_to_be16(x) ((bfdev_be16)(uint16_t)(x)) +#define bfdev_cpu_to_be32(x) ((bfdev_be32)(uint32_t)(x)) +#define bfdev_cpu_to_be64(x) ((bfdev_be64)(uint64_t)(x)) + +#define bfdev_cpu_to_le16s(x) bfdev_swab16s((x)) +#define bfdev_cpu_to_le32s(x) bfdev_swab32s((x)) +#define bfdev_cpu_to_le64s(x) bfdev_swab64s((x)) +#define bfdev_le16_to_cpus(x) bfdev_swab16s((x)) +#define bfdev_le32_to_cpus(x) bfdev_swab32s((x)) +#define bfdev_le64_to_cpus(x) bfdev_swab64s((x)) + +#define bfdev_cpu_to_be16s(x) do { (void)(x); } while (0) +#define bfdev_cpu_to_be32s(x) do { (void)(x); } while (0) +#define bfdev_cpu_to_be64s(x) do { (void)(x); } while (0) +#define bfdev_be16_to_cpus(x) do { (void)(x); } while (0) +#define bfdev_be32_to_cpus(x) do { (void)(x); } while (0) +#define bfdev_be64_to_cpus(x) do { (void)(x); } while (0) + +static __bfdev_always_inline bfdev_le16 +bfdev_cpu_to_le16p(const uint16_t *p) +{ + return (bfdev_le16)bfdev_swab16p(p); +} + +static __bfdev_always_inline bfdev_le32 +bfdev_cpu_to_le32p(const uint32_t *p) +{ + return (bfdev_le32)bfdev_swab32p(p); +} + +static __bfdev_always_inline bfdev_le64 +bfdev_cpu_to_le64p(const uint64_t *p) +{ + return (bfdev_le64)bfdev_swab64p(p); +} + +static __bfdev_always_inline uint16_t +bfdev_le16_to_cpup(const bfdev_le16 *p) +{ + return bfdev_swab16p((uint16_t *)p); +} + +static __bfdev_always_inline uint32_t +bfdev_le32_to_cpup(const bfdev_le32 *p) +{ + return bfdev_swab32p((uint32_t *)p); +} + +static __bfdev_always_inline uint64_t +bfdev_le64_to_cpup(const bfdev_le64 *p) +{ + return bfdev_swab64p((uint64_t *)p); +} + +static __bfdev_always_inline bfdev_be16 +bfdev_cpu_to_be16p(const uint16_t *p) +{ + return (bfdev_be16)*p; +} + +static __bfdev_always_inline bfdev_be32 +bfdev_cpu_to_be32p(const uint32_t *p) +{ + return (bfdev_be32)*p; +} + +static __bfdev_always_inline bfdev_be64 +bfdev_cpu_to_be64p(const uint64_t *p) +{ + return (bfdev_be64)*p; +} + +static __bfdev_always_inline uint16_t +bfdev_be16_to_cpup(const bfdev_be16 *p) +{ + return (uint16_t)*p; +} + +static __bfdev_always_inline uint32_t +bfdev_be32_to_cpup(const bfdev_be32 *p) +{ + return (uint32_t)*p; +} + +static __bfdev_always_inline uint64_t +bfdev_be64_to_cpup(const bfdev_be64 *p) +{ + return (uint64_t)*p; +} + +BFDEV_END_DECLS + +#endif /* _BFDEV_BYTEORDER_LITTLE_ENDIAN_H_ */ diff --git a/include/bfdev/byteorder/little_endian.h b/include/bfdev/byteorder/little_endian.h new file mode 100644 index 00000000..fbb08712 --- /dev/null +++ b/include/bfdev/byteorder/little_endian.h @@ -0,0 +1,140 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#ifndef _BFDEV_BYTEORDER_LITTLE_ENDIAN_H_ +#define _BFDEV_BYTEORDER_LITTLE_ENDIAN_H_ + +#ifndef __BFDEV_LITTLE_ENDIAN__ +# define __BFDEV_LITTLE_ENDIAN__ +#endif + +#include +#include +#include + +BFDEV_BEGIN_DECLS + +#define bfdev_htons_const(x) ((bfdev_be16)bfdev_swab16_const((x))) +#define bfdev_htonl_const(x) ((bfdev_be32)bfdev_swab32_const((x))) +#define bfdev_ntohl_const(x) bfdev_swab32_const((bfdev_be32)(x)) +#define bfdev_ntohs_const(x) bfdev_swab16_const((bfdev_be16)(x)) + +#define bfdev_cpu_to_le16_const(x) ((bfdev_le16)(uint16_t)(x)) +#define bfdev_cpu_to_le32_const(x) ((bfdev_le32)(uint32_t)(x)) +#define bfdev_cpu_to_le64_const(x) ((bfdev_le64)(uint64_t)(x)) +#define bfdev_le16_to_cpu_const(x) ((uint16_t)(bfdev_le16)(x)) +#define bfdev_le32_to_cpu_const(x) ((uint32_t)(bfdev_le32)(x)) +#define bfdev_le64_to_cpu_const(x) ((uint64_t)(bfdev_le64)(x)) + +#define bfdev_cpu_to_be16_const(x) ((bfdev_be16)bfdev_swab16_const((x))) +#define bfdev_cpu_to_be32_const(x) ((bfdev_be32)bfdev_swab32_const((x))) +#define bfdev_cpu_to_be64_const(x) ((bfdev_be64)bfdev_swab64_const((x))) +#define bfdev_be16_to_cpu_const(x) bfdev_swab16_const((uint16_t)(bfdev_be16)(x)) +#define bfdev_be32_to_cpu_const(x) bfdev_swab32_const((uint32_t)(bfdev_be32)(x)) +#define bfdev_be64_to_cpu_const(x) bfdev_swab64_const((uint64_t)(bfdev_be64)(x)) + +#define bfdev_cpu_to_le16(x) ((bfdev_le16)(uint16_t)(x)) +#define bfdev_cpu_to_le32(x) ((bfdev_le32)(uint32_t)(x)) +#define bfdev_cpu_to_le64(x) ((bfdev_le64)(uint64_t)(x)) +#define bfdev_le16_to_cpu(x) ((uint16_t)(bfdev_le16)(x)) +#define bfdev_le32_to_cpu(x) ((uint32_t)(bfdev_le32)(x)) +#define bfdev_le64_to_cpu(x) ((uint64_t)(bfdev_le64)(x)) + +#define bfdev_cpu_to_be16(x) ((bfdev_be16)bfdev_swab16((x))) +#define bfdev_cpu_to_be32(x) ((bfdev_be32)bfdev_swab32((x))) +#define bfdev_cpu_to_be64(x) ((bfdev_be64)bfdev_swab64((x))) +#define bfdev_be16_to_cpu(x) bfdev_swab16((uint16_t)(bfdev_be16)(x)) +#define bfdev_be32_to_cpu(x) bfdev_swab32((uint32_t)(bfdev_be32)(x)) +#define bfdev_be64_to_cpu(x) bfdev_swab64((uint64_t)(bfdev_be64)(x)) + +#define bfdev_cpu_to_le16s(x) do { (void)(x); } while (0) +#define bfdev_cpu_to_le32s(x) do { (void)(x); } while (0) +#define bfdev_cpu_to_le64s(x) do { (void)(x); } while (0) +#define bfdev_le16_to_cpus(x) do { (void)(x); } while (0) +#define bfdev_le32_to_cpus(x) do { (void)(x); } while (0) +#define bfdev_le64_to_cpus(x) do { (void)(x); } while (0) + +#define bfdev_cpu_to_be16s(x) bfdev_swab16s((x)) +#define bfdev_cpu_to_be32s(x) bfdev_swab32s((x)) +#define bfdev_cpu_to_be64s(x) bfdev_swab64s((x)) +#define bfdev_be16_to_cpus(x) bfdev_swab16s((x)) +#define bfdev_be32_to_cpus(x) bfdev_swab32s((x)) +#define bfdev_be64_to_cpus(x) bfdev_swab64s((x)) + +static __bfdev_always_inline bfdev_le16 +bfdev_cpu_to_le16p(const uint16_t *p) +{ + return (bfdev_le16)*p; +} + +static __bfdev_always_inline bfdev_le32 +bfdev_cpu_to_le32p(const uint32_t *p) +{ + return (bfdev_le32)*p; +} + +static __bfdev_always_inline bfdev_le64 +bfdev_cpu_to_le64p(const uint64_t *p) +{ + return (bfdev_le64)*p; +} + +static __bfdev_always_inline uint16_t +bfdev_le16_to_cpup(const bfdev_le16 *p) +{ + return (uint16_t)*p; +} + +static __bfdev_always_inline uint32_t +bfdev_le32_to_cpup(const bfdev_le32 *p) +{ + return (uint32_t)*p; +} + +static __bfdev_always_inline uint64_t +bfdev_le64_to_cpup(const bfdev_le64 *p) +{ + return (uint64_t)*p; +} + +static __bfdev_always_inline bfdev_be16 +bfdev_cpu_to_be16p(const uint16_t *p) +{ + return (bfdev_be16)bfdev_swab16p(p); +} + +static __bfdev_always_inline bfdev_be32 +bfdev_cpu_to_be32p(const uint32_t *p) +{ + return (bfdev_be32)bfdev_swab32p(p); +} + +static __bfdev_always_inline bfdev_be64 +bfdev_cpu_to_be64p(const uint64_t *p) +{ + return (bfdev_be64)bfdev_swab64p(p); +} + +static __bfdev_always_inline uint16_t +bfdev_be16_to_cpup(const bfdev_be16 *p) +{ + return bfdev_swab16p((uint16_t *)p); +} + +static __bfdev_always_inline uint32_t +bfdev_be32_to_cpup(const bfdev_be32 *p) +{ + return bfdev_swab32p((uint32_t *)p); +} + +static __bfdev_always_inline uint64_t +bfdev_be64_to_cpup(const bfdev_be64 *p) +{ + return bfdev_swab64p((uint64_t *)p); +} + +BFDEV_END_DECLS + +#endif /* _BFDEV_BYTEORDER_LITTLE_ENDIAN_H_ */ diff --git a/include/bfdev/cache.h b/include/bfdev/cache.h new file mode 100644 index 00000000..0774aa05 --- /dev/null +++ b/include/bfdev/cache.h @@ -0,0 +1,168 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#ifndef _BFDEV_CACHE_H_ +#define _BFDEV_CACHE_H_ + +#include +#include +#include +#include +#include +#include + +BFDEV_BEGIN_DECLS + +#ifndef BFDEV_CACHE_FREE_TAG +# define BFDEV_CACHE_FREE_TAG ULONG_MAX +#endif + +enum bfdev_cache_obtain { + __BFDEV_CACHE_CHANGE = 0, + __BFDEV_CACHE_UNCOMMITTED, + + BFDEV_CACHE_CHANGE = BFDEV_BIT(__BFDEV_CACHE_CHANGE), + BFDEV_CACHE_UNCOMMITTED = BFDEV_BIT(__BFDEV_CACHE_UNCOMMITTED), +}; + +enum bfdev_cache_flags { + __BFDEV_CACHE_DIRTY = 0, + __BFDEV_CACHE_STARVING, + + BFDEV_CACHE_DIRTY = BFDEV_BIT(__BFDEV_CACHE_DIRTY), + BFDEV_CACHE_STARVING = BFDEV_BIT(__BFDEV_CACHE_STARVING), +}; + +enum bfdev_cache_status { + BFDEV_CACHE_FREED = 0, + BFDEV_CACHE_PENDING, + BFDEV_CACHE_USING, + BFDEV_CACHE_MANAGED, +}; + +struct bfdev_cache_node { + struct bfdev_hlist_node hash; + struct bfdev_list_head list; + enum bfdev_cache_status status; + + unsigned long index; + unsigned long tag; + unsigned long refcnt; + void *pdata; +}; + +struct bfdev_cache_head { + const struct bfdev_alloc *alloc; + const struct bfdev_cache_algo *algo; + struct bfdev_hlist_head *taghash; + struct bfdev_cache_node **nodes; + + struct bfdev_list_head using; + struct bfdev_list_head freed; + struct bfdev_list_head changing; + + /* const settings */ + unsigned long size; + unsigned long maxpend; + + /* status description */ + unsigned long flags; + unsigned long used; + unsigned long pending; + + /* state counter */ + unsigned long changed; + unsigned long starve; + unsigned long hits; + unsigned long misses; +}; + +struct bfdev_cache_algo { + struct bfdev_list_head list; + const char *name; + + bool (*starving)(struct bfdev_cache_head *head); + struct bfdev_cache_node *(*obtain)(struct bfdev_cache_head *head); + void (*get)(struct bfdev_cache_head *head, struct bfdev_cache_node *node); + void (*put)(struct bfdev_cache_head *head, struct bfdev_cache_node *node); + void (*update)(struct bfdev_cache_head *head, struct bfdev_cache_node *node); + void (*clear)(struct bfdev_cache_head *head, struct bfdev_cache_node *node); + void (*reset)(struct bfdev_cache_head *head); + + struct bfdev_cache_head *(*create)(const struct bfdev_alloc *alloc, unsigned long size); + void (*destroy)(struct bfdev_cache_head *head); +}; + +BFDEV_BITFLAGS_STRUCT(bfdev_cache, + struct bfdev_cache_head, flags +); + +BFDEV_BITFLAGS_STRUCT_FLAG(bfdev_cache, + struct bfdev_cache_head, flags, + dirty, __BFDEV_CACHE_DIRTY +); + +BFDEV_BITFLAGS_STRUCT_FLAG(bfdev_cache, + struct bfdev_cache_head, flags, + starving, __BFDEV_CACHE_STARVING +); + +extern struct bfdev_cache_node * +bfdev_cache_find(struct bfdev_cache_head *head, unsigned long tag); + +extern struct bfdev_cache_node * +bfdev_cache_obtain(struct bfdev_cache_head *head, unsigned long tag, + unsigned long flags); + +extern unsigned long +bfdev_cache_put(struct bfdev_cache_head *head, struct bfdev_cache_node *node); + +extern int +bfdev_cache_del(struct bfdev_cache_head *head, struct bfdev_cache_node *node); + +extern int +bfdev_cache_set(struct bfdev_cache_head *head, struct bfdev_cache_node *node, + unsigned long tag); + +extern void +bfdev_cache_committed(struct bfdev_cache_head *head); + +extern void +bfdev_cache_reset(struct bfdev_cache_head *head); + +extern struct bfdev_cache_head * +bfdev_cache_create(const char *name, const struct bfdev_alloc *alloc, + unsigned long size, unsigned long maxp); + +extern void +bfdev_cache_destroy(struct bfdev_cache_head *head); + +static inline struct bfdev_cache_node * +bfdev_cache_get(struct bfdev_cache_head *head, unsigned long tag) +{ + return bfdev_cache_obtain(head, tag, BFDEV_CACHE_CHANGE); +} + +static inline struct bfdev_cache_node * +bfdev_cache_try_get(struct bfdev_cache_head *head, unsigned long tag) +{ + return bfdev_cache_obtain(head, tag, 0); +} + +static inline struct bfdev_cache_node * +bfdev_cache_cumulative(struct bfdev_cache_head *head, unsigned long tag) +{ + return bfdev_cache_obtain(head, tag, BFDEV_CACHE_CHANGE | BFDEV_CACHE_UNCOMMITTED); +} + +extern int +bfdev_cache_register(struct bfdev_cache_algo *algo); + +extern void +bfdev_cache_unregister(struct bfdev_cache_algo *algo); + +BFDEV_END_DECLS + +#endif /* _BFDEV_CACHE_H_ */ diff --git a/include/bfdev/callback.h b/include/bfdev/callback.h new file mode 100644 index 00000000..2d33ea1b --- /dev/null +++ b/include/bfdev/callback.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#ifndef _BFDEV_CALLBACK_H_ +#define _BFDEV_CALLBACK_H_ + +#include + +BFDEV_BEGIN_DECLS + +extern void bfdev_cbfunc_noop(void); +extern long bfdev_cbfunc_ret0(void); +extern long bfdev_cbfunc_ret1(void); + +#define bfdev_dummy_noop ((void *)bfdev_cbfunc_noop) +#define bfdev_dummy_ret0 ((void *)bfdev_cbfunc_ret0) +#define bfdev_dummy_ret1 ((void *)bfdev_cbfunc_ret1) + +BFDEV_END_DECLS + +#endif /* _BFDEV_CALLBACK_H_ */ diff --git a/include/bfdev/cdefs.h b/include/bfdev/cdefs.h new file mode 100644 index 00000000..693cb30b --- /dev/null +++ b/include/bfdev/cdefs.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#ifndef _BFDEV_CDEFS_H_ +#define _BFDEV_CDEFS_H_ + +/* + * GCC and clang have various useful declarations that can be made with + * the '__attribute__' syntax. All of the ways we use this do fine if + * they are omitted for compilers that don't understand it. + */ +#if !(defined __GNUC__ || defined __clang__) +# define __attribute__(xyz) /* Ignore */ +#endif + +#ifdef __cplusplus +# define BFDEV_BEGIN_DECLS extern "C" { +# define BFDEV_END_DECLS } +#else +# define BFDEV_BEGIN_DECLS +# define BFDEV_END_DECLS +#endif + +#endif /* _BFDEV_CDEFS_H_ */ diff --git a/include/bfdev/cmpxchg.h b/include/bfdev/cmpxchg.h new file mode 100644 index 00000000..a48b9473 --- /dev/null +++ b/include/bfdev/cmpxchg.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#ifndef _BFDEV_CMPXCHG_H_ +#define _BFDEV_CMPXCHG_H_ + +#include +#include + +BFDEV_BEGIN_DECLS + +#ifndef bfdev_xchg +static __bfdev_always_inline bfdev_atomic_t +bfdev_xchg(bfdev_atomic_t *atomic, bfdev_atomic_t value) +{ + return bfdev_arch_xchg(atomic, value); +} +#endif + +#ifndef bfdev_cmpxchg +static __bfdev_always_inline bfdev_atomic_t +bfdev_cmpxchg(bfdev_atomic_t *atomic, bfdev_atomic_t old, bfdev_atomic_t value) +{ + return bfdev_arch_cmpxchg(atomic, old, value); +} +#endif + +#ifndef bfdev_try_cmpxchg +static __bfdev_always_inline bool +bfdev_try_cmpxchg(bfdev_atomic_t *atomic, bfdev_atomic_t *old, bfdev_atomic_t value) +{ + return bfdev_arch_try_cmpxchg(atomic, old, value); +} +#endif + +BFDEV_END_DECLS + +#endif /* _BFDEV_CMPXCHG_H_ */ diff --git a/include/bfdev/compiler.h b/include/bfdev/compiler.h new file mode 100644 index 00000000..14243383 --- /dev/null +++ b/include/bfdev/compiler.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#ifndef _BFDEV_COMPILER_H_ +#define _BFDEV_COMPILER_H_ + +#include +#include + +BFDEV_BEGIN_DECLS + +#ifndef bfdev_likely +# define bfdev_likely(x) __builtin_expect(!!(x), 1) +# define bfdev_unlikely(x) __builtin_expect(!!(x), 0) +# define bfdev_likely_notrace(x) __builtin_expect(!!(x), 1) +# define bfdev_unlikely_notrace(x) __builtin_expect(!!(x), 0) +#endif + +/* + * Optimization barrier + * The "volatile" is due to gcc bugs + */ +#ifndef bfdev_barrier +# define bfdev_barrier() __asm__ __volatile__("": : :"memory") +#endif + +/* Not-quite-unique ID. */ +#ifndef __BFDEV_UNIQUE_ID +# define __BFDEV_UNIQUE_ID(prefix) __BFDEV_PASTE(__BFDEV_PASTE(__UNIQUE_ID_, prefix), __LINE__) +#endif + +BFDEV_END_DECLS + +#endif /* _BFDEV_COMPILER_H_ */ diff --git a/include/bfdev/compiler/attributes.h b/include/bfdev/compiler/attributes.h new file mode 100644 index 00000000..e287fbac --- /dev/null +++ b/include/bfdev/compiler/attributes.h @@ -0,0 +1,308 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2023 John Sanpe + */ + +#ifndef _BFDEV_COMPILER_ATTRIBUTES_H_ +#define _BFDEV_COMPILER_ATTRIBUTES_H_ + +#include + +BFDEV_BEGIN_DECLS + +/* + * The attributes in this file are unconditionally defined and they directly + * map to compiler attribute(s), unless one of the compilers does not support + * the attribute. In that case, __has_attribute is used to check for support + * and the reason is stated in its comment ("Optional: ..."). + */ + +/* + * __has_attribute is supported on gcc >= 5, clang >= 2.9. + * In the meantime, to support gcc < 5, we implement __has_attribute + * by hand. + */ +#ifndef __has_attribute +# define __has_attribute(x) __GCC4_has_attribute_##x +# define __GCC4_has_attribute___assume_aligned__ (__GNUC_MINOR__ >= 9) +# define __GCC4_has_attribute___copy__ 0 +# define __GCC4_has_attribute___designated_init__ 0 +# define __GCC4_has_attribute___externally_visible__ 1 +# define __GCC4_has_attribute___no_caller_saved_registers__ 0 +# define __GCC4_has_attribute___noclone__ 1 +# define __GCC4_has_attribute___nonstring__ 0 +# define __GCC4_has_attribute___no_sanitize_address__ (__GNUC_MINOR__ >= 8) +# define __GCC4_has_attribute___no_sanitize_undefined__ (__GNUC_MINOR__ >= 9) +# define __GCC4_has_attribute___fallthrough__ 0 +#endif + +/* + * gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-alias-function-attribute + */ +#define __bfdev_alias(symbol) __attribute__((__alias__(symbol))) + +/* + * gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-aligned-function-attribute + * gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Type-Attributes.html#index-aligned-type-attribute + * gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html#index-aligned-variable-attribute + */ +#define __bfdev_aligned(x) __attribute__((__aligned__(x))) +#define __bfdev_aligned_largest __attribute__((__aligned__)) + +/* + * Note: users of __bfdev_always_inline currently do not write "inline" themselves, + * which seems to be required by gcc to apply the attribute according + * to its docs (and also "warning: always_inline function might not be + * inlinable [-Wattributes]" is emitted). + * + * gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-always_005finline-function-attribute + * clang: mentioned + */ +#define __bfdev_always_inline inline __attribute__((__always_inline__)) + +/* + * gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-assume_005faligned-function-attribute + * clang: https://clang.llvm.org/docs/AttributeReference.html#assume-aligned + */ +#if __has_attribute(__assume_aligned__) +# define __bfdev_assume_aligned(a, ...) __attribute__((__assume_aligned__(a, ## __VA_ARGS__))) +#else +# define __bfdev_assume_aligned(a, ...) +#endif + +/* + * gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-cold-function-attribute + * gcc: https://gcc.gnu.org/onlinedocs/gcc/Label-Attributes.html#index-cold-label-attribute + */ +#define __bfdev_cold __attribute__((__cold__)) + +/* + * gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html#index-cleanup-variable-attribute + * clang: https://clang.llvm.org/docs/AttributeReference.html#cleanup + */ +#define __bfdev_cleanup(func) __attribute__((__cleanup__(func))) + +/* + * Note the long name. + * + * gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-const-function-attribute + */ +#define __bfdev_attribute_const __attribute__((__const__)) + +/* + * Optional: only supported since gcc >= 9 + * Optional: not supported by clang + * + * gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-copy-function-attribute + */ +#if __has_attribute(__copy__) +# define __bfdev_copy(symbol) __attribute__((__copy__(symbol))) +#else +# define __bfdev_copy(symbol) +#endif + +/* + * Optional: only supported since gcc >= 14 + * Optional: only supported since clang >= 18 + * + * gcc: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108896 + * clang: https://reviews.llvm.org/D148381 + */ +#if __has_attribute(__counted_by__) +# define __bfdev_counted_by(member) __attribute__((__counted_by__(member))) +#else +# define __bfdev_counted_by(member) +#endif + +/* + * Optional: only supported since gcc >= 5.1 + * Optional: not supported by clang + * + * gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Type-Attributes.html#index-designated_005finit-type-attribute + */ +#if __has_attribute(__designated_init__) +# define __bfdev_designated_init __attribute__((__designated_init__)) +#else +# define __bfdev_designated_init +#endif + +/* + * Optional: not supported by clang + * + * gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-externally_005fvisible-function-attribute + */ +#if __has_attribute(__externally_visible__) +# define __bfdev_visible __attribute__((__externally_visible__)) +#else +# define __bfdev_visible +#endif + +/* + * gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-format-function-attribute + * clang: https://clang.llvm.org/docs/AttributeReference.html#format + */ +#define __bfdev_printf(a, b) __attribute__((__format__(printf, a, b))) +#define __bfdev_scanf(a, b) __attribute__((__format__(scanf, a, b))) + +/* + * gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-nonnull-function-attribute + * clang: https://clang.llvm.org/docs/AttributeReference.html#nonnull + */ +#define __bfdev_nonnull(nr, ...) __attribute__((__nonnull__(nr, ##__VA_ARGS__))) + +/* + * gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-gnu_005finline-function-attribute + * clang: https://clang.llvm.org/docs/AttributeReference.html#gnu-inline + */ +#define __bfdev_gnu_inline __attribute__((__gnu_inline__)) + +/* + * gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-malloc-function-attribute + */ +#define __bfdev_malloc __attribute__((__malloc__)) + +/* + * gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Type-Attributes.html#index-mode-type-attribute + * gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html#index-mode-variable-attribute + */ +#define __bfdev_mode(x) __attribute__((__mode__(x))) + +/* + * Optional: only supported since gcc >= 7 + * + * gcc: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-no_005fcaller_005fsaved_005fregisters-function-attribute_002c-x86 + * clang: https://clang.llvm.org/docs/AttributeReference.html#no-caller-saved-registers + */ +#if __has_attribute(__no_caller_saved_registers__) +# define __bfdev_no_caller_saved_registers __attribute__((__no_caller_saved_registers__)) +#else +# define __bfdev_no_caller_saved_registers +#endif + +/* + * Optional: not supported by clang + * + * gcc: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-noclone-function-attribute + */ +#if __has_attribute(__noclone__) +# define __bfdev_noclone __attribute__((__noclone__)) +#else +# define __bfdev_noclone +#endif + +/* + * Add the pseudo keyword 'fallthrough' so case statement blocks + * must end with any of these keywords: + * break; + * fallthrough; + * goto