<commit_before>Parcer::Parcer(std::string filename){
  Tokens = LexicalAnaltysis(filename);
};

/*  構文解析実行
    @return 成功：true 失敗：false
*/
bool Parser::doParse(){
    if(!Tokens){
      fprintf(stderr, "error at lexer\n");
      return false;
    }
    else{
      return VisitTranslationUnit();
    }
};

TranslationUnitAST &Parser::getAST(){
  if(TU){
    return *TU;
  }
  else{
    return *(new TranslationUnitAST());
  }
};

// TranslationUnit用構文解析メソッド
bool Parser::visitTranslationUnit(){
  TU = new TranslatonUnitAST();

  // ExternalDecl
  while(true){
    if(!visitExternalDeclaration(TU)){
      SAFE_DELETE(TU);
      return false;
    }
    if(Tokens->getCurType == TOK_EOF){
      break;
    }
  }
  return true;
}

// ExternalDeclaration用構文解析メソッド
bool Parser::visitExternalDeclaration(TranslationUnitAST *tunit){
  PrototypeAST *proto = visitFunctionDeclaration();
  if(proto){
    tunit->addPrototype(proto);
    return true;
  }

  FunctionAST *func_def = visitFunctionDefinition();
  if(func_def){
    tunit->addFunction(func_def);
    return true;
  }

  return false;
}

PrototypeAST *Parser::zisitFunctionDeclaration(){
  int backup = Tokens->getCurIndex();
  PrototypeAST *proto = visitPrototype();
  if(!proto){
    return NULL;
  }

  if(Tokens->getCurString() == ';'){
    // 本来であればここで再定義されていないか確認
    Tokens->getNextToken();
    return proto;
  }
  else{
    SAFE_DELETE(proto);
    Tokens->applyTokenIndex(backup);
    return NULL;
  }
}

FunctionAST *Parser::visitFunctionDefinition(){
  int backup = Tokens->getCurIndex();

  PrototypeAST *proto = visitPrototype();
  if(!proto){
    return NULL;
  }

  // 本来であればここで再定義されていないか確認
  FunctionStmtAST *func_stmt = visitFunctionStatement(proto);
}
<commit_msg>変数宣言のチェック<commit_after>Parcer::Parcer(std::string filename){
  Tokens = LexicalAnaltysis(filename);
};

/*  構文解析実行
    @return 成功：true 失敗：false
*/
bool Parser::doParse(){
    if(!Tokens){
      fprintf(stderr, "error at lexer\n");
      return false;
    }
    else{
      return VisitTranslationUnit();
    }
};

TranslationUnitAST &Parser::getAST(){
  if(TU){
    return *TU;
  }
  else{
    return *(new TranslationUnitAST());
  }
};

// TranslationUnit用構文解析メソッド
bool Parser::visitTranslationUnit(){
  TU = new TranslatonUnitAST();

  // ExternalDecl
  while(true){
    if(!visitExternalDeclaration(TU)){
      SAFE_DELETE(TU);
      return false;
    }
    if(Tokens->getCurType == TOK_EOF){
      break;
    }
  }
  return true;
}

// ExternalDeclaration用構文解析メソッド
bool Parser::visitExternalDeclaration(TranslationUnitAST *tunit){
  PrototypeAST *proto = visitFunctionDeclaration();
  if(proto){
    tunit->addPrototype(proto);
    return true;
  }

  FunctionAST *func_def = visitFunctionDefinition();
  if(func_def){
    tunit->addFunction(func_def);
    return true;
  }

  return false;
}

PrototypeAST *Parser::zisitFunctionDeclaration(){
  int backup = Tokens->getCurIndex();
  PrototypeAST *proto = visitPrototype();
  if(!proto){
    return NULL;
  }

  if(Tokens->getCurString() == ";"){
    // 本来であればここで再定義されていないか確認
    Tokens->getNextToken();
    return proto;
  }
  else{
    SAFE_DELETE(proto);
    Tokens->applyTokenIndex(backup);
    return NULL;
  }
}

FunctionAST *Parser::visitFunctionDefinition(){
  int backup = Tokens->getCurIndex();

  PrototypeAST *proto = visitPrototype();
  if(!proto){
    return NULL;
  }

  // 本来であればここで再定義されていないか確認
  FunctionStmtAST *func_stmt = visitFunctionStatement(proto);
}

PrototypeAST *Parser::visitPrototype(){
  int backup = Tokens->getCurIndex();

  bool is_first_param = true;
  std::vector<std::string> param_list;
  while(true){
    if(!is_first_param && Tokens->getCurType() == TOK_SYMBOL && Tokens->getCurString() == ","){
      Tokens->getNextToken();
    }
    if(Tokens->getCurType() == TOK_INT){
      Tokens->getNextToken();
    }
    else{
      break;
    }

    if(Tokens->getCurType() == TOK_IDENTIFIRE){
      param_list.push_back(Tokens->getCurString());
      Tokens->getNextToken();
    }
    else{
      Tokens->applyTokenIndex(buckup);
      return NULL;
    }
  }
}
<|endoftext|>


