Mapping and lists: the dictionaries module

The dictionaries module is Futile’s YAML-like tree container. User code declares dictionaries as pointers, initializes them with dict_init() or the constructors dict_new() and list_new(), navigates with the // operator, and releases storage with dict_free().

The API descriptions below are extracted from the Fortran source. This page keeps only the narrative and runnable examples needed to understand the public contract.

Several lifecycle and query routines are implemented in dictionaries_base, but they are also public through dictionaries. For ordinary client code, use dictionaries is sufficient to access dictionary, dict_init(), dict_free(), dict_len(), dict_size(), dict_key(), dict_item(), and dict_value().

Core storage and lifecycle API from dictionaries_base

These objects are implemented in dictionaries_base and re-exported by dictionaries. They are shown with their implementation module so the source location remains clear.

Description

Low-level dictionary storage and lifecycle routines. Applications normally use the higher-level dictionaries module, which re-exports this public API.

Quick access

Types:

dictionary

Routines:

dict_free(), dict_init(), dict_item(), dict_key(), dict_len(), dict_size(), dict_value()

Needed modules

  • f_precisions: Defines the portable Futile kind policy, undefined sentinels, precision conversion helpers, and low-level address inquiry helpers. Host codes should use these names instead of compiler-specific kind

Types

  • type  dictionaries_base/dictionary

    Opaque dictionary node used to serialize, store, and traverse YAML-like data. User code must declare dictionary objects as pointers and initialize them with dict_init, dict_new, or list_new before use.

    Type fields:
    • % child [dictionary, pointer/optional/default=>]

    • % data [storage] :: Internal key, value, and list/mapping counters.

    • % next [dictionary, pointer/optional/default=>]

    • % null [dictionary, pointer]

    • % parent [dictionary, pointer/optional/default=>]

    • % previous [dictionary, pointer/optional/default=>]

Subroutines and functions

interface  dictionaries_base/dict_free(dict, dict0, dict1[, dict2, dict3, dict4, dict5, dict6, dict7, dict8, dict9])
Parameters:
Options:
subroutine  dictionaries_base/dict_init(dict)

Initialize a dictionary node and make it ready for use. The dictionary may be undefined on input; free an already initialized instance before calling dict_init again.

Parameters:

dict [dictionary, pointer] :: Dictionary pointer associated on output.

subroutine  dictionaries_base/dict_free(dict)

Free a dictionary tree recursively and nullify the pointer.

Parameters:

dict [dictionary, pointer] :: Dictionary to be freed and nullified.

function  dictionaries_base/dict_len(dict)

Return the length of a dictionary used as a list of objects. Returns 0 for mappings and scalar nodes, and -1 if the dictionary is nullified. Use dict_size for mappings.

Parameters:

dict [dictionary, in,pointer]

Return:

dict_len [integer] :: Number of list items, 0 for mappings/scalars, -1 if nullified.

function  dictionaries_base/dict_size(dict)

Return the number of keys in a dictionary used as a mapping. Returns 0 for lists and scalar nodes, and -1 if the dictionary is nullified. Use dict_len for lists.

Parameters:

dict [dictionary, in,pointer]

Return:

dict_size [integer] :: Number of mapping keys, 0 for lists/scalars, -1 if nullified.

function  dictionaries_base/dict_key(dict)

Return the mapping key of a dictionary node. This is commonly used when iterating over a mapping with dict_iter and dict_next.

Parameters:

dict [dictionary, in,pointer]

Return:

dict_key [character(len=max_field_length)] :: Key of dict, or an empty string if nullified.

function  dictionaries_base/dict_item(dict)

Return the list index of a dictionary node. This is commonly used when iterating over a list with dict_iter and dict_next.

Parameters:

dict [dictionary, in,pointer]

Return:

dict_item [integer] :: Zero-based list item index, or -1 if nullified/not a list item.

function  dictionaries_base/dict_value(dict)

Return the scalar value stored in a dictionary node. For nested mappings and lists the result is TYPE_DICT or TYPE_LIST. If the value is not a scalar, it returns either :f:var`TYPE_DICT` or TYPE_LIST.

Parameters:

dict [dictionary, in,pointer]

Return:

dict_value [character(len=max_field_length)] :: Scalar value, TYPE_DICT, TYPE_LIST, or empty if nullified.

High-level constructors and iterators from dictionaries

Description

High-level dictionary API used throughout Futile and BigDFT. A dictionary is a pointer-based tree that can represent scalars, ordered mappings, and lists. It maps directly to YAML data and is manipulated with constructors such as dict_new and list_new, the // navigation operator, and set/add routines.

