<commit_before>/* See LICENSE file for copyright and license details. */
#include "./assemble.h"

#include <cstdio>
#include <tbb/tbb_exception.h>
#include <tbb/task_scheduler_init.h>
#include <boost/program_options.hpp>
#include <boost/lexical_cast.hpp>

namespace po = boost::program_options;

int main(int ac, char* av[]) {
  try {
    std::string world;
    std::string render_mode;
    std::string shadow_quality;
    std::string sun_direction;
    int shadow_strength, relief_strength;
    std::string rotation;

    std::stringstream ss;
    std::string program_name = boost::filesystem::path(av[0]).filename();
    ss << "Usage: " << program_name << " world-number [options]" << std::endl
       << "   or: " << program_name << " directory-name [options]" << std::endl
                    << std::endl
                    << "Options";
    po::options_description desc(ss.str());
    desc.add_options()
      ("help,h", "produce help message\n")
      ("render-mode,m", po::value<std::string>(&render_mode)
                                            ->default_value("top-view"),
                        "'top-view'  or '0'\n"
                        "'oblique'   or '1'\n"
                        "'isometric' or '2'\n")
      ("shadow-quality,q", po::value<std::string>(&shadow_quality)
                                            ->default_value("normal"),
                        "'normal'    or '0'\n"
                        "'high'      or '1'\n"
                        "'ultra'     or '2'\n")
      ("sun-direction,d", po::value<std::string>(&sun_direction)
                                            ->default_value("NW"),
                        "where the sun light comes from (note: this direction "
                        "is already relative to the rotated map):\n"
                        "'NW', 'W', 'SW', 'S',\n"
                        "'SE', 'E', 'NE', 'N'\n")
      ("shadow-strength,s", po::value<int>(&shadow_strength)
                                            ->default_value(60),
                        "set to 0 to disable shadows\n"
                        "set higher to make shadows stronger\n")
      ("relief-strength,l", po::value<int>(&relief_strength)
                                            ->default_value(10),
                        "set to 0 to disable relief effect\n"
                        "set higher to make relief effect stronger\n")
      ("rotation,r", po::value<std::string>(&rotation)
                                            ->default_value("N"),
                        "the top of the map points to:\n"
                        "'N', 'W', 'S', 'E'\n")
      ("night-mode,n",  "enables night mode")
      ("height-map-mono",  "renders monochrome height map")
      ("height-map-color",  "renders color height map")
    ;
    po::options_description hidden("Hidden options");
    hidden.add_options()
      ("world-number,w", po::value<std::string>(&world),
                         "Minecraft world number")
    ;

    po::positional_options_description p;
    p.add("world-number", 1);
    po::options_description all;
    all.add(desc).add(hidden);
    po::options_description visible;
    visible.add(desc);

    po::variables_map vm;
    try {
      po::store(po::command_line_parser(ac, av).options(all).positional(p)
                                               .run(), vm);
      po::notify(vm);
    } catch(po::error e) {
      std::cerr << e.what() << std::endl;
      std::cerr << visible << std::endl;
      return 1;
    }

    Settings set;
    if (vm.count("help")) {
      std::cerr << visible << std::endl;
      return 1;
    }
    if (!vm.count("world-number")) {
      std::cerr << visible << std::endl;
      return 1;
    }
    if (!render_mode.compare("top-view") || !render_mode.compare("0")) {
      set.topview = true;
      set.oblique = false;
      set.isometric = false;
    } else if (!render_mode.compare("oblique") || !render_mode.compare("1")) {
      set.topview = false;
      set.oblique = true;
      set.isometric = false;
    } else if (!render_mode.compare("isometric") || !render_mode.compare("2")) {
      set.topview = false;
      set.oblique = false;
      set.isometric = true;
    } else {
      std::cerr << visible << std::endl;
      return 1;
    }
    if (!shadow_quality.compare("normal") || !shadow_quality.compare("0")) {
      set.shadow_quality = false;
      set.shadow_quality_ultra = false;
    } else if (!shadow_quality.compare("high") || !shadow_quality.compare("1")) {
      set.shadow_quality = true;
      set.shadow_quality_ultra = false;
    } else if (!shadow_quality.compare("ultra") || !shadow_quality.compare("2")) {
      set.shadow_quality = true;
      set.shadow_quality_ultra = true;
    } else {
      std::cerr << visible << std::endl;
      return 1;
    }
    if (!sun_direction.compare("NW")) {
      set.sun_direction = 1;
    } else if (!sun_direction.compare("W")) {
      set.sun_direction = 2;
    } else if (!sun_direction.compare("SW")) {
      set.sun_direction = 3;
    } else if (!sun_direction.compare("S")) {
      set.sun_direction = 4;
    } else if (!sun_direction.compare("SE")) {
      set.sun_direction = 5;
    } else if (!sun_direction.compare("E")) {
      set.sun_direction = 6;
    } else if (!sun_direction.compare("NE")) {
      set.sun_direction = 7;
    } else if (!sun_direction.compare("N")) {
      set.sun_direction = 0;
    } else {
      std::cerr << visible << std::endl;
      return 1;
    }
    set.shadow_strength = shadow_strength;
    set.relief_strength = relief_strength;
    if (!rotation.compare("N")) {
      set.rotate = 1;
    } else if (!rotation.compare("W")) {
      set.rotate = 2;
    } else if (!rotation.compare("S")) {
      set.rotate = 3;
    } else if (!rotation.compare("E")) {
      set.rotate = 0;
    } else {
      std::cerr << visible << std::endl;
      return 1;
    }
    set.nightmode = vm.count("night-mode");
    set.heightmap = vm.count("height-map-mono") || vm.count("height-map-color");
    set.color = vm.count("height-map-color");
    if (!set.topview && (set.heightmap || set.color)) {
      std::cerr << "Height maps are only supported in top-view mode!"
                << std::endl;
      std::cerr << visible << std::endl;
      return 1;
    }

    int world_number;
    try {
      world_number = boost::lexical_cast<int>(world);
      if (world_number > 5 || world_number < 1) {
        std::cerr << "World number must lie between 1 and 5!" << std::endl;
        return 1;
      }
    } catch (boost::bad_lexical_cast& e) {
      world_number = 0;
    }

    nbt bf = world_number ? nbt(world_number) : nbt(av[1]);
    if (bf.bad_world) {
      std::cerr << "Invalid World!" << std::endl;
      return 1;
    }
    std::cout << bf.string();
    bf.setSettings(set);
    std::pair<int, int> min_norm, max_norm;
    calculateMinMaxPoint(min_norm, max_norm, bf);
    std::string buffer_file = "";

    size_t range = static_cast<size_t>(max_norm.second - min_norm.second + 1);
    boost::progress_display show_progress(range);
    std::list<std::vector<int> > tiles(range);
    size_t tiles_nr = fillTiles(tiles, bf, min_norm, max_norm, show_progress);

    writeHeader(buffer_file, min_norm, max_norm, bf);
    FILE* out_file = fopen("test.png", "wb");
    if (!out_file) {
      std::cerr << "Could not open output image file!" << std::endl;
      return 1;
    }

    tbb::atomic<size_t> progress_index;
    progress_index = 0;
    show_progress.restart(tiles_nr);
    std::list<std::vector<int> >::iterator it = tiles.begin();
    tbb::task_scheduler_init init;
    for (int i = min_norm.second; i <= max_norm.second; ++i) {
      tbb::parallel_for(tbb::blocked_range<std::vector<int>::iterator>
                                                         (it->begin(), it->end()),
                        ApplyFoo(&bf, i, &progress_index, min_norm));
      ++it;
      show_progress += progress_index;
      progress_index = 0;
    }

    pamToPng(out_file);
  } catch (std::runtime_error e) {
    std::cerr << e.what() << std::endl;
    return 1;
  } catch (tbb::captured_exception e) {
    std::cerr << "In tbb loop: " << e.what() << e.name() << std::endl;
    return 1;
  }
  return 0;
}
<commit_msg>return when just one tag was read<commit_after>/* See LICENSE file for copyright and license details. */
#include "./assemble.h"

#include <cstdio>
#include <tbb/tbb_exception.h>
#include <tbb/task_scheduler_init.h>
#include <boost/program_options.hpp>
#include <boost/lexical_cast.hpp>

namespace po = boost::program_options;

