<commit_before>#include <rss.h>
#include <config.h>
#include <stringprep.h>
#include <cache.h>
#include <xmlpullparser.h>
#include <utils.h>
#include <logger.h>
#include <sstream>
#include <iostream>
#include <configcontainer.h>

using namespace newsbeuter;

rss_parser::rss_parser(const char * uri, cache * c, configcontainer * cfg) : my_uri(uri), ch(c), cfgcont(cfg), mrss(0) { }

rss_parser::~rss_parser() { }

rss_feed rss_parser::parse() {
	rss_feed feed(ch);

	feed.set_rssurl(my_uri);

	char * proxy = NULL;
	char * proxy_auth = NULL;

	if (cfgcont->get_configvalue_as_bool("use-proxy") == true) {
		proxy = const_cast<char *>(cfgcont->get_configvalue("proxy").c_str());
		proxy_auth = const_cast<char *>(cfgcont->get_configvalue("proxy-auth").c_str());
	}

	mrss_options_t * options = mrss_options_new(30, proxy, proxy_auth, NULL, NULL, NULL, 0, NULL, USER_AGENT);
	mrss_error_t err = mrss_parse_url_with_options(const_cast<char *>(my_uri.c_str()), &mrss, options);
	mrss_options_free(options);

	if (err != MRSS_OK) {
		GetLogger().log(LOG_ERROR,"rss_parser::parse: mrss_parse_url_with_options failed: err = %s (%d)",mrss_strerror(err), err);
		if (mrss) {
			mrss_free(mrss);
		}
		throw std::string(mrss_strerror(err));
	}

	const char * encoding = mrss->encoding ? mrss->encoding : "utf-8";

	if (mrss->title) {
		char * str = stringprep_convert(mrss->title, stringprep_locale_charset(), encoding);
		if (str) {
			feed.set_title(str);
			free(str);
		}
	}

	if (mrss->description) {
		char * str = stringprep_convert(mrss->description, stringprep_locale_charset(), encoding);
		if (str) {
			feed.set_description(str);
			free(str);
		}
	}

	if (mrss->link) feed.set_link(mrss->link);
	if (mrss->pubDate)
		feed.set_pubDate(parse_date(mrss->pubDate));
	else
		feed.set_pubDate(::time(NULL));

	GetLogger().log(LOG_DEBUG, "rss_parser::parse: feed title = `%s' link = `%s'", feed.title().c_str(), feed.link().c_str());

	for (mrss_item_t * item = mrss->item; item != NULL; item = item->next ) {
		rss_item x(ch);
		if (item->title) {
			char * str = stringprep_convert(item->title,stringprep_locale_charset(), encoding);
			if (str) {
				x.set_title(str);
				free(str);
			}
		}
		if (item->link) x.set_link(item->link);
		if (item->author) x.set_author(item->author);

		mrss_tag_t * content;

		if (mrss->version == MRSS_VERSION_2_0 && mrss_search_tag(item, "encoded", "http://purl.org/rss/1.0/modules/content/", &content) == MRSS_OK && content) {
			/* RSS 2.0 content:encoded */
			GetLogger().log(LOG_DEBUG, "rss_parser::parse: found rss 2.0 content:encoded: %s\n", content->value);
			if (content->value) {
				char * str = stringprep_convert(content->value, stringprep_locale_charset(), encoding);
				if (str) {
					x.set_description(str);
					free(str);
					GetLogger().log(LOG_DEBUG, "rss_parser::parse: conversion was successful: %s\n", x.description().c_str());
				} else {
					GetLogger().log(LOG_WARN, "rss_parser::parse: stringprep_convert() failed for %s, but trying anyway...", x.link().c_str());
					x.set_description(content->value);
				}
			}
		} else {
			GetLogger().log(LOG_DEBUG, "rss_parser::parse: found no rss 2.0 content:encoded");
		}

		if ((mrss->version == MRSS_VERSION_ATOM_0_3 || mrss->version == MRSS_VERSION_ATOM_1_0)) {
			int rc;
			if (((rc = mrss_search_tag(item, "content", "http://www.w3.org/2005/Atom", &content)) == MRSS_OK && content) ||
			    ((rc = mrss_search_tag(item, "content", "http://purl.org/atom/ns#", &content)) == MRSS_OK && content)) {
				GetLogger().log(LOG_DEBUG, "rss_parser::parse: found atom content: %s\n", content ? content->value : "(content = null)");
				if (content && content->value) {
					char * str = stringprep_convert(content->value, stringprep_locale_charset(), encoding);
					if (str) {
						x.set_description(str);
						free(str);
					} else {
						x.set_description(content->value);
					}
				}
			} else {
				GetLogger().log(LOG_DEBUG, "rss_parser::parse: mrss_search_tag(content) failed with rc = %d content = %p", rc, content);
			}
		} else {
			GetLogger().log(LOG_DEBUG, "rss_parser::parse: not an atom feed");
		}

		if (x.description().length() == 0 && item->description) {
			char * str = stringprep_convert(item->description,stringprep_locale_charset(), encoding);
			if (str) {
				x.set_description(str);
				free(str);
			}
		}

		if (item->pubDate)
			x.set_pubDate(parse_date(item->pubDate));
		else
			x.set_pubDate(::time(NULL));

		if (item->guid)
			x.set_guid(item->guid);
		else
			x.set_guid(item->link); // XXX hash something to get a better alternative GUID

		if (item->enclosure_url) {
			x.set_enclosure_url(item->enclosure_url);
			GetLogger().log(LOG_DEBUG, "rss_parser::parse: found enclosure_url: %s", item->enclosure_url);
		}
		if (item->enclosure_type) {
			x.set_enclosure_type(item->enclosure_type);
			GetLogger().log(LOG_DEBUG, "rss_parser::parse: found enclosure_type: %s", item->enclosure_type);
		}

		GetLogger().log(LOG_DEBUG, "rss_parser::parse: item title = `%s' link = `%s' pubDate = `%s' (%d) description = `%s'",
			x.title().c_str(), x.link().c_str(), x.pubDate().c_str(), x.pubDate_timestamp(), x.description().c_str());
		feed.items().push_back(x);
	}

	mrss_free(mrss);

	return feed;
}

// rss_item setters

void rss_item::set_title(const std::string& t) {
	title_ = t;
}

void rss_item::set_link(const std::string& l) {
	link_ = l;
}

void rss_item::set_author(const std::string& a) {
	author_ = a;
}

void rss_item::set_description(const std::string& d) {
	description_ = d;
}

void rss_item::set_pubDate(time_t t) {
	pubDate_ = t;
}

void rss_item::set_guid(const std::string& g) {
	guid_ = g;
}

void rss_item::set_unread(bool u) {
	if (unread_ != u) {
		unread_ = u;
		if (ch) ch->update_rssitem_unread_and_enqueued(*this, feedurl_);
	}
}

std::string rss_item::pubDate() const {
	char text[1024];
	strftime(text,sizeof(text),"%a, %d %b %Y %T", gmtime(&pubDate_));
	return std::string(text);
}

unsigned int rss_feed::unread_item_count() const {
	unsigned int count = 0;
	for (std::vector<rss_item>::const_iterator it=items_.begin();it!=items_.end();++it) {
		if (it->unread())
			++count;
	}
	return count;
}

time_t rss_parser::parse_date(const std::string& datestr) {
	// TODO: refactor
	std::istringstream is(datestr);
	std::string monthstr, time, tmp;
	struct tm stm;

	memset(&stm,0,sizeof(stm));

	is >> tmp;
	if (tmp[tmp.length()-1] == ',')
		is >> tmp;

	std::istringstream dayis(tmp);
	dayis >> stm.tm_mday;

	is >> monthstr;

	if (monthstr == "Jan")
		stm.tm_mon = 0;
	else if (monthstr == "Feb")
		stm.tm_mon = 1;
	else if (monthstr == "Mar")
		stm.tm_mon = 2;
	else if (monthstr == "Apr")
		stm.tm_mon = 3;
	else if (monthstr == "May")
		stm.tm_mon = 4;
	else if (monthstr == "Jun")
		stm.tm_mon = 5;
	else if (monthstr == "Jul")
		stm.tm_mon = 6;
	else if (monthstr == "Aug")
		stm.tm_mon = 7;
	else if (monthstr == "Sep")
		stm.tm_mon = 8;
	else if (monthstr == "Oct")
		stm.tm_mon = 9;
	else if (monthstr == "Nov")
		stm.tm_mon = 10;
	else if (monthstr == "Dec")
		stm.tm_mon = 11;

	int year;
	is >> year;
	stm.tm_year = year - 1900;

	is >> time;

    stm.tm_hour = stm.tm_min = stm.tm_sec = 0;

	std::vector<std::string> tkns = utils::tokenize(time,":");
	if (tkns.size() > 0) {
        std::istringstream hs(tkns[0]);
        hs >> stm.tm_hour;
        if (tkns.size() > 1) {
            std::istringstream ms(tkns[1]);
            ms >> stm.tm_min;
            if (tkns.size() > 2) {
                std::istringstream ss(tkns[2]);
                ss >> stm.tm_sec;
            }
        }
    }

	time_t value = mktime(&stm);
	return value;
}

bool rss_feed::matches_tag(const std::string& tag) {
	for (std::vector<std::string>::iterator it=tags_.begin();it!=tags_.end();++it) {
		if (tag == *it)
			return true;
	}
	return false;
}

std::string rss_feed::get_tags() {
	std::string tags;
	for (std::vector<std::string>::iterator it=tags_.begin();it!=tags_.end();++it) {
		tags.append(*it);
		tags.append(" ");
	}
	return tags;
}

void rss_feed::set_tags(const std::vector<std::string>& tags) {
	if (tags_.size() > 0)
		tags_.erase(tags_.begin(), tags_.end());
	for (std::vector<std::string>::const_iterator it=tags.begin();it!=tags.end();++it) {
		tags_.push_back(*it);
	}
}

void rss_item::set_enclosure_url(const std::string& url) {
	enclosure_url_ = url;
}

void rss_item::set_enclosure_type(const std::string& type) {
	enclosure_type_ = type;
}
<commit_msg>Andreas Krennmair: 	improved support for podcast (<itunes:summary>) summaries.<commit_after>#include <rss.h>
#include <config.h>
#include <stringprep.h>
#include <cache.h>
#include <xmlpullparser.h>
#include <utils.h>
#include <logger.h>
#include <sstream>
#include <iostream>
#include <configcontainer.h>

using namespace newsbeuter;

