<commit_before>#include "tile.hpp"
#include "font_face_set.hpp"
#include "harfbuzz_shaper.hpp"

// node
#include <node_buffer.h>

// stl
#include <algorithm>
#include <memory>
#include <iostream>

// freetype2
extern "C"
{
#include <ft2build.h>
#include FT_FREETYPE_H
// #include FT_STROKER_H
}

struct ShapeBaton {
    v8::Persistent<v8::Function> callback;
    Tile *tile;
    std::string fontstack;
};

v8::Persistent<v8::FunctionTemplate> Tile::constructor;

Tile::Tile(const char *data, size_t length) : node::ObjectWrap() {
    tile.ParseFromArray(data, length);
}

Tile::~Tile() {}

void Tile::Init(v8::Handle<v8::Object> target) {
    v8::HandleScope scope;

    v8::Local<v8::FunctionTemplate> tpl = v8::FunctionTemplate::New(New);
    v8::Local<v8::String> name = v8::String::NewSymbol("Tile");

    constructor = v8::Persistent<v8::FunctionTemplate>::New(tpl);

    // node::ObjectWrap uses the first internal field to store the wrapped pointer.
    constructor->InstanceTemplate()->SetInternalFieldCount(1);
    constructor->SetClassName(name);

    // Add all prototype methods, getters and setters here.
    constructor->PrototypeTemplate()->SetAccessor(v8::String::NewSymbol("length"), Length);
    NODE_SET_PROTOTYPE_METHOD(constructor, "serialize", Serialize);
    NODE_SET_PROTOTYPE_METHOD(constructor, "shape", Shape);

    // This has to be last, otherwise the properties won't show up on the
    // object in JavaScript.
    target->Set(name, constructor->GetFunction());
}

v8::Handle<v8::Value> Tile::New(const v8::Arguments& args) {
    if (!args.IsConstructCall()) {
        return ThrowException(v8::Exception::TypeError(v8::String::New("Constructor must be called with new keyword")));
    }
    if (args.Length() < 1 || !node::Buffer::HasInstance(args[0])) {
        return ThrowException(v8::Exception::TypeError(v8::String::New("First argument must be a buffer")));
    }

    v8::Local<v8::Object> buffer = args[0]->ToObject();

    Tile* tile = new Tile(node::Buffer::Data(buffer), node::Buffer::Length(buffer));
    tile->Wrap(args.This());

    return args.This();
}

bool Tile::HasInstance(v8::Handle<v8::Value> val) {
    if (!val->IsObject()) return false;
    return constructor->HasInstance(val->ToObject());
}

v8::Handle<v8::Value> Tile::Length(v8::Local<v8::String> property, const v8::AccessorInfo &info) {
    v8::HandleScope scope;
    Tile* tile = node::ObjectWrap::Unwrap<Tile>(info.This());
    v8::Local<v8::Number> length = v8::Uint32::New(tile->tile.layers_size());
    return scope.Close(length);
}

v8::Handle<v8::Value> Tile::Serialize(const v8::Arguments& args) {
    v8::HandleScope scope;
    llmr::vector::tile& tile = node::ObjectWrap::Unwrap<Tile>(args.This())->tile;
    std::string serialized = tile.SerializeAsString();
    return scope.Close(node::Buffer::New(serialized.data(), serialized.length())->handle_);
}

v8::Handle<v8::Value> Tile::Shape(const v8::Arguments& args) {
    v8::HandleScope scope;

    if (args.Length() < 1) {
        return ThrowException(v8::Exception::TypeError(
            v8::String::New("First argument must be a font stack")));
    }

    if (args.Length() < 2 || !args[1]->IsFunction()) {
        return ThrowException(v8::Exception::TypeError(
            v8::String::New("Second argument must be a callback function")));
    }
    v8::Local<v8::Function> callback = v8::Local<v8::Function>::Cast(args[1]);
    // TODO: validate this is a string
    v8::String::Utf8Value fontstack(args[0]->ToString());

    Tile *tile = node::ObjectWrap::Unwrap<Tile>(args.This());

    ShapeBaton* baton = new ShapeBaton();
    baton->callback = v8::Persistent<v8::Function>::New(callback);
    baton->tile = tile;
    baton->fontstack = *fontstack;

    uv_work_t *req = new uv_work_t();
    req->data = baton;

    int status = uv_queue_work(uv_default_loop(), req, AsyncShape, (uv_after_work_cb)ShapeAfter);
    assert(status == 0);

    return v8::Undefined();
}

void Tile::AsyncShape(uv_work_t* req) {
    ShapeBaton* baton = static_cast<ShapeBaton*>(req->data);
    // Maps char index (UTF-16) to width. If multiple glyphs map to the
    // same char the sum of all widths is used.
    // Note: this probably isn't the best solution. it would be better
    // to have an object for each cluster, but it needs to be
    // implemented with no overhead.
    std::map<unsigned, double> width_map_;
    fontserver::freetype_engine font_engine_;
    fontserver::face_manager_freetype font_manager(font_engine_);
    fontserver::text_itemizer itemizer;

    fontserver::font_set fset(baton->fontstack);
    fset.add_fontstack(baton->fontstack, ',');

    fontserver::face_set_ptr face_set = font_manager.get_face_set(fset);
    if (!face_set->size()) return;

    std::map<fontserver::face_ptr, fontserver::tile_face *> face_map;
    std::vector<fontserver::tile_face *> tile_faces;

    llmr::vector::tile& tile = baton->tile->tile;

    // for every label
    for (int i = 0; i < tile.layers_size(); i++) {
        const llmr::vector::layer& layer = tile.layers(i);

        typedef std::set<int> Strings;
        Strings strings;

        // Compile a set of all strings we need to shape.
        for (int j = 0; j < layer.features_size(); j++) {
            const llmr::vector::feature& feature = layer.features(j);

            for (int k = 1; k < feature.tags_size(); k += 2) {
                const std::string& key = layer.keys(feature.tags(k - 1));
                if (key == "name") {
                    // TODO: handle multiple fonts stacks
                    strings.insert(feature.tags(k));
                }
                // TODO: extract all keys we need to shape
            }
        }

        llmr::vector::layer* mutable_layer = tile.mutable_layers(i);

        fontserver::text_format format(baton->fontstack, 24);
        fontserver::text_format_ptr format_ptr =
            std::make_shared<fontserver::text_format>(format);

        // Process strings per layer.
        for (auto const& key : strings) {
            const llmr::vector::value& value = layer.values(key);
            std::string text;
            if (value.has_string_value()) {
                text = value.string_value();
            }

            if (!text.empty()) {
                // Clear cluster widths.
                width_map_.clear();

                UnicodeString const& str = text.data();

                fontserver::text_line line(0, str.length() - 1);

                itemizer.add_text(str, format_ptr);

                const double scale_factor = 1.0;

                // Shape the text.
                fontserver::harfbuzz_shaper shaper;
                shaper.shape_text(line,
                                  itemizer,
                                  width_map_,
                                  face_set,
                                  // font_manager,
                                  scale_factor);

                llmr::vector::label *label = mutable_layer->add_labels();
                label->set_text(key);

                // TODO: support multiple font stacks
                label->set_stack(0);

                // Add all glyphs for this labels and add new font
                // faces as they appear.
                for (auto const& glyph : line) {
                    if (!glyph.face) {
                        std::cout << text << ' ' <<
                            line.size() << " glyphs\n" <<
                            " codepoint: " << glyph.glyph_index <<
                            " char_index: " << glyph.char_index <<
                            " face_ptr: " << glyph.face <<
                            '\n';
                        continue;
                    }

                    // Try to find whether this font has already been
                    // used in this tile.
                    std::map<fontserver::face_ptr, fontserver::tile_face *>::iterator face_map_itr = face_map.find(glyph.face);
                    if (face_map_itr == face_map.end()) {
                        fontserver::tile_face *face =
                            new fontserver::tile_face(glyph.face);
                        std::pair<fontserver::face_ptr, fontserver::tile_face *> keyed(glyph.face, face);
                        face_map_itr = face_map.insert(keyed).first;

                        // Add to shared face cache if not found.
                        fontserver::font_face_set::iterator face_itr = std::find(face_set->begin(), face_set->end(), glyph.face);
                        if (face_itr == face_set->end()) {
                            face_set->add(glyph.face);
                        }
                    }

                    fontserver::tile_face *face = face_map_itr->second;

                    // Find out whether this font has been used in
                    // this tile before and get its position.
                    std::vector<fontserver::tile_face *>::iterator tile_itr = std::find(tile_faces.begin(), tile_faces.end(), face);
                    if (tile_itr == tile_faces.end()) {
                        tile_faces.push_back(face);
                        tile_itr = tile_faces.end() - 1;
                    }

                    int tile_face_id = tile_itr - tile_faces.begin();

                    // Add glyph to tile_face.
                    face->add_glyph(glyph);

                    label->add_faces(tile_face_id);
                    label->add_glyphs(glyph.glyph_index);
                    label->add_x(width_map_[glyph.char_index]);
                    label->add_y(glyph.offset.y);
                }

                itemizer.clear();
            }
        }

        // Add a textual representation of the font so that we can figure out
        // later what font we need to use.
        for (auto const& face : tile_faces) {
            std::string name = face->family + " " + face->style;
            mutable_layer->add_faces(name);
            // We don't delete the TileFace objects here because
            // they are 'owned' by the global faces map and deleted
            // later on.
        }

        // Insert FAKE stacks
        mutable_layer->add_stacks(baton->fontstack);
    }

    InsertGlyphs(tile, tile_faces);
}

void Tile::AsyncRange(uv_work_t* req) {
    ShapeBaton* baton = static_cast<ShapeBaton*>(req->data);

    fontserver::freetype_engine font_engine_;
    fontserver::face_manager_freetype font_manager(font_engine_);

    fontserver::font_set fset(baton->fontstack);
    fset.add_fontstack(baton->fontstack, ',');

    fontserver::face_set_ptr face_set = font_manager.get_face_set(fset);
    if (!face_set->size()) return;

    std::map<fontserver::face_ptr, fontserver::tile_face *> face_map;
    std::vector<fontserver::tile_face *> tile_faces;

    llmr::vector::tile& tile = baton->tile->tile;

    fontserver::text_format format(baton->fontstack, 24);
    const double scale_factor = 1.0;

    // Set character sizes.
    double size = format.text_size * scale_factor;
    face_set->set_character_sizes(size);

    FT_UInt glyph_index = 0;
    FT_UInt glyph_end = 128;

    for (auto const& face : *face_set) {
        // Create tile_face, add to face_map and tile_faces.
        fontserver::tile_face *t_face = new fontserver::tile_face(face);
        face_map.emplace(face, t_face);
        tile_faces.push_back(t_face);

        // Get FreeType face from face_ptr.
        FT_Face ft_face = face->get_face();

        // Add all glyphs for this labels and add new font
        // faces as they appear.
        FT_ULong char_code = FT_Get_First_Char(ft_face, &glyph_index);
        while (glyph_index != 0 && char_code < glyph_end) {
            fontserver::glyph_info glyph;
            glyph.glyph_index = char_code;

            face->glyph_dimensions(glyph);

            // Add glyph to t_face.
            t_face->add_glyph(glyph);

            // Advance char_code to next glyph index.
            char_code = FT_Get_Next_Char(ft_face, char_code, &glyph_index);
        }
    }

    InsertGlyphs(tile, tile_faces);
}