int main(int ac, char* av[]) {
  try {
    std::string world;
    std::string render_mode;
    std::string shadow_quality;
    std::string sun_direction;
    int shadow_strength, relief_strength;
    std::string rotation;

    std::stringstream ss;
    std::string program_name = boost::filesystem::path(av[0]).filename();
    ss << "Usage: " << program_name << " world-number [options]" << std::endl
       << "   or: " << program_name << " directory-name [options]" << std::endl
                    << std::endl
                    << "Options";
    po::options_description desc(ss.str());
    desc.add_options()
      ("help,h", "produce help message\n")
      ("render-mode,m", po::value<std::string>(&render_mode)
                                            ->default_value("top-view"),
                        "'top-view'  or '0'\n"
                        "'oblique'   or '1'\n"
                        "'isometric' or '2'\n")
      ("shadow-quality,q", po::value<std::string>(&shadow_quality)
                                            ->default_value("normal"),
                        "'normal'    or '0'\n"
                        "'high'      or '1'\n"
                        "'ultra'     or '2'\n")
      ("sun-direction,d", po::value<std::string>(&sun_direction)
                                            ->default_value("NW"),
                        "where the sun light comes from (note: this direction "
                        "is already relative to the rotated map):\n"
                        "'NW', 'W', 'SW', 'S',\n"
                        "'SE', 'E', 'NE', 'N'\n")
      ("shadow-strength,s", po::value<int>(&shadow_strength)
                                            ->default_value(60),
                        "set to 0 to disable shadows\n"
                        "set higher to make shadows stronger\n")
      ("relief-strength,l", po::value<int>(&relief_strength)
                                            ->default_value(10),
                        "set to 0 to disable relief effect\n"
                        "set higher to make relief effect stronger\n")
      ("rotation,r", po::value<std::string>(&rotation)
                                            ->default_value("N"),
                        "the top of the map points to:\n"
                        "'N', 'W', 'S', 'E'\n")
      ("night-mode,n",  "enables night mode")
      ("height-map-mono",  "renders monochrome height map")
      ("height-map-color",  "renders color height map")
    ;
    po::options_description hidden("Hidden options");
    hidden.add_options()
      ("world-number,w", po::value<std::string>(&world),
                         "Minecraft world number")
    ;

    po::positional_options_description p;
    p.add("world-number", 1);
    po::options_description all;
    all.add(desc).add(hidden);
    po::options_description visible;
    visible.add(desc);

    po::variables_map vm;
    try {
      po::store(po::command_line_parser(ac, av).options(all).positional(p)
                                               .run(), vm);
      po::notify(vm);
    } catch(po::error e) {
      std::cerr << e.what() << std::endl;
      std::cerr << visible << std::endl;
      return 1;
    }

    Settings set;
    if (vm.count("help")) {
      std::cerr << visible << std::endl;
      return 1;
    }
    if (!vm.count("world-number")) {
      std::cerr << visible << std::endl;
      return 1;
    }
    if (!render_mode.compare("top-view") || !render_mode.compare("0")) {
      set.topview = true;
      set.oblique = false;
      set.isometric = false;
    } else if (!render_mode.compare("oblique") || !render_mode.compare("1")) {
      set.topview = false;
      set.oblique = true;
      set.isometric = false;
    } else if (!render_mode.compare("isometric") || !render_mode.compare("2")) {
      set.topview = false;
      set.oblique = false;
      set.isometric = true;
    } else {
      std::cerr << visible << std::endl;
      return 1;
    }
    if (!shadow_quality.compare("normal") || !shadow_quality.compare("0")) {
      set.shadow_quality = false;
      set.shadow_quality_ultra = false;
    } else if (!shadow_quality.compare("high") || !shadow_quality.compare("1")) {
      set.shadow_quality = true;
      set.shadow_quality_ultra = false;
    } else if (!shadow_quality.compare("ultra") || !shadow_quality.compare("2")) {
      set.shadow_quality = true;
      set.shadow_quality_ultra = true;
    } else {
      std::cerr << visible << std::endl;
      return 1;
    }
    if (!sun_direction.compare("NW")) {
      set.sun_direction = 1;
    } else if (!sun_direction.compare("W")) {
      set.sun_direction = 2;
    } else if (!sun_direction.compare("SW")) {
      set.sun_direction = 3;
    } else if (!sun_direction.compare("S")) {
      set.sun_direction = 4;
    } else if (!sun_direction.compare("SE")) {
      set.sun_direction = 5;
    } else if (!sun_direction.compare("E")) {
      set.sun_direction = 6;
    } else if (!sun_direction.compare("NE")) {
      set.sun_direction = 7;
    } else if (!sun_direction.compare("N")) {
      set.sun_direction = 0;
    } else {
      std::cerr << visible << std::endl;
      return 1;
    }
    set.shadow_strength = shadow_strength;
    set.relief_strength = relief_strength;
    if (!rotation.compare("N")) {
      set.rotate = 1;
    } else if (!rotation.compare("W")) {
      set.rotate = 2;
    } else if (!rotation.compare("S")) {
      set.rotate = 3;
    } else if (!rotation.compare("E")) {
      set.rotate = 0;
    } else {
      std::cerr << visible << std::endl;
      return 1;
    }
    set.nightmode = vm.count("night-mode");
    set.heightmap = vm.count("height-map-mono") || vm.count("height-map-color");
    set.color = vm.count("height-map-color");
    if (!set.topview && (set.heightmap || set.color)) {
      std::cerr << "Height maps are only supported in top-view mode!"
                << std::endl;
      std::cerr << visible << std::endl;
      return 1;
    }

    int world_number;
    try {
      world_number = boost::lexical_cast<int>(world);
      if (world_number > 5 || world_number < 1) {
        std::cerr << "World number must lie between 1 and 5!" << std::endl;
        return 1;
      }
    } catch (boost::bad_lexical_cast& e) {
      world_number = 0;
    }

    nbt bf = world_number ? nbt(world_number) : nbt(av[1]);
    if (bf.bad_world) {
      std::cerr << "Invalid World!" << std::endl;
      return 1;
    }
    std::cout << bf.string();
    if (bf.tag_) return 0;
    bf.setSettings(set);
    std::pair<int, int> min_norm, max_norm;
    calculateMinMaxPoint(min_norm, max_norm, bf);
    std::string buffer_file = "";

    size_t range = static_cast<size_t>(max_norm.second - min_norm.second + 1);
    boost::progress_display show_progress(range);
    std::list<std::vector<int> > tiles(range);
    size_t tiles_nr = fillTiles(tiles, bf, min_norm, max_norm, show_progress);

    writeHeader(buffer_file, min_norm, max_norm, bf);
    FILE* out_file = fopen("test.png", "wb");
    if (!out_file) {
      std::cerr << "Could not open output image file!" << std::endl;
      return 1;
    }

    tbb::atomic<size_t> progress_index;
    progress_index = 0;
    show_progress.restart(tiles_nr);
    std::list<std::vector<int> >::iterator it = tiles.begin();
    tbb::task_scheduler_init init;
    for (int i = min_norm.second; i <= max_norm.second; ++i) {
      tbb::parallel_for(tbb::blocked_range<std::vector<int>::iterator>
                                                         (it->begin(), it->end()),
                        ApplyFoo(&bf, i, &progress_index, min_norm));
      ++it;
      show_progress += progress_index;
      progress_index = 0;
    }

    pamToPng(out_file);
  } catch (std::runtime_error e) {
    std::cerr << e.what() << std::endl;
    return 1;
  } catch (tbb::captured_exception e) {
    std::cerr << "In tbb loop: " << e.what() << e.name() << std::endl;
    return 1;
  }
  return 0;
}
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2015 Artem Pavlenko, Jean-Francois Doyon
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#include <mapnik/config.hpp>
#include "boost_std_shared_shim.hpp"

#pragma GCC diagnostic push
#include <mapnik/warning_ignore.hpp>
#include <boost/python.hpp>
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
#pragma GCC diagnostic pop

// mapnik
#include <mapnik/layer.hpp>
#include <mapnik/datasource.hpp>
#include <mapnik/datasource_cache.hpp>

using mapnik::layer;
using mapnik::parameters;
using mapnik::datasource_cache;

struct layer_pickle_suite : boost::python::pickle_suite
{
    static boost::python::tuple
    getinitargs(const layer& l)
    {
        return boost::python::make_tuple(l.name(),l.srs());
    }

    static  boost::python::tuple
    getstate(const layer& l)
    {
        boost::python::list s;
        std::vector<std::string> const& style_names = l.styles();
        for (unsigned i = 0; i < style_names.size(); ++i)
        {
            s.append(style_names[i]);
        }
        return boost::python::make_tuple(l.clear_label_cache(),l.minimum_scale_denominator(),l.maximum_scale_denominator(),l.queryable(),l.datasource()->params(),l.cache_features(),s);
    }

    static void
    setstate (layer& l, boost::python::tuple state)
    {
        using namespace boost::python;
        if (len(state) != 9)
        {
            PyErr_SetObject(PyExc_ValueError,
                            ("expected 9-item tuple in call to __setstate__; got %s"
                             % state).ptr()
                );
            throw_error_already_set();
        }

        l.set_clear_label_cache(extract<bool>(state[0]));

        l.set_minimum_scale_denominator(extract<double>(state[1]));

        l.set_maximum_scale_denominator(extract<double>(state[2]));

        l.set_queryable(extract<bool>(state[3]));

        mapnik::parameters params = extract<parameters>(state[4]);
        l.set_datasource(datasource_cache::instance().create(params));

        boost::python::list s = extract<boost::python::list>(state[5]);
        for (int i=0;i<len(s);++i)
        {
            l.add_style(extract<std::string>(s[i]));
        }

        l.set_cache_features(extract<bool>(state[6]));
    }
};

std::vector<std::string> & (mapnik::layer::*_styles_)() = &mapnik::layer::styles;

void set_maximum_extent(mapnik::layer & l, boost::optional<mapnik::box2d<double> > const& box)
{
    if (box)
    {
        l.set_maximum_extent(*box);
    }
    else
    {
        l.reset_maximum_extent();
    }
}

void set_buffer_size(mapnik::layer & l, boost::optional<int> const& buffer_size)
{
    if (buffer_size)
    {
        l.set_buffer_size(*buffer_size);
    }
    else
    {
        l.reset_buffer_size();
    }
}

PyObject * get_buffer_size(mapnik::layer & l)
{
    boost::optional<int> buffer_size = l.buffer_size();
    if (buffer_size)
    {
#if PY_VERSION_HEX >= 0x03000000
        return PyLong_FromLong(*buffer_size);
#else
        return PyInt_FromLong(*buffer_size);
#endif
    }
    else
    {
        Py_RETURN_NONE;
    }
}

