These are chat archives for TridentSDK/Trident

11th
Mar 2015
TigerReborn
@TigerReborn
Mar 11 2015 22:53
u w0t
Pierre C
@AgentTroll
Mar 11 2015 22:54
.....
mattrick
@devmattrick
Mar 11 2015 22:55
Gay

Markdown

Pierre C
@AgentTroll
Mar 11 2015 22:56
i didn't start it
mattrick
@devmattrick
Mar 11 2015 22:56
"
?
Pierre C
@AgentTroll
Mar 11 2015 22:57
gonna test some code
900+ lines
ready
mattrick
@devmattrick
Mar 11 2015 22:57
Ah
Pierre C
@AgentTroll
Mar 11 2015 22:57
oh
apparently doesn't support that many
/*
 * Trident - A Multithreaded Server Alternative
 * Copyright 2014 The TridentSDK Team
 *
 * Licensed 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 net.tridentsdk.util;

import com.google.common.collect.Sets;
import net.tridentsdk.Trident;
import net.tridentsdk.docs.InternalUseOnly;
import net.tridentsdk.entity.Entity;
import net.tridentsdk.entity.decorate.DecorationAdapter;

import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.ThreadSafe;
import java.lang.ref.WeakReference;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * A reference to an entity
 *
 * <p>Three constructors are provided. In the case that the stored value comes from an <em>alien-source</em>, or any
 * general situation where the value to be held by the WeakEntity is unknown and unspecified, the recommended factory
 * method to use is {@link #orEmpty(net.tridentsdk.entity.Entity)}. This prevents the creation of unnecessary instances
 * of WeakEntity where the value is always going to {@code null}. Because this method always returns the same instance
 * of a {@code null} holding WeakEntity, registration does not need to be executed, where registration means to place
 * the reference into a queue which will be cleared once the entity has been removed. In this context, and alien method
 * is: <em>"A method you call for which you have no control over the code, and further don’t even know what the code
 * does, other than the method signature</em> [...] <em>it could refer to calls to third party libraries</em>."</p>
 *
 * <p>Because entities are loaded with all of their data and AI, the removal of them entirely depends on the references
 * left held to it. If the entity is technically removed by the server, but still held by a plugin, for example, then
 * a memory leak will occur because the entity will never actually be removed. It is not updated for players, but the
 * reference stays in memory, wasting computing power on a non-existent entity.</p>
 *
 * <p>Use this class to store a link or bridge to the reference of an entity. The storage of an instance of this class
 * will only hold this class only, and the reference to the entity in this class may become {@code null} at any time,
 * in which case is indicated by {@link #isNull()} returning {@code true}.</p>
 *
 * <p>Much thought was put into the design of this class, especially if it should be made thread-safe. Because this is
 * an internal change, it can be easily done without breaking the API. However, the decision was made to make this
 * class
 * thread-safe in order to preserve the fact that both the users of this API, including plugins and the server itself
 * is concurrent. It would decrease the burden to handle this safely using the internal implementation rather than
 * having the client code execute awkward constructs in order to keep consistency. This is OK for the implementation to
 * perform, but because plugin authors may not always think about the concurrent nature of this API, it was done at the
 * cost of performance to reduce bugs which are often difficult to find.</p>
 *
 * <p>This is the equivalent of {@link com.google.common.base.Optional} but for entities specifically, much like an
 * optional which stores a {@link java.lang.ref.WeakReference} of the specified property. While this class does use
 * WeakReference to manage the references, other methods to safeguard the reference is also implemented, such
all that fits
lol
// Stores references and collects/cleans up null references
    private static class CleaningRefCollection implements Runnable {
        @GuardedBy("lock")
        private RefEntry[] entries = new RefEntry[16];

        @GuardedBy("lock")
        private int length;

        // Locking mechanisms
        private final Lock lock = new ReentrantLock();
        private final Condition hasNodes = lock.newCondition();

        // INVARIANT: MODIFIED THREAD-LOCALLY ONLY
        private final Set<WeakEntity> marked = Sets.newHashSet();

        private CleaningRefCollection() {
        }

        public static CleaningRefCollection newQueue() {
            return new CleaningRefCollection();
        }

        public void put(WeakEntity<?> weakEntity) {
            RefList node = RefList.newNode(weakEntity, get(weakEntity.or(null)));
            add(node.finder(), node);
        }

        // Clears references to the entity, forcing the sweep to run
        // this leaves the empty node to be collected by the sweeper
        public void clearReference(Entity entity) {
            RefList entities = get(entity);

            if (entities == null)
                return;
            for (WeakEntity<?> e : entities)
                e.clear();

            // Clear unused reference
            beginSweep();
        }

        public Object finderOf(Entity entity) {
            RefList node = get(entity);
            if (node == null)
                return RefList.NULL;

            return node.finder();
        }

        public void beginSweep() {
            lock.lock();
            try {
                hasNodes.signal();
            } finally {
                lock.unlock();
            }
        }

        @Override
        public void run() {
            while (true) {
                try {
                    lock.lockInterruptibly();
                    while (marked.isEmpty())
                        hasNodes.await();

                    // Step 1: find nodes
                    Set<RefEntry> entries = entries();

                    // Step 2: mark
                    for (RefEntry entry : entries) {
                        Set<WeakEntity> weakRefs = entry.val().refs();

                        for (WeakEntity ref : weakRefs) {
                            if (ref.isNull()) {
                                marked.add(ref);
                            }
                        }
                    }

                    // Step 3: sweep
                    for (RefEntry entry : entries) {
                        Set<WeakEntity> refs = entry.val().refs();
                        refs.removeAll(marked);

                        if (refs.isEmpty()) {
                            remove(entry.val());
                        }
                    }

                    // Remove marked entries
                    marked.clear();
                } catch (InterruptedException ignored) {
                    // Run by a daemon thread, doesn't matter if it was interrupted
                } finally {
                    lock.unlock();
                }
            }
        }

        // Collection ops
        private void add(Object key, RefList value) {
            lock.lock();
            try {
                int hash = hash(key);
                RefEntry toSet = this.search(key, value, hash);
                toSet.setHash(hash);
                toSet.setVal(value);
            } finally {
                lock.unlock();
            }
        }

        private RefList get(Object key) {
            lock.lock();
            try {
                int hash = hash(key);
                RefEntry node = this.loop(key, this.entries[hash]);
                if (node == null)
                    return null;
                else
                    return node.val();
            } finally {
                lock.unlock();
            }
        }

        private void remove(Object key) {
            try {
                RefEntry head = this.entries[hash(key)];
                if (head == null)
                    return;
hm
the code highlighting isn't all that bad to be honest
Mazen K
@MazenMC
Mar 11 2015 23:04
It needs some improvements
but not bad
Pierre C
@AgentTroll
Mar 11 2015 23:05
yea
could've used github syntax
but the white background would kill
Mazen K
@MazenMC
Mar 11 2015 23:05
eh, I like dark more
works better at night
Pierre C
@AgentTroll
Mar 11 2015 23:05
true true
why are we even using this
Mazen K
@MazenMC
Mar 11 2015 23:05
idk how people use light themes tbh
Pierre C
@AgentTroll
Mar 11 2015 23:05
yea
Mazen K
@MazenMC
Mar 11 2015 23:05
why not?
Pierre C
@AgentTroll
Mar 11 2015 23:05
hurts the eyes
eh
could use the public chat
lol