rss_parser::rss_parser(const char * uri, cache * c, configcontainer * cfg) : my_uri(uri), ch(c), cfgcont(cfg), mrss(0) { }

rss_parser::~rss_parser() { }

rss_feed rss_parser::parse() {
	rss_feed feed(ch);

	feed.set_rssurl(my_uri);

	char * proxy = NULL;
	char * proxy_auth = NULL;

	if (cfgcont->get_configvalue_as_bool("use-proxy") == true) {
		proxy = const_cast<char *>(cfgcont->get_configvalue("proxy").c_str());
		proxy_auth = const_cast<char *>(cfgcont->get_configvalue("proxy-auth").c_str());
	}

	mrss_options_t * options = mrss_options_new(30, proxy, proxy_auth, NULL, NULL, NULL, 0, NULL, USER_AGENT);
	mrss_error_t err = mrss_parse_url_with_options(const_cast<char *>(my_uri.c_str()), &mrss, options);
	mrss_options_free(options);

	if (err != MRSS_OK) {
		GetLogger().log(LOG_ERROR,"rss_parser::parse: mrss_parse_url_with_options failed: err = %s (%d)",mrss_strerror(err), err);
		if (mrss) {
			mrss_free(mrss);
		}
		throw std::string(mrss_strerror(err));
	}

	const char * encoding = mrss->encoding ? mrss->encoding : "utf-8";

	if (mrss->title) {
		char * str = stringprep_convert(mrss->title, stringprep_locale_charset(), encoding);
		if (str) {
			feed.set_title(str);
			free(str);
		}
	}

	if (mrss->description) {
		char * str = stringprep_convert(mrss->description, stringprep_locale_charset(), encoding);
		if (str) {
			feed.set_description(str);
			free(str);
		}
	}

	if (mrss->link) feed.set_link(mrss->link);
	if (mrss->pubDate)
		feed.set_pubDate(parse_date(mrss->pubDate));
	else
		feed.set_pubDate(::time(NULL));

	GetLogger().log(LOG_DEBUG, "rss_parser::parse: feed title = `%s' link = `%s'", feed.title().c_str(), feed.link().c_str());

	for (mrss_item_t * item = mrss->item; item != NULL; item = item->next ) {
		rss_item x(ch);
		if (item->title) {
			char * str = stringprep_convert(item->title,stringprep_locale_charset(), encoding);
			if (str) {
				x.set_title(str);
				free(str);
			}
		}
		if (item->link) x.set_link(item->link);
		if (item->author) x.set_author(item->author);

		mrss_tag_t * content;

		if (mrss->version == MRSS_VERSION_2_0 && mrss_search_tag(item, "encoded", "http://purl.org/rss/1.0/modules/content/", &content) == MRSS_OK && content) {
			/* RSS 2.0 content:encoded */
			GetLogger().log(LOG_DEBUG, "rss_parser::parse: found rss 2.0 content:encoded: %s\n", content->value);
			if (content->value) {
				char * str = stringprep_convert(content->value, stringprep_locale_charset(), encoding);
				if (str) {
					x.set_description(str);
					free(str);
					GetLogger().log(LOG_DEBUG, "rss_parser::parse: conversion was successful: %s\n", x.description().c_str());
				} else {
					GetLogger().log(LOG_WARN, "rss_parser::parse: stringprep_convert() failed for %s, but trying anyway...", x.link().c_str());
					x.set_description(content->value);
				}
			}
		} else {
			GetLogger().log(LOG_DEBUG, "rss_parser::parse: found no rss 2.0 content:encoded");
		}

		if ((mrss->version == MRSS_VERSION_ATOM_0_3 || mrss->version == MRSS_VERSION_ATOM_1_0)) {
			int rc;
			if (((rc = mrss_search_tag(item, "content", "http://www.w3.org/2005/Atom", &content)) == MRSS_OK && content) ||
			    ((rc = mrss_search_tag(item, "content", "http://purl.org/atom/ns#", &content)) == MRSS_OK && content)) {
				GetLogger().log(LOG_DEBUG, "rss_parser::parse: found atom content: %s\n", content ? content->value : "(content = null)");
				if (content && content->value) {
					char * str = stringprep_convert(content->value, stringprep_locale_charset(), encoding);
					if (str) {
						x.set_description(str);
						free(str);
					} else {
						x.set_description(content->value);
					}
				}
			} else {
				GetLogger().log(LOG_DEBUG, "rss_parser::parse: mrss_search_tag(content) failed with rc = %d content = %p", rc, content);
			}
		} else {
			GetLogger().log(LOG_DEBUG, "rss_parser::parse: not an atom feed");
		}

		/* last resort: search for itunes:summary tag (may be a podcast) */
		if (x.description().length() == 0 && mrss_search_tag(item, "summary", "http://www.itunes.com/dtds/podcast-1.0.dtd", &content) == MRSS_OK && content) {
			GetLogger().log(LOG_DEBUG, "rss_parser::parse: found itunes:summary: %s\n", content->value);
			if (content->value) {
				char * str = stringprep_convert(content->value, stringprep_locale_charset(), encoding);
				if (str) {
					std::string desc = "<pre>";
					desc.append(str);
					desc.append("</pre>");
					x.set_description(desc);
					free(str);
					GetLogger().log(LOG_DEBUG, "rss_parser::parse: conversion was successful: %s\n", x.description().c_str());
				} else {
					GetLogger().log(LOG_WARN, "rss_parser::parse: stringprep_convert() failed for %s, but trying anyway...", x.link().c_str());
					x.set_description(content->value);
				}
			}

		} else {
			GetLogger().log(LOG_DEBUG, "rss_parser::parse: no luck with itunes:summary");
		}

		if (x.description().length() == 0 && item->description) {
			char * str = stringprep_convert(item->description,stringprep_locale_charset(), encoding);
			if (str) {
				x.set_description(str);
				free(str);
			}
		}

		if (item->pubDate)
			x.set_pubDate(parse_date(item->pubDate));
		else
			x.set_pubDate(::time(NULL));

		if (item->guid)
			x.set_guid(item->guid);
		else
			x.set_guid(item->link); // XXX hash something to get a better alternative GUID

		if (item->enclosure_url) {
			x.set_enclosure_url(item->enclosure_url);
			GetLogger().log(LOG_DEBUG, "rss_parser::parse: found enclosure_url: %s", item->enclosure_url);
		}
		if (item->enclosure_type) {
			x.set_enclosure_type(item->enclosure_type);
			GetLogger().log(LOG_DEBUG, "rss_parser::parse: found enclosure_type: %s", item->enclosure_type);
		}

		GetLogger().log(LOG_DEBUG, "rss_parser::parse: item title = `%s' link = `%s' pubDate = `%s' (%d) description = `%s'",
			x.title().c_str(), x.link().c_str(), x.pubDate().c_str(), x.pubDate_timestamp(), x.description().c_str());
		feed.items().push_back(x);
	}

	mrss_free(mrss);

	return feed;
}

// rss_item setters

void rss_item::set_title(const std::string& t) {
	title_ = t;
}

void rss_item::set_link(const std::string& l) {
	link_ = l;
}

void rss_item::set_author(const std::string& a) {
	author_ = a;
}

void rss_item::set_description(const std::string& d) {
	description_ = d;
}

void rss_item::set_pubDate(time_t t) {
	pubDate_ = t;
}

void rss_item::set_guid(const std::string& g) {
	guid_ = g;
}

void rss_item::set_unread(bool u) {
	if (unread_ != u) {
		unread_ = u;
		if (ch) ch->update_rssitem_unread_and_enqueued(*this, feedurl_);
	}
}

std::string rss_item::pubDate() const {
	char text[1024];
	strftime(text,sizeof(text),"%a, %d %b %Y %T", gmtime(&pubDate_));
	return std::string(text);
}

unsigned int rss_feed::unread_item_count() const {
	unsigned int count = 0;
	for (std::vector<rss_item>::const_iterator it=items_.begin();it!=items_.end();++it) {
		if (it->unread())
			++count;
	}
	return count;
}

time_t rss_parser::parse_date(const std::string& datestr) {
	// TODO: refactor
	std::istringstream is(datestr);
	std::string monthstr, time, tmp;
	struct tm stm;

	memset(&stm,0,sizeof(stm));

	is >> tmp;
	if (tmp[tmp.length()-1] == ',')
		is >> tmp;

	std::istringstream dayis(tmp);
	dayis >> stm.tm_mday;

	is >> monthstr;

	if (monthstr == "Jan")
		stm.tm_mon = 0;
	else if (monthstr == "Feb")
		stm.tm_mon = 1;
	else if (monthstr == "Mar")
		stm.tm_mon = 2;
	else if (monthstr == "Apr")
		stm.tm_mon = 3;
	else if (monthstr == "May")
		stm.tm_mon = 4;
	else if (monthstr == "Jun")
		stm.tm_mon = 5;
	else if (monthstr == "Jul")
		stm.tm_mon = 6;
	else if (monthstr == "Aug")
		stm.tm_mon = 7;
	else if (monthstr == "Sep")
		stm.tm_mon = 8;
	else if (monthstr == "Oct")
		stm.tm_mon = 9;
	else if (monthstr == "Nov")
		stm.tm_mon = 10;
	else if (monthstr == "Dec")
		stm.tm_mon = 11;

	int year;
	is >> year;
	stm.tm_year = year - 1900;

	is >> time;

    stm.tm_hour = stm.tm_min = stm.tm_sec = 0;

	std::vector<std::string> tkns = utils::tokenize(time,":");
	if (tkns.size() > 0) {
        std::istringstream hs(tkns[0]);
        hs >> stm.tm_hour;
        if (tkns.size() > 1) {
            std::istringstream ms(tkns[1]);
            ms >> stm.tm_min;
            if (tkns.size() > 2) {
                std::istringstream ss(tkns[2]);
                ss >> stm.tm_sec;
            }
        }
    }

	time_t value = mktime(&stm);
	return value;
}

bool rss_feed::matches_tag(const std::string& tag) {
	for (std::vector<std::string>::iterator it=tags_.begin();it!=tags_.end();++it) {
		if (tag == *it)
			return true;
	}
	return false;
}

std::string rss_feed::get_tags() {
	std::string tags;
	for (std::vector<std::string>::iterator it=tags_.begin();it!=tags_.end();++it) {
		tags.append(*it);
		tags.append(" ");
	}
	return tags;
}

