<commit_before>//
// TreeView.cpp
//
// Copyright (c) 2001-2006 Virtual Terrain Project
// Free for all uses, see license.txt for details.
//

// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"

#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif

#include "vtdata/FilePath.h"
#include "vtdata/vtLog.h"

#include "App.h"
#include "TreeView.h"
#include "MenuEnum.h"	// for LayerTree_Ctrl
#include "Frame.h"
#include "BuilderView.h"
#include "vtui/Helper.h"

DECLARE_APP(BuilderApp)

// Under Windows, the icons are in the .rc file; on Unix, they are included
// from .xpm files.
#ifndef __WXMSW__
#include "building.xpm"
#include "file1.xpm"
#include "file2.xpm"
#include "folder1.xpm"
#include "folder2.xpm"
#include "folder3.xpm"

#include "grid.xpm"
#include "image.xpm"
#include "raw.xpm"
#include "road.xpm"
#include "veg1.xpm"
#include "water.xpm"
#include "util.xpm"
#include "transit.xpm"
#endif

/////////////////////////////////////////////////

// MyTreeCtrl implementation
IMPLEMENT_DYNAMIC_CLASS(MyTreeCtrl, wxTreeCtrl)

MyTreeCtrl::MyTreeCtrl(wxWindow *parent, const wxWindowID id,
	const wxPoint& pos, const wxSize& size,
	long style)
: wxTreeCtrl(parent, id, pos, size, style)
{
	m_reverseSort = false;
	m_imageListNormal = NULL;
	m_bShowPaths = true;

	CreateImageList(16);

	// Add some items to the tree
	RefreshTreeItems(NULL);
}

void MyTreeCtrl::CreateImageList(int size)
{
	delete m_imageListNormal;

	if ( size == -1 )
	{
		m_imageListNormal = NULL;
		return;
	}

	// Make an image list containing small icons
	m_imageListNormal = new wxImageList(size, size, TRUE);

	// should correspond to TreeCtrlIcon_xxx enum
	wxIcon icons[14];
	icons[0] = wxICON(file1);
	icons[1] = wxICON(file2);
	icons[2] = wxICON(folder1);
	icons[3] = wxICON(folder2);
	icons[4] = wxICON(folder3);
	icons[5] = wxICON(building);
	icons[6] = wxICON(road);
	icons[7] = wxICON(grid);
	icons[8] = wxICON(image);
	icons[9] = wxICON(veg1);
	icons[10] = wxICON(water);
	icons[11] = wxICON(transit);
	icons[12] = wxICON(util);
	icons[13] = wxICON(raw);

	int sizeOrig = icons[0].GetWidth();
	for ( size_t i = 0; i < WXSIZEOF(icons); i++ )
	{
		if ( size == sizeOrig )
			m_imageListNormal->Add(icons[i]);
		else
			m_imageListNormal->Add(wxBitmap(icons[i]).ConvertToImage().Rescale(size, size));
	}

	SetImageList(m_imageListNormal);
}

MyTreeCtrl::~MyTreeCtrl()
{
	delete m_imageListNormal;
}

int MyTreeCtrl::OnCompareItems(const wxTreeItemId& item1,
	const wxTreeItemId& item2)
{
	if ( m_reverseSort )
	{
		// just exchange 1st and 2nd items
		return wxTreeCtrl::OnCompareItems(item2, item1);
	}
	else
	{
		return wxTreeCtrl::OnCompareItems(item1, item2);
	}
}

wxTreeItemId rootId;

wxTreeItemId MyTreeCtrl::AddRootItem(int image, const wxString &text)
{
	wxTreeItemId id = AppendItem(rootId, text, image);
	SetItemBold(id);
	return id;
}

wxString MyTreeCtrl::MakeItemName(vtLayerPtr lp)
{
	wxString str;
	if (lp->GetModified())
		str = _T("(*) ");
	wxString path = lp->GetLayerFilename();

	if (!m_bShowPaths)
		path = StartOfFilename(path);

	str += path;
	return str;
}

void MyTreeCtrl::RefreshTreeItems(MainFrame *pFrame)
{
	VTLOG("Refreshing Tree Items\n");

	DeleteAllItems();

	rootId = AddRoot(_("Layers"));
	SetItemBold(rootId);

	int	image, imageSel;

	wxTreeItemId elevId =	AddRootItem(MyTreeCtrl::TreeCtrlIcon_Grid, _("Elevation"));
#ifndef ELEVATION_ONLY
	wxTreeItemId imageId =	AddRootItem(MyTreeCtrl::TreeCtrlIcon_Image, _("Images"));
	wxTreeItemId buildId =	AddRootItem(MyTreeCtrl::TreeCtrlIcon_Building, _("Structures"));
	wxTreeItemId roadId =	AddRootItem(MyTreeCtrl::TreeCtrlIcon_Road, _("Roads"));
	wxTreeItemId vegId =	AddRootItem(MyTreeCtrl::TreeCtrlIcon_Veg1, _("Vegetation"));
	wxTreeItemId waterId =	AddRootItem(MyTreeCtrl::TreeCtrlIcon_Water, _("Water"));
#if SUPPORT_TRANSIT
	wxTreeItemId transId =	AddRootItem(MyTreeCtrl::TreeCtrlIcon_Transit, _("Transit"));
#endif
	wxTreeItemId utilityId = AddRootItem(MyTreeCtrl::TreeCtrlIcon_Utility, _("Utilities"));
#endif
	wxTreeItemId rawId =	AddRootItem(MyTreeCtrl::TreeCtrlIcon_Raw, _("Raw"));

	image = TreeCtrlIcon_File;
	imageSel = TreeCtrlIcon_FileSelected;
	vtLayerPtr lp;
	int iLayers = 0;
	if (pFrame) iLayers = pFrame->NumLayers();
	for (int i = 0; i < iLayers; i++)
	{
		lp = pFrame->GetLayer(i);

		wxString str = MakeItemName(lp);

		wxTreeItemId hItem;
		switch (lp->GetType())
		{
			case LT_ELEVATION:
				hItem = AppendItem(elevId, str, image, imageSel);
				break;
#ifndef ELEVATION_ONLY
			case LT_IMAGE:
				hItem = AppendItem(imageId, str, image, imageSel);
				break;
			case LT_ROAD:
				hItem = AppendItem(roadId, str, image, imageSel);
				break;
			case LT_STRUCTURE:
				hItem = AppendItem(buildId, str, image, imageSel);
				break;
			case LT_VEG:
				hItem = AppendItem(vegId, str, image, imageSel);
				break;
			case LT_WATER:
				hItem = AppendItem(waterId, str, image, imageSel);
				break;
#if SUPPORT_TRANSIT
			case LT_TRANSIT:
				hItem = AppendItem(transId, str, image, imageSel);
				break;
#endif
			case LT_UTILITY:
				hItem = AppendItem(utilityId, str, image, imageSel);
				break;
#endif
			case LT_RAW:
				hItem = AppendItem(rawId, str, image, imageSel);
				break;
		}
		if (hItem.IsOk())
		{
			SetItemData(hItem, new MyTreeItemData(lp));

			if (lp == pFrame->GetActiveLayer())
				SelectItem(hItem);
		}
	}

	Expand(rootId);
	Expand(elevId);
#ifndef ELEVATION_ONLY
	Expand(imageId);
	Expand(roadId);
	Expand(buildId);
	Expand(vegId);
	Expand(waterId);
#if SUPPORT_TRANSIT
	Expand(transId);
#endif
	Expand(utilityId);
#endif
	Expand(rawId);
}

void MyTreeCtrl::RefreshTreeStatus(MainFrame *pFrame)
{
	VTLOG("(Refreshing Tree Status)\n");

	wxTreeItemId root = GetRootItem();
	wxTreeItemId parent, item;

	wxTreeItemIdValue cookie;
	for (parent = GetFirstChild(root, cookie); parent; parent = GetNextChild(root, cookie))
	{
		wxTreeItemIdValue cookie2;
		for (item = GetFirstChild(parent, cookie2); item; item = GetNextChild(parent, cookie2))
		{
			MyTreeItemData *data = (MyTreeItemData *)GetItemData(item);
			if (data)
			{
				SetItemText(item, MakeItemName(data->m_pLayer));
				if (data->m_pLayer == pFrame->GetActiveLayer())
					SelectItem(item);
			}
		}
	}
}

// avoid repetition
#define TREE_EVENT_HANDLER(name)			\
void MyTreeCtrl::name(wxTreeEvent& event)	\
{											\
	event.Skip();							\
}

TREE_EVENT_HANDLER(OnBeginRDrag)
TREE_EVENT_HANDLER(OnDeleteItem)
TREE_EVENT_HANDLER(OnGetInfo)
TREE_EVENT_HANDLER(OnSetInfo)
TREE_EVENT_HANDLER(OnItemExpanded)
TREE_EVENT_HANDLER(OnItemExpanding)
TREE_EVENT_HANDLER(OnItemCollapsed)
TREE_EVENT_HANDLER(OnSelChanging)
TREE_EVENT_HANDLER(OnTreeKeyDown)

#undef TREE_EVENT_HANDLER

void MyTreeCtrl::OnSelChanged(wxTreeEvent& event)
{
	wxTreeItemId item = event.GetItem();
	if (!item.IsOk())
		return;

	MyTreeItemData *data = (MyTreeItemData *)GetItemData(item);
	vtLayerPtr lp = NULL;
	if (data)
		lp = data->m_pLayer;

	MainFrame *frame = GetMainFrame();
	vtLayerPtr last = frame->GetActiveLayer();
	if (lp != last)
		frame->GetView()->SetActiveLayer(lp);

	LayerType last_ltype = last ? last->GetType() : LT_UNKNOWN;
	if (lp && lp->GetType() != last_ltype)
		frame->RefreshToolbar();
}

void MyTreeCtrl::OnBeginDrag(wxTreeEvent& event)
{
}

void MyTreeCtrl::OnEndDrag(wxTreeEvent& event)
{
}

void MyTreeCtrl::OnBeginLabelEdit(wxTreeEvent& event)
{
#if 0
	wxLogMessage("OnBeginLabelEdit");

	// for testing, prevent this items label editing
	wxTreeItemId itemId = event.GetItem();
	if ( IsTestItem(itemId) )
	{
		wxMessageBox("You can't edit this item.");

		event.Veto();
	}
#endif
}

void MyTreeCtrl::OnEndLabelEdit(wxTreeEvent& event)
{
#if 0
	wxLogMessage("OnEndLabelEdit");

	// don't allow anything except letters in the labels
	if ( !event.GetLabel().IsWord() )
	{
		wxMessageBox("The label should contain only letters.");

		event.Veto();
	}
#endif
}

void MyTreeCtrl::OnItemCollapsing(wxTreeEvent& event)
{
#if 0
	wxLogMessage("OnItemCollapsing");

	// for testing, prevent the user from collapsing the first child folder
	wxTreeItemId itemId = event.GetItem();
	if ( IsTestItem(itemId) )
	{
		wxMessageBox("You can't collapse this item.");

		event.Veto();
	}
#endif
}

