thread_safe-0.3.6/ 0000755 0000041 0000041 00000000000 13062220653 014014 5 ustar www-data www-data thread_safe-0.3.6/yard-template/ 0000755 0000041 0000041 00000000000 13062220653 016564 5 ustar www-data www-data thread_safe-0.3.6/yard-template/default/ 0000755 0000041 0000041 00000000000 13062220653 020210 5 ustar www-data www-data thread_safe-0.3.6/yard-template/default/layout/ 0000755 0000041 0000041 00000000000 13062220653 021525 5 ustar www-data www-data thread_safe-0.3.6/yard-template/default/layout/html/ 0000755 0000041 0000041 00000000000 13062220653 022471 5 ustar www-data www-data thread_safe-0.3.6/yard-template/default/layout/html/footer.erb 0000644 0000041 0000041 00000001200 13062220653 024452 0 ustar www-data www-data
thread_safe-0.3.6/yard-template/default/fulldoc/ 0000755 0000041 0000041 00000000000 13062220653 021640 5 ustar www-data www-data thread_safe-0.3.6/yard-template/default/fulldoc/html/ 0000755 0000041 0000041 00000000000 13062220653 022604 5 ustar www-data www-data thread_safe-0.3.6/yard-template/default/fulldoc/html/css/ 0000755 0000041 0000041 00000000000 13062220653 023374 5 ustar www-data www-data thread_safe-0.3.6/yard-template/default/fulldoc/html/css/common.css 0000644 0000041 0000041 00000004146 13062220653 025403 0 ustar www-data www-data /* Override this file with custom rules */ body { line-height: 18px; } .docstring code, .docstring .object_link a, #filecontents code { padding: 0px 3px 1px 3px; border: 1px solid #eef; background: #f5f5ff; } #filecontents pre code, .docstring pre code { border: none; background: none; padding: 0; } #filecontents pre.code, .docstring pre.code, .tags pre.example, .docstring code, .docstring .object_link a, #filecontents code { -moz-border-radius: 2px; -webkit-border-radius: 2px; } /* syntax highlighting */ .source_code { display: none; padding: 3px 8px; border-left: 8px solid #ddd; margin-top: 5px; } #filecontents pre.code, .docstring pre.code, .source_code pre { font-family: monospace; } #filecontents pre.code, .docstring pre.code { display: block; } .source_code .lines { padding-right: 12px; color: #555; text-align: right; } #filecontents pre.code, .docstring pre.code, .tags pre.example { padding: 5px 12px; margin-top: 4px; border: 1px solid #eef; background: #f5f5ff; } pre.code { color: #000; } pre.code .info.file { color: #555; } pre.code .val { color: #036A07; } pre.code .tstring_content, pre.code .heredoc_beg, pre.code .heredoc_end, pre.code .qwords_beg, pre.code .qwords_end, pre.code .tstring, pre.code .dstring { color: #036A07; } pre.code .fid, pre.code .rubyid_new, pre.code .rubyid_to_s, pre.code .rubyid_to_sym, pre.code .rubyid_to_f, pre.code .rubyid_to_i, pre.code .rubyid_each { color: inherit; } pre.code .comment { color: #777; font-style: italic; } pre.code .const, pre.code .constant { color: inherit; font-weight: bold; font-style: italic; } pre.code .label, pre.code .symbol { color: #C5060B; } pre.code .kw, pre.code .rubyid_require, pre.code .rubyid_extend, pre.code .rubyid_include, pre.code .int { color: #0000FF; } pre.code .ivar { color: #660E7A; } pre.code .gvar, pre.code .rubyid_backref, pre.code .rubyid_nth_ref { color: #6D79DE; } pre.code .regexp, .dregexp { color: #036A07; } pre.code a { border-bottom: 1px dotted #bbf; } thread_safe-0.3.6/Rakefile 0000644 0000041 0000041 00000003223 13062220653 015461 0 ustar www-data www-data require 'bundler/gem_tasks' require 'rspec' require 'rspec/core/rake_task' ## safely load all the rake tasks in the `tasks` directory def safe_load(file) begin load file rescue LoadError => ex puts "Error loading rake tasks from '#{file}' but will continue..." puts ex.message end end Dir.glob('tasks/**/*.rake').each do |rakefile| safe_load rakefile end task :default => :test if defined?(JRUBY_VERSION) require 'ant' directory 'pkg/classes' directory 'pkg/tests' desc "Clean up build artifacts" task :clean do rm_rf "pkg/classes" rm_rf "pkg/tests" rm_rf "lib/thread_safe/jruby_cache_backend.jar" end desc "Compile the extension" task :compile => "pkg/classes" do |t| ant.javac :srcdir => "ext", :destdir => t.prerequisites.first, :source => "1.5", :target => "1.5", :debug => true, :classpath => "${java.class.path}:${sun.boot.class.path}" end desc "Build the jar" task :jar => :compile do ant.jar :basedir => "pkg/classes", :destfile => "lib/thread_safe/jruby_cache_backend.jar", :includes => "**/*.class" end desc "Build test jar" task 'test-jar' => 'pkg/tests' do |t| ant.javac :srcdir => 'spec/src', :destdir => t.prerequisites.first, :source => "1.5", :target => "1.5", :debug => true ant.jar :basedir => 'pkg/tests', :destfile => 'spec/package.jar', :includes => '**/*.class' end task :package => [ :clean, :compile, :jar, 'test-jar' ] else # No need to package anything for non-jruby rubies task :package end RSpec::Core::RakeTask.new :test => :package do |t| t.rspec_opts = '--color --backtrace --tag ~unfinished --seed 1 --format documentation ./spec' end thread_safe-0.3.6/Gemfile 0000644 0000041 0000041 00000001217 13062220653 015310 0 ustar www-data www-data source 'https://rubygems.org' gemspec group :development, :test do gem 'rspec', '~> 3.2.0' gem 'simplecov', '~> 0.9.2', :require => false if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.0.0') gem 'term-ansicolor', '~> 1.3.2', :require => false gem 'tins', '~> 1.6.0', :require => false end gem 'coveralls', '~> 0.7.11', :require => false end group :documentation do gem 'countloc', '~> 0.4.0', :platforms => :mri, :require => false gem 'yard', '~> 0.8.7.6', :require => false gem 'inch', '~> 0.5.10', :platforms => :mri, :require => false gem 'redcarpet', '~> 3.2.2', platforms: :mri # understands github markdown end thread_safe-0.3.6/examples/ 0000755 0000041 0000041 00000000000 13062220653 015632 5 ustar www-data www-data thread_safe-0.3.6/examples/bench_cache.rb 0000755 0000041 0000041 00000001131 13062220653 020360 0 ustar www-data www-data #!/usr/bin/env ruby -wKU require "benchmark" require "thread_safe" hash = {} cache = ThreadSafe::Cache.new ENTRIES = 10_000 ENTRIES.times do |i| hash[i] = i cache[i] = i end TESTS = 40_000_000 Benchmark.bmbm do |results| key = rand(10_000) results.report('Hash#[]') do TESTS.times { hash[key] } end results.report('Cache#[]') do TESTS.times { cache[key] } end results.report('Hash#each_pair') do (TESTS / ENTRIES).times { hash.each_pair {|k,v| v} } end results.report('Cache#each_pair') do (TESTS / ENTRIES).times { cache.each_pair {|k,v| v} } end end thread_safe-0.3.6/.rspec 0000644 0000041 0000041 00000000050 13062220653 015124 0 ustar www-data www-data --require spec_helper --format progress thread_safe-0.3.6/thread_safe.gemspec 0000644 0000041 0000041 00000002440 13062220653 017626 0 ustar www-data www-data # -*- encoding: utf-8 -*- $:.push File.expand_path('../lib', __FILE__) unless $:.include?('lib') require 'thread_safe/version' Gem::Specification.new do |gem| gem.authors = ["Charles Oliver Nutter", "thedarkone"] gem.email = ["headius@headius.com", "thedarkone2@gmail.com"] gem.summary = %q{Thread-safe collections and utilities for Ruby} gem.description = %q{A collection of data structures and utilities to make thread-safe programming in Ruby easier} gem.homepage = "https://github.com/ruby-concurrency/thread_safe" gem.files = `git ls-files`.split($\) gem.files += ['lib/thread_safe/jruby_cache_backend.jar'] if defined?(JRUBY_VERSION) gem.files -= ['.gitignore'] # see https://github.com/headius/thread_safe/issues/40#issuecomment-42315441 gem.platform = 'java' if defined?(JRUBY_VERSION) gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) } gem.test_files = gem.files.grep(%r{^(test|spec|features)/}) gem.name = "thread_safe" gem.require_paths = ["lib"] gem.version = ThreadSafe::VERSION gem.license = "Apache-2.0" gem.add_development_dependency 'atomic', '= 1.1.16' gem.add_development_dependency 'rake', '< 12.0' gem.add_development_dependency 'rspec', '~> 3.2' end thread_safe-0.3.6/spec/ 0000755 0000041 0000041 00000000000 13062220653 014746 5 ustar www-data www-data thread_safe-0.3.6/spec/src/ 0000755 0000041 0000041 00000000000 13062220653 015535 5 ustar www-data www-data thread_safe-0.3.6/spec/src/thread_safe/ 0000755 0000041 0000041 00000000000 13062220653 020002 5 ustar www-data www-data thread_safe-0.3.6/spec/src/thread_safe/SecurityManager.java 0000644 0000041 0000041 00000000750 13062220653 023751 0 ustar www-data www-data package thread_safe; import java.security.Permission; import java.util.ArrayList; import java.util.List; public class SecurityManager extends java.lang.SecurityManager { private final ListUsages of this class should typically be of the form: * {@code ThreadLocalRandom.current().nextX(...)} (where * {@code X} is {@code Int}, {@code Long}, etc). * When all usages are of this form, it is never possible to * accidently share a {@code ThreadLocalRandom} across multiple threads. * *
This class also provides additional commonly used bounded random
* generation methods.
*
* @since 1.7
* @author Doug Lea
*/
public class ThreadLocalRandom extends Random {
// same constants as Random, but must be redeclared because private
private static final long multiplier = 0x5DEECE66DL;
private static final long addend = 0xBL;
private static final long mask = (1L << 48) - 1;
/**
* The random seed. We can't use super.seed.
*/
private long rnd;
/**
* Initialization flag to permit calls to setSeed to succeed only
* while executing the Random constructor. We can't allow others
* since it would cause setting seed in one part of a program to
* unintentionally impact other usages by the thread.
*/
boolean initialized;
// Padding to help avoid memory contention among seed updates in
// different TLRs in the common case that they are located near
// each other.
private long pad0, pad1, pad2, pad3, pad4, pad5, pad6, pad7;
/**
* The actual ThreadLocal
*/
private static final ThreadLocal This class is usually preferable to {@link AtomicLong} when
* multiple threads update a common sum that is used for purposes such
* as collecting statistics, not for fine-grained synchronization
* control. Under low update contention, the two classes have similar
* characteristics. But under high contention, expected throughput of
* this class is significantly higher, at the expense of higher space
* consumption.
*
* This class extends {@link Number}, but does not define
* methods such as {@code hashCode} and {@code compareTo} because
* instances are expected to be mutated, and so are not useful as
* collection keys.
*
* jsr166e note: This class is targeted to be placed in
* java.util.concurrent.atomic.
*
* @since 1.8
* @author Doug Lea
*/
public class LongAdder extends Striped64 implements Serializable {
private static final long serialVersionUID = 7249069246863182397L;
/**
* Version of plus for use in retryUpdate
*/
final long fn(long v, long x) { return v + x; }
/**
* Creates a new adder with initial sum of zero.
*/
public LongAdder() {
}
/**
* Adds the given value.
*
* @param x the value to add
*/
public void add(long x) {
Cell[] as; long b, v; HashCode hc; Cell a; int n;
if ((as = cells) != null || !casBase(b = base, b + x)) {
boolean uncontended = true;
int h = (hc = threadHashCode.get()).code;
if (as == null || (n = as.length) < 1 ||
(a = as[(n - 1) & h]) == null ||
!(uncontended = a.cas(v = a.value, v + x)))
retryUpdate(x, hc, uncontended);
}
}
/**
* Equivalent to {@code add(1)}.
*/
public void increment() {
add(1L);
}
/**
* Equivalent to {@code add(-1)}.
*/
public void decrement() {
add(-1L);
}
/**
* Returns the current sum. The returned value is NOT an
* atomic snapshot: Invocation in the absence of concurrent
* updates returns an accurate result, but concurrent updates that
* occur while the sum is being calculated might not be
* incorporated.
*
* @return the sum
*/
public long sum() {
long sum = base;
Cell[] as = cells;
if (as != null) {
int n = as.length;
for (int i = 0; i < n; ++i) {
Cell a = as[i];
if (a != null)
sum += a.value;
}
}
return sum;
}
/**
* Resets variables maintaining the sum to zero. This method may
* be a useful alternative to creating a new adder, but is only
* effective if there are no concurrent updates. Because this
* method is intrinsically racy, it should only be used when it is
* known that no threads are concurrently updating.
*/
public void reset() {
internalReset(0L);
}
/**
* Equivalent in effect to {@link #sum} followed by {@link
* #reset}. This method may apply for example during quiescent
* points between multithreaded computations. If there are
* updates concurrent with this method, the returned value is
* not guaranteed to be the final value occurring before
* the reset.
*
* @return the sum
*/
public long sumThenReset() {
long sum = base;
Cell[] as = cells;
base = 0L;
if (as != null) {
int n = as.length;
for (int i = 0; i < n; ++i) {
Cell a = as[i];
if (a != null) {
sum += a.value;
a.value = 0L;
}
}
}
return sum;
}
/**
* Returns the String representation of the {@link #sum}.
* @return the String representation of the {@link #sum}
*/
public String toString() {
return Long.toString(sum());
}
/**
* Equivalent to {@link #sum}.
*
* @return the sum
*/
public long longValue() {
return sum();
}
/**
* Returns the {@link #sum} as an {@code int} after a narrowing
* primitive conversion.
*/
public int intValue() {
return (int)sum();
}
/**
* Returns the {@link #sum} as a {@code float}
* after a widening primitive conversion.
*/
public float floatValue() {
return (float)sum();
}
/**
* Returns the {@link #sum} as a {@code double} after a widening
* primitive conversion.
*/
public double doubleValue() {
return (double)sum();
}
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
s.defaultWriteObject();
s.writeLong(sum());
}
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException {
s.defaultReadObject();
busy = 0;
cells = null;
base = s.readLong();
}
}
thread_safe-0.3.6/ext/org/jruby/ext/thread_safe/jsr166e/nounsafe/ConcurrentHashMapV8.java 0000644 0000041 0000041 00000464216 13062220653 031303 0 ustar www-data www-data /*
* Written by Doug Lea with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
*/
// This is based on the 1.79 version.
package org.jruby.ext.thread_safe.jsr166e.nounsafe;
import org.jruby.RubyClass;
import org.jruby.RubyNumeric;
import org.jruby.RubyObject;
import org.jruby.exceptions.RaiseException;
import org.jruby.ext.thread_safe.jsr166e.ConcurrentHashMap;
import org.jruby.ext.thread_safe.jsr166y.ThreadLocalRandom;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;
import java.util.Collection;
import java.util.Hashtable;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Enumeration;
import java.util.ConcurrentModificationException;
import java.util.NoSuchElementException;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
import java.util.concurrent.atomic.AtomicReferenceArray;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.io.Serializable;
/**
* A hash table supporting full concurrency of retrievals and
* high expected concurrency for updates. This class obeys the
* same functional specification as {@link java.util.Hashtable}, and
* includes versions of methods corresponding to each method of
* {@code Hashtable}. However, even though all operations are
* thread-safe, retrieval operations do not entail locking,
* and there is not any support for locking the entire table
* in a way that prevents all access. This class is fully
* interoperable with {@code Hashtable} in programs that rely on its
* thread safety but not on its synchronization details.
*
* Retrieval operations (including {@code get}) generally do not
* block, so may overlap with update operations (including {@code put}
* and {@code remove}). Retrievals reflect the results of the most
* recently completed update operations holding upon their
* onset. (More formally, an update operation for a given key bears a
* happens-before relation with any (non-null) retrieval for
* that key reporting the updated value.) For aggregate operations
* such as {@code putAll} and {@code clear}, concurrent retrievals may
* reflect insertion or removal of only some entries. Similarly,
* Iterators and Enumerations return elements reflecting the state of
* the hash table at some point at or since the creation of the
* iterator/enumeration. They do not throw {@link
* ConcurrentModificationException}. However, iterators are designed
* to be used by only one thread at a time. Bear in mind that the
* results of aggregate status methods including {@code size}, {@code
* isEmpty}, and {@code containsValue} are typically useful only when
* a map is not undergoing concurrent updates in other threads.
* Otherwise the results of these methods reflect transient states
* that may be adequate for monitoring or estimation purposes, but not
* for program control.
*
* The table is dynamically expanded when there are too many
* collisions (i.e., keys that have distinct hash codes but fall into
* the same slot modulo the table size), with the expected average
* effect of maintaining roughly two bins per mapping (corresponding
* to a 0.75 load factor threshold for resizing). There may be much
* variance around this average as mappings are added and removed, but
* overall, this maintains a commonly accepted time/space tradeoff for
* hash tables. However, resizing this or any other kind of hash
* table may be a relatively slow operation. When possible, it is a
* good idea to provide a size estimate as an optional {@code
* initialCapacity} constructor argument. An additional optional
* {@code loadFactor} constructor argument provides a further means of
* customizing initial table capacity by specifying the table density
* to be used in calculating the amount of space to allocate for the
* given number of elements. Also, for compatibility with previous
* versions of this class, constructors may optionally specify an
* expected {@code concurrencyLevel} as an additional hint for
* internal sizing. Note that using many keys with exactly the same
* {@code hashCode()} is a sure way to slow down performance of any
* hash table.
*
* A {@link Set} projection of a ConcurrentHashMapV8 may be created
* (using {@link #newKeySet()} or {@link #newKeySet(int)}), or viewed
* (using {@link #keySet(Object)} when only keys are of interest, and the
* mapped values are (perhaps transiently) not used or all take the
* same mapping value.
*
* A ConcurrentHashMapV8 can be used as scalable frequency map (a
* form of histogram or multiset) by using {@link LongAdder} values
* and initializing via {@link #computeIfAbsent}. For example, to add
* a count to a {@code ConcurrentHashMapV8 This class and its views and iterators implement all of the
* optional methods of the {@link Map} and {@link Iterator}
* interfaces.
*
* Like {@link Hashtable} but unlike {@link HashMap}, this class
* does not allow {@code null} to be used as a key or value.
*
* ConcurrentHashMapV8s support parallel operations using the {@link
* ForkJoinPool#commonPool}. (Tasks that may be used in other contexts
* are available in class {@link ForkJoinTasks}). These operations are
* designed to be safely, and often sensibly, applied even with maps
* that are being concurrently updated by other threads; for example,
* when computing a snapshot summary of the values in a shared
* registry. There are three kinds of operation, each with four
* forms, accepting functions with Keys, Values, Entries, and (Key,
* Value) arguments and/or return values. (The first three forms are
* also available via the {@link #keySet()}, {@link #values()} and
* {@link #entrySet()} views). Because the elements of a
* ConcurrentHashMapV8 are not ordered in any particular way, and may be
* processed in different orders in different parallel executions, the
* correctness of supplied functions should not depend on any
* ordering, or on any other objects or values that may transiently
* change while computation is in progress; and except for forEach
* actions, should ideally be side-effect-free.
*
* The concurrency properties of bulk operations follow
* from those of ConcurrentHashMapV8: Any non-null result returned
* from {@code get(key)} and related access methods bears a
* happens-before relation with the associated insertion or
* update. The result of any bulk operation reflects the
* composition of these per-element relations (but is not
* necessarily atomic with respect to the map as a whole unless it
* is somehow known to be quiescent). Conversely, because keys
* and values in the map are never null, null serves as a reliable
* atomic indicator of the current lack of any result. To
* maintain this property, null serves as an implicit basis for
* all non-scalar reduction operations. For the double, long, and
* int versions, the basis should be one that, when combined with
* any other value, returns that other value (more formally, it
* should be the identity element for the reduction). Most common
* reductions have these properties; for example, computing a sum
* with basis 0 or a minimum with basis MAX_VALUE.
*
* Search and transformation functions provided as arguments
* should similarly return null to indicate the lack of any result
* (in which case it is not used). In the case of mapped
* reductions, this also enables transformations to serve as
* filters, returning null (or, in the case of primitive
* specializations, the identity basis) if the element should not
* be combined. You can create compound transformations and
* filterings by composing them yourself under this "null means
* there is nothing there now" rule before using them in search or
* reduce operations.
*
* Methods accepting and/or returning Entry arguments maintain
* key-value associations. They may be useful for example when
* finding the key for the greatest value. Note that "plain" Entry
* arguments can be supplied using {@code new
* AbstractMap.SimpleEntry(k,v)}.
*
* Bulk operations may complete abruptly, throwing an
* exception encountered in the application of a supplied
* function. Bear in mind when handling such exceptions that other
* concurrently executing functions could also have thrown
* exceptions, or would have done so if the first exception had
* not occurred.
*
* Parallel speedups for bulk operations compared to sequential
* processing are common but not guaranteed. Operations involving
* brief functions on small maps may execute more slowly than
* sequential loops if the underlying work to parallelize the
* computation is more expensive than the computation itself.
* Similarly, parallelization may not lead to much actual parallelism
* if all processors are busy performing unrelated tasks.
*
* All arguments to all task methods must be non-null.
*
* jsr166e note: During transition, this class
* uses nested functional interfaces with different names but the
* same forms as those expected for JDK8.
*
* This class is a member of the
*
* Java Collections Framework.
*
* @since 1.5
* @author Doug Lea
* @param This interface exports a subset of expected JDK8
* functionality.
*
* Sample usage: Here is one (of the several) ways to compute
* the sum of the values held in a map using the ForkJoin
* framework. As illustrated here, Spliterators are well suited to
* designs in which a task repeatedly splits off half its work
* into forked subtasks until small enough to process directly,
* and then joins these subtasks. Variants of this style can also
* be used in completion-based designs.
*
* More formally, if this map contains a mapping from a key
* {@code k} to a value {@code v} such that {@code key.equals(k)},
* then this method returns {@code v}; otherwise it returns
* {@code null}. (There can be at most one such mapping.)
*
* @throws NullPointerException if the specified key is null
*/
@SuppressWarnings("unchecked") public V get(Object key) {
if (key == null)
throw new NullPointerException();
return (V)internalGet(key);
}
/**
* Returns the value to which the specified key is mapped,
* or the given defaultValue if this map contains no mapping for the key.
*
* @param key the key
* @param defaultValue the value to return if this map contains
* no mapping for the given key
* @return the mapping for the key, if present; else the defaultValue
* @throws NullPointerException if the specified key is null
*/
@SuppressWarnings("unchecked") public V getValueOrDefault(Object key, V defaultValue) {
if (key == null)
throw new NullPointerException();
V v = (V) internalGet(key);
return v == null ? defaultValue : v;
}
/**
* Tests if the specified object is a key in this table.
*
* @param key possible key
* @return {@code true} if and only if the specified object
* is a key in this table, as determined by the
* {@code equals} method; {@code false} otherwise
* @throws NullPointerException if the specified key is null
*/
public boolean containsKey(Object key) {
if (key == null)
throw new NullPointerException();
return internalGet(key) != null;
}
/**
* Returns {@code true} if this map maps one or more keys to the
* specified value. Note: This method may require a full traversal
* of the map, and is much slower than method {@code containsKey}.
*
* @param value value whose presence in this map is to be tested
* @return {@code true} if this map maps one or more keys to the
* specified value
* @throws NullPointerException if the specified value is null
*/
public boolean containsValue(Object value) {
if (value == null)
throw new NullPointerException();
Object v;
Traverser The value can be retrieved by calling the {@code get} method
* with a key that is equal to the original key.
*
* @param key key with which the specified value is to be associated
* @param value value to be associated with the specified key
* @return the previous value associated with {@code key}, or
* {@code null} if there was no mapping for {@code key}
* @throws NullPointerException if the specified key or value is null
*/
@SuppressWarnings("unchecked") public V put(K key, V value) {
if (key == null || value == null)
throw new NullPointerException();
return (V)internalPut(key, value);
}
/**
* {@inheritDoc}
*
* @return the previous value associated with the specified key,
* or {@code null} if there was no mapping for the key
* @throws NullPointerException if the specified key or value is null
*/
@SuppressWarnings("unchecked") public V putIfAbsent(K key, V value) {
if (key == null || value == null)
throw new NullPointerException();
return (V)internalPutIfAbsent(key, value);
}
/**
* Copies all of the mappings from the specified map to this one.
* These mappings replace any mappings that this map had for any of the
* keys currently in the specified map.
*
* @param m mappings to be stored in this map
*/
public void putAll(Map extends K, ? extends V> m) {
internalPutAll(m);
}
/**
* If the specified key is not already associated with a value,
* computes its value using the given mappingFunction and enters
* it into the map unless null. This is equivalent to
* The view's {@code iterator} is a "weakly consistent" iterator
* that will never throw {@link ConcurrentModificationException},
* and guarantees to traverse elements as they existed upon
* construction of the iterator, and may (but is not guaranteed to)
* reflect any modifications subsequent to construction.
*/
public Set The view's {@code iterator} is a "weakly consistent" iterator
* that will never throw {@link ConcurrentModificationException},
* and guarantees to traverse elements as they existed upon
* construction of the iterator, and may (but is not guaranteed to)
* reflect any modifications subsequent to construction.
*/
public static final class ValuesView This class is usually preferable to {@link AtomicLong} when
* multiple threads update a common sum that is used for purposes such
* as collecting statistics, not for fine-grained synchronization
* control. Under low update contention, the two classes have similar
* characteristics. But under high contention, expected throughput of
* this class is significantly higher, at the expense of higher space
* consumption.
*
* This class extends {@link Number}, but does not define
* methods such as {@code hashCode} and {@code compareTo} because
* instances are expected to be mutated, and so are not useful as
* collection keys.
*
* jsr166e note: This class is targeted to be placed in
* java.util.concurrent.atomic.
*
* @since 1.8
* @author Doug Lea
*/
public class LongAdder extends Striped64 implements Serializable {
private static final long serialVersionUID = 7249069246863182397L;
/**
* Version of plus for use in retryUpdate
*/
final long fn(long v, long x) { return v + x; }
/**
* Creates a new adder with initial sum of zero.
*/
public LongAdder() {
}
/**
* Adds the given value.
*
* @param x the value to add
*/
public void add(long x) {
Cell[] as; long b, v; HashCode hc; Cell a; int n;
if ((as = cells) != null || !casBase(b = base, b + x)) {
boolean uncontended = true;
int h = (hc = threadHashCode.get()).code;
if (as == null || (n = as.length) < 1 ||
(a = as[(n - 1) & h]) == null ||
!(uncontended = a.cas(v = a.value, v + x)))
retryUpdate(x, hc, uncontended);
}
}
/**
* Equivalent to {@code add(1)}.
*/
public void increment() {
add(1L);
}
/**
* Equivalent to {@code add(-1)}.
*/
public void decrement() {
add(-1L);
}
/**
* Returns the current sum. The returned value is NOT an
* atomic snapshot: Invocation in the absence of concurrent
* updates returns an accurate result, but concurrent updates that
* occur while the sum is being calculated might not be
* incorporated.
*
* @return the sum
*/
public long sum() {
long sum = base;
Cell[] as = cells;
if (as != null) {
int n = as.length;
for (int i = 0; i < n; ++i) {
Cell a = as[i];
if (a != null)
sum += a.value;
}
}
return sum;
}
/**
* Resets variables maintaining the sum to zero. This method may
* be a useful alternative to creating a new adder, but is only
* effective if there are no concurrent updates. Because this
* method is intrinsically racy, it should only be used when it is
* known that no threads are concurrently updating.
*/
public void reset() {
internalReset(0L);
}
/**
* Equivalent in effect to {@link #sum} followed by {@link
* #reset}. This method may apply for example during quiescent
* points between multithreaded computations. If there are
* updates concurrent with this method, the returned value is
* not guaranteed to be the final value occurring before
* the reset.
*
* @return the sum
*/
public long sumThenReset() {
long sum = base;
Cell[] as = cells;
base = 0L;
if (as != null) {
int n = as.length;
for (int i = 0; i < n; ++i) {
Cell a = as[i];
if (a != null) {
sum += a.value;
a.value = 0L;
}
}
}
return sum;
}
/**
* Returns the String representation of the {@link #sum}.
* @return the String representation of the {@link #sum}
*/
public String toString() {
return Long.toString(sum());
}
/**
* Equivalent to {@link #sum}.
*
* @return the sum
*/
public long longValue() {
return sum();
}
/**
* Returns the {@link #sum} as an {@code int} after a narrowing
* primitive conversion.
*/
public int intValue() {
return (int)sum();
}
/**
* Returns the {@link #sum} as a {@code float}
* after a widening primitive conversion.
*/
public float floatValue() {
return (float)sum();
}
/**
* Returns the {@link #sum} as a {@code double} after a widening
* primitive conversion.
*/
public double doubleValue() {
return (double)sum();
}
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException {
s.defaultWriteObject();
s.writeLong(sum());
}
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException {
s.defaultReadObject();
busy = 0;
cells = null;
base = s.readLong();
}
}
thread_safe-0.3.6/ext/org/jruby/ext/thread_safe/jsr166e/ConcurrentHashMapV8.java 0000644 0000041 0000041 00000467110 13062220653 027461 0 ustar www-data www-data /*
* Written by Doug Lea with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
*/
// This is based on the 1.79 version.
package org.jruby.ext.thread_safe.jsr166e;
import org.jruby.RubyClass;
import org.jruby.RubyNumeric;
import org.jruby.RubyObject;
import org.jruby.exceptions.RaiseException;
import org.jruby.ext.thread_safe.jsr166y.ThreadLocalRandom;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;
import java.util.Collection;
import java.util.Hashtable;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Enumeration;
import java.util.ConcurrentModificationException;
import java.util.NoSuchElementException;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.io.Serializable;
/**
* A hash table supporting full concurrency of retrievals and
* high expected concurrency for updates. This class obeys the
* same functional specification as {@link java.util.Hashtable}, and
* includes versions of methods corresponding to each method of
* {@code Hashtable}. However, even though all operations are
* thread-safe, retrieval operations do not entail locking,
* and there is not any support for locking the entire table
* in a way that prevents all access. This class is fully
* interoperable with {@code Hashtable} in programs that rely on its
* thread safety but not on its synchronization details.
*
* Retrieval operations (including {@code get}) generally do not
* block, so may overlap with update operations (including {@code put}
* and {@code remove}). Retrievals reflect the results of the most
* recently completed update operations holding upon their
* onset. (More formally, an update operation for a given key bears a
* happens-before relation with any (non-null) retrieval for
* that key reporting the updated value.) For aggregate operations
* such as {@code putAll} and {@code clear}, concurrent retrievals may
* reflect insertion or removal of only some entries. Similarly,
* Iterators and Enumerations return elements reflecting the state of
* the hash table at some point at or since the creation of the
* iterator/enumeration. They do not throw {@link
* ConcurrentModificationException}. However, iterators are designed
* to be used by only one thread at a time. Bear in mind that the
* results of aggregate status methods including {@code size}, {@code
* isEmpty}, and {@code containsValue} are typically useful only when
* a map is not undergoing concurrent updates in other threads.
* Otherwise the results of these methods reflect transient states
* that may be adequate for monitoring or estimation purposes, but not
* for program control.
*
* The table is dynamically expanded when there are too many
* collisions (i.e., keys that have distinct hash codes but fall into
* the same slot modulo the table size), with the expected average
* effect of maintaining roughly two bins per mapping (corresponding
* to a 0.75 load factor threshold for resizing). There may be much
* variance around this average as mappings are added and removed, but
* overall, this maintains a commonly accepted time/space tradeoff for
* hash tables. However, resizing this or any other kind of hash
* table may be a relatively slow operation. When possible, it is a
* good idea to provide a size estimate as an optional {@code
* initialCapacity} constructor argument. An additional optional
* {@code loadFactor} constructor argument provides a further means of
* customizing initial table capacity by specifying the table density
* to be used in calculating the amount of space to allocate for the
* given number of elements. Also, for compatibility with previous
* versions of this class, constructors may optionally specify an
* expected {@code concurrencyLevel} as an additional hint for
* internal sizing. Note that using many keys with exactly the same
* {@code hashCode()} is a sure way to slow down performance of any
* hash table.
*
* A {@link Set} projection of a ConcurrentHashMapV8 may be created
* (using {@link #newKeySet()} or {@link #newKeySet(int)}), or viewed
* (using {@link #keySet(Object)} when only keys are of interest, and the
* mapped values are (perhaps transiently) not used or all take the
* same mapping value.
*
* A ConcurrentHashMapV8 can be used as scalable frequency map (a
* form of histogram or multiset) by using {@link LongAdder} values
* and initializing via {@link #computeIfAbsent}. For example, to add
* a count to a {@code ConcurrentHashMapV8 This class and its views and iterators implement all of the
* optional methods of the {@link Map} and {@link Iterator}
* interfaces.
*
* Like {@link Hashtable} but unlike {@link HashMap}, this class
* does not allow {@code null} to be used as a key or value.
*
* ConcurrentHashMapV8s support parallel operations using the {@link
* ForkJoinPool#commonPool}. (Tasks that may be used in other contexts
* are available in class {@link ForkJoinTasks}). These operations are
* designed to be safely, and often sensibly, applied even with maps
* that are being concurrently updated by other threads; for example,
* when computing a snapshot summary of the values in a shared
* registry. There are three kinds of operation, each with four
* forms, accepting functions with Keys, Values, Entries, and (Key,
* Value) arguments and/or return values. (The first three forms are
* also available via the {@link #keySet()}, {@link #values()} and
* {@link #entrySet()} views). Because the elements of a
* ConcurrentHashMapV8 are not ordered in any particular way, and may be
* processed in different orders in different parallel executions, the
* correctness of supplied functions should not depend on any
* ordering, or on any other objects or values that may transiently
* change while computation is in progress; and except for forEach
* actions, should ideally be side-effect-free.
*
* The concurrency properties of bulk operations follow
* from those of ConcurrentHashMapV8: Any non-null result returned
* from {@code get(key)} and related access methods bears a
* happens-before relation with the associated insertion or
* update. The result of any bulk operation reflects the
* composition of these per-element relations (but is not
* necessarily atomic with respect to the map as a whole unless it
* is somehow known to be quiescent). Conversely, because keys
* and values in the map are never null, null serves as a reliable
* atomic indicator of the current lack of any result. To
* maintain this property, null serves as an implicit basis for
* all non-scalar reduction operations. For the double, long, and
* int versions, the basis should be one that, when combined with
* any other value, returns that other value (more formally, it
* should be the identity element for the reduction). Most common
* reductions have these properties; for example, computing a sum
* with basis 0 or a minimum with basis MAX_VALUE.
*
* Search and transformation functions provided as arguments
* should similarly return null to indicate the lack of any result
* (in which case it is not used). In the case of mapped
* reductions, this also enables transformations to serve as
* filters, returning null (or, in the case of primitive
* specializations, the identity basis) if the element should not
* be combined. You can create compound transformations and
* filterings by composing them yourself under this "null means
* there is nothing there now" rule before using them in search or
* reduce operations.
*
* Methods accepting and/or returning Entry arguments maintain
* key-value associations. They may be useful for example when
* finding the key for the greatest value. Note that "plain" Entry
* arguments can be supplied using {@code new
* AbstractMap.SimpleEntry(k,v)}.
*
* Bulk operations may complete abruptly, throwing an
* exception encountered in the application of a supplied
* function. Bear in mind when handling such exceptions that other
* concurrently executing functions could also have thrown
* exceptions, or would have done so if the first exception had
* not occurred.
*
* Parallel speedups for bulk operations compared to sequential
* processing are common but not guaranteed. Operations involving
* brief functions on small maps may execute more slowly than
* sequential loops if the underlying work to parallelize the
* computation is more expensive than the computation itself.
* Similarly, parallelization may not lead to much actual parallelism
* if all processors are busy performing unrelated tasks.
*
* All arguments to all task methods must be non-null.
*
* jsr166e note: During transition, this class
* uses nested functional interfaces with different names but the
* same forms as those expected for JDK8.
*
* This class is a member of the
*
* Java Collections Framework.
*
* @since 1.5
* @author Doug Lea
* @param This interface exports a subset of expected JDK8
* functionality.
*
* Sample usage: Here is one (of the several) ways to compute
* the sum of the values held in a map using the ForkJoin
* framework. As illustrated here, Spliterators are well suited to
* designs in which a task repeatedly splits off half its work
* into forked subtasks until small enough to process directly,
* and then joins these subtasks. Variants of this style can also
* be used in completion-based designs.
*
* More formally, if this map contains a mapping from a key
* {@code k} to a value {@code v} such that {@code key.equals(k)},
* then this method returns {@code v}; otherwise it returns
* {@code null}. (There can be at most one such mapping.)
*
* @throws NullPointerException if the specified key is null
*/
@SuppressWarnings("unchecked") public V get(Object key) {
if (key == null)
throw new NullPointerException();
return (V)internalGet(key);
}
/**
* Returns the value to which the specified key is mapped,
* or the given defaultValue if this map contains no mapping for the key.
*
* @param key the key
* @param defaultValue the value to return if this map contains
* no mapping for the given key
* @return the mapping for the key, if present; else the defaultValue
* @throws NullPointerException if the specified key is null
*/
@SuppressWarnings("unchecked") public V getValueOrDefault(Object key, V defaultValue) {
if (key == null)
throw new NullPointerException();
V v = (V) internalGet(key);
return v == null ? defaultValue : v;
}
/**
* Tests if the specified object is a key in this table.
*
* @param key possible key
* @return {@code true} if and only if the specified object
* is a key in this table, as determined by the
* {@code equals} method; {@code false} otherwise
* @throws NullPointerException if the specified key is null
*/
public boolean containsKey(Object key) {
if (key == null)
throw new NullPointerException();
return internalGet(key) != null;
}
/**
* Returns {@code true} if this map maps one or more keys to the
* specified value. Note: This method may require a full traversal
* of the map, and is much slower than method {@code containsKey}.
*
* @param value value whose presence in this map is to be tested
* @return {@code true} if this map maps one or more keys to the
* specified value
* @throws NullPointerException if the specified value is null
*/
public boolean containsValue(Object value) {
if (value == null)
throw new NullPointerException();
Object v;
Traverser The value can be retrieved by calling the {@code get} method
* with a key that is equal to the original key.
*
* @param key key with which the specified value is to be associated
* @param value value to be associated with the specified key
* @return the previous value associated with {@code key}, or
* {@code null} if there was no mapping for {@code key}
* @throws NullPointerException if the specified key or value is null
*/
@SuppressWarnings("unchecked") public V put(K key, V value) {
if (key == null || value == null)
throw new NullPointerException();
return (V)internalPut(key, value);
}
/**
* {@inheritDoc}
*
* @return the previous value associated with the specified key,
* or {@code null} if there was no mapping for the key
* @throws NullPointerException if the specified key or value is null
*/
@SuppressWarnings("unchecked") public V putIfAbsent(K key, V value) {
if (key == null || value == null)
throw new NullPointerException();
return (V)internalPutIfAbsent(key, value);
}
/**
* Copies all of the mappings from the specified map to this one.
* These mappings replace any mappings that this map had for any of the
* keys currently in the specified map.
*
* @param m mappings to be stored in this map
*/
public void putAll(Map extends K, ? extends V> m) {
internalPutAll(m);
}
/**
* If the specified key is not already associated with a value,
* computes its value using the given mappingFunction and enters
* it into the map unless null. This is equivalent to
* The view's {@code iterator} is a "weakly consistent" iterator
* that will never throw {@link ConcurrentModificationException},
* and guarantees to traverse elements as they existed upon
* construction of the iterator, and may (but is not guaranteed to)
* reflect any modifications subsequent to construction.
*/
public Set
*
*
*
*
*
*
* {@code ConcurrentHashMapV8
*/
public static interface Spliterator {@code
* if (map.containsKey(key))
* return map.get(key);
* value = mappingFunction.apply(key);
* if (value != null)
* map.put(key, value);
* return value;}
*
* except that the action is performed atomically. If the
* function returns {@code null} no mapping is recorded. If the
* function itself throws an (unchecked) exception, the exception
* is rethrown to its caller, and no mapping is recorded. Some
* attempted update operations on this map by other threads may be
* blocked while computation is in progress, so the computation
* should be short and simple, and must not attempt to update any
* other mappings of this Map. The most appropriate usage is to
* construct a new object serving as an initial mapped value, or
* memoized result, as in:
*
* {@code
* map.computeIfAbsent(key, new Fun
*
* @param key key with which the specified value is to be associated
* @param mappingFunction the function to compute a value
* @return the current (existing or computed) value associated with
* the specified key, or null if the computed value is null
* @throws NullPointerException if the specified key or mappingFunction
* is null
* @throws IllegalStateException if the computation detectably
* attempts a recursive update to this map that would
* otherwise never complete
* @throws RuntimeException or Error if the mappingFunction does so,
* in which case the mapping is left unestablished
*/
@SuppressWarnings("unchecked") public V computeIfAbsent
(K key, Fun super K, ? extends V> mappingFunction) {
if (key == null || mappingFunction == null)
throw new NullPointerException();
return (V)internalComputeIfAbsent(key, mappingFunction);
}
/**
* If the given key is present, computes a new mapping value given a key and
* its current mapped value. This is equivalent to
* {@code
* if (map.containsKey(key)) {
* value = remappingFunction.apply(key, map.get(key));
* if (value != null)
* map.put(key, value);
* else
* map.remove(key);
* }
* }
*
* except that the action is performed atomically. If the
* function returns {@code null}, the mapping is removed. If the
* function itself throws an (unchecked) exception, the exception
* is rethrown to its caller, and the current mapping is left
* unchanged. Some attempted update operations on this map by
* other threads may be blocked while computation is in progress,
* so the computation should be short and simple, and must not
* attempt to update any other mappings of this Map. For example,
* to either create or append new messages to a value mapping:
*
* @param key key with which the specified value is to be associated
* @param remappingFunction the function to compute a value
* @return the new value associated with the specified key, or null if none
* @throws NullPointerException if the specified key or remappingFunction
* is null
* @throws IllegalStateException if the computation detectably
* attempts a recursive update to this map that would
* otherwise never complete
* @throws RuntimeException or Error if the remappingFunction does so,
* in which case the mapping is unchanged
*/
@SuppressWarnings("unchecked") public V computeIfPresent
(K key, BiFun super K, ? super V, ? extends V> remappingFunction) {
if (key == null || remappingFunction == null)
throw new NullPointerException();
return (V)internalCompute(key, true, remappingFunction);
}
/**
* Computes a new mapping value given a key and
* its current mapped value (or {@code null} if there is no current
* mapping). This is equivalent to
* {@code
* value = remappingFunction.apply(key, map.get(key));
* if (value != null)
* map.put(key, value);
* else
* map.remove(key);
* }
*
* except that the action is performed atomically. If the
* function returns {@code null}, the mapping is removed. If the
* function itself throws an (unchecked) exception, the exception
* is rethrown to its caller, and the current mapping is left
* unchanged. Some attempted update operations on this map by
* other threads may be blocked while computation is in progress,
* so the computation should be short and simple, and must not
* attempt to update any other mappings of this Map. For example,
* to either create or append new messages to a value mapping:
*
* {@code
* Map
*
* @param key key with which the specified value is to be associated
* @param remappingFunction the function to compute a value
* @return the new value associated with the specified key, or null if none
* @throws NullPointerException if the specified key or remappingFunction
* is null
* @throws IllegalStateException if the computation detectably
* attempts a recursive update to this map that would
* otherwise never complete
* @throws RuntimeException or Error if the remappingFunction does so,
* in which case the mapping is unchanged
*/
@SuppressWarnings("unchecked") public V compute
(K key, BiFun super K, ? super V, ? extends V> remappingFunction) {
if (key == null || remappingFunction == null)
throw new NullPointerException();
return (V)internalCompute(key, false, remappingFunction);
}
/**
* If the specified key is not already associated
* with a value, associate it with the given value.
* Otherwise, replace the value with the results of
* the given remapping function. This is equivalent to:
* {@code
* if (!map.containsKey(key))
* map.put(value);
* else {
* newValue = remappingFunction.apply(map.get(key), value);
* if (value != null)
* map.put(key, value);
* else
* map.remove(key);
* }
* }
* except that the action is performed atomically. If the
* function returns {@code null}, the mapping is removed. If the
* function itself throws an (unchecked) exception, the exception
* is rethrown to its caller, and the current mapping is left
* unchanged. Some attempted update operations on this map by
* other threads may be blocked while computation is in progress,
* so the computation should be short and simple, and must not
* attempt to update any other mappings of this Map.
*/
@SuppressWarnings("unchecked") public V merge
(K key, V value, BiFun super V, ? super V, ? extends V> remappingFunction) {
if (key == null || value == null || remappingFunction == null)
throw new NullPointerException();
return (V)internalMerge(key, value, remappingFunction);
}
/**
* Removes the key (and its corresponding value) from this map.
* This method does nothing if the key is not in the map.
*
* @param key the key that needs to be removed
* @return the previous value associated with {@code key}, or
* {@code null} if there was no mapping for {@code key}
* @throws NullPointerException if the specified key is null
*/
@SuppressWarnings("unchecked") public V remove(Object key) {
if (key == null)
throw new NullPointerException();
return (V)internalReplace(key, null, null);
}
/**
* {@inheritDoc}
*
* @throws NullPointerException if the specified key is null
*/
public boolean remove(Object key, Object value) {
if (key == null)
throw new NullPointerException();
if (value == null)
return false;
return internalReplace(key, null, value) != null;
}
/**
* {@inheritDoc}
*
* @throws NullPointerException if any of the arguments are null
*/
public boolean replace(K key, V oldValue, V newValue) {
if (key == null || oldValue == null || newValue == null)
throw new NullPointerException();
return internalReplace(key, newValue, oldValue) != null;
}
/**
* {@inheritDoc}
*
* @return the previous value associated with the specified key,
* or {@code null} if there was no mapping for the key
* @throws NullPointerException if the specified key or value is null
*/
@SuppressWarnings("unchecked") public V replace(K key, V value) {
if (key == null || value == null)
throw new NullPointerException();
return (V)internalReplace(key, value, null);
}
/**
* Removes all of the mappings from this map.
*/
public void clear() {
internalClear();
}
/**
* Returns a {@link Set} view of the keys contained in this map.
* The set is backed by the map, so changes to the map are
* reflected in the set, and vice-versa.
*
* @return the set view
*/
public KeySetView
*
*
*
*
*
*
* {@code ConcurrentHashMapV8
*/
public static interface Spliterator {@code
* if (map.containsKey(key))
* return map.get(key);
* value = mappingFunction.apply(key);
* if (value != null)
* map.put(key, value);
* return value;}
*
* except that the action is performed atomically. If the
* function returns {@code null} no mapping is recorded. If the
* function itself throws an (unchecked) exception, the exception
* is rethrown to its caller, and no mapping is recorded. Some
* attempted update operations on this map by other threads may be
* blocked while computation is in progress, so the computation
* should be short and simple, and must not attempt to update any
* other mappings of this Map. The most appropriate usage is to
* construct a new object serving as an initial mapped value, or
* memoized result, as in:
*
* {@code
* map.computeIfAbsent(key, new Fun
*
* @param key key with which the specified value is to be associated
* @param mappingFunction the function to compute a value
* @return the current (existing or computed) value associated with
* the specified key, or null if the computed value is null
* @throws NullPointerException if the specified key or mappingFunction
* is null
* @throws IllegalStateException if the computation detectably
* attempts a recursive update to this map that would
* otherwise never complete
* @throws RuntimeException or Error if the mappingFunction does so,
* in which case the mapping is left unestablished
*/
@SuppressWarnings("unchecked") public V computeIfAbsent
(K key, Fun super K, ? extends V> mappingFunction) {
if (key == null || mappingFunction == null)
throw new NullPointerException();
return (V)internalComputeIfAbsent(key, mappingFunction);
}
/**
* If the given key is present, computes a new mapping value given a key and
* its current mapped value. This is equivalent to
* {@code
* if (map.containsKey(key)) {
* value = remappingFunction.apply(key, map.get(key));
* if (value != null)
* map.put(key, value);
* else
* map.remove(key);
* }
* }
*
* except that the action is performed atomically. If the
* function returns {@code null}, the mapping is removed. If the
* function itself throws an (unchecked) exception, the exception
* is rethrown to its caller, and the current mapping is left
* unchanged. Some attempted update operations on this map by
* other threads may be blocked while computation is in progress,
* so the computation should be short and simple, and must not
* attempt to update any other mappings of this Map. For example,
* to either create or append new messages to a value mapping:
*
* @param key key with which the specified value is to be associated
* @param remappingFunction the function to compute a value
* @return the new value associated with the specified key, or null if none
* @throws NullPointerException if the specified key or remappingFunction
* is null
* @throws IllegalStateException if the computation detectably
* attempts a recursive update to this map that would
* otherwise never complete
* @throws RuntimeException or Error if the remappingFunction does so,
* in which case the mapping is unchanged
*/
@SuppressWarnings("unchecked") public V computeIfPresent
(K key, BiFun super K, ? super V, ? extends V> remappingFunction) {
if (key == null || remappingFunction == null)
throw new NullPointerException();
return (V)internalCompute(key, true, remappingFunction);
}
/**
* Computes a new mapping value given a key and
* its current mapped value (or {@code null} if there is no current
* mapping). This is equivalent to
* {@code
* value = remappingFunction.apply(key, map.get(key));
* if (value != null)
* map.put(key, value);
* else
* map.remove(key);
* }
*
* except that the action is performed atomically. If the
* function returns {@code null}, the mapping is removed. If the
* function itself throws an (unchecked) exception, the exception
* is rethrown to its caller, and the current mapping is left
* unchanged. Some attempted update operations on this map by
* other threads may be blocked while computation is in progress,
* so the computation should be short and simple, and must not
* attempt to update any other mappings of this Map. For example,
* to either create or append new messages to a value mapping:
*
* {@code
* Map
*
* @param key key with which the specified value is to be associated
* @param remappingFunction the function to compute a value
* @return the new value associated with the specified key, or null if none
* @throws NullPointerException if the specified key or remappingFunction
* is null
* @throws IllegalStateException if the computation detectably
* attempts a recursive update to this map that would
* otherwise never complete
* @throws RuntimeException or Error if the remappingFunction does so,
* in which case the mapping is unchanged
*/
@SuppressWarnings("unchecked") public V compute
(K key, BiFun super K, ? super V, ? extends V> remappingFunction) {
if (key == null || remappingFunction == null)
throw new NullPointerException();
return (V)internalCompute(key, false, remappingFunction);
}
/**
* If the specified key is not already associated
* with a value, associate it with the given value.
* Otherwise, replace the value with the results of
* the given remapping function. This is equivalent to:
* {@code
* if (!map.containsKey(key))
* map.put(value);
* else {
* newValue = remappingFunction.apply(map.get(key), value);
* if (value != null)
* map.put(key, value);
* else
* map.remove(key);
* }
* }
* except that the action is performed atomically. If the
* function returns {@code null}, the mapping is removed. If the
* function itself throws an (unchecked) exception, the exception
* is rethrown to its caller, and the current mapping is left
* unchanged. Some attempted update operations on this map by
* other threads may be blocked while computation is in progress,
* so the computation should be short and simple, and must not
* attempt to update any other mappings of this Map.
*/
@SuppressWarnings("unchecked") public V merge
(K key, V value, BiFun super V, ? super V, ? extends V> remappingFunction) {
if (key == null || value == null || remappingFunction == null)
throw new NullPointerException();
return (V)internalMerge(key, value, remappingFunction);
}
/**
* Removes the key (and its corresponding value) from this map.
* This method does nothing if the key is not in the map.
*
* @param key the key that needs to be removed
* @return the previous value associated with {@code key}, or
* {@code null} if there was no mapping for {@code key}
* @throws NullPointerException if the specified key is null
*/
@SuppressWarnings("unchecked") public V remove(Object key) {
if (key == null)
throw new NullPointerException();
return (V)internalReplace(key, null, null);
}
/**
* {@inheritDoc}
*
* @throws NullPointerException if the specified key is null
*/
public boolean remove(Object key, Object value) {
if (key == null)
throw new NullPointerException();
if (value == null)
return false;
return internalReplace(key, null, value) != null;
}
/**
* {@inheritDoc}
*
* @throws NullPointerException if any of the arguments are null
*/
public boolean replace(K key, V oldValue, V newValue) {
if (key == null || oldValue == null || newValue == null)
throw new NullPointerException();
return internalReplace(key, newValue, oldValue) != null;
}
/**
* {@inheritDoc}
*
* @return the previous value associated with the specified key,
* or {@code null} if there was no mapping for the key
* @throws NullPointerException if the specified key or value is null
*/
@SuppressWarnings("unchecked") public V replace(K key, V value) {
if (key == null || value == null)
throw new NullPointerException();
return (V)internalReplace(key, value, null);
}
/**
* Removes all of the mappings from this map.
*/
public void clear() {
internalClear();
}
/**
* Returns a {@link Set} view of the keys contained in this map.
* The set is backed by the map, so changes to the map are
* reflected in the set, and vice-versa.
*
* @return the set view
*/
public KeySetView