// Insert SDF glyphs + bitmaps
void Tile::InsertGlyphs(llmr::vector::tile &tile,
                        std::vector<fontserver::tile_face *> &tile_faces) {
    for (auto const& face : tile_faces) {
        llmr::vector::face *mutable_face = tile.add_faces();
        mutable_face->set_family(face->family);
        mutable_face->set_style(face->style);

        for (auto const& glyph : face->glyphs) {
            llmr::vector::glyph *mutable_glyph = mutable_face->add_glyphs();
            mutable_glyph->set_id(glyph.glyph_index);
            mutable_glyph->set_width(glyph.width);
            mutable_glyph->set_height(glyph.height);
            mutable_glyph->set_left(glyph.left);
            mutable_glyph->set_top(glyph.top);
            mutable_glyph->set_advance(glyph.advance);
            if (glyph.width > 0) {
                mutable_glyph->set_bitmap(glyph.bitmap);
            }
        }
    }
}

void Tile::ShapeAfter(uv_work_t* req) {
    v8::HandleScope scope;
    ShapeBaton* baton = static_cast<ShapeBaton*>(req->data);

    const unsigned argc = 1;
    v8::Local<v8::Value> argv[argc] = { v8::Local<v8::Value>::New(v8::Null()) };

    v8::TryCatch try_catch;
    baton->callback->Call(v8::Context::GetCurrent()->Global(), argc, argv);
    if (try_catch.HasCaught()) {
        node::FatalException(try_catch);
    }

    baton->callback.Dispose();

    delete baton;
    delete req;
}
<commit_msg>comment break<commit_after>#include "tile.hpp"
#include "font_face_set.hpp"
#include "harfbuzz_shaper.hpp"

// node
#include <node_buffer.h>

// stl
#include <algorithm>
#include <memory>
#include <iostream>

// freetype2
extern "C"
{
#include <ft2build.h>
#include FT_FREETYPE_H
// #include FT_STROKER_H
}

struct ShapeBaton {
    v8::Persistent<v8::Function> callback;
    Tile *tile;
    std::string fontstack;
};

v8::Persistent<v8::FunctionTemplate> Tile::constructor;

Tile::Tile(const char *data, size_t length) : node::ObjectWrap() {
    tile.ParseFromArray(data, length);
}

Tile::~Tile() {}

void Tile::Init(v8::Handle<v8::Object> target) {
    v8::HandleScope scope;

    v8::Local<v8::FunctionTemplate> tpl = v8::FunctionTemplate::New(New);
    v8::Local<v8::String> name = v8::String::NewSymbol("Tile");

    constructor = v8::Persistent<v8::FunctionTemplate>::New(tpl);

    // node::ObjectWrap uses the first internal field to store the wrapped pointer.
    constructor->InstanceTemplate()->SetInternalFieldCount(1);
    constructor->SetClassName(name);

    // Add all prototype methods, getters and setters here.
    constructor->PrototypeTemplate()->SetAccessor(v8::String::NewSymbol("length"), Length);
    NODE_SET_PROTOTYPE_METHOD(constructor, "serialize", Serialize);
    NODE_SET_PROTOTYPE_METHOD(constructor, "shape", Shape);

    // This has to be last, otherwise the properties won't show up on the
    // object in JavaScript.
    target->Set(name, constructor->GetFunction());
}

v8::Handle<v8::Value> Tile::New(const v8::Arguments& args) {
    if (!args.IsConstructCall()) {
        return ThrowException(v8::Exception::TypeError(v8::String::New("Constructor must be called with new keyword")));
    }
    if (args.Length() < 1 || !node::Buffer::HasInstance(args[0])) {
        return ThrowException(v8::Exception::TypeError(v8::String::New("First argument must be a buffer")));
    }

    v8::Local<v8::Object> buffer = args[0]->ToObject();

    Tile* tile = new Tile(node::Buffer::Data(buffer), node::Buffer::Length(buffer));
    tile->Wrap(args.This());

    return args.This();
}

bool Tile::HasInstance(v8::Handle<v8::Value> val) {
    if (!val->IsObject()) return false;
    return constructor->HasInstance(val->ToObject());
}

v8::Handle<v8::Value> Tile::Length(v8::Local<v8::String> property, const v8::AccessorInfo &info) {
    v8::HandleScope scope;
    Tile* tile = node::ObjectWrap::Unwrap<Tile>(info.This());
    v8::Local<v8::Number> length = v8::Uint32::New(tile->tile.layers_size());
    return scope.Close(length);
}

v8::Handle<v8::Value> Tile::Serialize(const v8::Arguments& args) {
    v8::HandleScope scope;
    llmr::vector::tile& tile = node::ObjectWrap::Unwrap<Tile>(args.This())->tile;
    std::string serialized = tile.SerializeAsString();
    return scope.Close(node::Buffer::New(serialized.data(), serialized.length())->handle_);
}

v8::Handle<v8::Value> Tile::Shape(const v8::Arguments& args) {
    v8::HandleScope scope;

    if (args.Length() < 1) {
        return ThrowException(v8::Exception::TypeError(
            v8::String::New("First argument must be a font stack")));
    }

    if (args.Length() < 2 || !args[1]->IsFunction()) {
        return ThrowException(v8::Exception::TypeError(
            v8::String::New("Second argument must be a callback function")));
    }
    v8::Local<v8::Function> callback = v8::Local<v8::Function>::Cast(args[1]);
    // TODO: validate this is a string
    v8::String::Utf8Value fontstack(args[0]->ToString());

    Tile *tile = node::ObjectWrap::Unwrap<Tile>(args.This());

    ShapeBaton* baton = new ShapeBaton();
    baton->callback = v8::Persistent<v8::Function>::New(callback);
    baton->tile = tile;
    baton->fontstack = *fontstack;

    uv_work_t *req = new uv_work_t();
    req->data = baton;

    int status = uv_queue_work(uv_default_loop(), req, AsyncShape, (uv_after_work_cb)ShapeAfter);
    assert(status == 0);

    return v8::Undefined();
}

void Tile::AsyncShape(uv_work_t* req) {
    ShapeBaton* baton = static_cast<ShapeBaton*>(req->data);
    // Maps char index (UTF-16) to width. If multiple glyphs map to the
    // same char the sum of all widths is used.
    // Note: this probably isn't the best solution. it would be better
    // to have an object for each cluster, but it needs to be
    // implemented with no overhead.
    std::map<unsigned, double> width_map_;
    fontserver::freetype_engine font_engine_;
    fontserver::face_manager_freetype font_manager(font_engine_);
    fontserver::text_itemizer itemizer;

    fontserver::font_set fset(baton->fontstack);
    fset.add_fontstack(baton->fontstack, ',');

    fontserver::face_set_ptr face_set = font_manager.get_face_set(fset);
    if (!face_set->size()) return;

    std::map<fontserver::face_ptr, fontserver::tile_face *> face_map;
    std::vector<fontserver::tile_face *> tile_faces;

    llmr::vector::tile& tile = baton->tile->tile;

    // for every label
    for (int i = 0; i < tile.layers_size(); i++) {
        const llmr::vector::layer& layer = tile.layers(i);

        typedef std::set<int> Strings;
        Strings strings;

        // Compile a set of all strings we need to shape.
        for (int j = 0; j < layer.features_size(); j++) {
            const llmr::vector::feature& feature = layer.features(j);

            for (int k = 1; k < feature.tags_size(); k += 2) {
                const std::string& key = layer.keys(feature.tags(k - 1));
                if (key == "name") {
                    // TODO: handle multiple fonts stacks
                    strings.insert(feature.tags(k));
                }
                // TODO: extract all keys we need to shape
            }
        }

        llmr::vector::layer* mutable_layer = tile.mutable_layers(i);

        fontserver::text_format format(baton->fontstack, 24);
        fontserver::text_format_ptr format_ptr =
            std::make_shared<fontserver::text_format>(format);

        // Process strings per layer.
        for (auto const& key : strings) {
            const llmr::vector::value& value = layer.values(key);
            std::string text;
            if (value.has_string_value()) {
                text = value.string_value();
            }

            if (!text.empty()) {
                // Clear cluster widths.
                width_map_.clear();

                UnicodeString const& str = text.data();

                fontserver::text_line line(0, str.length() - 1);

                itemizer.add_text(str, format_ptr);

                const double scale_factor = 1.0;

                // Shape the text.
                fontserver::harfbuzz_shaper shaper;
                shaper.shape_text(line,
                                  itemizer,
                                  width_map_,
                                  face_set,
                                  // font_manager,
                                  scale_factor);

                llmr::vector::label *label = mutable_layer->add_labels();
                label->set_text(key);

                // TODO: support multiple font stacks
                label->set_stack(0);

                // Add all glyphs for this labels and add new font
                // faces as they appear.
                for (auto const& glyph : line) {
                    if (!glyph.face) {
                        std::cout << text << ' ' <<
                            line.size() << " glyphs\n" <<
                            " codepoint: " << glyph.glyph_index <<
                            " char_index: " << glyph.char_index <<
                            " face_ptr: " << glyph.face <<
                            '\n';
                        continue;
                    }

                    // Try to find whether this font has already been
                    // used in this tile.
                    std::map<fontserver::face_ptr, fontserver::tile_face *>::iterator face_map_itr = face_map.find(glyph.face);
                    if (face_map_itr == face_map.end()) {
                        fontserver::tile_face *face =
                            new fontserver::tile_face(glyph.face);
                        std::pair<fontserver::face_ptr, fontserver::tile_face *> keyed(glyph.face, face);
                        face_map_itr = face_map.insert(keyed).first;

                        // Add to shared face cache if not found.
                        fontserver::font_face_set::iterator face_itr = std::find(face_set->begin(), face_set->end(), glyph.face);
                        if (face_itr == face_set->end()) {
                            face_set->add(glyph.face);
                        }
                    }

                    fontserver::tile_face *face = face_map_itr->second;

                    // Find out whether this font has been used in
                    // this tile before and get its position.
                    std::vector<fontserver::tile_face *>::iterator tile_itr = std::find(tile_faces.begin(), tile_faces.end(), face);
                    if (tile_itr == tile_faces.end()) {
                        tile_faces.push_back(face);
                        tile_itr = tile_faces.end() - 1;
                    }

                    int tile_face_id = tile_itr - tile_faces.begin();

                    // Add glyph to tile_face.
                    face->add_glyph(glyph);

                    label->add_faces(tile_face_id);
                    label->add_glyphs(glyph.glyph_index);
                    label->add_x(width_map_[glyph.char_index]);
                    label->add_y(glyph.offset.y);
                }

                itemizer.clear();
            }
        }

        // Add a textual representation of the font so that we can figure
        // out later what font we need to use.
        for (auto const& face : tile_faces) {
            std::string name = face->family + " " + face->style;
            mutable_layer->add_faces(name);
            // We don't delete the TileFace objects here because
            // they are 'owned' by the global faces map and deleted
            // later on.
        }

        // Insert FAKE stacks
        mutable_layer->add_stacks(baton->fontstack);
    }

    InsertGlyphs(tile, tile_faces);
}