void export_layer()
{
    using namespace boost::python;
    class_<std::vector<std::string> >("Names")
        .def(vector_indexing_suite<std::vector<std::string>,true >())
        ;

    class_<layer>("Layer", "A Mapnik map layer.", init<std::string const&,optional<std::string const&> >(
                      "Create a Layer with a named string and, optionally, an srs string.\n"
                      "\n"
                      "The srs can be either a Proj.4 epsg code ('+init=epsg:<code>') or\n"
                      "of a Proj.4 literal ('+proj=<literal>').\n"
                      "If no srs is specified it will default to '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs'\n"
                      "\n"
                      "Usage:\n"
                      ">>> from mapnik import Layer\n"
                      ">>> lyr = Layer('My Layer','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')\n"
                      ">>> lyr\n"
                      "<mapnik._mapnik.Layer object at 0x6a270>\n"
                      ))

        .def_pickle(layer_pickle_suite())

        .def("envelope",&layer::envelope,
             "Return the geographic envelope/bounding box."
             "\n"
             "Determined based on the layer datasource.\n"
             "\n"
             "Usage:\n"
             ">>> from mapnik import Layer\n"
             ">>> lyr = Layer('My Layer','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')\n"
             ">>> lyr.envelope()\n"
             "box2d(-1.0,-1.0,0.0,0.0) # default until a datasource is loaded\n"
            )

        .def("visible", &layer::visible,
             "Return True if this layer's data is active and visible at a given scale_denom.\n"
             "\n"
             "Otherwise returns False.\n"
             "Accepts a scale value as an integer or float input.\n"
             "Will return False if:\n"
             "\tscale_denom >= minimum_scale_denominator - 1e-6\n"
             "\tor:\n"
             "\tscale_denom < maximum_scale_denominator + 1e-6\n"
             "\n"
             "Usage:\n"
             ">>> from mapnik import Layer\n"
             ">>> lyr = Layer('My Layer','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')\n"
             ">>> lyr.visible(1.0/1000000)\n"
             "True\n"
             ">>> lyr.active = False\n"
             ">>> lyr.visible(1.0/1000000)\n"
             "False\n"
            )

        .add_property("active",
                      &layer::active,
                      &layer::set_active,
                      "Get/Set whether this layer is active and will be rendered (same as status property).\n"
                      "\n"
                      "Usage:\n"
                      ">>> from mapnik import Layer\n"
                      ">>> lyr = Layer('My Layer','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')\n"
                      ">>> lyr.active\n"
                      "True # Active by default\n"
                      ">>> lyr.active = False # set False to disable layer rendering\n"
                      ">>> lyr.active\n"
                      "False\n"
            )

        .add_property("status",
                      &layer::active,
                      &layer::set_active,
                      "Get/Set whether this layer is active and will be rendered.\n"
                      "\n"
                      "Usage:\n"
                      ">>> from mapnik import Layer\n"
                      ">>> lyr = Layer('My Layer','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')\n"
                      ">>> lyr.status\n"
                      "True # Active by default\n"
                      ">>> lyr.status = False # set False to disable layer rendering\n"
                      ">>> lyr.status\n"
                      "False\n"
            )

        .add_property("clear_label_cache",
                      &layer::clear_label_cache,
                      &layer::set_clear_label_cache,
                      "Get/Set whether to clear the label collision detector cache for this layer during rendering\n"
                      "\n"
                      "Usage:\n"
                      ">>> lyr.clear_label_cache\n"
                      "False # False by default, meaning label positions from other layers will impact placement \n"
                      ">>> lyr.clear_label_cache = True # set to True to clear the label collision detector cache\n"
            )

        .add_property("cache_features",
                      &layer::cache_features,
                      &layer::set_cache_features,
                      "Get/Set whether features should be cached during rendering if used between multiple styles\n"
                      "\n"
                      "Usage:\n"
                      ">>> lyr.cache_features\n"
                      "False # False by default\n"
                      ">>> lyr.cache_features = True # set to True to enable feature caching\n"
            )

        .add_property("datasource",
                      &layer::datasource,
                      &layer::set_datasource,
                      "The datasource attached to this layer.\n"
                      "\n"
                      "Usage:\n"
                      ">>> from mapnik import Layer, Datasource\n"
                      ">>> lyr = Layer('My Layer','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')\n"
                      ">>> lyr.datasource = Datasource(type='shape',file='world_borders')\n"
                      ">>> lyr.datasource\n"
                      "<mapnik.Datasource object at 0x65470>\n"
            )

        .add_property("buffer_size",
                      &get_buffer_size,
                      &set_buffer_size,
                      "Get/Set the size of buffer around layer in pixels.\n"
                      "\n"
                      "Usage:\n"
                      ">>> print(l.buffer_size)\n"
                      "None # None by default\n"
                      ">>> l.buffer_size = 2\n"
                      ">>> l.buffer_size\n"
                      "2\n"
            )

        .add_property("maximum_extent",make_function
                      (&layer::maximum_extent,return_value_policy<copy_const_reference>()),
                      &set_maximum_extent,
                      "The maximum extent of the map.\n"
                      "\n"
                      "Usage:\n"
                      ">>> m.maximum_extent = Box2d(-180,-90,180,90)\n"
            )

        .add_property("maximum_scale_denominator",
                      &layer::maximum_scale_denominator,
                      &layer::set_maximum_scale_denominator,
                      "Get/Set the maximum scale denominator of the layer.\n"
                      "\n"
                      "Usage:\n"
                      ">>> from mapnik import Layer\n"
                      ">>> lyr = Layer('My Layer','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')\n"
                      ">>> lyr.maximum_scale_denominator\n"
                      "1.7976931348623157e+308 # default is the numerical maximum\n"
                      ">>> lyr.maximum_scale_denominator = 1.0/1000000\n"
                      ">>> lyr.maximum_scale_denominator\n"
                      "9.9999999999999995e-07\n"
            )

        .add_property("minimum_scale_denominator",
                      &layer::minimum_scale_denominator,
                      &layer::set_minimum_scale_denominator,
                      "Get/Set the minimum scale demoninator of the layer.\n"
                      "\n"
                      "Usage:\n"
                      ">>> from mapnik import Layer\n"
                      ">>> lyr = Layer('My Layer','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')\n"
                      ">>> lyr.minimum_scale_denominator # default is 0\n"
                      "0.0\n"
                      ">>> lyr.minimum_scale_denominator = 1.0/1000000\n"
                      ">>> lyr.minimum_scale_denominator\n"
                      "9.9999999999999995e-07\n"
            )

        .add_property("name",
                      make_function(&layer::name, return_value_policy<copy_const_reference>()),
                      &layer::set_name,
                      "Get/Set the name of the layer.\n"
                      "\n"
                      "Usage:\n"
                      ">>> from mapnik import Layer\n"
                      ">>> lyr = Layer('My Layer','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')\n"
                      ">>> lyr.name\n"
                      "'My Layer'\n"
                      ">>> lyr.name = 'New Name'\n"
                      ">>> lyr.name\n"
                      "'New Name'\n"
            )

        .add_property("queryable",
                      &layer::queryable,
                      &layer::set_queryable,
                      "Get/Set whether this layer is queryable.\n"
                      "\n"
                      "Usage:\n"
                      ">>> from mapnik import layer\n"
                      ">>> lyr = layer('My layer','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')\n"
                      ">>> lyr.queryable\n"
                      "False # Not queryable by default\n"
                      ">>> lyr.queryable = True\n"
                      ">>> lyr.queryable\n"
                      "True\n"
            )

        .add_property("srs",
                      make_function(&layer::srs,return_value_policy<copy_const_reference>()),
                      &layer::set_srs,
                      "Get/Set the SRS of the layer.\n"
                      "\n"
                      "Usage:\n"
                      ">>> from mapnik import layer\n"
                      ">>> lyr = layer('My layer','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')\n"
                      ">>> lyr.srs\n"
                      "'+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs' # The default srs if not initialized with custom srs\n"
                      ">>> # set to google mercator with Proj.4 literal\n"
                      "... \n"
                      ">>> lyr.srs = '+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over'\n"
            )

        .add_property("group_by",
                      make_function(&layer::group_by,return_value_policy<copy_const_reference>()),
                      &layer::set_group_by,
                      "Get/Set the optional layer group name.\n"
                      "\n"
                      "More details at https://github.com/mapnik/mapnik/wiki/Grouped-rendering:\n"
            )

        .add_property("styles",
                      make_function(_styles_,return_value_policy<reference_existing_object>()),
                      "The styles list attached to this layer.\n"
                      "\n"
                      "Usage:\n"
                      ">>> from mapnik import layer\n"
                      ">>> lyr = layer('My layer','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')\n"
                      ">>> lyr.styles\n"
                      "<mapnik._mapnik.Names object at 0x6d3e8>\n"
                      ">>> len(lyr.styles)\n"
                      "0\n # no styles until you append them\n"
                      "lyr.styles.append('My Style') # mapnik uses named styles for flexibility\n"
                      ">>> len(lyr.styles)\n"
                      "1\n"
                      ">>> lyr.styles[0]\n"
                      "'My Style'\n"
            )
        // comparison
        .def(self == self)
        ;
}
<commit_msg>Fix 'demoninator' typo, replace with 'denominator'.<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2015 Artem Pavlenko, Jean-Francois Doyon
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#include <mapnik/config.hpp>
#include "boost_std_shared_shim.hpp"

#pragma GCC diagnostic push
#include <mapnik/warning_ignore.hpp>
#include <boost/python.hpp>
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
#pragma GCC diagnostic pop

// mapnik
#include <mapnik/layer.hpp>
#include <mapnik/datasource.hpp>
#include <mapnik/datasource_cache.hpp>

using mapnik::layer;
using mapnik::parameters;
using mapnik::datasource_cache;

struct layer_pickle_suite : boost::python::pickle_suite
{
    static boost::python::tuple
    getinitargs(const layer& l)
    {
        return boost::python::make_tuple(l.name(),l.srs());
    }

    static  boost::python::tuple
    getstate(const layer& l)
    {
        boost::python::list s;
        std::vector<std::string> const& style_names = l.styles();
        for (unsigned i = 0; i < style_names.size(); ++i)
        {
            s.append(style_names[i]);
        }
        return boost::python::make_tuple(l.clear_label_cache(),l.minimum_scale_denominator(),l.maximum_scale_denominator(),l.queryable(),l.datasource()->params(),l.cache_features(),s);
    }

    static void
    setstate (layer& l, boost::python::tuple state)
    {
        using namespace boost::python;
        if (len(state) != 9)
        {
            PyErr_SetObject(PyExc_ValueError,
                            ("expected 9-item tuple in call to __setstate__; got %s"
                             % state).ptr()
                );
            throw_error_already_set();
        }

        l.set_clear_label_cache(extract<bool>(state[0]));

        l.set_minimum_scale_denominator(extract<double>(state[1]));

        l.set_maximum_scale_denominator(extract<double>(state[2]));

        l.set_queryable(extract<bool>(state[3]));

        mapnik::parameters params = extract<parameters>(state[4]);
        l.set_datasource(datasource_cache::instance().create(params));

        boost::python::list s = extract<boost::python::list>(state[5]);
        for (int i=0;i<len(s);++i)
        {
            l.add_style(extract<std::string>(s[i]));
        }

        l.set_cache_features(extract<bool>(state[6]));
    }
};

std::vector<std::string> & (mapnik::layer::*_styles_)() = &mapnik::layer::styles;

void set_maximum_extent(mapnik::layer & l, boost::optional<mapnik::box2d<double> > const& box)
{
    if (box)
    {
        l.set_maximum_extent(*box);
    }
    else
    {
        l.reset_maximum_extent();
    }
}

void set_buffer_size(mapnik::layer & l, boost::optional<int> const& buffer_size)
{
    if (buffer_size)
    {
        l.set_buffer_size(*buffer_size);
    }
    else
    {
        l.reset_buffer_size();
    }
}

PyObject * get_buffer_size(mapnik::layer & l)
{
    boost::optional<int> buffer_size = l.buffer_size();
    if (buffer_size)
    {
#if PY_VERSION_HEX >= 0x03000000
        return PyLong_FromLong(*buffer_size);
#else
        return PyInt_FromLong(*buffer_size);
#endif
    }
    else
    {
        Py_RETURN_NONE;
    }
}