<commit_before>/*
 * Copyright 2014 David Moreno
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <iostream>

#include "parser.hpp"
#include "tokenizer.hpp"
#include "ast.hpp"
#include "ast_all.hpp"
#include "program.hpp"

using namespace loglang;
namespace loglang{

	class Parser{
		Tokenizer tokenizer;

		AST parse_stmt();
		AST parse_expr();
		AST parse_expr2();
		AST parse_expr3();
		AST parse_expr4();
		AST parse_term();
		AST parse_val();

		void parse_arg_list(std::unique_ptr<ast::Function> &f);

		AST parse_block();

		Token &assert_next(Token::type_t t);
	public:
		Parser(const std::string &sourcecode);
		AST parse();
	};

	AST parse_program(const std::string &sourcecode){
		Parser parser(sourcecode);
		return parser.parse();
	}
}

Parser::Parser(const std::string& sourcecode) : tokenizer(sourcecode)
{
}

AST Parser::parse()
{
	try{
		AST ret=parse_stmt();
// 		std::cerr<<ret->to_string()<<std::endl;
		return std::move(ret);
	}
	catch(parsing_exception &excp){
		std::cerr<<"Error parsing: "<<excp.what()<<std::endl;
		std::cerr<<tokenizer.position_to_string()<<std::endl;
		throw;
	}
}

Token &Parser::assert_next(Token::type_t expected)
{
	Token &tok=tokenizer.next();
	if (tok.type!=expected){
		print_backtrace();
		std::stringstream s;
		s<<tokenizer.position_to_string();
		s<<"Got "<<std::to_string(tok)<<" expected token type "<<expected;
		throw unexpected_token_type(s.str());
	}
	return tok;
}

AST Parser::parse_stmt()
{
	Token &tok=tokenizer.next();
	if (tok.type==Token::OPEN_CURLY){
		return parse_block();
	}
	tokenizer.rewind();
	return parse_expr();
}

AST Parser::parse_block()
{
	AST retblock=std::make_unique<ast::Block>();
	ast::Block *block=static_cast<ast::Block*>(&*retblock);
	Token &tok=tokenizer.next();
	while (tok.type!=Token::CLOSE_CURLY){
		tokenizer.rewind();
		block->stmts.push_back( std::move(parse_stmt()) );
		assert_next(Token::COLON);
		tok=tokenizer.next();
	}
	return retblock;
}

AST Parser::parse_expr()
{
	AST op1=parse_expr2();
	auto &op=tokenizer.next();
	if (op.type==Token::OP && op.token=="="){
		AST op2=parse_expr();
		ASTBase *op1p=&*op1;
		auto var=dynamic_cast<ast::Value_var*>(op1p);
		if (var==nullptr){
			throw semantic_exception(tokenizer.position_to_string() + "; lvalue invalid. Only variables are allowed.");
		}
		return std::make_unique<ast::Equal>(std::move(var->var), std::move(op2));
	}
	tokenizer.rewind();
	return op1;
}

AST Parser::parse_expr2() // < > <= >= == in and or
{
	AST op1=parse_expr3();
	auto &op=tokenizer.next();
	if (op.type==Token::OP){
		if (op.token=="<"){
			AST op2=parse_expr2();
			return std::make_unique<ast::Expr_lt>(std::move(op1), std::move(op2));
		}
		if (op.token==">"){
			AST op2=parse_expr2();
			return std::make_unique<ast::Expr_gt>(std::move(op1), std::move(op2));
		}
		if (op.token=="<="){
			AST op2=parse_expr2();
			return std::make_unique<ast::Expr_lte>(std::move(op1), std::move(op2));
		}
		if (op.token==">="){
			AST op2=parse_expr2();
			return std::make_unique<ast::Expr_gte>(std::move(op1), std::move(op2));
		}
		if (op.token=="=="){
			AST op2=parse_expr2();
			return std::make_unique<ast::Expr_eq>(std::move(op1), std::move(op2));
		}
		if (op.token=="!="){
			AST op2=parse_expr2();
			return std::make_unique<ast::Expr_neq>(std::move(op1), std::move(op2));
		}
		if (op.token=="and"){
			AST op2=parse_expr2();
			return std::make_unique<ast::Expr_and>(std::move(op1), std::move(op2));
		}
		if (op.token=="or"){
			AST op2=parse_expr2();
			return std::make_unique<ast::Expr_or>(std::move(op1), std::move(op2));
		}
		if (op.token=="in"){
			AST op2=parse_expr2();
			throw parsing_exception("'in' not yet");
			//return std::make_unique<ast::Expr_gt>(std::move(op1), std::move(op2));
		}
	}
	tokenizer.rewind(); // Ops, not any of those
	return op1;
}

AST Parser::parse_expr3() // + -
{
	AST op1=parse_expr4();
	auto &op=tokenizer.next();
	if (op.type==Token::OP){
		if (op.token=="+"){
			AST op2=parse_expr3();
			return std::make_unique<ast::Expr_add>(std::move(op1), std::move(op2));
		}
		if (op.token=="-"){
			AST op2=parse_expr3();
			return std::make_unique<ast::Expr_sub>(std::move(op1), std::move(op2));
		}
	}
	tokenizer.rewind(); // Ops, not + nor -
	return op1;
}

AST Parser::parse_expr4() // * /
{
	AST op1=parse_term();
	auto &op=tokenizer.next();
	if (op.type==Token::OP){
		if (op.token=="*"){
			AST op2=parse_expr4();
			return std::make_unique<ast::Expr_mul>(std::move(op1), std::move(op2));
		}
		if (op.token=="/"){
			AST op2=parse_expr4();
			return std::make_unique<ast::Expr_div>(std::move(op1), std::move(op2));
		}
	}
	tokenizer.rewind(); // Ops, not / nor *
	return op1;
}

AST Parser::parse_term()
{
	auto &tok=tokenizer.next();
	if (tok.type==Token::IF){
		throw parsing_exception("'if' not yet");
	}
	if (tok.type==Token::EDGE_IF){
		auto cmp=parse_expr();
		assert_next(Token::THEN);
		auto if_true=parse_stmt();
		assert_next(Token::ELSE);
		auto if_false=parse_stmt();
		return std::make_unique<ast::Edge_if>(std::move(cmp), std::move(if_true), std::move(if_false));
	}
	if (tok.type==Token::AT){
		auto at=parse_expr();
		assert_next(Token::DO);
		auto then=parse_stmt();
		return std::make_unique<ast::At>(std::move(at), std::move(then));
	}
	if (tok.type==Token::OPEN_PAREN){
		auto expr=parse_expr();
		assert_next(Token::CLOSE_PAREN);
		return expr;
	}
	if (tok.type==Token::OP && tok.token=="-"){
		auto expr=parse_expr();
		throw parsing_exception("unary op '-' not yet");
		//return std::make_unique<ast::Neg>(std::move(expr));
	}
	tokenizer.rewind();
	return parse_val();
}

AST Parser::parse_val()
{
	Token tok=tokenizer.next();
	if (tok.type==Token::NUMBER || tok.type==Token::STRING){
		return std::make_unique<ast::Value_const>(tok);
	}
	if (tok.type==Token::VAR){
		Token &next=tokenizer.next();
		if (next.type==Token::OPEN_PAREN){
			auto f=std::make_unique<ast::Function>(tok.token);
			parse_arg_list(f);
			assert_next(Token::CLOSE_PAREN);
			return std::move(f);
		}
		tokenizer.rewind();
		if (tok.type==Token::VAR){
			if (std::find(std::begin(tok.token), std::end(tok.token), '*')==std::end(tok.token) && std::find(std::begin(tok.token), std::end(tok.token), '?')==std::end(tok.token))
				return std::make_unique<ast::Value_var>(tok);
			else
				return std::make_unique<ast::Value_glob>(tok);
		}
	}
	throw unexpected_token_type(tok);
}

void Parser::parse_arg_list(std::unique_ptr< ast::Function >& f)
{
	while (true){
		f->params.push_back( std::move(parse_expr()) );
		Token &tok=tokenizer.next();
		if (tok.type==Token::CLOSE_PAREN){
			tokenizer.rewind();
			return;
		}
		tokenizer.rewind();
		assert_next(Token::COMMA);
	}
}
<commit_msg>Allow parse "*" as var name for all vars.<commit_after>/*
 * Copyright 2014 David Moreno
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <iostream>

#include "parser.hpp"
#include "tokenizer.hpp"
#include "ast.hpp"
#include "ast_all.hpp"
#include "program.hpp"

using namespace loglang;
namespace loglang{

	class Parser{
		Tokenizer tokenizer;

		AST parse_stmt();
		AST parse_expr();
		AST parse_expr2();
		AST parse_expr3();
		AST parse_expr4();
		AST parse_term();
		AST parse_val();

		void parse_arg_list(std::unique_ptr<ast::Function> &f);

		AST parse_block();

		Token &assert_next(Token::type_t t);
	public:
		Parser(const std::string &sourcecode);
		AST parse();
	};

	AST parse_program(const std::string &sourcecode){
		Parser parser(sourcecode);
		return parser.parse();
	}
}

Parser::Parser(const std::string& sourcecode) : tokenizer(sourcecode)
{
}

AST Parser::parse()
{
	try{
		AST ret=parse_stmt();
// 		std::cerr<<ret->to_string()<<std::endl;
		return std::move(ret);
	}
	catch(parsing_exception &excp){
		std::cerr<<"Error parsing: "<<excp.what()<<std::endl;
		std::cerr<<tokenizer.position_to_string()<<std::endl;
		throw;
	}
}

Token &Parser::assert_next(Token::type_t expected)
{
	Token &tok=tokenizer.next();
	if (tok.type!=expected){
		print_backtrace();
		std::stringstream s;
		s<<tokenizer.position_to_string();
		s<<"Got "<<std::to_string(tok)<<" expected token type "<<expected;
		throw unexpected_token_type(s.str());
	}
	return tok;
}

AST Parser::parse_stmt()
{
	Token &tok=tokenizer.next();
	if (tok.type==Token::OPEN_CURLY){
		return parse_block();
	}
	tokenizer.rewind();
	return parse_expr();
}

AST Parser::parse_block()
{
	AST retblock=std::make_unique<ast::Block>();
	ast::Block *block=static_cast<ast::Block*>(&*retblock);
	Token &tok=tokenizer.next();
	while (tok.type!=Token::CLOSE_CURLY){
		tokenizer.rewind();
		block->stmts.push_back( std::move(parse_stmt()) );
		assert_next(Token::COLON);
		tok=tokenizer.next();
	}
	return retblock;
}

AST Parser::parse_expr()
{
	AST op1=parse_expr2();
	auto &op=tokenizer.next();
	if (op.type==Token::OP && op.token=="="){
		AST op2=parse_expr();
		ASTBase *op1p=&*op1;
		auto var=dynamic_cast<ast::Value_var*>(op1p);
		if (var==nullptr){
			throw semantic_exception(tokenizer.position_to_string() + "; lvalue invalid. Only variables are allowed.");
		}
		return std::make_unique<ast::Equal>(std::move(var->var), std::move(op2));
	}
	tokenizer.rewind();
	return op1;
}

AST Parser::parse_expr2() // < > <= >= == in and or
{
	AST op1=parse_expr3();
	auto &op=tokenizer.next();
	if (op.type==Token::OP){
		if (op.token=="<"){
			AST op2=parse_expr2();
			return std::make_unique<ast::Expr_lt>(std::move(op1), std::move(op2));
		}
		if (op.token==">"){
			AST op2=parse_expr2();
			return std::make_unique<ast::Expr_gt>(std::move(op1), std::move(op2));
		}
		if (op.token=="<="){
			AST op2=parse_expr2();
			return std::make_unique<ast::Expr_lte>(std::move(op1), std::move(op2));
		}
		if (op.token==">="){
			AST op2=parse_expr2();
			return std::make_unique<ast::Expr_gte>(std::move(op1), std::move(op2));
		}
		if (op.token=="=="){
			AST op2=parse_expr2();
			return std::make_unique<ast::Expr_eq>(std::move(op1), std::move(op2));
		}
		if (op.token=="!="){
			AST op2=parse_expr2();
			return std::make_unique<ast::Expr_neq>(std::move(op1), std::move(op2));
		}
		if (op.token=="and"){
			AST op2=parse_expr2();
			return std::make_unique<ast::Expr_and>(std::move(op1), std::move(op2));
		}
		if (op.token=="or"){
			AST op2=parse_expr2();
			return std::make_unique<ast::Expr_or>(std::move(op1), std::move(op2));
		}
		if (op.token=="in"){
			AST op2=parse_expr2();
			throw parsing_exception("'in' not yet");
			//return std::make_unique<ast::Expr_gt>(std::move(op1), std::move(op2));
		}
	}
	tokenizer.rewind(); // Ops, not any of those
	return op1;
}

AST Parser::parse_expr3() // + -
{
	AST op1=parse_expr4();
	auto &op=tokenizer.next();
	if (op.type==Token::OP){
		if (op.token=="+"){
			AST op2=parse_expr3();
			return std::make_unique<ast::Expr_add>(std::move(op1), std::move(op2));
		}
		if (op.token=="-"){
			AST op2=parse_expr3();
			return std::make_unique<ast::Expr_sub>(std::move(op1), std::move(op2));
		}
	}
	tokenizer.rewind(); // Ops, not + nor -
	return op1;
}

AST Parser::parse_expr4() // * /
{
	AST op1=parse_term();
	auto &op=tokenizer.next();
	if (op.type==Token::OP){
		if (op.token=="*"){
			AST op2=parse_expr4();
			return std::make_unique<ast::Expr_mul>(std::move(op1), std::move(op2));
		}
		if (op.token=="/"){
			AST op2=parse_expr4();
			return std::make_unique<ast::Expr_div>(std::move(op1), std::move(op2));
		}
	}
	tokenizer.rewind(); // Ops, not / nor *
	return op1;
}

AST Parser::parse_term()
{
	auto &tok=tokenizer.next();
	if (tok.type==Token::IF){
		throw parsing_exception("'if' not yet");
	}
	if (tok.type==Token::EDGE_IF){
		auto cmp=parse_expr();
		assert_next(Token::THEN);
		auto if_true=parse_stmt();
		assert_next(Token::ELSE);
		auto if_false=parse_stmt();
		return std::make_unique<ast::Edge_if>(std::move(cmp), std::move(if_true), std::move(if_false));
	}
	if (tok.type==Token::AT){
		auto at=parse_expr();
		assert_next(Token::DO);
		auto then=parse_stmt();
		return std::make_unique<ast::At>(std::move(at), std::move(then));
	}
	if (tok.type==Token::OPEN_PAREN){
		auto expr=parse_expr();
		assert_next(Token::CLOSE_PAREN);
		return expr;
	}
	if (tok.type==Token::OP && tok.token=="-"){
		auto expr=parse_expr();
		throw parsing_exception("unary op '-' not yet");
		//return std::make_unique<ast::Neg>(std::move(expr));
	}
	tokenizer.rewind();
	return parse_val();
}

AST Parser::parse_val()
{
	Token tok=tokenizer.next();
	if (tok.type==Token::NUMBER || tok.type==Token::STRING){
		return std::make_unique<ast::Value_const>(tok);
	}
	if (tok.token=="*") // All vars glob
		tok.type=Token::VAR;
	if (tok.type==Token::VAR){
		Token &next=tokenizer.next();
		if (next.type==Token::OPEN_PAREN){
			auto f=std::make_unique<ast::Function>(tok.token);
			parse_arg_list(f);
			assert_next(Token::CLOSE_PAREN);
			return std::move(f);
		}
		tokenizer.rewind();
		if (tok.type==Token::VAR){
			if (std::find(std::begin(tok.token), std::end(tok.token), '*')==std::end(tok.token) && std::find(std::begin(tok.token), std::end(tok.token), '?')==std::end(tok.token))
				return std::make_unique<ast::Value_var>(tok);
			else
				return std::make_unique<ast::Value_glob>(tok);
		}
	}
	throw unexpected_token_type(tok);
}

void Parser::parse_arg_list(std::unique_ptr< ast::Function >& f)
{
	while (true){
		f->params.push_back( std::move(parse_expr()) );
		Token &tok=tokenizer.next();
		if (tok.type==Token::CLOSE_PAREN){
			tokenizer.rewind();
			return;
		}
		tokenizer.rewind();
		assert_next(Token::COMMA);
	}
}
<|endoftext|>


<commit_before>/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Written (W) 2011 Heiko Strathmann
 * Copyright (C) 2011 Berlin Institute of Technology and Max-Planck-Society
 */

#include <shogun/base/init.h>
#include <shogun/features/SparseFeatures.h>
#include <shogun/features/Subset.h>

using namespace shogun;

void print_message(FILE* target, const char* str)
{
	fprintf(target, "%s", str);
}

const int32_t num_vectors=6;
const int32_t dim_features=6;

void check_transposed(CSparseFeatures<int32_t>* features)
{
	CSparseFeatures<int32_t>* transposed=features->get_transposed();
	CSparseFeatures<int32_t>* double_transposed=transposed->get_transposed();

	for (index_t i=0; i<features->get_num_vectors(); ++i)
	{
		int32_t len;
		bool free_1, free_2;
		SGSparseVectorEntry<int32_t>* orig_vec=
				features->get_sparse_feature_vector(i, len, free_1);
		SGSparseVectorEntry<int32_t>* new_vec=
				double_transposed->get_sparse_feature_vector(i, len, free_2);

		for (index_t j=0; j<len; j++)
			ASSERT(orig_vec[j].entry==new_vec[j].entry);

		/* not necessary since feature matrix is in memory. for documentation */
		features->free_sparse_feature_vector(orig_vec, i, free_1);
		double_transposed->free_sparse_feature_vector(new_vec, i, free_2);
	}

	SG_UNREF(transposed);
	SG_UNREF(double_transposed);
}

