<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2014 <NAME>
 *
 * 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
 *
 *****************************************************************************/

#ifndef MAPNIK_GEOMETRY_TO_WKB_HPP
#define MAPNIK_GEOMETRY_TO_WKB_HPP

// mapnik
#include <mapnik/config.hpp>
#include <mapnik/make_unique.hpp>
#include <mapnik/geometry.hpp>

#include <mapnik/vertex.hpp>

// stl
#include <sstream>
#include <vector>
#include <cstdio>
#include <cstring>
#include <memory>
#include <cassert>

namespace mapnik { namespace util {

std::string to_hex(const char* blob, unsigned size)
{
    std::string buf;
    buf.reserve(size*2);
    std::ostringstream s(buf);
    s.seekp(0);
    char hex[3];
    std::memset(hex,0,3);
    for ( unsigned pos=0; pos < size; ++pos)
    {
        std::sprintf (hex, "%02x", int(blob[pos]) & 0xff);
        s << hex;
    }
    return s.str();
}

inline void reverse_bytes(char size, char *address)
{
    char * first = address;
    char * last = first + size - 1;
    for(;first < last;++first, --last)
    {
        char x = *last;
        *last = *first;
        *first = x;
    }
}

struct wkb_stream
{
    wkb_stream(char * buffer, std::size_t size)
        : buffer_(buffer),
          size_(size),
          pos_(0) {}

    void write(char const* data, std::size_t size)
    {
        std::copy(data, data + size, buffer_ + pos_);
        pos_ += size;
    }

    bool good()
    {
        return (pos_ <= size_) ? true : false;
    }

    char * buffer_;
    std::streamsize size_;
    std::streamsize pos_;
};

template <typename S, typename T>
inline void write (S & stream, T val, std::size_t size, wkbByteOrder byte_order)
{
    bool need_swap =  byte_order ? wkbXDR : wkbNDR;
    char* buf = reinterpret_cast<char*>(&val);
    if (need_swap)
    {
        reverse_bytes(size,buf);
    }
    stream.write(buf,size);
}

struct wkb_buffer
{
    wkb_buffer(std::size_t size)
        : size_(size),
          data_( (size_!=0) ? static_cast<char*>(::operator new (size_)):0)
    {}

    ~wkb_buffer()
    {
        ::operator delete(data_);
    }

    inline std::size_t size() const
    {
        return size_;
    }

    inline char* buffer()
    {
        return data_;
    }

