MayaChemTools

   1 package BitVector;
   2 #
   3 # File: BitVector.pm
   4 # Author: Manish Sud <msud@san.rr.com>
   5 #
   6 # Copyright (C) 2024 Manish Sud. All rights reserved.
   7 #
   8 # This file is part of MayaChemTools.
   9 #
  10 # MayaChemTools is free software; you can redistribute it and/or modify it under
  11 # the terms of the GNU Lesser General Public License as published by the Free
  12 # Software Foundation; either version 3 of the License, or (at your option) any
  13 # later version.
  14 #
  15 # MayaChemTools is distributed in the hope that it will be useful, but without
  16 # any warranty; without even the implied warranty of merchantability of fitness
  17 # for a particular purpose.  See the GNU Lesser General Public License for more
  18 # details.
  19 #
  20 # You should have received a copy of the GNU Lesser General Public License
  21 # along with MayaChemTools; if not, see <http://www.gnu.org/licenses/> or
  22 # write to the Free Software Foundation Inc., 59 Temple Place, Suite 330,
  23 # Boston, MA, 02111-1307, USA.
  24 #
  25 
  26 use strict;
  27 use Carp;
  28 use Exporter;
  29 use Scalar::Util ();
  30 use TextUtil ();
  31 use ConversionsUtil ();
  32 use MathUtil;
  33 
  34 use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
  35 
  36 @ISA = qw(Exporter);
  37 @EXPORT = qw(IsBitVector);
  38 @EXPORT_OK = qw(NewFromBinaryString NewFromDecimalString NewFromHexadecimalString NewFromOctalString NewFromRawBinaryString);
  39 
  40 %EXPORT_TAGS = (all  => [@EXPORT, @EXPORT_OK]);
  41 
  42 # Setup class variables...
  43 my($ClassName, $ValueFormat, $ValueBitOrder);
  44 _InitializeClass();
  45 
  46 #
  47 # Overload bitwise and some logical operators...
  48 #
  49 # 'fallback' is set to 'false' to raise exception for all other operators.
  50 #
  51 use overload '""' => 'StringifyBitVector',
  52   '&' => '_BitVectorAndOperator',
  53   '|' => '_BitVectorOrOperator',
  54   '^' => '_BitVectorExclusiveOrOperator',
  55 
  56   '~' => '_BitVectorNegationOperator',
  57 
  58   '==' => '_BitVectorEqualOperator',
  59   '!=' => '_BitVectorNotEqualOperator',
  60 
  61   'fallback' => undef;
  62 
  63 # Class constructor...
  64 #
  65 sub new {
  66   my($Class, $Size) = @_;
  67 
  68   # Initialize object...
  69   my $This = {};
  70   bless $This, ref($Class) || $Class;
  71   $This->_InitializeBitVector($Size);
  72 
  73   return $This;
  74 }
  75 
  76 # Initialize object data...
  77 #
  78 # Note:
  79 #  . Perl pack function used to initialize vector automatically sets its size to
  80 #    nearest power of 2 value.
  81 #
  82 sub _InitializeBitVector {
  83   my($This, $Size) = @_;
  84 
  85   if (!defined $Size) {
  86     croak "Error: ${ClassName}->new: BitVector object instantiated without specifying its size ...";
  87   }
  88   if ($Size <=0) {
  89     croak "Error: ${ClassName}->new: Bit vector size, $Size, must be a positive integer...";
  90   }
  91 
  92   # Initialize vector with zeros...
  93   $This->{BitValues} = pack("b*", "0" x $Size);
  94 
  95   # Size to automatically set to nearest power of 2 by Perl pack function. So use the length
  96   # of packed vector to set size...
  97   $This->{Size} = length($This->GetBitsAsBinaryString());
  98 
  99   return $This;
 100 }
 101 
 102 # Initialize class ...
 103 sub _InitializeClass {
 104   #Class name...
 105   $ClassName = __PACKAGE__;
 106 
 107   # Print format for bit vectore values...
 108   $ValueFormat = "Binary";
 109 
 110   # Bit ordering for printing bit vector value strings. Default is to print lowest bit of each
 111   # byte on the left.
 112   #
 113   # Internally, bits are stored in ascending order using Perl vec function. Regardless
 114   # of machine order, big-endian or little-endian, vec function always considers first
 115   # string byte as the lowest byte and first bit within each byte as the lowest bit.
 116   #
 117   # Possible values: Ascending or Descending
 118   #
 119   $ValueBitOrder = 'Ascending';
 120 }
 121 
 122 # Create a new bit vector using binary string. This functionality can be
 123 # either invoked as a class function or an object method.
 124 #
 125 # The size of bit vector is automatically set to reflect the string.
 126 #
 127 sub NewFromBinaryString ($;$) {
 128   my($FirstParameter, $SecondParameter, $ThirdParameter) = @_;
 129 
 130   if (_IsBitVector($FirstParameter)) {
 131     return _NewBitVectorFromString('Binary', $SecondParameter, $ThirdParameter);
 132   }
 133   else {
 134     return _NewBitVectorFromString( 'Binary', $FirstParameter, $SecondParameter);
 135   }
 136 }
 137 
 138 # Create a new bit vector using hexadecimal string. This functionality can be
 139 # either invoked as a class function or an object method.
 140 #
 141 # The size of bit vector is automatically set to reflect the string.
 142 #
 143 sub NewFromHexadecimalString ($;$) {
 144   my($FirstParameter, $SecondParameter, $ThirdParameter) = @_;
 145 
 146   if (_IsBitVector($FirstParameter)) {
 147     return _NewBitVectorFromString('Hexadecimal', $SecondParameter, $ThirdParameter);
 148   }
 149   else {
 150     return _NewBitVectorFromString( 'Hexadecimal', $FirstParameter, $SecondParameter);
 151   }
 152 }
 153 
 154 # Create a new bit vector using octal string. This functionality can be
 155 # either invoked as a class function or an object method.
 156 #
 157 # The size of bit vector is automatically set to reflect the string.
 158 #
 159 sub NewFromOctalString ($;$) {
 160   my($FirstParameter, $SecondParameter, $ThirdParameter) = @_;
 161 
 162   if (_IsBitVector($FirstParameter)) {
 163     return _NewBitVectorFromString('Octal', $SecondParameter, $ThirdParameter);
 164   }
 165   else {
 166     return _NewBitVectorFromString( 'Octal', $FirstParameter, $SecondParameter);
 167   }
 168 }
 169 
 170 # Create a new bit vector using decimal string. This functionality can be
 171 # either invoked as a class function or an object method.
 172 #
 173 # The size of bit vector is automatically set to reflect the string.
 174 #
 175 sub NewFromDecimalString ($;$) {
 176   my($FirstParameter, $SecondParameter, $ThirdParameter) = @_;
 177 
 178   if (_IsBitVector($FirstParameter)) {
 179     return _NewBitVectorFromString('Decimal', $SecondParameter, $ThirdParameter);
 180   }
 181   else {
 182     return _NewBitVectorFromString( 'Decimal', $FirstParameter, $SecondParameter);
 183   }
 184 }
 185 
 186 # Create a new bit vector using raw binary string. This functionality can be
 187 # either invoked as a class function or an object method.
 188 #
 189 # The size of bit vector is automatically set to reflect the string.
 190 #
 191 sub NewFromRawBinaryString ($;$) {
 192   my($FirstParameter, $SecondParameter, $ThirdParameter) = @_;
 193 
 194   if (_IsBitVector($FirstParameter)) {
 195     return _NewBitVectorFromString('RawBinary', $SecondParameter, $ThirdParameter);
 196   }
 197   else {
 198     return _NewBitVectorFromString( 'RawBinary', $FirstParameter, $SecondParameter);
 199   }
 200 }
 201 
 202 # Create a new bit vector from a string...
 203 #
 204 sub _NewBitVectorFromString ($$;$) {
 205   my($Format, $String, $BitOrder) = @_;
 206   my($Size, $BitVector);
 207 
 208   $Size = _CalculateStringSizeInBits($Format, $String);
 209 
 210   $BitVector = new BitVector($Size);
 211   $BitVector->_SetBitsAsString($Format, $String, $BitOrder);
 212 
 213   return $BitVector;
 214 }
 215 
 216 # Copy bit vector...
 217 sub Copy {
 218   my($This) = @_;
 219   my($BitVector);
 220 
 221   # Make a new bit vector...
 222   $BitVector = (ref $This)->new($This->{Size});
 223 
 224   # Copy bit values...
 225   $BitVector->{BitValues} = $This->{BitValues};
 226 
 227   # Copy value format for stringification...
 228   if (exists $This->{ValueFormat}) {
 229     $BitVector->{ValueFormat} = $This->{ValueFormat};
 230   }
 231   # Copy value bit order for stringification...
 232   if (exists $This->{ValueBitOrder}) {
 233     $BitVector->{ValueBitOrder} = $This->{ValueBitOrder};
 234   }
 235   return $BitVector;
 236 }
 237 
 238 # Reverse bit values in bit vector...
 239 sub Reverse {
 240   my($This) = @_;
 241   my($BitNum, $ReverseBitNum, $BitValue, $ReverseBitValue);
 242 
 243   $BitNum = 0; $ReverseBitNum = $This->{Size} - 1;
 244 
 245   while ($BitNum < $ReverseBitNum) {
 246     $BitValue = $This->_GetBitValue($BitNum);
 247     $ReverseBitValue = $This->_GetBitValue($ReverseBitNum);
 248 
 249     $This->_SetBitValue($BitNum, $ReverseBitValue);
 250     $This->_SetBitValue($ReverseBitNum, $BitValue);
 251 
 252     $BitNum++; $ReverseBitNum--;
 253   }
 254   return $This;
 255 }
 256 
 257 # Is it a bit vector object?
 258 sub IsBitVector ($) {
 259   my($Object) = @_;
 260 
 261   return _IsBitVector($Object);
 262 }
 263 
 264 # Get size...
 265 sub GetSize {
 266   my($This) = @_;
 267 
 268   return $This->{Size};
 269 }
 270 
 271 # Set a bit...
 272 #
 273 sub SetBit {
 274   my($This, $BitNum, $SkipCheck) = @_;
 275 
 276   # Just set it...
 277   if ($SkipCheck) {
 278     return $This->_SetBitValue($BitNum, 1);
 279   }
 280 
 281   # Check and set...
 282   $This->_ValidateBitNumber("SetBit", $BitNum);
 283 
 284   return $This->_SetBitValue($BitNum, 1);
 285 }
 286 
 287 # Set arbitrary bits specified as a list of bit numbers...
 288 #
 289 sub SetBits {
 290   my($This, @BitNums) = @_;
 291   my($BitNum);
 292 
 293   for $BitNum (@BitNums) {
 294     $This->SetBit($BitNum);
 295   }
 296   return $This;
 297 }
 298 
 299 # Set bits in a specified range...
 300 #
 301 sub SetBitsRange {
 302   my($This, $MinBitNum, $MaxBitNum) = @_;
 303   my($BitNum);
 304 
 305   $This->_ValidateBitNumber("SetBitsRange", $MinBitNum);
 306   $This->_ValidateBitNumber("SetBitsRange", $MaxBitNum);
 307 
 308   for $BitNum ($MinBitNum .. $MaxBitNum) {
 309     $This->_SetBitValue($BitNum, 1);
 310   }
 311   return $This;
 312 }
 313 
 314 # Set all bits...
 315 #
 316 sub SetAllBits {
 317   my($This) = @_;
 318 
 319   $This->{BitValues} = pack("b*", "1" x $This->{Size});
 320 }
 321 
 322 # Clear a bit...
 323 #
 324 sub ClearBit {
 325   my($This, $BitNum) = @_;
 326 
 327   $This->_ValidateBitNumber("ClearBit", $BitNum);
 328 
 329   return $This->_SetBitValue($BitNum, 0);
 330 }
 331 
 332 # Clear arbitrary bits specified as a list of bit numbers...
 333 #
 334 sub ClearBits {
 335   my($This, @BitNums) = @_;
 336   my($BitNum);
 337 
 338   for $BitNum (@BitNums) {
 339     $This->ClearBit($BitNum);
 340   }
 341   return $This;
 342 }
 343 
 344 # Clear bits in a specified range...
 345 #
 346 sub ClearBitsRange {
 347   my($This, $MinBitNum, $MaxBitNum) = @_;
 348   my($BitNum);
 349 
 350   $This->_ValidateBitNumber("ClearBitsRange", $MinBitNum);
 351   $This->_ValidateBitNumber("ClearBitsRange", $MaxBitNum);
 352 
 353   for $BitNum ($MinBitNum .. $MaxBitNum) {
 354     $This->_SetBitValue($BitNum, 0);
 355   }
 356   return $This;
 357 }
 358 
 359 # Clear all bits...
 360 #
 361 sub ClearAllBits {
 362   my($This) = @_;
 363 
 364   $This->{BitValues} = pack("b*", "0" x $This->{Size});
 365 
 366   return $This;
 367 }
 368 
 369 # Set or clear bit...
 370 #
 371 sub SetBitValue {
 372   my($This, $BitNum, $BitValue) = @_;
 373 
 374  BITVALUE: {
 375     if ($BitValue == 1) { return $This->SetBit($BitNum); last BITVALUE; }
 376     if ($BitValue == 0) { return $This->ClearBit($BitNum); last BITVALUE; }
 377     croak "Error: ${ClassName}->SetBit: Specified bit value, $BitValue, must be 0 or 1...";
 378   }
 379   return $This;
 380 }
 381 
 382 # Flip bit value...
 383 #
 384 sub FlipBit {
 385   my($This, $BitNum) = @_;
 386 
 387   $This->_ValidateBitNumber("FlipBit", $BitNum);
 388   return $This->_FlipBit($BitNum);
 389 }
 390 
 391 # Flip arbitrary bits specified as a list of bit numbers...
 392 #
 393 sub FlipBits {
 394   my($This, @BitNums) = @_;
 395   my($BitNum);
 396 
 397   for $BitNum (@BitNums) {
 398     $This->FlipBit();
 399   }
 400   return $This;
 401 }
 402 
 403 # Flip bit value in a specified bit range...
 404 #
 405 sub FlipBitsRange {
 406   my($This, $MinBitNum, $MaxBitNum) = @_;
 407   my($BitNum);
 408 
 409   $This->_ValidateBitNumber("FlipBitsRange", $MinBitNum);
 410   $This->_ValidateBitNumber("FlipBitsRange", $MaxBitNum);
 411 
 412   for $BitNum ($MinBitNum .. $MaxBitNum) {
 413     $This->_FlipBit();
 414   }
 415   return $This;
 416 }
 417 
 418 # Flip all bit valus...
 419 #
 420 sub FlipAllBits {
 421   my($This) = @_;
 422 
 423   return $This->FlipBits(0, ($This->{Size} - 1));
 424 }
 425 
 426 # Flip bit value...
 427 sub _FlipBit {
 428   my($This, $BitNum) = @_;
 429 
 430   if ($This->_GetBitValue($BitNum)) {
 431     return $This->_SetBitValue($BitNum, 0);
 432   }
 433   else {
 434     return $This->_SetBitValue($BitNum, 1);
 435   }
 436 }
 437 
 438 # Get bit value...
 439 #
 440 sub GetBit {
 441   my($This, $BitNum) = @_;
 442 
 443   $This->_ValidateBitNumber("GetBit", $BitNum);
 444 
 445   return $This->_GetBitValue($BitNum);
 446 }
 447 
 448 # Is a specific bit set?
 449 #
 450 sub IsBitSet {
 451   my($This, $BitNum) = @_;
 452 
 453   if (!(defined($BitNum) && ($BitNum >= 0) && ($BitNum < $This->{Size}))) {
 454     return undef;
 455   }
 456 
 457   return $This->_GetBitValue($BitNum) ? 1 : 0;
 458 }
 459 
 460 # Is a specific bit clear?
 461 #
 462 sub IsBitClear {
 463   my($This, $BitNum) = @_;
 464 
 465   if (!(defined($BitNum) && ($BitNum >= 0) && ($BitNum < $This->{Size}))) {
 466     return undef;
 467   }
 468 
 469   return $This->_GetBitValue($BitNum) ? 0 : 1;
 470 }
 471 
 472 # Get number of set bits...
 473 #
 474 sub GetNumOfSetBits {
 475   my($This) = @_;
 476 
 477   return unpack("%b*", $This->{BitValues});
 478 }
 479 
 480 # Get number of clear bits...
 481 #
 482 sub GetNumOfClearBits {
 483   my($This) = @_;
 484 
 485   return ($This->{Size} - $This->GetNumOfSetBits());
 486 }
 487 
 488 # Get density of set bits...
 489 #
 490 sub GetDensityOfSetBits {
 491   my($This) = @_;
 492 
 493   return $This->{Size} ? ($This->GetNumOfSetBits()/$This->{Size}) : 0;
 494 }
 495 
 496 # Get density of clear bits...
 497 #
 498 sub GetDensityOfClearBits {
 499   my($This) = @_;
 500 
 501   return $This->GetNumOfClearBits()/$This->{Size};
 502 }
 503 
 504 # Convert internal bit values stored using Perl vec function with first string byte
 505 # as the lowest byte and first bit within each byte as the lowest bit into a binary
 506 # string with ascending or descending bit order within each byte. The internal
 507 # bit order corresponds to ascending bit order within each byte.
 508 #
 509 sub GetBitsAsBinaryString {
 510   my($This, $BitOrder) = @_;
 511 
 512   return $This->_GetBitsAsString('Binary', $BitOrder);
 513 }
 514 
 515 # Convert internal bit values stored using Perl vec function with first string byte
 516 # as the lowest byte and first bit within each byte as the lowest bit into a hexadecimal
 517 # string with ascending or descending bit order within each byte. The internal
 518 # bit order corresponds to ascending bit order within each byte.
 519 #
 520 #
 521 sub GetBitsAsHexadecimalString {
 522   my($This, $BitOrder) = @_;
 523 
 524   return $This->_GetBitsAsString('Hexadecimal', $BitOrder);
 525 }
 526 
 527 # Convert bit values into a octal string value...
 528 #
 529 sub GetBitsAsOctalString {
 530   my($This, $BitOrder) = @_;
 531 
 532   return $This->_GetBitsAsString('Octal', $BitOrder);
 533 }
 534 
 535 # Convert bit values into a decimal string value...
 536 #
 537 sub GetBitsAsDecimalString {
 538   my($This, $BitOrder) = @_;
 539 
 540   return $This->_GetBitsAsString('Decimal', $BitOrder);
 541 }
 542 
 543 # Return packed bit values which also contains nonprintable characters...
 544 #
 545 sub GetBitsAsRawBinaryString {
 546   my($This) = @_;
 547 
 548   return $This->_GetBitsAsString('RawBinary');
 549 }
 550 
 551 # Convert internal bit values stored using Perl vec function with first string byte
 552 # as the lowest byte and first bit within each byte as the lowest bit into a
 553 # string with ascending or descending bit order within each byte. The internal
 554 # bit order corresponds to ascending bit order within each byte.
 555 #
 556 #
 557 sub _GetBitsAsString {
 558   my($This, $Format, $BitOrder) = @_;
 559   my($BinaryTemplate, $HexadecimalTemplate);
 560 
 561   ($BinaryTemplate, $HexadecimalTemplate) = $This->_SetupBitsPackUnpackTemplate($BitOrder);
 562 
 563   FORMAT : {
 564     if ($Format =~ /^(Hexadecimal|Hex|HexadecimalString)$/i) { return unpack($HexadecimalTemplate, $This->{BitValues}); last FORMAT; }
 565     if ($Format =~ /^(Octal|Oct|OctalString)$/i) { return ConversionsUtil::HexadecimalToOctal(unpack($HexadecimalTemplate, $This->{BitValues})); last FORMAT; }
 566     if ($Format =~ /^(Decimal|Dec|DecimalString)$/i) { return ConversionsUtil::HexadecimalToDecimal(unpack($HexadecimalTemplate, $This->{BitValues})); last FORMAT; }
 567     if ($Format =~ /^(Binary|Bin|BinaryString)$/i) { return unpack($BinaryTemplate, $This->{BitValues}); last FORMAT; }
 568     if ($Format =~ /^(RawBinary|RawBin|RawBinaryString)$/i) { return $This->{BitValues}; last FORMAT; }
 569     croak "Error: ${ClassName}->_GetBitsAsString: Specified bit vector string format, $Format, is not supported. Value values: Binary, Bin, BinaryString, Hexdecimal, Hex, HexadecimalString, Decimal, Dec, DecimalString, Octal, Oct, OctalString, RawBinary, RawBin, RawBinaryString...";
 570   }
 571 }
 572 
 573 # Setup templates to unpack bits...
 574 #
 575 sub _SetupBitsPackUnpackTemplate {
 576   my($This, $BitOrder) = @_;
 577   my($BinaryTemplate, $HexadecimalTemplate);
 578 
 579   $BitOrder = (defined($BitOrder) && $BitOrder) ? $BitOrder : 'Ascending';
 580 
 581   if ($BitOrder =~ /^Ascending$/i) {
 582     $BinaryTemplate = "b*";
 583     $HexadecimalTemplate = "h*";
 584   }
 585   elsif ($BitOrder =~ /^Descending$/i) {
 586     $BinaryTemplate = "B*";
 587     $HexadecimalTemplate = "H*";
 588   }
 589   else {
 590     croak "Warning: ${ClassName}::_SetupBitsPackUnpackTemplate: Specified bit order value, $BitOrder, is not supported. Supported values: Ascending, Descending...";
 591   }
 592   return ($BinaryTemplate, $HexadecimalTemplate);
 593 }
 594 
 595 # Set bit values using hexadecimal string. The initial size of bit vector is not changed.
 596 #
 597 sub SetBitsAsHexadecimalString {
 598   my($This, $Hexadecimal, $BitOrder) = @_;
 599 
 600   if ($Hexadecimal =~ /^0x/i) {
 601     $Hexadecimal =~ s/^0x//i;
 602   }
 603   return $This->_SetBitsAsString('Hexadecimal', $Hexadecimal, $BitOrder);
 604 }
 605 
 606 # Set bit values using octal string. The initial size of bit vector is not changed.
 607 #
 608 sub SetBitsAsOctalString {
 609   my($This, $Octal, $BitOrder) = @_;
 610 
 611   if ($Octal =~ /^0/i) {
 612     $Octal =~ s/^0//i;
 613   }
 614   return $This->_SetBitsAsString('Octal', $Octal, $BitOrder);
 615 }
 616 
 617 # Set bit values using a decimal number. The initial size of bit vector is not changed.
 618 #
 619 sub SetBitsAsDecimalString {
 620   my($This, $Decimal, $BitOrder) = @_;
 621 
 622   if (!TextUtil::IsPositiveInteger($Decimal)) {
 623     croak "Error: ${ClassName}->SetBitsAsDecimalString: Specified decimal value, $Decimal, must be a positive integer...";
 624   }
 625   if ($Decimal =~ /[+]/) {
 626     $Decimal =~ s/[+]//;
 627   }
 628   return $This->_SetBitsAsString('Decimal', $Decimal, $BitOrder);
 629 }
 630 
 631 # Set bit values using hexadecimal string. The initial size of bit vector is not changed.
 632 #
 633 sub SetBitsAsBinaryString {
 634   my($This, $Binary, $BitOrder) = @_;
 635 
 636   if ($Binary =~ /^0b/i) {
 637     $Binary =~ s/^0b//i;
 638   }
 639   return $This->_SetBitsAsString('Binary', $Binary, $BitOrder);
 640 }
 641 
 642 # Set bit values using packed binary string. The size of bit vector is changed to reflect
 643 # the input raw string...
 644 #
 645 sub SetBitsAsRawBinaryString {
 646   my($This, $RawBinary) = @_;
 647 
 648   return $This->_SetBitsAsString('RawBinary', $RawBinary);
 649 }
 650 
 651 # Set bits using string in a specified format. This size of bit vector is not changed except for
 652 # RawBinary string type...
 653 #
 654 sub _SetBitsAsString {
 655   my($This, $Format, $String, $BitOrder) = @_;
 656   my($Size, $BinaryTemplate, $HexadecimalTemplate);
 657 
 658   ($BinaryTemplate, $HexadecimalTemplate) = $This->_SetupBitsPackUnpackTemplate($BitOrder);
 659 
 660   $Size = $This->{Size};
 661   FORMAT : {
 662     if ($Format =~ /^(Hexadecimal|Hex|HexadecimalString)$/i) { $This->{BitValues} = pack($HexadecimalTemplate, $String); last FORMAT; }
 663     if ($Format =~ /^(Octal|Oct|OctalString)$/i) { vec($This->{BitValues}, 0, $Size) = ConversionsUtil::OctalToDecimal($String); last FORMAT; }
 664     if ($Format =~ /^(Decimal|Dec|DecimalString)$/i) { vec($This->{BitValues}, 0, $Size) = $String; last FORMAT; }
 665     if ($Format =~ /^(Binary|Bin|BinaryString)$/i) { $This->{BitValues} = pack($BinaryTemplate, $String); last FORMAT; }
 666     if ($Format =~ /^(RawBinary|RawBin|RawBinaryString)$/i) { $This->{BitValues} = $String; last FORMAT; }
 667     croak "Error: ${ClassName}->_SetBitsAsString: Specified bit vector string format, $Format, is not supported. Value values: Binary, Bin, BinaryString, Hexdecimal, Hex, HexadecimalString, Decimal, Dec, DecimalString, Octal, Oct, OctalString, RawBinary, RawBin, RawBinaryString...";
 668   }
 669 
 670   # Set size using packed string...
 671   $Size = length($This->GetBitsAsBinaryString());
 672   if ($Size <=0) {
 673     croak "Error: ${ClassName}->_SetBitsAsString: Bit vector size, $Size, must be a positive integer...";
 674   }
 675   $This->{Size} = $Size;
 676 
 677   return $This;
 678 }
 679 
 680 # Calculate string size in bits...
 681 #
 682 sub _CalculateStringSizeInBits ($$;$) {
 683   my($FirstParameter, $SecondParameter, $ThisParameter) = @_;
 684   my($This, $Format, $String, $Size);
 685 
 686   if ((@_ == 3) && (_IsBitVector($FirstParameter))) {
 687     ($This, $Format, $String) = ($FirstParameter, $SecondParameter, $ThisParameter);
 688   }
 689   else {
 690     ($This, $Format, $String) = (undef, $FirstParameter, $SecondParameter);
 691   }
 692 
 693   FORMAT : {
 694     if ($Format =~ /^(Hexadecimal|Hex|HexadecimalString)$/i) { $Size = length($String) * 4; last FORMAT; }
 695     if ($Format =~ /^(Octal|Oct|OctalString)$/i) { $Size = length($String) * 3; last FORMAT; }
 696     if ($Format =~ /^(Decimal|Dec|DecimalString)$/i) { $Size = length(ConversionsUtil::DecimalToHexadecimal($String)) * 4; last FORMAT; }
 697     if ($Format =~ /^(Binary|Bin|BinaryString)$/i) { $Size = length($String); last FORMAT; }
 698     if ($Format =~ /^(RawBinary|RawBin|RawBinaryString)$/i) { $Size = length(unpack("B*", $String)); last FORMAT; }
 699     croak "Error: ${ClassName}::_CalculateStringSizeInBits: Specified bit vector string format, $Format, is not supported. Value values: Binary, Bin, BinaryString, Hexdecimal, Hex, HexadecimalString, Decimal, Dec, DecimalString, Octal, Oct, OctalString, RawBinary, RawBin, RawBinaryString...";
 700   }
 701   return $Size;
 702 }
 703 
 704 # Set bit value using Perl vec function with bit numbers going from left to right.
 705 # First bit number corresponds to 0.
 706 #
 707 sub _SetBitValue {
 708   my($This, $BitNum, $BitValue) = @_;
 709   my($Offset, $Width);
 710 
 711   $Offset = $BitNum;
 712   $Width = 1;
 713 
 714   vec($This->{BitValues}, $Offset, $Width) = $BitValue;
 715 
 716   return $This;
 717 }
 718 
 719 # Get bit value Perl vec function with bit numbers going from left to right.
 720 # First bit number corresponds to 0.
 721 #
 722 sub _GetBitValue {
 723   my($This, $BitNum) = @_;
 724   my($Offset, $Width, $BitValue);
 725 
 726   $Offset = $BitNum;
 727   $Width = 1;
 728 
 729   $BitValue = vec($This->{BitValues}, $Offset, $Width);
 730 
 731   return $BitValue;
 732 }
 733 
 734 # Check to make sure it's a valid bit number...
 735 #
 736 sub _ValidateBitNumber {
 737   my($This, $CallerName, $BitNum) = @_;
 738 
 739   if (!defined $BitNum) {
 740     croak "Error: ${ClassName}->${CallerName}: Bit number is not defined...";
 741   }
 742   if ($BitNum < 0) {
 743     croak "Error: ${ClassName}->${CallerName}: Bit number value, $BitNum, must be >= 0 ...";
 744   }
 745   if ($BitNum >= $This->{Size}) {
 746     croak "Error: ${ClassName}->${CallerName}: Bit number number value, $BitNum, must be less than the size of bit vector, ", $This->{Size}, "...";
 747   }
 748 
 749   return $This;
 750 }
 751 
 752 # Set bit values print format for an individual object or the whole class...
 753 #
 754 sub SetBitValuePrintFormat ($;$) {
 755   my($FirstParameter, $SecondParameter) = @_;
 756 
 757   if ((@_ == 2) && (_IsBitVector($FirstParameter))) {
 758     # Set bit values print format for the specific object...
 759     my($This, $ValuePrintFormat) = ($FirstParameter, $SecondParameter);
 760 
 761     if (!_ValidateBitValuePrintFormat($ValuePrintFormat)) {
 762       return;
 763     }
 764 
 765     $This->{ValueFormat} = $ValuePrintFormat;
 766   }
 767   else {
 768     # Set value print format for the class...
 769     my($ValuePrintFormat) = ($FirstParameter);
 770 
 771     if (!_ValidateBitValuePrintFormat($ValuePrintFormat)) {
 772       return;
 773     }
 774 
 775     $ValueFormat = $ValuePrintFormat;
 776   }
 777 }
 778 
 779 # Set bit values bit order for an individual object or the whole class...
 780 #
 781 sub SetBitValueBitOrder ($;$) {
 782   my($FirstParameter, $SecondParameter) = @_;
 783 
 784   if ((@_ == 2) && (_IsBitVector($FirstParameter))) {
 785     # Set bit value bit order for the specific object...
 786     my($This, $BitOrder) = ($FirstParameter, $SecondParameter);
 787 
 788     if (!_ValidateBitValueBitOrder($BitOrder)) {
 789       return;
 790     }
 791 
 792     $This->{ValueBitOrder} = $BitOrder;
 793   }
 794   else {
 795     # Set bit value bit order for the class...
 796     my($BitOrder) = ($FirstParameter);
 797 
 798     if (!_ValidateBitValueBitOrder($BitOrder)) {
 799       return;
 800     }
 801 
 802     $ValueBitOrder = $BitOrder;
 803   }
 804 }
 805 
 806 # Validate print format for bit values...
 807 sub _ValidateBitValueBitOrder {
 808   my($BitOrder) = @_;
 809 
 810   if ($BitOrder !~ /^(Ascending|Descending)$/i) {
 811     carp "Warning: ${ClassName}::_ValidateBitValueBitOrder: Specified bit order value, $BitOrder, is not supported. Supported values: Ascending, Descending...";
 812     return 0;
 813   }
 814   return 1;
 815 }
 816 
 817 # Validate print format for bit values...
 818 sub _ValidateBitValuePrintFormat {
 819   my($ValuePrintFormat) = @_;
 820 
 821   if ($ValuePrintFormat !~ /^(Binary|Bin||BinaryString|Hexadecimal|Hex||HexadecimalString|Decimal|Dec||DecimalString|Octal|Oct||OctalString|RawBinary|RawBin|RawBinaryString)$/i) {
 822     carp "Warning: ${ClassName}::_ValidateBitValuePrintFormat: Specified bit vector print format value, $ValuePrintFormat, is not supported. Supported values: Binary, Bin, BinaryString, Hexdecimal, Hex, HexadecimalString, Decimal, Dec, DecimalString, Octal, Oct, OctalString, RawBinary, RawBin, RawBinaryString...";
 823     return 0;
 824   }
 825   return 1;
 826 }
 827 
 828 # Bitwise AND operation for BitVectors...
 829 #
 830 sub _BitVectorAndOperator {
 831   my($This, $Other, $OrderFlipped, $OtherIsBitVector, $ErrorMsg, $CheckBitVectorSizes);
 832 
 833   $ErrorMsg = "_BitVectorAndOperator: Bitwise AND oparation failed";
 834   $CheckBitVectorSizes = 1;
 835   ($This, $Other, $OrderFlipped, $OtherIsBitVector) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_, $CheckBitVectorSizes);
 836 
 837   if (!$OtherIsBitVector) {
 838     if ($OrderFlipped) {
 839       croak "Error: ${ClassName}->${ErrorMsg}: First object must be a bit vector...";
 840     }
 841   }
 842   my($BitVector);
 843   $BitVector = (ref $This)->new($This->{Size});
 844   $BitVector->{BitValues} = $This->{BitValues} & $Other->{BitValues};
 845 
 846   return $BitVector;
 847 }
 848 
 849 # Bitwise OR operation for BitVectors...
 850 #
 851 sub _BitVectorOrOperator {
 852   my($This, $Other, $OrderFlipped, $OtherIsBitVector, $ErrorMsg, $CheckBitVectorSizes);
 853 
 854   $ErrorMsg = "_BitVectorAndOperator: Bitwise OR oparation failed";
 855   $CheckBitVectorSizes = 1;
 856   ($This, $Other, $OrderFlipped, $OtherIsBitVector) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_, $CheckBitVectorSizes);
 857 
 858   if (!$OtherIsBitVector) {
 859     if ($OrderFlipped) {
 860       croak "Error: ${ClassName}->${ErrorMsg}: First object must be a bit vector...";
 861     }
 862   }
 863   my($BitVector);
 864   $BitVector = (ref $This)->new($This->{Size});
 865   $BitVector->{BitValues} = $This->{BitValues} | $Other->{BitValues};
 866 
 867   return $BitVector;
 868 }
 869 
 870 # Bitwise XOR operation for BitVectors...
 871 #
 872 sub _BitVectorExclusiveOrOperator {
 873   my($This, $Other, $OrderFlipped, $OtherIsBitVector, $ErrorMsg, $CheckBitVectorSizes);
 874 
 875   $ErrorMsg = "_BitVectorAndOperator: Bitwise XOR oparation failed";
 876   $CheckBitVectorSizes = 1;
 877   ($This, $Other, $OrderFlipped, $OtherIsBitVector) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_, $CheckBitVectorSizes);
 878 
 879   if (!$OtherIsBitVector) {
 880     if ($OrderFlipped) {
 881       croak "Error: ${ClassName}->${ErrorMsg}: First object must be a bit vector...";
 882     }
 883   }
 884   my($BitVector);
 885   $BitVector = (ref $This)->new($This->{Size});
 886   $BitVector->{BitValues} = $This->{BitValues} ^ $Other->{BitValues};
 887 
 888   return $BitVector;
 889 }
 890 
 891 # Bitwise negation operation for BitVectors...
 892 #
 893 sub _BitVectorNegationOperator {
 894   my($This, $Other, $OrderFlipped, $OtherIsBitVector, $ErrorMsg, $CheckBitVectorSizes);
 895 
 896   $ErrorMsg = "_BitVectorAndOperator: Bitwise negation oparation failed";
 897   $CheckBitVectorSizes = 1;
 898   ($This, $Other, $OrderFlipped, $OtherIsBitVector) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_, $CheckBitVectorSizes);
 899 
 900   my($BitVector);
 901   $BitVector = (ref $This)->new($This->{Size});
 902   $BitVector->{BitValues} = ~ $This->{BitValues};
 903 
 904   return $BitVector;
 905 }
 906 
 907 # Bit vector equla operator. Two bit vectors are considered equal assuming their size
 908 # is same and bits are on at the same positions...
 909 #
 910 sub _BitVectorEqualOperator {
 911   my($This, $Other, $OrderFlipped, $OtherIsBitVector, $ErrorMsg, $CheckBitVectorSizes);
 912 
 913   $ErrorMsg = "_BitVectorEqualOperator: BitVector == oparation failed";
 914   $CheckBitVectorSizes = 0;
 915   ($This, $Other, $OrderFlipped, $OtherIsBitVector) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_, $CheckBitVectorSizes);
 916 
 917   if (!$OtherIsBitVector) {
 918     if ($OrderFlipped) {
 919       croak "Error: ${ClassName}->${ErrorMsg}: First object must be a bit vector...";
 920     }
 921   }
 922   if ($This->GetSize() != $Other->GetSize()) {
 923     return 0;
 924   }
 925   if ($This->GetNumOfSetBits() != $Other->GetNumOfSetBits()) {
 926     return 0;
 927   }
 928   # Check number of On bits only in This vector. It must be zero for vectors to be equal...
 929   my($BitVector);
 930   $BitVector = $This & ~$Other;
 931 
 932   return $BitVector->GetNumOfSetBits() ? 0 : 1;
 933 }
 934 
 935 # Bit vector not equal operator. Two bit vectors are considered not equal when their size
 936 # is different or bits are on at the same positions...
 937 #
 938 sub _BitVectorNotEqualOperator {
 939   my($This, $Other, $OrderFlipped, $OtherIsBitVector, $ErrorMsg, $CheckBitVectorSizes);
 940 
 941   $ErrorMsg = "_BitVectorEqualOperator: BitVector != oparation failed";
 942   $CheckBitVectorSizes = 0;
 943   ($This, $Other, $OrderFlipped, $OtherIsBitVector) = _ProcessOverloadedOperatorParameters($ErrorMsg, @_, $CheckBitVectorSizes);
 944 
 945   if (!$OtherIsBitVector) {
 946     if ($OrderFlipped) {
 947       croak "Error: ${ClassName}->${ErrorMsg}: First object must be a bit vector...";
 948     }
 949   }
 950   if ($This->GetSize() != $Other->GetSize()) {
 951     return 1;
 952   }
 953   if ($This->GetNumOfSetBits() != $Other->GetNumOfSetBits()) {
 954     return 1;
 955   }
 956   # Check number of On bits only in This vector. It must be zero for vectors to be equal...
 957   my($BitVector);
 958   $BitVector = $This & ~$Other;
 959 
 960   return $BitVector->GetNumOfSetBits() ? 1 : 0;
 961 }
 962 
 963 # Process parameters passed to overloaded operators...
 964 #
 965 # For uninary operators, $SecondParameter is not defined.
 966 sub _ProcessOverloadedOperatorParameters {
 967   my($ErrorMsg, $FirstParameter, $SecondParameter, $ParametersOrderStatus, $CheckBitVectorSizesStatus) = @_;
 968   my($This, $Other, $OrderFlipped, $OtherIsBitVector, $CheckBitVectorSizes);
 969 
 970   ($This, $Other) =  ($FirstParameter, $SecondParameter);
 971   $OrderFlipped = (defined($ParametersOrderStatus) && $ParametersOrderStatus) ? 1 : 0;
 972   $CheckBitVectorSizes = (defined $CheckBitVectorSizesStatus) ? $CheckBitVectorSizesStatus : 1;
 973 
 974   _ValidateBitVector($ErrorMsg, $This);
 975 
 976   $OtherIsBitVector = 0;
 977   if (defined($Other) && (ref $Other)) {
 978     # Make sure $Other is a vector...
 979     _ValidateBitVector($ErrorMsg, $Other);
 980     if ($CheckBitVectorSizes) {
 981       _ValidateBitVectorSizesAreEqual($ErrorMsg, $This, $Other);
 982     }
 983     $OtherIsBitVector = 1;
 984   }
 985   return ($This, $Other, $OrderFlipped, $OtherIsBitVector);
 986 }
 987 
 988 # Is it a bit vector object?
 989 sub _IsBitVector {
 990   my($Object) = @_;
 991 
 992   return (Scalar::Util::blessed($Object) && $Object->isa($ClassName)) ? 1 : 0;
 993 }
 994 
 995 # Make sure it's a bit vector reference...
 996 sub _ValidateBitVector {
 997   my($ErrorMsg, $Vector) = @_;
 998 
 999   if (!_IsBitVector($Vector)) {
1000     croak "Error: ${ClassName}->${ErrorMsg}: Object must be a bit vector...";
1001   }
1002 }
1003 
1004 # Make sure size of the two bit vectors are equal...
1005 sub _ValidateBitVectorSizesAreEqual {
1006   my($ErrorMsg, $BitVector1, $BitVector2) = @_;
1007 
1008   if ($BitVector1->GetSize() != $BitVector2->GetSize()) {
1009     croak "Error: ${ClassName}->${ErrorMsg}: Size of the bit vectors must be same...";
1010   }
1011 }
1012 
1013 # Return a string containing vector values...
1014 sub StringifyBitVector {
1015   my($This) = @_;
1016   my($BitVectorString, $PrintFormat, $BitOrder, $BitsValue);
1017 
1018   $PrintFormat = (exists $This->{ValueFormat}) ? $This->{ValueFormat} : $ValueFormat;
1019   $BitOrder = (exists $This->{ValueBitOrder}) ? $This->{ValueBitOrder} : $ValueBitOrder;
1020   $BitVectorString = '';
1021 
1022   FORMAT: {
1023       if ($PrintFormat =~ /^(Hexadecimal|Hex|HexadecimalString)$/i) { $BitsValue = $This->_GetBitsAsString('Hexadecimal', $BitOrder);  last FORMAT; }
1024       if ($PrintFormat =~ /^(Octal|Oct|OctalString)$/i) { $BitsValue = $This->_GetBitsAsString('Octal', $BitOrder);  last FORMAT; }
1025       if ($PrintFormat =~ /^(Decimal|Dec|DecimalString)$/i) { $BitsValue = $This->_GetBitsAsString('Decimal', $BitOrder);  last FORMAT; }
1026       if ($PrintFormat =~ /^(RawBinary|RawBin|RawBinaryString)$/i) { $BitsValue = $This->_GetBitsAsString('RawBinary');  last FORMAT; }
1027       # Default is bninary format...
1028       $BitsValue = $This->_GetBitsAsString('Binary', $BitOrder);
1029   }
1030   $BitVectorString = "<Size: ". $This->GetSize() . ";BitOrder: $BitOrder; Value: " . $BitsValue . ">";
1031 
1032   return $BitVectorString;
1033 }
1034