<commit_before>/*
 *******************************************************************************************************
 * DESIGN CONSIDERATIONS:
 *******************************************************************************************************
 *      Looking at the earlier version of the code, we found similarities at
 *      various levels of code. Only changes were the naming terminologies for
 *      different methods, but the overall structuring and orchestration was
 *      pretty much similar at various levels.
 *
 *      With this in mind, the immediate thought process in mind was to work
 *      with macros and its concatenation with '##'. It will help us to generate
 *      similar code at various levels, but from the same location. Advantages
 *      of this approach are:
 *      1. Modularity of the code
 *      2. Code maintenance is easy as nomenclature and set of methods to write
 *          is unified and generic for all new enhancements.
 *      3. Reduces number of lines of visible code and easy to understand for
 *          developers once they get acquainted with the terminologies used.
 *
 *      Disadvantages:
 *      1. Macros are not debug friendly, but the function calls called within
 *          the macros can be debugged.
 *      2. Macro backbone should be stable enough. Then any issue occurred in
 *          the future can be debugged at the function level as we are trusting
 *          the backbone.
 *      3. Developers need to have clear understanding about the expansion of
 *          macros and location of their function calls which will be generated
 *          during the expansion with '##'.
 *
 *          (In case, if developer wants to see the expanded code of macro,
 *          gcc provides an option flag '-E'.
 *          This can be updated before the ".c" file name in Makefile.
 *          The ".c" file should have the Macro call which developer expects to
 *          expand.)
 *
 *******************************************************************************************************
 *
 *  Here is the overall view of architecture terminologies used to write macros:
 *  level => It represents the processing level in the code flow and can take
 *          following values. e.g. DEFAULT, MAP, LIST.
 *      DEFAULT represents that we are processing Record.
 *      MAP represents that we are processing Map.
 *      LIST represents that we are processing List.
 *
 *  method => It represents the method we are processing. viz. GET OR PUT.
 *           It can take any other method values in future sharing similar
 *           infrastructure.
 *
 *  action => It represents the action to be taken on that 'level' for that
 *           'method'.
 *           e.g. ASSOC, APPEND, INDEX
 *           ASSOC => All set(PUT) and/or assoc(GET) operations in Record and
 *              Map(with string keys for GET) are represented by action 'ASSOC'.
 *           INDEX => All assoc(GET) operations in Map(with integer keys for GET)
 *              are represented by action 'INDEX'.
 *           APPEND => All append(PUT) and/or get next (GET) operations in List
 *              are represented by action 'APPEND'.
 *
 *  datatype => It represents the actual data type which needs to be processed
 *  at particular 'level' for particular 'method' with particular 'action'.
 *  The datatypes will vary for GET as well as PUT method.
 *  The data types in GET method are inherited from the data types of CSDK.
 *  The data types in PUT method corresponds to the PHP data types.
 *
 *  Method name call will look like following as per the specification::
 *  "AEROSPIKE_##level_##method_##action_##datatype"
 *
 *  It can be derived to following names,
 *  for example,
 *  
 *  AEROSPIKE_MAP_GET_ASSOC_STRING
 *  AEROSPIKE_LIST_PUT_APPEND_INTEGER
 *  AEROSPIKE_DEFAULT_GET_ASSOC_MAP
 *
 *  Special Case:
 *  AEROSPIKE_##level##_PUT_##action##_ARRAY
 *
 *  In the PHP code, Map and List are interpreted as an Array.
 *  In order to differentiate the incoming Array, and categorize them into
 *  List and Map, we have special implementation inside the switch case of Array
 *  to handle this case for method 'PUT'.
 *
 *******************************************************************************************************
 */

#ifndef __AEROSPIKE_TRANSFORM_H__
#define __AEROSPIKE_TRANSFORM_H__
#include "aerospike/as_boolean.h"

#define AS_LIST_DATATYPE as_list
#define AS_MAP_DATATYPE as_map

#define AS_MAP_FOREACH as_map_foreach
#define AS_LIST_FOREACH as_list_foreach

#define AS_MAP_FOREACH_CALLBACK as_map_foreach_callback
#define AS_LIST_FOREACH_CALLBACK as_list_foreach_callback