    std::size_t size_;
    char * data_;
};

using wkb_buffer_ptr = std::unique_ptr<wkb_buffer>;

template<typename GeometryType>
wkb_buffer_ptr to_point_wkb( GeometryType const& g, wkbByteOrder byte_order)
{
    assert(g.size() == 1);
    std::size_t size = 1 + 4 + 8*2 ; // byteOrder + wkbType + Point
    wkb_buffer_ptr wkb = std::make_unique<wkb_buffer>(size);
    wkb_stream ss(wkb->buffer(), wkb->size());
    ss.write(reinterpret_cast<char*>(&byte_order),1);
    int type = static_cast<int>(mapnik::new_geometry::geometry_types::Point);
    write(ss,type,4,byte_order);
    double x = 0;
    double y = 0;
    g.vertex(0,&x,&y);
    write(ss,x,8,byte_order);
    write(ss,y,8,byte_order);
    assert(ss.good());
    return std::move(wkb);
}

template<typename GeometryType>
wkb_buffer_ptr to_line_string_wkb( GeometryType const& g, wkbByteOrder byte_order)
{
    unsigned num_points = g.size();
    assert(num_points > 1);
    std::size_t size = 1 + 4 + 4 + 8*2*num_points ; // byteOrder + wkbType + numPoints + Point*numPoints
    wkb_buffer_ptr wkb = std::make_unique<wkb_buffer>(size);
    wkb_stream ss(wkb->buffer(), wkb->size());
    ss.write(reinterpret_cast<char*>(&byte_order),1);
    int type = static_cast<int>(mapnik::new_geometry::geometry_types::LineString);
    write(ss,type,4,byte_order);
    write(ss,num_points,4,byte_order);
    double x = 0;
    double y = 0;
    for (unsigned i=0; i< num_points; ++i)
    {
        g.vertex(i,&x,&y);
        write(ss,x,8,byte_order);
        write(ss,y,8,byte_order);
    }
    assert(ss.good());
    return std::move(wkb);
}

template<typename GeometryType>
wkb_buffer_ptr to_polygon_wkb( GeometryType const& g, wkbByteOrder byte_order)
{
    unsigned num_points = g.size();
    assert(num_points > 1);

    using point_type = std::pair<double,double>;
    using linear_ring = std::vector<point_type>;
    std::vector<linear_ring> rings;

    double x = 0;
    double y = 0;
    std::size_t size = 1 + 4 + 4 ; // byteOrder + wkbType + numRings
    for (unsigned i=0; i< num_points; ++i)
    {
        unsigned command = g.vertex(i,&x,&y);
        if (command == SEG_MOVETO)
        {
            linear_ring ring;
            ring.reserve(1);
            ring.emplace_back(x,y);
            rings.push_back(std::move(ring)); // start new loop
            size += 4; // num_points
            size += 2 * 8; // point
        }
        else if (command == SEG_LINETO)
        {
            rings.back().emplace_back(x,y);
            size += 2 * 8; // point
        }
    }
    unsigned num_rings = rings.size();
    wkb_buffer_ptr wkb = std::make_unique<wkb_buffer>(size);
    wkb_stream ss(wkb->buffer(), wkb->size());
    ss.write(reinterpret_cast<char*>(&byte_order),1);
    int type = static_cast<int>(mapnik::new_geometry::geometry_types::Polygon);
    write(ss,type,4,byte_order);
    write(ss,num_rings,4,byte_order);

    for ( linear_ring const& ring : rings)
    {
        unsigned num_ring_points = ring.size();
        write(ss,num_ring_points,4,byte_order);
        for ( point_type const& pt : ring)
        {
            write(ss,pt.first,8,byte_order);
            write(ss,pt.second,8,byte_order);
        }
    }

    assert(ss.good());
    return std::move(wkb);
}

template<typename GeometryType>
wkb_buffer_ptr to_wkb(GeometryType const& g, wkbByteOrder byte_order )
{
    wkb_buffer_ptr wkb;
    vertex_adapter va(g);
    switch (va.type())
    {
    case mapnik::new_geometry::geometry_types::Point:
        wkb = to_point_wkb(va, byte_order);
        break;
    case mapnik::new_geometry::geometry_types::LineString:
        wkb = to_line_string_wkb(va, byte_order);
        break;
    case mapnik::new_geometry::geometry_types::Polygon:
        wkb = to_polygon_wkb(va, byte_order);
        break;
    default:
        break;
    }
    return wkb;
}

wkb_buffer_ptr to_wkb(geometry_container const& paths, wkbByteOrder byte_order )
{
    if (paths.size() == 1)
    {
        // single geometry
        return to_wkb(paths.front(), byte_order);
    }

    if (paths.size() > 1)
    {
        // multi geometry or geometry collection
        std::vector<wkb_buffer_ptr> wkb_cont;
        bool collection = false;
        int multi_type = 0;
        size_t multi_size = 1 + 4 + 4;

        for (auto const& geom : paths)
        {
            wkb_buffer_ptr wkb = to_wkb(geom,byte_order);
            multi_size += wkb->size();
            int type = static_cast<int>(geom.type());
            if (multi_type > 0 && multi_type != geom.type())
                collection = true;
            multi_type = type;
            wkb_cont.push_back(std::move(wkb));
        }

        wkb_buffer_ptr multi_wkb = std::make_unique<wkb_buffer>(multi_size);
        wkb_stream ss(multi_wkb->buffer(), multi_wkb->size());
        ss.write(reinterpret_cast<char*>(&byte_order),1);
        multi_type = collection ? 7 : multi_type + 3;
        write(ss,multi_type, 4, byte_order);
        write(ss,paths.size(),4,byte_order);

        for ( wkb_buffer_ptr const& wkb : wkb_cont)
        {
            ss.write(wkb->buffer(),wkb->size());
        }
        return std::move(multi_wkb);
    }

    return wkb_buffer_ptr();
}
}}

#endif // MAPNIK_GEOMETRY_TO_WKB_HPP
<commit_msg>mapnik-geometry based to_wkb() implementation<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2015 <NAME>
 *
 * 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
 *
 *****************************************************************************/

#ifndef MAPNIK_GEOMETRY_TO_WKB_HPP
#define MAPNIK_GEOMETRY_TO_WKB_HPP

// mapnik
#include <mapnik/config.hpp>
#include <mapnik/make_unique.hpp>
#include <mapnik/wkb.hpp>
#include <mapnik/geometry_impl.hpp>
#include <mapnik/geometry_type.hpp>

// stl
#include <sstream>
#include <vector>
#include <cstdio>
#include <cstring>
#include <memory>
#include <cassert>

