<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
 *
 *****************************************************************************/

#ifndef MAPNIK_HARFBUZZ_SHAPER_HPP
#define MAPNIK_HARFBUZZ_SHAPER_HPP

// mapnik
#include <mapnik/text/text_properties.hpp>
#include <mapnik/text/text_line.hpp>
#include <mapnik/text/face.hpp>
#include <mapnik/text/font_feature_settings.hpp>
#include <mapnik/text/itemizer.hpp>
#include <mapnik/safe_cast.hpp>
#include <mapnik/font_engine_freetype.hpp>

// stl
#include <list>
#include <type_traits>

// harfbuzz
#include <harfbuzz/hb.h>
#include <harfbuzz/hb-ft.h>

// icu
#include <unicode/uscript.h>

namespace mapnik
{

static inline hb_script_t _icu_script_to_script(UScriptCode script)
{
    if (script == USCRIPT_INVALID_CODE) return HB_SCRIPT_INVALID;
        return hb_script_from_string(uscript_getShortName(script), -1);
}

static inline const uint16_t * uchar_to_utf16(const UChar* src)
{
   static_assert(sizeof(UChar) == sizeof(uint16_t),"UChar is eq size to uint16_t");
#if defined(_MSC_VER)
   return reinterpret_cast<const uint16_t *>(src);
#else
   return src;
#endif
}

struct harfbuzz_shaper
{
static void shape_text(text_line & line,
                       text_itemizer & itemizer,
                       std::map<unsigned,double> & width_map,
                       face_manager_freetype & font_manager,
                       double scale_factor)
{
    unsigned start = line.first_char();
    unsigned end = line.last_char();
    std::size_t length = end - start;
    if (!length) return;

    std::list<text_item> const& list = itemizer.itemize(start, end);

    line.reserve(length);

    auto hb_buffer_deleter = [](hb_buffer_t * buffer) { hb_buffer_destroy(buffer);};
    const std::unique_ptr<hb_buffer_t, decltype(hb_buffer_deleter)> buffer(hb_buffer_create(),hb_buffer_deleter);
    hb_buffer_pre_allocate(buffer.get(), safe_cast<int>(length));
    mapnik::value_unicode_string const& text = itemizer.text();

    for (auto const& text_item : list)
    {
        face_set_ptr face_set = font_manager.get_face_set(text_item.format_->face_name, text_item.format_->fontset);
        double size = text_item.format_->text_size * scale_factor;
        face_set->set_unscaled_character_sizes();
        std::size_t num_faces = face_set->size();
        std::size_t pos = 0;
        font_feature_settings const& ff_settings = text_item.format_->ff_settings;
        int ff_count = safe_cast<int>(ff_settings.count());

        struct glyph_face_info
        {
            face_ptr face;
            hb_glyph_info_t glyph;
            hb_glyph_position_t position;
        };
        std::vector<glyph_face_info> glyphinfos;
        unsigned valid_glyphs = 0;

        for (auto const& face : *face_set)
        {
            ++pos;
            hb_buffer_clear_contents(buffer.get());
            hb_buffer_add_utf16(buffer.get(), uchar_to_utf16(text.getBuffer()), text.length(), text_item.start, static_cast<int>(text_item.end - text_item.start));
            hb_buffer_set_direction(buffer.get(), (text_item.dir == UBIDI_RTL)?HB_DIRECTION_RTL:HB_DIRECTION_LTR);
            hb_buffer_set_script(buffer.get(), _icu_script_to_script(text_item.script));
            hb_font_t *font(hb_ft_font_create(face->get_face(), nullptr));
            // https://github.com/mapnik/test-data-visual/pull/25
            #if HB_VERSION_MAJOR > 0
             #if HB_VERSION_ATLEAST(1, 0 , 5)
            hb_ft_font_set_load_flags(font,FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING);
             #endif
            #endif
            hb_shape(font, buffer.get(), ff_settings.get_features(), ff_count);
            hb_font_destroy(font);

            unsigned num_glyphs = hb_buffer_get_length(buffer.get());

            if (num_glyphs > glyphinfos.size())
            {
                glyphinfos.resize(num_glyphs);
            }

            hb_glyph_info_t *glyphs = hb_buffer_get_glyph_infos(buffer.get(), nullptr);
            hb_glyph_position_t *positions = hb_buffer_get_glyph_positions(buffer.get(), nullptr);

            // Check if all glyphs are valid.
            for (unsigned i=0; i<num_glyphs; ++i)
            {
                if (glyphs[i].codepoint && !glyphinfos[i].glyph.codepoint)
                {
                    glyphinfos[i] = { face, glyphs[i], positions[i] };
                    ++valid_glyphs;
                }
            }
            if (valid_glyphs < num_glyphs && (pos < num_faces))
            {
                //Try next font in fontset
                continue;
            }

            double max_glyph_height = 0;
            for (unsigned i=0; i<num_glyphs; ++i)
            {
                glyph_face_info const* gfi = glyphinfos[i].glyph.codepoint ? &glyphinfos[i] : nullptr;
                auto const& gpos = gfi ? gfi->position : positions[i];
                auto const& glyph = gfi ? gfi->glyph : glyphs[i];
                auto const& theface = gfi ? gfi->face : face;
                unsigned char_index = glyph.cluster;
                glyph_info g(glyph.codepoint,char_index,text_item.format_);
                if (theface->glyph_dimensions(g))
                {
                    g.face = theface;
                    g.scale_multiplier = size / theface->get_face()->units_per_EM;
                    //Overwrite default advance with better value provided by HarfBuzz
                    g.unscaled_advance = gpos.x_advance;
                    g.offset.set(gpos.x_offset * g.scale_multiplier, gpos.y_offset * g.scale_multiplier);
                    double tmp_height = g.height();
                    if (tmp_height > max_glyph_height) max_glyph_height = tmp_height;
                    width_map[char_index] += g.advance();
                    line.add_glyph(std::move(g), scale_factor);
                }
            }
            line.update_max_char_height(max_glyph_height);
            break; //When we reach this point the current font had all glyphs.
        }
    }
}
};
} // namespace mapnik

#endif // MAPNIK_HARFBUZZ_SHAPER_HPP
<commit_msg>less ternaries<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
 *
 *****************************************************************************/

#ifndef MAPNIK_HARFBUZZ_SHAPER_HPP
#define MAPNIK_HARFBUZZ_SHAPER_HPP

// mapnik
#include <mapnik/text/text_properties.hpp>
#include <mapnik/text/text_line.hpp>
#include <mapnik/text/face.hpp>
#include <mapnik/text/font_feature_settings.hpp>
#include <mapnik/text/itemizer.hpp>
#include <mapnik/safe_cast.hpp>
#include <mapnik/font_engine_freetype.hpp>

// stl
#include <list>
#include <type_traits>

// harfbuzz
#include <harfbuzz/hb.h>
#include <harfbuzz/hb-ft.h>

// icu
#include <unicode/uscript.h>

namespace mapnik
{

static inline hb_script_t _icu_script_to_script(UScriptCode script)
{
    if (script == USCRIPT_INVALID_CODE) return HB_SCRIPT_INVALID;
        return hb_script_from_string(uscript_getShortName(script), -1);
}

static inline const uint16_t * uchar_to_utf16(const UChar* src)
{
   static_assert(sizeof(UChar) == sizeof(uint16_t),"UChar is eq size to uint16_t");
#if defined(_MSC_VER)
   return reinterpret_cast<const uint16_t *>(src);
#else
   return src;
#endif
}

struct harfbuzz_shaper
{
static void shape_text(text_line & line,
                       text_itemizer & itemizer,
                       std::map<unsigned,double> & width_map,
                       face_manager_freetype & font_manager,
                       double scale_factor)
{
    unsigned start = line.first_char();
    unsigned end = line.last_char();
    std::size_t length = end - start;
    if (!length) return;

    std::list<text_item> const& list = itemizer.itemize(start, end);

    line.reserve(length);

    auto hb_buffer_deleter = [](hb_buffer_t * buffer) { hb_buffer_destroy(buffer);};
    const std::unique_ptr<hb_buffer_t, decltype(hb_buffer_deleter)> buffer(hb_buffer_create(),hb_buffer_deleter);
    hb_buffer_pre_allocate(buffer.get(), safe_cast<int>(length));
    mapnik::value_unicode_string const& text = itemizer.text();

    for (auto const& text_item : list)
    {
        face_set_ptr face_set = font_manager.get_face_set(text_item.format_->face_name, text_item.format_->fontset);
        double size = text_item.format_->text_size * scale_factor;
        face_set->set_unscaled_character_sizes();
        std::size_t num_faces = face_set->size();
        std::size_t pos = 0;
        font_feature_settings const& ff_settings = text_item.format_->ff_settings;
        int ff_count = safe_cast<int>(ff_settings.count());

        struct glyph_face_info
        {
            face_ptr face;
            hb_glyph_info_t glyph;
            hb_glyph_position_t position;
        };
        std::vector<glyph_face_info> glyphinfos;
        unsigned valid_glyphs = 0;

        for (auto const& face : *face_set)
        {
            ++pos;
            hb_buffer_clear_contents(buffer.get());
            hb_buffer_add_utf16(buffer.get(), uchar_to_utf16(text.getBuffer()), text.length(), text_item.start, static_cast<int>(text_item.end - text_item.start));
            hb_buffer_set_direction(buffer.get(), (text_item.dir == UBIDI_RTL)?HB_DIRECTION_RTL:HB_DIRECTION_LTR);
            hb_buffer_set_script(buffer.get(), _icu_script_to_script(text_item.script));
            hb_font_t *font(hb_ft_font_create(face->get_face(), nullptr));
            // https://github.com/mapnik/test-data-visual/pull/25
            #if HB_VERSION_MAJOR > 0
             #if HB_VERSION_ATLEAST(1, 0 , 5)
            hb_ft_font_set_load_flags(font,FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING);
             #endif
            #endif
            hb_shape(font, buffer.get(), ff_settings.get_features(), ff_count);
            hb_font_destroy(font);

            unsigned num_glyphs = hb_buffer_get_length(buffer.get());

            if (num_glyphs > glyphinfos.size())
            {
                glyphinfos.resize(num_glyphs);
            }

            hb_glyph_info_t *glyphs = hb_buffer_get_glyph_infos(buffer.get(), nullptr);
            hb_glyph_position_t *positions = hb_buffer_get_glyph_positions(buffer.get(), nullptr);

            // Check if all glyphs are valid.
            for (unsigned i=0; i<num_glyphs; ++i)
            {
                if (glyphs[i].codepoint && !glyphinfos[i].glyph.codepoint)
                {
                    glyphinfos[i] = { face, glyphs[i], positions[i] };
                    ++valid_glyphs;
                }
            }
            if (valid_glyphs < num_glyphs && (pos < num_faces))
            {
                //Try next font in fontset
                continue;
            }

            double max_glyph_height = 0;
            for (unsigned i=0; i<num_glyphs; ++i)
            {
                auto& gpos = positions[i];
                auto& glyph = glyphs[i];
                face_ptr theface = face;
                if (glyphinfos[i].glyph.codepoint)
                {
                    gpos = glyphinfos[i].position;
                    glyph = glyphinfos[i].glyph;
                    theface = glyphinfos[i].face;
                }
                unsigned char_index = glyph.cluster;
                glyph_info g(glyph.codepoint,char_index,text_item.format_);
                if (theface->glyph_dimensions(g))
                {
                    g.face = theface;
                    g.scale_multiplier = size / theface->get_face()->units_per_EM;
                    //Overwrite default advance with better value provided by HarfBuzz
                    g.unscaled_advance = gpos.x_advance;
                    g.offset.set(gpos.x_offset * g.scale_multiplier, gpos.y_offset * g.scale_multiplier);
                    double tmp_height = g.height();
                    if (tmp_height > max_glyph_height) max_glyph_height = tmp_height;
                    width_map[char_index] += g.advance();
                    line.add_glyph(std::move(g), scale_factor);
                }
            }
            line.update_max_char_height(max_glyph_height);
            break; //When we reach this point the current font had all glyphs.
        }
    }
}
};
} // namespace mapnik

