<commit_before>// Copyright (c) 2013, German Neuroinformatics Node (G-Node)
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted under the terms of the BSD License. See
// LICENSE file in the root of the Project.

#include <list>
#include <algorithm>

#include <nix/Section.hpp>

using namespace std;
using namespace nix;

Section::Section()
    : NamedEntity()
{
}

Section::Section(nullptr_t ptr)
    : NamedEntity()
{
}

Section::Section(const Section &other)
    : NamedEntity(other.impl())
{
}

Section::Section(const shared_ptr<base::ISection> &p_impl)
    : NamedEntity(p_impl)
{
}

Section::Section(shared_ptr<base::ISection> &&ptr)
    : NamedEntity(std::move(ptr))
{
}

void Section::link(const Section &link) {
    if (link == none) {
        backend()->link(none);
    } else {
        backend()->link(link.id());
    }
}

//-----------------------------------------------------
// Methods concerning child sections
//-----------------------------------------------------

bool Section::hasSection(const Section &section) const {
    if (section == none) {
        throw std::runtime_error("Section::hasSection: Empty Section entity given!");
    }
    return backend()->hasSection(section.id());
}

bool Section::deleteSection(const Section &section) {
    if (section == none) {
        throw std::runtime_error("Section::deleteSection: Empty Section entity given!");
    }
    return backend()->deleteSection(section.id());
}

/*
 * Helper struct for {@link findSections}.
 */
struct SectionCont {
    SectionCont(Section s, size_t d = 0)
    : entity(s), depth(d)
    {}

    Section entity;
    size_t depth;
};

std::vector<Section> Section::sections(const util::Filter<Section>::type &filter) const {
    auto f = [this] (size_t i) { return getSection(i); };
    return getEntities<Section>(f,
                                sectionCount(),
                                filter);
}

std::vector<Section> Section::findSections(const util::Filter<Section>::type &filter,
                                           size_t max_depth) const
{
    std::vector<Section>  results;
    std::list<SectionCont> todo;

    todo.push_back(SectionCont(*this));

    while (todo.size() > 0)
    {
        SectionCont current = todo.front();
        todo.pop_front();

        bool filter_ok = filter(current.entity);
        if (filter_ok) {
            results.push_back(current.entity);
        }

        if (current.depth < max_depth) {
            std::vector<Section> children = current.entity.sections();
            size_t next_depth = current.depth + 1;

            for (auto it = children.begin(); it != children.end(); ++it) {
                todo.push_back(SectionCont(*it, next_depth));
            }
        }
    }

    return results;
}

static inline auto erase_section_with_id(vector<Section> &sections, const string &my_id)
    -> decltype(sections.size())
{
    sections.erase(remove_if(sections.begin(),
                             sections.end(),
                             [&my_id](const Section &section) {
                                 return my_id == section.id();
                             }),
                   sections.end());

    return sections.size();
}

std::vector<Section> Section::findRelated(const util::Filter<Section>::type &filter) const
{
    std::vector<Section> results = findDownstream(filter);
    const string &my_id = id();

    //This checking of results can be removed if we decide not to include this in findSection
    auto results_size = erase_section_with_id(results, my_id);

    if (results_size == 0) {
        results = findUpstream(filter);
    }
    //This checking of results can be removed if we decide not to include this in findSection
    results_size = erase_section_with_id(results, my_id);

    if (results_size == 0) {
        results = findSideways(filter, id());
    }
    return results;
}

//-----------------------------------------------------
// Methods for property access
//-----------------------------------------------------

bool Section::hasProperty(const Property &property) const {
    if (property == none) {
        throw std::runtime_error("Section::hasProperty: Empty Property entity given!");
    }
    return backend()->hasProperty(property.id());
}

std::vector<Property> Section::properties(const util::Filter<Property>::type &filter) const {
    auto f = [this] (size_t i) { return getProperty(i); };
    return getEntities<Property>(f,
            propertyCount(),
            filter);
}

bool Section::deleteProperty(const Property &property) {
    if (property == none) {
        throw std::runtime_error("Section::deleteProperty: Empty Property entity given!");
    }
    return backend()->deleteProperty(property.id());
}

vector<Property> Section::inheritedProperties() const {

    vector<Property> own = properties();

    if (link() == nullptr)
        return own;

    const vector<Property> linked = link().properties();

    copy_if (linked.begin(), linked.end(),
             back_inserter(own),
             [&own](const Property &linked_prop) {
                 return find_if (own.begin(), own.end(),
                                [&linked_prop](const Property &own_prop) {
                                    return linked_prop.name() == own_prop.name();
                                }) == own.end();
             });

    return own;
}

//------------------------------------------------------
// Operators and other functions
//------------------------------------------------------

size_t Section::tree_depth() const{
  const vector<Section> children = sections();
  size_t depth = 0;
  if (children.size() > 0) {
      for (auto &child : children) {
          depth = max(depth, child.tree_depth());
      }
      depth += 1;
  }
  return depth;
}

vector<Section> Section::findDownstream(const std::function<bool(Section)> &filter) const{
    vector<Section> results;
    size_t max_depth = tree_depth();
    size_t actual_depth = 1;
    while (results.size() == 0 && actual_depth <= max_depth) {
        results = findSections(filter, actual_depth);
        actual_depth += 1;
    }
    return results;
}

vector<Section> Section::findUpstream(const std::function<bool(Section)> &filter) const{
    vector<Section> results;
    Section p = parent();

    if (p != nullptr) {
        results = p.findSections(filter,1);
        if (results.size() > 0) {
            return results;
        }
        return p.findUpstream(filter);
    }
    return results;
}

vector<Section> Section::findSideways(const std::function<bool(Section)> &filter, const string &caller_id) const{
    vector<Section> results;
    Section p = parent();
    if (p != nullptr) {
        results = p.findSections(filter,1);
        if (results.size() > 0) {

            results.erase(remove_if(results.begin(),
                                    results.end(),
                                    [&caller_id](const Section &section) {
                                        return section.id() == caller_id;
                                    }),
                          results.end());

            return results;
        }
        return p.findSideways(filter, caller_id);
    }
    return results;
}

std::ostream& nix::operator<<(ostream &out, const Section &ent) {
    out << "Section: {name = " << ent.name();
    out << ", type = " << ent.type();
    out << ", id = " << ent.id() << "}";
    return out;
}
<commit_msg>Section: add <iterator> include<commit_after>// Copyright (c) 2013, German Neuroinformatics Node (G-Node)
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted under the terms of the BSD License. See
// LICENSE file in the root of the Project.

#include <list>
#include <algorithm>
#include <iterator>

#include <nix/Section.hpp>

using namespace std;
using namespace nix;

Section::Section()
    : NamedEntity()
{
}

Section::Section(nullptr_t ptr)
    : NamedEntity()
{
}

Section::Section(const Section &other)
    : NamedEntity(other.impl())
{
}

Section::Section(const shared_ptr<base::ISection> &p_impl)
    : NamedEntity(p_impl)
{
}

Section::Section(shared_ptr<base::ISection> &&ptr)
    : NamedEntity(std::move(ptr))
{
}

void Section::link(const Section &link) {
    if (link == none) {
        backend()->link(none);
    } else {
        backend()->link(link.id());
    }
}

//-----------------------------------------------------
// Methods concerning child sections
//-----------------------------------------------------

bool Section::hasSection(const Section &section) const {
    if (section == none) {
        throw std::runtime_error("Section::hasSection: Empty Section entity given!");
    }
    return backend()->hasSection(section.id());
}

bool Section::deleteSection(const Section &section) {
    if (section == none) {
        throw std::runtime_error("Section::deleteSection: Empty Section entity given!");
    }
    return backend()->deleteSection(section.id());
}

/*
 * Helper struct for {@link findSections}.
 */
struct SectionCont {
    SectionCont(Section s, size_t d = 0)
    : entity(s), depth(d)
    {}

    Section entity;
    size_t depth;
};

std::vector<Section> Section::sections(const util::Filter<Section>::type &filter) const {
    auto f = [this] (size_t i) { return getSection(i); };
    return getEntities<Section>(f,
                                sectionCount(),
                                filter);
}

std::vector<Section> Section::findSections(const util::Filter<Section>::type &filter,
                                           size_t max_depth) const
{
    std::vector<Section>  results;
    std::list<SectionCont> todo;

    todo.push_back(SectionCont(*this));

    while (todo.size() > 0)
    {
        SectionCont current = todo.front();
        todo.pop_front();

        bool filter_ok = filter(current.entity);
        if (filter_ok) {
            results.push_back(current.entity);
        }

        if (current.depth < max_depth) {
            std::vector<Section> children = current.entity.sections();
            size_t next_depth = current.depth + 1;

            for (auto it = children.begin(); it != children.end(); ++it) {
                todo.push_back(SectionCont(*it, next_depth));
            }
        }
    }

    return results;
}

static inline auto erase_section_with_id(vector<Section> &sections, const string &my_id)
    -> decltype(sections.size())
{
    sections.erase(remove_if(sections.begin(),
                             sections.end(),
                             [&my_id](const Section &section) {
                                 return my_id == section.id();
                             }),
                   sections.end());

    return sections.size();
}

std::vector<Section> Section::findRelated(const util::Filter<Section>::type &filter) const
{
    std::vector<Section> results = findDownstream(filter);
    const string &my_id = id();

    //This checking of results can be removed if we decide not to include this in findSection
    auto results_size = erase_section_with_id(results, my_id);

    if (results_size == 0) {
        results = findUpstream(filter);
    }
    //This checking of results can be removed if we decide not to include this in findSection
    results_size = erase_section_with_id(results, my_id);

    if (results_size == 0) {
        results = findSideways(filter, id());
    }
    return results;
}

//-----------------------------------------------------
// Methods for property access
//-----------------------------------------------------

bool Section::hasProperty(const Property &property) const {
    if (property == none) {
        throw std::runtime_error("Section::hasProperty: Empty Property entity given!");
    }
    return backend()->hasProperty(property.id());
}

std::vector<Property> Section::properties(const util::Filter<Property>::type &filter) const {
    auto f = [this] (size_t i) { return getProperty(i); };
    return getEntities<Property>(f,
            propertyCount(),
            filter);
}

bool Section::deleteProperty(const Property &property) {
    if (property == none) {
        throw std::runtime_error("Section::deleteProperty: Empty Property entity given!");
    }
    return backend()->deleteProperty(property.id());
}

vector<Property> Section::inheritedProperties() const {

    vector<Property> own = properties();

    if (link() == nullptr)
        return own;

    const vector<Property> linked = link().properties();

    copy_if (linked.begin(), linked.end(),
             back_inserter(own),
             [&own](const Property &linked_prop) {
                 return find_if (own.begin(), own.end(),
                                [&linked_prop](const Property &own_prop) {
                                    return linked_prop.name() == own_prop.name();
                                }) == own.end();
             });

    return own;
}

//------------------------------------------------------
// Operators and other functions
//------------------------------------------------------

size_t Section::tree_depth() const{
  const vector<Section> children = sections();
  size_t depth = 0;
  if (children.size() > 0) {
      for (auto &child : children) {
          depth = max(depth, child.tree_depth());
      }
      depth += 1;
  }
  return depth;
}