void MyTreeCtrl::OnItemActivated(wxTreeEvent& event)
{
#if 0
	// show some info about this item
	wxTreeItemId itemId = event.GetItem();
	MyTreeItemData *item = (MyTreeItemData *)GetItemData(itemId);

	if ( item != NULL )
	{
		item->ShowInfo(this);
	}
	wxLogMessage("OnItemActivated");
#endif
}

void MyTreeCtrl::OnRMouseDClick(wxMouseEvent& event)
{
#if 0
	wxTreeItemId id = HitTest(event.GetPosition());
	if ( !id )
		wxLogMessage("No item under mouse");
	else
	{
		MyTreeItemData *item = (MyTreeItemData *)GetItemData(id);
		if ( item )
			wxLogMessage("Item '%s' under mouse", item->GetDesc());
	}
#endif
}

/////////////////////////////////////////////////

BEGIN_EVENT_TABLE(MyTreeCtrl, wxTreeCtrl)
EVT_TREE_BEGIN_DRAG(LayerTree_Ctrl, MyTreeCtrl::OnBeginDrag)
EVT_TREE_BEGIN_RDRAG(LayerTree_Ctrl, MyTreeCtrl::OnBeginRDrag)
EVT_TREE_END_DRAG(LayerTree_Ctrl, MyTreeCtrl::OnEndDrag)
EVT_TREE_BEGIN_LABEL_EDIT(LayerTree_Ctrl, MyTreeCtrl::OnBeginLabelEdit)
EVT_TREE_END_LABEL_EDIT(LayerTree_Ctrl, MyTreeCtrl::OnEndLabelEdit)
EVT_TREE_DELETE_ITEM(LayerTree_Ctrl, MyTreeCtrl::OnDeleteItem)
EVT_TREE_SET_INFO(LayerTree_Ctrl, MyTreeCtrl::OnSetInfo)
EVT_TREE_ITEM_EXPANDED(LayerTree_Ctrl, MyTreeCtrl::OnItemExpanded)
EVT_TREE_ITEM_EXPANDING(LayerTree_Ctrl, MyTreeCtrl::OnItemExpanding)
EVT_TREE_ITEM_COLLAPSED(LayerTree_Ctrl, MyTreeCtrl::OnItemCollapsed)
EVT_TREE_ITEM_COLLAPSING(LayerTree_Ctrl, MyTreeCtrl::OnItemCollapsing)
EVT_TREE_SEL_CHANGED(LayerTree_Ctrl, MyTreeCtrl::OnSelChanged)
EVT_TREE_SEL_CHANGING(LayerTree_Ctrl, MyTreeCtrl::OnSelChanging)
EVT_TREE_KEY_DOWN(LayerTree_Ctrl, MyTreeCtrl::OnTreeKeyDown)
EVT_TREE_ITEM_ACTIVATED(LayerTree_Ctrl, MyTreeCtrl::OnItemActivated)
EVT_RIGHT_DCLICK(MyTreeCtrl::OnRMouseDClick)
END_EVENT_TABLE()
<commit_msg>made rootless<commit_after>//
// TreeView.cpp
//
// Copyright (c) 2001-2006 Virtual Terrain Project
// Free for all uses, see license.txt for details.
//

// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"

#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif

#include "vtdata/FilePath.h"
#include "vtdata/vtLog.h"

#include "App.h"
#include "TreeView.h"
#include "MenuEnum.h"	// for LayerTree_Ctrl
#include "Frame.h"
#include "BuilderView.h"
#include "vtui/Helper.h"

DECLARE_APP(BuilderApp)

// Under Windows, the icons are in the .rc file; on Unix, they are included
// from .xpm files.
#ifndef __WXMSW__
#include "building.xpm"
#include "file1.xpm"
#include "file2.xpm"
#include "folder1.xpm"
#include "folder2.xpm"
#include "folder3.xpm"

#include "grid.xpm"
#include "image.xpm"
#include "raw.xpm"
#include "road.xpm"
#include "veg1.xpm"
#include "water.xpm"
#include "util.xpm"
#include "transit.xpm"
#endif

/////////////////////////////////////////////////

// MyTreeCtrl implementation
IMPLEMENT_DYNAMIC_CLASS(MyTreeCtrl, wxTreeCtrl)

MyTreeCtrl::MyTreeCtrl(wxWindow *parent, const wxWindowID id,
	const wxPoint& pos, const wxSize& size,
	long style)
: wxTreeCtrl(parent, id, pos, size, style)
{
	m_reverseSort = false;
	m_imageListNormal = NULL;
	m_bShowPaths = true;

	CreateImageList(16);

	// Add some items to the tree
	RefreshTreeItems(NULL);
}

void MyTreeCtrl::CreateImageList(int size)
{
	delete m_imageListNormal;

	if ( size == -1 )
	{
		m_imageListNormal = NULL;
		return;
	}

	// Make an image list containing small icons
	m_imageListNormal = new wxImageList(size, size, TRUE);

	// should correspond to TreeCtrlIcon_xxx enum
	wxIcon icons[14];
	icons[0] = wxICON(file1);
	icons[1] = wxICON(file2);
	icons[2] = wxICON(folder1);
	icons[3] = wxICON(folder2);
	icons[4] = wxICON(folder3);
	icons[5] = wxICON(building);
	icons[6] = wxICON(road);
	icons[7] = wxICON(grid);
	icons[8] = wxICON(image);
	icons[9] = wxICON(veg1);
	icons[10] = wxICON(water);
	icons[11] = wxICON(transit);
	icons[12] = wxICON(util);
	icons[13] = wxICON(raw);

	int sizeOrig = icons[0].GetWidth();
	for ( size_t i = 0; i < WXSIZEOF(icons); i++ )
	{
		if ( size == sizeOrig )
			m_imageListNormal->Add(icons[i]);
		else
			m_imageListNormal->Add(wxBitmap(icons[i]).ConvertToImage().Rescale(size, size));
	}

	SetImageList(m_imageListNormal);
}

MyTreeCtrl::~MyTreeCtrl()
{
	delete m_imageListNormal;
}

int MyTreeCtrl::OnCompareItems(const wxTreeItemId& item1,
	const wxTreeItemId& item2)
{
	if ( m_reverseSort )
	{
		// just exchange 1st and 2nd items
		return wxTreeCtrl::OnCompareItems(item2, item1);
	}
	else
	{
		return wxTreeCtrl::OnCompareItems(item1, item2);
	}
}

wxTreeItemId rootId;

wxTreeItemId MyTreeCtrl::AddRootItem(int image, const wxString &text)
{
	wxTreeItemId id = AppendItem(rootId, text, image);
	SetItemBold(id);
	return id;
}

wxString MyTreeCtrl::MakeItemName(vtLayerPtr lp)
{
	wxString str;
	if (lp->GetModified())
		str = _T("(*) ");
	wxString path = lp->GetLayerFilename();

	if (!m_bShowPaths)
		path = StartOfFilename(path);

	str += path;
	return str;
}

void MyTreeCtrl::RefreshTreeItems(MainFrame *pFrame)
{
	VTLOG("Refreshing Tree Items\n");

	DeleteAllItems();

	rootId = AddRoot(_("Layers"));
	SetItemBold(rootId);

	int	image, imageSel;

	wxTreeItemId elevId =	AddRootItem(MyTreeCtrl::TreeCtrlIcon_Grid, _("Elevation"));
#ifndef ELEVATION_ONLY
	wxTreeItemId imageId =	AddRootItem(MyTreeCtrl::TreeCtrlIcon_Image, _("Images"));
	wxTreeItemId buildId =	AddRootItem(MyTreeCtrl::TreeCtrlIcon_Building, _("Structures"));
	wxTreeItemId roadId =	AddRootItem(MyTreeCtrl::TreeCtrlIcon_Road, _("Roads"));
	wxTreeItemId vegId =	AddRootItem(MyTreeCtrl::TreeCtrlIcon_Veg1, _("Vegetation"));
	wxTreeItemId waterId =	AddRootItem(MyTreeCtrl::TreeCtrlIcon_Water, _("Water"));
#if SUPPORT_TRANSIT
	wxTreeItemId transId =	AddRootItem(MyTreeCtrl::TreeCtrlIcon_Transit, _("Transit"));
#endif
	wxTreeItemId utilityId = AddRootItem(MyTreeCtrl::TreeCtrlIcon_Utility, _("Utilities"));
#endif
	wxTreeItemId rawId =	AddRootItem(MyTreeCtrl::TreeCtrlIcon_Raw, _("Raw"));

	image = TreeCtrlIcon_File;
	imageSel = TreeCtrlIcon_FileSelected;
	vtLayerPtr lp;
	int iLayers = 0;
	if (pFrame) iLayers = pFrame->NumLayers();
	for (int i = 0; i < iLayers; i++)
	{
		lp = pFrame->GetLayer(i);

		wxString str = MakeItemName(lp);

		wxTreeItemId hItem;
		switch (lp->GetType())
		{
			case LT_ELEVATION:
				hItem = AppendItem(elevId, str, image, imageSel);
				break;
#ifndef ELEVATION_ONLY
			case LT_IMAGE:
				hItem = AppendItem(imageId, str, image, imageSel);
				break;
			case LT_ROAD:
				hItem = AppendItem(roadId, str, image, imageSel);
				break;
			case LT_STRUCTURE:
				hItem = AppendItem(buildId, str, image, imageSel);
				break;
			case LT_VEG:
				hItem = AppendItem(vegId, str, image, imageSel);
				break;
			case LT_WATER:
				hItem = AppendItem(waterId, str, image, imageSel);
				break;
#if SUPPORT_TRANSIT
			case LT_TRANSIT:
				hItem = AppendItem(transId, str, image, imageSel);
				break;
#endif
			case LT_UTILITY:
				hItem = AppendItem(utilityId, str, image, imageSel);
				break;
#endif
			case LT_RAW:
				hItem = AppendItem(rawId, str, image, imageSel);
				break;
		}
		if (hItem.IsOk())
		{
			SetItemData(hItem, new MyTreeItemData(lp));

			if (lp == pFrame->GetActiveLayer())
				SelectItem(hItem);
		}
	}

	Expand(elevId);
#ifndef ELEVATION_ONLY
	Expand(imageId);
	Expand(roadId);
	Expand(buildId);
	Expand(vegId);
	Expand(waterId);
#if SUPPORT_TRANSIT
	Expand(transId);
#endif
	Expand(utilityId);
#endif
	Expand(rawId);
}

void MyTreeCtrl::RefreshTreeStatus(MainFrame *pFrame)
{
	VTLOG("(Refreshing Tree Status)\n");

	wxTreeItemId root = GetRootItem();
	wxTreeItemId parent, item;

	wxTreeItemIdValue cookie;
	for (parent = GetFirstChild(root, cookie); parent; parent = GetNextChild(root, cookie))
	{
		wxTreeItemIdValue cookie2;
		for (item = GetFirstChild(parent, cookie2); item; item = GetNextChild(parent, cookie2))
		{
			MyTreeItemData *data = (MyTreeItemData *)GetItemData(item);
			if (data)
			{
				SetItemText(item, MakeItemName(data->m_pLayer));
				if (data->m_pLayer == pFrame->GetActiveLayer())
					SelectItem(item);
			}
		}
	}
}