#endif // MAPNIK_HARFBUZZ_SHAPER_HPP
<|endoftext|>


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

//$Id$

#ifndef MAPNIK_GEOMETRY_TO_WKB_HPP
#define MAPNIK_GEOMETRY_TO_WKB_HPP

// mapnik
#include <mapnik/global.hpp>
#include <mapnik/geometry.hpp>
// boost
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/interprocess/streams/bufferstream.hpp>
#include <boost/foreach.hpp>
// stl
#include <vector>
#include <cstdio>

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();
}

enum wkbByteOrder {
    wkbXDR=0,
    wkbNDR=1
};

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;
    }
}

template <typename S, typename T>
inline void write (S & stream, T val, std::size_t size, wkbByteOrder byte_order)
{
#ifdef MAPNIK_BIG_ENDIAN
    bool need_swap =  byte_order ? wkbNDR : wkbXDR;
#else
    bool need_swap =  byte_order ? wkbXDR : wkbNDR;
#endif
    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_;
};

typedef boost::shared_ptr<wkb_buffer> wkb_buffer_ptr;

wkb_buffer_ptr to_point_wkb( geometry_type const& g, wkbByteOrder byte_order)
{
    assert(g.num_points() == 1);
    std::size_t size = 1 + 4 + 8*2 ; // byteOrder + wkbType + Point
    wkb_buffer_ptr wkb = boost::make_shared<wkb_buffer>(size);
    boost::interprocess::bufferstream ss(wkb->buffer(), wkb->size(), std::ios::out | std::ios::binary);
    ss.write(reinterpret_cast<char*>(&byte_order),1);
    int type = static_cast<int>(mapnik::Point);
    write(ss,type,4,byte_order);
    double x,y;
    g.get_vertex(0,&x,&y);
    write(ss,x,8,byte_order);
    write(ss,y,8,byte_order);
    assert(ss.good());
    return wkb;
}

wkb_buffer_ptr to_line_string_wkb( geometry_type const& g, wkbByteOrder byte_order)
{
    unsigned num_points = g.num_points();
    assert(num_points > 1);
    std::size_t size = 1 + 4 + 4 + 8*2*num_points ; // byteOrder + wkbType + numPoints + Point*numPoints
    wkb_buffer_ptr wkb = boost::make_shared<wkb_buffer>(size);
    boost::interprocess::bufferstream ss(wkb->buffer(), wkb->size(), std::ios::out | std::ios::binary);
    ss.write(reinterpret_cast<char*>(&byte_order),1);
    int type = static_cast<int>(mapnik::LineString);
    write(ss,type,4,byte_order);
    write(ss,num_points,4,byte_order);
    double x,y;
    for (unsigned i=0; i< num_points; ++i)
    {
        g.get_vertex(i,&x,&y);
        write(ss,x,8,byte_order);
        write(ss,y,8,byte_order);
    }
    assert(ss.good());
    return wkb;
}

wkb_buffer_ptr to_polygon_wkb( geometry_type const& g, wkbByteOrder byte_order)
{
    unsigned num_points = g.num_points();
    assert(num_points > 1);

    typedef std::pair<double,double> point_type;
    typedef std::vector<point_type> linear_ring;
    boost::ptr_vector<linear_ring> rings;

    double x,y;
    std::size_t size = 1 + 4 + 4 ; // byteOrder + wkbType + numRings
    for (unsigned i=0; i< num_points; ++i)
    {
        unsigned command = g.get_vertex(i,&x,&y);
        if (command == SEG_MOVETO)
        {
            rings.push_back(new linear_ring); // start new loop
            size += 4; // num_points
        }
        rings.back().push_back(std::make_pair(x,y));
        size += 2 * 8; // point
    }
    unsigned num_rings = rings.size();
    wkb_buffer_ptr wkb = boost::make_shared<wkb_buffer>(size);
    boost::interprocess::bufferstream ss(wkb->buffer(), wkb->size(), std::ios::out | std::ios::binary);

    ss.write(reinterpret_cast<char*>(&byte_order),1);
    int type = static_cast<int>(mapnik::Polygon);
    write(ss,type,4,byte_order);
    write(ss,num_rings,4,byte_order);

    BOOST_FOREACH ( linear_ring const& ring, rings)
    {
        unsigned num_points = ring.size();
        write(ss,num_points,4,byte_order);
        BOOST_FOREACH ( point_type const& pt, ring)
        {
            double x = pt.first;
            double y = pt.second;
            write(ss,x,8,byte_order);
            write(ss,y,8,byte_order);
        }
    }

    assert(ss.good());
    return wkb;
}

wkb_buffer_ptr to_wkb(geometry_type const& g, wkbByteOrder byte_order )
{
    wkb_buffer_ptr wkb;

    switch (g.type())
    {
    case mapnik::Point :
        wkb = to_point_wkb(g, byte_order);
        break;
    case mapnik::LineString:
        wkb = to_line_string_wkb(g, byte_order);
        break;
    case mapnik::Polygon:
        wkb = to_polygon_wkb(g, 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;
        geometry_container::const_iterator itr = paths.begin();
        geometry_container::const_iterator end = paths.end();
        for ( ; itr!=end; ++itr)
        {
            wkb_buffer_ptr wkb = to_wkb(*itr,byte_order);
            multi_size += wkb->size();
            int type = static_cast<int>(itr->type());
            if (multi_type > 0 && multi_type != itr->type())
                collection = true;
            multi_type = type;
            wkb_cont.push_back(wkb);
        }

        wkb_buffer_ptr multi_wkb = boost::make_shared<wkb_buffer>(multi_size);
        boost::interprocess::bufferstream ss(multi_wkb->buffer(), multi_wkb->size(), std::ios::out | std::ios::binary);
        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);

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

    return wkb_buffer_ptr();
}

}}

#endif // MAPNIK_GEOMETRY_TO_WKB_HPP
<commit_msg>formatting<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2011 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
 *
 *****************************************************************************/

//$Id$

#ifndef MAPNIK_GEOMETRY_TO_WKB_HPP
#define MAPNIK_GEOMETRY_TO_WKB_HPP

// mapnik
#include <mapnik/global.hpp>
#include <mapnik/geometry.hpp>
// boost
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/interprocess/streams/bufferstream.hpp>
#include <boost/foreach.hpp>
// stl
#include <vector>
#include <cstdio>

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();
}

enum wkbByteOrder {
    wkbXDR=0,
    wkbNDR=1
};

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;
    }
}

template <typename S, typename T>
inline void write (S & stream, T val, std::size_t size, wkbByteOrder byte_order)
{
#ifdef MAPNIK_BIG_ENDIAN
    bool need_swap =  byte_order ? wkbNDR : wkbXDR;
#else
    bool need_swap =  byte_order ? wkbXDR : wkbNDR;
#endif
    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_;
};

typedef boost::shared_ptr<wkb_buffer> wkb_buffer_ptr;

wkb_buffer_ptr to_point_wkb( geometry_type const& g, wkbByteOrder byte_order)
{
    assert(g.num_points() == 1);
    std::size_t size = 1 + 4 + 8*2 ; // byteOrder + wkbType + Point
    wkb_buffer_ptr wkb = boost::make_shared<wkb_buffer>(size);
    boost::interprocess::bufferstream ss(wkb->buffer(), wkb->size(), std::ios::out | std::ios::binary);
    ss.write(reinterpret_cast<char*>(&byte_order),1);
    int type = static_cast<int>(mapnik::Point);
    write(ss,type,4,byte_order);
    double x,y;
    g.get_vertex(0,&x,&y);
    write(ss,x,8,byte_order);
    write(ss,y,8,byte_order);
    assert(ss.good());
    return wkb;
}

wkb_buffer_ptr to_line_string_wkb( geometry_type const& g, wkbByteOrder byte_order)
{
    unsigned num_points = g.num_points();
    assert(num_points > 1);
    std::size_t size = 1 + 4 + 4 + 8*2*num_points ; // byteOrder + wkbType + numPoints + Point*numPoints
    wkb_buffer_ptr wkb = boost::make_shared<wkb_buffer>(size);
    boost::interprocess::bufferstream ss(wkb->buffer(), wkb->size(), std::ios::out | std::ios::binary);
    ss.write(reinterpret_cast<char*>(&byte_order),1);
    int type = static_cast<int>(mapnik::LineString);
    write(ss,type,4,byte_order);
    write(ss,num_points,4,byte_order);
    double x,y;
    for (unsigned i=0; i< num_points; ++i)
    {
        g.get_vertex(i,&x,&y);
        write(ss,x,8,byte_order);
        write(ss,y,8,byte_order);
    }
    assert(ss.good());
    return wkb;
}

wkb_buffer_ptr to_polygon_wkb( geometry_type const& g, wkbByteOrder byte_order)
{
    unsigned num_points = g.num_points();
    assert(num_points > 1);

    typedef std::pair<double,double> point_type;
    typedef std::vector<point_type> linear_ring;
    boost::ptr_vector<linear_ring> rings;

    double x,y;
    std::size_t size = 1 + 4 + 4 ; // byteOrder + wkbType + numRings
    for (unsigned i=0; i< num_points; ++i)
    {
        unsigned command = g.get_vertex(i,&x,&y);
        if (command == SEG_MOVETO)
        {
            rings.push_back(new linear_ring); // start new loop
            size += 4; // num_points
        }
        rings.back().push_back(std::make_pair(x,y));
        size += 2 * 8; // point
    }
    unsigned num_rings = rings.size();
    wkb_buffer_ptr wkb = boost::make_shared<wkb_buffer>(size);
    boost::interprocess::bufferstream ss(wkb->buffer(), wkb->size(), std::ios::out | std::ios::binary);

    ss.write(reinterpret_cast<char*>(&byte_order),1);
    int type = static_cast<int>(mapnik::Polygon);
    write(ss,type,4,byte_order);
    write(ss,num_rings,4,byte_order);

    BOOST_FOREACH ( linear_ring const& ring, rings)
    {
        unsigned num_points = ring.size();
        write(ss,num_points,4,byte_order);
        BOOST_FOREACH ( point_type const& pt, ring)
        {
            double x = pt.first;
            double y = pt.second;
            write(ss,x,8,byte_order);
            write(ss,y,8,byte_order);
        }
    }

    assert(ss.good());
    return wkb;
}