void Tile::AsyncRange(uv_work_t* req) {
    ShapeBaton* baton = static_cast<ShapeBaton*>(req->data);

    fontserver::freetype_engine font_engine_;
    fontserver::face_manager_freetype font_manager(font_engine_);

    fontserver::font_set fset(baton->fontstack);
    fset.add_fontstack(baton->fontstack, ',');

    fontserver::face_set_ptr face_set = font_manager.get_face_set(fset);
    if (!face_set->size()) return;

    std::map<fontserver::face_ptr, fontserver::tile_face *> face_map;
    std::vector<fontserver::tile_face *> tile_faces;

    llmr::vector::tile& tile = baton->tile->tile;

    fontserver::text_format format(baton->fontstack, 24);
    const double scale_factor = 1.0;

    // Set character sizes.
    double size = format.text_size * scale_factor;
    face_set->set_character_sizes(size);

    FT_UInt glyph_index = 0;
    FT_UInt glyph_end = 128;

    for (auto const& face : *face_set) {
        // Create tile_face, add to face_map and tile_faces.
        fontserver::tile_face *t_face = new fontserver::tile_face(face);
        face_map.emplace(face, t_face);
        tile_faces.push_back(t_face);

        // Get FreeType face from face_ptr.
        FT_Face ft_face = face->get_face();

        // Add all glyphs for this labels and add new font
        // faces as they appear.
        FT_ULong char_code = FT_Get_First_Char(ft_face, &glyph_index);
        while (glyph_index != 0 && char_code < glyph_end) {
            fontserver::glyph_info glyph;
            glyph.glyph_index = char_code;

            face->glyph_dimensions(glyph);

            // Add glyph to t_face.
            t_face->add_glyph(glyph);

            // Advance char_code to next glyph index.
            char_code = FT_Get_Next_Char(ft_face, char_code, &glyph_index);
        }
    }

    InsertGlyphs(tile, tile_faces);
}

// Insert SDF glyphs + bitmaps
void Tile::InsertGlyphs(llmr::vector::tile &tile,
                        std::vector<fontserver::tile_face *> &tile_faces) {
    for (auto const& face : tile_faces) {
        llmr::vector::face *mutable_face = tile.add_faces();
        mutable_face->set_family(face->family);
        mutable_face->set_style(face->style);

        for (auto const& glyph : face->glyphs) {
            llmr::vector::glyph *mutable_glyph = mutable_face->add_glyphs();
            mutable_glyph->set_id(glyph.glyph_index);
            mutable_glyph->set_width(glyph.width);
            mutable_glyph->set_height(glyph.height);
            mutable_glyph->set_left(glyph.left);
            mutable_glyph->set_top(glyph.top);
            mutable_glyph->set_advance(glyph.advance);
            if (glyph.width > 0) {
                mutable_glyph->set_bitmap(glyph.bitmap);
            }
        }
    }
}

void Tile::ShapeAfter(uv_work_t* req) {
    v8::HandleScope scope;
    ShapeBaton* baton = static_cast<ShapeBaton*>(req->data);

    const unsigned argc = 1;
    v8::Local<v8::Value> argv[argc] = { v8::Local<v8::Value>::New(v8::Null()) };

    v8::TryCatch try_catch;
    baton->callback->Call(v8::Context::GetCurrent()->Global(), argc, argv);
    if (try_catch.HasCaught()) {
        node::FatalException(try_catch);
    }

    baton->callback.Dispose();

    delete baton;
    delete req;
}
<|endoftext|>


<commit_before>#include "trie.hpp"

namespace esapp
{

/************************************************
 * Implementation: class FreqTrie
 ************************************************/

FreqTrie::FreqTrie(size_t max_depth, double smooth, Char boundary)
    : freq_avg_(NULL), max_depth_(max_depth), smooth_(smooth), boundary_(boundary)
{
    root_ = new FreqTrieNode();
}

FreqTrie::FreqTrie(const FreqTrie &trie)
    : freq_avg_(NULL), max_depth_(trie.max_depth_),
      smooth_(trie.smooth_), boundary_(trie.boundary_)
{
    root_ = new FreqTrieNode(*(trie.root_));
    if (trie.freq_avg_)
    {
        size_t trie_depth = trie.depth();
        freq_avg_ = new double[trie_depth];
        memcpy(freq_avg_, trie.freq_avg_, sizeof(double) * trie_depth);
    }
}

FreqTrie::~FreqTrie(void)
{
    clear_fm();
    delete root_;
}

FreqTrie &FreqTrie::operator=(const FreqTrie &trie)
{
    root_ = trie.root_;

    clear_fm();
    if (trie.freq_avg_)
    {
        size_t trie_depth = trie.depth();
        freq_avg_ = new double[trie_depth];
        memcpy(freq_avg_, trie.freq_avg_, sizeof(double) * trie_depth);
    }

    return *this;
}

void FreqTrie::increase(const Sequence &sequence, bool include_self)
{
    size_t n = sequence.size();
    for (size_t i = 0; i < n; ++i)
    {
        FreqTrieNode *node = root_;
        for (size_t j = i; j < n && j - i < max_depth_; ++j)
        {
            if (!include_self && i == 0 && j == n - 1) { continue; }

            node = node->get(sequence[j], true);
            node->f++;

            Char x = (i > 0)     ? sequence[i - 1] : boundary_;
            Char y = (j < n - 1) ? sequence[j + 1] : boundary_;
            node->sp1l[x]++;
            node->sp1r[y]++;
        }
    }
}

void FreqTrie::increase(const std::vector<Sequence> &sequences, bool include_self)
{
    for (std::vector<Sequence>::const_iterator it = sequences.begin();
         it != sequences.end(); ++it)
    {
        increase(*it, include_self);
    }
}

void FreqTrie::decrease(const Sequence &sequence, bool include_self)
{
    size_t n = sequence.size();
    for (size_t i = 0; i < n; ++i)
    {
        FreqTrieNode *node = root_;
        for (size_t j = i; j < n && j - i < max_depth_; ++j)
        {
            if (!include_self && i == 0 && j == n - 1) { continue; }

            node = node->children[sequence[j]];
            node->f--;
        }
    }
}

void FreqTrie::decrease(const std::vector<Sequence> &sequences, bool include_self)
{
    for (std::vector<Sequence>::const_iterator it = sequences.begin();
         it != sequences.end(); ++it)
    {
        decrease(*it, include_self);
    }
}

void FreqTrie::update_hsp1(void)
{
    size_t trie_depth = depth();
    size_t num_alphabets = root_->children.size() + 1;

    size_t *nums = new size_t[trie_depth];
    double *hl_avg = new double[trie_depth];
    double *hr_avg = new double[trie_depth];

    memset(nums, 0, sizeof(size_t) * trie_depth);
    memset(hl_avg, 0, sizeof(double) * trie_depth);
    memset(hr_avg, 0, sizeof(double) * trie_depth);

    for (Iterator it = begin(); it != end(); ++it)
    {
        size_t node_depth = it->first - 1;
        FreqTrieNode *node = it->second;

        node->hl = entropy(node->sp1l, num_alphabets);
        node->hr = entropy(node->sp1r, num_alphabets);
        hl_avg[node_depth] += node->hl;
        hr_avg[node_depth] += node->hr;
        nums[node_depth]++;
    }

    for (size_t i = 0; i < trie_depth; ++i)
    {
        hl_avg[i] /= nums[i];
        hr_avg[i] /= nums[i];
    }

    for (Iterator it = begin(); it != end(); ++it)
    {
        size_t node_depth = it->first - 1;
        FreqTrieNode *node = it->second;

        node->hl /= hl_avg[node_depth];
        node->hr /= hr_avg[node_depth];
    }

    delete [] nums;
    delete [] hl_avg;
    delete [] hr_avg;
}

void FreqTrie::update_fm(void)
{
    clear_fm();

    size_t trie_depth = depth();
    size_t *nums = new size_t[trie_depth];
    freq_avg_ = new double[trie_depth];

    memset(nums, 0, sizeof(size_t) * trie_depth);
    memset(freq_avg_, 0, sizeof(double) * trie_depth);

    for (Iterator it = begin(); it != end(); ++it)
    {
        size_t node_depth = it->first - 1;
        FreqTrieNode *node = it->second;

        freq_avg_[node_depth] += node->f;
        nums[node_depth]++;
    }

    for (size_t i = 0; i < trie_depth; ++i)
    {
        freq_avg_[i] /= nums[i];
    }

    delete [] nums;
}

void FreqTrie::update_iv(void)
{
    if (freq_avg_ == NULL) { throw std::exception(); }

    for (Iterator it = begin(); it != end(); ++it)
    {
        size_t node_depth = it->first - 1;
        FreqTrieNode *node = it->second;

        node->iv = pow(node->f / freq_avg_[node_depth], node_depth + 1);
    }
}

double FreqTrie::get_hl(const Sequence &sequence) const
{
    return get_hl(sequence.begin(), sequence.end());
}

double FreqTrie::get_hl(const Sequence::const_iterator &begin,
                        const Sequence::const_iterator &end) const
{
    FreqTrieNode const *node = find(begin, end);
    if (node == NULL) { return -1; }

    return node->hl;
}

double FreqTrie::get_hr(const Sequence &sequence) const
{
    return get_hr(sequence.begin(), sequence.end());
}

double FreqTrie::get_hr(const Sequence::const_iterator &begin,
                        const Sequence::const_iterator &end) const
{
    FreqTrieNode const *node = find(begin, end);
    if (node == NULL) { return -1; }

    return node->hr;
}

double FreqTrie::get_iv(const Sequence &sequence) const
{
    return get_iv(sequence.begin(), sequence.end());
}

double FreqTrie::get_iv(const Sequence::const_iterator &begin,
                        const Sequence::const_iterator &end) const
{
    FreqTrieNode const *node = find(begin, end);
    if (node == NULL) { return -1; }

    return node->iv;
}

size_t FreqTrie::depth(void) const
{
    return root_->depth();
}

size_t FreqTrie::max_depth(void) const
{
    return max_depth_;
}

FreqTrie::Iterator FreqTrie::begin(void)
{
    return ++Iterator(root_);
}

FreqTrie::ConstIterator FreqTrie::begin(void) const
{
    return ++ConstIterator(root_);
}

FreqTrie::Iterator FreqTrie::end(void)
{
    return Iterator();
}

FreqTrie::ConstIterator FreqTrie::end(void) const
{
    return ConstIterator();
}

FreqTrie::FreqTrieNode const *FreqTrie::find(const Sequence &sequence) const
{
    return find(sequence.begin(), sequence.end());
}

FreqTrie::FreqTrieNode const *FreqTrie::find(
    const Sequence::const_iterator &begin,
    const Sequence::const_iterator &end) const
{
    NodeCollection::const_iterator result_it;
    FreqTrieNode *node = root_;
    for (Sequence::const_iterator it = begin; it != end; ++it)
    {
        node = node->get(*it);
        if (node == NULL) { break; }
    }

    return node;
}

double FreqTrie::entropy(CharCounts counts, size_t num_events)
{
    double n = 0;
    for (CharCounts::const_iterator it = counts.begin();
         it != counts.end(); ++it)
    {
        n += it->second;
    }

    n *= (1 + smooth_);

    double h = 0;
    for (CharCounts::const_iterator it = counts.begin();
         it != counts.end(); ++it)
    {
        double p = (it->second + smooth_) / n;
        h -= p * log(p);
    }

    if (smooth_ > 0)
    {
        size_t num_zeros = num_events - counts.size();
        double p = smooth_ / n;
        h -= num_zeros * (p * log(p));
    }

    return h;
}

void FreqTrie::clear_fm(void)
{
    if (freq_avg_ != NULL)
    {
        delete [] freq_avg_;
    }

    freq_avg_ = NULL;
}

void FreqTrie::clear(void)
{
    root_->clear();
    clear_fm();
}

/************************************************
 * Implementation: class FreqTrie::BaseIterator
 ************************************************/

template<typename T>
FreqTrie::BaseIterator<T>::BaseIterator(void)
    : stack_()
{
    // do nothing
}

template<typename T>
FreqTrie::BaseIterator<T>::BaseIterator(T *node)
    : stack_()
{
    stack_.push(std::make_pair(0, node));
}

template<typename T>
FreqTrie::BaseIterator<T> &FreqTrie::BaseIterator<T>::operator++(void)
{
    Value top = stack_.top();
    stack_.pop();

    size_t depth = top.first + 1;
    T *node = top.second;
    for (NodeCollection::const_iterator it = node->children.begin();
         it != node->children.end(); ++it)
    {
        stack_.push(std::make_pair(depth, it->second));
    }

    return *this;
}

template<typename T>
FreqTrie::BaseIterator<T> FreqTrie::BaseIterator<T>::operator++(int)
{
    BaseIterator it(this);
    ++(*this);
    return it;
}

template<typename T>
std::pair<size_t, T *> &FreqTrie::BaseIterator<T>::operator*(void) const
{
    return stack_.top();
}

template<typename T>
std::pair<size_t, T *> const *FreqTrie::BaseIterator<T>::operator->(void) const
{
    return &(stack_.top());
}

template<typename T>
bool FreqTrie::BaseIterator<T>::operator==(const BaseIterator &it) const
{
    if (it.stack_.empty())      { return stack_.empty(); }
    else if (stack_.empty())    { return false; }

    return stack_.top() == it.stack_.top();
}

template<typename T>
bool FreqTrie::BaseIterator<T>::operator!=(const BaseIterator &it) const
{
    return !(*this == it);
}

/************************************************
 * Implementation: struct FreqTrie::FreqTrieNode
 ************************************************/

FreqTrie::FreqTrieNode::FreqTrieNode(void) : f(0), hl(0), hr(0), iv(0)
{
    // do nothing
}

FreqTrie::FreqTrieNode::FreqTrieNode(const FreqTrie::FreqTrieNode &node)
    : sp1l(node.sp1l), sp1r(node.sp1r), f(node.f), hl(node.hl), hr(node.hr), iv(node.iv)
{
    for (NodeCollection::const_iterator it = node.children.begin();
         it != node.children.end(); ++it)
    {
        FreqTrieNode *node = new FreqTrieNode(*(it->second));
        children[it->first] = node;
    }
}

FreqTrie::FreqTrieNode::~FreqTrieNode(void)
{
    clear();
}

FreqTrie::FreqTrieNode &FreqTrie::FreqTrieNode::operator=(const FreqTrie::FreqTrieNode &node)
{
    if (&node != this) { return *this; }

    clear();

    sp1l = node.sp1l;
    sp1r = node.sp1r;
    f = node.f;
    hl = node.hl;
    hr = node.hr;
    iv = node.iv;

    for (NodeCollection::const_iterator it = node.children.begin();
         it != node.children.end(); ++it)
    {
        FreqTrieNode *node = new FreqTrieNode(*(it->second));
        children[it->first] = node;
    }

    return *this;
}

FreqTrie::FreqTrieNode const *FreqTrie::FreqTrieNode::get(Char key) const
{
    NodeCollection::const_iterator it = children.find(key);
    if (it != children.end())
    {
        return it->second;
    }

    return NULL;
}

FreqTrie::FreqTrieNode *FreqTrie::FreqTrieNode::get(Char key, bool create)
{
    NodeCollection::iterator it = children.find(key);
    if (it != children.end())   { return it->second; }
    else if (!create)           { return NULL; }

    children[key] = new FreqTrieNode();
    return children[key];
}

size_t FreqTrie::FreqTrieNode::depth(void) const
{
    if (children.empty()) { return 0; }

    size_t max_depth = 0;
    for (NodeCollection::const_iterator it = children.begin();
         it != children.end(); ++it)
    {
        size_t depth = it->second->depth();
        if (depth > max_depth)
        {
            max_depth = depth;
        }
    }

    return max_depth + 1;
}

void FreqTrie::FreqTrieNode::clear(void)
{
    for (NodeCollection::const_iterator it = children.begin();
         it != children.end(); ++it)
    {
        delete it->second;
    }

    f = hl = hr = iv = 0;
}

} // namespace esa
<commit_msg>Clear node children after release the allocated memory<commit_after>#include "trie.hpp"

