15317bbafSopenharmony_ci/*
25317bbafSopenharmony_ci * Fast QR Code generator library
35317bbafSopenharmony_ci *
45317bbafSopenharmony_ci * Copyright (c) Project Nayuki. (MIT License)
55317bbafSopenharmony_ci * https://www.nayuki.io/page/fast-qr-code-generator-library
65317bbafSopenharmony_ci *
75317bbafSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy of
85317bbafSopenharmony_ci * this software and associated documentation files (the "Software"), to deal in
95317bbafSopenharmony_ci * the Software without restriction, including without limitation the rights to
105317bbafSopenharmony_ci * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
115317bbafSopenharmony_ci * the Software, and to permit persons to whom the Software is furnished to do so,
125317bbafSopenharmony_ci * subject to the following conditions:
135317bbafSopenharmony_ci * - The above copyright notice and this permission notice shall be included in
145317bbafSopenharmony_ci *   all copies or substantial portions of the Software.
155317bbafSopenharmony_ci * - The Software is provided "as is", without warranty of any kind, express or
165317bbafSopenharmony_ci *   implied, including but not limited to the warranties of merchantability,
175317bbafSopenharmony_ci *   fitness for a particular purpose and noninfringement. In no event shall the
185317bbafSopenharmony_ci *   authors or copyright holders be liable for any claim, damages or other
195317bbafSopenharmony_ci *   liability, whether in an action of contract, tort or otherwise, arising from,
205317bbafSopenharmony_ci *   out of or in connection with the Software or the use or other dealings in the
215317bbafSopenharmony_ci *   Software.
225317bbafSopenharmony_ci */
235317bbafSopenharmony_ci
245317bbafSopenharmony_cipackage io.nayuki.fastqrcodegen;
255317bbafSopenharmony_ci
265317bbafSopenharmony_ciimport java.lang.ref.SoftReference;
275317bbafSopenharmony_ciimport java.util.HashSet;
285317bbafSopenharmony_ciimport java.util.Map;
295317bbafSopenharmony_ciimport java.util.Set;
305317bbafSopenharmony_ciimport java.util.concurrent.ConcurrentHashMap;
315317bbafSopenharmony_ciimport java.util.function.Function;
325317bbafSopenharmony_ci
335317bbafSopenharmony_ci
345317bbafSopenharmony_ci// A thread-safe cache based on soft references.
355317bbafSopenharmony_cifinal class Memoizer<T,R> {
365317bbafSopenharmony_ci
375317bbafSopenharmony_ci	private final Function<T,R> function;
385317bbafSopenharmony_ci	Map<T,SoftReference<R>> cache = new ConcurrentHashMap<>();
395317bbafSopenharmony_ci	private Set<T> pending = new HashSet<>();
405317bbafSopenharmony_ci
415317bbafSopenharmony_ci
425317bbafSopenharmony_ci	// Creates a memoizer based on the given function that takes one input to compute an output.
435317bbafSopenharmony_ci	public Memoizer(Function<T,R> func) {
445317bbafSopenharmony_ci		function = func;
455317bbafSopenharmony_ci	}
465317bbafSopenharmony_ci
475317bbafSopenharmony_ci
485317bbafSopenharmony_ci	// Computes function.apply(arg) or returns a cached copy of a previous call.
495317bbafSopenharmony_ci	public R get(T arg) {
505317bbafSopenharmony_ci		// Non-blocking fast path
515317bbafSopenharmony_ci		{
525317bbafSopenharmony_ci			SoftReference<R> ref = cache.get(arg);
535317bbafSopenharmony_ci			if (ref != null) {
545317bbafSopenharmony_ci				R result = ref.get();
555317bbafSopenharmony_ci				if (result != null)
565317bbafSopenharmony_ci					return result;
575317bbafSopenharmony_ci			}
585317bbafSopenharmony_ci		}
595317bbafSopenharmony_ci
605317bbafSopenharmony_ci		// Sequential slow path
615317bbafSopenharmony_ci		while (true) {
625317bbafSopenharmony_ci			synchronized(this) {
635317bbafSopenharmony_ci				SoftReference<R> ref = cache.get(arg);
645317bbafSopenharmony_ci				if (ref != null) {
655317bbafSopenharmony_ci					R result = ref.get();
665317bbafSopenharmony_ci					if (result != null)
675317bbafSopenharmony_ci						return result;
685317bbafSopenharmony_ci					cache.remove(arg);
695317bbafSopenharmony_ci				}
705317bbafSopenharmony_ci				assert !cache.containsKey(arg);
715317bbafSopenharmony_ci
725317bbafSopenharmony_ci				if (pending.add(arg))
735317bbafSopenharmony_ci					break;
745317bbafSopenharmony_ci
755317bbafSopenharmony_ci				try {
765317bbafSopenharmony_ci					this.wait();
775317bbafSopenharmony_ci				} catch (InterruptedException e) {
785317bbafSopenharmony_ci					throw new RuntimeException(e);
795317bbafSopenharmony_ci				}
805317bbafSopenharmony_ci			}
815317bbafSopenharmony_ci		}
825317bbafSopenharmony_ci
835317bbafSopenharmony_ci		try {
845317bbafSopenharmony_ci			R result = function.apply(arg);
855317bbafSopenharmony_ci			cache.put(arg, new SoftReference<>(result));
865317bbafSopenharmony_ci			return result;
875317bbafSopenharmony_ci		} finally {
885317bbafSopenharmony_ci			synchronized(this) {
895317bbafSopenharmony_ci				pending.remove(arg);
905317bbafSopenharmony_ci				this.notifyAll();
915317bbafSopenharmony_ci			}
925317bbafSopenharmony_ci		}
935317bbafSopenharmony_ci	}
945317bbafSopenharmony_ci
955317bbafSopenharmony_ci}
96