hasty_key_base.f90 Source File

HASTY key class.

This File Depends On

sourcefile~~hasty_key_base.f90~~EfferentGraph sourcefile~hasty_key_base.f90 hasty_key_base.f90 sourcefile~penf.f90 penf.F90 sourcefile~penf.f90->sourcefile~hasty_key_base.f90 sourcefile~penf_b_size.f90 penf_b_size.F90 sourcefile~penf_b_size.f90->sourcefile~penf.f90 sourcefile~penf_stringify.f90 penf_stringify.F90 sourcefile~penf_b_size.f90->sourcefile~penf_stringify.f90 sourcefile~penf_global_parameters_variables.f90 penf_global_parameters_variables.F90 sourcefile~penf_global_parameters_variables.f90->sourcefile~penf.f90 sourcefile~penf_global_parameters_variables.f90->sourcefile~penf_b_size.f90 sourcefile~penf_global_parameters_variables.f90->sourcefile~penf_stringify.f90 sourcefile~penf_stringify.f90->sourcefile~penf.f90
Help

Files Dependent On This One

sourcefile~~hasty_key_base.f90~~AfferentGraph sourcefile~hasty_key_base.f90 hasty_key_base.f90 sourcefile~hasty_dictionary_node.f90 hasty_dictionary_node.f90 sourcefile~hasty_key_base.f90->sourcefile~hasty_dictionary_node.f90 sourcefile~hasty.f90 hasty.f90 sourcefile~hasty_key_base.f90->sourcefile~hasty.f90 sourcefile~hasty_dictionary.f90 hasty_dictionary.f90 sourcefile~hasty_key_base.f90->sourcefile~hasty_dictionary.f90 sourcefile~hasty_key_morton.f90 hasty_key_morton.f90 sourcefile~hasty_key_base.f90->sourcefile~hasty_key_morton.f90 sourcefile~hasty_hash_table.f90 hasty_hash_table.F90 sourcefile~hasty_key_base.f90->sourcefile~hasty_hash_table.f90 sourcefile~hasty_dictionary_node.f90->sourcefile~hasty.f90 sourcefile~hasty_dictionary_node.f90->sourcefile~hasty_dictionary.f90 sourcefile~hasty_test_hash_table_homokey_failure.f90 hasty_test_hash_table_homokey_failure.f90 sourcefile~hasty.f90->sourcefile~hasty_test_hash_table_homokey_failure.f90 sourcefile~hasty_test_hash_table.f90 hasty_test_hash_table.f90 sourcefile~hasty.f90->sourcefile~hasty_test_hash_table.f90 sourcefile~hasty_test_hash_table_homo.f90 hasty_test_hash_table_homo.f90 sourcefile~hasty.f90->sourcefile~hasty_test_hash_table_homo.f90 sourcefile~hasty_test_dictionary.f90 hasty_test_dictionary.f90 sourcefile~hasty.f90->sourcefile~hasty_test_dictionary.f90 sourcefile~hasty_test_caf_get_clone.f90 hasty_test_caf_get_clone.F90 sourcefile~hasty.f90->sourcefile~hasty_test_caf_get_clone.f90 sourcefile~hasty_test_hash_table_homocontent_failure.f90 hasty_test_hash_table_homocontent_failure.f90 sourcefile~hasty.f90->sourcefile~hasty_test_hash_table_homocontent_failure.f90 sourcefile~hasty_test_caf_basic.f90 hasty_test_caf_basic.F90 sourcefile~hasty.f90->sourcefile~hasty_test_caf_basic.f90 sourcefile~hasty_dictionary.f90->sourcefile~hasty.f90 sourcefile~hasty_dictionary.f90->sourcefile~hasty_hash_table.f90 sourcefile~hasty_key_morton.f90->sourcefile~hasty.f90 sourcefile~hasty_hash_table.f90->sourcefile~hasty.f90
Help

Source Code


Source Code

!< HASTY **key** class.
module hasty_key_base
!-----------------------------------------------------------------------------------------------------------------------------------
!< HASTY **key** class.
!-----------------------------------------------------------------------------------------------------------------------------------
use penf
!-----------------------------------------------------------------------------------------------------------------------------------

!-----------------------------------------------------------------------------------------------------------------------------------
implicit none
private
public :: is_key_allowed
public :: key_base
!-----------------------------------------------------------------------------------------------------------------------------------

