function mgcohashtable::_overloadBracketsRightSide, isRange, $
ss1, ss2, ss3, ss4, $
ss5, ss6, ss7, ss8
compile_opt strictarr
on_error, 2
if (isRange[0]) then begin
message, 'range not allowed'
endif else begin
value = self->get(ss1, found=found)
if (~found) then message, string(ss1, format='(%"element %s not found")')
return, value
endelse
end
pro mgcohashtable::_overloadBracketsLeftSide, objref, value, isRange, $
ss1, ss2, ss3, ss4, $
ss5, ss6, ss7, ss8
compile_opt strictarr
if (isRange[0]) then begin
message, 'range not allowed'
endif else begin
self->put, ss1, value
endelse
end
function mgcohashtable::_overloadPlus, left, right
compile_opt strictarr
on_error, 2
left->getProperty, key_type=leftKeyType, value_type=leftValueType
right->getProperty, key_type=rightKeyType, value_type=rightValueType
if (leftKeyType ne rightKeyType) then begin
message, 'cannot concatenate hash tables with different key types'
endif
if (leftValueType ne rightValueType) then begin
message, 'cannot concatenate hash tables with different value types'
endif
result = obj_new('MGcoHashTable', key_type=leftKeyType, value_type=leftValueType)
result->update, left
result->update, right
return, result
end
pro mgcohashtable::_findKeyPos, key, hcode, keyIndex
compile_opt strictarr
hcode = self->_calcHashCode(key) mod self.arraySize
keyIndex = 0L
iter = (*self.keyArray)[hcode]->iterator()
while (iter->hasNext()) do begin
element = iter->next()
if (element eq key) then break
keyIndex++
endwhile
obj_destroy, iter
end
function mgcohashtable::_findNextKey, key, done=done
compile_opt strictarr
if (n_elements(key) eq 0L) then begin
hcode = 0
keyIndex = -1
endif else begin
self->_findKeyPos, key, hcode, keyIndex
endelse
while (1B) do begin
keyIndex++
if (~obj_valid((*self.keyArray)[hcode]) $
|| keyIndex ge ((*self.keyArray)[hcode])->count()) then begin
hcode++
keyIndex = -1L
if (hcode ge self.arraySize) then begin
done = 1B
return, -1L
endif
continue
endif
done = 0
return, ((*self.keyArray)[hcode])->get(position=keyIndex)
endwhile
end
function mgcohashtable::_overloadForeach, value, key
compile_opt strictarr
key = self->_findNextKey(key, done=done)
if (done) then begin
return, 0
endif else begin
value = self->get(key)
return, 1
endelse
end
function mgcohashtable::_overloadPrint
compile_opt strictarr
keys = self->keys(count=count)
values = self->values()
if (count eq 0) then return, ''
output = strarr(1, count)
for i = 0L, count - 1L do begin
if (size(values[i], /type) eq 11) then begin
if (obj_isa(values[i], 'IDL_Object') && obj_hasmethod(values[i], '_overloadPrint')) then begin
_val = (values[i])->_overloadPrint()
endif else begin
help, values[i], output=output
tokens = strsplit(output, /extract)
_val = tokens[3]
endelse
endif else _val = values[i]
if (size(keys[i], /type) eq 11) then begin
if (obj_isa(keys[i], 'IDL_Object') && obj_hasmethod(keys[i], '_overloadPrint')) then begin
_key = (keys[i])->_overloadPrint()
endif else begin
help, keys[i], output=output
tokens = strsplit(output, /extract)
_key = tokens[3]
endelse
endif else _key = keys[i]
output[i] = string(_key, _val, format='(%"%s -> %s")')
endfor
return, output
end
function mgcohashtable::_overloadHelp, varname
compile_opt strictarr
all_types = ['UNDEFINED', 'BYTE', 'INT', 'LONG', 'FLOAT', 'DOUBLE', $
'COMPLEX', 'STRING', 'STRUCTURE', 'DCOMPLEX', 'POINTER', $
'OBJREF', 'UINT', 'ULONG', 'LONG64', 'ULONG64']
keyType = all_types[self.keyType]
valueType = all_types[self.valueType]
type = string(keyType, valueType, format='(%"%s->%s")')
specs = string(self->count(), '(%"MGcoHashTable[%d]")')
return, string(varname, type, specs, format='(%"%-15s %-20s = %s")')
end
function mgcohashtable::_overloadSize
compile_opt strictarr
return, self->count()
end
pro mgcohashtable::getProperty, key_type=keyType, value_type=valueType, $
count=count
compile_opt strictarr
if (arg_present(keyType)) then keyType = self.keyType
if (arg_present(valueType)) then valueType = self.valueType
if (arg_present(count)) then count = self->count()
end
function mgcohashtable::_getHistogram
compile_opt strictarr
on_error, 2
hist = lonarr(self.arraySize)
for i = 0L, self.arraySize - 1L do begin
hist[i] = obj_valid((*self.keyArray)[i]) $
? (*self.keyArray)[i]->count() $
: 0L
endfor
return, hist
end
pro mgcohashtable::print, lun
compile_opt strictarr
myLun = n_elements(lun) eq 0 ? -1L : lun
keys = self->keys(count=count)
values = self->values()
if (count gt 0) then begin
for i = 0L, count - 1L do begin
printf, myLun, keys[i] + ' -> ' + values[i]
endfor
endif
end
function mgcohashtable::keys, count=count
compile_opt strictarr
on_error, 2
count = self->count()
if (count le 0L) then return, -1L
keyArray = make_array(type=self.keyType, count, /nozero)
idx = 0L
for i = 0L, self.arraySize - 1L do begin
list = (*self.keyArray)[i]
if (obj_valid(list)) then begin
keyArray[idx] = list->get(/all)
idx += list->count()
endif
endfor
return, keyArray
end
function mgcohashtable::values, count=count
compile_opt strictarr
on_error, 2
count = self->count()
if (count le 0L) then return, -1L
valueArray = make_array(type=self.valueType, count, /nozero)
idx = 0L
for i = 0, self.arraySize - 1 do begin
list = (*self.valueArray)[i]
if (obj_valid(list)) then begin
valueArray[idx] = list->get(/all)
idx += list->count()
endif
endfor
return, valueArray
end
function mgcohashtable::_calcHashCode, key
compile_opt strictarr
on_error, 2
errorNumber = 0L
catch, errorNumber
if (errorNumber) then begin
catch, /cancel
return, 0UL
endif
type = size(key, /type)
case type of
0 : return, 0UL
1 : return, ulong(key)
2 : return, ulong(key)
3 : return, ulong(key)
4 : return, ulong(key)
5 : return, ulong(key)
6 : return, ulong(abs(key))
7 : begin
ascii = ulong(byte(key))
total = 0UL
for i = 0, n_elements(ascii) - 1 do begin
total = total * 37UL + ascii[i]
endfor
return, total
end
8 : begin
hashCode = 0UL
for tagIndex = 0, n_tags(key) - 1 do begin
hashCode +=self->_calcHashCode(key.(tagIndex))
endfor
return, hashCode
end
9 : return, ulong(abs(key))
10 : return, ptr_valid(key) ? self->_calcHashCode(*key) : 0UL
11 : return, obj_valid(key) ? key->hashCode() : 0UL
12 : return, ulong(key)
13 : return, ulong(key)
14 : return, ulong(key)
15 : return, ulong(key)
endcase
end
function mgcohashtable::get, key, default=default, found=found
compile_opt strictarr
on_error, 2
hcode = self->_calcHashCode(key) mod self.arraySize
found = 0B
keyIndex = 0L
if (~obj_valid((*self.keyArray)[hcode])) then begin
found = 0B
return, n_elements(default) eq 0L ? -1L : default
endif
iter = (*self.keyArray)[hcode]->iterator()
while (iter->hasNext()) do begin
element = iter->next()
if (element eq key) then begin
found = 1B
break
endif
keyIndex++
endwhile
obj_destroy, iter
return, found $
? (*self.valueArray)[hcode]->get(position=keyIndex) $
: (n_elements(default) eq 0L ? -1L : default)
end
function mgcohashtable::setdefault, key, default=default
compile_opt strictarr
value = self->get(key, default=default, found=found)
if (~found || n_elements(default) gt 0L) then self->put, key, value
return, value
end
pro mgcohashtable::remove, key, all=all, found=found
compile_opt strictarr
on_error, 2
if (keyword_set(all)) then begin
keys = self->keys(count=nkeys)
if (nkeys gt 0L) then begin
for k = 0L, nkeys - 1L do begin
self->remove, keys[k]
endfor
endif
found = nkeys gt 0L
return
endif
hcode = self->_calcHashCode(key) mod self.arraySize
found = 0B
keyIndex = 0L
if (~obj_valid((*self.keyArray)[hcode])) then begin
found = 0B
return
endif
iter = (*self.keyArray)[hcode]->iterator()
while (iter->hasNext()) do begin
element = iter->next()
if (element eq key) then begin
found = 1B
break
endif
keyIndex++
endwhile
obj_destroy, iter
if (found) then begin
(*self.keyArray)[hcode]->remove, position=keyIndex
(*self.valueArray)[hcode]->remove, position=keyIndex
endif
end
pro mgcohashtable::update, hashtable
compile_opt strictarr
keys = hashtable->keys(count=nkeys)
for i = 0L, nkeys - 1L do self->put, keys[i], hashtable->get(keys[i])
end
pro mgcohashtable::put, key, value, found=found
compile_opt strictarr
on_error, 2
if (n_params() ne 2L) then message, 'put method requires key and value'
hcode = self->_calcHashCode(key) mod self.arraySize
if (obj_valid((*self.keyArray)[hcode])) then begin
found = 0B
keyIndex = 0L
iter = (*self.keyArray)[hcode]->iterator()
while (iter->hasNext()) do begin
el = iter->next()
if (el eq key) then begin
found = 1
break
endif
keyIndex++
endwhile
obj_destroy, iter
if (found) then begin
(*self.valueArray)[hcode]->remove, position=keyIndex
(*self.valueArray)[hcode]->add, value, position=keyIndex
endif else begin
(*self.keyArray)[hcode]->add, key
(*self.valueArray)[hcode]->add, value
endelse
endif else begin
found = 0
if (self.keyType eq 8) then begin
if (~ptr_valid(self.keyExample)) then self.keyExample = ptr_new(key)
(*self.keyArray)[hcode] $
= obj_new('MGcoArrayList', example=*self.keyExample, block_size=5)
endif else begin
(*self.keyArray)[hcode] $
= obj_new('MGcoArrayList', type=self.keyType, block_size=5)
endelse
(*self.keyArray)[hcode]->add, key
if (self.valueType eq 8) then begin
if (~ptr_valid(self.valueExample)) then self.valueExample = ptr_new(value)
(*self.valueArray)[hcode] $
= obj_new('MGcoArrayList', example=*self.valueExample, block_size=5)
endif else begin
(*self.valueArray)[hcode] $
= obj_new('MGcoArrayList', type=self.valueType, block_size=5)
endelse
(*self.valueArray)[hcode]->add, value
endelse
end
function mgcohashtable::count
compile_opt strictarr
on_error, 2
size = 0L
for keyIndex = 0L, n_elements(*self.keyArray) - 1L do begin
size += obj_valid((*self.keyArray)[keyIndex]) $
? (*self.keyArray)[keyIndex]->count() $
: 0L
endfor
return, size
end
function mgcohashtable::isEmpty
compile_opt strictarr
on_error, 2
for keyIndex = 0L, n_elements(*self.keyArray) - 1L do begin
testList = (*self.keyArray)[keyIndex]
if (obj_valid(testList)) then begin
if (testList->count() gt 0) then return, 0
endif
endfor
return, 1B
end
pro mgcohashtable::cleanup
compile_opt strictarr
on_error, 2
obj_destroy, [*self.keyArray, *self.valueArray]
ptr_free, self.keyExample, self.valueExample, self.keyArray, self.valueArray
self->IDL_Object::cleanup
end
function mgcohashtable::init, array_size=arraySize, $
key_type=keyType, $
value_type=valueType, $
key_example=keyExample, $
value_example=valueExample
compile_opt strictarr
on_error, 2
self.arraySize = n_elements(arraySize) eq 0 ? 101L : arraySize
if (n_elements(keyType) eq 0) then begin
if (n_elements(keyExample) eq 0) then begin
message, 'type of key must be defined with KEY_TYPE or KEY_EXAMPLE'
endif else begin
self.keyType = size(keyExample, /type)
endelse
endif else begin
self.keyType = keyType
endelse
if (n_elements(valueType) eq 0) then begin
if (n_elements(valueExample) eq 0) then begin
message, 'type of value must be defined with VALUE_TYPE or VALUE_EXAMPLE'
endif else begin
self.valueType = size(valueExample, /type)
endelse
endif else begin
self.valueType = valueType
endelse
self.keyArray = ptr_new(objarr(self.arraySize))
self.valueArray = ptr_new(objarr(self.arraySize))
return, 1
end
pro mgcohashtable__define
compile_opt strictarr
define = { MGcoHashTable, inherits IDL_Object, $
keyArray: ptr_new(), $
valueArray: ptr_new(), $
arraySize: 0L, $
keyType: 0L, $
valueType: 0L, $
keyExample: ptr_new(), $
valueExample: ptr_new() $
}
end
h = obj_new('MGcoHashTable', key_type=7, value_type=3)
h->put, 'Boulder', 80303
h->put, 'Lafayette', 80026
h->put, 'La Porte', 46350
print, h->keys()
print, h->values()
print, h->get('Boulder')
obj_destroy, h
end