void rss_feed::set_tags(const std::vector<std::string>& tags) {
	if (tags_.size() > 0)
		tags_.erase(tags_.begin(), tags_.end());
	for (std::vector<std::string>::const_iterator it=tags.begin();it!=tags.end();++it) {
		tags_.push_back(*it);
	}
}

void rss_item::set_enclosure_url(const std::string& url) {
	enclosure_url_ = url;
}

void rss_item::set_enclosure_type(const std::string& type) {
	enclosure_type_ = type;
}
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkHierarchicalBoxDataSet.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkHierarchicalBoxDataSet.h"

#include "vtkHierarchicalBoxDataSetInternal.h"

#include "vtkMultiGroupDataInformation.h"
#include "vtkInformation.h"
#include "vtkInformationIdTypeKey.h"
#include "vtkInformationIntegerVectorKey.h"
#include "vtkInformationKey.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkUniformGrid.h"
#include "vtkUnsignedCharArray.h"

vtkCxxRevisionMacro(vtkHierarchicalBoxDataSet, "1.16");
vtkStandardNewMacro(vtkHierarchicalBoxDataSet);

vtkInformationKeyMacro(vtkHierarchicalBoxDataSet,BOX,IntegerVector);
vtkInformationKeyMacro(vtkHierarchicalBoxDataSet,NUMBER_OF_BLANKED_POINTS,IdType);

typedef vtkstd::vector<vtkAMRBox> vtkAMRBoxList;
//----------------------------------------------------------------------------
vtkHierarchicalBoxDataSet::vtkHierarchicalBoxDataSet()
{
  this->BoxInternal = new vtkHierarchicalBoxDataSetInternal;
  this->ScalarRange[0]=VTK_DOUBLE_MAX;
  this->ScalarRange[0]=VTK_DOUBLE_MIN;
}

//----------------------------------------------------------------------------
vtkHierarchicalBoxDataSet::~vtkHierarchicalBoxDataSet()
{
  delete this->BoxInternal;
}

//----------------------------------------------------------------------------
void vtkHierarchicalBoxDataSet::SetDataSet(
  unsigned int level, unsigned int id, vtkAMRBox& box, vtkUniformGrid* dataSet)
{
  this->Superclass::SetDataSet(level, id, dataSet);

  vtkInformation* info =
    this->MultiGroupDataInformation->GetInformation(level, id);
  if (info)
    {
    info->Set(BOX(),
              box.LoCorner[0], box.LoCorner[1], box.LoCorner[2],
              box.HiCorner[0], box.HiCorner[1], box.HiCorner[2]);
    }
}

//----------------------------------------------------------------------------
vtkUniformGrid* vtkHierarchicalBoxDataSet::GetDataSet(unsigned int level,
                                                      unsigned int id,
                                                      vtkAMRBox& box)
{
  if (this->Internal->DataSets.size() <= level)
    {
    return 0;
    }

  vtkMultiGroupDataSetInternal::GroupDataSetsType& ldataSets =
    this->Internal->DataSets[level];
  if (ldataSets.size() <= id)
    {
    return 0;
    }

  if (!ldataSets[id])
    {
    return 0;
    }

  vtkInformation* info =
    this->MultiGroupDataInformation->GetInformation(level, id);
  if (info)
    {
    int* boxVec = info->Get(BOX());
    if (boxVec)
      {
      vtkAMRBoxInitialize<3>(box.LoCorner, box.HiCorner,
                             boxVec      , boxVec+3);
      }
    }
  return static_cast<vtkUniformGrid*>(ldataSets[id].GetPointer());
}

//----------------------------------------------------------------------------
void vtkHierarchicalBoxDataSet::SetRefinementRatio(unsigned int level,
                                                   int ratio)
{
  if (level >= this->BoxInternal->RefinementRatios.size())
    {
    this->BoxInternal->RefinementRatios.resize(level+1);
    }
  this->BoxInternal->RefinementRatios[level] = ratio;
}

//----------------------------------------------------------------------------
int vtkHierarchicalBoxDataSet::GetRefinementRatio(unsigned int level)
{
  if (level >= this->BoxInternal->RefinementRatios.size())
    {
    return 0;
    }
  return this->BoxInternal->RefinementRatios[level];
}

//----------------------------------------------------------------------------
int vtkHierarchicalBoxDataSetIsInBoxes(vtkAMRBoxList& boxes,
                                       int i, int j, int k)
{
  vtkAMRBoxList::iterator it;
  for(it = boxes.begin(); it != boxes.end(); it++)
    {
    if (it->DoesContainCell(i, j, k))
      {
      return 1;
      }
    }
  return 0;
}

//----------------------------------------------------------------------------
void vtkHierarchicalBoxDataSet::GenerateVisibilityArrays()
{
  if (!this->MultiGroupDataInformation)
    {
    vtkErrorMacro("No information about data layout is specified. "
                  "Cannot generate visibility arrays");
    return;
    }

  unsigned int numLevels = this->GetNumberOfLevels();

  for (unsigned int levelIdx=0; levelIdx<numLevels; levelIdx++)
    {
    // Copy boxes of higher level and coarsen to this level
    vtkAMRBoxList boxes;
    unsigned int numDataSets = this->GetNumberOfDataSets(levelIdx+1);
    unsigned int dataSetIdx;
    if (levelIdx < numLevels - 1)
      {
      for (dataSetIdx=0; dataSetIdx<numDataSets; dataSetIdx++)
        {
        if (!this->MultiGroupDataInformation->HasInformation(
              levelIdx+1, dataSetIdx))
          {
          continue;
          }
        vtkInformation* info =
          this->MultiGroupDataInformation->GetInformation(
            levelIdx+1,dataSetIdx);
        int* boxVec = info->Get(BOX());
        vtkAMRBox coarsebox(3, boxVec, boxVec+3);
        if (this->BoxInternal->RefinementRatios.size() <= levelIdx)
          {
          continue;
          }
        coarsebox.Coarsen(this->BoxInternal->RefinementRatios[levelIdx]);
        boxes.push_back(coarsebox);
        }
      }

    numDataSets = this->GetNumberOfDataSets(levelIdx);
    for (dataSetIdx=0; dataSetIdx<numDataSets; dataSetIdx++)
      {
      vtkAMRBox box;
      vtkUniformGrid* grid = this->GetDataSet(levelIdx, dataSetIdx, box);

      if (grid)
        {
        int i;
        int cellDims[3];
        for (i=0; i<3; i++)
          {
          cellDims[i] = box.HiCorner[i] - box.LoCorner[i] + 1;
          }
        vtkUnsignedCharArray* vis = vtkUnsignedCharArray::New();
        vtkIdType numCells = box.GetNumberOfCells();
        vis->SetNumberOfTuples(numCells);
        for (i=0; i<numCells; i++)
          {
          vis->SetValue(i, 1);
          }
        vtkIdType numBlankedPts = 0;
        for (int iz=box.LoCorner[2]; iz<=box.HiCorner[2]; iz++)
          {
          for (int iy=box.LoCorner[1]; iy<=box.HiCorner[1]; iy++)
            {
            for (int ix=box.LoCorner[0]; ix<=box.HiCorner[0]; ix++)
              {
              // Blank if cell is covered by a box of higher level
              if (vtkHierarchicalBoxDataSetIsInBoxes(boxes, ix, iy, iz))
                {
                vtkIdType id =
                  (iz-box.LoCorner[2])*cellDims[0]*cellDims[1] +
                  (iy-box.LoCorner[1])*cellDims[0] +
                  (ix-box.LoCorner[0]);
                vis->SetValue(id, 0);
                numBlankedPts++;
                }
              }
            }
          }
        grid->SetCellVisibilityArray(vis);
        vis->Delete();
        if (this->MultiGroupDataInformation->HasInformation(
              levelIdx, dataSetIdx))
          {
          vtkInformation* infotmp =
            this->MultiGroupDataInformation->GetInformation(
              levelIdx,dataSetIdx);
          infotmp->Set(NUMBER_OF_BLANKED_POINTS(), numBlankedPts);
          }
        }
      }
    }
}

//----------------------------------------------------------------------------
vtkIdType vtkHierarchicalBoxDataSet::GetNumberOfPoints()
{
  vtkIdType numPts = 0;

  unsigned int numLevels = this->GetNumberOfLevels();
  for (unsigned int level=0; level<numLevels; level++)
    {
    unsigned int numDataSets = this->GetNumberOfDataSets(level);
    for (unsigned int dataIdx=0; dataIdx<numDataSets; dataIdx++)
      {
      vtkIdType numBlankedPts = 0;
      vtkInformation* blockInfo =
        this->MultiGroupDataInformation->GetInformation(level, dataIdx);
      if (blockInfo)
        {
        if (blockInfo->Has(
              vtkHierarchicalBoxDataSet::NUMBER_OF_BLANKED_POINTS()))
          {
          numBlankedPts = blockInfo->Get(NUMBER_OF_BLANKED_POINTS());
          }
        }
      vtkDataSet* ds = vtkDataSet::SafeDownCast(
        this->GetDataSet(level, dataIdx));
      if (ds)
        {
        numPts += ds->GetNumberOfPoints() - numBlankedPts;
        }
      }
    }

  return numPts;
}

//----------------------------------------------------------------------------
void vtkHierarchicalBoxDataSet::ShallowCopy(vtkDataObject *src)
{
  if (src == this)
    {
    return;
    }
  this->InitializeDataSets();
  this->Modified();

  vtkHierarchicalBoxDataSet* from =
    vtkHierarchicalBoxDataSet::SafeDownCast(src);
  if (from)
    {
    // If the source is a vtkHierarchicalBoxDataSet, do not call
    // superclass' ShallowCopy, instead skip to vtkCompositeDataSet's
    // constructor
    this->vtkCompositeDataSet::ShallowCopy(src);

    unsigned int numLevels = from->GetNumberOfLevels();
    this->SetNumberOfLevels(numLevels);
    for (unsigned int i=0; i<numLevels; i++)
      {
      unsigned int numDataSets = from->GetNumberOfDataSets(i);
      this->SetNumberOfDataSets(i, numDataSets);
      for (unsigned int j=0; j<numDataSets; j++)
        {
        vtkAMRBox box;
        vtkUniformGrid* grid = from->GetDataSet(i, j, box);
        this->SetDataSet(i, j, box, grid);
        }
      }
    }
  else
    {
    this->Superclass::ShallowCopy(src);
    }
}