!-----------------------------------------------------------------------------------------------------------------------------------
type :: key_base
  !< **Key** class to identify a node.
  !<
  !< It can be extended by user.
  private
  integer(I8P),     allocatable :: id_       !< Unique key id.
  character(len=:), allocatable :: char_key_ !< Store character key.
  contains
    ! public methods
    procedure, pass(self) :: destroy        !< Destroy the key.
    procedure, pass(self) :: hash           !< Hash the key.
    procedure, pass(self) :: id             !< Return the id.
    procedure, nopass     :: is_key_allowed !< Typeguard for used key.
    procedure, pass(self) :: set            !< Set the key.
    procedure, pass(self) :: stringify      !< Return a string representation of the key.
    ! public generics
    generic, public :: operator(==) => is_equal !< Overloading `==` operator.
    ! private methods
    procedure, pass(lhs),  private :: is_equal    !< Implement `==` operator.
    procedure, nopass,     private :: hash_string !< Hash a string.
endtype key_base

interface key_base
  module procedure creator
endinterface key_base
!-----------------------------------------------------------------------------------------------------------------------------------
contains
  ! private non TBP
  elemental function creator(key, buckets_number) result(key_)
  !---------------------------------------------------------------------------------------------------------------------------------
  !< Return an  instance of [[key_base]]
  !---------------------------------------------------------------------------------------------------------------------------------
  class(*),     intent(in)           :: key            !< The key value.
  integer(I4P), intent(in), optional :: buckets_number !< Buckets number.
  type(key_base)                     :: key_           !< Instance of [[key_base]].
  !---------------------------------------------------------------------------------------------------------------------------------

  !---------------------------------------------------------------------------------------------------------------------------------
  call key_%set(key=key, buckets_number=buckets_number)
  !---------------------------------------------------------------------------------------------------------------------------------
  endfunction creator

  ! public methods
  elemental subroutine destroy(self)
  !---------------------------------------------------------------------------------------------------------------------------------
  !< Destroy the key.
  !---------------------------------------------------------------------------------------------------------------------------------
  class(key_base), intent(inout) :: self !< The key.
  !---------------------------------------------------------------------------------------------------------------------------------

  !---------------------------------------------------------------------------------------------------------------------------------
  if (allocated(self%id_)) deallocate(self%id_)
  if (allocated(self%char_key_)) deallocate(self%char_key_)
  !---------------------------------------------------------------------------------------------------------------------------------
  endsubroutine destroy

  elemental function hash(self, buckets_number) result(bucket)
  !---------------------------------------------------------------------------------------------------------------------------------
  !< Hash the key.
  !---------------------------------------------------------------------------------------------------------------------------------
  class(key_base), intent(in) :: self           !< The key.
  integer(I4P),    intent(in) :: buckets_number !< Buckets number.
  integer(I4P)                :: bucket         !< Bucket index corresponding to the key.
  !---------------------------------------------------------------------------------------------------------------------------------

  !---------------------------------------------------------------------------------------------------------------------------------
  bucket = 0
  if (allocated(self%id_)) bucket = int(mod(self%id_, int(buckets_number, I8P)), I4P) + 1
  !---------------------------------------------------------------------------------------------------------------------------------
  endfunction hash

  elemental function id(self)
  !---------------------------------------------------------------------------------------------------------------------------------
  !< Return the id.
  !---------------------------------------------------------------------------------------------------------------------------------
  class(key_base), intent(in) :: self !< The key.
  integer(I8P)                :: id   !< Unique key id.
  !---------------------------------------------------------------------------------------------------------------------------------

  !---------------------------------------------------------------------------------------------------------------------------------
  id = 0
  if (allocated(self%id_)) id = self%id_
  !---------------------------------------------------------------------------------------------------------------------------------
  endfunction id

  elemental function is_key_allowed(key)
  !---------------------------------------------------------------------------------------------------------------------------------
  !< Typeguard for used key.
  !---------------------------------------------------------------------------------------------------------------------------------
  class(*), intent(in) :: key            !< The key ID.
  logical              :: is_key_allowed !< Check result.
  !---------------------------------------------------------------------------------------------------------------------------------

  !---------------------------------------------------------------------------------------------------------------------------------
  is_key_allowed = .false.
  select type(key)
  class is(key_base)
    is_key_allowed = .true.
  type is(integer(I1P))
    if (key>0) is_key_allowed = .true.
  type is(integer(I2P))
    if (key>0) is_key_allowed = .true.
  type is(integer(I4P))
    if (key>0) is_key_allowed = .true.
  type is(integer(I8P))
    if (key>0) is_key_allowed = .true.
  type is(character(len=*))
    is_key_allowed = .true.
  endselect
  !---------------------------------------------------------------------------------------------------------------------------------
  endfunction is_key_allowed

  elemental subroutine set(self, key, buckets_number)
  !---------------------------------------------------------------------------------------------------------------------------------
  !< Set the key.
  !---------------------------------------------------------------------------------------------------------------------------------
  class(key_base), intent(inout)        :: self           !< The key.
  class(*),        intent(in)           :: key            !< The key value.
  integer(I4P),    intent(in), optional :: buckets_number !< Buckets number.
  !---------------------------------------------------------------------------------------------------------------------------------

  !---------------------------------------------------------------------------------------------------------------------------------
  if (self%is_key_allowed(key)) then
    call self%destroy
    allocate(self%id_)
    select type(key)
    class is (key_base)
      self%id_ = key%id_
    type is(integer(I1P))
      self%id_ = int(key, kind=I8P)
    type is(integer(I2P))
      self%id_ = int(key, kind=I8P)
    type is(integer(I4P))
      self%id_ = int(key, kind=I8P)
    type is(integer(I8P))
      self%id_ = int(key, kind=I8P)
    type is(character(len=*))
      if (present(buckets_number)) then
        self%id_ = self%hash_string(string=key, buckets_number=buckets_number)
      else
        self%id_ = self%hash_string(string=key, buckets_number=9973_I4P)
      endif
      self%char_key_ = key
    endselect
  endif
  !---------------------------------------------------------------------------------------------------------------------------------
  endsubroutine set

  pure function stringify(self) result(str_key)
  !---------------------------------------------------------------------------------------------------------------------------------
  !< Return a string representation of the key.
  !---------------------------------------------------------------------------------------------------------------------------------
  class(key_base), intent(in)   :: self    !< The key.
  character(len=:), allocatable :: str_key !< The key stringified.
  !---------------------------------------------------------------------------------------------------------------------------------

  !---------------------------------------------------------------------------------------------------------------------------------
  str_key = ''
  if (allocated(self%char_key_)) then
    str_key = self%char_key_
  else
    if (allocated(self%id_)) str_key = trim(str(self%id_))
  endif
  !---------------------------------------------------------------------------------------------------------------------------------
  endfunction stringify

  ! private methods
  elemental function hash_string(string, buckets_number) result(bucket)
  !---------------------------------------------------------------------------------------------------------------------------------
  !< Hash a string.
  !---------------------------------------------------------------------------------------------------------------------------------
  character(*), intent(in) :: string         !< The string.
  integer(I4P), intent(in) :: buckets_number !< Buckets number.
  integer(I8P)             :: bucket         !< Bucket index corresponding to the string.
  integer(I4P)             :: c              !< Counter.
  !---------------------------------------------------------------------------------------------------------------------------------

  !---------------------------------------------------------------------------------------------------------------------------------
  bucket = int(buckets_number, I8P)
  do c=1, len(string)
    bucket = (ishft(bucket, 5) + bucket) + ichar(string(c:c), kind=I8P)
  enddo
  !---------------------------------------------------------------------------------------------------------------------------------
  endfunction hash_string

  elemental logical function is_equal(lhs, rhs)
  !---------------------------------------------------------------------------------------------------------------------------------
  !< Implement `==` operator.
  !---------------------------------------------------------------------------------------------------------------------------------
  class(key_base), intent(in) :: lhs !< Left hand side.
  class(*),        intent(in) :: rhs !< Rigth hand side.
  !---------------------------------------------------------------------------------------------------------------------------------

  !---------------------------------------------------------------------------------------------------------------------------------
  is_equal = .false.
  if (allocated(lhs%id_)) then
    select type(rhs)
    class is(key_base)
      if (allocated(rhs%id_)) is_equal = lhs%id_==rhs%id_
    type is(integer(I1P))
      is_equal = lhs%id_==rhs
    type is(integer(I2P))
      is_equal = lhs%id_==rhs
    type is(integer(I4P))
      is_equal = lhs%id_==rhs
    type is(integer(I8P))
      is_equal = lhs%id_==rhs
    type is(character(len=*))
      if (allocated(lhs%char_key_)) is_equal = lhs%char_key_==rhs
    endselect
  endif
  !---------------------------------------------------------------------------------------------------------------------------------
  endfunction is_equal
endmodule hasty_key_base