<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2015 Artem Pavlenko
 *
 * 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 "catch.hpp"

#include <mapnik/map.hpp>
#include <mapnik/datasource.hpp>
#include <mapnik/datasource_cache.hpp>
#include <mapnik/geometry.hpp>
#include <mapnik/geometry_type.hpp>
#include <mapnik/util/fs.hpp>
#include <cstdlib>

#include <boost/filesystem/operations.hpp>
#include <boost/optional/optional_io.hpp>

namespace detail {

std::pair<mapnik::datasource_ptr,mapnik::feature_ptr> fetch_first_feature(std::string const& filename, bool cache_features)
{
    mapnik::parameters params;
    params["type"] = "geojson";
    params["file"] = filename;
    params["cache-features"] = cache_features;
    auto ds = mapnik::datasource_cache::instance().create(params);
    auto fields = ds->get_descriptor().get_descriptors();
    mapnik::query query(ds->envelope());
    for (auto const& field : fields)
    {
        query.add_property_name(field.get_name());
    }
    auto features = ds->features(query);
    auto feature = features->next();
    return std::make_pair(ds,feature);
}

int create_disk_index(std::string const& filename, bool silent)
{
    std::string cmd;
    if (std::getenv("DYLD_LIBRARY_PATH") != nullptr)
    {
        cmd += std::string("export DYLD_LIBRARY_PATH=") + std::getenv("DYLD_LIBRARY_PATH") + " && ";
    }
    cmd += "mapnik-index " + filename;
    if (silent)
    {
#ifndef _WINDOWS
        cmd += " 2>/dev/null";
#else
        cmd += "2> nul";
#endif
    }
    return std::system(cmd.c_str());
}

}

TEST_CASE("geojson") {

    std::string geojson_plugin("./plugins/input/geojson.input");
    if (mapnik::util::exists(geojson_plugin))
    {
        SECTION("GeoJSON Point")
        {
            for (auto cache_features : {true, false})
            {
                auto result = detail::fetch_first_feature("./test/data/json/point.json", cache_features);
                auto feature = result.second;
                auto ds = result.first;
                CHECK(ds->get_geometry_type() == mapnik::datasource_geometry_t::Point);
                auto const& geometry = feature->get_geometry();
                REQUIRE(mapnik::geometry::geometry_type(geometry) == mapnik::geometry::Point);
                auto const& pt = mapnik::util::get<mapnik::geometry::point<double> >(geometry);
                REQUIRE(pt.x == 100);
                REQUIRE(pt.y == 0);
            }
        }

        SECTION("GeoJSON LineString")
        {
            for (auto cache_features : {true, false})
            {
                auto result = detail::fetch_first_feature("./test/data/json/linestring.json", cache_features);
                auto feature = result.second;
                auto ds = result.first;
                CHECK(ds->get_geometry_type() == mapnik::datasource_geometry_t::LineString);
                auto const& geometry = feature->get_geometry();
                REQUIRE(mapnik::geometry::geometry_type(geometry) == mapnik::geometry::LineString);
                auto const& line = mapnik::util::get<mapnik::geometry::line_string<double> >(geometry);
                REQUIRE(line.size() == 2);
                REQUIRE(mapnik::geometry::envelope(line) == mapnik::box2d<double>(100,0,101,1));

            }
        }

        SECTION("GeoJSON Polygon")
        {
            for (auto cache_features : {true, false})
            {
                auto result = detail::fetch_first_feature("./test/data/json/polygon.json", cache_features);
                auto feature = result.second;
                auto ds = result.first;
                CHECK(ds->get_geometry_type() == mapnik::datasource_geometry_t::Polygon);
                auto const& geometry = feature->get_geometry();
                REQUIRE(mapnik::geometry::geometry_type(geometry) == mapnik::geometry::Polygon);
                auto const& poly = mapnik::util::get<mapnik::geometry::polygon<double> >(geometry);
                REQUIRE(poly.num_rings() == 2);
                REQUIRE(poly.exterior_ring.size() == 5);
                REQUIRE(poly.interior_rings.size() == 1);
                REQUIRE(poly.interior_rings[0].size() == 5);
                REQUIRE(mapnik::geometry::envelope(poly) == mapnik::box2d<double>(100,0,101,1));

            }
        }

        SECTION("GeoJSON MultiPoint")
        {
            for (auto cache_features : {true, false})
            {
                auto result = detail::fetch_first_feature("./test/data/json/multipoint.json", cache_features);
                auto feature = result.second;
                auto ds = result.first;
                CHECK(ds->get_geometry_type() == mapnik::datasource_geometry_t::Point);
                auto const& geometry = feature->get_geometry();
                REQUIRE(mapnik::geometry::geometry_type(geometry) == mapnik::geometry::MultiPoint);
                auto const& multi_pt = mapnik::util::get<mapnik::geometry::multi_point<double> >(geometry);
                REQUIRE(multi_pt.size() == 2);
                REQUIRE(mapnik::geometry::envelope(multi_pt) == mapnik::box2d<double>(100,0,101,1));
            }
        }

        SECTION("GeoJSON MultiLineString")
        {
            for (auto cache_features : {true, false})
            {
                auto result = detail::fetch_first_feature("./test/data/json/multilinestring.json", cache_features);
                auto feature = result.second;
                auto ds = result.first;
                CHECK(ds->get_geometry_type() == mapnik::datasource_geometry_t::LineString);
                auto const& geometry = feature->get_geometry();
                REQUIRE(mapnik::geometry::geometry_type(geometry) == mapnik::geometry::MultiLineString);
                auto const& multi_line = mapnik::util::get<mapnik::geometry::multi_line_string<double> >(geometry);
                REQUIRE(multi_line.size() == 2);
                REQUIRE(multi_line[0].size() == 2);
                REQUIRE(multi_line[1].size() == 2);
                REQUIRE(mapnik::geometry::envelope(multi_line) == mapnik::box2d<double>(100,0,103,3));

            }
        }

        SECTION("GeoJSON MultiPolygon")
        {
            for (auto cache_features : {true, false})
            {
                auto result = detail::fetch_first_feature("./test/data/json/multipolygon.json", cache_features);
                auto feature = result.second;
                auto ds = result.first;
                CHECK(ds->get_geometry_type() == mapnik::datasource_geometry_t::Polygon);
                // test
                auto const& geometry = feature->get_geometry();
                REQUIRE(mapnik::geometry::geometry_type(geometry) == mapnik::geometry::MultiPolygon);
                auto const& multi_poly = mapnik::util::get<mapnik::geometry::multi_polygon<double> >(geometry);
                REQUIRE(multi_poly.size() == 2);
                REQUIRE(multi_poly[0].num_rings() == 1);
                REQUIRE(multi_poly[1].num_rings() == 2);
                REQUIRE(mapnik::geometry::envelope(multi_poly) == mapnik::box2d<double>(100,0,103,3));

            }
        }

        SECTION("GeoJSON GeometryCollection")
        {
            std::string filename("./test/data/json/geometrycollection.json");
            for (auto create_index : { true, false })
            {
                if (create_index)
                {
                    int ret = detail::create_disk_index(filename, true);
                    int ret_posix = (ret >> 8) & 0x000000ff;
                    INFO(ret);
                    INFO(ret_posix);
                    // index will not exist because this is not a featurecollection
                    CHECK(!mapnik::util::exists(filename + ".index"));
                }

                for (auto cache_features : {true, false})
                {
                    auto result = detail::fetch_first_feature(filename, cache_features);
                    auto feature = result.second;
                    auto ds = result.first;
                    CHECK(ds->get_geometry_type() == mapnik::datasource_geometry_t::Collection);
                    // test
                    auto const& geometry = feature->get_geometry();
                    REQUIRE(mapnik::geometry::geometry_type(geometry) == mapnik::geometry::GeometryCollection);
                    auto const& collection = mapnik::util::get<mapnik::geometry::geometry_collection<double> >(geometry);
                    REQUIRE(collection.size() == 2);
                    REQUIRE(mapnik::geometry::geometry_type(collection[0]) == mapnik::geometry::Point);
                    REQUIRE(mapnik::geometry::geometry_type(collection[1]) == mapnik::geometry::LineString);
                    REQUIRE(mapnik::geometry::envelope(collection) == mapnik::box2d<double>(100,0,102,1));
                }
            }
        }

        SECTION("GeoJSON Feature")
        {
            // Create datasource
            mapnik::parameters params;
            params["type"] = "geojson";
            std::string filename("./test/data/json/feature.json");
            params["file"] = filename;
            for (auto create_index : { true, false })
            {
                if (create_index)
                {
                    int ret = detail::create_disk_index(filename, true);
                    int ret_posix = (ret >> 8) & 0x000000ff;
                    INFO(ret);
                    INFO(ret_posix);
                    // index will not exist because this is not a featurecollection
                    CHECK(!mapnik::util::exists(filename + ".index"));
                }

                for (auto cache_features : {true, false})
                {
                    params["cache-features"] = cache_features;
                    auto ds = mapnik::datasource_cache::instance().create(params);
                    REQUIRE(bool(ds));
                    auto fields = ds->get_descriptor().get_descriptors();
                    mapnik::query query(ds->envelope());
                    for (auto const& field : fields)
                    {
                        query.add_property_name(field.get_name());
                    }
                    auto features = ds->features(query);
                    REQUIRE(features != nullptr);
                    auto feature = features->next();
                    REQUIRE(feature != nullptr);
                }
            }
        }

        SECTION("GeoJSON FeatureCollection")
        {
            std::string filename("./test/data/json/featurecollection.json");

            // cleanup in the case of a failed previous run
            if (mapnik::util::exists(filename + ".index"))
            {
                boost::filesystem::remove(filename + ".index");
            }

            for (auto create_index : { true, false })
            {
                if (create_index)
                {
                    int ret = detail::create_disk_index(filename, true);
                    int ret_posix = (ret >> 8) & 0x000000ff;
                    INFO(ret);
                    INFO(ret_posix);
                    CHECK(mapnik::util::exists(filename + ".index"));
                }

                mapnik::parameters params;
                params["type"] = "geojson";
                params["file"] = filename;

                for (auto cache_features : {true, false})
                {
                    params["cache_features"] = cache_features;

                    auto ds = mapnik::datasource_cache::instance().create(params);
                    auto fields = ds->get_descriptor().get_descriptors();
                    mapnik::query query(ds->envelope());
                    for (auto const& field : fields)
                    {
                        query.add_property_name(field.get_name());
                    }
                    auto features = ds->features(query);
                    auto bounding_box = ds->envelope();
                    mapnik::box2d<double> bbox;
                    mapnik::value_integer count = 0;
                    while (true)
                    {
                        auto feature = features->next();
                        if (!feature) break;
                        if (!bbox.valid()) bbox = feature->envelope();
                        else bbox.expand_to_include(feature->envelope());
                        ++count;
                        REQUIRE(feature->id() == count);
                    }
                    REQUIRE(count == 3);
                    REQUIRE(bounding_box == bbox);
                }
                if (mapnik::util::exists(filename + ".index"))
                {
                    CHECK(mapnik::util::remove(filename + ".index"));
                }
            }
        }

        SECTION("GeoJSON extra properties")
        {
            // Create datasource
            mapnik::parameters params;
            params["type"] = "geojson";
            std::string filename("./test/data/json/feature_collection_extra_properties.json");
            params["file"] = filename;

            // cleanup in the case of a failed previous run
            if (mapnik::util::exists(filename + ".index"))
            {
                boost::filesystem::remove(filename + ".index");
            }

            for (auto create_index : { true, false })
            {
                if (create_index)
                {
                    int ret = detail::create_disk_index(filename, true);
                    int ret_posix = (ret >> 8) & 0x000000ff;
                    INFO(ret);
                    INFO(ret_posix);
                    CHECK(mapnik::util::exists(filename + ".index"));
                }

                for (auto cache_features : {true, false})
                {
                    params["cache-features"] = cache_features;
                    auto ds = mapnik::datasource_cache::instance().create(params);
                    REQUIRE(bool(ds));
                    auto fields = ds->get_descriptor().get_descriptors();
                    mapnik::query query(ds->envelope());
                    for (auto const& field : fields)
                    {
                        query.add_property_name(field.get_name());
                    }
                    auto features = ds->features(query);
                    REQUIRE(features != nullptr);
                    auto feature = features->next();
                    REQUIRE(feature != nullptr);
                    REQUIRE(feature->envelope() == mapnik::box2d<double>(123,456,123,456));
                }

                // cleanup
                if (create_index && mapnik::util::exists(filename + ".index"))
                {
                    boost::filesystem::remove(filename + ".index");
                }

            }
        }

        SECTION("GeoJSON ensure input fully consumed and throw exception otherwise")
        {
            mapnik::parameters params;
            params["type"] = "geojson";
            std::string filename("./test/data/json/points-malformed.geojson");
            params["file"] = filename; // mismatched parentheses

            // cleanup in the case of a failed previous run
            if (mapnik::util::exists(filename + ".index"))
            {
                boost::filesystem::remove(filename + ".index");
            }

            for (auto create_index : { true, false })
            {
                if (create_index)
                {
                    CHECK(!mapnik::util::exists(filename + ".index"));
                    int ret = detail::create_disk_index(filename, true);
                    int ret_posix = (ret >> 8) & 0x000000ff;
                    INFO(ret);
                    INFO(ret_posix);
                    CHECK(mapnik::util::exists(filename + ".index"));
                }

                for (auto cache_features : {true, false})
                {
                    std::stringstream msg;
                    msg << "testcase: create index " << create_index << " cache-features " << cache_features;
                    params["cache-features"] = cache_features;
                    INFO(msg.str());
                    CHECK_THROWS(mapnik::datasource_cache::instance().create(params));
                }

                // cleanup
                if (create_index && mapnik::util::exists(filename + ".index"))
                {
                    boost::filesystem::remove(filename + ".index");
                }
            }
        }
    }
}
<commit_msg>unit test geojson - only expect CHECK_THROW when *.index is not present. Bounding box extractor parser is not strict in the sense that it doesn't require input to be fully consumed (i.e it can handle extra traling characters).<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2015 Artem Pavlenko
 *
 * 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 "catch.hpp"

