<commit_before>/*
 Copyright (c) 2010, The Barbarian Group
 All rights reserved.

 Redistribution and use in source and binary forms, with or without modification, are permitted provided that
 the following conditions are met:

    * Redistributions of source code must retain the above copyright notice, this list of conditions and
	the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
	the following disclaimer in the documentation and/or other materials provided with the distribution.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.
*/

#include "cinder/app/App.h"
#include "cinder/params/Params.h"

#include "AntTweakBar.h"

#include <boost/assign/list_of.hpp>

using namespace std;

namespace cinder { namespace params {

namespace {

#undef DELETE

#define SYNONYM(ck,ak) ((int)cinder::app::KeyEvent::KEY_ ## ck, TW_KEY_ ## ak)
#define HOMONYM(k) SYNONYM(k,k)
    std::map<int,TwKeySpecial> specialKeys = boost::assign::map_list_of
        HOMONYM(RIGHT)
        HOMONYM(LEFT)
        HOMONYM(BACKSPACE)
        HOMONYM(DELETE)
        HOMONYM(TAB)
        HOMONYM(F1)
        HOMONYM(F2)
        HOMONYM(F3)
        HOMONYM(F4)
        HOMONYM(F5)
        HOMONYM(F6)
        HOMONYM(F7)
        HOMONYM(F8)
        HOMONYM(F9)
        HOMONYM(F10)
        HOMONYM(F11)
        HOMONYM(F12)
        HOMONYM(F13)
        HOMONYM(F14)
        HOMONYM(F15)
        HOMONYM(HOME)
        HOMONYM(END)
        SYNONYM(PAGEUP,PAGE_UP)
        SYNONYM(PAGEDOWN,PAGE_DOWN)
        ;
#undef SYNONYM
#undef HOMONYM

bool mouseDown( app::MouseEvent event )
{
	TwMouseButtonID button;
	if( event.isLeft() )
		button = TW_MOUSE_LEFT;
	else if( event.isRight() )
		button = TW_MOUSE_RIGHT;
	else
		button = TW_MOUSE_MIDDLE;
	return TwMouseButton( TW_MOUSE_PRESSED, button ) != 0;
}

bool mouseUp( app::MouseEvent event )
{
	TwMouseButtonID button;
	if( event.isLeft() )
		button = TW_MOUSE_LEFT;
	else if( event.isRight() )
		button = TW_MOUSE_RIGHT;
	else
		button = TW_MOUSE_MIDDLE;
	return TwMouseButton( TW_MOUSE_RELEASED, button ) != 0;
}

bool mouseWheel( app::MouseEvent event )
{
	static float sWheelPos = 0;
	sWheelPos += event.getWheelIncrement();
	return TwMouseWheel( (int)(sWheelPos) ) != 0;
}

bool mouseMove( app::MouseEvent event )
{
	return TwMouseMotion( event.getX(), event.getY() ) != 0;
}

bool keyDown( app::KeyEvent event )
{
	int kmod = 0;
	if( event.isShiftDown() )
		kmod |= TW_KMOD_SHIFT;
	if( event.isControlDown() )
		kmod |= TW_KMOD_CTRL;
	if( event.isAltDown() )
		kmod |= TW_KMOD_ALT;
	return TwKeyPressed(
            (specialKeys.count( event.getCode() ) > 0)
                ? specialKeys[event.getCode()]
                : event.getChar(),
            kmod ) != 0;
}

bool resize( cinder::app::WindowRef window )
{
	TwWindowSize( window->getWidth(), window->getHeight() );
	return false;
}

void TW_CALL implStdStringToClient( std::string& destinationClientString, const std::string& sourceLibraryString )
{
  // copy strings from the library to the client app
  destinationClientString = sourceLibraryString;
}

class AntMgr {
  public:
	AntMgr() {
		if( ! TwInit( TW_OPENGL, NULL ) ) {
			throw Exception();
		}
	}

	~AntMgr() {
		TwTerminate();
	}
};

} // anonymous namespace

void initAntGl()
{
	static std::shared_ptr<AntMgr> mgr;
	if( ! mgr )
		mgr = std::shared_ptr<AntMgr>( new AntMgr );
}

InterfaceGl::InterfaceGl( const std::string &title, const Vec2i &size, const ColorA color )
{
	init( app::App::get()->getWindow(), title, size, color );
}

InterfaceGl::InterfaceGl( app::WindowRef window, const std::string &title, const Vec2i &size, const ColorA color )
{
	init( window, title, size, color );
}

void InterfaceGl::init( app::WindowRef window, const std::string &title, const Vec2i &size, const ColorA color )
{
	initAntGl();

	mWindow = window;

	mBar = std::shared_ptr<TwBar>( TwNewBar( title.c_str() ), TwDeleteBar );
	char optionsStr[1024];
	sprintf( optionsStr, "`%s` size='%d %d' color='%d %d %d' alpha=%d", title.c_str(), size.x, size.y, (int)(color.r * 255), (int)(color.g * 255), (int)(color.b * 255), (int)(color.a * 255) );
	TwDefine( optionsStr );

	TwCopyStdStringToClientFunc( implStdStringToClient );

	mWindow->getSignalMouseDown().connect( mouseDown );
	mWindow->getSignalMouseUp().connect( mouseUp );
	mWindow->getSignalMouseWheel().connect( mouseWheel );
	mWindow->getSignalMouseMove().connect( mouseMove );
	mWindow->getSignalMouseDrag().connect( mouseMove );
	mWindow->getSignalKeyDown().connect( keyDown );
	mWindow->getSignalResize().connect( std::bind( resize, mWindow ) );
}

void InterfaceGl::draw()
{
	TwDraw();
}

void InterfaceGl::show( bool visible )
{
	int32_t visibleInt = ( visible ) ? 1 : 0;
	TwSetParam( mBar.get(), NULL, "visible", TW_PARAM_INT32, 1, &visibleInt );
}

void InterfaceGl::hide()
{
	int32_t visibleInt = 0;
	TwSetParam( mBar.get(), NULL, "visible", TW_PARAM_INT32, 1, &visibleInt );
}

bool InterfaceGl::isVisible() const
{
	int32_t visibleInt;
	TwGetParam( mBar.get(), NULL, "visible", TW_PARAM_INT32, 1, &visibleInt );
	return visibleInt != 0;
}

void InterfaceGl::implAddParam( const std::string &name, void *param, int type, const std::string &optionsStr, bool readOnly )
{
	if( readOnly )
		TwAddVarRO( mBar.get(), name.c_str(), (TwType)type, param, optionsStr.c_str() );
	else
		TwAddVarRW( mBar.get(), name.c_str(), (TwType)type, param, optionsStr.c_str() );
}

void InterfaceGl::addParam( const std::string &name, bool *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_BOOLCPP, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, float *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_FLOAT, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, double *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_DOUBLE, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, int32_t *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_INT32, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, Vec3f *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_DIR3F, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, Quatf *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_QUAT4F, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, Color *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_COLOR3F, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, ColorA *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_COLOR4F, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, std::string *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_STDSTRING, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, const std::vector<std::string> &enumNames, int *param, const std::string &optionsStr, bool readOnly )
{
	TwEnumVal *ev = new TwEnumVal[enumNames.size()];
	for( size_t v = 0; v < enumNames.size(); ++v ) {
		ev[v].Value = v;
		ev[v].Label = const_cast<char*>( enumNames[v].c_str() );
	}

	TwType evType = TwDefineEnum( (name + "EnumType").c_str(), ev, enumNames.size() );

	if( readOnly )
		TwAddVarRO( mBar.get(), name.c_str(), evType, param, optionsStr.c_str() );
	else
		TwAddVarRW( mBar.get(), name.c_str(), evType, param, optionsStr.c_str() );

	delete [] ev;
}

void InterfaceGl::addSeparator( const std::string &name, const std::string &optionsStr )
{
	TwAddSeparator( mBar.get(), name.c_str(), optionsStr.c_str() );
}

void InterfaceGl::addText( const std::string &name, const std::string &optionsStr )
{
	TwAddButton( mBar.get(), name.c_str(), NULL, NULL, optionsStr.c_str() );
}

namespace { // anonymous namespace
void TW_CALL implButtonCallback( void *clientData )
{
	std::function<void ()> *fn = reinterpret_cast<std::function<void ()>*>( clientData );
	(*fn)();
}
} // anonymous namespace

void InterfaceGl::addButton( const std::string &name, const std::function<void ()> &callback, const std::string &optionsStr )
{
	std::shared_ptr<std::function<void ()> > callbackPtr( new std::function<void ()>( callback ) );
	mButtonCallbacks.push_back( callbackPtr );
	TwAddButton( mBar.get(), name.c_str(), implButtonCallback, (void*)callbackPtr.get(), optionsStr.c_str() );
}

void InterfaceGl::removeParam( const std::string &name )
{
	TwRemoveVar( mBar.get(), name.c_str() );
}

void InterfaceGl::clear()
{
	TwRemoveAllVars( mBar.get() );
}

void InterfaceGl::setOptions( const std::string &name, const std::string &optionsStr )
{
	std::string target = "`" + (std::string)TwGetBarName( mBar.get() ) + "`";
	if( !( name.empty() ) )
		target += "/`" + name + "`";

	TwDefine( ( target + " " + optionsStr ).c_str() );
}

} } // namespace cinder::params
<commit_msg>Fixing issue where InterfaceGl was not capturing events properly<commit_after>/*
 Copyright (c) 2010, The Barbarian Group
 All rights reserved.

 Redistribution and use in source and binary forms, with or without modification, are permitted provided that
 the following conditions are met:

    * Redistributions of source code must retain the above copyright notice, this list of conditions and
	the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
	the following disclaimer in the documentation and/or other materials provided with the distribution.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.
*/