vector<Section> Section::findDownstream(const std::function<bool(Section)> &filter) const{
    vector<Section> results;
    size_t max_depth = tree_depth();
    size_t actual_depth = 1;
    while (results.size() == 0 && actual_depth <= max_depth) {
        results = findSections(filter, actual_depth);
        actual_depth += 1;
    }
    return results;
}

vector<Section> Section::findUpstream(const std::function<bool(Section)> &filter) const{
    vector<Section> results;
    Section p = parent();

    if (p != nullptr) {
        results = p.findSections(filter,1);
        if (results.size() > 0) {
            return results;
        }
        return p.findUpstream(filter);
    }
    return results;
}

vector<Section> Section::findSideways(const std::function<bool(Section)> &filter, const string &caller_id) const{
    vector<Section> results;
    Section p = parent();
    if (p != nullptr) {
        results = p.findSections(filter,1);
        if (results.size() > 0) {

            results.erase(remove_if(results.begin(),
                                    results.end(),
                                    [&caller_id](const Section &section) {
                                        return section.id() == caller_id;
                                    }),
                          results.end());

            return results;
        }
        return p.findSideways(filter, caller_id);
    }
    return results;
}

std::ostream& nix::operator<<(ostream &out, const Section &ent) {
    out << "Section: {name = " << ent.name();
    out << ", type = " << ent.type();
    out << ", id = " << ent.id() << "}";
    return out;
}
<|endoftext|>


<commit_before>#include "../header/int/Texture.h"
#include "../header/ext/EasyBMP.h"

Texture::Texture(){
	fileName = "";
	this->pixelData = NULL;
}

Texture::Texture(int _width, int _height){
	fileName = "";
	width = _width;
	height = _height;

	textureTarget = GL_TEXTURE_2D;
	pixelData = new RGBApixel[width*height];

	glGenTextures(1, &textureObj);
    Apply();
}

Texture::Texture(GLenum TextureTarget, const std::string& _fileName){
    textureTarget = TextureTarget;
    fileName      = _fileName;
	pixelData = NULL;
}

//Requires OpenGL context
void Texture::Load(void){
    BMP image;

	image.ReadFromFile(fileName.c_str());
	width = image.TellWidth();
	height = image.TellHeight();

	pixelData = new RGBApixel[width*height];
	for(int j = 0; j < height; j++){
		for(int i = 0; i < width; i++){
			pixelData[j*width+i] = image.GetPixel(i,j);
		}
	}

    glGenTextures(1, &textureObj);
    Apply();
}

void Texture::SetPixel(int x, int y, float r, float g, float b){
	RGBApixel pix;
	pix.Red   = (unsigned char)(255*r);
	pix.Green = (unsigned char)(255*g);
	pix.Blue  = (unsigned char)(255*b);
	pix.Alpha = 255;

	int index = y * width + x;
	pixelData[index] = pix;
}

void Texture::SetPixel(int x, int y, RGBApixel col){
	int index = y * width + x;
	pixelData[index] = col;
}

void Texture::GetPixel(int x, int y){
	//Not implemented yet.
}

