I split this one up by accident. There was a follow up commit that updated the 
places where they were updated in main. I don’t recall any particular issue 
being resolved, though I was comparing the 2.x and main branches to look for 
differences. Guess I did it in reverse here.
—
Matt Sicker

> On Nov 5, 2023, at 00:08, Ralph Goers <ralph.go...@dslextreme.com> wrote:
> 
> Matt,
> 
> I received 3 emails regarding this lazy stuff being back ported. Is there a 
> related issue for this? With the volume of emails I am getting I may have 
> missed it but I would like to understand, Furthermore, in none of these 
> commit emails did I see a changes file listed? How can I know why you did 
> this without that and user’s won’t either since it won’t appear in the 
> release notes.
> 
> Note that while I would like to avoid back porting from 3.x if it is being 
> done to resolve a bug then I am fine with that. But if this is just a random 
> “improvement” please don’t.
> 
> Ralph
> 
>> On Nov 3, 2023, at 4:22 PM, mattsic...@apache.org wrote:
>> 
>> 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 <mattsic...@apache.org>
>> 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