├── .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 |
--------------------------------------------------------------------------------