text: 
  /*
  
    KLayout Layout Viewer
    Copyright (C) 2006-2020 Matthias Koefferlein
  
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.
  
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
  
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  
  */
  
  
  #ifndef HDR_tlLog
  #define HDR_tlLog
  
  #include "tlCommon.h"
  
  #include "tlString.h"
  #include "tlThreads.h"
  #include "tlObjectCollection.h"
  
  namespace tl
  {
  
  /**
   *  @brief Set the verbosity level
   *
   *  Predefined levels are:
   *    0: none
   *    10: basic
   *    11: basic timing
   *    20: detailed 
   *    21: detailed timing
   *    30: verbose
   *    31: verbose timing
   *    100+: very verbose 
   */
  TL_PUBLIC void verbosity (int level);
  
  /**
   *  @brief Get the verbosity level
   */
  TL_PUBLIC int verbosity ();
  
  /**
   *  @brief A "endl" tag class
   *
   *  This class is supposed to issue a end-of-line.
   */
  
  struct TL_PUBLIC ChannelEndl 
  {
    //  just a "tag"
  };
  
  extern TL_PUBLIC ChannelEndl endl;
  
  /**
   *  @brief A "noendl" tag class
   *
   *  This class is supposed to suppress the implicit end-of-line.
   */
  
  struct TL_PUBLIC ChannelNoendl 
  {
    //  just a "tag"
  };
  
  extern TL_PUBLIC ChannelNoendl noendl;
  
  
  class TL_PUBLIC ChannelProxy;
  
  /**
   *  @brief A basic channel
   *
   *  Channels are supposed to be derived by subclasses providing 
   *  a special implementation for the channels.
   */
  
  class TL_PUBLIC Channel
    : public tl::Object
  {
  public:
    /**
     *  @brief Construct a channel 
     */
    Channel ();
  
    /**
     *  @brief Destructor
     */
    virtual ~Channel ();
  
    /**
     *  @brief Output "something"
     *  
     *  A proxy object to the original channel is returned that does
     *  locking of the channel and reference counting such that the
     *  channel is freed again once it is no longer used.
     */
    template <class T> 
    ChannelProxy operator<< (const T &t);
  
    /**
     *  @brief Output a const char *
     *
     *  For the return object see the generic operator<<
     */
    ChannelProxy operator<< (const char *s);
  
    /**
     *  @brief A end-of-line output
     */
    ChannelProxy operator<< (ChannelEndl);
    
    /**
     *  @brief Suppress the implicit end of line at the end
     */
    ChannelProxy operator<< (ChannelNoendl);
    
  protected:
    //  this is the interface implemented by the subclasses
    virtual void puts (const char *s) = 0;
    virtual void endl () = 0;
    virtual void end () = 0;
    virtual void begin () = 0;
  
    tl::Mutex m_lock;
  
  private:
    friend class ChannelProxy;
    friend class LogTee;
  
    ChannelProxy issue_proxy ();
    void release_proxy ();
  
    void noendl ()
    {
      m_no_endl = true;
    }
  
    bool m_no_endl;
    bool m_active;
  };
  
  /**
   *  @brief A channel proxy
   *
   *  The proxy objects are used to control when the channel is to
   *  be released.
   */
  
  class TL_PUBLIC ChannelProxy
  {
  public:
    /**
     *  @brief Construct a channel proxy to a channel
     */
    ChannelProxy (Channel *channel);
  
    /**
     *  @brief Destructor
     */
    ~ChannelProxy ();
  
    /**
     *  @brief Output "something"
     */
    template <class T> 
    ChannelProxy &operator<< (const T &t)
    {
      mp_channel->puts (tl::to_string (t).c_str ());
      return *this;
    }
  
    /**
     *  @brief Output a const char *
     */
    ChannelProxy &operator<< (const char *s)
    {
      mp_channel->puts (s);
      return *this;
    }
  
    /**
     *  @brief A end-of-line output
     */
    ChannelProxy &operator<< (ChannelEndl)
    {
      mp_channel->endl ();
      return *this;
    }
    
    /**
     *  @brief A end-of-line output
     */
    ChannelProxy &operator<< (ChannelNoendl)
    {
      mp_channel->noendl ();
      return *this;
    }
    
  private:
    Channel *mp_channel; 
  
    //  copying only by the Channel class. This one knows what it does
    friend class Channel;
    ChannelProxy &operator= (const ChannelProxy &);
    ChannelProxy (const ChannelProxy &);
  };
  
  template <class T> 
  inline ChannelProxy 
  Channel::operator<< (const T &t)
  {
    ChannelProxy p = issue_proxy ();
    puts (tl::to_string (t).c_str ());
    return p;
  }
  
  inline ChannelProxy 
  Channel::operator<< (const char *s)
  {
    ChannelProxy p = issue_proxy ();
    puts (s);
    return p;
  }
  
  inline ChannelProxy 
  Channel::operator<< (ChannelEndl)
  {
    ChannelProxy p = issue_proxy ();
    endl ();
    return p;
  }
  
  /**
   *  @brief A multi-cast log distribution object
   */
  
  class TL_PUBLIC LogTee : public Channel
  {
  public:
    LogTee ();
    LogTee (Channel *first, bool owned);
  
    void add (Channel *other, bool owned);
    void prepend (Channel *other, bool owned);
    void clear ();
  
  protected:
    virtual void puts (const char *s);
    virtual void endl ();
    virtual void end ();
    virtual void begin ();
  
  private:
    tl::weak_collection<tl::Channel> m_channels;
    tl::shared_collection<tl::Channel> m_owned_channels;
  };
  
  /// The static instance of the log channel
  /// The log channel is identical to the info channel but is silent depending on the verbosity and 
  /// the output mode. It should be used for general notifications like the beginning of a operation.
  extern TL_PUBLIC LogTee log;
  
  /// The static instance of the info channel
  extern TL_PUBLIC LogTee info;
  
  /// The static instance of the warning channel
  extern TL_PUBLIC LogTee warn;
  
  /// The static instance of the error channel
  extern TL_PUBLIC LogTee error;
  
  
  } // namespace tl
  
  #endif
  
  