namespace esapp
{

/************************************************
 * Implementation: class FreqTrie
 ************************************************/

FreqTrie::FreqTrie(size_t max_depth, double smooth, Char boundary)
    : freq_avg_(NULL), max_depth_(max_depth), smooth_(smooth), boundary_(boundary)
{
    root_ = new FreqTrieNode();
}

FreqTrie::FreqTrie(const FreqTrie &trie)
    : freq_avg_(NULL), max_depth_(trie.max_depth_),
      smooth_(trie.smooth_), boundary_(trie.boundary_)
{
    root_ = new FreqTrieNode(*(trie.root_));
    if (trie.freq_avg_)
    {
        size_t trie_depth = trie.depth();
        freq_avg_ = new double[trie_depth];
        memcpy(freq_avg_, trie.freq_avg_, sizeof(double) * trie_depth);
    }
}

FreqTrie::~FreqTrie(void)
{
    clear_fm();
    delete root_;
}

FreqTrie &FreqTrie::operator=(const FreqTrie &trie)
{
    root_ = trie.root_;

    clear_fm();
    if (trie.freq_avg_)
    {
        size_t trie_depth = trie.depth();
        freq_avg_ = new double[trie_depth];
        memcpy(freq_avg_, trie.freq_avg_, sizeof(double) * trie_depth);
    }

    return *this;
}

void FreqTrie::increase(const Sequence &sequence, bool include_self)
{
    size_t n = sequence.size();
    for (size_t i = 0; i < n; ++i)
    {
        FreqTrieNode *node = root_;
        for (size_t j = i; j < n && j - i < max_depth_; ++j)
        {
            if (!include_self && i == 0 && j == n - 1) { continue; }

            node = node->get(sequence[j], true);
            node->f++;

            Char x = (i > 0)     ? sequence[i - 1] : boundary_;
            Char y = (j < n - 1) ? sequence[j + 1] : boundary_;
            node->sp1l[x]++;
            node->sp1r[y]++;
        }
    }
}

void FreqTrie::increase(const std::vector<Sequence> &sequences, bool include_self)
{
    for (std::vector<Sequence>::const_iterator it = sequences.begin();
         it != sequences.end(); ++it)
    {
        increase(*it, include_self);
    }
}

void FreqTrie::decrease(const Sequence &sequence, bool include_self)
{
    size_t n = sequence.size();
    for (size_t i = 0; i < n; ++i)
    {
        FreqTrieNode *node = root_;
        for (size_t j = i; j < n && j - i < max_depth_; ++j)
        {
            if (!include_self && i == 0 && j == n - 1) { continue; }

            node = node->children[sequence[j]];
            node->f--;
        }
    }
}

void FreqTrie::decrease(const std::vector<Sequence> &sequences, bool include_self)
{
    for (std::vector<Sequence>::const_iterator it = sequences.begin();
         it != sequences.end(); ++it)
    {
        decrease(*it, include_self);
    }
}

void FreqTrie::update_hsp1(void)
{
    size_t trie_depth = depth();
    size_t num_alphabets = root_->children.size() + 1;

    size_t *nums = new size_t[trie_depth];
    double *hl_avg = new double[trie_depth];
    double *hr_avg = new double[trie_depth];

    memset(nums, 0, sizeof(size_t) * trie_depth);
    memset(hl_avg, 0, sizeof(double) * trie_depth);
    memset(hr_avg, 0, sizeof(double) * trie_depth);

    for (Iterator it = begin(); it != end(); ++it)
    {
        size_t node_depth = it->first - 1;
        FreqTrieNode *node = it->second;

        node->hl = entropy(node->sp1l, num_alphabets);
        node->hr = entropy(node->sp1r, num_alphabets);
        hl_avg[node_depth] += node->hl;
        hr_avg[node_depth] += node->hr;
        nums[node_depth]++;
    }

    for (size_t i = 0; i < trie_depth; ++i)
    {
        hl_avg[i] /= nums[i];
        hr_avg[i] /= nums[i];
    }

    for (Iterator it = begin(); it != end(); ++it)
    {
        size_t node_depth = it->first - 1;
        FreqTrieNode *node = it->second;

        node->hl /= hl_avg[node_depth];
        node->hr /= hr_avg[node_depth];
    }

    delete [] nums;
    delete [] hl_avg;
    delete [] hr_avg;
}

void FreqTrie::update_fm(void)
{
    clear_fm();

    size_t trie_depth = depth();
    size_t *nums = new size_t[trie_depth];
    freq_avg_ = new double[trie_depth];

    memset(nums, 0, sizeof(size_t) * trie_depth);
    memset(freq_avg_, 0, sizeof(double) * trie_depth);

    for (Iterator it = begin(); it != end(); ++it)
    {
        size_t node_depth = it->first - 1;
        FreqTrieNode *node = it->second;

        freq_avg_[node_depth] += node->f;
        nums[node_depth]++;
    }

    for (size_t i = 0; i < trie_depth; ++i)
    {
        freq_avg_[i] /= nums[i];
    }

    delete [] nums;
}

void FreqTrie::update_iv(void)
{
    if (freq_avg_ == NULL) { throw std::exception(); }

    for (Iterator it = begin(); it != end(); ++it)
    {
        size_t node_depth = it->first - 1;
        FreqTrieNode *node = it->second;

        node->iv = pow(node->f / freq_avg_[node_depth], node_depth + 1);
    }
}

double FreqTrie::get_hl(const Sequence &sequence) const
{
    return get_hl(sequence.begin(), sequence.end());
}

double FreqTrie::get_hl(const Sequence::const_iterator &begin,
                        const Sequence::const_iterator &end) const
{
    FreqTrieNode const *node = find(begin, end);
    if (node == NULL) { return -1; }

    return node->hl;
}

double FreqTrie::get_hr(const Sequence &sequence) const
{
    return get_hr(sequence.begin(), sequence.end());
}

double FreqTrie::get_hr(const Sequence::const_iterator &begin,
                        const Sequence::const_iterator &end) const
{
    FreqTrieNode const *node = find(begin, end);
    if (node == NULL) { return -1; }

    return node->hr;
}

double FreqTrie::get_iv(const Sequence &sequence) const
{
    return get_iv(sequence.begin(), sequence.end());
}

double FreqTrie::get_iv(const Sequence::const_iterator &begin,
                        const Sequence::const_iterator &end) const
{
    FreqTrieNode const *node = find(begin, end);
    if (node == NULL) { return -1; }

    return node->iv;
}

size_t FreqTrie::depth(void) const
{
    return root_->depth();
}

size_t FreqTrie::max_depth(void) const
{
    return max_depth_;
}

FreqTrie::Iterator FreqTrie::begin(void)
{
    return ++Iterator(root_);
}

FreqTrie::ConstIterator FreqTrie::begin(void) const
{
    return ++ConstIterator(root_);
}

FreqTrie::Iterator FreqTrie::end(void)
{
    return Iterator();
}

FreqTrie::ConstIterator FreqTrie::end(void) const
{
    return ConstIterator();
}

FreqTrie::FreqTrieNode const *FreqTrie::find(const Sequence &sequence) const
{
    return find(sequence.begin(), sequence.end());
}

FreqTrie::FreqTrieNode const *FreqTrie::find(
    const Sequence::const_iterator &begin,
    const Sequence::const_iterator &end) const
{
    NodeCollection::const_iterator result_it;
    FreqTrieNode *node = root_;
    for (Sequence::const_iterator it = begin; it != end; ++it)
    {
        node = node->get(*it);
        if (node == NULL) { break; }
    }

    return node;
}

double FreqTrie::entropy(CharCounts counts, size_t num_events)
{
    double n = 0;
    for (CharCounts::const_iterator it = counts.begin();
         it != counts.end(); ++it)
    {
        n += it->second;
    }

    n *= (1 + smooth_);

    double h = 0;
    for (CharCounts::const_iterator it = counts.begin();
         it != counts.end(); ++it)
    {
        double p = (it->second + smooth_) / n;
        h -= p * log(p);
    }

    if (smooth_ > 0)
    {
        size_t num_zeros = num_events - counts.size();
        double p = smooth_ / n;
        h -= num_zeros * (p * log(p));
    }

    return h;
}

void FreqTrie::clear_fm(void)
{
    if (freq_avg_ != NULL)
    {
        delete [] freq_avg_;
    }

    freq_avg_ = NULL;
}

void FreqTrie::clear(void)
{
    root_->clear();
    clear_fm();
}

/************************************************
 * Implementation: class FreqTrie::BaseIterator
 ************************************************/

template<typename T>
FreqTrie::BaseIterator<T>::BaseIterator(void)
    : stack_()
{
    // do nothing
}

template<typename T>
FreqTrie::BaseIterator<T>::BaseIterator(T *node)
    : stack_()
{
    stack_.push(std::make_pair(0, node));
}

template<typename T>
FreqTrie::BaseIterator<T> &FreqTrie::BaseIterator<T>::operator++(void)
{
    Value top = stack_.top();
    stack_.pop();

    size_t depth = top.first + 1;
    T *node = top.second;
    for (NodeCollection::const_iterator it = node->children.begin();
         it != node->children.end(); ++it)
    {
        stack_.push(std::make_pair(depth, it->second));
    }

    return *this;
}

template<typename T>
FreqTrie::BaseIterator<T> FreqTrie::BaseIterator<T>::operator++(int)
{
    BaseIterator it(this);
    ++(*this);
    return it;
}

template<typename T>
std::pair<size_t, T *> &FreqTrie::BaseIterator<T>::operator*(void) const
{
    return stack_.top();
}

template<typename T>
std::pair<size_t, T *> const *FreqTrie::BaseIterator<T>::operator->(void) const
{
    return &(stack_.top());
}

template<typename T>
bool FreqTrie::BaseIterator<T>::operator==(const BaseIterator &it) const
{
    if (it.stack_.empty())      { return stack_.empty(); }
    else if (stack_.empty())    { return false; }

    return stack_.top() == it.stack_.top();
}

template<typename T>
bool FreqTrie::BaseIterator<T>::operator!=(const BaseIterator &it) const
{
    return !(*this == it);
}

/************************************************
 * Implementation: struct FreqTrie::FreqTrieNode
 ************************************************/

FreqTrie::FreqTrieNode::FreqTrieNode(void) : f(0), hl(0), hr(0), iv(0)
{
    // do nothing
}

FreqTrie::FreqTrieNode::FreqTrieNode(const FreqTrie::FreqTrieNode &node)
    : sp1l(node.sp1l), sp1r(node.sp1r), f(node.f), hl(node.hl), hr(node.hr), iv(node.iv)
{
    for (NodeCollection::const_iterator it = node.children.begin();
         it != node.children.end(); ++it)
    {
        FreqTrieNode *node = new FreqTrieNode(*(it->second));
        children[it->first] = node;
    }
}

FreqTrie::FreqTrieNode::~FreqTrieNode(void)
{
    clear();
}

FreqTrie::FreqTrieNode &FreqTrie::FreqTrieNode::operator=(const FreqTrie::FreqTrieNode &node)
{
    if (&node != this) { return *this; }

    clear();

    sp1l = node.sp1l;
    sp1r = node.sp1r;
    f = node.f;
    hl = node.hl;
    hr = node.hr;
    iv = node.iv;

    for (NodeCollection::const_iterator it = node.children.begin();
         it != node.children.end(); ++it)
    {
        FreqTrieNode *node = new FreqTrieNode(*(it->second));
        children[it->first] = node;
    }

    return *this;
}

FreqTrie::FreqTrieNode const *FreqTrie::FreqTrieNode::get(Char key) const
{
    NodeCollection::const_iterator it = children.find(key);
    if (it != children.end())
    {
        return it->second;
    }

    return NULL;
}

FreqTrie::FreqTrieNode *FreqTrie::FreqTrieNode::get(Char key, bool create)
{
    NodeCollection::iterator it = children.find(key);
    if (it != children.end())   { return it->second; }
    else if (!create)           { return NULL; }

    children[key] = new FreqTrieNode();
    return children[key];
}

size_t FreqTrie::FreqTrieNode::depth(void) const
{
    if (children.empty()) { return 0; }

    size_t max_depth = 0;
    for (NodeCollection::const_iterator it = children.begin();
         it != children.end(); ++it)
    {
        size_t depth = it->second->depth();
        if (depth > max_depth)
        {
            max_depth = depth;
        }
    }

    return max_depth + 1;
}

void FreqTrie::FreqTrieNode::clear(void)
{
    for (NodeCollection::const_iterator it = children.begin();
         it != children.end(); ++it)
    {
        delete it->second;
    }

    children.clear();
    f = hl = hr = iv = 0;
}

} // namespace esa
<|endoftext|>