void export_layer()
{
    using namespace boost::python;
    class_<std::vector<std::string> >("Names")
        .def(vector_indexing_suite<std::vector<std::string>,true >())
        ;

    class_<layer>("Layer", "A Mapnik map layer.", init<std::string const&,optional<std::string const&> >(
                      "Create a Layer with a named string and, optionally, an srs string.\n"
                      "\n"
                      "The srs can be either a Proj.4 epsg code ('+init=epsg:<code>') or\n"
                      "of a Proj.4 literal ('+proj=<literal>').\n"
                      "If no srs is specified it will default to '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs'\n"
                      "\n"
                      "Usage:\n"
                      ">>> from mapnik import Layer\n"
                      ">>> lyr = Layer('My Layer','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')\n"
                      ">>> lyr\n"
                      "<mapnik._mapnik.Layer object at 0x6a270>\n"
                      ))

        .def_pickle(layer_pickle_suite())

        .def("envelope",&layer::envelope,
             "Return the geographic envelope/bounding box."
             "\n"
             "Determined based on the layer datasource.\n"
             "\n"
             "Usage:\n"
             ">>> from mapnik import Layer\n"
             ">>> lyr = Layer('My Layer','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')\n"
             ">>> lyr.envelope()\n"
             "box2d(-1.0,-1.0,0.0,0.0) # default until a datasource is loaded\n"
            )

        .def("visible", &layer::visible,
             "Return True if this layer's data is active and visible at a given scale_denom.\n"
             "\n"
             "Otherwise returns False.\n"
             "Accepts a scale value as an integer or float input.\n"
             "Will return False if:\n"
             "\tscale_denom >= minimum_scale_denominator - 1e-6\n"
             "\tor:\n"
             "\tscale_denom < maximum_scale_denominator + 1e-6\n"
             "\n"
             "Usage:\n"
             ">>> from mapnik import Layer\n"
             ">>> lyr = Layer('My Layer','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')\n"
             ">>> lyr.visible(1.0/1000000)\n"
             "True\n"
             ">>> lyr.active = False\n"
             ">>> lyr.visible(1.0/1000000)\n"
             "False\n"
            )

        .add_property("active",
                      &layer::active,
                      &layer::set_active,
                      "Get/Set whether this layer is active and will be rendered (same as status property).\n"
                      "\n"
                      "Usage:\n"
                      ">>> from mapnik import Layer\n"
                      ">>> lyr = Layer('My Layer','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')\n"
                      ">>> lyr.active\n"
                      "True # Active by default\n"
                      ">>> lyr.active = False # set False to disable layer rendering\n"
                      ">>> lyr.active\n"
                      "False\n"
            )

        .add_property("status",
                      &layer::active,
                      &layer::set_active,
                      "Get/Set whether this layer is active and will be rendered.\n"
                      "\n"
                      "Usage:\n"
                      ">>> from mapnik import Layer\n"
                      ">>> lyr = Layer('My Layer','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')\n"
                      ">>> lyr.status\n"
                      "True # Active by default\n"
                      ">>> lyr.status = False # set False to disable layer rendering\n"
                      ">>> lyr.status\n"
                      "False\n"
            )

        .add_property("clear_label_cache",
                      &layer::clear_label_cache,
                      &layer::set_clear_label_cache,
                      "Get/Set whether to clear the label collision detector cache for this layer during rendering\n"
                      "\n"
                      "Usage:\n"
                      ">>> lyr.clear_label_cache\n"
                      "False # False by default, meaning label positions from other layers will impact placement \n"
                      ">>> lyr.clear_label_cache = True # set to True to clear the label collision detector cache\n"
            )

        .add_property("cache_features",
                      &layer::cache_features,
                      &layer::set_cache_features,
                      "Get/Set whether features should be cached during rendering if used between multiple styles\n"
                      "\n"
                      "Usage:\n"
                      ">>> lyr.cache_features\n"
                      "False # False by default\n"
                      ">>> lyr.cache_features = True # set to True to enable feature caching\n"
            )

        .add_property("datasource",
                      &layer::datasource,
                      &layer::set_datasource,
                      "The datasource attached to this layer.\n"
                      "\n"
                      "Usage:\n"
                      ">>> from mapnik import Layer, Datasource\n"
                      ">>> lyr = Layer('My Layer','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')\n"
                      ">>> lyr.datasource = Datasource(type='shape',file='world_borders')\n"
                      ">>> lyr.datasource\n"
                      "<mapnik.Datasource object at 0x65470>\n"
            )

        .add_property("buffer_size",
                      &get_buffer_size,
                      &set_buffer_size,
                      "Get/Set the size of buffer around layer in pixels.\n"
                      "\n"
                      "Usage:\n"
                      ">>> print(l.buffer_size)\n"
                      "None # None by default\n"
                      ">>> l.buffer_size = 2\n"
                      ">>> l.buffer_size\n"
                      "2\n"
            )

        .add_property("maximum_extent",make_function
                      (&layer::maximum_extent,return_value_policy<copy_const_reference>()),
                      &set_maximum_extent,
                      "The maximum extent of the map.\n"
                      "\n"
                      "Usage:\n"
                      ">>> m.maximum_extent = Box2d(-180,-90,180,90)\n"
            )

        .add_property("maximum_scale_denominator",
                      &layer::maximum_scale_denominator,
                      &layer::set_maximum_scale_denominator,
                      "Get/Set the maximum scale denominator of the layer.\n"
                      "\n"
                      "Usage:\n"
                      ">>> from mapnik import Layer\n"
                      ">>> lyr = Layer('My Layer','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')\n"
                      ">>> lyr.maximum_scale_denominator\n"
                      "1.7976931348623157e+308 # default is the numerical maximum\n"
                      ">>> lyr.maximum_scale_denominator = 1.0/1000000\n"
                      ">>> lyr.maximum_scale_denominator\n"
                      "9.9999999999999995e-07\n"
            )

        .add_property("minimum_scale_denominator",
                      &layer::minimum_scale_denominator,
                      &layer::set_minimum_scale_denominator,
                      "Get/Set the minimum scale denominator of the layer.\n"
                      "\n"
                      "Usage:\n"
                      ">>> from mapnik import Layer\n"
                      ">>> lyr = Layer('My Layer','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')\n"
                      ">>> lyr.minimum_scale_denominator # default is 0\n"
                      "0.0\n"
                      ">>> lyr.minimum_scale_denominator = 1.0/1000000\n"
                      ">>> lyr.minimum_scale_denominator\n"
                      "9.9999999999999995e-07\n"
            )

        .add_property("name",
                      make_function(&layer::name, return_value_policy<copy_const_reference>()),
                      &layer::set_name,
                      "Get/Set the name of the layer.\n"
                      "\n"
                      "Usage:\n"
                      ">>> from mapnik import Layer\n"
                      ">>> lyr = Layer('My Layer','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')\n"
                      ">>> lyr.name\n"
                      "'My Layer'\n"
                      ">>> lyr.name = 'New Name'\n"
                      ">>> lyr.name\n"
                      "'New Name'\n"
            )

        .add_property("queryable",
                      &layer::queryable,
                      &layer::set_queryable,
                      "Get/Set whether this layer is queryable.\n"
                      "\n"
                      "Usage:\n"
                      ">>> from mapnik import layer\n"
                      ">>> lyr = layer('My layer','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')\n"
                      ">>> lyr.queryable\n"
                      "False # Not queryable by default\n"
                      ">>> lyr.queryable = True\n"
                      ">>> lyr.queryable\n"
                      "True\n"
            )

        .add_property("srs",
                      make_function(&layer::srs,return_value_policy<copy_const_reference>()),
                      &layer::set_srs,
                      "Get/Set the SRS of the layer.\n"
                      "\n"
                      "Usage:\n"
                      ">>> from mapnik import layer\n"
                      ">>> lyr = layer('My layer','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')\n"
                      ">>> lyr.srs\n"
                      "'+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs' # The default srs if not initialized with custom srs\n"
                      ">>> # set to google mercator with Proj.4 literal\n"
                      "... \n"
                      ">>> lyr.srs = '+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over'\n"
            )

        .add_property("group_by",
                      make_function(&layer::group_by,return_value_policy<copy_const_reference>()),
                      &layer::set_group_by,
                      "Get/Set the optional layer group name.\n"
                      "\n"
                      "More details at https://github.com/mapnik/mapnik/wiki/Grouped-rendering:\n"
            )

        .add_property("styles",
                      make_function(_styles_,return_value_policy<reference_existing_object>()),
                      "The styles list attached to this layer.\n"
                      "\n"
                      "Usage:\n"
                      ">>> from mapnik import layer\n"
                      ">>> lyr = layer('My layer','+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs')\n"
                      ">>> lyr.styles\n"
                      "<mapnik._mapnik.Names object at 0x6d3e8>\n"
                      ">>> len(lyr.styles)\n"
                      "0\n # no styles until you append them\n"
                      "lyr.styles.append('My Style') # mapnik uses named styles for flexibility\n"
                      ">>> len(lyr.styles)\n"
                      "1\n"
                      ">>> lyr.styles[0]\n"
                      "'My Style'\n"
            )
        // comparison
        .def(self == self)
        ;
}
<|endoftext|>


<commit_before>#include "mem/Compiler.hpp"