#define FETCH_VALUE_GET(val) as_val_type(val)
#define FETCH_VALUE_PUT(val) Z_TYPE_PP(val)

/*
 * Macro Expansion for data type LONG for method PUT:
 * ************************************************************************
 * => For level = DEFAULT, action = ASSOC
 * ************************************************************************
 * case IS_LONG:
 *      AEROSPIKE_DEFAULT_PUT_ASSOC_LONG(
 *              key, value, array, static_pool, serializer_policy, err)));
 *      if (AEROSPIKE_OK != (err->code)) {
 *          goto label;
 *      }
 *      break;
 * ************************************************************************
 * => For level = MAP, action = ASSOC
 * ************************************************************************
 * case IS_LONG:
 *      AEROSPIKE_MAP_PUT_ASSOC_LONG(
 *              key, value, array, static_pool, serializer_policy, err)));
 *      if (AEROSPIKE_OK != (err->code)) {
 *          goto label;
 *      }
 *      break;
 * ************************************************************************
 * => For level = LIST, action = APPEND
 * ************************************************************************
 * case IS_LONG:
 *      AEROSPIKE_LIST_PUT_APPEND_LONG(
 *              key, value, array, static_pool, serializer_policy, err)));
 *      if (AEROSPIKE_OK != (err->code)) {
 *          goto label;
 *      }
 *      break;
 * ************************************************************************
 */
#define EXPAND_CASE_PUT(level, method, action, datatype, key, value,             \
        array, err, static_pool, label, serializer_policy)                       \
    case IS_##datatype:                                                          \
        AEROSPIKE_##level##_##method##_##action##_##datatype(                    \
                key, value, array, static_pool, serializer_policy,               \
                err);                                                            \
        if (AEROSPIKE_OK != (err->code)) {                                       \
            goto label;                                                          \
        }                                                                        \
        break;

/*
 * Macro Expansion for data type STRING for method GET:
 * ************************************************************************
 * => For level = DEFAULT, action = ASSOC
 * ************************************************************************
 * case AS_STRING:
 *      AEROSPIKE_DEFAULT_GET_ASSOC_STRING(
 *              key, value, array, static_pool, err);
 *      if (AEROSPIKE_OK != ((as_error *)err)->code) {
 *          goto label;
 *      }
 *      break;
 * ************************************************************************
 * => For level = MAP, action = ASSOC
 * ************************************************************************
 * case AS_STRING:
 *      AEROSPIKE_MAP_GET_ASSOC_STRING(
 *              key, value, array, static_pool, err);
 *      if (AEROSPIKE_OK != ((as_error *)err)->code) {
 *          goto label;
 *      }
 *      break;
 * ************************************************************************
 * => For level = LIST, action = APPEND
 * ************************************************************************
 * case AS_STRING:
 *      AEROSPIKE_LIST_GET_APPEND_STRING(
 *              key, value, array, static_pool, err);
 *      if (AEROSPIKE_OK != ((as_error *)err)->code) {
 *          goto label;
 *      }
 *      break;
 * ************************************************************************
 */
#define EXPAND_CASE_GET(level, method, action, datatype, key, value,           \
        array, err, static_pool, label)                                        \
    case AS_##datatype:                                                        \
        AEROSPIKE_##level##_##method##_##action##_##datatype(                  \
                key, value, array, static_pool, err);                          \
        if (AEROSPIKE_OK != ((as_error *)err)->code) {                         \
            goto label;                                                        \
        }                                                                      \
        break;

/*
 *******************************************************************************************************
 * This is the main walker which will walk over all datatypes for all actions in
 * all methods at all levels.
 * You will find the wrapper macros over this one for particular tasks.
 *******************************************************************************************************
 */
#define AEROSPIKE_WALKER_SWITCH_CASE(method, level, action,                       \
        err, static_pool, key, value, array, label, serializer_policy)            \
        AEROSPIKE_WALKER_SWITCH_CASE_##method(method, level, action,              \
                err, static_pool, key, value, array, label, serializer_policy)

#define AEROSPIKE_HASHMAP_BUCKET_SIZE     32
#define AEROSPIKE_ASLIST_BLOCK_SIZE       0

/*
 *******************************************************************************************************
 * For the case of method PUT, we need to deduce the key for Record as well as
 * Map when we iterate over array sent by PHP.
 *
 * These methods will generalise the key generation.
 *******************************************************************************************************
 */
