File: //usr/local/rvm/gems/ruby-2.5.9/gems/tzinfo-2.0.4/lib/tzinfo/string_deduper.rb
# encoding: UTF-8
# frozen_string_literal: true
require 'concurrent'
module TZInfo
# Maintains a pool of `String` instances. The {#dedupe} method will return
# either a pooled copy of a given `String` or add the instance to the pool.
#
# @private
class StringDeduper #:nodoc:
class << self
# @return [StringDeduper] a globally available singleton instance of
# {StringDeduper}. This instance is safe for use in concurrently
# executing threads.
attr_reader :global
end
# Initializes a new {StringDeduper}.
def initialize
@strings = create_hash do |h, k|
v = k.dup.freeze
h[v] = v
end
end
# @param string [String] the string to deduplicate.
# @return [bool] `string` if it is frozen, otherwise a frozen, possibly
# pre-existing copy of `string`.
def dedupe(string)
return string if string.frozen?
@strings[string]
end
protected
# Creates a `Hash` to store pooled `String` instances.
#
# @param block [Proc] Default value block to be passed to `Hash.new`.
# @return [Hash] a `Hash` to store pooled `String` instances.
def create_hash(&block)
Hash.new(&block)
end
end
private_constant :StringDeduper
# A thread-safe version of {StringDeduper}.
#
# @private
class ConcurrentStringDeduper < StringDeduper #:nodoc:
protected
def create_hash(&block)
Concurrent::Map.new(&block)
end
end
private_constant :ConcurrentStringDeduper
string_unary_minus_does_dedupe = if '0'.respond_to?(:-@)
# :nocov_no_string_-@:
s1 = -('0'.dup)
s2 = -('0'.dup)
s1.object_id == s2.object_id
# :nocov_no_string_-@:
else
# :nocov_string_-@:
false
# :nocov_string_-@:
end
if string_unary_minus_does_dedupe
# :nocov_no_deduping_string_unary_minus:
# An implementation of {StringDeduper} using the `String#-@` method where
# that method performs deduplication (Ruby 2.5 and later).
#
# Note that this is slightly different to the plain {StringDeduper}
# implementation. In this implementation, frozen literal strings are already
# in the pool and are candidates for being returned, even when passed
# another equal frozen non-literal string. {StringDeduper} will always
# return frozen strings.
#
# There are also differences in encoding handling. This implementation will
# treat strings with different encodings as different strings.
# {StringDeduper} will treat strings with the compatible encodings as the
# same string.
#
# @private
class UnaryMinusGlobalStringDeduper #:nodoc:
# @param string [String] the string to deduplicate.
# @return [bool] `string` if it is frozen, otherwise a frozen, possibly
# pre-existing copy of `string`.
def dedupe(string)
# String#-@ on Ruby 2.6 will dedupe a frozen non-literal String. Ruby
# 2.5 will just return frozen strings.
#
# The pooled implementation can't tell the difference between frozen
# literals and frozen non-literals, so must always return frozen String
# instances to avoid doing unncessary work when loading format 2
# TZInfo::Data modules.
#
# For compatibility with the pooled implementation, just return frozen
# string instances (acting like Ruby 2.5).
return string if string.frozen?
-string
end
end
private_constant :UnaryMinusGlobalStringDeduper
StringDeduper.instance_variable_set(:@global, UnaryMinusGlobalStringDeduper.new)
# :nocov_no_deduping_string_unary_minus:
else
# :nocov_deduping_string_unary_minus:
StringDeduper.instance_variable_set(:@global, ConcurrentStringDeduper.new)
# :nocov_deduping_string_unary_minus:
end
end