#:include "common.fypp" submodule(stdlib_bitsets) stdlib_bitsets_large implicit none contains elemental module function all_large( self ) result(all) ! Returns .TRUE. if all bits in SELF are 1, .FALSE. otherwise. logical :: all class(bitset_large), intent(in) :: self integer(bits_kind) :: block, full_blocks, pos all = .true. full_blocks = bits(self)/block_size do block = 1_bits_kind, full_blocks if ( self % blocks(block) /= -1_block_kind ) then all = .false. return end if end do if ( full_blocks == size(self % blocks) ) return do pos=0_bits_kind, modulo( bits(self), block_size )-1 if ( .not. btest(self % blocks(full_blocks+1), pos) ) then all = .false. return end if end do end function all_large elemental module subroutine and_large(set1, set2) ! ! Sets the bits in SET1 to the bitwise AND of the original bits in SET1 ! and SET2. It is required that SET1 have the same number of bits as ! SET2 otherwise the result is undefined. ! type(bitset_large), intent(inout) :: set1 type(bitset_large), intent(in) :: set2 integer(bits_kind) :: block_ do block_ = 1_bits_kind, size(set1 % blocks, kind=bits_kind) set1 % blocks(block_) = iand( set1 % blocks(block_), & set2 % blocks(block_) ) end do end subroutine and_large elemental module subroutine and_not_large(set1, set2) ! ! Sets the bits in SET1 to the bitwise and of the original bits in SET1 ! with the bitwise negation of SET2. SET1 and SET2 must have the same ! number of bits otherwise the result is undefined. ! type(bitset_large), intent(inout) :: set1 type(bitset_large), intent(in) :: set2 integer(bits_kind) :: block_ do block_ = 1_bits_kind, size( set1 % blocks, kind=bits_kind ) set1 % blocks(block_) = & iand( set1 % blocks(block_), not( set2 % blocks(block_) ) ) end do end subroutine and_not_large elemental module function any_large(self) result(any) ! Returns .TRUE. if any bit in SELF is 1, .FALSE. otherwise. logical :: any class(bitset_large), intent(in) :: self integer(bits_kind) :: block_ do block_ = 1_bits_kind, size(self % blocks, kind=bits_kind) if ( self % blocks(block_) /= 0 ) then any = .true. return end if end do any = .false. end function any_large #:for k1 in INT_KINDS pure module subroutine assign_log${k1}$_large( self, logical_vector ) ! Used to define assignment from an array of type logical for bitset_large type(bitset_large), intent(out) :: self logical(${k1}$), intent(in) :: logical_vector(:) integer(bits_kind) :: blocks integer(bits_kind) :: log_size integer(bits_kind) :: index log_size = size( logical_vector, kind=bits_kind ) self % num_bits = log_size if ( log_size == 0 ) then blocks = 0 else blocks = (log_size-1)/block_size + 1 end if allocate( self % blocks( blocks ) ) self % blocks(:) = 0 do index=0_bits_kind, log_size-1 if ( logical_vector(index+1) ) then call self % set( index ) end if end do end subroutine assign_log${k1}$_large pure module subroutine log${k1}$_assign_large( logical_vector, set ) ! Used to define assignment to an array of type logical for bitset_large logical(${k1}$), intent(out), allocatable :: logical_vector(:) type(bitset_large), intent(in) :: set integer(bits_kind) :: index allocate( logical_vector( set % num_bits ) ) do index=0_bits_kind, set % num_bits-1 if ( set % value( index ) == 1 ) then logical_vector(index+1) = .true. else logical_vector(index+1) = .false. end if end do end subroutine log${k1}$_assign_large #:endfor elemental module function bit_count_large(self) result(bit_count) ! Returns the number of non-zero bits in SELF. integer(bits_kind) :: bit_count class(bitset_large), intent(in) :: self integer(bits_kind) :: nblocks, pos nblocks = size( self % blocks, kind=bits_kind ) bit_count = sum( popcnt( self % blocks(1:nblocks-1) ) ) do pos = 0_bits_kind, self % num_bits - (nblocks-1)*block_size - 1 if ( btest( self % blocks(nblocks), pos ) ) bit_count = bit_count + 1 end do end function bit_count_large elemental module subroutine clear_bit_large(self, pos) ! ! Sets to zero the POS position in SELF. If POS is less than zero or ! greater than BITS(SELF)-1 it is ignored. ! class(bitset_large), intent(inout) :: self integer(bits_kind), intent(in) :: pos integer :: clear_block, block_bit if ( pos < 0 .OR. (pos > self % num_bits-1) ) return clear_block = pos / block_size + 1 block_bit = pos - (clear_block - 1) * block_size self % blocks(clear_block) = & ibclr( self % blocks(clear_block), block_bit ) end subroutine clear_bit_large pure module subroutine clear_range_large(self, start_pos, stop_pos) ! ! Sets to zero all bits from the START_POS to STOP_POS positions in SELF. ! If STOP_POS < START_POS then no bits are modified. Positions outside ! the range 0 to BITS(SELF)-1 are ignored. ! class(bitset_large), intent(inout) :: self integer(bits_kind), intent(in) :: start_pos, stop_pos integer(bits_kind) :: bit, block_, first_block, last_block, & true_first, true_last true_first = max( 0_bits_kind, start_pos ) true_last = min( self % num_bits-1, stop_pos ) if ( true_last < true_first ) return first_block = true_first / block_size + 1 last_block = true_last / block_size + 1 if ( first_block == last_block ) then ! TRUE_FIRST and TRUE_LAST are in the same block call mvbits( all_zeros, & true_first - (first_block-1)*block_size, & true_last - true_first + 1, & self % blocks(first_block), & true_first - (first_block-1)*block_size ) return end if ! Do "partial" black containing FIRST bit = true_first - (first_block-1)*block_size call mvbits( all_zeros, & bit, & block_size - bit, & self % blocks(first_block), & bit ) ! Do "partial" black containing LAST bit = true_last - (last_block-1)*block_size call mvbits( all_zeros, & 0, & bit+1, & self % blocks(last_block), & 0 ) ! Do intermediate blocks do block_ = first_block+1, last_block-1 self % blocks(block_) = all_zeros end do end subroutine clear_range_large elemental module function eqv_large(set1, set2) result(eqv) ! ! Returns .TRUE. if all bits in SET1 and SET2 have the same value, ! .FALSE. otherwise. The sets must have the same number of bits ! otherwise the results are undefined. ! logical :: eqv type(bitset_large), intent(in) :: set1, set2 integer(bits_kind) :: block, common_blocks eqv = .false. common_blocks = size(set1 % blocks, kind=bits_kind) do block = 1, common_blocks if ( set1 % blocks(block) /= set2 % blocks(block) ) return end do eqv = .true. end function eqv_large module subroutine extract_large(new, old, start_pos, stop_pos, status) ! Creates a new bitset, NEW, from a range, START_POS to STOP_POS, in bitset ! OLD. If START_POS is greater than STOP_POS the new bitset is empty. ! If START_POS is less than zero or STOP_POS is greater than BITS(OLD)-1 ! then if STATUS is present it has the value INDEX_INVALID_ERROR, ! otherwise processing stops with an informative message. type(bitset_large), intent(out) :: new type(bitset_large), intent(in) :: old integer(bits_kind), intent(in) :: start_pos, stop_pos integer, intent(out), optional :: status integer(bits_kind) :: bits, blocks, ex_block, i, j, k, old_block character(*), parameter :: procedure = 'EXTRACT' if ( start_pos < 0 ) then call error_handler( 'had a START_POS less than 0.', & index_invalid_error, status, & module_name, procedure ) return end if if ( stop_pos >= old % num_bits ) then call error_handler( 'had a STOP_POS greater than BITS(OLD)-1.', & index_invalid_error, status, & module_name, procedure ) return end if bits = stop_pos - start_pos + 1 if ( bits <= 0 ) then new % num_bits = 0 allocate( new % blocks(0) ) return end if blocks = ((bits-1) / block_size) + 1 new % num_bits = bits allocate( new % blocks(blocks) ) new % blocks(:) = 0 do i=0_bits_kind, bits-1 ex_block = i / block_size + 1 j = i - (ex_block-1) * block_size old_block = (start_pos + i) / block_size + 1 k = (start_pos + i) - (old_block-1) * block_size if ( btest( old % blocks(old_block), k ) ) then new % blocks(ex_block) = ibset(new % blocks(ex_block), j) end if end do if ( present(status) ) status = success end subroutine extract_large elemental module subroutine flip_bit_large(self, pos) ! ! Flips the value at the POS position in SELF, provided the position is ! valid. If POS is less than 0 or greater than BITS(SELF)-1, no value is ! changed. ! class(bitset_large), intent(inout) :: self integer(bits_kind), intent(in) :: pos integer(bits_kind) :: flip_block, block_bit if ( pos < 0 .OR. pos > self % num_bits-1 ) return flip_block = pos / block_size + 1 block_bit = pos - (flip_block - 1) * block_size if ( btest( self % blocks(flip_block), block_bit ) ) then self % blocks(flip_block) = ibclr( self % blocks(flip_block), & block_bit ) else self % blocks(flip_block) = ibset( self % blocks(flip_block), & block_bit ) end if end subroutine flip_bit_large pure module subroutine flip_range_large(self, start_pos, stop_pos) ! ! Flips all valid bits from the START_POS to the STOP_POS positions in ! SELF. If STOP_POS < START_POS no bits are flipped. Positions less than ! 0 or greater than BITS(SELF)-1 are ignored. ! class(bitset_large), intent(inout) :: self integer(bits_kind), intent(in) :: start_pos, stop_pos integer(bits_kind) :: bit, block_, end_bit, first_block, last_block, & start_bit start_bit = max( 0_bits_kind, start_pos ) end_bit = min( stop_pos , self % num_bits-1 ) if ( end_bit < start_bit ) return first_block = start_bit / block_size + 1 last_block = end_bit / block_size + 1 if (first_block == last_block) then ! FIRST and LAST are in the same block call mvbits( not(self % blocks(first_block)), & start_bit - (first_block-1)*block_size, & end_bit - start_bit + 1, & self % blocks(first_block), & start_bit - (first_block-1)*block_size ) return end if ! Do "partial" black containing FIRST bit = start_bit - (first_block-1)*block_size call mvbits( not(self % blocks(first_block) ), & bit, & block_size - bit, & self % blocks(first_block), & bit ) ! Do "partial" black containing LAST bit = end_bit - (last_block-1)*block_size call mvbits( not( self % blocks(last_block) ), & 0, & bit+1, & self % blocks(last_block), & 0 ) ! Do remaining blocks do block_ = first_block+1, last_block-1 self % blocks(block_) = not( self % blocks(block_) ) end do end subroutine flip_range_large module subroutine from_string_large(self, string, status) ! Initializes the bitset `self` treating `string` as a binary literal ! `status` may have the values: ! `success` - if no problems were found, ! `alloc_fault` - if allocation of the bitset failed ! `char_string_too_large_error` - if `string` was too large, or ! `char_string_invalid_error` - if string had an invalid character. class(bitset_large), intent(out) :: self character(*), intent(in) :: string integer, intent(out), optional :: status character(*), parameter :: procedure = 'FROM_STRING' integer(int64) :: bit integer(int64) :: bits character(1) :: char bits = len(string, kind=int64) if ( bits > huge(0_bits_kind) ) then call error_handler( 'STRING was too long for a ' // & 'BITSET_LARGE SELF.', & char_string_too_large_error, status, & module_name, procedure ) return end if call init_zero_large( self, int(bits, kind=bits_kind), status ) if ( present(status) ) then if ( status /= success ) return end if do bit = 1_bits_kind, bits char = string(bit:bit) if ( char == '0' ) then call self % clear( int(bits-bit, kind=bits_kind) ) else if ( char == '1' ) then call self % set( int(bits-bit, kind=bits_kind) ) else call error_handler( 'STRING had a character other than ' // & '0 or 1.', & char_string_invalid_error, status, & module_name, procedure ) return end if end do if ( present(status) ) status = success end subroutine from_string_large elemental module function ge_large(set1, set2) result(ge) ! ! Returns .TRUE. if the bits in SET1 and SET2 are the same or the ! highest order different bit is set to 1 in SET1 and to 0 in set2. ! .FALSE. otherwise. The sets must have the same number of bits ! otherwise the results are undefined. ! logical :: ge type(bitset_large), intent(in) :: set1, set2 integer(bits_kind) :: block_ do block_ = size(set1 % blocks, kind=bits_kind), 1_bits_kind, -1 if ( set1 % blocks(block_) == set2 % blocks(block_) ) then cycle else if ( bgt(set1 % blocks(block_), set2 % blocks(block_) ) ) then ge = .true. return else ge = .false. return end if end do ge = .true. end function ge_large elemental module function gt_large(set1, set2) result(gt) ! ! Returns .TRUE. if the bits in SET1 and SET2 differ and the ! highest order different bit is set to 1 in SET1 and to 0 in set2. ! .FALSE. otherwise. The sets must have the same number of bits ! otherwise the results are undefined. ! logical :: gt type(bitset_large), intent(in) :: set1, set2 integer(bits_kind) :: block_ do block_ = size(set1 % blocks, kind=bits_kind), 1_bits_kind, -1 if ( set1 % blocks(block_) == set2 % blocks(block_) ) then cycle else if ( bgt( set1 % blocks(block_), & set2 % blocks(block_) ) ) then gt = .true. return else gt = .false. return end if end do gt = .false. end function gt_large module subroutine init_zero_large(self, bits, status) ! ! Creates the bitset, `self`, of size `bits`, with all bits initialized to ! zero. `bits` must be non-negative. If an error occurs and `status` is ! absent then processing stops with an informative stop code. `status` ! will have one of the values; ! * `success` - if no problems were found, ! * `array_size_invalid_error` - if `bits` is either negative or larger ! than 64 with `self` of class `bitset_64`, or ! * `alloc_fault` - if memory allocation failed ! class(bitset_large), intent(out) :: self integer(bits_kind), intent(in) :: bits integer, intent(out), optional :: status character(len=120) :: message character(*), parameter :: procedure = "INIT" integer :: blocks, ierr message = '' if ( bits < 0 ) then call error_handler( 'BITS had a negative value.', & array_size_invalid_error, status, & module_name, procedure ) return end if if (bits == 0) then self % num_bits = 0 allocate( self % blocks(0), stat=ierr, errmsg=message ) if (ierr /= 0) go to 998 return else blocks = ((bits-1) / block_size) + 1 end if self % num_bits = bits allocate( self % blocks(blocks), stat=ierr, errmsg=message ) if (ierr /= 0) go to 998 self % blocks(:) = all_zeros if ( present(status) ) status = success return 998 call error_handler( 'Allocation failure for SELF.', & alloc_fault, status, & module_name, procedure ) end subroutine init_zero_large module subroutine input_large(self, unit, status) ! ! Reads the components of the bitset, `self`, from the unformatted I/O ! unit, `unit`, assuming that the components were written using `output`. ! If an error occurs and `status` is absent then processing stops with ! an informative stop code. `status` has one of the values: ! * `success` - if no problem was found ! * `alloc_fault` - if it failed during allocation of memory for `self`, or ! * `array_size_invalid_error` if the `bits(self)` in `unit` is negative ! or greater than 64 for a `bitset_64` input. ! * `read_failure` - if it failed during the reads from `unit` ! class(bitset_large), intent(out) :: self integer, intent(in) :: unit integer, intent(out), optional :: status integer(bits_kind) :: bits integer :: ierr character(len=120) :: message character(*), parameter :: procedure = 'INPUT' integer :: stat read(unit, iostat=ierr, iomsg=message) bits if (ierr /= 0) then call error_handler( 'Failure on a READ statement for UNIT.', & read_failure, status, module_name, procedure ) return end if if ( bits < 0 ) then call error_handler( 'BITS in UNIT had a negative value.', & array_size_invalid_error, status, & module_name, procedure ) return end if call self % init(bits, stat) if (stat /= success) then call error_handler( 'Allocation failure for SELF.', & alloc_fault, status, module_name, procedure ) return end if if (bits < 1) return read(unit, iostat=ierr, iomsg=message) self % blocks(:) if (ierr /= 0) then call error_handler( 'Failure on a READ statement for UNIT.', & read_failure, status, module_name, procedure ) return end if if ( present(status) ) status = success end subroutine input_large elemental module function le_large(set1, set2) result(le) ! ! Returns .TRUE. if the bits in SET1 and SET2 are the same or the ! highest order different bit is set to 0 in SET1 and to 1 in set2. ! .FALSE. otherwise. The sets must have the same number of bits ! otherwise the results are undefined. ! logical :: le type(bitset_large), intent(in) :: set1, set2 integer(bits_kind) :: block_ do block_ = size(set1 % blocks, kind=bits_kind), 1_bits_kind, -1 if ( set1 % blocks(block_) == set2 % blocks(block_) ) then cycle else if ( blt( set1 % blocks(block_), & set2 % blocks(block_) ) ) then le = .true. return else le = .false. return end if end do le = .true. end function le_large elemental module function lt_large(set1, set2) result(lt) ! ! Returns .TRUE. if the bits in SET1 and SET2 differ and the ! highest order different bit is set to 0 in SET1 and to 1 in set2. ! .FALSE. otherwise. The sets must have the same number of bits ! otherwise the results are undefined. ! logical :: lt type(bitset_large), intent(in) :: set1, set2 integer(bits_kind) :: block_ do block_ = size(set1 % blocks, kind=bits_kind), 1_bits_kind, -1 if ( set1 % blocks(block_) == set2 % blocks(block_) ) then cycle else if ( blt( set1 % blocks(block_), & set2 % blocks(block_) ) ) then lt = .true. return else lt = .false. return end if end do lt = .false. end function lt_large elemental module function neqv_large(set1, set2) result(neqv) ! ! Returns .TRUE. if any bits in SET1 and SET2 differ in value, ! .FALSE. otherwise. The sets must have the same number of bits ! otherwise the results are undefined. ! logical :: neqv type(bitset_large), intent(in) :: set1, set2 integer(bits_kind) :: block_ neqv = .true. do block_ = 1_bits_kind, size(set1 % blocks, kind=bits_kind) if ( set1 % blocks(block_) /= set2 % blocks(block_) ) return end do neqv = .false. end function neqv_large elemental module function none_large(self) result(none) ! ! Returns .TRUE. if none of the bits in SELF have the value 1. ! logical :: none class(bitset_large), intent(in) :: self integer(bits_kind) :: block none = .true. do block = 1_bits_kind, size(self % blocks, kind=bits_kind) if (self % blocks(block) /= 0) then none = .false. return end if end do end function none_large elemental module subroutine not_large(self) ! ! Sets the bits in SELF to their logical complement ! class(bitset_large), intent(inout) :: self integer(bits_kind) :: bit, full_blocks, block integer :: remaining_bits if ( self % num_bits == 0 ) return full_blocks = self % num_bits / block_size do block = 1_bits_kind, full_blocks self % blocks(block) = not( self % blocks(block) ) end do remaining_bits = self % num_bits - full_blocks * block_size do bit=0, remaining_bits - 1 if ( btest( self % blocks( block ), bit ) ) then self % blocks( block ) = ibclr( self % blocks(block), bit ) else self % blocks( block ) = ibset( self % blocks(block), bit ) end if end do end subroutine not_large elemental module subroutine or_large(set1, set2) ! ! Sets the bits in SET1 to the bitwise OR of the original bits in SET1 ! and SET2. SET1 and SET2 must have the same number of bits otherwise ! the result is undefined. ! type(bitset_large), intent(inout) :: set1 type(bitset_large), intent(in) :: set2 integer(bits_kind) :: block_ do block_ = 1, size( set1 % blocks, kind=bits_kind ) set1 % blocks(block_) = ior( set1 % blocks(block_), & set2 % blocks(block_) ) end do end subroutine or_large module subroutine output_large(self, unit, status) ! ! Writes the components of the bitset, SELF, to the unformatted I/O ! unit, UNIT, in a unformatted sequence compatible with INPUT. If ! STATUS is absent an error results in an error stop with an ! informative stop code. If STATUS is present it has the default ! value of SUCCESS, or the value WRITE_FAILURE if the write failed. ! class(bitset_large), intent(in) :: self integer, intent(in) :: unit integer, intent(out), optional :: status integer :: ierr character(len=120) :: message character(*), parameter :: procedure = "OUTPUT" write(unit, iostat=ierr, iomsg=message) self % num_bits if (ierr /= 0) go to 999 if (self % num_bits < 1) return write(unit, iostat=ierr, iomsg=message) self % blocks(:) if (ierr /= 0) go to 999 return 999 call error_handler( 'Failure on a WRITE statement for UNIT.', & write_failure, status, module_name, procedure ) end subroutine output_large module subroutine read_bitset_string_large(self, string, status) ! ! Uses the bitset literal in the default character `string`, to define ! the bitset, `self`. The literal may be preceded by an an arbitrary ! sequence of blank characters. If `status` is absent an error results ! in an error stop with an informative stop code. If `status` ! is present it has one of the values ! * `success` - if no problems occurred, ! * `alloc_fault` - if allocation of memory for SELF failed, ! * `array_size_invalid_error - if `bits(self)` in `string` is greater ! than 64 for a `bitset_64`, ! * `char_string_invalid_error` - if the bitset literal has an invalid ! character, ! * `char_string_too_small_error - if the string ends before all the bits ! are read. ! * `integer_overflow_error` - if the bitset literal has a `bits(self)` ! value too large to be represented, ! class(bitset_large), intent(out) :: self character(len=*), intent(in) :: string integer, intent(out), optional :: status integer(bits_kind) :: bit, bits integer(bits_kind) :: digits, pos character(*), parameter :: procedure = "READ_BITSET" integer :: stat pos = 1 find_start: do pos=1_bits_kind, len(string, kind=bits_kind) if ( string(pos:pos) /= ' ' ) exit end do find_start if ( pos > len(string) - 8 ) go to 999 if ( string(pos:pos) /= 's' .AND. string(pos:pos) /= 'S' ) go to 999 pos = pos + 1 bits = 0 digits = 0 do select case( iachar( string(pos:pos) ) ) case(ia0:ia9) digits = digits + 1 if ( digits == max_digits .AND. bits > overflow_bits ) go to 996 if ( digits > max_digits ) go to 996 bits = bits*10 + iachar( string(pos:pos) ) - ia0 if ( bits < 0 ) go to 996 case(iachar('b'), iachar('B')) exit case default call error_handler( 'There was an invalid character ' // & 'in STRING', & char_string_invalid_error, status, & module_name, procedure ) return end select pos = pos + 1 end do if ( bits + pos > len(string) ) then call error_handler( 'STRING was too small for the number of ' // & 'bits specified by STRING.', & char_string_too_small_error, status, & module_name, procedure ) return end if call self % init( bits, stat ) if (stat /= success) then call error_handler( 'There was an allocation fault for SELF.', & alloc_fault, status, module_name, procedure ) return end if pos = pos + 1 bit = bits - 1 do if ( string(pos:pos) == '0' ) then call self % clear( bit ) else if ( string(pos:pos) == '1' ) then call self % set( bit ) else go to 999 end if pos = pos + 1 bit = bit - 1 if ( bit < 0 ) exit end do if ( present(status) ) status = success return 996 call error_handler( 'There was an integer overflow in reading' // & 'size of bitset literal from UNIT', & integer_overflow_error, status, & module_name, procedure ) return 999 call error_handler( 'There was an invalid character in STRING', & char_string_invalid_error, status, & module_name, procedure ) end subroutine read_bitset_string_large module subroutine read_bitset_unit_large(self, unit, advance, status) ! ! Uses the bitset literal at the current position in the formatted ! file with I/O unit, `unit`, to define the bitset, `self`. The literal ! may be preceded by an arbitrary sequence of blank characters. ! If `advance` is present it must be either 'YES' or 'NO'. If absent ! it has the default value of 'YES' to determine whether advancing ! I/O occurs. If `status` is absent an error results in an error stop ! with an informative stop code. If `status` is present it has one of ! the values: ! * `success` - if no problem occurred, ! * `alloc_fault` - if allocation of `self` failed, ! * `array_size_invalid_error` - if `bits(self)` in the bitset literal ! is greater than 64 for a `bitset_64`. ! * `char_string_invalid_error` - if the read of the bitset literal found ! an invalid character, ! * `eof_failure` - if a `read` statement reaches an end-of-file before ! completing the read of the bitset literal, ! * `integer_overflow_error` - if the bitset literal has a `bits(self)` ! value too large to be represented, ! * `read_failure` - if a `read` statement fails, ! class(bitset_large), intent(out) :: self integer, intent(in) :: unit character(*), intent(in), optional :: advance integer, intent(out), optional :: status integer(bits_kind) :: bit, bits, digits integer :: ierr character(len=128) :: message character(*), parameter :: procedure = "READ_BITSET" character(len=1) :: char do read( unit, & advance='NO', & FMT='(A1)', & err=997, & end=998, & iostat=ierr, & iomsg=message ) char select case( char ) case( ' ' ) cycle case( 's', 'S' ) exit case default go to 999 end select end do bits = 0 digits = 0 do read( unit, & advance='NO', & FMT='(A1)', & err=997, & end=998, & iostat=ierr, & iomsg=message ) char if ( char == 'b' .or. char == 'B' ) exit select case( char ) case( '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' ) digits = digits + 1 if ( digits == max_digits .AND. bits > overflow_bits ) & go to 996 if ( digits > max_digits ) go to 996 bits = 10*bits + iachar(char) - iachar('0') if ( bits < 0 ) go to 996 case default go to 999 end select end do if ( bits < 0 .OR. digits == 0 .OR. digits > max_digits ) go to 999 call self % init( bits, status ) if ( present(status) ) then call error_handler( 'There was an allocation fault for SELF.', & alloc_fault, status, module_name, procedure ) return end if do bit = 1, bits-1 read( unit, & advance='NO', & FMT='(A1)', & err=997, & end=998, & iostat=ierr, & iomsg=message ) char if ( char == '0' ) then call self % clear( bits-bit ) else if ( char == '1' ) then call self % set( bits-bit ) else go to 999 end if end do read( unit, & advance=optval(advance, 'YES'), & FMT='(A1)', & err=997, & end=998, & iostat=ierr, & iomsg=message ) char if ( char == '0' ) then call self % clear( bits-bit ) else if ( char == '1' ) then call self % set( bits-bit ) else go to 999 end if if ( present(status) ) status = success return 996 call error_handler( 'Integer overflow in reading size of ' // & 'bitset literal from UNIT.', & read_failure, status, module_name, procedure ) return 997 call error_handler( 'Failure on read of UNIT.', & read_failure, status, module_name, procedure ) return 998 call error_handler( 'End of File of UNIT before finishing a ' // & 'bitset literal.', & eof_failure, status, module_name, procedure ) return 999 call error_handler( 'Invalid character in bitset literal in UNIT ', & char_string_invalid_error, status, & module_name, procedure ) end subroutine read_bitset_unit_large elemental module subroutine set_bit_large(self, pos) ! ! Sets the value at the POS position in SELF, provided the position is ! valid. If the position is less than 0 or greater than BITS(SELF)-1 ! then SELF is unchanged. ! class(bitset_large), intent(inout) :: self integer(bits_kind), intent(in) :: pos integer(bits_kind) :: set_block, block_bit if ( pos < 0 .OR. pos > self % num_bits-1 ) return set_block = pos / block_size + 1 block_bit = pos - (set_block - 1) * block_size self % blocks(set_block) = ibset( self % blocks(set_block), block_bit ) end subroutine set_bit_large pure module subroutine set_range_large(self, start_pos, stop_pos) ! ! Sets all valid bits to 1 from the START_POS to the STOP_POS positions ! in SELF. If STOP_POS < START_POS no bits are changed. Positions outside ! the range 0 to BITS(SELF)-1 are ignored. ! class(bitset_large), intent(inout) :: self integer(bits_kind), intent(in) :: start_pos, stop_pos integer(bits_kind) :: bit, block_, end_bit, first_block, last_block, & start_bit start_bit = max( 0_bits_kind, start_pos ) end_bit = min( stop_pos, self % num_bits-1 ) if ( end_bit < start_bit ) return first_block = start_bit / block_size + 1 last_block = end_bit / block_size + 1 if ( first_block == last_block ) then ! FIRST and LAST are in the same block call mvbits( all_ones, & start_bit - (first_block-1)*block_size, & end_bit - start_bit + 1, & self % blocks(first_block), & start_bit - (first_block-1)*block_size ) return end if ! Do "partial" black containing FIRST bit = start_bit - (first_block-1)*block_size call mvbits( all_ones, & bit, & block_size - bit, & self % blocks(first_block), & bit ) ! Do "partial" black containing LAST bit = end_bit - (last_block-1)*block_size call mvbits( all_ones, & 0, & bit+1, & self % blocks(last_block), & 0 ) ! Do remaining blocks do block_ = first_block+1, last_block-1 self % blocks(block_) = all_ones end do end subroutine set_range_large elemental module function test_large(self, pos) result(test) ! ! Returns .TRUE. if the POS position is set, .FALSE. otherwise. If POS ! is negative or greater than BITS(SELF) - 1 the result is .FALSE.. ! logical :: test class(bitset_large), intent(in) :: self integer(bits_kind), intent(in) :: pos integer(bits_kind) :: bit_block if ( pos < 0 .or. pos >= self % num_bits ) then test = .false. else bit_block = pos / block_size + 1 test = btest( self % blocks(bit_block), & pos - ( bit_block-1 ) * block_size ) end if end function test_large module subroutine to_string_large(self, string, status) ! ! Represents the value of SELF as a binary literal in STRING ! Status may have the values SUCCESS or ALLOC_FAULT ! class(bitset_large), intent(in) :: self character(len=:), allocatable, intent(out) :: string integer, intent(out), optional :: status character(*), parameter :: procedure = 'TO_STRING' integer(bits_kind) :: bit, bit_count, pos integer :: stat bit_count = self % num_bits allocate( character(len=bit_count)::string, stat=stat ) if ( stat > 0 ) then call error_handler( 'There was an allocation fault for STRING.', & alloc_fault, status, module_name, procedure ) return end if do bit=0_bits_kind, bit_count-1 pos = bit_count - bit if ( self % test( bit) ) then string( pos:pos ) = '1' else string( pos:pos ) = '0' end if end do if ( present(status) ) status = success end subroutine to_string_large elemental module function value_large(self, pos) result(value) ! ! Returns 1 if the POS position is set, 0 otherwise. If POS is negative ! or greater than BITS(SELF) - 1 the result is 0. ! integer :: value class(bitset_large), intent(in) :: self integer(bits_kind), intent(in) :: pos integer :: bit_block if ( pos < 0 .or. pos >= self % num_bits ) then value = 0 else bit_block = pos / block_size + 1 if ( btest( self % blocks(bit_block), & pos - ( bit_block-1 ) * block_size ) ) then value = 1 else value = 0 end if end if end function value_large module subroutine write_bitset_string_large(self, string, status) ! ! Writes a bitset literal to the allocatable default character STRING, ! representing the individual bit values in the bitset_t, SELF. ! If STATUS is absent an error results in an error stop with an ! informative stop code. If STATUS is present it has the default ! value of SUCCESS, or the value ALLOC_FAULT if allocation of ! the output string failed. ! class(bitset_large), intent(in) :: self character(len=:), allocatable, intent(out) :: string integer, intent(out), optional :: status integer(bits_kind) :: bit, & bit_count, & count_digits, & pos integer :: stat character(*), parameter :: procedure = 'WRITE_BITSET' bit_count = bits(self) call digit_count( self % num_bits, count_digits ) allocate( character(len=count_digits+bit_count+2)::string, stat=stat ) if ( stat > 0 ) then call error_handler( 'There was an allocation fault for STRING.', & alloc_fault, status, module_name, procedure ) return end if write( string, "('S', i0)" ) self % num_bits string( count_digits + 2:count_digits + 2 ) = "B" do bit=0_bits_kind, bit_count-1 pos = count_digits + 2 + bit_count - bit if ( self % test( bit) ) then string( pos:pos ) = '1' else string( pos:pos ) = '0' end if end do if ( present(status) ) status = success contains subroutine digit_count( bits, digits ) integer(bits_kind), intent(in) :: bits integer(bits_kind), intent(out) :: digits integer(bits_kind) :: factor factor = bits if ( factor <= 0 ) then digits = 1 return end if do digits = 1, 127 factor = factor / 10 if ( factor == 0 ) return end do end subroutine digit_count end subroutine write_bitset_string_large module subroutine write_bitset_unit_large(self, unit, advance, status) ! ! Writes a bitset literal to the I/O unit, UNIT, representing the ! individual bit values in the bitset_t, SELF. By default or if ! ADVANCE is present with the value 'YES', advancing output is used. ! If ADVANCE is present with the value 'NO', then the current record ! is not advanced by the write. If STATUS is absent an error results ! in an error stop with an informative stop code. If STATUS is ! present it has the default value of SUCCESS, the value ! ALLOC_FAULT if allocation of the output string failed, or ! WRITE_FAILURE if the WRITE statement outputting the literal failed. ! class(bitset_large), intent(in) :: self integer, intent(in) :: unit character(len=*), intent(in), optional :: advance integer, intent(out), optional :: status integer :: ierr character(:), allocatable :: string character(len=120) :: message character(*), parameter :: procedure = "WRITE_BITSET" call self % write_bitset(string, status) if ( present(status) ) then if (status /= success ) return end if write( unit, & FMT='(A)', & advance=optval(advance, 'YES'), & iostat=ierr, & iomsg=message ) & string if (ierr /= 0) then call error_handler( 'Failure on a WRITE statement for UNIT.', & write_failure, status, module_name, procedure ) return endif end subroutine write_bitset_unit_large elemental module subroutine xor_large(set1, set2) ! ! Sets the bits in SET1 to the bitwise XOR of the original bits in SET1 ! and SET2. SET1 and SET2 must have the same number of bits otherwise ! the result is undefined. ! type(bitset_large), intent(inout) :: set1 type(bitset_large), intent(in) :: set2 integer(bits_kind) :: block_ do block_ = 1_bits_kind, size(set1 % blocks, kind=bits_kind) set1 % blocks(block_) = ieor( set1 % blocks(block_), & set2 % blocks(block_) ) end do end subroutine xor_large end submodule stdlib_bitsets_large