<commit_before>// Elementary DMRG for Heisenberg S=1/2 chain,
// infinite system algorithm
// ED with Lanczos
//
//Roger Melko Feb 26 2006

#include <blitz/array.h>

BZ_USING_NAMESPACE(blitz)

//template function prototypes
template<typename T> Array<T,2> reduceM2M2(const Array<T,4>&, const int);
void EigenValuesLAN(Array<double,4>&, Array<double,2>&, const int, double *);
void DMlargeEigen(Array<double,2>&, Array<double,2>&, const int, const int);

int main()
{
  int iter, NumI;
  int i1, i1p, i2, i2p, i3, i4;
  int b1;
  int m, st;     //# states
  int sites;     //# sites
  double Eval;   //Eigenvalue

  cout<<"# states to keep: ";
  cin>>m;

  //Matrices
  Array<double,4> TSR(2,2,2,2);  //tensor product for Hab hamiltonian

  Array<double,4> Habcd(4,4,4,4); //superblock hamiltonian
  Array<double,2> HAB(4,4);        //new SYSTEM Hamiltonian
  Array<double,2> Psi(4,4); // ground state wavefunction
  Array<double,2> rhoTSR(4,4); // reduced density matrix
  Array<double,2> OO(m,4);   //the TRUNCATION matrix
  Array<double,2> OT(4,m);   // trasposed truncation matrix
  Array<double,2> Hl(4,m);   // the left half of new system H

  Array<double,2> HAp(4,4);  //A' block hamiltonian
  Array<double,2> SzL(4,4);   //Sz(left) operator
  Array<double,2> SmL(4,4);   //Sm(left) operator
  Array<double,2> SpL(4,4);   //Sp(left) operator

  //create identity matrices
  Array<double,2> I2(2,2), I4(4,4), I2m(2*m,2*m);
  I2=0.0; I4=0.0; I2m=0.0;
  for (b1=0; b1<2; b1++) I2(b1,b1)=1.0;
  for (b1=0; b1<4; b1++) I4(b1,b1)=1.0;
  for (b1=0; b1<(2*m); b1++) I2m(b1,b1)=1.0;
  Array<double,2> I2st(4,4);
  I2st = I4;

  // Create pauli matrices
  Array<double,2> Sz(2,2), Sp(2,2), Sm(2,2);
  Sz = 0.5, 0,
       0, -0.5;
  Sp = 0, 1.0,
       0, 0;
  Sm = 0, 0,
       1.0, 0;

  //tensor indices
  firstIndex i;    secondIndex j;
  thirdIndex k;    fourthIndex l;

  cout<<"Iterations : ";
  cin>>NumI;

  //create a tensor product: two-site Hamiltonian
  TSR = Sz(i,k)*Sz(j,l)+ 0.5*Sp(i,k)*Sm(j,l) + 0.5*Sm(i,k)*Sp(j,l) ;
  //write as 2D matrix in combined basis
  Array<double,2> H12 = reduceM2M2(TSR,2);
  //cout<<"H12 "<<H12<<endl;

  TSR = Sz(i,k)*I2(j,l);
  Array<double,2> SzAB = reduceM2M2(TSR,2);

  TSR = Sm(i,k)*I2(j,l);
  Array<double,2> SmAB = reduceM2M2(TSR,2);

  TSR = Sp(i,k)*I2(j,l);
  Array<double,2> SpAB = reduceM2M2(TSR,2);

  HAB = H12;
  st = 4;     //start with a 2^2=4 state system
  sites = 2;

  /******infinite system algorithm loop first iteration**********/
  /******build system until number of desired states m **********/

  while(st <= m) {

   Habcd = HAB(i,k)*I2st(j,l) + I2st(i,k)*HAB(j,l) +
      SzAB(i,k)*SzAB(j,l)+ 0.5*SpAB(i,k)*SmAB(j,l) + 0.5*SmAB(i,k)*SpAB(j,l);

    EigenValuesLAN(Habcd,Psi,(st*st),&Eval);

    cout<<"sites: "<<2.0*sites;
    cout<<" Energy: "<<Eval/(2.0*sites)<<endl;

    HAp.resize(st,st);
    HAp = HAB;   /*USE IF NO RG FOR 1st STEP*/
    SzL.resize(st,st);
    SzL = SzAB;
    SpL.resize(st,st);
    SpL = SpAB;
    SmL.resize(st,st);
    SmL = SmAB;

    // Add a single spin  (m*m*2*2 tensor)
    TSR.resize(st,2,st,2);

    TSR = HAp(i,k)*I2(j,l) + SzL(i,k)*Sz(j,l)+
      0.5*SpL(i,k)*Sm(j,l) + 0.5*SmL(i,k)*Sp(j,l) ;
    HAB.resize(2*st,2*st);            //Hamiltonian for next iteration
    HAB = reduceM2M2(TSR,st);
   //   cout<<HAB<<endl;

    SzAB.resize(2*st,2*st);  //Operators for next iteration
    TSR = I2st(i,k)*Sz(j,l);
    SzAB = reduceM2M2(TSR,st);

    SpAB.resize(2*st,2*st);
    TSR = I2st(i,k)*Sp(j,l);
    SpAB = reduceM2M2(TSR,st);

    SmAB.resize(2*st,2*st);
    TSR = I2st(i,k)*Sm(j,l);
    SmAB = reduceM2M2(TSR,st);

    Habcd.resize(2*st,2*st,2*st,2*st);   //re-prepare superblock matrix
    Psi.resize(2*st,2*st);             //GS wavefunction
    rhoTSR.resize(2*st,2*st);
    OO.resize(st,(2*st));
    OT.resize((2*st),st);
    Hl.resize((2*st),st);

    st *= 2;
    sites += 1;

    I2st.resize(2*st,2*st);    //redifine identity matrix
    I2st = 0.0;
    for (b1=0; b1<(2*st); b1++) I2st(b1,b1)=1.0;

  }//end while

  /*******************second+ iteration down here*************/

  for (iter = 1; iter<NumI; iter++){

    Habcd = HAB(i,k)*I2m(j,l) + I2m(i,k)*HAB(j,l) +
      SzAB(i,k)*SzAB(j,l)+ 0.5*SpAB(i,k)*SmAB(j,l) + 0.5*SmAB(i,k)*SpAB(j,l);

    EigenValuesLAN(Habcd,Psi,(2*m)*(2*m),&Eval);
    cout<<2*sites<<" "<<Eval/(2.0*sites)<<endl;

    rhoTSR = 0;
    for (i1=0; i1<2*m; i1++)
      for (i1p=0; i1p<2*m; i1p++)
        for (i2=0; i2<2*m; i2++)
 	  rhoTSR(i1,i1p) += Psi(i1,i2)*Psi(i1p,i2);

    DMlargeEigen(rhoTSR, OO, (2*m), m);
    for (i1=0; i1<2*m; i1++)
      for (i2=0; i2<m; i2++)
        OT(i1,i2) = OO(i2,i1);  //Transpose

    //transform Operator Matrices to new basis
    Hl = sum(HAB(i,k)*OT(k,j),k);   //Ha'
    HAp = sum(OO(i,k)*Hl(k,j),k);   //(inner product)

    Hl = sum(SzAB(i,k)*OT(k,j),k);
    SzL = sum(OO(i,k)*Hl(k,j),k);

    Hl = sum(SpAB(i,k)*OT(k,j),k);
    SpL = sum(OO(i,k)*Hl(k,j),k);

    Hl = sum(SmAB(i,k)*OT(k,j),k);
    SmL = sum(OO(i,k)*Hl(k,j),k);

    // Add a single spin  (m*m*2*2 tensor)
    TSR = HAp(i,k)*I2(j,l) + SzL(i,k)*Sz(j,l)+
      0.5*SpL(i,k)*Sm(j,l) + 0.5*SmL(i,k)*Sp(j,l) ;
    HAB = reduceM2M2(TSR,m);

   sites += 1;

  }//iter

  return 0;
}

