001    /*
002     * Cobertura - http://cobertura.sourceforge.net/
003     *
004     * Copyright (C) 2010 Piotr Tabor
005     *
006     * Note: This file is dual licensed under the GPL and the Apache
007     * Source License (so that it can be used from both the main
008     * Cobertura classes and the ant tasks).
009     *
010     * Cobertura is free software; you can redistribute it and/or modify
011     * it under the terms of the GNU General Public License as published
012     * by the Free Software Foundation; either version 2 of the License,
013     * or (at your option) any later version.
014     *
015     * Cobertura is distributed in the hope that it will be useful, but
016     * WITHOUT ANY WARRANTY; without even the implied warranty of
017     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
018     * General Public License for more details.
019     *
020     * You should have received a copy of the GNU General Public License
021     * along with Cobertura; if not, write to the Free Software
022     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
023     * USA
024     */
025    
026    package net.sourceforge.cobertura.coveragedata.countermaps;
027    
028    import java.util.Iterator;
029    import java.util.LinkedHashMap;
030    import java.util.Map;
031    import java.util.concurrent.ConcurrentHashMap;
032    import java.util.concurrent.ConcurrentMap;
033    import java.util.concurrent.atomic.AtomicInteger;
034    
035    import net.sourceforge.cobertura.coveragedata.HasBeenInstrumented;
036    
037    /**
038     * Thread-safe implementation of map that counts number of keys (like multi-set)
039     * @author ptab
040     *
041     * @param <T>
042     */
043    public class AtomicCounterMap<T> implements CounterMap<T>,HasBeenInstrumented{
044            private final ConcurrentMap<T, AtomicInteger> counters=new ConcurrentHashMap<T, AtomicInteger>();
045            
046            public final void incrementValue(T key, int inc){
047                    AtomicInteger v=counters.get(key);
048                    if(v!=null){
049                            v.addAndGet(inc);
050                    }else{
051                            v=counters.putIfAbsent(key, new AtomicInteger(inc));
052                            if(v!=null)v.addAndGet(inc);                    
053                    }
054            }
055            
056            public final void incrementValue(T key){
057                    //AtomicInteger v=counters.putIfAbsent(key, new AtomicInteger(1));
058                    //return (v!=null)?v.incrementAndGet():1;
059                    AtomicInteger v=counters.get(key);
060                    if(v!=null){
061                            v.incrementAndGet();                    
062                    }else{
063                            v=counters.putIfAbsent(key, new AtomicInteger(1));
064                            if(v!=null)v.incrementAndGet();
065                    }
066            }       
067            
068            public final int getValue(T key){
069                    AtomicInteger v=counters.get(key);
070                    return v==null?0:v.get();
071            }
072            
073            
074            public synchronized  Map<T,Integer> getFinalStateAndCleanIt(){            
075                    Map<T,Integer> res=new LinkedHashMap<T, Integer>();
076                    Iterator<Map.Entry<T, AtomicInteger>> iterator=counters.entrySet().iterator();
077                    while (iterator.hasNext()) {
078                            Map.Entry<T, AtomicInteger> entry=iterator.next();
079                            T key=entry.getKey();
080                            int old=entry.getValue().get();
081                            iterator.remove();
082                            if(old>0){
083                                    res.put(key, old);
084                            }
085                    }               
086                    return res;             
087            }
088            
089            public int getSize(){
090                    return counters.size();
091            }
092    }