
/*

  KLayout Layout Viewer
  Copyright (C) 2006-2026 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_dbLEFDEFImporter
#define HDR_dbLEFDEFImporter

#include "dbPluginCommon.h"
#include "dbLayout.h"
#include "dbReader.h"
#include "dbCommonReader.h"
#include "dbStreamLayers.h"
#include "tlStream.h"
#include "tlVariant.h"

#include <vector>
#include <string>
#include <map>

namespace tl
{
  class AbsoluteProgress;
}

namespace db
{

class LEFDEFReaderState;
class LEFDEFImporter;
class LEFImporter;
struct MacroDesc;

/**
 *  @brief Correct a path relative to the stream and technology
 */
DB_PLUGIN_PUBLIC
std::vector<std::string> correct_path (const std::string &fn, const db::Layout &layout, const std::string &base_path, bool glob);

/**
 *  @brief Convers a string to a MASKSHIFT index list
 */
std::vector<unsigned int> string2masks (const std::string &s);

/**
 *  @brief Generic base class of DXF reader exceptions
 */
class DB_PLUGIN_PUBLIC LEFDEFReaderException
  : public db::ReaderException
{
public:
  LEFDEFReaderException (const std::string &msg, int line, const std::string &cell, const std::string &fn)
    : db::ReaderException (line >= 0 ? tl::sprintf (tl::to_string (tr ("%s (line=%d, cell=%s, file=%s)")), msg.c_str (), line, cell, fn) :
                                       tl::sprintf (tl::to_string (tr ("%s (file=%s)")), msg.c_str (), fn))
  { }
};

template <class Value>
const Value &per_mask_value (const std::map<unsigned int, Value> &map, const Value &def, unsigned int mask)
{
  typename std::map<unsigned int, Value>::const_iterator i = map.find (mask);
  return i == map.end () ? def : i->second;
}

inline bool per_mask_value_is_null (int dt) { return dt < 0; }
inline bool per_mask_value_is_null (const std::string &pfx) { return pfx.empty (); }

template <class Value>
void set_per_mask_value (std::map<unsigned int, Value> &map, unsigned int mask, const Value &value)
{
  if (per_mask_value_is_null (value)) {
    map.erase (mask);
  } else {
    map [mask] = value;
  }
}

template <class Value>
void get_max_mask_number (unsigned int &mm, const std::map<unsigned int, Value> &map)
{
  if (! map.empty ()) {
    mm = std::max (mm, (--map.end ())->first);
  }
}

/**
 *  @brief The LEF/DEF importer technology component
 *
 *  This component provides technology specific information for the LEF/DEF importer.
 */