int main(int argc, char **argv)
{
	init_shogun(&print_message, &print_message, &print_message);
	const int32_t num_subset_idx=CMath::random(1, num_vectors);

	/* create feature data matrix */
	SGMatrix<int32_t> data(dim_features, num_vectors);

	/* fill matrix with random data */
	for (index_t i=0; i<num_vectors*dim_features; ++i)
		data.matrix[i]=CMath::random(1, 9);

	/* create sparse features */
	CSparseFeatures<int32_t>* features=new CSparseFeatures<int32_t>(data);

	/* print dense feature matrix */
	CMath::display_matrix(data.matrix, data.num_rows, data.num_cols,
			"dense feature matrix");

	/* create subset indices */
	SGVector<index_t> subset_idx(CMath::randperm(num_subset_idx),
			num_subset_idx);

	/* print subset indices */
	CMath::display_vector(subset_idx.vector, subset_idx.vlen, "subset indices");

	/* apply subset to features */
	SG_SPRINT("\n-------------------\n"
	"applying subset to features\n"
	"-------------------\n");
	features->set_subset(new CSubset(subset_idx));

	/* do some stuff do check and output */
	ASSERT(features->get_num_vectors()==num_subset_idx);
	SG_SPRINT("features->get_num_vectors(): %d\n", features->get_num_vectors());

	/* check get_Transposed method */
	SG_SPRINT("checking transpose...");
	check_transposed(features);
	SG_SPRINT("does work\n");

	for (index_t i=0; i<features->get_num_vectors(); ++i)
	{
		int32_t len;
		bool free;
		SGSparseVectorEntry<int32_t>* vec=features->get_sparse_feature_vector(i,
				len, free);
		SG_SPRINT("sparse_vector[%d]=", i);
		for (index_t j=0; j<len; ++j)
		{
			SG_SPRINT("%d", vec[j].entry);
			if (j<len-1)
				SG_SPRINT(",");
		}

		SG_SPRINT("\n");

		for (index_t j=0; j<len; ++j)
			ASSERT(
					vec[j].entry==data.matrix[features->subset_idx_conversion( i)*num_vectors+j]);

		/* not necessary since feature matrix is in memory. for documentation */
		features->free_sparse_feature_vector(vec, i, free);
	}

	/* remove features subset */
	SG_SPRINT("\n-------------------\n"
	"removing subset from features\n"
	"-------------------\n");
	features->remove_subset();

	/* do some stuff do check and output */
	ASSERT(features->get_num_vectors()==num_vectors);
	SG_SPRINT("features->get_num_vectors(): %d\n", features->get_num_vectors());

	/* check get_Transposed method */
	SG_SPRINT("checking transpose...");
	check_transposed(features);
	SG_SPRINT("does work\n");

	for (index_t i=0; i<features->get_num_vectors(); ++i)
	{
		int32_t len;
		bool free;
		SGSparseVectorEntry<int32_t>* vec=features->get_sparse_feature_vector(i,
				len, free);
		SG_SPRINT("sparse_vector[%d]=", i);
		for (index_t j=0; j<len; ++j)
		{
			SG_SPRINT("%d", vec[j].entry);
			if (j<len-1)
				SG_SPRINT(",");
		}

		SG_SPRINT("\n");

		for (index_t j=0; j<len; ++j)
			ASSERT(vec[j].entry==data.matrix[i*num_vectors+j]);

		/* not necessary since feature matrix is in memory. for documentation */
		features->free_sparse_feature_vector(vec, i, free);
	}

	SG_UNREF(features);
	SG_FREE(data.matrix);

	SG_SPRINT("\nEND\n");
	exit_shogun();

	return 0;
}
<commit_msg>applied get_spare_vector() changes<commit_after>/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Written (W) 2011 Heiko Strathmann
 * Copyright (C) 2011 Berlin Institute of Technology and Max-Planck-Society
 */

#include <shogun/base/init.h>
#include <shogun/features/SparseFeatures.h>
#include <shogun/features/Subset.h>

using namespace shogun;

void print_message(FILE* target, const char* str)
{
	fprintf(target, "%s", str);
}

const int32_t num_vectors=6;
const int32_t dim_features=6;

void check_transposed(CSparseFeatures<int32_t>* features)
{
	CSparseFeatures<int32_t>* transposed=features->get_transposed();
	CSparseFeatures<int32_t>* double_transposed=transposed->get_transposed();

	for (index_t i=0; i<features->get_num_vectors(); ++i)
	{
		SGSparseVector<int32_t> orig_vec=features->get_sparse_feature_vector(i);
		SGSparseVector<int32_t> new_vec=
				double_transposed->get_sparse_feature_vector(i);

		for (index_t j=0; j<dim_features; j++)
			ASSERT(orig_vec.features[j].entry==new_vec.features[j].entry);

		/* not necessary since feature matrix is in memory. for documentation */
		features->free_sparse_feature_vector(orig_vec, i);
		double_transposed->free_sparse_feature_vector(new_vec, i);
	}

	SG_UNREF(transposed);
	SG_UNREF(double_transposed);
}

int main(int argc, char **argv)
{
	init_shogun(&print_message, &print_message, &print_message);
	const int32_t num_subset_idx=CMath::random(1, num_vectors);

	/* create feature data matrix */
	SGMatrix<int32_t> data(dim_features, num_vectors);

	/* fill matrix with random data */
	for (index_t i=0; i<num_vectors*dim_features; ++i)
		data.matrix[i]=CMath::random(1, 9);

	/* create sparse features */
	CSparseFeatures<int32_t>* features=new CSparseFeatures<int32_t>(data);

	/* print dense feature matrix */
	CMath::display_matrix(data.matrix, data.num_rows, data.num_cols,
			"dense feature matrix");

	/* create subset indices */
	SGVector<index_t> subset_idx(CMath::randperm(num_subset_idx),
			num_subset_idx);

	/* print subset indices */
	CMath::display_vector(subset_idx.vector, subset_idx.vlen, "subset indices");

	/* apply subset to features */
	SG_SPRINT("\n-------------------\n"
	"applying subset to features\n"
	"-------------------\n");
	features->set_subset(new CSubset(subset_idx));

	/* do some stuff do check and output */
	ASSERT(features->get_num_vectors()==num_subset_idx);
	SG_SPRINT("features->get_num_vectors(): %d\n", features->get_num_vectors());

	/* check get_Transposed method */
	SG_SPRINT("checking transpose...");
	check_transposed(features);
	SG_SPRINT("does work\n");

	for (index_t i=0; i<features->get_num_vectors(); ++i)
	{
		SGSparseVector<int32_t> vec=features->get_sparse_feature_vector(i);
		SG_SPRINT("sparse_vector[%d]=", i);
		for (index_t j=0; j<vec.num_feat_entries; ++j)
		{
			SG_SPRINT("%d", vec.features[j].entry);
			if (j<vec.num_feat_entries-1)
				SG_SPRINT(",");
		}

		SG_SPRINT("\n");

		for (index_t j=0; j<vec.num_feat_entries; ++j)
		{
			int32_t a=vec.features[j].entry;
			index_t ind=features->subset_idx_conversion(i)*num_vectors+j;
			int32_t	b=data.matrix[ind];
			ASSERT(a==b);
		}

		features->free_sparse_feature_vector(vec, i);
	}

	/* remove features subset */
	SG_SPRINT("\n-------------------\n"
	"removing subset from features\n"
	"-------------------\n");
	features->remove_subset();

	/* do some stuff do check and output */
	ASSERT(features->get_num_vectors()==num_vectors);
	SG_SPRINT("features->get_num_vectors(): %d\n", features->get_num_vectors());

	/* check get_Transposed method */
	SG_SPRINT("checking transpose...");
	check_transposed(features);
	SG_SPRINT("does work\n");

	for (index_t i=0; i<features->get_num_vectors(); ++i)
	{
		SGSparseVector<int32_t> vec=features->get_sparse_feature_vector(i);
		SG_SPRINT("sparse_vector[%d]=", i);
		for (index_t j=0; j<vec.num_feat_entries; ++j)
		{
			SG_SPRINT("%d", vec.features[j].entry);
			if (j<vec.num_feat_entries-1)
				SG_SPRINT(",");
		}

		SG_SPRINT("\n");

		for (index_t j=0; j<vec.num_feat_entries; ++j)
			ASSERT(vec.features[j].entry==data.matrix[i*num_vectors+j]);

		features->free_sparse_feature_vector(vec, i);
	}

	SG_UNREF(features);
	SG_FREE(data.matrix);

	exit_shogun();

	return 0;
}

<|endoftext|>


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

  This file is part of the elastix software.

  Copyright (c) University Medical Center Utrecht. All rights reserved.
  See src/CopyrightElastix.txt or http://elastix.isi.uu.nl/legal.php 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 notices for more information.

======================================================================*/

#ifndef __elxRayCastResampleInterpolator_hxx
#define __elxRayCastResampleInterpolator_hxx

#include "elxRayCastResampleInterpolator.h"
#include "itkImageFileWriter.h"

namespace elastix
{
using namespace itk;

  /*
   * ***************** BeforeAll *****************
   */

  template <class TElastix>
  void
  RayCastResampleInterpolator<TElastix>
  ::InitializeRayCastInterpolator( void )
  {

  this->m_CombinationTransform = CombinationTransformType::New();
  this->m_CombinationTransform->SetUseComposition( true );
  typedef typename elastix::OptimizerBase<
    TElastix>::ITKBaseType::ParametersType ParametersType;

  this->m_PreTransform = EulerTransformType::New();
  unsigned int numberofparameters = this->m_PreTransform->GetNumberOfParameters();
  TransformParametersType preParameters( numberofparameters );
  preParameters.Fill( 0.0 );

  for ( unsigned int i = 0; i < numberofparameters; i++ )
  {
      bool ret = this->GetConfiguration()->ReadParameter( preParameters[ i ],
        "PreParameters", this->GetComponentLabel(), i, 0 );
    if ( !ret )
    {
      std::cerr << " Error, not enough PreParameters are given" << std::endl;
    }
  }

  typename EulerTransformType::InputPointType centerofrotation;
  centerofrotation.Fill( 0.0 );

  for( unsigned int i = 0; i < this->m_Elastix->GetMovingImage()->GetImageDimension() ; i++ )
  {
      this->GetConfiguration()->ReadParameter( centerofrotation[ i ],
        "CenterOfRotationPoint", this->GetComponentLabel(), i, 0 );
  }

  this->m_PreTransform->SetParameters( preParameters );
  this->m_PreTransform->SetCenter( centerofrotation );
  this->m_CombinationTransform->SetInitialTransform( this->m_PreTransform );
  this->m_CombinationTransform->SetCurrentTransform(
    this->m_Elastix->GetElxTransformBase()->GetAsITKBaseType() );
  this->SetTransform( this->m_CombinationTransform );
  this->SetInputImage( this->m_Elastix->GetMovingImage() );

  PointType focalPoint;
  focalPoint.Fill( 0.0 );

  for ( unsigned int i = 0; i < this->m_Elastix->GetFixedImage()->GetImageDimension(); i++ )
  {
    bool ret = this->GetConfiguration()->ReadParameter( focalPoint[ i ],
        "FocalPoint", this->GetComponentLabel(), i, 0 );
    if ( !ret )
    {
      std::cerr << " Error, FocalPoint not assigned" << std::endl;
    }
  }

  this->SetFocalPoint( focalPoint );
  this->m_Elastix->GetElxResamplerBase()->GetAsITKBaseType()->SetTransform(
    this->m_CombinationTransform );
  double threshold = 0.;
  this->GetConfiguration()->ReadParameter( threshold, "Threshold", 0 );
  this->SetThreshold( threshold );

} // end InitializeRayCastInterpolator()

  /*
   * ***************** BeforeAll *****************
   */

  template <class TElastix>
  int
  RayCastResampleInterpolator<TElastix>
  ::BeforeAll( void )
  {

  // Check if 2D-3D
  if ( this->m_Elastix->GetFixedImage()->GetImageDimension() != 3 )
  {
      itkExceptionMacro( << "The RayCastInterpolator expects the fixed image to be 3D." );
      return 1;
  }
  if ( this->m_Elastix->GetMovingImage()->GetImageDimension() != 3 )
  {
      itkExceptionMacro( << "The RayCastInterpolator expects the moving image to be 3D." );
      return 1;
  }

  return 0;

  } // end BeforeAll()

  /*
   * ***************** BeforeRegistration *****************
   */

  template <class TElastix>
  void
  RayCastResampleInterpolator<TElastix>
  ::BeforeRegistration( void )
  {

  this->InitializeRayCastInterpolator();

  } // end BeforeRegistration()

  /*
   * ***************** ReadFromFile *****************
   */

  template <class TElastix>
  void
  RayCastResampleInterpolator<TElastix>
  ::ReadFromFile( void )
  {

  /** Call ReadFromFile of the ResamplerBase. */
  this->Superclass2::ReadFromFile();
  this->InitializeRayCastInterpolator();

  } // end ReadFromFile()

  /**
   * ******************* WriteToFile ******************************
   */

