{"id":27433542,"url":"https://github.com/zerothi/fdict","last_synced_at":"2025-04-14T17:17:05.797Z","repository":{"id":14910680,"uuid":"17634701","full_name":"zerothi/fdict","owner":"zerothi","description":"Fortran type-free variable and type-free dictionary","archived":false,"fork":false,"pushed_at":"2024-09-18T12:37:28.000Z","size":1773,"stargazers_count":75,"open_issues_count":6,"forks_count":17,"subscribers_count":8,"default_branch":"main","last_synced_at":"2025-04-14T17:16:54.398Z","etag":null,"topics":["dictionary","fortran","pointer"],"latest_commit_sha":null,"homepage":"http://zerothi.github.io/fdict","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zerothi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"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}},"created_at":"2014-03-11T15:06:20.000Z","updated_at":"2024-09-18T12:37:35.000Z","dependencies_parsed_at":"2025-04-14T17:16:57.143Z","dependency_job_id":null,"html_url":"https://github.com/zerothi/fdict","commit_stats":{"total_commits":202,"total_committers":2,"mean_commits":101.0,"dds":0.004950495049504955,"last_synced_commit":"7da486af5bf2411d16572d2bed566b24248c7fc6"},"previous_names":[],"tags_count":25,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zerothi%2Ffdict","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zerothi%2Ffdict/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zerothi%2Ffdict/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zerothi%2Ffdict/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zerothi","download_url":"https://codeload.github.com/zerothi/fdict/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248923739,"owners_count":21183953,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["dictionary","fortran","pointer"],"created_at":"2025-04-14T17:16:52.635Z","updated_at":"2025-04-14T17:17:05.789Z","avatar_url":"https://github.com/zerothi.png","language":"Python","funding_links":["https://www.paypal.com/cgi-bin/webscr?cmd=_donations\u0026business=NGNU2AA3JXX94\u0026lc=DK\u0026item_name=Papior%2dCodes\u0026item_number=codes\u0026currency_code=EUR\u0026bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted"],"categories":[],"sub_categories":[],"readme":"# fdict\n\n[![Build Status](https://travis-ci.org/zerothi/fdict.svg?branch=master)](https://travis-ci.org/zerothi/fdict)\n[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations\u0026business=NGNU2AA3JXX94\u0026lc=DK\u0026item_name=Papior%2dCodes\u0026item_number=codes\u0026currency_code=EUR\u0026bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted)\n\nA variable and dictionary in pure fortran for retaining any data-type\nand a fast hash-table dictionary.\n\n## Usage\n\nThis module consists of two separate modules which co-exist for\nmaintenance and usage reasons.\n\nFirst, the variable module which is a type-free variable that can contain\nany variable type, and any dimension as well.\n\nSecond, the dictionary module which contains a hash-table of variables\nthat can contain _any_ data-type allowed by the variable module.\n\n## Downloading and installation\n\nInstalling fdict requires a download of the library\nhosted at [github](https://github.com/) at [fdict@git].\n\nInstallation can be done via 2 different back-ends. 1)\n[smeka](https://github.com/zerothi/smeka) build system, or 2)\nCMake build.\n\n### smeka build system\n\nExtract and create an `setup.make` file for compilation, a minimal\n`setup.make` file can look like this\n\n```\nFC=gfortran\nFFLAGS = -g\n```\n\n# if in a build directory, also add this:\n\nPREFIX = \u003cpath to fdict top directory\u003e\n\nType `make` and a library called `libfdict.a` is created.\nSubsequently the installation may be performed by:\n\n```\nmake PREFIX=/path/to/fdict install\n```\n\nwhich installs the required files (modules and libraries) to the folder.\nIt will also install pkg-config files for auto-detection.\n\n### CMake\n\nCMake procedure can be done via the normal procedure:\n\n```\ncmake -S. -Bbuild-fdict\ncmake --build build-fdict\n```\n\nfdict should also be able to be used in a sub-project. If problems\noccur, feel free to open up an issue.\n\n### Linking to fdict\n\nTo use the dictionary you need to add include statements for the\nmodules as well as linking to the program.\n\nTo link fdict to your program the following can be used in a `Makefile`\n\n```\nFDICT_PATH  = /path/to/fdict/parent\nFDICT_LIBS  = -L$(FDICT_PATH) -lfdict\nFDICT_INC   = -I$(FDICT_PATH)\n```\n\nAlternatively, one can use pkg-config for obtaining the include flags and\nlibraries.\n\nFor parent programs that uses `fdict` there are 2 ways of knowing which `fdict`\nversion one is using:\n\n1. A simple header file (like C-preprocessor statements), this information\n   is found in `fdict.inc`\n1. A `fypp` compatible include file which contains library version and\n   which data types are included in the built library, see the file `fdict.fypp`\n\nThe file `fdict.inc` may be included in projects which exposes the following\ndefinitions:\n\n```\n_FDICT_MAJOR_ 0\n_FDICT_MINOR_ 9\n_FDICT_PATCH_ 0\n_FDICT_VERSION_ 0.9.0\n```\n\nThis is mainly meant as a feature usable when the fdict interface and\ne.g. modules change names.\n\nAlternatively the `fdict.fypp` inclusion file exposes variables such as:\n\n- the library version numbers (as above)\n- which data-types are enabled\n- the number of ranks for each kind\n\nThe `fdict.fypp` file is handy when you are already relying on `fypp`\nwhereas the regular `fdict.inc` header files are easy to use in standard\nfortran source compilation.\n\n#### Controlling interfaces\n\n__Typically not needed__: allows for customization of different interfaces.\n\nBy default the number of dimensions allowed by the library is 5, i.e.\nthere is no interface created for `real a(:,:,:,:,:,:)`, etc. However,\nto accomodate arbitrary dimensions you must define constants in your\n`setup.make` file.\n\nThere are several fine-tuning options that allows creating more or fewer\ninterfaces. As the number of dimensions increases, so does the library\nsize. If only a specific maximum range of ranks are required, it might\nbe beneficial to reduce maximum ranks to the used range.\n\nCurrently the `fdict` library supports the types listed in the below table:\n\n| Type               | Precision format (GNU)   | C-type                | Default |\n| ------------------ | ------------------------ | --------------------- | ------- |\n| `type(variable_t)` |                          | ---                   | yes     |\n| `character(len=1)` |                          | `char`                | yes     |\n| `integer`          | `selected_int_kind(2)`   | `byte`                | no      |\n| `integer`          | `selected_int_kind(4)`   | `short`               | no      |\n| `integer`          | `selected_int_kind(9)`   | `int`                 | yes     |\n| `integer`          | `selected_int_kind(18)`  | `long`                | yes     |\n| `real`             | `selected_real_kind(6)`  | `float`               | yes     |\n| `real`             | `selected_real_kind(15)` | `double`              | yes     |\n| `real`             | `selected_real_kind(18)` | `ext. double`         | no      |\n| `real`             | `selected_real_kind(30)` | `quad`                | no      |\n| `complex`          | `selected_real_kind(6)`  | `float complex`       | yes     |\n| `complex`          | `selected_real_kind(15)` | `double complex`      | yes     |\n| `complex`          | `selected_real_kind(18)` | `ext. double complex` | no      |\n| `complex`          | `selected_real_kind(30)` | `quad complex`        | no      |\n| `logical`          | `selected_int_kind(2)`   | `byte`                | no      |\n| `logical`          | `selected_int_kind(4)`   | `short`               | no      |\n| `logical`          | `selected_int_kind(9)`   | `int`                 | yes     |\n| `logical`          | `selected_int_kind(18)`  | `long`                | no      |\n| `type(c_ptr)`      |                          | `void *`              | no      |\n| `type(c_funptr)`   |                          | (procedure) `void *`  | no      |\n\nIn the `Default` column one can see which data-types are enabled by default. The most\ncommonly used data-types are enabled.\n\nTo enable the non-default data types you can do so with (Makefile scheme):\n\n```\nFYPPFLAGS += -DWITH_INT8=1 # for int kind(2)\nFYPPFLAGS += -DWITH_INT16=1 # for int kind(4)\n# Note that not all compilers support extended precisions\n# If you experience compiler errors, this is likely the cause.\nFYPPFLAGS += -DWITH_REAL80=1 # for real and complex kind(18)\nFYPPFLAGS += -DWITH_REAL128=1 # for real and complex kind(30)\nFYPPFLAGS += -DWITH_LOG8=1 # for logical kind(2)\nFYPPFLAGS += -DWITH_LOG16=1 # for logical kind(4)\nFYPPFLAGS += -DWITH_LOG64=1 # for logical kind(18)\nFYPPFLAGS += -DWITH_ISO_C=1 # for enabling c_ptr and c_funptr\n```\n\nFor `cmake` the variables are all prefixed with `FDICT_`, e.g. `-DFDICT_FYPPFLAGS`,\nto ensure there are no clashes with parent programs.\n\nBy default `fdict` generates the kind specifications from the `selected_*_kind` routines,\nhowever, if one wishes to use the `iso_fortran_env` module simply add `FYPPFLAGS += -DWITH_ISO_ENV`.\n\nTo control the maximum ranks in the interfaces one can add these:\n\n```\n# type(c_ptr), type(c_funptr) and character(len=1)\n# are data types that are not affected by the MAXRANK variable\n\n# globally define the maximum ranks of all but the above listed\nFYPPFLAGS += -DMAXRANK=n\n\n# integer(*) types maximum rank\nFYPPFLAGS += -DMAXRANK_INT=n\n\n# real(*) types maximum rank\nFYPPFLAGS += -DMAXRANK_REAL=n\n\n# complex(*) types maximum rank\nFYPPFLAGS += -DMAXRANK_CMPLX=n\n\n# logical(*) types maximum rank\nFYPPFLAGS += -DMAXRANK_LOG=n\n\n# type(c_ptr), type(c_funptr) types maximum rank\nFYPPFLAGS += -DMAXRANK_ISO_C=n\n```\n\n### variable\n\nUsing this module one gains access to a generic type variable which\ncan contain _any_ data format.\n\nIt is used like this:\n\n```\nuse variable\ninteger :: a(3\ntype(variable_t) :: v\na = 2\ncall assign(v,a)\na = 3\ncall assign(a,v)\n```\n\nAlso the variable contains an abbreviation for assigning pointers to\nnot copy data, but retain data locality:\n\n```\ninteger, target :: a(3)\ntype(variable_t) :: v\na = 2\ncall associate(v,a)\na = 3\n! Now v contains a = 3\n```\n\nTo delete a variable do:\n\n```\nuse variable\ntype(variable_t) :: v\ncall delete(v)\n```\n\nHowever, when the variable is using pointers, instead the user can do\n\n```\nuse variable\ntype(variable_t) :: v\n! preferred\ncall nullify(v)\n! or\ncall delete(v,dealloc=.false.)\n```\n\nwhich merely destroys the variable object and thus retains the data\nwhere it is. As with any other pointer arithmetic it is up to the programmer\nto ensure there is no memory leaks.\n\nIn some cases one does not know which data-type is being stored in a variable.\nHere it may be beneficial to lookup the type of data:\n\n```\nuse variable\ninteger, target :: a(3)\ntype(variable_t) :: v\na(:) = 2\ncall associate(v,a)\nif ( which(v) == which(a) ) then ! signal integer of 1D (i0 for scalar)\n   call assign(a, v)\nend if\n\n! Another possibility is to *try* to get the value\nlogical :: success\ninteger, target :: i1(3)\nreal, target :: r1(3)\n\ncall assign(r1, v, success=success)\nif ( .not. success ) then\n    call assign(i1, v, success=success)\nend if\n... etc ...\n```\n\nHowever, it may be better to explicitly check the type using `which`.\nFor consistency and API changes, it is encouraged to use `which(\u003ctype\u003e)` to\nensure that the data-types are as expected. I.e. `which([real(real64) ::])`\nis the preferred way of forcing a data-type contained in a variable.\n\n### dictionary\n\nUsing `type(variable_t)` it becomes easy to create dictionaries in fortran.\n\nUsing this module we implement a dictionary which can contain _any_ data\nformat using a `key:val` based formalism. The underlying data structure is a\nlinked list sorted according to hash-values of the keys. Hence searching\nfor specific elements in the dictionary is _extremely_ fast. Searching a\ndictionary with 100 keys 300000 times takes less than 0.04 seconds on\na Haswell laptop.\nConcatenating dictionaries is also very fast.\n\nCreating a dictionary is almost as easy as the Python equivalent:\n\n```\nuse dictionary\ntype(dictionary_t) :: dict\ndict = ('KEY'.kv.1)\n```\n\nTo extend a dictionary one uses the concatenating format:\n\n```\ndict = dict // ('Hello'.kv.'world') // ('No'.kv.'world')\n```\n\nAgain as is used by the `type(variable_t)` one can with benefit use `.kvp.` to create\nthe dictionary value by pointers instead of copying the content.\nHence doing:\n\n```\nreal :: r(4)\ndict = dict // ('reals'.kvp.r)\nr = 4\n```\n\nwill change the value in the dictionary.\nNote that one can easily create memory leaks with dictionaries:\n\n```\nuse dictionary\ntype(dictionary_t) :: dict\ndict = ('KEY'.kv.1)\ndict = dict // ('KEY'.kv.2)\ndict = ('KEY'.kv.3)\n```\n\nThe 1st assignement is valid since the dictionary is empty.\nThe 2nd assignment concatenates and does not produce any memory leaks.\nIn that case the old key `KEY` is deleted and the new value `2` is inserted.\nThe 3rd assignment produces a memory leak since the pointer to the original\ndictionary gets lost. Be sure to call `call delete(dict)` prior to single\nassignments.\n\nThere are various ways to access the data in a dictionary.\n\n1. Accessing specific keys may be exercised using\n\n   ```\n    use dictionary\n    type(dictionary_t) :: dict\n    type(variable_t) :: var\n    integer :: i\n    real :: r\n    logical :: success\n    dict = ('KEY'.kv.1)\n    call assign(r, dict, 'KEY', success=success)\n    if ( .not. success ) call assign(i, dict, 'KEY', success=success)\n    call assign(var, dict, 'KEY')\n   ```\n\n   Since values in dictionaries are stored using `variable_t` we have to\n   follow the limitations of that implementation. Therefore it may be better\n   to always use a temporary `variable_t` to retrieve the values stored. This\n   will remove a redundant lookup in the dictionary.\n\n1. Users may find the `.key.` and `.value.` operators which only acts on the first\n   element of the dictionary (which may be a surprise). This is only useful for looping\n   dictionaries.\n\n   ```\n    use dictionary\n    type(dictionary_t) :: dict, dict_first\n    type(variable_t) :: var\n    character(DICTIONARY_KEY_LENGTH) :: key\n    integer :: i\n    real :: r\n    logical :: success\n    dict = ('KEY'.kv.1)\n    dict = dict // ('KEY1'.kv.3)\n\n    ! start looping\n    dict_first = .first. dict\n    do while ( .not. (.empty. dict_first) )\n       ! now .key. and .value. could be used:\n       key = .key. dict_first\n       call assign(var, dict_first)\n       ! Get next dictionary entry\n       dict_first = .next. dict_first\n    end while\n   ```\n\nNote that the dictionary can also contain _any_ data type.\n\nHowever, if it needs to do custom data-types the programmer needs to\nextend the code by supplying a few custom routines.\n\nIntrinsically the dictionary can contain dictionaries by this:\n\n```\nuse dictionary\ntype(dictionary_t) :: d1, d2\nd1 = ('hello'.kv.'world')\nd2 = ('hello'.kv.'world')\nd1 = d1 // ('dict'.kvp.d2)\n```\n\nBut it will be up to the user to _know_ the key for data types other than\nintegers, reals, complex numbers, characters and `c_*` extension types.\n\nNote that the dictionary contained is passed by reference, and thus\nif you delete `d2`, you will have a dangling pointer in `d1`.\n\n## Contributions, issues and bugs\n\nI would advice any users to contribute as much feedback and/or PRs to further\nmaintain and expand this library.\n\nPlease do not hesitate to contribute!\n\nIf you find any bugs please form a [bug report/issue][issue].\n\nIf you have a fix please consider adding a [pull request][pr].\n\n## License\n\nThe fdict license is [MPL-2.0][mpl-2], see the LICENSE file.\n\n## Thanks\n\nA big thanks goes to Alberto Garcia for contributing ideas and giving\nme bug reports. Without him the interface would have been much more\ncomplex!\n\n\u003c!---\nLinks to external and internal sites.\n--\u003e\n\n\u003c!-- [fdict-doc]: https://github.com/zerothi/fdict/wiki --\u003e\n\n[fdict@git]: https://github.com/zerothi/fdict\n[issue]: https://github.com/zerothi/fdict/issues\n[mpl-2]: https://opensource.org/licenses/MPL-2.0\n[pr]: https://github.com/zerothi/fdict/pulls\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzerothi%2Ffdict","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzerothi%2Ffdict","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzerothi%2Ffdict/lists"}