/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkMultiThreaderLocal.h

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
// .NAME vtkMultiThreaderLocal - A vtkMultiThreader based local storage
// implementation.
// .SECTION Description
// A thread local object is one that maintains a copy of an object of the
// template type for each thread that processes data. vtkMultiThreaderLocal is
// designed in the same vein as vtkSMPThreadLocal, except that it works with a
// vtkMultiThreaderLocal and uses a map internally to track local storage
// objects with thread ids for the current thread provided by vtkMultiThreader.
// The object is created the first time Local() is called. Note that unlike
// creates storage for all threads but the actual objects are created
// the first time Local() is called.

#ifndef __vtkMultiThreaderLocal_h
#define __vtkMultiThreaderLocal_h

#include "vtkMultiThreader.h"
#include "vtkCriticalSection.h"
#include <map>

template <typename T>
class vtkMultiThreaderLocal
{
  typedef std::map<vtkMultiThreaderIDType, T> TLS;
  typedef typename TLS::iterator TLSIter;
public:
  // Description:
  // Default constructor. Creates a default exemplar.
  vtkMultiThreaderLocal()
    {
      this->Initialize();
    }

  // Description:
  // Constructor that allows the specification of an exemplar object
  // which is used when constructing objects when Local() is first called.
  // Note that a copy of the exemplar is created using its copy constructor.
  vtkMultiThreaderLocal(const T& exemplar) : Exemplar(exemplar)
    {
      this->Initialize();
    }

  // Description:
  // Returns an object of type T that is local to the current thread.
  // This needs to be called mainly within a threaded execution path.
  // It will create a new object (local to the tread so each thread
  // get their own when calling Local) which is a copy of exemplar as passed
  // to the constructor (or a default object if no exemplar was provided)
  // the first time it is called. After the first time, it will return
  // the same object.
  T& Local()
    {
      vtkMultiThreaderIDType tid = this->GetThreadID();
      CriticalSection.Lock();
      if (!this->Initialized[tid])
        {
        this->Internal[tid] = this->Exemplar;
        this->Initialized[tid] = true;
        }
      CriticalSection.Unlock();
      return this->Internal[tid];
    }

  // Description:
  // Subset of the standard iterator API.
  // The most common design patter is to use iterators in a sequential
  // code block and to use only the thread local objects in parallel
  // code blocks.
  // It is thread safe to iterate over the thread local containers
  // as long as each thread uses its own iterator and does not modify
  // objects in the container.
  class iterator
  {
  public:
    iterator& operator++()
      {
        this->InitIter++;
        this->Iter++;

        // Make sure to skip uninitialized
        // entries.
        while(this->InitIter != this->EndIter)
          {
          if (*this->InitIter)
            {
            break;
            }
          this->InitIter++;
          this->Iter++;
          }
        return *this;
      }

    bool operator!=(const iterator& other)
      {
        return this->Iter != other.Iter;
      }

    T& operator*()
      {
        return *this->Iter;
      }

  private:
    friend class vtkMultiThreaderLocal<T>;
    std::map<vtkMultiThreaderIDType, bool>::iterator InitIter;
    std::map<vtkMultiThreaderIDType, bool>::iterator EndIter;
    TLSIter Iter;
  };

  // Description:
  // Returns a new iterator pointing to the beginning of
  // the local storage container. Thread safe.
  iterator begin()
    {
      TLSIter iter = this->Internal.begin();
      std::map<vtkMultiThreaderIDType, bool>::iterator iter2 =
        this->Initialized.begin();
      std::map<vtkMultiThreaderIDType, bool>::iterator enditer =
        this->Initialized.end();
      // fast forward to first initialized
      // value
      while(iter2 != enditer)
        {
        if (*iter2)
          {
          break;
          }
        iter2++;
        iter++;
        }
      iterator retVal;
      retVal.InitIter = iter2;
      retVal.EndIter = enditer;
      retVal.Iter = iter;
      return retVal;
    };

  // Description:
  // Returns a new iterator pointing to past the end of
  // the local storage container. Thread safe.
  iterator end()
    {
      iterator retVal;
      retVal.InitIter = this->Initialized.end();
      retVal.EndIter = this->Initialized.end();
      retVal.Iter = this->Internal.end();
      return retVal;
    }

private:
  vtkSimpleCriticalSection CriticalSection;
  TLS Internal;
  std::map<vtkMultiThreaderIDType, bool> Initialized;
  T Exemplar;

  void Initialize()
    {
      CriticalSection.Lock();
      this->Initialized.clear();
      this->Internal.clear();
      CriticalSection.Unlock();
    }

  inline vtkMultiThreaderIDType GetThreadID()
    {
      return vtkMultiThreader::GetCurrentThreadID();
    }
};;

#endif
// VTK-HeaderTest-Exclude: vtkMultiThreaderLocal.h
