<commit_before>package com.alexvasilkov.events.cache;

import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
import android.support.annotation.NonNull;

import com.alexvasilkov.events.Event;
import com.alexvasilkov.events.EventResult;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

@SuppressWarnings("unused")
public class MemoryCache implements CacheProvider {

    public static final long NO_TIME_LIMIT = 0L;

    private static final Map<String, CacheEntry> cache = new HashMap<>();
    private static final Handler handler = new CacheHandler();

    private final long maxLifetime;
    private final boolean isClearExpired;

    public MemoryCache() {
        this(NO_TIME_LIMIT, false);
    }

    public MemoryCache(long maxLifetime, boolean isClearExpired) {
        this.maxLifetime = maxLifetime;
        this.isClearExpired = isClearExpired;
    }

    @Override
    public EventResult loadFromCache(@NonNull Event event) {
        synchronized (cache) {
            CacheEntry entry = cache.get(toCacheKey(event));
            boolean expired = entry == null || entry.expires < SystemClock.uptimeMillis();
            return entry == null || expired ? null : entry.result;
        }
    }

    @Override
    public void saveToCache(@NonNull Event event, EventResult result) {
        synchronized (cache) {
            long expires = maxLifetime == NO_TIME_LIMIT
                    ? Long.MAX_VALUE : SystemClock.uptimeMillis() + maxLifetime;
            cache.put(toCacheKey(event), new CacheEntry(result, expires, isClearExpired));
            if (isClearExpired) {
                handler.sendEmptyMessageAtTime(0, expires + 10);
            }
        }
    }

    protected String toCacheKey(@NonNull Event event) {
        StringBuilder builder = new StringBuilder();
        builder.append(event.getKey());

        int count = event.getParamsCount();
        for (int i = 0; i < count; i++) {
            builder.append('_').append(event.getParam(i));
        }

        return builder.toString();
    }

    private static class CacheEntry {
        final EventResult result;
        final long expires;
        final boolean isClearExpired;

        private CacheEntry(EventResult result, long expires, boolean isClearExpired) {
            this.result = result;
            this.expires = expires;
            this.isClearExpired = isClearExpired;
        }
    }

    private static class CacheHandler extends Handler {
        CacheHandler() {
            super(Looper.getMainLooper());
        }

        @Override
        public void handleMessage(@NonNull Message msg) {
            synchronized (cache) {
                long now = SystemClock.uptimeMillis();
                Iterator<Map.Entry<String, CacheEntry>> iterator = cache.entrySet().iterator();

                while (iterator.hasNext()) {
                    CacheEntry entry = iterator.next().getValue();
                    if (entry.isClearExpired && entry.expires < now) {
                        iterator.remove();
                    }
                }
            }
        }
    }

}<commit_msg>MemoryCache uses non static cache field. Removed "isClearExpired" parameter (always clearing cache).<commit_after>package com.alexvasilkov.events.cache;

import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
import android.support.annotation.NonNull;

import com.alexvasilkov.events.Event;
import com.alexvasilkov.events.EventResult;

import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class MemoryCache implements CacheProvider {

    public static final long NO_TIME_LIMIT = 0L;

    private final Map<String, CacheEntry> cache = new HashMap<>();
    private final CacheHandler handler = new CacheHandler(this);
    private final long maxLifetime;

    @SuppressWarnings("unused") // Used through reflection
    public MemoryCache() {
        this(NO_TIME_LIMIT);
    }

    public MemoryCache(long maxLifetime) {
        this.maxLifetime = maxLifetime;
    }

    /**
     * @deprecated {@code isClearExpired} parameter is ignored (it will always be true),
     * so use {@link #MemoryCache(long)} constructor instead.
     */
    @SuppressWarnings("UnusedParameters")
    @Deprecated
    public MemoryCache(long maxLifetime, boolean isClearExpired) {
        this(maxLifetime);
    }

    @Override
    public EventResult loadFromCache(@NonNull Event event) {
        synchronized (cache) {
            clearExpired();
            CacheEntry entry = cache.get(toCacheKey(event));
            return entry == null ? null : entry.result;
        }
    }

    @Override
    public void saveToCache(@NonNull Event event, EventResult result) {
        synchronized (cache) {
            long expires = maxLifetime == NO_TIME_LIMIT
                    ? Long.MAX_VALUE : SystemClock.uptimeMillis() + maxLifetime;
            cache.put(toCacheKey(event), new CacheEntry(result, expires));
            handler.clear(expires);
        }
    }

    protected void clearExpired() {
        synchronized (cache) {
            long now = SystemClock.uptimeMillis();
            for (Iterator<CacheEntry> iterator = cache.values().iterator(); iterator.hasNext(); ) {
                if (iterator.next().expires < now) {
                    iterator.remove();
                }
            }
        }
    }

    protected String toCacheKey(@NonNull Event event) {
        StringBuilder builder = new StringBuilder();
        builder.append(event.getKey());

        int count = event.getParamsCount();
        for (int i = 0; i < count; i++) {
            builder.append('_').append(event.getParam(i));
        }

        return builder.toString();
    }


    private static class CacheEntry {
        final EventResult result;
        final long expires;

        private CacheEntry(EventResult result, long expires) {
            this.result = result;
            this.expires = expires;
        }
    }

    private static class CacheHandler extends Handler {
        private WeakReference<MemoryCache> cache;

        CacheHandler(MemoryCache cache) {
            super(Looper.getMainLooper());
            this.cache = new WeakReference<>(cache);
        }

        private void clear(long when) {
            sendEmptyMessageAtTime(0, when + 10L);
        }

        @Override
        public void handleMessage(@NonNull Message msg) {
            MemoryCache cache = this.cache.get();
            if (cache != null) {
                cache.clearExpired();
            }
        }
    }

}
{'fraction_non_alphanumeric': 0.09607052144031077, 'fraction_numerical': 0.0014940983116689078, 'mean_word_length': 2.335326357747882, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 12, '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': '4264824', 'n_tokens_mistral': 1782, 'n_tokens_neox': 1746, 'n_words': 435}