class DB_PLUGIN_PUBLIC LEFDEFReaderOptions
  : public db::FormatSpecificReaderOptions
{
public:
  LEFDEFReaderOptions ();
  LEFDEFReaderOptions (const LEFDEFReaderOptions &d);
  LEFDEFReaderOptions &operator= (const LEFDEFReaderOptions &d);

  db::FormatSpecificReaderOptions *clone () const;
  virtual const std::string &format_name () const;

  bool paths_relative_to_cwd () const
  {
    return m_paths_relative_to_cwd;
  }

  void set_paths_relative_to_cwd (bool f)
  {
    m_paths_relative_to_cwd = f;
  }

  bool read_all_layers () const
  {
    return m_read_all_layers;
  }

  void set_read_all_layers (bool a) 
  {
    m_read_all_layers = a;
  }

  const db::LayerMap &layer_map () const
  {
    return m_layer_map;
  }

  db::LayerMap &layer_map ()
  {
    return m_layer_map;
  }

  void set_layer_map (const db::LayerMap &lm)
  {
    m_layer_map = lm;
  }

  double dbu () const
  {
    return m_dbu;
  }

  void set_dbu (double dbu) 
  {
    m_dbu = dbu;
  }

  bool produce_net_names () const
  {
    return m_produce_net_names;
  }

  void set_produce_net_names (bool f) 
  {
    m_produce_net_names = f;
  }

  const tl::Variant &net_property_name () const
  {
    return m_net_property_name;
  }

  void set_net_property_name (const tl::Variant &s) 
  {
    m_net_property_name = s;
  }

  bool produce_inst_names () const
  {
    return m_produce_inst_names;
  }

  void set_produce_inst_names (bool f)
  {
    m_produce_inst_names = f;
  }

  const tl::Variant &inst_property_name () const
  {
    return m_inst_property_name;
  }

  void set_inst_property_name (const tl::Variant &s)
  {
    m_inst_property_name = s;
  }

  bool produce_pin_names () const
  {
    return m_produce_pin_names;
  }

  void set_produce_pin_names (bool f)
  {
    m_produce_pin_names = f;
  }

  const tl::Variant &pin_property_name () const
  {
    return m_pin_property_name;
  }

  void set_pin_property_name (const tl::Variant &s)
  {
    m_pin_property_name = s;
  }

  bool produce_cell_outlines () const
  {
    return m_produce_cell_outlines;
  }

  void set_produce_cell_outlines (bool f) 
  {
    m_produce_cell_outlines = f;
  }

  const std::string &cell_outline_layer () const
  {
    return m_cell_outline_layer;
  }

  void set_cell_outline_layer (const std::string &s) 
  {
    m_cell_outline_layer = s;
  }

  bool produce_placement_blockages () const
  {
    return m_produce_placement_blockages;
  }

  void set_produce_placement_blockages (bool f) 
  {
    m_produce_placement_blockages = f;
  }

  const std::string &placement_blockage_layer () const
  {
    return m_placement_blockage_layer;
  }

  void set_placement_blockage_layer (const std::string &s) 
  {
    m_placement_blockage_layer = s;
  }

  bool produce_regions () const
  {
    return m_produce_regions;
  }

  void set_produce_regions (bool f)
  {
    m_produce_regions = f;
  }

  const std::string &region_layer () const
  {
    return m_region_layer;
  }

  void set_region_layer (const std::string &s)
  {
    m_region_layer = s;
  }

  bool produce_via_geometry () const
  {
    return m_produce_via_geometry;
  }

  void set_produce_via_geometry (bool f) 
  {
    m_produce_via_geometry = f;
  }

  const std::string &via_geometry_suffix () const
  {
    return m_via_geometry_suffix;
  }

  void set_via_geometry_suffix (const std::string &s) 
  {
    m_via_geometry_suffix = s;
  }

  int via_geometry_datatype () const
  {
    return m_via_geometry_datatype;
  }

  void set_via_geometry_datatype (int s) 
  {
    m_via_geometry_datatype = s;
  }

  void set_via_geometry_suffix_str (const std::string &s);
  std::string via_geometry_suffix_str () const;

  void set_via_geometry_datatype_str (const std::string &s);
  std::string via_geometry_datatype_str () const;

  void clear_via_geometry_suffixes_per_mask ()
  {
    m_via_geometry_suffixes.clear ();
  }

  void clear_via_geometry_datatypes_per_mask ()
  {
    m_via_geometry_datatypes.clear ();
  }

  const std::string &via_geometry_suffix_per_mask (unsigned int mask) const
  {
    return per_mask_value (m_via_geometry_suffixes, m_via_geometry_suffix, mask);
  }

  void set_via_geometry_suffix_per_mask (unsigned int mask, const std::string &s)
  {
    set_per_mask_value (m_via_geometry_suffixes, mask, s);
  }

  int via_geometry_datatype_per_mask (unsigned int mask) const
  {
    return per_mask_value (m_via_geometry_datatypes, m_via_geometry_datatype, mask);
  }

  void set_via_geometry_datatype_per_mask (unsigned int mask, int s)
  {
    set_per_mask_value (m_via_geometry_datatypes, mask, s);
  }

  const std::string &via_cellname_prefix () const
  {
    return m_via_cellname_prefix;
  }

  void set_via_cellname_prefix (const std::string &s)
  {
    m_via_cellname_prefix = s;
  }

  bool produce_pins () const
  {
    return m_produce_pins;
  }

  void set_produce_pins (bool f) 
  {
    m_produce_pins = f;
  }

  const std::string &pins_suffix () const
  {
    return m_pins_suffix;
  }

  void set_pins_suffix (const std::string &s) 
  {
    m_pins_suffix = s;
  }

  int pins_datatype () const
  {
    return m_pins_datatype;
  }

  void set_pins_datatype (int s) 
  {
    m_pins_datatype = s;
  }

  void set_pins_suffix_str (const std::string &s);
  std::string pins_suffix_str () const;

  void set_pins_datatype_str (const std::string &s);
  std::string pins_datatype_str () const;

  void clear_pins_suffixes_per_mask ()
  {
    m_pins_suffixes.clear ();
  }

  void clear_pins_datatypes_per_mask ()
  {
    m_pins_datatypes.clear ();
  }

  const std::string &pins_suffix_per_mask (unsigned int mask) const
  {
    return per_mask_value (m_pins_suffixes, m_pins_suffix, mask);
  }

  void set_pins_suffix_per_mask (unsigned int mask, const std::string &s)
  {
    set_per_mask_value (m_pins_suffixes, mask, s);
  }

  int pins_datatype_per_mask (unsigned int mask) const
  {
    return per_mask_value (m_pins_datatypes, m_pins_datatype, mask);
  }

  void set_pins_datatype_per_mask (unsigned int mask, int s)
  {
    set_per_mask_value (m_pins_datatypes, mask, s);
  }

  bool produce_lef_pins () const
  {
    return m_produce_lef_pins;
  }

  void set_produce_lef_pins (bool f)
  {
    m_produce_lef_pins = f;
  }

  const std::string &lef_pins_suffix () const
  {
    return m_lef_pins_suffix;
  }

  void set_lef_pins_suffix (const std::string &s)
  {
    m_lef_pins_suffix = s;
  }

  int lef_pins_datatype () const
  {
    return m_lef_pins_datatype;
  }

  void set_lef_pins_datatype (int s)
  {
    m_lef_pins_datatype = s;
  }

  void set_lef_pins_suffix_str (const std::string &s);
  std::string lef_pins_suffix_str () const;

  void set_lef_pins_datatype_str (const std::string &s);
  std::string lef_pins_datatype_str () const;

  void clear_lef_pins_suffixes_per_mask ()
  {
    m_lef_pins_suffixes.clear ();
  }

  void clear_lef_pins_datatypes_per_mask ()
  {
    m_lef_pins_datatypes.clear ();
  }

  const std::string &lef_pins_suffix_per_mask (unsigned int mask) const
  {
    return per_mask_value (m_lef_pins_suffixes, m_lef_pins_suffix, mask);
  }

  void set_lef_pins_suffix_per_mask (unsigned int mask, const std::string &s)
  {
    set_per_mask_value (m_lef_pins_suffixes, mask, s);
  }

  int lef_pins_datatype_per_mask (unsigned int mask) const
  {
    return per_mask_value (m_lef_pins_datatypes, m_lef_pins_datatype, mask);
  }

  void set_lef_pins_datatype_per_mask (unsigned int mask, int s)
  {
    set_per_mask_value (m_lef_pins_datatypes, mask, s);
  }

  bool produce_fills () const
  {
    return m_produce_fills;
  }

  void set_produce_fills (bool f)
  {
    m_produce_fills = f;
  }

  const std::string &fills_suffix () const
  {
    return m_fills_suffix;
  }

  void set_fills_suffix (const std::string &s)
  {
    m_fills_suffix = s;
  }

  int fills_datatype () const
  {
    return m_fills_datatype;
  }

  void set_fills_datatype (int s)
  {
    m_fills_datatype = s;
  }

  void set_fills_suffix_str (const std::string &s);
  std::string fills_suffix_str () const;

  void set_fills_datatype_str (const std::string &s);
  std::string fills_datatype_str () const;

  void clear_fills_suffixes_per_mask ()
  {
    m_fills_suffixes.clear ();
  }

  void clear_fills_datatypes_per_mask ()
  {
    m_fills_datatypes.clear ();
  }

  const std::string &fills_suffix_per_mask (unsigned int mask) const
  {
    return per_mask_value (m_fills_suffixes, m_fills_suffix, mask);
  }

  void set_fills_suffix_per_mask (unsigned int mask, const std::string &s)
  {
    set_per_mask_value (m_fills_suffixes, mask, s);
  }

  int fills_datatype_per_mask (unsigned int mask) const
  {
    return per_mask_value (m_fills_datatypes, m_fills_datatype, mask);
  }

  void set_fills_datatype_per_mask (unsigned int mask, int s)
  {
    set_per_mask_value (m_fills_datatypes, mask, s);
  }

  bool produce_obstructions () const
  {
    return m_produce_obstructions;
  }

  void set_produce_obstructions (bool f) 
  {
    m_produce_obstructions = f;
  }

  const std::string &obstructions_suffix () const
  {
    return m_obstructions_suffix;
  }

  void set_obstructions_suffix (const std::string &s) 
  {
    m_obstructions_suffix = s;
  }

  int obstructions_datatype () const
  {
    return m_obstructions_datatype;
  }

  void set_obstructions_datatype (int s) 
  {
    m_obstructions_datatype = s;
  }

  bool produce_blockages () const
  {
    return m_produce_blockages;
  }

  void set_produce_blockages (bool f) 
  {
    m_produce_blockages = f;
  }

  const std::string &blockages_suffix () const
  {
    return m_blockages_suffix;
  }

  void set_blockages_suffix (const std::string &s) 
  {
    m_blockages_suffix = s;
  }

  int blockages_datatype () const
  {
    return m_blockages_datatype;
  }

  void set_blockages_datatype (int s) 
  {
    m_blockages_datatype = s;
  }

  bool produce_labels () const
  {
    return m_produce_labels;
  }

  void set_produce_labels (bool f)
  {
    m_produce_labels = f;
  }

  const std::string &labels_suffix () const
  {
    return m_labels_suffix;
  }

  void set_labels_suffix (const std::string &s) 
  {
    m_labels_suffix = s;
  }

  int labels_datatype () const
  {
    return m_labels_datatype;
  }

  void set_labels_datatype (int s) 
  {
    m_labels_datatype = s;
  }

  bool produce_lef_labels () const
  {
    return m_produce_lef_labels;
  }

  void set_produce_lef_labels (bool f)
  {
    m_produce_lef_labels = f;
  }

  const std::string &lef_labels_suffix () const
  {
    return m_lef_labels_suffix;
  }

  void set_lef_labels_suffix (const std::string &s)
  {
    m_lef_labels_suffix = s;
  }

  int lef_labels_datatype () const
  {
    return m_lef_labels_datatype;
  }

  void set_lef_labels_datatype (int s)
  {
    m_lef_labels_datatype = s;
  }

  bool produce_routing () const
  {
    return m_produce_routing;
  }

  void set_produce_routing (bool f) 
  {
    m_produce_routing = f;
  }

  const std::string &routing_suffix () const
  {
    return m_routing_suffix;
  }

  void set_routing_suffix (const std::string &s) 
  {
    m_routing_suffix = s;
  }

  int routing_datatype () const
  {
    return m_routing_datatype;
  }

  void set_routing_datatype (int s) 
  {
    m_routing_datatype = s;
  }

  void set_routing_suffix_str (const std::string &s);
  std::string routing_suffix_str () const;

  void set_routing_datatype_str (const std::string &s);
  std::string routing_datatype_str () const;

  void clear_routing_suffixes_per_mask ()
  {
    m_routing_suffixes.clear ();
  }

  void clear_routing_datatypes_per_mask ()
  {
    m_routing_datatypes.clear ();
  }

  const std::string &routing_suffix_per_mask (unsigned int mask) const
  {
    return per_mask_value (m_routing_suffixes, m_routing_suffix, mask);
  }

  void set_routing_suffix_per_mask (unsigned int mask, const std::string &s)
  {
    set_per_mask_value (m_routing_suffixes, mask, s);
  }

  int routing_datatype_per_mask (unsigned int mask) const
  {
    return per_mask_value (m_routing_datatypes, m_routing_datatype, mask);
  }

  void set_routing_datatype_per_mask (unsigned int mask, int s)
  {
    set_per_mask_value (m_routing_datatypes, mask, s);
  }

  bool produce_special_routing () const
  {
    return m_produce_special_routing;
  }

  void set_produce_special_routing (bool f)
  {
    m_produce_special_routing = f;
  }

  const std::string &special_routing_suffix () const
  {
    return m_special_routing_suffix;
  }

  void set_special_routing_suffix (const std::string &s)
  {
    m_special_routing_suffix = s;
  }

  int special_routing_datatype () const
  {
    return m_special_routing_datatype;
  }

  void set_special_routing_datatype (int s)
  {
    m_special_routing_datatype = s;
  }

  void set_special_routing_suffix_str (const std::string &s);
  std::string special_routing_suffix_str () const;

  void set_special_routing_datatype_str (const std::string &s);
  std::string special_routing_datatype_str () const;

  void clear_special_routing_suffixes_per_mask ()
  {
    m_special_routing_suffixes.clear ();
  }

  void clear_special_routing_datatypes_per_mask ()
  {
    m_special_routing_datatypes.clear ();
  }

  const std::string &special_routing_suffix_per_mask (unsigned int mask) const
  {
    return per_mask_value (m_special_routing_suffixes, m_special_routing_suffix, mask);
  }

  void set_special_routing_suffix_per_mask (unsigned int mask, const std::string &s)
  {
    set_per_mask_value (m_special_routing_suffixes, mask, s);
  }

  int special_routing_datatype_per_mask (unsigned int mask) const
  {
    return per_mask_value (m_special_routing_datatypes, m_special_routing_datatype, mask);
  }

  void set_special_routing_datatype_per_mask (unsigned int mask, int s)
  {
    set_per_mask_value (m_special_routing_datatypes, mask, s);
  }

  unsigned int max_mask_number () const
  {
    unsigned int mm = 0;
    get_max_mask_number (mm, m_via_geometry_suffixes);
    get_max_mask_number (mm, m_via_geometry_datatypes);
    get_max_mask_number (mm, m_pins_suffixes);
    get_max_mask_number (mm, m_pins_datatypes);
    get_max_mask_number (mm, m_lef_pins_suffixes);
    get_max_mask_number (mm, m_lef_pins_datatypes);
    get_max_mask_number (mm, m_fills_suffixes);
    get_max_mask_number (mm, m_fills_datatypes);
    get_max_mask_number (mm, m_routing_suffixes);
    get_max_mask_number (mm, m_routing_datatypes);
    get_max_mask_number (mm, m_special_routing_suffixes);
    get_max_mask_number (mm, m_special_routing_datatypes);
    return mm;
  }

  void clear_lef_files ()
  {
    m_lef_files.clear ();
  }

  void push_lef_file (const std::string &l)
  {
    m_lef_files.push_back (l);
  }

  std::vector<std::string>::const_iterator begin_lef_files () const
  {
    return m_lef_files.begin ();
  }

  std::vector<std::string>::const_iterator end_lef_files () const
  {
    return m_lef_files.end ();
  }

  std::vector<std::string> lef_files () const
  {
    return m_lef_files;
  }

  void set_lef_files (const std::vector<std::string> &lf)
  {
    m_lef_files = lf;
  }

  bool read_lef_with_def () const
  {
    return m_read_lef_with_def;
  }

  void set_read_lef_with_def (bool f)
  {
    m_read_lef_with_def = f;
  }

  bool separate_groups () const
  {
    return m_separate_groups;
  }

  void set_separate_groups (bool f)
  {
    m_separate_groups = f;
  }

  bool joined_paths () const
  {
    return m_joined_paths;
  }

  void set_joined_paths (bool f)
  {
    m_joined_paths = f;
  }

  const std::vector<std::string> &map_files () const
  {
    return m_map_files;
  }

  void set_map_files (const std::vector<std::string> &f)
  {
    m_map_files = f;
  }

  bool skip_duplicate_macros () const
  {
      return m_skip_duplicate_macros;
  }

  void set_skip_duplicate_macros (bool v)
  {
      m_skip_duplicate_macros = v;
  }

  std::string single_map_file () const
  {
    return m_map_files.empty () ? std::string () : m_map_files.front ();
  }

  void set_single_map_file (const std::string &f)
  {
    m_map_files.clear ();
    if (! f.empty ()) {
      m_map_files.push_back (f);
    }
  }

  /**
   *  @brief Specify the LEF macro resolution strategy when reading DEF files
   *  Values are:
   *    0: propduce LEF geometry unless a FOREIGN cell is specified (default)
   *    1: produce LEF geometry always and ignore FOREIGN
   *    2: produce a placeholder cell always (even if FOREIGN isn't given)
   */
  unsigned int macro_resolution_mode () const
  {
    return m_macro_resolution_mode;
  }

  void set_macro_resolution_mode (unsigned int m)
  {
    m_macro_resolution_mode = m;
  }

  void set_macro_layouts (const std::vector<db::Layout *> &layouts)
  {
    for (std::vector<db::Layout *>::const_iterator l = layouts.begin (); l != layouts.end (); ++l) {
      m_macro_layouts.push_back (*l);
    }
  }

  std::vector<db::Layout *> macro_layouts () const
  {
    std::vector<db::Layout *> res;
    for (tl::weak_collection<db::Layout>::const_iterator m = m_macro_layouts.begin (); m != m_macro_layouts.end (); ++m) {
      if (m.operator-> ()) {
        res.push_back (const_cast<db::Layout *> (m.operator-> ()));
      }
    }
    return res;
  }

  void clear_macro_layout_files ()
  {
    m_macro_layout_files.clear ();
  }

  void push_macro_layout_file (const std::string &l)
  {
    m_macro_layout_files.push_back (l);
  }

  std::vector<std::string>::const_iterator begin_macro_layout_files () const
  {
    return m_macro_layout_files.begin ();
  }

  std::vector<std::string>::const_iterator end_macro_layout_files () const
  {
    return m_macro_layout_files.end ();
  }

  std::vector<std::string> macro_layout_files () const
  {
    return m_macro_layout_files;
  }

  void set_macro_layout_files (const std::vector<std::string> &lf)
  {
    m_macro_layout_files = lf;
  }

  /**
   *  @brief A hidden attribute to enable a LEF context
   *  LEF context are used for chaining DEF readers. This method must be
   *  called on local copy of the importer options. With this attribute
   *  set to "true", the client code can store a LEFDEFReaderState object
   *  in this object.
   *  Initially, this attribute is set to false.
   *  Note that this attribute is not copied.
   */
  void set_lef_context_enabled (bool context);

  bool lef_context_enabled () const
  {
    return m_lef_context_enabled;
  }

  //  makes the reader state object if required
  db::LEFDEFReaderState *reader_state (db::Layout &layout, const std::string &base_path, const LoadLayoutOptions &options) const;

private:
  bool m_read_all_layers;
  db::LayerMap m_layer_map;
  double m_dbu;
  bool m_produce_net_names;
  tl::Variant m_net_property_name;
  bool m_produce_inst_names;
  tl::Variant m_inst_property_name;
  bool m_produce_pin_names;
  tl::Variant m_pin_property_name;
  bool m_produce_cell_outlines;
  std::string m_cell_outline_layer;
  bool m_produce_placement_blockages;
  std::string m_placement_blockage_layer;
  bool m_produce_regions;
  std::string m_region_layer;
  bool m_produce_via_geometry;
  std::string m_via_geometry_suffix;
  int m_via_geometry_datatype;
  std::map<unsigned int, std::string> m_via_geometry_suffixes;
  std::map<unsigned int, int> m_via_geometry_datatypes;
  std::string m_via_cellname_prefix;
  bool m_produce_pins;
  std::string m_pins_suffix;
  int m_pins_datatype;
  std::map<unsigned int, std::string> m_pins_suffixes;
  std::map<unsigned int, int> m_pins_datatypes;
  bool m_produce_lef_pins;
  std::string m_lef_pins_suffix;
  int m_lef_pins_datatype;
  std::map<unsigned int, std::string> m_lef_pins_suffixes;
  std::map<unsigned int, int> m_lef_pins_datatypes;
  bool m_produce_fills;
  std::string m_fills_suffix;
  int m_fills_datatype;
  std::map<unsigned int, std::string> m_fills_suffixes;
  std::map<unsigned int, int> m_fills_datatypes;
  bool m_produce_obstructions;
  std::string m_obstructions_suffix;
  int m_obstructions_datatype;
  bool m_produce_blockages;
  std::string m_blockages_suffix;
  int m_blockages_datatype;
  bool m_produce_labels;
  std::string m_labels_suffix;
  int m_labels_datatype;
  bool m_produce_lef_labels;
  std::string m_lef_labels_suffix;
  int m_lef_labels_datatype;
  bool m_produce_routing;
  std::string m_routing_suffix;
  int m_routing_datatype;
  std::map<unsigned int, std::string> m_routing_suffixes;
  std::map<unsigned int, int> m_routing_datatypes;
  bool m_produce_special_routing;
  std::string m_special_routing_suffix;
  int m_special_routing_datatype;
  std::map<unsigned int, std::string> m_special_routing_suffixes;
  std::map<unsigned int, int> m_special_routing_datatypes;
  bool m_separate_groups;
  bool m_joined_paths;
  std::vector<std::string> m_map_files;
  bool m_skip_duplicate_macros;
  unsigned int m_macro_resolution_mode;
  bool m_read_lef_with_def;
  std::vector<std::string> m_lef_files;
  tl::weak_collection<db::Layout> m_macro_layouts;
  std::vector<std::string> m_macro_layout_files;
  bool m_paths_relative_to_cwd;
  bool m_lef_context_enabled;
  mutable std::unique_ptr<db::LEFDEFReaderState> mp_reader_state;
};