//----------------------------------------------------------------------------
void vtkHierarchicalBoxDataSet::DeepCopy(vtkDataObject *src)
{
  if (src == this)
    {
    return;
    }
  this->InitializeDataSets();
  this->Modified();

  vtkHierarchicalBoxDataSet* from =
    vtkHierarchicalBoxDataSet::SafeDownCast(src);
  if (from)
    {
    // If the source is a vtkHierarchicalBoxDataSet, do not call
    // superclass' DeepCopy, instead skip to vtkCompositeDataSet's
    // constructor
    this->vtkCompositeDataSet::ShallowCopy(src);

    unsigned int numLevels = from->GetNumberOfLevels();
    this->SetNumberOfLevels(numLevels);
    for (unsigned int i=0; i<numLevels; i++)
      {
      unsigned int numDataSets = from->GetNumberOfDataSets(i);
      this->SetNumberOfDataSets(i, numDataSets);
      for (unsigned int j=0; j<numDataSets; j++)
        {
        vtkAMRBox box;
        vtkUniformGrid* ds = from->GetDataSet(i, j, box);
        if (ds)
          {
          vtkUniformGrid* copy = ds->NewInstance();
          copy->DeepCopy(ds);
          this->SetDataSet(i, j, box, copy);
          }
        }
      }
    }
}

//----------------------------------------------------------------------------
void vtkHierarchicalBoxDataSet::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
  unsigned int numLevels = this->GetNumberOfLevels();
  os << indent << "Number of levels: " <<  numLevels << endl;
  for (unsigned int i=0; i<numLevels; i++)
    {
    unsigned int numDataSets = this->GetNumberOfDataSets(i);
    os << indent << "Level " << i << " number of datasets: " << numDataSets
       << endl;
    for (unsigned j=0; j<numDataSets; j++)
      {
      os << indent << "DataSet(" << i << "," << j << "):";
      vtkDataObject* dobj = this->GetDataSet(i, j);
      if (dobj)
        {
        os << endl;
        dobj->PrintSelf(os, indent.GetNextIndent());
        }
      else
        {
        os << "(none)" << endl;
        }
      }
    }
}

//----------------------------------------------------------------------------
vtkHierarchicalBoxDataSet* vtkHierarchicalBoxDataSet::GetData(
  vtkInformation* info)
{
  return
    info?vtkHierarchicalBoxDataSet::SafeDownCast(info->Get(DATA_OBJECT())) : 0;
}

//----------------------------------------------------------------------------
vtkHierarchicalBoxDataSet* vtkHierarchicalBoxDataSet::GetData(
  vtkInformationVector* v, int i)
{
  return vtkHierarchicalBoxDataSet::GetData(v->GetInformationObject(i));
}

//----------------------------------------------------------------------------
// Description:
// Copy the cached scalar range into range.
void vtkHierarchicalBoxDataSet::GetScalarRange(double range[2])
{
  this->ComputeScalarRange();
  range[0]=this->ScalarRange[0];
  range[1]=this->ScalarRange[1];
}

//----------------------------------------------------------------------------
// Description:
// Return the cached range.
double *vtkHierarchicalBoxDataSet::GetScalarRange()
{
  this->ComputeScalarRange();
  return this->ScalarRange;
}

//----------------------------------------------------------------------------
// Description:
// Compute the range of the scalars and cache it into ScalarRange
// only if the cache became invalid (ScalarRangeComputeTime).
void vtkHierarchicalBoxDataSet::ComputeScalarRange()
{
  if ( this->GetMTime() > this->ScalarRangeComputeTime )
    {
    double dataSetRange[2];
    this->ScalarRange[0]=VTK_DOUBLE_MAX;
    this->ScalarRange[1]=VTK_DOUBLE_MIN;
    unsigned int level=0;
    unsigned int levels=this->GetNumberOfLevels();
    while(level<levels)
      {
      unsigned int dataset=0;
      unsigned int datasets=this->GetNumberOfDataSets(level);
      while(dataset<datasets)
        {
        vtkUniformGrid *ug;
        ug=static_cast<vtkUniformGrid *>(this->GetDataSet(level,dataset));
        ug->GetScalarRange(dataSetRange);
        if(dataSetRange[0]<this->ScalarRange[0])
          {
          this->ScalarRange[0]=dataSetRange[0];
          }
        if(dataSetRange[1]>this->ScalarRange[1])
          {
          this->ScalarRange[1]=dataSetRange[1];
          }
        ++dataset;
        }
      ++level;
      }
    this->ScalarRangeComputeTime.Modified();
    }
}
<commit_msg>BUG:Fixed bad index.<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkHierarchicalBoxDataSet.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkHierarchicalBoxDataSet.h"

#include "vtkHierarchicalBoxDataSetInternal.h"

#include "vtkMultiGroupDataInformation.h"
#include "vtkInformation.h"
#include "vtkInformationIdTypeKey.h"
#include "vtkInformationIntegerVectorKey.h"
#include "vtkInformationKey.h"
#include "vtkInformationVector.h"
#include "vtkObjectFactory.h"
#include "vtkUniformGrid.h"
#include "vtkUnsignedCharArray.h"

vtkCxxRevisionMacro(vtkHierarchicalBoxDataSet, "1.17");
vtkStandardNewMacro(vtkHierarchicalBoxDataSet);

vtkInformationKeyMacro(vtkHierarchicalBoxDataSet,BOX,IntegerVector);
vtkInformationKeyMacro(vtkHierarchicalBoxDataSet,NUMBER_OF_BLANKED_POINTS,IdType);

typedef vtkstd::vector<vtkAMRBox> vtkAMRBoxList;
//----------------------------------------------------------------------------
vtkHierarchicalBoxDataSet::vtkHierarchicalBoxDataSet()
{
  this->BoxInternal = new vtkHierarchicalBoxDataSetInternal;
  this->ScalarRange[0]=VTK_DOUBLE_MAX;
  this->ScalarRange[1]=VTK_DOUBLE_MIN;
}

//----------------------------------------------------------------------------
vtkHierarchicalBoxDataSet::~vtkHierarchicalBoxDataSet()
{
  delete this->BoxInternal;
}

//----------------------------------------------------------------------------
void vtkHierarchicalBoxDataSet::SetDataSet(
  unsigned int level, unsigned int id, vtkAMRBox& box, vtkUniformGrid* dataSet)
{
  this->Superclass::SetDataSet(level, id, dataSet);

  vtkInformation* info =
    this->MultiGroupDataInformation->GetInformation(level, id);
  if (info)
    {
    info->Set(BOX(),
              box.LoCorner[0], box.LoCorner[1], box.LoCorner[2],
              box.HiCorner[0], box.HiCorner[1], box.HiCorner[2]);
    }
}

//----------------------------------------------------------------------------
vtkUniformGrid* vtkHierarchicalBoxDataSet::GetDataSet(unsigned int level,
                                                      unsigned int id,
                                                      vtkAMRBox& box)
{
  if (this->Internal->DataSets.size() <= level)
    {
    return 0;
    }

  vtkMultiGroupDataSetInternal::GroupDataSetsType& ldataSets =
    this->Internal->DataSets[level];
  if (ldataSets.size() <= id)
    {
    return 0;
    }

  if (!ldataSets[id])
    {
    return 0;
    }

  vtkInformation* info =
    this->MultiGroupDataInformation->GetInformation(level, id);
  if (info)
    {
    int* boxVec = info->Get(BOX());
    if (boxVec)
      {
      vtkAMRBoxInitialize<3>(box.LoCorner, box.HiCorner,
                             boxVec      , boxVec+3);
      }
    }
  return static_cast<vtkUniformGrid*>(ldataSets[id].GetPointer());
}

//----------------------------------------------------------------------------
void vtkHierarchicalBoxDataSet::SetRefinementRatio(unsigned int level,
                                                   int ratio)
{
  if (level >= this->BoxInternal->RefinementRatios.size())
    {
    this->BoxInternal->RefinementRatios.resize(level+1);
    }
  this->BoxInternal->RefinementRatios[level] = ratio;
}

//----------------------------------------------------------------------------
int vtkHierarchicalBoxDataSet::GetRefinementRatio(unsigned int level)
{
  if (level >= this->BoxInternal->RefinementRatios.size())
    {
    return 0;
    }
  return this->BoxInternal->RefinementRatios[level];
}

//----------------------------------------------------------------------------
int vtkHierarchicalBoxDataSetIsInBoxes(vtkAMRBoxList& boxes,
                                       int i, int j, int k)
{
  vtkAMRBoxList::iterator it;
  for(it = boxes.begin(); it != boxes.end(); it++)
    {
    if (it->DoesContainCell(i, j, k))
      {
      return 1;
      }
    }
  return 0;
}

//----------------------------------------------------------------------------
void vtkHierarchicalBoxDataSet::GenerateVisibilityArrays()
{
  if (!this->MultiGroupDataInformation)
    {
    vtkErrorMacro("No information about data layout is specified. "
                  "Cannot generate visibility arrays");
    return;
    }

  unsigned int numLevels = this->GetNumberOfLevels();

  for (unsigned int levelIdx=0; levelIdx<numLevels; levelIdx++)
    {
    // Copy boxes of higher level and coarsen to this level
    vtkAMRBoxList boxes;
    unsigned int numDataSets = this->GetNumberOfDataSets(levelIdx+1);
    unsigned int dataSetIdx;
    if (levelIdx < numLevels - 1)
      {
      for (dataSetIdx=0; dataSetIdx<numDataSets; dataSetIdx++)
        {
        if (!this->MultiGroupDataInformation->HasInformation(
              levelIdx+1, dataSetIdx))
          {
          continue;
          }
        vtkInformation* info =
          this->MultiGroupDataInformation->GetInformation(
            levelIdx+1,dataSetIdx);
        int* boxVec = info->Get(BOX());
        vtkAMRBox coarsebox(3, boxVec, boxVec+3);
        if (this->BoxInternal->RefinementRatios.size() <= levelIdx)
          {
          continue;
          }
        coarsebox.Coarsen(this->BoxInternal->RefinementRatios[levelIdx]);
        boxes.push_back(coarsebox);
        }
      }

    numDataSets = this->GetNumberOfDataSets(levelIdx);
    for (dataSetIdx=0; dataSetIdx<numDataSets; dataSetIdx++)
      {
      vtkAMRBox box;
      vtkUniformGrid* grid = this->GetDataSet(levelIdx, dataSetIdx, box);

      if (grid)
        {
        int i;
        int cellDims[3];
        for (i=0; i<3; i++)
          {
          cellDims[i] = box.HiCorner[i] - box.LoCorner[i] + 1;
          }
        vtkUnsignedCharArray* vis = vtkUnsignedCharArray::New();
        vtkIdType numCells = box.GetNumberOfCells();
        vis->SetNumberOfTuples(numCells);
        for (i=0; i<numCells; i++)
          {
          vis->SetValue(i, 1);
          }
        vtkIdType numBlankedPts = 0;
        for (int iz=box.LoCorner[2]; iz<=box.HiCorner[2]; iz++)
          {
          for (int iy=box.LoCorner[1]; iy<=box.HiCorner[1]; iy++)
            {
            for (int ix=box.LoCorner[0]; ix<=box.HiCorner[0]; ix++)
              {
              // Blank if cell is covered by a box of higher level
              if (vtkHierarchicalBoxDataSetIsInBoxes(boxes, ix, iy, iz))
                {
                vtkIdType id =
                  (iz-box.LoCorner[2])*cellDims[0]*cellDims[1] +
                  (iy-box.LoCorner[1])*cellDims[0] +
                  (ix-box.LoCorner[0]);
                vis->SetValue(id, 0);
                numBlankedPts++;
                }
              }
            }
          }
        grid->SetCellVisibilityArray(vis);
        vis->Delete();
        if (this->MultiGroupDataInformation->HasInformation(
              levelIdx, dataSetIdx))
          {
          vtkInformation* infotmp =
            this->MultiGroupDataInformation->GetInformation(
              levelIdx,dataSetIdx);
          infotmp->Set(NUMBER_OF_BLANKED_POINTS(), numBlankedPts);
          }
        }
      }
    }
}