wkb_buffer_ptr to_wkb(geometry_type const& g, wkbByteOrder byte_order )
{
    wkb_buffer_ptr wkb;

    switch (g.type())
    {
    case mapnik::Point:
        wkb = to_point_wkb(g, byte_order);
        break;
    case mapnik::LineString:
        wkb = to_line_string_wkb(g, byte_order);
        break;
    case mapnik::Polygon:
        wkb = to_polygon_wkb(g, 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;
        geometry_container::const_iterator itr = paths.begin();
        geometry_container::const_iterator end = paths.end();
        for ( ; itr!=end; ++itr)
        {
            wkb_buffer_ptr wkb = to_wkb(*itr,byte_order);
            multi_size += wkb->size();
            int type = static_cast<int>(itr->type());
            if (multi_type > 0 && multi_type != itr->type())
                collection = true;
            multi_type = type;
            wkb_cont.push_back(wkb);
        }

        wkb_buffer_ptr multi_wkb = boost::make_shared<wkb_buffer>(multi_size);
        boost::interprocess::bufferstream ss(multi_wkb->buffer(), multi_wkb->size(), std::ios::out | std::ios::binary);
        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);

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

    return wkb_buffer_ptr();
}

}}

#endif // MAPNIK_GEOMETRY_TO_WKB_HPP
<|endoftext|>


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

#ifndef MAPNIK_GEOMETRY_TO_WKB_HPP
#define MAPNIK_GEOMETRY_TO_WKB_HPP

// mapnik
#include <mapnik/global.hpp>
#include <mapnik/geometry.hpp>

// boost
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/interprocess/streams/bufferstream.hpp>
#include <boost/foreach.hpp>

// stl
#include <vector>
#include <cstdio>

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();
}

enum wkbByteOrder {
    wkbXDR=0,
    wkbNDR=1
};

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;
    }
}

template <typename S, typename T>
inline void write (S & stream, T val, std::size_t size, wkbByteOrder byte_order)
{
#ifdef MAPNIK_BIG_ENDIAN
    bool need_swap =  byte_order ? wkbNDR : wkbXDR;
#else
    bool need_swap =  byte_order ? wkbXDR : wkbNDR;
#endif
    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_;
};

typedef boost::shared_ptr<wkb_buffer> wkb_buffer_ptr;

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 = boost::make_shared<wkb_buffer>(size);
    boost::interprocess::bufferstream ss(wkb->buffer(), wkb->size(), std::ios::out | std::ios::binary);
    ss.write(reinterpret_cast<char*>(&byte_order),1);
    int type = static_cast<int>(mapnik::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 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 = boost::make_shared<wkb_buffer>(size);
    boost::interprocess::bufferstream ss(wkb->buffer(), wkb->size(), std::ios::out | std::ios::binary);
    ss.write(reinterpret_cast<char*>(&byte_order),1);
    int type = static_cast<int>(mapnik::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 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);

    typedef std::pair<double,double> point_type;
    typedef std::vector<point_type> linear_ring;
    boost::ptr_vector<linear_ring> rings;

    double x = 0;
    double y = 0;
    double start_x = 0;
    double start_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)
        {
            rings.push_back(new linear_ring); // start new loop
            rings.back().push_back(std::make_pair(x,y));
            size += 4; // num_points
            size += 2 * 8; // point
        }
        else if (command == SEG_LINETO)
        {
            rings.back().push_back(std::make_pair(x,y));
            size += 2 * 8; // point
        }
    }
    unsigned num_rings = rings.size();
    wkb_buffer_ptr wkb = boost::make_shared<wkb_buffer>(size);
    boost::interprocess::bufferstream ss(wkb->buffer(), wkb->size(), std::ios::out | std::ios::binary);

    ss.write(reinterpret_cast<char*>(&byte_order),1);
    int type = static_cast<int>(mapnik::Polygon);
    write(ss,type,4,byte_order);
    write(ss,num_rings,4,byte_order);

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

    assert(ss.good());
    return wkb;
}

template<typename GeometryType>
wkb_buffer_ptr to_wkb(GeometryType const& g, wkbByteOrder byte_order )
{
    wkb_buffer_ptr wkb;

    switch (g.type())
    {
    case mapnik::Point:
        wkb = to_point_wkb(g, byte_order);
        break;
    case mapnik::LineString:
        wkb = to_line_string_wkb(g, byte_order);
        break;
    case mapnik::Polygon:
        wkb = to_polygon_wkb(g, 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;
        geometry_container::const_iterator itr = paths.begin();
        geometry_container::const_iterator end = paths.end();
        for ( ; itr!=end; ++itr)
        {
            wkb_buffer_ptr wkb = to_wkb(*itr,byte_order);
            multi_size += wkb->size();
            int type = static_cast<int>(itr->type());
            if (multi_type > 0 && multi_type != itr->type())
                collection = true;
            multi_type = type;
            wkb_cont.push_back(wkb);
        }

        wkb_buffer_ptr multi_wkb = boost::make_shared<wkb_buffer>(multi_size);
        boost::interprocess::bufferstream ss(multi_wkb->buffer(), multi_wkb->size(), std::ios::out | std::ios::binary);
        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);

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

    return wkb_buffer_ptr();
}
}}

#endif // MAPNIK_GEOMETRY_TO_WKB_HPP
<commit_msg>+ remove unused vars<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2011 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
 *
 *****************************************************************************/

#ifndef MAPNIK_GEOMETRY_TO_WKB_HPP
#define MAPNIK_GEOMETRY_TO_WKB_HPP

// mapnik
#include <mapnik/global.hpp>
#include <mapnik/geometry.hpp>

// boost
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/interprocess/streams/bufferstream.hpp>
#include <boost/foreach.hpp>

// stl
#include <vector>
#include <cstdio>

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();
}

enum wkbByteOrder {
    wkbXDR=0,
    wkbNDR=1
};

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;
    }
}

template <typename S, typename T>
inline void write (S & stream, T val, std::size_t size, wkbByteOrder byte_order)
{
#ifdef MAPNIK_BIG_ENDIAN
    bool need_swap =  byte_order ? wkbNDR : wkbXDR;
#else
    bool need_swap =  byte_order ? wkbXDR : wkbNDR;
#endif
    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_;
};

typedef boost::shared_ptr<wkb_buffer> wkb_buffer_ptr;

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 = boost::make_shared<wkb_buffer>(size);
    boost::interprocess::bufferstream ss(wkb->buffer(), wkb->size(), std::ios::out | std::ios::binary);
    ss.write(reinterpret_cast<char*>(&byte_order),1);
    int type = static_cast<int>(mapnik::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 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 = boost::make_shared<wkb_buffer>(size);
    boost::interprocess::bufferstream ss(wkb->buffer(), wkb->size(), std::ios::out | std::ios::binary);
    ss.write(reinterpret_cast<char*>(&byte_order),1);
    int type = static_cast<int>(mapnik::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 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);

    typedef std::pair<double,double> point_type;
    typedef std::vector<point_type> linear_ring;
    boost::ptr_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)
        {
            rings.push_back(new linear_ring); // start new loop
            rings.back().push_back(std::make_pair(x,y));
            size += 4; // num_points
            size += 2 * 8; // point
        }
        else if (command == SEG_LINETO)
        {
            rings.back().push_back(std::make_pair(x,y));
            size += 2 * 8; // point
        }
    }
    unsigned num_rings = rings.size();
    wkb_buffer_ptr wkb = boost::make_shared<wkb_buffer>(size);
    boost::interprocess::bufferstream ss(wkb->buffer(), wkb->size(), std::ios::out | std::ios::binary);

    ss.write(reinterpret_cast<char*>(&byte_order),1);
    int type = static_cast<int>(mapnik::Polygon);
    write(ss,type,4,byte_order);
    write(ss,num_rings,4,byte_order);

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

    assert(ss.good());
    return wkb;
}

template<typename GeometryType>
wkb_buffer_ptr to_wkb(GeometryType const& g, wkbByteOrder byte_order )
{
    wkb_buffer_ptr wkb;

    switch (g.type())
    {
    case mapnik::Point:
        wkb = to_point_wkb(g, byte_order);
        break;
    case mapnik::LineString:
        wkb = to_line_string_wkb(g, byte_order);
        break;
    case mapnik::Polygon:
        wkb = to_polygon_wkb(g, 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;
        geometry_container::const_iterator itr = paths.begin();
        geometry_container::const_iterator end = paths.end();
        for ( ; itr!=end; ++itr)
        {
            wkb_buffer_ptr wkb = to_wkb(*itr,byte_order);
            multi_size += wkb->size();
            int type = static_cast<int>(itr->type());
            if (multi_type > 0 && multi_type != itr->type())
                collection = true;
            multi_type = type;
            wkb_cont.push_back(wkb);
        }

        wkb_buffer_ptr multi_wkb = boost::make_shared<wkb_buffer>(multi_size);
        boost::interprocess::bufferstream ss(multi_wkb->buffer(), multi_wkb->size(), std::ios::out | std::ios::binary);
        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);

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

    return wkb_buffer_ptr();
}
}}

#endif // MAPNIK_GEOMETRY_TO_WKB_HPP
<|endoftext|>


<commit_before>#pragma once

#include <limits>

#include "rapidcheck/detail/Utility.h"