  template <class TElastix>
  void
  RayCastResampleInterpolator<TElastix>
  ::WriteToFile( void ) const
  {

  /** Call WriteToFile of the ResamplerBase. */
  this->Superclass2::WriteToFile();

  PointType focalpoint = this->GetFocalPoint();

  xout["transpar"] << "(" << "FocalPoint ";
  for( unsigned int i = 0; i < this->m_Elastix->GetMovingImage()->GetImageDimension() ; i++ )
  {
      xout["transpar"] << focalpoint[i] << " ";
  }
  xout["transpar"] << ")" << std::endl;

  typedef typename elastix::OptimizerBase<TElastix>::ITKBaseType::ParametersType ParametersType;
  TransformParametersType preParameters = this->m_PreTransform->GetParameters();

  xout["transpar"] << "(" << "PreParameters ";

  unsigned int numberofparameters =
    this->m_Elastix->GetElxTransformBase()->GetAsITKBaseType()->GetNumberOfParameters();
  for( unsigned int i = 0; i < numberofparameters; i++ )
  {
    xout["transpar"] << preParameters[i] << " ";
  }
    xout["transpar"]<< ")" << std::endl;

  double threshold = this->GetThreshold();
    xout["transpar"] << "(Threshold "
    << threshold << ")" << std::endl;

  } // end WriteToFile()

} // end namespace elastix

#endif // end #ifndef __elxRayCastResampleInterpolator_hxx
<commit_msg>SK:<commit_after>/*======================================================================

  This file is part of the elastix software.

  Copyright (c) University Medical Center Utrecht. All rights reserved.
  See src/CopyrightElastix.txt or http://elastix.isi.uu.nl/legal.php 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 notices for more information.

======================================================================*/

#ifndef __elxRayCastResampleInterpolator_hxx
#define __elxRayCastResampleInterpolator_hxx

#include "elxRayCastResampleInterpolator.h"
#include "itkImageFileWriter.h"

namespace elastix
{
using namespace itk;

  /*
   * ***************** BeforeAll *****************
   */

  template <class TElastix>
  void
  RayCastResampleInterpolator<TElastix>
  ::InitializeRayCastInterpolator( void )
  {

  this->m_CombinationTransform = CombinationTransformType::New();
  this->m_CombinationTransform->SetUseComposition( true );
  typedef typename elastix::OptimizerBase<
    TElastix>::ITKBaseType::ParametersType ParametersType;

  this->m_PreTransform = EulerTransformType::New();
  unsigned int numberofparameters = this->m_PreTransform->GetNumberOfParameters();
  TransformParametersType preParameters( numberofparameters );
  preParameters.Fill( 0.0 );

  for ( unsigned int i = 0; i < numberofparameters; i++ )
  {
      bool ret = this->GetConfiguration()->ReadParameter( preParameters[ i ],
        "PreParameters", this->GetComponentLabel(), i, 0 );
    if ( !ret )
    {
      std::cerr << " Error, not enough PreParameters are given" << std::endl;
    }
  }

  typename EulerTransformType::InputPointType centerofrotation;
  centerofrotation.Fill( 0.0 );

  for( unsigned int i = 0; i < this->m_Elastix->GetMovingImage()->GetImageDimension() ; i++ )
  {
      this->GetConfiguration()->ReadParameter( centerofrotation[ i ],
        "CenterOfRotationPoint", this->GetComponentLabel(), i, 0 );
  }

  this->m_PreTransform->SetParameters( preParameters );
  this->m_PreTransform->SetCenter( centerofrotation );
  this->m_CombinationTransform->SetInitialTransform( this->m_PreTransform );
  this->m_CombinationTransform->SetCurrentTransform(
    this->m_Elastix->GetElxTransformBase()->GetAsITKBaseType() );
  this->SetTransform( this->m_CombinationTransform );
  this->SetInputImage( this->m_Elastix->GetMovingImage() );

  PointType focalPoint;
  focalPoint.Fill( 0.0 );

  for ( unsigned int i = 0; i < this->m_Elastix->GetFixedImage()->GetImageDimension(); i++ )
  {
    bool ret = this->GetConfiguration()->ReadParameter( focalPoint[ i ],
        "FocalPoint", this->GetComponentLabel(), i, 0 );
    if ( !ret )
    {
      std::cerr << " Error, FocalPoint not assigned" << std::endl;
    }
  }

  this->SetFocalPoint( focalPoint );
  this->m_Elastix->GetElxResamplerBase()->GetAsITKBaseType()->SetTransform(
    this->m_CombinationTransform );
  double threshold = 0.;
  this->GetConfiguration()->ReadParameter( threshold, "Threshold", 0 );
  this->SetThreshold( threshold );

} // end InitializeRayCastInterpolator()

  /*
   * ***************** BeforeAll *****************
   */

  template <class TElastix>
  int
  RayCastResampleInterpolator<TElastix>
  ::BeforeAll( void )
  {

  // Check if 2D-3D
  if ( this->m_Elastix->GetFixedImage()->GetImageDimension() != 3 )
  {
      itkExceptionMacro( << "The RayCastInterpolator expects the fixed image to be 3D." );
      return 1;
  }
  if ( this->m_Elastix->GetMovingImage()->GetImageDimension() != 3 )
  {
      itkExceptionMacro( << "The RayCastInterpolator expects the moving image to be 3D." );
      return 1;
  }

  return 0;

  } // end BeforeAll()

  /*
   * ***************** BeforeRegistration *****************
   */

  template <class TElastix>
  void
  RayCastResampleInterpolator<TElastix>
  ::BeforeRegistration( void )
  {

  this->InitializeRayCastInterpolator();

  } // end BeforeRegistration()

  /*
   * ***************** ReadFromFile *****************
   */

  template <class TElastix>
  void
  RayCastResampleInterpolator<TElastix>
  ::ReadFromFile( void )
  {

  /** Call ReadFromFile of the ResamplerBase. */
  this->Superclass2::ReadFromFile();
  this->InitializeRayCastInterpolator();

  } // end ReadFromFile()

  /**
   * ******************* WriteToFile ******************************
   */

  template <class TElastix>
  void
  RayCastResampleInterpolator<TElastix>
  ::WriteToFile( void ) const
  {

  /** Call WriteToFile of the ResamplerBase. */
  this->Superclass2::WriteToFile();

  PointType focalpoint = this->GetFocalPoint();

  xout["transpar"] << "(" << "FocalPoint ";
  for( unsigned int i = 0; i < this->m_Elastix->GetMovingImage()->GetImageDimension() ; i++ )
  {
      xout["transpar"] << focalpoint[i] << " ";
  }
  xout["transpar"] << ")" << std::endl;

  typedef typename elastix::OptimizerBase<TElastix>::ITKBaseType::ParametersType ParametersType;
  TransformParametersType preParameters = this->m_PreTransform->GetParameters();

  xout["transpar"] << "(" << "PreParameters ";

  unsigned int numberofparameters = preParameters.GetSize();
  for( unsigned int i = 0; i < numberofparameters; i++ )
  {
    xout["transpar"] << preParameters[i] << " ";
  }
    xout["transpar"]<< ")" << std::endl;

  double threshold = this->GetThreshold();
    xout["transpar"] << "(Threshold "
    << threshold << ")" << std::endl;

  } // end WriteToFile()

} // end namespace elastix

#endif // end #ifndef __elxRayCastResampleInterpolator_hxx
<|endoftext|>


<commit_before>#include <primio.h>
#include <algorithm>
#include <bits.h>
#include <cassert>
#include <charconv>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <exception.h>
#include <fcntl.h>
#include <kv.h>
#include <l.h>
#include <o.h>
#include <output.h>
#include <sym.h>
#include <unistd.h>

namespace {
    const index_t BUFFER_SIZE = 4064;

    H blush(H h);

    // stdout and stderr are initialized specially so they can be used for
    // debugging before write_buffers is initialized. We could use the Schwarz
    // counter to make sure write_buffers is initialized, but we don't want to,
    // since write_buffers allocates memory from the buddy allocator.

    List<X>* init_static_buf(void* p) {
        static_assert(sizeof(List<X>) == 24);
        assert((bitcast<std::uintptr_t>(p) & 31) == 0);
        List<X>* const buf = new (static_cast<char*>(p) + 8) List<X>;
        buf->a             = Attr::none;
        buf->apadv         = Opcode(0);
        buf->arity         = 0;
        buf->r             = 1;
        buf->n             = 0;
        buf->type          = ObjectTraits<X>::typet();
        return buf;
    }
    alignas(32) char ebuf[BUFFER_SIZE + 32];
    List<X>* err() {
        static List<X>* buf;
        if (!buf) buf = init_static_buf(ebuf);
        return buf;
    }
    alignas(32) char obuf[BUFFER_SIZE + 32];
    List<X>* out() {
        static List<X>* buf;
        if (!buf) buf = init_static_buf(obuf);
        return buf;
    }
    struct WriteBuffers {
        WriteBuffers() = default;
        ~WriteBuffers() { blush(H(1)); blush(H(2)); for (H h: d.key()) blush(h); }
        WriteBuffers(const WriteBuffers&) = delete;
        WriteBuffers& operator=(const WriteBuffers&) = delete;

        List<X>* operator[](H h) {
            return h == H(1)? out()
                :  h == H(2)? err()
                :  d.has(h) ? d[h].get()
                :  /* else */ nullptr;
        }
        void add(H h) { d.add(h, new_buffer()); }
        void remove(H h) { d.remove(h); }

    private:
        KV<H, L<X>> d;
        static L<X> new_buffer() { return L<X>(make_empty_list<X>(BUFFER_SIZE)); }
    } write_buffers;

    ssize_t writeall(int fd, const void* buf, index_t n) {
        const char* const p = static_cast<const char*>(buf);
        index_t total = 0;
        while (total < n) {
            const ssize_t written = write(fd, p + total, std::size_t(n - total));
            if      (0 <= written)   total += written;
            else if (errno != EINTR) return written;
        }
        return total;
    }

    H bblush(H h, char* buf, index_t* tail) {
        if (writeall(H::rep(h), buf, *tail) < 0)
            throw Exception("'os");
        *tail = 0;
        return h;
    }

    H blush(H h) {
        List<X>* const buf = write_buffers[h];
        if (!buf) return h;
        return bblush(h, reinterpret_cast<char*>(buf->begin()), &buf->n);
    }

    H bbrite(H h, const void* p, index_t n, char* buf, index_t* tail) {
        const index_t avail = BUFFER_SIZE - *tail;
        if (n <= avail) {
            memcpy(buf + *tail, p, std::size_t(n));
            *tail += n;
        } else if (n <= BUFFER_SIZE + avail) {
            memcpy(buf + *tail, p, std::size_t(avail));
            *tail += avail;
            bblush(h, buf, tail);
            memcpy(buf, static_cast<const char*>(p) + avail, std::size_t(n - avail));
            *tail = n - avail;
        } else {
            bblush(h, buf, tail);
            if (writeall(H::rep(h), p, n) < 0)
                throw Exception("'os");
        }
        return h;
    }

    H brite(H h, const void* p, index_t n) {
        List<X>* const buf = write_buffers[h];
        if (buf)
            bbrite(h, p, n, reinterpret_cast<char*>(buf->begin()), &buf->n);
        else if (writeall(H::rep(h), p, n) < 0)
            throw Exception("'os");
        return h;
    }

    H hopen(const char* path, int flags) {
        const int allrw = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
        const int fd = open(path, flags, allrw);
        if (fd != -1) write_buffers.add(H(fd));
        return H(fd);
    }
} // unnamed

H hopen(const char* path) {
    return hopen(path, O_CREAT|O_RDWR);
}

H hopen(const char* path, Truncate) {
    return hopen(path, O_CREAT|O_RDWR|O_TRUNC);
}

void hclose(H h) {
    blush(h);
    write_buffers.remove(h);
    close(H::rep(h));
}

H escape(H h, C x) { return escapec(h, x); }
H flush(H h) { return blush(h); }

H operator<<(H h, H(*f)(H)) { return f(h); }

H operator<<(H h, const char* s) { return brite(h, s , index_t(strlen(s))); }
H operator<<(H h, char        c) { return brite(h, &c, 1); }
H operator<<(H h, uint8_t     x) { return brite(h, &x, 1); }
H operator<<(H h, double      x) { return write_double(h, x); }