//----------------------------------------------------------------------------
vtkIdType vtkHierarchicalBoxDataSet::GetNumberOfPoints()
{
  vtkIdType numPts = 0;

  unsigned int numLevels = this->GetNumberOfLevels();
  for (unsigned int level=0; level<numLevels; level++)
    {
    unsigned int numDataSets = this->GetNumberOfDataSets(level);
    for (unsigned int dataIdx=0; dataIdx<numDataSets; dataIdx++)
      {
      vtkIdType numBlankedPts = 0;
      vtkInformation* blockInfo =
        this->MultiGroupDataInformation->GetInformation(level, dataIdx);
      if (blockInfo)
        {
        if (blockInfo->Has(
              vtkHierarchicalBoxDataSet::NUMBER_OF_BLANKED_POINTS()))
          {
          numBlankedPts = blockInfo->Get(NUMBER_OF_BLANKED_POINTS());
          }
        }
      vtkDataSet* ds = vtkDataSet::SafeDownCast(
        this->GetDataSet(level, dataIdx));
      if (ds)
        {
        numPts += ds->GetNumberOfPoints() - numBlankedPts;
        }
      }
    }

  return numPts;
}

//----------------------------------------------------------------------------
void vtkHierarchicalBoxDataSet::ShallowCopy(vtkDataObject *src)
{
  if (src == this)
    {
    return;
    }
  this->InitializeDataSets();
  this->Modified();

  vtkHierarchicalBoxDataSet* from =
    vtkHierarchicalBoxDataSet::SafeDownCast(src);
  if (from)
    {
    // If the source is a vtkHierarchicalBoxDataSet, do not call
    // superclass' ShallowCopy, instead skip to vtkCompositeDataSet's
    // constructor
    this->vtkCompositeDataSet::ShallowCopy(src);

    unsigned int numLevels = from->GetNumberOfLevels();
    this->SetNumberOfLevels(numLevels);
    for (unsigned int i=0; i<numLevels; i++)
      {
      unsigned int numDataSets = from->GetNumberOfDataSets(i);
      this->SetNumberOfDataSets(i, numDataSets);
      for (unsigned int j=0; j<numDataSets; j++)
        {
        vtkAMRBox box;
        vtkUniformGrid* grid = from->GetDataSet(i, j, box);
        this->SetDataSet(i, j, box, grid);
        }
      }
    }
  else
    {
    this->Superclass::ShallowCopy(src);
    }
}

//----------------------------------------------------------------------------
void vtkHierarchicalBoxDataSet::DeepCopy(vtkDataObject *src)
{
  if (src == this)
    {
    return;
    }
  this->InitializeDataSets();
  this->Modified();

  vtkHierarchicalBoxDataSet* from =
    vtkHierarchicalBoxDataSet::SafeDownCast(src);
  if (from)
    {
    // If the source is a vtkHierarchicalBoxDataSet, do not call
    // superclass' DeepCopy, instead skip to vtkCompositeDataSet's
    // constructor
    this->vtkCompositeDataSet::ShallowCopy(src);

    unsigned int numLevels = from->GetNumberOfLevels();
    this->SetNumberOfLevels(numLevels);
    for (unsigned int i=0; i<numLevels; i++)
      {
      unsigned int numDataSets = from->GetNumberOfDataSets(i);
      this->SetNumberOfDataSets(i, numDataSets);
      for (unsigned int j=0; j<numDataSets; j++)
        {
        vtkAMRBox box;
        vtkUniformGrid* ds = from->GetDataSet(i, j, box);
        if (ds)
          {
          vtkUniformGrid* copy = ds->NewInstance();
          copy->DeepCopy(ds);
          this->SetDataSet(i, j, box, copy);
          }
        }
      }
    }
}

//----------------------------------------------------------------------------
void vtkHierarchicalBoxDataSet::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
  unsigned int numLevels = this->GetNumberOfLevels();
  os << indent << "Number of levels: " <<  numLevels << endl;
  for (unsigned int i=0; i<numLevels; i++)
    {
    unsigned int numDataSets = this->GetNumberOfDataSets(i);
    os << indent << "Level " << i << " number of datasets: " << numDataSets
       << endl;
    for (unsigned j=0; j<numDataSets; j++)
      {
      os << indent << "DataSet(" << i << "," << j << "):";
      vtkDataObject* dobj = this->GetDataSet(i, j);
      if (dobj)
        {
        os << endl;
        dobj->PrintSelf(os, indent.GetNextIndent());
        }
      else
        {
        os << "(none)" << endl;
        }
      }
    }
}

//----------------------------------------------------------------------------
vtkHierarchicalBoxDataSet* vtkHierarchicalBoxDataSet::GetData(
  vtkInformation* info)
{
  return
    info?vtkHierarchicalBoxDataSet::SafeDownCast(info->Get(DATA_OBJECT())) : 0;
}

//----------------------------------------------------------------------------
vtkHierarchicalBoxDataSet* vtkHierarchicalBoxDataSet::GetData(
  vtkInformationVector* v, int i)
{
  return vtkHierarchicalBoxDataSet::GetData(v->GetInformationObject(i));
}

//----------------------------------------------------------------------------
// Description:
// Copy the cached scalar range into range.
void vtkHierarchicalBoxDataSet::GetScalarRange(double range[2])
{
  this->ComputeScalarRange();
  range[0]=this->ScalarRange[0];
  range[1]=this->ScalarRange[1];
}

//----------------------------------------------------------------------------
// Description:
// Return the cached range.
double *vtkHierarchicalBoxDataSet::GetScalarRange()
{
  this->ComputeScalarRange();
  return this->ScalarRange;
}

//----------------------------------------------------------------------------
// Description:
// Compute the range of the scalars and cache it into ScalarRange
// only if the cache became invalid (ScalarRangeComputeTime).
void vtkHierarchicalBoxDataSet::ComputeScalarRange()
{
  if ( this->GetMTime() > this->ScalarRangeComputeTime )
    {
    double dataSetRange[2];
    this->ScalarRange[0]=VTK_DOUBLE_MAX;
    this->ScalarRange[1]=VTK_DOUBLE_MIN;
    unsigned int level=0;
    unsigned int levels=this->GetNumberOfLevels();
    while(level<levels)
      {
      unsigned int dataset=0;
      unsigned int datasets=this->GetNumberOfDataSets(level);
      while(dataset<datasets)
        {
        vtkUniformGrid *ug;
        ug=static_cast<vtkUniformGrid *>(this->GetDataSet(level,dataset));
        ug->GetScalarRange(dataSetRange);
        if(dataSetRange[0]<this->ScalarRange[0])
          {
          this->ScalarRange[0]=dataSetRange[0];
          }
        if(dataSetRange[1]>this->ScalarRange[1])
          {
          this->ScalarRange[1]=dataSetRange[1];
          }
        ++dataset;
        }
      ++level;
      }
    this->ScalarRangeComputeTime.Modified();
    }
}
<|endoftext|>


<commit_before>#include "map.h"
#include <iostream>
#include "iterator.h"

using namespace v8;

void NodeMap::init(Local<Object> target) {
    Nan::HandleScope scope;

    Local<FunctionTemplate> constructor = Nan::New<FunctionTemplate>(Constructor);

    // got to do the Symbol.iterator function by hand, no Nan support
    Local<Symbol> symbol_iterator = Symbol::GetIterator(Isolate::GetCurrent());
    Local<FunctionTemplate> entries_templt = Nan::New<FunctionTemplate>(
        Entries
        , Local<Value>()
        , Nan::New<Signature>(constructor));
    constructor->PrototypeTemplate()->Set(symbol_iterator, entries_templt);
    entries_templt->SetClassName(Nan::New("Symbol(Symbol.iterator)").ToLocalChecked());

    constructor->SetClassName(Nan::New("NodeMap").ToLocalChecked());
    constructor->InstanceTemplate()->SetInternalFieldCount(1);

    Nan::SetPrototypeMethod(constructor, "set", Set);
    Nan::SetPrototypeMethod(constructor, "get", Get);
    Nan::SetPrototypeMethod(constructor, "has", Has);
    Nan::SetPrototypeMethod(constructor, "entries", Entries);
    Nan::SetPrototypeMethod(constructor, "keys", Keys);
    Nan::SetPrototypeMethod(constructor, "values", Values);
    Nan::SetPrototypeMethod(constructor, "delete", Delete);
    Nan::SetPrototypeMethod(constructor, "clear", Clear);
    Nan::SetPrototypeMethod(constructor, "forEach", ForEach);
    Nan::SetAccessor(constructor->InstanceTemplate(), Nan::New("size").ToLocalChecked(), Size);

    target->Set(Nan::New("NodeMap").ToLocalChecked(), constructor->GetFunction());

    PairNodeIterator::init(target);
}

NodeMap::NodeMap() {
    this->_version = 0;
    this->_iterator_count = 0;
}

NodeMap::~NodeMap() {
    for(MapType::const_iterator itr = this->_set.begin(); itr != this->_set.end(); ) {
        itr = this->_set.erase(itr);
    }
}