/*****************************************************************/
template<typename T>
Array<T,2> reduceM2M2(const Array<T,4>& T2, const int m)
/****reduces a m,2,m,2 matrix to a 2m*2m matrix
     over the direct product basis of 2 spins*************/
{
  int r,c;
  Array<double,2> M4(2*m,2*m);

  r=0;
  for (int a1=0; a1<m; a1++)
    for (int a2=0; a2<2; a2++){
      c=0;
      for (int a3=0; a3<m; a3++)
	for (int a4=0; a4<2; a4++){
	  M4(r,c) = T2(a1,a2,a3,a4);
	  c++;
	}
      r++;
    }

  return M4;

}

<commit_msg>works with any # states m: need to check definition m versus 2m<commit_after>// Elementary DMRG for Heisenberg S=1/2 chain,
// infinite system algorithm
// ED with Lanczos
//
//Roger Melko Feb 26 2006

#include <blitz/array.h>

BZ_USING_NAMESPACE(blitz)

//template function prototypes
template<typename T> Array<T,2> reduceM2M2(const Array<T,4>&, const int);
void EigenValuesLAN(Array<double,4>&, Array<double,2>&, const int, double *);
void DMlargeEigen(Array<double,2>&, Array<double,2>&, const int, const int);

int main()
{
  int iter, NumI;
  int i1, i1p, i2, i2p, i3, i4;
  int b1;
  int m, st;     //# states
  int sites;     //# sites
  double Eval;   //Eigenvalue

  cout<<"# states to keep: ";
  cin>>m;

  //Matrices
  Array<double,4> TSR(2,2,2,2);  //tensor product for Hab hamiltonian

  Array<double,4> Habcd(4,4,4,4); //superblock hamiltonian
  Array<double,2> HAB(4,4);        //new SYSTEM Hamiltonian
  Array<double,2> Psi(4,4); // ground state wavefunction
  Array<double,2> rhoTSR(4,4); // reduced density matrix
  Array<double,2> OO(m,4);   //the TRUNCATION matrix
  Array<double,2> OT(4,m);   // trasposed truncation matrix
  Array<double,2> Hl(4,m);   // the left half of new system H

  Array<double,2> HAp(4,4);  //A' block hamiltonian
  Array<double,2> SzL(4,4);   //Sz(left) operator
  Array<double,2> SmL(4,4);   //Sm(left) operator
  Array<double,2> SpL(4,4);   //Sp(left) operator

  //create identity matrices
  Array<double,2> I2(2,2), I4(4,4), I2m(2*m,2*m);
  I2=0.0; I4=0.0; I2m=0.0;
  for (b1=0; b1<2; b1++) I2(b1,b1)=1.0;
  for (b1=0; b1<4; b1++) I4(b1,b1)=1.0;
  for (b1=0; b1<(2*m); b1++) I2m(b1,b1)=1.0;
  Array<double,2> I2st(4,4);
  I2st = I4;

  // Create pauli matrices
  Array<double,2> Sz(2,2), Sp(2,2), Sm(2,2);
  Sz = 0.5, 0,
       0, -0.5;
  Sp = 0, 1.0,
       0, 0;
  Sm = 0, 0,
       1.0, 0;

  //tensor indices
  firstIndex i;    secondIndex j;
  thirdIndex k;    fourthIndex l;

  cout<<"Iterations : ";
  cin>>NumI;

  //create a tensor product: two-site Hamiltonian
  TSR = Sz(i,k)*Sz(j,l)+ 0.5*Sp(i,k)*Sm(j,l) + 0.5*Sm(i,k)*Sp(j,l) ;
  //write as 2D matrix in combined basis
  Array<double,2> H12 = reduceM2M2(TSR,2);
  //cout<<"H12 "<<H12<<endl;

  TSR = Sz(i,k)*I2(j,l);
  Array<double,2> SzAB = reduceM2M2(TSR,2);

  TSR = Sm(i,k)*I2(j,l);
  Array<double,2> SmAB = reduceM2M2(TSR,2);

  TSR = Sp(i,k)*I2(j,l);
  Array<double,2> SpAB = reduceM2M2(TSR,2);

  HAB = H12;
  st = 2;     //start with a 2^2=4 state system
  sites = 2;

  /******infinite system algorithm loop first iteration**********/
  /******build system until number of desired states m **********/

  while(st <= m) {

   Habcd = HAB(i,k)*I2st(j,l) + I2st(i,k)*HAB(j,l) +
      SzAB(i,k)*SzAB(j,l)+ 0.5*SpAB(i,k)*SmAB(j,l) + 0.5*SmAB(i,k)*SpAB(j,l);

    EigenValuesLAN(Habcd,Psi,(4*st*st),&Eval);

    cout<<"sites: "<<2.0*sites;
    cout<<" Energy: "<<Eval/(2.0*sites)<<endl;

    HAp.resize(2*st,2*st);
    HAp = HAB;   /*USE IF NO RG FOR 1st STEP*/
    SzL.resize(2*st,2*st);
    SzL = SzAB;
    SpL.resize(2*st,2*st);
    SpL = SpAB;
    SmL.resize(2*st,2*st);
    SmL = SmAB;

    // Add a single spin  (m*m*2*2 tensor)
    st *= 2;
    TSR.resize(st,2,st,2);

    TSR = HAp(i,k)*I2(j,l) + SzL(i,k)*Sz(j,l)+
      0.5*SpL(i,k)*Sm(j,l) + 0.5*SmL(i,k)*Sp(j,l) ;
    HAB.resize(2*st,2*st);            //Hamiltonian for next iteration
    HAB = reduceM2M2(TSR,st);
   //   cout<<HAB<<endl;

    SzAB.resize(2*st,2*st);  //Operators for next iteration
    TSR = I2st(i,k)*Sz(j,l);
    SzAB = reduceM2M2(TSR,st);

    SpAB.resize(2*st,2*st);
    TSR = I2st(i,k)*Sp(j,l);
    SpAB = reduceM2M2(TSR,st);

    SmAB.resize(2*st,2*st);
    TSR = I2st(i,k)*Sm(j,l);
    SmAB = reduceM2M2(TSR,st);

    Habcd.resize(2*st,2*st,2*st,2*st);   //re-prepare superblock matrix
    Psi.resize(2*st,2*st);             //GS wavefunction
    rhoTSR.resize(2*st,2*st);
    OO.resize(m,(2*st));
    OT.resize((2*st),m);
    Hl.resize((2*st),m);

//    st *= 2;
    sites += 1;

    I2st.resize(4*st,4*st);    //redifine identity matrix
    I2st = 0.0;
    for (b1=0; b1<(4*st); b1++) I2st(b1,b1)=1.0;

  }//end while

  /*******************second+ iteration down here*************/

  for (iter = 1; iter<NumI; iter++){

    Habcd = HAB(i,k)*I2st(j,l) + I2st(i,k)*HAB(j,l) +
      SzAB(i,k)*SzAB(j,l)+ 0.5*SpAB(i,k)*SmAB(j,l) + 0.5*SmAB(i,k)*SpAB(j,l);

    EigenValuesLAN(Habcd,Psi,(4*st*st),&Eval);
    cout<<2*sites<<" "<<Eval/(2.0*sites)<<endl;

    rhoTSR = 0;
    for (i1=0; i1< 2*st; i1++)
      for (i1p=0; i1p< 2*st; i1p++)
        for (i2=0; i2< 2*st; i2++)
 	  rhoTSR(i1,i1p) += Psi(i1,i2)*Psi(i1p,i2);

    DMlargeEigen(rhoTSR, OO, 2*st, m);
    for (i1=0; i1<2*st; i1++)
      for (i2=0; i2< m; i2++)
        OT(i1,i2) = OO(i2,i1);  //Transpose

    st = m;

    if (iter == 1) HAp.resize(m,m);
    //transform Operator Matrices to new basis
    Hl = sum(HAB(i,k)*OT(k,j),k);   //Ha'
    HAp = sum(OO(i,k)*Hl(k,j),k);   //(inner product)

    if (iter == 1) SzL.resize(m,m);
    Hl = sum(SzAB(i,k)*OT(k,j),k);
    SzL = sum(OO(i,k)*Hl(k,j),k);

    if (iter == 1) SpL.resize(m,m);
    Hl = sum(SpAB(i,k)*OT(k,j),k);
    SpL = sum(OO(i,k)*Hl(k,j),k);

    if (iter == 1) SmL.resize(m,m);
    Hl = sum(SmAB(i,k)*OT(k,j),k);
    SmL = sum(OO(i,k)*Hl(k,j),k);

   if (iter == 1) TSR.resize(m,2,m,2);
    // Add a single spin  (m*m*2*2 tensor)
    TSR = HAp(i,k)*I2(j,l) + SzL(i,k)*Sz(j,l)+
      0.5*SpL(i,k)*Sm(j,l) + 0.5*SmL(i,k)*Sp(j,l) ;
    if (iter == 1) HAB.resize(2*m,2*m);
    HAB = reduceM2M2(TSR,m);

    if (iter == 1){
      SzAB.resize(2*m,2*m);  //Operators for next iteration
      TSR = I2m(i,k)*Sz(j,l);
      SzAB = reduceM2M2(TSR,m);

      SpAB.resize(2*m,2*m);
      TSR = I2m(i,k)*Sp(j,l);
      SpAB = reduceM2M2(TSR,m);

      SmAB.resize(2*m,2*m);
      TSR = I2m(i,k)*Sm(j,l);
      SmAB = reduceM2M2(TSR,m);
    }

   st = m;
   sites += 1;

   if (iter == 1){    //final resize
    I2st.resize(2*m,2*m);
    I2st = I2m;

    Habcd.resize(2*m,2*m,2*m,2*m);   //re-prepare superblock matrix
    Psi.resize(2*m,2*m);             //GS wavefunction
    rhoTSR.resize(2*m,2*m);
    OO.resize(m,(2*m));
    OT.resize((2*m),m);
    Hl.resize((2*m),m);

   }

  }//iter

  return 0;
}