#include <mapnik/map.hpp>
#include <mapnik/datasource.hpp>
#include <mapnik/datasource_cache.hpp>
#include <mapnik/geometry.hpp>
#include <mapnik/geometry_type.hpp>
#include <mapnik/util/fs.hpp>
#include <cstdlib>

#include <boost/filesystem/operations.hpp>
#include <boost/optional/optional_io.hpp>

namespace detail {

std::pair<mapnik::datasource_ptr,mapnik::feature_ptr> fetch_first_feature(std::string const& filename, bool cache_features)
{
    mapnik::parameters params;
    params["type"] = "geojson";
    params["file"] = filename;
    params["cache-features"] = cache_features;
    auto ds = mapnik::datasource_cache::instance().create(params);
    auto fields = ds->get_descriptor().get_descriptors();
    mapnik::query query(ds->envelope());
    for (auto const& field : fields)
    {
        query.add_property_name(field.get_name());
    }
    auto features = ds->features(query);
    auto feature = features->next();
    return std::make_pair(ds,feature);
}

int create_disk_index(std::string const& filename, bool silent)
{
    std::string cmd;
    if (std::getenv("DYLD_LIBRARY_PATH") != nullptr)
    {
        cmd += std::string("export DYLD_LIBRARY_PATH=") + std::getenv("DYLD_LIBRARY_PATH") + " && ";
    }
    cmd += "mapnik-index " + filename;
    if (silent)
    {
#ifndef _WINDOWS
        cmd += " 2>/dev/null";
#else
        cmd += "2> nul";
#endif
    }
    return std::system(cmd.c_str());
}

}