#define AS_DEFAULT_KEY(hashtable, key, key_len, index, pointer,                \
        static_pool, err, label)                                               \
            zend_hash_get_current_key_ex(hashtable, (char **)&key, &key_len,   \
                    &index, 0, &pointer);                                      \
            if ((char*)key == NULL) {                                          \
                err->code = AEROSPIKE_ERR_CLIENT;                              \
                goto label;                                                    \
            }                                                                  \
            if (key_len > AS_BIN_NAME_MAX_LEN) {                               \
                err->code = AEROSPIKE_ERR_BIN_NAME;                            \
                goto label;                                                    \
            }

#define AS_LIST_KEY(hashtable, key, key_len, index, pointer, static_pool,      \
        err, label)                                                            \

#define AS_MAP_KEY(hashtable, key, key_len, index, pointer, static_pool,       \
        err, label)                                                            \
do {                                                                           \
    char *local_key;                                                           \
    uint key_type = zend_hash_get_current_key_ex(hashtable,                    \
            (char **)&local_key, &key_len, &index, 0, &pointer);               \
    if (key_type == HASH_KEY_IS_STRING) {                                      \
        as_string *map_str;                                                    \
        GET_STR_POOL(map_str, static_pool, err, label);                        \
        as_string_init(map_str, local_key, false);                             \
        key = (as_val*) (map_str);                                             \
    } else if (key_type == HASH_KEY_IS_LONG) {                                 \
        as_integer *map_int;                                                   \
        GET_INT_POOL(map_int, static_pool, err, label);                        \
        as_integer_init(map_int, index);                                       \
        key = (as_val*) map_int;                                               \
    } else {                                                                   \
        PHP_EXT_SET_AS_ERR(err, AEROSPIKE_ERR, "Invalid Key type for Map");    \
        goto label;                                                            \
    }                                                                          \
} while(0);

/* <commit_msg>Fix for the 14th character<commit_after>/*
 *******************************************************************************************************
 * DESIGN CONSIDERATIONS:
 *******************************************************************************************************
 *      Looking at the earlier version of the code, we found similarities at
 *      various levels of code. Only changes were the naming terminologies for
 *      different methods, but the overall structuring and orchestration was
 *      pretty much similar at various levels.
 *
 *      With this in mind, the immediate thought process in mind was to work
 *      with macros and its concatenation with '##'. It will help us to generate
 *      similar code at various levels, but from the same location. Advantages
 *      of this approach are:
 *      1. Modularity of the code
 *      2. Code maintenance is easy as nomenclature and set of methods to write
 *          is unified and generic for all new enhancements.
 *      3. Reduces number of lines of visible code and easy to understand for
 *          developers once they get acquainted with the terminologies used.
 *
 *      Disadvantages:
 *      1. Macros are not debug friendly, but the function calls called within
 *          the macros can be debugged.
 *      2. Macro backbone should be stable enough. Then any issue occurred in
 *          the future can be debugged at the function level as we are trusting
 *          the backbone.
 *      3. Developers need to have clear understanding about the expansion of
 *          macros and location of their function calls which will be generated
 *          during the expansion with '##'.
 *
 *          (In case, if developer wants to see the expanded code of macro,
 *          gcc provides an option flag '-E'.
 *          This can be updated before the ".c" file name in Makefile.
 *          The ".c" file should have the Macro call which developer expects to
 *          expand.)
 *
 *******************************************************************************************************
 *
 *  Here is the overall view of architecture terminologies used to write macros:
 *  level => It represents the processing level in the code flow and can take
 *          following values. e.g. DEFAULT, MAP, LIST.
 *      DEFAULT represents that we are processing Record.
 *      MAP represents that we are processing Map.
 *      LIST represents that we are processing List.
 *
 *  method => It represents the method we are processing. viz. GET OR PUT.
 *           It can take any other method values in future sharing similar
 *           infrastructure.
 *
 *  action => It represents the action to be taken on that 'level' for that
 *           'method'.
 *           e.g. ASSOC, APPEND, INDEX
 *           ASSOC => All set(PUT) and/or assoc(GET) operations in Record and
 *              Map(with string keys for GET) are represented by action 'ASSOC'.
 *           INDEX => All assoc(GET) operations in Map(with integer keys for GET)
 *              are represented by action 'INDEX'.
 *           APPEND => All append(PUT) and/or get next (GET) operations in List
 *              are represented by action 'APPEND'.
 *
 *  datatype => It represents the actual data type which needs to be processed
 *  at particular 'level' for particular 'method' with particular 'action'.
 *  The datatypes will vary for GET as well as PUT method.
 *  The data types in GET method are inherited from the data types of CSDK.
 *  The data types in PUT method corresponds to the PHP data types.
 *
 *  Method name call will look like following as per the specification::
 *  "AEROSPIKE_##level_##method_##action_##datatype"
 *
 *  It can be derived to following names,
 *  for example,
 *  
 *  AEROSPIKE_MAP_GET_ASSOC_STRING
 *  AEROSPIKE_LIST_PUT_APPEND_INTEGER
 *  AEROSPIKE_DEFAULT_GET_ASSOC_MAP
 *
 *  Special Case:
 *  AEROSPIKE_##level##_PUT_##action##_ARRAY
 *
 *  In the PHP code, Map and List are interpreted as an Array.
 *  In order to differentiate the incoming Array, and categorize them into
 *  List and Map, we have special implementation inside the switch case of Array
 *  to handle this case for method 'PUT'.
 *
 *******************************************************************************************************
 */