#include "cinder/app/App.h"
#include "cinder/params/Params.h"

#include "AntTweakBar.h"

#include <boost/assign/list_of.hpp>

using namespace std;

namespace cinder { namespace params {

namespace {

#undef DELETE

#define SYNONYM(ck,ak) ((int)cinder::app::KeyEvent::KEY_ ## ck, TW_KEY_ ## ak)
#define HOMONYM(k) SYNONYM(k,k)
    std::map<int,TwKeySpecial> specialKeys = boost::assign::map_list_of
        HOMONYM(RIGHT)
        HOMONYM(LEFT)
        HOMONYM(BACKSPACE)
        HOMONYM(DELETE)
        HOMONYM(TAB)
        HOMONYM(F1)
        HOMONYM(F2)
        HOMONYM(F3)
        HOMONYM(F4)
        HOMONYM(F5)
        HOMONYM(F6)
        HOMONYM(F7)
        HOMONYM(F8)
        HOMONYM(F9)
        HOMONYM(F10)
        HOMONYM(F11)
        HOMONYM(F12)
        HOMONYM(F13)
        HOMONYM(F14)
        HOMONYM(F15)
        HOMONYM(HOME)
        HOMONYM(END)
        SYNONYM(PAGEUP,PAGE_UP)
        SYNONYM(PAGEDOWN,PAGE_DOWN)
        ;
#undef SYNONYM
#undef HOMONYM

void mouseDown( app::MouseEvent &event )
{
	TwMouseButtonID button;
	if( event.isLeft() )
		button = TW_MOUSE_LEFT;
	else if( event.isRight() )
		button = TW_MOUSE_RIGHT;
	else
		button = TW_MOUSE_MIDDLE;
	event.setHandled( TwMouseButton( TW_MOUSE_PRESSED, button ) != 0 );
}

void mouseUp( app::MouseEvent &event )
{
	TwMouseButtonID button;
	if( event.isLeft() )
		button = TW_MOUSE_LEFT;
	else if( event.isRight() )
		button = TW_MOUSE_RIGHT;
	else
		button = TW_MOUSE_MIDDLE;
	event.setHandled( TwMouseButton( TW_MOUSE_RELEASED, button ) != 0 );
}

void mouseWheel( app::MouseEvent &event )
{
	static float sWheelPos = 0;
	sWheelPos += event.getWheelIncrement();
	event.setHandled( TwMouseWheel( (int)(sWheelPos) ) != 0 );
}

void mouseMove( app::MouseEvent &event )
{
	event.setHandled( TwMouseMotion( event.getX(), event.getY() ) != 0 );
}

void keyDown( app::KeyEvent &event )
{
	int kmod = 0;
	if( event.isShiftDown() )
		kmod |= TW_KMOD_SHIFT;
	if( event.isControlDown() )
		kmod |= TW_KMOD_CTRL;
	if( event.isAltDown() )
		kmod |= TW_KMOD_ALT;
	event.setHandled( TwKeyPressed(
            (specialKeys.count( event.getCode() ) > 0)
                ? specialKeys[event.getCode()]
                : event.getChar(),
            kmod ) != 0 );
}

void resize( cinder::app::WindowRef window )
{
	TwWindowSize( window->getWidth(), window->getHeight() );
}

void TW_CALL implStdStringToClient( std::string& destinationClientString, const std::string& sourceLibraryString )
{
  // copy strings from the library to the client app
  destinationClientString = sourceLibraryString;
}

class AntMgr {
  public:
	AntMgr() {
		if( ! TwInit( TW_OPENGL, NULL ) ) {
			throw Exception();
		}
	}

	~AntMgr() {
		TwTerminate();
	}
};

} // anonymous namespace

void initAntGl()
{
	static std::shared_ptr<AntMgr> mgr;
	if( ! mgr )
		mgr = std::shared_ptr<AntMgr>( new AntMgr );
}

InterfaceGl::InterfaceGl( const std::string &title, const Vec2i &size, const ColorA color )
{
	init( app::App::get()->getWindow(), title, size, color );
}

InterfaceGl::InterfaceGl( app::WindowRef window, const std::string &title, const Vec2i &size, const ColorA color )
{
	init( window, title, size, color );
}

void InterfaceGl::init( app::WindowRef window, const std::string &title, const Vec2i &size, const ColorA color )
{
	initAntGl();

	mWindow = window;

	mBar = std::shared_ptr<TwBar>( TwNewBar( title.c_str() ), TwDeleteBar );
	char optionsStr[1024];
	sprintf( optionsStr, "`%s` size='%d %d' color='%d %d %d' alpha=%d", title.c_str(), size.x, size.y, (int)(color.r * 255), (int)(color.g * 255), (int)(color.b * 255), (int)(color.a * 255) );
	TwDefine( optionsStr );

	TwCopyStdStringToClientFunc( implStdStringToClient );

	mWindow->getSignalMouseDown().connect( mouseDown );
	mWindow->getSignalMouseUp().connect( mouseUp );
	mWindow->getSignalMouseWheel().connect( mouseWheel );
	mWindow->getSignalMouseMove().connect( mouseMove );
	mWindow->getSignalMouseDrag().connect( mouseMove );
	mWindow->getSignalKeyDown().connect( keyDown );
	mWindow->getSignalResize().connect( std::bind( resize, mWindow ) );
}

void InterfaceGl::draw()
{
	TwDraw();
}

void InterfaceGl::show( bool visible )
{
	int32_t visibleInt = ( visible ) ? 1 : 0;
	TwSetParam( mBar.get(), NULL, "visible", TW_PARAM_INT32, 1, &visibleInt );
}

void InterfaceGl::hide()
{
	int32_t visibleInt = 0;
	TwSetParam( mBar.get(), NULL, "visible", TW_PARAM_INT32, 1, &visibleInt );
}

bool InterfaceGl::isVisible() const
{
	int32_t visibleInt;
	TwGetParam( mBar.get(), NULL, "visible", TW_PARAM_INT32, 1, &visibleInt );
	return visibleInt != 0;
}

void InterfaceGl::implAddParam( const std::string &name, void *param, int type, const std::string &optionsStr, bool readOnly )
{
	if( readOnly )
		TwAddVarRO( mBar.get(), name.c_str(), (TwType)type, param, optionsStr.c_str() );
	else
		TwAddVarRW( mBar.get(), name.c_str(), (TwType)type, param, optionsStr.c_str() );
}

void InterfaceGl::addParam( const std::string &name, bool *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_BOOLCPP, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, float *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_FLOAT, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, double *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_DOUBLE, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, int32_t *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_INT32, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, Vec3f *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_DIR3F, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, Quatf *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_QUAT4F, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, Color *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_COLOR3F, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, ColorA *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_COLOR4F, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, std::string *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_STDSTRING, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, const std::vector<std::string> &enumNames, int *param, const std::string &optionsStr, bool readOnly )
{
	TwEnumVal *ev = new TwEnumVal[enumNames.size()];
	for( size_t v = 0; v < enumNames.size(); ++v ) {
		ev[v].Value = v;
		ev[v].Label = const_cast<char*>( enumNames[v].c_str() );
	}

	TwType evType = TwDefineEnum( (name + "EnumType").c_str(), ev, enumNames.size() );

	if( readOnly )
		TwAddVarRO( mBar.get(), name.c_str(), evType, param, optionsStr.c_str() );
	else
		TwAddVarRW( mBar.get(), name.c_str(), evType, param, optionsStr.c_str() );

	delete [] ev;
}

void InterfaceGl::addSeparator( const std::string &name, const std::string &optionsStr )
{
	TwAddSeparator( mBar.get(), name.c_str(), optionsStr.c_str() );
}

void InterfaceGl::addText( const std::string &name, const std::string &optionsStr )
{
	TwAddButton( mBar.get(), name.c_str(), NULL, NULL, optionsStr.c_str() );
}

namespace { // anonymous namespace
void TW_CALL implButtonCallback( void *clientData )
{
	std::function<void ()> *fn = reinterpret_cast<std::function<void ()>*>( clientData );
	(*fn)();
}
} // anonymous namespace

void InterfaceGl::addButton( const std::string &name, const std::function<void ()> &callback, const std::string &optionsStr )
{
	std::shared_ptr<std::function<void ()> > callbackPtr( new std::function<void ()>( callback ) );
	mButtonCallbacks.push_back( callbackPtr );
	TwAddButton( mBar.get(), name.c_str(), implButtonCallback, (void*)callbackPtr.get(), optionsStr.c_str() );
}

void InterfaceGl::removeParam( const std::string &name )
{
	TwRemoveVar( mBar.get(), name.c_str() );
}

void InterfaceGl::clear()
{
	TwRemoveAllVars( mBar.get() );
}

void InterfaceGl::setOptions( const std::string &name, const std::string &optionsStr )
{
	std::string target = "`" + (std::string)TwGetBarName( mBar.get() ) + "`";
	if( !( name.empty() ) )
		target += "/`" + name + "`";

	TwDefine( ( target + " " + optionsStr ).c_str() );
}

} } // namespace cinder::params
<|endoftext|>