/**
 *  @brief Defines the layer purposes provided so far
 */
enum LayerPurpose 
{
  None = 0,
  Routing,            //  from DEF only
  Pins,               //  from DEF
  Fills,              //  from DEF
  FillsOPC,           //  from DEF
  SpecialRouting,     //  from DEF only
  LEFPins,            //  from LEF
  ViaGeometry,        //  from LEF+DEF
  Label,              //  from DEF
  LEFLabel,           //  from LEF
  Obstructions,       //  from LEF only
  Outline,            //  from LEF+DEF
  Blockage,           //  from DEF only
  PlacementBlockage,  //  from DEF only
  Regions,            //  from DEF only
  RegionsNone,        //  from DEF only
  RegionsFence,       //  from DEF only
  RegionsGuide,       //  from DEF only
  All                 //  from DEF only
};

/**
 *  @brief A structure holding the layer details like purpose, mask and via size
 */
struct LayerDetailsKey
{
  LayerDetailsKey ()
    : purpose (Routing), mask (0)
  { }

  LayerDetailsKey (LayerPurpose _purpose, unsigned int _mask = 0, const db::DVector &_via_size = db::DVector ())
    : purpose (_purpose), mask (_mask), via_size (_via_size)
  {
    //  normalize the via size such that x is smaller than y size (issue-1065)
    if (via_size.y () < via_size.x ()) {
      via_size = db::DVector (via_size.y (), via_size.x ());
    }
  }