uint32_t NodeMap::StartIterator() {
    uint32_t version = this->_version;
    this->_version++;
    if (this->_iterator_count == 0) {
        // if this is the first iterator, set the max load facto to infinity
        // so that a rehash doesn't happen while iterating
        this->_old_load_factor = this->_set.max_load_factor();
        this->_set.max_load_factor(std::numeric_limits<float>::infinity());
    }
    this->_iterator_count++;

    // return the latest version that should be valid for this iterator
    return version;
}

void NodeMap::StopIterator() {
    this->_iterator_count--;
    if (this->_iterator_count != 0) {
        return;
    }
    // that was the last iterator running, so now go through the whole set
    // and actually delete anything marked for deletion
    for(MapType::const_iterator itr = this->_set.begin(); itr != this->_set.end(); ) {
        if (itr->IsDeleted()) {
            itr = this->_set.erase(itr);
        } else {
            itr++;
        }
    }
    // since it was the last iterator, reset the max load factor back
    // to what it was before the first iterator, this might cause a
    // rehash to happen
    this->_set.max_load_factor(this->_old_load_factor);
}

MapType::const_iterator NodeMap::GetBegin() {
    return this->_set.begin();
}

MapType::const_iterator NodeMap::GetEnd() {
    return this->_set.end();
}

NAN_METHOD(NodeMap::Constructor) {
    Nan::HandleScope scope;
    NodeMap *obj = new NodeMap();

    Local<String> set = Nan::New("set").ToLocalChecked();
    Local<String> next = Nan::New("next").ToLocalChecked();
    Local<String> done = Nan::New("done").ToLocalChecked();
    Local<String> value = Nan::New("value").ToLocalChecked();
    Local<Symbol> symbol_iterator = Symbol::GetIterator(Isolate::GetCurrent());
    Local<Object> info0;
    Local<Object> iter;
    Local<Object> iter_obj;
    Local<Array> value_arr;
    Local<Value> func_args[2];
    Local<Function> setter;
    Local<Function> next_func;

    obj->Wrap(info.This());
    info.GetReturnValue().Set(info.This());

    if(info.Length() == 0) {
        return;
    }

    if (!info.This()->Has(set) || !Nan::Get(info.This(), set).ToLocalChecked()->IsFunction()) {
        Nan::ThrowTypeError("Invalid set method");
        return;

    }
    setter = Nan::Get(info.This(), set).ToLocalChecked().As<Function>();
    if (!info[0]->IsObject()) {
        Nan::ThrowTypeError("Invalid argument");
        return;
    }
    info0 = Nan::To<Object>(info[0]).ToLocalChecked();
    if (!info0->Has(symbol_iterator)) {
        Nan::ThrowTypeError("Argument not iterable");
        return;
    }

    iter = Nan::To<Object>(Nan::Call(Nan::Get(info0, symbol_iterator).ToLocalChecked().As<Function>(), info0, 0, 0).ToLocalChecked()).ToLocalChecked();
    next_func = Nan::Get(iter, next).ToLocalChecked().As<Function>();
    iter_obj = Nan::Call(next_func, iter, 0, 0).ToLocalChecked()->ToObject();
    while(!Nan::Get(iter_obj, done).ToLocalChecked()->BooleanValue()) {
        if (Nan::Get(iter_obj, value).ToLocalChecked()->IsArray()) {
            value_arr = Nan::Get(iter_obj, value).ToLocalChecked().As<Array>();
            if (value_arr->Length() >= 2) {
                func_args[0] = Nan::Get(value_arr, 0).ToLocalChecked();
                func_args[1] = Nan::Get(value_arr, 1).ToLocalChecked();
                Nan::Call(setter, info.This(), 2, func_args);
            }
        }
        iter_obj = Nan::Call(next_func, iter, 0, 0).ToLocalChecked()->ToObject();
    }
    return;
}

NAN_METHOD(NodeMap::Get) {
    Nan::HandleScope scope;

    if (info.Length() < 1 || info[0]->IsUndefined() || info[0]->IsNull()) {
        Nan::ThrowTypeError("Wrong arguments");
        return;
    }

    NodeMap *obj = Nan::ObjectWrap::Unwrap<NodeMap>(info.This());
    VersionedPersistentPair persistent(obj->_version, info[0]);

    MapType::const_iterator itr = obj->_set.find(persistent);
    MapType::const_iterator end = obj->_set.end();

    while(itr != end && itr->IsDeleted()) {
        itr++;
    }

    if(itr == end || !info[0]->StrictEquals(itr->GetLocalKey())) {
        //do nothing and return undefined
        info.GetReturnValue().Set(Nan::Undefined());
        return;
    }

    info.GetReturnValue().Set(itr->GetLocalValue());
    return;
}

NAN_METHOD(NodeMap::Has) {
    Nan::HandleScope scope;

    if (info.Length() < 1 || info[0]->IsUndefined() || info[0]->IsNull()) {
        Nan::ThrowTypeError("Wrong arguments");
        return;
    }

    NodeMap *obj = Nan::ObjectWrap::Unwrap<NodeMap>(info.This());
    VersionedPersistentPair persistent(obj->_version, info[0]);

    MapType::const_iterator itr = obj->_set.find(persistent);
    MapType::const_iterator end = obj->_set.end();

    while(itr != end && itr->IsDeleted()) {
        itr++;
    }

    if(itr == end || !info[0]->StrictEquals(itr->GetLocalKey())) {
        //do nothing and return false
        info.GetReturnValue().Set(Nan::False());
        return;
    }

    info.GetReturnValue().Set(Nan::True());
    return;
}

NAN_METHOD(NodeMap::Set) {
    Nan::HandleScope scope;

    if (info.Length() < 2 || info[0]->IsUndefined() || info[0]->IsNull()) {
        Nan::ThrowTypeError("Wrong arguments");
        return;
    }

    NodeMap *obj = Nan::ObjectWrap::Unwrap<NodeMap>(info.This());
    VersionedPersistentPair persistent(obj->_version, info[0], info[1]);

    MapType::const_iterator itr = obj->_set.find(persistent);
    MapType::const_iterator end = obj->_set.end();

    while(itr != end && itr->IsDeleted()) {
        itr++;
    }

    if(itr != end && info[0]->StrictEquals(itr->GetLocalKey())) {
        itr->ReplaceValue(obj->_version, info[1]);
    } else {
        obj->_set.insert(persistent);
    }

    //Return this
    info.GetReturnValue().Set(info.This());
    return;
}

NAN_METHOD(NodeMap::Entries) {
    Nan::HandleScope scope;

    NodeMap *obj = Nan::ObjectWrap::Unwrap<NodeMap>(info.This());

    Local<Object> iter = PairNodeIterator::New(PairNodeIterator::KEY_TYPE | PairNodeIterator::VALUE_TYPE, obj);

    info.GetReturnValue().Set(iter);
    return;
}

NAN_METHOD(NodeMap::Keys) {
    Nan::HandleScope scope;

    NodeMap *obj = Nan::ObjectWrap::Unwrap<NodeMap>(info.This());

    Local<Object> iter = PairNodeIterator::New(PairNodeIterator::KEY_TYPE, obj);

    info.GetReturnValue().Set(iter);
    return;
}

NAN_METHOD(NodeMap::Values) {
    Nan::HandleScope scope;

    NodeMap *obj = Nan::ObjectWrap::Unwrap<NodeMap>(info.This());

    Local<Object> iter = PairNodeIterator::New(PairNodeIterator::VALUE_TYPE, obj);

    info.GetReturnValue().Set(iter);
    return;
}

NAN_METHOD(NodeMap::Delete) {
    Nan::HandleScope scope;

    if (info.Length() < 1 || info[0]->IsUndefined() || info[0]->IsNull()) {
        Nan::ThrowTypeError("Wrong arguments");
        return;
    }

    NodeMap *obj = Nan::ObjectWrap::Unwrap<NodeMap>(info.This());
    VersionedPersistentPair persistent(obj->_version, info[0]);
    bool using_iterator = (obj->_iterator_count != 0);
    bool ret;

    if (using_iterator) {
        obj->StartIterator();
    }

    MapType::const_iterator itr = obj->_set.find(persistent);
    MapType::const_iterator end = obj->_set.end();

    while(itr != end && itr->IsDeleted()) {
        itr++;
    }

    ret = (itr != end && info[0]->StrictEquals(itr->GetLocalKey()));

    if (using_iterator) {
        if (ret) {
            itr->Delete();
        }
        obj->StopIterator();
    } else {
        if (ret) {
            obj->_set.erase(itr);
        }
    }

    if (ret) {
        info.GetReturnValue().Set(Nan::True());
    } else {
        info.GetReturnValue().Set(Nan::False());
    }
    return;
}

NAN_METHOD(NodeMap::Clear) {
    Nan::HandleScope scope;

    NodeMap *obj = Nan::ObjectWrap::Unwrap<NodeMap>(info.This());
    bool using_iterator = (obj->_iterator_count != 0);

    if (using_iterator) {
        obj->StartIterator();
    }

    for(MapType::const_iterator itr = obj->_set.begin(); itr != obj->_set.end(); ) {
        if (using_iterator) {
            itr->Delete();
            itr++;
        } else {
            itr = obj->_set.erase(itr);
        }
    }

    if (using_iterator) {
        obj->StopIterator();
    }

    info.GetReturnValue().Set(Nan::Undefined());
    return;
}

NAN_GETTER(NodeMap::Size) {
    NodeMap *obj = Nan::ObjectWrap::Unwrap<NodeMap>(info.This());
    uint32_t size = 0;
    if (obj->_iterator_count == 0) {
        size = obj->_set.size();
        info.GetReturnValue().Set(Nan::New<Integer>(size));
        return;
    }

    MapType::const_iterator itr = obj->_set.begin();
    MapType::const_iterator end = obj->_set.end();
    for (; itr != end; itr++) {
        if (itr->IsValid(obj->_version)) {
            size += 1;
        }
    }

    info.GetReturnValue().Set(Nan::New<Integer>(size));
    return;
}

