<commit_before>/*
 *  Copyright 2008 Adrian Thurston <thurston@complang.org>
 */

/*  This file is part of Ragel.
 *
 *  Ragel 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 2 of the License, or
 *  (at your option) any later version.
 *
 *  Ragel is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with Ragel; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "ragel.h"
#include "common.h"
#include "inputdata.h"
#include "parsedata.h"
#include "load.h"
#include "rlscan.h"

#include <iostream>
#include <unistd.h>

using std::istream;
using std::ifstream;
using std::ostream;
using std::cout;
using std::cerr;
using std::endl;
using std::ios;

/* Invoked by the parser when the root element is opened. */
void InputData::cdDefaultFileName( const char *inputFile )
{
	/* If the output format is code and no output file name is given, then
	 * make a default. */
	if ( outputFileName == 0 ) {
		const char *ext = findFileExtension( inputFile );
		if ( ext != 0 && strcmp( ext, ".rh" ) == 0 )
			outputFileName = fileNameFromStem( inputFile, ".h" );
		else {
			const char *defExtension = 0;
			switch ( hostLang->lang ) {
				case HostLang::C: defExtension = ".c"; break;
				case HostLang::D: defExtension = ".d"; break;
				default: break;
			}
			outputFileName = fileNameFromStem( inputFile, defExtension );
		}
	}
}

/* Invoked by the parser when the root element is opened. */
void InputData::goDefaultFileName( const char *inputFile )
{
	/* If the output format is code and no output file name is given, then
	 * make a default. */
	if ( outputFileName == 0 )
		outputFileName = fileNameFromStem( inputFile, ".go" );
}

/* Invoked by the parser when the root element is opened. */
void InputData::javaDefaultFileName( const char *inputFile )
{
	/* If the output format is code and no output file name is given, then
	 * make a default. */
	if ( outputFileName == 0 )
		outputFileName = fileNameFromStem( inputFile, ".java" );
}

/* Invoked by the parser when the root element is opened. */
void InputData::rubyDefaultFileName( const char *inputFile )
{
	/* If the output format is code and no output file name is given, then
	 * make a default. */
	if ( outputFileName == 0 )
		outputFileName = fileNameFromStem( inputFile, ".rb" );
}

/* Invoked by the parser when the root element is opened. */
void InputData::csharpDefaultFileName( const char *inputFile )
{
	/* If the output format is code and no output file name is given, then
	 * make a default. */
	if ( outputFileName == 0 ) {
		const char *ext = findFileExtension( inputFile );
		if ( ext != 0 && strcmp( ext, ".rh" ) == 0 )
			outputFileName = fileNameFromStem( inputFile, ".h" );
		else
			outputFileName = fileNameFromStem( inputFile, ".cs" );
	}
}

/* Invoked by the parser when the root element is opened. */
void InputData::ocamlDefaultFileName( const char *inputFile )
{
	/* If the output format is code and no output file name is given, then
	 * make a default. */
	if ( outputFileName == 0 )
		outputFileName = fileNameFromStem( inputFile, ".ml" );
}

/* Invoked by the parser when the root element is opened. */
void InputData::crackDefaultFileName( const char *inputFile )
{
	/* If the output format is code and no output file name is given, then
	 * make a default. */
	if ( outputFileName == 0 )
		outputFileName = fileNameFromStem( inputFile, ".crk" );
}

void InputData::asmDefaultFileName( const char *inputFile )
{
    if ( outputFileName == 0 )
        outputFileName = fileNameFromStem( inputFile, ".s" );
}

void InputData::makeDefaultFileName()
{
	switch ( hostLang->lang ) {
		case HostLang::C:
		case HostLang::D:
			cdDefaultFileName( inputFileName );
			break;
		case HostLang::Java:
			javaDefaultFileName( inputFileName );
			break;
		case HostLang::Go:
			goDefaultFileName( inputFileName );
			break;
		case HostLang::Ruby:
			rubyDefaultFileName( inputFileName );
			break;
		case HostLang::CSharp:
			csharpDefaultFileName( inputFileName );
			break;
		case HostLang::OCaml:
			ocamlDefaultFileName( inputFileName );
			break;
		case HostLang::Crack:
			crackDefaultFileName( inputFileName );
			break;
		case HostLang::Asm:
			asmDefaultFileName( inputFileName );
			break;
	}
}

void InputData::makeOutputStream()
{
	/* Make sure we are not writing to the same file as the input file. */
	if ( outputFileName != 0 ) {
		if ( strcmp( inputFileName, outputFileName  ) == 0 ) {
			error() << "output file \"" << outputFileName  <<
					"\" is the same as the input file" << endl;
		}

		/* Create the filter on the output and open it. */
		outFilter = new output_filter( outputFileName );

		/* Open the output stream, attaching it to the filter. */
		outStream = new ostream( outFilter );
	}
	else {
		/* Writing out ot std out. */
		outStream = &cout;
	}
}

void InputData::openOutput()
{
	if ( outFilter != 0 ) {
		outFilter->open( outputFileName, ios::out|ios::trunc );
		if ( !outFilter->is_open() ) {
			error() << "error opening " << outputFileName << " for writing" << endl;
			exit(1);
		}
	}
}

void InputData::prepareSingleMachine()
{
	/* Locate a machine spec to generate dot output for. We can only emit.
	 * Dot takes one graph at a time. */
	if ( machineSpec != 0 ) {
		/* Machine specified. */
		ParserDictEl *pdEl = parserDict.find( machineSpec );
		if ( pdEl == 0 )
			error() << "could not locate machine specified with -S and/or -M" << endp;
		dotGenParser = pdEl->value;
	}
	else {
		/* No machine spec given, generate the first one. */
		if ( parserList.length() == 0 )
			error() << "no machine specification to generate graphviz output" << endp;

		dotGenParser = parserList.head;
	}

	GraphDictEl *gdEl = 0;

	if ( machineName != 0 ) {
		gdEl = dotGenParser->pd->graphDict.find( machineName );
		if ( gdEl == 0 )
			error() << "machine definition/instantiation not found" << endp;
	}
	else {
		/* We are using the whole machine spec. Need to make sure there
		 * are instances in the spec. */
		if ( dotGenParser->pd->instanceList.length() == 0 )
			error() << "no machine instantiations to generate graphviz output" << endp;
	}

	dotGenParser->pd->prepareMachineGen( gdEl, hostLang );
}

void InputData::prepareAllMachines()
{
	for ( ParseDataDict::Iter pdel = parseDataDict; pdel.lte(); pdel++ ) {
		ParseData *pd = pdel->value;
		if ( pd->instanceList.length() > 0 )
			pd->prepareMachineGen( 0, hostLang );
	}
}

void InputData::generateReduced()
{
	for ( ParseDataDict::Iter pdel = parseDataDict; pdel.lte(); pdel++ ) {
		ParseData *pd = pdel->value;
		if ( pd->instanceList.length() > 0 )
			pd->generateReduced( inputFileName, codeStyle, *outStream, hostLang );
	}
}

void InputData::verifyWritesHaveData()
{
	for ( InputItemList::Iter ii = inputItems; ii.lte(); ii++ ) {
		if ( ii->type == InputItem::Write ) {
			if ( ii->pd->cgd == 0 )
				error( ii->loc ) << "no machine instantiations to write" << endl;
		}
	}
}

void InputData::writeOutput()
{
	for ( InputItemList::Iter ii = inputItems; ii.lte(); ii++ ) {
		if ( ii->type == InputItem::Write ) {
			CodeGenData *cgd = ii->pd->cgd;
			cgd->writeStatement( ii->loc, ii->writeArgs.length(),
					ii->writeArgs.data, generateDot, hostLang );
		}
		else {
			switch ( backend ) {
				case Direct:
					*outStream << ii->data.str();
					break;
				case Translated:
					openHostBlock( '@', this, *outStream, inputFileName, ii->loc.line );
					*outStream << ii->data.str();
					*outStream << "}@";
					break;
			}
		}
	}
}

void InputData::closeOutput()
{
	/* If writing to a file, delete the ostream, causing it to flush.
	 * Standard out is flushed automatically. */
	if ( outputFileName != 0 ) {
		delete outStream;
		delete outFilter;
	}
}

void InputData::processXML()
{
	/* Compiles machines. */
	prepareAllMachines();

	if ( gblErrorCount > 0 )
		exit(1);

	makeOutputStream();

	if ( gblErrorCount > 0 )
		exit(1);

	/*
	 * From this point on we should not be reporting any errors.
	 */

	openOutput();
	writeXML( *outStream );
	closeOutput();
}

void InputData::processDot()
{
	/* Compiles the DOT machines. */
	prepareSingleMachine();

	if ( gblErrorCount > 0 )
		exit(1);

	makeOutputStream();

	if ( gblErrorCount > 0 )
		exit(1);

	/*
	 * From this point on we should not be reporting any errors.
	 */

	openOutput();
	writeDot( *outStream );
	closeOutput();
}

void InputData::processCode()
{
	/* Compiles machines. */
	prepareAllMachines();

	if ( gblErrorCount > 0 )
		exit(1);

	makeDefaultFileName();

	if ( backend == Translated ) {
		origOutputFileName = outputFileName;
		genOutputFileName = fileNameFromStem( inputFileName, ".ri" );
		outputFileName = genOutputFileName.c_str();
	}

	makeOutputStream();

	/* Generates the reduced machine, which we use to write output. */
	generateReduced();

	if ( gblErrorCount > 0 )
		exit(1);

	verifyWritesHaveData();

	if ( gblErrorCount > 0 )
		exit(1);

	/*
	 * From this point on we should not be reporting any errors.
	 */

	openOutput();
	writeOutput();
	closeOutput();

	if ( backend == Translated ) {
#ifdef WITH_COLM
		if ( !noIntermediate ) {
			string rlhc = dirName + "/rlhc " +
					origOutputFileName + " " +
					genOutputFileName + " " +
					hostLang->rlhcArg;

			if ( rlhcShowCmd )
				std::cout << rlhc << std::endl;

			int res = system( rlhc.c_str() );
			if ( res != 0 )
				exit( 1 );

			if ( !saveTemps )
				unlink( genOutputFileName.c_str() );
		}
#else
		error() << "colm-based codegen not available" << endp;
#endif
	}
}

void InputData::makeFirstInputItem()
{
	/* Make the first input item. */
	InputItem *firstInputItem = new InputItem;
	firstInputItem->type = InputItem::HostData;
	firstInputItem->loc.fileName = inputFileName;
	firstInputItem->loc.line = 1;
	firstInputItem->loc.col = 1;
	inputItems.append( firstInputItem );
}

/* Send eof to all parsers. */
void InputData::terminateAllParsers( )
{
	/* FIXME: a proper token is needed here. Suppose we should use the
	 * location of EOF in the last file that the parser was referenced in. */
	InputLoc loc;
	loc.fileName = "<EOF>";
	loc.line = 0;
	loc.col = 0;
	for ( ParserDict::Iter pdel = parserDict; pdel.lte(); pdel++ )
		pdel->value->token( loc, Parser6_tk_eof, 0, 0 );
}

void InputData::process()
{
	ifstream *inFile;

	switch ( frontend ) {
		case KelbtBased: {
			/*
			 * Ragel Parser from ragel 6.
			 */

			/* Open the input file for reading. */
			assert( inputFileName != 0 );
			inFile = new ifstream( inputFileName );
			if ( ! inFile->is_open() )
				error() << "could not open " << inputFileName << " for reading" << endp;

			/* Used for just a few things. */
			std::ostringstream hostData;

			/* Make the first input item. */
			InputItem *firstInputItem = new InputItem;
			firstInputItem->type = InputItem::HostData;
			firstInputItem->loc.fileName = inputFileName;
			firstInputItem->loc.line = 1;
			firstInputItem->loc.col = 1;
			inputItems.append( firstInputItem );

			Scanner scanner( *this, inputFileName, *inFile, 0, 0, 0, false );
			scanner.do_scan();

			/* Finished, final check for errors.. */
			if ( gblErrorCount > 0 )
				exit(1);

			/* Now send EOF to all parsers. */
			terminateAllParsers();
			break;
		}
		case ColmBased: {
			std::cout << "colm frontend" << std::endl;
#ifdef WITH_COLM
			/*
			 * Ragel parser introduced in ragel 7. Uses more memory.
			 */

			/* Check input file. */
			inFile = new ifstream( inputFileName );
			if ( ! inFile->is_open() )
				error() << "could not open " << inputFileName << " for reading" << endp;
			delete inFile;

			makeFirstInputItem();

			LoadRagel *lr = newLoadRagel( *this, hostLang, minimizeLevel, minimizeOpt );
			loadRagel( lr, inputFileName );
			deleteLoadRagel( lr );
#endif
			break;
		}
	}

	/* Bail on above error. */
	if ( gblErrorCount > 0 )
		exit(1);

	if ( generateXML )
		processXML();
	else if ( generateDot )
		processDot();
	else
		processCode();

	assert( gblErrorCount == 0 );
}