namespace mem {

Compiler::Compiler ()
{
   this->logger.sFormatter(new log::ConsoleFormatter());

   setUpOptions();

   addAstVisitor(new ast::visitor::Prechecker());
   addAstVisitor(new ast::visitor::FindClasses());
   addAstVisitor(new ast::visitor::TopTypesChecker());
   addAstVisitor(new ast::visitor::BlockTypesChecker());
   addAstVisitor(new ast::visitor::TypeMatch());
   addAstVisitor(new ast::visitor::CheckValidity());
   addAstVisitor(new ast::visitor::FindEntryPoint());

   addStVisitor(new st::visitor::DepBuilder());

   st::Util::setupBool(this->symbols, this->symbols.gCoreTypes());
   st::Util::setupInts(this->symbols, this->symbols.gCoreTypes());
   st::Util::setupVoid(this->symbols, this->symbols.gCoreTypes());
}

Compiler::~Compiler ()
{
   // Delete AST visitors
   for (size_t i = 0; i < ast_visitors.size(); ++i)
   {
      delete ast_visitors[i];
   }

   // Delete ST visitors
   for (size_t i = 0; i < st_visitors.size(); ++i)
   {
      delete st_visitors[i];
   }
}

void
Compiler::compile (int argc, char** argv)
{
   fm.appendPath(".");

   // Need to set this before parsing command line arguments because it can
   // raise warnings
   logger.sLevel(log::WARNING);

   opt::Parser opt_parser;
   opt_parser.parse(argc, argv, &logger, gOptions());

   logger.sLevel(gOptions()->getInt("log.level"));

   if (opt_parser._params.size() >= 1)
   {
      _parse_queue.push(opt_parser._params[0]);

      processParseQueue();

      runAstVisitors();
      runStVisitors();

      if (isBuildSuccessful()) emitCode();

      reset_lexer(); // Cleans up lexer global vars

      if (gOptions()->isSet("ast.dump.file")) dumpAst();
      dumpSt();

      printBuildSummary();
   }
   else
   {
      printUsage(std::cout);
   }
}

void
Compiler::dumpAst ()
{
   std::ofstream dump_file;
   dump_file.open(gOptions()->getStr("ast.dump.file").c_str());

   mem::ast::dumper::XmlDumper dumper;
   dumper.dump_to(&ast, dump_file);

   dump_file.close();
   logger.debug("AST dumped to %s", gOptions()->getStr("ast.dump.file").c_str());
}

void
Compiler::dumpSt ()
{
   if (gOptions()->isSet("st.dump.xml"))
   {
      // Open dump file
      // TODO We should have a default output file in case the user did not
      // give one
      std::ofstream st_dump_file(gOptions()->getStr("st.dump.xml").c_str());

      st::visitor::IDumper* dumper = new st::visitor::XmlDumper;
      dumper->_out = &st_dump_file;
      dumper->setup();
      dumper->visitPreorder(symbols._root);

      st_dump_file.close();
      logger.debug("SymbolTable dumped to %s (XML)",
         gOptions()->getStr("st.dump.xml").c_str());
   }
}

void
Compiler::emitCode ()
{
   if (gOptions()->isSet("codegen.llvm-bc"))
   {
      mem::codegen::llvm_::Codegen cg;
      cg._st = &symbols;
      cg.gen(&ast);

      std::ofstream bc_file;
      bc_file.open(gOptions()->getStr("codegen.llvm-bc").c_str());
      bc_file << cg.getLlvmByteCode();
      bc_file.close();

      logger.debug("LLVM ByteCode dumped to %s",
         gOptions()->getStr("codegen.llvm-bc").c_str());
   }
}

void
Compiler::parse (std::string file_path)
{
   this->logger.debug("[%s] parsing...", file_path.c_str());

   // @TODO Split it
   st::Namespace* file_sym = st::Util::createNamespace(this->symbols._root, Util::split(Util::stripFileExtension(file_path),'/'));
   assert(file_sym != NULL);

   reset_lexer();
   std::vector<std::string> paths_tried;
   std::string include_path("");

   // Try finding the file using include path directories
   // TODO This should be moved to fs::FileManager
   fs::File* file = this->fm.openFile(file_path);
   paths_tried.push_back(file_path);
   if (file == NULL)
   {
      std::vector<std::string>::size_type i;
      std::string try_file_path;
      for (i=0; file==NULL && i<this->fm._path.size(); ++i)
      {
         try_file_path.assign(this->fm._path[i] + "/" + file_path);
         file = this->fm.openFile(try_file_path);
         paths_tried.push_back(try_file_path);
         if (file != NULL)
         {
            include_path = this->fm._path[i];
         }
      }
      if (file != NULL)
      {
         file_path.assign(try_file_path);
      }
   }

   if (file != NULL)
   {
      std::string ns(file_path.substr(include_path.length(), file_path.length() - include_path.length() + 1));
      mem::Util::path_to_namespace(ns);
      ast::node::File* file_node = new ast::node::File();
      file_node->sBoundSymbol(file_sym);
      file_node->_id.assign(ns);
      file_node->_include_path.assign(include_path);
      file_node->_path = file_path;
      ast.pushChild(file_node);

      // Used by yyparse
      yyin = fopen(file_path.c_str(), "rb");
      // TODO The file was opened ms before
      // We could open the file only once if we used Bison++
      assert(yyin != NULL);
      yyfile = file;
      yyparse(this->fm, file_node, this->symbols, this->logger, file);

      ast::visitor::FindUse find_use;
      find_use.visit_preorder(file_node);
      for (size_t i = 0; i < find_use._uses.size(); ++i)
      {
         if (ns == find_use._uses[i])
         {
            // FIXME This thing is probably failing, should use a pointer.
            log::Message warn(log::WARNING);
            warn.formatMessage(
               "File {path:%s} is trying to include itself: include ignored.",
               file_path.c_str()
            );
            this->logger.log(&warn);
         }
         else
         {
            std::string rel_file_path (find_use._uses[i]);
            mem::Util::namespace_to_path(rel_file_path);
            rel_file_path += ".mem";
            this->_parse_queue.push(rel_file_path);
         }
      }
      fclose(yyin);
   }
   else
   {
      std::string description = "We tried :\n";
      std::vector<std::string>::size_type i;
      for (i=0; i<paths_tried.size(); ++i)
      {
         description.append("* {path:" + paths_tried[i] + "}\n");
      }

      log::Message* msg = new log::Error();
      msg->formatMessage("Couldn't open file {path:%s}.", file_path.c_str());
      msg->sDescription(description);
      this->logger.log(msg);
   }
}

void
Compiler::printBuildSummary ()
{
   std::ostringstream sum;
   if (this->logger._n_fatal_errors > 0)
   {
      sum << this->logger._n_fatal_errors;
      sum << " fatal errors, ";
   }
   if (this->logger._n_errors > 0)
   {
      sum << this->logger._n_errors;
      sum << " errors, ";
   }

   if (this->logger._n_warnings > 0)
   {
      sum << this->logger._n_warnings;
      sum << " warnings, ";
   }

   if (this->isBuildSuccessful())
   {
      this->logger.info("Build SUCCESSFUL", "");
   }
   else
   {
      this->logger.info(sum.str().c_str(), "");
      this->logger.fatalError("Build FAILED", "");
   }
}

void
Compiler::printUsage (std::ostream& out)
{
   out << "USAGE: memc [OPTIONS] <input>\n\n";
   out << "OPTIONS:\n";
   std::map<std::string, opt::CliOption*>::iterator i;
   for (i = gOptions()->_cli_options.begin(); i != gOptions()->_cli_options.end(); ++i)
   {
      if (i->second != NULL)
      {
         out << " --";
         out << i->second->_cli_name;
         out << " : ";
         out << i->second->_description;
         out << "\n";
      }
   }
}

void
Compiler::processParseQueue ()
{
   while (!_parse_queue.empty())
   {
      parse(_parse_queue.front());
      _parse_queue.pop();
   }
}

void
Compiler::runAstVisitors ()
{
   for (size_t i=0;
      i < ast_visitors.size() && logger._n_fatal_errors == 0; ++i)
   {
      logger.debug("[%s] running...", ast_visitors[i]->_name.c_str());
      ast_visitors[i]->setup(&symbols, &logger);
      ast_visitors[i]->visit_preorder(&ast);
      ast_visitors[i]->tearDown();
   }
}

void
Compiler::runStVisitors ()
{
   for (size_t i = 0; i < st_visitors.size(); ++i)
   {
      logger.debug("[%s] running...", st_visitors[i]->gNameCstr());
      st_visitors[i]->setup();
      st_visitors[i]->visitPreorder(symbols.gRoot());
      st_visitors[i]->tearDown();
   }
}

void
Compiler::setUpOptions ()
{
   _opts.addStrOpt("ast.dump.file");
   _opts.addBoolOpt("codegen.native");
   _opts.addStrOpt("codegen.llvm-bc");
   _opts.addIntEnumOpt("log.level")
      ->bind("unknown", log::UNKNOWN)
      ->bind("debug", log::DEBUG)
      ->bind("info", log::INFO)
      ->bind("warning", log::WARNING)
      ->bind("error", log::ERROR)
      ->bind("fatal-error", log::FATAL_ERROR);
   _opts.addBoolOpt("help.show");
   _opts.addStrOpt("st.dump.xml");

   // Set CLI options
   _opts.addCliOpt ("help", "help.show", "Display available options");
   _opts.addCliOpt ("emit-llvm-bc", "codegen.llvm-bc", "Emit LLVM bytecode");
}

}
<commit_msg>Add a CLI option to dump ST as XML (--dump-st-xml)<commit_after>#include "mem/Compiler.hpp"