// avoid repetition
#define TREE_EVENT_HANDLER(name)			\
void MyTreeCtrl::name(wxTreeEvent& event)	\
{											\
	event.Skip();							\
}

TREE_EVENT_HANDLER(OnBeginRDrag)
TREE_EVENT_HANDLER(OnDeleteItem)
TREE_EVENT_HANDLER(OnGetInfo)
TREE_EVENT_HANDLER(OnSetInfo)
TREE_EVENT_HANDLER(OnItemExpanded)
TREE_EVENT_HANDLER(OnItemExpanding)
TREE_EVENT_HANDLER(OnItemCollapsed)
TREE_EVENT_HANDLER(OnSelChanging)
TREE_EVENT_HANDLER(OnTreeKeyDown)

#undef TREE_EVENT_HANDLER

void MyTreeCtrl::OnSelChanged(wxTreeEvent& event)
{
	wxTreeItemId item = event.GetItem();
	if (!item.IsOk())
		return;

	MyTreeItemData *data = (MyTreeItemData *)GetItemData(item);
	vtLayerPtr lp = NULL;
	if (data)
		lp = data->m_pLayer;

	MainFrame *frame = GetMainFrame();
	vtLayerPtr last = frame->GetActiveLayer();
	if (lp != last)
		frame->GetView()->SetActiveLayer(lp);

	LayerType curr_ltype = lp ? lp->GetType() : LT_UNKNOWN;
	LayerType last_ltype = last ? last->GetType() : LT_UNKNOWN;
	if (curr_ltype != last_ltype)
		frame->RefreshToolbars();
}

void MyTreeCtrl::OnBeginDrag(wxTreeEvent& event)
{
}

void MyTreeCtrl::OnEndDrag(wxTreeEvent& event)
{
}

void MyTreeCtrl::OnBeginLabelEdit(wxTreeEvent& event)
{
#if 0
	wxLogMessage("OnBeginLabelEdit");

	// for testing, prevent this items label editing
	wxTreeItemId itemId = event.GetItem();
	if ( IsTestItem(itemId) )
	{
		wxMessageBox("You can't edit this item.");

		event.Veto();
	}
#endif
}

void MyTreeCtrl::OnEndLabelEdit(wxTreeEvent& event)
{
#if 0
	wxLogMessage("OnEndLabelEdit");

	// don't allow anything except letters in the labels
	if ( !event.GetLabel().IsWord() )
	{
		wxMessageBox("The label should contain only letters.");

		event.Veto();
	}
#endif
}

void MyTreeCtrl::OnItemCollapsing(wxTreeEvent& event)
{
#if 0
	wxLogMessage("OnItemCollapsing");

	// for testing, prevent the user from collapsing the first child folder
	wxTreeItemId itemId = event.GetItem();
	if ( IsTestItem(itemId) )
	{
		wxMessageBox("You can't collapse this item.");

		event.Veto();
	}
#endif
}

void MyTreeCtrl::OnItemActivated(wxTreeEvent& event)
{
#if 0
	// show some info about this item
	wxTreeItemId itemId = event.GetItem();
	MyTreeItemData *item = (MyTreeItemData *)GetItemData(itemId);

	if ( item != NULL )
	{
		item->ShowInfo(this);
	}
	wxLogMessage("OnItemActivated");
#endif
}

void MyTreeCtrl::OnRMouseDClick(wxMouseEvent& event)
{
#if 0
	wxTreeItemId id = HitTest(event.GetPosition());
	if ( !id )
		wxLogMessage("No item under mouse");
	else
	{
		MyTreeItemData *item = (MyTreeItemData *)GetItemData(id);
		if ( item )
			wxLogMessage("Item '%s' under mouse", item->GetDesc());
	}
#endif
}

/////////////////////////////////////////////////

BEGIN_EVENT_TABLE(MyTreeCtrl, wxTreeCtrl)
EVT_TREE_BEGIN_DRAG(LayerTree_Ctrl, MyTreeCtrl::OnBeginDrag)
EVT_TREE_BEGIN_RDRAG(LayerTree_Ctrl, MyTreeCtrl::OnBeginRDrag)
EVT_TREE_END_DRAG(LayerTree_Ctrl, MyTreeCtrl::OnEndDrag)
EVT_TREE_BEGIN_LABEL_EDIT(LayerTree_Ctrl, MyTreeCtrl::OnBeginLabelEdit)
EVT_TREE_END_LABEL_EDIT(LayerTree_Ctrl, MyTreeCtrl::OnEndLabelEdit)
EVT_TREE_DELETE_ITEM(LayerTree_Ctrl, MyTreeCtrl::OnDeleteItem)
EVT_TREE_SET_INFO(LayerTree_Ctrl, MyTreeCtrl::OnSetInfo)
EVT_TREE_ITEM_EXPANDED(LayerTree_Ctrl, MyTreeCtrl::OnItemExpanded)
EVT_TREE_ITEM_EXPANDING(LayerTree_Ctrl, MyTreeCtrl::OnItemExpanding)
EVT_TREE_ITEM_COLLAPSED(LayerTree_Ctrl, MyTreeCtrl::OnItemCollapsed)
EVT_TREE_ITEM_COLLAPSING(LayerTree_Ctrl, MyTreeCtrl::OnItemCollapsing)
EVT_TREE_SEL_CHANGED(LayerTree_Ctrl, MyTreeCtrl::OnSelChanged)
EVT_TREE_SEL_CHANGING(LayerTree_Ctrl, MyTreeCtrl::OnSelChanging)
EVT_TREE_KEY_DOWN(LayerTree_Ctrl, MyTreeCtrl::OnTreeKeyDown)
EVT_TREE_ITEM_ACTIVATED(LayerTree_Ctrl, MyTreeCtrl::OnItemActivated)
EVT_RIGHT_DCLICK(MyTreeCtrl::OnRMouseDClick)
END_EVENT_TABLE()
<|endoftext|>


<commit_before>/** Program Stream (PS) DeMUXer.
 *  Copyright 2008 Takayuki Minegishi
 *
 *  Permission is hereby granted, free of charge, to any person
 *  obtaining a copy of this software and associated documentation
 *  files (the "Software"), to deal in the Software without
 *  restriction, including without limitation the rights to use, copy,
 *  modify, merge, publish, distribute, sublicense, and/or sell copies
 *  of the Software, and to permit persons to whom the Software is
 *  furnished to do so, subject to the following conditions:
 *
 *  The above copyright notice and this permission notice shall be
 *  included in all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 *  NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 *  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 *  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 *  DEALINGS IN THE SOFTWARE.
 */

#include <assert.h>
#include <string.h>
#include "mpeg_demux.h"
#include "mpeg2.h"

static inline int skip_packet(pes_demuxer_t *dmx);
static int video_element_packet(pes_demuxer_t *dmx);

static int process_system_packet(pes_demuxer_t *dmx)
{
	int err;
	int code;

	dec_bits *bit = dmx->stream;
	code = get_bits(bit, 8);
	err = 0;
	switch (code) {
	case 0xb9:
		return -1; /* end of iso */
		/* NOT REACHED */
		break;
	case 0xba:
		skip_bytes(bit, 8);
		break;
	case 0xbd:
		err = skip_packet(dmx);
		break;
	case 0xc0:
		err = skip_packet(dmx);
		break;
	case 0xe0:
		err = video_element_packet(dmx);
		break;
	default:
		err = skip_packet(dmx);
		break;
	}
	return err;
}

static inline int skip_packet(pes_demuxer_t *dmx)
{
	int block_size = get_bits(dmx->stream, 2 * 8);
	skip_bytes(dmx->stream, block_size);
	return (0 < block_size) ? 0 : -1;
}

static int video_element_packet(pes_demuxer_t *dmx)
{
	dec_bits *bit = dmx->stream;
	int val = get_bits(bit, 3 * 8);
	const byte_t *packet_tail;

	packet_tail = dec_bits_current(bit) + ((unsigned)val >> 8) - 1;
	dmx->shortage = (int)(packet_tail - dec_bits_tail(bit));
	if ((val & 0xc0) == 0x80) {
		val = get_bits(bit, 2 * 8) & 255;
		if (val) {
			skip_bytes(bit, val);
		}
	} else {
		val &= 255;
		while (val == 255) {
			val = get_bits(bit, 8);
		}
		if (val & 0xc0) {
			if (val & 0x80) {
				return -1;
			}
			val = get_bits(bit, 2 * 8) & 255;
		}
		if (0x30 <= val) {
			if (val & 0xc0) {
				return -1;
			}
			skip_bytes(bit, 9);
		} else if (val & 0x20) {
			skip_bytes(bit, 4);
		} else if (val != 0x0f) {
			return -1;
		}
	}
	dmx->packet_head = dec_bits_current(bit);
	if (0 < dmx->shortage) {
		dmx->packet_len = (int)(dec_bits_tail(bit) - dmx->packet_head);
	} else {
		dmx->packet_len = (int)(packet_tail - dmx->packet_head);
	}
	skip_bytes(bit, dmx->packet_len);
	return 1;
}

int mpeg_demux_init(pes_demuxer_t *dmx, int (*callback_func)(void *), void *arg)
{
	if (dmx == 0) {
		return -1;
	}
	memset((void *)dmx, 0, sizeof(*dmx));
	dec_bits_open(dmx->stream = &dmx->stream_i, 0);
	dec_bits_set_callback(dmx->stream, callback_func, arg);
	return 0;
}

const byte_t *mpeg_demux_get_video(pes_demuxer_t *dmx, int *packet_size_p)
{
	dec_bits *stream;
	int err;

	stream = dmx->stream;
	if (setjmp(stream->jmp) != 0) {
		return 0;
	}
	if (0 < dmx->shortage) {
		const byte_t *current;
		int rest, min;

		show_bits(stream, 8);
		current = dec_bits_current(stream);
		rest = (int)(dec_bits_tail(stream) - current);
		min = (rest < dmx->shortage) ? rest : dmx->shortage;
		skip_bytes(stream, min);
		*packet_size_p = min;
		dmx->shortage -= rest;
		return current;
	} else {
		err = 0;
		do {
			if (err < 0 || m2d_find_mpeg_data(stream) < 0) {
				*packet_size_p = 0;
				return 0;
			}
			err = process_system_packet(dmx);
		} while (err <= 0);
		*packet_size_p = dmx->packet_len;
		return dmx->packet_head;
	}
}

