This is an automated email from the ASF dual-hosted git repository.

mattsicker pushed a commit to branch 2.x
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git


The following commit(s) were added to refs/heads/2.x by this push:
     new 4243f7cfce Backport Lazy util
4243f7cfce is described below

commit 4243f7cfceae535c898b863ada75417c0e4217fc
Author: Matt Sicker <[email protected]>
AuthorDate: Fri Nov 3 18:18:10 2023 -0500

    Backport Lazy util
---
 .../java/org/apache/logging/log4j/util/Lazy.java   |  93 +++++++++++
 .../org/apache/logging/log4j/util/LazyBoolean.java |  66 ++++++++
 .../org/apache/logging/log4j/util/LazyUtil.java    | 171 +++++++++++++++++++++
 3 files changed, 330 insertions(+)

diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/Lazy.java 
b/log4j-api/src/main/java/org/apache/logging/log4j/util/Lazy.java
new file mode 100644
index 0000000000..2e0d84b3ce
--- /dev/null
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/Lazy.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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
+ *
+ *      http://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 org.apache.logging.log4j.util;
+
+import java.util.Objects;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+/**
+ * Provides a lazily-initialized value from a {@code Supplier<T>}.
+ *
+ * @param <T> type of value
+ */
+public interface Lazy<T> extends Supplier<T> {
+    /**
+     * Returns the value held by this lazy. This may cause the value to 
initialize if it hasn't been already.
+     */
+    T value();
+
+    /**
+     * Returns the value held by this lazy. This may cause the value to 
initialize if it hasn't been already.
+     */
+    @Override
+    default T get() {
+        return value();
+    }
+
+    /**
+     * Creates a new lazy value derived from this lazy value using the 
provided value mapping function.
+     */
+    default <R> Lazy<R> map(final Function<? super T, ? extends R> function) {
+        return lazy(() -> function.apply(value()));
+    }
+
+    /**
+     * Indicates whether this lazy value has been initialized.
+     */
+    boolean isInitialized();
+
+    /**
+     * Sets this lazy value to the provided value.
+     *
+     * @throws UnsupportedOperationException if this type of lazy value cannot 
be updated
+     */
+    void set(final T newValue);
+
+    /**
+     * Creates a strict lazy value using the provided Supplier. The supplier 
is guaranteed to only be invoked by at
+     * most one thread, and all threads will see the same published value when 
this returns.
+     */
+    static <T> Lazy<T> lazy(final Supplier<T> supplier) {
+        Objects.requireNonNull(supplier);
+        return new LazyUtil.SafeLazy<>(supplier);
+    }
+
+    /**
+     * Creates a lazy value using the provided constant value.
+     */
+    static <T> Lazy<T> value(final T value) {
+        return new LazyUtil.Constant<>(value);
+    }
+
+    /**
+     * Creates a lazy value using a weak reference to the provided value.
+     */
+    static <T> Lazy<T> weak(final T value) {
+        return new LazyUtil.WeakConstant<>(value);
+    }
+
+    /**
+     * Creates a pure lazy value using the provided Supplier to initialize the 
value. The supplier may be invoked more
+     * than once, and the return value should be a purely computed value as 
the result may be a different instance
+     * each time. This is useful for building cache tables and other pure 
computations.
+     */
+    static <T> Lazy<T> pure(final Supplier<T> supplier) {
+        Objects.requireNonNull(supplier);
+        return new LazyUtil.PureLazy<>(supplier);
+    }
+}
diff --git 
a/log4j-api/src/main/java/org/apache/logging/log4j/util/LazyBoolean.java 
b/log4j-api/src/main/java/org/apache/logging/log4j/util/LazyBoolean.java
new file mode 100644
index 0000000000..26db8639de
--- /dev/null
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/LazyBoolean.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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
+ *
+ *      http://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 org.apache.logging.log4j.util;
+
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.BooleanSupplier;
+
+public class LazyBoolean implements BooleanSupplier {
+    private final BooleanSupplier supplier;
+    private final Lock lock = new ReentrantLock();
+    private volatile boolean initialized;
+    private volatile boolean value;
+
+    public LazyBoolean(final BooleanSupplier supplier) {
+        this.supplier = supplier;
+    }
+
+    @Override
+    public boolean getAsBoolean() {
+        boolean uninitialized = !initialized;
+        boolean value = this.value;
+        if (uninitialized) {
+            lock.lock();
+            try {
+                uninitialized = !initialized;
+                if (uninitialized) {
+                    this.value = value = supplier.getAsBoolean();
+                    initialized = true;
+                }
+            } finally {
+                lock.unlock();
+            }
+        }
+        return value;
+    }
+
+    public void setAsBoolean(final boolean b) {
+        lock.lock();
+        try {
+            initialized = false;
+            value = b;
+            initialized = true;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public void reset() {
+        initialized = false;
+    }
+}
diff --git 
a/log4j-api/src/main/java/org/apache/logging/log4j/util/LazyUtil.java 
b/log4j-api/src/main/java/org/apache/logging/log4j/util/LazyUtil.java
new file mode 100644
index 0000000000..8b0b8c7a29
--- /dev/null
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/LazyUtil.java
@@ -0,0 +1,171 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you 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
+ *
+ *      http://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 org.apache.logging.log4j.util;
+
+import java.lang.ref.WeakReference;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.Supplier;
+
+final class LazyUtil {
+    private static final Object NULL = new Object() {
+        @Override
+        public String toString() {
+            return "null";
+        }
+    };
+
+    static Object wrapNull(final Object value) {
+        return value == null ? NULL : value;
+    }
+
+    static <T> T unwrapNull(final Object value) {
+        return value == NULL ? null : Cast.cast(value);
+    }
+
+    static class Constant<T> implements Lazy<T> {
+        private final T value;
+
+        Constant(final T value) {
+            this.value = value;
+        }
+
+        @Override
+        public T value() {
+            return value;
+        }
+
+        @Override
+        public boolean isInitialized() {
+            return true;
+        }
+
+        @Override
+        public void set(final T newValue) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public String toString() {
+            return String.valueOf(value);
+        }
+    }
+
+    static class WeakConstant<T> implements Lazy<T> {
+        private final WeakReference<T> reference;
+
+        WeakConstant(final T value) {
+            reference = new WeakReference<>(value);
+        }
+
+        @Override
+        public T value() {
+            return reference.get();
+        }
+
+        @Override
+        public boolean isInitialized() {
+            return true;
+        }
+
+        @Override
+        public void set(final T newValue) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public String toString() {
+            return String.valueOf(value());
+        }
+    }
+
+    static class SafeLazy<T> implements Lazy<T> {
+        private final Lock lock = new ReentrantLock();
+        private final Supplier<T> supplier;
+        private volatile Object value;
+
+        SafeLazy(final Supplier<T> supplier) {
+            this.supplier = supplier;
+        }
+
+        @Override
+        public T value() {
+            Object value = this.value;
+            if (value == null) {
+                lock.lock();
+                try {
+                    value = this.value;
+                    if (value == null) {
+                        value = supplier.get();
+                        this.value = wrapNull(value);
+                    }
+                } finally {
+                    lock.unlock();
+                }
+            }
+            return unwrapNull(value);
+        }
+
+        @Override
+        public void set(final T newValue) {
+            value = newValue;
+        }
+
+        public void reset() {
+            value = null;
+        }
+
+        @Override
+        public boolean isInitialized() {
+            return value != null;
+        }
+
+        @Override
+        public String toString() {
+            return isInitialized() ? String.valueOf(value) : "Lazy value not 
initialized";
+        }
+    }
+
+    static class PureLazy<T> implements Lazy<T> {
+        private final Supplier<T> supplier;
+        private Object value;
+
+        public PureLazy(final Supplier<T> supplier) {
+            this.supplier = supplier;
+        }
+
+        @Override
+        public T value() {
+            Object value = this.value;
+            if (value == null) {
+                value = supplier.get();
+                this.value = wrapNull(value);
+            }
+            return unwrapNull(value);
+        }
+
+        @Override
+        public boolean isInitialized() {
+            return value != null;
+        }
+
+        @Override
+        public void set(final T newValue) {
+            value = newValue;
+        }
+    }
+}

Reply via email to