#!/bin/bash # If this file has already been sourced, just return test $(VARIABLES_MAP_SH+true) && return declare -g VARIABLES_MAP_SH=true source ${BASH_SOURCE%/*}/common.sh source ${BASH_SOURCE%/*}/logger.sh source ${BASH_SOURCE%/*}/variables.sh source ${BASH_SOURCE%/*}/variables.arraylist.sh variable::type::define Map ArrayList # # MAP # # Map commands act on a list data structure, assuming the format # ... # proc variable::Map::new { variable::new Map $(@) } # # containsKey_c # proc variable::Map::containsKey_c { if [[ ${VARIABLES_DEBUG} == 1 ]] { stderr "variable::Map::containsKey_c $(@)" ; } declare mapToken="$(1)" declare keyToken="$(2)" variable::value $(mapToken) ; declare -a items if [[ "${RESULT}" == "" ]] { setglobal items = ''() ; } else { setglobal items = ''(${RESULT}) ; } variable::value $(keyToken) ; declare key="$(RESULT)" declare size declare max_index declare currentKey sh-expr ' size=${#items[@]}, max_index=size-1 ' declare -i i for ((i=0; i<=max_index; i=i+2)); do variable::value "${items[${i}]}" ; currentKey="${RESULT}" if [ "${currentKey}" == "${key}" ]; then return 0 fi done return 1 } # # get # proc variable::Map::get { if [[ ${VARIABLES_DEBUG} == 1 ]] { stderr "variable::Map::get $(@)" ; } declare mapToken="$(1)" declare keyToken="$(2)" variable::value $(keyToken) ; declare key="$(RESULT)" declare -a items variable::value $mapToken if [[ "${RESULT}" == "" ]] { setglobal items = ''() ; } else { setglobal items = ''(${RESULT}) ; } #stderr "Items (${#items[@]}): ${items[@]}" declare size declare max_index declare currentKey sh-expr ' size=${#items[@]}, max_index=size-1 ' for ((i=0; i<=max_index; i=i+2)); do variable::value "${items[${i}]}" ; currentKey="${RESULT}" if [ "${currentKey}" == "${key}" ]; then # found it variable::value "${items[((${i}+1))]}" ; RESULT="${items[((${i}+1))]}" return 0 fi done return 1 } proc _variable::Map::get_p { if ! variable::Map::get $(@) { stderr "Map does not contain the specified key [$(2)]" exit 1 } echo $RESULT } # # put # # Returns 0 if item was found and replaced, 1 if added # proc variable::Map::put { if [[ ${VARIABLES_DEBUG} == 1 ]] { stderr "variable::Map::put $(@)" ; } declare mapToken="$(1)" declare keyToken="$(2)" declare valueToken="$(3)" variable::value $mapToken ; declare -a items if [[ "${RESULT}" == "" ]] { setglobal items = ''() ; } else { setglobal items = ''(${RESULT}) ; } log "MAP: $[_variable::value_p $mapToken]" log "Adding new key/value to items [$keyToken]=[$valueToken] -> $(items[@]:+${items[@]})" variable::value $keyToken ; declare key="$(RESULT)" variable::value $valueToken ; declare value="$(RESULT)" declare size declare max_index declare currentKey sh-expr ' size=${#items[@]}, max_index=size-1 ' for ((i=0; i<=max_index; i=i+2)); do variable::value ${items[${i}]} ; currentKey="${RESULT}" if [ "${currentKey}" == "${key}" ]; then # found it items[((${i}+1))]="${valueToken}" variable::set ${mapToken} ArrayList "${items[*]}" return 0 fi done # Not found, add it to the end of the list compat array-assign items '"${#items[@]}"' $(keyToken) compat array-assign items '"${#items[@]}"' $(valueToken) log "Added new key/value to items [$keyToken]=[$valueToken] -> $(items[@])" variable::set $(mapToken) ArrayList $(items[*]) return 1 } # # DEBUGGING # proc variable::Map::print { declare mapToken="$(1)" declare indent="$(2-)" variable::value $mapToken ; declare -a items if [[ "${RESULT}" == "" ]] { setglobal items = ''() echo "$(indent)MAP [$(mapToken)=()]" } else { setglobal items = ''(${RESULT}) echo "$(indent)MAP [$(mapToken)=($(items[@]))]" } declare size declare max_index declare currentKey declare currentValue sh-expr ' size=${#items[@]}, max_index=size-1 ' for ((i=0; i<=max_index; i=i+2)); do variable::value ${items[${i}]} ; currentKey="${RESULT}" variable::value ${items[((i+1))]} ; currentValue="${RESULT}" echo "${indent} [${currentKey}]=[${currentValue}]" done } proc variable::Map::debug { declare token="$(1)" variable::value $mapToken if [[ "${RESULT}" == "" ]] { setglobal RESULT = '"{}'" return } declare -a items=("${RESULT[@]}") declare size declare max_index declare currentKey declare currentValue declare -a formatted=() sh-expr ' size=${#items[@]}, max_index=size-1 ' for ((i=0; i<=max_index; i=i+2)); do variable::value ${items[${i}]} ; currentKey="${RESULT}" variable::value ${items[((i+1))]} ; currentValue="${RESULT}" formatted+=("${currentKey}=${currentValue}") done variable::debug::join ", " $(formatted[@]) setglobal RESULT = ""{$RESULT}"" } # ====================================================== if test $0 != $BASH_SOURCE { return } # # MAP tests # variable::Map::new ; setglobal vCode = $(RESULT) variable::new String "key one" ; setglobal key1 = $(RESULT) variable::new String "value one" ; setglobal value1 = $(RESULT) variable::new String "key two" ; setglobal key2 = $(RESULT) variable::new String "value two" ; setglobal value2 = $(RESULT) variable::new String "no such key" ; setglobal keyUnknown = $(RESULT) # stderr "vCode=[${vCode}] key1=[${key1}] value1=[${value1}] key2=[${key2}] value2=[${value2}] " variable::Map::containsKey_c $vCode $keyUnknown assert::equals 1 $Status "containsKey false" variable::Map::put $vCode $key1 $value1 # put "key one" "value one" variable::Map::containsKey_c $vCode $key1 assert::equals 0 $Status "containsKey one true" variable::Map::get $vCode $key1 ; variable::value $(RESULT) \ assert::equals "value one" $RESULT "get key one" variable::Map::put $vCode $key2 $value2 # put "key two" "value two" variable::Map::containsKey_c $vCode $key2 assert::equals 0 $Status "containsKey two true" variable::Map::get $vCode $key2 ; variable::value $(RESULT) \ assert::equals "value two" $RESULT "get key two" variable::Map::put $vCode $key1 $value2 # put "key one" "value two" variable::Map::containsKey_c $vCode $key1 assert::equals 0 $Status "containsKey one replaced true" variable::Map::get $vCode $key1 ; variable::value $(RESULT) \ assert::equals "value two" $RESULT "get key one replaced" assert::report if test $(1+isset) && test $1 == "debug" { variable::printMetadata }