<commit_msg>Fix CRLFs.<commit_after>/** Program Stream (PS) DeMUXer.
 *  Copyright 2008 Takayuki Minegishi
 *
 *  Permission is hereby granted, free of charge, to any person
 *  obtaining a copy of this software and associated documentation
 *  files (the "Software"), to deal in the Software without
 *  restriction, including without limitation the rights to use, copy,
 *  modify, merge, publish, distribute, sublicense, and/or sell copies
 *  of the Software, and to permit persons to whom the Software is
 *  furnished to do so, subject to the following conditions:
 *
 *  The above copyright notice and this permission notice shall be
 *  included in all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 *  NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 *  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 *  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 *  DEALINGS IN THE SOFTWARE.
 */

#include <assert.h>
#include <string.h>
#include "mpeg_demux.h"
#include "mpeg2.h"

static inline int skip_packet(pes_demuxer_t *dmx);
static int video_element_packet(pes_demuxer_t *dmx);

static int process_system_packet(pes_demuxer_t *dmx)
{
	int err;
	int code;

	dec_bits *bit = dmx->stream;
	code = get_bits(bit, 8);
	err = 0;
	switch (code) {
	case 0xb9:
		return -1; /* end of iso */
		/* NOT REACHED */
		break;
	case 0xba:
		skip_bytes(bit, 8);
		break;
	case 0xbd:
		err = skip_packet(dmx);
		break;
	case 0xc0:
		err = skip_packet(dmx);
		break;
	case 0xe0:
		err = video_element_packet(dmx);
		break;
	default:
		err = skip_packet(dmx);
		break;
	}
	return err;
}

static inline int skip_packet(pes_demuxer_t *dmx)
{
	int block_size = get_bits(dmx->stream, 2 * 8);
	skip_bytes(dmx->stream, block_size);
	return (0 < block_size) ? 0 : -1;
}

static int video_element_packet(pes_demuxer_t *dmx)
{
	dec_bits *bit = dmx->stream;
	int val = get_bits(bit, 3 * 8);
	const byte_t *packet_tail;

	packet_tail = dec_bits_current(bit) + ((unsigned)val >> 8) - 1;
	dmx->shortage = (int)(packet_tail - dec_bits_tail(bit));
	if ((val & 0xc0) == 0x80) {
		val = get_bits(bit, 2 * 8) & 255;
		if (val) {
			skip_bytes(bit, val);
		}
	} else {
		val &= 255;
		while (val == 255) {
			val = get_bits(bit, 8);
		}
		if (val & 0xc0) {
			if (val & 0x80) {
				return -1;
			}
			val = get_bits(bit, 2 * 8) & 255;
		}
		if (0x30 <= val) {
			if (val & 0xc0) {
				return -1;
			}
			skip_bytes(bit, 9);
		} else if (val & 0x20) {
			skip_bytes(bit, 4);
		} else if (val != 0x0f) {
			return -1;
		}
	}
	dmx->packet_head = dec_bits_current(bit);
	if (0 < dmx->shortage) {
		dmx->packet_len = (int)(dec_bits_tail(bit) - dmx->packet_head);
	} else {
		dmx->packet_len = (int)(packet_tail - dmx->packet_head);
	}
	skip_bytes(bit, dmx->packet_len);
	return 1;
}

int mpeg_demux_init(pes_demuxer_t *dmx, int (*callback_func)(void *), void *arg)
{
	if (dmx == 0) {
		return -1;
	}
	memset((void *)dmx, 0, sizeof(*dmx));
	dec_bits_open(dmx->stream = &dmx->stream_i, 0);
	dec_bits_set_callback(dmx->stream, callback_func, arg);
	return 0;
}

const byte_t *mpeg_demux_get_video(pes_demuxer_t *dmx, int *packet_size_p)
{
	dec_bits *stream;
	int err;

	stream = dmx->stream;
	if (setjmp(stream->jmp) != 0) {
		return 0;
	}
	if (0 < dmx->shortage) {
		const byte_t *current;
		int rest, min;

		show_bits(stream, 8);
		current = dec_bits_current(stream);
		rest = (int)(dec_bits_tail(stream) - current);
		min = (rest < dmx->shortage) ? rest : dmx->shortage;
		skip_bytes(stream, min);
		*packet_size_p = min;
		dmx->shortage -= rest;
		return current;
	} else {
		err = 0;
		do {
			if (err < 0 || m2d_find_mpeg_data(stream) < 0) {
				*packet_size_p = 0;
				return 0;
			}
			err = process_system_packet(dmx);
		} while (err <= 0);
		*packet_size_p = dmx->packet_len;
		return dmx->packet_head;
	}
}

<|endoftext|>


<commit_before>#ifndef ALEPH_GEOMETRY_COVER_TREE_HH__
#define ALEPH_GEOMETRY_COVER_TREE_HH__

#include <algorithm>
#include <iterator>
#include <limits>
#include <memory>
#include <ostream>
#include <queue>
#include <stack>
#include <stdexcept>
#include <vector>

// FIXME: remove after debugging
#include <iostream>

#include <cassert>
#include <cmath>

namespace aleph
{

namespace geometry
{

/**
  @class CoverTree
  @brief Generic cover tree data structure

  This class models a cover tree data structure, as described in the
  paper "Cover trees for nearest neighbor" by Beygelzimer et al.; an
  implementation is given at:

    http://hunch.net/~jl/projects/cover_tree/cover_tree.html

  This implementation attempts to be as generic as possible. It uses
  the simplified description of the cover tree, as given by Izbicki,
  Shelton in "Faster Cover Trees".
*/

template <class Point, class Metric> class CoverTree
{
public:

  /**
    Covering constant of the cover tree. It might make sense to change
    this later on in order to improve performance. Some papers set the
    constant to `1.3`.
  */

  constexpr static const double coveringConstant = 2.0;

  class Node
  {
  public:

    /** Creates a new node that stores a point */
    Node( const Point& point, unsigned level )
      : _point( point )
      , _level( level )
    {
      assert( _level >= 1 );
    }

    /** Calculates current covering distance of the node */
    double coveringDistance() const noexcept
    {
      return std::pow( coveringConstant, static_cast<double>( _level ) );
    }

    /** @returns true if the node is a leaf node */
    bool isLeaf() const noexcept
    {
      return _children.empty();
    }

    void insert( const Point& p )
    {
      auto d = Metric()( _point, p );

      std::cerr << __PRETTY_FUNCTION__ << ": Covering distance           = " << this->coveringDistance() << "\n";
      std::cerr << __PRETTY_FUNCTION__ << ": Distance from point to root = " << d << "\n";

      if( d > this->coveringDistance() )
      {
        while( d > 2 * this->coveringDistance() )
        {
          std::cerr << __PRETTY_FUNCTION__ << ": Distance is bigger than covering distance; need to raise level of tree\n";

          std::stack<Node*> nodes;
          nodes.push( this );

          Node* leaf   = nullptr;
          Node* parent = nullptr;

          while( !nodes.empty() )
          {
            auto&& node = nodes.top();
            for( auto&& child : parent->_children )
            {
              if( child->isLeaf() )
              {
                leaf   = child.get();
                parent = node;
                break;
              }
            }

            nodes.pop();
          }

          // There is no leaf, so there is nothing to do and we just
          // skip to the bottom where we add the current node as the
          // new root of the tree.
          if( !leaf )
            break;

          assert( leaf );
          assert( parent );

          // Remove leaf from subtree ----------------------------------

          std::unique_ptr<Node> leaf_ptr( nullptr );

          parent->_children.erase(
            std::remove_if(
              parent->_children.begin(), parent->_children.end(),
              [&leaf, &leaf_ptr] ( std::unique_ptr<Node>& child )
              {
                if( child.get() == leaf )
                {
                  leaf_ptr = std::move( child );
                  return true;
                }

                return false;
              }
            ),
            parent->_children.end()
          );

          // Make leaf node the new root node --------------------------
          //
          // Notice that this does increase the level of the current
          // root. This has to be adjusted for.

          auto oldRoot
            = std::unique_ptr<Node>( new Node( this->_point, this->_level ) );

          for( auto&& child : _children )
            oldRoot->_children.push_back( std::move( child ) );

          _point = leaf->_point;
          _level = _level + 1;

          _children.clear();
          _children.push_back( std::move( oldRoot ) );
        }

        // Make current point the new root -----------------------------

        auto oldRoot
          = std::unique_ptr<Node>( new Node( this->_point, this->_level ) );

        for( auto&& child : _children )
          oldRoot->_children.push_back( std::move( child ) );

        _point = p;
        _level = _level + 1;

        _children.clear();
        _children.push_back( std::move( oldRoot ) );

        return;
      }

      return insert_( p );
    }

    /**
      Auxiliary function for performing the recursive insertion of a new
      node into the tree.
    */

    void insert_( const Point& p )
    {
      for( auto&& child : _children )
      {
        auto d = Metric()( child->_point, p );
        if( d <= child->coveringDistance() )
        {
          std::cerr << __PRETTY_FUNCTION__ << ": Recursive enumeration of the tree\n";

          // We found a node in which the new point can be inserted
          // *without* violating the covering invariant.
          child->insert_( p );
          return;
        }
      }

      // Add the new point as a child of the current root node. This
      // might require updating levels.

      if( _children.empty() )
        _level += 1;

      _children.push_back( std::unique_ptr<Node>( new Node( p, _level - 1 ) ) );
    }

    Point    _point; //< The point stored in the node
    unsigned _level; //< The level of the node (>= 1)

    /**
      All children of the node. Their order depends on the insertion
      order into the data set.
    */

    std::vector< std::unique_ptr<Node> > _children;
  };

  /**
    Inserts a new point into the cover tree. If the tree is empty,
    the new point will become the root of the tree. Else, it shall
    be inserted according to the covering invariant.
  */

  void insert( const Point& p )
  {
    if( !_root )
      _root = std::unique_ptr<Node>( new Node(p,1) );
    else
      _root->insert( p );

    this->updateLevels();
  }

  // Pretty-printing function for the tree; this is only meant for
  // debugging purposes and could conceivably be implemented using
  // `std::ostream`.
  void print( std::ostream& o )
  {
    std::queue<const Node*> nodes;
    nodes.push( _root.get() );

    while( !nodes.empty() )
    {
      {
        auto n = nodes.size();

        for( decltype(n) i = 0; i < n; i++ )
        {
          auto&& node = nodes.front();

          if( i == 0 )
            o << node->_level << ": ";
          else
            o << " ";

          o << node->_point;

          for( auto&& child : node->_children )
            nodes.push( child.get() );

          nodes.pop();
        }

        o << "\n";
      }
    }
  }

private:

  /**
    Updates the levels of a cover tree. This function ensures that all
    information is being represented correctly. It is not mentioned in
    the original paper but appears to be necessary.
  */

  void updateLevels()
  {
    // Forward pass ----------------------------------------------------
    //
    // Determine depth of the tree. This is required in order to assign
    // levels correctly later on.

    unsigned depth = 0;

    std::queue<const Node*> nodes;
    nodes.push( _root.get() );

    while( !nodes.empty() )
    {
      auto n = nodes.size();

      for( decltype(n) i = 0; i < n; i++ )
      {
        auto node = nodes.front();
        nodes.pop();

        for( auto&& child : node->_children )
          nodes.push( child.get() );
      }

      ++depth;
    }

    assert( nodes.empty() );

    // Backward pass ---------------------------------------------------
    //
    // Set the level of the root node and update child levels. Note that
    // all nodes will be traversed because this function is dumb.

    _root->_level = depth;

    nodes.push( _root.get() );

    while( !nodes.empty() )
    {
      {
        auto&& parent = nodes.front();

        for( auto&& child : parent->_children )
        {
          assert( parent->_level >= 1 );

          child->_level = parent->_level - 1;
          nodes.push( child.get() );
        }
      }

      nodes.pop();
    }
  }

  /** Root pointer of the tree */
  std::unique_ptr<Node> _root;
};

} // namespace geometry

} // namespace aleph

