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
026package net.sourceforge.cobertura.coveragedata.countermaps;
027
028import java.util.Iterator;
029import java.util.LinkedHashMap;
030import java.util.Map;
031import java.util.concurrent.ConcurrentHashMap;
032import java.util.concurrent.ConcurrentMap;
033import java.util.concurrent.atomic.AtomicInteger;
034
035import 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 */
043public 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}