├── .github └── workflows │ └── ci.yml ├── .gitignore ├── License-lgpl3.txt ├── Makefile ├── README.md ├── example.c ├── mem.h ├── mmc.c └── mmc.h /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | # (documetation) TBD 2 | 3 | name: mmc CI 4 | on: [push, pull_request] 5 | permissions: 6 | contents: read 7 | 8 | jobs: 9 | mmc-c-compilers: 10 | name: CC=${{ matrix.cc }}, ${{ matrix.os }} 11 | strategy: 12 | fail-fast: false # 'false' means Don't stop matrix workflows even if some matrix failed. 13 | matrix: 14 | include: [ 15 | # You can access the following values via ${{ matrix.??? }} 16 | # 17 | # pkgs : apt-get package names. It can include multiple package names which are delimited by space. 18 | # cc : C compiler executable. 19 | # cxx : C++ compiler executable for `make ctocpptest`. 20 | # x32 : Set 'true' if compiler supports x32. Otherwise, set 'false'. 21 | # Set 'fail' if it supports x32 but fails for now. 'fail' cases must be removed. 22 | # x86 : Set 'true' if compiler supports x86 (-m32). Otherwise, set 'false'. 23 | # Set 'fail' if it supports x86 but fails for now. 'fail' cases must be removed. 24 | # cxxtest : Set 'true' if it can be compiled as C++ code. Otherwise, set 'false'. 25 | # os : GitHub Actions YAML workflow label. See https://github.com/actions/virtual-environments#available-environments 26 | 27 | # cc 28 | { pkgs: '', cc: cc, cxx: c++, x32: 'true', x86: 'true', cxxtest: 'true', os: ubuntu-latest, }, 29 | 30 | # gcc 31 | { pkgs: '', cc: gcc, cxx: g++, x32: 'true', x86: 'true', cxxtest: 'true', os: ubuntu-latest, }, 32 | { pkgs: 'gcc-11 g++-11 lib32gcc-11-dev libx32gcc-11-dev', cc: gcc-11, cxx: g++-11, x32: 'true', x86: 'true', cxxtest: 'true', os: ubuntu-20.04, }, 33 | { pkgs: 'gcc-10 lib32gcc-10-dev libx32gcc-10-dev', cc: gcc-10, cxx: g++-10, x32: 'true', x86: 'true', cxxtest: 'true', os: ubuntu-20.04, }, 34 | { pkgs: 'gcc-9 lib32gcc-9-dev libx32gcc-9-dev', cc: gcc-9, cxx: g++-9, x32: 'true', x86: 'true', cxxtest: 'true', os: ubuntu-20.04, }, 35 | { pkgs: 'gcc-8 g++-8 lib32gcc-8-dev libx32gcc-8-dev', cc: gcc-8, cxx: g++-8, x32: 'true', x86: 'true', cxxtest: 'true', os: ubuntu-20.04, }, 36 | { pkgs: 'gcc-7 g++-7 lib32gcc-7-dev libx32gcc-7-dev', cc: gcc-7, cxx: g++-7, x32: 'true', x86: 'true', cxxtest: 'true', os: ubuntu-20.04, }, 37 | { pkgs: 'gcc-6 g++-6 lib32gcc-6-dev libx32gcc-6-dev', cc: gcc-6, cxx: g++-6, x32: 'true', x86: 'true', cxxtest: 'true', os: ubuntu-18.04, }, 38 | { pkgs: 'gcc-5 g++-5 lib32gcc-5-dev libx32gcc-5-dev', cc: gcc-5, cxx: g++-5, x32: 'true', x86: 'true', cxxtest: 'true', os: ubuntu-18.04, }, 39 | { pkgs: 'gcc-4.8 g++-4.8 lib32gcc-4.8-dev libx32gcc-4.8-dev', cc: gcc-4.8, cxx: g++-4.8, x32: 'true', x86: 'true', cxxtest: 'true', os: ubuntu-18.04, }, 40 | 41 | # clang 42 | { pkgs: 'lib32gcc-11-dev libx32gcc-11-dev', cc: clang, cxx: clang++, x32: 'true', x86: 'true', cxxtest: 'true', os: ubuntu-latest, }, 43 | { pkgs: 'clang-12 lib32gcc-11-dev libx32gcc-11-dev', cc: clang-12, cxx: clang++-12, x32: 'true', x86: 'true', cxxtest: 'true', os: ubuntu-20.04, }, 44 | { pkgs: 'clang-11 lib32gcc-11-dev libx32gcc-11-dev', cc: clang-11, cxx: clang++-11, x32: 'true', x86: 'true', cxxtest: 'true', os: ubuntu-20.04, }, 45 | { pkgs: 'clang-10 lib32gcc-11-dev libx32gcc-11-dev', cc: clang-10, cxx: clang++-10, x32: 'true', x86: 'true', cxxtest: 'true', os: ubuntu-20.04, }, 46 | { pkgs: 'clang-9 lib32gcc-11-dev libx32gcc-11-dev', cc: clang-9, cxx: clang++-9, x32: 'true', x86: 'true', cxxtest: 'true', os: ubuntu-20.04, }, 47 | { pkgs: 'clang-8 lib32gcc-11-dev libx32gcc-11-dev', cc: clang-8, cxx: clang++-8, x32: 'true', x86: 'true', cxxtest: 'true', os: ubuntu-20.04, }, 48 | { pkgs: 'clang-7 lib32gcc-7-dev libx32gcc-7-dev', cc: clang-7, cxx: clang++-7, x32: 'true', x86: 'true', cxxtest: 'true', os: ubuntu-20.04, }, 49 | { pkgs: 'clang-6.0 lib32gcc-11-dev libx32gcc-11-dev', cc: clang-6.0, cxx: clang++-6.0, x32: 'true', x86: 'true', cxxtest: 'true', os: ubuntu-20.04, }, 50 | { pkgs: 'clang-5.0 lib32gcc-11-dev libx32gcc-11-dev', cc: clang-5.0, cxx: clang++-5.0, x32: 'true', x86: 'true', cxxtest: 'true', os: ubuntu-18.04, }, 51 | { pkgs: 'clang-4.0 lib32gcc-11-dev libx32gcc-11-dev', cc: clang-4.0, cxx: clang++-4.0, x32: 'true', x86: 'true', cxxtest: 'true', os: ubuntu-18.04, }, 52 | { pkgs: 'clang-3.9', cc: clang-3.9, cxx: clang++-3.9, x32: 'fail', x86: 'fail', cxxtest: 'false', os: ubuntu-18.04, }, 53 | ] 54 | 55 | runs-on: ${{ matrix.os }} 56 | env: # Set environment variables 57 | # We globally set CC and CXX to improve compatibility with .travis.yml 58 | CC: ${{ matrix.cc }} 59 | CXX: ${{ matrix.cxx }} 60 | steps: 61 | - uses: actions/checkout@v2 # https://github.com/actions/checkout 62 | 63 | - name: apt-get install 64 | run: | 65 | sudo apt-get update 66 | sudo apt-get install gcc-multilib 67 | sudo apt-get install ${{ matrix.pkgs }} 68 | 69 | - name: Environment info 70 | run: | 71 | echo && type $CC && which $CC && $CC --version 72 | echo && type $CXX && which $CXX && $CXX --version 73 | 74 | - name: make 75 | if: always() 76 | run: make V=1 77 | 78 | - name: make c_standards (C90) 79 | if: always() 80 | run: | 81 | make clean 82 | CFLAGS="-std=c90 -Werror" make V=1 83 | 84 | - name: make c_standards (C11) 85 | if: always() 86 | run: | 87 | make clean 88 | CFLAGS="-std=c11 -Werror" make V=1 89 | 90 | # Note : doesn't work (yet) 91 | # - name: make cxxtest 92 | # if: ${{ matrix.cxxtest == 'true' }} 93 | # run: | 94 | # make clean 95 | # CC=g++ make V=1 96 | 97 | - name: make example 98 | if: always() 99 | run: make clean; make V=1 example; ./example README.md 100 | 101 | - name: make clangtest (clang only) 102 | if: ${{ startsWith( matrix.cc , 'clang' ) }} 103 | run: make clean; CC=clang make V=1 104 | 105 | - name: make -C tests test MOREFLAGS='-mx32' 106 | if: ${{ matrix.x32 == 'true' }} 107 | run: make clean; LDFLAGS='-Wl,--verbose' MOREFLAGS='-mx32' make -j V=1 108 | 109 | 110 | ############################################################### 111 | # Check tools 112 | # 113 | # - scan-build 114 | # - valgrind 115 | # - ubsan 116 | # - asan 117 | # 118 | 119 | mmc-scan-build: 120 | name: make staticAnalyze 121 | runs-on: ubuntu-latest 122 | steps: 123 | - uses: actions/checkout@v2 # https://github.com/actions/checkout 124 | - name: apt-get install 125 | run: | 126 | sudo apt-get update 127 | sudo apt-get install clang-tools 128 | 129 | - name: Environment info 130 | run: | 131 | echo && type gcc && which gcc && gcc --version 132 | echo && type clang && which clang && clang --version 133 | echo && type scan-build && which scan-build # scan-build doesn't have any --version equivalent option 134 | echo && type make && which make && make -v 135 | echo && cat /proc/cpuinfo || echo /proc/cpuinfo is not present 136 | 137 | - name: scan-build 138 | run: scan-build --status-bugs -v --force-analyze-debug-code make all 139 | 140 | mmc-valgrind: 141 | name: valgrind 142 | runs-on: ubuntu-latest 143 | steps: 144 | - uses: actions/checkout@v2 # https://github.com/actions/checkout 145 | - name: apt-get install 146 | run: | 147 | sudo apt-get update 148 | sudo apt-get install valgrind 149 | 150 | - name: Environment info 151 | run: | 152 | echo && type cc && which cc && cc --version 153 | echo && type valgrind && which valgrind && valgrind --version 154 | 155 | - name: valgrind 156 | env: 157 | CFLAGS: -g 158 | run: | 159 | make clean 160 | make V=1 example 161 | valgrind --leak-check=yes --error-exitcode=1 -- ./example README.md 162 | 163 | 164 | mmc-ubsan-x64: 165 | name: Linux x64 ubsan 166 | runs-on: ubuntu-latest 167 | steps: 168 | - uses: actions/checkout@v2 # https://github.com/actions/checkout 169 | 170 | - name: ubsan 171 | run: | 172 | make clean 173 | MOREFLAGS="-fsanitize=undefined -fno-sanitize-recover=undefined" make V=1 example 174 | ./example README.md 175 | 176 | 177 | mmc-ubsan-x86: 178 | name: Linux x86 ubsan 179 | runs-on: ubuntu-latest 180 | steps: 181 | - uses: actions/checkout@v2 # https://github.com/actions/checkout 182 | 183 | - name: apt-get install 184 | run: | 185 | sudo apt-get update 186 | sudo apt-get install gcc-multilib 187 | sudo apt-get install lib32gcc-11-dev 188 | 189 | - name: ubsan32 190 | env: # Set environment variables 191 | CFLAGS: -m32 192 | MOREFLAGS: -fsanitize=undefined -fno-sanitize-recover=undefined 193 | run: | 194 | make clean 195 | make V=1 example 196 | ./example README.md 197 | 198 | 199 | mmc-asan-x64: 200 | name: Linux x64 ASAN 201 | runs-on: ubuntu-latest 202 | steps: 203 | - uses: actions/checkout@v2 # https://github.com/actions/checkout 204 | 205 | - name: asan 206 | env: 207 | MOREFLAGS: -fsanitize=address 208 | run: | 209 | make clean 210 | make V=1 example 211 | ./example README.md 212 | 213 | mmc-msan-x64: 214 | name: Linux x64 MSAN 215 | runs-on: ubuntu-latest 216 | steps: 217 | - uses: actions/checkout@v2 # https://github.com/actions/checkout 218 | 219 | - name: msan 220 | env: 221 | MOREFLAGS: -fsanitize=memory 222 | CC: clang 223 | run: | 224 | make clean 225 | make V=1 example 226 | ./example README.md 227 | 228 | ############################################################### 229 | # Platforms 230 | # 231 | # - QEMU (ARM, ARM64, PPC, PPC64LE, S390X) 232 | # - macOS 233 | # 234 | 235 | # QEMU 236 | # All tests use QEMU (static) and gcc cross compiler. 237 | # 238 | # note: 239 | # We don't employ completely matrix method which provides `MOREFLAGS` 240 | # etc in the matrix. Because some platform may need its special 241 | # compiler options and test. 242 | # For example, xxHash already has tests for scalar and SIMD version of 243 | # it. But compiler options are quite different between platforms. 244 | # 245 | # So, please keep them simple and independent. 246 | # 247 | mmc-qemu-platforms: 248 | name: QEMU ${{ matrix.type }} 249 | strategy: 250 | fail-fast: false # 'false' means Don't stop matrix workflows even if some matrix instance failed. 251 | matrix: 252 | include: [ 253 | # You can access the following values via ${{ matrix.??? }} 254 | # type : Architecture type for `if:` statement. 255 | # pkgs : apt-get package names. You can include multiple packages which are delimited by space. 256 | # xcc : gcc cross C compiler executable. 257 | # xemu : QEMU static emulator executable. 258 | # os : GitHub Actions YAML workflow label. See https://github.com/actions/virtual-environments#available-environments 259 | 260 | { type: ARM, pkgs: 'qemu-system-arm gcc-arm-linux-gnueabi', xcc: arm-linux-gnueabi-gcc, xemu: qemu-arm-static, os: ubuntu-latest, }, 261 | { type: ARM64, pkgs: 'qemu-system-arm gcc-aarch64-linux-gnu', xcc: aarch64-linux-gnu-gcc, xemu: qemu-aarch64-static, os: ubuntu-latest, }, 262 | { type: PPC, pkgs: 'qemu-system-ppc gcc-powerpc-linux-gnu', xcc: powerpc-linux-gnu-gcc, xemu: qemu-ppc-static, os: ubuntu-latest, }, 263 | { type: PPC64LE, pkgs: 'qemu-system-ppc gcc-powerpc64le-linux-gnu', xcc: powerpc64le-linux-gnu-gcc, xemu: qemu-ppc64le-static, os: ubuntu-latest, }, 264 | { type: S390X, pkgs: 'qemu-system-s390x gcc-s390x-linux-gnu', xcc: s390x-linux-gnu-gcc, xemu: qemu-s390x-static, os: ubuntu-latest, }, 265 | ] 266 | 267 | runs-on: ${{ matrix.os }} 268 | env: # Set environment variables 269 | XCC: ${{ matrix.xcc }} 270 | XEMU: ${{ matrix.xemu }} 271 | steps: 272 | - uses: actions/checkout@v2 # https://github.com/actions/checkout 273 | 274 | - name: apt-get install 275 | run: | 276 | sudo apt-get update 277 | sudo apt-get install gcc-multilib 278 | sudo apt-get install qemu-utils qemu-user-static 279 | sudo apt-get install ${{ matrix.pkgs }} 280 | 281 | - name: Environment info 282 | run: | 283 | echo && type $XCC && which $XCC && $XCC --version 284 | echo && $XCC -v # Show built-in specs 285 | echo && type $XEMU && which $XEMU && $XEMU --version 286 | 287 | - name: ARM64 288 | if: ${{ matrix.type == 'ARM64' }} 289 | run: make V=1 CC=$XCC QEMU_SYS=$XEMU 290 | 291 | - name: ARM 292 | if: ${{ matrix.type == 'ARM' }} 293 | run: make V=1 CC=$XCC QEMU_SYS=$XEMU 294 | 295 | - name: PPC 296 | if: ${{ matrix.type == 'PPC' }} 297 | run: make V=1 CC=$XCC QEMU_SYS=$XEMU 298 | 299 | - name: PPC64LE 300 | if: ${{ matrix.type == 'PPC64LE' }} 301 | run: make V=1 CC=$XCC QEMU_SYS=$XEMU MOREFLAGS=-m64 302 | 303 | - name: S390X 304 | if: ${{ matrix.type == 'S390X' }} 305 | run: make V=1 CC=$XCC QEMU_SYS=$XEMU 306 | 307 | 308 | # macOS 309 | mmc-platform-macos-latest: 310 | name: macOS 311 | runs-on: macos-latest 312 | steps: 313 | - uses: actions/checkout@v2 314 | 315 | - name: Environment info 316 | run: | 317 | echo && type cc && which cc && cc --version 318 | echo && type make && which make && make -v 319 | echo && sysctl -a | grep machdep.cpu # cpuinfo 320 | 321 | - name: make default 322 | run: CFLAGS="-Werror" make V=1 clean default 323 | 324 | 325 | ############################################################ 326 | # Gather CI environment information. 327 | # 328 | mmc-env-info: 329 | name: GH-Actions Virtual Env Info (${{ matrix.os }}) 330 | strategy: 331 | matrix: 332 | include: [ 333 | { os: ubuntu-latest, }, # https://github.com/actions/virtual-environments/ 334 | { os: ubuntu-22.04, }, # https://github.com/actions/virtual-environments/blob/main/images/linux/Ubuntu2204-Readme.md 335 | { os: ubuntu-20.04, }, # https://github.com/actions/virtual-environments/blob/main/images/linux/Ubuntu2004-Readme.md 336 | { os: ubuntu-18.04, }, # https://github.com/actions/virtual-environments/blob/main/images/linux/Ubuntu1804-Readme.md 337 | ] 338 | 339 | runs-on: ${{ matrix.os }} 340 | steps: 341 | - uses: actions/checkout@v2 342 | 343 | - name: init 344 | run: | 345 | sudo apt-get update 346 | 347 | - name: cc --version 348 | run: echo && type cc && which cc && cc --version 349 | 350 | - name: gcc --version 351 | run: echo && type gcc && which gcc && gcc --version 352 | 353 | - name: clang --version 354 | run: echo && type clang && which clang && clang --version 355 | 356 | - name: make -v 357 | run: echo && type make && which make && make -v 358 | 359 | - name: g++ --version 360 | run: echo && type g++ && which g++ && g++ --version 361 | 362 | - name: git --version 363 | run: echo && type git && which git && git --version 364 | 365 | - name: gcc packages (apt-cache) 366 | run: apt-cache search gcc | grep "^gcc-[0-9\.]* " | sort 367 | 368 | - name: lib32gcc packages for i386 (apt-cache) 369 | run: apt-cache search lib32gcc | grep "^lib32gcc-" | sort 370 | 371 | - name: libx32gcc packages for x32 (apt-cache) 372 | run: apt-cache search libx32gcc | grep "^libx32gcc-" | sort 373 | 374 | - name: gcc multilib packages (apt-cache) 375 | run: apt-cache search multilib | grep "gcc-" | sort 376 | 377 | - name: clang packages (apt-cache) 378 | run: apt-cache search clang | grep "^clang-[0-9\.]* " | sort 379 | 380 | - name: QEMU packages (apt-cache) 381 | run: apt-cache search qemu | grep "^qemu-system-.*QEMU full system" | sort 382 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # build artifacts 2 | *.o 3 | *.a 4 | *.dylib 5 | *.so.* 6 | example 7 | 8 | #test artifacts 9 | tmp* 10 | -------------------------------------------------------------------------------- /License-lgpl3.txt: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # ########################################################################## 2 | # MMC - Morphing Match Chain library 3 | # Copyright (C) Yann Collet 2010-2015 4 | # 5 | # GPL v2 License 6 | # 7 | # This program is free software; you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 2 of the License, or 10 | # (at your option) any later version. 11 | # 12 | # This program is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License along 18 | # with this program; if not, write to the Free Software Foundation, Inc., 19 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 20 | # 21 | # You can contact the author at : 22 | # - ZSTD source repository : http://code.google.com/p/zstd/ 23 | # - Public forum : https://groups.google.com/forum/#!forum/lz4c 24 | # ########################################################################## 25 | 26 | LIBVER_MAJOR = 0 27 | LIBVER_MINOR = 2 28 | LIBVER_PATCH = 1 29 | LIBVER = $(LIBVER_MAJOR).$(LIBVER_MINOR).$(LIBVER_PATCH) 30 | VERSION?= $(LIBVER) 31 | 32 | DESTDIR?= 33 | PREFIX ?= /usr/local 34 | CFLAGS ?= -O3 # -falign-loops=32 # not always positive 35 | DEBUGFLAGS = -Wall -Wextra -Wundef -Wshadow -Wcast-qual -Wcast-align -Wstrict-prototypes 36 | CFLAGS += $(DEBUGFLAGS) 37 | CFLAGS += $(MOREFLAGS) 38 | LDFLAGS += $(MOREFLAGS) 39 | 40 | BINDIR = $(PREFIX)/bin 41 | MANDIR = $(PREFIX)/share/man/man1 42 | LIBDIR ?= $(PREFIX)/lib 43 | INCLUDEDIR=$(PREFIX)/include 44 | 45 | # Define *.exe as extension for Windows systems 46 | ifneq (,$(filter Windows%,$(OS))) 47 | EXT =.exe 48 | VOID = nul 49 | else 50 | EXT = 51 | VOID = /dev/null 52 | endif 53 | 54 | # OS X linker doesn't support -soname, and use different extension 55 | # see : https://developer.apple.com/library/mac/documentation/DeveloperTools/Conceptual/DynamicLibraries/100-Articles/DynamicLibraryDesignGuidelines.html 56 | ifeq ($(shell uname), Darwin) 57 | SHARED_EXT = dylib 58 | SHARED_EXT_MAJOR = $(LIBVER_MAJOR).$(SHARED_EXT) 59 | SHARED_EXT_VER = $(LIBVER).$(SHARED_EXT) 60 | SONAME_FLAGS = -install_name $(PREFIX)/lib/libmmc.$(SHARED_EXT_MAJOR) -compatibility_version $(LIBVER_MAJOR) -current_version $(LIBVER) 61 | else 62 | SONAME_FLAGS = -Wl,-soname=libmmc.$(SHARED_EXT).$(LIBVER_MAJOR) 63 | SHARED_EXT = so 64 | SHARED_EXT_MAJOR = $(SHARED_EXT).$(LIBVER_MAJOR) 65 | SHARED_EXT_VER = $(SHARED_EXT).$(LIBVER) 66 | endif 67 | 68 | default: libmmc 69 | 70 | all: libmmc 71 | 72 | libmmc: mmc.c 73 | @echo compiling static library 74 | @$(CC) $(FLAGS) -c $^ 75 | @$(AR) rcs $@.a mmc.o 76 | @echo compiling dynamic library $(LIBVER) 77 | @$(CC) $(FLAGS) -shared $^ -fPIC $(SONAME_FLAGS) -o $@.$(SHARED_EXT_VER) 78 | @echo creating versioned links 79 | @ln -sf $@.$(SHARED_EXT_VER) $@.$(SHARED_EXT_MAJOR) 80 | @ln -sf $@.$(SHARED_EXT_VER) $@.$(SHARED_EXT) 81 | 82 | example: mmc.o 83 | 84 | clean: 85 | @rm -f core *.o *.a *.$(SHARED_EXT) *.$(SHARED_EXT).* libmmc.pc 86 | @echo Cleaning completed 87 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mmc 2 | Automatically exported from code.google.com/p/mmc 3 | 4 | MMC stands for Morphing Match Chain. 5 | 6 | It's an algorithm for fast longest match search (primarily useful for compression softwares) 7 | 8 | MMC has been tested in combination with LZ4HC and zhuff compression algorithms. 9 | 10 | The algorithm is described on its homepage : http://fastcompression.blogspot.com/p/mmc-morphing-match-chain.html 11 | -------------------------------------------------------------------------------- /example.c: -------------------------------------------------------------------------------- 1 | /* minor example usage of mmc.c 2 | Copyright (C) Yann Collet 2018-present 3 | 4 | GPL v2 License 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License as published by 7 | the Free Software Foundation; either version 2 of the License, or 8 | (at your option) any later version. 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | You should have received a copy of the GNU General Public License along 14 | with this program; if not, write to the Free Software Foundation, Inc., 15 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 16 | You can contact the author at : 17 | - public issue list : https://github.com/Cyan4973/mmc/issues 18 | - website : http://fastcompression.blogspot.com/ 19 | */ 20 | 21 | #include /* malloc, free */ 22 | #include /* fopen, fread, fclose */ 23 | #include 24 | 25 | #include "mmc.h" 26 | 27 | #define KB *(1<<10) 28 | 29 | 30 | /* --- safe variants --- */ 31 | static void* MALLOC(size_t s) 32 | { 33 | void* const buf = calloc(1, s); 34 | assert(buf != NULL); 35 | return buf; 36 | } 37 | #define FREE free /* cannot fail */ 38 | 39 | static FILE* FOPEN(const char* name, const char* mode) 40 | { 41 | FILE* f = fopen(name, mode); 42 | assert(f != NULL); 43 | return f; 44 | } 45 | 46 | static size_t FREAD(void* buf, size_t s, size_t n, FILE* f) 47 | { 48 | size_t const read = fread(buf, s, n, f); 49 | assert(ferror(f) == 0); 50 | assert(read <= s*n); 51 | return read; 52 | } 53 | 54 | static void FCLOSE(FILE* f) 55 | { 56 | assert(fclose(f) == 0); 57 | } 58 | 59 | 60 | /* --- example --- */ 61 | 62 | char printableChar(char c) 63 | { 64 | if (32 <= c && c <= 126) return c; 65 | return '.'; 66 | } 67 | 68 | /* this function displays printable characters 69 | * and replaces all other ones by `.` */ 70 | void printContent(const void* p, size_t l) 71 | { 72 | #define PRINT_CONTENT_LENGTH_MAX 80 73 | const char* b = p; 74 | size_t u; 75 | if (l > PRINT_CONTENT_LENGTH_MAX) l = PRINT_CONTENT_LENGTH_MAX; 76 | for (u=0; u 0) { 93 | assert(match >= buffer); 94 | printf("pos%6zu: found match of length%3zu at pos%6zi ( ", 95 | pos, length, (const char*)match - buf); 96 | printContent(buf + pos, length); 97 | printf(" ) \n"); 98 | } } 99 | 100 | MMC_free(mmc); 101 | } 102 | 103 | 104 | int main(int argc, const char** argv) 105 | { 106 | size_t const bufferSize = 64 KB; 107 | void* const buffer = MALLOC(bufferSize); 108 | const char* exename = argv[0]; 109 | const char* filename = argv[1]; 110 | 111 | assert(argc >= 1); 112 | if (argc != 2) { 113 | printf("usage : %s FILENAME \n", exename); 114 | return 1; /* usage : exe Filename */ 115 | } 116 | 117 | /* read up to 64 KB from input, then search matches into it */ 118 | { FILE* const f = FOPEN(filename, "rb"); 119 | size_t const size = FREAD(buffer, 1, bufferSize, f); 120 | FCLOSE(f); 121 | printMatches(buffer, size); 122 | } 123 | 124 | FREE(buffer); 125 | } 126 | -------------------------------------------------------------------------------- /mem.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-present, Yann Collet 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under both the BSD-style license (found in the 6 | * LICENSE file in the root directory of this source tree) and the GPLv2 (found 7 | * in the COPYING file in the root directory of this source tree). 8 | * You may select, at your option, one of the above-listed licenses. 9 | */ 10 | 11 | #ifndef MEM_H_MODULE 12 | #define MEM_H_MODULE 13 | 14 | #if defined (__cplusplus) 15 | extern "C" { 16 | #endif 17 | 18 | /*-**************************************** 19 | * Dependencies 20 | ******************************************/ 21 | #include /* size_t, ptrdiff_t */ 22 | #include /* memcpy */ 23 | 24 | 25 | /*-**************************************** 26 | * Compiler specifics 27 | ******************************************/ 28 | #if defined(_MSC_VER) /* Visual Studio */ 29 | # include /* _byteswap_ulong */ 30 | # include /* _byteswap_* */ 31 | #endif 32 | #if defined(__GNUC__) 33 | # define MEM_STATIC static __inline __attribute__((unused)) 34 | #elif defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) 35 | # define MEM_STATIC static inline 36 | #elif defined(_MSC_VER) 37 | # define MEM_STATIC static __inline 38 | #else 39 | # define MEM_STATIC static /* this version may generate warnings for unused static functions; disable the relevant warning */ 40 | #endif 41 | 42 | /* code only tested on 32 and 64 bits systems */ 43 | #define MEM_STATIC_ASSERT(c) { enum { MEM_static_assert = 1/(int)(!!(c)) }; } 44 | MEM_STATIC void MEM_check(void) { MEM_STATIC_ASSERT((sizeof(size_t)==4) || (sizeof(size_t)==8)); } 45 | 46 | 47 | /*-************************************************************** 48 | * Basic Types 49 | *****************************************************************/ 50 | #if !defined (__VMS) && (defined (__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) ) 51 | # include 52 | typedef uint8_t BYTE; 53 | typedef uint16_t U16; 54 | typedef int16_t S16; 55 | typedef uint32_t U32; 56 | typedef int32_t S32; 57 | typedef uint64_t U64; 58 | typedef int64_t S64; 59 | #else 60 | typedef unsigned char BYTE; 61 | typedef unsigned short U16; 62 | typedef signed short S16; 63 | typedef unsigned int U32; 64 | typedef signed int S32; 65 | typedef unsigned long long U64; 66 | typedef signed long long S64; 67 | #endif 68 | 69 | 70 | /*-************************************************************** 71 | * Memory I/O 72 | *****************************************************************/ 73 | /* MEM_FORCE_MEMORY_ACCESS : 74 | * By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable. 75 | * Unfortunately, on some target/compiler combinations, the generated assembly is sub-optimal. 76 | * The below switch allow to select different access method for improved performance. 77 | * Method 0 (default) : use `memcpy()`. Safe and portable. 78 | * Method 1 : `__packed` statement. It depends on compiler extension (i.e., not portable). 79 | * This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`. 80 | * Method 2 : direct access. This method is portable but violate C standard. 81 | * It can generate buggy code on targets depending on alignment. 82 | * In some circumstances, it's the only known way to get the most performance (i.e. GCC + ARMv6) 83 | * See http://fastcompression.blogspot.fr/2015/08/accessing-unaligned-memory.html for details. 84 | * Prefer these methods in priority order (0 > 1 > 2) 85 | */ 86 | #ifndef MEM_FORCE_MEMORY_ACCESS /* can be defined externally, on command line for example */ 87 | # if defined(__GNUC__) && ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) ) 88 | # define MEM_FORCE_MEMORY_ACCESS 2 89 | # elif defined(__INTEL_COMPILER) || defined(__GNUC__) 90 | # define MEM_FORCE_MEMORY_ACCESS 1 91 | # endif 92 | #endif 93 | 94 | MEM_STATIC unsigned MEM_32bits(void) { return sizeof(size_t)==4; } 95 | MEM_STATIC unsigned MEM_64bits(void) { return sizeof(size_t)==8; } 96 | 97 | MEM_STATIC unsigned MEM_isLittleEndian(void) 98 | { 99 | const union { U32 u; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */ 100 | return one.c[0]; 101 | } 102 | 103 | #if defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==2) 104 | 105 | /* violates C standard, by lying on structure alignment. 106 | Only use if no other choice to achieve best performance on target platform */ 107 | MEM_STATIC U16 MEM_read16(const void* memPtr) { return *(const U16*) memPtr; } 108 | MEM_STATIC U32 MEM_read32(const void* memPtr) { return *(const U32*) memPtr; } 109 | MEM_STATIC U64 MEM_read64(const void* memPtr) { return *(const U64*) memPtr; } 110 | MEM_STATIC size_t MEM_readST(const void* memPtr) { return *(const size_t*) memPtr; } 111 | 112 | MEM_STATIC void MEM_write16(void* memPtr, U16 value) { *(U16*)memPtr = value; } 113 | MEM_STATIC void MEM_write32(void* memPtr, U32 value) { *(U32*)memPtr = value; } 114 | MEM_STATIC void MEM_write64(void* memPtr, U64 value) { *(U64*)memPtr = value; } 115 | 116 | #elif defined(MEM_FORCE_MEMORY_ACCESS) && (MEM_FORCE_MEMORY_ACCESS==1) 117 | 118 | /* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */ 119 | /* currently only defined for gcc and icc */ 120 | #if defined(_MSC_VER) || (defined(__INTEL_COMPILER) && defined(WIN32)) 121 | __pragma( pack(push, 1) ) 122 | typedef struct { U16 v; } unalign16; 123 | typedef struct { U32 v; } unalign32; 124 | typedef struct { U64 v; } unalign64; 125 | typedef struct { size_t v; } unalignArch; 126 | __pragma( pack(pop) ) 127 | #else 128 | typedef struct { U16 v; } __attribute__((packed)) unalign16; 129 | typedef struct { U32 v; } __attribute__((packed)) unalign32; 130 | typedef struct { U64 v; } __attribute__((packed)) unalign64; 131 | typedef struct { size_t v; } __attribute__((packed)) unalignArch; 132 | #endif 133 | 134 | MEM_STATIC U16 MEM_read16(const void* ptr) { return ((const unalign16*)ptr)->v; } 135 | MEM_STATIC U32 MEM_read32(const void* ptr) { return ((const unalign32*)ptr)->v; } 136 | MEM_STATIC U64 MEM_read64(const void* ptr) { return ((const unalign64*)ptr)->v; } 137 | MEM_STATIC size_t MEM_readST(const void* ptr) { return ((const unalignArch*)ptr)->v; } 138 | 139 | MEM_STATIC void MEM_write16(void* memPtr, U16 value) { ((unalign16*)memPtr)->v = value; } 140 | MEM_STATIC void MEM_write32(void* memPtr, U32 value) { ((unalign32*)memPtr)->v = value; } 141 | MEM_STATIC void MEM_write64(void* memPtr, U64 value) { ((unalign64*)memPtr)->v = value; } 142 | 143 | #else 144 | 145 | /* default method, safe and standard. 146 | can sometimes prove slower */ 147 | 148 | MEM_STATIC U16 MEM_read16(const void* memPtr) 149 | { 150 | U16 val; memcpy(&val, memPtr, sizeof(val)); return val; 151 | } 152 | 153 | MEM_STATIC U32 MEM_read32(const void* memPtr) 154 | { 155 | U32 val; memcpy(&val, memPtr, sizeof(val)); return val; 156 | } 157 | 158 | MEM_STATIC U64 MEM_read64(const void* memPtr) 159 | { 160 | U64 val; memcpy(&val, memPtr, sizeof(val)); return val; 161 | } 162 | 163 | MEM_STATIC size_t MEM_readST(const void* memPtr) 164 | { 165 | size_t val; memcpy(&val, memPtr, sizeof(val)); return val; 166 | } 167 | 168 | MEM_STATIC void MEM_write16(void* memPtr, U16 value) 169 | { 170 | memcpy(memPtr, &value, sizeof(value)); 171 | } 172 | 173 | MEM_STATIC void MEM_write32(void* memPtr, U32 value) 174 | { 175 | memcpy(memPtr, &value, sizeof(value)); 176 | } 177 | 178 | MEM_STATIC void MEM_write64(void* memPtr, U64 value) 179 | { 180 | memcpy(memPtr, &value, sizeof(value)); 181 | } 182 | 183 | #endif /* MEM_FORCE_MEMORY_ACCESS */ 184 | 185 | MEM_STATIC U32 MEM_swap32(U32 in) 186 | { 187 | #if defined(_MSC_VER) /* Visual Studio */ 188 | return _byteswap_ulong(in); 189 | #elif defined (__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 403) 190 | return __builtin_bswap32(in); 191 | #else 192 | return ((in << 24) & 0xff000000 ) | 193 | ((in << 8) & 0x00ff0000 ) | 194 | ((in >> 8) & 0x0000ff00 ) | 195 | ((in >> 24) & 0x000000ff ); 196 | #endif 197 | } 198 | 199 | MEM_STATIC U64 MEM_swap64(U64 in) 200 | { 201 | #if defined(_MSC_VER) /* Visual Studio */ 202 | return _byteswap_uint64(in); 203 | #elif defined (__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 403) 204 | return __builtin_bswap64(in); 205 | #else 206 | return ((in << 56) & 0xff00000000000000ULL) | 207 | ((in << 40) & 0x00ff000000000000ULL) | 208 | ((in << 24) & 0x0000ff0000000000ULL) | 209 | ((in << 8) & 0x000000ff00000000ULL) | 210 | ((in >> 8) & 0x00000000ff000000ULL) | 211 | ((in >> 24) & 0x0000000000ff0000ULL) | 212 | ((in >> 40) & 0x000000000000ff00ULL) | 213 | ((in >> 56) & 0x00000000000000ffULL); 214 | #endif 215 | } 216 | 217 | MEM_STATIC size_t MEM_swapST(size_t in) 218 | { 219 | if (MEM_32bits()) 220 | return (size_t)MEM_swap32((U32)in); 221 | else 222 | return (size_t)MEM_swap64((U64)in); 223 | } 224 | 225 | /*=== Little endian r/w ===*/ 226 | 227 | MEM_STATIC U16 MEM_readLE16(const void* memPtr) 228 | { 229 | if (MEM_isLittleEndian()) 230 | return MEM_read16(memPtr); 231 | else { 232 | const BYTE* p = (const BYTE*)memPtr; 233 | return (U16)(p[0] + (p[1]<<8)); 234 | } 235 | } 236 | 237 | MEM_STATIC void MEM_writeLE16(void* memPtr, U16 val) 238 | { 239 | if (MEM_isLittleEndian()) { 240 | MEM_write16(memPtr, val); 241 | } else { 242 | BYTE* p = (BYTE*)memPtr; 243 | p[0] = (BYTE)val; 244 | p[1] = (BYTE)(val>>8); 245 | } 246 | } 247 | 248 | MEM_STATIC U32 MEM_readLE24(const void* memPtr) 249 | { 250 | return MEM_readLE16(memPtr) + (((const BYTE*)memPtr)[2] << 16); 251 | } 252 | 253 | MEM_STATIC void MEM_writeLE24(void* memPtr, U32 val) 254 | { 255 | MEM_writeLE16(memPtr, (U16)val); 256 | ((BYTE*)memPtr)[2] = (BYTE)(val>>16); 257 | } 258 | 259 | MEM_STATIC U32 MEM_readLE32(const void* memPtr) 260 | { 261 | if (MEM_isLittleEndian()) 262 | return MEM_read32(memPtr); 263 | else 264 | return MEM_swap32(MEM_read32(memPtr)); 265 | } 266 | 267 | MEM_STATIC void MEM_writeLE32(void* memPtr, U32 val32) 268 | { 269 | if (MEM_isLittleEndian()) 270 | MEM_write32(memPtr, val32); 271 | else 272 | MEM_write32(memPtr, MEM_swap32(val32)); 273 | } 274 | 275 | MEM_STATIC U64 MEM_readLE64(const void* memPtr) 276 | { 277 | if (MEM_isLittleEndian()) 278 | return MEM_read64(memPtr); 279 | else 280 | return MEM_swap64(MEM_read64(memPtr)); 281 | } 282 | 283 | MEM_STATIC void MEM_writeLE64(void* memPtr, U64 val64) 284 | { 285 | if (MEM_isLittleEndian()) 286 | MEM_write64(memPtr, val64); 287 | else 288 | MEM_write64(memPtr, MEM_swap64(val64)); 289 | } 290 | 291 | MEM_STATIC size_t MEM_readLEST(const void* memPtr) 292 | { 293 | if (MEM_32bits()) 294 | return (size_t)MEM_readLE32(memPtr); 295 | else 296 | return (size_t)MEM_readLE64(memPtr); 297 | } 298 | 299 | MEM_STATIC void MEM_writeLEST(void* memPtr, size_t val) 300 | { 301 | if (MEM_32bits()) 302 | MEM_writeLE32(memPtr, (U32)val); 303 | else 304 | MEM_writeLE64(memPtr, (U64)val); 305 | } 306 | 307 | /*=== Big endian r/w ===*/ 308 | 309 | MEM_STATIC U32 MEM_readBE32(const void* memPtr) 310 | { 311 | if (MEM_isLittleEndian()) 312 | return MEM_swap32(MEM_read32(memPtr)); 313 | else 314 | return MEM_read32(memPtr); 315 | } 316 | 317 | MEM_STATIC void MEM_writeBE32(void* memPtr, U32 val32) 318 | { 319 | if (MEM_isLittleEndian()) 320 | MEM_write32(memPtr, MEM_swap32(val32)); 321 | else 322 | MEM_write32(memPtr, val32); 323 | } 324 | 325 | MEM_STATIC U64 MEM_readBE64(const void* memPtr) 326 | { 327 | if (MEM_isLittleEndian()) 328 | return MEM_swap64(MEM_read64(memPtr)); 329 | else 330 | return MEM_read64(memPtr); 331 | } 332 | 333 | MEM_STATIC void MEM_writeBE64(void* memPtr, U64 val64) 334 | { 335 | if (MEM_isLittleEndian()) 336 | MEM_write64(memPtr, MEM_swap64(val64)); 337 | else 338 | MEM_write64(memPtr, val64); 339 | } 340 | 341 | MEM_STATIC size_t MEM_readBEST(const void* memPtr) 342 | { 343 | if (MEM_32bits()) 344 | return (size_t)MEM_readBE32(memPtr); 345 | else 346 | return (size_t)MEM_readBE64(memPtr); 347 | } 348 | 349 | MEM_STATIC void MEM_writeBEST(void* memPtr, size_t val) 350 | { 351 | if (MEM_32bits()) 352 | MEM_writeBE32(memPtr, (U32)val); 353 | else 354 | MEM_writeBE64(memPtr, (U64)val); 355 | } 356 | 357 | 358 | #if defined (__cplusplus) 359 | } 360 | #endif 361 | 362 | #endif /* MEM_H_MODULE */ 363 | -------------------------------------------------------------------------------- /mmc.c: -------------------------------------------------------------------------------- 1 | /* 2 | MMC (Morphing Match Chain) 3 | Match Finder 4 | Copyright (C) Yann Collet 2010-present 5 | 6 | License : GNU L-GPLv3 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU Lesser General Public License as published by 10 | the Free Software Foundation; either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU Lesser General Public License for more details. 17 | 18 | You should have received a copy of the GNU Lesser General Public License along 19 | with this program; if not, see , 20 | or write to the Free Software Foundation, Inc., 21 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 | 23 | You can contact the author at : 24 | - MMC homepage : http://fastcompression.blogspot.com/p/mmc-morphing-match-chain.html 25 | - MMC source repository : https://github.com/Cyan4973/mmc 26 | */ 27 | 28 | /* ********************************************************** 29 | * Includes 30 | ************************************************************/ 31 | #include 32 | #define ALLOCATOR(s) calloc(1,s) 33 | #define REALLOCATOR(p,s) realloc(p,s) 34 | #define FREEMEM free 35 | #include 36 | #define MEM_INIT memset 37 | 38 | #include "mem.h" /* basic types and mem access */ 39 | #include "mmc.h" 40 | 41 | 42 | 43 | /* *********************************************************** 44 | * Constants 45 | ************************************************************/ 46 | #define MINMATCH 4 /* Note : for the time being, this cannot be changed */ 47 | #define DICTIONARY_LOGSIZE 16 /* Dictionary Size as a power of 2 (ex : 2^16 = 64K) */ 48 | /* Total RAM allocated is 10x Dictionary (ex : Dictionary 64K ==> 640K) */ 49 | 50 | #define MAXD (1 << DICTIONARY_LOGSIZE) 51 | #define MAXD_MASK ((U32)(MAXD - 1)) 52 | #define MAX_DISTANCE (MAXD - 1) 53 | 54 | #define HASH_LOG (DICTIONARY_LOGSIZE-1) 55 | #define HASHTABLESIZE (1 << HASH_LOG) 56 | #define HASH_MASK (HASHTABLESIZE - 1) 57 | 58 | #define MAX_LEVELS_LOG (DICTIONARY_LOGSIZE-1) 59 | #define MAX_LEVELS (1U<=1) 79 | # include 80 | #else 81 | # define assert(condition) ((void)0) /* disable assert (default) */ 82 | #endif 83 | 84 | 85 | /* ********************************************************** 86 | * Local Types 87 | ************************************************************/ 88 | typedef struct { 89 | const BYTE* levelUp; 90 | const BYTE* nextTry; 91 | } selectNextHop_t; 92 | 93 | typedef struct { 94 | const BYTE* position; 95 | U32 size; 96 | } segmentInfo_t; 97 | 98 | typedef struct { 99 | segmentInfo_t * segments; 100 | U16 start; 101 | U16 max; 102 | } segmentTracker_t; 103 | 104 | struct MMC_ctx_s 105 | { 106 | const BYTE* beginBuffer; /* First byte of data buffer being searched */ 107 | const BYTE* lastPosInserted; /* excluded */ 108 | const BYTE* hashTable[HASHTABLESIZE]; 109 | selectNextHop_t chainTable[MAXD]; 110 | segmentTracker_t segments[NBCHARACTERS]; 111 | const BYTE* levelList[MAX_LEVELS]; 112 | const BYTE** trackPtr[NBCHARACTERS]; 113 | U16 trackStep[NBCHARACTERS]; 114 | }; /* typedef'd to MMC_ctx within "mmc.h" */ 115 | 116 | 117 | /* ********************************************************** 118 | * Macros 119 | ************************************************************/ 120 | #define HASH_VALUE(p) MMC_hash(MEM_read32(p)) 121 | #define NEXT_TRY(p) chainTable[(size_t)(p) & MAXD_MASK].nextTry 122 | #define LEVEL_UP(p) chainTable[(size_t)(p) & MAXD_MASK].levelUp 123 | #define ADD_HASH(p) { NEXT_TRY(p) = HashTable[HASH_VALUE(p)]; LEVEL_UP(p)=0; HashTable[HASH_VALUE(p)] = p; } 124 | #define LEVEL(l) levelList[(l)&MAX_LEVELS_MASK] 125 | 126 | 127 | /* ********************************************************** 128 | * Object Allocation 129 | ************************************************************/ 130 | MMC_ctx* MMC_create (void) 131 | { 132 | return (MMC_ctx*) ALLOCATOR(sizeof(MMC_ctx)); 133 | } 134 | 135 | size_t MMC_init(MMC_ctx* MMC, const void* beginBuffer) 136 | { 137 | MMC->beginBuffer = (const BYTE*)beginBuffer; 138 | MMC->lastPosInserted = MMC->beginBuffer; 139 | MEM_INIT(MMC->chainTable, 0, sizeof(MMC->chainTable)); 140 | MEM_INIT(MMC->hashTable, 0, sizeof(MMC->hashTable)); 141 | /* Init RLE detector */ 142 | { int c; 143 | for (c=0; csegments[c].segments, NB_INITIAL_SEGMENTS * sizeof(segmentInfo_t)); 145 | if (newSegment == NULL) return 1; /* realloc failed : existing segment is preserved */ 146 | MMC->segments[c].segments = newSegment; 147 | MMC->segments[c].max = NB_INITIAL_SEGMENTS; 148 | MMC->segments[c].start = 0; 149 | MMC->segments[c].segments[0].size = -1; 150 | MMC->segments[c].segments[0].position = (const BYTE*)beginBuffer - (MAX_DISTANCE+1); 151 | } } 152 | return 0; 153 | } 154 | 155 | 156 | void MMC_free (MMC_ctx* ctx) 157 | { 158 | int c; 159 | if (ctx==NULL) return; /* compatible free on NULL */ 160 | for (c=0; csegments[c].segments); 162 | FREEMEM(ctx); 163 | } 164 | 165 | 166 | /* ******************************************************************* 167 | * Basic Search operations (Greedy / Lazy / Flexible parsing) 168 | *********************************************************************/ 169 | static U32 MMC_hash(U32 u) { return (u * 2654435761U) >> (32-HASH_LOG); } 170 | 171 | static size_t MMC_insert_once (MMC_ctx* MMC, const void* ptr, size_t max); 172 | 173 | size_t MMC_insertAndFindBestMatch (MMC_ctx* MMC, const void* inputPointer, size_t maxLength, const void** matchpos) 174 | { 175 | segmentTracker_t* const Segments = MMC->segments; 176 | selectNextHop_t* const chainTable = MMC->chainTable; 177 | const BYTE** const HashTable = MMC->hashTable; 178 | const BYTE** const levelList = MMC->levelList; 179 | const BYTE*** const trackPtr = MMC->trackPtr; 180 | U16* const trackStep = MMC->trackStep; 181 | const BYTE* const iend = (const BYTE*)inputPointer + maxLength; 182 | const BYTE* const ip = (const BYTE*)inputPointer; 183 | const BYTE* ref; 184 | const BYTE** gateway; 185 | U16 stepNb=0; 186 | U32 currentLevel, maxLevel; 187 | U32 ml=0, mlt=0, nbChars=0; 188 | U32 sequence; 189 | 190 | if (maxLength < 4) return 0; /* no solution */ 191 | sequence = MEM_read32(ip); 192 | 193 | // RLE match finder (special case) 194 | if ( (U16)sequence == (U16)(sequence>>16) 195 | && (BYTE)sequence == (BYTE)(sequence>>8) ) { 196 | BYTE const c = (BYTE)sequence; 197 | U32 index = Segments[c].start; 198 | const BYTE* endSegment = ip+MINMATCH; 199 | 200 | while ((*endSegment==c) && (endSegmentMMC->beginBuffer) && (*(ip-1)==c)) { 211 | // obvious RLE solution 212 | *matchpos= ip-1; 213 | return nbChars; 214 | } 215 | return 0; 216 | } 217 | 218 | ref = NEXT_TRY(ip)= Segments[c].segments[index].position - nbChars; 219 | currentLevel = maxLevel = ml = nbChars; 220 | LEVEL(currentLevel) = ip; 221 | gateway = 0; // work around due to erasing 222 | LEVEL_UP(ip) = 0; 223 | if (*(ip-1)==c) *matchpos = ip-1; else *matchpos = ref; // "basis" to be improved upon 224 | if (nbChars==MINMATCH) { 225 | MMC_insert_once(MMC, ip, iend-ip); 226 | gateway = &LEVEL_UP(ip); 227 | } 228 | goto _FindBetterMatch; 229 | } 230 | 231 | // MMC match finder 232 | ref = HashTable[MMC_hash(sequence)]; 233 | ADD_HASH(ip); 234 | if (!ref) return 0; 235 | gateway = &LEVEL_UP(ip); 236 | currentLevel = maxLevel = MINMATCH-1; 237 | LEVEL(MINMATCH-1) = ip; 238 | 239 | // Collision detection & avoidance 240 | while ((ref) && ((ip-ref) < MAX_DISTANCE)) { 241 | if (MEM_read32(ref) != sequence) { 242 | LEVEL(MINMATCH-1) = ref; 243 | ref = NEXT_TRY(ref); 244 | continue; 245 | } 246 | 247 | mlt = MINMATCH; 248 | while ((mlt<(U32)maxLength) && (*(ip+mlt)) == *(ref+mlt)) mlt++; 249 | 250 | if (mlt > ml) { 251 | ml = mlt; 252 | *matchpos = ref; 253 | } 254 | 255 | // Continue level mlt chain 256 | if (mlt <= maxLevel) { 257 | NEXT_TRY(LEVEL(mlt)) = ref; LEVEL(mlt) = ref; // Completing chain at Level mlt 258 | } 259 | 260 | // New level creation 261 | else { 262 | if (gateway) { 263 | // Only guaranteed the first time (gateway is ip) 264 | maxLevel++; 265 | *gateway = ref; 266 | LEVEL(maxLevel)=ref; // First element of level maxLevel 267 | if (mlt>maxLevel) gateway=&(LEVEL_UP(ref)); else gateway=0; 268 | } 269 | 270 | // Special case : no gateway, but mlt>maxLevel 271 | else { 272 | gateway = &(LEVEL_UP(ref)); 273 | NEXT_TRY(LEVEL(maxLevel)) = ref; LEVEL(maxLevel) = ref; // Completing chain at Level maxLevel 274 | } 275 | } 276 | 277 | { const BYTE* currentP = ref; 278 | NEXT_TRY(LEVEL(MINMATCH-1)) = NEXT_TRY(ref); // Extraction from base level 279 | if (LEVEL_UP(ref)) { 280 | ref = LEVEL_UP(ref); 281 | NEXT_TRY(currentP) = LEVEL_UP(currentP) = 0; // Clean, because extracted 282 | currentLevel++; 283 | NEXT_TRY(LEVEL(MINMATCH)) = ref; 284 | break; 285 | } 286 | ref = NEXT_TRY(ref); 287 | NEXT_TRY(currentP) = 0; // initialisation, due to promotion; note that LEVEL_UP(ref)==0; 288 | } } 289 | 290 | if (ml == 0) return 0; // no match found 291 | 292 | 293 | // looking for better length of match 294 | _FindBetterMatch: 295 | while ((ref) && ((ip-ref) < MAX_DISTANCE)) { 296 | // Reset rolling counter for Secondary Promotions 297 | if (!stepNb) { 298 | U32 i; 299 | for (i=0; i continue on current chain 308 | if (mlt==currentLevel) { 309 | BYTE c = *(ref+currentLevel); 310 | if (trackStep[c] == stepNb) { 311 | // this wrong character was already met before 312 | const BYTE* next = NEXT_TRY(ref); 313 | *trackPtr[c] = ref; // linking 314 | NEXT_TRY(LEVEL(currentLevel)) = NEXT_TRY(ref); // extraction 315 | if (LEVEL_UP(ref)) { 316 | NEXT_TRY(ref) = LEVEL_UP(ref); // Promotion 317 | LEVEL_UP(ref) = 0; 318 | trackStep[c] = 0; // Shutdown chain (avoid overwriting when multiple unfinished chains) 319 | } else { 320 | NEXT_TRY(ref) = LEVEL_DOWN; // Promotion, but link back to previous level for now 321 | trackPtr[c] = &(NEXT_TRY(ref)); // saving for next link 322 | } 323 | 324 | if (next==LEVEL_DOWN) { 325 | NEXT_TRY(LEVEL(currentLevel)) = 0; // Erase the LEVEL_DOWN 326 | currentLevel--; stepNb++; 327 | next = NEXT_TRY(LEVEL(currentLevel)); 328 | while (next > ref) { LEVEL(currentLevel) = next; next = NEXT_TRY(next); } 329 | } 330 | ref = next; 331 | 332 | continue; 333 | } 334 | 335 | // first time we see this character 336 | if (LEVEL_UP(ref)==0) // don't interfere if a serie has already started... 337 | // Note : to "catch up" the serie, it would be necessary to scan it, up to its last element 338 | // this effort would be useless if the chain is complete 339 | // Alternatively : we could keep that gateway in memory, and scan the chain on finding that it is not complete. 340 | // But would it be worth it ?? 341 | { 342 | trackStep[c] = stepNb; 343 | trackPtr[c] = &(LEVEL_UP(ref)); 344 | } 345 | 346 | _continue_same_level: 347 | LEVEL(currentLevel) = ref; 348 | ref = NEXT_TRY(ref); 349 | if (ref == LEVEL_DOWN) { 350 | const BYTE* localCurrentP = LEVEL(currentLevel); 351 | const BYTE* next = NEXT_TRY(LEVEL(currentLevel-1)); 352 | NEXT_TRY(localCurrentP) = 0; // Erase the LEVEL_DOWN 353 | while (next>localCurrentP) { LEVEL(currentLevel-1) = next; next = NEXT_TRY(next);} 354 | ref = next; 355 | currentLevel--; stepNb++; 356 | } 357 | continue; 358 | } 359 | 360 | // Now, mlt > currentLevel 361 | if (mlt>ml) { 362 | ml = mlt; 363 | *matchpos = ref; 364 | } 365 | 366 | // placing into corresponding chain 367 | if (mlt<=maxLevel) { 368 | NEXT_TRY(LEVEL(mlt)) = ref; LEVEL(mlt) = ref; // Completing chain at Level mlt 369 | _check_mmc_levelup: 370 | { const BYTE* currentP = ref; 371 | NEXT_TRY(LEVEL(currentLevel)) = NEXT_TRY(ref); // Extraction from base level 372 | if (LEVEL_UP(ref)) { 373 | ref = LEVEL_UP(ref); // LevelUp 374 | NEXT_TRY(currentP) = LEVEL_UP(currentP) = 0; // Clean, because extracted 375 | currentLevel++; stepNb++; 376 | NEXT_TRY(LEVEL(currentLevel)) = ref; // We don't know yet ref's level, but just in case it would be only ==currentLevel... 377 | } else { 378 | ref = NEXT_TRY(ref); 379 | NEXT_TRY(currentP) = 0; // promotion to level mlt; note that LEVEL_UP(ref)=0; 380 | if (ref == LEVEL_DOWN) { 381 | const BYTE* next = NEXT_TRY(LEVEL(currentLevel-1)); 382 | NEXT_TRY(LEVEL(currentLevel)) = 0; // Erase the LEVEL_DOWN (which has been transfered) 383 | while (next>currentP) { LEVEL(currentLevel-1) = next; next = NEXT_TRY(next); } 384 | ref = next; 385 | currentLevel--; stepNb++; 386 | } 387 | } 388 | continue; 389 | } } 390 | 391 | // MaxLevel increase 392 | if (gateway) { 393 | *gateway = ref; 394 | maxLevel++; 395 | LEVEL(maxLevel) = ref; // First element of level max 396 | if (mlt>maxLevel) gateway=&(LEVEL_UP(ref)); else gateway=0; 397 | goto _check_mmc_levelup; 398 | } 399 | 400 | // Special case : mlt>maxLevel==currentLevel, no Level_up nor gateway 401 | if ((maxLevel==currentLevel) && (!(LEVEL_UP(ref)))) { 402 | gateway = &(LEVEL_UP(ref)); // note : *gateway = 0 403 | goto _continue_same_level; 404 | } 405 | 406 | // Special case : mlt>maxLevel==currentLevel, Level_up available, but no gateway 407 | if (maxLevel==currentLevel) { 408 | LEVEL(currentLevel) = ref; 409 | ref = LEVEL_UP(ref); 410 | maxLevel++; 411 | currentLevel++; stepNb++; 412 | continue; 413 | } 414 | 415 | // Special case : mlt>maxLevel, but no gateway; Note that we don't know about level_up yet 416 | gateway = &(LEVEL_UP(ref)); 417 | NEXT_TRY(LEVEL(maxLevel)) = ref; LEVEL(maxLevel) = ref; // Completing chain of maxLevel 418 | goto _check_mmc_levelup; 419 | } 420 | 421 | if (gateway) *gateway=ip-MAX_DISTANCE-1; // early end trick 422 | stepNb++; 423 | 424 | // prevent match beyond buffer 425 | if ((ip+ml)>iend) ml = iend-ip; 426 | 427 | return ml; 428 | } 429 | 430 | 431 | static size_t MMC_insert_once (MMC_ctx* MMC, const void* ptr, size_t max) 432 | { 433 | segmentTracker_t * Segments = MMC->segments; 434 | selectNextHop_t * chainTable = MMC->chainTable; 435 | const BYTE** HashTable = MMC->hashTable; 436 | const BYTE* ip = (const BYTE*)ptr; 437 | const BYTE* iend = ip+max; 438 | const BYTE* beginBuffer = MMC->beginBuffer; 439 | 440 | /* RLE updater */ 441 | if ( (MEM_read16(ip) == MEM_read16(ip+2)) 442 | && (*ip == *(ip+1)) ) /* 4 identical bytes */ 443 | { 444 | BYTE const c = *ip; 445 | U32 nbForwardChars, nbPreviousChars, segmentSize, n=MINMATCH; 446 | const BYTE* endSegment = ip+MINMATCH; 447 | const BYTE* baseStreamP = ip; 448 | 449 | iend += MINMATCH; 450 | while ((*endSegment==c) && (endSegmentbeginBuffer) && (baseStreamP[-1]==c)) baseStreamP--; 454 | nbPreviousChars = ip-baseStreamP; 455 | segmentSize = nbForwardChars + nbPreviousChars; 456 | if (segmentSize > MAX_DISTANCE-1) segmentSize = MAX_DISTANCE-1; 457 | 458 | while (Segments[c].segments[Segments[c].start].size <= segmentSize) { 459 | if (Segments[c].segments[Segments[c].start].position <= (ip-MAX_DISTANCE)) break; 460 | for ( ; n<=Segments[c].segments[Segments[c].start].size ; n++) { 461 | NEXT_TRY(endSegment-n) = Segments[c].segments[Segments[c].start].position - n; 462 | LEVEL_UP(endSegment-n) = 0; 463 | } 464 | Segments[c].start--; 465 | } 466 | 467 | if (Segments[c].segments[Segments[c].start].position <= (ip-MAX_DISTANCE)) 468 | Segments[c].start = 0; /* no large enough serie within range */ 469 | 470 | for ( ; n<=segmentSize ; n++) { 471 | NEXT_TRY(endSegment-n) = Segments[c].segments[Segments[c].start].position - n; 472 | LEVEL_UP(endSegment-n) = 0; 473 | } 474 | 475 | /* overflow protection : new segment smaller than previous, but too many segments in memory */ 476 | if (Segments[c].start > Segments[c].max-2) { 477 | segmentInfo_t* newSegment = REALLOCATOR (Segments[c].segments, (Segments[c].max * 2) * sizeof(segmentInfo_t)); 478 | U32 beginning=0; 479 | 480 | if (newSegment == NULL) return 0; /* allocation failed : we stop search here. Ideally, it should be an error, rather than a soft "end of search" */ 481 | Segments[c].max *= 2; 482 | Segments[c].segments = newSegment; 483 | /* transfer still valid positions (within window size) towards beginning of buffer */ 484 | while (newSegment[beginning].position < (ip-MAX_DISTANCE)) beginning++; 485 | { U32 u; for (u = beginning; u <= Segments[c].start; u++) { 486 | newSegment[u - (beginning-1)] = newSegment[u]; 487 | } } 488 | Segments[c].start -= (beginning-1); 489 | } 490 | Segments[c].start++; 491 | Segments[c].segments[Segments[c].start].position = endSegment; 492 | Segments[c].segments[Segments[c].start].size = segmentSize; 493 | 494 | return (endSegment-ip-(MINMATCH-1)); 495 | } 496 | 497 | /* Normal update */ 498 | NEXT_TRY(ip) = HashTable[HASH_VALUE(ip)]; 499 | LEVEL_UP(ip) = 0; 500 | HashTable[HASH_VALUE(ip)] = ip; 501 | 502 | return 1; 503 | } 504 | -------------------------------------------------------------------------------- /mmc.h: -------------------------------------------------------------------------------- 1 | /* 2 | MMC (Morphing Match Chain) 3 | Match Finder 4 | Copyright (C) Yann Collet 2010-present 5 | 6 | License : GNU L-GPLv3 7 | 8 | This program is free software; you can redistribute it and/or modify 9 | it under the terms of the GNU Lesser General Public License as published by 10 | the Free Software Foundation; either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU Lesser General Public License for more details. 17 | 18 | You should have received a copy of the GNU Lesser General Public License along 19 | with this program; if not, see , 20 | or write to the Free Software Foundation, Inc., 21 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 22 | 23 | You can contact the author at : 24 | - MMC homepage : http://fastcompression.blogspot.com/p/mmc-morphing-match-chain.html 25 | - MMC source repository : https://github.com/Cyan4973/mmc 26 | */ 27 | 28 | #ifndef MMC_H 29 | #define MMC_H 30 | 31 | #if defined (__cplusplus) 32 | extern "C" { 33 | #endif 34 | 35 | /* ************************************* 36 | * Includes 37 | ***************************************/ 38 | #include /* size_t */ 39 | 40 | 41 | /* ********************************************************** 42 | * Object Allocation 43 | ************************************************************/ 44 | typedef struct MMC_ctx_s MMC_ctx; /* incomplete type */ 45 | 46 | MMC_ctx* MMC_create(void); 47 | size_t MMC_init (MMC_ctx* ctx, const void* beginBuffer); 48 | void MMC_free (MMC_ctx* ctx); 49 | 50 | /** 51 | MMC_create : create an MMC object to search matches into a single continuous bufferSize 52 | up to a distance of WindowSize (Note : WindowSize is a compile-time constant). 53 | @return : Pointer to MMC Data Structure; NULL = error 54 | MMC_init : prepare MMC object to start searching from position beginBuffer; 55 | @return : 0 on success, 1 on error. 56 | MMC_free : free memory from MMC Data Structure; 57 | ctx must be NULL of valid. 58 | */ 59 | 60 | /* *********************************************************** 61 | * Search operations 62 | *************************************************************/ 63 | 64 | size_t MMC_insertAndFindBestMatch (MMC_ctx* ctx, const void* inputPointer, size_t maxLength, const void** matchpos); 65 | 66 | /** 67 | MMC_insertAndFindBestMatch : 68 | @inputPointer : position being inserted & searched 69 | @maxLength : maximum match length autorized 70 | @return : length of Best Match 71 | if return == 0, no match was found 72 | if return > 0, match position is stored into *matchpos 73 | */ 74 | 75 | 76 | #if defined (__cplusplus) 77 | } 78 | #endif 79 | 80 | #endif /* MMC_H */ 81 | --------------------------------------------------------------------------------