001/** 002 * The MIT License (MIT) 003 * 004 * Copyright (c) 2018 nobark (tools4j), Marco Terzer, Anton Anufriev 005 * 006 * Permission is hereby granted, free of charge, to any person obtaining a copy 007 * of this software and associated documentation files (the "Software"), to deal 008 * in the Software without restriction, including without limitation the rights 009 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 010 * copies of the Software, and to permit persons to whom the Software is 011 * furnished to do so, subject to the following conditions: 012 * 013 * The above copyright notice and this permission notice shall be included in all 014 * copies or substantial portions of the Software. 015 * 016 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 017 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 018 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 019 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 020 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 021 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 022 * SOFTWARE. 023 */ 024package org.tools4j.nobark.queue; 025 026import java.util.Objects; 027import java.util.function.BiConsumer; 028import java.util.function.Function; 029 030/** 031 * A conflation queue variant that allows exchanging of elements between the consumer and the producer. Naturally the 032 * producer already sends values to the consumer; with an exchange queue the consumer can pass values back to the 033 * producer when polling values. This can for instance be used to reduce garbage by circulating and reusing values 034 * between producer and consumer. 035 * 036 * @param <K> the type of the conflation key 037 * @param <V> the type of values in the queue 038 */ 039public interface ExchangeConflationQueue<K,V> extends ConflationQueue<K,V> { 040 @Override 041 Appender<K,V> appender(); 042 043 @Override 044 ExchangePoller<K,V> poller(); 045 046 /** 047 * Poller object used by the consumer to poll values; exchange poller adds functionality for exchanging values with 048 * the producer during poll operations. 049 * 050 * @param <K> the type of the conflation key 051 * @param <V> the type of values in the queue 052 */ 053 @FunctionalInterface 054 interface ExchangePoller<K, V> extends Poller<K,V> { 055 /** 056 * Polls the queue passing an unused value in exchange to the queue. The given consumer is invoked with 057 * conflation key and polled value if the queue was non-empty and the value is returned. If the queue was 058 * empty, null is returned. 059 * <p> 060 * If polling was successful, the exchange value will at some point be returned by an enqueue operation with 061 * the same conflation key and can be reused by the producer. The caller retains ownership of the exchange 062 * value if polling failed and null was returned. 063 * 064 * @param consumer consumer for conflation key and polled value 065 * @param exchange a value offered in exchange for the polled value, to be returned by an enqueue operation 066 * @return the polled value, or null if the queue was empty 067 */ 068 V poll(BiConsumer<? super K, ? super V> consumer, V exchange); 069 070 /** 071 * Polls the queue passing an unused value in exchange to the queue. Returns the polled value if any value was 072 * present in the queue, or null if the queue was empty. 073 * <p> 074 * If polling was successful, the exchange value will at some point be returned by an enqueue operation with 075 * the same conflation key and can be reused by the producer. The caller retains ownership of the exchange 076 * value if polling failed and null was returned. 077 * 078 * @param exchange a value offered in exchange for the polled value, to be returned by an enqueue operation 079 * @return the polled value, or null if the queue was empty 080 */ 081 default V poll(final V exchange) { 082 return poll((k,v) -> {}, exchange); 083 } 084 085 @Override 086 default V poll(final BiConsumer<? super K, ? super V> consumer) { 087 return poll(consumer, null); 088 } 089 } 090 091 /** 092 * Returns an {@link ExchangeConflationQueue} whose appender is guaranteed to never return null on enqueue. If the 093 * unsafe queue returns null on enqueue e.g. because the queue is empty and no exchange values can be retrieved yet, 094 * the specified factory is used to create a value. 095 * 096 * @param unsafeQueue the unsafe queue possibly returning null values on enqueue 097 * @param valueFactory the value factory used if the unsafe queue returned null when a value was enqueued 098 * @param <K> the type of the conflation key 099 * @param <V> the type of values in the queue 100 * @return a null-safe version of the queue that never returns null values when enqueuing values 101 */ 102 static <K,V> ExchangeConflationQueue<K, V> nullSafe(final ExchangeConflationQueue<K,V> unsafeQueue, 103 final Function<? super K, ? extends V> valueFactory) { 104 Objects.requireNonNull(unsafeQueue); 105 Objects.requireNonNull(valueFactory); 106 return new ExchangeConflationQueue<K, V>() { 107 final ThreadLocal<Appender<K,V>> appender = ThreadLocal.withInitial(() -> nullSafe(unsafeQueue.appender(), valueFactory)); 108 @Override 109 public Appender<K, V> appender() { 110 return appender.get(); 111 } 112 113 @Override 114 public ExchangePoller<K, V> poller() { 115 return unsafeQueue.poller(); 116 } 117 118 @Override 119 public int size() { 120 return unsafeQueue.size(); 121 } 122 }; 123 } 124 125 /** 126 * Returns an {@link Appender} whose {@link Appender#enqueue(Object, Object) enqueue(..)} method is guaranteed to 127 * never return null. If the unsafe appender returns null on enqueue e.g. because the queue is empty and no 128 * exchange values can be retrieved yet, the specified factory is used to create a value. 129 * 130 * @param unsafeAppender the unsafe appender possibly returning null values on enqueue 131 * @param valueFactory the value factory used if the unsafe enqueuing operation returned null 132 * @param <K> the type of the conflation key 133 * @param <V> the type of values in the queue 134 * @return a null-safe version of the appender that never returns null values when enqueuing values 135 */ 136 static <K,V> Appender<K, V> nullSafe(final Appender<K,V> unsafeAppender, 137 final Function<? super K, ? extends V> valueFactory) { 138 Objects.requireNonNull(unsafeAppender); 139 Objects.requireNonNull(valueFactory); 140 return (k, v) -> { 141 final V value = unsafeAppender.enqueue(k, v); 142 return value == null ? 143 Objects.requireNonNull(valueFactory.apply(k), "value factory returned null") : 144 value; 145 }; 146 } 147}