#endif
<commit_msg>Changed covering distance calculation<commit_after>#ifndef ALEPH_GEOMETRY_COVER_TREE_HH__
#define ALEPH_GEOMETRY_COVER_TREE_HH__

#include <algorithm>
#include <iterator>
#include <limits>
#include <memory>
#include <ostream>
#include <queue>
#include <stack>
#include <stdexcept>
#include <vector>

// FIXME: remove after debugging
#include <iostream>

#include <cassert>
#include <cmath>

namespace aleph
{

namespace geometry
{

/**
  @class CoverTree
  @brief Generic cover tree data structure

  This class models a cover tree data structure, as described in the
  paper "Cover trees for nearest neighbor" by Beygelzimer et al.; an
  implementation is given at:

    http://hunch.net/~jl/projects/cover_tree/cover_tree.html

  This implementation attempts to be as generic as possible. It uses
  the simplified description of the cover tree, as given by Izbicki,
  Shelton in "Faster Cover Trees".
*/

template <class Point, class Metric> class CoverTree
{
public:

  /**
    Covering constant of the cover tree. It might make sense to change
    this later on in order to improve performance. Some papers set the
    constant to `1.3`.
  */

  constexpr static const double coveringConstant = 2.0;

  class Node
  {
  public:

    /** Creates a new node that stores a point */
    Node( const Point& point, unsigned level )
      : _point( point )
      , _level( level )
    {
      assert( _level >= 1 );
    }

    /** Calculates current covering distance of the node */
    double coveringDistance() const noexcept
    {
      return std::pow( 1.0 / coveringConstant, static_cast<double>( _level ) );
    }

    /** @returns true if the node is a leaf node */
    bool isLeaf() const noexcept
    {
      return _children.empty();
    }

    void insert( const Point& p )
    {
      auto d = Metric()( _point, p );

      std::cerr << __PRETTY_FUNCTION__ << ": Covering distance           = " << this->coveringDistance() << "\n";
      std::cerr << __PRETTY_FUNCTION__ << ": Distance from point to root = " << d << "\n";

      if( d > this->coveringDistance() )
      {
        while( d > 2 * this->coveringDistance() )
        {
          std::cerr << __PRETTY_FUNCTION__ << ": Distance is bigger than covering distance; need to raise level of tree\n";

          std::stack<Node*> nodes;
          nodes.push( this );

          Node* leaf   = nullptr;
          Node* parent = nullptr;

          while( !nodes.empty() )
          {
            auto&& node = nodes.top();
            for( auto&& child : parent->_children )
            {
              if( child->isLeaf() )
              {
                leaf   = child.get();
                parent = node;
                break;
              }
            }

            nodes.pop();
          }

          // There is no leaf, so there is nothing to do and we just
          // skip to the bottom where we add the current node as the
          // new root of the tree.
          if( !leaf )
            break;

          assert( leaf );
          assert( parent );

          // Remove leaf from subtree ----------------------------------

          std::unique_ptr<Node> leaf_ptr( nullptr );

          parent->_children.erase(
            std::remove_if(
              parent->_children.begin(), parent->_children.end(),
              [&leaf, &leaf_ptr] ( std::unique_ptr<Node>& child )
              {
                if( child.get() == leaf )
                {
                  leaf_ptr = std::move( child );
                  return true;
                }

                return false;
              }
            ),
            parent->_children.end()
          );

          // Make leaf node the new root node --------------------------
          //
          // Notice that this does increase the level of the current
          // root. This has to be adjusted for.

          auto oldRoot
            = std::unique_ptr<Node>( new Node( this->_point, this->_level ) );

          for( auto&& child : _children )
            oldRoot->_children.push_back( std::move( child ) );

          _point = leaf->_point;
          _level = _level + 1;

          _children.clear();
          _children.push_back( std::move( oldRoot ) );
        }

        // Make current point the new root -----------------------------

        auto oldRoot
          = std::unique_ptr<Node>( new Node( this->_point, this->_level ) );

        for( auto&& child : _children )
          oldRoot->_children.push_back( std::move( child ) );

        _point = p;
        _level = _level + 1;

        _children.clear();
        _children.push_back( std::move( oldRoot ) );

        return;
      }

      return insert_( p );
    }

    /**
      Auxiliary function for performing the recursive insertion of a new
      node into the tree.
    */

    void insert_( const Point& p )
    {
      for( auto&& child : _children )
      {
        auto d = Metric()( child->_point, p );
        if( d <= child->coveringDistance() )
        {
          std::cerr << __PRETTY_FUNCTION__ << ": Recursive enumeration of the tree\n";

          // We found a node in which the new point can be inserted
          // *without* violating the covering invariant.
          child->insert_( p );
          return;
        }
      }

      // Add the new point as a child of the current root node. This
      // might require updating levels.

      if( _children.empty() )
        _level += 1;

      _children.push_back( std::unique_ptr<Node>( new Node( p, _level - 1 ) ) );
    }

    Point    _point; //< The point stored in the node
    unsigned _level; //< The level of the node (>= 1)

    /**
      All children of the node. Their order depends on the insertion
      order into the data set.
    */

    std::vector< std::unique_ptr<Node> > _children;
  };

  /**
    Inserts a new point into the cover tree. If the tree is empty,
    the new point will become the root of the tree. Else, it shall
    be inserted according to the covering invariant.
  */

  void insert( const Point& p )
  {
    if( !_root )
      _root = std::unique_ptr<Node>( new Node(p,1) );
    else
      _root->insert( p );

    this->updateLevels();
  }

  // Pretty-printing function for the tree; this is only meant for
  // debugging purposes and could conceivably be implemented using
  // `std::ostream`.
  void print( std::ostream& o )
  {
    std::queue<const Node*> nodes;
    nodes.push( _root.get() );

    while( !nodes.empty() )
    {
      {
        auto n = nodes.size();

        for( decltype(n) i = 0; i < n; i++ )
        {
          auto&& node = nodes.front();

          if( i == 0 )
            o << node->_level << ": ";
          else
            o << " ";

          o << node->_point;

          for( auto&& child : node->_children )
            nodes.push( child.get() );

          nodes.pop();
        }

        o << "\n";
      }
    }
  }

private:

  /**
    Updates the levels of a cover tree. This function ensures that all
    information is being represented correctly. It is not mentioned in
    the original paper but appears to be necessary.
  */

  void updateLevels()
  {
    // Forward pass ----------------------------------------------------
    //
    // Determine depth of the tree. This is required in order to assign
    // levels correctly later on.

    unsigned depth = 0;

    std::queue<const Node*> nodes;
    nodes.push( _root.get() );

    while( !nodes.empty() )
    {
      auto n = nodes.size();

      for( decltype(n) i = 0; i < n; i++ )
      {
        auto node = nodes.front();
        nodes.pop();

        for( auto&& child : node->_children )
          nodes.push( child.get() );
      }

      ++depth;
    }

    assert( nodes.empty() );

    // Backward pass ---------------------------------------------------
    //
    // Set the level of the root node and update child levels. Note that
    // all nodes will be traversed because this function is dumb.

    _root->_level = depth;

    nodes.push( _root.get() );

    while( !nodes.empty() )
    {
      {
        auto&& parent = nodes.front();

        for( auto&& child : parent->_children )
        {
          assert( parent->_level >= 1 );

          child->_level = parent->_level - 1;
          nodes.push( child.get() );
        }
      }

      nodes.pop();
    }
  }

  /** Root pointer of the tree */
  std::unique_ptr<Node> _root;
};

} // namespace geometry

} // namespace aleph

#endif
<|endoftext|>