  bool operator< (const LayerDetailsKey &other) const
  {
    if (purpose != other.purpose) {
      return purpose < other.purpose;
    }
    if (mask != other.mask) {
      return mask < other.mask;
    }
    return via_size.less (other.via_size);
  }

  bool operator== (const LayerDetailsKey &other) const
  {
    if (purpose != other.purpose) {
      return false;
    }
    if (mask != other.mask) {
      return false;
    }
    return via_size.equal (other.via_size);
  }

  LayerPurpose purpose;
  unsigned int mask;
  db::DVector via_size;
};

/**
 *  @brief An interface for resolving the number of masks from a layer name
 */
class DB_PLUGIN_PUBLIC LEFDEFNumberOfMasks
{
public:
  LEFDEFNumberOfMasks () { }
  virtual ~LEFDEFNumberOfMasks () { }

  virtual unsigned int number_of_masks (const std::string &layer_name) const = 0;
};

/**
 *  @brief Provides a via generator base class
 */
class DB_PLUGIN_PUBLIC LEFDEFLayoutGenerator
{
public:
  LEFDEFLayoutGenerator () : def_local (false) { }
  virtual ~LEFDEFLayoutGenerator () { }

  virtual void create_cell (LEFDEFReaderState &reader, db::Layout &layout, db::Cell &cell, const std::vector<std::string> *maskshift_layers, const std::vector<unsigned int> &masks, const LEFDEFNumberOfMasks *nm) = 0;
  virtual std::vector<std::string> maskshift_layers () const = 0;
  virtual bool is_fixedmask () const = 0;