NAN_METHOD(NodeMap::ForEach) {
    Nan::HandleScope scope;

    NodeMap *obj = Nan::ObjectWrap::Unwrap<NodeMap>(info.This());

    if (info.Length() < 1 || !info[0]->IsFunction()) {
        Nan::ThrowTypeError("Wrong arguments");
        return;
    }
    Local<Function> cb = info[0].As<v8::Function>();

    Local<Object> ctx;
    if (info.Length() > 1 && info[1]->IsObject()) {
        ctx = info[1]->ToObject();
    } else {
        ctx = Nan::GetCurrentContext()->Global();
    }

    const unsigned argc = 3;
    Local<Value> argv[argc];
    argv[2] = info.This();

    uint32_t version = obj->StartIterator();
    MapType::const_iterator itr = obj->_set.begin();
    MapType::const_iterator end = obj->_set.end();

    while (itr != end) {
        if (itr->IsValid(version)) {
            argv[0] = itr->GetLocalValue();
            argv[1] = itr->GetLocalKey();
            cb->Call(ctx, argc, argv);
        }
        itr++;
    }
    obj->StopIterator();

    info.GetReturnValue().Set(Nan::Undefined());
    return;
}

extern "C" void
init (Local<Object> target) {
    Nan::HandleScope scope;

    NodeMap::init(target);
}

NODE_MODULE(map, init);
<commit_msg>Validate that constructor argument is an array of key-value entries<commit_after>#include "map.h"
#include <iostream>
#include "iterator.h"

using namespace v8;

void NodeMap::init(Local<Object> target) {
    Nan::HandleScope scope;

    Local<FunctionTemplate> constructor = Nan::New<FunctionTemplate>(Constructor);

    // got to do the Symbol.iterator function by hand, no Nan support
    Local<Symbol> symbol_iterator = Symbol::GetIterator(Isolate::GetCurrent());
    Local<FunctionTemplate> entries_templt = Nan::New<FunctionTemplate>(
        Entries
        , Local<Value>()
        , Nan::New<Signature>(constructor));
    constructor->PrototypeTemplate()->Set(symbol_iterator, entries_templt);
    entries_templt->SetClassName(Nan::New("Symbol(Symbol.iterator)").ToLocalChecked());

    constructor->SetClassName(Nan::New("NodeMap").ToLocalChecked());
    constructor->InstanceTemplate()->SetInternalFieldCount(1);

    Nan::SetPrototypeMethod(constructor, "set", Set);
    Nan::SetPrototypeMethod(constructor, "get", Get);
    Nan::SetPrototypeMethod(constructor, "has", Has);
    Nan::SetPrototypeMethod(constructor, "entries", Entries);
    Nan::SetPrototypeMethod(constructor, "keys", Keys);
    Nan::SetPrototypeMethod(constructor, "values", Values);
    Nan::SetPrototypeMethod(constructor, "delete", Delete);
    Nan::SetPrototypeMethod(constructor, "clear", Clear);
    Nan::SetPrototypeMethod(constructor, "forEach", ForEach);
    Nan::SetAccessor(constructor->InstanceTemplate(), Nan::New("size").ToLocalChecked(), Size);

    target->Set(Nan::New("NodeMap").ToLocalChecked(), constructor->GetFunction());

    PairNodeIterator::init(target);
}

NodeMap::NodeMap() {
    this->_version = 0;
    this->_iterator_count = 0;
}

NodeMap::~NodeMap() {
    for(MapType::const_iterator itr = this->_set.begin(); itr != this->_set.end(); ) {
        itr = this->_set.erase(itr);
    }
}

uint32_t NodeMap::StartIterator() {
    uint32_t version = this->_version;
    this->_version++;
    if (this->_iterator_count == 0) {
        // if this is the first iterator, set the max load facto to infinity
        // so that a rehash doesn't happen while iterating
        this->_old_load_factor = this->_set.max_load_factor();
        this->_set.max_load_factor(std::numeric_limits<float>::infinity());
    }
    this->_iterator_count++;

    // return the latest version that should be valid for this iterator
    return version;
}

void NodeMap::StopIterator() {
    this->_iterator_count--;
    if (this->_iterator_count != 0) {
        return;
    }
    // that was the last iterator running, so now go through the whole set
    // and actually delete anything marked for deletion
    for(MapType::const_iterator itr = this->_set.begin(); itr != this->_set.end(); ) {
        if (itr->IsDeleted()) {
            itr = this->_set.erase(itr);
        } else {
            itr++;
        }
    }
    // since it was the last iterator, reset the max load factor back
    // to what it was before the first iterator, this might cause a
    // rehash to happen
    this->_set.max_load_factor(this->_old_load_factor);
}

MapType::const_iterator NodeMap::GetBegin() {
    return this->_set.begin();
}

MapType::const_iterator NodeMap::GetEnd() {
    return this->_set.end();
}

NAN_METHOD(NodeMap::Constructor) {
    Nan::HandleScope scope;
    NodeMap *obj = new NodeMap();

    Local<String> set = Nan::New("set").ToLocalChecked();
    Local<String> next = Nan::New("next").ToLocalChecked();
    Local<String> done = Nan::New("done").ToLocalChecked();
    Local<String> value = Nan::New("value").ToLocalChecked();
    Local<Symbol> symbol_iterator = Symbol::GetIterator(Isolate::GetCurrent());
    Local<Object> info0;
    Local<Object> iter;
    Local<Object> iter_obj;
    Local<Array> value_arr;
    Local<Value> func_args[2];
    Local<Function> setter;
    Local<Function> next_func;

    obj->Wrap(info.This());
    info.GetReturnValue().Set(info.This());

    if(info.Length() == 0) {
        return;
    }

    if (!info.This()->Has(set) || !Nan::Get(info.This(), set).ToLocalChecked()->IsFunction()) {
        Nan::ThrowTypeError("Invalid set method");
        return;

    }
    setter = Nan::Get(info.This(), set).ToLocalChecked().As<Function>();
    if (!info[0]->IsObject()) {
        Nan::ThrowTypeError("Invalid argument");
        return;
    }
    info0 = Nan::To<Object>(info[0]).ToLocalChecked();
    if (!info0->Has(symbol_iterator)) {
        Nan::ThrowTypeError("Argument not iterable");
        return;
    }

    iter = Nan::To<Object>(Nan::Call(Nan::Get(info0, symbol_iterator).ToLocalChecked().As<Function>(), info0, 0, 0).ToLocalChecked()).ToLocalChecked();
    next_func = Nan::Get(iter, next).ToLocalChecked().As<Function>();
    iter_obj = Nan::Call(next_func, iter, 0, 0).ToLocalChecked()->ToObject();
    while(!Nan::Get(iter_obj, done).ToLocalChecked()->BooleanValue()) {
        if (Nan::Get(iter_obj, value).ToLocalChecked()->IsArray()) {
            value_arr = Nan::Get(iter_obj, value).ToLocalChecked().As<Array>();
            if (value_arr->Length() >= 2) {
                func_args[0] = Nan::Get(value_arr, 0).ToLocalChecked();
                func_args[1] = Nan::Get(value_arr, 1).ToLocalChecked();
                Nan::Call(setter, info.This(), 2, func_args);
            } else {
              Nan::ThrowTypeError("Iterator contains non-entry object");
              return;
            }
        } else {
          Nan::ThrowTypeError("Iterator contains non-entry object");
          return;
        }
        iter_obj = Nan::Call(next_func, iter, 0, 0).ToLocalChecked()->ToObject();
    }
    return;
}

NAN_METHOD(NodeMap::Get) {
    Nan::HandleScope scope;

    if (info.Length() < 1 || info[0]->IsUndefined() || info[0]->IsNull()) {
        Nan::ThrowTypeError("Wrong arguments");
        return;
    }

    NodeMap *obj = Nan::ObjectWrap::Unwrap<NodeMap>(info.This());
    VersionedPersistentPair persistent(obj->_version, info[0]);

    MapType::const_iterator itr = obj->_set.find(persistent);
    MapType::const_iterator end = obj->_set.end();

    while(itr != end && itr->IsDeleted()) {
        itr++;
    }

    if(itr == end || !info[0]->StrictEquals(itr->GetLocalKey())) {
        //do nothing and return undefined
        info.GetReturnValue().Set(Nan::Undefined());
        return;
    }

    info.GetReturnValue().Set(itr->GetLocalValue());
    return;
}

NAN_METHOD(NodeMap::Has) {
    Nan::HandleScope scope;

    if (info.Length() < 1 || info[0]->IsUndefined() || info[0]->IsNull()) {
        Nan::ThrowTypeError("Wrong arguments");
        return;
    }

    NodeMap *obj = Nan::ObjectWrap::Unwrap<NodeMap>(info.This());
    VersionedPersistentPair persistent(obj->_version, info[0]);

    MapType::const_iterator itr = obj->_set.find(persistent);
    MapType::const_iterator end = obj->_set.end();

    while(itr != end && itr->IsDeleted()) {
        itr++;
    }

    if(itr == end || !info[0]->StrictEquals(itr->GetLocalKey())) {
        //do nothing and return false
        info.GetReturnValue().Set(Nan::False());
        return;
    }

    info.GetReturnValue().Set(Nan::True());
    return;
}

NAN_METHOD(NodeMap::Set) {
    Nan::HandleScope scope;

    if (info.Length() < 2 || info[0]->IsUndefined() || info[0]->IsNull()) {
        Nan::ThrowTypeError("Wrong arguments");
        return;
    }

    NodeMap *obj = Nan::ObjectWrap::Unwrap<NodeMap>(info.This());
    VersionedPersistentPair persistent(obj->_version, info[0], info[1]);

    MapType::const_iterator itr = obj->_set.find(persistent);
    MapType::const_iterator end = obj->_set.end();

    while(itr != end && itr->IsDeleted()) {
        itr++;
    }

    if(itr != end && info[0]->StrictEquals(itr->GetLocalKey())) {
        itr->ReplaceValue(obj->_version, info[1]);
    } else {
        obj->_set.insert(persistent);
    }

    //Return this
    info.GetReturnValue().Set(info.This());
    return;
}

NAN_METHOD(NodeMap::Entries) {
    Nan::HandleScope scope;

    NodeMap *obj = Nan::ObjectWrap::Unwrap<NodeMap>(info.This());

    Local<Object> iter = PairNodeIterator::New(PairNodeIterator::KEY_TYPE | PairNodeIterator::VALUE_TYPE, obj);

    info.GetReturnValue().Set(iter);
    return;
}

NAN_METHOD(NodeMap::Keys) {
    Nan::HandleScope scope;

    NodeMap *obj = Nan::ObjectWrap::Unwrap<NodeMap>(info.This());

    Local<Object> iter = PairNodeIterator::New(PairNodeIterator::KEY_TYPE, obj);

    info.GetReturnValue().Set(iter);
    return;
}

NAN_METHOD(NodeMap::Values) {
    Nan::HandleScope scope;

    NodeMap *obj = Nan::ObjectWrap::Unwrap<NodeMap>(info.This());

    Local<Object> iter = PairNodeIterator::New(PairNodeIterator::VALUE_TYPE, obj);

    info.GetReturnValue().Set(iter);
    return;
}