namespace mem {

Compiler::Compiler ()
{
   this->logger.sFormatter(new log::ConsoleFormatter());

   setUpOptions();

   addAstVisitor(new ast::visitor::Prechecker());
   addAstVisitor(new ast::visitor::FindClasses());
   addAstVisitor(new ast::visitor::TopTypesChecker());
   addAstVisitor(new ast::visitor::BlockTypesChecker());
   addAstVisitor(new ast::visitor::TypeMatch());
   addAstVisitor(new ast::visitor::CheckValidity());
   addAstVisitor(new ast::visitor::FindEntryPoint());

   addStVisitor(new st::visitor::DepBuilder());

   st::Util::setupBool(this->symbols, this->symbols.gCoreTypes());
   st::Util::setupInts(this->symbols, this->symbols.gCoreTypes());
   st::Util::setupVoid(this->symbols, this->symbols.gCoreTypes());
}

Compiler::~Compiler ()
{
   // Delete AST visitors
   for (size_t i = 0; i < ast_visitors.size(); ++i)
   {
      delete ast_visitors[i];
   }

   // Delete ST visitors
   for (size_t i = 0; i < st_visitors.size(); ++i)
   {
      delete st_visitors[i];
   }
}

void
Compiler::compile (int argc, char** argv)
{
   fm.appendPath(".");

   // Need to set this before parsing command line arguments because it can
   // raise warnings
   logger.sLevel(log::WARNING);

   opt::Parser opt_parser;
   opt_parser.parse(argc, argv, &logger, gOptions());

   logger.sLevel(gOptions()->getInt("log.level"));

   if (opt_parser._params.size() >= 1)
   {
      _parse_queue.push(opt_parser._params[0]);

      processParseQueue();

      runAstVisitors();
      runStVisitors();

      if (isBuildSuccessful()) emitCode();

      reset_lexer(); // Cleans up lexer global vars

      if (gOptions()->isSet("ast.dump.file")) dumpAst();
      dumpSt();

      printBuildSummary();
   }
   else
   {
      printUsage(std::cout);
   }
}

void
Compiler::dumpAst ()
{
   std::ofstream dump_file;
   dump_file.open(gOptions()->getStr("ast.dump.file").c_str());

   mem::ast::dumper::XmlDumper dumper;
   dumper.dump_to(&ast, dump_file);

   dump_file.close();
   logger.debug("AST dumped to %s", gOptions()->getStr("ast.dump.file").c_str());
}

void
Compiler::dumpSt ()
{
   if (gOptions()->isSet("st.dump.xml"))
   {
      // Open dump file
      // TODO We should have a default output file in case the user did not
      // give one
      std::ofstream st_dump_file(gOptions()->getStr("st.dump.xml").c_str());

      st::visitor::IDumper* dumper = new st::visitor::XmlDumper;
      dumper->_out = &st_dump_file;
      dumper->setup();
      dumper->visitPreorder(symbols._root);

      st_dump_file.close();
      logger.debug("SymbolTable dumped to %s (XML)",
         gOptions()->getStr("st.dump.xml").c_str());
   }
}

void
Compiler::emitCode ()
{
   if (gOptions()->isSet("codegen.llvm-bc"))
   {
      mem::codegen::llvm_::Codegen cg;
      cg._st = &symbols;
      cg.gen(&ast);

      std::ofstream bc_file;
      bc_file.open(gOptions()->getStr("codegen.llvm-bc").c_str());
      bc_file << cg.getLlvmByteCode();
      bc_file.close();

      logger.debug("LLVM ByteCode dumped to %s",
         gOptions()->getStr("codegen.llvm-bc").c_str());
   }
}

void
Compiler::parse (std::string file_path)
{
   this->logger.debug("[%s] parsing...", file_path.c_str());

   // @TODO Split it
   st::Namespace* file_sym = st::Util::createNamespace(this->symbols._root, Util::split(Util::stripFileExtension(file_path),'/'));
   assert(file_sym != NULL);

   reset_lexer();
   std::vector<std::string> paths_tried;
   std::string include_path("");

   // Try finding the file using include path directories
   // TODO This should be moved to fs::FileManager
   fs::File* file = this->fm.openFile(file_path);
   paths_tried.push_back(file_path);
   if (file == NULL)
   {
      std::vector<std::string>::size_type i;
      std::string try_file_path;
      for (i=0; file==NULL && i<this->fm._path.size(); ++i)
      {
         try_file_path.assign(this->fm._path[i] + "/" + file_path);
         file = this->fm.openFile(try_file_path);
         paths_tried.push_back(try_file_path);
         if (file != NULL)
         {
            include_path = this->fm._path[i];
         }
      }
      if (file != NULL)
      {
         file_path.assign(try_file_path);
      }
   }

   if (file != NULL)
   {
      std::string ns(file_path.substr(include_path.length(), file_path.length() - include_path.length() + 1));
      mem::Util::path_to_namespace(ns);
      ast::node::File* file_node = new ast::node::File();
      file_node->sBoundSymbol(file_sym);
      file_node->_id.assign(ns);
      file_node->_include_path.assign(include_path);
      file_node->_path = file_path;
      ast.pushChild(file_node);

      // Used by yyparse
      yyin = fopen(file_path.c_str(), "rb");
      // TODO The file was opened ms before
      // We could open the file only once if we used Bison++
      assert(yyin != NULL);
      yyfile = file;
      yyparse(this->fm, file_node, this->symbols, this->logger, file);

      ast::visitor::FindUse find_use;
      find_use.visit_preorder(file_node);
      for (size_t i = 0; i < find_use._uses.size(); ++i)
      {
         if (ns == find_use._uses[i])
         {
            // FIXME This thing is probably failing, should use a pointer.
            log::Message warn(log::WARNING);
            warn.formatMessage(
               "File {path:%s} is trying to include itself: include ignored.",
               file_path.c_str()
            );
            this->logger.log(&warn);
         }
         else
         {
            std::string rel_file_path (find_use._uses[i]);
            mem::Util::namespace_to_path(rel_file_path);
            rel_file_path += ".mem";
            this->_parse_queue.push(rel_file_path);
         }
      }
      fclose(yyin);
   }
   else
   {
      std::string description = "We tried :\n";
      std::vector<std::string>::size_type i;
      for (i=0; i<paths_tried.size(); ++i)
      {
         description.append("* {path:" + paths_tried[i] + "}\n");
      }

      log::Message* msg = new log::Error();
      msg->formatMessage("Couldn't open file {path:%s}.", file_path.c_str());
      msg->sDescription(description);
      this->logger.log(msg);
   }
}

void
Compiler::printBuildSummary ()
{
   std::ostringstream sum;
   if (this->logger._n_fatal_errors > 0)
   {
      sum << this->logger._n_fatal_errors;
      sum << " fatal errors, ";
   }
   if (this->logger._n_errors > 0)
   {
      sum << this->logger._n_errors;
      sum << " errors, ";
   }

   if (this->logger._n_warnings > 0)
   {
      sum << this->logger._n_warnings;
      sum << " warnings, ";
   }

   if (this->isBuildSuccessful())
   {
      this->logger.info("Build SUCCESSFUL", "");
   }
   else
   {
      this->logger.info(sum.str().c_str(), "");
      this->logger.fatalError("Build FAILED", "");
   }
}

void
Compiler::printUsage (std::ostream& out)
{
   out << "USAGE: memc [OPTIONS] <input>\n\n";
   out << "OPTIONS:\n";
   std::map<std::string, opt::CliOption*>::iterator i;
   for (i = gOptions()->_cli_options.begin(); i != gOptions()->_cli_options.end(); ++i)
   {
      if (i->second != NULL)
      {
         out << " --";
         out << i->second->_cli_name;
         out << " : ";
         out << i->second->_description;
         out << "\n";
      }
   }
}

void
Compiler::processParseQueue ()
{
   while (!_parse_queue.empty())
   {
      parse(_parse_queue.front());
      _parse_queue.pop();
   }
}

void
Compiler::runAstVisitors ()
{
   for (size_t i=0;
      i < ast_visitors.size() && logger._n_fatal_errors == 0; ++i)
   {
      logger.debug("[%s] running...", ast_visitors[i]->_name.c_str());
      ast_visitors[i]->setup(&symbols, &logger);
      ast_visitors[i]->visit_preorder(&ast);
      ast_visitors[i]->tearDown();
   }
}

void
Compiler::runStVisitors ()
{
   for (size_t i = 0; i < st_visitors.size(); ++i)
   {
      logger.debug("[%s] running...", st_visitors[i]->gNameCstr());
      st_visitors[i]->setup();
      st_visitors[i]->visitPreorder(symbols.gRoot());
      st_visitors[i]->tearDown();
   }
}

void
Compiler::setUpOptions ()
{
   _opts.addStrOpt("ast.dump.file");
   _opts.addBoolOpt("codegen.native");
   _opts.addStrOpt("codegen.llvm-bc");
   _opts.addIntEnumOpt("log.level")
      ->bind("unknown", log::UNKNOWN)
      ->bind("debug", log::DEBUG)
      ->bind("info", log::INFO)
      ->bind("warning", log::WARNING)
      ->bind("error", log::ERROR)
      ->bind("fatal-error", log::FATAL_ERROR);
   _opts.addBoolOpt("help.show");
   _opts.addStrOpt("st.dump.xml");

   // Set CLI options
   _opts.addCliOpt("dump-st-xml", "st.dump.xml", "Dump the Symbol Table as XML");
   _opts.addCliOpt("emit-llvm-bc", "codegen.llvm-bc", "Emit LLVM bytecode");
   _opts.addCliOpt("help", "help.show", "Display available options");
}

}
<|endoftext|>


<commit_before>// The libMesh Finite Element Library.
// Copyright (C) 2002-2014 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner

// This library is free software; you can redistribute and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.

// This library 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
// Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

// library configuration
#include "libmesh/libmesh_config.h"

// C++ includes
#include <algorithm> // for std::min
#include <map>       // for std::multimap
#include <sstream>   // for std::ostringstream

// Local includes
#include "libmesh/boundary_info.h"
#include "libmesh/elem.h"
#include "libmesh/mesh_base.h"
#include "libmesh/parallel.h"
#include "libmesh/partitioner.h"
#include "libmesh/point_locator_base.h"
#include "libmesh/threads.h"