  bool def_local;
};

/**
 *  @brief Provides a via generator implementation for rule-based vias
 */
class DB_PLUGIN_PUBLIC RuleBasedViaGenerator
  : public LEFDEFLayoutGenerator
{
public:
  RuleBasedViaGenerator ();

  virtual void create_cell (LEFDEFReaderState &reader, Layout &layout, db::Cell &cell, const std::vector<std::string> *maskshift_layers, const std::vector<unsigned int> &masks, const LEFDEFNumberOfMasks *nm);

  virtual std::vector<std::string> maskshift_layers () const
  {
    std::vector<std::string> msl;
    msl.push_back (m_bottom_layer);
    msl.push_back (m_cut_layer);
    msl.push_back (m_top_layer);
    return msl;
  }

  virtual bool is_fixedmask () const
  {
    return false;
  }

  void set_cutsize (const db::Vector &cutsize) { m_cutsize = cutsize; }
  void set_cutspacing (const db::Vector &cutspacing) { m_cutspacing = cutspacing; }
  void set_offset (const db::Point &offset) { m_offset = offset; }
  void set_be (const db::Vector &be) { m_be = be; }
  void set_te (const db::Vector &te) { m_te = te; }
  void set_bo (const db::Vector &bo) { m_bo = bo; }
  void set_to (const db::Vector &to) { m_to = to; }
  void set_rows (int rows) { m_rows = rows; }
  void set_columns (int columns) { m_columns = columns; }
  void set_pattern (const std::string &pattern) { m_pattern = pattern; }
  void set_bottom_layer (const std::string &ln) { m_bottom_layer = ln; }
  void set_cut_layer (const std::string &ln) { m_cut_layer = ln; }
  void set_top_layer (const std::string &ln) { m_top_layer = ln; }
  void set_bottom_mask (unsigned int m) { m_bottom_mask = m; }
  void set_cut_mask (unsigned int m) { m_cut_mask = m; }
  void set_top_mask (unsigned int m) { m_top_mask = m; }

private:
  std::string m_bottom_layer, m_cut_layer, m_top_layer;
  unsigned int m_bottom_mask, m_cut_mask, m_top_mask;
  db::Vector m_cutsize, m_cutspacing;
  db::Vector m_be, m_te;
  db::Vector m_bo, m_to;
  db::Point m_offset;
  int m_rows, m_columns;
  std::string m_pattern;
};

/**
 *  @brief Provides a geometry-based via generator implementation
 */