This module use-associates dictionaries_base and re-exports its core public routines and types, including dictionary, dict_init, dict_free, dict_len, dict_size, dict_key, dict_item, and dict_value. Client code should normally write use dictionaries; a separate use dictionaries_base is needed only for low-level code that intentionally avoids the higher-level dependencies.

Quick access

Types:

dictionary_container, list_container

Variables:

dict_key, dictionary

Routines:

dict_get(), dict_isdict(), dict_islist(), dict_isscalar(), dict_iter(), dict_keys(), dict_new(), dict_next(), list_new()

Needed modules

Types

  • type  dictionaries/list_container

    Container produced by the .item. operator and consumed by list_new.

    Type fields:
    • % dict [dictionary, pointer/optional/default=>]

    • % null [dictionary, pointer]

    • % val [character(len=max_field_length), optional/default=’ ‘] :: Scalar value serialized as text.

  • type  dictionaries/dictionary_container

    Container produced by the .is. operator and consumed by dict_new.

    Type fields:
    • % child [dictionary, pointer/optional/default=>]

    • % key [character(len=max_field_length), optional/default=’ ‘] :: Mapping key.

    • % null [dictionary, pointer]

    • % value [character(len=max_field_length), optional/default=’ ‘] :: Scalar mapping value serialized as text.

Variables

  • dictionaries/dict_key [public]
  • dictionaries/dictionary [public]

Subroutines and functions

interface  dictionaries/dict_get()
interface  dictionaries/dict_iter(dict)
Parameters:

dict [dictionary, in,pointer] :: Dictionary whose children are inspected.

interface  dictionaries/list_new(dicts)

Create a dictionary tree interpreted as an ordered list. Items are usually passed with the .item. operator.

Parameters:

dicts (*) [list_container]

interface  dictionaries/dict_new(dicts)

Create a dictionary tree interpreted as an ordered mapping. Entries are usually passed with the .is. operator.

Parameters:

dicts (*) [dictionary_container, in] :: Key/value entries, usually produced with .is.

function  dictionaries/dict_islist(dict)
Parameters:

dict [dictionary, pointer]

Return:

ok [logical]

function  dictionaries/dict_isdict(dict)
Parameters:

dict [dictionary, pointer]

Return:

ok [logical]

function  dictionaries/dict_isscalar(dict)
Parameters:

dict [dictionary, pointer]

Return:

ok [logical]

function  dictionaries/dict_new(dicts)

Build a mapping dictionary from an array of dictionary_container entries.

Parameters:

dicts (*) [dictionary_container, in] :: Key/value entries, usually produced with .is.

Return:

dict_new [dictionary, pointer] :: Newly allocated mapping dictionary.

function  dictionaries/dict_iter(dict)

Return the first child node for iterating over a list or mapping.

Parameters:

dict [dictionary, in,pointer] :: Dictionary whose children are inspected.

Return:

dict_iter [dictionary, pointer] :: First child node, or null if dict is not associated.

function  dictionaries/dict_next(dict)

Return the next sibling node during dictionary/list iteration.

Parameters:

dict [dictionary, in,pointer] :: Current node.

Return:

dict_next [dictionary, pointer] :: Next sibling node, first child, or null.

function  dictionaries/dict_keys(dict)
Parameters:

dict [dictionary, in] :: <the dictionary must be associated

Return:

dict_keys (dict%data%nelems) [character(len=max_field_length)]

Called from:

dict_keys()

Call to:

dict_keys(), dict_key()

function  dictionaries/list_new(dicts)
Parameters:

dicts (*) [list_container]

Return:

list_new [dictionary, pointer]

function  dictionaries/f_err_check([err_id, err_name])
Options:
  • err_id [integer, in,]

  • err_name [character(len=*), in,]

Return:

f_err_check [logical]

Constructor syntax

Lists are built from .item. entries:

list => list_new([.item. 'first', .item. 'second'])

Mappings are built from .is. entries:

dict => dict_new(['key1' .is. 'value1', 'key2' .is. 'value2'])

Values may be intrinsic scalars, one-dimensional intrinsic arrays, or nested type(dictionary), pointer objects. Array values become ordered list items.

Examples from the Futile tests

The examples below are included from the regression tests so the documentation and tested behavior remain synchronized.

  dict_tmp => list_new([.item. 'one',.item. '4',.item. '1.1'])
  dict1=>dict_new()
  dictA=>dict_new('Key' .is. 'Scalar')
  dict1=>dict_new(['Key1' .is. 'One',&
       'Key2' .is. 'Two','Key3' .is. 'Three'])