namespace rc {
namespace detail {

template <typename T>
constexpr int numBits() {
  return std::numeric_limits<T>::digits + (std::is_signed<T>::value ? 1 : 0);
}

template <typename Source>
BitStream<Source>::BitStream(Source source)
    : m_source(source)
    , m_bits(0)
    , m_numBits(0) {}

template <typename Source>
template <typename T>
T BitStream<Source>::next() {
  return next<T>(numBits<T>());
}

template <typename Source>
template <typename T>
T BitStream<Source>::next(int nbits) {
  return next<T>(nbits, std::is_same<T, bool>());
}

template <typename Source>
template <typename T>
T BitStream<Source>::next(int /*nbits*/, std::true_type) {
  return next<unsigned int>(1) != 0;
}

template <typename Source>
template <typename T>
T BitStream<Source>::next(int nbits, std::false_type) {
  using SourceType = decltype(m_source.next());

  if (nbits == 0) {
    return 0;
  }

  T value = 0;
  int wantBits = nbits;
  while (wantBits > 0) {
    // Out of bits, refill
    if (m_numBits == 0) {
      m_bits = m_source.next();
      m_numBits += numBits<SourceType>();
    }

    const auto n = std::min(m_numBits, wantBits);
    const auto bits = m_bits & bitMask<SourceType>(n);
    value |= (bits << (nbits - wantBits));
    m_bits >>= static_cast<SourceType>(n);
    m_numBits -= n;
    wantBits -= n;
  }

  if (std::is_signed<T>::value) {
    T signBit = static_cast<T>(0x1) << static_cast<T>(nbits - 1);
    if ((value & signBit) != 0) {
      // For signed values, we use the last bit as the sign bit. Since this
      // was 1, mask away by setting all bits above this one to 1 to make it a
      // negative number in 2's complement
      value |= ~bitMask<T>(nbits);
    }
  }

  return value;
}

template <typename Source>
template <typename T>
T BitStream<Source>::nextWithSize(int size) {
  return next<T>((size * numBits<T>() + (kNominalSize / 2)) / kNominalSize);
}

template <typename Source>
BitStream<Source &> bitStreamOf(Source &source) {
  return BitStream<Source &>(source);
}

/// Returns a bitstream with the given source as a copy.
template <typename Source>
BitStream<Source> bitStreamOf(const Source &source) {
  return BitStream<Source>(source);
}

} // namespace detail
} // namespace rc
<commit_msg>Avoid right-shifting past the width a type<commit_after>#pragma once

#include <limits>

#include "rapidcheck/detail/Utility.h"

namespace rc {
namespace detail {

template <typename T>
constexpr int numBits() {
  return std::numeric_limits<T>::digits + (std::is_signed<T>::value ? 1 : 0);
}

template <typename Source>
BitStream<Source>::BitStream(Source source)
    : m_source(source)
    , m_bits(0)
    , m_numBits(0) {}

template <typename Source>
template <typename T>
T BitStream<Source>::next() {
  return next<T>(numBits<T>());
}

template <typename Source>
template <typename T>
T BitStream<Source>::next(int nbits) {
  return next<T>(nbits, std::is_same<T, bool>());
}

template <typename Source>
template <typename T>
T BitStream<Source>::next(int /*nbits*/, std::true_type) {
  return next<unsigned int>(1) != 0;
}

template <typename Source>
template <typename T>
T BitStream<Source>::next(int nbits, std::false_type) {
  using SourceType = decltype(m_source.next());
  auto sourceTypeLength = (sizeof(SourceType) * 8);

  if (nbits == 0) {
    return 0;
  }

  T value = 0;
  int wantBits = nbits;
  while (wantBits > 0) {
    // Out of bits, refill
    if (m_numBits == 0) {
      m_bits = m_source.next();
      m_numBits += numBits<SourceType>();
    }

    const auto n = std::min(m_numBits, wantBits);
    const auto bits = m_bits & bitMask<SourceType>(n);
    value |= (bits << (nbits - wantBits));
    // To avoid right-shifting data beyond the width of the given type (which is
    // undefined behavior, because of course it is) only perform this shift-
    // assignment if we have room.
    if (static_cast<SourceType>(n) < sourceTypeLength) {
      m_bits >>= static_cast<SourceType>(n);
    }
    m_numBits -= n;
    wantBits -= n;
  }

  if (std::is_signed<T>::value) {
    T signBit = static_cast<T>(0x1) << static_cast<T>(nbits - 1);
    if ((value & signBit) != 0) {
      // For signed values, we use the last bit as the sign bit. Since this
      // was 1, mask away by setting all bits above this one to 1 to make it a
      // negative number in 2's complement
      value |= ~bitMask<T>(nbits);
    }
  }

  return value;
}

template <typename Source>
template <typename T>
T BitStream<Source>::nextWithSize(int size) {
  return next<T>((size * numBits<T>() + (kNominalSize / 2)) / kNominalSize);
}

template <typename Source>
BitStream<Source &> bitStreamOf(Source &source) {
  return BitStream<Source &>(source);
}

/// Returns a bitstream with the given source as a copy.
template <typename Source>
BitStream<Source> bitStreamOf(const Source &source) {
  return BitStream<Source>(source);
}

} // namespace detail
} // namespace rc
<|endoftext|>


<commit_before>#include <iostream>
#include <fstream>
#include <cassert>

#include "lru.h"

lru::lru()
  : policy{stats{"",{},0}}
  , map{}
  , queue{}
{
  stat.apps = {};
}

lru::lru(stats stat)
  : policy{stat}
  , map{}
  , queue{}
{
}

lru::~lru () {
}

// Simply returns the current number of bytes cached.
size_t lru::get_bytes_cached() const { return stat.bytes_cached; }

// Public accessors for hits and accesses.
size_t lru::get_hits() { return stat.hits; }
size_t lru::get_accs() { return stat.accesses; }

// Removes a request with matching key from the chain and
// updates bytes_cached accordingly.
// Returns the 'stack distance' which is calc's by summing
// the bytes for all requests in the chain until 'r' is reached.
int64_t lru::remove (const request *r) {

  // If r is not in the map something weird has happened.
  auto it = map.find(r->kid);
  if(it == map.end())
    return -1;

  // Sum the sizes of all requests up until we reach 'r'.
  size_t stack_dist  = 0;
  for ( const auto &i : queue ) {
    if (i.kid != r->kid)
      break;
    stack_dist += i.size();
  }

  // Adjust the local bytes_cached value, remove 'r'
  // from the hash table, and from the LRU chain.
  auto& list_it = it->second;
  stat.bytes_cached -= list_it->size();
  queue.erase(list_it);
  map.erase(it);

  return stack_dist;
}

void lru::expand(size_t bytes) {
  stat.global_mem += bytes;
}

bool lru::would_cause_eviction(const request* r) {
  return (map.find(r->kid) == map.end()) &&
         (stat.bytes_cached + size_t(r->size()) > stat.global_mem);
}

bool lru::would_hit(const request *r) {
  auto it = map.find(r->kid);
  return it != map.end();
}

void lru::add(const request *r) {
  auto it = map.find(r->kid);
  assert(it == map.end());

  // Throw out enough junk to make room for new record.
  while (stat.bytes_cached + size_t(r->size()) > stat.global_mem) {
    // If the queue is already empty, then we are in trouble. The cache
    // just isn't big enough to hold this object under any circumstances.
    // Though, you probably shouldn't be setting the cache size smaller
    // than the max memcache object size.
    //
    // This case can occur when an lru is part of a slab allocator, since
    // initially all lrus start with 0 bytes and expand as the slab pool
    // allows.
    if (queue.empty())
      return;

    request* victim = &queue.back();
    stat.bytes_cached -= victim->size();
    ++stat.evicted_items;
    stat.evicted_bytes += victim->size();
    map.erase(victim->kid);
    queue.pop_back();
  }

  // Add the new request.
  queue.emplace_front(*r);
  map[r->kid] = queue.begin();
  stat.bytes_cached += r->size();
}

bool lru::try_add_tail(const request *r) {
  auto it = map.find(r->kid);
  assert(it == map.end());

  if (stat.bytes_cached + size_t(r->size()) > stat.global_mem)
    return false;

  // Add the new request.
  queue.emplace_back(*r);
  auto back_it = queue.end();
  --back_it;
  map[r->kid] = back_it;
  stat.bytes_cached += r->size();

  return true;
}

// checks the map for membership, if the key is found
// returns a hit, otherwise the key is added to the map
// and to the LRU queue and returns a miss. Returns absolute
// number of bytes added to the cache.
size_t lru::proc(const request *r, bool warmup) {
  assert(r->size() > 0);

  if (stat.apps.empty())
    stat.apps.insert(r->appid);
  //assert(stat.apps.count(r->appid) == 1);

  if (!warmup)
    ++stat.accesses;

  auto it = map.find(r->kid);
  if (it != map.end()) {
    auto list_it = it->second;
    request& prior_request = *list_it;

    if (prior_request.size() == r->size()) {
      // Promote this item to the front.
      queue.erase(list_it);
      queue.emplace_front(*r);
      map[r->kid] = queue.begin();

      if (!warmup)
        stat.hits++;

      return 1;
    } else {
      // If the size changed, then we have to put it in head. Just
      // falling through to the code below handles that. We still
      // count this record as a single hit, even though some miss
      // would have had to have happened to shootdown the old stale
      // sized value. This is to be fair to other policies like gLRU
      // that don't detect these size changes.

      queue.erase(list_it);
      map.erase(prior_request.kid);
      stat.bytes_cached -= prior_request.size();
    }
  } else {
    // If miss in hash table, then count a miss. This get will count
    // as a second access that hits below.
  }

  add(r);

  return PROC_MISS;
}

double lru::get_running_hit_rate() {
  return double(stat.hits) / stat.accesses;
}

double lru::get_running_utilization() {
  size_t in_use = 0;
  for (auto& request : queue)
    in_use += request.size();

  assert(in_use == stat.bytes_cached);

  return double(in_use) / stat.global_mem;
}

std::unordered_map<int32_t, size_t> lru::get_per_app_bytes_in_use() const
{
  std::unordered_map<int32_t, size_t> result{};
  for (auto& request : queue)
    result[request.appid] += request.size();

  return result;
}
<commit_msg>Fix lru so that any size change is counted as a miss.<commit_after>#include <iostream>
#include <fstream>
#include <cassert>

#include "lru.h"

lru::lru()
  : policy{stats{"",{},0}}
  , map{}
  , queue{}
{
  stat.apps = {};
}

lru::lru(stats stat)
  : policy{stat}
  , map{}
  , queue{}
{
}

lru::~lru () {
}

// Simply returns the current number of bytes cached.
size_t lru::get_bytes_cached() const { return stat.bytes_cached; }

// Public accessors for hits and accesses.
size_t lru::get_hits() { return stat.hits; }
size_t lru::get_accs() { return stat.accesses; }

// Removes a request with matching key from the chain and
// updates bytes_cached accordingly.
// Returns the 'stack distance' which is calc's by summing
// the bytes for all requests in the chain until 'r' is reached.
int64_t lru::remove (const request *r) {

  // If r is not in the map something weird has happened.
  auto it = map.find(r->kid);
  if(it == map.end())
    return -1;

  // Sum the sizes of all requests up until we reach 'r'.
  size_t stack_dist  = 0;
  for ( const auto &i : queue ) {
    if (i.kid != r->kid)
      break;
    stack_dist += i.size();
  }

  // Adjust the local bytes_cached value, remove 'r'
  // from the hash table, and from the LRU chain.
  auto& list_it = it->second;
  stat.bytes_cached -= list_it->size();
  queue.erase(list_it);
  map.erase(it);

  return stack_dist;
}