<commit_before>/**
 * \file
 * Copyright 2017 Alexander Matthes
 *
 * This file is part of alpaka.
 *
 * alpaka is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * alpaka 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with alpaka.
 * If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include <boost/predef.h>

//-----------------------------------------------------------------------------
// In boost since 1.68.0
// BOOST_PREDEF_MAKE_10_VVRRP(V)
#if !defined(BOOST_PREDEF_MAKE_10_VVRRP)
    #define BOOST_PREDEF_MAKE_10_VVRRP(V) BOOST_VERSION_NUMBER(((V)/1000)%100,((V)/10)%100,(V)%10)
#endif

//-----------------------------------------------------------------------------
// In boost since 1.68.0
// CUDA language detection
// - clang defines __CUDA__ and __CUDACC__ when compiling CUDA code ('-x cuda')
// - nvcc defines __CUDACC__ when compiling CUDA code
#if !defined(BOOST_LANG_CUDA)
    #if defined(__CUDA__) || defined(__CUDACC__)
        #include <cuda.h>
        #define BOOST_LANG_CUDA BOOST_PREDEF_MAKE_10_VVRRP(CUDA_VERSION)
    #else
        #define BOOST_LANG_CUDA BOOST_VERSION_NUMBER_NOT_AVAILABLE
    #endif
#endif

//-----------------------------------------------------------------------------
// In boost since 1.68.0
// CUDA device architecture detection
#if !defined(BOOST_ARCH_PTX)
    #if defined(__CUDA_ARCH__)
        #define BOOST_ARCH_PTX BOOST_PREDEF_MAKE_10_VRP(__CUDA_ARCH__)
    #else
        #define BOOST_ARCH_PTX BOOST_VERSION_NUMBER_NOT_AVAILABLE
    #endif
#endif

//-----------------------------------------------------------------------------
// In boost since 1.68.0
// nvcc CUDA compiler detection

#include <boost/version.hpp>
#if BOOST_VERSION >= 106800
    // BOOST_COMP_NVCC_EMULATED is defined by boost instead of BOOST_COMP_NVCC
    #if defined(BOOST_COMP_NVCC) && defined(BOOST_COMP_NVCC_EMULATED)
        #undef BOOST_COMP_NVCC
        #define BOOST_COMP_NVCC BOOST_COMP_NVCC_EMULATED
    #endif
#endif

#if !defined(BOOST_COMP_NVCC)
    #if defined(__NVCC__)
        // The __CUDACC_VER_MAJOR__, __CUDACC_VER_MINOR__ and __CUDACC_VER_BUILD__
        // have been added with nvcc 7.5 and have not been available before.
        #if !defined(__CUDACC_VER_MAJOR__) || !defined(__CUDACC_VER_MINOR__) || !defined(__CUDACC_VER_BUILD__)
            #define BOOST_COMP_NVCC BOOST_VERSION_NUMBER_AVAILABLE
        #else
            #define BOOST_COMP_NVCC BOOST_VERSION_NUMBER(__CUDACC_VER_MAJOR__, __CUDACC_VER_MINOR__, __CUDACC_VER_BUILD__)
        #endif
    #else
        #define BOOST_COMP_NVCC BOOST_VERSION_NUMBER_NOT_AVAILABLE
    #endif
#endif

//-----------------------------------------------------------------------------
// In boost since 1.64.0
// Work around for broken intel detection
#if BOOST_COMP_INTEL == 0
    #if defined(__INTEL_COMPILER)
        #ifdef BOOST_COMP_INTEL_DETECTION
            #undef BOOST_COMP_INTEL_DETECTION
        #endif
        #define BOOST_COMP_INTEL_DETECTION BOOST_PREDEF_MAKE_10_VVRR(__INTEL_COMPILER)
        #if defined(BOOST_COMP_INTEL)
            #undef BOOST_COMP_INTEL
        #endif
        #define BOOST_COMP_INTEL BOOST_COMP_INTEL_DETECTION
    #endif
#endif
<commit_msg>incorporate review comments<commit_after>/**
 * \file
 * Copyright 2017-2018 Alexander Matthes, Benjamin Worpitz
 *
 * This file is part of alpaka.
 *
 * alpaka is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * alpaka 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with alpaka.
 * If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include <boost/predef.h>

//-----------------------------------------------------------------------------
// In boost since 1.68.0
// BOOST_PREDEF_MAKE_10_VVRRP(V)
#if !defined(BOOST_PREDEF_MAKE_10_VVRRP)
    #define BOOST_PREDEF_MAKE_10_VVRRP(V) BOOST_VERSION_NUMBER(((V)/1000)%100,((V)/10)%100,(V)%10)
#endif

//-----------------------------------------------------------------------------
// In boost since 1.68.0
// CUDA language detection
// - clang defines __CUDA__ and __CUDACC__ when compiling CUDA code ('-x cuda')
// - nvcc defines __CUDACC__ when compiling CUDA code
#if !defined(BOOST_LANG_CUDA)
    #if defined(__CUDA__) || defined(__CUDACC__)
        #include <cuda.h>
        #define BOOST_LANG_CUDA BOOST_PREDEF_MAKE_10_VVRRP(CUDA_VERSION)
    #else
        #define BOOST_LANG_CUDA BOOST_VERSION_NUMBER_NOT_AVAILABLE
    #endif
#endif

//-----------------------------------------------------------------------------
// In boost since 1.68.0
// CUDA device architecture detection
#if !defined(BOOST_ARCH_PTX)
    #if defined(__CUDA_ARCH__)
        #define BOOST_ARCH_PTX BOOST_PREDEF_MAKE_10_VRP(__CUDA_ARCH__)
    #else
        #define BOOST_ARCH_PTX BOOST_VERSION_NUMBER_NOT_AVAILABLE
    #endif
#endif

//-----------------------------------------------------------------------------
// In boost since 1.68.0
// nvcc CUDA compiler detection

#include <boost/version.hpp>
#if BOOST_VERSION >= 106800
    // BOOST_COMP_NVCC_EMULATED is defined by boost instead of BOOST_COMP_NVCC
    #if defined(BOOST_COMP_NVCC) && defined(BOOST_COMP_NVCC_EMULATED)
        #undef BOOST_COMP_NVCC
        #define BOOST_COMP_NVCC BOOST_COMP_NVCC_EMULATED
    #endif
#endif

#if !defined(BOOST_COMP_NVCC)
    #if defined(__NVCC__)
        // The __CUDACC_VER_MAJOR__, __CUDACC_VER_MINOR__ and __CUDACC_VER_BUILD__
        // have been added with nvcc 7.5 and have not been available before.
        #if !defined(__CUDACC_VER_MAJOR__) || !defined(__CUDACC_VER_MINOR__) || !defined(__CUDACC_VER_BUILD__)
            #define BOOST_COMP_NVCC BOOST_VERSION_NUMBER_AVAILABLE
        #else
            #define BOOST_COMP_NVCC BOOST_VERSION_NUMBER(__CUDACC_VER_MAJOR__, __CUDACC_VER_MINOR__, __CUDACC_VER_BUILD__)
        #endif
    #else
        #define BOOST_COMP_NVCC BOOST_VERSION_NUMBER_NOT_AVAILABLE
    #endif
#endif

//-----------------------------------------------------------------------------
// In boost since 1.64.0
// Work around for broken intel detection
#if BOOST_COMP_INTEL == 0
    #if defined(__INTEL_COMPILER)
        #ifdef BOOST_COMP_INTEL_DETECTION
            #undef BOOST_COMP_INTEL_DETECTION
        #endif
        #define BOOST_COMP_INTEL_DETECTION BOOST_PREDEF_MAKE_10_VVRR(__INTEL_COMPILER)
        #if defined(BOOST_COMP_INTEL)
            #undef BOOST_COMP_INTEL
        #endif
        #define BOOST_COMP_INTEL BOOST_COMP_INTEL_DETECTION
    #endif
#endif
<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2014 Siyuan Ren (netheril96@gmail.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#ifndef AUTOJSONCXX_ARRAY_TYPES_HPP_29A4C106C1B1
#define AUTOJSONCXX_ARRAY_TYPES_HPP_29A4C106C1B1

#include <autojsoncxx/base.hpp>
#include <autojsoncxx/error.hpp>
#include <vector>
#include <deque>
#include <stack>
#include <cassert>

#if AUTOJSONCXX_HAS_MODERN_TYPES
#include <array>
#endif

namespace autojsoncxx {

template <class ElementType, class Derived>
class VectorBaseSAXEventHandler {
private:
    ElementType current;
    SAXEventHandler<ElementType> internal_handler;
    utility::scoped_ptr<error::ErrorBase> the_error;
    std::stack<signed char> state;
    // A stack of StartArray() and StartObject() event
    // must be recorded, so we know when the current
    // element has been fully parsed, and needs to be
    // pushed back into the container

    void push_when_time_is_right()
    {
        if (state.size() == 1 && state.top() == internal::ARRAY) {
            static_cast<Derived*>(this)->Push(AUTOJSONCXX_MOVE_IF_NOEXCEPT(current));
            current = ElementType();
            internal_handler.PrepareForReuse();
        }
    }

    bool check_array_length(SizeType length)
    {
        if (state.size() == 1 && state.top() == internal::ARRAY
            && !static_cast<Derived*>(this)->CheckLength(length)) {
            this->the_error.reset(new error::ArrayLengthMismatchError(static_cast<Derived*>(this)->ExpectedLength(), length));
            return false;
        }
        return true;
    }

    bool check_depth(const char* type)
    {
        if (state.empty()) {
            the_error.reset(new error::TypeMismatchError("array", type));
            return false;
        }
        return true;
    }

    bool checked_event_forwarding(bool success)
    {
        if (success) {
            push_when_time_is_right();
            return true;
        }

        set_element_error();
        return false;
    }

    void set_element_error()
    {
        this->the_error.reset(new error::ArrayElementError(static_cast<Derived*>(this)->GetCurrentSize()));
    }

public:
    explicit VectorBaseSAXEventHandler()
        : current()
        , internal_handler(&current)
    {
    }

    bool Null()
    {
        return check_depth("null") && checked_event_forwarding(internal_handler.Null());
    }

    bool Bool(bool b)
    {
        return check_depth("bool") && checked_event_forwarding(internal_handler.Bool(b));
    }

    bool Int(int i)
    {
        return check_depth("int") && checked_event_forwarding(internal_handler.Int(i));
    }

    bool Uint(unsigned i)
    {
        return check_depth("unsigned") && checked_event_forwarding(internal_handler.Uint(i));
    }

    bool Int64(int64_t i)
    {
        return check_depth("int64_t") && checked_event_forwarding(internal_handler.Int64(i));
    }

    bool Uint64(uint64_t i)
    {
        return check_depth("uint64_t") && checked_event_forwarding(internal_handler.Uint64(i));
    }

    bool Double(double d)
    {
        return check_depth("double") && checked_event_forwarding(internal_handler.Double(d));
    }

    bool String(const char* str, SizeType length, bool copy)
    {
        return check_depth("string") && checked_event_forwarding(internal_handler.String(str, length, copy));
    }

    bool Key(const char* str, SizeType length, bool copy)
    {
        return check_depth("object") && checked_event_forwarding(internal_handler.Key(str, length, copy));
    }

    bool StartArray()
    {
        state.push(internal::ARRAY);
        if (state.size() > 1 && !internal_handler.StartArray()) {
            set_element_error();
            return false;
        }
        return true;
    }

    bool EndArray(SizeType length)
    {
        assert(state.top() == internal::ARRAY);

        // When depth > 1, this event should be forwarded to the element
        if (state.size() > 1 && !internal_handler.EndArray(length)) {
            set_element_error();
            return false;
        }

        if (!check_array_length(length))
            return false;

        // When depth == 2, this event will close the underlying element
        // and it should be pushed backed into the container
        state.pop();
        push_when_time_is_right();

        return true;
    }

    bool StartObject()
    {
        state.push(internal::OBJECT);
        return check_depth("object") && checked_event_forwarding(internal_handler.StartObject());
    }

    bool EndObject(SizeType length)
    {
        assert(state.top() == internal::OBJECT);
        state.pop();
        return check_depth("object") && checked_event_forwarding(internal_handler.EndObject(length));
    }

    bool HasError() const
    {
        return !this->the_error.empty();
    }

    bool ReapError(error::ErrorStack& errs)
    {
        if (this->the_error.empty())
            return false;

        errs.push(this->the_error.release());
        internal_handler.ReapError(errs);
        return true;
    }

    void PrepareForReuse()
    {
        std::stack<signed char>().swap(state);
    }
};

template <class T, class Allocator>
class SAXEventHandler<std::vector<T, Allocator> >
    : public VectorBaseSAXEventHandler<T, SAXEventHandler<std::vector<T, Allocator> > > {

public:
    typedef std::vector<T, Allocator> vector_type;
    typedef VectorBaseSAXEventHandler<T, SAXEventHandler<std::vector<T, Allocator> > > base_type;

private:
    vector_type* m_value;

public:
    explicit SAXEventHandler(vector_type* v)
        : m_value(v)
    {
    }

    void Push(const T& c)
    {
        m_value->push_back(c);
    }

#if AUTOJSONCXX_HAS_RVALUE

    void Push(T&& c)
    {
        m_value->push_back(AUTOJSONCXX_MOVE(c));
    }

#endif

    bool CheckLength(SizeType) const
    {
        return true;
    }

    size_t ExpectedLength()
    {
        return 0;
    }

    size_t GetCurrentSize() const
    {
        return m_value->size();
    }
};

template <class T, class Allocator>
class SAXEventHandler<std::deque<T, Allocator> >
    : public VectorBaseSAXEventHandler<T, SAXEventHandler<std::deque<T, Allocator> > > {

public:
    typedef std::deque<T, Allocator> vector_type;
    typedef VectorBaseSAXEventHandler<T, SAXEventHandler<std::deque<T, Allocator> > > base_type;

private:
    vector_type* m_value;

public:
    explicit SAXEventHandler(vector_type* v)
        : m_value(v)
    {
    }

    void Push(const T& c)
    {
        m_value->push_back(c);
    }

#if AUTOJSONCXX_HAS_RVALUE

    void Push(T&& c)
    {
        m_value->push_back(AUTOJSONCXX_MOVE(c));
    }

#endif

    bool CheckLength(SizeType) const
    {
        return true;
    }

    size_t ExpectedLength()
    {
        return 0;
    }

    size_t GetCurrentSize() const
    {
        return m_value->size();
    }
};

template <class Writer, class Container, class ValueType, class ConstIteratorType>
struct ContainerSerializer {
    void operator()(Writer& w, const Container& con) const
    {
        w.StartArray();
        for (ConstIteratorType it = con.begin(), end = con.end(); it != end; ++it)
            Serializer<Writer, ValueType>()(w, *it);
        w.EndArray();
    }
};

template <class Writer, class T, class Allocator>
struct Serializer<Writer, std::vector<T, Allocator> >
    : public ContainerSerializer<Writer, std::vector<T, Allocator>,
                                 typename std::vector<T, Allocator>::value_type,
                                 typename std::vector<T, Allocator>::const_iterator> {
};

template <class Writer, class T, class Allocator>
struct Serializer<Writer, std::deque<T, Allocator> >
    : public ContainerSerializer<Writer, std::deque<T, Allocator>,
                                 typename std::deque<T, Allocator>::value_type,
                                 typename std::deque<T, Allocator>::const_iterator> {
};

#if AUTOJSONCXX_HAS_MODERN_TYPES
template <class T, size_t N>
class SAXEventHandler<std::array<T, N> >
    : public VectorBaseSAXEventHandler<T, SAXEventHandler<std::array<T, N> > > {

public:
    typedef std::array<T, N> vector_type;
    typedef VectorBaseSAXEventHandler<T, SAXEventHandler<std::array<T, N> > > base_type;

private:
    vector_type* m_value;
    size_t index;

public:
    explicit SAXEventHandler(vector_type* v)
        : m_value(v)
        , index(0)
    {
    }

    void Push(const T& c)
    {
        (*m_value)[index] = c;
        index = (index + 1) % N;
    }

#if AUTOJSONCXX_HAS_RVALUE

    void Push(T&& c)
    {
        (*m_value)[index] = AUTOJSONCXX_MOVE(c);
        index = (index + 1) % N;
    }

#endif

    bool CheckLength(SizeType length)
    {
        return length == N;
    }

    size_t ExpectedLength() const
    {
        return N;
    }

    size_t GetCurrentSize()
    {
        return index;
    }
};

template <class Writer, class T, std::size_t N>
struct Serializer<Writer, std::array<T, N> >
    : public ContainerSerializer<Writer, std::array<T, N>,
                                 typename std::array<T, N>::value_type,
                                 typename std::array<T, N>::const_iterator> {
};

#endif
}
#endif
<commit_msg>Fix detection of mismatch between array/object<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2014 Siyuan Ren (netheril96@gmail.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#ifndef AUTOJSONCXX_ARRAY_TYPES_HPP_29A4C106C1B1
#define AUTOJSONCXX_ARRAY_TYPES_HPP_29A4C106C1B1

#include <autojsoncxx/base.hpp>
#include <autojsoncxx/error.hpp>
#include <vector>
#include <deque>
#include <stack>
#include <cassert>

#if AUTOJSONCXX_HAS_MODERN_TYPES
#include <array>
#endif

namespace autojsoncxx {

template <class ElementType, class Derived>
class VectorBaseSAXEventHandler {
private:
    ElementType current;
    SAXEventHandler<ElementType> internal_handler;
    utility::scoped_ptr<error::ErrorBase> the_error;
    std::stack<signed char> state;
    // A stack of StartArray() and StartObject() event
    // must be recorded, so we know when the current
    // element has been fully parsed, and needs to be
    // pushed back into the container

    void push_when_time_is_right()
    {
        if (state.size() == 1 && state.top() == internal::ARRAY) {
            static_cast<Derived*>(this)->Push(AUTOJSONCXX_MOVE_IF_NOEXCEPT(current));
            current = ElementType();
            internal_handler.PrepareForReuse();
        }
    }

    bool check_array_length(SizeType length)
    {
        if (state.size() == 1 && state.top() == internal::ARRAY
            && !static_cast<Derived*>(this)->CheckLength(length)) {
            this->the_error.reset(new error::ArrayLengthMismatchError(static_cast<Derived*>(this)->ExpectedLength(), length));
            return false;
        }
        return true;
    }

    bool check_depth(const char* type)
    {
        if (state.empty()) {
            the_error.reset(new error::TypeMismatchError("array", type));
            return false;
        }
        return true;
    }

    bool checked_event_forwarding(bool success)
    {
        if (success) {
            push_when_time_is_right();
            return true;
        }

        set_element_error();
        return false;
    }

    void set_element_error()
    {
        this->the_error.reset(new error::ArrayElementError(static_cast<Derived*>(this)->GetCurrentSize()));
    }

public:
    explicit VectorBaseSAXEventHandler()
        : current()
        , internal_handler(&current)
    {
    }

    bool Null()
    {
        return check_depth("null") && checked_event_forwarding(internal_handler.Null());
    }

    bool Bool(bool b)
    {
        return check_depth("bool") && checked_event_forwarding(internal_handler.Bool(b));
    }

    bool Int(int i)
    {
        return check_depth("int") && checked_event_forwarding(internal_handler.Int(i));
    }

    bool Uint(unsigned i)
    {
        return check_depth("unsigned") && checked_event_forwarding(internal_handler.Uint(i));
    }

    bool Int64(int64_t i)
    {
        return check_depth("int64_t") && checked_event_forwarding(internal_handler.Int64(i));
    }

    bool Uint64(uint64_t i)
    {
        return check_depth("uint64_t") && checked_event_forwarding(internal_handler.Uint64(i));
    }

    bool Double(double d)
    {
        return check_depth("double") && checked_event_forwarding(internal_handler.Double(d));
    }

    bool String(const char* str, SizeType length, bool copy)
    {
        return check_depth("string") && checked_event_forwarding(internal_handler.String(str, length, copy));
    }

    bool Key(const char* str, SizeType length, bool copy)
    {
        return check_depth("object") && checked_event_forwarding(internal_handler.Key(str, length, copy));
    }

    bool StartArray()
    {
        state.push(internal::ARRAY);
        if (state.size() > 1 && !internal_handler.StartArray()) {
            set_element_error();
            return false;
        }
        return true;
    }

    bool EndArray(SizeType length)
    {
        assert(state.top() == internal::ARRAY);

        // When depth > 1, this event should be forwarded to the element
        if (state.size() > 1 && !internal_handler.EndArray(length)) {
            set_element_error();
            return false;
        }

        if (!check_array_length(length))
            return false;

        // When depth == 2, this event will close the underlying element
        // and it should be pushed backed into the container
        state.pop();
        push_when_time_is_right();

        return true;
    }

    bool StartObject()
    {
        if (!check_depth("object"))
            return false;
        state.push(internal::OBJECT);
        return checked_event_forwarding(internal_handler.StartObject());
    }

    bool EndObject(SizeType length)
    {
        assert(state.top() == internal::OBJECT);
        state.pop();
        return check_depth("object") && checked_event_forwarding(internal_handler.EndObject(length));
    }

    bool HasError() const
    {
        return !this->the_error.empty();
    }

    bool ReapError(error::ErrorStack& errs)
    {
        if (this->the_error.empty())
            return false;

        errs.push(this->the_error.release());
        internal_handler.ReapError(errs);
        return true;
    }

    void PrepareForReuse()
    {
        std::stack<signed char>().swap(state);
    }
};

template <class T, class Allocator>
class SAXEventHandler<std::vector<T, Allocator> >
    : public VectorBaseSAXEventHandler<T, SAXEventHandler<std::vector<T, Allocator> > > {

public:
    typedef std::vector<T, Allocator> vector_type;
    typedef VectorBaseSAXEventHandler<T, SAXEventHandler<std::vector<T, Allocator> > > base_type;

private:
    vector_type* m_value;

public:
    explicit SAXEventHandler(vector_type* v)
        : m_value(v)
    {
    }

    void Push(const T& c)
    {
        m_value->push_back(c);
    }

#if AUTOJSONCXX_HAS_RVALUE

    void Push(T&& c)
    {
        m_value->push_back(AUTOJSONCXX_MOVE(c));
    }

#endif

    bool CheckLength(SizeType) const
    {
        return true;
    }

    size_t ExpectedLength()
    {
        return 0;
    }

    size_t GetCurrentSize() const
    {
        return m_value->size();
    }
};

template <class T, class Allocator>
class SAXEventHandler<std::deque<T, Allocator> >
    : public VectorBaseSAXEventHandler<T, SAXEventHandler<std::deque<T, Allocator> > > {

public:
    typedef std::deque<T, Allocator> vector_type;
    typedef VectorBaseSAXEventHandler<T, SAXEventHandler<std::deque<T, Allocator> > > base_type;

private:
    vector_type* m_value;

public:
    explicit SAXEventHandler(vector_type* v)
        : m_value(v)
    {
    }

    void Push(const T& c)
    {
        m_value->push_back(c);
    }

#if AUTOJSONCXX_HAS_RVALUE

    void Push(T&& c)
    {
        m_value->push_back(AUTOJSONCXX_MOVE(c));
    }

#endif

    bool CheckLength(SizeType) const
    {
        return true;
    }

    size_t ExpectedLength()
    {
        return 0;
    }

    size_t GetCurrentSize() const
    {
        return m_value->size();
    }
};

template <class Writer, class Container, class ValueType, class ConstIteratorType>
struct ContainerSerializer {
    void operator()(Writer& w, const Container& con) const
    {
        w.StartArray();
        for (ConstIteratorType it = con.begin(), end = con.end(); it != end; ++it)
            Serializer<Writer, ValueType>()(w, *it);
        w.EndArray();
    }
};

template <class Writer, class T, class Allocator>
struct Serializer<Writer, std::vector<T, Allocator> >
    : public ContainerSerializer<Writer, std::vector<T, Allocator>,
                                 typename std::vector<T, Allocator>::value_type,
                                 typename std::vector<T, Allocator>::const_iterator> {
};

template <class Writer, class T, class Allocator>
struct Serializer<Writer, std::deque<T, Allocator> >
    : public ContainerSerializer<Writer, std::deque<T, Allocator>,
                                 typename std::deque<T, Allocator>::value_type,
                                 typename std::deque<T, Allocator>::const_iterator> {
};

#if AUTOJSONCXX_HAS_MODERN_TYPES
template <class T, size_t N>
class SAXEventHandler<std::array<T, N> >
    : public VectorBaseSAXEventHandler<T, SAXEventHandler<std::array<T, N> > > {

public:
    typedef std::array<T, N> vector_type;
    typedef VectorBaseSAXEventHandler<T, SAXEventHandler<std::array<T, N> > > base_type;

private:
    vector_type* m_value;
    size_t index;

public:
    explicit SAXEventHandler(vector_type* v)
        : m_value(v)
        , index(0)
    {
    }

    void Push(const T& c)
    {
        (*m_value)[index] = c;
        index = (index + 1) % N;
    }

#if AUTOJSONCXX_HAS_RVALUE

    void Push(T&& c)
    {
        (*m_value)[index] = AUTOJSONCXX_MOVE(c);
        index = (index + 1) % N;
    }

#endif

    bool CheckLength(SizeType length)
    {
        return length == N;
    }

    size_t ExpectedLength() const
    {
        return N;
    }

    size_t GetCurrentSize()
    {
        return index;
    }
};

template <class Writer, class T, std::size_t N>
struct Serializer<Writer, std::array<T, N> >
    : public ContainerSerializer<Writer, std::array<T, N>,
                                 typename std::array<T, N>::value_type,
                                 typename std::array<T, N>::const_iterator> {
};

#endif
}
#endif
<|endoftext|>


<commit_before>#ifndef KGR_KANGARU_INCLUDE_KANGARU_DETAIL_INJECTED_HPP
#define KGR_KANGARU_INCLUDE_KANGARU_DETAIL_INJECTED_HPP

#include "utils.hpp"
#include "single.hpp"
#include "traits.hpp"
#include "service_storage.hpp"

namespace kgr {
namespace detail {

/*
 * This class is a non virtual service being injected.
 * The service injected in this is either a single or a non-single.
 *
 * When T is a reference type, the service definition T is a single.
 */