TEST_CASE("geojson") {

    std::string geojson_plugin("./plugins/input/geojson.input");
    if (mapnik::util::exists(geojson_plugin))
    {
        SECTION("GeoJSON Point")
        {
            for (auto cache_features : {true, false})
            {
                auto result = detail::fetch_first_feature("./test/data/json/point.json", cache_features);
                auto feature = result.second;
                auto ds = result.first;
                CHECK(ds->get_geometry_type() == mapnik::datasource_geometry_t::Point);
                auto const& geometry = feature->get_geometry();
                REQUIRE(mapnik::geometry::geometry_type(geometry) == mapnik::geometry::Point);
                auto const& pt = mapnik::util::get<mapnik::geometry::point<double> >(geometry);
                REQUIRE(pt.x == 100);
                REQUIRE(pt.y == 0);
            }
        }

        SECTION("GeoJSON LineString")
        {
            for (auto cache_features : {true, false})
            {
                auto result = detail::fetch_first_feature("./test/data/json/linestring.json", cache_features);
                auto feature = result.second;
                auto ds = result.first;
                CHECK(ds->get_geometry_type() == mapnik::datasource_geometry_t::LineString);
                auto const& geometry = feature->get_geometry();
                REQUIRE(mapnik::geometry::geometry_type(geometry) == mapnik::geometry::LineString);
                auto const& line = mapnik::util::get<mapnik::geometry::line_string<double> >(geometry);
                REQUIRE(line.size() == 2);
                REQUIRE(mapnik::geometry::envelope(line) == mapnik::box2d<double>(100,0,101,1));

            }
        }

        SECTION("GeoJSON Polygon")
        {
            for (auto cache_features : {true, false})
            {
                auto result = detail::fetch_first_feature("./test/data/json/polygon.json", cache_features);
                auto feature = result.second;
                auto ds = result.first;
                CHECK(ds->get_geometry_type() == mapnik::datasource_geometry_t::Polygon);
                auto const& geometry = feature->get_geometry();
                REQUIRE(mapnik::geometry::geometry_type(geometry) == mapnik::geometry::Polygon);
                auto const& poly = mapnik::util::get<mapnik::geometry::polygon<double> >(geometry);
                REQUIRE(poly.num_rings() == 2);
                REQUIRE(poly.exterior_ring.size() == 5);
                REQUIRE(poly.interior_rings.size() == 1);
                REQUIRE(poly.interior_rings[0].size() == 5);
                REQUIRE(mapnik::geometry::envelope(poly) == mapnik::box2d<double>(100,0,101,1));

            }
        }

        SECTION("GeoJSON MultiPoint")
        {
            for (auto cache_features : {true, false})
            {
                auto result = detail::fetch_first_feature("./test/data/json/multipoint.json", cache_features);
                auto feature = result.second;
                auto ds = result.first;
                CHECK(ds->get_geometry_type() == mapnik::datasource_geometry_t::Point);
                auto const& geometry = feature->get_geometry();
                REQUIRE(mapnik::geometry::geometry_type(geometry) == mapnik::geometry::MultiPoint);
                auto const& multi_pt = mapnik::util::get<mapnik::geometry::multi_point<double> >(geometry);
                REQUIRE(multi_pt.size() == 2);
                REQUIRE(mapnik::geometry::envelope(multi_pt) == mapnik::box2d<double>(100,0,101,1));
            }
        }

        SECTION("GeoJSON MultiLineString")
        {
            for (auto cache_features : {true, false})
            {
                auto result = detail::fetch_first_feature("./test/data/json/multilinestring.json", cache_features);
                auto feature = result.second;
                auto ds = result.first;
                CHECK(ds->get_geometry_type() == mapnik::datasource_geometry_t::LineString);
                auto const& geometry = feature->get_geometry();
                REQUIRE(mapnik::geometry::geometry_type(geometry) == mapnik::geometry::MultiLineString);
                auto const& multi_line = mapnik::util::get<mapnik::geometry::multi_line_string<double> >(geometry);
                REQUIRE(multi_line.size() == 2);
                REQUIRE(multi_line[0].size() == 2);
                REQUIRE(multi_line[1].size() == 2);
                REQUIRE(mapnik::geometry::envelope(multi_line) == mapnik::box2d<double>(100,0,103,3));

            }
        }

        SECTION("GeoJSON MultiPolygon")
        {
            for (auto cache_features : {true, false})
            {
                auto result = detail::fetch_first_feature("./test/data/json/multipolygon.json", cache_features);
                auto feature = result.second;
                auto ds = result.first;
                CHECK(ds->get_geometry_type() == mapnik::datasource_geometry_t::Polygon);
                // test
                auto const& geometry = feature->get_geometry();
                REQUIRE(mapnik::geometry::geometry_type(geometry) == mapnik::geometry::MultiPolygon);
                auto const& multi_poly = mapnik::util::get<mapnik::geometry::multi_polygon<double> >(geometry);
                REQUIRE(multi_poly.size() == 2);
                REQUIRE(multi_poly[0].num_rings() == 1);
                REQUIRE(multi_poly[1].num_rings() == 2);
                REQUIRE(mapnik::geometry::envelope(multi_poly) == mapnik::box2d<double>(100,0,103,3));

            }
        }

        SECTION("GeoJSON GeometryCollection")
        {
            std::string filename("./test/data/json/geometrycollection.json");
            for (auto create_index : { true, false })
            {
                if (create_index)
                {
                    int ret = detail::create_disk_index(filename, true);
                    int ret_posix = (ret >> 8) & 0x000000ff;
                    INFO(ret);
                    INFO(ret_posix);
                    // index will not exist because this is not a featurecollection
                    CHECK(!mapnik::util::exists(filename + ".index"));
                }

                for (auto cache_features : {true, false})
                {
                    auto result = detail::fetch_first_feature(filename, cache_features);
                    auto feature = result.second;
                    auto ds = result.first;
                    CHECK(ds->get_geometry_type() == mapnik::datasource_geometry_t::Collection);
                    // test
                    auto const& geometry = feature->get_geometry();
                    REQUIRE(mapnik::geometry::geometry_type(geometry) == mapnik::geometry::GeometryCollection);
                    auto const& collection = mapnik::util::get<mapnik::geometry::geometry_collection<double> >(geometry);
                    REQUIRE(collection.size() == 2);
                    REQUIRE(mapnik::geometry::geometry_type(collection[0]) == mapnik::geometry::Point);
                    REQUIRE(mapnik::geometry::geometry_type(collection[1]) == mapnik::geometry::LineString);
                    REQUIRE(mapnik::geometry::envelope(collection) == mapnik::box2d<double>(100,0,102,1));
                }
            }
        }

        SECTION("GeoJSON Feature")
        {
            // Create datasource
            mapnik::parameters params;
            params["type"] = "geojson";
            std::string filename("./test/data/json/feature.json");
            params["file"] = filename;
            for (auto create_index : { true, false })
            {
                if (create_index)
                {
                    int ret = detail::create_disk_index(filename, true);
                    int ret_posix = (ret >> 8) & 0x000000ff;
                    INFO(ret);
                    INFO(ret_posix);
                    // index will not exist because this is not a featurecollection
                    CHECK(!mapnik::util::exists(filename + ".index"));
                }

                for (auto cache_features : {true, false})
                {
                    params["cache-features"] = cache_features;
                    auto ds = mapnik::datasource_cache::instance().create(params);
                    REQUIRE(bool(ds));
                    auto fields = ds->get_descriptor().get_descriptors();
                    mapnik::query query(ds->envelope());
                    for (auto const& field : fields)
                    {
                        query.add_property_name(field.get_name());
                    }
                    auto features = ds->features(query);
                    REQUIRE(features != nullptr);
                    auto feature = features->next();
                    REQUIRE(feature != nullptr);
                }
            }
        }

        SECTION("GeoJSON FeatureCollection")
        {
            std::string filename("./test/data/json/featurecollection.json");

            // cleanup in the case of a failed previous run
            if (mapnik::util::exists(filename + ".index"))
            {
                boost::filesystem::remove(filename + ".index");
            }

            for (auto create_index : { true, false })
            {
                if (create_index)
                {
                    int ret = detail::create_disk_index(filename, true);
                    int ret_posix = (ret >> 8) & 0x000000ff;
                    INFO(ret);
                    INFO(ret_posix);
                    CHECK(mapnik::util::exists(filename + ".index"));
                }

                mapnik::parameters params;
                params["type"] = "geojson";
                params["file"] = filename;

                for (auto cache_features : {true, false})
                {
                    params["cache_features"] = cache_features;

                    auto ds = mapnik::datasource_cache::instance().create(params);
                    auto fields = ds->get_descriptor().get_descriptors();
                    mapnik::query query(ds->envelope());
                    for (auto const& field : fields)
                    {
                        query.add_property_name(field.get_name());
                    }
                    auto features = ds->features(query);
                    auto bounding_box = ds->envelope();
                    mapnik::box2d<double> bbox;
                    mapnik::value_integer count = 0;
                    while (true)
                    {
                        auto feature = features->next();
                        if (!feature) break;
                        if (!bbox.valid()) bbox = feature->envelope();
                        else bbox.expand_to_include(feature->envelope());
                        ++count;
                        REQUIRE(feature->id() == count);
                    }
                    REQUIRE(count == 3);
                    REQUIRE(bounding_box == bbox);
                }
                if (mapnik::util::exists(filename + ".index"))
                {
                    CHECK(mapnik::util::remove(filename + ".index"));
                }
            }
        }

        SECTION("GeoJSON extra properties")
        {
            // Create datasource
            mapnik::parameters params;
            params["type"] = "geojson";
            std::string filename("./test/data/json/feature_collection_extra_properties.json");
            params["file"] = filename;

            // cleanup in the case of a failed previous run
            if (mapnik::util::exists(filename + ".index"))
            {
                boost::filesystem::remove(filename + ".index");
            }

            for (auto create_index : { true, false })
            {
                if (create_index)
                {
                    int ret = detail::create_disk_index(filename, true);
                    int ret_posix = (ret >> 8) & 0x000000ff;
                    INFO(ret);
                    INFO(ret_posix);
                    CHECK(mapnik::util::exists(filename + ".index"));
                }

                for (auto cache_features : {true, false})
                {
                    params["cache-features"] = cache_features;
                    auto ds = mapnik::datasource_cache::instance().create(params);
                    REQUIRE(bool(ds));
                    auto fields = ds->get_descriptor().get_descriptors();
                    mapnik::query query(ds->envelope());
                    for (auto const& field : fields)
                    {
                        query.add_property_name(field.get_name());
                    }
                    auto features = ds->features(query);
                    REQUIRE(features != nullptr);
                    auto feature = features->next();
                    REQUIRE(feature != nullptr);
                    REQUIRE(feature->envelope() == mapnik::box2d<double>(123,456,123,456));
                }

                // cleanup
                if (create_index && mapnik::util::exists(filename + ".index"))
                {
                    boost::filesystem::remove(filename + ".index");
                }

            }
        }

        SECTION("GeoJSON ensure input fully consumed and throw exception otherwise")
        {
            mapnik::parameters params;
            params["type"] = "geojson";
            std::string filename("./test/data/json/points-malformed.geojson");
            params["file"] = filename; // mismatched parentheses

            // cleanup in the case of a failed previous run
            if (mapnik::util::exists(filename + ".index"))
            {
                boost::filesystem::remove(filename + ".index");
            }

            for (auto create_index : { true, false })
            {
                if (create_index)
                {
                    CHECK(!mapnik::util::exists(filename + ".index"));
                    int ret = detail::create_disk_index(filename, true);
                    int ret_posix = (ret >> 8) & 0x000000ff;
                    INFO(ret);
                    INFO(ret_posix);
                    CHECK(mapnik::util::exists(filename + ".index"));
                }

                for (auto cache_features : {true, false})
                {
                    std::stringstream msg;
                    msg << "testcase: create index " << create_index << " cache-features " << cache_features;
                    params["cache-features"] = cache_features;
                    INFO(msg.str());
                    if (!create_index) CHECK_THROWS(mapnik::datasource_cache::instance().create(params));
                }

                // cleanup
                if (create_index && mapnik::util::exists(filename + ".index"))
                {
                    boost::filesystem::remove(filename + ".index");
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>#ifndef LIBPORT_UNIQUE_POINTER_HXX
# define LIBPORT_UNIQUE_POINTER_HXX

#include <iostream>
# include <libport/containers.hh>

namespace libport
{
  template <typename T>
  inline
  bool
  UniquePointer::operator() (T* t)
  {
    std::cerr << "Register: " << t << std::endl;
    if (libport::mhas(set_, t))
      return false;
    else
    {
      set_.insert (t);
      return true;
    }
  }

  template <typename T>
  inline
  bool
  UniquePointer::operator() (T& t)
  {
    return operator()(&t);
  }

}

#endif // !LIBPORT_UNIQUE_POINTER_HXX
<commit_msg>Remove trailing debug code. Reported by Samuel Tardieu.<commit_after>#ifndef LIBPORT_UNIQUE_POINTER_HXX
# define LIBPORT_UNIQUE_POINTER_HXX

#include <iostream>
# include <libport/containers.hh>

namespace libport
{
  template <typename T>
  inline
  bool
  UniquePointer::operator() (T* t)
  {
    if (libport::mhas(set_, t))
      return false;
    else
    {
      set_.insert (t);
      return true;
    }
  }

  template <typename T>
  inline
  bool
  UniquePointer::operator() (T& t)
  {
    return operator()(&t);
  }

}

#endif // !LIBPORT_UNIQUE_POINTER_HXX
<|endoftext|>


<commit_before>
#pragma once

#include "numerics/fast_sin_cos_cycle.hpp"

#include <pmmintrin.h>

#include "base/macros.hpp"
#include "numerics/polynomial.hpp"
#include "numerics/polynomial_evaluators.hpp"

namespace principia {
namespace numerics {

namespace {

using P3 = PolynomialInMonomialBasis</*Value=*/double,
                                     /*Argument=*/double,
                                     /*degree=*/3,
                                     /*Evaluator=*/EstrinEvaluator>;
P3 sin_polynomial(P3::Coefficients{6.28316404405113818577981340506,
                                   -41.3371423477858688509416864345,
                                   81.3407682603799599938651480917,
                                   -70.9934281315300026308830925659});
P3 cos_polynomial(P3::Coefficients{-19.7391820689166533085010275514,
                                   64.9352211775039525420259682190,
                                   -85.2540004035261113433497714557,
                                   56.3405940928237075549636782571});

}  // namespace

void FastSinCosCycle(double x, double& sin, double& cos) {
  // Argument reduction.  Since the unit of x is the cycle, we just drop the
  // integer part.
  double x_fractional;
#if PRINCIPIA_USE_SSE3_INTRINSICS
  __m128d const x_128d = _mm_load1_pd(&x);
  // Note that _mm_cvtpd has lower latency than _mm_cvtsd.
  __m128i const x_128i = _mm_cvtpd_epi32(x_128d);
  __m128d const x_integer_128d = _mm_cvtepi32_pd(x_128i);
  __m128d const x_fractional_128d = _mm_sub_pd(x_128d, x_integer_128d);
  x_fractional = _mm_cvtsd_f64(x_fractional_128d);
#else
#error "Argument reduction not implemented for non-SSE3 processors"
#endif

  double const x_fractional = x_fractional * x_fractional;
  sin = sin_polynomial.Evaluate(x_fractional) * x_fractional;
  cos = 1.0 + cos_polynomial.Evaluate(x_fractional) * x_fractional;
}

}  // namespace numerics
}  // namespace principia
<commit_msg>Full implementation.<commit_after>
#pragma once

#include "numerics/fast_sin_cos_cycle.hpp"

#include <pmmintrin.h>

#include "base/macros.hpp"
#include "numerics/polynomial.hpp"
#include "numerics/polynomial_evaluators.hpp"

namespace principia {
namespace numerics {

namespace {

using P3 = PolynomialInMonomialBasis</*Value=*/double,
                                     /*Argument=*/double,
                                     /*degree=*/3,
                                     /*Evaluator=*/EstrinEvaluator>;
P3 sin_polynomial(P3::Coefficients{6.28316404405113818577981340506,
                                   -41.3371423477858688509416864345,
                                   81.3407682603799599938651480917,
                                   -70.9934281315300026308830925659});
P3 cos_polynomial(P3::Coefficients{-19.7391820689166533085010275514,
                                   64.9352211775039525420259682190,
                                   -85.2540004035261113433497714557,
                                   56.3405940928237075549636782571});

}  // namespace

void FastSinCosCycle(double x, double& sin, double& cos) {
  // Argument reduction.  Since the unit of x is the cycle, we just drop the
  // integer part.
  double x_fractional;
#if PRINCIPIA_USE_SSE3_INTRINSICS
  __m128d const x_128d = _mm_load1_pd(&x);
  // Note that _mm_cvtpd has lower latency than _mm_cvtsd.
  __m128i const x_128i = _mm_cvtpd_epi32(x_128d);
  __m128d const x_integer_128d = _mm_cvtepi32_pd(x_128i);
  __m128d const x_fractional_128d = _mm_sub_pd(x_128d, x_integer_128d);
  x_fractional = _mm_cvtsd_f64(x_fractional_128d);
#else
#error "Argument reduction not implemented for non-SSE3 processors"
#endif

  double sign = 1.0;
  if (x_fractional > 0.25) {
    x_fractional -= 0.5;
    sign = -1.0;
  } else if (x_fractional < -0.25) {
    x_fractional += 0.5;
    sign = -1.0;
  }

  double const x_fractional = x_fractional * x_fractional;
  sin = sin_polynomial.Evaluate(x_fractional) * (sign * x_fractional);
  cos = sign + cos_polynomial.Evaluate(x_fractional) * (sign * x_fractional);
}

}  // namespace numerics
}  // namespace principia
<|endoftext|>


<commit_before>///
/// @file   int128.hpp
/// @brief  Additional integer types used in primecount:
///         int128_t, uint128_t, intfast64_t, intfast128_t, maxint_t,
///         maxuint_t.
///
/// Copyright (C) 2014 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#ifndef INTTYPES_HPP
#define INTTYPES_HPP

#include <limits>
#include <stdint.h>

#if __cplusplus >= 201103L
  #include <type_traits>
#endif

#if defined(HAVE_INT128_T)

namespace primecount {

typedef int128_t maxint_t;
typedef uint128_t maxuint_t;

}

#elif defined(HAVE___INT128_T)

#define HAVE_INT128_T

#include <ostream>
#include <string>

namespace primecount {

typedef __int128_t int128_t;
typedef __uint128_t uint128_t;

typedef __int128_t maxint_t;
typedef __uint128_t maxuint_t;

inline std::ostream& operator<<(std::ostream& stream, uint128_t n)
{
  std::string str;

  while (n > 0)
  {
    str += '0' + n % 10;
    n /= 10;
  }
  if (str.empty())
    str = "0";

  stream << std::string(str.rbegin(), str.rend());
  return stream;
}

inline std::ostream& operator<<(std::ostream& stream, int128_t n)
{
  if (n < 0)
  {
    stream << "-";
    n = -n;
  }
  stream << (uint128_t) n;
  return stream;
}

} // namespace

#else /* int128_t not supported */

namespace primecount {

typedef int64_t maxint_t;
typedef int64_t maxuint_t;

}

#endif /* HAVE_INT128_T */

namespace primecount {

/// Fastest 64-bit integer type for division.
/// On most Intel CPUs before 2015 unsigned 64-bit division is about
/// 10 percent faster than signed division. It is likely that in a few
/// years signed and unsigned division will run equally fast.
///
typedef uint64_t intfast64_t;

#if defined(HAVE_INT128_T)

/// Fastest 128-bit integer type for division.
/// On the author's Intel Core-i7 4770 CPU from 2013 using uint128_t
/// instead of int128_t gives 10 percent better performance.
///
typedef uint128_t intfast128_t;

#endif

/// Portable namespace, includes functions which (unlike the versions
/// form the C++ standard library) work with the int128_t and
/// uint128_t types (2014).
///
namespace prt {

#if __cplusplus >= 201103L
  #define CONSTEXPR constexpr
#else
  #define CONSTEXPR
#endif

template <typename T>
struct numeric_limits
{
  static CONSTEXPR T max()
  {
    return std::numeric_limits<T>::max();
  }
};

#if defined(HAVE_INT128_T)

template <>
struct numeric_limits<int128_t>
{
  static CONSTEXPR int128_t max() { return ~(((int128_t) 1) << 127); }
};

template <>
struct numeric_limits<uint128_t>
{
  static CONSTEXPR uint128_t max() { return ~((int128_t) 0); }
};

#endif
#undef CONSTEXPR

#if __cplusplus >= 201103L

template <typename T>
struct make_signed
{
#ifndef HAVE_INT128_T
  typedef typename std::make_signed<T>::type type;
#else
  typedef typename std::conditional<std::is_same<T, uint8_t>::value, int8_t,
          typename std::conditional<std::is_same<T, uint16_t>::value, int16_t,
          typename std::conditional<std::is_same<T, uint32_t>::value, int32_t,
          typename std::conditional<std::is_same<T, uint64_t>::value, int64_t,
          typename std::conditional<std::is_same<T, uint128_t>::value, int128_t,
          T>::type>::type>::type>::type>::type type;
#endif
};

template <typename T>
struct is_integral
{
  enum
  {
#ifndef HAVE_INT128_T
    value = std::is_integral<T>::value
#else
    value = std::is_integral<T>::value ||
            std::is_same<T, int128_t>::value ||
            std::is_same<T, uint128_t>::value
#endif
  };
};

#endif /* __cplusplus >= 201103L */

} // namespace prt
} // namespace primecount

#endif /* INTTYPES_HPP */
<commit_msg>Refactoring<commit_after>///
/// @file   int128.hpp
/// @brief  Additional integer types used in primecount:
///         int128_t, uint128_t, intfast64_t, intfast128_t, maxint_t,
///         maxuint_t.
///
/// Copyright (C) 2014 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#ifndef INTTYPES_HPP
#define INTTYPES_HPP

#include <limits>
#include <stdint.h>

#if __cplusplus >= 201103L
  #include <type_traits>
#endif

#if defined(HAVE_INT128_T)

namespace primecount {

typedef int128_t maxint_t;
typedef uint128_t maxuint_t;

}

#elif defined(HAVE___INT128_T)

#define HAVE_INT128_T

#include <ostream>
#include <string>

namespace primecount {

typedef __int128_t int128_t;
typedef __uint128_t uint128_t;

typedef __int128_t maxint_t;
typedef __uint128_t maxuint_t;

inline std::ostream& operator<<(std::ostream& stream, uint128_t n)
{
  std::string str;

  while (n > 0)
  {
    str += '0' + n % 10;
    n /= 10;
  }
  if (str.empty())
    str = "0";

  stream << std::string(str.rbegin(), str.rend());
  return stream;
}

inline std::ostream& operator<<(std::ostream& stream, int128_t n)
{
  if (n < 0)
  {
    stream << "-";
    n = -n;
  }
  stream << (uint128_t) n;
  return stream;
}

} // namespace

#else /* int128_t not supported */

namespace primecount {

typedef int64_t maxint_t;
typedef int64_t maxuint_t;

}

#endif /* HAVE_INT128_T */

namespace primecount {

/// Fastest 64-bit integer type for division.
/// On most Intel CPUs before 2015 unsigned 64-bit division is about
/// 10 percent faster than signed division. It is likely that in a few
/// years signed and unsigned division will run equally fast.
///
typedef uint64_t intfast64_t;

#if defined(HAVE_INT128_T)

/// Fastest 128-bit integer type for division.
/// On the author's Intel Core-i7 4770 CPU from 2013 using uint128_t
/// instead of int128_t gives 10 percent better performance.
///
typedef uint128_t intfast128_t;

#endif

/// Portable namespace, includes functions which (unlike the versions
/// form the C++ standard library) work with the int128_t and
/// uint128_t types (2014).
///
namespace prt {

#if __cplusplus >= 201103L
  #define CONSTEXPR constexpr
#else
  #define CONSTEXPR
#endif

template <typename T>
struct numeric_limits
{
  static CONSTEXPR T max()
  {
    return std::numeric_limits<T>::max();
  }
};

#if defined(HAVE_INT128_T)

template <>
struct numeric_limits<int128_t>
{
  static CONSTEXPR int128_t max()
  {
    return ~(((int128_t) 1) << 127);
  }
};

template <>
struct numeric_limits<uint128_t>
{
  static CONSTEXPR uint128_t max()
  {
    return ~((int128_t) 0);
  }
};

#endif
#undef CONSTEXPR

#if __cplusplus >= 201103L

template <typename T>
struct make_signed
{
#ifndef HAVE_INT128_T
  typedef typename std::make_signed<T>::type type;
#else
  typedef typename std::conditional<std::is_same<T, uint8_t>::value, int8_t,
          typename std::conditional<std::is_same<T, uint16_t>::value, int16_t,
          typename std::conditional<std::is_same<T, uint32_t>::value, int32_t,
          typename std::conditional<std::is_same<T, uint64_t>::value, int64_t,
          typename std::conditional<std::is_same<T, uint128_t>::value, int128_t,
          T>::type>::type>::type>::type>::type type;
#endif
};

template <typename T>
struct is_integral
{
  enum
  {
#ifndef HAVE_INT128_T
    value = std::is_integral<T>::value
#else
    value = std::is_integral<T>::value ||
            std::is_same<T, int128_t>::value ||
            std::is_same<T, uint128_t>::value
#endif
  };
};

#endif /* __cplusplus >= 201103L */

} // namespace prt
} // namespace primecount

#endif /* INTTYPES_HPP */
<|endoftext|>


<commit_before>/*
 * metallicar_concurrency.hpp
 *
 *  Created on: Jul 15, 2014
 *      Author: Pimenta
 */

#ifndef METALLICAR_CONCURRENCY_HPP_
#define METALLICAR_CONCURRENCY_HPP_

// standard
#include <functional>
#include <memory>
#include <map>

// lib
#include "SDL.h"

namespace metallicar {

class Thread {
  private:
    std::function<void()> callback;
    SDL_Thread* thread;
    bool joined;
    bool* terminated;
  public:
    enum Priority {
      LOW, NORMAL, HIGH
    };

    Thread(const std::function<void()>& callback);
    ~Thread();
    Thread(const Thread& other);
    Thread& operator=(const Thread& other);
    Thread(Thread&& other);
    Thread& operator=(Thread&& other);

    void start();
    void join();
    bool running() const;
    uint32_t getID() const;

    static uint32_t ID();
    static void sleep(uint32_t ms, const bool* keepCondition = nullptr);
    static void setPriority(Priority priority);
};

class Mutex {
  private:
    SDL_mutex* mutex;
  public:
    Mutex();
    ~Mutex();
    void lock();
    void unlock();
    bool tryLock();
};

class Semaphore {
  private:
    uint32_t initial_value;
    SDL_sem* semaphore;
  public:
    Semaphore(uint32_t initialValue);
    ~Semaphore();
    void wait();
    void post();
    bool tryWait();
    bool waitTimeout(uint32_t ms);
    uint32_t value() const;
    uint32_t initialValue() const;
};

class Condition {
  private:
    SDL_cond* condition;
  public:
    Condition();
    ~Condition();
    void wait(Mutex& mutex);
    void signal();
    bool waitTimeout(Mutex& mutex, uint32_t ms);
    void broadcast();
};

class AtomicBase {
  protected:
    AtomicBase();
  public:
    virtual ~AtomicBase();
};

template <class T>
class Atomic : public AtomicBase {
  private:
    std::unique_ptr<T> val;
    Mutex mutex;
  public:
    Atomic(T* val) : val(val) {

    }

    ~Atomic() {

    }

    void lock() {
      mutex.lock();
    }

    void unlock() {
      mutex.unlock();
    }

    T& value() const {
      return *(val.get());
    }
};

class AtomicGlobals {
  private:
    static std::map<std::string, AtomicBase*> atomics;
  public:
    template <typename T> static Atomic<T>* get(const std::string& key) {
      auto atomic = atomics.find(key);
      if (atomic == atomics.end()) {
        return nullptr;
      }
      return (Atomic<T>*)atomic->second;
    }
    static void put(const std::string& key, AtomicBase* value);
    static void erase(const std::string& key);
};

} // namespace metallicar

#endif /* METALLICAR_CONCURRENCY_HPP_ */
<commit_msg>Now is possible to create atomics without args in the constructor<commit_after>/*
 * metallicar_concurrency.hpp
 *
 *  Created on: Jul 15, 2014
 *      Author: Pimenta
 */

#ifndef METALLICAR_CONCURRENCY_HPP_
#define METALLICAR_CONCURRENCY_HPP_

// standard
#include <functional>
#include <memory>
#include <map>

// lib
#include "SDL.h"

namespace metallicar {

class Thread {
  private:
    std::function<void()> callback;
    SDL_Thread* thread;
    bool joined;
    bool* terminated;
  public:
    enum Priority {
      LOW, NORMAL, HIGH
    };

    Thread(const std::function<void()>& callback);
    ~Thread();
    Thread(const Thread& other);
    Thread& operator=(const Thread& other);
    Thread(Thread&& other);
    Thread& operator=(Thread&& other);

    void start();
    void join();
    bool running() const;
    uint32_t getID() const;

    static uint32_t ID();
    static void sleep(uint32_t ms, const bool* keepCondition = nullptr);
    static void setPriority(Priority priority);
};

class Mutex {
  private:
    SDL_mutex* mutex;
  public:
    Mutex();
    ~Mutex();
    void lock();
    void unlock();
    bool tryLock();
};

class Semaphore {
  private:
    uint32_t initial_value;
    SDL_sem* semaphore;
  public:
    Semaphore(uint32_t initialValue);
    ~Semaphore();
    void wait();
    void post();
    bool tryWait();
    bool waitTimeout(uint32_t ms);
    uint32_t value() const;
    uint32_t initialValue() const;
};

class Condition {
  private:
    SDL_cond* condition;
  public:
    Condition();
    ~Condition();
    void wait(Mutex& mutex);
    void signal();
    bool waitTimeout(Mutex& mutex, uint32_t ms);
    void broadcast();
};

class AtomicBase {
  protected:
    AtomicBase();
  public:
    virtual ~AtomicBase();
};

template <class T>
class Atomic : public AtomicBase {
  private:
    std::unique_ptr<T> val;
    Mutex mutex;
  public:
    Atomic(T* val = nullptr) : val(val ? val : new T) {

    }

    ~Atomic() {

    }

    void lock() {
      mutex.lock();
    }

    void unlock() {
      mutex.unlock();
    }

    T& value() const {
      return *(val.get());
    }
};

class AtomicGlobals {
  private:
    static std::map<std::string, AtomicBase*> atomics;
  public:
    template <typename T> static Atomic<T>* get(const std::string& key) {
      auto atomic = atomics.find(key);
      if (atomic == atomics.end()) {
        return nullptr;
      }
      return (Atomic<T>*)atomic->second;
    }
    static void put(const std::string& key, AtomicBase* value);
    static void erase(const std::string& key);
};

} // namespace metallicar

#endif /* METALLICAR_CONCURRENCY_HPP_ */
<|endoftext|>


<commit_before><commit_msg>GL fix. Code was DCHECKing valid conditions and therefore asserting in debug mode.<commit_after><|endoftext|>


<commit_before>// Copyright 2016-2019 Francesco Biscani (bluescarni@gmail.com)
//
// This file is part of the mp++ library.
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.

#ifndef MPPP_DETAIL_VISIBILITY_HPP
#define MPPP_DETAIL_VISIBILITY_HPP

#include <mp++/config.hpp>

// The visibility setup makes sense only for shared
// library builds.
#if defined(MPPP_STATIC_BUILD)

#define MPPP_DLL_PUBLIC
#define MPPP_DLL_LOCAL

#else

// Convenience macros for setting the visibility of entities
// when building/using the shared library. Mostly inspired by:
// https://gcc.gnu.org/wiki/Visibility
// We check first for Windows, where we assume every compiler
// knows dllexport/dllimport. On other platforms, we use the GCC-like
// syntax for GCC, clang and ICC. Otherwise, we leave the definitions
// empty.
#if defined(_WIN32) || defined(__CYGWIN__)

#if defined(mppp_EXPORTS)

#define MPPP_DLL_PUBLIC __declspec(dllexport)

#else

#define MPPP_DLL_PUBLIC __declspec(dllimport)

#endif

#define MPPP_DLL_LOCAL

#elif defined(__clang__) || defined(__GNUC__) || defined(__INTEL_COMPILER)

#define MPPP_DLL_PUBLIC __attribute__((visibility("default")))
#define MPPP_DLL_LOCAL __attribute__((visibility("hidden")))

#else

#define MPPP_DLL_PUBLIC
#define MPPP_DLL_LOCAL

#endif

// NOTE: it seems like on Windows using dllimport/dllexport on inline classes
// is generally not helpful (and potentially harmful), apart from special use cases:
// https://stackoverflow.com/questions/8876279/c-inline-functions-with-dllimport-dllexport
// https://stackoverflow.com/questions/24511376/how-to-dllexport-a-class-derived-from-stdruntime-error
// https://devblogs.microsoft.com/oldnewthing/20140109-00/?p=2123
// Setting the visibility attribute on GCC-like compilers for inline classes, however, seems to be ok.
// Thus, we use a specialised definition for marking "public"ly visible inline classes.
#if defined(_WIN32) || defined(__CYGWIN__)

#define MPPP_DLL_PUBLIC_INLINE_CLASS

#else

#define MPPP_DLL_PUBLIC_INLINE_CLASS MPPP_DLL_PUBLIC

#endif

#endif

#endif
<commit_msg>Forgot one definition.<commit_after>// Copyright 2016-2019 Francesco Biscani (bluescarni@gmail.com)
//
// This file is part of the mp++ library.
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.

#ifndef MPPP_DETAIL_VISIBILITY_HPP
#define MPPP_DETAIL_VISIBILITY_HPP

#include <mp++/config.hpp>

// The visibility setup makes sense only for shared
// library builds.
#if defined(MPPP_STATIC_BUILD)

#define MPPP_DLL_PUBLIC
#define MPPP_DLL_LOCAL
#define MPPP_DLL_PUBLIC_INLINE_CLASS

#else

// Convenience macros for setting the visibility of entities
// when building/using the shared library. Mostly inspired by:
// https://gcc.gnu.org/wiki/Visibility
// We check first for Windows, where we assume every compiler
// knows dllexport/dllimport. On other platforms, we use the GCC-like
// syntax for GCC, clang and ICC. Otherwise, we leave the definitions
// empty.
#if defined(_WIN32) || defined(__CYGWIN__)

#if defined(mppp_EXPORTS)

#define MPPP_DLL_PUBLIC __declspec(dllexport)

#else

#define MPPP_DLL_PUBLIC __declspec(dllimport)

#endif

#define MPPP_DLL_LOCAL

#elif defined(__clang__) || defined(__GNUC__) || defined(__INTEL_COMPILER)

#define MPPP_DLL_PUBLIC __attribute__((visibility("default")))
#define MPPP_DLL_LOCAL __attribute__((visibility("hidden")))

#else

#define MPPP_DLL_PUBLIC
#define MPPP_DLL_LOCAL

#endif

// NOTE: it seems like on Windows using dllimport/dllexport on inline classes
// is generally not helpful (and potentially harmful), apart from special use cases:
// https://stackoverflow.com/questions/8876279/c-inline-functions-with-dllimport-dllexport
// https://stackoverflow.com/questions/24511376/how-to-dllexport-a-class-derived-from-stdruntime-error
// https://devblogs.microsoft.com/oldnewthing/20140109-00/?p=2123
// Setting the visibility attribute on GCC-like compilers for inline classes, however, seems to be ok.
// Thus, we use a specialised definition for marking "public"ly visible inline classes.
#if defined(_WIN32) || defined(__CYGWIN__)

#define MPPP_DLL_PUBLIC_INLINE_CLASS

#else

#define MPPP_DLL_PUBLIC_INLINE_CLASS MPPP_DLL_PUBLIC

#endif

#endif

#endif
<|endoftext|>


<commit_before>/*
    sievedebugdialog.cpp

    KMail, the KDE mail client.
    Copyright (c) 2005 Martijn Klingens <klingens@kde.org>

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License,
    version 2.0, as published by the Free Software Foundation.
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software Foundation,
    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, US
*/

// This file is only compiled when debug is enabled, it is
// not useful enough for non-developers to have this in releases.
#if !defined(NDEBUG)

#include "sievedebugdialog.h"

#include <cassert>
#include <limits.h>

#include <QDateTime>

#include <kdebug.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <ktextedit.h>

#include <kmime/kmime_header_parsing.h>
#include <ksieve/error.h>
#include <ksieve/parser.h>
#include <ksieve/scriptbuilder.h>
#include <kpimidentities/identity.h>
#include <kpimidentities/identitymanager.h>

#include "kmacctimap.h"
#include "accountmanager.h"
using KMail::AccountManager;
#include "kmkernel.h"
#include "sievejob.h"

using KMail::SieveJob;
using KMime::Types::AddrSpecList;

namespace
{

class SieveDebugDataExtractor : public KSieve::ScriptBuilder
{
    enum Context
    {
        None = 0,

        // command itself:
        SieveDebugCommand,

        // tagged args:
        Days, Addresses
    };

public:
    SieveDebugDataExtractor()
    :   KSieve::ScriptBuilder()
    {
        kDebug() ;
    }

    virtual ~SieveDebugDataExtractor()
    {
        kDebug() ;
    }

private:
    void commandStart( const QString & identifier )
    {
        kDebug() << "Identifier: '" << identifier <<"'";
        reset();
    }

    void commandEnd()
    {
        kDebug() ;
    }

    void testStart( const QString & )
    {
        kDebug() ;
    }

    void testEnd()
    {
        kDebug() ;
    }

    void testListStart()
    {
        kDebug() ;
    }

    void testListEnd()
    {
        kDebug() ;
    }

    void blockStart()
    {
        kDebug() ;
    }

    void blockEnd()
    {
        kDebug() ;
    }

    void hashComment( const QString & )
    {
        kDebug() ;
    }

    void bracketComment( const QString & )
    {
        kDebug() ;
    }

    void lineFeed()
    {
        kDebug() ;
    }

    void error( const KSieve::Error & e )
    {
        kDebug() << "###" <<"Error:" <<
            e.asString() << "@" << e.line() << "," << e.column();
    }

    void finished()
    {
        kDebug() ;
    }

    void taggedArgument( const QString & tag )
    {
        kDebug() << "Tag: '" << tag <<"'";
    }

    void stringArgument( const QString & string, bool, const QString & )
    {
        kDebug() << "String: '" << string <<"'";
    }

    void numberArgument( unsigned long number, char )
    {
        kDebug() << "Number:" << number;
    }

    void stringListArgumentStart()
    {
        kDebug() ;
    }

    void stringListEntry( const QString & string, bool, const QString & )
    {
        kDebug() << "String: '" << string <<"'";
    }

    void stringListArgumentEnd()
    {
        kDebug() ;
    }

private:
    void reset()
    {
        kDebug() ;
    }
};

} // Anon namespace

namespace KMail
{

SieveDebugDialog::SieveDebugDialog( QWidget *parent )
:   KDialog( parent ),
    mSieveJob( 0 )
{
    setCaption( i18n( "Sieve Diagnostics" ) );
    setButtons( Ok );
    // Collect all accounts
    AccountManager *am = kmkernel->acctMgr();
    assert( am );
    QList<KMAccount*>::iterator accountIt = am->begin();
    while ( accountIt != am->end() ) {
      KMAccount *account = *accountIt;
      ++accountIt;
      mAccountList.append( account );
    }

    mEdit = new KTextEdit( this );
    mEdit->setReadOnly( true );
    setMainWidget( mEdit );

    mEdit->setText( i18n( "Collecting diagnostic information about Sieve support...\n\n" ) );

    setInitialSize( QSize( 640, 480 ) );

    if ( !mAccountList.isEmpty() )
        QTimer::singleShot( 0, this, SLOT( slotDiagNextAccount() ) );
}

SieveDebugDialog::~SieveDebugDialog()
{
    if ( mSieveJob )
    {
        mSieveJob->kill();
        mSieveJob = 0;
    }
    kDebug() ;
}

static KUrl urlFromAccount( const KMail::ImapAccountBase * a ) {
    const SieveConfig sieve = a->sieveConfig();
    if ( !sieve.managesieveSupported() )
        return KUrl();

    KUrl u;
    if ( sieve.reuseConfig() ) {
        // assemble Sieve url from the settings of the account:
        u.setProtocol( "sieve" );
        u.setHost( a->host() );
        u.setUser( a->login() );
        u.setPass( a->passwd() );
        u.setPort( sieve.port() );

        // Translate IMAP LOGIN to PLAIN:
        u.addQueryItem( "x-mech", a->auth() == "*" ? "PLAIN" : a->auth() );
        if ( !a->useSSL() && !a->useTLS() )
            u.addQueryItem( "x-allow-unencrypted", "true" );
    } else {
        u = sieve.alternateURL();
        if ( u.protocol().toLower() == "sieve" && !a->useSSL() && !a->useTLS() && u.queryItem("x-allow-unencrypted").isEmpty() )
            u.addQueryItem( "x-allow-unencrypted", "true" );
    }
    return u;
}

void SieveDebugDialog::slotDiagNextAccount()
{
    if ( mAccountList.isEmpty() )
        return;

    KMAccount *acc = mAccountList.first();
    mAccountList.pop_front();

    mEdit->append( i18n( "Collecting data for account '%1'...\n", acc->name() ) );
    mEdit->append( i18n( "------------------------------------------------------------\n" ) );
    mAccountBase = dynamic_cast<KMail::ImapAccountBase *>( acc );
    if ( mAccountBase )
    {
        // Detect URL for this IMAP account
        const KUrl url = urlFromAccount( mAccountBase );
        if ( !url.isValid() )
        {
            mEdit->append( i18n( "(Account does not support Sieve)\n\n" ) );
        } else {
            mUrl = url;

            mSieveJob = SieveJob::list( mUrl );

            connect( mSieveJob, SIGNAL( gotList( KMail::SieveJob *, bool, const QStringList &, const QString & ) ),
                SLOT( slotGetScriptList( KMail::SieveJob *, bool, const QStringList &, const QString & ) ) );

            // Bypass the singleShot timer -- it's fired when we get our data
            return;
        }
    } else {
        mEdit->append( i18n( "(Account is not an IMAP account)\n\n" ) );
    }

    // Handle next account async
    QTimer::singleShot( 0, this, SLOT( slotDiagNextAccount() ) );
}

void SieveDebugDialog::slotDiagNextScript()
{
    if ( mScriptList.isEmpty() )
    {
        // Continue handling accounts instead
        mScriptList.clear();
        QTimer::singleShot( 0, this, SLOT( slotDiagNextAccount() ) );
        return;
    }

    QString scriptFile = mScriptList.first();
    mScriptList.pop_front();

    mEdit->append( i18n( "Contents of script '%1':\n", scriptFile ) );
    mUrl = urlFromAccount( mAccountBase );
    mUrl.setFileName( scriptFile );

    mSieveJob = SieveJob::get( mUrl );

    connect( mSieveJob, SIGNAL( gotScript( KMail::SieveJob *, bool, const QString &, bool ) ),
        SLOT( slotGetScript( KMail::SieveJob *, bool, const QString &, bool ) ) );
}

void SieveDebugDialog::slotGetScript( SieveJob * /* job */, bool success,
    const QString &script, bool active )
{
    kDebug() << "( ??," << success
                   << ", ?," << active << ")" << endl
                   << "script:" << endl
                   << script;
    mSieveJob = 0; // job deletes itself after returning from this slot!

    if ( script.isEmpty() )
    {
        mEdit->append( i18n( "(This script is empty.)\n\n" ) );
    }
    else
    {
        mEdit->append( i18n(
            "------------------------------------------------------------\n"
            "%1\n"
            "------------------------------------------------------------\n\n", script ) );
    }

    // Fetch next script
    QTimer::singleShot( 0, this, SLOT( slotDiagNextScript() ) );
}

void SieveDebugDialog::slotGetScriptList( SieveJob *job, bool success,
    const QStringList &scriptList, const QString &activeScript )
{
    kDebug() << "Success:" << success <<", List:" << scriptList.join("," ) <<
        ", active:" << activeScript;
    mSieveJob = 0; // job deletes itself after returning from this slot!

    mEdit->append( i18n( "Sieve capabilities:\n" ) );
    const QStringList caps = job->sieveCapabilities();
    if ( caps.isEmpty() )
    {
        mEdit->append( i18n( "(No special capabilities available)" ) );
    }
    else
    {
        for ( QStringList::const_iterator it = caps.constBegin(); it != caps.constEnd(); ++it )
            mEdit->append( "* " + *it + '\n' );
        mEdit->append( "\n" );
    }

    mEdit->append( i18n( "Available Sieve scripts:\n" ) );

    if ( scriptList.isEmpty() )
    {
        mEdit->append( i18n( "(No Sieve scripts available on this server)\n\n" ) );
    }
    else
    {
        mScriptList = scriptList;
        for ( QStringList::const_iterator it = scriptList.begin(); it != scriptList.end(); ++it )
            mEdit->append( "* " + *it + '\n' );
        mEdit->append( "\n" );
        mEdit->append( i18n( "Active script: %1\n\n", activeScript ) );
    }

    // Handle next job: dump scripts for this server
    QTimer::singleShot( 0, this, SLOT( slotDiagNextScript() ) );
}

void SieveDebugDialog::slotDialogOk()
{
    kDebug();
}

void SieveDebugDialog::slotPutActiveResult( SieveJob * job, bool success )
{
    handlePutResult( job, success, true );
}

void SieveDebugDialog::slotPutInactiveResult( SieveJob * job, bool success )
{
    handlePutResult( job, success, false );
}

void SieveDebugDialog::handlePutResult( SieveJob *, bool success, bool activated )
{
    if ( success )
    {
        KMessageBox::information( 0, activated ? i18n(
            "Sieve script installed successfully on the server.\n"
            "Out of Office reply is now active." )
            : i18n( "Sieve script installed successfully on the server.\n"
            "Out of Office reply has been deactivated." ) );
    }

    kDebug() << "( ???," << success <<", ? )";
    mSieveJob = 0; // job deletes itself after returning from this slot!
}

} // namespace KMail

#include "sievedebugdialog.moc"

#endif // NDEBUG

<commit_msg>Make it link (on my laptop yesterday it linked)<commit_after>/*
    sievedebugdialog.cpp

    KMail, the KDE mail client.
    Copyright (c) 2005 Martijn Klingens <klingens@kde.org>

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License,
    version 2.0, as published by the Free Software Foundation.
    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software Foundation,
    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, US
*/

// This file is only compiled when debug is enabled, it is
// not useful enough for non-developers to have this in releases.
#if !defined(NDEBUG)

#include "sievedebugdialog.h"

#include <cassert>
#include <limits.h>

#include <QDateTime>

#include <kdebug.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <ktextedit.h>

#include <kmime/kmime_header_parsing.h>
#include <ksieve/error.h>
#include <ksieve/parser.h>
#include <ksieve/scriptbuilder.h>
#include <kpimidentities/identity.h>
#include <kpimidentities/identitymanager.h>

#include "kmacctimap.h"
#include "accountmanager.h"
using KMail::AccountManager;
#include "kmkernel.h"
#include "sievejob.h"

using KMail::SieveJob;
using KMime::Types::AddrSpecList;

namespace
{

class SieveDebugDataExtractor : public KSieve::ScriptBuilder
{
    enum Context
    {
        None = 0,

        // command itself:
        SieveDebugCommand,

        // tagged args:
        Days, Addresses
    };

public:
    SieveDebugDataExtractor()
    :   KSieve::ScriptBuilder()
    {
        kDebug() ;
    }

    virtual ~SieveDebugDataExtractor()
    {
        kDebug() ;
    }

private:
    void commandStart( const QString & identifier )
    {
        kDebug() << "Identifier: '" << identifier <<"'";
        reset();
    }

    void commandEnd()
    {
        kDebug() ;
    }

    void testStart( const QString & )
    {
        kDebug() ;
    }

    void testEnd()
    {
        kDebug() ;
    }

    void testListStart()
    {
        kDebug() ;
    }

    void testListEnd()
    {
        kDebug() ;
    }

    void blockStart()
    {
        kDebug() ;
    }

    void blockEnd()
    {
        kDebug() ;
    }

    void hashComment( const QString & )
    {
        kDebug() ;
    }

    void bracketComment( const QString & )
    {
        kDebug() ;
    }

    void lineFeed()
    {
        kDebug() ;
    }

    void error( const KSieve::Error & e )
    {
        kDebug() << "###" <<"Error:" <<
            e.asString() << "@" << e.line() << "," << e.column();
    }

    void finished()
    {
        kDebug() ;
    }

    void taggedArgument( const QString & tag )
    {
        kDebug() << "Tag: '" << tag <<"'";
    }

    void stringArgument( const QString & string, bool, const QString & )
    {
        kDebug() << "String: '" << string <<"'";
    }

    void numberArgument( unsigned long number, char )
    {
        kDebug() << "Number:" << number;
    }

    void stringListArgumentStart()
    {
        kDebug() ;
    }

    void stringListEntry( const QString & string, bool, const QString & )
    {
        kDebug() << "String: '" << string <<"'";
    }

    void stringListArgumentEnd()
    {
        kDebug() ;
    }

private:
    void reset()
    {
        kDebug() ;
    }
};

} // Anon namespace

namespace KMail
{

SieveDebugDialog::SieveDebugDialog( QWidget *parent )
:   KDialog( parent ),
    mSieveJob( 0 )
{
    setCaption( i18n( "Sieve Diagnostics" ) );
    setButtons( Ok );
    // Collect all accounts
    AccountManager *am = kmkernel->acctMgr();
    assert( am );
    QList<KMAccount*>::iterator accountIt = am->begin();
    while ( accountIt != am->end() ) {
      KMAccount *account = *accountIt;
      ++accountIt;
      mAccountList.append( account );
    }

    mEdit = new KTextEdit( this );
    mEdit->setReadOnly( true );
    setMainWidget( mEdit );

    mEdit->setText( i18n( "Collecting diagnostic information about Sieve support...\n\n" ) );

    setInitialSize( QSize( 640, 480 ) );

    if ( !mAccountList.isEmpty() )
        QTimer::singleShot( 0, this, SLOT( slotDiagNextAccount() ) );
}

SieveDebugDialog::~SieveDebugDialog()
{
    if ( mSieveJob )
    {
        mSieveJob->kill();
        mSieveJob = 0;
    }
    kDebug() ;
}

static KUrl urlFromAccount( const KMail::ImapAccountBase * a ) {
    const SieveConfig sieve = a->sieveConfig();
    if ( !sieve.managesieveSupported() )
        return KUrl();

    KUrl u;
    if ( sieve.reuseConfig() ) {
        // assemble Sieve url from the settings of the account:
        u.setProtocol( "sieve" );
        u.setHost( a->host() );
        u.setUser( a->login() );
        u.setPass( a->passwd() );
        u.setPort( sieve.port() );

        // Translate IMAP LOGIN to PLAIN:
        u.addQueryItem( "x-mech", a->auth() == "*" ? "PLAIN" : a->auth() );
        if ( !a->useSSL() && !a->useTLS() )
            u.addQueryItem( "x-allow-unencrypted", "true" );
    } else {
        u = sieve.alternateURL();
        if ( u.protocol().toLower() == "sieve" && !a->useSSL() && !a->useTLS() && u.queryItem("x-allow-unencrypted").isEmpty() )
            u.addQueryItem( "x-allow-unencrypted", "true" );
    }
    return u;
}

void SieveDebugDialog::slotDiagNextAccount()
{
    if ( mAccountList.isEmpty() )
        return;
#if 0 //Port to akonadi
    KMAccount *acc = mAccountList.first();
    mAccountList.pop_front();

    mEdit->append( i18n( "Collecting data for account '%1'...\n", acc->name() ) );
    mEdit->append( i18n( "------------------------------------------------------------\n" ) );
    mAccountBase = dynamic_cast<KMail::ImapAccountBase *>( acc );
    if ( mAccountBase )
    {
        // Detect URL for this IMAP account
        const KUrl url = urlFromAccount( mAccountBase );
        if ( !url.isValid() )
        {
            mEdit->append( i18n( "(Account does not support Sieve)\n\n" ) );
        } else {
            mUrl = url;

            mSieveJob = SieveJob::list( mUrl );

            connect( mSieveJob, SIGNAL( gotList( KMail::SieveJob *, bool, const QStringList &, const QString & ) ),
                SLOT( slotGetScriptList( KMail::SieveJob *, bool, const QStringList &, const QString & ) ) );

            // Bypass the singleShot timer -- it's fired when we get our data
            return;
        }
    } else {
        mEdit->append( i18n( "(Account is not an IMAP account)\n\n" ) );
    }

    // Handle next account async
    QTimer::singleShot( 0, this, SLOT( slotDiagNextAccount() ) );
#endif
}

void SieveDebugDialog::slotDiagNextScript()
{
    if ( mScriptList.isEmpty() )
    {
        // Continue handling accounts instead
        mScriptList.clear();
        QTimer::singleShot( 0, this, SLOT( slotDiagNextAccount() ) );
        return;
    }

    QString scriptFile = mScriptList.first();
    mScriptList.pop_front();

    mEdit->append( i18n( "Contents of script '%1':\n", scriptFile ) );
    mUrl = urlFromAccount( mAccountBase );
    mUrl.setFileName( scriptFile );

    mSieveJob = SieveJob::get( mUrl );

    connect( mSieveJob, SIGNAL( gotScript( KMail::SieveJob *, bool, const QString &, bool ) ),
        SLOT( slotGetScript( KMail::SieveJob *, bool, const QString &, bool ) ) );
}

void SieveDebugDialog::slotGetScript( SieveJob * /* job */, bool success,
    const QString &script, bool active )
{
    kDebug() << "( ??," << success
                   << ", ?," << active << ")" << endl
                   << "script:" << endl
                   << script;
    mSieveJob = 0; // job deletes itself after returning from this slot!

    if ( script.isEmpty() )
    {
        mEdit->append( i18n( "(This script is empty.)\n\n" ) );
    }
    else
    {
        mEdit->append( i18n(
            "------------------------------------------------------------\n"
            "%1\n"
            "------------------------------------------------------------\n\n", script ) );
    }

    // Fetch next script
    QTimer::singleShot( 0, this, SLOT( slotDiagNextScript() ) );
}

void SieveDebugDialog::slotGetScriptList( SieveJob *job, bool success,
    const QStringList &scriptList, const QString &activeScript )
{
    kDebug() << "Success:" << success <<", List:" << scriptList.join("," ) <<
        ", active:" << activeScript;
    mSieveJob = 0; // job deletes itself after returning from this slot!

    mEdit->append( i18n( "Sieve capabilities:\n" ) );
    const QStringList caps = job->sieveCapabilities();
    if ( caps.isEmpty() )
    {
        mEdit->append( i18n( "(No special capabilities available)" ) );
    }
    else
    {
        for ( QStringList::const_iterator it = caps.constBegin(); it != caps.constEnd(); ++it )
            mEdit->append( "* " + *it + '\n' );
        mEdit->append( "\n" );
    }

    mEdit->append( i18n( "Available Sieve scripts:\n" ) );

    if ( scriptList.isEmpty() )
    {
        mEdit->append( i18n( "(No Sieve scripts available on this server)\n\n" ) );
    }
    else
    {
        mScriptList = scriptList;
        for ( QStringList::const_iterator it = scriptList.begin(); it != scriptList.end(); ++it )
            mEdit->append( "* " + *it + '\n' );
        mEdit->append( "\n" );
        mEdit->append( i18n( "Active script: %1\n\n", activeScript ) );
    }

    // Handle next job: dump scripts for this server
    QTimer::singleShot( 0, this, SLOT( slotDiagNextScript() ) );
}

void SieveDebugDialog::slotDialogOk()
{
    kDebug();
}

void SieveDebugDialog::slotPutActiveResult( SieveJob * job, bool success )
{
    handlePutResult( job, success, true );
}

void SieveDebugDialog::slotPutInactiveResult( SieveJob * job, bool success )
{
    handlePutResult( job, success, false );
}

void SieveDebugDialog::handlePutResult( SieveJob *, bool success, bool activated )
{
    if ( success )
    {
        KMessageBox::information( 0, activated ? i18n(
            "Sieve script installed successfully on the server.\n"
            "Out of Office reply is now active." )
            : i18n( "Sieve script installed successfully on the server.\n"
            "Out of Office reply has been deactivated." ) );
    }

    kDebug() << "( ???," << success <<", ? )";
    mSieveJob = 0; // job deletes itself after returning from this slot!
}

} // namespace KMail

#include "sievedebugdialog.moc"

#endif // NDEBUG

<|endoftext|>


<commit_before>#pragma once

#include <algorithm>
#include <cmath>
#include <cstdint>
#include <tuple>
#include <vector>
#include <cassert>

namespace kdbush {

template <std::uint8_t I, typename T>
struct nth {
    inline static typename std::tuple_element<I, T>::type get(const T &t) {
        return std::get<I>(t);
    }
};

template <typename TPoint, typename TIndex = std::size_t>
class KDBush {

public:
    using TNumber = decltype(nth<0, TPoint>::get(std::declval<TPoint>()));
    static_assert(
        std::is_same<TNumber, decltype(nth<1, TPoint>::get(std::declval<TPoint>()))>::value,
        "point component types must be identical");

    static const std::uint8_t defaultNodeSize = 64;

    KDBush(const std::uint8_t nodeSize_ = defaultNodeSize) : nodeSize(nodeSize_) {
    }

    KDBush(const std::vector<TPoint> &points_, const std::uint8_t nodeSize_ = defaultNodeSize)
        : KDBush(std::begin(points_), std::end(points_), nodeSize_) {
    }

    template <typename TPointIter>
    KDBush(const TPointIter &points_begin,
           const TPointIter &points_end,
           const std::uint8_t nodeSize_ = defaultNodeSize)
        : nodeSize(nodeSize_) {
        fill(points_begin, points_end);
    }

    void fill(const std::vector<TPoint> &points_) {
        fill(std::begin(points_), std::end(points_));
    }

    template <typename TPointIter>
    void fill(const TPointIter &points_begin, const TPointIter &points_end) {
        assert(points.empty());
        const TIndex size = static_cast<TIndex>(std::distance(points_begin, points_end));

        if (size == 0) return;

        points.reserve(size);
        ids.reserve(size);

        TIndex i = 0;
        for (auto p = points_begin; p != points_end; p++) {
            points.emplace_back(nth<0, TPoint>::get(*p), nth<1, TPoint>::get(*p));
            ids.push_back(i++);
        }

        sortKD(0, size - 1, 0);
    }

    template <typename TVisitor>
    void range(const TNumber minX,
               const TNumber minY,
               const TNumber maxX,
               const TNumber maxY,
               const TVisitor &visitor) {
        range(minX, minY, maxX, maxY, visitor, 0, static_cast<TIndex>(ids.size() - 1), 0);
    }

    template <typename TVisitor>
    void within(const TNumber qx, const TNumber qy, const TNumber r, const TVisitor &visitor) {
        within(qx, qy, r, visitor, 0, static_cast<TIndex>(ids.size() - 1), 0);
    }

protected:
    std::vector<TIndex> ids;
    std::vector<std::pair<TNumber, TNumber>> points;

private:
    std::uint8_t nodeSize;

    template <typename TVisitor>
    void range(const TNumber minX,
               const TNumber minY,
               const TNumber maxX,
               const TNumber maxY,
               const TVisitor &visitor,
               const TIndex left,
               const TIndex right,
               const std::uint8_t axis) {

        if (points.empty()) return;

        if (right - left <= nodeSize) {
            for (auto i = left; i <= right; i++) {
                const TNumber x = std::get<0>(points[i]);
                const TNumber y = std::get<1>(points[i]);
                if (x >= minX && x <= maxX && y >= minY && y <= maxY) visitor(ids[i]);
            }
            return;
        }

        const TIndex m = (left + right) >> 1;
        const TNumber x = std::get<0>(points[m]);
        const TNumber y = std::get<1>(points[m]);

        if (x >= minX && x <= maxX && y >= minY && y <= maxY) visitor(ids[m]);

        if (axis == 0 ? minX <= x : minY <= y)
            range(minX, minY, maxX, maxY, visitor, left, m - 1, (axis + 1) % 2);

        if (axis == 0 ? maxX >= x : maxY >= y)
            range(minX, minY, maxX, maxY, visitor, m + 1, right, (axis + 1) % 2);
    }

    template <typename TVisitor>
    void within(const TNumber qx,
                const TNumber qy,
                const TNumber r,
                const TVisitor &visitor,
                const TIndex left,
                const TIndex right,
                const std::uint8_t axis) {

        if (points.empty()) return;

        const TNumber r2 = r * r;

        if (right - left <= nodeSize) {
            for (auto i = left; i <= right; i++) {
                const TNumber x = std::get<0>(points[i]);
                const TNumber y = std::get<1>(points[i]);
                if (sqDist(x, y, qx, qy) <= r2) visitor(ids[i]);
            }
            return;
        }

        const TIndex m = (left + right) >> 1;
        const TNumber x = std::get<0>(points[m]);
        const TNumber y = std::get<1>(points[m]);

        if (sqDist(x, y, qx, qy) <= r2) visitor(ids[m]);

        if (axis == 0 ? qx - r <= x : qy - r <= y)
            within(qx, qy, r, visitor, left, m - 1, (axis + 1) % 2);

        if (axis == 0 ? qx + r >= x : qy + r >= y)
            within(qx, qy, r, visitor, m + 1, right, (axis + 1) % 2);
    }

    void sortKD(const TIndex left, const TIndex right, const std::uint8_t axis) {
        if (right - left <= nodeSize) return;
        const TIndex m = (left + right) >> 1;
        if (axis == 0) {
            select<0>(m, left, right);
        } else {
            select<1>(m, left, right);
        }
        sortKD(left, m - 1, (axis + 1) % 2);
        sortKD(m + 1, right, (axis + 1) % 2);
    }

    template <std::uint8_t I>
    void select(const TIndex k, TIndex left, TIndex right) {

        while (right > left) {
            if (right - left > 600) {
                const double n = right - left + 1;
                const double m = k - left + 1;
                const double z = std::log(n);
                const double s = 0.5 * std::exp(2 * z / 3);
                const double r =
                    k - m * s / n + 0.5 * std::sqrt(z * s * (1 - s / n)) * (2 * m < n ? -1 : 1);
                select<I>(k, std::max(left, TIndex(r)), std::min(right, TIndex(r + s)));
            }

            const TNumber t = std::get<I>(points[k]);
            TIndex i = left;
            TIndex j = right;

            swapItem(left, k);
            if (std::get<I>(points[right]) > t) swapItem(left, right);

            while (i < j) {
                swapItem(i++, j--);
                while (std::get<I>(points[i]) < t) i++;
                while (std::get<I>(points[j]) > t) j--;
            }

            if (std::get<I>(points[left]) == t)
                swapItem(left, j);
            else {
                swapItem(++j, right);
            }

            if (j <= k) left = j + 1;
            if (k <= j) right = j - 1;
        }
    }

    void swapItem(const TIndex i, const TIndex j) {
        std::iter_swap(ids.begin() + static_cast<std::int32_t>(i), ids.begin() + static_cast<std::int32_t>(j));
        std::iter_swap(points.begin() + static_cast<std::int32_t>(i), points.begin() + static_cast<std::int32_t>(j));
    }

    TNumber sqDist(const TNumber ax, const TNumber ay, const TNumber bx, const TNumber by) {
        auto dx = ax - bx;
        auto dy = ay - by;
        return dx * dx + dy * dy;
    }
};

} // namespace kdbush
<commit_msg>mark search methods as const<commit_after>#pragma once

#include <algorithm>
#include <cmath>
#include <cstdint>
#include <tuple>
#include <vector>
#include <cassert>

namespace kdbush {

template <std::uint8_t I, typename T>
struct nth {
    inline static typename std::tuple_element<I, T>::type get(const T &t) {
        return std::get<I>(t);
    }
};

template <typename TPoint, typename TIndex = std::size_t>
class KDBush {

public:
    using TNumber = decltype(nth<0, TPoint>::get(std::declval<TPoint>()));
    static_assert(
        std::is_same<TNumber, decltype(nth<1, TPoint>::get(std::declval<TPoint>()))>::value,
        "point component types must be identical");

    static const std::uint8_t defaultNodeSize = 64;

    KDBush(const std::uint8_t nodeSize_ = defaultNodeSize) : nodeSize(nodeSize_) {
    }

    KDBush(const std::vector<TPoint> &points_, const std::uint8_t nodeSize_ = defaultNodeSize)
        : KDBush(std::begin(points_), std::end(points_), nodeSize_) {
    }

    template <typename TPointIter>
    KDBush(const TPointIter &points_begin,
           const TPointIter &points_end,
           const std::uint8_t nodeSize_ = defaultNodeSize)
        : nodeSize(nodeSize_) {
        fill(points_begin, points_end);
    }

    void fill(const std::vector<TPoint> &points_) {
        fill(std::begin(points_), std::end(points_));
    }

    template <typename TPointIter>
    void fill(const TPointIter &points_begin, const TPointIter &points_end) {
        assert(points.empty());
        const TIndex size = static_cast<TIndex>(std::distance(points_begin, points_end));

        if (size == 0) return;

        points.reserve(size);
        ids.reserve(size);

        TIndex i = 0;
        for (auto p = points_begin; p != points_end; p++) {
            points.emplace_back(nth<0, TPoint>::get(*p), nth<1, TPoint>::get(*p));
            ids.push_back(i++);
        }

        sortKD(0, size - 1, 0);
    }

    template <typename TVisitor>
    void range(const TNumber minX,
               const TNumber minY,
               const TNumber maxX,
               const TNumber maxY,
               const TVisitor &visitor) const {
        range(minX, minY, maxX, maxY, visitor, 0, static_cast<TIndex>(ids.size() - 1), 0);
    }

    template <typename TVisitor>
    void within(const TNumber qx, const TNumber qy, const TNumber r, const TVisitor &visitor) const {
        within(qx, qy, r, visitor, 0, static_cast<TIndex>(ids.size() - 1), 0);
    }

protected:
    std::vector<TIndex> ids;
    std::vector<std::pair<TNumber, TNumber>> points;

private:
    const std::uint8_t nodeSize;

    template <typename TVisitor>
    void range(const TNumber minX,
               const TNumber minY,
               const TNumber maxX,
               const TNumber maxY,
               const TVisitor &visitor,
               const TIndex left,
               const TIndex right,
               const std::uint8_t axis) const {

        if (points.empty()) return;

        if (right - left <= nodeSize) {
            for (auto i = left; i <= right; i++) {
                const TNumber x = std::get<0>(points[i]);
                const TNumber y = std::get<1>(points[i]);
                if (x >= minX && x <= maxX && y >= minY && y <= maxY) visitor(ids[i]);
            }
            return;
        }

        const TIndex m = (left + right) >> 1;
        const TNumber x = std::get<0>(points[m]);
        const TNumber y = std::get<1>(points[m]);

        if (x >= minX && x <= maxX && y >= minY && y <= maxY) visitor(ids[m]);

        if (axis == 0 ? minX <= x : minY <= y)
            range(minX, minY, maxX, maxY, visitor, left, m - 1, (axis + 1) % 2);

        if (axis == 0 ? maxX >= x : maxY >= y)
            range(minX, minY, maxX, maxY, visitor, m + 1, right, (axis + 1) % 2);
    }

    template <typename TVisitor>
    void within(const TNumber qx,
                const TNumber qy,
                const TNumber r,
                const TVisitor &visitor,
                const TIndex left,
                const TIndex right,
                const std::uint8_t axis) const {

        if (points.empty()) return;

        const TNumber r2 = r * r;

        if (right - left <= nodeSize) {
            for (auto i = left; i <= right; i++) {
                const TNumber x = std::get<0>(points[i]);
                const TNumber y = std::get<1>(points[i]);
                if (sqDist(x, y, qx, qy) <= r2) visitor(ids[i]);
            }
            return;
        }

        const TIndex m = (left + right) >> 1;
        const TNumber x = std::get<0>(points[m]);
        const TNumber y = std::get<1>(points[m]);

        if (sqDist(x, y, qx, qy) <= r2) visitor(ids[m]);

        if (axis == 0 ? qx - r <= x : qy - r <= y)
            within(qx, qy, r, visitor, left, m - 1, (axis + 1) % 2);

        if (axis == 0 ? qx + r >= x : qy + r >= y)
            within(qx, qy, r, visitor, m + 1, right, (axis + 1) % 2);
    }

    void sortKD(const TIndex left, const TIndex right, const std::uint8_t axis) {
        if (right - left <= nodeSize) return;
        const TIndex m = (left + right) >> 1;
        if (axis == 0) {
            select<0>(m, left, right);
        } else {
            select<1>(m, left, right);
        }
        sortKD(left, m - 1, (axis + 1) % 2);
        sortKD(m + 1, right, (axis + 1) % 2);
    }

    template <std::uint8_t I>
    void select(const TIndex k, TIndex left, TIndex right) {

        while (right > left) {
            if (right - left > 600) {
                const double n = right - left + 1;
                const double m = k - left + 1;
                const double z = std::log(n);
                const double s = 0.5 * std::exp(2 * z / 3);
                const double r =
                    k - m * s / n + 0.5 * std::sqrt(z * s * (1 - s / n)) * (2 * m < n ? -1 : 1);
                select<I>(k, std::max(left, TIndex(r)), std::min(right, TIndex(r + s)));
            }

            const TNumber t = std::get<I>(points[k]);
            TIndex i = left;
            TIndex j = right;

            swapItem(left, k);
            if (std::get<I>(points[right]) > t) swapItem(left, right);

            while (i < j) {
                swapItem(i++, j--);
                while (std::get<I>(points[i]) < t) i++;
                while (std::get<I>(points[j]) > t) j--;
            }

            if (std::get<I>(points[left]) == t)
                swapItem(left, j);
            else {
                swapItem(++j, right);
            }

            if (j <= k) left = j + 1;
            if (k <= j) right = j - 1;
        }
    }

    void swapItem(const TIndex i, const TIndex j) {
        std::iter_swap(ids.begin() + static_cast<std::int32_t>(i), ids.begin() + static_cast<std::int32_t>(j));
        std::iter_swap(points.begin() + static_cast<std::int32_t>(i), points.begin() + static_cast<std::int32_t>(j));
    }

    TNumber sqDist(const TNumber ax, const TNumber ay, const TNumber bx, const TNumber by) const {
        auto dx = ax - bx;
        auto dy = ay - by;
        return dx * dx + dy * dy;
    }
};

} // namespace kdbush
<|endoftext|>


<commit_before><commit_msg>early return if platform not found<commit_after><|endoftext|>