H operator<<(H h, int32_t     x) { return write_int64(h, x); }
H operator<<(H h, int64_t     x) { return write_int64(h, x); }
H operator<<(H h, uint32_t    x) { return write_uint64(h, x); }
H operator<<(H h, uint64_t    x) { return write_uint64(h, x); }

#ifndef __GNUG__
// TODO need to test if std::is_same_v<uin64_t, std::size_t>
// or just make one of them unnecessary
H operator<<(H h, std::size_t x) { return write_uint64(h, x); }
#endif

H operator<<(H h, const void* x) { return write_pointer(h, x); }
H operator<<(H h, std::pair<const char*, const char*> x) {
    return brite(h, x.first, x.second - x.first);
}

H operator<<(H h, B x) { return h << "01"[B::rep(x)] << 'b'; }
H operator<<(H h, C x) { return h << C::rep(x); }
H operator<<(H h, D x) { return write_date(h, x); }
H operator<<(H h, F x) { return h << F::rep(x); }
H operator<<(H h, H x) { return h << H::rep(x); }

H operator<<(H h, I x) {
    return x.is_null()? h << "0Ni"
         : x == WI    ? h << "0Wi"
         : x == -WI   ? h << "-0Wi"
         : /* else */   h << I::rep(x);
}

H operator<<(H h, J x) {
    return x.is_null()? h << "0N"
         : x == WJ    ? h << "0W"
         : x == -WJ   ? h << "-0W"
         : /* else */   h << J::rep(x);
}

H operator<<(H h, S x) { return h << '`' << c_str(x); }
H operator<<(H h, T x) { return write_time(h, x); }
H operator<<(H h, X x) { return write_byte(h, x); }

H operator<<(H h, std::pair<const C*, const C*> x) {
    assert(x.first <= x.second);
    return brite(h, x.first, x.second - x.first);
}
<commit_msg>Revert AP change to primio.cpp<commit_after>#include <primio.h>
#include <algorithm>
#include <bits.h>
#include <cassert>
#include <charconv>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <exception.h>
#include <fcntl.h>
#include <kv.h>
#include <l.h>
#include <o.h>
#include <output.h>
#include <sym.h>
#include <unistd.h>

namespace {
    const index_t BUFFER_SIZE = 4064;

    H blush(H h);

    // stdout and stderr are initialized specially so they can be used for
    // debugging before write_buffers is initialized. We could use the Schwarz
    // counter to make sure write_buffers is initialized, but we don't want to,
    // since write_buffers allocates memory from the buddy allocator.

    List<X>* init_static_buf(void* p) {
        static_assert(sizeof(List<X>) == 24);
        assert((bitcast<std::uintptr_t>(p) & 31) == 0);
        List<X>* const buf = new (static_cast<char*>(p) + 8) List<X>;
        buf->a             = Attr::none;
        buf->m             = 0;
        buf->r             = 1;
        buf->n             = 0;
        buf->type          = ObjectTraits<X>::typet();
        return buf;
    }
    alignas(32) char ebuf[BUFFER_SIZE + 32];
    List<X>* err() {
        static List<X>* buf;
        if (!buf) buf = init_static_buf(ebuf);
        return buf;
    }
    alignas(32) char obuf[BUFFER_SIZE + 32];
    List<X>* out() {
        static List<X>* buf;
        if (!buf) buf = init_static_buf(obuf);
        return buf;
    }
    struct WriteBuffers {
        WriteBuffers() = default;
        ~WriteBuffers() { blush(H(1)); blush(H(2)); for (H h: d.key()) blush(h); }
        WriteBuffers(const WriteBuffers&) = delete;
        WriteBuffers& operator=(const WriteBuffers&) = delete;

        List<X>* operator[](H h) {
            return h == H(1)? out()
                :  h == H(2)? err()
                :  d.has(h) ? d[h].get()
                :  /* else */ nullptr;
        }
        void add(H h) { d.add(h, new_buffer()); }
        void remove(H h) { d.remove(h); }

    private:
        KV<H, L<X>> d;
        static L<X> new_buffer() { return L<X>(make_empty_list<X>(BUFFER_SIZE)); }
    } write_buffers;

    ssize_t writeall(int fd, const void* buf, index_t n) {
        const char* const p = static_cast<const char*>(buf);
        index_t total = 0;
        while (total < n) {
            const ssize_t written = write(fd, p + total, std::size_t(n - total));
            if      (0 <= written)   total += written;
            else if (errno != EINTR) return written;
        }
        return total;
    }

    H bblush(H h, char* buf, index_t* tail) {
        if (writeall(H::rep(h), buf, *tail) < 0)
            throw Exception("'os");
        *tail = 0;
        return h;
    }

    H blush(H h) {
        List<X>* const buf = write_buffers[h];
        if (!buf) return h;
        return bblush(h, reinterpret_cast<char*>(buf->begin()), &buf->n);
    }

    H bbrite(H h, const void* p, index_t n, char* buf, index_t* tail) {
        const index_t avail = BUFFER_SIZE - *tail;
        if (n <= avail) {
            memcpy(buf + *tail, p, std::size_t(n));
            *tail += n;
        } else if (n <= BUFFER_SIZE + avail) {
            memcpy(buf + *tail, p, std::size_t(avail));
            *tail += avail;
            bblush(h, buf, tail);
            memcpy(buf, static_cast<const char*>(p) + avail, std::size_t(n - avail));
            *tail = n - avail;
        } else {
            bblush(h, buf, tail);
            if (writeall(H::rep(h), p, n) < 0)
                throw Exception("'os");
        }
        return h;
    }

    H brite(H h, const void* p, index_t n) {
        List<X>* const buf = write_buffers[h];
        if (buf)
            bbrite(h, p, n, reinterpret_cast<char*>(buf->begin()), &buf->n);
        else if (writeall(H::rep(h), p, n) < 0)
            throw Exception("'os");
        return h;
    }

    H hopen(const char* path, int flags) {
        const int allrw = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
        const int fd = open(path, flags, allrw);
        if (fd != -1) write_buffers.add(H(fd));
        return H(fd);
    }
} // unnamed

H hopen(const char* path) {
    return hopen(path, O_CREAT|O_RDWR);
}

H hopen(const char* path, Truncate) {
    return hopen(path, O_CREAT|O_RDWR|O_TRUNC);
}

void hclose(H h) {
    blush(h);
    write_buffers.remove(h);
    close(H::rep(h));
}

H escape(H h, C x) { return escapec(h, x); }
H flush(H h) { return blush(h); }

H operator<<(H h, H(*f)(H)) { return f(h); }

H operator<<(H h, const char* s) { return brite(h, s , index_t(strlen(s))); }
H operator<<(H h, char        c) { return brite(h, &c, 1); }
H operator<<(H h, uint8_t     x) { return brite(h, &x, 1); }
H operator<<(H h, double      x) { return write_double(h, x); }

H operator<<(H h, int32_t     x) { return write_int64(h, x); }
H operator<<(H h, int64_t     x) { return write_int64(h, x); }
H operator<<(H h, uint32_t    x) { return write_uint64(h, x); }
H operator<<(H h, uint64_t    x) { return write_uint64(h, x); }

#ifndef __GNUG__
// TODO need to test if std::is_same_v<uin64_t, std::size_t>
// or just make one of them unnecessary
H operator<<(H h, std::size_t x) { return write_uint64(h, x); }
#endif

H operator<<(H h, const void* x) { return write_pointer(h, x); }
H operator<<(H h, std::pair<const char*, const char*> x) {
    return brite(h, x.first, x.second - x.first);
}

H operator<<(H h, B x) { return h << "01"[B::rep(x)] << 'b'; }
H operator<<(H h, C x) { return h << C::rep(x); }
H operator<<(H h, D x) { return write_date(h, x); }
H operator<<(H h, F x) { return h << F::rep(x); }
H operator<<(H h, H x) { return h << H::rep(x); }

H operator<<(H h, I x) {
    return x.is_null()? h << "0Ni"
         : x == WI    ? h << "0Wi"
         : x == -WI   ? h << "-0Wi"
         : /* else */   h << I::rep(x);
}

H operator<<(H h, J x) {
    return x.is_null()? h << "0N"
         : x == WJ    ? h << "0W"
         : x == -WJ   ? h << "-0W"
         : /* else */   h << J::rep(x);
}

H operator<<(H h, S x) { return h << '`' << c_str(x); }
H operator<<(H h, T x) { return write_time(h, x); }
H operator<<(H h, X x) { return write_byte(h, x); }

H operator<<(H h, std::pair<const C*, const C*> x) {
    assert(x.first <= x.second);
    return brite(h, x.first, x.second - x.first);
}
<|endoftext|>


<commit_before>struct Client1;
struct Client2;
typedef Visitor<Client1, Client2> BaseClientVisitor;
struct Client1 : BaseClientVisitor::Visitable<Client1> { };
struct Client2 : BaseClientVisitor::Visitable<Client2> { };

struct Client2a;
struct Client2b;
typedef Visitor<Client2a, Client2b> Client2Visitor;
struct Client2a : Client2, Client2Visitor::Visitable<Clien2a> { };
struct Client2b : Client2, Client2Visitor::Visitable<Clien2b> { };

struct AllClientsVisitor : BaseClientVisitor, Client2Visitor
{
  virtual void visit( Client2 & t )
	{
		t.accept( static_cast<Client2Visitor&>(*this) );
	}
};
<commit_msg>Update visitor_test.cpp<commit_after>struct Client1;
struct Client2;
typedef Visitor<Client1, Client2> BaseClientVisitor;
struct Client1 : BaseClientVisitor::Visitable<Client1> { };
struct Client2 : BaseClientVisitor::Visitable<Client2> { };

struct Client2a;
struct Client2b;
typedef Visitor<Client2a, Client2b> Client2Visitor;
struct Client2a : Client2, Client2Visitor::Visitable<Clien2a> { };
struct Client2b : Client2, Client2Visitor::Visitable<Clien2b> { };

struct AllClientsVisitor : BaseClientVisitor, Client2Visitor
{
	virtual void visit( Client2 & t )
	{
		t.accept( static_cast<Client2Visitor&>(*this) );
	}
};
<|endoftext|>


<commit_before>#include "wide_graph_with_listener.h"
#include "../src/transwarp.h"
#include <iostream>
#include <fstream>
#include <random>
#include <numeric>
namespace tw = transwarp;

namespace {

std::mt19937 gen{1};
std::mutex mutex; // protect the generator

using data_t = std::shared_ptr<std::vector<double>>;

data_t transform(data_t data) {
    std::uniform_real_distribution<double> dist(0.5, 1.5);
    for (auto& v : *data) {
        std::lock_guard<std::mutex> lock{mutex};
        v *= dist(gen);
    }
    return data;
}

double mean(data_t data) {
    return std::accumulate(data->begin(), data->end(), 0.) / static_cast<double>(data->size());
}

class listener : public tw::listener {
public:

    // Note: this is called on the thread the task is run on for the after_finished event
    void handle_event(tw::event_type event, const std::shared_ptr<tw::node>&) {
        if (event == tw::event_type::after_finished) {
            // task has finished
        }
    }

};

std::shared_ptr<tw::task<double>> build_graph(std::shared_ptr<tw::task<data_t>> input) {
    std::vector<std::shared_ptr<tw::task<data_t>>> parents;
    for (int i=0; i<8; ++i) {
        auto t = tw::make_task(tw::consume, transform, input)->then(tw::consume, transform);
        parents.emplace_back(t);
    }
    auto final = tw::make_task(tw::consume, [](const std::vector<data_t>& parents) {
                                                double res = 0;
                                                for (const auto p : parents) {
                                                    res += mean(p);
                                                }
                                                return res;
                                            }, parents);
    return final;
}

}