void lru::expand(size_t bytes) {
  stat.global_mem += bytes;
}

bool lru::would_cause_eviction(const request* r) {
  return (map.find(r->kid) == map.end()) &&
         (stat.bytes_cached + size_t(r->size()) > stat.global_mem);
}

bool lru::would_hit(const request *r) {
  auto it = map.find(r->kid);
  return it != map.end();
}

void lru::add(const request *r) {
  auto it = map.find(r->kid);
  assert(it == map.end());

  // Throw out enough junk to make room for new record.
  while (stat.bytes_cached + size_t(r->size()) > stat.global_mem) {
    // If the queue is already empty, then we are in trouble. The cache
    // just isn't big enough to hold this object under any circumstances.
    // Though, you probably shouldn't be setting the cache size smaller
    // than the max memcache object size.
    //
    // This case can occur when an lru is part of a slab allocator, since
    // initially all lrus start with 0 bytes and expand as the slab pool
    // allows.
    if (queue.empty())
      return;

    request* victim = &queue.back();
    stat.bytes_cached -= victim->size();
    ++stat.evicted_items;
    stat.evicted_bytes += victim->size();
    map.erase(victim->kid);
    queue.pop_back();
  }

  // Add the new request.
  queue.emplace_front(*r);
  map[r->kid] = queue.begin();
  stat.bytes_cached += r->size();
}

bool lru::try_add_tail(const request *r) {
  auto it = map.find(r->kid);
  assert(it == map.end());

  if (stat.bytes_cached + size_t(r->size()) > stat.global_mem)
    return false;

  // Add the new request.
  queue.emplace_back(*r);
  auto back_it = queue.end();
  --back_it;
  map[r->kid] = back_it;
  stat.bytes_cached += r->size();

  return true;
}

// checks the map for membership, if the key is found
// returns a hit, otherwise the key is added to the map
// and to the LRU queue and returns a miss. Returns absolute
// number of bytes added to the cache.
size_t lru::proc(const request *r, bool warmup) {
  assert(r->size() > 0);

  if (stat.apps.empty())
    stat.apps.insert(r->appid);
  //assert(stat.apps.count(r->appid) == 1);

  if (!warmup)
    ++stat.accesses;

  auto it = map.find(r->kid);
  if (it != map.end()) {
    auto list_it = it->second;
    request& prior_request = *list_it;

    if (prior_request.size() == r->size() &&
        prior_request.frag_sz == r->frag_sz) {
      // Promote this item to the front.
      queue.erase(list_it);
      queue.emplace_front(*r);
      map[r->kid] = queue.begin();

      if (!warmup)
        stat.hits++;

      return 1;
    } else {
      // If the size changed, then we have to put it in head. Just
      // falling through to the code below handles that. We still
      // count this record as a single hit, even though some miss
      // would have had to have happened to shootdown the old stale
      // sized value. This is to be fair to other policies like gLRU
      // that don't detect these size changes.

      queue.erase(list_it);
      map.erase(prior_request.kid);
      stat.bytes_cached -= prior_request.size();
    }
  } else {
    // If miss in hash table, then count a miss. This get will count
    // as a second access that hits below.
  }

  add(r);

  return PROC_MISS;
}

double lru::get_running_hit_rate() {
  return double(stat.hits) / stat.accesses;
}

double lru::get_running_utilization() {
  size_t in_use = 0;
  for (auto& request : queue)
    in_use += request.size();

  assert(in_use == stat.bytes_cached);

  return double(in_use) / stat.global_mem;
}

std::unordered_map<int32_t, size_t> lru::get_per_app_bytes_in_use() const
{
  std::unordered_map<int32_t, size_t> result{};
  for (auto& request : queue)
    result[request.appid] += request.size();

  return result;
}
<|endoftext|>


<commit_before>#ifndef ORG_EEROS_SOCKET_SERVER_HPP_
#define ORG_EEROS_SOCKET_SERVER_HPP_

#include <eeros/core/Thread.hpp>
#include <atomic>
#include <array>
#include <unistd.h>
#include <netdb.h>
#include <arpa/inet.h> 		/* inet_ntoa() to format IP address */
#include <string.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <eeros/core/Fault.hpp>
#include <iostream>
#include <cstring>
#include <signal.h>

namespace eeros {
	namespace sockets {

		void sigPipeHandler(int signum);

		template < uint32_t BufInLen, typename inT, uint32_t BufOutLen, typename outT >
		class SocketServer : public eeros::Thread {
		public:
			SocketServer(uint16_t port, double period = 0.01, double timeout = 1.0) : read1({0}), read2({0}), read3({0}) {
				this->port = port;
				this->period = period;
				this->timeout = timeout;
				signal(SIGPIPE, sigPipeHandler);	// make sure, that a broken pipe does not stop application
				read_ptr.store(&read1);
				send_ptr.store(&send1);
				running = false;
			}

			virtual ~SocketServer() {
				join();
			}

			virtual void stop() {
				running = false;
			}

			virtual bool isRunning() {
				return running;
			}

			virtual std::array<outT, BufOutLen>& getReceiveBuffer() {
				return *read_ptr.load();
			}

			virtual void setSendBuffer(std::array<inT, BufInLen>& data) {
				auto p = send_ptr.load();
				if (p == &send1) send1 = data;
				else if (p == &send2) send2 = data;
				else if (p == &send3) send3 = data;
			}

			outT readbuffer;
			bool newData = false;

		private:
			virtual void run() {
				log.info() << "SocketServer thread started";
				struct sockaddr_in servAddr;
				sockfd = socket(AF_INET, SOCK_STREAM, 0);
				if (sockfd < 0) throw Fault("ERROR opening socket");

				bzero((char *) &servAddr, sizeof(servAddr));
				servAddr.sin_port = htons(port);
				servAddr.sin_family = AF_INET;
				servAddr.sin_addr.s_addr = htonl(INADDR_ANY) ;
				if (bind(sockfd, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0)
					throw Fault("ERROR on binding");

				socklen_t clilen;
				listen(sockfd,1);
				struct sockaddr_in cliAddr;
				clilen = sizeof(cliAddr);

				running = true;
				while (running) {
					newsockfd = accept(sockfd, (struct sockaddr *) &cliAddr,  &clilen);
					if (newsockfd < 0) throw Fault("ERROR on accept");
					bool connected = true;
					char cliName[INET6_ADDRSTRLEN];
					getnameinfo((struct sockaddr*)&cliAddr, sizeof cliAddr, cliName, sizeof(cliName), NULL, 0, NI_NUMERICHOST|NI_NUMERICSERV);
					log.info() << "Client connection from ip=" << cliName << " accepted";
					inT b_write[BufInLen]; outT b_read[BufOutLen];
					using seconds = std::chrono::duration<double, std::chrono::seconds::period>;
					auto next_cycle = std::chrono::steady_clock::now() + seconds(period);

					while (connected) {
						std::this_thread::sleep_until(next_cycle);

						// write
						std::array<inT, BufInLen> &sendValue = getNextSendBuffer();
						for(int i = 0; i < BufInLen; i++) b_write[i] = sendValue[i];
// 						log.trace() << "try to write " << b_write[0];
						int n = write(newsockfd, b_write, BufInLen * sizeof(inT));
						if (n < 0) {
							log.trace() << "error = " << std::strerror(errno);
							connected = false;
						}

						// read
						size_t count = BufOutLen * sizeof(outT);
						uint8_t* ptr = (uint8_t *)b_read;
						auto endTime = std::chrono::steady_clock::now() + seconds(timeout);
						while (connected && count) {
							if (std::chrono::steady_clock::now() > endTime) {
								log.trace() << "error = socket read timed out";
								connected = false;
							}
// 							log.trace() << "try to read " << count << " Bytes";
							n = read(newsockfd, ptr, count);
							if (n < 0) {
								log.trace() << "error = " << std::strerror(errno);
								connected = false;
							}
							ptr += n;
							count -= n;
						}
						std::array<outT, BufOutLen> &readValue = getNextReceiveBuffer();
						for(int i = 0; i < BufOutLen; i++) readValue[i] = b_read[i];
						flip();
						next_cycle += seconds(period);
					}
					close(newsockfd);
					// if disconnected clear receive buffer
					std::array<outT, BufOutLen> &readValue = getNextReceiveBuffer();
					for(int i = 0; i < BufOutLen; i++) readValue[i] = 0;
					newData = true;
					flip();
				}
				close(sockfd);
			}

			std::array<outT, BufOutLen>& getNextReceiveBuffer() {
				auto p = read_ptr.load();
				if (p == &read1) return read2;
				else if (p == &read2) return read3;
				else if (p == &read3) return read1;
			}

			std::array<inT, BufInLen>& getNextSendBuffer() {
				auto p = send_ptr.load();
				if (p == &send1) return send2;
				else if (p == &send2) return send3;
				else if (p == &send3) return send1;
			}

			void flip(){
				read_ptr.store(&getNextReceiveBuffer());
				send_ptr.store(&getNextSendBuffer());
			}

			bool running;
			uint16_t port;
			double period;
			double timeout;	// time which thread tries to read until socket read timed out
			struct hostent *server;
			int sockfd;
			int newsockfd;

			std::array<outT, BufOutLen> read1, read2, read3;
			std::array<inT, BufInLen> send1, send2, send3;
			std::atomic< std::array<outT, BufOutLen>* > read_ptr;
			std::atomic< std::array<inT, BufInLen>* > send_ptr;
		};

		// specialization used when server doesn't receive data from its client
		template < uint32_t BufInLen, typename inT >
		class SocketServer<BufInLen, inT, 0, std::nullptr_t> : public eeros::Thread {
		public:
			SocketServer(uint16_t port, double period = 0.01) {
				this->port = port;
				this->period = period;
				signal(SIGPIPE, sigPipeHandler);	// make sure, that a broken pipe does not stop application
				send_ptr.store(&send1);
				running = false;
			}

			virtual ~SocketServer() {
				join();
			}

			virtual void stop(){
				running = false;
			}

			virtual bool isRunning() {
				return running;
			}

			virtual void setSendBuffer(std::array<inT, BufInLen>& data) {
				auto p = send_ptr.load();
				if (p == &send1) send1 = data;
				else if (p == &send2) send2 = data;
				else if (p == &send3) send3 = data;
			}