class DB_PLUGIN_PUBLIC GeometryBasedLayoutGenerator
  : public LEFDEFLayoutGenerator
{
public:
  GeometryBasedLayoutGenerator ();

  virtual void create_cell (LEFDEFReaderState &reader, Layout &layout, db::Cell &cell, const std::vector<std::string> *maskshift_layers, const std::vector<unsigned int> &masks, const LEFDEFNumberOfMasks *num_cut_masks);
  virtual std::vector<std::string> maskshift_layers () const { return m_maskshift_layers; }
  virtual bool is_fixedmask () const { return m_fixedmask; }

  void add_polygon (const std::string &ln, LayerPurpose purpose, const db::Polygon &poly, unsigned int mask, properties_id_type prop_id, const DVector &via_size = db::DVector ());
  void add_box (const std::string &ln, LayerPurpose purpose, const db::Box &box, unsigned int mask, properties_id_type prop_id, const DVector &via_size = db::DVector ());
  void add_path (const std::string &ln, LayerPurpose purpose, const db::Path &path, unsigned int mask, properties_id_type prop_id, const DVector &via_size = db::DVector ());
  void add_via (const std::string &vn, const db::Trans &trans, unsigned int bottom_mask, unsigned int cut_mask, unsigned int top_mask);
  void add_text (const std::string &ln, LayerPurpose purpose, const db::Text &text, unsigned int mask, db::properties_id_type prop_id);

  void set_maskshift_layers (const std::vector<std::string> &ln) { m_maskshift_layers = ln; }

  void set_maskshift_layer (unsigned int l, const std::string &s)
  {
    if (m_maskshift_layers.size () <= size_t (l)) {
      m_maskshift_layers.resize (l + 1, std::string ());
    }
    m_maskshift_layers[l] = s;
  }

  void set_fixedmask (bool f)
  {
    m_fixedmask = f;
  }

  void subtract_overlap_from_outline (const std::set<std::string> &overlap_layers);

private:
  struct Via {
    Via () : bottom_mask (0), cut_mask (0), top_mask (0) { }
    std::string name;
    std::string nondefaultrule;
    unsigned int bottom_mask, cut_mask, top_mask;
    db::Trans trans;
  };

  std::map <std::pair<std::string, LayerDetailsKey>, db::Shapes> m_shapes;
  std::list<Via> m_vias;
  std::vector<std::string> m_maskshift_layers;
  bool m_fixedmask;

  unsigned int get_maskshift (const std::string &ln, const std::vector<std::string> *maskshift_layers, const std::vector<unsigned int> &masks);
  unsigned int mask_for (const std::string &ln, unsigned int m, unsigned int mshift, const LEFDEFNumberOfMasks *nm) const;
  unsigned int combine_maskshifts (const std::string &ln, unsigned int mshift1, unsigned int mshift2, const LEFDEFNumberOfMasks *nm) const;
};

/**
 *  @brief Layer handler delegate
 *
 *  This class will handle the creation and management of layers in the LEF/DEF reader context
 */