namespace mapnik { namespace util { namespace detail {

std::string to_hex(const char* blob, unsigned size)
{
    std::string buf;
    buf.reserve(size * 2);
    std::ostringstream s(buf);
    s.seekp(0);
    char hex[3];
    std::memset(hex, 0, 3);
    for ( unsigned pos = 0; pos < size; ++pos)
    {
        std::sprintf (hex, "%02x", int(blob[pos]) & 0xff);
        s << hex;
    }
    return s.str();
}

inline void reverse_bytes(char size, char *address)
{
    char * first = address;
    char * last = first + size - 1;
    for(;first < last;++first, --last)
    {
        char x = *last;
        *last = *first;
        *first = x;
    }
}

struct wkb_stream
{
    wkb_stream(char * buffer, std::size_t size)
        : buffer_(buffer),
          size_(size),
          pos_(0) {}

    void write(char const* data, std::size_t size)
    {
        std::copy(data, data + size, buffer_ + pos_);
        pos_ += size;
    }

    bool good()
    {
        return (pos_ <= size_) ? true : false;
    }

    char * buffer_;
    std::streamsize size_;
    std::streamsize pos_;
};

template <typename S, typename T>
inline void write (S & stream, T val, std::size_t size, wkbByteOrder byte_order)
{
    bool need_swap =  byte_order ? wkbXDR : wkbNDR;
    char* buf = reinterpret_cast<char*>(&val);
    if (need_swap)
    {
        reverse_bytes(size,buf);
    }
    stream.write(buf,size);
}

struct wkb_buffer
{
    wkb_buffer(std::size_t size)
        : size_(size),
          data_( (size_ != 0) ? static_cast<char*>(::operator new (size_)) : 0)
    {}

    ~wkb_buffer()
    {
        ::operator delete(data_);
    }

    inline std::size_t size() const
    {
        return size_;
    }

    inline char* buffer()
    {
        return data_;
    }

    std::size_t size_;
    char * data_;
};

using wkb_buffer_ptr = std::unique_ptr<wkb_buffer>;

wkb_buffer_ptr point_wkb( new_geometry::point const& pt, wkbByteOrder byte_order)
{
    std::size_t size = 1 + 4 + 8 * 2 ; // byteOrder + wkbType + Point
    wkb_buffer_ptr wkb = std::make_unique<wkb_buffer>(size);
    wkb_stream ss(wkb->buffer(), wkb->size());
    ss.write(reinterpret_cast<char*>(&byte_order),1);
    write(ss, static_cast<int>(new_geometry::geometry_types::Point), 4 , byte_order);
    write(ss, pt.x, 8, byte_order);
    write(ss, pt.y, 8, byte_order);
    assert(ss.good());
    return std::move(wkb);
}

wkb_buffer_ptr line_string_wkb(new_geometry::line_string const& line, wkbByteOrder byte_order)
{
    unsigned num_points = line.size();
    assert(num_points > 1);
    std::size_t size = 1 + 4 + 4 + 8 * 2 * num_points ; // byteOrder + wkbType + numPoints + Point*numPoints
    wkb_buffer_ptr wkb = std::make_unique<wkb_buffer>(size);
    wkb_stream ss(wkb->buffer(), wkb->size());
    ss.write(reinterpret_cast<char*>(&byte_order),1);
    write(ss, static_cast<int>(mapnik::new_geometry::geometry_types::LineString) , 4, byte_order);
    write(ss, num_points, 4, byte_order);
    for (unsigned i=0; i< num_points; ++i)
    {
        new_geometry::point const& pt = line[i];
        write(ss, pt.x, 8, byte_order);
        write(ss, pt.y, 8, byte_order);
    }
    assert(ss.good());
    return std::move(wkb);
}

wkb_buffer_ptr polygon_wkb( new_geometry::polygon const& poly, wkbByteOrder byte_order)
{
    std::size_t size = 1 + 4 + 4 ; // byteOrder + wkbType + numRings
    size += 4 + 2 * 8 * poly.exterior_ring.size();
    for ( auto const& ring : poly.interior_rings)
    {

        size += 4 + 2 * 8 * ring.size();
    }

    wkb_buffer_ptr wkb = std::make_unique<wkb_buffer>(size);
    wkb_stream ss(wkb->buffer(), wkb->size());
    ss.write(reinterpret_cast<char*>(&byte_order),1);
    write(ss, static_cast<int>(mapnik::new_geometry::geometry_types::Polygon), 4, byte_order);
    write(ss, poly.num_rings(), 4, byte_order);

    // exterior
    write(ss, poly.exterior_ring.size(), 4, byte_order);
    for (auto const& pt : poly.exterior_ring)
    {
        write(ss, pt.x, 8, byte_order);
        write(ss, pt.y, 8, byte_order);
    }
    // interiors
    for (auto const& ring : poly.interior_rings)
    {
        write(ss, ring.size(), 4, byte_order);
        for ( auto const& pt : ring)
        {
            write(ss, pt.x, 8, byte_order);
            write(ss, pt.y, 8, byte_order);
        }
    }

    assert(ss.good());
    return std::move(wkb);
}

wkb_buffer_ptr multi_point_wkb( new_geometry::multi_point const& multi_pt, wkbByteOrder byte_order)
{
    std::size_t size = 1 + 4 + (1 + 4 + 8 * 2) * multi_pt.size() ; // byteOrder + wkbType + Point.size * num_points
    wkb_buffer_ptr wkb = std::make_unique<wkb_buffer>(size);
    wkb_stream ss(wkb->buffer(), wkb->size());
    ss.write(reinterpret_cast<char*>(&byte_order),1);
    write(ss, static_cast<int>(new_geometry::geometry_types::MultiPoint), 4, byte_order);
    write(ss, multi_pt.size(), 4 ,byte_order);
    for (auto const& pt : multi_pt)
    {
        ss.write(reinterpret_cast<char*>(&byte_order),1);
        write(ss, static_cast<int>(new_geometry::geometry_types::Point), 4, byte_order);
        write(ss, pt.x, 8, byte_order);
        write(ss, pt.y, 8, byte_order);
    }
    assert(ss.good());
    return std::move(wkb);
}


template <typename MultiGeometry>
    wkb_buffer_ptr multi_geom_wkb(MultiGeometry const& multi_geom, wkbByteOrder byte_order);

struct geometry_to_wkb
{
    using result_type = wkb_buffer_ptr;