		private:
			virtual void run() {
				log.info() << "SocketServer thread started";
				struct sockaddr_in servAddr;
				sockfd = socket(AF_INET, SOCK_STREAM, 0);
				if (sockfd < 0) throw Fault("ERROR opening socket");

				bzero((char *) &servAddr, sizeof(servAddr));
				servAddr.sin_port = htons(port);
				servAddr.sin_family = AF_INET;
				servAddr.sin_addr.s_addr = htonl(INADDR_ANY) ;
				if (bind(sockfd, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0)
					throw Fault("ERROR on binding");

				socklen_t clilen;
				listen(sockfd,1);
				struct sockaddr_in cliAddr;
				clilen = sizeof(cliAddr);

				running = true;
				while (running) {
					newsockfd = accept(sockfd, (struct sockaddr *) &cliAddr,  &clilen);
					if (newsockfd < 0) throw Fault("ERROR on accept");
					bool connected = true;
					char cliName[INET6_ADDRSTRLEN];
					getnameinfo((struct sockaddr*)&cliAddr, sizeof cliAddr, cliName, sizeof(cliName), NULL, 0, NI_NUMERICHOST|NI_NUMERICSERV);
					log.info() << "Client connection from ip=" << cliName << " accepted";
					inT b_write[BufInLen];
					using seconds = std::chrono::duration<double, std::chrono::seconds::period>;
					auto next_cycle = std::chrono::steady_clock::now() + seconds(period);

					while (connected) {
						std::this_thread::sleep_until(next_cycle);

						// write
						std::array<inT, BufInLen> &sendValue = getNextSendBuffer();
						for(int i = 0; i < BufInLen; i++) b_write[i] = sendValue[i];
// 						log.trace() << "try to write " << b_write[0];
						int n = write(newsockfd, b_write, BufInLen * sizeof(inT));
						if (n < 0) {
							log.trace() << "error = " << std::strerror(errno);
							connected = false;
						}

						flip();
						next_cycle += seconds(period);
					}
					close(newsockfd);
				}
				close(sockfd);
			}

			std::array<inT, BufInLen>& getNextSendBuffer() {
				auto p = send_ptr.load();
				if (p == &send1) return send2;
				else if (p == &send2) return send3;
				else if (p == &send3) return send1;
			}

			void flip(){
				send_ptr.store(&getNextSendBuffer());
			}

			bool running;
			uint16_t port;
			double period;
			struct hostent *server;
			int sockfd;
			int newsockfd;

			std::array<inT, BufInLen> send1, send2, send3;
			std::atomic< std::array<inT, BufInLen>* > send_ptr;
		};

	};
};

#endif // ORG_EEROS_SOCKET_SERVER_HPP_<commit_msg>reuse address for socket<commit_after>#ifndef ORG_EEROS_SOCKET_SERVER_HPP_
#define ORG_EEROS_SOCKET_SERVER_HPP_

#include <eeros/core/Thread.hpp>
#include <atomic>
#include <array>
#include <unistd.h>
#include <netdb.h>
#include <arpa/inet.h> 		/* inet_ntoa() to format IP address */
#include <string.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <eeros/core/Fault.hpp>
#include <iostream>
#include <cstring>
#include <signal.h>

namespace eeros {
	namespace sockets {

		void sigPipeHandler(int signum);

		template < uint32_t BufInLen, typename inT, uint32_t BufOutLen, typename outT >
		class SocketServer : public eeros::Thread {
		public:
			SocketServer(uint16_t port, double period = 0.01, double timeout = 1.0) : read1({0}), read2({0}), read3({0}) {
				this->port = port;
				this->period = period;
				this->timeout = timeout;
				signal(SIGPIPE, sigPipeHandler);	// make sure, that a broken pipe does not stop application
				read_ptr.store(&read1);
				send_ptr.store(&send1);
				running = false;
			}

			virtual ~SocketServer() {
				join();
			}

			virtual void stop() {
				running = false;
			}

			virtual bool isRunning() {
				return running;
			}

			virtual std::array<outT, BufOutLen>& getReceiveBuffer() {
				return *read_ptr.load();
			}

			virtual void setSendBuffer(std::array<inT, BufInLen>& data) {
				auto p = send_ptr.load();
				if (p == &send1) send1 = data;
				else if (p == &send2) send2 = data;
				else if (p == &send3) send3 = data;
			}

			outT readbuffer;
			bool newData = false;

		private:
			virtual void run() {
				log.info() << "SocketServer thread started";
				struct sockaddr_in servAddr;
				sockfd = socket(AF_INET, SOCK_STREAM, 0);
				if (sockfd < 0) throw Fault("ERROR opening socket");

				bzero((char *) &servAddr, sizeof(servAddr));
				servAddr.sin_port = htons(port);
				servAddr.sin_family = AF_INET;
				servAddr.sin_addr.s_addr = htonl(INADDR_ANY) ;
				int yes = 1;
				if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1)
					throw Fault("ERROR on set socket option");
				if (bind(sockfd, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0)
					throw Fault("ERROR on socket binding");

				socklen_t clilen;
				listen(sockfd,1);
				struct sockaddr_in cliAddr;
				clilen = sizeof(cliAddr);

				running = true;
				while (running) {
					newsockfd = accept(sockfd, (struct sockaddr *) &cliAddr,  &clilen);
					if (newsockfd < 0) throw Fault("ERROR on socket accept");
					bool connected = true;
					char cliName[INET6_ADDRSTRLEN];
					getnameinfo((struct sockaddr*)&cliAddr, sizeof cliAddr, cliName, sizeof(cliName), NULL, 0, NI_NUMERICHOST|NI_NUMERICSERV);
					log.info() << "Client connection from ip=" << cliName << " accepted";
					inT b_write[BufInLen]; outT b_read[BufOutLen];
					using seconds = std::chrono::duration<double, std::chrono::seconds::period>;
					auto next_cycle = std::chrono::steady_clock::now() + seconds(period);

					while (connected) {
						std::this_thread::sleep_until(next_cycle);

						// write
						std::array<inT, BufInLen> &sendValue = getNextSendBuffer();
						for(int i = 0; i < BufInLen; i++) b_write[i] = sendValue[i];
// 						log.trace() << "try to write " << b_write[0];
						int n = write(newsockfd, b_write, BufInLen * sizeof(inT));
						if (n < 0) {
							log.trace() << "error = " << std::strerror(errno);
							connected = false;
						}

						// read
						size_t count = BufOutLen * sizeof(outT);
						uint8_t* ptr = (uint8_t *)b_read;
						auto endTime = std::chrono::steady_clock::now() + seconds(timeout);
						while (connected && count) {
							if (std::chrono::steady_clock::now() > endTime) {
								log.trace() << "error = socket read timed out";
								connected = false;
							}
// 							log.trace() << "try to read " << count << " Bytes";
							n = read(newsockfd, ptr, count);
							if (n < 0) {
								log.trace() << "error = " << std::strerror(errno);
								connected = false;
							}
							ptr += n;
							count -= n;
						}
						std::array<outT, BufOutLen> &readValue = getNextReceiveBuffer();
						for(int i = 0; i < BufOutLen; i++) readValue[i] = b_read[i];
						flip();
						next_cycle += seconds(period);
					}
					close(newsockfd);
					// if disconnected clear receive buffer
					std::array<outT, BufOutLen> &readValue = getNextReceiveBuffer();
					for(int i = 0; i < BufOutLen; i++) readValue[i] = 0;
					newData = true;
					flip();
				}
				close(sockfd);
			}

			std::array<outT, BufOutLen>& getNextReceiveBuffer() {
				auto p = read_ptr.load();
				if (p == &read1) return read2;
				else if (p == &read2) return read3;
				else if (p == &read3) return read1;
			}

			std::array<inT, BufInLen>& getNextSendBuffer() {
				auto p = send_ptr.load();
				if (p == &send1) return send2;
				else if (p == &send2) return send3;
				else if (p == &send3) return send1;
			}

			void flip(){
				read_ptr.store(&getNextReceiveBuffer());
				send_ptr.store(&getNextSendBuffer());
			}

			bool running;
			uint16_t port;
			double period;
			double timeout;	// time which thread tries to read until socket read timed out
			struct hostent *server;
			int sockfd;
			int newsockfd;

			std::array<outT, BufOutLen> read1, read2, read3;
			std::array<inT, BufInLen> send1, send2, send3;
			std::atomic< std::array<outT, BufOutLen>* > read_ptr;
			std::atomic< std::array<inT, BufInLen>* > send_ptr;
		};

		// specialization used when server doesn't receive data from its client
		template < uint32_t BufInLen, typename inT >
		class SocketServer<BufInLen, inT, 0, std::nullptr_t> : public eeros::Thread {
		public:
			SocketServer(uint16_t port, double period = 0.01) {
				this->port = port;
				this->period = period;
				signal(SIGPIPE, sigPipeHandler);	// make sure, that a broken pipe does not stop application
				send_ptr.store(&send1);
				running = false;
			}

			virtual ~SocketServer() {
				join();
			}

			virtual void stop(){
				running = false;
			}

			virtual bool isRunning() {
				return running;
			}

			virtual void setSendBuffer(std::array<inT, BufInLen>& data) {
				auto p = send_ptr.load();
				if (p == &send1) send1 = data;
				else if (p == &send2) send2 = data;
				else if (p == &send3) send3 = data;
			}