namespace examples {

// This example demonstrates the scheduling of an extra wide graph.
// It also shows how the listener interface can be used to handle task events.
// Increase iterations and size and observe your CPU load.
// In this example, new data cannot be scheduled until the last result
// was retrieved. However, this can be changed to use a pool of graphs
// to process every data input as soon as possible.
void wide_graph_with_listener(std::ostream& os, std::size_t iterations, std::size_t size) {
    tw::parallel exec{8}; // thread pool with 8 threads

    // The data input task at the root of the graph
    auto input = tw::make_value_task(std::make_shared<std::vector<double>>());

    // Build graph and return the final task
    auto final = build_graph(input);
    final->add_listener(std::make_shared<listener>());

    // Output the graph for visualization
    const auto graph = final->get_graph();
    std::ofstream("wide_graph_with_listener.dot") << tw::to_string(graph);

    // This is to generate random data
    std::uniform_int_distribution<std::size_t> dist(size, size * 10);

    for (std::size_t i=0; i<iterations; ++i) {
        auto data = std::make_shared<std::vector<double>>(dist(gen), 1);
        input->set_value(data); // New data arrive
        final->schedule_all(exec); // Schedule the graph immediately after data arrived
        os << final->get() << std::endl; // Print result
    }
}

}

#ifndef UNITTEST
int main() {
    std::cout << "Running example: wide_graph_with_listener ..." << std::endl;
    examples::wide_graph_with_listener(std::cout);
}
#endif
<commit_msg>fix mean calc<commit_after>#include "wide_graph_with_listener.h"
#include "../src/transwarp.h"
#include <iostream>
#include <fstream>
#include <random>
#include <numeric>
namespace tw = transwarp;

namespace {

std::mt19937 gen{1};
std::mutex mutex; // protect the generator

using data_t = std::shared_ptr<std::vector<double>>;

data_t transform(data_t data) {
    std::uniform_real_distribution<double> dist(0.5, 1.5);
    for (auto& v : *data) {
        std::lock_guard<std::mutex> lock{mutex};
        v *= dist(gen);
    }
    return data;
}

double mean(data_t data) {
    return std::accumulate(data->begin(), data->end(), 0.) / static_cast<double>(data->size());
}

class listener : public tw::listener {
public:

    // Note: this is called on the thread the task is run on for the after_finished event
    void handle_event(tw::event_type event, const std::shared_ptr<tw::node>&) {
        if (event == tw::event_type::after_finished) {
            // task has finished
        }
    }

};

std::shared_ptr<tw::task<double>> build_graph(std::shared_ptr<tw::task<data_t>> input) {
    std::vector<std::shared_ptr<tw::task<data_t>>> parents;
    for (int i=0; i<8; ++i) {
        auto t = tw::make_task(tw::consume, transform, input)->then(tw::consume, transform);
        parents.emplace_back(t);
    }
    auto final = tw::make_task(tw::consume, [](const std::vector<data_t>& parents) {
                                                double res = 0;
                                                for (const auto p : parents) {
                                                    res += mean(p);
                                                }
                                                return res / parents.size();
                                            }, parents);
    return final;
}

}

namespace examples {

// This example demonstrates the scheduling of an extra wide graph.
// It also shows how the listener interface can be used to handle task events.
// Increase iterations and size and observe your CPU load.
// In this example, new data cannot be scheduled until the last result
// was retrieved. However, this can be changed to use a pool of graphs
// to process every data input as soon as possible.
void wide_graph_with_listener(std::ostream& os, std::size_t iterations, std::size_t size) {
    tw::parallel exec{8}; // thread pool with 8 threads

    // The data input task at the root of the graph
    auto input = tw::make_value_task(std::make_shared<std::vector<double>>());

    // Build graph and return the final task
    auto final = build_graph(input);
    final->add_listener(std::make_shared<listener>());

    // Output the graph for visualization
    const auto graph = final->get_graph();
    std::ofstream("wide_graph_with_listener.dot") << tw::to_string(graph);

    // This is to generate random data
    std::uniform_int_distribution<std::size_t> dist(size, size * 10);

    for (std::size_t i=0; i<iterations; ++i) {
        auto data = std::make_shared<std::vector<double>>(dist(gen), 1);
        input->set_value(data); // New data arrive
        final->schedule_all(exec); // Schedule the graph immediately after data arrived
        os << final->get() << std::endl; // Print result
    }
}

}

#ifndef UNITTEST
int main() {
    std::cout << "Running example: wide_graph_with_listener ..." << std::endl;
    examples::wide_graph_with_listener(std::cout);
}
#endif
<|endoftext|>


<commit_before>// Copyright © 2012, Université catholique de Louvain
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// *  Redistributions of source code must retain the above copyright notice,
//    this list of conditions and the following disclaimer.
// *  Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

#include "mozart.hh"

namespace mozart {

struct SuspendTrailEntry {
  SuspendTrailEntry(StableNode* left, StableNode* right) :
    left(left), right(right) {}

  StableNode* left;
  StableNode* right;
};

typedef VMAllocatedList<SuspendTrailEntry> SuspendTrail;

typedef VMAllocatedList<NodeBackup> RebindTrail;

struct StructuralDualWalk {
public:
  enum Kind {
    wkUnify, wkEquals, wkPatternMatch
  };
public:
  StructuralDualWalk(VM vm, Kind kind,
                     StaticArray<UnstableNode> captures = nullptr):
    vm(vm), kind(kind), captures(captures) {}

  OpResult run(RichNode left, RichNode right);
private:
  inline
  OpResult processPair(VM vm, RichNode left, RichNode right);

  inline
  void rebind(VM vm, RichNode left, RichNode right);

  inline
  void undoBindings(VM vm);

  inline
  void doCapture(VM vm, RichNode value, RichNode capture);

  inline
  void doConjunction(VM vm, RichNode value, RichNode conjunction);

  inline
  OpResult doOpenRecord(VM vm, RichNode value, RichNode pattern);

  VM vm;
  Kind kind;

  WalkStack stack;
  RebindTrail rebindTrail;
  SuspendTrail suspendTrail;

  StaticArray<UnstableNode> captures;
};

/////////////////
// Entry point //
/////////////////

OpResult fullUnify(VM vm, RichNode left, RichNode right) {
  StructuralDualWalk walk(vm, StructuralDualWalk::wkUnify);
  return walk.run(left, right);
}

OpResult fullEquals(VM vm, RichNode left, RichNode right, bool& result) {
  StructuralDualWalk walk(vm, StructuralDualWalk::wkEquals);
  return walk.run(left, right).mapProceedFailToTrueFalse(result);
}

OpResult fullPatternMatch(VM vm, RichNode value, RichNode pattern,
                          StaticArray<UnstableNode> captures, bool& result) {
  StructuralDualWalk walk(vm, StructuralDualWalk::wkPatternMatch, captures);
  return walk.run(value, pattern).mapProceedFailToTrueFalse(result);
}

////////////////////
// The real thing //
////////////////////

OpResult StructuralDualWalk::run(RichNode left, RichNode right) {
  VM vm = this->vm;

  while (true) {
    // Process the pair
    OpResult pairResult = processPair(vm, left, right);

    switch (pairResult.kind()) {
      case OpResult::orFail:
      case OpResult::orRaise: {
        stack.clear(vm);
        suspendTrail.clear(vm);
        undoBindings(vm);
        return pairResult;
      }

      case OpResult::orWaitBefore:
      case OpResult::orWaitQuietBefore: {
        if (!RichNode(*pairResult.getWaiteeNode()).is<FailedValue>()) {
          // TODO Do we need to actually support the *quiet* here?
          suspendTrail.push_back_new(vm, left.getStableRef(vm),
                                     right.getStableRef(vm));
          break;
        } else {
          stack.clear(vm);
          suspendTrail.clear(vm);
          undoBindings(vm);
          return pairResult;
        }
      }

      case OpResult::orProceed: {
        // nothing to do
      }
    }

    // Finished?
    if (stack.empty())
      break;

    // Pop next pair
    left = *stack.front().left;
    right = *stack.front().right;

    // Go to next item
    stack.remove_front(vm);
  }

  // Do we need to suspend on something?
  if (!suspendTrail.empty()) {
    // Undo temporary bindings

    undoBindings(vm);

    // Create the control variable

    UnstableNode unstableControlVar = Variable::build(vm);
    RichNode controlVar = unstableControlVar;
    controlVar.ensureStable(vm);

    // Reduce the remaining unifications
    size_t count = suspendTrail.size();

    if (count == 1) {
      left = *suspendTrail.front().left;
      right = *suspendTrail.front().right;

      if (left.isTransient())
        DataflowVariable(left).addToSuspendList(vm, controlVar);

      if (right.isTransient())
        DataflowVariable(right).addToSuspendList(vm, controlVar);
    } else {
      UnstableNode label = Atom::build(vm, vm->coreatoms.pipe);

      UnstableNode unstableLeft = Tuple::build(vm, count, label);
      UnstableNode unstableRight = Tuple::build(vm, count, label);

      auto leftTuple = RichNode(unstableLeft).as<Tuple>();
      auto rightTuple = RichNode(unstableRight).as<Tuple>();

      size_t i = 0;
      for (auto iter = suspendTrail.begin();
           iter != suspendTrail.end(); i++, ++iter) {
        UnstableNode leftTemp(vm, *iter->left);
        leftTuple.initElement(vm, i, leftTemp);

        RichNode richLeftTemp = leftTemp;
        if (richLeftTemp.isTransient())
          DataflowVariable(richLeftTemp).addToSuspendList(vm, controlVar);

        UnstableNode rightTemp(vm, *iter->right);
        rightTuple.initElement(vm, i, rightTemp);

        RichNode richRightTemp = rightTemp;
        if (richRightTemp.isTransient())
          DataflowVariable(richRightTemp).addToSuspendList(vm, controlVar);
      }
    }

    suspendTrail.clear(vm);

    // TODO Replace initial operands by unstableLeft and unstableRight

    return OpResult::waitFor(vm, controlVar);
  }

  /* No need to undo temporary bindings here, even if we are in wkEquals mode.
   * In fact, we should not undo them in that case, as that compactifies
   * the store, and speeds up subsequent tests and/or unifications.
   *
   * However, the above is *wrong* when in a subspace, because of speculative
   * bindings.
   *
   * The above would also be *wrong* when in wkPatternMatch mode. But in that
   * mode we do not perform temporary bindings in the first place.
   */
  if (!vm->isOnTopLevel())
    undoBindings(vm);

  return OpResult::proceed();
}

OpResult StructuralDualWalk::processPair(VM vm, RichNode left,
                                         RichNode right) {
  // Identical nodes
  if (left.isSameNode(right))
    return OpResult::proceed();

  auto leftType = left.type();
  auto rightType = right.type();

  StructuralBehavior leftBehavior = leftType.getStructuralBehavior();
  StructuralBehavior rightBehavior = rightType.getStructuralBehavior();

  // Handle captures
  if (kind == wkPatternMatch) {
    if (rightType == PatMatCapture::type()) {
      doCapture(vm, left, right);
      return OpResult::proceed();
    } else if (rightType == PatMatConjunction::type()) {
      doConjunction(vm, left, right);
      return OpResult::proceed();
    } else if (rightType == PatMatOpenRecord::type()) {
      return doOpenRecord(vm, left, right);
    }
  }

  // One of them is a variable
  switch (kind) {
    case wkUnify: {
      if (leftBehavior == sbVariable) {
        if (rightBehavior == sbVariable) {
          if (leftType.getBindingPriority() > rightType.getBindingPriority())
            return DataflowVariable(left).bind(vm, right);
          else
            return DataflowVariable(right).bind(vm, left);
        } else {
          return DataflowVariable(left).bind(vm, right);
        }
      } else if (rightBehavior == sbVariable) {
        return DataflowVariable(right).bind(vm, left);
      }

      break;
    }

    case wkEquals:
    case wkPatternMatch: {
      if (leftBehavior == sbVariable) {
        assert(leftType.isTransient());
        return OpResult::waitFor(vm, left);
      } else if (rightBehavior == sbVariable) {
        assert(rightType.isTransient());
        return OpResult::waitFor(vm, right);
      }

      break;
    }
  }

  // If we reach this, both left and right are non-var
  if (leftType != rightType)
    return OpResult::fail();

  switch (leftBehavior) {
    case sbValue: {
      bool success = ValueEquatable(left).equals(vm, right);
      return success ? OpResult::proceed() : OpResult::fail();
    }

    case sbStructural: {
      bool success = StructuralEquatable(left).equals(vm, right, stack);
      if (success) {
        if (kind != wkPatternMatch)
          rebind(vm, left, right);
        return OpResult::proceed();
      } else {
        return OpResult::fail();
      }
    }

    case sbTokenEq: {
      assert(!left.isSameNode(right)); // this was tested earlier
      return OpResult::fail();
    }

    case sbVariable: {
      assert(false);
      return OpResult::fail();
    }
  }

  // We should not reach this point
  assert(false);
  return OpResult::proceed();
}

void StructuralDualWalk::rebind(VM vm, RichNode left, RichNode right) {
  rebindTrail.push_back(vm, left.makeBackup());
  left.reinit(vm, right);
}

void StructuralDualWalk::undoBindings(VM vm) {
  while (!rebindTrail.empty()) {
    rebindTrail.front().restore();
    rebindTrail.remove_front(vm);
  }
}

void StructuralDualWalk::doCapture(VM vm, RichNode value, RichNode capture) {
  nativeint index = capture.as<PatMatCapture>().index();

  if (index >= 0)
    captures[(size_t) index].copy(vm, value);
}

void StructuralDualWalk::doConjunction(VM vm, RichNode value,
                                       RichNode conjunction) {
  auto conj = conjunction.as<PatMatConjunction>();
  StableNode* stableValue = value.getStableRef(vm);

  for (size_t i = conj.getCount(); i > 0; i--)
    stack.push(vm, stableValue, conj.getElement(i-1));
}

OpResult StructuralDualWalk::doOpenRecord(VM vm, RichNode value,
                                          RichNode pattern) {
  bool boolResult = false;
  auto pat = pattern.as<PatMatOpenRecord>();
  auto arity = RichNode(*pat.getArity()).as<Arity>();

  // Check that the value is a record

  MOZART_CHECK_OPRESULT(RecordLike(value).isRecord(vm, boolResult));
  if (!boolResult)
    return OpResult::fail();

  // Check that the labels match

  UnstableNode recordLabel;
  MOZART_CHECK_OPRESULT(RecordLike(value).label(vm, recordLabel));

  MOZART_CHECK_OPRESULT(equals(vm, *arity.getLabel(), recordLabel, boolResult));
  if (!boolResult)
    return OpResult::fail();

  // Now iterate over the features of the pattern

  for (size_t i = 0; i < arity.getArraySize(); i++) {
    RichNode feature = *arity.getElement(i);

    MOZART_CHECK_OPRESULT(Dottable(value).hasFeature(vm, feature, boolResult));
    if (!boolResult)
      return OpResult::fail();

    UnstableNode lhsValue;
    MOZART_CHECK_OPRESULT(Dottable(value).dot(vm, feature, lhsValue));
    StableNode* rhsValue = pat.getElement(i);

    stack.push(vm, RichNode(lhsValue).getStableRef(vm), rhsValue);
  }

  return OpResult::proceed();
}

}
<commit_msg>Fixed: unify must mark the waitees as needed.<commit_after>// Copyright © 2012, Université catholique de Louvain
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// *  Redistributions of source code must retain the above copyright notice,
//    this list of conditions and the following disclaimer.
// *  Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

