<commit_before>/**
 * @file tree.h
 * @author <NAME> <<EMAIL>>
 * @brief libyang generic macros and functions to work with YANG schema or data trees.
 *
 * Copyright (c) 2019 CESNET, z.s.p.o.
 *
 * This source code is licensed under BSD 3-Clause License (the "License").
 * You may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://opensource.org/licenses/BSD-3-Clause
 */

#ifndef LY_TREE_H_
#define LY_TREE_H_

#include <inttypes.h>

#include "tree_data.h"

#ifdef __cplusplus
extern "C" {
#endif

/**
 * @page howtoXPath XPath Addressing
 *
 * Internally, XPath evaluation is performed on __when__ and __must__ conditions in the schema. For that almost
 * a full [XPath 1.0](http://www.w3.org/TR/1999/REC-xpath-19991116/) evaluator was implemented.
 * In YANG models you can also find paths identifying __augment__ targets, __leafref__ targets, and trivial paths in
 * __choice default__ and __unique__ statements argument. The exact format of all those paths can be found in the
 * relevant RFCs. Further will only be discussed paths that are used directly in libyang API functions.
 *
 * XPath
 * =====
 *
 * Generally, any xpath argument expects an expression similar to _when_ or _must_ as the same evaluator is used. As for
 * the format of any prefixes, the standardized JSON ([RFC 7951](https://tools.ietf.org/html/rfc7951#section-6.11))
 * was used. Summarized, xpath follows these conventions:
 *   - full XPath can be used, but only data nodes (node sets) will always be returned,
 *   - as per the specification, prefixes are actually __module names__,
 *   - also in the specification, for _absolute_ paths, the first (leftmost) node _MUST_ have a prefix,
 *   - for _relative_ paths, you specify the __context node__, which then acts as a parent for the first node in the path,
 *   - nodes always inherit their module (prefix) from their __parent node__ so whenever a node is from a different
 *     module than its parent, it _MUST_ have a prefix,
 *   - nodes from the same module as their __parent__ _MUST NOT_ have a prefix,
 *   - note that non-data nodes/schema-only node (choice, case, uses, input, output) are skipped and _MUST_ not be
 *     included in the path.
 *
 * Functions List
 * --------------
 * - ::lyd_find_xpath()
 * - ::lys_find_xpath()
 *
 * Path
 * ====
 *
 * The term path is used when a simplified (subset of) XPath is expected. Path is always a valid XPath but not
 * the other way around. In short, paths only identify a specific (set of) nodes based on their ancestors in the
 * schema. Predicates are allowed the same as for an [instance-identifier](https://tools.ietf.org/html/rfc7950#section-9.13).
 * Specifically, key values of a list, leaf-list value, or position of lists without keys can be used.
 *
 * Examples
 * --------
 *
 * - get __list__ instance with __key1__ of value __1__ and __key2__ of value __2__ (this can return more __list__ instances if there are more keys than __key1__ and __key2__)
 *
 *       /module-name:container/list[key1='1'][key2='2']
 *
 * - get __leaf-list__ instance with the value __val__
 *
 *       /module-name:container/leaf-list[.='val']
 *
 * - get __3rd list-without-keys__ instance with no keys defined
 *
 *       /module-name:container/list-without-keys[3]
 *
 * - get __aug-list__ with __aug-list-key__, which was added to __module-name__ from an augment module __augment-module__
 *
 *       /module-name:container/container2/augment-module:aug-cont/aug-list[aug-list-key='value']
 *
 * Functions List
 * --------------
 * - ::lyd_new_path()
 * - ::lyd_new_path2()
 * - ::lyd_path()
 * - ::lys_find_path()
 *
 */

/**
 * @defgroup trees Trees
 *
 * Generic macros, functions, etc. to work with both [schema](@ref schematree) and [data](@ref datatree) trees.
 *
 * @{
 */

/**
 * @brief Type (i.e. size) of the [sized array](@ref sizedarrays)'s size counter.
 *
 * To print the value via a print format, use LY_PRI_ARRAY_COUNT_TYPE specifier.
 */
#define LY_ARRAY_COUNT_TYPE uint64_t

/**
 * @brief Printing format specifier macro for LY_ARRAY_SIZE_TYPE values.
 */
#define LY_PRI_ARRAY_COUNT_TYPE PRIu64

/**
 * @brief Macro selector for other LY_ARRAY_* macros, do not use directly!
 */
#define LY_ARRAY_SELECT(_1, _2, NAME, ...) NAME

/**
 * @brief Helper macro to go through sized-arrays with a pointer iterator.
 *
 * Use with opening curly bracket (`{`).
 *
 * @param[in] ARRAY Array to go through
 * @param[in] TYPE Type of the records in the ARRAY
 * @param[out] ITER Iterating pointer to the item being processed in each loop
 */
#define LY_ARRAY_FOR_ITER(ARRAY, TYPE, ITER) \
    for (ITER = ARRAY; \
         (ARRAY) && ((void*)ITER - (void*)ARRAY)/(sizeof(TYPE)) < (*((LY_ARRAY_COUNT_TYPE*)(ARRAY) - 1)); \
         ITER = (void*)((TYPE*)ITER + 1))

/**
 * @brief Helper macro to go through sized-arrays with a numeric iterator.
 *
 * Use with opening curly bracket (`{`).
 *
 * To access an item with the INDEX value, use always LY_ARRAY_INDEX macro!
 *
 * @param[in] ARRAY Array to go through
 * @param[out] INDEX Iterating index of the item being processed in each loop
 */
#define LY_ARRAY_FOR_INDEX(ARRAY, INDEX) \
    for (INDEX = 0; \
         ARRAY && INDEX < (*((LY_ARRAY_COUNT_TYPE*)(ARRAY) - 1)); \
         ++INDEX)

/**
 * @brief Get the number of records in the ARRAY.
 *
 * Does not check if array exists!
 */
#define LY_ARRAY_COUNT(ARRAY) (*((LY_ARRAY_COUNT_TYPE*)(ARRAY) - 1))

/**
 * @brief Sized-array iterator (for-loop).
 *
 * Use with opening curly bracket (`{`).
 *
 * There are 2 variants:
 *
 *     LY_ARRAY_FOR(ARRAY, TYPE, ITER)<commit_msg>docs BUGFIX update description of LY_ARRAY_FOR_INDEX() macro<commit_after>/**
 * @file tree.h
 * @author <NAME> <<EMAIL>>
 * @brief libyang generic macros and functions to work with YANG schema or data trees.
 *
 * Copyright (c) 2019 CESNET, z.s.p.o.
 *
 * This source code is licensed under BSD 3-Clause License (the "License").
 * You may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://opensource.org/licenses/BSD-3-Clause
 */

#ifndef LY_TREE_H_
#define LY_TREE_H_

#include <inttypes.h>

#include "tree_data.h"

#ifdef __cplusplus
extern "C" {
#endif

/**
 * @page howtoXPath XPath Addressing
 *
 * Internally, XPath evaluation is performed on __when__ and __must__ conditions in the schema. For that almost
 * a full [XPath 1.0](http://www.w3.org/TR/1999/REC-xpath-19991116/) evaluator was implemented.
 * In YANG models you can also find paths identifying __augment__ targets, __leafref__ targets, and trivial paths in
 * __choice default__ and __unique__ statements argument. The exact format of all those paths can be found in the
 * relevant RFCs. Further will only be discussed paths that are used directly in libyang API functions.
 *
 * XPath
 * =====
 *
 * Generally, any xpath argument expects an expression similar to _when_ or _must_ as the same evaluator is used. As for
 * the format of any prefixes, the standardized JSON ([RFC 7951](https://tools.ietf.org/html/rfc7951#section-6.11))
 * was used. Summarized, xpath follows these conventions:
 *   - full XPath can be used, but only data nodes (node sets) will always be returned,
 *   - as per the specification, prefixes are actually __module names__,
 *   - also in the specification, for _absolute_ paths, the first (leftmost) node _MUST_ have a prefix,
 *   - for _relative_ paths, you specify the __context node__, which then acts as a parent for the first node in the path,
 *   - nodes always inherit their module (prefix) from their __parent node__ so whenever a node is from a different
 *     module than its parent, it _MUST_ have a prefix,
 *   - nodes from the same module as their __parent__ _MUST NOT_ have a prefix,
 *   - note that non-data nodes/schema-only node (choice, case, uses, input, output) are skipped and _MUST_ not be
 *     included in the path.
 *
 * Functions List
 * --------------
 * - ::lyd_find_xpath()
 * - ::lys_find_xpath()
 *
 * Path
 * ====
 *
 * The term path is used when a simplified (subset of) XPath is expected. Path is always a valid XPath but not
 * the other way around. In short, paths only identify a specific (set of) nodes based on their ancestors in the
 * schema. Predicates are allowed the same as for an [instance-identifier](https://tools.ietf.org/html/rfc7950#section-9.13).
 * Specifically, key values of a list, leaf-list value, or position of lists without keys can be used.
 *
 * Examples
 * --------
 *
 * - get __list__ instance with __key1__ of value __1__ and __key2__ of value __2__ (this can return more __list__ instances if there are more keys than __key1__ and __key2__)
 *
 *       /module-name:container/list[key1='1'][key2='2']
 *
 * - get __leaf-list__ instance with the value __val__
 *
 *       /module-name:container/leaf-list[.='val']
 *
 * - get __3rd list-without-keys__ instance with no keys defined
 *
 *       /module-name:container/list-without-keys[3]
 *
 * - get __aug-list__ with __aug-list-key__, which was added to __module-name__ from an augment module __augment-module__
 *
 *       /module-name:container/container2/augment-module:aug-cont/aug-list[aug-list-key='value']
 *
 * Functions List
 * --------------
 * - ::lyd_new_path()
 * - ::lyd_new_path2()
 * - ::lyd_path()
 * - ::lys_find_path()
 *
 */

/**
 * @defgroup trees Trees
 *
 * Generic macros, functions, etc. to work with both [schema](@ref schematree) and [data](@ref datatree) trees.
 *
 * @{
 */

/**
 * @brief Type (i.e. size) of the [sized array](@ref sizedarrays)'s size counter.
 *
 * To print the value via a print format, use LY_PRI_ARRAY_COUNT_TYPE specifier.
 */
#define LY_ARRAY_COUNT_TYPE uint64_t

/**
 * @brief Printing format specifier macro for LY_ARRAY_SIZE_TYPE values.
 */
#define LY_PRI_ARRAY_COUNT_TYPE PRIu64

/**
 * @brief Macro selector for other LY_ARRAY_* macros, do not use directly!
 */
#define LY_ARRAY_SELECT(_1, _2, NAME, ...) NAME

/**
 * @brief Helper macro to go through sized-arrays with a pointer iterator.
 *
 * Use with opening curly bracket (`{`).
 *
 * @param[in] ARRAY Array to go through
 * @param[in] TYPE Type of the records in the ARRAY
 * @param[out] ITER Iterating pointer to the item being processed in each loop
 */
#define LY_ARRAY_FOR_ITER(ARRAY, TYPE, ITER) \
    for (ITER = ARRAY; \
         (ARRAY) && ((void*)ITER - (void*)ARRAY)/(sizeof(TYPE)) < (*((LY_ARRAY_COUNT_TYPE*)(ARRAY) - 1)); \
         ITER = (void*)((TYPE*)ITER + 1))

/**
 * @brief Helper macro to go through sized-arrays with a numeric iterator.
 *
 * Use with opening curly bracket (`{`).
 *
 * The item on the current INDEX in the ARRAY can be accessed in a standard C way as ARRAY[INDEX].
 *
 * @param[in] ARRAY Array to go through
 * @param[out] INDEX Variable for the iterating index of the item being processed in each loop
 */
#define LY_ARRAY_FOR_INDEX(ARRAY, INDEX) \
    for (INDEX = 0; \
         ARRAY && INDEX < (*((LY_ARRAY_COUNT_TYPE*)(ARRAY) - 1)); \
         ++INDEX)

/**
 * @brief Get the number of records in the ARRAY.
 *
 * Does not check if array exists!
 */
#define LY_ARRAY_COUNT(ARRAY) (*((LY_ARRAY_COUNT_TYPE*)(ARRAY) - 1))

/**
 * @brief Sized-array iterator (for-loop).
 *
 * Use with opening curly bracket (`{`).
 *
 * There are 2 variants:
 *
 *     LY_ARRAY_FOR(ARRAY, TYPE, ITER)
{'fraction_non_alphanumeric': 0.11593565966423486, 'fraction_numerical': 0.01142656236266151, 'mean_word_length': 3.4619607843137254, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 11, 'https://': 6, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '701069', 'n_tokens_mistral': 3710, 'n_tokens_neox': 3569, 'n_words': 1349}