<commit_msg>removed colm-frontend message<commit_after>/*
 *  Copyright 2008 Adrian Thurston <thurston@complang.org>
 */

/*  This file is part of Ragel.
 *
 *  Ragel 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 2 of the License, or
 *  (at your option) any later version.
 *
 *  Ragel is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with Ragel; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include "ragel.h"
#include "common.h"
#include "inputdata.h"
#include "parsedata.h"
#include "load.h"
#include "rlscan.h"

#include <iostream>
#include <unistd.h>

using std::istream;
using std::ifstream;
using std::ostream;
using std::cout;
using std::cerr;
using std::endl;
using std::ios;

/* Invoked by the parser when the root element is opened. */
void InputData::cdDefaultFileName( const char *inputFile )
{
	/* If the output format is code and no output file name is given, then
	 * make a default. */
	if ( outputFileName == 0 ) {
		const char *ext = findFileExtension( inputFile );
		if ( ext != 0 && strcmp( ext, ".rh" ) == 0 )
			outputFileName = fileNameFromStem( inputFile, ".h" );
		else {
			const char *defExtension = 0;
			switch ( hostLang->lang ) {
				case HostLang::C: defExtension = ".c"; break;
				case HostLang::D: defExtension = ".d"; break;
				default: break;
			}
			outputFileName = fileNameFromStem( inputFile, defExtension );
		}
	}
}

/* Invoked by the parser when the root element is opened. */
void InputData::goDefaultFileName( const char *inputFile )
{
	/* If the output format is code and no output file name is given, then
	 * make a default. */
	if ( outputFileName == 0 )
		outputFileName = fileNameFromStem( inputFile, ".go" );
}

/* Invoked by the parser when the root element is opened. */
void InputData::javaDefaultFileName( const char *inputFile )
{
	/* If the output format is code and no output file name is given, then
	 * make a default. */
	if ( outputFileName == 0 )
		outputFileName = fileNameFromStem( inputFile, ".java" );
}

/* Invoked by the parser when the root element is opened. */
void InputData::rubyDefaultFileName( const char *inputFile )
{
	/* If the output format is code and no output file name is given, then
	 * make a default. */
	if ( outputFileName == 0 )
		outputFileName = fileNameFromStem( inputFile, ".rb" );
}

/* Invoked by the parser when the root element is opened. */
void InputData::csharpDefaultFileName( const char *inputFile )
{
	/* If the output format is code and no output file name is given, then
	 * make a default. */
	if ( outputFileName == 0 ) {
		const char *ext = findFileExtension( inputFile );
		if ( ext != 0 && strcmp( ext, ".rh" ) == 0 )
			outputFileName = fileNameFromStem( inputFile, ".h" );
		else
			outputFileName = fileNameFromStem( inputFile, ".cs" );
	}
}

/* Invoked by the parser when the root element is opened. */
void InputData::ocamlDefaultFileName( const char *inputFile )
{
	/* If the output format is code and no output file name is given, then
	 * make a default. */
	if ( outputFileName == 0 )
		outputFileName = fileNameFromStem( inputFile, ".ml" );
}

/* Invoked by the parser when the root element is opened. */
void InputData::crackDefaultFileName( const char *inputFile )
{
	/* If the output format is code and no output file name is given, then
	 * make a default. */
	if ( outputFileName == 0 )
		outputFileName = fileNameFromStem( inputFile, ".crk" );
}

void InputData::asmDefaultFileName( const char *inputFile )
{
    if ( outputFileName == 0 )
        outputFileName = fileNameFromStem( inputFile, ".s" );
}

void InputData::makeDefaultFileName()
{
	switch ( hostLang->lang ) {
		case HostLang::C:
		case HostLang::D:
			cdDefaultFileName( inputFileName );
			break;
		case HostLang::Java:
			javaDefaultFileName( inputFileName );
			break;
		case HostLang::Go:
			goDefaultFileName( inputFileName );
			break;
		case HostLang::Ruby:
			rubyDefaultFileName( inputFileName );
			break;
		case HostLang::CSharp:
			csharpDefaultFileName( inputFileName );
			break;
		case HostLang::OCaml:
			ocamlDefaultFileName( inputFileName );
			break;
		case HostLang::Crack:
			crackDefaultFileName( inputFileName );
			break;
		case HostLang::Asm:
			asmDefaultFileName( inputFileName );
			break;
	}
}

void InputData::makeOutputStream()
{
	/* Make sure we are not writing to the same file as the input file. */
	if ( outputFileName != 0 ) {
		if ( strcmp( inputFileName, outputFileName  ) == 0 ) {
			error() << "output file \"" << outputFileName  <<
					"\" is the same as the input file" << endl;
		}

		/* Create the filter on the output and open it. */
		outFilter = new output_filter( outputFileName );

		/* Open the output stream, attaching it to the filter. */
		outStream = new ostream( outFilter );
	}
	else {
		/* Writing out ot std out. */
		outStream = &cout;
	}
}

void InputData::openOutput()
{
	if ( outFilter != 0 ) {
		outFilter->open( outputFileName, ios::out|ios::trunc );
		if ( !outFilter->is_open() ) {
			error() << "error opening " << outputFileName << " for writing" << endl;
			exit(1);
		}
	}
}

void InputData::prepareSingleMachine()
{
	/* Locate a machine spec to generate dot output for. We can only emit.
	 * Dot takes one graph at a time. */
	if ( machineSpec != 0 ) {
		/* Machine specified. */
		ParserDictEl *pdEl = parserDict.find( machineSpec );
		if ( pdEl == 0 )
			error() << "could not locate machine specified with -S and/or -M" << endp;
		dotGenParser = pdEl->value;
	}
	else {
		/* No machine spec given, generate the first one. */
		if ( parserList.length() == 0 )
			error() << "no machine specification to generate graphviz output" << endp;

		dotGenParser = parserList.head;
	}

	GraphDictEl *gdEl = 0;

	if ( machineName != 0 ) {
		gdEl = dotGenParser->pd->graphDict.find( machineName );
		if ( gdEl == 0 )
			error() << "machine definition/instantiation not found" << endp;
	}
	else {
		/* We are using the whole machine spec. Need to make sure there
		 * are instances in the spec. */
		if ( dotGenParser->pd->instanceList.length() == 0 )
			error() << "no machine instantiations to generate graphviz output" << endp;
	}

	dotGenParser->pd->prepareMachineGen( gdEl, hostLang );
}

void InputData::prepareAllMachines()
{
	for ( ParseDataDict::Iter pdel = parseDataDict; pdel.lte(); pdel++ ) {
		ParseData *pd = pdel->value;
		if ( pd->instanceList.length() > 0 )
			pd->prepareMachineGen( 0, hostLang );
	}
}

void InputData::generateReduced()
{
	for ( ParseDataDict::Iter pdel = parseDataDict; pdel.lte(); pdel++ ) {
		ParseData *pd = pdel->value;
		if ( pd->instanceList.length() > 0 )
			pd->generateReduced( inputFileName, codeStyle, *outStream, hostLang );
	}
}

void InputData::verifyWritesHaveData()
{
	for ( InputItemList::Iter ii = inputItems; ii.lte(); ii++ ) {
		if ( ii->type == InputItem::Write ) {
			if ( ii->pd->cgd == 0 )
				error( ii->loc ) << "no machine instantiations to write" << endl;
		}
	}
}

void InputData::writeOutput()
{
	for ( InputItemList::Iter ii = inputItems; ii.lte(); ii++ ) {
		if ( ii->type == InputItem::Write ) {
			CodeGenData *cgd = ii->pd->cgd;
			cgd->writeStatement( ii->loc, ii->writeArgs.length(),
					ii->writeArgs.data, generateDot, hostLang );
		}
		else {
			switch ( backend ) {
				case Direct:
					*outStream << ii->data.str();
					break;
				case Translated:
					openHostBlock( '@', this, *outStream, inputFileName, ii->loc.line );
					*outStream << ii->data.str();
					*outStream << "}@";
					break;
			}
		}
	}
}

void InputData::closeOutput()
{
	/* If writing to a file, delete the ostream, causing it to flush.
	 * Standard out is flushed automatically. */
	if ( outputFileName != 0 ) {
		delete outStream;
		delete outFilter;
	}
}

void InputData::processXML()
{
	/* Compiles machines. */
	prepareAllMachines();

	if ( gblErrorCount > 0 )
		exit(1);

	makeOutputStream();

	if ( gblErrorCount > 0 )
		exit(1);

	/*
	 * From this point on we should not be reporting any errors.
	 */

	openOutput();
	writeXML( *outStream );
	closeOutput();
}

void InputData::processDot()
{
	/* Compiles the DOT machines. */
	prepareSingleMachine();

	if ( gblErrorCount > 0 )
		exit(1);

	makeOutputStream();

	if ( gblErrorCount > 0 )
		exit(1);

	/*
	 * From this point on we should not be reporting any errors.
	 */

	openOutput();
	writeDot( *outStream );
	closeOutput();
}

void InputData::processCode()
{
	/* Compiles machines. */
	prepareAllMachines();

	if ( gblErrorCount > 0 )
		exit(1);

	makeDefaultFileName();

	if ( backend == Translated ) {
		origOutputFileName = outputFileName;
		genOutputFileName = fileNameFromStem( inputFileName, ".ri" );
		outputFileName = genOutputFileName.c_str();
	}

	makeOutputStream();

	/* Generates the reduced machine, which we use to write output. */
	generateReduced();

	if ( gblErrorCount > 0 )
		exit(1);

	verifyWritesHaveData();

	if ( gblErrorCount > 0 )
		exit(1);

	/*
	 * From this point on we should not be reporting any errors.
	 */

	openOutput();
	writeOutput();
	closeOutput();

	if ( backend == Translated ) {
#ifdef WITH_COLM
		if ( !noIntermediate ) {
			string rlhc = dirName + "/rlhc " +
					origOutputFileName + " " +
					genOutputFileName + " " +
					hostLang->rlhcArg;

			if ( rlhcShowCmd )
				std::cout << rlhc << std::endl;

			int res = system( rlhc.c_str() );
			if ( res != 0 )
				exit( 1 );

			if ( !saveTemps )
				unlink( genOutputFileName.c_str() );
		}
#else
		error() << "colm-based codegen not available" << endp;
#endif
	}
}

void InputData::makeFirstInputItem()
{
	/* Make the first input item. */
	InputItem *firstInputItem = new InputItem;
	firstInputItem->type = InputItem::HostData;
	firstInputItem->loc.fileName = inputFileName;
	firstInputItem->loc.line = 1;
	firstInputItem->loc.col = 1;
	inputItems.append( firstInputItem );
}

/* Send eof to all parsers. */
void InputData::terminateAllParsers( )
{
	/* FIXME: a proper token is needed here. Suppose we should use the
	 * location of EOF in the last file that the parser was referenced in. */
	InputLoc loc;
	loc.fileName = "<EOF>";
	loc.line = 0;
	loc.col = 0;
	for ( ParserDict::Iter pdel = parserDict; pdel.lte(); pdel++ )
		pdel->value->token( loc, Parser6_tk_eof, 0, 0 );
}