template<typename T>
struct injected {
private:
	using Type = conditional_t<is_single<T>::value, T&, T>;

public:
	// TODO: kangaru 5: use () parens contructor by default
	template<typename... Args, enable_if_t<is_brace_constructible<Type, Args...>::value, int> = 0>
	explicit injected(Args&&... args) noexcept(noexcept(Type{std::forward<Args>(args)...})) :
		_service{std::forward<Args>(args)...} {}

	template<typename... Args, enable_if_t<
		!is_brace_constructible<Type, Args...>::value &&
		std::is_constructible<Type, Args...>::value, int> = 0>
	explicit injected(Args&&... args) noexcept(std::is_nothrow_constructible<Type, Args...>::value) :
		_service(std::forward<Args>(args)...) {}

	// TODO: kangaru 5: use () parens contructor by default
	// When using this function, Type is always a reference so no copy is done.
	template<typename... Args>

	explicit injected(service_storage& storage) noexcept :
		_service{storage.service<T>()} {}

	auto forward() noexcept(noexcept(std::declval<Type>().forward())) -> service_type<T> {
		return _service.forward();
	}

private:
	Type _service;
};

/*
 * This class is a virtual service being injected.
 * It contains a pointer to the service and it's forward function.
 */
template<typename T>
struct virtual_injected {
	explicit virtual_injected(service_storage& storage) noexcept : virtual_injected{storage.cast<T>()} {}
	explicit virtual_injected(void* service, forward_ptr<T> f) noexcept : _service{service}, _forward{f} {}
	explicit virtual_injected(const typed_service_storage<T>& storage) noexcept :
		_service{storage.service}, _forward{storage.forward} {}