#ifndef __AEROSPIKE_TRANSFORM_H__
#define __AEROSPIKE_TRANSFORM_H__
#include "aerospike/as_boolean.h"

#define AS_LIST_DATATYPE as_list
#define AS_MAP_DATATYPE as_map

#define AS_MAP_FOREACH as_map_foreach
#define AS_LIST_FOREACH as_list_foreach

#define AS_MAP_FOREACH_CALLBACK as_map_foreach_callback
#define AS_LIST_FOREACH_CALLBACK as_list_foreach_callback

#define FETCH_VALUE_GET(val) as_val_type(val)
#define FETCH_VALUE_PUT(val) Z_TYPE_PP(val)

/*
 * Macro Expansion for data type LONG for method PUT:
 * ************************************************************************
 * => For level = DEFAULT, action = ASSOC
 * ************************************************************************
 * case IS_LONG:
 *      AEROSPIKE_DEFAULT_PUT_ASSOC_LONG(
 *              key, value, array, static_pool, serializer_policy, err)));
 *      if (AEROSPIKE_OK != (err->code)) {
 *          goto label;
 *      }
 *      break;
 * ************************************************************************
 * => For level = MAP, action = ASSOC
 * ************************************************************************
 * case IS_LONG:
 *      AEROSPIKE_MAP_PUT_ASSOC_LONG(
 *              key, value, array, static_pool, serializer_policy, err)));
 *      if (AEROSPIKE_OK != (err->code)) {
 *          goto label;
 *      }
 *      break;
 * ************************************************************************
 * => For level = LIST, action = APPEND
 * ************************************************************************
 * case IS_LONG:
 *      AEROSPIKE_LIST_PUT_APPEND_LONG(
 *              key, value, array, static_pool, serializer_policy, err)));
 *      if (AEROSPIKE_OK != (err->code)) {
 *          goto label;
 *      }
 *      break;
 * ************************************************************************
 */
#define EXPAND_CASE_PUT(level, method, action, datatype, key, value,             \
        array, err, static_pool, label, serializer_policy)                       \
    case IS_##datatype:                                                          \
        AEROSPIKE_##level##_##method##_##action##_##datatype(                    \
                key, value, array, static_pool, serializer_policy,               \
                err);                                                            \
        if (AEROSPIKE_OK != (err->code)) {                                       \
            goto label;                                                          \
        }                                                                        \
        break;