		private:
			virtual void run() {
				log.info() << "SocketServer thread started";
				struct sockaddr_in servAddr;
				sockfd = socket(AF_INET, SOCK_STREAM, 0);
				if (sockfd < 0) throw Fault("ERROR opening socket");

				bzero((char *) &servAddr, sizeof(servAddr));
				servAddr.sin_port = htons(port);
				servAddr.sin_family = AF_INET;
				servAddr.sin_addr.s_addr = htonl(INADDR_ANY) ;
				if (bind(sockfd, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0)
					throw Fault("ERROR on binding");

				socklen_t clilen;
				listen(sockfd,1);
				struct sockaddr_in cliAddr;
				clilen = sizeof(cliAddr);

				running = true;
				while (running) {
					newsockfd = accept(sockfd, (struct sockaddr *) &cliAddr,  &clilen);
					if (newsockfd < 0) throw Fault("ERROR on accept");
					bool connected = true;
					char cliName[INET6_ADDRSTRLEN];
					getnameinfo((struct sockaddr*)&cliAddr, sizeof cliAddr, cliName, sizeof(cliName), NULL, 0, NI_NUMERICHOST|NI_NUMERICSERV);
					log.info() << "Client connection from ip=" << cliName << " accepted";
					inT b_write[BufInLen];
					using seconds = std::chrono::duration<double, std::chrono::seconds::period>;
					auto next_cycle = std::chrono::steady_clock::now() + seconds(period);

					while (connected) {
						std::this_thread::sleep_until(next_cycle);

						// write
						std::array<inT, BufInLen> &sendValue = getNextSendBuffer();
						for(int i = 0; i < BufInLen; i++) b_write[i] = sendValue[i];
// 						log.trace() << "try to write " << b_write[0];
						int n = write(newsockfd, b_write, BufInLen * sizeof(inT));
						if (n < 0) {
							log.trace() << "error = " << std::strerror(errno);
							connected = false;
						}

						flip();
						next_cycle += seconds(period);
					}
					close(newsockfd);
				}
				close(sockfd);
			}

			std::array<inT, BufInLen>& getNextSendBuffer() {
				auto p = send_ptr.load();
				if (p == &send1) return send2;
				else if (p == &send2) return send3;
				else if (p == &send3) return send1;
			}

			void flip(){
				send_ptr.store(&getNextSendBuffer());
			}

			bool running;
			uint16_t port;
			double period;
			struct hostent *server;
			int sockfd;
			int newsockfd;

			std::array<inT, BufInLen> send1, send2, send3;
			std::atomic< std::array<inT, BufInLen>* > send_ptr;
		};

	};
};

#endif // ORG_EEROS_SOCKET_SERVER_HPP_<|endoftext|>


<commit_before>#include <iostream>
#include <string>
#include <unistd.h>
using namespace std;

int main(){
  char HOSTNAME[128];
  gethostname(HOSTNAME, sizeof HOSTNAME);
  bool REPEAT = true;

  while (REPEAT){
    string input;
    cout << getlogin() << "@" << HOSTNAME << "$ ";
    getline(cin, input);

    if (input == "exit"){
		REPEAT = false;
	}
  }

  return 0;
}
<commit_msg>Delete main.cc<commit_after><|endoftext|>


<commit_before>#include <iostream>
#include "NTClient.h"
#include "NTLogger.h"
using namespace std;

NTClient cli;
void testLogger() {
	NTLogger out = NTLogger("Username");
	out << LOG_INFO;
	out.wr("Test message");
	out << LOG_INFO;
	out << "Here is an integer: ";
	out << (int)3;
	out.ln();
}
void initBot() {
	NTClient nclient = NTClient();
	cout << "Logging account in...\n";
	nclient.login("gfsiosd", "123asd123"); // Throw-away account
	nclient.connect();
}
int main(int argc, char** argv) {
	testLogger();
	//initBot();
	return 0;
}<commit_msg>Stop logger testing<commit_after>#include <iostream>
#include "NTClient.h"
#include "NTLogger.h"
using namespace std;

NTClient cli;
void testLogger() {
	NTLogger out = NTLogger("Username");
	out << LOG_INFO;
	out.wr("Test message");
	out << LOG_INFO;
	out << "Here is an integer: ";
	out << (int)3;
	out.ln();
}
void initBot() {
	NTClient nclient = NTClient();
	cout << "Logging account in...\n";
	nclient.login("gfsiosd", "123asd123"); // Throw-away account
	nclient.connect();
}
int main(int argc, char** argv) {
	// testLogger();
	initBot();
	return 0;
}<|endoftext|>


<commit_before>#include <memory>
#include <iostream>
#include <fstream>

#include <deal.II/base/conditional_ostream.h>
#include <deal.II/base/parameter_handler.h>
#include <deal.II/base/mpi.h>

#include "framework/builder/framework_builder.h"
#include "utility/reporter/mpi.h"
#include "problem/parameters_dealii_handler.h"

int main(int argc, char* argv[]) {
  try {
    if (argc != 2) {
      std::cerr
          << "Call the program as mpirun -np num_proc bart input_file_name"
          << std::endl;
      return 1;
    }

    std::cout << "BAY AREA RADIATION TRANSPORT\n"
              << "Developed at the University of California, Berkeley"
              << std::endl;

    bart::problem::ParametersDealiiHandler prm;
    dealii::ParameterHandler d2_prm;
    const std::string filename{argv[1]};

    prm.SetUp(d2_prm);
    d2_prm.parse_input(filename, "");
    prm.Parse(d2_prm);

    dealii::Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1);

    double k_eff_final;

    const int n_processes = dealii::Utilities::MPI::n_mpi_processes(MPI_COMM_WORLD);
    const int process_id = dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD);

    // Open file for output, if there are multiple processes they will end with
    // a number indicating the process number.
    std::ofstream output_stream, master_output_stream;
    const std::string output_filename_base{prm.OutputFilenameBase()};
    if (n_processes > 1) {
      const std::string full_filename = output_filename_base + dealii::Utilities::int_to_string(process_id, 4);
      output_stream.open((full_filename + ".vtu").c_str());
      master_output_stream.open(output_filename_base + ".pvtu");
    } else {
      output_stream.open((output_filename_base + ".vtu").c_str());
    }
    std::vector<std::string> filenames;
    // Write master pvtu record if multiple files are required
    if ((n_processes > 1) && (process_id == 0)) {
      for (int process = 0; process < n_processes; ++process) {
        const std::string full_filename =
            output_filename_base + dealii::Utilities::int_to_string(process, 4);
        filenames.push_back(full_filename + ".vtu");
      }
    }

    auto reporter_ptr = std::make_shared<bart::utility::reporter::Mpi>(
        std::make_unique<dealii::ConditionalOStream>(std::cout, process_id == 0));
    switch(prm.SpatialDimension()) {
      case 1: {
        bart::framework::builder::FrameworkBuilder<1> builder(reporter_ptr);
        auto framework_ptr = builder.BuildFramework("main", prm);
        framework_ptr->SolveSystem();
        framework_ptr->OutputResults(output_stream);
        if (n_processes > 1)
          framework_ptr->OutputMasterFile(master_output_stream, filenames, process_id);
        k_eff_final = framework_ptr->system()->k_effective.value_or(0);
        break;
      }
      case 2: {
        bart::framework::builder::FrameworkBuilder<2> builder(reporter_ptr);
        auto framework_ptr = builder.BuildFramework("main", prm);
        framework_ptr->SolveSystem();
        framework_ptr->OutputResults(output_stream);
        if (n_processes > 1)
          framework_ptr->OutputMasterFile(master_output_stream, filenames, process_id);
        k_eff_final = framework_ptr->system()->k_effective.value_or(0);
        break;
      }
      case 3: {
        bart::framework::builder::FrameworkBuilder<3> builder(reporter_ptr);
        auto framework_ptr = builder.BuildFramework("main", prm);
        framework_ptr->SolveSystem();
        framework_ptr->OutputResults(output_stream);
        if (n_processes > 1)
          framework_ptr->OutputMasterFile(master_output_stream, filenames, process_id);
        k_eff_final = framework_ptr->system()->k_effective.value_or(0);
        break;
      }
    }

    std::cout << "Final k_effective: " << k_eff_final << std::endl;

  } catch (std::exception &exc) {
    std::cerr << std::endl << std::endl
              << "----------------------------------------------------"
              << std::endl;
    std::cerr << "Exception on processing: " << std::endl
              << exc.what() << std::endl
              << "Aborting!" << std::endl
              << "----------------------------------------------------"
              << std::endl;
    return 1;
  } catch (...) {
    std::cerr << std::endl << std::endl
              << "----------------------------------------------------"
              << std::endl;
    std::cerr << "Unknown exception!" << std::endl
              << "Aborting!" << std::endl
              << "----------------------------------------------------"
              << std::endl;
    return 1;
  }
  return 0;
}
<commit_msg>added output of error vs. iteration data, refactored main<commit_after>#include <memory>
#include <iostream>
#include <fstream>

#include <deal.II/base/conditional_ostream.h>
#include <deal.II/base/parameter_handler.h>
#include <deal.II/base/mpi.h>

#include "framework/builder/framework_builder.h"
#include "utility/reporter/mpi.h"
#include "problem/parameters_dealii_handler.h"

int main(int argc, char* argv[]) {
  try {
    if (argc != 2) {
      std::cerr
          << "Call the program as mpirun -np num_proc bart input_file_name"
          << std::endl;
      return 1;
    }

    std::cout << "BAY AREA RADIATION TRANSPORT\n"
              << "Developed at the University of California, Berkeley"
              << std::endl;

    bart::problem::ParametersDealiiHandler prm;
    dealii::ParameterHandler d2_prm;
    const std::string filename{argv[1]};

    prm.SetUp(d2_prm);
    d2_prm.parse_input(filename, "");
    prm.Parse(d2_prm);

    dealii::Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1);

    double k_eff_final;

    const int n_processes = dealii::Utilities::MPI::n_mpi_processes(MPI_COMM_WORLD);
    const int process_id = dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD);

    // Open file for output, if there are multiple processes they will end with
    // a number indicating the process number.
    std::ofstream output_stream, master_output_stream;
    const std::string output_filename_base{prm.OutputFilenameBase()};
    if (n_processes > 1) {
      const std::string full_filename = output_filename_base + dealii::Utilities::int_to_string(process_id, 4);
      output_stream.open((full_filename + ".vtu").c_str());
      master_output_stream.open(output_filename_base + ".pvtu");
    } else {
      output_stream.open((output_filename_base + ".vtu").c_str());
    }
    std::vector<std::string> filenames;
    // Write master pvtu record if multiple files are required
    if ((n_processes > 1) && (process_id == 0)) {
      for (int process = 0; process < n_processes; ++process) {
        const std::string full_filename =
            output_filename_base + dealii::Utilities::int_to_string(process, 4);
        filenames.push_back(full_filename + ".vtu");
      }
    }

    // Error output file stream
    std::ofstream output_error_stream;
    output_error_stream.open(output_filename_base + "_iteration_error.csv");

    // Framework pointer
    std::unique_ptr<bart::framework::FrameworkI> framework_ptr;

    auto reporter_ptr = std::make_shared<bart::utility::reporter::Mpi>(
        std::make_unique<dealii::ConditionalOStream>(std::cout, process_id == 0));
    switch(prm.SpatialDimension()) {
      case 1: {
        bart::framework::builder::FrameworkBuilder<1> builder(reporter_ptr);
        framework_ptr = builder.BuildFramework("main", prm);
        break;
      }
      case 2: {
        bart::framework::builder::FrameworkBuilder<2> builder(reporter_ptr);
        auto framework_ptr = builder.BuildFramework("main", prm);
        break;
      }
      case 3: {
        bart::framework::builder::FrameworkBuilder<3> builder(reporter_ptr);
        auto framework_ptr = builder.BuildFramework("main", prm);
        break;
      }
    }

    framework_ptr->SolveSystem();
    framework_ptr->OutputResults(output_stream);
    if (n_processes > 1)
      framework_ptr->OutputMasterFile(master_output_stream, filenames, process_id);
    k_eff_final = framework_ptr->system()->k_effective.value_or(0);
    framework_ptr->OutputIterationError(output_error_stream);

    std::cout << "Final k_effective: " << k_eff_final << std::endl;

  } catch (std::exception &exc) {
    std::cerr << std::endl << std::endl
              << "----------------------------------------------------"
              << std::endl;
    std::cerr << "Exception on processing: " << std::endl
              << exc.what() << std::endl
              << "Aborting!" << std::endl
              << "----------------------------------------------------"
              << std::endl;
    return 1;
  } catch (...) {
    std::cerr << std::endl << std::endl
              << "----------------------------------------------------"
              << std::endl;
    std::cerr << "Unknown exception!" << std::endl
              << "Aborting!" << std::endl
              << "----------------------------------------------------"
              << std::endl;
    return 1;
  }
  return 0;
}
<|endoftext|>