<commit_before>#include "LLVMCodeGen.h"

using namespace llvm;
using namespace codegen;

void LLVMCodeGen::visit(common::FloatPattern &Node) {
    auto PatVal = ConstantFP::get(getType(Node.RetTy), Node.Val);
    CurVal = Builder.CreateFCmpONE(PatVal, &*CurArg, "cmptmp");
}

void LLVMCodeGen::visit(common::IntPattern &Node) {
    auto PatVal = ConstantInt::get(getType(Node.RetTy), (uint64_t)Node.Val);
    CurVal = Builder.CreateICmpEQ(PatVal, &*CurArg, "cmptmp");
}

void LLVMCodeGen::visit(common::BoolPattern &Node) {
    auto PatVal = ConstantInt::get(getType(Node.RetTy), (uint64_t)Node.Val);
    CurVal = Builder.CreateICmpEQ(PatVal, &*CurArg, "cmptmp");
}

void LLVMCodeGen::visit(common::CharPattern &Node) {
    auto PatVal = ConstantInt::get(getType(Node.RetTy), (uint64_t)Node.Val);
    CurVal = Builder.CreateICmpEQ(PatVal, &*CurArg, "cmptmp");
}

void LLVMCodeGen::visit(common::IdPattern &Node) {
    CtxVals[Node.Val] = &*CurArg;
    CurVal = ConstantInt::get(Int1, 1);
}

void LLVMCodeGen::visit(common::WildPattern &Node) {
    CurVal = ConstantInt::get(Int1, 1);
}

void LLVMCodeGen::visit(common::TuplePattern &Node) {
    std::vector<llvm::Constant *> TupleVal;
    for (auto &Element : Node.Patterns) {
        Element->accept(*this);
        TupleVal.push_back((Constant *)CurVal);
    }

    auto ConstVal = ConstantStruct::get(getTupleType(Node.RetTy), TupleVal);
    CurVal = new GlobalVariable(*Module.get(), ConstVal->getType(), true,
                                GlobalVariable::ExternalLinkage, ConstVal);
}

void LLVMCodeGen::visit(common::ListPattern &Node) {
    std::vector<llvm::Constant *> ListData;

    for (auto &Element : Node.Patterns) {
        Element->accept(*this);
        ListData.push_back(static_cast<Constant *>(CurVal));
    }

    auto ListType = ArrayType::get(getType(Node.RetTy), Node.Patterns.size());
    auto ConstVal = ConstantArray::get(ListType, ListData);

    CurVal = new GlobalVariable(*Module.get(), ConstVal->getType(), true,
                                GlobalVariable::ExternalLinkage, ConstVal);
}

void LLVMCodeGen::visit(common::ParPattern &Node) {
    Node.Pat->accept(*this);
}
<commit_msg>llvm: change to c++ style cast<commit_after>#include "LLVMCodeGen.h"

using namespace llvm;
using namespace codegen;

void LLVMCodeGen::visit(common::FloatPattern &Node) {
    auto PatVal = ConstantFP::get(getType(Node.RetTy), Node.Val);
    CurVal = Builder.CreateFCmpONE(PatVal, &*CurArg, "cmptmp");
}

void LLVMCodeGen::visit(common::IntPattern &Node) {
    auto PatVal = ConstantInt::get(getType(Node.RetTy), (uint64_t)Node.Val);
    CurVal = Builder.CreateICmpEQ(PatVal, &*CurArg, "cmptmp");
}

void LLVMCodeGen::visit(common::BoolPattern &Node) {
    auto PatVal = ConstantInt::get(getType(Node.RetTy), (uint64_t)Node.Val);
    CurVal = Builder.CreateICmpEQ(PatVal, &*CurArg, "cmptmp");
}

void LLVMCodeGen::visit(common::CharPattern &Node) {
    auto PatVal = ConstantInt::get(getType(Node.RetTy), (uint64_t)Node.Val);
    CurVal = Builder.CreateICmpEQ(PatVal, &*CurArg, "cmptmp");
}

void LLVMCodeGen::visit(common::IdPattern &Node) {
    CtxVals[Node.Val] = &*CurArg;
    CurVal = ConstantInt::get(Int1, 1);
}

void LLVMCodeGen::visit(common::WildPattern &Node) {
    CurVal = ConstantInt::get(Int1, 1);
}

void LLVMCodeGen::visit(common::TuplePattern &Node) {
    std::vector<llvm::Constant *> TupleVal;
    for (auto &Element : Node.Patterns) {
        Element->accept(*this);
        TupleVal.push_back(static_cast<Constant *>(CurVal));
    }

    auto ConstVal = ConstantStruct::get(getTupleType(Node.RetTy), TupleVal);
    CurVal = new GlobalVariable(*Module.get(), ConstVal->getType(), true,
                                GlobalVariable::ExternalLinkage, ConstVal);
}

void LLVMCodeGen::visit(common::ListPattern &Node) {
    std::vector<llvm::Constant *> ListData;

    for (auto &Element : Node.Patterns) {
        Element->accept(*this);
        ListData.push_back(static_cast<Constant *>(CurVal));
    }

    auto ListType = ArrayType::get(getType(Node.RetTy), Node.Patterns.size());
    auto ConstVal = ConstantArray::get(ListType, ListData);

    CurVal = new GlobalVariable(*Module.get(), ConstVal->getType(), true,
                                GlobalVariable::ExternalLinkage, ConstVal);
}

void LLVMCodeGen::visit(common::ParPattern &Node) {
    Node.Pat->accept(*this);
}
<|endoftext|>


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

/*
This file is the implementation of the Model class.
*/

#include "src/data/model_parameters.h"

#include <string.h>
#include <pmmintrin.h>  // for SSE

#include "src/base/file_util.h"
#include "src/base/format_print.h"
#include "src/base/math.h"
#include "src/base/logging.h"
#include "src/base/stringprintf.h"

