<commit_before>package com.winterwell.utils;

import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;

import com.winterwell.utils.containers.Containers;
import com.winterwell.utils.log.Log;

/**
 * Dependency: Store common dependencies, like settings, database access objects, etc.
 * Stuff you might otherwise put in a static field somewhere.
 * A simple form of dependency injection - without forcing your code into a framework.
 * 
 * @see Environment ?? Should we merge these two classes?
 * @author daniel
 * @testedby DepTest
 */
public final class Dep {

	// ah, just look in the logs
//	static boolean debug;
//	
//	/**
//	 * If true, Dep will record the source for each object
//	 * @param debug
//	 */
//	public static void setDebug(boolean debug) {
//		Dep.debug = debug;
//	}
	
	static ConcurrentHashMap<DKey, Object> stash = new ConcurrentHashMap<>();
	
	static ConcurrentHashMap<DKey, Supplier> factory = new ConcurrentHashMap<>();
	
	public static <X> void setSupplier(Class<X> klass, boolean singleton, Supplier<X> supplier) {
		Log.d("dep", "set "+klass+" = <supplier> "+ReflectionUtils.getSomeStack(6, Dep.class.getName()));
		DepContext ctxt = getContext();
		if (singleton) {
			Supplier supplier2 = () -> {
				X x = supplier.get();
				stash.put(key(klass, ctxt), x);
				return x;
			};
			factory.put(key(klass, ctxt), supplier2);
		}
		factory.put(key(klass, ctxt), supplier);
	}

	
	
	private static DKey key(Class klass, DepContext ctxt) {
		return new DKey(klass, ctxt);
	}

	/**
	 * For use in try-with blocks, e.g.
	 * <code>
	 * try (DepContext context = Dep.with(MyThing.class, myThing)) {
	 * 
	 * }
	 * </code>
	 * @param klass
	 * @param value
	 * @return
	 */
	public static <X> DepContext with(Class<X> klass, X value) {
		DepContext context = Dep.setContext(Utils.getRandom().nextInt());
		Dep.set(klass, value);		
		return context;
	}
	
	/**
	 * NB: Very similar to {@link #getWithDefault(Class, Object)}
	 * NB: not thread-safe
	 * @param klass
	 * @param value
	 * @return the value held/set
	 */
	public static <X> X setIfAbsent(Class<X> klass, X value) {
		if (has(klass)) {
			X got = get(klass);
			assert got != null : klass;
			return got;	
		}
		set(klass, value);
		return value;
	}


	/**
	 * NB: Very similar to {@link #setIfAbsent(Class, Object)} but does not set
	 * @param <X>
	 * @param klass
	 * @param defaultValue
	 * @return the value held / the default
	 */
	public static <X> X getWithDefault(Class<X> klass, X defaultValue) {
		if (has(klass)) {
			X got = get(klass);
			// NB: race condition
			if (got != null) return got;	
		}
		return defaultValue;
	}

	/**
	 * 
	 * @param klass
	 * @param value
	 * @return value
	 */
	public static <X> X set(Class<X> klass, X value) {
		Log.d("dep", "set "+klass+" = "+value+" "+ReflectionUtils.getSomeStack(6, Dep.class.getName()));
		DepContext ctxt = getContext();
		DKey key = key(klass, ctxt);
		stash.put(key, value);
		// as a debug aid 
		key.stacktrace = ReflectionUtils.getSomeStack(12);<commit_msg>AppNexus-id-encoding<commit_after>package com.winterwell.utils;

import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;

import com.winterwell.utils.containers.Containers;
import com.winterwell.utils.log.Log;

/**
 * Dependency: Store common dependencies, like settings, database access objects, etc.
 * Stuff you might otherwise put in a static field somewhere.
 * A simple form of dependency injection - without forcing your code into a framework.
 * 
 * @see Environment ?? Should we merge these two classes?
 * @author daniel
 * @testedby DepTest
 */
public final class Dep {

	// ah, just look in the logs
//	static boolean debug;
//	
//	/**
//	 * If true, Dep will record the source for each object
//	 * @param debug
//	 */
//	public static void setDebug(boolean debug) {
//		Dep.debug = debug;
//	}
	
	static ConcurrentHashMap<DKey, Object> stash = new ConcurrentHashMap<>();
	
	static ConcurrentHashMap<DKey, Supplier> factory = new ConcurrentHashMap<>();
	
	public static <X> void setSupplier(Class<X> klass, boolean singleton, Supplier<X> supplier) {
		Log.d("dep", "set "+klass+" = <supplier> "+ReflectionUtils.getSomeStack(6, Dep.class.getName()));
		DepContext ctxt = getContext();
		if (singleton) {
			Supplier supplier2 = () -> {
				X x = supplier.get();
				stash.put(key(klass, ctxt), x);
				return x;
			};
			factory.put(key(klass, ctxt), supplier2);
		}
		factory.put(key(klass, ctxt), supplier);
	}

	
	
	private static DKey key(Class klass, DepContext ctxt) {
		return new DKey(klass, ctxt);
	}

	/**
	 * For use in try-with blocks, e.g.
	 * <code>
	 * try (DepContext context = Dep.with(MyThing.class, myThing)) {
	 * 
	 * }
	 * </code>
	 * @param klass
	 * @param value
	 * @return
	 */
	public static <X> DepContext with(Class<X> klass, X value) {
		DepContext context = Dep.setContext(Utils.getRandom().nextInt());
		Dep.set(klass, value);		
		return context;
	}
	
	/**
	 * NB: Very similar to {@link #getWithDefault(Class, Object)}
	 * NB: not thread-safe
	 * @param klass
	 * @param value
	 * @return the value held/set
	 */
	public static <X> X setIfAbsent(Class<X> klass, X value) {
		if (has(klass)) {
			X got = get(klass);
			assert got != null : klass;
			return got;	
		}
		set(klass, value);
		return value;
	}


	/**
	 * NB: Very similar to {@link #setIfAbsent(Class, Object)} but does not set
	 * @param <X>
	 * @param klass
	 * @param defaultValue
	 * @return the value held / the default
	 */
	public static <X> X getWithDefault(Class<X> klass, X defaultValue) {
		if (has(klass)) {
			X got = get(klass);
			// NB: race condition
			if (got != null) return got;	
		}
		return defaultValue;
	}

	/**
	 * Set - can override
	 * @param klass
	 * @param value
	 * @return value
	 */
	public static <X> X set(Class<X> klass, X value) {
		Log.d("dep", "set "+klass+" = "+value+" "+ReflectionUtils.getSomeStack(6, Dep.class.getName()));
		DepContext ctxt = getContext();
		DKey key = key(klass, ctxt);
		Object old = stash.put(key, value);		
		// as a debug aid 
		key.stacktrace = ReflectionUtils.getSomeStack(12);
		if (old != null) {
			Log.w("dep", "set "+klass+" Override! "+old+" with "+value+" Best practice is NOT to override.");
		}
{'fraction_non_alphanumeric': 0.14474102319669527, 'fraction_numerical': 0.0019065776930409914, 'mean_word_length': 3.426863572433193, 'pattern_counts': {'":': 0, '<': 41, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7552472', 'n_tokens_mistral': 2264, 'n_tokens_neox': 2106, 'n_words': 628}