/*
 * Macro Expansion for data type STRING for method GET:
 * ************************************************************************
 * => For level = DEFAULT, action = ASSOC
 * ************************************************************************
 * case AS_STRING:
 *      AEROSPIKE_DEFAULT_GET_ASSOC_STRING(
 *              key, value, array, static_pool, err);
 *      if (AEROSPIKE_OK != ((as_error *)err)->code) {
 *          goto label;
 *      }
 *      break;
 * ************************************************************************
 * => For level = MAP, action = ASSOC
 * ************************************************************************
 * case AS_STRING:
 *      AEROSPIKE_MAP_GET_ASSOC_STRING(
 *              key, value, array, static_pool, err);
 *      if (AEROSPIKE_OK != ((as_error *)err)->code) {
 *          goto label;
 *      }
 *      break;
 * ************************************************************************
 * => For level = LIST, action = APPEND
 * ************************************************************************
 * case AS_STRING:
 *      AEROSPIKE_LIST_GET_APPEND_STRING(
 *              key, value, array, static_pool, err);
 *      if (AEROSPIKE_OK != ((as_error *)err)->code) {
 *          goto label;
 *      }
 *      break;
 * ************************************************************************
 */
#define EXPAND_CASE_GET(level, method, action, datatype, key, value,           \
        array, err, static_pool, label)                                        \
    case AS_##datatype:                                                        \
        AEROSPIKE_##level##_##method##_##action##_##datatype(                  \
                key, value, array, static_pool, err);                          \
        if (AEROSPIKE_OK != ((as_error *)err)->code) {                         \
            goto label;                                                        \
        }                                                                      \
        break;

/*
 *******************************************************************************************************
 * This is the main walker which will walk over all datatypes for all actions in
 * all methods at all levels.
 * You will find the wrapper macros over this one for particular tasks.
 *******************************************************************************************************
 */
#define AEROSPIKE_WALKER_SWITCH_CASE(method, level, action,                       \
        err, static_pool, key, value, array, label, serializer_policy)            \
        AEROSPIKE_WALKER_SWITCH_CASE_##method(method, level, action,              \
                err, static_pool, key, value, array, label, serializer_policy)

#define AEROSPIKE_HASHMAP_BUCKET_SIZE     32
#define AEROSPIKE_ASLIST_BLOCK_SIZE       0

/*
 *******************************************************************************************************
 * For the case of method PUT, we need to deduce the key for Record as well as
 * Map when we iterate over array sent by PHP.
 *
 * These methods will generalise the key generation.
 *******************************************************************************************************
 */
#define AS_DEFAULT_KEY(hashtable, key, key_len, index, pointer,                \
        static_pool, err, label)                                               \
            zend_hash_get_current_key_ex(hashtable, (char **)&key, &key_len,   \
                    &index, 0, &pointer);                                      \
            if ((char*)key == NULL) {                                          \
                err->code = AEROSPIKE_ERR_CLIENT;                              \
                goto label;                                                    \
            }                                                                  \
            if (key_len > (AS_BIN_NAME_MAX_LEN + 1)) {                               \
                err->code = AEROSPIKE_ERR_BIN_NAME;                            \
                goto label;                                                    \
            }

#define AS_LIST_KEY(hashtable, key, key_len, index, pointer, static_pool,      \
        err, label)                                                            \

#define AS_MAP_KEY(hashtable, key, key_len, index, pointer, static_pool,       \
        err, label)                                                            \
do {                                                                           \
    char *local_key;                                                           \
    uint key_type = zend_hash_get_current_key_ex(hashtable,                    \
            (char **)&local_key, &key_len, &index, 0, &pointer);               \
    if (key_type == HASH_KEY_IS_STRING) {                                      \
        as_string *map_str;                                                    \
        GET_STR_POOL(map_str, static_pool, err, label);                        \
        as_string_init(map_str, local_key, false);                             \
        key = (as_val*) (map_str);                                             \
    } else if (key_type == HASH_KEY_IS_LONG) {                                 \
        as_integer *map_int;                                                   \
        GET_INT_POOL(map_int, static_pool, err, label);                        \
        as_integer_init(map_int, index);                                       \
        key = (as_val*) map_int;                                               \
    } else {                                                                   \
        PHP_EXT_SET_AS_ERR(err, AEROSPIKE_ERR, "Invalid Key type for Map");    \
        goto label;                                                            \
    }                                                                          \
} while(0);

/* 
{'fraction_non_alphanumeric': 0.20865821017106947, 'fraction_numerical': 0.001047364133597114, 'mean_word_length': 1.8227307565969562, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 51, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 117, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6869988', 'n_tokens_mistral': 6133, 'n_tokens_neox': 5837, 'n_words': 1859}