namespace libMesh
{

// ------------------------------------------------------------
// MeshBase class member functions
MeshBase::MeshBase (const Parallel::Communicator &comm_in,
                    unsigned char d) :
  ParallelObject (comm_in),
  boundary_info  (new BoundaryInfo(*this)),
  _n_parts       (1),
  _is_prepared   (false),
  _point_locator (NULL),
  _partitioner   (NULL),
#ifdef LIBMESH_ENABLE_UNIQUE_ID
  _next_unique_id(DofObject::invalid_unique_id),
#endif
  _skip_partitioning(false),
  _skip_renumber_nodes_and_elements(false)
{
  _elem_dims.insert(d);
  libmesh_assert_less_equal (LIBMESH_DIM, 3);
  libmesh_assert_greater_equal (LIBMESH_DIM, d);
  libmesh_assert (libMesh::initialized());
}

#ifndef LIBMESH_DISABLE_COMMWORLD
MeshBase::MeshBase (unsigned char d) :
  ParallelObject (CommWorld),
  boundary_info  (new BoundaryInfo(*this)),
  _n_parts       (1),
  _is_prepared   (false),
  _point_locator (NULL),
  _partitioner   (NULL),
#ifdef LIBMESH_ENABLE_UNIQUE_ID
  _next_unique_id(DofObject::invalid_unique_id),
#endif
  _skip_partitioning(false),
  _skip_renumber_nodes_and_elements(false)
{
  _elem_dims.insert(d);
  libmesh_assert_less_equal (LIBMESH_DIM, 3);
  libmesh_assert_greater_equal (LIBMESH_DIM, d);
  libmesh_assert (libMesh::initialized());
}
#endif // !LIBMESH_DISABLE_COMMWORLD

MeshBase::MeshBase (const MeshBase& other_mesh) :
  ParallelObject (other_mesh),
  boundary_info  (new BoundaryInfo(*this)),
  _n_parts       (other_mesh._n_parts),
  _is_prepared   (other_mesh._is_prepared),
  _point_locator (NULL),
  _partitioner   (NULL),
#ifdef LIBMESH_ENABLE_UNIQUE_ID
  _next_unique_id(other_mesh._next_unique_id),
#endif
  _skip_partitioning(other_mesh._skip_partitioning),
  _skip_renumber_nodes_and_elements(false),
  _elem_dims(other_mesh._elem_dims)
{
  if(other_mesh._partitioner.get())
    {
      _partitioner = other_mesh._partitioner->clone();
    }
}

MeshBase::~MeshBase()
{
  this->clear();

  libmesh_exceptionless_assert (!libMesh::closed());
}

unsigned int MeshBase::mesh_dimension() const
{
  libmesh_assert(!_elem_dims.empty());
  return cast_int<unsigned int>(*_elem_dims.rbegin());
}

void MeshBase::prepare_for_use (const bool skip_renumber_nodes_and_elements, const bool skip_find_neighbors)
{
  parallel_object_only();

  // A distributed mesh may have processors with no elements (or
  // processors with no elements of higher dimension, if we ever
  // support mixed-dimension meshes), but we want consistent
  // mesh_dimension anyways.
  libmesh_assert(this->comm().verify(this->is_serial()));

  if (!this->is_serial())
    {
      unsigned char dim = this->mesh_dimension();
      this->comm().max(dim);
      this->set_mesh_dimension(dim);
    }

  // Renumber the nodes and elements so that they in contiguous
  // blocks.  By default, _skip_renumber_nodes_and_elements is false.
  //
  // We may currently change that by passing
  // skip_renumber_nodes_and_elements==true to this function, but we
  // should use the allow_renumbering() accessor instead.
  //
  // Instances where you if prepare_for_use() should not renumber the nodes
  // and elements include reading in e.g. an xda/r or gmv file. In
  // this case, the ordering of the nodes may depend on an accompanying
  // solution, and the node ordering cannot be changed.

  if (skip_renumber_nodes_and_elements)
    {
      libmesh_deprecated();
      this->allow_renumbering(false);
    }

  // Mesh modification operations might not leave us with consistent
  // id counts, but our partitioner might need that consistency.
  if(!_skip_renumber_nodes_and_elements)
    this->renumber_nodes_and_elements();
  else
    this->update_parallel_id_counts();

  // Let all the elements find their neighbors
  if(!skip_find_neighbors)
    this->find_neighbors();

  // Partition the mesh.
  this->partition();

  // If we're using ParallelMesh, we'll want it parallelized.
  this->delete_remote_elements();

#ifdef LIBMESH_ENABLE_UNIQUE_ID
  // Assign DOF object unique ids
  this->assign_unique_ids();
#endif

  if(!_skip_renumber_nodes_and_elements)
    this->renumber_nodes_and_elements();

  // Search the mesh for all the dimensions of the elements
  // and cache them.
  this->cache_elem_dims();

  // Reset our PointLocator.  This needs to happen any time the elements
  // in the underlying elements in the mesh have changed, so we do it here.
  this->clear_point_locator();

  // The mesh is now prepared for use.
  _is_prepared = true;
}

void MeshBase::clear ()
{
  // Reset the number of partitions
  _n_parts = 1;

  // Reset the _is_prepared flag
  _is_prepared = false;

  // Clear boundary information
  this->get_boundary_info().clear();

  // Clear element dimensions
  _elem_dims.clear();

  // Clear our point locator.
  this->clear_point_locator();
}

void MeshBase::subdomain_ids (std::set<subdomain_id_type> &ids) const
{
  // This requires an inspection on every processor
  parallel_object_only();

  ids.clear();

  const_element_iterator el  = this->active_local_elements_begin();
  const_element_iterator end = this->active_local_elements_end();

  for (; el!=end; ++el)
    ids.insert((*el)->subdomain_id());

  // Some subdomains may only live on other processors
  this->comm().set_union(ids);
}

subdomain_id_type MeshBase::n_subdomains() const
{
  // This requires an inspection on every processor
  parallel_object_only();

  std::set<subdomain_id_type> ids;

  this->subdomain_ids (ids);

  return cast_int<subdomain_id_type>(ids.size());
}

dof_id_type MeshBase::n_nodes_on_proc (const processor_id_type proc_id) const
{
  // We're either counting a processor's nodes or unpartitioned
  // nodes
  libmesh_assert (proc_id < this->n_processors() ||
                  proc_id == DofObject::invalid_processor_id);

  return static_cast<dof_id_type>(std::distance (this->pid_nodes_begin(proc_id),
                                                 this->pid_nodes_end  (proc_id)));
}

dof_id_type MeshBase::n_elem_on_proc (const processor_id_type proc_id) const
{
  // We're either counting a processor's elements or unpartitioned
  // elements
  libmesh_assert (proc_id < this->n_processors() ||
                  proc_id == DofObject::invalid_processor_id);

  return static_cast<dof_id_type>(std::distance (this->pid_elements_begin(proc_id),
                                                 this->pid_elements_end  (proc_id)));
}

dof_id_type MeshBase::n_active_elem_on_proc (const processor_id_type proc_id) const
{
  libmesh_assert_less (proc_id, this->n_processors());
  return static_cast<dof_id_type>(std::distance (this->active_pid_elements_begin(proc_id),
                                                 this->active_pid_elements_end  (proc_id)));
}

dof_id_type MeshBase::n_sub_elem () const
{
  dof_id_type ne=0;

  const_element_iterator       el  = this->elements_begin();
  const const_element_iterator end = this->elements_end();

  for (; el!=end; ++el)
    ne += (*el)->n_sub_elem();

  return ne;
}

dof_id_type MeshBase::n_active_sub_elem () const
{
  dof_id_type ne=0;

  const_element_iterator       el  = this->active_elements_begin();
  const const_element_iterator end = this->active_elements_end();

  for (; el!=end; ++el)
    ne += (*el)->n_sub_elem();

  return ne;
}

std::string MeshBase::get_info() const
{
  std::ostringstream oss;

  oss << " Mesh Information:"                                  << '\n'
      << "  mesh_dimension()="    << this->mesh_dimension()    << '\n'
      << "  spatial_dimension()=" << this->spatial_dimension() << '\n'
      << "  n_nodes()="           << this->n_nodes()           << '\n'
      << "    n_local_nodes()="   << this->n_local_nodes()     << '\n'
      << "  n_elem()="            << this->n_elem()            << '\n'
      << "    n_local_elem()="    << this->n_local_elem()      << '\n'
#ifdef LIBMESH_ENABLE_AMR
      << "    n_active_elem()="   << this->n_active_elem()     << '\n'
#endif
      << "  n_subdomains()="      << static_cast<std::size_t>(this->n_subdomains()) << '\n'
      << "  n_partitions()="      << static_cast<std::size_t>(this->n_partitions()) << '\n'
      << "  n_processors()="      << static_cast<std::size_t>(this->n_processors()) << '\n'
      << "  n_threads()="         << static_cast<std::size_t>(libMesh::n_threads()) << '\n'
      << "  processor_id()="      << static_cast<std::size_t>(this->processor_id()) << '\n';

  return oss.str();
}

void MeshBase::print_info(std::ostream& os) const
{
  os << this->get_info()
     << std::endl;
}

std::ostream& operator << (std::ostream& os, const MeshBase& m)
{
  m.print_info(os);
  return os;
}

void MeshBase::partition (const unsigned int n_parts)
{
  // NULL partitioner means don't partition
  // Non-serial meshes aren't ready for partitioning yet.
  if(!skip_partitioning() &&
     partitioner().get() &&
     this->is_serial())
    {
      partitioner()->partition (*this, n_parts);
    }
  else
    {
      // Adaptive coarsening may have "orphaned" nodes on processors
      // whose elements no longer share them.  We need to check for
      // and possibly fix that.
      Partitioner::set_node_processor_ids(*this);

      // Make sure locally cached partition count
      this->recalculate_n_partitions();

      // Make sure any other locally cached data is correct
      this->update_post_partitioning();
    }
}

unsigned int MeshBase::recalculate_n_partitions()
{
  // This requires an inspection on every processor
  parallel_object_only();

  const_element_iterator el  = this->active_local_elements_begin();
  const_element_iterator end = this->active_local_elements_end();

  unsigned int max_proc_id=0;

  for (; el!=end; ++el)
    max_proc_id = std::max(max_proc_id, static_cast<unsigned int>((*el)->processor_id()));

  // The number of partitions is one more than the max processor ID.
  _n_parts = max_proc_id+1;

  this->comm().max(_n_parts);

  return _n_parts;
}

const PointLocatorBase& MeshBase::point_locator () const
{
  libmesh_deprecated();

  if (_point_locator.get() == NULL)
    {
      // PointLocator construction may not be safe within threads
      libmesh_assert(!Threads::in_threads);

      _point_locator.reset (PointLocatorBase::build(TREE_ELEMENTS, *this).release());
    }

  return *_point_locator;
}

AutoPtr<PointLocatorBase> MeshBase::sub_point_locator () const
{
  if (_point_locator.get() == NULL)
    {
      // PointLocator construction may not be safe within threads
      libmesh_assert(!Threads::in_threads);

      _point_locator.reset (PointLocatorBase::build(TREE_ELEMENTS, *this).release());
    }

  return PointLocatorBase::build(TREE_ELEMENTS, *this, _point_locator.get());
}

void MeshBase::clear_point_locator ()
{
  _point_locator.reset(NULL);
}

std::string& MeshBase::subdomain_name(subdomain_id_type id)
{
  return _block_id_to_name[id];
}

const std::string& MeshBase::subdomain_name(subdomain_id_type id) const
{
  // An empty string to return when no matching subdomain name is found
  static const std::string empty;

  std::map<subdomain_id_type, std::string>::const_iterator iter = _block_id_to_name.find(id);
  if (iter == _block_id_to_name.end())
    return empty;
  else
    return iter->second;
}

subdomain_id_type MeshBase::get_id_by_name(const std::string& name) const
{
  // Linear search over the map values.
  std::map<subdomain_id_type, std::string>::const_iterator
    iter = _block_id_to_name.begin(),
    end_iter = _block_id_to_name.end();

  for ( ; iter != end_iter; ++iter)
    if (iter->second == name)
      return iter->first;

  // If we made it here without returning, we don't have a subdomain
  // with the requested name, so return Elem::invalid_subdomain_id.
  return Elem::invalid_subdomain_id;
}

void MeshBase::cache_elem_dims()
{
  // This requires an inspection on every processor
  parallel_object_only();

  const_element_iterator el  = this->active_local_elements_begin();
  const_element_iterator end = this->active_local_elements_end();

  for (; el!=end; ++el)
    _elem_dims.insert((*el)->dim());

  // Some different dimension elements may only live on other processors
  this->comm().set_union(_elem_dims);
}

} // namespace libMesh
<commit_msg>Add --skip-partitioning command line option<commit_after>// The libMesh Finite Element Library.
// Copyright (C) 2002-2014 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner

// This library is free software; you can redistribute and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.

// This library 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
// Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

// library configuration
#include "libmesh/libmesh_config.h"

// C++ includes
#include <algorithm> // for std::min
#include <map>       // for std::multimap
#include <sstream>   // for std::ostringstream

// Local includes
#include "libmesh/boundary_info.h"
#include "libmesh/elem.h"
#include "libmesh/mesh_base.h"
#include "libmesh/parallel.h"
#include "libmesh/partitioner.h"
#include "libmesh/point_locator_base.h"
#include "libmesh/threads.h"