class DB_PLUGIN_PUBLIC LEFDEFReaderState
  : public db::CommonReaderBase
{
public:
  /**
   *  @brief Constructor
   */
  LEFDEFReaderState (const LEFDEFReaderOptions *tc);

  /**
   *  @brief Destructor
   */
  ~LEFDEFReaderState ();

  /**
   *  @brief Initialize with the layout and base path
   */
  void init (db::Layout &layout, const std::string &base_path, const LoadLayoutOptions &options);

  /**
   *  @brief Attaches to or detaches from an importer
   */
  void attach_reader (LEFDEFImporter *importer)
  {
    mp_importer = importer;
  }

  /**
   *  @brief Reads the given list of map files
   *
   *  If multiple files are given, they are concatenated.
   */
  void read_map_files (const std::vector<std::string> &filename, db::Layout &layout, const std::string &base_path);

  /**
   *  @brief Gets the layer map
   */
  const db::LayerMap &layer_map () const
  {
    return m_layer_map;
  }

  /**
   *  @brief Create a new layer or return the index of the given layer
   */
  std::set<unsigned int> open_layer (db::Layout &layout, const std::string &name, LayerPurpose purpose, unsigned int mask, const DVector &via_size = db::DVector ());

  /**
   *  @brief Create a new layer or return the index of the given layer
   */
  template <class Shape>
  std::set<unsigned int> open_layer (db::Layout &layout, const std::string &name, LayerPurpose purpose, unsigned int mask, const Shape &via_shape)
  {
    db::Box via_box = db::box_convert<Shape> () (via_shape);
    return open_layer (layout, name, purpose, mask, db::DVector (via_box.width () * layout.dbu (), via_box.height () * layout.dbu ()));
  }

  /**
   *  @brief Registers a layer (assign a new default layer number)
   */
  void register_layer (const std::string &l);

  /**
   *  @brief Start reading a file
   *  After the file is read, "finish" needs to be called.
   */
  void start ();

  /**
   *  @brief Finish, i.e. assign GDS layer numbers to the layers
   *  This is the counterpart for "start".
   */
  void finish (db::Layout &layout);

  /**
   *  @brief Registers a via generator for the via with the given name
   *
   *  The generator is capable of creating a via for a specific mask configuration
   */
  void register_via_cell (const std::string &vn, const std::string &nondefaultrule, LEFDEFLayoutGenerator *generator);

  /**
   *  @brief Gets the via cell for the given via name or 0 if no such via is registered
   */
  db::Cell *via_cell (const std::string &vn, const std::string &nondefaultrule, Layout &layout, unsigned int mask_bottom, unsigned int mask_cut, unsigned int mask_top, const LEFDEFNumberOfMasks *nm);

  /**
   *  @brief Gets the via generator for a given via name or 0 if there is no such generator
   */
  LEFDEFLayoutGenerator *via_generator (const std::string &vn, const std::string &nondefaultrule);

  /**
   *  @brief Registers a macro generator for the macro with the given name
   *
   *  The generator is capable of creating a macro for a specific mask configuration
   */
  void register_macro_cell (const std::string &mn, LEFDEFLayoutGenerator *generator);

  /**
   *  @brief Gets the macro cell for the given macro name or 0 if no such macro is registered
   */
  std::pair<db::Cell *, db::Trans> macro_cell (const std::string &mn, Layout &layout, const std::vector<std::string> &maskshift_layers, const std::vector<unsigned int> &masks, const MacroDesc &macro_desc, const LEFDEFNumberOfMasks *nm);

  /**
   *  @brief Gets the macro generator for a given macro name or 0 if there is no such generator
   */
  LEFDEFLayoutGenerator *macro_generator (const std::string &mn);

  /**
   *  @brief Get the technology component pointer
   */
  const LEFDEFReaderOptions *tech_comp () const
  {
    return mp_tech_comp;
  }

  /**
   *  @brief Gets a map of foreign cells vs. name
   */
  const std::map<std::string, db::cell_index_type> &foreign_cells () const
  {
    return m_foreign_cells;
  }

  /**
   *  @brief Issues an error
   */
  void error (const std::string &msg);

  /**
   *  @brief Issues a warning
   */
  void warn (const std::string &msg, int warn_level = 1);

  /**
   *  @brief Ensures the LEF importer for DEF reading is available
   */
  void ensure_lef_importer (int warn_level);

  /**
   *  @brief Gets the LEF importer for DEF reading
   */
  db::LEFImporter &lef_importer ();

  /**
   *  @brief Reads a LEF file into the LEF importer
   *
   *  Multiple LEF files can be read.
   */
  void read_lef (const std::string &fn, db::Layout &layout);

  /**
   *  @brief Provided for test purposes
   */
  void finish_lef (db::Layout &layout);

  /**
   *  @brief Gets a value indicating whether the given LEF file was already read
   */
  bool lef_file_already_read (const std::string &fn)
  {
    return m_lef_files_read.find (fn) != m_lef_files_read.end ();
  }

  /**
   *  @brief Gets the stored macro layouts
   */
  const std::vector<db::Layout *> &macro_layouts () const
  {
    return m_macro_layouts;
  }

protected:
  virtual void common_reader_error (const std::string &msg) { error (msg); }
  virtual void common_reader_warn (const std::string &msg, int warn_level) { warn (msg, warn_level); }

private:
  /**
   *  @brief A key for the via cache
   */
  struct ViaKey
  {
    ViaKey (const std::string &n, const std::string &ndr, unsigned int mb, unsigned int mc, unsigned int mt)
      : name (n), nondefaultrule (ndr), mask_bottom (mb), mask_cut (mc), mask_top (mt)
    { }

    bool operator== (const ViaKey &other) const
    {
      return name == other.name && nondefaultrule == other.nondefaultrule && mask_bottom == other.mask_bottom && mask_cut == other.mask_cut && mask_top == other.mask_top;
    }

    bool operator< (const ViaKey &other) const
    {
      if (name != other.name) {
        return name < other.name;
      }
      if (nondefaultrule != other.nondefaultrule) {
        return nondefaultrule < other.nondefaultrule;
      }
      if (mask_bottom != other.mask_bottom) {
        return mask_bottom < other.mask_bottom;
      }
      if (mask_cut != other.mask_cut) {
        return mask_cut < other.mask_cut;
      }
      if (mask_top != other.mask_top) {
        return mask_top < other.mask_top;
      }
      return false;
    }

    std::string name, nondefaultrule;
    unsigned int mask_bottom, mask_cut, mask_top;
  };

  /**
   *  @brief A key for the via cache
   */
  struct MacroKey
  {
    MacroKey ()
    { }

    MacroKey (const std::string &n, const std::vector<unsigned int> &m)
      : name (n), masks (m)
    { }

    bool operator== (const MacroKey &other) const
    {
      return name == other.name && masks == other.masks;
    }

    bool operator< (const MacroKey &other) const
    {
      if (name != other.name) {
        return name < other.name;
      }
      if (masks != other.masks) {
        return masks < other.masks;
      }
      return false;
    }

    std::string name;
    std::vector<unsigned int> masks;
  };

  //  no copying
  LEFDEFReaderState (const LEFDEFReaderState &);
  LEFDEFReaderState &operator= (const LEFDEFReaderState &);

  LEFDEFImporter *mp_importer;
  std::map <std::pair<std::string, LayerDetailsKey>, std::set<unsigned int> > m_layers;
  db::LayerMap m_layer_map;
  bool m_create_layers;
  bool m_has_explicit_layer_mapping;
  int m_laynum;
  std::map<std::string, int> m_default_number;
  const LEFDEFReaderOptions *mp_tech_comp;
  std::map<ViaKey, db::Cell *> m_via_cells;
  std::multimap<std::pair<std::string, std::string>, LEFDEFLayoutGenerator *> m_via_generators;
  std::map<MacroKey, std::pair<db::Cell *, db::Trans> > m_macro_cells;
  std::map<std::string, LEFDEFLayoutGenerator *> m_macro_generators;
  std::map<std::string, db::cell_index_type> m_foreign_cells;
  std::set<std::string> m_lef_files_read;
  std::vector<db::Layout *> m_macro_layouts;
  tl::shared_collection<db::Layout> m_macro_layout_object_holder;
  std::unique_ptr<db::LEFImporter> mp_lef_importer;

  std::set<unsigned int> open_layer_uncached (db::Layout &layout, const std::string &name, LayerPurpose purpose, unsigned int mask);
  db::cell_index_type foreign_cell(Layout &layout, const std::string &name);
  void read_single_map_file (const std::string &path, std::map<std::pair<std::string, LayerDetailsKey>, std::vector<db::LayerProperties> > &layer_map);
  std::pair<LEFDEFLayoutGenerator *, std::string> via_generator_and_rule (const std::string &vn, const std::string &nondefaultrule);
};

/**
 *  @brief A structure describing a via
 */
struct DB_PLUGIN_PUBLIC ViaDesc
{
  ViaDesc () { }

  /**
   *  @brief The names of bottom and top metal respectively
   */
  std::string m1, m2;
};

/**
 *  @brief A structure describing a macro
 */
struct DB_PLUGIN_PUBLIC MacroDesc
{
  MacroDesc () { }

  /**
   *  @brief The name of the FOREIGN cell if present
   */
  std::string foreign_name;

  /**
   *  @brief The transformation of the FOREIGN cell
   */
  db::Trans foreign_trans;

  /**
   *  @brief The origin
   */
  db::Point origin;

  /**
   *  @brief The bounding box
   */
  db::Box bbox;
};

/**
 *  @brief The LEF importer object
 */