/*****************************************************************/
template<typename T>
Array<T,2> reduceM2M2(const Array<T,4>& T2, const int m)
/****reduces a m,2,m,2 matrix to a 2m*2m matrix
     over the direct product basis of 2 spins*************/
{
  int r,c;
  Array<double,2> M4(2*m,2*m);

  r=0;
  for (int a1=0; a1<m; a1++)
    for (int a2=0; a2<2; a2++){
      c=0;
      for (int a3=0; a3<m; a3++)
	for (int a4=0; a4<2; a4++){
	  M4(r,c) = T2(a1,a2,a3,a4);
	  c++;
	}
      r++;
    }

  return M4;

}

<|endoftext|>


<commit_before>// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#if defined(HAVE_CONFIG_H)
#include <config/syscoin-config.h>
#endif

#include <cstddef>
#include <cstdint>
// SYSCOIN
#define _GNU_SOURCE 1
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <sys/cdefs.h>
#ifndef WIN32
#include <fcntl.h>
#include <sys/time.h>
#endif
#ifdef HAVE_SYS_GETRANDOM
#include <sys/syscall.h>
#include <linux/random.h>
#endif
#include <stdio.h>
#include <cstdlib>
#include <cstring>
#define likely(x)      __builtin_expect(!!(x), 1)
#define unlikely(x)    __builtin_expect(!!(x), 0)

#if defined(__i386__) || defined(__arm__)

extern "C" int64_t __udivmoddi4(uint64_t u, uint64_t v, uint64_t* rp);

extern "C" int64_t __wrap___divmoddi4(int64_t u, int64_t v, int64_t* rp)
{
    int32_t c1 = 0, c2 = 0;
    int64_t uu = u, vv = v;
    int64_t w;
    int64_t r;

    if (uu < 0) {
        c1 = ~c1, c2 = ~c2, uu = -uu;
    }
    if (vv < 0) {
        c1 = ~c1, vv = -vv;
    }

    w = __udivmoddi4(uu, vv, (uint64_t*)&r);
    if (c1)
        w = -w;
    if (c2)
        r = -r;

    *rp = r;
    return w;
}
#endif

extern "C" float log2f_old(float x);
#ifdef __i386__
__asm(".symver log2f_old,log2f@GLIBC_2.1");
#elif defined(__amd64__)
__asm(".symver log2f_old,log2f@GLIBC_2.2.5");
#elif defined(__arm__)
__asm(".symver log2f_old,log2f@GLIBC_2.4");
#elif defined(__aarch64__)
__asm(".symver log2f_old,log2f@GLIBC_2.17");
#elif defined(__powerpc64__)
#  ifdef WORDS_BIGENDIAN
__asm(".symver log2f_old,log2f@GLIBC_2.3");
#  else
__asm(".symver log2f_old,log2f@GLIBC_2.17");
#  endif
#elif defined(__riscv)
__asm(".symver log2f_old,log2f@GLIBC_2.27");
#endif
extern "C" float __wrap_log2f(float x)
{
    return log2f_old(x);
}
// SYSCOIN wrapper for getrandom 2.25 glibc compatibility for up to 2.17 backwards
#ifndef WIN32
/** Fallback: get 32 bytes of system entropy from /dev/urandom. The most
 * compatible way to get cryptographic randomness on UNIX-ish platforms.
 */
static ssize_t GetDevURandom(unsigned char *ent32, size_t length)
{
    int f = open("/dev/urandom", O_RDONLY);
    if (f == -1) {
        return -1;
    }
    size_t have = 0;
    do {
        ssize_t n = read(f, ent32 + have, length - have);
        if (n <= 0 || n + have > length) {
            close(f);
            return n;
        }
        have += n;
    } while (have < length);
    close(f);
    return (ssize_t)have;
}
#endif

/* Write LENGTH bytes of randomness starting at BUFFER.  Return 0 on
    success and -1 on failure.  */
extern "C" ssize_t __wrap_getrandom (void *buffer, size_t length, unsigned int flags)
{
    ssize_t rv = -1;
    #if defined(HAVE_SYS_GETRANDOM)
    /* Linux. From the getrandom(2) man page:
    * "If the urandom source has been initialized, reads of up to 256 bytes
    * will always return as many bytes as requested and will not be
    * interrupted by signals."
    */
    rv = syscall(SYS_getrandom, buffer, length, flags);
    if ((size_t)rv != length) {
        if (rv < 0 && errno == ENOSYS) {
            /* Fallback for kernel <3.17: the return value will be -1 and errno
            * ENOSYS if the syscall is not available, in that case fall back
            * to /dev/urandom.
            */
            return GetDevURandom((unsigned char*)buffer, length);
        }
    }
    #else
        return GetDevURandom((unsigned char*)buffer, length);
    #endif
    return rv;
}

/* Write LENGTH bytes of randomness starting at BUFFER.  Return 0 on
   success and -1 on failure.  */
extern "C" int getentropy (void *buffer, size_t length)
{
  /* The interface is documented to return EIO for buffer lengths
     longer than 256 bytes.  */
  if (length > 256)
    {
      errno = EIO;
      return -1;
    }

  /* Try to fill the buffer completely.  Even with the 256 byte limit
     above, we might still receive an EINTR error (when blocking
     during boot).  */
  void *end = buffer + length;
  while (buffer < end)
    {
      /* NB: No cancellation point.  */

      ssize_t bytes = getrandom(buffer, end - buffer, 0);
      if (bytes < 0)
        {
          if (errno == EINTR)
            /* Try again if interrupted by a signal.  */
            continue;
          else
            return -1;
        }
      if (bytes == 0)
        {
          /* No more bytes available.  This should not happen under
             normal circumstances.  */
          errno = EIO;
          return -1;
        }
      /* Try again in case of a short read.  */
      buffer += bytes;
    }
  return 0;
}

// fmemopen

typedef struct fmemopen_cookie_struct fmemopen_cookie_t;
struct fmemopen_cookie_struct
{
  char        *buffer;   /* memory buffer.  */
  int         mybuffer;  /* allocated my buffer?  */
  int         append;    /* buffer open for append?  */
  size_t      size;      /* buffer length in bytes.  */
  off_t     pos;       /* current position at the buffer.  */
  size_t      maxpos;    /* max position in buffer.  */
};

static ssize_t
fmemopen_read (void *cookie, char *b, size_t s)
{
  fmemopen_cookie_t *c = (fmemopen_cookie_t *) cookie;

  if (c->pos + s > c->maxpos)
    {
      s = c->maxpos - c->pos;
      if ((size_t) c->pos > c->maxpos)
	s = 0;
    }

  memcpy (b, &(c->buffer[c->pos]), s);

  c->pos += s;

  return s;
}

static ssize_t
fmemopen_write (void *cookie, const char *b, size_t s)
{
  fmemopen_cookie_t *c = (fmemopen_cookie_t *) cookie;;
  off_t pos = c->append ? c->maxpos : c->pos;
  int addnullc = (s == 0 || b[s - 1] != '\0');

  if (pos + s > c->size)
    {
      if ((size_t) (c->pos + addnullc) >= c->size)
	{
	  errno = ENOSPC;
	  return 0;
	}
      s = c->size - pos;
    }

  memcpy (&(c->buffer[pos]), b, s);

  c->pos = pos + s;
  if ((size_t) c->pos > c->maxpos)
    {
      c->maxpos = c->pos;
      if (c->maxpos < c->size && addnullc)
	c->buffer[c->maxpos] = '\0';
      /* A null byte is written in a stream open for update iff it fits.  */
      else if (c->append == 0 && addnullc != 0)
	c->buffer[c->size-1] = '\0';
    }

  return s;
}

static int
fmemopen_seek (void *cookie, off_t *p, int w)
{
  off_t np;
  fmemopen_cookie_t *c = (fmemopen_cookie_t *) cookie;

  switch (w)
    {
    case SEEK_SET:
      np = *p;
      break;

    case SEEK_CUR:
      np = c->pos + *p;
      break;

    case SEEK_END:
      np = c->maxpos + *p;
      break;

    default:
      return -1;
    }

  if (np < 0 || (size_t) np > c->size)
    {
      errno = EINVAL;
      return -1;
    }

  *p = c->pos = np;

  return 0;
}

static int
fmemopen_close (void *cookie)
{
  fmemopen_cookie_t *c = (fmemopen_cookie_t *) cookie;

  if (c->mybuffer)
    free (c->buffer);
  free (c);

  return 0;
}

extern "C" FILE * __wrap_fmemopen (void *buf, size_t len, const char *mode)
{
  cookie_io_functions_t iof;
  fmemopen_cookie_t *c;
  FILE *result;

  c = (fmemopen_cookie_t *) calloc (sizeof (fmemopen_cookie_t), 1);
  if (c == NULL)
    return NULL;

  c->mybuffer = (buf == NULL);

  if (c->mybuffer)
    {
      c->buffer = (char *) malloc (len);
      if (c->buffer == NULL)
	{
	  free (c);
	  return NULL;
	}
      c->buffer[0] = '\0';
    }
  else
    {
      if (likely ((uintptr_t) len > -(uintptr_t) buf))
	{
	  free (c);
	  errno = EINVAL;
	  return NULL;
	}

      c->buffer = (char*)buf;

      /* POSIX states that w+ mode should truncate the buffer.  */
      if (mode[0] == 'w' && mode[1] == '+')
	c->buffer[0] = '\0';

      if (mode[0] == 'a')
        c->maxpos = strnlen (c->buffer, len);
    }

  /* Mode   |  starting position (cookie::pos) |          size (cookie::size)
     ------ |----------------------------------|-----------------------------
     read   |          beginning of the buffer |                size argument
     write  |          beginning of the buffer |                         zero
     append |    first null or size buffer + 1 |  first null or size argument
   */

  c->size = len;

  if (mode[0] == 'r')
    c->maxpos = len;

  c->append = mode[0] == 'a';
  if (c->append)
    c->pos = c->maxpos;
  else
    c->pos = 0;

  iof.read = fmemopen_read;
  iof.write = fmemopen_write;
  iof.seek = fmemopen_seek;
  iof.close = fmemopen_close;

  result = fopencookie (c, mode, iof);
  if (likely (result == NULL))
    {
      if (c->mybuffer)
	free (c->buffer);

      free (c);
    }

  return result;
}<commit_msg>Revert "Revert "Update glibc_compat.cpp""<commit_after>// Copyright (c) 2009-2020 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#if defined(HAVE_CONFIG_H)
#include <config/syscoin-config.h>
#endif