	service_type<T> forward() {
		return _forward(_service);
	}

private:
	void* _service;
	forward_ptr<T> _forward;
};

/*
 * This class is a simple type trait, that receive an injected service type,
 * and extract the definition type.
 */
template<typename>
struct injected_service {};

/*
 * This is for non-virtual services.
 */
template<typename T>
struct injected_service<injected<T>&&> {
	using type = T;
};

/*
 * This is for virtual services.
 */
template<typename T>
struct injected_service<virtual_injected<T>&&> {
	using type = T;
};

/*
 * This is an alias for the typedef in injected_service
 */
template<typename T>
using injected_service_t = typename injected_service<T>::type;

/*
 * This is the contrary of injected_service.
 * We get a service definition type, and we return the wrapper type.
 * We cannot use conditional_t here, since it makes MSVC to crash when instanciating construct functions.
 */
template<typename T>
using injected_wrapper = typename std::conditional<is_polymorphic<T>::value,
	virtual_injected<T>,
	injected<T>
>::type;

template<std::size_t n, typename F>
using injected_argument_t = injected_service_t<function_argument_t<n, F>>;

template<typename... Ts>
struct inject_result_helper {
	using type = std::tuple<typename remove_rvalue_reference<Ts>::type...>;
};

template<typename, typename>
struct single_insertion_result;

template<typename T, typename... Parents>
struct single_insertion_result<T, meta_list<Parents...>> {
	using type = std::tuple<detail::typed_service_storage<T>, detail::typed_service_storage<Parents>...>;
};

template<typename T>
using single_insertion_result_t = typename single_insertion_result<T, parent_types<T>>::type;

} // namespace detail

/*
 * This is an injected argument type in construct functions.
 */
template<typename T>
using inject_t = detail::injected_wrapper<T>&&;

/*
 * The function makes a tuple of either l-value reference, or objects.
 * The is because non-single service don't live past the statement that `Definition::construct` is called.
 * But we need the non-singles to live past that, so they are moved into the tuple of injected arguments.
 *
 * Single service live as long as the container lives. They can, and should be l-value references.
 */
template<typename... Args>
constexpr auto inject(Args&&... args) -> std::tuple<detail::remove_rvalue_reference_t<Args>...> {
	return std::tuple<detail::remove_rvalue_reference_t<Args>...>{std::forward<Args>(args)...};
}

/*
 * Alias to help write a return type for construct functions.
 * Yield the return type of inject(Ts...)
 */
template<typename... Ts>
using inject_result = typename detail::inject_result_helper<Ts...>::type;

} // namespace kgr

#endif // KGR_KANGARU_INCLUDE_KANGARU_DETAIL_INJECTED_HPP
<commit_msg>GCC 4.8 compatibility<commit_after>#ifndef KGR_KANGARU_INCLUDE_KANGARU_DETAIL_INJECTED_HPP
#define KGR_KANGARU_INCLUDE_KANGARU_DETAIL_INJECTED_HPP

#include "utils.hpp"
#include "single.hpp"
#include "traits.hpp"
#include "service_storage.hpp"

namespace kgr {
namespace detail {

/*
 * This class is a non virtual service being injected.
 * The service injected in this is either a single or a non-single.
 *
 * When T is a reference type, the service definition T is a single.
 */
template<typename T>
struct injected {
private:
	using Type = conditional_t<is_single<T>::value, T&, T>;

public:
	// TODO: kangaru 5: use () parens contructor by default
	template<typename... Args, enable_if_t<is_brace_constructible<Type, Args...>::value, int> = 0>
	explicit injected(Args&&... args) noexcept(noexcept(Type{std::forward<Args>(args)...})) :
		_service{std::forward<Args>(args)...} {}

	template<typename... Args, enable_if_t<
		!is_brace_constructible<Type, Args...>::value &&
		std::is_constructible<Type, Args...>::value, int> = 0>
	explicit injected(Args&&... args) noexcept(std::is_nothrow_constructible<Type, Args...>::value) :
		_service(std::forward<Args>(args)...) {}

	// TODO: kangaru 5: use () parens contructor by default
	// When using this function, Type is always a reference so no copy is done.
	template<typename... Args>

	explicit injected(service_storage& storage) noexcept :
		_service(storage.service<T>()) {}

	auto forward() noexcept(noexcept(std::declval<Type>().forward())) -> service_type<T> {
		return _service.forward();
	}

private:
	Type _service;
};

/*
 * This class is a virtual service being injected.
 * It contains a pointer to the service and it's forward function.
 */
template<typename T>
struct virtual_injected {
	explicit virtual_injected(service_storage& storage) noexcept : virtual_injected{storage.cast<T>()} {}
	explicit virtual_injected(void* service, forward_ptr<T> f) noexcept : _service{service}, _forward{f} {}
	explicit virtual_injected(const typed_service_storage<T>& storage) noexcept :
		_service{storage.service}, _forward{storage.forward} {}

	service_type<T> forward() {
		return _forward(_service);
	}

private:
	void* _service;
	forward_ptr<T> _forward;
};

/*
 * This class is a simple type trait, that receive an injected service type,
 * and extract the definition type.
 */
template<typename>
struct injected_service {};

/*
 * This is for non-virtual services.
 */
template<typename T>
struct injected_service<injected<T>&&> {
	using type = T;
};

/*
 * This is for virtual services.
 */
template<typename T>
struct injected_service<virtual_injected<T>&&> {
	using type = T;
};

/*
 * This is an alias for the typedef in injected_service
 */
template<typename T>
using injected_service_t = typename injected_service<T>::type;

/*
 * This is the contrary of injected_service.
 * We get a service definition type, and we return the wrapper type.
 * We cannot use conditional_t here, since it makes MSVC to crash when instanciating construct functions.
 */
template<typename T>
using injected_wrapper = typename std::conditional<is_polymorphic<T>::value,
	virtual_injected<T>,
	injected<T>
>::type;

template<std::size_t n, typename F>
using injected_argument_t = injected_service_t<function_argument_t<n, F>>;

template<typename... Ts>
struct inject_result_helper {
	using type = std::tuple<typename remove_rvalue_reference<Ts>::type...>;
};

template<typename, typename>
struct single_insertion_result;

template<typename T, typename... Parents>
struct single_insertion_result<T, meta_list<Parents...>> {
	using type = std::tuple<detail::typed_service_storage<T>, detail::typed_service_storage<Parents>...>;
};

template<typename T>
using single_insertion_result_t = typename single_insertion_result<T, parent_types<T>>::type;

} // namespace detail

/*
 * This is an injected argument type in construct functions.
 */
template<typename T>
using inject_t = detail::injected_wrapper<T>&&;

/*
 * The function makes a tuple of either l-value reference, or objects.
 * The is because non-single service don't live past the statement that `Definition::construct` is called.
 * But we need the non-singles to live past that, so they are moved into the tuple of injected arguments.
 *
 * Single service live as long as the container lives. They can, and should be l-value references.
 */
template<typename... Args>
constexpr auto inject(Args&&... args) -> std::tuple<detail::remove_rvalue_reference_t<Args>...> {
	return std::tuple<detail::remove_rvalue_reference_t<Args>...>{std::forward<Args>(args)...};
}

/*
 * Alias to help write a return type for construct functions.
 * Yield the return type of inject(Ts...)
 */
template<typename... Ts>
using inject_result = typename detail::inject_result_helper<Ts...>::type;

} // namespace kgr

#endif // KGR_KANGARU_INCLUDE_KANGARU_DETAIL_INJECTED_HPP
<|endoftext|>