void Texture::Apply(){
	if(pixelData != NULL){
		glBindTexture(textureTarget, textureObj);
		glTexImage2D(textureTarget, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixelData);
		glTexParameterf(textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexParameterf(textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	}
}

void Texture::Bind(GLenum TextureUnit){
    glActiveTexture(TextureUnit);
    glBindTexture(textureTarget, textureObj);
}

Texture::~Texture(){
	fileName="";
	if(pixelData != NULL){
		delete[] pixelData;
	}
}<commit_msg>Changed texture import from RGBA to BGRA.<commit_after>#include "../header/int/Texture.h"
#include "../header/ext/EasyBMP.h"

Texture::Texture(){
	fileName = "";
	this->pixelData = NULL;
}

Texture::Texture(int _width, int _height){
	fileName = "";
	width = _width;
	height = _height;

	textureTarget = GL_TEXTURE_2D;
	pixelData = new RGBApixel[width*height];

	glGenTextures(1, &textureObj);
    Apply();
}

Texture::Texture(GLenum TextureTarget, const std::string& _fileName){
    textureTarget = TextureTarget;
    fileName      = _fileName;
	pixelData = NULL;
}

//Requires OpenGL context
void Texture::Load(void){
    BMP image;

	image.ReadFromFile(fileName.c_str());
	width = image.TellWidth();
	height = image.TellHeight();

	pixelData = new RGBApixel[width*height];
	for(int j = 0; j < height; j++){
		for(int i = 0; i < width; i++){
			pixelData[j*width+i] = image.GetPixel(i,j);
		}
	}

    glGenTextures(1, &textureObj);
    Apply();
}

void Texture::SetPixel(int x, int y, float r, float g, float b){
	RGBApixel pix;
	pix.Red   = (unsigned char)(255*r);
	pix.Green = (unsigned char)(255*g);
	pix.Blue  = (unsigned char)(255*b);
	pix.Alpha = 255;

	int index = y * width + x;
	pixelData[index] = pix;
}

void Texture::SetPixel(int x, int y, RGBApixel col){
	int index = y * width + x;
	pixelData[index] = col;
}

void Texture::GetPixel(int x, int y){
	//Not implemented yet.
}

void Texture::Apply(){
	if(pixelData != NULL){
		glBindTexture(textureTarget, textureObj);
		glTexImage2D(textureTarget, 0, GL_RGBA, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, pixelData);
		glTexParameterf(textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexParameterf(textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	}
}

void Texture::Bind(GLenum TextureUnit){
    glActiveTexture(TextureUnit);
    glBindTexture(textureTarget, textureObj);
}

Texture::~Texture(){
	fileName="";
	if(pixelData != NULL){
		delete[] pixelData;
	}
}<|endoftext|>


<commit_before>/**
 * @file attrmap.cpp
 * @brief Class for manipulating node attributes
 *
 * (c) 2013-2014 by Mega Limited, Auckland, New Zealand
 *
 * This file is part of the MEGA SDK - Client Access Engine.
 *
 * Applications using the MEGA API must present a valid application key
 * and comply with the the rules set forth in the Terms of Service.
 *
 * The MEGA SDK 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.
 *
 * @copyright Simplified (2-clause) BSD License.
 *
 * You should have received a copy of the license along with this
 * program.
 */

#include "mega/attrmap.h"

namespace mega {
// approximate raw storage size of serialized AttrMap, not taking JSON escaping
// or name length into account
unsigned AttrMap::storagesize(int perrecord) const
{
    assert(perrecord >= 0);
    unsigned t = 0;

    for (attr_map::const_iterator it = map.begin(); it != map.end(); it++)
    {
        t += static_cast<unsigned>(perrecord + it->second.size());
    }

    return t;
}

int AttrMap::nameid2string(nameid id, char* buf)
{
    char* ptr = buf;

    for (int i = 64; (i -= 8) >= 0;)
    {
        if ((*ptr = static_cast<char>( (id >> i) & 0xff)))
        {
            ptr++;
        }
    }

    return static_cast<int>(ptr - buf);
}

string AttrMap::nameid2string(nameid id)
{
    string s;
    s.resize(10);
    s.resize(nameid2string(id, const_cast<char*>(s.data())));
    return s;
}

nameid AttrMap::string2nameid(const char *a)
{
    if (!a)
    {
        return 0;
    }

    size_t len = strlen(a);
    if (len > 8)
    {
        return 0;
    }

    switch (len)
    {
        case 1:
            return *a;
        case 2:
            return MAKENAMEID2(a[0], a[1]);
        case 3:
            return MAKENAMEID3(a[0], a[1], a[2]);
        case 4:
            return MAKENAMEID4(a[0], a[1], a[2], a[3]);
        case 5:
            return MAKENAMEID5(a[0], a[1], a[2], a[3], a[4]);
        case 6:
            return MAKENAMEID6(a[0], a[1], a[2], a[3], a[4], a[5]);
        case 7:
            return MAKENAMEID7(a[0], a[1], a[2], a[3], a[4], a[5], a[6]);
        case 8:
            return MAKENAMEID8(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]);
        default:
            break;
    }
    return 0;
}

// generate binary serialize of attr_map name-value pairs
void AttrMap::serialize(string* d) const
{
    char buf[8];
    unsigned char l;
    unsigned short ll;

    for (attr_map::const_iterator it = map.begin(); it != map.end(); it++)
    {
        if ((l = (unsigned char)nameid2string(it->first, buf)))
        {
            d->append((char*)&l, sizeof l);
            d->append(buf, l);
            ll = (unsigned short)it->second.size();
            d->append((char*)&ll, sizeof ll);
            d->append(it->second.data(), ll);
        }
    }

    d->append("", 1);
}

// read binary serialize, return final offset
const char* AttrMap::unserialize(const char* ptr , const char *end)
{
    unsigned char l;
    unsigned short ll;
    nameid id;

    while ((ptr < end) && (l = *ptr++))
    {
        id = 0;

        if (ptr + l + sizeof ll > end)
        {
            return NULL;
        }

        while (l--)
        {
            id = (id << 8) + (unsigned char)*ptr++;
        }

        ll = MemAccess::get<short>(ptr);
        ptr += sizeof ll;

        if (ptr + ll > end)
        {
            return NULL;
        }

        map[id].assign(ptr, ll);
        ptr += ll;
    }

    return ptr;
}

bool AttrMap::hasUpdate(const attr_map& updates, nameid attrId) const
{
    auto curIt = map.find(attrId);
    auto updIt = updates.find(attrId);
    return curIt != map.end() && (updIt == updates.end() || curIt->second != updIt->second);
}

void AttrMap::applyUpdates(const attr_map& updates)
{
    for (auto& u : updates)
    {
        if (u.second.empty()) map.erase(u.first);
        else map[u.first] = u.second;
    }
}

// generate JSON object containing attr_map
void AttrMap::getjson(string* s) const
{
    nameid id;
    char buf[8];
    const char* ptr;
    const char* pptr;

    // reserve estimated size of final string
    s->erase();
    s->reserve(storagesize(20));

    for (attr_map::const_iterator it = map.begin(); it != map.end(); it++)
    {
        s->append(s->size() ? ",\"" : "\"");

        if ((id = it->first))
        {
            // no JSON escaping here, as no escape characters are allowed in
            // attribute names
            s->append(buf, nameid2string(id, buf));
            s->append("\":\"");

            // JSON-escape value
            pptr = it->second.c_str();
            ptr = it->second.c_str();

            for (int i = static_cast<int>(it->second.size()); i-- >= 0; ptr++)
            {
                if ((i < 0) || ((*(const signed char*)ptr >= 0) && (*ptr < ' ')) || (*ptr == '"') || (*ptr == '\\'))
                {
                    if (ptr > pptr)
                    {
                        s->append(pptr, ptr - pptr);
                    }

                    if (i >= 0)
                    {
                        s->append("\\");

                        switch (*ptr)
                        {
                            case '"':
                                s->append("\"");
                                break;

                            case '\\':
                                s->append("\\");
                                break;

                            case '\n':
                                s->append("n");
                                break;

                            case '\r':
                                s->append("r");
                                break;

                            case '\b':
                                s->append("b");
                                break;

                            case '\f':
                                s->append("f");
                                break;

                            case '\t':
                                s->append("t");
                                break;

                            default:
                                s->append("u00");
                                sprintf(buf, "%02x", (unsigned char)*ptr);
                                s->append(buf);
                        }

                        pptr = ptr + 1;
                    }
                }
            }

            s->append("\"");
        }
    }
}
} // namespace
<commit_msg>Add comment to explain confusing update of AttrMap<commit_after>/**
 * @file attrmap.cpp
 * @brief Class for manipulating node attributes
 *
 * (c) 2013-2014 by Mega Limited, Auckland, New Zealand
 *
 * This file is part of the MEGA SDK - Client Access Engine.
 *
 * Applications using the MEGA API must present a valid application key
 * and comply with the the rules set forth in the Terms of Service.
 *
 * The MEGA SDK 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.
 *
 * @copyright Simplified (2-clause) BSD License.
 *
 * You should have received a copy of the license along with this
 * program.
 */

#include "mega/attrmap.h"

namespace mega {
// approximate raw storage size of serialized AttrMap, not taking JSON escaping
// or name length into account
unsigned AttrMap::storagesize(int perrecord) const
{
    assert(perrecord >= 0);
    unsigned t = 0;

    for (attr_map::const_iterator it = map.begin(); it != map.end(); it++)
    {
        t += static_cast<unsigned>(perrecord + it->second.size());
    }

    return t;
}

int AttrMap::nameid2string(nameid id, char* buf)
{
    char* ptr = buf;

    for (int i = 64; (i -= 8) >= 0;)
    {
        if ((*ptr = static_cast<char>( (id >> i) & 0xff)))
        {
            ptr++;
        }
    }

    return static_cast<int>(ptr - buf);
}

string AttrMap::nameid2string(nameid id)
{
    string s;
    s.resize(10);
    s.resize(nameid2string(id, const_cast<char*>(s.data())));
    return s;
}

nameid AttrMap::string2nameid(const char *a)
{
    if (!a)
    {
        return 0;
    }

    size_t len = strlen(a);
    if (len > 8)
    {
        return 0;
    }

    switch (len)
    {
        case 1:
            return *a;
        case 2:
            return MAKENAMEID2(a[0], a[1]);
        case 3:
            return MAKENAMEID3(a[0], a[1], a[2]);
        case 4:
            return MAKENAMEID4(a[0], a[1], a[2], a[3]);
        case 5:
            return MAKENAMEID5(a[0], a[1], a[2], a[3], a[4]);
        case 6:
            return MAKENAMEID6(a[0], a[1], a[2], a[3], a[4], a[5]);
        case 7:
            return MAKENAMEID7(a[0], a[1], a[2], a[3], a[4], a[5], a[6]);
        case 8:
            return MAKENAMEID8(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7]);
        default:
            break;
    }
    return 0;
}

// generate binary serialize of attr_map name-value pairs
void AttrMap::serialize(string* d) const
{
    char buf[8];
    unsigned char l;
    unsigned short ll;

    for (attr_map::const_iterator it = map.begin(); it != map.end(); it++)
    {
        if ((l = (unsigned char)nameid2string(it->first, buf)))
        {
            d->append((char*)&l, sizeof l);
            d->append(buf, l);
            ll = (unsigned short)it->second.size();
            d->append((char*)&ll, sizeof ll);
            d->append(it->second.data(), ll);
        }
    }

    d->append("", 1);
}

// read binary serialize, return final offset
const char* AttrMap::unserialize(const char* ptr , const char *end)
{
    unsigned char l;
    unsigned short ll;
    nameid id;

    while ((ptr < end) && (l = *ptr++))
    {
        id = 0;

        if (ptr + l + sizeof ll > end)
        {
            return NULL;
        }

        while (l--)
        {
            id = (id << 8) + (unsigned char)*ptr++;
        }

        ll = MemAccess::get<short>(ptr);
        ptr += sizeof ll;

        if (ptr + ll > end)
        {
            return NULL;
        }

        map[id].assign(ptr, ll);
        ptr += ll;
    }

    return ptr;
}

bool AttrMap::hasUpdate(const attr_map& updates, nameid attrId) const
{
    // An attribute will only be touched if it was included in `updates` map.
    // Even for removing it, it should be present there with an empty value.
    auto curIt = map.find(attrId);
    auto updIt = updates.find(attrId);
    return curIt != map.end() && (updIt == updates.end() || curIt->second != updIt->second);
}

void AttrMap::applyUpdates(const attr_map& updates)
{
    for (auto& u : updates)
    {
        if (u.second.empty()) map.erase(u.first);
        else map[u.first] = u.second;
    }
}

// generate JSON object containing attr_map
void AttrMap::getjson(string* s) const
{
    nameid id;
    char buf[8];
    const char* ptr;
    const char* pptr;

    // reserve estimated size of final string
    s->erase();
    s->reserve(storagesize(20));

    for (attr_map::const_iterator it = map.begin(); it != map.end(); it++)
    {
        s->append(s->size() ? ",\"" : "\"");

        if ((id = it->first))
        {
            // no JSON escaping here, as no escape characters are allowed in
            // attribute names
            s->append(buf, nameid2string(id, buf));
            s->append("\":\"");

            // JSON-escape value
            pptr = it->second.c_str();
            ptr = it->second.c_str();

            for (int i = static_cast<int>(it->second.size()); i-- >= 0; ptr++)
            {
                if ((i < 0) || ((*(const signed char*)ptr >= 0) && (*ptr < ' ')) || (*ptr == '"') || (*ptr == '\\'))
                {
                    if (ptr > pptr)
                    {
                        s->append(pptr, ptr - pptr);
                    }

                    if (i >= 0)
                    {
                        s->append("\\");

                        switch (*ptr)
                        {
                            case '"':
                                s->append("\"");
                                break;

                            case '\\':
                                s->append("\\");
                                break;

                            case '\n':
                                s->append("n");
                                break;

                            case '\r':
                                s->append("r");
                                break;

                            case '\b':
                                s->append("b");
                                break;

                            case '\f':
                                s->append("f");
                                break;

                            case '\t':
                                s->append("t");
                                break;

                            default:
                                s->append("u00");
                                sprintf(buf, "%02x", (unsigned char)*ptr);
                                s->append(buf);
                        }

                        pptr = ptr + 1;
                    }
                }
            }

            s->append("\"");
        }
    }
}
} // namespace
<|endoftext|>


<commit_before>// Copyright 2010, Camilo Aguilar. Cloudescape, LLC.
#include "bindings.h"

/* size of the event structure, not counting name */
#define EVENT_SIZE  (sizeof (struct inotify_event))

/* reasonable guess as to size of 1024 events */
#define BUF_LEN        (1024 * (EVENT_SIZE + 16))

namespace NodeInotify {
    static Persistent<String> path_sym;
    static Persistent<String> watch_for_sym;
    static Persistent<String> callback_sym;
    static Persistent<String> persistent_sym;
    static Persistent<String> watch_sym;
    static Persistent<String> mask_sym;
    static Persistent<String> cookie_sym;
    static Persistent<String> name_sym;

    void Inotify::Initialize(Handle<Object> target) {
        Local<FunctionTemplate> t = FunctionTemplate::New(Inotify::New);

        t->Inherit(EventEmitter::constructor_template);
        t->InstanceTemplate()->SetInternalFieldCount(1);

        NODE_SET_PROTOTYPE_METHOD(t, "addWatch",
                                      Inotify::AddWatch);
        NODE_SET_PROTOTYPE_METHOD(t, "removeWatch",
                                      Inotify::RemoveWatch);
        NODE_SET_PROTOTYPE_METHOD(t, "close",
                                      Inotify::Close);

        //Constants initialization
        NODE_DEFINE_CONSTANT(t, IN_ACCESS); //File was accessed (read)
        NODE_DEFINE_CONSTANT(t, IN_ATTRIB); //Metadata changed, e.g., permissions, timestamps,
                                                      //extended attributes, link count (since Linux 2.6.25),
                                                      //UID, GID, etc.
        NODE_DEFINE_CONSTANT(t, IN_CLOSE_WRITE); //File opened for writing was closed
        NODE_DEFINE_CONSTANT(t, IN_CLOSE_NOWRITE); //File not opened for writing was closed
        NODE_DEFINE_CONSTANT(t, IN_CREATE); //File/directory created in watched directory
        NODE_DEFINE_CONSTANT(t, IN_DELETE); //File/directory deleted from watched directory
        NODE_DEFINE_CONSTANT(t, IN_DELETE_SELF); //Watched file/directory was itself deleted
        NODE_DEFINE_CONSTANT(t, IN_MODIFY); //File was modified
        NODE_DEFINE_CONSTANT(t, IN_MOVE_SELF); //Watched file/directory was itself moved
        NODE_DEFINE_CONSTANT(t, IN_MOVED_FROM); //File moved out of watched directory
        NODE_DEFINE_CONSTANT(t, IN_MOVED_TO); //File moved into watched directory
        NODE_DEFINE_CONSTANT(t, IN_OPEN); //File was opened
        NODE_DEFINE_CONSTANT(t, IN_IGNORED); // Watch was removed explicitly (inotify.watch.rm) or
                                                       //automatically (file was deleted, or file system was
                                                        //unmounted)
        NODE_DEFINE_CONSTANT(t, IN_ISDIR); //Subject of this event is a directory
        NODE_DEFINE_CONSTANT(t, IN_Q_OVERFLOW); //Event queue overflowed (wd is -1 for this event)
        NODE_DEFINE_CONSTANT(t, IN_UNMOUNT); //File system containing watched object was unmounted
        NODE_DEFINE_CONSTANT(t, IN_ALL_EVENTS);

        NODE_DEFINE_CONSTANT(t, IN_ONLYDIR); // Only watch the path if it is a directory.
        NODE_DEFINE_CONSTANT(t, IN_DONT_FOLLOW); // Do not follow a sym link
        NODE_DEFINE_CONSTANT(t, IN_ONESHOT); // Only send event once
        NODE_DEFINE_CONSTANT(t, IN_MASK_ADD); //Add (OR) events to watch mask for this pathname if it
                                                        //already exists (instead of replacing mask).

        NODE_DEFINE_CONSTANT(t, IN_CLOSE); // (IN_CLOSE_WRITE | IN_CLOSE_NOWRITE)  Close
        NODE_DEFINE_CONSTANT(t, IN_MOVE);  //  (IN_MOVED_FROM | IN_MOVED_TO)  Moves

        path_sym        = NODE_PSYMBOL("path");
        watch_for_sym   = NODE_PSYMBOL("watch_for");
        callback_sym    = NODE_PSYMBOL("callback");
        persistent_sym  = NODE_PSYMBOL("persistent");

        watch_sym       = NODE_PSYMBOL("watch");
        mask_sym        = NODE_PSYMBOL("mask");
        cookie_sym      = NODE_PSYMBOL("cookie");
        name_sym        = NODE_PSYMBOL("name");

        Local<ObjectTemplate> object_tmpl = t->InstanceTemplate();
        object_tmpl->SetAccessor(persistent_sym, Inotify::GetPersistent);

        t->SetClassName(String::NewSymbol("Inotify"));
        target->Set(String::NewSymbol("Inotify"), t->GetFunction());
    }

    Inotify::Inotify() : EventEmitter() {
        ev_init(&read_watcher, Inotify::Callback);
        read_watcher.data = this;  //preserving my reference to use it inside Inotify::Callback
        persistent = true;
    }

    Inotify::Inotify(bool nonpersistent) : EventEmitter() {
        ev_init(&read_watcher, Inotify::Callback);
        read_watcher.data = this;  //preserving my reference to use it inside Inotify::Callback
        persistent = nonpersistent;
    }

    Inotify::~Inotify() {
        if(!persistent) {
            ev_ref(EV_DEFAULT_UC);
        }
        ev_io_stop(EV_DEFAULT_UC_ &read_watcher);
        assert(!ev_is_active(&read_watcher));
        assert(!ev_is_pending(&read_watcher));
    }

    Handle<Value> Inotify::New(const Arguments& args) {
        HandleScope scope;

        Inotify *inotify = NULL;
        if(args.Length() == 1 && args[0]->IsBoolean()) {
            inotify = new Inotify(args[0]->IsTrue());
        } else {
            inotify = new Inotify();
        }

 	inotify->fd = inotify_init();

        if(inotify->fd == -1) {
            ThrowException(String::New(strerror(errno)));
            return Null();
        }

	int flags = fcntl(inotify->fd, F_GETFL);
	if(flags == -1) {
	    flags = 0;
	}

	fcntl(inotify->fd, F_SETFL, flags | O_NONBLOCK | O_CLOEXEC);

        ev_io_set(&inotify->read_watcher, inotify->fd, EV_READ);
        ev_io_start(EV_DEFAULT_UC_ &inotify->read_watcher);

        Local<Object> obj = args.This();
        inotify->Wrap(obj);

        if(!inotify->persistent) {
            ev_unref(EV_DEFAULT_UC);
        }
        /*Increment object references to avoid be GCed while
         I'm waiting for inotify events in th ev_pool.
         Also, the object is not weak anymore */
        inotify->Ref();

        return scope.Close(obj);
    }

    Handle<Value> Inotify::AddWatch(const Arguments& args) {
        HandleScope scope;
        uint32_t mask = 0;
        int watch_descriptor = 0;

        if(args.Length() < 1 || !args[0]->IsObject()) {
            return ThrowException(Exception::TypeError(
            String::New("You must specify an object as first argument")));
        }

        Local<Object> args_ = args[0]->ToObject();

        if(!args_->Has(path_sym)) {
            return ThrowException(Exception::TypeError(
            String::New("You must specify a path to watch for events")));
        }

        if(!args_->Has(callback_sym) ||
            !args_->Get(callback_sym)->IsFunction()) {
            return ThrowException(Exception::TypeError(
            String::New("You must specify a callback function")));
        }

        if(!args_->Has(watch_for_sym)) {
            mask |= IN_ALL_EVENTS;
        } else {
            if(!args_->Get(watch_for_sym)->IsInt32()) {
                return ThrowException(Exception::TypeError(
                String::New("You must specify OR'ed set of events")));
            }
            mask |= args_->Get(watch_for_sym)->Int32Value();
            if(mask == 0) {
                return ThrowException(Exception::TypeError(
                String::New("You must specify OR'ed set of events")));
            }
       }

        String::Utf8Value path(args_->Get(path_sym));

        Inotify *inotify = ObjectWrap::Unwrap<Inotify>(args.This());

        /* add watch */
        watch_descriptor = inotify_add_watch(inotify->fd, (const char *) *path, mask);

        Local<Integer> descriptor = Integer::New(watch_descriptor);

        //Local<Function> callback = Local<Function>::Cast(args_->Get(callback_sym));
        inotify->handle_->Set(descriptor, args_->Get(callback_sym));

        return scope.Close(descriptor);
    }

    Handle<Value> Inotify::RemoveWatch(const Arguments& args) {
        HandleScope scope;
        uint32_t watch = 0;
        int ret = -1;

        if(args.Length() == 0 || !args[0]->IsInt32()) {
            return ThrowException(Exception::TypeError(
            String::New("You must specify a valid watcher descriptor as argument")));
        }
        watch = args[0]->Int32Value();

        Inotify *inotify = ObjectWrap::Unwrap<Inotify>(args.This());

        ret = inotify_rm_watch(inotify->fd, watch);
        if(ret == -1) {
            ThrowException(String::New(strerror(errno)));
            return False();
        }

        return True();
    }

    Handle<Value> Inotify::Close(const Arguments& args) {
        HandleScope scope;
        int ret = -1;

        Inotify *inotify = ObjectWrap::Unwrap<Inotify>(args.This());
        ret = close(inotify->fd);

        if(ret == -1) {
            ThrowException(String::New(strerror(errno)));
            return False();
        }

        if(!inotify->persistent) {
            ev_ref(EV_DEFAULT_UC);
        }

        ev_io_stop(EV_DEFAULT_UC_ &inotify->read_watcher);

        /*Eliminating reference created inside of Inotify::New.
        The object is also weak again.
        Now v8 can do its stuff and GC the object.
        */
        inotify->Unref();

        return True();
    }

    void Inotify::Callback(EV_P_ ev_io *watcher, int revents) {
        HandleScope scope;

        Inotify *inotify = static_cast<Inotify*>(watcher->data);
        assert(watcher == &inotify->read_watcher);

        char buffer[BUF_LEN];

        //int length = read(inotify->fd, buffer, BUF_LEN);

        Local<Value> argv[1];
        TryCatch try_catch;

        int i = 0;
        while (i < read(inotify->fd, buffer, BUF_LEN)) {
            struct inotify_event *event;
            event = (struct inotify_event *) &buffer[i];

            Local<Object> obj = Object::New();
            obj->Set(watch_sym, Integer::New(event->wd));
            obj->Set(mask_sym, Integer::New(event->mask));
            obj->Set(cookie_sym, Integer::New(event->cookie));

            if(event->len) {
                obj->Set(name_sym, String::New(event->name));
            }
            argv[0] = obj;

            inotify->Ref();
            Local<Value> callback_ = inotify->handle_->Get(Integer::New(event->wd));
            Local<Function> callback = Local<Function>::Cast(callback_);

            callback->Call(inotify->handle_, 1, argv);
            inotify->Unref();

            if(event->mask & IN_IGNORED) {
                //deleting callback because the watch was removed
                Local<Value> wd = Integer::New(event->wd);
                inotify->handle_->Delete(wd->ToString());
            }

            if (try_catch.HasCaught()) {
                FatalException(try_catch);
            }

            i += EVENT_SIZE + event->len;
        }
    }

    Handle<Value> Inotify::GetPersistent(Local<String> property,
                                        const AccessorInfo& info) {
        Inotify *inotify = ObjectWrap::Unwrap<Inotify>(info.This());

        return inotify->persistent ? True() : False();
     }
}//namespace NodeInotify

<commit_msg>adds compatibility with kernels versions under 2.6.23, O_CLOEXEC is not important in nodejs context since there is always just one thread accessing files.<commit_after>// Copyright 2010, Camilo Aguilar. Cloudescape, LLC.
#include "bindings.h"

/* size of the event structure, not counting name */
#define EVENT_SIZE  (sizeof (struct inotify_event))

/* reasonable guess as to size of 1024 events */
#define BUF_LEN        (1024 * (EVENT_SIZE + 16))

namespace NodeInotify {
    static Persistent<String> path_sym;
    static Persistent<String> watch_for_sym;
    static Persistent<String> callback_sym;
    static Persistent<String> persistent_sym;
    static Persistent<String> watch_sym;
    static Persistent<String> mask_sym;
    static Persistent<String> cookie_sym;
    static Persistent<String> name_sym;

    void Inotify::Initialize(Handle<Object> target) {
        Local<FunctionTemplate> t = FunctionTemplate::New(Inotify::New);

        t->Inherit(EventEmitter::constructor_template);
        t->InstanceTemplate()->SetInternalFieldCount(1);

        NODE_SET_PROTOTYPE_METHOD(t, "addWatch",
                                      Inotify::AddWatch);
        NODE_SET_PROTOTYPE_METHOD(t, "removeWatch",
                                      Inotify::RemoveWatch);
        NODE_SET_PROTOTYPE_METHOD(t, "close",
                                      Inotify::Close);

        //Constants initialization
        NODE_DEFINE_CONSTANT(t, IN_ACCESS); //File was accessed (read)
        NODE_DEFINE_CONSTANT(t, IN_ATTRIB); //Metadata changed, e.g., permissions, timestamps,
                                                      //extended attributes, link count (since Linux 2.6.25),
                                                      //UID, GID, etc.
        NODE_DEFINE_CONSTANT(t, IN_CLOSE_WRITE); //File opened for writing was closed
        NODE_DEFINE_CONSTANT(t, IN_CLOSE_NOWRITE); //File not opened for writing was closed
        NODE_DEFINE_CONSTANT(t, IN_CREATE); //File/directory created in watched directory
        NODE_DEFINE_CONSTANT(t, IN_DELETE); //File/directory deleted from watched directory
        NODE_DEFINE_CONSTANT(t, IN_DELETE_SELF); //Watched file/directory was itself deleted
        NODE_DEFINE_CONSTANT(t, IN_MODIFY); //File was modified
        NODE_DEFINE_CONSTANT(t, IN_MOVE_SELF); //Watched file/directory was itself moved
        NODE_DEFINE_CONSTANT(t, IN_MOVED_FROM); //File moved out of watched directory
        NODE_DEFINE_CONSTANT(t, IN_MOVED_TO); //File moved into watched directory
        NODE_DEFINE_CONSTANT(t, IN_OPEN); //File was opened
        NODE_DEFINE_CONSTANT(t, IN_IGNORED); // Watch was removed explicitly (inotify.watch.rm) or
                                                       //automatically (file was deleted, or file system was
                                                        //unmounted)
        NODE_DEFINE_CONSTANT(t, IN_ISDIR); //Subject of this event is a directory
        NODE_DEFINE_CONSTANT(t, IN_Q_OVERFLOW); //Event queue overflowed (wd is -1 for this event)
        NODE_DEFINE_CONSTANT(t, IN_UNMOUNT); //File system containing watched object was unmounted
        NODE_DEFINE_CONSTANT(t, IN_ALL_EVENTS);

        NODE_DEFINE_CONSTANT(t, IN_ONLYDIR); // Only watch the path if it is a directory.
        NODE_DEFINE_CONSTANT(t, IN_DONT_FOLLOW); // Do not follow a sym link
        NODE_DEFINE_CONSTANT(t, IN_ONESHOT); // Only send event once
        NODE_DEFINE_CONSTANT(t, IN_MASK_ADD); //Add (OR) events to watch mask for this pathname if it
                                                        //already exists (instead of replacing mask).

        NODE_DEFINE_CONSTANT(t, IN_CLOSE); // (IN_CLOSE_WRITE | IN_CLOSE_NOWRITE)  Close
        NODE_DEFINE_CONSTANT(t, IN_MOVE);  //  (IN_MOVED_FROM | IN_MOVED_TO)  Moves

        path_sym        = NODE_PSYMBOL("path");
        watch_for_sym   = NODE_PSYMBOL("watch_for");
        callback_sym    = NODE_PSYMBOL("callback");
        persistent_sym  = NODE_PSYMBOL("persistent");

        watch_sym       = NODE_PSYMBOL("watch");
        mask_sym        = NODE_PSYMBOL("mask");
        cookie_sym      = NODE_PSYMBOL("cookie");
        name_sym        = NODE_PSYMBOL("name");

        Local<ObjectTemplate> object_tmpl = t->InstanceTemplate();
        object_tmpl->SetAccessor(persistent_sym, Inotify::GetPersistent);

        t->SetClassName(String::NewSymbol("Inotify"));
        target->Set(String::NewSymbol("Inotify"), t->GetFunction());
    }

    Inotify::Inotify() : EventEmitter() {
        ev_init(&read_watcher, Inotify::Callback);
        read_watcher.data = this;  //preserving my reference to use it inside Inotify::Callback
        persistent = true;
    }

    Inotify::Inotify(bool nonpersistent) : EventEmitter() {
        ev_init(&read_watcher, Inotify::Callback);
        read_watcher.data = this;  //preserving my reference to use it inside Inotify::Callback
        persistent = nonpersistent;
    }

    Inotify::~Inotify() {
        if(!persistent) {
            ev_ref(EV_DEFAULT_UC);
        }
        ev_io_stop(EV_DEFAULT_UC_ &read_watcher);
        assert(!ev_is_active(&read_watcher));
        assert(!ev_is_pending(&read_watcher));
    }

    Handle<Value> Inotify::New(const Arguments& args) {
        HandleScope scope;

        Inotify *inotify = NULL;
        if(args.Length() == 1 && args[0]->IsBoolean()) {
            inotify = new Inotify(args[0]->IsTrue());
        } else {
            inotify = new Inotify();
        }

 	inotify->fd = inotify_init();

        if(inotify->fd == -1) {
            ThrowException(String::New(strerror(errno)));
            return Null();
        }

	int flags = fcntl(inotify->fd, F_GETFL);
	if(flags == -1) {
	    flags = 0;
	}

	fcntl(inotify->fd, F_SETFL, flags | O_NONBLOCK);

        ev_io_set(&inotify->read_watcher, inotify->fd, EV_READ);
        ev_io_start(EV_DEFAULT_UC_ &inotify->read_watcher);

        Local<Object> obj = args.This();
        inotify->Wrap(obj);

        if(!inotify->persistent) {
            ev_unref(EV_DEFAULT_UC);
        }
        /*Increment object references to avoid be GCed while
         I'm waiting for inotify events in th ev_pool.
         Also, the object is not weak anymore */
        inotify->Ref();

        return scope.Close(obj);
    }

    Handle<Value> Inotify::AddWatch(const Arguments& args) {
        HandleScope scope;
        uint32_t mask = 0;
        int watch_descriptor = 0;

        if(args.Length() < 1 || !args[0]->IsObject()) {
            return ThrowException(Exception::TypeError(
            String::New("You must specify an object as first argument")));
        }

        Local<Object> args_ = args[0]->ToObject();

        if(!args_->Has(path_sym)) {
            return ThrowException(Exception::TypeError(
            String::New("You must specify a path to watch for events")));
        }

        if(!args_->Has(callback_sym) ||
            !args_->Get(callback_sym)->IsFunction()) {
            return ThrowException(Exception::TypeError(
            String::New("You must specify a callback function")));
        }

        if(!args_->Has(watch_for_sym)) {
            mask |= IN_ALL_EVENTS;
        } else {
            if(!args_->Get(watch_for_sym)->IsInt32()) {
                return ThrowException(Exception::TypeError(
                String::New("You must specify OR'ed set of events")));
            }
            mask |= args_->Get(watch_for_sym)->Int32Value();
            if(mask == 0) {
                return ThrowException(Exception::TypeError(
                String::New("You must specify OR'ed set of events")));
            }
       }

        String::Utf8Value path(args_->Get(path_sym));

        Inotify *inotify = ObjectWrap::Unwrap<Inotify>(args.This());

        /* add watch */
        watch_descriptor = inotify_add_watch(inotify->fd, (const char *) *path, mask);

        Local<Integer> descriptor = Integer::New(watch_descriptor);

        //Local<Function> callback = Local<Function>::Cast(args_->Get(callback_sym));
        inotify->handle_->Set(descriptor, args_->Get(callback_sym));

        return scope.Close(descriptor);
    }

    Handle<Value> Inotify::RemoveWatch(const Arguments& args) {
        HandleScope scope;
        uint32_t watch = 0;
        int ret = -1;

        if(args.Length() == 0 || !args[0]->IsInt32()) {
            return ThrowException(Exception::TypeError(
            String::New("You must specify a valid watcher descriptor as argument")));
        }
        watch = args[0]->Int32Value();

        Inotify *inotify = ObjectWrap::Unwrap<Inotify>(args.This());

        ret = inotify_rm_watch(inotify->fd, watch);
        if(ret == -1) {
            ThrowException(String::New(strerror(errno)));
            return False();
        }

        return True();
    }

    Handle<Value> Inotify::Close(const Arguments& args) {
        HandleScope scope;
        int ret = -1;

        Inotify *inotify = ObjectWrap::Unwrap<Inotify>(args.This());
        ret = close(inotify->fd);

        if(ret == -1) {
            ThrowException(String::New(strerror(errno)));
            return False();
        }

        if(!inotify->persistent) {
            ev_ref(EV_DEFAULT_UC);
        }

        ev_io_stop(EV_DEFAULT_UC_ &inotify->read_watcher);

        /*Eliminating reference created inside of Inotify::New.
        The object is also weak again.
        Now v8 can do its stuff and GC the object.
        */
        inotify->Unref();

        return True();
    }

    void Inotify::Callback(EV_P_ ev_io *watcher, int revents) {
        HandleScope scope;

        Inotify *inotify = static_cast<Inotify*>(watcher->data);
        assert(watcher == &inotify->read_watcher);

        char buffer[BUF_LEN];

        //int length = read(inotify->fd, buffer, BUF_LEN);

        Local<Value> argv[1];
        TryCatch try_catch;

        int i = 0;
        while (i < read(inotify->fd, buffer, BUF_LEN)) {
            struct inotify_event *event;
            event = (struct inotify_event *) &buffer[i];

            Local<Object> obj = Object::New();
            obj->Set(watch_sym, Integer::New(event->wd));
            obj->Set(mask_sym, Integer::New(event->mask));
            obj->Set(cookie_sym, Integer::New(event->cookie));

            if(event->len) {
                obj->Set(name_sym, String::New(event->name));
            }
            argv[0] = obj;

            inotify->Ref();
            Local<Value> callback_ = inotify->handle_->Get(Integer::New(event->wd));
            Local<Function> callback = Local<Function>::Cast(callback_);

            callback->Call(inotify->handle_, 1, argv);
            inotify->Unref();

            if(event->mask & IN_IGNORED) {
                //deleting callback because the watch was removed
                Local<Value> wd = Integer::New(event->wd);
                inotify->handle_->Delete(wd->ToString());
            }

            if (try_catch.HasCaught()) {
                FatalException(try_catch);
            }

            i += EVENT_SIZE + event->len;
        }
    }

    Handle<Value> Inotify::GetPersistent(Local<String> property,
                                        const AccessorInfo& info) {
        Inotify *inotify = ObjectWrap::Unwrap<Inotify>(info.This());

        return inotify->persistent ? True() : False();
     }
}//namespace NodeInotify

<|endoftext|>


<commit_before>#ifndef _C4_LIST_HPP_
#define _C4_LIST_HPP_

#include "c4/config.hpp"
#include "c4/error.hpp"
#include "c4/storage/raw.hpp"

#include <iterator>

C4_BEGIN_NAMESPACE(c4)

template< class T, class I=C4_SIZE_TYPE >
using default_list_storage = stg::raw_paged_rt< T, I >;

template< class T, class I=C4_SIZE_TYPE, template< class T_, class I_ > class LinearStorage=default_list_storage >
class split_list;

template< class T, class I=C4_SIZE_TYPE, template< class T_, class I_ > class LinearStorage=default_list_storage >
class split_fwd_list;

template< class T, class I=C4_SIZE_TYPE, template< class T_, class I_ > class LinearStorage=default_list_storage >
class flat_list;

template< class T, class I=C4_SIZE_TYPE, template< class T_, class I_ > class LinearStorage=default_list_storage >
class flat_fwd_list;

template< class T, class I=C4_SIZE_TYPE > struct flat_list_elm;
template< class T, class I=C4_SIZE_TYPE > struct flat_fwd_list_elm;

//-----------------------------------------------------------------------------
template< class T, class I >
struct flat_list_elm
{
    T elm;
    I prev;
    I next;
};

template< class T, class I >
struct flat_fwd_list_elm
{
    T elm;
    I next;
};

//-----------------------------------------------------------------------------

template< class T, class List >
struct fwd_list_iterator : public std::iterator< std::forward_iterator_tag, typename List::value_type >
{
    using I = typename List::size_type;

    List *list;
    I i;

    fwd_list_iterator(List *l, I i_) : list(l), i(i_) {}

    C4_ALWAYS_INLINE T* operator-> () { return &list->elm(i); }
    C4_ALWAYS_INLINE T& operator*  () { return  list->elm(i); }

    C4_ALWAYS_INLINE fwd_list_iterator& operator++ (   ) noexcept {                               i = list->next(i); return *this; }
    C4_ALWAYS_INLINE fwd_list_iterator& operator++ (int) noexcept { fwd_list_iterator it = *this; i = list->next(i); return    it; }

    C4_ALWAYS_INLINE bool operator== (fwd_list_iterator const& that) const noexcept { return i == that.i && list == that.list; }
    C4_ALWAYS_INLINE bool operator!= (fwd_list_iterator const& that) const noexcept { return i != that.i || list != that.list; }
};

template< class T, class List >
struct list_iterator : public std::iterator< std::bidirectional_iterator_tag, typename List::value_type >
{
    using I = typename List::size_type;

    List *list;
    I i;

    list_iterator(List *l, I i_) : list(l), i(i_) {}

    C4_ALWAYS_INLINE T& operator*  () { return  list->elm(i); }
    C4_ALWAYS_INLINE T* operator-> () { return &list->elm(i); }

    C4_ALWAYS_INLINE list_iterator& operator++ (   ) noexcept {                           i = list->next(i); return *this; }
    C4_ALWAYS_INLINE list_iterator& operator++ (int) noexcept { list_iterator it = *this; i = list->next(i); return    it; }

    C4_ALWAYS_INLINE list_iterator& operator-- (   ) noexcept {                           i = list->prev(i); return *this; }
    C4_ALWAYS_INLINE list_iterator& operator-- (int) noexcept { list_iterator it = *this; i = list->prev(i); return    it; }

    C4_ALWAYS_INLINE bool operator== (list_iterator const& that) const noexcept { return i == that.i && list == that.list; }
    C4_ALWAYS_INLINE bool operator!= (list_iterator const& that) const noexcept { return i != that.i || list != that.list; }
};

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
template< class T, class I, template< class T, class I > class RawStorage >
class split_list
{
public:

    RawStorage< T, I > m_elm;
    RawStorage< I, I > m_prev;
    RawStorage< I, I > m_next;

    I m_head;
    I m_tail;
    I m_size;
    I m_fhead;

    enum : I { npos = static_cast< I >(-1) };

public:

    using value_type = T;
    using size_type = I;

    using iterator = list_iterator< T, split_list >;
    using const_iterator = list_iterator< const T, const split_list >;

public:

    split_list() : m_elm(), m_prev(), m_next(), m_head(0), m_tail(0), m_size(0), m_fhead(0) {}

    void _init_seq()
    {
        C4_ASSERT(m_elm.capacity() == m_prev.capacity() && m_elm.capacity() == m_next.capacity());
        I cap = m_elm.capacity();
        if(cap == 0) return;
        m_prev[0] = npos;
        for(I i = 1; i < cap-1; ++i)
        {
            m_prev[i] = i - 1;
        }
        m_next[0] = 1;
        for(I i = 1; i < cap-1; ++i)
        {
            m_next[i] = i + 1;
        }
        if(cap < 2) return;
        m_prev[cap - 1] = cap - 2;
        m_next[cap - 1] = npos;
    }

    void _growto(I next_cap)
    {
    }

public:

    C4_ALWAYS_INLINE I size() const noexcept { return m_size; }
    C4_ALWAYS_INLINE I capacity() const noexcept { return m_elm.capacity(); }

    C4_ALWAYS_INLINE T      & elm(I i)       C4_NOEXCEPT_X { C4_XASSERT(i < m_size); return m_elms[i]; }
    C4_ALWAYS_INLINE T const& elm(I i) const C4_NOEXCEPT_X { C4_XASSERT(i < m_size); return m_elms[i]; }

    C4_ALWAYS_INLINE I prev(I i) const C4_NOEXCEPT_X { C4_XASSERT(i < m_size); return m_prev[i]; }
    C4_ALWAYS_INLINE I next(I i) const C4_NOEXCEPT_X { C4_XASSERT(i < m_size); return m_next[i]; }

    C4_ALWAYS_INLINE iterator begin() noexcept { return iterator(this, m_head); }
    C4_ALWAYS_INLINE iterator end  () noexcept { return iterator(this, m_tail); }

    C4_ALWAYS_INLINE const_iterator begin() const noexcept { return const_iterator(this, m_head); }
    C4_ALWAYS_INLINE const_iterator end  () const noexcept { return const_iterator(this, m_tail); }

public:

     void push_back(T const& var)
     {
         I cap = capacity();
         if(size() == cap)
         {
             _growto(cap, cap+1);
         }
         I pos = m_fhead;
         C4_XASSERT(pos != npos && pos < m_size);
         c4::construct(&m_elm[pos], var);
         m_prev[pos] = m_tail;
         m_next[pos] = npos;
         m_tail = pos;
         C4_XASSERT(m_fhead != npos);
         m_fhead = m_next[m_fhead];
         ++m_size;
     }
     void push_front(T const& var)
     {
     }

};

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
template< class T, class I, template< class T, class I > class RawStorage >
class flat_list
{
public:

    RawStorage< flat_list_elm<T, I>, I > m_elms;

    I m_head;
    I m_tail;
    I m_size;
    I m_fhead;

public:

    using value_type = T;
    using size_type = I;

    using iterator = list_iterator< T, flat_list >;
    using const_iterator = list_iterator< const T, const flat_list >;

public:

    flat_list() : m_elms(), m_head(0), m_tail(0), m_size(0), m_fhead(0) {}

public:

    C4_ALWAYS_INLINE I size() const noexcept { return m_size; }
    C4_ALWAYS_INLINE I capacity() const noexcept { return m_elms.capacity(); }

    C4_ALWAYS_INLINE T      & elm(I i)       C4_NOEXCEPT_X { C4_XASSERT(i < m_size); return m_elms[i].elm; }
    C4_ALWAYS_INLINE T const& elm(I i) const C4_NOEXCEPT_X { C4_XASSERT(i < m_size); return m_elms[i].elm; }

    C4_ALWAYS_INLINE I prev(I i) const C4_NOEXCEPT_X { C4_XASSERT(i < m_size); return m_elms[i].prev; }
    C4_ALWAYS_INLINE I next(I i) const C4_NOEXCEPT_X { C4_XASSERT(i < m_size); return m_elms[i].next; }

    C4_ALWAYS_INLINE iterator begin() noexcept { return iterator(this, m_head); }
    C4_ALWAYS_INLINE iterator end  () noexcept { return iterator(this, m_tail); }

    C4_ALWAYS_INLINE const_iterator begin() const noexcept { return const_iterator(this, m_head); }
    C4_ALWAYS_INLINE const_iterator end  () const noexcept { return const_iterator(this, m_tail); }

};

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
template< class T, class I, template< class T, class I > class RawStorage >
class split_fwd_list
{
public:

    RawStorage< T, I > m_elm;
    RawStorage< I, I > m_next;

    I m_head;
    I m_tail;
    I m_size;
    I m_fhead;

public:

    using value_type = T;
    using size_type = I;

    using iterator = list_iterator< T, split_fwd_list >;
    using const_iterator = list_iterator< const T, const split_fwd_list >;

public:

    split_fwd_list() : m_elm(), m_next(), m_head(0), m_tail(0), m_size(0), m_fhead(0) {}

public:

    C4_ALWAYS_INLINE I size() const noexcept { return m_size; }
    C4_ALWAYS_INLINE I capacity() const noexcept { return m_elm.capacity(); }

    C4_ALWAYS_INLINE T      & elm(I i)       C4_NOEXCEPT_X { C4_XASSERT(i < m_size); return m_elms[i]; }
    C4_ALWAYS_INLINE T const& elm(I i) const C4_NOEXCEPT_X { C4_XASSERT(i < m_size); return m_elms[i]; }

    C4_ALWAYS_INLINE I next(I i) const C4_NOEXCEPT_X { C4_XASSERT(i < m_size); return m_next[i]; }

    C4_ALWAYS_INLINE iterator begin() noexcept { return iterator(this, m_head); }
    C4_ALWAYS_INLINE iterator end  () noexcept { return iterator(this, m_tail); }

    C4_ALWAYS_INLINE const_iterator begin() const noexcept { return const_iterator(this, m_head); }
    C4_ALWAYS_INLINE const_iterator end  () const noexcept { return const_iterator(this, m_tail); }

};

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
template< class T, class I, template< class T, class I > class RawStorage >
class flat_fwd_list
{
public:

    RawStorage< flat_fwd_list_elm<T, I>, I > m_elms;

    I m_head;
    I m_tail;
    I m_size;
    I m_fhead;

public:

    using value_type = T;
    using size_type = I;

    using iterator = list_iterator< T, flat_fwd_list >;
    using const_iterator = list_iterator< const T, const flat_fwd_list >;

public:

    flat_fwd_list() : m_elms(), m_head(0), m_tail(0), m_size(0), m_fhead(0) {}

public:

    C4_ALWAYS_INLINE I size() const noexcept { return m_size; }
    C4_ALWAYS_INLINE I capacity() const noexcept { return m_elm.capacity(); }

    C4_ALWAYS_INLINE T      & elm(I i)       C4_NOEXCEPT_X { C4_XASSERT(i < m_elm.size()); return m_elms[i].elm; }
    C4_ALWAYS_INLINE T const& elm(I i) const C4_NOEXCEPT_X { C4_XASSERT(i < m_elm.size()); return m_elms[i].elm; }

    C4_ALWAYS_INLINE I next(I i) const C4_NOEXCEPT_X { C4_XASSERT(i < m_next.size()); return m_next[i].next; }

    C4_ALWAYS_INLINE iterator begin() noexcept { return iterator(this, m_head); }
    C4_ALWAYS_INLINE iterator end  () noexcept { return iterator(this, m_tail); }

    C4_ALWAYS_INLINE const_iterator begin() const noexcept { return const_iterator(this, m_head); }
    C4_ALWAYS_INLINE const_iterator end  () const noexcept { return const_iterator(this, m_tail); }

};

C4_END_NAMESPACE(c4)

#endif /* _C4_LIST_HPP_ */
<commit_msg>list: change the order to (flat, split)x(doubly,fwd)<commit_after>#ifndef _C4_LIST_HPP_
#define _C4_LIST_HPP_

#include "c4/config.hpp"
#include "c4/error.hpp"
#include "c4/storage/raw.hpp"

#include <iterator>

C4_BEGIN_NAMESPACE(c4)

template< class T, class I=C4_SIZE_TYPE >
using default_list_storage = stg::raw_paged_rt< T, I >;

template< class T, class I=C4_SIZE_TYPE, template< class T_, class I_ > class LinearStorage=default_list_storage >
class split_list;

template< class T, class I=C4_SIZE_TYPE, template< class T_, class I_ > class LinearStorage=default_list_storage >
class split_fwd_list;

template< class T, class I=C4_SIZE_TYPE, template< class T_, class I_ > class LinearStorage=default_list_storage >
class flat_list;

template< class T, class I=C4_SIZE_TYPE, template< class T_, class I_ > class LinearStorage=default_list_storage >
class flat_fwd_list;

template< class T, class I=C4_SIZE_TYPE > struct flat_list_elm;
template< class T, class I=C4_SIZE_TYPE > struct flat_fwd_list_elm;

//-----------------------------------------------------------------------------
template< class T, class I >
struct flat_list_elm
{
    T elm;
    I prev;
    I next;
};

template< class T, class I >
struct flat_fwd_list_elm
{
    T elm;
    I next;
};

//-----------------------------------------------------------------------------

template< class T, class List >
struct list_iterator : public std::iterator< std::bidirectional_iterator_tag, typename List::value_type >
{
    using I = typename List::size_type;

    List *list;
    I i;

    list_iterator(List *l, I i_) : list(l), i(i_) {}

    C4_ALWAYS_INLINE T& operator*  () { return  list->elm(i); }
    C4_ALWAYS_INLINE T* operator-> () { return &list->elm(i); }

    C4_ALWAYS_INLINE list_iterator& operator++ (   ) noexcept {                           i = list->next(i); return *this; }
    C4_ALWAYS_INLINE list_iterator& operator++ (int) noexcept { list_iterator it = *this; i = list->next(i); return    it; }

    C4_ALWAYS_INLINE list_iterator& operator-- (   ) noexcept {                           i = list->prev(i); return *this; }
    C4_ALWAYS_INLINE list_iterator& operator-- (int) noexcept { list_iterator it = *this; i = list->prev(i); return    it; }

    C4_ALWAYS_INLINE bool operator== (list_iterator const& that) const noexcept { return i == that.i && list == that.list; }
    C4_ALWAYS_INLINE bool operator!= (list_iterator const& that) const noexcept { return i != that.i || list != that.list; }
};

template< class T, class List >
struct fwd_list_iterator : public std::iterator< std::forward_iterator_tag, typename List::value_type >
{
    using I = typename List::size_type;

    List *list;
    I i;

    fwd_list_iterator(List *l, I i_) : list(l), i(i_) {}

    C4_ALWAYS_INLINE T* operator-> () { return &list->elm(i); }
    C4_ALWAYS_INLINE T& operator*  () { return  list->elm(i); }

    C4_ALWAYS_INLINE fwd_list_iterator& operator++ (   ) noexcept {                               i = list->next(i); return *this; }
    C4_ALWAYS_INLINE fwd_list_iterator& operator++ (int) noexcept { fwd_list_iterator it = *this; i = list->next(i); return    it; }

    C4_ALWAYS_INLINE bool operator== (fwd_list_iterator const& that) const noexcept { return i == that.i && list == that.list; }
    C4_ALWAYS_INLINE bool operator!= (fwd_list_iterator const& that) const noexcept { return i != that.i || list != that.list; }
};

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
template< class T, class I, template< class T, class I > class RawStorage >
class flat_list
{
public:

    RawStorage< flat_list_elm<T, I>, I > m_elms;

    I m_head;
    I m_tail;
    I m_size;
    I m_fhead;

public:

    using value_type = T;
    using size_type = I;

    using iterator = list_iterator< T, flat_list >;
    using const_iterator = list_iterator< const T, const flat_list >;

public:

    flat_list() : m_elms(), m_head(0), m_tail(0), m_size(0), m_fhead(0) {}

public:

    C4_ALWAYS_INLINE I size    () const noexcept { return m_size; }
    C4_ALWAYS_INLINE I capacity() const noexcept { return m_elms.capacity(); }

    C4_ALWAYS_INLINE T      & elm(I i)       C4_NOEXCEPT_X { C4_XASSERT(i < m_size); return m_elms[i].elm; }
    C4_ALWAYS_INLINE T const& elm(I i) const C4_NOEXCEPT_X { C4_XASSERT(i < m_size); return m_elms[i].elm; }

    C4_ALWAYS_INLINE I prev(I i) const C4_NOEXCEPT_X { C4_XASSERT(i < m_size); return m_elms[i].prev; }
    C4_ALWAYS_INLINE I next(I i) const C4_NOEXCEPT_X { C4_XASSERT(i < m_size); return m_elms[i].next; }

    C4_ALWAYS_INLINE iterator begin() noexcept { return iterator(this, m_head); }
    C4_ALWAYS_INLINE iterator end  () noexcept { return iterator(this, m_tail); }

    C4_ALWAYS_INLINE const_iterator begin() const noexcept { return const_iterator(this, m_head); }
    C4_ALWAYS_INLINE const_iterator end  () const noexcept { return const_iterator(this, m_tail); }

};

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
template< class T, class I, template< class T, class I > class RawStorage >
class split_list
{
public:

    RawStorage< T, I > m_elm;
    RawStorage< I, I > m_prev;
    RawStorage< I, I > m_next;

    I m_head;
    I m_tail;
    I m_size;
    I m_fhead; //< the head of the free list (the list containing free elements)

    enum : I { npos = static_cast< I >(-1) };

public:

    using value_type = T;
    using size_type = I;

    using iterator = list_iterator< T, split_list >;
    using const_iterator = list_iterator< const T, const split_list >;

public:

    split_list() : m_elm(), m_prev(), m_next(), m_head(0), m_tail(0), m_size(0), m_fhead(0)
    {
        _init_seq(0, capacity());
    }

    split_list(c4::with_capacity_t, I cap) : m_elm(cap), m_prev(cap), m_next(cap), m_head(0), m_tail(0), m_size(0), m_fhead(0)
    {
        _init_seq(0, capacity());
    }

    split_list(c4::aggregate_t, std::initializer_list< T > il) : m_elm(szconv< I >(il.size())), m_prev(szconv< I >(il.size())), m_next(szconv< I >(il.size())), m_head(0), m_tail(0), m_size(0), m_fhead(0)
    {
        _init_seq(0, capacity());
    }

    void _growto(I next_cap)
    {
        I curr = capacity();
        m_elm._raw_reserve(next_cap);
        m_prev._raw_reserve(next_cap);
        m_next._raw_reserve(next_cap);
        _init_seq(curr, next_cap);
    }

    void _init_seq(I first, I last)
    {
        C4_ASSERT(m_elm.capacity() == m_prev.capacity() && m_elm.capacity() == m_next.capacity());
        I cap = m_elm.capacity();
        if(cap == 0) return;
        m_prev[0] = npos;
        for(I i = 1; i < cap; ++i)
        {
            m_prev[i] = i - 1;
        }
        for(I i = 0; i < cap-1; ++i) // cap must be > 0 at this point
        {
            m_next[i] = i + 1;
        }
        m_next[cap - 1] = npos;
    }

public:

    C4_ALWAYS_INLINE I size() const noexcept { return m_size; }
    C4_ALWAYS_INLINE I capacity() const noexcept { return m_elm.capacity(); }

    C4_ALWAYS_INLINE T      & elm(I i)       C4_NOEXCEPT_X { C4_XASSERT(i < m_size); return m_elms[i]; }
    C4_ALWAYS_INLINE T const& elm(I i) const C4_NOEXCEPT_X { C4_XASSERT(i < m_size); return m_elms[i]; }

    C4_ALWAYS_INLINE I prev(I i) const C4_NOEXCEPT_X { C4_XASSERT(i < m_size); return m_prev[i]; }
    C4_ALWAYS_INLINE I next(I i) const C4_NOEXCEPT_X { C4_XASSERT(i < m_size); return m_next[i]; }

    C4_ALWAYS_INLINE iterator begin() noexcept { return iterator(this, m_head); }
    C4_ALWAYS_INLINE iterator end  () noexcept { return iterator(this, m_tail); }

    C4_ALWAYS_INLINE const_iterator begin() const noexcept { return const_iterator(this, m_head); }
    C4_ALWAYS_INLINE const_iterator end  () const noexcept { return const_iterator(this, m_tail); }

public:

     void push_back(T const& var)
     {
         I cap = capacity();
         if(size() == cap)
         {
             _growto(cap, cap+1);
         }
         I pos = m_fhead;
         C4_XASSERT(pos != npos && pos < m_size);
         c4::construct(&m_elm[pos], var);
         m_prev[pos] = m_tail;
         m_next[pos] = npos;
         m_tail = pos;
         C4_XASSERT(m_fhead != npos);
         m_fhead = m_next[m_fhead];
         ++m_size;
     }
     void push_front(T const& var)
     {
     }

};

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
template< class T, class I, template< class T, class I > class RawStorage >
class flat_fwd_list
{
public:

    RawStorage< flat_fwd_list_elm<T, I>, I > m_elms;

    I m_head;
    I m_tail;
    I m_size;
    I m_fhead;

public:

    using value_type = T;
    using size_type = I;

    using iterator = list_iterator< T, flat_fwd_list >;
    using const_iterator = list_iterator< const T, const flat_fwd_list >;

public:

    flat_fwd_list() : m_elms(), m_head(0), m_tail(0), m_size(0), m_fhead(0) {}

public:

    C4_ALWAYS_INLINE I size() const noexcept { return m_size; }
    C4_ALWAYS_INLINE I capacity() const noexcept { return m_elm.capacity(); }

    C4_ALWAYS_INLINE T      & elm(I i)       C4_NOEXCEPT_X { C4_XASSERT(i < m_elm.size()); return m_elms[i].elm; }
    C4_ALWAYS_INLINE T const& elm(I i) const C4_NOEXCEPT_X { C4_XASSERT(i < m_elm.size()); return m_elms[i].elm; }

    C4_ALWAYS_INLINE I next(I i) const C4_NOEXCEPT_X { C4_XASSERT(i < m_next.size()); return m_next[i].next; }

    C4_ALWAYS_INLINE iterator begin() noexcept { return iterator(this, m_head); }
    C4_ALWAYS_INLINE iterator end  () noexcept { return iterator(this, m_tail); }

    C4_ALWAYS_INLINE const_iterator begin() const noexcept { return const_iterator(this, m_head); }
    C4_ALWAYS_INLINE const_iterator end  () const noexcept { return const_iterator(this, m_tail); }

};

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
template< class T, class I, template< class T, class I > class RawStorage >
class split_fwd_list
{
public:

    RawStorage< T, I > m_elm;
    RawStorage< I, I > m_next;

    I m_head;
    I m_tail;
    I m_size;
    I m_fhead;

public:

    using value_type = T;
    using size_type = I;

    using iterator = list_iterator< T, split_fwd_list >;
    using const_iterator = list_iterator< const T, const split_fwd_list >;

public:

    split_fwd_list() : m_elm(), m_next(), m_head(0), m_tail(0), m_size(0), m_fhead(0) {}

public:

    C4_ALWAYS_INLINE I size() const noexcept { return m_size; }
    C4_ALWAYS_INLINE I capacity() const noexcept { return m_elm.capacity(); }

    C4_ALWAYS_INLINE T      & elm(I i)       C4_NOEXCEPT_X { C4_XASSERT(i < m_size); return m_elms[i]; }
    C4_ALWAYS_INLINE T const& elm(I i) const C4_NOEXCEPT_X { C4_XASSERT(i < m_size); return m_elms[i]; }

    C4_ALWAYS_INLINE I next(I i) const C4_NOEXCEPT_X { C4_XASSERT(i < m_size); return m_next[i]; }

    C4_ALWAYS_INLINE iterator begin() noexcept { return iterator(this, m_head); }
    C4_ALWAYS_INLINE iterator end  () noexcept { return iterator(this, m_tail); }

    C4_ALWAYS_INLINE const_iterator begin() const noexcept { return const_iterator(this, m_head); }
    C4_ALWAYS_INLINE const_iterator end  () const noexcept { return const_iterator(this, m_tail); }

};
C4_END_NAMESPACE(c4)

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


<commit_before>#include "canread.h"
#include <stdlib.h>

float decodeCanSignal(CanSignal* signal, uint64_t data) {
    uint64_t rawValue = getBitField(data, signal->bitPosition,
            signal->bitSize);
    return rawValue * signal->factor + signal->offset;
}

float passthroughHandler(CanSignal* signal, CanSignal* signals, int signalCount,
        float value, bool* send) {
    return value;
}

bool booleanHandler(CanSignal* signal, CanSignal* signals, int signalCount,
        float value, bool* send) {
    return value == 0.0 ? false : true;
}

float ignoreHandler(CanSignal* signal, CanSignal* signals, int signalCount,
        float value, bool* send) {
    *send = false;
    return value;
}

const char* stateHandler(CanSignal* signal, CanSignal* signals,
        int signalCount, float value, bool* send) {
    CanSignalState* signalState = lookupSignalState(value, signal, signals,
            signalCount);
    if(signalState != NULL) {
        return signalState->name;
    }
    *send = false;
    return NULL;
}

/* Private: Serialize the root JSON object to a string (ending with a newline)
 * and send it to the listener.
 *
 * root - The JSON object to send.
 * listener - The listener device to send on.
 */
void sendJSON(cJSON* root, Listener* listener) {
    char* message = cJSON_PrintUnformatted(root);
    sendMessage(listener, (uint8_t*) message, strlen(message));
    cJSON_Delete(root);
    free(message);
}

/* Private: Combine the given name and value into a JSON object (conforming to
 * the OpenXC standard) and send it out to the listener.
 *
 * name - The value for the name field of the OpenXC message.
 * value - The numerical, string or booelan for the value field of the OpenXC
 *     message.
 * event - (Optional) The event for the event field of the OpenXC message.
 * listener - The listener device to send on.
 */
void sendJSONMessage(const char* name, cJSON* value, cJSON* event,
        Listener* listener) {
    cJSON *root = cJSON_CreateObject();
    cJSON_AddStringToObject(root, NAME_FIELD_NAME, name);
    cJSON_AddItemToObject(root, VALUE_FIELD_NAME, value);
    if(event != NULL) {
        cJSON_AddItemToObject(root, EVENT_FIELD_NAME, event);
    }
    sendJSON(root, listener);
}

void sendNumericalMessage(const char* name, float value, Listener* listener) {
    sendJSONMessage(name, cJSON_CreateNumber(value), NULL, listener);
}

void sendBooleanMessage(const char* name, bool value, Listener* listener) {
    sendJSONMessage(name, cJSON_CreateBool(value), NULL, listener);
}

void sendStringMessage(const char* name, const char* value,
        Listener* listener) {
    sendJSONMessage(name, cJSON_CreateString(value), NULL, listener);
}

void sendEventedBooleanMessage(const char* name, const char* value, bool event,
        Listener* listener) {
    sendJSONMessage(name, cJSON_CreateString(value), cJSON_CreateBool(event),
            listener);
}

void sendEventedStringMessage(const char* name, const char* value,
        const char* event, Listener* listener) {
    sendJSONMessage(name, cJSON_CreateString(value), cJSON_CreateString(event),
            listener);
}

void passthroughCanMessage(Listener* listener, int id, uint64_t data) {
    cJSON *root = cJSON_CreateObject();
    cJSON_AddNumberToObject(root, ID_FIELD_NAME, id);

    char encodedData[67];
    union {
        uint64_t whole;
        uint8_t bytes[8];
    } combined;
    combined.whole = data;

    sprintf(encodedData, "0x%02x %02x %02x %02x %02x %02x %02x %02x",
            combined.bytes[0],
            combined.bytes[1],
            combined.bytes[2],
            combined.bytes[3],
            combined.bytes[4],
            combined.bytes[5],
            combined.bytes[6],
            combined.bytes[7]);
    cJSON_AddStringToObject(root, NAME_FIELD_NAME, encodedData);

    sendJSON(root, listener);
}

// TODO there is lots of duplicated code in these functions, but I don't see an
// obvious way to share code and still keep the different data types returned
// by the handlers.
void translateCanSignal(Listener* listener, CanSignal* signal,
        uint64_t data,
        float (*handler)(CanSignal*, CanSignal*, int, float, bool*),
        CanSignal* signals, int signalCount) {
    float value = decodeCanSignal(signal, data);
    bool send = true;
    float processedValue = handler(signal, signals, signalCount, value, &send);

    if(signal->sendClock == signal->sendFrequency) {
        if(send && (signal->sendSame || !signal->received ||
                    value != signal->lastValue)) {
            signal->received = true;
            sendNumericalMessage(signal->genericName, processedValue, listener);
        }
        signal->sendClock = 0;
    } else {
        ++signal->sendClock;
    }
    signal->lastValue = value;
}

void translateCanSignal(Listener* listener, CanSignal* signal,
        uint64_t data,
        const char* (*handler)(CanSignal*, CanSignal*, int, float, bool*),
        CanSignal* signals, int signalCount) {
    float value = decodeCanSignal(signal, data);
    bool send = true;
    const char* stringValue = handler(signal, signals, signalCount, value,
            &send);

    if(signal->sendClock == signal->sendFrequency) {
        if(send && (signal->sendSame || !signal->received ||
                    value != signal->lastValue)) {
            signal->received = true;
            sendStringMessage(signal->genericName, stringValue, listener);
        }
        signal->sendClock = 0;
    } else {
        ++signal->sendClock;
    }
    signal->lastValue = value;
}

void translateCanSignal(Listener* listener, CanSignal* signal,
        uint64_t data,
        bool (*handler)(CanSignal*, CanSignal*, int, float, bool*),
        CanSignal* signals, int signalCount) {
    float value = decodeCanSignal(signal, data);
    bool send = true;
    bool booleanValue = handler(signal, signals, signalCount, value, &send);

    if(signal->sendClock == signal->sendFrequency) {
        if(send && (signal->sendSame || !signal->received ||
                    value != signal->lastValue)) {
            signal->received = true;
            sendBooleanMessage(signal->genericName, booleanValue, listener);
        }
        signal->sendClock = 0;
    } else {
        ++signal->sendClock;
    }
    signal->lastValue = value;
}

void translateCanSignal(Listener* listener, CanSignal* signal,
        uint64_t data, CanSignal* signals, int signalCount) {
    translateCanSignal(listener, signal, data, passthroughHandler, signals,
            signalCount);
}
<commit_msg>Remove spaces from output in passthrough handlers. Works with mpide-newlib.<commit_after>#include "canread.h"
#include <stdlib.h>

float decodeCanSignal(CanSignal* signal, uint64_t data) {
    uint64_t rawValue = getBitField(data, signal->bitPosition,
            signal->bitSize);
    return rawValue * signal->factor + signal->offset;
}

float passthroughHandler(CanSignal* signal, CanSignal* signals, int signalCount,
        float value, bool* send) {
    return value;
}

bool booleanHandler(CanSignal* signal, CanSignal* signals, int signalCount,
        float value, bool* send) {
    return value == 0.0 ? false : true;
}

float ignoreHandler(CanSignal* signal, CanSignal* signals, int signalCount,
        float value, bool* send) {
    *send = false;
    return value;
}

const char* stateHandler(CanSignal* signal, CanSignal* signals,
        int signalCount, float value, bool* send) {
    CanSignalState* signalState = lookupSignalState(value, signal, signals,
            signalCount);
    if(signalState != NULL) {
        return signalState->name;
    }
    *send = false;
    return NULL;
}

/* Private: Serialize the root JSON object to a string (ending with a newline)
 * and send it to the listener.
 *
 * root - The JSON object to send.
 * listener - The listener device to send on.
 */
void sendJSON(cJSON* root, Listener* listener) {
    char* message = cJSON_PrintUnformatted(root);
    sendMessage(listener, (uint8_t*) message, strlen(message));
    cJSON_Delete(root);
    free(message);
}

/* Private: Combine the given name and value into a JSON object (conforming to
 * the OpenXC standard) and send it out to the listener.
 *
 * name - The value for the name field of the OpenXC message.
 * value - The numerical, string or booelan for the value field of the OpenXC
 *     message.
 * event - (Optional) The event for the event field of the OpenXC message.
 * listener - The listener device to send on.
 */
void sendJSONMessage(const char* name, cJSON* value, cJSON* event,
        Listener* listener) {
    cJSON *root = cJSON_CreateObject();
    cJSON_AddStringToObject(root, NAME_FIELD_NAME, name);
    cJSON_AddItemToObject(root, VALUE_FIELD_NAME, value);
    if(event != NULL) {
        cJSON_AddItemToObject(root, EVENT_FIELD_NAME, event);
    }
    sendJSON(root, listener);
}

void sendNumericalMessage(const char* name, float value, Listener* listener) {
    sendJSONMessage(name, cJSON_CreateNumber(value), NULL, listener);
}

void sendBooleanMessage(const char* name, bool value, Listener* listener) {
    sendJSONMessage(name, cJSON_CreateBool(value), NULL, listener);
}

void sendStringMessage(const char* name, const char* value,
        Listener* listener) {
    sendJSONMessage(name, cJSON_CreateString(value), NULL, listener);
}

void sendEventedBooleanMessage(const char* name, const char* value, bool event,
        Listener* listener) {
    sendJSONMessage(name, cJSON_CreateString(value), cJSON_CreateBool(event),
            listener);
}

void sendEventedStringMessage(const char* name, const char* value,
        const char* event, Listener* listener) {
    sendJSONMessage(name, cJSON_CreateString(value), cJSON_CreateString(event),
            listener);
}

void passthroughCanMessage(Listener* listener, int id, uint64_t data) {
    cJSON *root = cJSON_CreateObject();
    cJSON_AddNumberToObject(root, ID_FIELD_NAME, id);

    char encodedData[67];
    union {
        uint64_t whole;
        uint8_t bytes[8];
    } combined;
    combined.whole = data;

    sprintf(encodedData, "0x%02x%02x%02x%02x%02x%02x%02x%02x",
            combined.bytes[0],
            combined.bytes[1],
            combined.bytes[2],
            combined.bytes[3],
            combined.bytes[4],
            combined.bytes[5],
            combined.bytes[6],
            combined.bytes[7]);
    cJSON_AddStringToObject(root, NAME_FIELD_NAME, encodedData);

    sendJSON(root, listener);
}

// TODO there is lots of duplicated code in these functions, but I don't see an
// obvious way to share code and still keep the different data types returned
// by the handlers.
void translateCanSignal(Listener* listener, CanSignal* signal,
        uint64_t data,
        float (*handler)(CanSignal*, CanSignal*, int, float, bool*),
        CanSignal* signals, int signalCount) {
    float value = decodeCanSignal(signal, data);
    bool send = true;
    float processedValue = handler(signal, signals, signalCount, value, &send);

    if(signal->sendClock == signal->sendFrequency) {
        if(send && (signal->sendSame || !signal->received ||
                    value != signal->lastValue)) {
            signal->received = true;
            sendNumericalMessage(signal->genericName, processedValue, listener);
        }
        signal->sendClock = 0;
    } else {
        ++signal->sendClock;
    }
    signal->lastValue = value;
}

void translateCanSignal(Listener* listener, CanSignal* signal,
        uint64_t data,
        const char* (*handler)(CanSignal*, CanSignal*, int, float, bool*),
        CanSignal* signals, int signalCount) {
    float value = decodeCanSignal(signal, data);
    bool send = true;
    const char* stringValue = handler(signal, signals, signalCount, value,
            &send);

    if(signal->sendClock == signal->sendFrequency) {
        if(send && (signal->sendSame || !signal->received ||
                    value != signal->lastValue)) {
            signal->received = true;
            sendStringMessage(signal->genericName, stringValue, listener);
        }
        signal->sendClock = 0;
    } else {
        ++signal->sendClock;
    }
    signal->lastValue = value;
}

void translateCanSignal(Listener* listener, CanSignal* signal,
        uint64_t data,
        bool (*handler)(CanSignal*, CanSignal*, int, float, bool*),
        CanSignal* signals, int signalCount) {
    float value = decodeCanSignal(signal, data);
    bool send = true;
    bool booleanValue = handler(signal, signals, signalCount, value, &send);

    if(signal->sendClock == signal->sendFrequency) {
        if(send && (signal->sendSame || !signal->received ||
                    value != signal->lastValue)) {
            signal->received = true;
            sendBooleanMessage(signal->genericName, booleanValue, listener);
        }
        signal->sendClock = 0;
    } else {
        ++signal->sendClock;
    }
    signal->lastValue = value;
}

void translateCanSignal(Listener* listener, CanSignal* signal,
        uint64_t data, CanSignal* signals, int signalCount) {
    translateCanSignal(listener, signal, data, passthroughHandler, signals,
            signalCount);
}
<|endoftext|>