class BSON::Decimal128::Builder::FromString

Helper class for parsing a String into Decimal128 high and low bits.

@api private

@since 4.2.0

Constants

INFINITY_REGEX

Regex matching a string representing positive or negative Infinity.

@return [ Regex ] A regex matching a positive or negative Infinity string.

@since 4.2.0

NAN_REGEX

Regex matching a string representing NaN.

@return [ Regex ] A regex matching a NaN string.

@since 4.2.0

SCIENTIFIC_EXPONENT_REGEX

Regex matching a scientific exponent.

@return [ Regex ] A regex matching E, e, E+, e+.

@since 4.2.0

SIGNIFICAND_WITH_LEADING_ZEROS_REGEX

Regex for the fraction, including leading zeros.

@return [ Regex ] The regex for matching the fraction,

including leading zeros.

@since 4.2.0

SIGN_AND_DIGITS_REGEX

Regex for separating a negative sign from the significands.

@return [ Regex ] The regex for separating a sign from significands.

@since 4.2.0

TRAILING_ZEROS_REGEX

Regex for capturing trailing zeros.

@since 4.2.0

VALID_DECIMAL128_STRING_REGEX

Regex for a valid decimal128 string format.

@return [ Regex ] The regex for a valid decimal128 string.

@since 4.2.0

Public Class Methods

new(string) click to toggle source

Initialize the FromString Builder object.

@example Create the FromString builder.

Builder::FromString.new(string)

@param [ String ] string The string to create a Decimal128 from.

@since 4.2.0

# File lib/bson/decimal128/builder.rb, line 163
def initialize(string)
  @string = string
end

Public Instance Methods

bits() click to toggle source

Get the bits representing the Decimal128 that the string corresponds to.

@example Get the bits for the Decimal128 object created from the string.

builder.bits

@return [ Array ] Tuple of the low and high bits.

@since 4.2.0

# File lib/bson/decimal128/builder.rb, line 175
def bits
  if special?
    to_special_bits
  else
    validate_format!
    to_bits
  end
end

Private Instance Methods

clamp(exponent, significand) click to toggle source
# File lib/bson/decimal128/builder.rb, line 226
def clamp(exponent, significand)
  if exponent > Decimal128::MAX_EXPONENT
    if significand.to_i == 0
      adjust = exponent - Decimal128::MAX_EXPONENT
      significand = '0'
    else
      adjust = [ (exponent - Decimal128::MAX_EXPONENT),
                 Decimal128::MAX_DIGITS_OF_PRECISION - significand.length ].min
      significand << '0'* adjust
    end
    exponent -= adjust
  end

  [ exponent, significand ]
end
round_exact(exponent, significand) click to toggle source
# File lib/bson/decimal128/builder.rb, line 202
def round_exact(exponent, significand)
  if exponent < Decimal128::MIN_EXPONENT
    if significand.to_i == 0
      round = Decimal128::MIN_EXPONENT - exponent
      exponent += round
    elsif trailing_zeros = TRAILING_ZEROS_REGEX.match(significand)
      round = [ (Decimal128::MIN_EXPONENT - exponent),
                trailing_zeros[1].size ].min
      significand = significand[0...-round]
      exponent += round
    end
  elsif significand.length > Decimal128::MAX_DIGITS_OF_PRECISION
    trailing_zeros = TRAILING_ZEROS_REGEX.match(significand)
    if trailing_zeros
      round = [ trailing_zeros[1].size,
                (significand.length - Decimal128::MAX_DIGITS_OF_PRECISION),
                (Decimal128::MAX_EXPONENT - exponent)].min
      significand = significand[0...-round]
      exponent += round
    end
  end
  [ exponent, significand ]
end
special?() click to toggle source
# File lib/bson/decimal128/builder.rb, line 255
def special?
  @string =~ NAN_REGEX || @string =~ INFINITY_REGEX
end
to_bits() click to toggle source
# File lib/bson/decimal128/builder.rb, line 186
def to_bits
  original, sign, digits_str = SIGN_AND_DIGITS_REGEX.match(@string).to_a
  digits, e, scientific_exp = digits_str.partition(SCIENTIFIC_EXPONENT_REGEX)
  before_decimal, decimal, after_decimal = digits.partition('.')

  significand_str = before_decimal << after_decimal
  significand_str = SIGNIFICAND_WITH_LEADING_ZEROS_REGEX.match(significand_str).to_a[2]

  exponent = -(after_decimal.length)
  exponent = exponent + scientific_exp.to_i
  exponent, significand_str = round_exact(exponent, significand_str)
  exponent, significand_str = clamp(exponent, significand_str)

  Builder.parts_to_bits(significand_str.to_i, exponent, sign == '-')
end
to_special_bits() click to toggle source
# File lib/bson/decimal128/builder.rb, line 242
def to_special_bits
  high = 0
  if match = NAN_REGEX.match(@string)
    high = NAN_MASK
    high = high | SIGN_BIT_MASK if match[1]
    high = high | SNAN_MASK if match[2]
  elsif match = INFINITY_REGEX.match(@string)
    high = INFINITY_MASK
    high = high | SIGN_BIT_MASK if match[1] == '-'
  end
  [ 0, high ]
end
validate_format!() click to toggle source
# File lib/bson/decimal128/builder.rb, line 259
def validate_format!
  raise BSON::Decimal128::InvalidString.new unless @string =~ VALID_DECIMAL128_STRING_REGEX
end