#include <cstddef>
#include <cstdint>
// SYSCOIN
#define _GNU_SOURCE 1
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <sys/cdefs.h>
#ifndef WIN32
#include <fcntl.h>
#include <sys/time.h>
#endif
#ifdef HAVE_SYS_GETRANDOM
#include <sys/syscall.h>
#include <linux/random.h>
#endif
#include <stdio.h>
#include <cstdlib>
#include <cstring>
#define likely(x)      __builtin_expect(!!(x), 1)
#define unlikely(x)    __builtin_expect(!!(x), 0)

#if defined(__i386__) || defined(__arm__)

extern "C" int64_t __udivmoddi4(uint64_t u, uint64_t v, uint64_t* rp);

extern "C" int64_t __wrap___divmoddi4(int64_t u, int64_t v, int64_t* rp)
{
    int32_t c1 = 0, c2 = 0;
    int64_t uu = u, vv = v;
    int64_t w;
    int64_t r;

    if (uu < 0) {
        c1 = ~c1, c2 = ~c2, uu = -uu;
    }
    if (vv < 0) {
        c1 = ~c1, vv = -vv;
    }

    w = __udivmoddi4(uu, vv, (uint64_t*)&r);
    if (c1)
        w = -w;
    if (c2)
        r = -r;

    *rp = r;
    return w;
}
#endif

extern "C" float log2f_old(float x);
#ifdef __i386__
__asm(".symver log2f_old,log2f@GLIBC_2.1");
#elif defined(__amd64__)
__asm(".symver log2f_old,log2f@GLIBC_2.2.5");
#elif defined(__arm__)
__asm(".symver log2f_old,log2f@GLIBC_2.4");
#elif defined(__aarch64__)
__asm(".symver log2f_old,log2f@GLIBC_2.17");
#elif defined(__powerpc64__)
#  ifdef WORDS_BIGENDIAN
__asm(".symver log2f_old,log2f@GLIBC_2.3");
#  else
__asm(".symver log2f_old,log2f@GLIBC_2.17");
#  endif
#elif defined(__riscv)
__asm(".symver log2f_old,log2f@GLIBC_2.27");
#endif
extern "C" float __wrap_log2f(float x)
{
    return log2f_old(x);
}
// SYSCOIN wrapper for getrandom 2.25 glibc compatibility for up to 2.17 backwards
#ifndef WIN32
/** Fallback: get 32 bytes of system entropy from /dev/urandom. The most
 * compatible way to get cryptographic randomness on UNIX-ish platforms.
 */
static ssize_t GetDevURandom(unsigned char *ent32, size_t length)
{
    int f = open("/dev/urandom", O_RDONLY);
    if (f == -1) {
        return -1;
    }
    size_t have = 0;
    do {
        ssize_t n = read(f, ent32 + have, length - have);
        if (n <= 0 || n + have > length) {
            close(f);
            return n;
        }
        have += n;
    } while (have < length);
    close(f);
    return (ssize_t)have;
}
#endif

/* Write LENGTH bytes of randomness starting at BUFFER.  Return 0 on
    success and -1 on failure.  */
extern "C" ssize_t __wrap_getrandom (void *buffer, size_t length, unsigned int flags)
{
    ssize_t rv = -1;
    #if defined(HAVE_SYS_GETRANDOM)
    /* Linux. From the getrandom(2) man page:
    * "If the urandom source has been initialized, reads of up to 256 bytes
    * will always return as many bytes as requested and will not be
    * interrupted by signals."
    */
    rv = syscall(SYS_getrandom, buffer, length, flags);
    if ((size_t)rv != length) {
        if (rv < 0 && errno == ENOSYS) {
            /* Fallback for kernel <3.17: the return value will be -1 and errno
            * ENOSYS if the syscall is not available, in that case fall back
            * to /dev/urandom.
            */
            return GetDevURandom((unsigned char*)buffer, length);
        }
    }
    #else
        return GetDevURandom((unsigned char*)buffer, length);
    #endif
    return rv;
}

/* Write LENGTH bytes of randomness starting at BUFFER.  Return 0 on
   success and -1 on failure.  */
extern "C" int __wrap_getentropy (void *buffer, size_t length)
{
  /* The interface is documented to return EIO for buffer lengths
     longer than 256 bytes.  */
  if (length > 256)
    {
      errno = EIO;
      return -1;
    }

  /* Try to fill the buffer completely.  Even with the 256 byte limit
     above, we might still receive an EINTR error (when blocking
     during boot).  */
  void *end = buffer + length;
  while (buffer < end)
    {
      /* NB: No cancellation point.  */

      ssize_t bytes = getrandom(buffer, end - buffer, 0);
      if (bytes < 0)
        {
          if (errno == EINTR)
            /* Try again if interrupted by a signal.  */
            continue;
          else
            return -1;
        }
      if (bytes == 0)
        {
          /* No more bytes available.  This should not happen under
             normal circumstances.  */
          errno = EIO;
          return -1;
        }
      /* Try again in case of a short read.  */
      buffer += bytes;
    }
  return 0;
}

// fmemopen

typedef struct fmemopen_cookie_struct fmemopen_cookie_t;
struct fmemopen_cookie_struct
{
  char        *buffer;   /* memory buffer.  */
  int         mybuffer;  /* allocated my buffer?  */
  int         append;    /* buffer open for append?  */
  size_t      size;      /* buffer length in bytes.  */
  off_t     pos;       /* current position at the buffer.  */
  size_t      maxpos;    /* max position in buffer.  */
};

static ssize_t
fmemopen_read (void *cookie, char *b, size_t s)
{
  fmemopen_cookie_t *c = (fmemopen_cookie_t *) cookie;

  if (c->pos + s > c->maxpos)
    {
      s = c->maxpos - c->pos;
      if ((size_t) c->pos > c->maxpos)
	s = 0;
    }

  memcpy (b, &(c->buffer[c->pos]), s);

  c->pos += s;

  return s;
}

static ssize_t
fmemopen_write (void *cookie, const char *b, size_t s)
{
  fmemopen_cookie_t *c = (fmemopen_cookie_t *) cookie;;
  off_t pos = c->append ? c->maxpos : c->pos;
  int addnullc = (s == 0 || b[s - 1] != '\0');

  if (pos + s > c->size)
    {
      if ((size_t) (c->pos + addnullc) >= c->size)
	{
	  errno = ENOSPC;
	  return 0;
	}
      s = c->size - pos;
    }

  memcpy (&(c->buffer[pos]), b, s);

  c->pos = pos + s;
  if ((size_t) c->pos > c->maxpos)
    {
      c->maxpos = c->pos;
      if (c->maxpos < c->size && addnullc)
	c->buffer[c->maxpos] = '\0';
      /* A null byte is written in a stream open for update iff it fits.  */
      else if (c->append == 0 && addnullc != 0)
	c->buffer[c->size-1] = '\0';
    }

  return s;
}

static int
fmemopen_seek (void *cookie, off_t *p, int w)
{
  off_t np;
  fmemopen_cookie_t *c = (fmemopen_cookie_t *) cookie;

  switch (w)
    {
    case SEEK_SET:
      np = *p;
      break;

    case SEEK_CUR:
      np = c->pos + *p;
      break;

    case SEEK_END:
      np = c->maxpos + *p;
      break;

    default:
      return -1;
    }

  if (np < 0 || (size_t) np > c->size)
    {
      errno = EINVAL;
      return -1;
    }

  *p = c->pos = np;

  return 0;
}

static int
fmemopen_close (void *cookie)
{
  fmemopen_cookie_t *c = (fmemopen_cookie_t *) cookie;

  if (c->mybuffer)
    free (c->buffer);
  free (c);

  return 0;
}

extern "C" FILE * __wrap_fmemopen (void *buf, size_t len, const char *mode)
{
  cookie_io_functions_t iof;
  fmemopen_cookie_t *c;
  FILE *result;

  c = (fmemopen_cookie_t *) calloc (sizeof (fmemopen_cookie_t), 1);
  if (c == NULL)
    return NULL;

  c->mybuffer = (buf == NULL);

  if (c->mybuffer)
    {
      c->buffer = (char *) malloc (len);
      if (c->buffer == NULL)
	{
	  free (c);
	  return NULL;
	}
      c->buffer[0] = '\0';
    }
  else
    {
      if (likely ((uintptr_t) len > -(uintptr_t) buf))
	{
	  free (c);
	  errno = EINVAL;
	  return NULL;
	}

      c->buffer = (char*)buf;

      /* POSIX states that w+ mode should truncate the buffer.  */
      if (mode[0] == 'w' && mode[1] == '+')
	c->buffer[0] = '\0';

      if (mode[0] == 'a')
        c->maxpos = strnlen (c->buffer, len);
    }

  /* Mode   |  starting position (cookie::pos) |          size (cookie::size)
     ------ |----------------------------------|-----------------------------
     read   |          beginning of the buffer |                size argument
     write  |          beginning of the buffer |                         zero
     append |    first null or size buffer + 1 |  first null or size argument
   */

  c->size = len;

  if (mode[0] == 'r')
    c->maxpos = len;

  c->append = mode[0] == 'a';
  if (c->append)
    c->pos = c->maxpos;
  else
    c->pos = 0;

  iof.read = fmemopen_read;
  iof.write = fmemopen_write;
  iof.seek = fmemopen_seek;
  iof.close = fmemopen_close;

  result = fopencookie (c, mode, iof);
  if (likely (result == NULL))
    {
      if (c->mybuffer)
	free (c->buffer);

      free (c);
    }

  return result;
}<|endoftext|>


<commit_before>// This file is part of Fuxedo
// Copyright (C) 2017 Aivars Kalvans <aivars.kalvans@gmail.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

#include <clara.hpp>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>

#include "extreader.h"

int main(int argc, char *argv[]) {
  /*
  bool show_help = false;

  std::vector<std::string> files;

  auto parser =
      clara::Help(show_help) +
      clara::Arg(files, "field_table")("field tables to process");

  auto result = parser.parse(clara::Args(argc, argv));
  if (!result || result.value().type() != clara::ParseResultType::Matched) {
    std::cerr << parser;
    return -1;
  }
  */

  try {
    extreader r(stdin);
    r.parse();
  } catch (const std::system_error &e) {
    std::cerr << e.code().message() << std::endl;
    return -1;
  } catch (const std::exception &e) {
    std::cerr << e.what() << std::endl;
    return -1;
  }

  return 0;
}
<commit_msg>one more fix for clang<commit_after>// This file is part of Fuxedo
// Copyright (C) 2017 Aivars Kalvans <aivars.kalvans@gmail.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

#include <clara.hpp>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include <system_error>

#include "extreader.h"

int main(int argc, char *argv[]) {
  /*
  bool show_help = false;

  std::vector<std::string> files;

  auto parser =
      clara::Help(show_help) +
      clara::Arg(files, "field_table")("field tables to process");

  auto result = parser.parse(clara::Args(argc, argv));
  if (!result || result.value().type() != clara::ParseResultType::Matched) {
    std::cerr << parser;
    return -1;
  }
  */

  try {
    extreader r(stdin);
    r.parse();
  } catch (const std::system_error &e) {
    std::cerr << e.code().message() << std::endl;
    return -1;
  } catch (const std::exception &e) {
    std::cerr << e.what() << std::endl;
    return -1;
  }

  return 0;
}
<|endoftext|>