{"id":13726289,"url":"https://github.com/c-cube/ocaml-containers","last_synced_at":"2026-02-15T03:07:14.171Z","repository":{"id":2222956,"uuid":"8457448","full_name":"c-cube/ocaml-containers","owner":"c-cube","description":"A lightweight, modular standard library extension, string library, and interfaces to various libraries (unix, threads, etc.) BSD license.","archived":false,"fork":false,"pushed_at":"2026-02-11T03:37:43.000Z","size":22894,"stargazers_count":516,"open_issues_count":25,"forks_count":89,"subscribers_count":16,"default_branch":"main","last_synced_at":"2026-02-11T06:54:37.735Z","etag":null,"topics":["data-structure","lightweight","modular","ocaml","permissive-license","portable","stdlib"],"latest_commit_sha":null,"homepage":"https://c-cube.github.io/ocaml-containers/","language":"OCaml","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-2-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/c-cube.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2013-02-27T14:17:32.000Z","updated_at":"2026-02-11T03:37:46.000Z","dependencies_parsed_at":"2025-12-08T19:10:17.464Z","dependency_job_id":null,"html_url":"https://github.com/c-cube/ocaml-containers","commit_stats":{"total_commits":2714,"total_committers":76,"mean_commits":35.71052631578947,"dds":0.1606484893146647,"last_synced_commit":"99bfa200afb6a28edae55ce4158c002e3a16e24f"},"previous_names":[],"tags_count":84,"template":false,"template_full_name":null,"purl":"pkg:github/c-cube/ocaml-containers","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/c-cube%2Focaml-containers","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/c-cube%2Focaml-containers/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/c-cube%2Focaml-containers/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/c-cube%2Focaml-containers/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/c-cube","download_url":"https://codeload.github.com/c-cube/ocaml-containers/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/c-cube%2Focaml-containers/sbom","scorecard":{"id":260715,"data":{"date":"2025-08-11","repo":{"name":"github.com/c-cube/ocaml-containers","commit":"3b49ad2a4e8cfe366d0588e1940d626f0e1b8a2d"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.7,"checks":[{"name":"Code-Review","score":2,"reason":"Found 4/15 approved changesets -- score normalized to 2","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":5,"reason":"6 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 5","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/gh-pages.yml:1","Warn: no topLevel permission defined: .github/workflows/main.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/gh-pages.yml:13: update your workflow using https://app.stepsecurity.io/secureworkflow/c-cube/ocaml-containers/gh-pages.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/gh-pages.yml:16: update your workflow using https://app.stepsecurity.io/secureworkflow/c-cube/ocaml-containers/gh-pages.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/gh-pages.yml:28: update your workflow using https://app.stepsecurity.io/secureworkflow/c-cube/ocaml-containers/gh-pages.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/main.yml:27: update your workflow using https://app.stepsecurity.io/secureworkflow/c-cube/ocaml-containers/main.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/main.yml:29: update your workflow using https://app.stepsecurity.io/secureworkflow/c-cube/ocaml-containers/main.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/main.yml:53: update your workflow using https://app.stepsecurity.io/secureworkflow/c-cube/ocaml-containers/main.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/main.yml:55: update your workflow using https://app.stepsecurity.io/secureworkflow/c-cube/ocaml-containers/main.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/main.yml:74: update your workflow using https://app.stepsecurity.io/secureworkflow/c-cube/ocaml-containers/main.yml/main?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/main.yml:76: update your workflow using https://app.stepsecurity.io/secureworkflow/c-cube/ocaml-containers/main.yml/main?enable=pin","Info:   0 out of   4 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   5 third-party GitHubAction dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: BSD 2-Clause \"Simplified\" License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'main'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Signed-Releases","score":0,"reason":"Project has not signed or included provenance with any releases.","details":["Warn: release artifact v3.16 not signed: https://api.github.com/repos/c-cube/ocaml-containers/releases/221255526","Warn: release artifact v3.15 not signed: https://api.github.com/repos/c-cube/ocaml-containers/releases/186032506","Warn: release artifact v3.14 not signed: https://api.github.com/repos/c-cube/ocaml-containers/releases/174327622","Warn: release artifact v3.13.1 not signed: https://api.github.com/repos/c-cube/ocaml-containers/releases/134682143","Warn: release artifact v3.13 not signed: https://api.github.com/repos/c-cube/ocaml-containers/releases/132746214","Warn: release artifact v3.16 does not have provenance: https://api.github.com/repos/c-cube/ocaml-containers/releases/221255526","Warn: release artifact v3.15 does not have provenance: https://api.github.com/repos/c-cube/ocaml-containers/releases/186032506","Warn: release artifact v3.14 does not have provenance: https://api.github.com/repos/c-cube/ocaml-containers/releases/174327622","Warn: release artifact v3.13.1 does not have provenance: https://api.github.com/repos/c-cube/ocaml-containers/releases/134682143","Warn: release artifact v3.13 does not have provenance: https://api.github.com/repos/c-cube/ocaml-containers/releases/132746214"],"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 19 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-17T10:46:28.851Z","repository_id":2222956,"created_at":"2025-08-17T10:46:28.851Z","updated_at":"2025-08-17T10:46:28.851Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29466925,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-15T01:01:38.065Z","status":"online","status_checked_at":"2026-02-15T02:00:07.449Z","response_time":118,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["data-structure","lightweight","modular","ocaml","permissive-license","portable","stdlib"],"created_at":"2024-08-03T01:02:58.187Z","updated_at":"2026-02-15T03:07:14.143Z","avatar_url":"https://github.com/c-cube.png","language":"OCaml","readme":"# OCaml-containers 📦 [![Build and test](https://github.com/c-cube/ocaml-containers/actions/workflows/main.yml/badge.svg)](https://github.com/c-cube/ocaml-containers/actions/workflows/main.yml)\n\nA modular, clean and powerful extension of the OCaml standard library.\n\n[(Jump to the current API documentation)](https://c-cube.github.io/ocaml-containers/)\n\nContainers is an extension of OCaml's standard library (under BSD license)\nfocused on data structures, combinators and iterators, without dependencies on\nunix, str or num. Every module is independent and is prefixed with 'CC' in the\nglobal namespace. Some modules extend the stdlib (e.g. `CCList` provides safe\n`map`/`fold_right`/`append`, and additional functions on lists).\nAlternatively, `open Containers` will bring enhanced versions of the standard\nmodules into scope.\n\n## Quick Summary\n\nContainers is:\n\n- A usable, reasonably well-designed library that extends OCaml's standard\n  library (in 'src/core/', packaged under `containers` in ocamlfind. Modules\n  are totally independent and are prefixed with `CC` (for \"containers-core\"\n  or \"companion-cube\" because I'm a megalomaniac). This part should be\n  usable and should work. For instance, `CCList` contains functions and\n  lists including safe versions of `map` and `append`. It also\n  provides a drop-in replacement to the standard library, in the module\n  `Containers` (intended to be opened, replaces some stdlib modules\n  with extended ones), and a small S-expression printer and parser\n  that can be functorized over the representation of values.\n- Some sub-libraries with a specific focus each:\n  * Utilities around the `unix` library in `containers.unix` (mainly to spawn\n    sub-processes easily and deal with resources safely)\n  * A bencode codec in `containers.bencode`. This is a tiny json-like\n    serialization format that is extremely simple. It comes from bittorrent files.\n  * A [CBOR](https://cbor.io) codec in `containers.cbor`. This is a\n    compact binary serialization format.\n  * The [Strongly Connected Component](https://en.wikipedia.org/wiki/Strongly_connected_component)\n    algorithm, functorized, in `containers.scc`\n- A separate library `containers-data` with additional\n  data structures that don't have an equivalent in the standard library,\n  typically not as thoroughly maintained. This is now in its own package\n  since 3.0.\n\nSome of the modules have been moved to their own repository (e.g. `sequence` (now `iter`),\n`gen`, `qcheck`) and are on opam for great fun and profit.\n\nContainers-thread has been removed in favor of [Moonpool](https://github.com/c-cube/moonpool/).\n\n## Migration Guide\n\n### To 3.0\n\nThe [changelog's breaking section](CHANGELOG.md) contains a list of the breaking\nchanges in this release.\n\n1. The biggest change is that some sub-libraries have been either turned into\n  their own packages (`containers-data`),\n  deleted (`containers.iter`),or merged elsewhere (`containers.sexp`).\n  This means that if use these libraries you will have to edit your\n  `dune`/`_oasis`/`opam` files.\n\n  - if you use `containers.sexp` (i.e. the `CCSexp` module), it now lives in\n    `containers` itself.\n  - if you used anything in `containers.data`, you need to depend on the\n    `containers-data` package now.\n\n2. Another large change is the removal (at last!) of functions deprecated\n  in 2.8, related to the spread of `Seq.t` as the standard iterator type.\n  Functions like `CCVector.of_seq` now operate on this standard `Seq.t` type,\n  and old-time iteration based on [iter](https://github.com/c-cube/iter)\n  is now named `of_iter`, `to_iter`, etc.\n\n  Here you need to change your code, possibly using search and replace.\n  Thankfully, the typechecker should guide you.\n\n3. `Array_slice` and `String.Sub` have been removed to simplify the\n  code and `String` more lightweight. There is no replacement at the moment.\n  Please tell us if you need this to be turned into a sub-library.\n\n4. Renaming of some functions into more explicit/clear names.\n  Examples:\n\n  * `CCVector.shrink` is now `CCVector.truncate`\n  * `CCVector.remove` is now `CCVector.remove_unordered`, to be\n    contrasted with the new `CCVector.remove_and_shift`.\n  * `CCPair.map_fst` and `map_snd` now transform a tuple into another tuple\n    by modify the first (resp. second) element.\n\n5. All the collection pretty-printers now take their separator/start/stop\n  optional arguments as `unit printer` (i.e. `Format.formatter -\u003e unit -\u003e unit`\n  functions) rather than strings. This gives the caller better control\n  over the formatting of lists, arrays, queues, tables, etc.\n\n6. Removal of many deprecated functions.\n\n\n### To 2.0\n\n- The type system should detect issues related to `print` renamed into `pp` easily.\n  If you are lucky, a call to `sed -i 's/print/pp/g'` on the concerned files\n  might help rename all the calls\n  properly.\n\n- many optional arguments have become mandatory, because their default value\n  would be a polymorphic \"magic\" operator such as `(=)` or `(\u003e=)`.\n  Now these have to be specified explicitly, but during the transition\n  you can use `Stdlib.(=)` and `Stdlib.(\u003e=)` as explicit arguments.\n\n- if your code contains `open Containers`, the biggest hurdle you face\n  might be that operators have become monomorphic by default.\n  We believe this is a useful change that prevents many subtle bugs.\n  However, during migration and until you use proper combinators for\n  equality (`CCEqual`), comparison (`CCOrd`), and hashing (`CCHash`),\n  you might want to add `open Stdlib` just after the `open Containers`.\n  See [the section on monomorphic operators](#monomorphic-operators-why-and-how) for more details.\n\n## Monomorphic operators: why, and how?\n\n### Why shadow polymorphic operators by default?\n\nTo quote @bluddy in [#196](https://github.com/c-cube/ocaml-containers/issues/196):\n\nThe main problem with polymorphic comparison is that many data structures will\ngive one result for structural comparison, and a different result for semantic\ncomparison. The classic example is comparing maps. If you have a list of maps\nand try to use comparison to sort them, you'll get the wrong result: multiple\nmap structures can represent the same semantic mapping from key to value, and\ncomparing them in terms of structure is simply wrong. A far more pernicious bug\noccurs with hashtables. Identical hashtables will seem to be identical for a\nwhile, as before they've had a key clash, the outer array is likely to be the\nsame. Once you get a key clash though, you start getting lists inside the\narrays (or maps inside the arrays if you try to make a smarter hashtable) and\nthat will cause comparison errors ie. identical hashtables will be seen as\ndifferent or vice versa.\n\nEvery time you use a polymorphic comparison where you're using a data type\nwhere structural comparison != semantic comparison, it's a bug. And every time\nyou use polymorphic comparison where the type of data being compared may vary\n(e.g. it's an int now, but it may be a map later), you're planting a bug for\nthe future.\n\nSee also:\n\n- https://blog.janestreet.com/the-perils-of-polymorphic-compare/\n- https://blog.janestreet.com/building-a-better-compare/\n\n### Sometimes polymorphic operators still make sense!\n\nIf you just want to use polymorphic operators, it's fine! You can access them\neasily by using `Stdlib.(=)`, `Stdlib.max`, etc.\n\nWhen migrating a module, you can add `open Stdlib` on top of it to restore\nthe default behavior. It is, however, recommended to export an `equal` function\n(and `compare`, and `hash`) for all the public types, even if their internal\ndefinition is just the corresponding polymorphic operator.\nThis way, other modules can refer to `Foo.equal` and will not have to be\nupdated the day `Foo.equal` is no longer just polymorphic equality.\nAnother bonus is that `Hashtbl.Make(Foo)` or `Map.Make(Foo)` will just work™.\n\n### Further discussions\n\nSee issues\n[#196](https://github.com/c-cube/ocaml-containers/issues/196),\n[#197](https://github.com/c-cube/ocaml-containers/issues/197)\n\n## Debugging with `ocamldebug`\n\nTo print values with types defined in `containers` in the bytecode debugger,\nyou first have to load the appropriate bytecode archives. After starting a\nsession, e.g. `ocamldebug your_program.bc`,\n\n```ocaml non-deterministic=command\n# #load_printer containers_monomorphic.cma;;\n# #load_printer containers.cma;;\n```\n\nFor these archives to be found, you may have to `run` the program first. Now\nprinting functions that have the appropriate type `Format.formatter -\u003e 'a -\u003e\nunit` can be installed. For example,\n\n```ocaml non-deterministic=command\n# #install_printer Containers.Int.pp;;\n```\n\nHowever, printer combinators are not easily handled by `ocamldebug`. For\ninstance `# install_printer Containers.(List.pp Int.pp)` will *not* work out of\nthe box. You can make this work by writing a short module which defines\nready-made combined printing functions, and loading that in ocamldebug. For\ninstance\n\n```ocaml non-deterministic=command\nmodule M = struct\n\tlet pp_int_list = Containers.(List.pp Int.pp)\nend;;\n```\n\nloaded via `# load_printer m.cmo` and installed as `# install_printer\nM.pp_int_list`.\n\n\n## Change Log\n\nSee [this file](./CHANGELOG.md).\n\n## Finding help\n\n- [Mailing List](http://lists.ocaml.org/listinfo/containers-users)\n  the address is \u003cmailto:containers-users@lists.ocaml.org\u003e\n- the [github wiki](https://github.com/c-cube/ocaml-containers/wiki)\n- on IRC, ask `companion_cube` on `#ocaml@irc.libera.chat`\n- there is a `#containers` channel on OCaml's discord server.\n\n## Use\n\nYou might start with the [tutorial](#tutorial) to get a picture of how to use the library.\n\nYou can either build and install the library (see [build](#build)), or just copy\nfiles to your own project. The last solution has the benefits that you\ndon't have additional dependencies nor build complications (and it may enable\nmore inlining). Since modules have a friendly license and are mostly\nindependent, both options are easy.\n\nIn a toplevel, using ocamlfind:\n\n```ocaml\n# #use \"topfind\";;\n...\n# #require \"containers\";;\n# #require \"containers-data\";;\n# CCList.flat_map;;\n- : ('a -\u003e 'b list) -\u003e 'a list -\u003e 'b list = \u003cfun\u003e\n# open Containers (* optional *);;\n# List.flat_map ;;\n- : ('a -\u003e 'b list) -\u003e 'a list -\u003e 'b list = \u003cfun\u003e\n```\n\nIf you have comments, requests, or bugfixes, please share them! :-)\n\n## License\n\nThis code is free, under the BSD license.\n\n## Contents\n\nSee [the documentation](http://c-cube.github.io/ocaml-containers/)\nand [the tutorial below](#tutorial) for a gentle introduction.\n\n## Documentation\n\nIn general, see http://c-cube.github.io/ocaml-containers/last/ for the **API documentation**.\n\nSome examples can be found [there](doc/containers.md),\nper-version doc [there](http://c-cube.github.io/ocaml-containers/).\n\n## Build\n\nYou will need OCaml `\u003e=` 4.03.0.\n\n### Via opam\n\nThe preferred way to install is through [opam](http://opam.ocaml.org/).\n\n```\n$ opam install containers\n```\n\n### From Sources\n\n\u003cdetails\u003e\n\nYou need dune (formerly jbuilder).\n\n```\n$ make\n```\n\nTo build and run tests (requires `qcheck-core`, `gen`, `iter`):\n\n```\n$ opam install qcheck-core\n$ make test\n```\n\nTo build the small benchmarking suite (requires [benchmark](https://github.com/chris00/ocaml-benchmark)):\n\n```\n$ opam install benchmark batteries\n$ make bench\n$ ./benchs/run_benchs.sh\n```\n\n\u003c/details\u003e\n\n## Contributing\n\nPRs on github are very welcome (patches by email too, if you prefer so).\n\n\u003cdetails\u003e\n\u003csummary\u003ehow to contribute (click to unfold)\u003c/summary\u003e\n\n### List of authors\n\nThe list of contributors can be seen [on github](https://github.com/c-cube/ocaml-containers/graphs/contributors).\n\nAlternatively, `git authors` from git-extras can be invoked from within the repo\nto list authors based on the git commits.\n\n### First-Time Contributors\n\nAssuming your are in a clone of the repository:\n\n1. Some dependencies are required, you'll need\n  `opam install benchmark qcheck-core iter gen mdx uutf yojson`.\n2. run `make all` to enable everything (including tests).\n3. make your changes, commit, push, and open a PR.\n4. use `make test` without moderation! It must pass before a PR\n  is merged.  There are around 1150 tests right now, and new\n  features should come with their own tests.\n\nIf you feel like writing new tests, that is totally worth a PR\n(and my gratefulness).\n\n### General Guidelines\n\nA few guidelines to follow the philosophy of containers:\n\n- no dependencies between basic modules (even just for signatures);\n- add `@since` tags for new functions;\n- add tests if possible (see `tests/` dir)\n  There are numerous inline tests already,\n  to see what it looks like search for comments starting with `(*$`\n  in source files.\n\n### For Total Beginners\n\nThanks for wanting to contribute!\nTo contribute a change, here are the steps (roughly):\n\n1. click \"fork\" on https://github.com/c-cube/ocaml-containers on the top right of the page. This will create a copy of the repository on your own github account.\n2. click the big green \"clone or download\" button, with \"SSH\". Copy the URL (which should look like `git@github.com:\u003cyour username\u003e/ocaml-containers.git`) into a terminal to enter the command:\n\n    ```\n    $ git clone git@github.com:\u003cyour username\u003e/ocaml-containers.git\n    ```\n\n3. then, `cd` into the newly created directory.\n4. make the changes you want. See \u003c#first-time-contributors\u003e for\n  more details about what to do in particular.\n5. use `git add` and `git commit` to commit these changes.\n6. `git push origin master` to push the new change(s) onto your\n  copy of the repository\n7. on github, open a \"pull request\" (PR). Et voilà !\n\n\u003c/details\u003e\n\n## Tutorial\n\nThis tutorial contains a few examples to illustrate the features and\nusage of containers.\n\n\n\u003cdetails\u003e\n\u003csummary\u003ean introduction to containers (click to unfold)\u003c/summary\u003e\n\nWe assume containers is installed and that\nthe library is loaded, e.g. with:\n\n```ocaml\n# #require \"containers\";;\n# Format.set_margin 50 (* for readability here *);;\n- : unit = ()\n```\n\n### Basics\n\nWe will start with a few list helpers, then look at other parts of\nthe library, including printers, maps, etc.\n\n```ocaml\n# (|\u003e) (* quick reminder of this awesome standard operator *);;\n- : 'a -\u003e ('a -\u003e 'b) -\u003e 'b = \u003cfun\u003e\n# 10 |\u003e succ;;\n- : int = 11\n\n# open CCList.Infix;;\n\n# let l = 1 -- 100;;\nval l : int list =\n  [1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 11; 12; 13; 14; 15; 16; 17; 18; 19; 20; 21;\n   22; 23; 24; 25; 26; 27; 28; 29; 30; 31; 32; 33; 34; 35; 36; 37; 38; 39;\n   40; 41; 42; 43; 44; 45; 46; 47; 48; 49; 50; 51; 52; 53; 54; 55; 56; 57;\n   58; 59; 60; 61; 62; 63; 64; 65; 66; 67; 68; 69; 70; 71; 72; 73; 74; 75;\n   76; 77; 78; 79; 80; 81; 82; 83; 84; 85; 86; 87; 88; 89; 90; 91; 92; 93;\n   94; 95; 96; 97; 98; 99; 100]\n\n# (* transform a list, dropping some elements *)\n  l\n  |\u003e CCList.filter_map\n     (fun x-\u003e if x mod 3=0 then Some (float x) else None)\n  |\u003e CCList.take 5 ;;\n- : float list = [3.; 6.; 9.; 12.; 15.]\n\n# let l2 = l |\u003e CCList.take_while (fun x -\u003e x\u003c10) ;;\nval l2 : int list = [1; 2; 3; 4; 5; 6; 7; 8; 9]\n```\n\n```ocaml\n(* an extension of Map.Make, compatible with Map.Make(CCInt) *)\nmodule IntMap = CCMap.Make(CCInt);;\n```\n\n```ocaml\n# (* conversions using the \"iter\" type, fast iterators that are\n   pervasively used in containers. Combinators can be found\n   in the opam library \"iter\". *)\n  let map : string IntMap.t =\n    l2\n    |\u003e List.map (fun x -\u003e x, string_of_int x)\n    |\u003e CCList.to_iter\n    |\u003e IntMap.of_iter;;\nval map : string IntMap.t = \u003cabstr\u003e\n\n# CCList.to_iter (* check the type *);;\n- : 'a list -\u003e 'a CCList.iter = \u003cfun\u003e\n# IntMap.of_iter ;;\n- : (int * 'a) CCMap.iter -\u003e 'a IntMap.t = \u003cfun\u003e\n\n# (* we can print, too *)\n  Format.printf \"@[\u003c2\u003emap =@ @[\u003chov\u003e%a@]@]@.\"\n    (IntMap.pp CCFormat.int CCFormat.string_quoted)\n    map;;\nmap =\n  1 -\u003e \"1\", 2 -\u003e \"2\", 3 -\u003e \"3\", 4 -\u003e \"4\", 5\n  -\u003e \"5\", 6 -\u003e \"6\", 7 -\u003e \"7\", 8 -\u003e \"8\", 9 -\u003e \"9\"\n- : unit = ()\n\n# (* options are good *)\n  IntMap.get 3 map |\u003e CCOption.map (fun s-\u003es ^ s);;\n- : string option = Some \"33\"\n```\n\n### New types: `CCVector`, `CCHeap`, `CCResult`, `CCSexp`, `CCByte_buffer`\n\nContainers also contains (!) a few datatypes that are not from the standard\nlibrary but that are useful in a lot of situations:\n\n- `CCVector`:\n  A resizable array, with a mutability parameter. A value of type\n  `('a, CCVector.ro) CCVector.t` is an immutable vector of values of type `'a`,\n  whereas a `('a, CCVector.rw) CCVector.t` is a mutable vector that\n  can be modified. This way, vectors can be used in a quite functional\n  way, using operations such as `map` or `flat_map`, or in a more\n  imperative way.\n- `CCHeap`:\n  A priority queue (currently, leftist heaps) functorized over\n  a module `sig val t val leq : t -\u003e t -\u003e bool` that provides a type `t`\n  and a partial order `leq` on `t`.\n- `CCResult`\n  An error type for making error handling more explicit (an error monad,\n  really, if you're not afraid of the \"M\"-word).\n  Subsumes and replaces the old `CCError`.\n  It uses the new `result` type from the standard library (or from\n  the retrocompatibility package on opam) and provides\n  many combinators for dealing with `result`.\n- `CCSexp` and `CCCanonical_sexp`:\n  functorized printer and parser for S-expressions, respectively as\n  actual S-expressions (like `sexplib`) and as canonical binary-safe\n  S-expressions (like `csexp`)\n- `CCByte_buffer`: a better version of the standard `Buffer.t` which cannot be\n  extended and prevents access to its internal byte array. This type is\n  designed for (blocking) IOs and to produce complex strings incrementally\n  in an efficient way.\n\nNow for a few examples:\n\n```ocaml\n# (* create a new empty vector. It is mutable, for otherwise it would\n   not be very useful. *)\n  CCVector.create;;\n- : unit -\u003e ('a, CCVector.rw) CCVector.t = \u003cfun\u003e\n\n# (* init, similar to Array.init, can be used to produce a\n   vector that is mutable OR immutable (see the 'mut parameter?) *)\n  CCVector.init ;;\n- : int -\u003e (int -\u003e 'a) -\u003e ('a, 'mut) CCVector.t = \u003cfun\u003e\n```\n\n```ocaml non-deterministic=output\n# (* use the infix (--) operator for creating a range. Notice\n   that v is a vector of integer but its mutability is not\n   decided yet. *)\n  let v = CCVector.(1 -- 10);;\nval v : (int, '_a) CCVector.t = \u003cabstr\u003e\n```\n\n```ocaml\n# Format.printf \"v = @[%a@]@.\" (CCVector.pp CCInt.pp) v;;\nv = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10\n- : unit = ()\n# CCVector.push v 42;;\n- : unit = ()\n\n# v (* now v is a mutable vector *);;\n- : (int, CCVector.rw) CCVector.t = \u003cabstr\u003e\n\n# (* functional combinators! *)\n  let v2 : _ CCVector.ro_vector = v\n  |\u003e CCVector.map (fun x-\u003e x+1)\n  |\u003e CCVector.filter (fun x-\u003e x mod 2=0)\n  |\u003e CCVector.rev ;;\nval v2 : int CCVector.ro_vector = \u003cabstr\u003e\n\n# Format.printf \"v2 = @[%a@]@.\" (CCVector.pp CCInt.pp) v2;;\nv2 = 10, 8, 6, 4, 2\n- : unit = ()\n```\n\n```ocaml\n(* let's transfer to a heap *)\nmodule IntHeap = CCHeap.Make(struct type t = int let leq = (\u003c=) end);;\n```\n\n```ocaml\n# let h = v2 |\u003e CCVector.to_iter |\u003e IntHeap.of_iter ;;\nval h : IntHeap.t = \u003cabstr\u003e\n\n# (* We can print the content of h\n  (printing is not necessarily in order, though) *)\n  Format.printf \"h = [@[%a@]]@.\" (IntHeap.pp CCInt.pp) h;;\nh = [2,4,6,8,10]\n- : unit = ()\n\n# (* we can remove the first element, which also returns a new heap\n   that does not contain it — CCHeap is a functional data structure *)\n  IntHeap.take h;;\n- : (IntHeap.t * int) option = Some (\u003cabstr\u003e, 2)\n\n# let h', x = IntHeap.take_exn h ;;\nval h' : IntHeap.t = \u003cabstr\u003e\nval x : int = 2\n\n# IntHeap.to_list h' (* see, 2 is removed *);;\n- : int list = [4; 8; 10; 6]\n```\n\n### IO helpers\n\nThe core library contains a module called `CCIO` that provides useful\nfunctions for reading and writing files. It provides functions that\nmake resource handling easy, following\nthe pattern `with_resource : resource -\u003e (access -\u003e 'a) -\u003e 'a` where\nthe type `access` is a temporary handle to the resource (e.g.,\nimagine `resource` is a file name and `access` a file descriptor).\nCalling `with_resource r f` will access `r`, give the  result to `f`,\ncompute the result of `f` and, whether `f` succeeds or raises an\nerror, it will free the resource.\n\nConsider for instance:\n\n```ocaml\n# CCIO.with_out \"./foobar\"\n    (fun out_channel -\u003e\n      CCIO.write_lines_l out_channel [\"hello\"; \"world\"]);;\n- : unit = ()\n```\n\nThis just opened the file 'foobar', creating it if it didn't exist,\nand wrote two lines in it. We did not have to close the file descriptor\nbecause `with_out` took care of it. By the way, the type signatures are:\n\n```ocaml non-deterministic=command\nval with_out :\n  ?mode:int -\u003e ?flags:open_flag list -\u003e\n  string -\u003e (out_channel -\u003e 'a) -\u003e 'a\n\nval write_lines_l : out_channel -\u003e string list -\u003e unit\n```\n\nSo we see the pattern for `with_out` (which opens a function in write\nmode and gives its functional argument the corresponding file descriptor).\n\nNOTE: you should never let the resource escape the\nscope of the `with_resource` call, because it will not be valid outside.\nOCaml's type system doesn't make it easy to forbid that so we rely\non convention here (it would be possible, but cumbersome, using\na record with an explicitly quantified function type).\n\nNow we can read the file again:\n\n```ocaml\n# let lines : string list = CCIO.with_in \"./foobar\" CCIO.read_lines_l ;;\nval lines : string list = [\"hello\"; \"world\"]\n```\n\nThere are some other functions in `CCIO` that return _generators_\ninstead of lists. The type of generators in containers\nis `type 'a gen = unit -\u003e 'a option` (combinators can be\nfound in the opam library called \"gen\"). A generator is to be called\nto obtain successive values, until it returns `None` (which means it\nhas been exhausted). In particular, python users might recognize\nthe function\n\n```ocaml non-deterministic=command\n# CCIO.File.walk ;;\n- : string -\u003e walk_item gen = \u003cfun\u003e;;\n```\n\nwhere `type walk_item = [ ``Dir | ``File ] * string` is a path\npaired with a flag distinguishing files from directories.\n\n\n### To go further: `containers-data`\n\nThere is also a library called `containers-data`, with lots of\nmore specialized data-structures.\nThe documentation contains the API for all the modules; they also provide\ninterface to `iter` and, as the rest of containers, minimize\ndependencies over other modules. To use `containers-data` you need to link it,\neither in your build system or by `#require containers-data;;`\n\nA quick example based on purely functional double-ended queues:\n\n```ocaml\n# #require \"containers-data\";;\n# #install_printer CCFQueue.pp  (* better printing of queues! *);;\n\n# let q = CCFQueue.of_list [2;3;4] ;;\nval q : int CCFQueue.t = queue {2; 3; 4}\n\n# let q2 = q |\u003e CCFQueue.cons 1 |\u003e CCFQueue.cons 0 ;;\nval q2 : int CCFQueue.t = queue {0; 1; 2; 3; 4}\n\n# (* remove first element *)\n  CCFQueue.take_front q2;;\n- : (int * int CCFQueue.t) option = Some (0, queue {1; 2; 3; 4})\n\n# (* q was not changed *)\n  CCFQueue.take_front q;;\n- : (int * int CCFQueue.t) option = Some (2, queue {3; 4})\n\n# (* take works on both ends of the queue *)\n  CCFQueue.take_back_l 2 q2;;\n- : int CCFQueue.t * int list = (queue {0; 1; 2}, [3; 4])\n```\n\n### Common Type Definitions\n\nSome structural types are used throughout the library:\n\n- `gen`: `'a gen = unit -\u003e 'a option` is an iterator type. Many combinators\n  are defined in the opam library [gen](https://github.com/c-cube/gen)\n- `iter`: `'a iter = (unit -\u003e 'a) -\u003e unit` is also an iterator type, formerly\n  named `sequence`.\n  It is easier to define on data structures than `gen`, but it a bit less\n  powerful. The opam library [iter](https://github.com/c-cube/iter)\n  can be used to consume and produce values of this type.\n\n  It was renamed\n  from `'a sequence` to `'a iter` to distinguish it better from `Core.Sequence`\n  and the standard `seq`.\n- `error`: `'a or_error = ('a, string) result = Error of string | Ok of 'a`\n  using the standard `result` type, supported in `CCResult`.\n- `printer`: `'a printer = Format.formatter -\u003e 'a -\u003e unit` is a pretty-printer\n  to be used with the standard module `Format`. In particular, in many cases,\n  `\"foo: %a\" Foo.print foo` will type-check.\n\n### Extended Documentation\n\nSee [the extended documentation](doc/containers.md) for more examples.\n\n\u003c/details\u003e\n\n## HOWTO (for contributors)\n\n\u003cdetails\u003e\n\n### Make a release\n\nBeforehand, check `grep deprecated -r src` to see whether some functions\ncan be removed.\n\n- `make all`\n- update version in `containers.opam`\n- `make update_next_tag` (to update `@since` comments; be careful not to change symlinks)\n- check status of modules (`{b status: foo}`) and update if required;\n   removed deprecated functions, etc.\n- update `CHANGELOG.md` (see its end to find the right git command)\n- commit the changes\n- `make test doc`\n- `export VERSION=\u003ctag here\u003e; git tag -f $VERSION; git push origin :$VERSION; git push origin $VERSION`\n- new opam package: `opam publish https://github.com/c-cube/ocaml-containers/archive/\u003ctag\u003e.tar.gz`\n- re-generate doc: `make doc` and put it into `gh-pages`\n\n### List Authors\n\n```\ngit log --format='%aN' | sort -u\n```\n\n\u003c/details\u003e\n","funding_links":[],"categories":["Libraries","Application Libraries","OCaml"],"sub_categories":["Core Libraries"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fc-cube%2Focaml-containers","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fc-cube%2Focaml-containers","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fc-cube%2Focaml-containers/lists"}