namespace libMesh
{

// ------------------------------------------------------------
// MeshBase class member functions
MeshBase::MeshBase (const Parallel::Communicator &comm_in,
                    unsigned char d) :
  ParallelObject (comm_in),
  boundary_info  (new BoundaryInfo(*this)),
  _n_parts       (1),
  _is_prepared   (false),
  _point_locator (NULL),
  _partitioner   (NULL),
#ifdef LIBMESH_ENABLE_UNIQUE_ID
  _next_unique_id(DofObject::invalid_unique_id),
#endif
  _skip_partitioning(libMesh::on_command_line("--skip-partitioning")),
  _skip_renumber_nodes_and_elements(false)
{
  _elem_dims.insert(d);
  libmesh_assert_less_equal (LIBMESH_DIM, 3);
  libmesh_assert_greater_equal (LIBMESH_DIM, d);
  libmesh_assert (libMesh::initialized());
}

#ifndef LIBMESH_DISABLE_COMMWORLD
MeshBase::MeshBase (unsigned char d) :
  ParallelObject (CommWorld),
  boundary_info  (new BoundaryInfo(*this)),
  _n_parts       (1),
  _is_prepared   (false),
  _point_locator (NULL),
  _partitioner   (NULL),
#ifdef LIBMESH_ENABLE_UNIQUE_ID
  _next_unique_id(DofObject::invalid_unique_id),
#endif
  _skip_partitioning(libMesh::on_command_line("--skip-partitioning")),
  _skip_renumber_nodes_and_elements(false)
{
  _elem_dims.insert(d);
  libmesh_assert_less_equal (LIBMESH_DIM, 3);
  libmesh_assert_greater_equal (LIBMESH_DIM, d);
  libmesh_assert (libMesh::initialized());
}
#endif // !LIBMESH_DISABLE_COMMWORLD

MeshBase::MeshBase (const MeshBase& other_mesh) :
  ParallelObject (other_mesh),
  boundary_info  (new BoundaryInfo(*this)),
  _n_parts       (other_mesh._n_parts),
  _is_prepared   (other_mesh._is_prepared),
  _point_locator (NULL),
  _partitioner   (NULL),
#ifdef LIBMESH_ENABLE_UNIQUE_ID
  _next_unique_id(other_mesh._next_unique_id),
#endif
  _skip_partitioning(libMesh::on_command_line("--skip-partitioning")),
  _skip_renumber_nodes_and_elements(false),
  _elem_dims(other_mesh._elem_dims)
{
  if(other_mesh._partitioner.get())
    {
      _partitioner = other_mesh._partitioner->clone();
    }
}

MeshBase::~MeshBase()
{
  this->clear();

  libmesh_exceptionless_assert (!libMesh::closed());
}

unsigned int MeshBase::mesh_dimension() const
{
  libmesh_assert(!_elem_dims.empty());
  return cast_int<unsigned int>(*_elem_dims.rbegin());
}

void MeshBase::prepare_for_use (const bool skip_renumber_nodes_and_elements, const bool skip_find_neighbors)
{
  parallel_object_only();

  // A distributed mesh may have processors with no elements (or
  // processors with no elements of higher dimension, if we ever
  // support mixed-dimension meshes), but we want consistent
  // mesh_dimension anyways.
  libmesh_assert(this->comm().verify(this->is_serial()));

  if (!this->is_serial())
    {
      unsigned char dim = this->mesh_dimension();
      this->comm().max(dim);
      this->set_mesh_dimension(dim);
    }

  // Renumber the nodes and elements so that they in contiguous
  // blocks.  By default, _skip_renumber_nodes_and_elements is false.
  //
  // We may currently change that by passing
  // skip_renumber_nodes_and_elements==true to this function, but we
  // should use the allow_renumbering() accessor instead.
  //
  // Instances where you if prepare_for_use() should not renumber the nodes
  // and elements include reading in e.g. an xda/r or gmv file. In
  // this case, the ordering of the nodes may depend on an accompanying
  // solution, and the node ordering cannot be changed.

  if (skip_renumber_nodes_and_elements)
    {
      libmesh_deprecated();
      this->allow_renumbering(false);
    }

  // Mesh modification operations might not leave us with consistent
  // id counts, but our partitioner might need that consistency.
  if(!_skip_renumber_nodes_and_elements)
    this->renumber_nodes_and_elements();
  else
    this->update_parallel_id_counts();

  // Let all the elements find their neighbors
  if(!skip_find_neighbors)
    this->find_neighbors();

  // Partition the mesh.
  this->partition();

  // If we're using ParallelMesh, we'll want it parallelized.
  this->delete_remote_elements();

#ifdef LIBMESH_ENABLE_UNIQUE_ID
  // Assign DOF object unique ids
  this->assign_unique_ids();
#endif

  if(!_skip_renumber_nodes_and_elements)
    this->renumber_nodes_and_elements();

  // Search the mesh for all the dimensions of the elements
  // and cache them.
  this->cache_elem_dims();

  // Reset our PointLocator.  This needs to happen any time the elements
  // in the underlying elements in the mesh have changed, so we do it here.
  this->clear_point_locator();

  // The mesh is now prepared for use.
  _is_prepared = true;
}

void MeshBase::clear ()
{
  // Reset the number of partitions
  _n_parts = 1;

  // Reset the _is_prepared flag
  _is_prepared = false;

  // Clear boundary information
  this->get_boundary_info().clear();

  // Clear element dimensions
  _elem_dims.clear();

  // Clear our point locator.
  this->clear_point_locator();
}

void MeshBase::subdomain_ids (std::set<subdomain_id_type> &ids) const
{
  // This requires an inspection on every processor
  parallel_object_only();

  ids.clear();

  const_element_iterator el  = this->active_local_elements_begin();
  const_element_iterator end = this->active_local_elements_end();

  for (; el!=end; ++el)
    ids.insert((*el)->subdomain_id());

  // Some subdomains may only live on other processors
  this->comm().set_union(ids);
}

subdomain_id_type MeshBase::n_subdomains() const
{
  // This requires an inspection on every processor
  parallel_object_only();

  std::set<subdomain_id_type> ids;

  this->subdomain_ids (ids);

  return cast_int<subdomain_id_type>(ids.size());
}

dof_id_type MeshBase::n_nodes_on_proc (const processor_id_type proc_id) const
{
  // We're either counting a processor's nodes or unpartitioned
  // nodes
  libmesh_assert (proc_id < this->n_processors() ||
                  proc_id == DofObject::invalid_processor_id);

  return static_cast<dof_id_type>(std::distance (this->pid_nodes_begin(proc_id),
                                                 this->pid_nodes_end  (proc_id)));
}

dof_id_type MeshBase::n_elem_on_proc (const processor_id_type proc_id) const
{
  // We're either counting a processor's elements or unpartitioned
  // elements
  libmesh_assert (proc_id < this->n_processors() ||
                  proc_id == DofObject::invalid_processor_id);

  return static_cast<dof_id_type>(std::distance (this->pid_elements_begin(proc_id),
                                                 this->pid_elements_end  (proc_id)));
}

dof_id_type MeshBase::n_active_elem_on_proc (const processor_id_type proc_id) const
{
  libmesh_assert_less (proc_id, this->n_processors());
  return static_cast<dof_id_type>(std::distance (this->active_pid_elements_begin(proc_id),
                                                 this->active_pid_elements_end  (proc_id)));
}

dof_id_type MeshBase::n_sub_elem () const
{
  dof_id_type ne=0;

  const_element_iterator       el  = this->elements_begin();
  const const_element_iterator end = this->elements_end();

  for (; el!=end; ++el)
    ne += (*el)->n_sub_elem();

  return ne;
}

dof_id_type MeshBase::n_active_sub_elem () const
{
  dof_id_type ne=0;

  const_element_iterator       el  = this->active_elements_begin();
  const const_element_iterator end = this->active_elements_end();

  for (; el!=end; ++el)
    ne += (*el)->n_sub_elem();

  return ne;
}

std::string MeshBase::get_info() const
{
  std::ostringstream oss;

  oss << " Mesh Information:"                                  << '\n'
      << "  mesh_dimension()="    << this->mesh_dimension()    << '\n'
      << "  spatial_dimension()=" << this->spatial_dimension() << '\n'
      << "  n_nodes()="           << this->n_nodes()           << '\n'
      << "    n_local_nodes()="   << this->n_local_nodes()     << '\n'
      << "  n_elem()="            << this->n_elem()            << '\n'
      << "    n_local_elem()="    << this->n_local_elem()      << '\n'
#ifdef LIBMESH_ENABLE_AMR
      << "    n_active_elem()="   << this->n_active_elem()     << '\n'
#endif
      << "  n_subdomains()="      << static_cast<std::size_t>(this->n_subdomains()) << '\n'
      << "  n_partitions()="      << static_cast<std::size_t>(this->n_partitions()) << '\n'
      << "  n_processors()="      << static_cast<std::size_t>(this->n_processors()) << '\n'
      << "  n_threads()="         << static_cast<std::size_t>(libMesh::n_threads()) << '\n'
      << "  processor_id()="      << static_cast<std::size_t>(this->processor_id()) << '\n';

  return oss.str();
}

void MeshBase::print_info(std::ostream& os) const
{
  os << this->get_info()
     << std::endl;
}

std::ostream& operator << (std::ostream& os, const MeshBase& m)
{
  m.print_info(os);
  return os;
}

void MeshBase::partition (const unsigned int n_parts)
{
  // NULL partitioner means don't partition
  // Non-serial meshes aren't ready for partitioning yet.
  if(!skip_partitioning() &&
     partitioner().get() &&
     this->is_serial())
    {
      partitioner()->partition (*this, n_parts);
    }
  else
    {
      // Adaptive coarsening may have "orphaned" nodes on processors
      // whose elements no longer share them.  We need to check for
      // and possibly fix that.
      Partitioner::set_node_processor_ids(*this);

      // Make sure locally cached partition count
      this->recalculate_n_partitions();

      // Make sure any other locally cached data is correct
      this->update_post_partitioning();
    }
}

unsigned int MeshBase::recalculate_n_partitions()
{
  // This requires an inspection on every processor
  parallel_object_only();

  const_element_iterator el  = this->active_local_elements_begin();
  const_element_iterator end = this->active_local_elements_end();

  unsigned int max_proc_id=0;

  for (; el!=end; ++el)
    max_proc_id = std::max(max_proc_id, static_cast<unsigned int>((*el)->processor_id()));

  // The number of partitions is one more than the max processor ID.
  _n_parts = max_proc_id+1;

  this->comm().max(_n_parts);

  return _n_parts;
}

const PointLocatorBase& MeshBase::point_locator () const
{
  libmesh_deprecated();

  if (_point_locator.get() == NULL)
    {
      // PointLocator construction may not be safe within threads
      libmesh_assert(!Threads::in_threads);

      _point_locator.reset (PointLocatorBase::build(TREE_ELEMENTS, *this).release());
    }

  return *_point_locator;
}

AutoPtr<PointLocatorBase> MeshBase::sub_point_locator () const
{
  if (_point_locator.get() == NULL)
    {
      // PointLocator construction may not be safe within threads
      libmesh_assert(!Threads::in_threads);

      _point_locator.reset (PointLocatorBase::build(TREE_ELEMENTS, *this).release());
    }

  return PointLocatorBase::build(TREE_ELEMENTS, *this, _point_locator.get());
}

void MeshBase::clear_point_locator ()
{
  _point_locator.reset(NULL);
}

std::string& MeshBase::subdomain_name(subdomain_id_type id)
{
  return _block_id_to_name[id];
}

const std::string& MeshBase::subdomain_name(subdomain_id_type id) const
{
  // An empty string to return when no matching subdomain name is found
  static const std::string empty;

  std::map<subdomain_id_type, std::string>::const_iterator iter = _block_id_to_name.find(id);
  if (iter == _block_id_to_name.end())
    return empty;
  else
    return iter->second;
}

subdomain_id_type MeshBase::get_id_by_name(const std::string& name) const
{
  // Linear search over the map values.
  std::map<subdomain_id_type, std::string>::const_iterator
    iter = _block_id_to_name.begin(),
    end_iter = _block_id_to_name.end();

  for ( ; iter != end_iter; ++iter)
    if (iter->second == name)
      return iter->first;

  // If we made it here without returning, we don't have a subdomain
  // with the requested name, so return Elem::invalid_subdomain_id.
  return Elem::invalid_subdomain_id;
}

void MeshBase::cache_elem_dims()
{
  // This requires an inspection on every processor
  parallel_object_only();

  const_element_iterator el  = this->active_local_elements_begin();
  const_element_iterator end = this->active_local_elements_end();

  for (; el!=end; ++el)
    _elem_dims.insert((*el)->dim());

  // Some different dimension elements may only live on other processors
  this->comm().set_union(_elem_dims);
}

} // namespace libMesh
<|endoftext|>