#include "mozart.hh"

namespace mozart {

struct SuspendTrailEntry {
  SuspendTrailEntry(StableNode* left, StableNode* right) :
    left(left), right(right) {}

  StableNode* left;
  StableNode* right;
};

typedef VMAllocatedList<SuspendTrailEntry> SuspendTrail;

typedef VMAllocatedList<NodeBackup> RebindTrail;

struct StructuralDualWalk {
public:
  enum Kind {
    wkUnify, wkEquals, wkPatternMatch
  };
public:
  StructuralDualWalk(VM vm, Kind kind,
                     StaticArray<UnstableNode> captures = nullptr):
    vm(vm), kind(kind), captures(captures) {}

  OpResult run(RichNode left, RichNode right);
private:
  inline
  OpResult processPair(VM vm, RichNode left, RichNode right);

  inline
  void rebind(VM vm, RichNode left, RichNode right);

  inline
  void undoBindings(VM vm);

  inline
  void doCapture(VM vm, RichNode value, RichNode capture);

  inline
  void doConjunction(VM vm, RichNode value, RichNode conjunction);

  inline
  OpResult doOpenRecord(VM vm, RichNode value, RichNode pattern);

  VM vm;
  Kind kind;

  WalkStack stack;
  RebindTrail rebindTrail;
  SuspendTrail suspendTrail;

  StaticArray<UnstableNode> captures;
};

/////////////////
// Entry point //
/////////////////

OpResult fullUnify(VM vm, RichNode left, RichNode right) {
  StructuralDualWalk walk(vm, StructuralDualWalk::wkUnify);
  return walk.run(left, right);
}

OpResult fullEquals(VM vm, RichNode left, RichNode right, bool& result) {
  StructuralDualWalk walk(vm, StructuralDualWalk::wkEquals);
  return walk.run(left, right).mapProceedFailToTrueFalse(result);
}

OpResult fullPatternMatch(VM vm, RichNode value, RichNode pattern,
                          StaticArray<UnstableNode> captures, bool& result) {
  StructuralDualWalk walk(vm, StructuralDualWalk::wkPatternMatch, captures);
  return walk.run(value, pattern).mapProceedFailToTrueFalse(result);
}

////////////////////
// The real thing //
////////////////////

OpResult StructuralDualWalk::run(RichNode left, RichNode right) {
  VM vm = this->vm;

  while (true) {
    // Process the pair
    OpResult pairResult = processPair(vm, left, right);

    switch (pairResult.kind()) {
      case OpResult::orFail:
      case OpResult::orRaise: {
        stack.clear(vm);
        suspendTrail.clear(vm);
        undoBindings(vm);
        return pairResult;
      }

      case OpResult::orWaitBefore:
      case OpResult::orWaitQuietBefore: {
        if (!RichNode(*pairResult.getWaiteeNode()).is<FailedValue>()) {
          // TODO Do we need to actually support the *quiet* here?
          suspendTrail.push_back_new(vm, left.getStableRef(vm),
                                     right.getStableRef(vm));
          break;
        } else {
          stack.clear(vm);
          suspendTrail.clear(vm);
          undoBindings(vm);
          return pairResult;
        }
      }

      case OpResult::orProceed: {
        // nothing to do
      }
    }

    // Finished?
    if (stack.empty())
      break;

    // Pop next pair
    left = *stack.front().left;
    right = *stack.front().right;

    // Go to next item
    stack.remove_front(vm);
  }

  // Do we need to suspend on something?
  if (!suspendTrail.empty()) {
    // Undo temporary bindings

    undoBindings(vm);

    // Create the control variable

    UnstableNode unstableControlVar = Variable::build(vm);
    RichNode controlVar = unstableControlVar;
    controlVar.ensureStable(vm);

    // Reduce the remaining unifications
    size_t count = suspendTrail.size();

    if (count == 1) {
      left = *suspendTrail.front().left;
      right = *suspendTrail.front().right;

      if (left.isTransient()) {
        DataflowVariable(left).markNeeded(vm);
        DataflowVariable(left).addToSuspendList(vm, controlVar);
      }

      if (right.isTransient()) {
        DataflowVariable(right).markNeeded(vm);
        DataflowVariable(right).addToSuspendList(vm, controlVar);
      }
    } else {
      UnstableNode label = Atom::build(vm, vm->coreatoms.pipe);

      UnstableNode unstableLeft = Tuple::build(vm, count, label);
      UnstableNode unstableRight = Tuple::build(vm, count, label);

      auto leftTuple = RichNode(unstableLeft).as<Tuple>();
      auto rightTuple = RichNode(unstableRight).as<Tuple>();

      size_t i = 0;
      for (auto iter = suspendTrail.begin();
           iter != suspendTrail.end(); i++, ++iter) {
        UnstableNode leftTemp(vm, *iter->left);
        leftTuple.initElement(vm, i, leftTemp);

        RichNode richLeftTemp = leftTemp;
        if (richLeftTemp.isTransient()) {
          DataflowVariable(richLeftTemp).markNeeded(vm);
          DataflowVariable(richLeftTemp).addToSuspendList(vm, controlVar);
        }

        UnstableNode rightTemp(vm, *iter->right);
        rightTuple.initElement(vm, i, rightTemp);

        RichNode richRightTemp = rightTemp;
        if (richRightTemp.isTransient()) {
          DataflowVariable(richRightTemp).markNeeded(vm);
          DataflowVariable(richRightTemp).addToSuspendList(vm, controlVar);
        }
      }
    }

    suspendTrail.clear(vm);

    // TODO Replace initial operands by unstableLeft and unstableRight

    return OpResult::waitFor(vm, controlVar);
  }

  /* No need to undo temporary bindings here, even if we are in wkEquals mode.
   * In fact, we should not undo them in that case, as that compactifies
   * the store, and speeds up subsequent tests and/or unifications.
   *
   * However, the above is *wrong* when in a subspace, because of speculative
   * bindings.
   *
   * The above would also be *wrong* when in wkPatternMatch mode. But in that
   * mode we do not perform temporary bindings in the first place.
   */
  if (!vm->isOnTopLevel())
    undoBindings(vm);

  return OpResult::proceed();
}

OpResult StructuralDualWalk::processPair(VM vm, RichNode left,
                                         RichNode right) {
  // Identical nodes
  if (left.isSameNode(right))
    return OpResult::proceed();

  auto leftType = left.type();
  auto rightType = right.type();

  StructuralBehavior leftBehavior = leftType.getStructuralBehavior();
  StructuralBehavior rightBehavior = rightType.getStructuralBehavior();

  // Handle captures
  if (kind == wkPatternMatch) {
    if (rightType == PatMatCapture::type()) {
      doCapture(vm, left, right);
      return OpResult::proceed();
    } else if (rightType == PatMatConjunction::type()) {
      doConjunction(vm, left, right);
      return OpResult::proceed();
    } else if (rightType == PatMatOpenRecord::type()) {
      return doOpenRecord(vm, left, right);
    }
  }

  // One of them is a variable
  switch (kind) {
    case wkUnify: {
      if (leftBehavior == sbVariable) {
        if (rightBehavior == sbVariable) {
          if (leftType.getBindingPriority() > rightType.getBindingPriority())
            return DataflowVariable(left).bind(vm, right);
          else
            return DataflowVariable(right).bind(vm, left);
        } else {
          return DataflowVariable(left).bind(vm, right);
        }
      } else if (rightBehavior == sbVariable) {
        return DataflowVariable(right).bind(vm, left);
      }

      break;
    }

    case wkEquals:
    case wkPatternMatch: {
      if (leftBehavior == sbVariable) {
        assert(leftType.isTransient());
        return OpResult::waitFor(vm, left);
      } else if (rightBehavior == sbVariable) {
        assert(rightType.isTransient());
        return OpResult::waitFor(vm, right);
      }

      break;
    }
  }

  // If we reach this, both left and right are non-var
  if (leftType != rightType)
    return OpResult::fail();

  switch (leftBehavior) {
    case sbValue: {
      bool success = ValueEquatable(left).equals(vm, right);
      return success ? OpResult::proceed() : OpResult::fail();
    }

    case sbStructural: {
      bool success = StructuralEquatable(left).equals(vm, right, stack);
      if (success) {
        if (kind != wkPatternMatch)
          rebind(vm, left, right);
        return OpResult::proceed();
      } else {
        return OpResult::fail();
      }
    }

    case sbTokenEq: {
      assert(!left.isSameNode(right)); // this was tested earlier
      return OpResult::fail();
    }

    case sbVariable: {
      assert(false);
      return OpResult::fail();
    }
  }

  // We should not reach this point
  assert(false);
  return OpResult::proceed();
}

void StructuralDualWalk::rebind(VM vm, RichNode left, RichNode right) {
  rebindTrail.push_back(vm, left.makeBackup());
  left.reinit(vm, right);
}

void StructuralDualWalk::undoBindings(VM vm) {
  while (!rebindTrail.empty()) {
    rebindTrail.front().restore();
    rebindTrail.remove_front(vm);
  }
}

void StructuralDualWalk::doCapture(VM vm, RichNode value, RichNode capture) {
  nativeint index = capture.as<PatMatCapture>().index();

  if (index >= 0)
    captures[(size_t) index].copy(vm, value);
}

void StructuralDualWalk::doConjunction(VM vm, RichNode value,
                                       RichNode conjunction) {
  auto conj = conjunction.as<PatMatConjunction>();
  StableNode* stableValue = value.getStableRef(vm);

  for (size_t i = conj.getCount(); i > 0; i--)
    stack.push(vm, stableValue, conj.getElement(i-1));
}

OpResult StructuralDualWalk::doOpenRecord(VM vm, RichNode value,
                                          RichNode pattern) {
  bool boolResult = false;
  auto pat = pattern.as<PatMatOpenRecord>();
  auto arity = RichNode(*pat.getArity()).as<Arity>();

  // Check that the value is a record

  MOZART_CHECK_OPRESULT(RecordLike(value).isRecord(vm, boolResult));
  if (!boolResult)
    return OpResult::fail();

  // Check that the labels match

  UnstableNode recordLabel;
  MOZART_CHECK_OPRESULT(RecordLike(value).label(vm, recordLabel));

  MOZART_CHECK_OPRESULT(equals(vm, *arity.getLabel(), recordLabel, boolResult));
  if (!boolResult)
    return OpResult::fail();

  // Now iterate over the features of the pattern

  for (size_t i = 0; i < arity.getArraySize(); i++) {
    RichNode feature = *arity.getElement(i);

    MOZART_CHECK_OPRESULT(Dottable(value).hasFeature(vm, feature, boolResult));
    if (!boolResult)
      return OpResult::fail();

    UnstableNode lhsValue;
    MOZART_CHECK_OPRESULT(Dottable(value).dot(vm, feature, lhsValue));
    StableNode* rhsValue = pat.getElement(i);

    stack.push(vm, RichNode(lhsValue).getStableRef(vm), rhsValue);
  }

  return OpResult::proceed();
}

}
<|endoftext|>