    geometry_to_wkb(wkbByteOrder byte_order)
        : byte_order_(byte_order) {}

    result_type operator() (new_geometry::geometry const& geom) const
    {
        return util::apply_visitor(*this, geom);
    }

    result_type operator() (new_geometry::point const& pt) const
    {
        return point_wkb(pt, byte_order_);
    }

    result_type operator() (new_geometry::line_string const& line) const
    {
        return line_string_wkb(line, byte_order_);
    }

    result_type operator() (new_geometry::polygon const& poly) const
    {
        return polygon_wkb(poly, byte_order_);
    }

    // multi/collection

    //result_type operator() (new_geometry::multi_point const& multi_pt) const
    //{
    //    return multi_point_wkb(multi_pt, byte_order_);
    //}

    template <typename Geometry>
    result_type operator() (Geometry const& geom) const
    {
        return multi_geom_wkb(geom, byte_order_);
    }

    wkbByteOrder byte_order_;
};

template <typename MultiGeometry>
wkb_buffer_ptr multi_geom_wkb(MultiGeometry const& multi_geom, wkbByteOrder byte_order)
{
    size_t multi_size = 1 + 4 + 4;
    std::vector<wkb_buffer_ptr> wkb_cont;
    for (auto const& geom : multi_geom)
    {
        wkb_buffer_ptr wkb = geometry_to_wkb(byte_order)(geom);
        multi_size += wkb->size();
        wkb_cont.push_back(std::move(wkb));
    }
    wkb_buffer_ptr multi_wkb = std::make_unique<wkb_buffer>(multi_size);
    wkb_stream ss(multi_wkb->buffer(), multi_wkb->size());
    ss.write(reinterpret_cast<char*>(&byte_order),1);
    write(ss, static_cast<int>(new_geometry::detail::geometry_type()(multi_geom)) , 4, byte_order);
    write(ss, multi_geom.size(), 4 ,byte_order);

    for ( wkb_buffer_ptr const& wkb : wkb_cont)
    {
        ss.write(wkb->buffer(), wkb->size());
    }

    return std::move(multi_wkb);
}
} // ns detail

using wkb_buffer_ptr = detail::wkb_buffer_ptr;

template<typename GeometryType>
wkb_buffer_ptr to_wkb(GeometryType const& geom, wkbByteOrder byte_order )
{
    return std::move(detail::geometry_to_wkb(byte_order)(geom));
}

}}

#endif // MAPNIK_GEOMETRY_TO_WKB_HPP

{'fraction_non_alphanumeric': 0.14904488184404574, 'fraction_numerical': 0.010102769552342798, 'mean_word_length': 3.145367027677497, 'pattern_counts': {'":': 0, '<': 89, '<?xml version=': 0, '>': 105, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7235105', 'n_tokens_mistral': 6058, 'n_tokens_neox': 5847, 'n_words': 1340}