namespace xLearn {

//------------------------------------------------------------------------------
// The Model class
//------------------------------------------------------------------------------

// Basic contributor.
void Model::Initialize(const std::string& score_func,
                  const std::string& loss_func,
                  index_t num_feature,
                  index_t num_field,
                  index_t num_K,
                  index_t aux_size,
                  real_t scale) {
  CHECK(!score_func.empty());
  CHECK(!loss_func.empty());
  CHECK_GT(num_feature, 0);
  CHECK_GE(num_field, 0);
  CHECK_GE(num_K, 0);
  // The aux_size is used for different
  // optimization method
  CHECK_GE(aux_size, 0);
  CHECK_GT(scale, 0);
  score_func_ = score_func;
  loss_func_ = loss_func;
  num_feat_ = num_feature;
  num_field_ = num_field;
  num_K_ = num_K;
  aux_size_ = aux_size;
  scale_ = scale;
  // Calculate the number of model parameters
  param_num_w_ = num_feature * aux_size_;
  // latent vector
  if (score_func == "linear") {
    param_num_v_ = 0;
  } else if (score_func == "fm") {
    // fm: feature * K
    param_num_v_ = num_feature * get_aligned_k() * aux_size_;
  } else if (score_func == "ffm") {
    // ffm: feature * K * field
    param_num_v_ = num_feature * get_aligned_k() * num_field * aux_size_;
  } else {
    LOG(FATAL) << "Unknow score function: " << score_func;
  }
  this->initial(true);
}

// To get the best performance for SSE, we need to
// allocate memory for the model parameters in aligned way.
// For SSE, the align number should be 16 byte (kAlignByte).
void Model::initial(bool set_val) {
  try {
    // Conventional malloc for linear term and bias
    param_w_ = (real_t*)malloc(param_num_w_ * sizeof(real_t));
    param_b_ = (real_t*)malloc(aux_size_ * sizeof(real_t));
    if (score_func_.compare("fm") == 0 ||
        score_func_.compare("ffm") == 0) {
      // Aligned malloc for latent factor
#ifdef _WIN32
      param_v_ = _aligned_malloc(
                 param_num_v_ * sizeof(real_t),
                 kAlignByte);
#else
      int ret = posix_memalign(
                (void**)&param_v_,
                kAlignByte,
                param_num_v_ * sizeof(real_t));
      CHECK_EQ(ret, 0);
#endif
    } else {
      param_v_ = nullptr;
    }
  } catch (std::bad_alloc&) {
    LOG(FATAL) << "Cannot allocate enough memory for current  \
                   model parameters. Parameter size: "
               << GetNumParameter();
  }
  // Set value for model
  if (set_val) {
    set_value();
  }
}

// Set value for model
void Model::set_value() {
  // Use distribution to transform the random unsigned
  // int generated by gen into a float in [(0.0, 1.0) * coef]
  std::default_random_engine generator;
  std::uniform_real_distribution<real_t> dis(0.0, 1.0);
  /*********************************************************
   *  Initialize linear and bias term                      *
   *********************************************************/
  for (index_t i = 0; i < param_num_w_; i += aux_size_) {
    param_w_[i] = 0.0;        /* model */
    for (index_t j = 1; j < aux_size_; ++j) {
      param_w_[i+j] = 1.0;    /* gradient cache */
    }
  }
  param_b_[0] = 0.0;      /* model */
  for (index_t j = 1; j < aux_size_; ++j) {
    param_b_[j] = 1.0;    /* gradient cache */
  }
  /*********************************************************
   *  Initialize latent factor for fm                      *
   *********************************************************/
  if (score_func_.compare("fm") == 0) {
    index_t k_aligned = get_aligned_k();
    real_t coef = 1.0f / sqrt(num_K_) * scale_;
    real_t* w = param_v_;
    for (index_t j = 0; j < num_feat_; ++j) {
      for(index_t d = 0; d < num_K_; d++, w++) {
        *w = coef * dis(generator);  /* model */
      }
      for(index_t d = num_K_; d < k_aligned; d++, w++) {
        *w = 0;  /* Beyond aligned number */
      }
      for(index_t d = k_aligned; d < aux_size_*k_aligned; d++, w++) {
        *w = 1.0;  /* gradient cache */
      }
    }
  }
  /*********************************************************
   *  Initialize latent factor for ffm                     *
   *********************************************************/
  else if (score_func_.compare("ffm") == 0) {
    index_t k_aligned = get_aligned_k();
    real_t* w = param_v_;
    real_t coef = 1.0f / sqrt(num_K_) * scale_;
    for (index_t j = 0; j < num_feat_; ++j) {
      for (index_t f = 0; f < num_field_; ++f) {
        for (index_t d = 0; d < k_aligned; ) {
          for (index_t s = 0; s < kAlign; s++, w++, d++) {
            w[0] = (d < num_K_) ? coef * dis(generator) : 0.0; /* model */
            for (index_t j = 1; j < aux_size_; ++j) {
              w[kAlign * j] = 1.0; /* gradient cache */
            }
          }
          w += (aux_size_-1) * kAlign;
        }
      }
    }
  }
}

// Free the allocated memory
void Model::free_model() {
  free(param_w_);
  free(param_v_);
  free(param_b_);
  if (param_best_w_ != nullptr) {
    free(param_best_w_);
  }
  if (param_best_v_ != nullptr) {
    free(param_best_v_);
  }
  if (param_best_b_ != nullptr) {
    free(param_best_b_);
  }
}

// Initialize model from a checkpoint file
Model::Model(const std::string& filename) {
  CHECK_NE(filename.empty(), true);
  if (this->Deserialize(filename) == false) {
    Color::print_error(
      StringPrintf("Cannot Load model from the file: %s",
           filename.c_str())
    );
    exit(0);
  }
}

// Serialize current model to a disk file
void Model::Serialize(const std::string& filename) {
  CHECK_NE(filename.empty(), true);
  FILE* file = OpenFileOrDie(filename.c_str(), "w");
  // Write score function
  WriteStringToFile(file, score_func_);
  // Write loss function
  WriteStringToFile(file, loss_func_);
  // Write feature num
  WriteDataToDisk(file, (char*)&num_feat_, sizeof(num_feat_));
  // Write field num
  WriteDataToDisk(file, (char*)&num_field_, sizeof(num_field_));
  // Write K
  WriteDataToDisk(file, (char*)&num_K_, sizeof(num_K_));
  // Write aux_size
  WriteDataToDisk(file, (char*)&aux_size_, sizeof(aux_size_));
  // Write w
  this->serialize_w_v_b(file);
  Close(file);
}

// Serialize current model to a TXT file.
void Model::SerializeToTXT(const std::string& filename) {
  CHECK_NE(filename.empty(), true);
  std::ofstream o_file(filename);
  /*********************************************************
   *  Initialize linear and bias term                      *
   *********************************************************/
  // bias term
  o_file << "bias: " << param_b_[0] << "\n";
  // linear term
  index_t idx = 0;
  for (index_t i = 0; i < param_num_w_; i += aux_size_) {
    o_file << "i_" << idx << ": " << param_w_[i] << "\n";
    idx++;
  }
  /*********************************************************
   *  Initialize latent factor for fm                      *
   *********************************************************/
  if (score_func_.compare("fm") == 0) {
    index_t k_aligned = get_aligned_k();
    real_t* w = param_v_;
    for (index_t j = 0; j < num_feat_; ++j) {
      o_file << "v_" << j << ": ";
      for(index_t d = 0; d < num_K_; d++, w++) {
        o_file << *w;
        if (d != num_K_-1) {
          o_file << " ";
        }
      }
      o_file << "\n";
      // skip the rest parameters
      index_t skip = aux_size_*k_aligned-num_K_;
      w += skip;
    }
  }
  /*********************************************************
   *  Initialize latent factor for ffm                     *
   *********************************************************/
  if (score_func_.compare("ffm") == 0) {
    index_t k_aligned = get_aligned_k();
    real_t* w = param_v_;
    for (index_t j = 0; j < num_feat_; ++j) {
      for (index_t f = 0; f < num_field_; ++f) {
        o_file << "v_" << j << "_" << f << ": ";
        for (index_t d = 0; d < k_aligned; ) {
          for (index_t s = 0; s < kAlign; s++, w++, d++) {
            if (d < num_K_) {
              o_file << w[0];
              if (d != num_K_-1) {
                o_file << " ";
              }
            }
          }
          w += (aux_size_-1) * kAlign;
        }
        o_file << "\n";
      }
    }
  }
}

// Deserialize model from a checkpoint file
bool Model::Deserialize(const std::string& filename) {
  CHECK_NE(filename.empty(), true);
  FILE* file = OpenFileOrDie(filename.c_str(), "r");
  if (file == NULL) { return false; }
  // Read score function
  ReadStringFromFile(file, score_func_);
  // Read loss function
  ReadStringFromFile(file, loss_func_);
  // Read feature num
  ReadDataFromDisk(file, (char*)&num_feat_, sizeof(num_feat_));
  // Read field num
  ReadDataFromDisk(file, (char*)&num_field_, sizeof(num_field_));
  // Read K
  ReadDataFromDisk(file, (char*)&num_K_, sizeof(num_K_));
  // Read aux_size
  ReadDataFromDisk(file, (char*)&aux_size_, sizeof(aux_size_));
  // Read w
  this->deserialize_w_v_b(file);
  Close(file);
  return true;
}

// Take a record of the best model during training
void Model::SetBestModel() {
  try {
    if (param_best_w_ == nullptr) {
        param_best_w_ = (real_t*)malloc(
        param_num_w_*sizeof(real_t));
    }
    if (param_best_v_ == nullptr &&
        score_func_.compare("linear") != 0) {
  #ifdef _WIN32
        param_best_v_ = _aligned_malloc(
        param_num_v_ * sizeof(real_t),
        kAlignByte);
  #else
      int ret = posix_memalign(
                (void**)&param_best_v_,
                kAlignByte,
                param_num_v_ * sizeof(real_t));
      CHECK_EQ(ret, 0);
  #endif
    }
    if (param_best_b_ == nullptr) {
        param_best_b_ = (real_t*)malloc(
         aux_size_ * sizeof(real_t)
        );
    }
  } catch (std::bad_alloc&) {
    LOG(FATAL) << "Cannot allocate enough memory for current  \
                   model parameters. Parameter size: "
               << GetNumParameter();
  }
  // Copy current model parameters
  memcpy(param_best_w_, param_w_, param_num_w_*sizeof(real_t));
  memcpy(param_best_v_, param_v_, param_num_v_*sizeof(real_t));
  memcpy(param_best_b_, param_b_, aux_size_*sizeof(real_t));
}

// Shrink back for getting the best model
void Model::Shrink() {
  // Copy best model parameters
  if (param_best_w_ != nullptr) {
    memcpy(param_w_, param_best_w_, param_num_w_*sizeof(real_t));
  }
  if (param_best_v_ != nullptr) {
    memcpy(param_v_, param_best_v_, param_num_v_*sizeof(real_t));
  }
  if (param_best_b_ != nullptr) {
    memcpy(param_b_, param_best_b_, aux_size_*sizeof(real_t));
  }
}

// Serialize w,v,b to disk file
void Model::serialize_w_v_b(FILE* file) {
  // Write size of w
  WriteDataToDisk(file, (char*)&param_num_w_, sizeof(param_num_w_));
  // Write size of v
  if (score_func_.compare("linear") != 0) {
    WriteDataToDisk(file, (char*)&param_num_v_, sizeof(param_num_v_));
  }
  // Write w
  WriteDataToDisk(file, (char*)param_w_, sizeof(real_t)*param_num_w_);
  // Write b
  WriteDataToDisk(file, (char*)param_b_, sizeof(real_t)*aux_size_);
  // Write v
  if (score_func_.compare("linear") != 0) {
    WriteDataToDisk(file, (char*)param_v_, sizeof(real_t)*param_num_v_);
  }
}

// Deserialize w,v,b from disk file
void Model::deserialize_w_v_b(FILE* file) {
  // Read size of w
  ReadDataFromDisk(file, (char*)&param_num_w_, sizeof(param_num_w_));
  // Read size of v
  if (score_func_.compare("linear") != 0) {
    ReadDataFromDisk(file, (char*)&param_num_v_, sizeof(param_num_v_));
  }
  // Allocate memory. Don't set value here
  this->initial(false);
  // Read w
  ReadDataFromDisk(file, (char*)param_w_, sizeof(real_t)*param_num_w_);
  // Read b
  ReadDataFromDisk(file, (char*)param_b_, sizeof(real_t)*aux_size_);
  // Read v
  if (score_func_.compare("linear") != 0) {
    ReadDataFromDisk(file, (char*)param_v_, sizeof(real_t)*param_num_v_);
  }
}

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

/*
This file is the implementation of the Model class.
*/

#include "src/data/model_parameters.h"

#include <string.h>
#include <pmmintrin.h>  // for SSE

#include "src/base/file_util.h"
#include "src/base/format_print.h"
#include "src/base/math.h"
#include "src/base/logging.h"
#include "src/base/stringprintf.h"

namespace xLearn {

//------------------------------------------------------------------------------
// The Model class
//------------------------------------------------------------------------------

// Basic contributor.
void Model::Initialize(const std::string& score_func,
                  const std::string& loss_func,
                  index_t num_feature,
                  index_t num_field,
                  index_t num_K,
                  index_t aux_size,
                  real_t scale) {
  CHECK(!score_func.empty());
  CHECK(!loss_func.empty());
  CHECK_GT(num_feature, 0);
  CHECK_GE(num_field, 0);
  CHECK_GE(num_K, 0);
  // The aux_size is used for different
  // optimization method
  CHECK_GE(aux_size, 0);
  CHECK_GT(scale, 0);
  score_func_ = score_func;
  loss_func_ = loss_func;
  num_feat_ = num_feature;
  num_field_ = num_field;
  num_K_ = num_K;
  aux_size_ = aux_size;
  scale_ = scale;
  // Calculate the number of model parameters
  param_num_w_ = num_feature * aux_size_;
  // latent vector
  if (score_func == "linear") {
    param_num_v_ = 0;
  } else if (score_func == "fm") {
    // fm: feature * K
    param_num_v_ = num_feature * get_aligned_k() * aux_size_;
  } else if (score_func == "ffm") {
    // ffm: feature * K * field
    param_num_v_ = num_feature * get_aligned_k() * num_field * aux_size_;
  } else {
    LOG(FATAL) << "Unknow score function: " << score_func;
  }
  this->initial(true);
}

// To get the best performance for SSE, we need to
// allocate memory for the model parameters in aligned way.
// For SSE, the align number should be 16 byte (kAlignByte).
void Model::initial(bool set_val) {
  try {
    // Conventional malloc for linear term and bias
    param_w_ = (real_t*)malloc(param_num_w_ * sizeof(real_t));
    param_b_ = (real_t*)malloc(aux_size_ * sizeof(real_t));
    if (score_func_.compare("fm") == 0 ||
        score_func_.compare("ffm") == 0) {
      // Aligned malloc for latent factor
#ifdef _WIN32
      param_v_ = _aligned_malloc(
                 param_num_v_ * sizeof(real_t),
                 kAlignByte);
#else
      int ret = posix_memalign(
                (void**)&param_v_,
                kAlignByte,
                param_num_v_ * sizeof(real_t));
      CHECK_EQ(ret, 0);
#endif
    } else {
      param_v_ = nullptr;
    }
  } catch (std::bad_alloc&) {
    LOG(FATAL) << "Cannot allocate enough memory for current  \
                   model parameters. Parameter size: "
               << GetNumParameter();
  }
  // Set value for model
  if (set_val) {
    set_value();
  }
}

// Set value for model
void Model::set_value() {
  // Use distribution to transform the random unsigned
  // int generated by gen into a float in [(0.0, 1.0) * coef]
  std::default_random_engine generator;
  std::uniform_real_distribution<real_t> dis(0.0, 1.0);
  /*********************************************************
   *  Initialize linear and bias term                      *
   *********************************************************/
  for (index_t i = 0; i < param_num_w_; i += aux_size_) {
    param_w_[i] = 0.0;        /* model */
    for (index_t j = 1; j < aux_size_; ++j) {
      param_w_[i+j] = 1.0;    /* gradient cache */
    }
  }
  param_b_[0] = 0.0;      /* model */
  for (index_t j = 1; j < aux_size_; ++j) {
    param_b_[j] = 1.0;    /* gradient cache */
  }
  /*********************************************************
   *  Initialize latent factor for fm                      *
   *********************************************************/
  if (score_func_.compare("fm") == 0) {
    index_t k_aligned = get_aligned_k();
    real_t coef = 1.0f / sqrt(num_K_) * scale_;
    real_t* w = param_v_;
    for (index_t j = 0; j < num_feat_; ++j) {
      for(index_t d = 0; d < num_K_; d++, w++) {
        *w = coef * dis(generator);  /* model */
      }
      for(index_t d = num_K_; d < k_aligned; d++, w++) {
        *w = 0;  /* Beyond aligned number */
      }
      for(index_t d = k_aligned; d < aux_size_*k_aligned; d++, w++) {
        *w = 1.0;  /* gradient cache */
      }
    }
  }
  /*********************************************************
   *  Initialize latent factor for ffm                     *
   *********************************************************/
  else if (score_func_.compare("ffm") == 0) {
    index_t k_aligned = get_aligned_k();
    real_t* w = param_v_;
    real_t coef = 1.0f / sqrt(num_K_) * scale_;
    for (index_t j = 0; j < num_feat_; ++j) {
      for (index_t f = 0; f < num_field_; ++f) {
        for (index_t d = 0; d < k_aligned; ) {
          for (index_t s = 0; s < kAlign; s++, w++, d++) {
            w[0] = (d < num_K_) ? coef * dis(generator) : 0.0; /* model */
            for (index_t j = 1; j < aux_size_; ++j) {
              w[kAlign * j] = 1.0; /* gradient cache */
            }
          }
          w += (aux_size_-1) * kAlign;
        }
      }
    }
  }
}

// Free the allocated memory
void Model::free_model() {
  free(param_w_);
  free(param_v_);
  free(param_b_);
  if (param_best_w_ != nullptr) {
    free(param_best_w_);
  }
  if (param_best_v_ != nullptr) {
    free(param_best_v_);
  }
  if (param_best_b_ != nullptr) {
    free(param_best_b_);
  }
}

// Initialize model from a checkpoint file
Model::Model(const std::string& filename) {
  CHECK_NE(filename.empty(), true);
  if (this->Deserialize(filename) == false) {
    Color::print_error(
      StringPrintf("Cannot Load model from the file: %s",
           filename.c_str())
    );
    exit(0);
  }
}

// Serialize current model to a disk file
void Model::Serialize(const std::string& filename) {
  CHECK_NE(filename.empty(), true);
  FILE* file = OpenFileOrDie(filename.c_str(), "w");
  // Write score function
  WriteStringToFile(file, score_func_);
  // Write loss function
  WriteStringToFile(file, loss_func_);
  // Write feature num
  WriteDataToDisk(file, (char*)&num_feat_, sizeof(num_feat_));
  // Write field num
  WriteDataToDisk(file, (char*)&num_field_, sizeof(num_field_));
  // Write K
  WriteDataToDisk(file, (char*)&num_K_, sizeof(num_K_));
  // Write aux_size
  WriteDataToDisk(file, (char*)&aux_size_, sizeof(aux_size_));
  // Write w
  this->serialize_w_v_b(file);
  Close(file);
}

// Serialize current model to a TXT file.
void Model::SerializeToTXT(const std::string& filename) {
  CHECK_NE(filename.empty(), true);
  std::ofstream o_file(filename);
  /*********************************************************
   *  Write linear and bias term                      *
   *********************************************************/
  // bias term
  o_file << "bias: " << param_b_[0] << "\n";
  // linear term
  index_t idx = 0;
  for (index_t i = 0; i < param_num_w_; i += aux_size_) {
    o_file << "i_" << idx << ": " << param_w_[i] << "\n";
    idx++;
  }
  /*********************************************************
   *  Write latent factor for fm                      *
   *********************************************************/
  if (score_func_.compare("fm") == 0) {
    index_t k_aligned = get_aligned_k();
    real_t* w = param_v_;
    for (index_t j = 0; j < num_feat_; ++j) {
      o_file << "v_" << j << ": ";
      for(index_t d = 0; d < num_K_; d++, w++) {
        o_file << *w;
        if (d != num_K_-1) {
          o_file << " ";
        }
      }
      o_file << "\n";
      // skip the rest parameters
      index_t skip = aux_size_*k_aligned-num_K_;
      w += skip;
    }
  }
  /*********************************************************
   *  Write latent factor for ffm                     *
   *********************************************************/
  if (score_func_.compare("ffm") == 0) {
    index_t k_aligned = get_aligned_k();
    real_t* w = param_v_;
    for (index_t j = 0; j < num_feat_; ++j) {
      for (index_t f = 0; f < num_field_; ++f) {
        o_file << "v_" << j << "_" << f << ": ";
        for (index_t d = 0; d < k_aligned; ) {
          for (index_t s = 0; s < kAlign; s++, w++, d++) {
            if (d < num_K_) {
              o_file << w[0];
              if (d != num_K_-1) {
                o_file << " ";
              }
            }
          }
          w += (aux_size_-1) * kAlign;
        }
        o_file << "\n";
      }
    }
  }
}

// Deserialize model from a checkpoint file
bool Model::Deserialize(const std::string& filename) {
  CHECK_NE(filename.empty(), true);
  FILE* file = OpenFileOrDie(filename.c_str(), "r");
  if (file == NULL) { return false; }
  // Read score function
  ReadStringFromFile(file, score_func_);
  // Read loss function
  ReadStringFromFile(file, loss_func_);
  // Read feature num
  ReadDataFromDisk(file, (char*)&num_feat_, sizeof(num_feat_));
  // Read field num
  ReadDataFromDisk(file, (char*)&num_field_, sizeof(num_field_));
  // Read K
  ReadDataFromDisk(file, (char*)&num_K_, sizeof(num_K_));
  // Read aux_size
  ReadDataFromDisk(file, (char*)&aux_size_, sizeof(aux_size_));
  // Read w
  this->deserialize_w_v_b(file);
  Close(file);
  return true;
}

// Take a record of the best model during training
void Model::SetBestModel() {
  try {
    if (param_best_w_ == nullptr) {
        param_best_w_ = (real_t*)malloc(
        param_num_w_*sizeof(real_t));
    }
    if (param_best_v_ == nullptr &&
        score_func_.compare("linear") != 0) {
  #ifdef _WIN32
        param_best_v_ = _aligned_malloc(
        param_num_v_ * sizeof(real_t),
        kAlignByte);
  #else
      int ret = posix_memalign(
                (void**)&param_best_v_,
                kAlignByte,
                param_num_v_ * sizeof(real_t));
      CHECK_EQ(ret, 0);
  #endif
    }
    if (param_best_b_ == nullptr) {
        param_best_b_ = (real_t*)malloc(
         aux_size_ * sizeof(real_t)
        );
    }
  } catch (std::bad_alloc&) {
    LOG(FATAL) << "Cannot allocate enough memory for current  \
                   model parameters. Parameter size: "
               << GetNumParameter();
  }
  // Copy current model parameters
  memcpy(param_best_w_, param_w_, param_num_w_*sizeof(real_t));
  memcpy(param_best_v_, param_v_, param_num_v_*sizeof(real_t));
  memcpy(param_best_b_, param_b_, aux_size_*sizeof(real_t));
}

// Shrink back for getting the best model
void Model::Shrink() {
  // Copy best model parameters
  if (param_best_w_ != nullptr) {
    memcpy(param_w_, param_best_w_, param_num_w_*sizeof(real_t));
  }
  if (param_best_v_ != nullptr) {
    memcpy(param_v_, param_best_v_, param_num_v_*sizeof(real_t));
  }
  if (param_best_b_ != nullptr) {
    memcpy(param_b_, param_best_b_, aux_size_*sizeof(real_t));
  }
}

// Serialize w,v,b to disk file
void Model::serialize_w_v_b(FILE* file) {
  // Write size of w
  WriteDataToDisk(file, (char*)&param_num_w_, sizeof(param_num_w_));
  // Write size of v
  if (score_func_.compare("linear") != 0) {
    WriteDataToDisk(file, (char*)&param_num_v_, sizeof(param_num_v_));
  }
  // Write w
  WriteDataToDisk(file, (char*)param_w_, sizeof(real_t)*param_num_w_);
  // Write b
  WriteDataToDisk(file, (char*)param_b_, sizeof(real_t)*aux_size_);
  // Write v
  if (score_func_.compare("linear") != 0) {
    WriteDataToDisk(file, (char*)param_v_, sizeof(real_t)*param_num_v_);
  }
}

// Deserialize w,v,b from disk file
void Model::deserialize_w_v_b(FILE* file) {
  // Read size of w
  ReadDataFromDisk(file, (char*)&param_num_w_, sizeof(param_num_w_));
  // Read size of v
  if (score_func_.compare("linear") != 0) {
    ReadDataFromDisk(file, (char*)&param_num_v_, sizeof(param_num_v_));
  }
  // Allocate memory. Don't set value here
  this->initial(false);
  // Read w
  ReadDataFromDisk(file, (char*)param_w_, sizeof(real_t)*param_num_w_);
  // Read b
  ReadDataFromDisk(file, (char*)param_b_, sizeof(real_t)*aux_size_);
  // Read v
  if (score_func_.compare("linear") != 0) {
    ReadDataFromDisk(file, (char*)param_v_, sizeof(real_t)*param_num_v_);
  }
}

}  // namespace xLearn
<|endoftext|>


<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2000 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Id$
 */

#include "NamedNodeMapImpl.hpp"
#include "NodeVector.hpp"
#include "AttrImpl.hpp"
#include "DOM_DOMException.hpp"
#include "DocumentImpl.hpp"

int        NamedNodeMapImpl::gLiveNamedNodeMaps  = 0;
int        NamedNodeMapImpl::gTotalNamedNodeMaps = 0;

NamedNodeMapImpl::NamedNodeMapImpl(NodeImpl *ownerNod)
{
    this->ownerNode=ownerNod;
    this->nodes = null;
    this->readOnly = false;
    this->refCount = 1;
    gLiveNamedNodeMaps++;
    gTotalNamedNodeMaps++;
};

NamedNodeMapImpl::~NamedNodeMapImpl()
{
    if (nodes)
    {
        // It is the responsibility of whoever was using the named node
        // map to do any cleanup on the nodes contained in the map
        //  before deleting it.
        delete nodes;
        nodes = 0;
    }
    gLiveNamedNodeMaps--;
};

void NamedNodeMapImpl::addRef(NamedNodeMapImpl *This)
{
    if (This)
        ++This->refCount;
};

NamedNodeMapImpl *NamedNodeMapImpl::cloneMap(NodeImpl *ownerNod)
{
    NamedNodeMapImpl *newmap = new NamedNodeMapImpl(ownerNod);

    if (nodes != null)
    {
        newmap->nodes = new NodeVector(nodes->size());
        for (unsigned int i = 0; i < nodes->size(); ++i)
        {
            NodeImpl *n = nodes->elementAt(i)->cloneNode(true);
			n->isSpecified(nodes->elementAt(i)->isSpecified());
            n->ownerNode = ownerNod;
            n->isOwned(true);
            newmap->nodes->addElement(n);
        }
    }

    return newmap;
};

//
//  removeAll - This function removes all elements from a named node map.
//              It is called from the destructors for Elements and DocumentTypes,
//              to remove the contents when the owning Element or DocType goes
//              away.  The empty NamedNodeMap may persist if the user code
//              has a reference to it.
//
//              AH Revist - the empty map should be made read-only, since
//              adding it was logically part of the [Element, DocumentType]
//              that has been deleted, and adding anything new to it would
//              be meaningless, and almost certainly an error.
//
void NamedNodeMapImpl::removeAll()
{
    if (nodes)
    {

        for (int i=nodes->size()-1; i>=0; i--)
        {
            NodeImpl *n = nodes->elementAt(i);
            n->ownerNode = ownerNode->getOwnerDocument();
            n->isOwned(false);
            if (n->nodeRefCount == 0)
                NodeImpl::deleteIf(n);
        }
        delete nodes;
        nodes = null;
    }
}

int NamedNodeMapImpl::findNamePoint(const DOMString &name)
{

    // Binary search
    int i=0;
    if(nodes!=null)
    {
        int first=0,last=nodes->size()-1;

        while(first<=last)
        {
            i=(first+last)/2;
            int test = name.compareString(nodes->elementAt(i)->getNodeName());
            if(test==0)
                return i; // Name found
            else if(test<0)
                last=i-1;
            else
                first=i+1;
        }
        if(first>i) i=first;
    }
    /********************
    // Linear search
    int i = 0;
    if (nodes != null)
    for (i = 0; i < nodes.size(); ++i)
    {
    int test = name.compareTo(((NodeImpl *) (nodes.elementAt(i))).getNodeName());
    if (test == 0)
    return i;
    else
    if (test < 0)
    {
    break; // Found insertpoint
    }
    }

    *******************/
    return -1 - i; // not-found has to be encoded.
};

unsigned int NamedNodeMapImpl::getLength()
{
    return (nodes != null) ? nodes->size() : 0;
};

NodeImpl * NamedNodeMapImpl::getNamedItem(const DOMString &name)
{
    int i=findNamePoint(name);
    return (i<0) ? null : (NodeImpl *)(nodes->elementAt(i));
};

NodeImpl * NamedNodeMapImpl::item(unsigned int index)
{
    return (nodes != null && index < nodes->size()) ?
        (NodeImpl *) (nodes->elementAt(index)) : null;
};

//
// removeNamedItem() - Remove the named item, and return it.
//                      The caller must arrange for deletion of the
//                      returned item if its refcount has gone to zero -
//                      we can't do it here because the caller would
//                      never see the returned node.
//
NodeImpl * NamedNodeMapImpl::removeNamedItem(const DOMString &name)
{
    if (readOnly)
        throw DOM_DOMException(
            DOM_DOMException::NO_MODIFICATION_ALLOWED_ERR, null);
    int i=findNamePoint(name);
    NodeImpl *n = null;

    if(i<0)
        throw DOM_DOMException(DOM_DOMException::NOT_FOUND_ERR, null);

    n = (NodeImpl *) (nodes->elementAt(i));
    nodes->removeElementAt(i);
    n->ownerNode = ownerNode->getOwnerDocument();
    n->isOwned(false);
    return n;
};

void NamedNodeMapImpl::removeRef(NamedNodeMapImpl *This)
{
    if (This && --This->refCount == 0)
        delete This;
};

//
// setNamedItem()  Put the item into the NamedNodeList by name.
//                  If an item with the same name already was
//                  in the list, replace it.  Return the old
//                  item, if there was one.
//                  Caller is responsible for arranging for
//                  deletion of the old item if its ref count is
//                  zero.
//
NodeImpl * NamedNodeMapImpl::setNamedItem(NodeImpl * arg)
{
    if(arg->getOwnerDocument() != ownerNode->getOwnerDocument())
        throw DOM_DOMException(DOM_DOMException::WRONG_DOCUMENT_ERR,null);
    if (readOnly)
        throw DOM_DOMException(DOM_DOMException::NO_MODIFICATION_ALLOWED_ERR, null);
    if (arg->isOwned())
        throw DOM_DOMException(DOM_DOMException::INUSE_ATTRIBUTE_ERR,null);

    arg->ownerNode = ownerNode;
    arg->isOwned(true);
    int i=findNamePoint(arg->getNodeName());
    NodeImpl * previous=null;
    if(i>=0)
    {
        previous = nodes->elementAt(i);
        nodes->setElementAt(arg,i);
    }
    else
    {
        i=-1-i; // Insert point (may be end of list)
        if(null==nodes)
            nodes=new NodeVector();
        nodes->insertElementAt(arg,i);
    }
    if (previous != null) {
        previous->ownerNode = ownerNode->getOwnerDocument();
        previous->isOwned(false);
    }

    return previous;
};

void NamedNodeMapImpl::setReadOnly(bool readOnl, bool deep)
{
    this->readOnly=readOnl;
    if(deep && nodes!=null)
    {
        //Enumeration e=nodes->elements();
        //while(e->hasMoreElements())
        //      ((NodeImpl)e->nextElement())->setReadOnly(readOnl,deep);
        int sz = nodes->size();
        for (int i=0; i<sz; ++i) {
            nodes->elementAt(i)->setReadOnly(readOnl, deep);
        }
    }
};

//Introduced in DOM Level 2

int NamedNodeMapImpl::findNamePoint(const DOMString &namespaceURI,
	const DOMString &localName)
{
    if (nodes == null)
	return -1;
    // This is a linear search through the same nodes Vector.
    // The Vector is sorted on the DOM Level 1 nodename.
    // The DOM Level 2 NS keys are namespaceURI and Localname,
    // so we must linear search thru it.
    // In addition, to get this to work with nodes without any namespace
    // (namespaceURI and localNames are both null) we then use the nodeName
    // as a secondary key.
    int i, len = nodes -> size();
    for (i = 0; i < len; ++i) {
	NodeImpl *node = nodes -> elementAt(i);
	if (! node -> getNamespaceURI().equals(namespaceURI))	//URI not match
	    continue;
        DOMString nLocalName = node->getLocalName();
	if (nLocalName.equals(localName)
            ||
            (nLocalName == null && localName.equals(node->getNodeName())))
	    return i;
    }
    return -1;	//not found
}

NodeImpl *NamedNodeMapImpl::getNamedItemNS(const DOMString &namespaceURI,
	const DOMString &localName)
{
    int i = findNamePoint(namespaceURI, localName);
    return i < 0 ? null : nodes -> elementAt(i);
}

//
// setNamedItemNS()  Put the item into the NamedNodeList by name.
//                  If an item with the same name already was
//                  in the list, replace it.  Return the old
//                  item, if there was one.
//                  Caller is responsible for arranging for
//                  deletion of the old item if its ref count is
//                  zero.
//
NodeImpl * NamedNodeMapImpl::setNamedItemNS(NodeImpl *arg)
{
    if (arg->getOwnerDocument() != ownerNode->getOwnerDocument())
        throw DOM_DOMException(DOM_DOMException::WRONG_DOCUMENT_ERR,null);
    if (readOnly)
        throw DOM_DOMException(DOM_DOMException::NO_MODIFICATION_ALLOWED_ERR, null);
    if (arg->isOwned())
        throw DOM_DOMException(DOM_DOMException::INUSE_ATTRIBUTE_ERR,null);

    arg->ownerNode = ownerNode;
    arg->isOwned(true);
    int i=findNamePoint(arg->getNamespaceURI(), arg->getLocalName());
    NodeImpl *previous=null;
    if(i>=0) {
        previous = nodes->elementAt(i);
        nodes->setElementAt(arg,i);
    } else {
        i=-1-i; // Insert point (may be end of list)
        if(null==nodes)
            nodes=new NodeVector();
        nodes->insertElementAt(arg,i);
    }
    if (previous != null) {
        previous->ownerNode = ownerNode->getOwnerDocument();
        previous->isOwned(false);
    }

    return previous;
};

// removeNamedItemNS() - Remove the named item, and return it.
//                      The caller must arrange for deletion of the
//                      returned item if its refcount has gone to zero -
//                      we can't do it here because the caller would
//                      never see the returned node.
NodeImpl *NamedNodeMapImpl::removeNamedItemNS(const DOMString &namespaceURI,
	const DOMString &localName)
{
    if (readOnly)
        throw DOM_DOMException(
        DOM_DOMException::NO_MODIFICATION_ALLOWED_ERR, null);
    int i = findNamePoint(namespaceURI, localName);
    if (i < 0)
        throw DOM_DOMException(DOM_DOMException::NOT_FOUND_ERR, null);

    NodeImpl * n = nodes -> elementAt(i);
    nodes -> removeElementAt(i);	//remove n from nodes
    n->ownerNode = ownerNode->getOwnerDocument();
    n->isOwned(false);
    return n;
}

/**
 * NON-DOM
 * set the ownerDocument of this node, its children, and its attributes
 */
void NamedNodeMapImpl::setOwnerDocument(DocumentImpl *doc) {
    if (nodes != null) {
        for (unsigned int i = 0; i < nodes->size(); i++) {
            item(i)->setOwnerDocument(doc);
        }
    }
}

void NamedNodeMapImpl::cloneContent(NamedNodeMapImpl *srcmap) {
	if ((srcmap != null) && (srcmap->nodes != null))
	{
		if (nodes != null)
			delete nodes;
		nodes = new NodeVector(srcmap->nodes->size());
		for (unsigned int i = 0; i < srcmap->nodes->size(); i++)
		{
			NodeImpl *n = srcmap->nodes->elementAt(i);
 			NodeImpl *clone = n->cloneNode(true);
			clone->isSpecified(n->isSpecified());
			clone->ownerNode = ownerNode;
			clone->isOwned(true);
			nodes->addElement(clone);
//			n = null;
//			clone = null;
		}
	}
}
<commit_msg>changed again findNamePoint to only consider the nodeName when namespaceURI is null<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999-2000 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/*
 * $Id$
 */

#include "NamedNodeMapImpl.hpp"
#include "NodeVector.hpp"
#include "AttrImpl.hpp"
#include "DOM_DOMException.hpp"
#include "DocumentImpl.hpp"

int        NamedNodeMapImpl::gLiveNamedNodeMaps  = 0;
int        NamedNodeMapImpl::gTotalNamedNodeMaps = 0;

NamedNodeMapImpl::NamedNodeMapImpl(NodeImpl *ownerNod)
{
    this->ownerNode=ownerNod;
    this->nodes = null;
    this->readOnly = false;
    this->refCount = 1;
    gLiveNamedNodeMaps++;
    gTotalNamedNodeMaps++;
};

NamedNodeMapImpl::~NamedNodeMapImpl()
{
    if (nodes)
    {
        // It is the responsibility of whoever was using the named node
        // map to do any cleanup on the nodes contained in the map
        //  before deleting it.
        delete nodes;
        nodes = 0;
    }
    gLiveNamedNodeMaps--;
};

void NamedNodeMapImpl::addRef(NamedNodeMapImpl *This)
{
    if (This)
        ++This->refCount;
};

NamedNodeMapImpl *NamedNodeMapImpl::cloneMap(NodeImpl *ownerNod)
{
    NamedNodeMapImpl *newmap = new NamedNodeMapImpl(ownerNod);

    if (nodes != null)
    {
        newmap->nodes = new NodeVector(nodes->size());
        for (unsigned int i = 0; i < nodes->size(); ++i)
        {
            NodeImpl *n = nodes->elementAt(i)->cloneNode(true);
			n->isSpecified(nodes->elementAt(i)->isSpecified());
            n->ownerNode = ownerNod;
            n->isOwned(true);
            newmap->nodes->addElement(n);
        }
    }

    return newmap;
};

//
//  removeAll - This function removes all elements from a named node map.
//              It is called from the destructors for Elements and DocumentTypes,
//              to remove the contents when the owning Element or DocType goes
//              away.  The empty NamedNodeMap may persist if the user code
//              has a reference to it.
//
//              AH Revist - the empty map should be made read-only, since
//              adding it was logically part of the [Element, DocumentType]
//              that has been deleted, and adding anything new to it would
//              be meaningless, and almost certainly an error.
//
void NamedNodeMapImpl::removeAll()
{
    if (nodes)
    {

        for (int i=nodes->size()-1; i>=0; i--)
        {
            NodeImpl *n = nodes->elementAt(i);
            n->ownerNode = ownerNode->getOwnerDocument();
            n->isOwned(false);
            if (n->nodeRefCount == 0)
                NodeImpl::deleteIf(n);
        }
        delete nodes;
        nodes = null;
    }
}

int NamedNodeMapImpl::findNamePoint(const DOMString &name)
{

    // Binary search
    int i=0;
    if(nodes!=null)
    {
        int first=0,last=nodes->size()-1;

        while(first<=last)
        {
            i=(first+last)/2;
            int test = name.compareString(nodes->elementAt(i)->getNodeName());
            if(test==0)
                return i; // Name found
            else if(test<0)
                last=i-1;
            else
                first=i+1;
        }
        if(first>i) i=first;
    }
    /********************
    // Linear search
    int i = 0;
    if (nodes != null)
    for (i = 0; i < nodes.size(); ++i)
    {
    int test = name.compareTo(((NodeImpl *) (nodes.elementAt(i))).getNodeName());
    if (test == 0)
    return i;
    else
    if (test < 0)
    {
    break; // Found insertpoint
    }
    }

    *******************/
    return -1 - i; // not-found has to be encoded.
};

unsigned int NamedNodeMapImpl::getLength()
{
    return (nodes != null) ? nodes->size() : 0;
};

NodeImpl * NamedNodeMapImpl::getNamedItem(const DOMString &name)
{
    int i=findNamePoint(name);
    return (i<0) ? null : (NodeImpl *)(nodes->elementAt(i));
};

NodeImpl * NamedNodeMapImpl::item(unsigned int index)
{
    return (nodes != null && index < nodes->size()) ?
        (NodeImpl *) (nodes->elementAt(index)) : null;
};

//
// removeNamedItem() - Remove the named item, and return it.
//                      The caller must arrange for deletion of the
//                      returned item if its refcount has gone to zero -
//                      we can't do it here because the caller would
//                      never see the returned node.
//
NodeImpl * NamedNodeMapImpl::removeNamedItem(const DOMString &name)
{
    if (readOnly)
        throw DOM_DOMException(
            DOM_DOMException::NO_MODIFICATION_ALLOWED_ERR, null);
    int i=findNamePoint(name);
    NodeImpl *n = null;

    if(i<0)
        throw DOM_DOMException(DOM_DOMException::NOT_FOUND_ERR, null);

    n = (NodeImpl *) (nodes->elementAt(i));
    nodes->removeElementAt(i);
    n->ownerNode = ownerNode->getOwnerDocument();
    n->isOwned(false);
    return n;
};

void NamedNodeMapImpl::removeRef(NamedNodeMapImpl *This)
{
    if (This && --This->refCount == 0)
        delete This;
};

//
// setNamedItem()  Put the item into the NamedNodeList by name.
//                  If an item with the same name already was
//                  in the list, replace it.  Return the old
//                  item, if there was one.
//                  Caller is responsible for arranging for
//                  deletion of the old item if its ref count is
//                  zero.
//
NodeImpl * NamedNodeMapImpl::setNamedItem(NodeImpl * arg)
{
    if(arg->getOwnerDocument() != ownerNode->getOwnerDocument())
        throw DOM_DOMException(DOM_DOMException::WRONG_DOCUMENT_ERR,null);
    if (readOnly)
        throw DOM_DOMException(DOM_DOMException::NO_MODIFICATION_ALLOWED_ERR, null);
    if (arg->isOwned())
        throw DOM_DOMException(DOM_DOMException::INUSE_ATTRIBUTE_ERR,null);

    arg->ownerNode = ownerNode;
    arg->isOwned(true);
    int i=findNamePoint(arg->getNodeName());
    NodeImpl * previous=null;
    if(i>=0)
    {
        previous = nodes->elementAt(i);
        nodes->setElementAt(arg,i);
    }
    else
    {
        i=-1-i; // Insert point (may be end of list)
        if(null==nodes)
            nodes=new NodeVector();
        nodes->insertElementAt(arg,i);
    }
    if (previous != null) {
        previous->ownerNode = ownerNode->getOwnerDocument();
        previous->isOwned(false);
    }

    return previous;
};

void NamedNodeMapImpl::setReadOnly(bool readOnl, bool deep)
{
    this->readOnly=readOnl;
    if(deep && nodes!=null)
    {
        //Enumeration e=nodes->elements();
        //while(e->hasMoreElements())
        //      ((NodeImpl)e->nextElement())->setReadOnly(readOnl,deep);
        int sz = nodes->size();
        for (int i=0; i<sz; ++i) {
            nodes->elementAt(i)->setReadOnly(readOnl, deep);
        }
    }
};

//Introduced in DOM Level 2

int NamedNodeMapImpl::findNamePoint(const DOMString &namespaceURI,
	const DOMString &localName)
{
    if (nodes == null)
	return -1;
    // This is a linear search through the same nodes Vector.
    // The Vector is sorted on the DOM Level 1 nodename.
    // The DOM Level 2 NS keys are namespaceURI and Localname,
    // so we must linear search thru it.
    // In addition, to get this to work with nodes without any namespace
    // (namespaceURI and localNames are both null) we then use the nodeName
    // as a secondary key.
    int i, len = nodes -> size();
    for (i = 0; i < len; ++i) {
	NodeImpl *node = nodes -> elementAt(i);
	if (! node -> getNamespaceURI().equals(namespaceURI))	//URI not match
	    continue;
        DOMString nNamespaceURI = node->getNamespaceURI();
        DOMString nLocalName = node->getLocalName();
        if (namespaceURI == null) {
            if (nNamespaceURI == null
                &&
                (localName.equals(nLocalName)
                 ||
                 (nLocalName == null && localName.equals(node->getNodeName()))))
                return i;
        } else {
            if (namespaceURI.equals(nNamespaceURI)
                &&
                localName.equals(nLocalName))
                return i;
        }
    }
    return -1;	//not found
}

NodeImpl *NamedNodeMapImpl::getNamedItemNS(const DOMString &namespaceURI,
	const DOMString &localName)
{
    int i = findNamePoint(namespaceURI, localName);
    return i < 0 ? null : nodes -> elementAt(i);
}

//
// setNamedItemNS()  Put the item into the NamedNodeList by name.
//                  If an item with the same name already was
//                  in the list, replace it.  Return the old
//                  item, if there was one.
//                  Caller is responsible for arranging for
//                  deletion of the old item if its ref count is
//                  zero.
//
NodeImpl * NamedNodeMapImpl::setNamedItemNS(NodeImpl *arg)
{
    if (arg->getOwnerDocument() != ownerNode->getOwnerDocument())
        throw DOM_DOMException(DOM_DOMException::WRONG_DOCUMENT_ERR,null);
    if (readOnly)
        throw DOM_DOMException(DOM_DOMException::NO_MODIFICATION_ALLOWED_ERR, null);
    if (arg->isOwned())
        throw DOM_DOMException(DOM_DOMException::INUSE_ATTRIBUTE_ERR,null);

    arg->ownerNode = ownerNode;
    arg->isOwned(true);
    int i=findNamePoint(arg->getNamespaceURI(), arg->getLocalName());
    NodeImpl *previous=null;
    if(i>=0) {
        previous = nodes->elementAt(i);
        nodes->setElementAt(arg,i);
    } else {
        i=-1-i; // Insert point (may be end of list)
        if(null==nodes)
            nodes=new NodeVector();
        nodes->insertElementAt(arg,i);
    }
    if (previous != null) {
        previous->ownerNode = ownerNode->getOwnerDocument();
        previous->isOwned(false);
    }

    return previous;
};

// removeNamedItemNS() - Remove the named item, and return it.
//                      The caller must arrange for deletion of the
//                      returned item if its refcount has gone to zero -
//                      we can't do it here because the caller would
//                      never see the returned node.
NodeImpl *NamedNodeMapImpl::removeNamedItemNS(const DOMString &namespaceURI,
	const DOMString &localName)
{
    if (readOnly)
        throw DOM_DOMException(
        DOM_DOMException::NO_MODIFICATION_ALLOWED_ERR, null);
    int i = findNamePoint(namespaceURI, localName);
    if (i < 0)
        throw DOM_DOMException(DOM_DOMException::NOT_FOUND_ERR, null);

    NodeImpl * n = nodes -> elementAt(i);
    nodes -> removeElementAt(i);	//remove n from nodes
    n->ownerNode = ownerNode->getOwnerDocument();
    n->isOwned(false);
    return n;
}

/**
 * NON-DOM
 * set the ownerDocument of this node, its children, and its attributes
 */
void NamedNodeMapImpl::setOwnerDocument(DocumentImpl *doc) {
    if (nodes != null) {
        for (unsigned int i = 0; i < nodes->size(); i++) {
            item(i)->setOwnerDocument(doc);
        }
    }
}

void NamedNodeMapImpl::cloneContent(NamedNodeMapImpl *srcmap) {
	if ((srcmap != null) && (srcmap->nodes != null))
	{
		if (nodes != null)
			delete nodes;
		nodes = new NodeVector(srcmap->nodes->size());
		for (unsigned int i = 0; i < srcmap->nodes->size(); i++)
		{
			NodeImpl *n = srcmap->nodes->elementAt(i);
 			NodeImpl *clone = n->cloneNode(true);
			clone->isSpecified(n->isSpecified());
			clone->ownerNode = ownerNode;
			clone->isOwned(true);
			nodes->addElement(clone);
//			n = null;
//			clone = null;
		}
	}
}
<|endoftext|>