├── .gitignore ├── CHANGES.md ├── COPYING ├── LICENSE ├── Makefile ├── README.md ├── TODO ├── dune ├── dune-project ├── ptmap.ml ├── ptmap.mli ├── ptmap.opam └── test.ml /.gitignore: -------------------------------------------------------------------------------- 1 | .merlin 2 | _build/ 3 | -------------------------------------------------------------------------------- /CHANGES.md: -------------------------------------------------------------------------------- 1 | 2 | # 2.0.5 3 | - switch from obuild to dune and to opam 2.0 4 | - fixed compilation with old versions of OCaml 5 | - document the difference wrt `Map.S` specs (issue #11) 6 | - more efficient implementation of `union` (issue #7) 7 | - add `update` (Andy Li) 8 | - add `filter_map` (rwmjones) 9 | - no more use of qtest, move tests from ptmap.ml to test.ml 10 | 11 | # 2.0.0 12 | - added missing functions to conform to `Map.S` (Francois Berenger) 13 | - unit tests (Francois Berenger) 14 | 15 | # 1.0.0 16 | - first opam package 17 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | bitv - Objective Caml bit vectors library 2 | Copyright (C) 1999 Jean-Christophe FILLIATRE 3 | 4 | This software is free software; you can redistribute it and/or 5 | modify it under the terms of the GNU Library General Public 6 | License version 2, with the special exception on linking 7 | described in file LICENSE. 8 | 9 | This software 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. 12 | 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The Library is distributed under the terms of the GNU Library General 2 | Public License version 2 (included below). 3 | 4 | As a special exception to the GNU Library General Public License, you 5 | may link, statically or dynamically, a "work that uses the Library" 6 | with a publicly distributed version of the Library to produce an 7 | executable file containing portions of the Library, and distribute 8 | that executable file under terms of your choice, without any of the 9 | additional requirements listed in clause 6 of the GNU Library General 10 | Public License. By "a publicly distributed version of the Library", we 11 | mean either the unmodified Library as distributed, or a 12 | modified version of the Library that is distributed under the 13 | conditions defined in clause 3 of the GNU Library General Public 14 | License. This exception does not however invalidate any other reasons 15 | why the executable file might be covered by the GNU Library General 16 | Public License. 17 | 18 | ====================================================================== 19 | GNU LIBRARY GENERAL PUBLIC LICENSE 20 | Version 2, June 1991 21 | 22 | Copyright (C) 1991 Free Software Foundation, Inc. 23 | 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 24 | Everyone is permitted to copy and distribute verbatim copies 25 | of this license document, but changing it is not allowed. 26 | 27 | [This is the first released version of the library GPL. It is 28 | numbered 2 because it goes with version 2 of the ordinary GPL.] 29 | 30 | Preamble 31 | 32 | The licenses for most software are designed to take away your 33 | freedom to share and change it. By contrast, the GNU General Public 34 | Licenses are intended to guarantee your freedom to share and change 35 | free software--to make sure the software is free for all its users. 36 | 37 | This license, the Library General Public License, applies to some 38 | specially designated Free Software Foundation software, and to any 39 | other libraries whose authors decide to use it. You can use it for 40 | your libraries, too. 41 | 42 | When we speak of free software, we are referring to freedom, not 43 | price. Our General Public Licenses are designed to make sure that you 44 | have the freedom to distribute copies of free software (and charge for 45 | this service if you wish), that you receive source code or can get it 46 | if you want it, that you can change the software or use pieces of it 47 | in new free programs; and that you know you can do these things. 48 | 49 | To protect your rights, we need to make restrictions that forbid 50 | anyone to deny you these rights or to ask you to surrender the rights. 51 | These restrictions translate to certain responsibilities for you if 52 | you distribute copies of the library, or if you modify it. 53 | 54 | For example, if you distribute copies of the library, whether gratis 55 | or for a fee, you must give the recipients all the rights that we gave 56 | you. You must make sure that they, too, receive or can get the source 57 | code. If you link a program with the library, you must provide 58 | complete object files to the recipients so that they can relink them 59 | with the library, after making changes to the library and recompiling 60 | it. And you must show them these terms so they know their rights. 61 | 62 | Our method of protecting your rights has two steps: (1) copyright 63 | the library, and (2) offer you this license which gives you legal 64 | permission to copy, distribute and/or modify the library. 65 | 66 | Also, for each distributor's protection, we want to make certain 67 | that everyone understands that there is no warranty for this free 68 | library. If the library is modified by someone else and passed on, we 69 | want its recipients to know that what they have is not the original 70 | version, so that any problems introduced by others will not reflect on 71 | the original authors' reputations. 72 | 73 | Finally, any free program is threatened constantly by software 74 | patents. We wish to avoid the danger that companies distributing free 75 | software will individually obtain patent licenses, thus in effect 76 | transforming the program into proprietary software. To prevent this, 77 | we have made it clear that any patent must be licensed for everyone's 78 | free use or not licensed at all. 79 | 80 | Most GNU software, including some libraries, is covered by the ordinary 81 | GNU General Public License, which was designed for utility programs. This 82 | license, the GNU Library General Public License, applies to certain 83 | designated libraries. This license is quite different from the ordinary 84 | one; be sure to read it in full, and don't assume that anything in it is 85 | the same as in the ordinary license. 86 | 87 | The reason we have a separate public license for some libraries is that 88 | they blur the distinction we usually make between modifying or adding to a 89 | program and simply using it. Linking a program with a library, without 90 | changing the library, is in some sense simply using the library, and is 91 | analogous to running a utility program or application program. However, in 92 | a textual and legal sense, the linked executable is a combined work, a 93 | derivative of the original library, and the ordinary General Public License 94 | treats it as such. 95 | 96 | Because of this blurred distinction, using the ordinary General 97 | Public License for libraries did not effectively promote software 98 | sharing, because most developers did not use the libraries. We 99 | concluded that weaker conditions might promote sharing better. 100 | 101 | However, unrestricted linking of non-free programs would deprive the 102 | users of those programs of all benefit from the free status of the 103 | libraries themselves. This Library General Public License is intended to 104 | permit developers of non-free programs to use free libraries, while 105 | preserving your freedom as a user of such programs to change the free 106 | libraries that are incorporated in them. (We have not seen how to achieve 107 | this as regards changes in header files, but we have achieved it as regards 108 | changes in the actual functions of the Library.) The hope is that this 109 | will lead to faster development of free libraries. 110 | 111 | The precise terms and conditions for copying, distribution and 112 | modification follow. Pay close attention to the difference between a 113 | "work based on the library" and a "work that uses the library". The 114 | former contains code derived from the library, while the latter only 115 | works together with the library. 116 | 117 | Note that it is possible for a library to be covered by the ordinary 118 | General Public License rather than by this special one. 119 | 120 | GNU LIBRARY GENERAL PUBLIC LICENSE 121 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 122 | 123 | 0. This License Agreement applies to any software library which 124 | contains a notice placed by the copyright holder or other authorized 125 | party saying it may be distributed under the terms of this Library 126 | General Public License (also called "this License"). Each licensee is 127 | addressed as "you". 128 | 129 | A "library" means a collection of software functions and/or data 130 | prepared so as to be conveniently linked with application programs 131 | (which use some of those functions and data) to form executables. 132 | 133 | The "Library", below, refers to any such software library or work 134 | which has been distributed under these terms. A "work based on the 135 | Library" means either the Library or any derivative work under 136 | copyright law: that is to say, a work containing the Library or a 137 | portion of it, either verbatim or with modifications and/or translated 138 | straightforwardly into another language. (Hereinafter, translation is 139 | included without limitation in the term "modification".) 140 | 141 | "Source code" for a work means the preferred form of the work for 142 | making modifications to it. For a library, complete source code means 143 | all the source code for all modules it contains, plus any associated 144 | interface definition files, plus the scripts used to control compilation 145 | and installation of the library. 146 | 147 | Activities other than copying, distribution and modification are not 148 | covered by this License; they are outside its scope. The act of 149 | running a program using the Library is not restricted, and output from 150 | such a program is covered only if its contents constitute a work based 151 | on the Library (independent of the use of the Library in a tool for 152 | writing it). Whether that is true depends on what the Library does 153 | and what the program that uses the Library does. 154 | 155 | 1. You may copy and distribute verbatim copies of the Library's 156 | complete source code as you receive it, in any medium, provided that 157 | you conspicuously and appropriately publish on each copy an 158 | appropriate copyright notice and disclaimer of warranty; keep intact 159 | all the notices that refer to this License and to the absence of any 160 | warranty; and distribute a copy of this License along with the 161 | Library. 162 | 163 | You may charge a fee for the physical act of transferring a copy, 164 | and you may at your option offer warranty protection in exchange for a 165 | fee. 166 | 167 | 2. You may modify your copy or copies of the Library or any portion 168 | of it, thus forming a work based on the Library, and copy and 169 | distribute such modifications or work under the terms of Section 1 170 | above, provided that you also meet all of these conditions: 171 | 172 | a) The modified work must itself be a software library. 173 | 174 | b) You must cause the files modified to carry prominent notices 175 | stating that you changed the files and the date of any change. 176 | 177 | c) You must cause the whole of the work to be licensed at no 178 | charge to all third parties under the terms of this License. 179 | 180 | d) If a facility in the modified Library refers to a function or a 181 | table of data to be supplied by an application program that uses 182 | the facility, other than as an argument passed when the facility 183 | is invoked, then you must make a good faith effort to ensure that, 184 | in the event an application does not supply such function or 185 | table, the facility still operates, and performs whatever part of 186 | its purpose remains meaningful. 187 | 188 | (For example, a function in a library to compute square roots has 189 | a purpose that is entirely well-defined independent of the 190 | application. Therefore, Subsection 2d requires that any 191 | application-supplied function or table used by this function must 192 | be optional: if the application does not supply it, the square 193 | root function must still compute square roots.) 194 | 195 | These requirements apply to the modified work as a whole. If 196 | identifiable sections of that work are not derived from the Library, 197 | and can be reasonably considered independent and separate works in 198 | themselves, then this License, and its terms, do not apply to those 199 | sections when you distribute them as separate works. But when you 200 | distribute the same sections as part of a whole which is a work based 201 | on the Library, the distribution of the whole must be on the terms of 202 | this License, whose permissions for other licensees extend to the 203 | entire whole, and thus to each and every part regardless of who wrote 204 | it. 205 | 206 | Thus, it is not the intent of this section to claim rights or contest 207 | your rights to work written entirely by you; rather, the intent is to 208 | exercise the right to control the distribution of derivative or 209 | collective works based on the Library. 210 | 211 | In addition, mere aggregation of another work not based on the Library 212 | with the Library (or with a work based on the Library) on a volume of 213 | a storage or distribution medium does not bring the other work under 214 | the scope of this License. 215 | 216 | 3. You may opt to apply the terms of the ordinary GNU General Public 217 | License instead of this License to a given copy of the Library. To do 218 | this, you must alter all the notices that refer to this License, so 219 | that they refer to the ordinary GNU General Public License, version 2, 220 | instead of to this License. (If a newer version than version 2 of the 221 | ordinary GNU General Public License has appeared, then you can specify 222 | that version instead if you wish.) Do not make any other change in 223 | these notices. 224 | 225 | Once this change is made in a given copy, it is irreversible for 226 | that copy, so the ordinary GNU General Public License applies to all 227 | subsequent copies and derivative works made from that copy. 228 | 229 | This option is useful when you wish to copy part of the code of 230 | the Library into a program that is not a library. 231 | 232 | 4. You may copy and distribute the Library (or a portion or 233 | derivative of it, under Section 2) in object code or executable form 234 | under the terms of Sections 1 and 2 above provided that you accompany 235 | it with the complete corresponding machine-readable source code, which 236 | must be distributed under the terms of Sections 1 and 2 above on a 237 | medium customarily used for software interchange. 238 | 239 | If distribution of object code is made by offering access to copy 240 | from a designated place, then offering equivalent access to copy the 241 | source code from the same place satisfies the requirement to 242 | distribute the source code, even though third parties are not 243 | compelled to copy the source along with the object code. 244 | 245 | 5. A program that contains no derivative of any portion of the 246 | Library, but is designed to work with the Library by being compiled or 247 | linked with it, is called a "work that uses the Library". Such a 248 | work, in isolation, is not a derivative work of the Library, and 249 | therefore falls outside the scope of this License. 250 | 251 | However, linking a "work that uses the Library" with the Library 252 | creates an executable that is a derivative of the Library (because it 253 | contains portions of the Library), rather than a "work that uses the 254 | library". The executable is therefore covered by this License. 255 | Section 6 states terms for distribution of such executables. 256 | 257 | When a "work that uses the Library" uses material from a header file 258 | that is part of the Library, the object code for the work may be a 259 | derivative work of the Library even though the source code is not. 260 | Whether this is true is especially significant if the work can be 261 | linked without the Library, or if the work is itself a library. The 262 | threshold for this to be true is not precisely defined by law. 263 | 264 | If such an object file uses only numerical parameters, data 265 | structure layouts and accessors, and small macros and small inline 266 | functions (ten lines or less in length), then the use of the object 267 | file is unrestricted, regardless of whether it is legally a derivative 268 | work. (Executables containing this object code plus portions of the 269 | Library will still fall under Section 6.) 270 | 271 | Otherwise, if the work is a derivative of the Library, you may 272 | distribute the object code for the work under the terms of Section 6. 273 | Any executables containing that work also fall under Section 6, 274 | whether or not they are linked directly with the Library itself. 275 | 276 | 6. As an exception to the Sections above, you may also compile or 277 | link a "work that uses the Library" with the Library to produce a 278 | work containing portions of the Library, and distribute that work 279 | under terms of your choice, provided that the terms permit 280 | modification of the work for the customer's own use and reverse 281 | engineering for debugging such modifications. 282 | 283 | You must give prominent notice with each copy of the work that the 284 | Library is used in it and that the Library and its use are covered by 285 | this License. You must supply a copy of this License. If the work 286 | during execution displays copyright notices, you must include the 287 | copyright notice for the Library among them, as well as a reference 288 | directing the user to the copy of this License. Also, you must do one 289 | of these things: 290 | 291 | a) Accompany the work with the complete corresponding 292 | machine-readable source code for the Library including whatever 293 | changes were used in the work (which must be distributed under 294 | Sections 1 and 2 above); and, if the work is an executable linked 295 | with the Library, with the complete machine-readable "work that 296 | uses the Library", as object code and/or source code, so that the 297 | user can modify the Library and then relink to produce a modified 298 | executable containing the modified Library. (It is understood 299 | that the user who changes the contents of definitions files in the 300 | Library will not necessarily be able to recompile the application 301 | to use the modified definitions.) 302 | 303 | b) Accompany the work with a written offer, valid for at 304 | least three years, to give the same user the materials 305 | specified in Subsection 6a, above, for a charge no more 306 | than the cost of performing this distribution. 307 | 308 | c) If distribution of the work is made by offering access to copy 309 | from a designated place, offer equivalent access to copy the above 310 | specified materials from the same place. 311 | 312 | d) Verify that the user has already received a copy of these 313 | materials or that you have already sent this user a copy. 314 | 315 | For an executable, the required form of the "work that uses the 316 | Library" must include any data and utility programs needed for 317 | reproducing the executable from it. However, as a special exception, 318 | the source code distributed need not include anything that is normally 319 | distributed (in either source or binary form) with the major 320 | components (compiler, kernel, and so on) of the operating system on 321 | which the executable runs, unless that component itself accompanies 322 | the executable. 323 | 324 | It may happen that this requirement contradicts the license 325 | restrictions of other proprietary libraries that do not normally 326 | accompany the operating system. Such a contradiction means you cannot 327 | use both them and the Library together in an executable that you 328 | distribute. 329 | 330 | 7. You may place library facilities that are a work based on the 331 | Library side-by-side in a single library together with other library 332 | facilities not covered by this License, and distribute such a combined 333 | library, provided that the separate distribution of the work based on 334 | the Library and of the other library facilities is otherwise 335 | permitted, and provided that you do these two things: 336 | 337 | a) Accompany the combined library with a copy of the same work 338 | based on the Library, uncombined with any other library 339 | facilities. This must be distributed under the terms of the 340 | Sections above. 341 | 342 | b) Give prominent notice with the combined library of the fact 343 | that part of it is a work based on the Library, and explaining 344 | where to find the accompanying uncombined form of the same work. 345 | 346 | 8. You may not copy, modify, sublicense, link with, or distribute 347 | the Library except as expressly provided under this License. Any 348 | attempt otherwise to copy, modify, sublicense, link with, or 349 | distribute the Library is void, and will automatically terminate your 350 | rights under this License. However, parties who have received copies, 351 | or rights, from you under this License will not have their licenses 352 | terminated so long as such parties remain in full compliance. 353 | 354 | 9. You are not required to accept this License, since you have not 355 | signed it. However, nothing else grants you permission to modify or 356 | distribute the Library or its derivative works. These actions are 357 | prohibited by law if you do not accept this License. Therefore, by 358 | modifying or distributing the Library (or any work based on the 359 | Library), you indicate your acceptance of this License to do so, and 360 | all its terms and conditions for copying, distributing or modifying 361 | the Library or works based on it. 362 | 363 | 10. Each time you redistribute the Library (or any work based on the 364 | Library), the recipient automatically receives a license from the 365 | original licensor to copy, distribute, link with or modify the Library 366 | subject to these terms and conditions. You may not impose any further 367 | restrictions on the recipients' exercise of the rights granted herein. 368 | You are not responsible for enforcing compliance by third parties to 369 | this License. 370 | 371 | 11. If, as a consequence of a court judgment or allegation of patent 372 | infringement or for any other reason (not limited to patent issues), 373 | conditions are imposed on you (whether by court order, agreement or 374 | otherwise) that contradict the conditions of this License, they do not 375 | excuse you from the conditions of this License. If you cannot 376 | distribute so as to satisfy simultaneously your obligations under this 377 | License and any other pertinent obligations, then as a consequence you 378 | may not distribute the Library at all. For example, if a patent 379 | license would not permit royalty-free redistribution of the Library by 380 | all those who receive copies directly or indirectly through you, then 381 | the only way you could satisfy both it and this License would be to 382 | refrain entirely from distribution of the Library. 383 | 384 | If any portion of this section is held invalid or unenforceable under any 385 | particular circumstance, the balance of the section is intended to apply, 386 | and the section as a whole is intended to apply in other circumstances. 387 | 388 | It is not the purpose of this section to induce you to infringe any 389 | patents or other property right claims or to contest validity of any 390 | such claims; this section has the sole purpose of protecting the 391 | integrity of the free software distribution system which is 392 | implemented by public license practices. Many people have made 393 | generous contributions to the wide range of software distributed 394 | through that system in reliance on consistent application of that 395 | system; it is up to the author/donor to decide if he or she is willing 396 | to distribute software through any other system and a licensee cannot 397 | impose that choice. 398 | 399 | This section is intended to make thoroughly clear what is believed to 400 | be a consequence of the rest of this License. 401 | 402 | 12. If the distribution and/or use of the Library is restricted in 403 | certain countries either by patents or by copyrighted interfaces, the 404 | original copyright holder who places the Library under this License may add 405 | an explicit geographical distribution limitation excluding those countries, 406 | so that distribution is permitted only in or among countries not thus 407 | excluded. In such case, this License incorporates the limitation as if 408 | written in the body of this License. 409 | 410 | 13. The Free Software Foundation may publish revised and/or new 411 | versions of the Library General Public License from time to time. 412 | Such new versions will be similar in spirit to the present version, 413 | but may differ in detail to address new problems or concerns. 414 | 415 | Each version is given a distinguishing version number. If the Library 416 | specifies a version number of this License which applies to it and 417 | "any later version", you have the option of following the terms and 418 | conditions either of that version or of any later version published by 419 | the Free Software Foundation. If the Library does not specify a 420 | license version number, you may choose any version ever published by 421 | the Free Software Foundation. 422 | 423 | 14. If you wish to incorporate parts of the Library into other free 424 | programs whose distribution conditions are incompatible with these, 425 | write to the author to ask for permission. For software which is 426 | copyrighted by the Free Software Foundation, write to the Free 427 | Software Foundation; we sometimes make exceptions for this. Our 428 | decision will be guided by the two goals of preserving the free status 429 | of all derivatives of our free software and of promoting the sharing 430 | and reuse of software generally. 431 | 432 | NO WARRANTY 433 | 434 | 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO 435 | WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. 436 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR 437 | OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY 438 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE 439 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 440 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE 441 | LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME 442 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 443 | 444 | 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN 445 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY 446 | AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU 447 | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR 448 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE 449 | LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING 450 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A 451 | FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF 452 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 453 | DAMAGES. 454 | 455 | END OF TERMS AND CONDITIONS 456 | 457 | How to Apply These Terms to Your New Libraries 458 | 459 | If you develop a new library, and you want it to be of the greatest 460 | possible use to the public, we recommend making it free software that 461 | everyone can redistribute and change. You can do so by permitting 462 | redistribution under these terms (or, alternatively, under the terms of the 463 | ordinary General Public License). 464 | 465 | To apply these terms, attach the following notices to the library. It is 466 | safest to attach them to the start of each source file to most effectively 467 | convey the exclusion of warranty; and each file should have at least the 468 | "copyright" line and a pointer to where the full notice is found. 469 | 470 | 471 | Copyright (C) 472 | 473 | This library is free software; you can redistribute it and/or 474 | modify it under the terms of the GNU Library General Public 475 | License as published by the Free Software Foundation; either 476 | version 2 of the License, or (at your option) any later version. 477 | 478 | This library is distributed in the hope that it will be useful, 479 | but WITHOUT ANY WARRANTY; without even the implied warranty of 480 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 481 | Library General Public License for more details. 482 | 483 | You should have received a copy of the GNU Library General Public 484 | License along with this library; if not, write to the Free 485 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 486 | 487 | Also add information on how to contact you by electronic and paper mail. 488 | 489 | You should also get your employer (if you work as a programmer) or your 490 | school, if any, to sign a "copyright disclaimer" for the library, if 491 | necessary. Here is a sample; alter the names: 492 | 493 | Yoyodyne, Inc., hereby disclaims all copyright interest in the 494 | library `Frob' (a library for tweaking knobs) written by James Random Hacker. 495 | 496 | , 1 April 1990 497 | Ty Coon, President of Vice 498 | 499 | That's all there is to it! 500 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | all: 3 | dune build 4 | 5 | test: 6 | dune runtest 7 | 8 | doc: 9 | dune build @doc 10 | 11 | clean: 12 | dune clean 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Integer map implementation using Patricia trees 2 | 3 | Follows "Fast Mergeable Integer Maps" by Chris Okasaki and Andrew Gill 4 | (Workshop on ML, 1998) 5 | 6 | Note: In 2017, a bug was found in the paper above, which is described 7 | in "QuickChecking Patricia Trees" by Jan Midtgaard. This is fixed in 8 | the present OCaml code. 9 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | - rm ptset.ml{i} 2 | - check with latest ocaml compiler and oldest 3 | - opam package 4 | -------------------------------------------------------------------------------- /dune: -------------------------------------------------------------------------------- 1 | (library 2 | (public_name ptmap) 3 | (modules ptmap) 4 | (libraries seq)) 5 | 6 | (test 7 | (name test) 8 | (modules test) 9 | (libraries stdlib-shims ptmap)) 10 | -------------------------------------------------------------------------------- /dune-project: -------------------------------------------------------------------------------- 1 | (lang dune 2.0) 2 | (name ptmap) 3 | (formatting (enabled_for dune)) 4 | -------------------------------------------------------------------------------- /ptmap.ml: -------------------------------------------------------------------------------- 1 | (**************************************************************************) 2 | (* *) 3 | (* Copyright (C) Jean-Christophe Filliatre *) 4 | (* *) 5 | (* This software is free software; you can redistribute it and/or *) 6 | (* modify it under the terms of the GNU Lesser General Public *) 7 | (* License version 2.1, with the special exception on linking *) 8 | (* described in file LICENSE. *) 9 | (* *) 10 | (* This software is distributed in the hope that it will be useful, *) 11 | (* but WITHOUT ANY WARRANTY; without even the implied warranty of *) 12 | (* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *) 13 | (* *) 14 | (**************************************************************************) 15 | 16 | (*s Maps of integers implemented as Patricia trees, following Chris 17 | Okasaki and Andrew Gill's paper {\em Fast Mergeable Integer Maps} 18 | ({\tt\small http://www.cs.columbia.edu/\~{}cdo/papers.html\#ml98maps}). 19 | See the documentation of module [Ptset] which is also based on the 20 | same data-structure. *) 21 | 22 | type key = int 23 | 24 | type 'a t = 25 | | Empty 26 | | Leaf of int * 'a 27 | | Branch of int * int * 'a t * 'a t 28 | 29 | let empty = Empty 30 | 31 | let is_empty t = t = Empty 32 | 33 | let zero_bit k m = (k land m) == 0 34 | 35 | let rec mem k = function 36 | | Empty -> false 37 | | Leaf (j,_) -> k == j 38 | | Branch (_, m, l, r) -> mem k (if zero_bit k m then l else r) 39 | 40 | let rec find k = function 41 | | Empty -> raise Not_found 42 | | Leaf (j,x) -> if k == j then x else raise Not_found 43 | | Branch (_, m, l, r) -> find k (if zero_bit k m then l else r) 44 | 45 | let find_opt k m = try Some (find k m) with Not_found -> None 46 | 47 | (* Note: find_first/last have to look in both subtrees 48 | as these are little-endian Patricia trees *) 49 | let rec find_first_opt f = function 50 | | Empty -> None 51 | | Leaf (j,x) -> if f j then Some (j,x) else None 52 | | Branch (_, _, l, r) -> 53 | match find_first_opt f l, find_first_opt f r with 54 | | Some (lk,lv) , Some (rk,rv) -> 55 | if lk < rk then Some (lk,lv) else Some (rk,rv) 56 | | Some v, None | None, Some v -> Some v 57 | | None, None -> None 58 | 59 | let find_first f = function 60 | | Empty -> raise Not_found 61 | | Leaf (j,x) -> if f j then (j,x) else raise Not_found 62 | | Branch (_, _, l, r) -> 63 | match find_first_opt f l, find_first_opt f r with 64 | | Some (lk,lv) , Some (rk,rv) -> if lk < rk then (lk,lv) else (rk,rv) 65 | | Some v, None | None, Some v -> v 66 | | None, None -> raise Not_found 67 | 68 | let rec find_last_opt f = function 69 | | Empty -> None 70 | | Leaf (j,x) -> if f j then Some (j,x) else None 71 | | Branch (_, _, l, r) -> 72 | match find_last_opt f l, find_last_opt f r with 73 | | Some (lk,lv) , Some (rk,rv) -> 74 | if lk > rk then Some (lk,lv) else Some (rk,rv) 75 | | Some v, None | None, Some v -> Some v 76 | | None, None -> None 77 | 78 | let find_last f = function 79 | | Empty -> raise Not_found 80 | | Leaf (j,x) -> if f j then (j,x) else raise Not_found 81 | | Branch (_, _, l, r) -> 82 | match find_last_opt f l, find_last_opt f r with 83 | | Some (lk,lv) , Some (rk,rv) -> if lk > rk then (lk,lv) else (rk,rv) 84 | | Some v, None | None, Some v -> v 85 | | None, None -> raise Not_found 86 | 87 | let lowest_bit x = x land (-x) 88 | 89 | let branching_bit p0 p1 = lowest_bit (p0 lxor p1) 90 | 91 | let mask p m = p land (m-1) 92 | 93 | let join (p0,t0,p1,t1) = 94 | let m = branching_bit p0 p1 in 95 | if zero_bit p0 m then 96 | Branch (mask p0 m, m, t0, t1) 97 | else 98 | Branch (mask p0 m, m, t1, t0) 99 | 100 | let match_prefix k p m = (mask k m) == p 101 | 102 | let add k x t = 103 | let rec ins = function 104 | | Empty -> Leaf (k,x) 105 | | Leaf (j,_) as t -> 106 | if j == k then Leaf (k,x) else join (k, Leaf (k,x), j, t) 107 | | Branch (p,m,t0,t1) as t -> 108 | if match_prefix k p m then 109 | if zero_bit k m then 110 | Branch (p, m, ins t0, t1) 111 | else 112 | Branch (p, m, t0, ins t1) 113 | else 114 | join (k, Leaf (k,x), p, t) 115 | in 116 | ins t 117 | 118 | let singleton k v = 119 | add k v empty 120 | 121 | let branch = function 122 | | (_,_,Empty,t) -> t 123 | | (_,_,t,Empty) -> t 124 | | (p,m,t0,t1) -> Branch (p,m,t0,t1) 125 | 126 | let remove k t = 127 | let rec rmv = function 128 | | Empty -> Empty 129 | | Leaf (j,_) as t -> if k == j then Empty else t 130 | | Branch (p,m,t0,t1) as t -> 131 | if match_prefix k p m then 132 | if zero_bit k m then 133 | branch (p, m, rmv t0, t1) 134 | else 135 | branch (p, m, t0, rmv t1) 136 | else 137 | t 138 | in 139 | rmv t 140 | 141 | let rec cardinal = function 142 | | Empty -> 0 143 | | Leaf _ -> 1 144 | | Branch (_,_,t0,t1) -> cardinal t0 + cardinal t1 145 | 146 | let rec iter f = function 147 | | Empty -> () 148 | | Leaf (k,x) -> f k x 149 | | Branch (_,_,t0,t1) -> iter f t0; iter f t1 150 | 151 | let rec map f = function 152 | | Empty -> Empty 153 | | Leaf (k,x) -> Leaf (k, f x) 154 | | Branch (p,m,t0,t1) -> Branch (p, m, map f t0, map f t1) 155 | 156 | let rec mapi f = function 157 | | Empty -> Empty 158 | | Leaf (k,x) -> Leaf (k, f k x) 159 | | Branch (p,m,t0,t1) -> Branch (p, m, mapi f t0, mapi f t1) 160 | 161 | let rec fold f s accu = match s with 162 | | Empty -> accu 163 | | Leaf (k,x) -> f k x accu 164 | | Branch (_,_,t0,t1) -> fold f t0 (fold f t1 accu) 165 | 166 | let rec for_all p = function 167 | | Empty -> true 168 | | Leaf (k, v) -> p k v 169 | | Branch (_,_,t0,t1) -> for_all p t0 && for_all p t1 170 | 171 | let rec exists p = function 172 | | Empty -> false 173 | | Leaf (k, v) -> p k v 174 | | Branch (_,_,t0,t1) -> exists p t0 || exists p t1 175 | 176 | let rec filter pr = function 177 | | Empty -> Empty 178 | | Leaf (k, v) as t -> if pr k v then t else Empty 179 | | Branch (p,m,t0,t1) -> branch (p, m, filter pr t0, filter pr t1) 180 | 181 | let rec filter_map pr = function 182 | | Empty -> Empty 183 | | Leaf (k, v) -> (match pr k v with Some v' -> Leaf (k, v') | None -> Empty) 184 | | Branch (p,m,t0,t1) -> branch (p, m, filter_map pr t0, filter_map pr t1) 185 | 186 | let partition p s = 187 | let rec part (t,f as acc) = function 188 | | Empty -> acc 189 | | Leaf (k, v) -> if p k v then (add k v t, f) else (t, add k v f) 190 | | Branch (_,_,t0,t1) -> part (part acc t0) t1 191 | in 192 | part (Empty, Empty) s 193 | 194 | let rec choose = function 195 | | Empty -> raise Not_found 196 | | Leaf (k, v) -> (k, v) 197 | | Branch (_, _, t0, _) -> choose t0 (* we know that [t0] is non-empty *) 198 | 199 | let rec choose_opt = function 200 | | Empty -> None 201 | | Leaf (k, v) -> Some (k, v) 202 | | Branch (_, _, t0, _) -> choose_opt t0 (* we know that [t0] is non-empty *) 203 | 204 | let split x m = 205 | let coll k v (l, b, r) = 206 | if k < x then add k v l, b, r 207 | else if k > x then l, b, add k v r 208 | else l, Some v, r 209 | in 210 | fold coll m (empty, None, empty) 211 | 212 | let rec min_binding = function 213 | | Empty -> raise Not_found 214 | | Leaf (k, v) -> (k, v) 215 | | Branch (_,_,s,t) -> 216 | let (ks, _) as bs = min_binding s in 217 | let (kt, _) as bt = min_binding t in 218 | if ks < kt then bs else bt 219 | 220 | let rec min_binding_opt = function 221 | | Empty -> None 222 | | Leaf (k, v) -> Some (k, v) 223 | | Branch (_,_,s,t) -> 224 | match (min_binding_opt s, min_binding_opt t) with 225 | | None, None -> None 226 | | None, bt -> bt 227 | | bs, None -> bs 228 | | (Some (ks, _) as bs), (Some (kt, _) as bt) -> 229 | if ks < kt then bs else bt 230 | 231 | let rec max_binding = function 232 | | Empty -> raise Not_found 233 | | Leaf (k, v) -> (k, v) 234 | | Branch (_,_,s,t) -> 235 | let (ks, _) as bs = max_binding s in 236 | let (kt, _) as bt = max_binding t in 237 | if ks > kt then bs else bt 238 | 239 | let rec max_binding_opt = function 240 | | Empty -> None 241 | | Leaf (k, v) -> Some (k, v) 242 | | Branch (_,_,s,t) -> 243 | match max_binding_opt s, max_binding_opt t with 244 | | None, None -> None 245 | | None, bt -> bt 246 | | bs, None -> bs 247 | | (Some (ks, _) as bs), (Some (kt, _) as bt) -> 248 | if ks > kt then bs else bt 249 | 250 | let bindings m = 251 | fold (fun k v acc -> (k, v) :: acc) m [] 252 | 253 | (* we order constructors as Empty < Leaf < Branch *) 254 | let compare cmp t1 t2 = 255 | let rec compare_aux t1 t2 = match t1,t2 with 256 | | Empty, Empty -> 0 257 | | Empty, _ -> -1 258 | | _, Empty -> 1 259 | | Leaf (k1,x1), Leaf (k2,x2) -> 260 | let c = compare k1 k2 in 261 | if c <> 0 then c else cmp x1 x2 262 | | Leaf _, Branch _ -> -1 263 | | Branch _, Leaf _ -> 1 264 | | Branch (p1,m1,l1,r1), Branch (p2,m2,l2,r2) -> 265 | let c = compare p1 p2 in 266 | if c <> 0 then c else 267 | let c = compare m1 m2 in 268 | if c <> 0 then c else 269 | let c = compare_aux l1 l2 in 270 | if c <> 0 then c else 271 | compare_aux r1 r2 272 | in 273 | compare_aux t1 t2 274 | 275 | let equal eq t1 t2 = 276 | let rec equal_aux t1 t2 = match t1, t2 with 277 | | Empty, Empty -> true 278 | | Leaf (k1,x1), Leaf (k2,x2) -> k1 = k2 && eq x1 x2 279 | | Branch (p1,m1,l1,r1), Branch (p2,m2,l2,r2) -> 280 | p1 = p2 && m1 = m2 && equal_aux l1 l2 && equal_aux r1 r2 281 | | _ -> false 282 | in 283 | equal_aux t1 t2 284 | 285 | let merge f m1 m2 = 286 | let add m k = function None -> m | Some v -> add k v m in 287 | (* first consider all bindings in m1 *) 288 | let m = fold 289 | (fun k1 v1 m -> add m k1 (f k1 (Some v1) (find_opt k1 m2))) m1 empty in 290 | (* then bindings in m2 that are not in m1 *) 291 | fold (fun k2 v2 m -> if mem k2 m1 then m else add m k2 (f k2 None (Some v2))) 292 | m2 m 293 | 294 | let update x f m = 295 | match f (find_opt x m) with 296 | | None -> remove x m 297 | | Some z -> add x z m 298 | 299 | let unsigned_lt n m = n >= 0 && (m < 0 || n < m) 300 | 301 | let rec union f = function 302 | | Empty, t -> t 303 | | t, Empty -> t 304 | | Leaf (k,v1), t -> 305 | update k (function None -> Some v1 | Some v2 -> f k v1 v2) t 306 | | t, Leaf (k,v2) -> 307 | update k (function None -> Some v2 | Some v1 -> f k v1 v2) t 308 | | (Branch (p,m,s0,s1) as s), (Branch (q,n,t0,t1) as t) -> 309 | if m == n && match_prefix q p m then 310 | (* The trees have the same prefix. Merge the subtrees. *) 311 | branch (p, m, union f (s0,t0), union f (s1,t1)) 312 | else if unsigned_lt m n && match_prefix q p m then 313 | (* [q] contains [p]. Merge [t] with a subtree of [s]. *) 314 | if zero_bit q m then 315 | branch (p, m, union f (s0,t), s1) 316 | else 317 | branch (p, m, s0, union f (s1,t)) 318 | else if unsigned_lt n m && match_prefix p q n then 319 | (* [p] contains [q]. Merge [s] with a subtree of [t]. *) 320 | if zero_bit p n then 321 | branch (q, n, union f (s,t0), t1) 322 | else 323 | branch (q, n, t0, union f (s,t1)) 324 | else 325 | (* The prefixes disagree. *) 326 | join (p, s, q, t) 327 | 328 | let union f s t = union f (s,t) 329 | 330 | let to_seq m = 331 | let rec prepend_seq m s = match m with 332 | | Empty -> s 333 | | Leaf (k, v) -> fun () -> Seq.Cons((k,v), s) 334 | | Branch (_, _, l, r) -> prepend_seq l (prepend_seq r s) 335 | in 336 | prepend_seq m Seq.empty 337 | 338 | let to_seq_from k m = 339 | let rec prepend_seq m s = match m with 340 | | Empty -> s 341 | | Leaf (key, v) -> if key >= k then fun () -> Seq.Cons((key,v), s) else s 342 | | Branch (_, _, l, r) -> prepend_seq l (prepend_seq r s) 343 | in 344 | prepend_seq m Seq.empty 345 | 346 | let add_seq s m = 347 | Seq.fold_left (fun m (k, v) -> add k v m) m s 348 | 349 | let of_seq s = 350 | Seq.fold_left (fun m (k, v) -> add k v m) empty s 351 | -------------------------------------------------------------------------------- /ptmap.mli: -------------------------------------------------------------------------------- 1 | (**************************************************************************) 2 | (* *) 3 | (* Copyright (C) Jean-Christophe Filliatre *) 4 | (* *) 5 | (* This software is free software; you can redistribute it and/or *) 6 | (* modify it under the terms of the GNU Lesser General Public *) 7 | (* License version 2.1, with the special exception on linking *) 8 | (* described in file LICENSE. *) 9 | (* *) 10 | (* This software is distributed in the hope that it will be useful, *) 11 | (* but WITHOUT ANY WARRANTY; without even the implied warranty of *) 12 | (* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *) 13 | (* *) 14 | (**************************************************************************) 15 | 16 | (** Maps over integers implemented as Patricia trees. 17 | 18 | The following signature is a subset of [Map.S with type key = int], 19 | with the same specifications (not repeated here) unless specified 20 | otherwise. 21 | 22 | These are little-endian Patricia trees, so there is no efficient 23 | ordering of keys within the structure. Consequently, 24 | - [min/max_binding], [find_first/last] are rather inefficient (linear) 25 | - [iter], [fold] *do not* iterate in the key order 26 | - [bindings] is *not sorted* by keys 27 | *) 28 | 29 | type key = int 30 | 31 | type (+'a) t 32 | 33 | val empty: 'a t 34 | 35 | val is_empty: 'a t -> bool 36 | 37 | val mem: key -> 'a t -> bool 38 | 39 | val add: key -> 'a -> 'a t -> 'a t 40 | 41 | val update: key -> ('a option -> 'a option) -> 'a t -> 'a t 42 | 43 | val singleton: key -> 'a -> 'a t 44 | 45 | val remove: key -> 'a t -> 'a t 46 | 47 | val merge: 48 | (key -> 'a option -> 'b option -> 'c option) -> 'a t -> 'b t -> 'c t 49 | 50 | val union: (key -> 'a -> 'a -> 'a option) -> 'a t -> 'a t -> 'a t 51 | 52 | val compare: ('a -> 'a -> int) -> 'a t -> 'a t -> int 53 | 54 | val equal: ('a -> 'a -> bool) -> 'a t -> 'a t -> bool 55 | 56 | val iter: (key -> 'a -> unit) -> 'a t -> unit 57 | 58 | val fold: (key -> 'a -> 'b -> 'b) -> 'a t -> 'b -> 'b 59 | 60 | val for_all: (key -> 'a -> bool) -> 'a t -> bool 61 | 62 | val exists: (key -> 'a -> bool) -> 'a t -> bool 63 | 64 | val filter: (key -> 'a -> bool) -> 'a t -> 'a t 65 | 66 | val filter_map: (key -> 'a -> 'b option) -> 'a t -> 'b t 67 | 68 | val partition: (key -> 'a -> bool) -> 'a t -> 'a t * 'a t 69 | 70 | val cardinal: 'a t -> int 71 | 72 | val bindings: 'a t -> (key * 'a) list 73 | 74 | val min_binding: 'a t -> (key * 'a) 75 | 76 | val min_binding_opt: 'a t -> (key * 'a) option 77 | 78 | val max_binding: 'a t -> (key * 'a) 79 | 80 | val max_binding_opt: 'a t -> (key * 'a) option 81 | 82 | val choose: 'a t -> (key * 'a) 83 | 84 | val choose_opt: 'a t -> (key * 'a) option 85 | 86 | val split: key -> 'a t -> 'a t * 'a option * 'a t 87 | 88 | val find: key -> 'a t -> 'a 89 | 90 | val find_opt: key -> 'a t -> 'a option 91 | 92 | val find_first: (key -> bool) -> 'a t -> key * 'a 93 | 94 | val find_first_opt: (key -> bool) -> 'a t -> (key * 'a) option 95 | 96 | val find_last: (key -> bool) -> 'a t -> key * 'a 97 | 98 | val find_last_opt: (key -> bool) -> 'a t -> (key * 'a) option 99 | 100 | val map: ('a -> 'b) -> 'a t -> 'b t 101 | 102 | val mapi: (key -> 'a -> 'b) -> 'a t -> 'b t 103 | 104 | val to_seq : 'a t -> (key * 'a) Seq.t 105 | 106 | val to_seq_from : key -> 'a t -> (key * 'a) Seq.t 107 | 108 | val add_seq : (key * 'a) Seq.t -> 'a t -> 'a t 109 | 110 | val of_seq : (key * 'a) Seq.t -> 'a t 111 | -------------------------------------------------------------------------------- /ptmap.opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | maintainer: "Jean-Christophe.Filliatre@lri.fr" 3 | authors: "Jean-Christophe Filliâtre" 4 | synopsis: "Maps of integers implemented as Patricia trees" 5 | description: "An implementation inspired by Okasaki & Gill's paper 6 | 'Fast Mergeable Integer Maps'" 7 | license: "LGPL-2.1" 8 | homepage: "https://github.com/backtracking/ptmap" 9 | doc: "https://backtracking.github.io/ptmap" 10 | bug-reports: "https://github.com/backtracking/ptmap/issues" 11 | depends: [ 12 | "ocaml" 13 | "stdlib-shims" 14 | "seq" 15 | "dune" {>= "2.0.0"} 16 | ] 17 | build: [ 18 | ["dune" "subst"] {pinned} 19 | ["dune" "build" "-p" name "-j" jobs] 20 | ["dune" "runtest" "-p" name] {with-test} 21 | ] 22 | dev-repo: "git+https://github.com/backtracking/ptmap.git" 23 | -------------------------------------------------------------------------------- /test.ml: -------------------------------------------------------------------------------- 1 | 2 | open Ptmap 3 | 4 | let of_list l = 5 | List.fold_left (fun acc (k, v) -> add k v acc) empty l 6 | 7 | let list_to_map lst = 8 | let rec loop l map = match l with 9 | | [] -> map 10 | | item :: ls -> loop ls (add item true map) 11 | in 12 | loop lst empty 13 | 14 | (* basic add/mem test *) 15 | let () = 16 | let max_int = 1 lsl 30 - 1 in 17 | let seed = Random.int max_int in 18 | Random.init seed; 19 | let s = 20 | let rec loop s i = 21 | if i = 1000 then s else loop (add (Random.int max_int) true s) (succ i) 22 | in 23 | loop empty 0 24 | in 25 | Random.init seed; 26 | for _i = 0 to 999 do assert (mem (Random.int max_int) s) done 27 | 28 | (* the bug from "QuickChecking Patricia Trees" is fixed *) 29 | let () = 30 | let m1 = add min_int true (add 0 true empty) in 31 | let m2 = add min_int true (add 1 true empty) in 32 | let m = union (fun _ _ _ -> Some true) m1 m2 in 33 | assert (cardinal m = 3) 34 | 35 | let interval lo hi = 36 | let rec build k m = if k > hi then m else build (k+1) (add k true m) in 37 | build lo empty 38 | 39 | (* cardinal *) 40 | let () = 41 | assert (cardinal empty = 0); 42 | assert (cardinal (of_list [(-1,false); (5,true); (0,false)]) = 3); 43 | assert (cardinal (interval (-10) 10) = 21) 44 | 45 | (* choose *) 46 | let () = 47 | assert (try let _ = choose empty in false with Not_found -> true); 48 | assert (choose (add 1 true empty) = (1, true)) 49 | 50 | (* min/max_binding *) 51 | let () = 52 | assert (try let _ = min_binding empty in false with Not_found -> true); 53 | assert (min_binding (of_list [(-1,false); (5,true); (0,false)]) = (-1,false)); 54 | assert (try let _ = max_binding empty in false with Not_found -> true); 55 | assert (max_binding (of_list [(-1,false); (5,true); (0,false)]) = (5,true)) 56 | 57 | (* bindings *) 58 | let () = 59 | assert (bindings empty = []); 60 | let l = bindings (of_list [(-1,false); (5,true); (0,false)]) in 61 | assert (List.sort Stdlib.compare l = [(-1,false); (0,false); (5,true)]); 62 | let itv = bindings (interval (-10) 10) in 63 | assert (List.length itv = 21) 64 | 65 | (* merge *) 66 | let () = 67 | let l1 = [(-1,-1); (0,0); (5,4)] in 68 | let l2 = [(5,5)] in 69 | let l3 = [(-1,-1); (0,0); (5,5)] in 70 | assert (equal (=) (of_list l3) 71 | (merge (fun _k x y -> max x y) (of_list l1) (of_list l2))) 72 | 73 | (* union *) 74 | let () = 75 | let l1 = [(-1,false); (0,false); (5,true)] in 76 | let l2 = [(0,true); (6,true)] in 77 | let l3 = [(-1,false); (5,true); (6,true)] in 78 | let m1 = of_list l1 in 79 | let m2 = of_list l2 in 80 | let m3 = of_list l3 in 81 | assert (equal (=) m3 (union (fun _ _ _ -> None) m1 m2)) 82 | 83 | (* find_first *) 84 | let () = 85 | let k,_ = find_first (fun i -> i > 3) (list_to_map [3; 1; 2; 4; 6; 5]) in 86 | assert (k = 4) 87 | 88 | (* find_first_opt *) 89 | let () = 90 | assert (find_first_opt (fun _ -> true) empty = None); 91 | match find_first_opt (fun i -> i > 3) (list_to_map [3; 1; 2; 4; 6; 5]) with 92 | | Some (4, _) -> assert true 93 | | _ -> assert false 94 | 95 | (* find_last *) 96 | let () = 97 | let k,_ = find_last (fun i -> i < 4) (list_to_map [3; 1; 2; 4; 6; 5]) in 98 | assert (k = 3) 99 | 100 | (* find_last_opt *) 101 | let () = 102 | assert (find_last_opt (fun _ -> true) empty = None); 103 | match find_last_opt (fun i -> i < 4) (list_to_map [3; 1; 2; 4; 6; 5]) with 104 | | Some (3, _) -> assert true 105 | | _ -> assert false 106 | 107 | (* update_remove *) 108 | let () = 109 | let m = update 2 (fun _ -> None) (list_to_map [3; 1; 2; 4; 6; 5]) in 110 | match find_opt 2 m with 111 | | None -> assert true 112 | | _ -> assert false 113 | 114 | (* update_add *) 115 | let () = 116 | let m = update 2 (fun _ -> Some true) (list_to_map [3; 1; 4; 6; 5]) in 117 | match find_opt 2 m with 118 | | Some true -> assert true 119 | | _ -> assert true 120 | 121 | (* update_update *) 122 | let () = 123 | let m = update 2 (fun _ -> Some false) (list_to_map [3; 1; 2; 4; 6; 5]) in 124 | match find_opt 2 m with 125 | | Some false -> assert true 126 | | _ -> assert true 127 | 128 | let list_of_seq s = Seq.fold_left (fun l b -> b :: l) [] s 129 | let list_to_seq l = 130 | let rec aux l () = match l with 131 | | [] -> Seq.Nil | x :: tail -> Seq.Cons (x, aux tail) in 132 | aux l 133 | 134 | (* to_seq *) 135 | let () = 136 | let o = [3; 1; 2; 4; 6; 5] in 137 | let l = list_of_seq (to_seq (list_to_map o)) in 138 | assert (List.length l = List.length o); 139 | assert (List.for_all (fun (k,_) -> List.exists ((=) k) o) l) 140 | 141 | (* to_seq_from *) 142 | let () = 143 | let o = [3; 1; 2; 4; 6; 5] in 144 | let r = [3; 4; 5; 6] in 145 | let l = list_of_seq (to_seq_from 3 (list_to_map o)) in 146 | assert (List.length l = List.length r); 147 | assert (List.for_all (fun (k,_) -> List.exists ((=) k) r) l) 148 | 149 | (* of_seq *) 150 | let () = 151 | let o = [3; 1; 2; 4; 6; 5] in 152 | let m = of_seq (list_to_seq (List.map (fun v -> (v, true)) o)) in 153 | assert (cardinal m = List.length o); 154 | assert (for_all (fun k _ -> List.exists ((=) k) o) m) 155 | 156 | (* add_seq *) 157 | let () = 158 | let o = [3; 1; 6; 5] in 159 | let a = [2; 4] in 160 | let r = [3; 1; 2; 4; 6; 5] in 161 | let m = add_seq (list_to_seq (List.map (fun v -> (v, true)) a)) (list_to_map o) in 162 | assert (cardinal m = List.length r); 163 | assert (for_all (fun k _ -> List.exists ((=) k) r) m) 164 | --------------------------------------------------------------------------------