NAN_METHOD(NodeMap::Delete) {
    Nan::HandleScope scope;

    if (info.Length() < 1 || info[0]->IsUndefined() || info[0]->IsNull()) {
        Nan::ThrowTypeError("Wrong arguments");
        return;
    }

    NodeMap *obj = Nan::ObjectWrap::Unwrap<NodeMap>(info.This());
    VersionedPersistentPair persistent(obj->_version, info[0]);
    bool using_iterator = (obj->_iterator_count != 0);
    bool ret;

    if (using_iterator) {
        obj->StartIterator();
    }

    MapType::const_iterator itr = obj->_set.find(persistent);
    MapType::const_iterator end = obj->_set.end();

    while(itr != end && itr->IsDeleted()) {
        itr++;
    }

    ret = (itr != end && info[0]->StrictEquals(itr->GetLocalKey()));

    if (using_iterator) {
        if (ret) {
            itr->Delete();
        }
        obj->StopIterator();
    } else {
        if (ret) {
            obj->_set.erase(itr);
        }
    }

    if (ret) {
        info.GetReturnValue().Set(Nan::True());
    } else {
        info.GetReturnValue().Set(Nan::False());
    }
    return;
}

NAN_METHOD(NodeMap::Clear) {
    Nan::HandleScope scope;

    NodeMap *obj = Nan::ObjectWrap::Unwrap<NodeMap>(info.This());
    bool using_iterator = (obj->_iterator_count != 0);

    if (using_iterator) {
        obj->StartIterator();
    }

    for(MapType::const_iterator itr = obj->_set.begin(); itr != obj->_set.end(); ) {
        if (using_iterator) {
            itr->Delete();
            itr++;
        } else {
            itr = obj->_set.erase(itr);
        }
    }

    if (using_iterator) {
        obj->StopIterator();
    }

    info.GetReturnValue().Set(Nan::Undefined());
    return;
}

NAN_GETTER(NodeMap::Size) {
    NodeMap *obj = Nan::ObjectWrap::Unwrap<NodeMap>(info.This());
    uint32_t size = 0;
    if (obj->_iterator_count == 0) {
        size = obj->_set.size();
        info.GetReturnValue().Set(Nan::New<Integer>(size));
        return;
    }

    MapType::const_iterator itr = obj->_set.begin();
    MapType::const_iterator end = obj->_set.end();
    for (; itr != end; itr++) {
        if (itr->IsValid(obj->_version)) {
            size += 1;
        }
    }

    info.GetReturnValue().Set(Nan::New<Integer>(size));
    return;
}

NAN_METHOD(NodeMap::ForEach) {
    Nan::HandleScope scope;

    NodeMap *obj = Nan::ObjectWrap::Unwrap<NodeMap>(info.This());

    if (info.Length() < 1 || !info[0]->IsFunction()) {
        Nan::ThrowTypeError("Wrong arguments");
        return;
    }
    Local<Function> cb = info[0].As<v8::Function>();

    Local<Object> ctx;
    if (info.Length() > 1 && info[1]->IsObject()) {
        ctx = info[1]->ToObject();
    } else {
        ctx = Nan::GetCurrentContext()->Global();
    }

    const unsigned argc = 3;
    Local<Value> argv[argc];
    argv[2] = info.This();

    uint32_t version = obj->StartIterator();
    MapType::const_iterator itr = obj->_set.begin();
    MapType::const_iterator end = obj->_set.end();

    while (itr != end) {
        if (itr->IsValid(version)) {
            argv[0] = itr->GetLocalValue();
            argv[1] = itr->GetLocalKey();
            cb->Call(ctx, argc, argv);
        }
        itr++;
    }
    obj->StopIterator();

    info.GetReturnValue().Set(Nan::Undefined());
    return;
}

extern "C" void
init (Local<Object> target) {
    Nan::HandleScope scope;

    NodeMap::init(target);
}

NODE_MODULE(map, init);
<|endoftext|>


<commit_before>#include <Urho3D/Core/Object.h>
#include "ClassWrappers.hpp"

namespace Urho3D
{

class ManagedObjectFactory : public ObjectFactory
{
public:
    ManagedObjectFactory(Context* context, const char* typeName, StringHash baseType)
        : ObjectFactory(context)
        , baseType_(baseType)
        , managedType_(typeName)
    {
        typeInfo_ = new TypeInfo(typeName, context_->GetScripts()->GetRegisteredType(baseType));
    }

    ~ManagedObjectFactory() override
    {
        delete typeInfo_;
    }

public:
    SharedPtr<Object> CreateObject() override
    {
        return SharedPtr<Object>(context_->GetScripts()->CreateObject(context_, managedType_.Value()));
    }

protected:
    StringHash baseType_;
    StringHash managedType_;
};

class ManagedEventHandler : public EventHandler
{
public:
    ManagedEventHandler(Object* receiver, void* gcHandle, void(*function)(void*, StringHash, VariantMap*))
        : EventHandler(receiver, nullptr)
        , function_(function)
        , gcHandle_(gcHandle)
    {
    }

    ~ManagedEventHandler() override
    {
        receiver_->GetScripts()->FreeGCHandle(gcHandle_);
        gcHandle_ = nullptr;
    }

    void Invoke(VariantMap& eventData) override
    {
        function_(gcHandle_, eventType_, &eventData);
    }

    EventHandler* Clone() const override
    {
        return new ManagedEventHandler(receiver_, receiver_->GetScripts()->CloneGCHandle(gcHandle_), function_);
    }

public:

protected:
    void* gcHandle_ = nullptr;
    void(*function_)(void*, StringHash, VariantMap*) = nullptr;
};

}

extern "C"
{

void Urho3D_Context_RegisterFactory(Context* context, MonoString* typeName, unsigned baseType,
    const char* category)
{
    context->RegisterFactory(new Urho3D::ManagedObjectFactory(context, CSharpConverter<MonoString>::FromCSharp<MonoStringHolder>(typeName), StringHash(baseType)), category);
}

void Urho3D_Object_SubscribeToEvent(Object* receiver, void* gcHandle, unsigned eventType,
    void(*function)(void*, StringHash, VariantMap*), Object* sender)
{
    // gcHandle is a handle to Action<> which references receiver object. We have to ensure object is alive as long as
    // engine will be sending events to it. On the other hand pinning receiver object is not required as it's lifetime
    // is managed by user or engine. If such object is deallocated it will simply stop sending events.
    if (sender == nullptr)
        receiver->SubscribeToEvent(StringHash(eventType), new ManagedEventHandler(receiver, gcHandle, function));
    else
        receiver->SubscribeToEvent(sender, StringHash(eventType), new ManagedEventHandler(receiver, gcHandle, function));
}

void RegisterObjectInternalCalls(Context* context)
{
    MONO_INTERNAL_CALL(Urho3D.Context, Urho3D_Context_RegisterFactory);
    MONO_INTERNAL_CALL(Urho3D.Object, Urho3D_Object_SubscribeToEvent);
}

}
<commit_msg>CSharp: Fix category string conversion in factory registration.<commit_after>#include <Urho3D/Core/Object.h>
#include "ClassWrappers.hpp"

namespace Urho3D
{

class ManagedObjectFactory : public ObjectFactory
{
public:
    ManagedObjectFactory(Context* context, const char* typeName, StringHash baseType)
        : ObjectFactory(context)
        , baseType_(baseType)
        , managedType_(typeName)
    {
        typeInfo_ = new TypeInfo(typeName, context_->GetScripts()->GetRegisteredType(baseType));
    }

    ~ManagedObjectFactory() override
    {
        delete typeInfo_;
    }

public:
    SharedPtr<Object> CreateObject() override
    {
        return SharedPtr<Object>(context_->GetScripts()->CreateObject(context_, managedType_.Value()));
    }

protected:
    StringHash baseType_;
    StringHash managedType_;
};

class ManagedEventHandler : public EventHandler
{
public:
    ManagedEventHandler(Object* receiver, void* gcHandle, void(*function)(void*, StringHash, VariantMap*))
        : EventHandler(receiver, nullptr)
        , function_(function)
        , gcHandle_(gcHandle)
    {
    }

    ~ManagedEventHandler() override
    {
        receiver_->GetScripts()->FreeGCHandle(gcHandle_);
        gcHandle_ = nullptr;
    }

    void Invoke(VariantMap& eventData) override
    {
        function_(gcHandle_, eventType_, &eventData);
    }

    EventHandler* Clone() const override
    {
        return new ManagedEventHandler(receiver_, receiver_->GetScripts()->CloneGCHandle(gcHandle_), function_);
    }

public:

protected:
    void* gcHandle_ = nullptr;
    void(*function_)(void*, StringHash, VariantMap*) = nullptr;
};

}

extern "C"
{

void Urho3D_Context_RegisterFactory(Context* context, MonoString* typeName, unsigned baseType,
                                    MonoString* category)
{
    context->RegisterFactory(new Urho3D::ManagedObjectFactory(context,
        CSharpConverter<MonoString>::FromCSharp<MonoStringHolder>(typeName), StringHash(baseType)),
        CSharpConverter<MonoString>::FromCSharp<MonoStringHolder>(category));
}

void Urho3D_Object_SubscribeToEvent(Object* receiver, void* gcHandle, unsigned eventType,
    void(*function)(void*, StringHash, VariantMap*), Object* sender)
{
    // gcHandle is a handle to Action<> which references receiver object. We have to ensure object is alive as long as
    // engine will be sending events to it. On the other hand pinning receiver object is not required as it's lifetime
    // is managed by user or engine. If such object is deallocated it will simply stop sending events.
    if (sender == nullptr)
        receiver->SubscribeToEvent(StringHash(eventType), new ManagedEventHandler(receiver, gcHandle, function));
    else
        receiver->SubscribeToEvent(sender, StringHash(eventType), new ManagedEventHandler(receiver, gcHandle, function));
}

void RegisterObjectInternalCalls(Context* context)
{
    MONO_INTERNAL_CALL(Urho3D.Context, Urho3D_Context_RegisterFactory);
    MONO_INTERNAL_CALL(Urho3D.Object, Urho3D_Object_SubscribeToEvent);
}

}
<|endoftext|>


<commit_before><commit_msg>Remove Dead Code<commit_after><|endoftext|>


<commit_before><commit_msg>-Werror,-Wunused-member-function<commit_after><|endoftext|>