/* * Copyright 2023-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package xyz.zhouxy.plusone.commons.collection; import com.google.common.annotations.Beta; import com.google.common.collect.ImmutableTable; import com.google.common.collect.Table; import xyz.zhouxy.plusone.commons.annotation.ReaderMethod; import xyz.zhouxy.plusone.commons.annotation.WriterMethod; import javax.annotation.CheckForNull; import javax.annotation.Nonnull; import javax.annotation.concurrent.ThreadSafe; import java.util.Collection; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.concurrent.locks.ReentrantReadWriteLock; /** * 使用 {@link ReentrantReadWriteLock} 将 {@link Table} 包装为线程安全的集合。 * *

* 可通过以下方式构建一个线程安全的 {@link Table} *

* *
 * LockedTable.of(HashBasedTable.create())
 * 
* *

* NOTE: 如果 {@link Table} 不需要更改,请使用 {@link ImmutableTable} *

* * @author ZhouXY * @see Table * @see ImmutableTable * @see ReentrantReadWriteLock * @since 0.1.0-SNAPSHOT */ @Beta @ThreadSafe public class ReadWriteLockedTable implements Table { private final Table table; private final ReentrantReadWriteLock.ReadLock readLock; private final ReentrantReadWriteLock.WriteLock writeLock; private ReadWriteLockedTable(Table table, boolean fair) { this.table = Objects.requireNonNull(table); ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(fair); this.readLock = rwl.readLock(); this.writeLock = rwl.writeLock(); } public static ReadWriteLockedTable of(Table table) { if (table instanceof ReadWriteLockedTable) { return (ReadWriteLockedTable) table; } else { return new ReadWriteLockedTable<>(table, false); } } public static ReadWriteLockedTable of(Table table, boolean fair) { if (table instanceof ReadWriteLockedTable) { return (ReadWriteLockedTable) table; } else { return new ReadWriteLockedTable<>(table, fair); } } @Override @ReaderMethod public boolean contains(@CheckForNull @Nonnull Object rowKey, @CheckForNull @Nonnull Object columnKey) { readLock.lock(); try { return this.table.contains(rowKey, columnKey); } finally { readLock.unlock(); } } @Override @ReaderMethod public boolean containsRow(@CheckForNull @Nonnull Object rowKey) { readLock.lock(); try { return this.table.containsRow(rowKey); } finally { readLock.unlock(); } } @Override @ReaderMethod public boolean containsColumn(@CheckForNull @Nonnull Object columnKey) { readLock.lock(); try { return this.table.containsColumn(columnKey); } finally { readLock.unlock(); } } @Override @ReaderMethod public boolean containsValue(@CheckForNull @Nonnull Object value) { readLock.lock(); try { return this.table.containsValue(value); } finally { readLock.unlock(); } } @Override @ReaderMethod public V get(@CheckForNull @Nonnull Object rowKey, @CheckForNull @Nonnull Object columnKey) { readLock.lock(); try { return this.table.get(rowKey, columnKey); } finally { readLock.unlock(); } } @Override @ReaderMethod public boolean isEmpty() { readLock.lock(); try { return this.table.isEmpty(); } finally { readLock.unlock(); } } @Override @ReaderMethod public int size() { readLock.lock(); try { return this.table.size(); } finally { readLock.unlock(); } } @Override @WriterMethod public void clear() { writeLock.lock(); try { this.table.clear(); } finally { writeLock.unlock(); } } @Override @WriterMethod public V put(@CheckForNull @Nonnull R rowKey, @CheckForNull @Nonnull C columnKey, @CheckForNull @Nonnull V value) { writeLock.lock(); try { return this.table.put(rowKey, columnKey, value); } finally { writeLock.unlock(); } } @Override @WriterMethod public void putAll(@Nonnull Table table) { writeLock.lock(); try { this.table.putAll(table); } finally { writeLock.unlock(); } } @Override @WriterMethod public V remove(@CheckForNull @Nonnull Object rowKey, @CheckForNull @Nonnull Object columnKey) { writeLock.lock(); try { return this.table.remove(rowKey, columnKey); } finally { writeLock.unlock(); } } @Override @ReaderMethod public Map row(@CheckForNull @Nonnull R rowKey) { readLock.lock(); try { return this.table.row(rowKey); } finally { readLock.unlock(); } } @Override @ReaderMethod public Map column(@CheckForNull @Nonnull C columnKey) { readLock.lock(); try { return this.table.column(columnKey); } finally { readLock.unlock(); } } @Override @ReaderMethod public Set> cellSet() { readLock.lock(); try { return this.table.cellSet(); } finally { readLock.unlock(); } } @Override @ReaderMethod public Set rowKeySet() { readLock.lock(); try { return this.table.rowKeySet(); } finally { readLock.unlock(); } } @Override @ReaderMethod public Set columnKeySet() { readLock.lock(); try { return this.table.columnKeySet(); } finally { readLock.unlock(); } } @Override @ReaderMethod public Collection values() { readLock.lock(); try { return this.table.values(); } finally { readLock.unlock(); } } @Override @ReaderMethod public Map> rowMap() { readLock.lock(); try { return this.table.rowMap(); } finally { readLock.unlock(); } } @Override @ReaderMethod public Map> columnMap() { readLock.lock(); try { return this.table.columnMap(); } finally { readLock.unlock(); } } }