class DB_PLUGIN_PUBLIC LEFDEFImporter
{
public:
  friend class LEFDEFReaderState;

  /**
   *  @brief Default constructor
   */
  LEFDEFImporter (int warn_level);

  /**
   *  @brief Destructor
   */
  virtual ~LEFDEFImporter ();

  /**
   *  @brief Read into an existing layout
   *
   *  This method reads the layout specified into the given layout
   */
  void read (tl::InputStream &stream, db::Layout &layout, LEFDEFReaderState &state);

  /**
   *  @brief Issue an error at the current location
   */
  void error (const std::string &msg);

  /**
   *  @brief Issue a warning at the current location
   */
  void warn (const std::string &msg, int wl = 1);

protected:
  /**
   *  @brief Actually does the reading
   *
   *  Reimplement that method for the LEF and DEF implementation
   */
  virtual void do_read (db::Layout &layout) = 0;

  /**
   *  @brief Returns true if the reader is at the end of the file
   */
  bool at_end ();

  /**
   *  @brief Test whether the next token matches the given one and consume it in that case
   */
  bool test (const std::string &token);

  /**
   *  @brief Test whether the next token matches the given one, but don't consume it
   */
  bool peek (const std::string &token);

  /**
   *  @brief Test whether the next token matches the given one and raise an error if it does not
   */
  void expect (const std::string &token);

  /**
   *  @brief Test whether the next token matches one of the given ones and raise an error if it does not
   */
  void expect (const std::string &token1, const std::string &token2);

  /**
   *  @brief Test whether the next token matches one of the given ones and raise an error if it does not
   */
  void expect (const std::string &token, const std::string &token2, const std::string &token3);

  /**
   *  @brief Gets the next token
   */
  std::string get ();

  /**
   *  @brief Consumes the current token
   */
  void take ();

  /**
   *  @brief Reads the next token as a double value
   */
  double get_double ();

  /**
   *  @brief Reads the next token as a long value
   */
  long get_long ();

  /**
   *  @brief Gets an orientation code
   *  The orientation code is read employing the LEF/DEF convention ("N" for r0 etc.)
   */
  db::FTrans get_orient (bool optional);

  /**
   *  @brief Reads a point
   *  A point is given by two coordinates, x and y
   */
  db::Point get_point (double scale);

  /**
   *  @brief Reads a vector
   *  A vector is given by two coordinates, x and y
   */
  db::Vector get_vector (double scale);

  /**
   *  @brief Turns a number into a mask number
   */
  unsigned int get_mask (long m);

  /**
   *  @brief Create a new layer or return the index of the given layer
   */
  std::set<unsigned int> open_layer (db::Layout &layout, const std::string &name, LayerPurpose purpose, unsigned int mask, const db::DVector &via_size = db::DVector ())
  {
    return mp_reader_state->open_layer (layout, name, purpose, mask, via_size);
  }

  /**
   *  @brief Registers a layer (assign a new default layer number)
   */
  void register_layer (const std::string &l)
  {
    mp_reader_state->register_layer (l);
  }

  /**
   *  @brief Sets the current cell name
   */
  void set_cellname (const std::string &cn)
  {
    m_cellname = cn;
  }

  /**
   *  @brief Reset the current cell name
   */
  void reset_cellname ()
  {
    m_cellname.clear ();
  }

  /**
   *  @brief Gets a flag indicating whether net names shall be produced as properties
   */
  bool produce_net_props () const
  {
    return m_produce_net_props;
  }

  /**
   *  @brief Gets the property name id of the net name property
   */
  db::property_names_id_type net_prop_name_id () const
  {
    return m_net_prop_name_id;
  }

  /**
   *  @brief Gets a flag indicating whether instance names shall be produced as properties
   */
  bool produce_inst_props () const
  {
    return m_produce_inst_props;
  }

  /**
   *  @brief Gets the property name id of the instance name property
   */
  db::property_names_id_type inst_prop_name_id () const
  {
    return m_inst_prop_name_id;
  }

  /**
   *  @brief Gets a flag indicating whether pin names shall be produced as properties
   */
  bool produce_pin_props () const
  {
    return m_produce_pin_props;
  }

  /**
   *  @brief Gets the property name id of the pin name property
   */
  db::property_names_id_type pin_prop_name_id () const
  {
    return m_pin_prop_name_id;
  }

  /**
   *  @brief Gets the reader options
   */
  const db::LEFDEFReaderOptions &options () const
  {
    return m_options;
  }

  /**
   *  @brief Gets the reader state object
   */
  db::LEFDEFReaderState *reader_state ()
  {
    return mp_reader_state;
  }

private:
  tl::AbsoluteProgress *mp_progress;
  tl::TextInputStream *mp_stream;
  LEFDEFReaderState *mp_reader_state;
  std::string m_cellname;
  std::string m_fn;
  std::string m_last_token;
  bool m_produce_net_props;
  db::property_names_id_type m_net_prop_name_id;
  bool m_produce_inst_props;
  db::property_names_id_type m_inst_prop_name_id;
  bool m_produce_pin_props;
  db::property_names_id_type m_pin_prop_name_id;
  db::LEFDEFReaderOptions m_options;
  int m_warn_level;
  std::vector<std::string> m_sections;

  friend class LEFDEFSection;

  const std::string &next ();
  void enter_section (const std::string &name);
  void leave_section ();
};

class DB_PLUGIN_PUBLIC LEFDEFSection
{
public:
  LEFDEFSection (LEFDEFImporter *importer, const std::string &name)
    : mp_importer (importer)
  {
    mp_importer->enter_section (name);
  }

  ~LEFDEFSection ()
  {
    mp_importer->leave_section ();
  }

private:
  LEFDEFImporter *mp_importer;
};

class DB_PLUGIN_PUBLIC LEFDEFReader
  : public db::ReaderBase
{
public:
  LEFDEFReader (tl::InputStream &s);

  virtual const db::LayerMap &read (db::Layout &layout, const db::LoadLayoutOptions &options);
  virtual const db::LayerMap &read (db::Layout &layout);

  virtual const char *format () const;

  const db::LayerMap &read_lefdef (db::Layout &layout, const db::LoadLayoutOptions &options, bool import_lef);

private:
  tl::InputStream &m_stream;
  db::LayerMap m_layer_map;
};

}

#endif