void InputData::process()
{
	ifstream *inFile;

	switch ( frontend ) {
		case KelbtBased: {
			/*
			 * Ragel Parser from ragel 6.
			 */

			/* Open the input file for reading. */
			assert( inputFileName != 0 );
			inFile = new ifstream( inputFileName );
			if ( ! inFile->is_open() )
				error() << "could not open " << inputFileName << " for reading" << endp;

			/* Used for just a few things. */
			std::ostringstream hostData;

			/* Make the first input item. */
			InputItem *firstInputItem = new InputItem;
			firstInputItem->type = InputItem::HostData;
			firstInputItem->loc.fileName = inputFileName;
			firstInputItem->loc.line = 1;
			firstInputItem->loc.col = 1;
			inputItems.append( firstInputItem );

			Scanner scanner( *this, inputFileName, *inFile, 0, 0, 0, false );
			scanner.do_scan();

			/* Finished, final check for errors.. */
			if ( gblErrorCount > 0 )
				exit(1);

			/* Now send EOF to all parsers. */
			terminateAllParsers();
			break;
		}
		case ColmBased: {
#ifdef WITH_COLM
			/*
			 * Colm-based parser introduced in ragel 7. Uses more memory.
			 */

			/* Check input file. */
			inFile = new ifstream( inputFileName );
			if ( ! inFile->is_open() )
				error() << "could not open " << inputFileName << " for reading" << endp;
			delete inFile;

			makeFirstInputItem();

			LoadRagel *lr = newLoadRagel( *this, hostLang, minimizeLevel, minimizeOpt );
			loadRagel( lr, inputFileName );
			deleteLoadRagel( lr );
#endif
			break;
		}
	}

	/* Bail on above error. */
	if ( gblErrorCount > 0 )
		exit(1);

	if ( generateXML )
		processXML();
	else if ( generateDot )
		processDot();
	else
		processCode();

	assert( gblErrorCount == 0 );
}

<|endoftext|>


<commit_before>/* This file is part of the KDE project

   Copyright (C) 2014 Dominik Haumann <dhaumann@kde.org>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.
*/

#include "tabswitcher.h"
#include "tabswitchertreeview.h"

#include <KTextEditor/Application>
#include <KTextEditor/Document>
#include <KTextEditor/Editor>
#include <KTextEditor/View>

#include <KActionCollection>
#include <KLocalizedString>
#include <KPluginFactory>
#include <KXMLGUIFactory>

#include <QAction>
#include <QMimeDatabase>
#include <QScrollBar>
#include <QStandardItemModel>

K_PLUGIN_FACTORY_WITH_JSON(TabSwitcherPluginFactory, "tabswitcherplugin.json", registerPlugin<TabSwitcherPlugin>();)

TabSwitcherPlugin::TabSwitcherPlugin(QObject *parent, const QList<QVariant> &):
    KTextEditor::Plugin(parent)
{
}

QObject *TabSwitcherPlugin::createView(KTextEditor::MainWindow *mainWindow)
{
    return new TabSwitcherPluginView(this, mainWindow);
}

TabSwitcherPluginView::TabSwitcherPluginView(TabSwitcherPlugin *plugin, KTextEditor::MainWindow *mainWindow)
    : QObject(mainWindow)
    , m_plugin(plugin)
    , m_mainWindow(mainWindow)
{
    // register this view
    m_plugin->m_views.append(this);

    m_model = new QStandardItemModel(this);
    m_treeView = new TabSwitcherTreeView();
    m_treeView->setModel(m_model);

    KXMLGUIClient::setComponentName(QStringLiteral("tabswitcher"), i18n("Document Switcher"));
    setXMLFile(QStringLiteral("ui.rc"));

    // note: call after m_treeView is created
    setupActions();

    // fill the model
    setupModel();

    // register action in menu
    m_mainWindow->guiFactory()->addClient(this);

    // popup connections
    connect(m_treeView, SIGNAL(pressed(QModelIndex)), SLOT(switchToClicked(QModelIndex)));
    connect(m_treeView, SIGNAL(itemActivated(QModelIndex)), SLOT(activateView(QModelIndex)));

    // track existing documents
    connect(KTextEditor::Editor::instance()->application(), SIGNAL(documentCreated(KTextEditor::Document*)),
            this, SLOT(registerDocument(KTextEditor::Document*)));
    connect(KTextEditor::Editor::instance()->application(), SIGNAL(documentWillBeDeleted(KTextEditor::Document*)),
            this, SLOT(unregisterDocument(KTextEditor::Document*)));

    // track lru activation of views to raise the respective documents in the model
    connect(m_mainWindow, SIGNAL(viewChanged(KTextEditor::View*)),
            this, SLOT(raiseView(KTextEditor::View*)));
}

TabSwitcherPluginView::~TabSwitcherPluginView()
{
    // delete popup widget
    delete m_treeView;

    // unregister action in menu
    m_mainWindow->guiFactory()->removeClient(this);

    // unregister this view
    m_plugin->m_views.removeAll(this);
}

void TabSwitcherPluginView::setupActions()
{
    auto aNext = actionCollection()->addAction(QStringLiteral("view_lru_document_next"));
    aNext->setText(i18n("Last Used Views"));
    aNext->setIcon(QIcon::fromTheme(QStringLiteral("go-next-view-page")));
    actionCollection()->setDefaultShortcut(aNext, Qt::CTRL | Qt::Key_Tab);
    aNext->setWhatsThis(i18n("Opens a list to walk through the list of last used views."));
    aNext->setStatusTip(i18n("Walk through the list of last used views"));
    connect(aNext, SIGNAL(triggered()), SLOT(walkForward()));

    auto aPrev = actionCollection()->addAction(QStringLiteral("view_lru_document_prev"));
    aPrev->setText(i18n("Last Used Views (Reverse)"));
    aPrev->setIcon(QIcon::fromTheme(QStringLiteral("go-previous-view-page")));
    actionCollection()->setDefaultShortcut(aPrev, Qt::CTRL | Qt::SHIFT | Qt::Key_Tab);
    aPrev->setWhatsThis(i18n("Opens a list to walk through the list of last used views in reverse."));
    aPrev->setStatusTip(i18n("Walk through the list of last used views"));
    connect(aPrev, SIGNAL(triggered()), SLOT(walkBackward()));

    // make sure action work when the popup has focus
    m_treeView->addAction(aNext);
    m_treeView->addAction(aPrev);
}

static QIcon iconForDocument(KTextEditor::Document * doc)
{
    return QIcon::fromTheme(QMimeDatabase().mimeTypeForUrl(doc->url()).iconName());
}

void TabSwitcherPluginView::setupModel()
{
    // initial fill of model
    foreach (auto doc, KTextEditor::Editor::instance()->application()->documents()) {
        registerDocument(doc);
    }
}

void TabSwitcherPluginView::registerDocument(KTextEditor::Document * document)
{
    auto item = new QStandardItem(iconForDocument(document), document->documentName());
    item->setData(QVariant::fromValue(document));
    m_model->insertRow(0, item);

    // track document name changes
    connect(document, SIGNAL(documentNameChanged(KTextEditor::Document*)),
            this, SLOT(updateDocumentName(KTextEditor::Document*)));
}

void TabSwitcherPluginView::unregisterDocument(KTextEditor::Document * document)
{
    const auto rowCount = m_model->rowCount();
    for (int i = 0; i < rowCount; ++i) {
        auto doc = m_model->item(i)->data().value<KTextEditor::Document*>();
        if (doc == document) {
            m_model->removeRow(i);

            // disconnect documentNameChanged() signal
            disconnect(document, 0, this, 0);

            break;
        }
    }
}

void TabSwitcherPluginView::updateDocumentName(KTextEditor::Document * document)
{
    const auto rowCount = m_model->rowCount();
    for (int i = 0; i < rowCount; ++i) {
        auto doc = m_model->item(i)->data().value<KTextEditor::Document*>();
        if (doc == document) {
            m_model->item(i)->setText(document->documentName());
            break;
        }
    }
}

void TabSwitcherPluginView::raiseView(KTextEditor::View * view)
{
    if (!view) {
        return;
    }

    unregisterDocument(view->document());
    registerDocument(view->document());
}