<commit_before>/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at LICENSE-CDDL
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at LICENSE-CDDL.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright (c) 2013, OmniTI Computer Consulting, Inc. All rights reserved.
 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
 * Copyright (c) 1995, Theo Schlossnagle. All rights reserved.
 * Copyright (c) 1990  Mentat Inc.
 */

#include "ife.h"
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <inet/mib2.h>
#include <sys/stream.h>
#include <stropts.h>
#include <sys/strstat.h>
#include <sys/tihdr.h>

static int arpcache_psize = 0;
static arp_entry *arpcache_private = NULL;

const unsigned char ff_ff_ff_ff_ff_ff[ETH_ALEN] =
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };

#define ROUNDUP(a) \
        ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))

int sample_arp_cache(arp_entry **l) {
  int s=-1, getcode, flags, count = 0;
  char buf[512], *dbuf = NULL;
  struct opthdr *req;
  struct strbuf ctlbuf, databuf;
  struct T_optmgmt_req *tor = (struct T_optmgmt_req *)buf;
  struct T_optmgmt_ack *toa = (struct T_optmgmt_ack *)buf;
  struct T_error_ack *tea = (struct T_error_ack *)buf;
  mib2_ipNetToMediaEntry_t *np;
  mib2_ip_t *ip = NULL;

  if(l) *l = NULL;
  if(!arpcache_private) {
    arpcache_psize = 2;
    arpcache_private = (arp_entry *)calloc(sizeof(*arpcache_private), arpcache_psize);
    arpcache_private[0].ipaddr.s_addr = 0;
  }
  if(s < 0) {
    if((s = open("/dev/arp", O_RDWR)) < 0) {
      return -1;
    }
    if(ioctl(s, I_PUSH, "tcp") ||
       ioctl(s, I_PUSH, "udp") ||
       ioctl(s, I_PUSH, "icmp") )
      goto error;
  }

  tor->PRIM_type = T_SVR4_OPTMGMT_REQ;
  tor->OPT_offset = sizeof (struct T_optmgmt_req);
  tor->OPT_length = sizeof (struct opthdr);
  tor->MGMT_flags = T_CURRENT;

  req = (struct opthdr *)&tor[1];
  req->level = EXPER_IP_AND_ALL_IRES;
  req->name  = 0;
  req->len   = 1;

  ctlbuf.buf = (char *)buf;
  ctlbuf.len = tor->OPT_length + tor->OPT_offset;
  flags = 0;
  if (putmsg(s, &ctlbuf, (struct strbuf *)0, flags) == -1) goto error;

  req = (struct opthdr *)&toa[1];
  ctlbuf.maxlen = sizeof (buf);
  for (;;) {
    flags = 0;
    getcode = getmsg(s, &ctlbuf, (struct strbuf *)0, &flags);
    if (getcode == -1) goto error;
    if (getcode == 0 &&
        ctlbuf.len >= (int)sizeof (struct T_optmgmt_ack) &&
        toa->PRIM_type == T_OPTMGMT_ACK &&
        toa->MGMT_flags == T_SUCCESS &&
        req->len == 0)  {
      break; /* ?? */
    }
    if (ctlbuf.len >= (int)sizeof (struct T_error_ack) &&
        tea->PRIM_type == T_ERROR_ACK) {
      goto error;
    }
    if (getcode != MOREDATA ||
        ctlbuf.len < (int)sizeof (struct T_optmgmt_ack) ||
        toa->PRIM_type != T_OPTMGMT_ACK ||
        toa->MGMT_flags != T_SUCCESS) {
      goto error;
    }

    dbuf = (char *)malloc(req->len);
    if(dbuf == NULL) goto error;
    databuf.maxlen = req->len;
    databuf.buf    = (char *)dbuf;
    databuf.len    = 0;
    flags = 0;
    getcode = getmsg(s, (struct strbuf *)0, &databuf, &flags);
    if(getcode != 0) goto error;

    if(req->level == MIB2_IP && req->name == 0) {
      ip = (mib2_ip_t *)dbuf;
    }
    if(ip && req->level == MIB2_IP && req->name == MIB2_IP_MEDIA) {
      for(np = (mib2_ipNetToMediaEntry_t *)dbuf;
          (char *)np < (char *)dbuf + databuf.len;
          np = (mib2_ipNetToMediaEntry_t *)((char *)np + ip->ipNetToMediaEntrySize)) {
        if(count >= arpcache_psize) {
          arpcache_psize <<= 1;
          arpcache_private = (arp_entry *)realloc(arpcache_private, sizeof(arp_entry)*(arpcache_psize+1));
        }
        if(np->ipNetToMediaPhysAddress.o_length == ETH_ALEN) {
          arpcache_private[count].ipaddr.s_addr = np->ipNetToMediaNetAddress;
          memcpy(arpcache_private[count].mac, np->ipNetToMediaPhysAddress.o_bytes, ETH_ALEN);
          count++;
        }
      }
    }
    free(dbuf);
    dbuf = NULL;
  }
  if(l) *l = arpcache_private;
  close(s);
  return count;
 error:
  if(dbuf) free(dbuf);
  close(s);
  return -1;
}
<commit_msg>prevent an infinite loop when the ip->ipNetToMediaEntrySize is 0<commit_after>/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at LICENSE-CDDL
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at LICENSE-CDDL.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright (c) 2013, OmniTI Computer Consulting, Inc. All rights reserved.
 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
 * Copyright (c) 1995, Theo Schlossnagle. All rights reserved.
 * Copyright (c) 1990  Mentat Inc.
 */

#include "ife.h"
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <inet/mib2.h>
#include <sys/stream.h>
#include <stropts.h>
#include <sys/strstat.h>
#include <sys/tihdr.h>

static int arpcache_psize = 0;
static arp_entry *arpcache_private = NULL;

const unsigned char ff_ff_ff_ff_ff_ff[ETH_ALEN] =
    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };

#define ROUNDUP(a) \
        ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))

int sample_arp_cache(arp_entry **l) {
  int s=-1, getcode, flags, count = 0;
  char buf[512], *dbuf = NULL;
  struct opthdr *req;
  struct strbuf ctlbuf, databuf;
  struct T_optmgmt_req *tor = (struct T_optmgmt_req *)buf;
  struct T_optmgmt_ack *toa = (struct T_optmgmt_ack *)buf;
  struct T_error_ack *tea = (struct T_error_ack *)buf;
  mib2_ipNetToMediaEntry_t *np;
  mib2_ip_t *ip = NULL;

  if(l) *l = NULL;
  if(!arpcache_private) {
    arpcache_psize = 2;
    arpcache_private = (arp_entry *)calloc(sizeof(*arpcache_private), arpcache_psize);
    arpcache_private[0].ipaddr.s_addr = 0;
  }
  if(s < 0) {
    if((s = open("/dev/arp", O_RDWR)) < 0) {
      return -1;
    }
    if(ioctl(s, I_PUSH, "tcp") ||
       ioctl(s, I_PUSH, "udp") ||
       ioctl(s, I_PUSH, "icmp") )
      goto error;
  }

  tor->PRIM_type = T_SVR4_OPTMGMT_REQ;
  tor->OPT_offset = sizeof (struct T_optmgmt_req);
  tor->OPT_length = sizeof (struct opthdr);
  tor->MGMT_flags = T_CURRENT;

  req = (struct opthdr *)&tor[1];
  req->level = EXPER_IP_AND_ALL_IRES;
  req->name  = 0;
  req->len   = 1;

  ctlbuf.buf = (char *)buf;
  ctlbuf.len = tor->OPT_length + tor->OPT_offset;
  flags = 0;
  if (putmsg(s, &ctlbuf, (struct strbuf *)0, flags) == -1) goto error;

  req = (struct opthdr *)&toa[1];
  ctlbuf.maxlen = sizeof (buf);
  for (;;) {
    flags = 0;
    getcode = getmsg(s, &ctlbuf, (struct strbuf *)0, &flags);
    if (getcode == -1) goto error;
    if (getcode == 0 &&
        ctlbuf.len >= (int)sizeof (struct T_optmgmt_ack) &&
        toa->PRIM_type == T_OPTMGMT_ACK &&
        toa->MGMT_flags == T_SUCCESS &&
        req->len == 0)  {
      break; /* ?? */
    }
    if (ctlbuf.len >= (int)sizeof (struct T_error_ack) &&
        tea->PRIM_type == T_ERROR_ACK) {
      goto error;
    }
    if (getcode != MOREDATA ||
        ctlbuf.len < (int)sizeof (struct T_optmgmt_ack) ||
        toa->PRIM_type != T_OPTMGMT_ACK ||
        toa->MGMT_flags != T_SUCCESS) {
      goto error;
    }

    dbuf = (char *)malloc(req->len);
    if(dbuf == NULL) goto error;
    databuf.maxlen = req->len;
    databuf.buf    = (char *)dbuf;
    databuf.len    = 0;
    flags = 0;
    getcode = getmsg(s, (struct strbuf *)0, &databuf, &flags);
    if(getcode != 0) goto error;

    if(req->level == MIB2_IP && req->name == 0) {
      ip = (mib2_ip_t *)dbuf;
    }
    if(ip && req->level == MIB2_IP && req->name == MIB2_IP_MEDIA) {
      for(np = (mib2_ipNetToMediaEntry_t *)dbuf;
          (char *)np < (char *)dbuf + databuf.len;
          np = (mib2_ipNetToMediaEntry_t *)((char *)np + ip->ipNetToMediaEntrySize)) {
        if(ip->ipNetToMediaEntrySize == 0) break;
        if(count >= arpcache_psize) {
          arpcache_psize <<= 1;
          arpcache_private = (arp_entry *)realloc(arpcache_private, sizeof(arp_entry)*(arpcache_psize+1));
        }
        if(np->ipNetToMediaPhysAddress.o_length == ETH_ALEN) {
          arpcache_private[count].ipaddr.s_addr = np->ipNetToMediaNetAddress;
          memcpy(arpcache_private[count].mac, np->ipNetToMediaPhysAddress.o_bytes, ETH_ALEN);
          count++;
        }
      }
    }
    free(dbuf);
    dbuf = NULL;
  }
  if(l) *l = arpcache_private;
  close(s);
  return count;
 error:
  if(dbuf) free(dbuf);
  close(s);
  return -1;
}
<|endoftext|>