<commit_before>#include <fstream>

#include "cpu.h"

int main() {
    using namespace std;

    ifstream rom("../image/rom");
    ifstream flash("../image/kernel");

    CPU cpu(rom, flash);

    cpu.run();

}

<commit_msg>rename flash file<commit_after>#include <fstream>

#include "cpu.h"

int main() {
    using namespace std;

    ifstream rom("../image/rom");
    ifstream flash("../image/disk0");

    CPU cpu(rom, flash);

    cpu.run();

}

<|endoftext|>


<commit_before>#include <bits/stdc++.h>
#include <iostream>
#include <string>
/*add the header if you need*/
using namespace std;

//Abstract base class for Dessert Item hierarchy
class DessertItem
{
private:
    //Name of the DessertItem object
    string name;

public:
    DessertItem(){}
    DessertItem(string name):name(name){}
    //Empty virtual destructor for DessertItem class
    virtual ~DessertItem(){}
    //returns Name of DessertItem
    string getName(){ return name;}
    virtual string getDetails() = 0;
    virtual double getCost() = 0;
};

class IceCream : public DessertItem
{
public:
    /* Write about IceCream Constructor
       IceCream(string name, double cost):DessertItem(name),cost(cost)
    */
    IceCream() {}
    IceCream(string name, double cost):DessertItem(name), cost(cost) {}
    virtual ~IceCream() {}

    /* Write about IceCream other member functions*/
    virtual string getDetails() { return ""; }
    virtual double getCost() { return cost; }

private:
    double cost;
};

class Topping : public IceCream
{
public:
    /* Write about Topping Constructor
       Topping(string iceCreamName, double iceCreamCost,
	string toppingName, double toppingCost)
    */
    Topping() {}
    Topping(string iceCreamName, double iceCreamCost, string toppingName, double toppingCost):IceCream(toppingName+" with "+iceCreamName,iceCreamCost),toppingName(toppingName),toppingCost(toppingCost+iceCreamCost) {}
    virtual ~Topping() {}

    /* Write about Topping other member functions*/
    virtual string getDetails() { return ""; }
    virtual double getCost() { return toppingCost; }

private:
    string toppingName;
    double toppingCost;
};

class Cookie : public DessertItem
{
public:
    /* Write about Cookie Constructor
       Cookie(string name, int number, double pricePerDozen)
    */
    Cookie() {}
    Cookie(string name, int number, double pricePerDozen):DessertItem(name),number(number),pricePerDozen(pricePerDozen) {}
    virtual ~Cookie() {}

    /* Write about Cookie other member functions*/
    virtual string getDetails() { return "("+to_string(number)+" dozen(s) * "+to_string(pricePerDozen)+"/dozen)\n"; }
    virtual double getCost() { return pricePerDozen*number; }

private:
//Number of dozens of Cookie
    int number;
    double pricePerDozen;
};

class Candy : public DessertItem
{
public:
    /* Write here about Candy Constructor
       Candy(string name, double weight, double pricePerGram)
    */
    Candy() {}
    Candy(string name, double weight, double pricePerGram):DessertItem(name),weight(weight),pricePerGram(pricePerGram) {}
    virtual ~Candy() {}

    /* Write about Candy other member functions*/
    virtual string getDetails() { return "("+to_string(weight)+" gram(s) * "+to_string(pricePerGram)+"/gram)\n"; }
    virtual double getCost() { return pricePerGram * weight; }

private:
//Weight of Candy
    double weight;
    double pricePerGram;
};

class Checkout {

public:
    friend ostream &operator<<(std::ostream &, Checkout &);

    /* Write about Checkout member functions
    1. "enterItem" function to add the element into the list
    2. "removeItem" function to remove the elemtent from the list
    3. calculate the total cost and tax in the list
    4. "numberOfItems" for number of Item in the list
    5. "clear" clear all Items from list
    */
    template<typename T>
    void enterItem(T *di) {
        itemList.push_back(di);
        return;
    }
    template<typename T>
    void removeItem(const T *di) {
        itemList.remove(di);
        return;
    }
    double totalCost() {
        double cost = 0;
        for(list<DessertItem*>::iterator it = itemList.begin(); it != itemList.end(); ++it)
            cost += (*it)->getCost();
        return cost;
    }
    double tax() {
        return totalCost() * 0.05;
    }
    int numberOfIteams() {
        return itemList.size();
    }
    void clear () {
        itemList.clear();
        return;
    }
private:
    list<DessertItem*> itemList;
};

ostream &operator<<(ostream &output, Checkout &checkout){

    /*Overloaded operator that output a receipt for the current list of items*/
    output << "Welcome to OOP’s shop\n------------------------------\n" << endl;
    output << "Number of items: " << checkout.numberOfIteams() << endl << endl;
    for(list<DessertItem*>::iterator it = checkout.itemList.begin(); it != checkout.itemList.end(); ++it)
        output << setw(30) << left << (*it)->getName() << setw(10) << right << round((*it)->getCost()) << endl << (*it)->getDetails();
    output << "\n------------------------------\n";
    output << setw(30) << left << "Cost" << setw(10) << right << round(checkout.totalCost()) << endl;
    output << setw(30) << left << "Tax" << setw(10) << right << round(checkout.tax()) << endl << endl;
    output << setw(30) << left << "Total cost" << setw(10) << right << round(checkout.totalCost()+checkout.tax()) << endl;
    output.clear();
    return output;
}
<commit_msg>Debug for p1.cpp<commit_after>#include <bits/stdc++.h>
#include <iostream>
#include <string>
/*add the header if you need*/
using namespace std;

//Abstract base class for Dessert Item hierarchy
class DessertItem
{
private:
    //Name of the DessertItem object
    string name;

public:
    DessertItem(){}
    DessertItem(string name):name(name){}
    //Empty virtual destructor for DessertItem class
    virtual ~DessertItem(){}
    //returns Name of DessertItem
    string getName(){ return name;}
    virtual string getDetails() = 0;
    virtual double getCost() = 0;
};

class IceCream : public DessertItem
{
public:
    /* Write about IceCream Constructor
       IceCream(string name, double cost):DessertItem(name),cost(cost)
    */
    IceCream() {}
    IceCream(string name, double cost):DessertItem(name), cost(cost) {}
    virtual ~IceCream() {}

    /* Write about IceCream other member functions*/
    virtual string getDetails() { return ""; }
    virtual double getCost() { return cost; }

private:
    double cost;
};

class Topping : public IceCream
{
public:
    /* Write about Topping Constructor
       Topping(string iceCreamName, double iceCreamCost,
	string toppingName, double toppingCost)
    */
    Topping() {}
    Topping(string iceCreamName, double iceCreamCost, string toppingName, double toppingCost):IceCream(toppingName+" Sundae with "+iceCreamName,iceCreamCost),toppingName(toppingName),toppingCost(toppingCost+iceCreamCost) {}
    virtual ~Topping() {}

    /* Write about Topping other member functions*/
    virtual string getDetails() { return ""; }
    virtual double getCost() { return toppingCost; }

private:
    string toppingName;
    double toppingCost;
};

class Cookie : public DessertItem
{
public:
    /* Write about Cookie Constructor
       Cookie(string name, int number, double pricePerDozen)
    */
    Cookie() {}
    Cookie(string name, int number, double pricePerDozen):DessertItem(name),number(number),pricePerDozen(pricePerDozen) {}
    virtual ~Cookie() {}

    /* Write about Cookie other member functions*/
    virtual string getDetails() {
        stringstream s;
        string strn, strp;
        s << number;
        s >> strn;
        s.clear();
        s << pricePerDozen;
        s >> strp;
        return "("+strn+" dozen(s) * "+strp+"/dozen)\n";
    }
    virtual double getCost() { return pricePerDozen*number; }

private:
//Number of dozens of Cookie
    int number;
    double pricePerDozen;
};

class Candy : public DessertItem
{
public:
    /* Write here about Candy Constructor
       Candy(string name, double weight, double pricePerGram)
    */
    Candy() {}
    Candy(string name, double weight, double pricePerGram):DessertItem(name),weight(weight),pricePerGram(pricePerGram) {}
    virtual ~Candy() {}

    /* Write about Candy other member functions*/
    virtual string getDetails() {
        stringstream s;
        string strw, strp;
        s << weight;
        s >> strw;
        s.clear();
        s << pricePerGram;
        s >> strp;
        return "("+strw+" gram(s) * "+strp+"/gram)\n";
    }
    virtual double getCost() { return pricePerGram * weight; }

private:
//Weight of Candy
    double weight;
    double pricePerGram;
};

class Checkout {

public:
    friend ostream &operator<<(std::ostream &, Checkout &);

    /* Write about Checkout member functions
    1. "enterItem" function to add the element into the list
    2. "removeItem" function to remove the elemtent from the list
    3. calculate the total cost and tax in the list
    4. "numberOfItems" for number of Item in the list
    5. "clear" clear all Items from list
    */
    template<typename T>
    void enterItem(T *di) {
        itemList.push_back(di);
        return;
    }
    template<typename T>
    void removeItem(const T *di) {
        itemList.remove(di);
        return;
    }
    double totalCost() {
        double cost = 0;
        for(list<DessertItem*>::iterator it = itemList.begin(); it != itemList.end(); ++it)
            cost += (*it)->getCost();
        return cost;
    }
    double tax() {
        return totalCost() * 0.05;
    }
    int numberOfIteams() {
        return itemList.size();
    }
    void clear () {
        itemList.clear();
        return;
    }
private:
    list<DessertItem*> itemList;
};

ostream &operator<<(ostream &output, Checkout &checkout){

    /*Overloaded operator that output a receipt for the current list of items*/
    output << "Welcome to OOP’s shop\n------------------------------\n" << endl;
    output << "Number of items: " << checkout.numberOfIteams() << endl << endl;
    for(list<DessertItem*>::iterator it = checkout.itemList.begin(); it != checkout.itemList.end(); ++it)
        output << setw(40) << left << (*it)->getName() << setw(5) << right << round((*it)->getCost()) << endl << (*it)->getDetails();
    output << "\n------------------------------\n";
    output << setw(40) << left << "Cost" << setw(5) << right << round(checkout.totalCost()) << endl;
    output << setw(40) << left << "Tax" << setw(5) << right << round(checkout.tax()) << endl << endl;
    output << setw(40) << left << "Total cost" << setw(5) << right << round(checkout.totalCost()+checkout.tax()) << endl;
    output.clear();
    return output;
}
<|endoftext|>