void TabSwitcherPluginView::walk(const int from, const int to)
{
    QModelIndex index;
    const int step = from < to ? 1 : -1;
    if (! m_treeView->isVisible()) {
        updateViewGeometry();
        index = m_model->index(from + step, 0);
        if(! index.isValid()) {
            index = m_model->index(0, 0);
        }
        m_treeView->show();
        m_treeView->setFocus();
    } else {
        int newRow = m_treeView->selectionModel()->currentIndex().row() + step;
        if(newRow == to + step) { newRow = from; }
        index = m_model->index(newRow, 0);
    }

    m_treeView->selectionModel()->select(index, QItemSelectionModel::Rows | QItemSelectionModel::ClearAndSelect);
    m_treeView->selectionModel()->setCurrentIndex(index, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
}

void TabSwitcherPluginView::walkForward()
{
    walk(0, m_model->rowCount() - 1);
}

void TabSwitcherPluginView::walkBackward()
{
    walk(m_model->rowCount() - 1, 0);
}

void TabSwitcherPluginView::updateViewGeometry()
{
    QWidget * window = m_mainWindow->window();
    const QSize centralSize = window->size();

    // Maximum size of the view is 3/4th of the central widget (the editor area)
    // so the view does not overlap the mainwindow since that looks awkward.
    const QSize viewMaxSize( centralSize.width() * 3/4, centralSize.height() * 3/4 );

    // The actual view size should be as big as the columns/rows need it, but
    // smaller than the max-size. This means the view will get quite high with
    // many open files but I think thats ok. Otherwise one can easily tweak the
    // max size to be only 1/2th of the central widget size
    const QSize viewSize(std::min(m_treeView->sizeHintForColumn(0) + m_treeView->verticalScrollBar()->width(), viewMaxSize.width()),
                         std::min(std::max(m_treeView->sizeHintForRow(0) * m_model->rowCount(), m_treeView->sizeHintForRow(0) * 6 ), viewMaxSize.height()));

    // Position should be central over the editor area, so map to global from
    // parent of central widget since the view is positioned in global coords
    const QPoint centralWidgetPos = window->parentWidget() ? window->mapToGlobal(window->pos()) : window->pos();
    const int xPos = std::max(0, centralWidgetPos.x() + (centralSize.width()  - viewSize.width()  ) / 2);
    const int yPos = std::max(0, centralWidgetPos.y() + (centralSize.height() - viewSize.height() ) / 2);

    m_treeView->setFixedSize(viewSize);
    m_treeView->move(xPos, yPos);
}

void TabSwitcherPluginView::switchToClicked(const QModelIndex & index)
{
    m_treeView->selectionModel()->select(index, QItemSelectionModel::ClearAndSelect);
    activateView(index);
}

void TabSwitcherPluginView::activateView(const QModelIndex & index)
{
    Q_UNUSED(index)

    // guard against empty selection
    if (m_treeView->selectionModel()->selectedRows().isEmpty()) {
        return;
    }

    const int row = m_treeView->selectionModel()->selectedRows().first().row();

    auto doc = m_model->item(row)->data().value<KTextEditor::Document*>();
    m_mainWindow->activateView(doc);

    m_treeView->hide();
}

// required for TabSwitcherPluginFactory vtable
#include "tabswitcher.moc"
<commit_msg>Tab Switcher Plugin: Make sure the height fits all items<commit_after>/* This file is part of the KDE project

   Copyright (C) 2014 Dominik Haumann <dhaumann@kde.org>

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.
*/

#include "tabswitcher.h"
#include "tabswitchertreeview.h"

#include <KTextEditor/Application>
#include <KTextEditor/Document>
#include <KTextEditor/Editor>
#include <KTextEditor/View>

#include <KActionCollection>
#include <KLocalizedString>
#include <KPluginFactory>
#include <KXMLGUIFactory>

#include <QAction>
#include <QMimeDatabase>
#include <QScrollBar>
#include <QStandardItemModel>

K_PLUGIN_FACTORY_WITH_JSON(TabSwitcherPluginFactory, "tabswitcherplugin.json", registerPlugin<TabSwitcherPlugin>();)

TabSwitcherPlugin::TabSwitcherPlugin(QObject *parent, const QList<QVariant> &):
    KTextEditor::Plugin(parent)
{
}

QObject *TabSwitcherPlugin::createView(KTextEditor::MainWindow *mainWindow)
{
    return new TabSwitcherPluginView(this, mainWindow);
}

TabSwitcherPluginView::TabSwitcherPluginView(TabSwitcherPlugin *plugin, KTextEditor::MainWindow *mainWindow)
    : QObject(mainWindow)
    , m_plugin(plugin)
    , m_mainWindow(mainWindow)
{
    // register this view
    m_plugin->m_views.append(this);

    m_model = new QStandardItemModel(this);
    m_treeView = new TabSwitcherTreeView();
    m_treeView->setModel(m_model);

    KXMLGUIClient::setComponentName(QStringLiteral("tabswitcher"), i18n("Document Switcher"));
    setXMLFile(QStringLiteral("ui.rc"));

    // note: call after m_treeView is created
    setupActions();

    // fill the model
    setupModel();

    // register action in menu
    m_mainWindow->guiFactory()->addClient(this);

    // popup connections
    connect(m_treeView, SIGNAL(pressed(QModelIndex)), SLOT(switchToClicked(QModelIndex)));
    connect(m_treeView, SIGNAL(itemActivated(QModelIndex)), SLOT(activateView(QModelIndex)));

    // track existing documents
    connect(KTextEditor::Editor::instance()->application(), SIGNAL(documentCreated(KTextEditor::Document*)),
            this, SLOT(registerDocument(KTextEditor::Document*)));
    connect(KTextEditor::Editor::instance()->application(), SIGNAL(documentWillBeDeleted(KTextEditor::Document*)),
            this, SLOT(unregisterDocument(KTextEditor::Document*)));

    // track lru activation of views to raise the respective documents in the model
    connect(m_mainWindow, SIGNAL(viewChanged(KTextEditor::View*)),
            this, SLOT(raiseView(KTextEditor::View*)));
}

TabSwitcherPluginView::~TabSwitcherPluginView()
{
    // delete popup widget
    delete m_treeView;

    // unregister action in menu
    m_mainWindow->guiFactory()->removeClient(this);

    // unregister this view
    m_plugin->m_views.removeAll(this);
}

void TabSwitcherPluginView::setupActions()
{
    auto aNext = actionCollection()->addAction(QStringLiteral("view_lru_document_next"));
    aNext->setText(i18n("Last Used Views"));
    aNext->setIcon(QIcon::fromTheme(QStringLiteral("go-next-view-page")));
    actionCollection()->setDefaultShortcut(aNext, Qt::CTRL | Qt::Key_Tab);
    aNext->setWhatsThis(i18n("Opens a list to walk through the list of last used views."));
    aNext->setStatusTip(i18n("Walk through the list of last used views"));
    connect(aNext, SIGNAL(triggered()), SLOT(walkForward()));

    auto aPrev = actionCollection()->addAction(QStringLiteral("view_lru_document_prev"));
    aPrev->setText(i18n("Last Used Views (Reverse)"));
    aPrev->setIcon(QIcon::fromTheme(QStringLiteral("go-previous-view-page")));
    actionCollection()->setDefaultShortcut(aPrev, Qt::CTRL | Qt::SHIFT | Qt::Key_Tab);
    aPrev->setWhatsThis(i18n("Opens a list to walk through the list of last used views in reverse."));
    aPrev->setStatusTip(i18n("Walk through the list of last used views"));
    connect(aPrev, SIGNAL(triggered()), SLOT(walkBackward()));

    // make sure action work when the popup has focus
    m_treeView->addAction(aNext);
    m_treeView->addAction(aPrev);
}

static QIcon iconForDocument(KTextEditor::Document * doc)
{
    return QIcon::fromTheme(QMimeDatabase().mimeTypeForUrl(doc->url()).iconName());
}

void TabSwitcherPluginView::setupModel()
{
    // initial fill of model
    foreach (auto doc, KTextEditor::Editor::instance()->application()->documents()) {
        registerDocument(doc);
    }
}

void TabSwitcherPluginView::registerDocument(KTextEditor::Document * document)
{
    auto item = new QStandardItem(iconForDocument(document), document->documentName());
    item->setData(QVariant::fromValue(document));
    m_model->insertRow(0, item);

    // track document name changes
    connect(document, SIGNAL(documentNameChanged(KTextEditor::Document*)),
            this, SLOT(updateDocumentName(KTextEditor::Document*)));
}

void TabSwitcherPluginView::unregisterDocument(KTextEditor::Document * document)
{
    const auto rowCount = m_model->rowCount();
    for (int i = 0; i < rowCount; ++i) {
        auto doc = m_model->item(i)->data().value<KTextEditor::Document*>();
        if (doc == document) {
            m_model->removeRow(i);

            // disconnect documentNameChanged() signal
            disconnect(document, 0, this, 0);

            break;
        }
    }
}

void TabSwitcherPluginView::updateDocumentName(KTextEditor::Document * document)
{
    const auto rowCount = m_model->rowCount();
    for (int i = 0; i < rowCount; ++i) {
        auto doc = m_model->item(i)->data().value<KTextEditor::Document*>();
        if (doc == document) {
            m_model->item(i)->setText(document->documentName());
            break;
        }
    }
}

void TabSwitcherPluginView::raiseView(KTextEditor::View * view)
{
    if (!view) {
        return;
    }

    unregisterDocument(view->document());
    registerDocument(view->document());
}

void TabSwitcherPluginView::walk(const int from, const int to)
{
    QModelIndex index;
    const int step = from < to ? 1 : -1;
    if (! m_treeView->isVisible()) {
        updateViewGeometry();
        index = m_model->index(from + step, 0);
        if(! index.isValid()) {
            index = m_model->index(0, 0);
        }
        m_treeView->show();
        m_treeView->setFocus();
    } else {
        int newRow = m_treeView->selectionModel()->currentIndex().row() + step;
        if(newRow == to + step) { newRow = from; }
        index = m_model->index(newRow, 0);
    }

    m_treeView->selectionModel()->select(index, QItemSelectionModel::Rows | QItemSelectionModel::ClearAndSelect);
    m_treeView->selectionModel()->setCurrentIndex(index, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
}

void TabSwitcherPluginView::walkForward()
{
    walk(0, m_model->rowCount() - 1);
}

void TabSwitcherPluginView::walkBackward()
{
    walk(m_model->rowCount() - 1, 0);
}

void TabSwitcherPluginView::updateViewGeometry()
{
    QWidget * window = m_mainWindow->window();
    const QSize centralSize = window->size();

    // Maximum size of the view is 3/4th of the central widget (the editor area)
    // so the view does not overlap the mainwindow since that looks awkward.
    const QSize viewMaxSize( centralSize.width() * 3/4, centralSize.height() * 3/4 );

    // The actual view size should be as big as the columns/rows need it, but
    // smaller than the max-size. This means the view will get quite high with
    // many open files but I think thats ok. Otherwise one can easily tweak the
    // max size to be only 1/2th of the central widget size
    const int rowHeight = m_treeView->sizeHintForRow(0);
    const int frameWidth = m_treeView->frameWidth();
    const QSize viewSize(std::min(m_treeView->sizeHintForColumn(0) + 2 * frameWidth + m_treeView->verticalScrollBar()->width(), viewMaxSize.width()),
                         std::min(std::max(rowHeight * m_model->rowCount() + 2 * frameWidth, rowHeight * 6 ), viewMaxSize.height()));

    // Position should be central over the editor area, so map to global from
    // parent of central widget since the view is positioned in global coords
    const QPoint centralWidgetPos = window->parentWidget() ? window->mapToGlobal(window->pos()) : window->pos();
    const int xPos = std::max(0, centralWidgetPos.x() + (centralSize.width()  - viewSize.width()  ) / 2);
    const int yPos = std::max(0, centralWidgetPos.y() + (centralSize.height() - viewSize.height() ) / 2);

    m_treeView->setFixedSize(viewSize);
    m_treeView->move(xPos, yPos);
}

void TabSwitcherPluginView::switchToClicked(const QModelIndex & index)
{
    m_treeView->selectionModel()->select(index, QItemSelectionModel::ClearAndSelect);
    activateView(index);
}

void TabSwitcherPluginView::activateView(const QModelIndex & index)
{
    Q_UNUSED(index)

    // guard against empty selection
    if (m_treeView->selectionModel()->selectedRows().isEmpty()) {
        return;
    }

    const int row = m_treeView->selectionModel()->selectedRows().first().row();

    auto doc = m_model->item(row)->data().value<KTextEditor::Document*>();
    m_mainWindow->activateView(doc);

    m_treeView->hide();
}

// required for TabSwitcherPluginFactory vtable
#include "tabswitcher.moc"
<|endoftext|>


<commit_before>#include "common.h"
#include "types.h"
#include "util.h"

namespace wlcjs {

SimplePersistent<Object> persistent_interface;

#define MK_SCOPE\
  ISOLATE(persistent_interface); \
  HandleScope scope(isolate);

MaybeLocal<Value> CallCallback(const char* name, int argc, Local<Value> argv[]) {
  ISOLATE(persistent_interface);
  Local<Object> interface = persistent_interface.Unwrap();
  Local<Value> v;

  if (!Unwrap(interface->Get(isolate->GetCurrentContext(), NewString(name)), &v)) {
    return MaybeLocal<Value>();
  }

  if (v->IsFunction()) {
    return v.As<Function>()->Call(isolate->GetCurrentContext(), Null(isolate), argc, argv);
  }
  return Undefined(isolate);
}

bool output_created(wlc_handle output) {
  // TODO return true or false
  MK_SCOPE
  Local<Value> argv[] = {
    Number::New(isolate, output),
  };
  CallCallback("outputCreated", 1, argv);
  return true;
}

void output_destroyed(wlc_handle output) {
  MK_SCOPE
  Local<Value> argv[] = {
    Number::New(isolate, output),
  };
  CallCallback("outputDestroyed", 1, argv);
}

void output_focus(wlc_handle output, bool focus) {
  MK_SCOPE
  Local<Value> argv[] = {
    Number::New(isolate, output),
    Boolean::New(isolate, focus),
  };
  CallCallback("outputFocus", 2, argv);
}

void output_resolution(wlc_handle output, const wlc_size* from, const wlc_size* to) {
  MK_SCOPE
  Local<Object> from_js;
  Local<Object> to_js;
  if (!TryCast(from, &from_js)) return;
  if (!TryCast(to, &to_js)) return;

  Local<Value> argv[] = {
    Number::New(isolate, output),
    from_js,
    to_js,
  };
  CallCallback("outputResolution", 3, argv);
}

bool keyboard_key(wlc_handle view, uint32_t time, const wlc_modifiers* modifiers, uint32_t key, wlc_key_state key_state) {
  MK_SCOPE
  Local<Object> modifiers_js;
  if (!TryCast(modifiers, &modifiers_js)) return true;

  Local<Value> argv[] = {
    Number::New(isolate, view),
    Number::New(isolate, time),
    modifiers_js,
    Number::New(isolate, key),
    Number::New(isolate, key_state),
  };

  // TODO return true or false
  CallCallback("keyboardKey", 5, argv);
  return true;
}

bool view_created(wlc_handle view) {
  // TODO return true or false
  MK_SCOPE
  Local<Value> argv[] = {
    Number::New(isolate, view),
  };
  CallCallback("viewCreated", 1, argv);
  return true;
}

void view_destroyed(wlc_handle view) {
  MK_SCOPE
  Local<Value> argv[] = {
    Number::New(isolate, view),
  };
  CallCallback("viewDestroyed", 1, argv);
}

void view_focus(wlc_handle view, bool focus) {
  MK_SCOPE
  Local<Value> argv[] = {
    Number::New(isolate, view),
    Boolean::New(isolate, focus),
  };
  CallCallback("viewFocus", 2, argv);
}

void view_move_to_output(wlc_handle view, wlc_handle from_output, wlc_handle to_output) {
  MK_SCOPE
  Local<Value> argv[] = {
    Number::New(isolate, view),
    Number::New(isolate, from_output),
    Number::New(isolate, to_output),
  };
  CallCallback("viewMoveToOutput", 3, argv);
}

bool pointer_button(wlc_handle view, uint32_t time,
    const struct wlc_modifiers* modifiers, uint32_t button,
    enum wlc_button_state state, const struct wlc_origin* origin) {

  MK_SCOPE
  Local<Object> modifiers_js;
  Local<Object> origin_js;
  if (!TryCast(modifiers, &modifiers_js)) return true;
  if (!TryCast(origin, &origin_js)) return true;

  Local<Value> argv[] = {
    Number::New(isolate, view),
    Number::New(isolate, time),
    modifiers_js,
    Number::New(isolate, button),
    Number::New(isolate, state),
    origin_js,
  };
  CallCallback("pointerButton", 6, argv);
  return true; // TODO return true or false
}

bool pointer_scroll(wlc_handle view, uint32_t time,
    const struct wlc_modifiers* modifiers, uint8_t axis_bits,
    double amount[2]) {

  MK_SCOPE
  auto context = isolate->GetCurrentContext();
  Local<Object> modifiers_js;
  if (!TryCast(modifiers, &modifiers_js)) return true;

  Local<Array> amount_js = Array::New(isolate, 2);
  if (amount_js->Set(context, 0, Number::New(isolate, amount[0])).IsNothing() ||
      amount_js->Set(context, 1, Number::New(isolate, amount[1])).IsNothing()) {
    return true;
  }

  Local<Value> argv[] = {
    Number::New(isolate, view),
    Number::New(isolate, time),
    modifiers_js,
    Number::New(isolate, axis_bits),
    amount_js,
  };
  CallCallback("pointerScroll", 5, argv);
  return true;
}

bool pointer_motion(wlc_handle view, uint32_t time,
    const struct wlc_origin* origin) {

  MK_SCOPE
  Local<Object> origin_js;
  if (!TryCast(origin, &origin_js)) return false;

  Local<Value> argv[] = {
    Number::New(isolate, view),
    Number::New(isolate, time),
    origin_js,
  };
  CallCallback("pointerMotion", 3, argv);
  return false;
}

wlc_interface global_interface = {

  .output = {
    // bool (*created)(wlc_handle output);
    .created = output_created,
    // void (*destroyed)(wlc_handle output);
    .destroyed = output_destroyed,
    // void (*focus)(wlc_handle output, bool focus);
    .focus = output_focus,
    // void (*resolution)(wlc_handle output, const struct wlc_size *from, const struct wlc_size *to);
    .resolution = output_resolution,
  },

  .view = {
    // bool (*created)(wlc_handle view);
    .created = view_created,
    // void (*destroyed)(wlc_handle view);
    .destroyed = view_destroyed,
    // void (*focus)(wlc_handle view, bool focus);
    .focus = view_focus,
    // void (*move_to_output)(wlc_handle view, wlc_handle from_output, wlc_handle to_output);
    .move_to_output = view_move_to_output,

    .request = {
      // void (*geometry)(wlc_handle view, const struct wlc_geometry*);
      .geometry = NULL,
      // void (*state)(wlc_handle view, enum wlc_view_state_bit, bool toggle);
      .state = NULL,
      // void (*move)(wlc_handle view, const struct wlc_origin *origin);
      .move = NULL,
      // void (*resize)(wlc_handle view, uint32_t edges, const struct wlc_origin *origin);
      .resize = NULL,
    },
  },

  .keyboard = {
    // bool (*key)(wlc_handle view, uint32_t time, const struct wlc_modifiers*, uint32_t key, enum wlc_key_state);
    .key = keyboard_key,
  },

  .pointer = {
    // bool (*button)(wlc_handle view, uint32_t time, const struct wlc_modifiers*, uint32_t button, enum wlc_button_state, const struct wlc_origin*);
    .button = pointer_button,
    // bool (*scroll)(wlc_handle view, uint32_t time, const struct wlc_modifiers*, uint8_t axis_bits, double amount[2]);
    .scroll = pointer_scroll,
    // bool (*motion)(wlc_handle view, uint32_t time, const struct wlc_origin*);
    .motion = pointer_motion,
  },

  .touch = {
    // bool (*touch)(wlc_handle view, uint32_t time, const struct wlc_modifiers*, enum wlc_touch_type, int32_t slot, const struct wlc_origin*);
    .touch = NULL,
  },

  .compositor = {
    // void (*ready)(void);
    .ready = NULL,
  },

  .input = {
    // bool (*created)(struct libinput_device *device);
    .created = NULL,
    // void (*destroyed)(struct libinput_device *device);
    .destroyed = NULL,
  },

};

wlc_interface* get_wlc_interface(Isolate* isolate, Local<Object> value) {
  persistent_interface.Reset(isolate, value);
  return &global_interface;
}

}
<commit_msg>Interface callbacks are returning booleans<commit_after>#include "common.h"
#include "types.h"
#include "util.h"

namespace wlcjs {

SimplePersistent<Object> persistent_interface;

#define MK_SCOPE\
  ISOLATE(persistent_interface); \
  HandleScope scope(isolate);

MaybeLocal<Value> CallMeMaybe(const char* name, int argc, Local<Value> argv[]) {
  ISOLATE(persistent_interface);
  Local<Object> interface = persistent_interface.Unwrap();
  Local<Function> v;

  if (!Unwrap(interface->Get(isolate->GetCurrentContext(), NewString(name)), &v)) {
    return MaybeLocal<Value>();
  }

  return v.As<Function>()->Call(isolate->GetCurrentContext(), Null(isolate), argc, argv);
}

template <class T>
T CallCallback(const char* name, T default_, int argc, Local<Value> argv[]) {
  T result;
  if (!Unwrap(CallMeMaybe(name, argc, argv), &result)) return default_;
  return result;
}

void CallCallback(const char* name, int argc, Local<Value> argv[]) {
  CallMeMaybe(name, argc, argv);
}

bool output_created(wlc_handle output) {
  MK_SCOPE
  Local<Value> argv[] = {
    Number::New(isolate, output),
  };
  return CallCallback("outputCreated", true, 1, argv);
}

void output_destroyed(wlc_handle output) {
  MK_SCOPE
  Local<Value> argv[] = {
    Number::New(isolate, output),
  };
  CallCallback("outputDestroyed", 1, argv);
}

void output_focus(wlc_handle output, bool focus) {
  MK_SCOPE
  Local<Value> argv[] = {
    Number::New(isolate, output),
    Boolean::New(isolate, focus),
  };
  CallCallback("outputFocus", 2, argv);
}

void output_resolution(wlc_handle output, const wlc_size* from, const wlc_size* to) {
  MK_SCOPE
  Local<Object> from_js;
  Local<Object> to_js;
  if (!TryCast(from, &from_js)) return;
  if (!TryCast(to, &to_js)) return;

  Local<Value> argv[] = {
    Number::New(isolate, output),
    from_js,
    to_js,
  };
  CallCallback("outputResolution", 3, argv);
}

bool keyboard_key(wlc_handle view, uint32_t time, const wlc_modifiers* modifiers, uint32_t key, wlc_key_state key_state) {
  MK_SCOPE
  Local<Object> modifiers_js;
  if (!TryCast(modifiers, &modifiers_js)) return false;

  Local<Value> argv[] = {
    Number::New(isolate, view),
    Number::New(isolate, time),
    modifiers_js,
    Number::New(isolate, key),
    Number::New(isolate, key_state),
  };
  return CallCallback("keyboardKey", false, 5, argv);
}

bool view_created(wlc_handle view) {
  MK_SCOPE
  Local<Value> argv[] = {
    Number::New(isolate, view),
  };
  return CallCallback("viewCreated", true, 1, argv);
}

void view_destroyed(wlc_handle view) {
  MK_SCOPE
  Local<Value> argv[] = {
    Number::New(isolate, view),
  };
  CallCallback("viewDestroyed", 1, argv);
}

void view_focus(wlc_handle view, bool focus) {
  MK_SCOPE
  Local<Value> argv[] = {
    Number::New(isolate, view),
    Boolean::New(isolate, focus),
  };
  CallCallback("viewFocus", 2, argv);
}

void view_move_to_output(wlc_handle view, wlc_handle from_output, wlc_handle to_output) {
  MK_SCOPE
  Local<Value> argv[] = {
    Number::New(isolate, view),
    Number::New(isolate, from_output),
    Number::New(isolate, to_output),
  };
  CallCallback("viewMoveToOutput", 3, argv);
}

bool pointer_button(wlc_handle view, uint32_t time,
    const struct wlc_modifiers* modifiers, uint32_t button,
    enum wlc_button_state state, const struct wlc_origin* origin) {

  MK_SCOPE
  Local<Object> modifiers_js;
  Local<Object> origin_js;
  if (!TryCast(modifiers, &modifiers_js)) return false;
  if (!TryCast(origin, &origin_js)) return false;

  Local<Value> argv[] = {
    Number::New(isolate, view),
    Number::New(isolate, time),
    modifiers_js,
    Number::New(isolate, button),
    Number::New(isolate, state),
    origin_js,
  };
  return CallCallback("pointerButton", false, 6, argv);
}

bool pointer_scroll(wlc_handle view, uint32_t time,
    const struct wlc_modifiers* modifiers, uint8_t axis_bits,
    double amount[2]) {

  MK_SCOPE
  auto context = isolate->GetCurrentContext();
  Local<Object> modifiers_js;
  if (!TryCast(modifiers, &modifiers_js)) return false;

  Local<Array> amount_js = Array::New(isolate, 2);
  if (amount_js->Set(context, 0, Number::New(isolate, amount[0])).IsNothing() ||
      amount_js->Set(context, 1, Number::New(isolate, amount[1])).IsNothing()) {
    return false;
  }

  Local<Value> argv[] = {
    Number::New(isolate, view),
    Number::New(isolate, time),
    modifiers_js,
    Number::New(isolate, axis_bits),
    amount_js,
  };
  return CallCallback("pointerScroll", false, 5, argv);
}

bool pointer_motion(wlc_handle view, uint32_t time,
    const struct wlc_origin* origin) {

  MK_SCOPE
  Local<Object> origin_js;
  if (!TryCast(origin, &origin_js)) return false;

  Local<Value> argv[] = {
    Number::New(isolate, view),
    Number::New(isolate, time),
    origin_js,
  };
  return CallCallback("pointerMotion", false, 3, argv);
}

wlc_interface global_interface = {

  .output = {
    // bool (*created)(wlc_handle output);
    .created = output_created,
    // void (*destroyed)(wlc_handle output);
    .destroyed = output_destroyed,
    // void (*focus)(wlc_handle output, bool focus);
    .focus = output_focus,
    // void (*resolution)(wlc_handle output, const struct wlc_size *from, const struct wlc_size *to);
    .resolution = output_resolution,
  },

  .view = {
    // bool (*created)(wlc_handle view);
    .created = view_created,
    // void (*destroyed)(wlc_handle view);
    .destroyed = view_destroyed,
    // void (*focus)(wlc_handle view, bool focus);
    .focus = view_focus,
    // void (*move_to_output)(wlc_handle view, wlc_handle from_output, wlc_handle to_output);
    .move_to_output = view_move_to_output,

    .request = {
      // void (*geometry)(wlc_handle view, const struct wlc_geometry*);
      .geometry = NULL,
      // void (*state)(wlc_handle view, enum wlc_view_state_bit, bool toggle);
      .state = NULL,
      // void (*move)(wlc_handle view, const struct wlc_origin *origin);
      .move = NULL,
      // void (*resize)(wlc_handle view, uint32_t edges, const struct wlc_origin *origin);
      .resize = NULL,
    },
  },

  .keyboard = {
    // bool (*key)(wlc_handle view, uint32_t time, const struct wlc_modifiers*, uint32_t key, enum wlc_key_state);
    .key = keyboard_key,
  },

  .pointer = {
    // bool (*button)(wlc_handle view, uint32_t time, const struct wlc_modifiers*, uint32_t button, enum wlc_button_state, const struct wlc_origin*);
    .button = pointer_button,
    // bool (*scroll)(wlc_handle view, uint32_t time, const struct wlc_modifiers*, uint8_t axis_bits, double amount[2]);
    .scroll = pointer_scroll,
    // bool (*motion)(wlc_handle view, uint32_t time, const struct wlc_origin*);
    .motion = pointer_motion,
  },

  .touch = {
    // bool (*touch)(wlc_handle view, uint32_t time, const struct wlc_modifiers*, enum wlc_touch_type, int32_t slot, const struct wlc_origin*);
    .touch = NULL,
  },

  .compositor = {
    // void (*ready)(void);
    .ready = NULL,
  },

  .input = {
    // bool (*created)(struct libinput_device *device);
    .created = NULL,
    // void (*destroyed)(struct libinput_device *device);
    .destroyed = NULL,
  },

};

wlc_interface* get_wlc_interface(Isolate* isolate, Local<Object> value) {
  persistent_interface.Reset(isolate, value);
  return &global_interface;
}

}
<|endoftext|>


<commit_before>/**
 * @file disk_index.cpp
 * @author Sean Massung
 */

#include <numeric>

#include "index/disk_index.h"
#include "index/disk_index_impl.h"
#include "index/string_list.h"
#include "index/string_list_writer.h"
#include "index/vocabulary_map.h"
#include "analyzers/analyzer.h"
#include "util/disk_vector.h"
#include "util/mapping.h"
#include "util/optional.h"
#include "util/pimpl.tcc"

namespace meta
{
namespace index
{

disk_index::disk_index(const cpptoml::toml_group& config,
                       const std::string& name)
{
    impl_->index_name_ = name;
}

std::string disk_index::index_name() const
{
    return impl_->index_name_;
}

term_id disk_index::get_term_id(const std::string& term)
{
    std::lock_guard<std::mutex> lock{impl_->mutex_};

    auto termID = impl_->term_id_mapping_->find(term);
    if (termID)
        return term_id{*termID};

    uint64_t size = impl_->term_id_mapping_->size();
    return term_id{size};
}

class_label disk_index::label(doc_id d_id) const
{
    return class_label_from_id(impl_->labels_->at(d_id));
}

label_id disk_index::id(class_label label) const
{
    return impl_->label_ids_.get_value(label);
}

class_label disk_index::class_label_from_id(label_id l_id) const
{
    return impl_->label_ids_.get_key(l_id);
}

std::vector<class_label> disk_index::class_labels() const
{
    return impl_->class_labels();
}

uint64_t disk_index::unique_terms(doc_id d_id) const
{
    return impl_->unique_terms_->at(d_id);
}

uint64_t disk_index::unique_terms() const
{
    return impl_->term_id_mapping_->size();
}

uint64_t disk_index::doc_size(doc_id d_id) const
{
    return impl_->doc_sizes_->at(d_id);
}

uint64_t disk_index::num_docs() const
{
    return impl_->doc_sizes_->size();
}

std::string disk_index::doc_name(doc_id d_id) const
{
    auto path = doc_path(d_id);
    return path.substr(path.find_last_of("/") + 1);
}

std::string disk_index::doc_path(doc_id d_id) const
{
    return impl_->doc_id_mapping_->at(d_id);
}

std::vector<doc_id> disk_index::docs() const
{
    std::vector<doc_id> ret(impl_->doc_id_mapping_->size());
    std::iota(ret.begin(), ret.end(), 0);
    return ret;
}

// disk_index_impl

const std::vector<const char*> disk_index::disk_index_impl::files
    = {"/docids.mapping", "/docids.mapping_index", "/docsizes.counts",
       "/docs.labels",    "/docs.uniqueterms",     "/labelids.mapping",
       "/postings.index", "/termids.mapping",      "/termids.mapping.inverse"};

label_id disk_index::disk_index_impl::get_label_id(const class_label& lbl)
{
    std::lock_guard<std::mutex> lock{mutex_};
    if (!label_ids_.contains_key(lbl))
    {
        label_id next_id{static_cast<label_id>(label_ids_.size())};
        label_ids_.insert(lbl, next_id);
        return next_id;
    }
    else
        return label_ids_.get_value(lbl);
}

void disk_index::disk_index_impl::initialize_metadata(uint64_t num_docs)
{
    load_doc_sizes(num_docs);
    load_labels(num_docs);
    load_unique_terms(num_docs);
}

void disk_index::disk_index_impl::load_doc_sizes(uint64_t num_docs)
{
    doc_sizes_ = util::disk_vector<double>{index_name_ + files[DOC_SIZES],
                                           num_docs};
}

void disk_index::disk_index_impl::load_labels(uint64_t num_docs)
{
    labels_ = util::disk_vector<label_id>{index_name_ + files[DOC_LABELS],
                                          num_docs};
}

void disk_index::disk_index_impl::load_unique_terms(uint64_t num_docs)
{
    unique_terms_ = util::disk_vector<uint64_t>{
        index_name_ + files[DOC_UNIQUETERMS], num_docs};
}

void disk_index::disk_index_impl::load_doc_id_mapping()
{
    doc_id_mapping_ = string_list{index_name_ + files[DOC_IDS_MAPPING]};
}

void disk_index::disk_index_impl::load_term_id_mapping()
{
    term_id_mapping_ = vocabulary_map{index_name_ + files[TERM_IDS_MAPPING]};
}

void disk_index::disk_index_impl::load_label_id_mapping()
{
    map::load_mapping(label_ids_, index_name_ + files[LABEL_IDS_MAPPING]);
}

void disk_index::disk_index_impl::load_postings()
{
    postings_ = io::mmap_file{index_name_ + files[POSTINGS]};
}

void disk_index::disk_index_impl::save_label_id_mapping()
{
    map::save_mapping(label_ids_, index_name_ + files[LABEL_IDS_MAPPING]);
}

string_list_writer
    disk_index::disk_index_impl::make_doc_id_writer(uint64_t num_docs) const
{
    return {index_name_ + files[DOC_IDS_MAPPING], num_docs};
}

void disk_index::disk_index_impl::set_label(doc_id id, const class_label& label)
{
    (*labels_)[id] = get_label_id(label);
}

void disk_index::disk_index_impl::set_length(doc_id id, uint64_t length)
{
    (*doc_sizes_)[id] = length;
}

void disk_index::disk_index_impl::set_unique_terms(doc_id id, uint64_t terms)
{
    (*unique_terms_)[id] = terms;
}

const io::mmap_file& disk_index::disk_index_impl::postings() const
{
    return *postings_;
}

uint64_t disk_index::disk_index_impl::total_unique_terms() const
{
    return term_id_mapping_->size();
}

label_id disk_index::disk_index_impl::doc_label_id(doc_id id) const
{
    return labels_->at(id);
}

std::vector<class_label> disk_index::disk_index_impl::class_labels() const
{
    std::vector<class_label> labels;
    labels.reserve(label_ids_.size());
    for (const auto& pair : label_ids_)
        labels.emplace_back(pair.first);
    return labels;
}

std::string disk_index::term_text(term_id t_id) const
{
    if (t_id >= impl_->term_id_mapping_->size())
        return "";
    return impl_->term_id_mapping_->find_term(t_id);
}
}
}
<commit_msg>make label ids start from one for compatibility with svm light<commit_after>/**
 * @file disk_index.cpp
 * @author Sean Massung
 */

#include <numeric>

#include "index/disk_index.h"
#include "index/disk_index_impl.h"
#include "index/string_list.h"
#include "index/string_list_writer.h"
#include "index/vocabulary_map.h"
#include "analyzers/analyzer.h"
#include "util/disk_vector.h"
#include "util/mapping.h"
#include "util/optional.h"
#include "util/pimpl.tcc"

namespace meta
{
namespace index
{

disk_index::disk_index(const cpptoml::toml_group& config,
                       const std::string& name)
{
    impl_->index_name_ = name;
}

std::string disk_index::index_name() const
{
    return impl_->index_name_;
}

term_id disk_index::get_term_id(const std::string& term)
{
    std::lock_guard<std::mutex> lock{impl_->mutex_};

    auto termID = impl_->term_id_mapping_->find(term);
    if (termID)
        return term_id{*termID};

    uint64_t size = impl_->term_id_mapping_->size();
    return term_id{size};
}

class_label disk_index::label(doc_id d_id) const
{
    return class_label_from_id(impl_->labels_->at(d_id));
}

label_id disk_index::id(class_label label) const
{
    return impl_->label_ids_.get_value(label);
}

class_label disk_index::class_label_from_id(label_id l_id) const
{
    return impl_->label_ids_.get_key(l_id);
}

std::vector<class_label> disk_index::class_labels() const
{
    return impl_->class_labels();
}

uint64_t disk_index::unique_terms(doc_id d_id) const
{
    return impl_->unique_terms_->at(d_id);
}

uint64_t disk_index::unique_terms() const
{
    return impl_->term_id_mapping_->size();
}

uint64_t disk_index::doc_size(doc_id d_id) const
{
    return impl_->doc_sizes_->at(d_id);
}

uint64_t disk_index::num_docs() const
{
    return impl_->doc_sizes_->size();
}

std::string disk_index::doc_name(doc_id d_id) const
{
    auto path = doc_path(d_id);
    return path.substr(path.find_last_of("/") + 1);
}

std::string disk_index::doc_path(doc_id d_id) const
{
    return impl_->doc_id_mapping_->at(d_id);
}

std::vector<doc_id> disk_index::docs() const
{
    std::vector<doc_id> ret(impl_->doc_id_mapping_->size());
    std::iota(ret.begin(), ret.end(), 0);
    return ret;
}

// disk_index_impl

const std::vector<const char*> disk_index::disk_index_impl::files
    = {"/docids.mapping", "/docids.mapping_index", "/docsizes.counts",
       "/docs.labels",    "/docs.uniqueterms",     "/labelids.mapping",
       "/postings.index", "/termids.mapping",      "/termids.mapping.inverse"};

label_id disk_index::disk_index_impl::get_label_id(const class_label& lbl)
{
    std::lock_guard<std::mutex> lock{mutex_};
    if (!label_ids_.contains_key(lbl))
    {
        // SVM multiclass has label_ids starting at 1
        label_id next_id{static_cast<label_id>(label_ids_.size() + 1)};
        label_ids_.insert(lbl, next_id);
        return next_id;
    }
    else
        return label_ids_.get_value(lbl);
}

void disk_index::disk_index_impl::initialize_metadata(uint64_t num_docs)
{
    load_doc_sizes(num_docs);
    load_labels(num_docs);
    load_unique_terms(num_docs);
}

void disk_index::disk_index_impl::load_doc_sizes(uint64_t num_docs)
{
    doc_sizes_ = util::disk_vector<double>{index_name_ + files[DOC_SIZES],
                                           num_docs};
}

void disk_index::disk_index_impl::load_labels(uint64_t num_docs)
{
    labels_ = util::disk_vector<label_id>{index_name_ + files[DOC_LABELS],
                                          num_docs};
}

void disk_index::disk_index_impl::load_unique_terms(uint64_t num_docs)
{
    unique_terms_ = util::disk_vector<uint64_t>{
        index_name_ + files[DOC_UNIQUETERMS], num_docs};
}

void disk_index::disk_index_impl::load_doc_id_mapping()
{
    doc_id_mapping_ = string_list{index_name_ + files[DOC_IDS_MAPPING]};
}

void disk_index::disk_index_impl::load_term_id_mapping()
{
    term_id_mapping_ = vocabulary_map{index_name_ + files[TERM_IDS_MAPPING]};
}

void disk_index::disk_index_impl::load_label_id_mapping()
{
    map::load_mapping(label_ids_, index_name_ + files[LABEL_IDS_MAPPING]);
}

void disk_index::disk_index_impl::load_postings()
{
    postings_ = io::mmap_file{index_name_ + files[POSTINGS]};
}

void disk_index::disk_index_impl::save_label_id_mapping()
{
    map::save_mapping(label_ids_, index_name_ + files[LABEL_IDS_MAPPING]);
}

string_list_writer
    disk_index::disk_index_impl::make_doc_id_writer(uint64_t num_docs) const
{
    return {index_name_ + files[DOC_IDS_MAPPING], num_docs};
}

void disk_index::disk_index_impl::set_label(doc_id id, const class_label& label)
{
    (*labels_)[id] = get_label_id(label);
}

void disk_index::disk_index_impl::set_length(doc_id id, uint64_t length)
{
    (*doc_sizes_)[id] = length;
}

void disk_index::disk_index_impl::set_unique_terms(doc_id id, uint64_t terms)
{
    (*unique_terms_)[id] = terms;
}

const io::mmap_file& disk_index::disk_index_impl::postings() const
{
    return *postings_;
}

uint64_t disk_index::disk_index_impl::total_unique_terms() const
{
    return term_id_mapping_->size();
}

label_id disk_index::disk_index_impl::doc_label_id(doc_id id) const
{
    return labels_->at(id);
}

std::vector<class_label> disk_index::disk_index_impl::class_labels() const
{
    std::vector<class_label> labels;
    labels.reserve(label_ids_.size());
    for (const auto& pair : label_ids_)
        labels.emplace_back(pair.first);
    return labels;
}

std::string disk_index::term_text(term_id t_id) const
{
    if (t_id >= impl_->term_id_mapping_->size())
        return "";
    return impl_->term_id_mapping_->find_term(t_id);
}
}
}
<|endoftext|>


<commit_before>//===----------------------------------------------------------------------===//
//
//                         Peloton
//
// btree_index.cpp
//
// Identification: src/index/index_util.cpp
//
// Copyright (c) 2015-16, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//

#include <cassert>
#include <map>

#include "common/types.h"
#include "common/logger.h"
#include "common/value.h"
#include "common/value_factory.h"

#include "index/index_util.h"
#include "index/index.h"

namespace peloton {
namespace index {

/*
 * DefinesLowerBound() - Returns true if the expression is > or >= or ==
 *
 * Note: Since we consider equality (==) as both forward and backward
 * expression, when dealing with expression type both could be true
 *
 * NOTE 2: We put equality at the first to compare since we want a fast result
 * when it is equality (lazy evaluation)
 */
inline bool DefinesLowerBound(ExpressionType e) {
  // To reduce branch misprediction penalty
  return e == EXPRESSION_TYPE_COMPARE_EQUAL ||
         e == EXPRESSION_TYPE_COMPARE_GREATERTHAN ||
         e == EXPRESSION_TYPE_COMPARE_GREATERTHANOREQUALTO;
}

/*
 * DefinesUpperBound() - Returns true if the expression is < or <= or ==
 *
 * Please refer to DefinesLowerBound() for more information
 */
inline bool DefinesUpperBound(ExpressionType e) {
  return e == EXPRESSION_TYPE_COMPARE_EQUAL ||
         e == EXPRESSION_TYPE_COMPARE_LESSTHAN ||
         e == EXPRESSION_TYPE_COMPARE_LESSTHANOREQUALTO;
}

/*
 * HasNonOptimizablePredicate() - Check whether there are expressions that
 *                                cause the entire predicate non-optmizable
 *
 * This function simply checks whether there is any expression of the
 * following types that renders the scan predicate non-optmizable:
 *
 * NOTEQUAL
 * IN
 * LIKE
 * NOTLIKE
 *
 * If any of these appears as part of the scan predicate then we could
 * stop optimizing the predicate at the beginning. So this check serves
 * as a fast path
 *
 * Please refer to src/include/common/types.h for a complete list of comparison
 * operators
 */
bool HasNonOptimizablePredicate(const std::vector<ExpressionType> &expr_types) {
  for(auto t : expr_types) {
    if (t == EXPRESSION_TYPE_COMPARE_NOTEQUAL ||
        t == EXPRESSION_TYPE_COMPARE_IN       ||
        t == EXPRESSION_TYPE_COMPARE_LIKE     ||
        t == EXPRESSION_TYPE_COMPARE_NOTLIKE) {
      return false;
    }
  }

  return true;
}

/*
 * IsPointQuery() - Check whether a predicate scan is point query
 *
 * Point query may be implemented by the index as a more efficient
 * operation than scanning with a key, which is the case for BwTree.
 * Therefore, it is desirable for the index system to be albe to
 * identify point queries and optimize for them.
 *
 * NOTE: This function checks whether all expression types are equality
 * and also it checks WHETHER THE COLUMN ID LIST COVERS ALL COLUMNS IN
 * THE INDEX KEY. Since it is possible that some columns are left not bounded
 * by the predicate in which case even if all predicates are equal on
 * the remaining columns, it is not a point query
 *
 * The tuple column id list complies with the following protocol between
 * the optimizer and index wrapper:
 *   1. tuple_column_id_list contains indices into tuple key schema rather
 *      than the key schema
 *   2. tuple_column_id_list contains indices only for columns that are indexed
 *      For those columns not indexed by the current metadata they shall not
 *      appear
 *   3. tuple_column_id_list is not sorted by any means
 *   4. tuple_column_id_list may have duplicated entries, because
 *     4.1 there might be more than one predicate on the same column, e.g.
 *         a > 5 AND a < 3
 *     4.2 there might be duplicated (malformed) input from the user, e.g.
 *         a == 5 AND a== 3; a == 5 AND a > 10. It is assumed that such
 *         malformed expressions are not removed by the optimizer, but they
 *         should be filtered out by the executor (which keeps a separate
 *         predicate)
 */
bool IsPointQuery(const IndexMetadata *metadata_p,
                  const std::vector<oid_t> &tuple_column_id_list,
                  const std::vector<ExpressionType> &expr_list) {

  // Number of columns in index key
  size_t index_column_count = metadata_p->GetColumnCount();

  // This is an array of length of the key columns
  // We use this to track whether all columns have at least
  // an equality constraint
  //
  // NOTE: It could have more than one constraint in this case,
  // e.g. a == 10 AND a > 20, which will resolve to empty set
  // but anyway we do the scan, and let the executor to filter it out
  bool has_equality[index_column_count];

  // Initialize all values to false
  std::fill(has_equality, has_equality + index_column_count, false);

  // This is used to count how many index columns have an "==" predicate
  size_t counter = 0;
  for(oid_t i = 0;i < tuple_column_id_list.size();i++) {

    // If the constraint type is not equal then continue to the next
    if(expr_list[i] != EXPRESSION_TYPE_COMPARE_EQUAL) {
      continue;
    }

    oid_t tuple_column_id = tuple_column_id_list[i];

    // Map tuple column to index column
    oid_t index_column_id = \
      metadata_p->GetTupleToIndexMapping()[tuple_column_id];

    PL_ASSERT(index_column_id < index_column_count);

    // If there is a column not yet seen an equality then
    // make it true and increase counter
    if(has_equality[index_column_id] == false) {
      counter++;

      // If after increment the counter reaches index col count
      // then we know all columns are "==" since we never increase
      // counter twice for the same column
      if(counter == index_column_count) {
        return true;
      }

      // We only write memory at the end of loop to save
      // the last memory write which could be avoided
      has_equality[index_column_id] = true;
    }
  }

  return false;
}

/*
 * ValuePairComparator() - Compares std::pair<Value, int>
 *
 * Values are compared first and if not equal return result
 * If values are equal then compare the second element which is an int
 * and return the result
 */
bool ValuePairComparator(const std::pair<peloton::Value, int> &i,
                         const std::pair<peloton::Value, int> &j) {

  // If first elements are equal then compare the second element
  if (i.first.Compare(j.first) == VALUE_COMPARE_EQUAL) {
    return i.second < j.second;
  }

  // Otherwise compare the first element for "<" or ">"
  return i.first.Compare(j.first) == VALUE_COMPARE_LESSTHAN;
}

void ConstructIntervals(oid_t leading_column_id,
                        const std::vector<Value> &values,
                        const std::vector<oid_t> &key_column_ids,
                        const std::vector<ExpressionType> &expr_types,
                        std::vector<std::pair<Value, Value>> &intervals) {
  // Find all contrains of leading column.
  // Equal --> > < num
  // > >= --->  > num
  // < <= ----> < num
  std::vector<std::pair<peloton::Value, int>> nums;
  for (size_t i = 0; i < key_column_ids.size(); i++) {
    if (key_column_ids[i] != leading_column_id) {
      continue;
    }

    // If leading column
    if (DefinesLowerBound(expr_types[i])) {
      nums.push_back(std::pair<Value, int>(values[i], -1));
    } else if (DefinesUpperBound(expr_types[i])) {
      nums.push_back(std::pair<Value, int>(values[i], 1));
    } else {
      // Currently if it is not >  < <= then it must be ==
      // *** I could not find BETWEEN expression in types.h so did not add it
      // into the list
      PL_ASSERT(expr_types[i] == EXPRESSION_TYPE_COMPARE_EQUAL);

      nums.push_back(std::pair<Value, int>(values[i], -1));
      nums.push_back(std::pair<Value, int>(values[i], 1));
    }
  }

  // Have merged all constraints in a single line, sort this line.
  std::sort(nums.begin(), nums.end(), ValuePairComparator);

  // This enforces that there must be at least one constraint on the
  // leading column, if the search is eligible for optimization
  PL_ASSERT(nums.size() > 0);

  // Build intervals.
  Value cur;
  size_t i = 0;
  if (nums[0].second < 0) {
    cur = nums[0].first;
    i++;
  } else {
    cur = Value::GetMinValue(nums[0].first.GetValueType());
  }

  while (i < nums.size()) {
    if (nums[i].second > 0) {
      if (i + 1 < nums.size() && nums[i + 1].second < 0) {
        // right value
        intervals.push_back(std::pair<Value, Value>(cur, nums[i].first));
        cur = nums[i + 1].first;
      } else if (i + 1 == nums.size()) {
        // Last value while right value
        intervals.push_back(std::pair<Value, Value>(cur, nums[i].first));
        cur = Value::GetNullValue(nums[0].first.GetValueType());
      }
    }
    i++;
  }

  if (cur.IsNull() == false) {
    intervals.push_back(std::pair<Value, Value>(
        cur, Value::GetMaxValue(nums[0].first.GetValueType())));
  }

  // Finish invtervals building.
};

void FindMaxMinInColumns(oid_t leading_column_id,
                         const std::vector<Value> &values,
                         const std::vector<oid_t> &key_column_ids,
                         const std::vector<ExpressionType> &expr_types,
                         std::map<oid_t, std::pair<Value, Value>> &non_leading_columns) {
  // find extreme nums on each column.
  LOG_TRACE("FindMinMax leading column %d\n", leading_column_id);
  for (size_t i = 0; i < key_column_ids.size(); i++) {
    oid_t column_id = key_column_ids[i];
    if (column_id == leading_column_id) {
      continue;
    }

    if (non_leading_columns.find(column_id) == non_leading_columns.end()) {
      auto type = values[i].GetValueType();
      // std::pair<Value, Value> *range = new std::pair<Value,
      // Value>(Value::GetMaxValue(type),
      //                                            Value::GetMinValue(type));
      // std::pair<oid_t, std::pair<Value, Value>> key_value(column_id, range);
      non_leading_columns.insert(std::pair<oid_t, std::pair<Value, Value>>(
          column_id, std::pair<Value, Value>(Value::GetNullValue(type),
                                             Value::GetNullValue(type))));
      //  non_leading_columns[column_id] = *range;
      // delete range;
      LOG_TRACE("Insert a init bounds\tleft size %lu\t right description %s\n",
                non_leading_columns[column_id].first.GetInfo().size(),
                non_leading_columns[column_id].second.GetInfo().c_str());
    }

    if (DefinesLowerBound(expr_types[i]) ||
        expr_types[i] == EXPRESSION_TYPE_COMPARE_EQUAL) {
      LOG_TRACE("min cur %lu compare with %s\n",
                non_leading_columns[column_id].first.GetInfo().size(),
                values[i].GetInfo().c_str());
      if (non_leading_columns[column_id].first.IsNull() ||
          non_leading_columns[column_id].first.Compare(values[i]) ==
              VALUE_COMPARE_GREATERTHAN) {
        LOG_TRACE("Update min\n");
        non_leading_columns[column_id].first =
            ValueFactory::Clone(values[i], nullptr);
      }
    }

    if (DefinesUpperBound(expr_types[i]) ||
        expr_types[i] == EXPRESSION_TYPE_COMPARE_EQUAL) {
      LOG_TRACE("max cur %s compare with %s\n",
                non_leading_columns[column_id].second.GetInfo().c_str(),
                values[i].GetInfo().c_str());
      if (non_leading_columns[column_id].first.IsNull() ||
          non_leading_columns[column_id].second.Compare(values[i]) ==
              VALUE_COMPARE_LESSTHAN) {
        LOG_TRACE("Update max\n");
        non_leading_columns[column_id].second =
            ValueFactory::Clone(values[i], nullptr);
      }
    }
  }

  // check if min value is right bound or max value is left bound, if so, update
  for (const auto &k_v : non_leading_columns) {
    if (k_v.second.first.IsNull()) {
      non_leading_columns[k_v.first].first =
          Value::GetMinValue(k_v.second.first.GetValueType());
    }
    if (k_v.second.second.IsNull()) {
      non_leading_columns[k_v.first].second =
          Value::GetMaxValue(k_v.second.second.GetValueType());
    }
  }
};

}  // End index namespace
}  // End peloton namespace
<commit_msg>Adding one more assertion on the length of column ids and expressions<commit_after>//===----------------------------------------------------------------------===//
//
//                         Peloton
//
// btree_index.cpp
//
// Identification: src/index/index_util.cpp
//
// Copyright (c) 2015-16, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//

#include <cassert>
#include <map>

#include "common/types.h"
#include "common/logger.h"
#include "common/value.h"
#include "common/value_factory.h"

#include "index/index_util.h"
#include "index/index.h"

namespace peloton {
namespace index {

/*
 * DefinesLowerBound() - Returns true if the expression is > or >= or ==
 *
 * Note: Since we consider equality (==) as both forward and backward
 * expression, when dealing with expression type both could be true
 *
 * NOTE 2: We put equality at the first to compare since we want a fast result
 * when it is equality (lazy evaluation)
 */
inline bool DefinesLowerBound(ExpressionType e) {
  // To reduce branch misprediction penalty
  return e == EXPRESSION_TYPE_COMPARE_EQUAL ||
         e == EXPRESSION_TYPE_COMPARE_GREATERTHAN ||
         e == EXPRESSION_TYPE_COMPARE_GREATERTHANOREQUALTO;
}

/*
 * DefinesUpperBound() - Returns true if the expression is < or <= or ==
 *
 * Please refer to DefinesLowerBound() for more information
 */
inline bool DefinesUpperBound(ExpressionType e) {
  return e == EXPRESSION_TYPE_COMPARE_EQUAL ||
         e == EXPRESSION_TYPE_COMPARE_LESSTHAN ||
         e == EXPRESSION_TYPE_COMPARE_LESSTHANOREQUALTO;
}

/*
 * HasNonOptimizablePredicate() - Check whether there are expressions that
 *                                cause the entire predicate non-optmizable
 *
 * This function simply checks whether there is any expression of the
 * following types that renders the scan predicate non-optmizable:
 *
 * NOTEQUAL
 * IN
 * LIKE
 * NOTLIKE
 *
 * If any of these appears as part of the scan predicate then we could
 * stop optimizing the predicate at the beginning. So this check serves
 * as a fast path
 *
 * Please refer to src/include/common/types.h for a complete list of comparison
 * operators
 */
bool HasNonOptimizablePredicate(const std::vector<ExpressionType> &expr_types) {
  for(auto t : expr_types) {
    if (t == EXPRESSION_TYPE_COMPARE_NOTEQUAL ||
        t == EXPRESSION_TYPE_COMPARE_IN       ||
        t == EXPRESSION_TYPE_COMPARE_LIKE     ||
        t == EXPRESSION_TYPE_COMPARE_NOTLIKE) {
      return false;
    }
  }

  return true;
}

/*
 * IsPointQuery() - Check whether a predicate scan is point query
 *
 * Point query may be implemented by the index as a more efficient
 * operation than scanning with a key, which is the case for BwTree.
 * Therefore, it is desirable for the index system to be albe to
 * identify point queries and optimize for them.
 *
 * NOTE: This function checks whether all expression types are equality
 * and also it checks WHETHER THE COLUMN ID LIST COVERS ALL COLUMNS IN
 * THE INDEX KEY. Since it is possible that some columns are left not bounded
 * by the predicate in which case even if all predicates are equal on
 * the remaining columns, it is not a point query
 *
 * The tuple column id list complies with the following protocol between
 * the optimizer and index wrapper:
 *   1. tuple_column_id_list contains indices into tuple key schema rather
 *      than the key schema
 *   2. tuple_column_id_list contains indices only for columns that are indexed
 *      For those columns not indexed by the current metadata they shall not
 *      appear
 *   3. tuple_column_id_list is not sorted by any means
 *   4. tuple_column_id_list may have duplicated entries, because
 *     4.1 there might be more than one predicate on the same column, e.g.
 *         a > 5 AND a < 3
 *     4.2 there might be duplicated (malformed) input from the user, e.g.
 *         a == 5 AND a== 3; a == 5 AND a > 10. It is assumed that such
 *         malformed expressions are not removed by the optimizer, but they
 *         should be filtered out by the executor (which keeps a separate
 *         predicate)
 */
bool IsPointQuery(const IndexMetadata *metadata_p,
                  const std::vector<oid_t> &tuple_column_id_list,
                  const std::vector<ExpressionType> &expr_list) {

  // Make sure these two are consistent at least on legnth
  assert(tuple_column_id_list.size() == expr_list.size());

  // Number of columns in index key
  size_t index_column_count = metadata_p->GetColumnCount();

  // This is an array of length of the key columns
  // We use this to track whether all columns have at least
  // an equality constraint
  //
  // NOTE: It could have more than one constraint in this case,
  // e.g. a == 10 AND a > 20, which will resolve to empty set
  // but anyway we do the scan, and let the executor to filter it out
  bool has_equality[index_column_count];

  // Initialize all values to false
  std::fill(has_equality, has_equality + index_column_count, false);

  // This is used to count how many index columns have an "==" predicate
  size_t counter = 0;
  for(oid_t i = 0;i < tuple_column_id_list.size();i++) {

    // If the constraint type is not equal then continue to the next
    if(expr_list[i] != EXPRESSION_TYPE_COMPARE_EQUAL) {
      continue;
    }

    oid_t tuple_column_id = tuple_column_id_list[i];

    // Map tuple column to index column
    oid_t index_column_id = \
      metadata_p->GetTupleToIndexMapping()[tuple_column_id];

    // Make sure the mapping exists (i.e. the tuple column is in
    // index columns)
    PL_ASSERT(index_column_id != INVALID_OID);
    PL_ASSERT(index_column_id < index_column_count);

    // If there is a column not yet seen an equality then
    // make it true and increase counter
    if(has_equality[index_column_id] == false) {
      counter++;

      // If after increment the counter reaches index col count
      // then we know all columns are "==" since we never increase
      // counter twice for the same column
      if(counter == index_column_count) {
        return true;
      }

      // We only write memory at the end of loop to save
      // the last memory write which could be avoided
      has_equality[index_column_id] = true;
    }
  }

  return false;
}

/*
 * ValuePairComparator() - Compares std::pair<Value, int>
 *
 * Values are compared first and if not equal return result
 * If values are equal then compare the second element which is an int
 * and return the result
 */
bool ValuePairComparator(const std::pair<peloton::Value, int> &i,
                         const std::pair<peloton::Value, int> &j) {

  // If first elements are equal then compare the second element
  if (i.first.Compare(j.first) == VALUE_COMPARE_EQUAL) {
    return i.second < j.second;
  }

  // Otherwise compare the first element for "<" or ">"
  return i.first.Compare(j.first) == VALUE_COMPARE_LESSTHAN;
}

void ConstructIntervals(oid_t leading_column_id,
                        const std::vector<Value> &values,
                        const std::vector<oid_t> &key_column_ids,
                        const std::vector<ExpressionType> &expr_types,
                        std::vector<std::pair<Value, Value>> &intervals) {
  // Find all contrains of leading column.
  // Equal --> > < num
  // > >= --->  > num
  // < <= ----> < num
  std::vector<std::pair<peloton::Value, int>> nums;
  for (size_t i = 0; i < key_column_ids.size(); i++) {
    if (key_column_ids[i] != leading_column_id) {
      continue;
    }

    // If leading column
    if (DefinesLowerBound(expr_types[i])) {
      nums.push_back(std::pair<Value, int>(values[i], -1));
    } else if (DefinesUpperBound(expr_types[i])) {
      nums.push_back(std::pair<Value, int>(values[i], 1));
    } else {
      // Currently if it is not >  < <= then it must be ==
      // *** I could not find BETWEEN expression in types.h so did not add it
      // into the list
      PL_ASSERT(expr_types[i] == EXPRESSION_TYPE_COMPARE_EQUAL);

      nums.push_back(std::pair<Value, int>(values[i], -1));
      nums.push_back(std::pair<Value, int>(values[i], 1));
    }
  }

  // Have merged all constraints in a single line, sort this line.
  std::sort(nums.begin(), nums.end(), ValuePairComparator);

  // This enforces that there must be at least one constraint on the
  // leading column, if the search is eligible for optimization
  PL_ASSERT(nums.size() > 0);

  // Build intervals.
  Value cur;
  size_t i = 0;
  if (nums[0].second < 0) {
    cur = nums[0].first;
    i++;
  } else {
    cur = Value::GetMinValue(nums[0].first.GetValueType());
  }

  while (i < nums.size()) {
    if (nums[i].second > 0) {
      if (i + 1 < nums.size() && nums[i + 1].second < 0) {
        // right value
        intervals.push_back(std::pair<Value, Value>(cur, nums[i].first));
        cur = nums[i + 1].first;
      } else if (i + 1 == nums.size()) {
        // Last value while right value
        intervals.push_back(std::pair<Value, Value>(cur, nums[i].first));
        cur = Value::GetNullValue(nums[0].first.GetValueType());
      }
    }
    i++;
  }

  if (cur.IsNull() == false) {
    intervals.push_back(std::pair<Value, Value>(
        cur, Value::GetMaxValue(nums[0].first.GetValueType())));
  }

  // Finish invtervals building.
};

void FindMaxMinInColumns(oid_t leading_column_id,
                         const std::vector<Value> &values,
                         const std::vector<oid_t> &key_column_ids,
                         const std::vector<ExpressionType> &expr_types,
                         std::map<oid_t, std::pair<Value, Value>> &non_leading_columns) {
  // find extreme nums on each column.
  LOG_TRACE("FindMinMax leading column %d\n", leading_column_id);
  for (size_t i = 0; i < key_column_ids.size(); i++) {
    oid_t column_id = key_column_ids[i];
    if (column_id == leading_column_id) {
      continue;
    }

    if (non_leading_columns.find(column_id) == non_leading_columns.end()) {
      auto type = values[i].GetValueType();
      // std::pair<Value, Value> *range = new std::pair<Value,
      // Value>(Value::GetMaxValue(type),
      //                                            Value::GetMinValue(type));
      // std::pair<oid_t, std::pair<Value, Value>> key_value(column_id, range);
      non_leading_columns.insert(std::pair<oid_t, std::pair<Value, Value>>(
          column_id, std::pair<Value, Value>(Value::GetNullValue(type),
                                             Value::GetNullValue(type))));
      //  non_leading_columns[column_id] = *range;
      // delete range;
      LOG_TRACE("Insert a init bounds\tleft size %lu\t right description %s\n",
                non_leading_columns[column_id].first.GetInfo().size(),
                non_leading_columns[column_id].second.GetInfo().c_str());
    }

    if (DefinesLowerBound(expr_types[i]) ||
        expr_types[i] == EXPRESSION_TYPE_COMPARE_EQUAL) {
      LOG_TRACE("min cur %lu compare with %s\n",
                non_leading_columns[column_id].first.GetInfo().size(),
                values[i].GetInfo().c_str());
      if (non_leading_columns[column_id].first.IsNull() ||
          non_leading_columns[column_id].first.Compare(values[i]) ==
              VALUE_COMPARE_GREATERTHAN) {
        LOG_TRACE("Update min\n");
        non_leading_columns[column_id].first =
            ValueFactory::Clone(values[i], nullptr);
      }
    }

    if (DefinesUpperBound(expr_types[i]) ||
        expr_types[i] == EXPRESSION_TYPE_COMPARE_EQUAL) {
      LOG_TRACE("max cur %s compare with %s\n",
                non_leading_columns[column_id].second.GetInfo().c_str(),
                values[i].GetInfo().c_str());
      if (non_leading_columns[column_id].first.IsNull() ||
          non_leading_columns[column_id].second.Compare(values[i]) ==
              VALUE_COMPARE_LESSTHAN) {
        LOG_TRACE("Update max\n");
        non_leading_columns[column_id].second =
            ValueFactory::Clone(values[i], nullptr);
      }
    }
  }

  // check if min value is right bound or max value is left bound, if so, update
  for (const auto &k_v : non_leading_columns) {
    if (k_v.second.first.IsNull()) {
      non_leading_columns[k_v.first].first =
          Value::GetMinValue(k_v.second.first.GetValueType());
    }
    if (k_v.second.second.IsNull()) {
      non_leading_columns[k_v.first].second =
          Value::GetMaxValue(k_v.second.second.GetValueType());
    }
  }
};

}  // End index namespace
}  // End peloton namespace
<|endoftext|>