<commit_before>// Copyright 2016 Frog Chen
//
// 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.
//=============================================================================
// ■ graphics.cpp
//-----------------------------------------------------------------------------
//   图形模式显卡驱动。
//=============================================================================

namespace Graphics {
	//-------------------------------------------------------------------------
	// ● 定义
	//-------------------------------------------------------------------------
	#include "default-font.cpp"
	const type_address vram_base = 0xa0000;

	enum indexed_color {
		#include "generated/colors-cpp.txt"
	};

	unsigned int width;
	unsigned int height;

	//-------------------------------------------------------------------------
	// ● 初始化
	//-------------------------------------------------------------------------
	void initialize() {
		width = 320;
		height = 200;
		ASM::initialize_pattle();
	}

	//-------------------------------------------------------------------------
	// ● 计算显示位置的内存地址
	//-------------------------------------------------------------------------
	inline type_address memory_address(struct pos pos) {
		return vram_base + pos.x + pos.y * width;
	}

	//-------------------------------------------------------------------------
	// ● 设定像素的颜色
	//-------------------------------------------------------------------------
	void set_pixel(struct pos pos, enum indexed_color color) {
		Memory::write8_at(memory_address(pos), color);
	}

	//-------------------------------------------------------------------------
	// ● 填充矩形
	//-------------------------------------------------------------------------
	void fill_rect(struct rect rect, enum indexed_color color) {
		int x, y;
		int end_x = rect.x + rect.width;
		int end_y = rect.y + rect.height;
		for (y = rect.y; y < end_y; y++) {
			for (x = rect.x; x < end_x; x++) {
				set_pixel((struct pos) {x, y}, color);
			}
		}
	}
	void fill_rect(int x, int y, unsigned int width, unsigned int height,
	enum indexed_color color) {
		fill_rect((struct rect) {
			.x = x,
			.y = y,
			.width = width,
			.height = height,
		}, color);
	}

	//-------------------------------------------------------------------------
	// ● 绘制字符
	//-------------------------------------------------------------------------
	void draw_char(struct pos pos, char c, enum indexed_color color) {
		int i, y;
		uint8_t line;
		type_address address;
		unsigned int index = c - 32;
		for (i = 0; i < default_font_height; i++) {
			y = pos.y + i;
			line = default_font[index][i];
			address = memory_address((struct pos) {pos.x, y});
			if (line & 1 << 0) Memory::write8_at(address + 7, color);
			if (line & 1 << 1) Memory::write8_at(address + 6, color);
			if (line & 1 << 2) Memory::write8_at(address + 5, color);
			if (line & 1 << 3) Memory::write8_at(address + 4, color);
			if (line & 1 << 4) Memory::write8_at(address + 3, color);
			if (line & 1 << 5) Memory::write8_at(address + 2, color);
			if (line & 1 << 6) Memory::write8_at(address + 1, color);
			if (line & 1 << 7) Memory::write8_at(address    , color);
		}
	}

	//-------------------------------------------------------------------------
	// ● 绘制“a”
	//-------------------------------------------------------------------------
	void draw_a(struct pos pos, enum indexed_color color) {
		draw_char(pos, 'a', color);
	}

	//-------------------------------------------------------------------------
	// ● 绘制文本
	//-------------------------------------------------------------------------
	void draw_text(struct pos pos, const char* str, enum indexed_color color) {
		int x = pos.x, y = pos.y;
		while (*str != '\0') {
			draw_char((struct pos) {x, y}, *str, color);
			x += default_font_width;
			str++;
		}
	}

	//-------------------------------------------------------------------------
	// ● 绘制数值
	//-------------------------------------------------------------------------
	void draw_text(struct pos pos, long value, enum indexed_color color) {
		char buf[12];
		FMString::long2charbuf(buf, value);
		draw_text(pos, buf, color);
	}

	//-------------------------------------------------------------------------
	// ● 绘制鼠标指针
	//-------------------------------------------------------------------------
	void draw_cursor(struct pos pos) {
		char buf[15];
		set_pixel(pos, WEB_C99);
		fill_rect((struct rect) {
			.x = 0,
			.y = 12,
			.width = Graphics::width,
			.height = Graphics::default_font_height,
		}, BLACK);
		FMString::long2charbuf(buf, pos.x);
		draw_text((struct pos) {0, 12}, buf, WHITE);
		FMString::long2charbuf(buf, pos.y);
		draw_text((struct pos) {100, 12}, buf, WHITE);
	}
}
<commit_msg>创建了最丑的鼠标指针<commit_after>// Copyright 2016 Frog Chen
//
// 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.
//=============================================================================
// ■ graphics.cpp
//-----------------------------------------------------------------------------
//   图形模式显卡驱动。
//=============================================================================

namespace Graphics {
	//-------------------------------------------------------------------------
	// ● 定义
	//-------------------------------------------------------------------------
	#include "default-font.cpp"
	const type_address vram_base = 0xa0000;

	enum indexed_color {
		#include "generated/colors-cpp.txt"
	};

	unsigned int width;
	unsigned int height;
	enum indexed_color cursor_color;

	//-------------------------------------------------------------------------
	// ● 初始化
	//-------------------------------------------------------------------------
	void initialize() {
		width = 320;
		height = 200;
		ASM::initialize_pattle();
		cursor_color = WEB_CCC;
	}

	//-------------------------------------------------------------------------
	// ● 计算显示位置的内存地址
	//-------------------------------------------------------------------------
	inline type_address memory_address(struct pos pos) {
		return vram_base + pos.x + pos.y * width;
	}

	//-------------------------------------------------------------------------
	// ● 设定像素的颜色
	//-------------------------------------------------------------------------
	void set_pixel(struct pos pos, enum indexed_color color) {
		Memory::write8_at(memory_address(pos), color);
	}

	//-------------------------------------------------------------------------
	// ● 填充矩形
	//-------------------------------------------------------------------------
	void fill_rect(struct rect rect, enum indexed_color color) {
		int x, y;
		int end_x = rect.x + rect.width;
		int end_y = rect.y + rect.height;
		for (y = rect.y; y < end_y; y++) {
			for (x = rect.x; x < end_x; x++) {
				set_pixel((struct pos) {x, y}, color);
			}
		}
	}
	void fill_rect(int x, int y, unsigned int width, unsigned int height,
	enum indexed_color color) {
		fill_rect((struct rect) {
			.x = x,
			.y = y,
			.width = width,
			.height = height,
		}, color);
	}

	//-------------------------------------------------------------------------
	// ● 绘制字符
	//-------------------------------------------------------------------------
	void draw_char(struct pos pos, char c, enum indexed_color color) {
		int i, y;
		uint8_t line;
		type_address address;
		unsigned int index = c - 32;
		for (i = 0; i < default_font_height; i++) {
			y = pos.y + i;
			line = default_font[index][i];
			address = memory_address((struct pos) {pos.x, y});
			if (line & 1 << 0) Memory::write8_at(address + 7, color);
			if (line & 1 << 1) Memory::write8_at(address + 6, color);
			if (line & 1 << 2) Memory::write8_at(address + 5, color);
			if (line & 1 << 3) Memory::write8_at(address + 4, color);
			if (line & 1 << 4) Memory::write8_at(address + 3, color);
			if (line & 1 << 5) Memory::write8_at(address + 2, color);
			if (line & 1 << 6) Memory::write8_at(address + 1, color);
			if (line & 1 << 7) Memory::write8_at(address    , color);
		}
	}

	//-------------------------------------------------------------------------
	// ● 绘制“a”
	//-------------------------------------------------------------------------
	void draw_a(struct pos pos, enum indexed_color color) {
		draw_char(pos, 'a', color);
	}

	//-------------------------------------------------------------------------
	// ● 绘制文本
	//-------------------------------------------------------------------------
	void draw_text(struct pos pos, const char* str, enum indexed_color color) {
		int x = pos.x, y = pos.y;
		while (*str != '\0') {
			draw_char((struct pos) {x, y}, *str, color);
			x += default_font_width;
			str++;
		}
	}

	//-------------------------------------------------------------------------
	// ● 绘制数值
	//-------------------------------------------------------------------------
	void draw_text(struct pos pos, long value, enum indexed_color color) {
		char buf[12];
		FMString::long2charbuf(buf, value);
		draw_text(pos, buf, color);
	}

	//-------------------------------------------------------------------------
	// ● 绘制鼠标指针
	//-------------------------------------------------------------------------
	void draw_cursor(struct pos pos) {
		fill_rect((struct rect) {pos.x - 3, pos.y, 7, 1}, cursor_color);
		fill_rect((struct rect) {pos.x, pos.y - 3, 1, 7}, cursor_color);
	}
}
<|endoftext|>


<commit_before>#include <wx/wx.h>
#include <wx/stc/stc.h>
#include <wx/aui/aui.h>
#include <wx/filename.h>
#include <wx/msgdlg.h>

#include <vector>
#include <cassert>

#include "ride/mainwindow.h"
#include "ride/fileedit.h"

enum
{
  m_LineNrID = 0,
  m_DividerID = 1,
  m_FoldingID = 2,
  m_FoldingMargin = 16
};

const int ANNOTATION_STYLE = wxSTC_STYLE_LASTPREDEFINED + 1;

int C(ride::EdgeStyle e) {
  switch (e) {
  case ride::EDGESTYLE_BACKGROUND:
    return wxSTC_EDGE_BACKGROUND;
  case ride::EDGESTYLE_LINE:
    return wxSTC_EDGE_LINE;
  case ride::EDGESTYLE_NONE:
    return wxSTC_EDGE_NONE;
  default:
    assert(false && "Invalid edge style");
    return wxSTC_EDGE_NONE;
  }
}

int C(ride::ViewWhitespace e) {
  switch (e) {
  case ride::VIEWWHITESPACE_ALWAYS:
    return wxSTC_WS_VISIBLEALWAYS;
  case ride::VIEWWHITESPACE_AFTER_IDENT:
    return wxSTC_WS_VISIBLEAFTERINDENT;
  case ride::VIEWWHITESPACE_HIDDEN:
    return wxSTC_WS_INVISIBLE;
  default:
    assert(false && "Invalid whitespace style");
    return wxSTC_WS_INVISIBLE;
  }
}

int C(ride::WrapMode e) {
  switch (e) {
  case ride::WRAPMODE_CHAR:
    return wxSTC_WRAP_CHAR;
  case ride::WRAPMODE_WORD:
    return wxSTC_WRAP_WORD;
  case ride::WRAPMODE_NONE:
    return wxSTC_WRAP_NONE;
  default:
    assert(false && "Invalid wrap mode");
    return wxSTC_WRAP_NONE;
  }
}

int C(ride::FoldFlags f) {
  int ret = 0;

  if (f.linebefore_expanded()) {
    ret |= wxSTC_FOLDFLAG_LINEBEFORE_EXPANDED;
  }
  if (f.linebefore_contracted()) {
    ret |= wxSTC_FOLDFLAG_LINEBEFORE_CONTRACTED;
  }
  if (f.lineafter_expanded()) {
    ret |= wxSTC_FOLDFLAG_LINEAFTER_EXPANDED;
  }
  if (f.lineafter_contracted()) {
    ret |= wxSTC_FOLDFLAG_LINEAFTER_CONTRACTED;
  }
  if (f.levelnumbers()) {
    ret |= wxSTC_FOLDFLAG_LEVELNUMBERS;
  }

  return ret;
}

wxColor C(const ride::Color& c) {
  return wxColor(c.r(), c.g(), c.b());
}

FileEdit::FileEdit(wxAuiNotebook* anotebook, MainWindow* parent, const wxString& source, const wxString& file) : wxControl(parent, wxID_ANY), main(parent), notebook(anotebook), dirty(false), currentLanguage(NULL) {
  text = new wxStyledTextCtrl(this,  wxID_ANY, wxDefaultPosition, wxDefaultSize,
#ifndef __WXMAC__
    wxSUNKEN_BORDER |
#endif
    wxVSCROLL);

  filename = file;

  if (filename.IsEmpty()) {
    text->SetText(source);
  }
  else {
    text->LoadFile(filename);
  }
  dirty = false;

  m_LineNrMargin = text->TextWidth(wxSTC_STYLE_LINENUMBER, wxT("_999999"));

  wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
  sizer->Add(text, 1, wxEXPAND);
  SetSizer(sizer);

  notebook->AddPage(this, wxT(""), true);
  updateFilename();
  updateTitle();
}

bool FileEdit::save() {
  if (shouldBeSaved() == false) return true;
  if (filename.IsEmpty()) return saveAs();
  else return saveTo(filename);
}

bool FileEdit::saveAs() {
  wxFileDialog saveFileDialog(this, _("Save file"), "", "",
    FILE_PATTERN, wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
  if (saveFileDialog.ShowModal() == wxID_CANCEL)
    return false;
  return saveTo(saveFileDialog.GetPath());
}

bool FileEdit::saveTo(const wxString& target) {
  if (false == text->SaveFile(target)) {
    return false;
  }
  filename = target;
  dirty = false;
  updateFilename();
  updateTitle();
  return true;
}

unsigned int UntitledCount = 0;

void SetStyle(wxStyledTextCtrl* text, int id, const ride::Style& style) {
  if (C(style.foreground()) != wxNullColour) {
    // todo: check this
    text->StyleSetForeground(id, C(style.foreground()));
  }
  if (C(style.background()) != wxNullColour) {
    // todo: check this
    text->StyleSetBackground(id, C(style.background()));
  }
  /*
  // todo...
  wxFont temp = style.font;
  text->StyleSetFont(id, temp);*/
}

wxString b2s01(bool b) {
  if (b) return _("1");
  else return _("0");
}

void FileEdit::UpdateTextControl() {
  // initialize styles
  text->StyleClearAll();
  wxFont font(wxFontInfo(10).Family(wxFONTFAMILY_TELETYPE));
  const wxColor grey(100, 100, 100);
  const wxColor white(255, 255, 255);
  const wxColor darkgray = wxColour(20, 20, 20);

  const ride::Settings& set = main->getSettings();

  // setup language color
  assert(currentLanguage);
  currentLanguage->style(text, set);

  // setup style colors and font
  SetStyle(text, wxSTC_STYLE_DEFAULT,  set.default_style());
  SetStyle(text, wxSTC_STYLE_BRACELIGHT, set.bracelight_style());
  SetStyle(text, wxSTC_STYLE_BRACEBAD, set.bracebad_style());
  SetStyle(text, wxSTC_STYLE_CONTROLCHAR, set.controlchar_style());
  SetStyle(text, wxSTC_STYLE_INDENTGUIDE, set.indentguide_style());
  SetStyle(text, wxSTC_STYLE_CALLTIP, set.calltip_style());

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

  // set margin for line numbers
  text->SetMarginType(m_LineNrID, wxSTC_MARGIN_NUMBER);
  text->SetMarginWidth(m_LineNrID, set.linenumberenable() ? m_LineNrMargin : 0);

  // set margin as unused
  text->SetMarginType(m_DividerID, wxSTC_MARGIN_SYMBOL);
  text->SetMarginWidth(m_DividerID, 15);
  text->SetMarginSensitive(m_DividerID, false);

  // folding settings
  // todo: move to settings
  text->SetMarginType(m_FoldingID, wxSTC_MARGIN_SYMBOL);
  text->SetMarginMask(m_FoldingID, wxSTC_MASK_FOLDERS);
  // text->StyleSetBackground(m_FoldingID, wxColor(200, 200, 200));
  text->SetMarginWidth(m_FoldingID, 15);
  text->SetMarginSensitive(m_FoldingID, true);
  text->SetFoldMarginColour(true, wxColor(200, 200, 200));
  text->SetFoldMarginHiColour(true, wxColor(200, 200, 200));
  text->SetMarginWidth(m_FoldingID, set.foldenable() ? m_FoldingMargin : 0);
  text->SetMarginSensitive(m_FoldingID, set.foldenable());
  text->SetFoldFlags(C(set.foldflags()));
  // todo: expose theese
  text->MarkerDefine(wxSTC_MARKNUM_FOLDER, wxSTC_MARK_ARROW, grey, grey);
  text->MarkerDefine(wxSTC_MARKNUM_FOLDEROPEN, wxSTC_MARK_ARROWDOWN, grey, grey);
  text->MarkerDefine(wxSTC_MARKNUM_FOLDERSUB, wxSTC_MARK_EMPTY, grey, grey);
  text->MarkerDefine(wxSTC_MARKNUM_FOLDEREND, wxSTC_MARK_ARROW, grey, white);
  text->MarkerDefine(wxSTC_MARKNUM_FOLDEROPENMID, wxSTC_MARK_ARROWDOWN, grey, white);
  text->MarkerDefine(wxSTC_MARKNUM_FOLDERMIDTAIL, wxSTC_MARK_EMPTY, grey, grey);
  text->MarkerDefine(wxSTC_MARKNUM_FOLDERTAIL, wxSTC_MARK_EMPTY, grey, grey);

  // set spaces and indention
  text->SetTabWidth(set.tabwidth());
  text->SetUseTabs(set.usetabs());
  text->SetTabIndents(set.tabindents());
  text->SetBackSpaceUnIndents(set.backspaceunindents());
  text->SetIndent(set.tabwidth());

  text->SetFont(font);

  text->SetViewEOL(set.displayeolenable());
  text->SetIndentationGuides(set.indentguideenable());
  text->SetEdgeMode(C(set.edgestyle()));
  text->SetEdgeColour(C(set.edgecolor()));
  text->SetEdgeColumn(set.edgecolumn());
  text->SetViewWhiteSpace(C(set.whitespace()));
  text->SetOvertype(false);
  text->SetReadOnly(false);
  text->SetWrapMode(C(set.wordwrap()));

  // set visibility
  // todo: investigate this
  text->SetVisiblePolicy(wxSTC_VISIBLE_STRICT | wxSTC_VISIBLE_SLOP, 1);
  text->SetXCaretPolicy(wxSTC_CARET_EVEN | wxSTC_VISIBLE_STRICT | wxSTC_CARET_SLOP, 1);
  text->SetYCaretPolicy(wxSTC_CARET_EVEN | wxSTC_VISIBLE_STRICT | wxSTC_CARET_SLOP, 1);

  // todo: expose this
  text->SetCaretLineVisible(true);
}

void FileEdit::updateFilename() {
  if (filename.IsEmpty()) {
    docname = wxString::Format("Untitled %d", ++UntitledCount);
  }
  else {
    wxFileName fn(filename);
    docname = fn.GetFullName();
  }

  if (filename.IsEmpty() == false) {
    size_t index = notebook->GetPageIndex(this);
    notebook->SetPageToolTip(index, filename);

    wxFileName fname(filename);
    currentLanguage = DetermineLanguage(fname.GetFullName());
    UpdateTextControl();
  }
}

void FileEdit::updateTitle() {
  size_t index = notebook->GetPageIndex(this);
  const wxString changestar = dirty ? "*" : "";
  notebook->SetPageText(index, docname + changestar);
}

bool FileEdit::shouldBeSaved() {
  return dirty || filename.IsEmpty();
}

bool FileEdit::canClose(bool canAbort) {
  if (shouldBeSaved()) {
    const int yesNoFlags = canAbort ? (wxYES_NO | wxCANCEL) : wxYES_NO;
    wxMessageDialog dlg(this, _(""), _("Save file?"), yesNoFlags | wxICON_QUESTION);

    const wxMessageDialogBase::ButtonLabel yesButton = _("&Save it");
    const wxMessageDialogBase::ButtonLabel noButton = _("&Discard changes");
    const wxMessageDialogBase::ButtonLabel cancelButton = _("&Abort");

    const bool labelChangeOk = canAbort
      ? dlg.SetYesNoCancelLabels(yesButton, noButton, cancelButton)
      : dlg.SetYesNoLabels(yesButton, noButton)
      ;

    if (labelChangeOk) {
      dlg.SetMessage("\"" + docname + "\" has changed since last time...");
    }
    else {
      dlg.SetMessage("\"" + docname + "\" has changed since last time, save it?");
    }

    const int answer = dlg.ShowModal();
    if (answer == wxID_YES) {
      return save();
    }
    else if (answer == wxID_NO) {
      return true;
    }
    else {
      return false;
    }
  }
  return true;
}

FileEdit::~FileEdit() {
  text->SetClientData(NULL);
}

wxBEGIN_EVENT_TABLE(FileEdit, wxControl)
  EVT_STC_MARGINCLICK(wxID_ANY, OnMarginClick)
  EVT_STC_CHARADDED(wxID_ANY, OnTextChanged)
wxEND_EVENT_TABLE()

void FileEdit::OnMarginClick(wxStyledTextEvent& event)
{
  if (event.GetMargin() == m_FoldingID)
  {
    int lineClick = text->LineFromPosition(event.GetPosition());
    int levelClick = text->GetFoldLevel(lineClick);

    if ((levelClick & wxSTC_FOLDLEVELHEADERFLAG) > 0)
    {
      text->ToggleFold(lineClick);
    }
  }
}

void FileEdit::OnTextChanged(wxStyledTextEvent& event)
{
  if (dirty == false) {
    dirty = true;
    updateTitle();
  }
}
<commit_msg>leave at default is color is undefined<commit_after>#include <wx/wx.h>
#include <wx/stc/stc.h>
#include <wx/aui/aui.h>
#include <wx/filename.h>
#include <wx/msgdlg.h>

#include <vector>
#include <cassert>

#include "ride/mainwindow.h"
#include "ride/fileedit.h"

enum
{
  m_LineNrID = 0,
  m_DividerID = 1,
  m_FoldingID = 2,
  m_FoldingMargin = 16
};

const int ANNOTATION_STYLE = wxSTC_STYLE_LASTPREDEFINED + 1;

int C(ride::EdgeStyle e) {
  switch (e) {
  case ride::EDGESTYLE_BACKGROUND:
    return wxSTC_EDGE_BACKGROUND;
  case ride::EDGESTYLE_LINE:
    return wxSTC_EDGE_LINE;
  case ride::EDGESTYLE_NONE:
    return wxSTC_EDGE_NONE;
  default:
    assert(false && "Invalid edge style");
    return wxSTC_EDGE_NONE;
  }
}

int C(ride::ViewWhitespace e) {
  switch (e) {
  case ride::VIEWWHITESPACE_ALWAYS:
    return wxSTC_WS_VISIBLEALWAYS;
  case ride::VIEWWHITESPACE_AFTER_IDENT:
    return wxSTC_WS_VISIBLEAFTERINDENT;
  case ride::VIEWWHITESPACE_HIDDEN:
    return wxSTC_WS_INVISIBLE;
  default:
    assert(false && "Invalid whitespace style");
    return wxSTC_WS_INVISIBLE;
  }
}

int C(ride::WrapMode e) {
  switch (e) {
  case ride::WRAPMODE_CHAR:
    return wxSTC_WRAP_CHAR;
  case ride::WRAPMODE_WORD:
    return wxSTC_WRAP_WORD;
  case ride::WRAPMODE_NONE:
    return wxSTC_WRAP_NONE;
  default:
    assert(false && "Invalid wrap mode");
    return wxSTC_WRAP_NONE;
  }
}

int C(ride::FoldFlags f) {
  int ret = 0;

  if (f.linebefore_expanded()) {
    ret |= wxSTC_FOLDFLAG_LINEBEFORE_EXPANDED;
  }
  if (f.linebefore_contracted()) {
    ret |= wxSTC_FOLDFLAG_LINEBEFORE_CONTRACTED;
  }
  if (f.lineafter_expanded()) {
    ret |= wxSTC_FOLDFLAG_LINEAFTER_EXPANDED;
  }
  if (f.lineafter_contracted()) {
    ret |= wxSTC_FOLDFLAG_LINEAFTER_CONTRACTED;
  }
  if (f.levelnumbers()) {
    ret |= wxSTC_FOLDFLAG_LEVELNUMBERS;
  }

  return ret;
}

wxColor C(const ride::Color& c) {
  return wxColor(c.r(), c.g(), c.b());
}

FileEdit::FileEdit(wxAuiNotebook* anotebook, MainWindow* parent, const wxString& source, const wxString& file) : wxControl(parent, wxID_ANY), main(parent), notebook(anotebook), dirty(false), currentLanguage(NULL) {
  text = new wxStyledTextCtrl(this,  wxID_ANY, wxDefaultPosition, wxDefaultSize,
#ifndef __WXMAC__
    wxSUNKEN_BORDER |
#endif
    wxVSCROLL);

  filename = file;

  if (filename.IsEmpty()) {
    text->SetText(source);
  }
  else {
    text->LoadFile(filename);
  }
  dirty = false;

  m_LineNrMargin = text->TextWidth(wxSTC_STYLE_LINENUMBER, wxT("_999999"));

  wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
  sizer->Add(text, 1, wxEXPAND);
  SetSizer(sizer);

  notebook->AddPage(this, wxT(""), true);
  updateFilename();
  updateTitle();
}

bool FileEdit::save() {
  if (shouldBeSaved() == false) return true;
  if (filename.IsEmpty()) return saveAs();
  else return saveTo(filename);
}

bool FileEdit::saveAs() {
  wxFileDialog saveFileDialog(this, _("Save file"), "", "",
    FILE_PATTERN, wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
  if (saveFileDialog.ShowModal() == wxID_CANCEL)
    return false;
  return saveTo(saveFileDialog.GetPath());
}

bool FileEdit::saveTo(const wxString& target) {
  if (false == text->SaveFile(target)) {
    return false;
  }
  filename = target;
  dirty = false;
  updateFilename();
  updateTitle();
  return true;
}

unsigned int UntitledCount = 0;

void SetStyle(wxStyledTextCtrl* text, int id, const ride::Style& style) {
  if (style.has_foreground()) {
    // todo: check this
    text->StyleSetForeground(id, C(style.foreground()));
  }
  if (style.has_background()) {
    // todo: check this
    text->StyleSetBackground(id, C(style.background()));
  }
  /*
  // todo...
  wxFont temp = style.font;
  text->StyleSetFont(id, temp);*/
}

wxString b2s01(bool b) {
  if (b) return _("1");
  else return _("0");
}

void FileEdit::UpdateTextControl() {
  // initialize styles
  text->StyleClearAll();
  wxFont font(wxFontInfo(10).Family(wxFONTFAMILY_TELETYPE));
  const wxColor grey(100, 100, 100);
  const wxColor white(255, 255, 255);
  const wxColor darkgray = wxColour(20, 20, 20);

  const ride::Settings& set = main->getSettings();

  // setup language color
  assert(currentLanguage);
  currentLanguage->style(text, set);

  // setup style colors and font
  SetStyle(text, wxSTC_STYLE_DEFAULT,  set.default_style());
  SetStyle(text, wxSTC_STYLE_BRACELIGHT, set.bracelight_style());
  SetStyle(text, wxSTC_STYLE_BRACEBAD, set.bracebad_style());
  SetStyle(text, wxSTC_STYLE_CONTROLCHAR, set.controlchar_style());
  SetStyle(text, wxSTC_STYLE_INDENTGUIDE, set.indentguide_style());
  SetStyle(text, wxSTC_STYLE_CALLTIP, set.calltip_style());

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

  // set margin for line numbers
  text->SetMarginType(m_LineNrID, wxSTC_MARGIN_NUMBER);
  text->SetMarginWidth(m_LineNrID, set.linenumberenable() ? m_LineNrMargin : 0);

  // set margin as unused
  text->SetMarginType(m_DividerID, wxSTC_MARGIN_SYMBOL);
  text->SetMarginWidth(m_DividerID, 15);
  text->SetMarginSensitive(m_DividerID, false);

  // folding settings
  // todo: move to settings
  text->SetMarginType(m_FoldingID, wxSTC_MARGIN_SYMBOL);
  text->SetMarginMask(m_FoldingID, wxSTC_MASK_FOLDERS);
  // text->StyleSetBackground(m_FoldingID, wxColor(200, 200, 200));
  text->SetMarginWidth(m_FoldingID, 15);
  text->SetMarginSensitive(m_FoldingID, true);
  text->SetFoldMarginColour(true, wxColor(200, 200, 200));
  text->SetFoldMarginHiColour(true, wxColor(200, 200, 200));
  text->SetMarginWidth(m_FoldingID, set.foldenable() ? m_FoldingMargin : 0);
  text->SetMarginSensitive(m_FoldingID, set.foldenable());
  text->SetFoldFlags(C(set.foldflags()));
  // todo: expose theese
  text->MarkerDefine(wxSTC_MARKNUM_FOLDER, wxSTC_MARK_ARROW, grey, grey);
  text->MarkerDefine(wxSTC_MARKNUM_FOLDEROPEN, wxSTC_MARK_ARROWDOWN, grey, grey);
  text->MarkerDefine(wxSTC_MARKNUM_FOLDERSUB, wxSTC_MARK_EMPTY, grey, grey);
  text->MarkerDefine(wxSTC_MARKNUM_FOLDEREND, wxSTC_MARK_ARROW, grey, white);
  text->MarkerDefine(wxSTC_MARKNUM_FOLDEROPENMID, wxSTC_MARK_ARROWDOWN, grey, white);
  text->MarkerDefine(wxSTC_MARKNUM_FOLDERMIDTAIL, wxSTC_MARK_EMPTY, grey, grey);
  text->MarkerDefine(wxSTC_MARKNUM_FOLDERTAIL, wxSTC_MARK_EMPTY, grey, grey);

  // set spaces and indention
  text->SetTabWidth(set.tabwidth());
  text->SetUseTabs(set.usetabs());
  text->SetTabIndents(set.tabindents());
  text->SetBackSpaceUnIndents(set.backspaceunindents());
  text->SetIndent(set.tabwidth());

  text->SetFont(font);

  text->SetViewEOL(set.displayeolenable());
  text->SetIndentationGuides(set.indentguideenable());
  text->SetEdgeMode(C(set.edgestyle()));
  text->SetEdgeColour(C(set.edgecolor()));
  text->SetEdgeColumn(set.edgecolumn());
  text->SetViewWhiteSpace(C(set.whitespace()));
  text->SetOvertype(false);
  text->SetReadOnly(false);
  text->SetWrapMode(C(set.wordwrap()));

  // set visibility
  // todo: investigate this
  text->SetVisiblePolicy(wxSTC_VISIBLE_STRICT | wxSTC_VISIBLE_SLOP, 1);
  text->SetXCaretPolicy(wxSTC_CARET_EVEN | wxSTC_VISIBLE_STRICT | wxSTC_CARET_SLOP, 1);
  text->SetYCaretPolicy(wxSTC_CARET_EVEN | wxSTC_VISIBLE_STRICT | wxSTC_CARET_SLOP, 1);

  // todo: expose this
  text->SetCaretLineVisible(true);
}

void FileEdit::updateFilename() {
  if (filename.IsEmpty()) {
    docname = wxString::Format("Untitled %d", ++UntitledCount);
  }
  else {
    wxFileName fn(filename);
    docname = fn.GetFullName();
  }

  if (filename.IsEmpty() == false) {
    size_t index = notebook->GetPageIndex(this);
    notebook->SetPageToolTip(index, filename);

    wxFileName fname(filename);
    currentLanguage = DetermineLanguage(fname.GetFullName());
    UpdateTextControl();
  }
}

void FileEdit::updateTitle() {
  size_t index = notebook->GetPageIndex(this);
  const wxString changestar = dirty ? "*" : "";
  notebook->SetPageText(index, docname + changestar);
}

bool FileEdit::shouldBeSaved() {
  return dirty || filename.IsEmpty();
}

bool FileEdit::canClose(bool canAbort) {
  if (shouldBeSaved()) {
    const int yesNoFlags = canAbort ? (wxYES_NO | wxCANCEL) : wxYES_NO;
    wxMessageDialog dlg(this, _(""), _("Save file?"), yesNoFlags | wxICON_QUESTION);

    const wxMessageDialogBase::ButtonLabel yesButton = _("&Save it");
    const wxMessageDialogBase::ButtonLabel noButton = _("&Discard changes");
    const wxMessageDialogBase::ButtonLabel cancelButton = _("&Abort");

    const bool labelChangeOk = canAbort
      ? dlg.SetYesNoCancelLabels(yesButton, noButton, cancelButton)
      : dlg.SetYesNoLabels(yesButton, noButton)
      ;

    if (labelChangeOk) {
      dlg.SetMessage("\"" + docname + "\" has changed since last time...");
    }
    else {
      dlg.SetMessage("\"" + docname + "\" has changed since last time, save it?");
    }

    const int answer = dlg.ShowModal();
    if (answer == wxID_YES) {
      return save();
    }
    else if (answer == wxID_NO) {
      return true;
    }
    else {
      return false;
    }
  }
  return true;
}

FileEdit::~FileEdit() {
  text->SetClientData(NULL);
}

wxBEGIN_EVENT_TABLE(FileEdit, wxControl)
  EVT_STC_MARGINCLICK(wxID_ANY, OnMarginClick)
  EVT_STC_CHARADDED(wxID_ANY, OnTextChanged)
wxEND_EVENT_TABLE()

void FileEdit::OnMarginClick(wxStyledTextEvent& event)
{
  if (event.GetMargin() == m_FoldingID)
  {
    int lineClick = text->LineFromPosition(event.GetPosition());
    int levelClick = text->GetFoldLevel(lineClick);

    if ((levelClick & wxSTC_FOLDLEVELHEADERFLAG) > 0)
    {
      text->ToggleFold(lineClick);
    }
  }
}

void FileEdit::OnTextChanged(wxStyledTextEvent& event)
{
  if (dirty == false) {
    dirty = true;
    updateTitle();
  }
}
<|endoftext|>


<commit_before>// Aho Corasick - <O(sum(m)), O(n + #matches)>
// Multiple string matching

int p[N], f[N], nxt[N][26], ch[N];
int tsz=1; // size of the trie

int cnt[N]; // used to know number of matches

// used to know which strings matches.
// S is the number of strings. Can use set instead
const int S = 2e3+5;
bitset<S> elem[N];

void init() {
  tsz=1;
  memset(f, 0, sizeof(f));
  memset(nxt, 0, sizeof(nxt));
  memset(cnt, 0, sizeof(cnt));
  for (int i = 0; i < N; i++) elem[i].reset();
}

void add(const string &s, int x) {
  int cur = 1; // the first element of the trie is the root

  for (int i=0; s[i]; ++i) {
    int j = s[i] - 'a';
    if (!nxt[cur][j]) {
      tsz++;
      p[tsz] = cur;
      ch[tsz] = j;
      nxt[cur][j] = tsz;
    }
    cur = nxt[cur][j];
  }

  cnt[cur]++; //
  elem[cur].set(x);
}

void build() {
  queue<int> q;

  for(int i=0; i<26; ++i) {
    nxt[0][i] = 1;
    if (nxt[1][i]) q.push(nxt[1][i]);
  }

  while (!q.empty()) {
    int v = q.front(); q.pop();
    int u = f[p[v]];

    while (u and !nxt[u][ch[v]]) u = f[u];
    f[v] = nxt[u][ch[v]];
    cnt[v] += cnt[f[v]];
    elem[v] |= elem[f[v]];

    for (int i = 0; i < 26; ++i) {
      if (nxt[v][i]) q.push(nxt[v][i]);
      else {
        int ax = f[v];
        while(ax and !nxt[ax][i]) ax = f[ax];
        nxt[v][i] = nxt[ax][i];
      }
    }
  }
}

// Return ans to get number of matches
// Return a map (or global array) if want to know how many of each string have matched
bitset<S> match(char *s) {
  int ans = 0;    // used to know the number of matches
  bitset<S> found; // used to know which strings matches

  int x = 1;
  for (int i = 0; s[i]; ++i) {
    int t = s[i] - 'a';
    while (x and !nxt[x][t]) x = f[x];
    x = nxt[x][t];

    // match found
    ans += cnt[x];
    found |= elem[x];
  }

  return found;
}

<commit_msg>Update aho.cpp<commit_after>// Aho Corasick - <O(sum(m)), O(n + #matches)>
// Multiple string matching

int p[N], f[N], nxt[N][26], ch[N];
int tsz=1; // size of the trie

int cnt[N]; // used to know number of matches

// used to know which strings matches.
// S is the number of strings. Can use set instead
const int S = 2e3+5;
bitset<S> elem[N];

void init() {
  tsz=1;
  memset(f, 0, sizeof(f));
  memset(nxt, 0, sizeof(nxt));
  memset(cnt, 0, sizeof(cnt));
  for (int i = 0; i < N; i++) elem[i].reset();
}

void add(const string &s, int x) {
  int cur = 1; // the first element of the trie is the root

  for (int i=0; s[i]; ++i) {
    int j = s[i] - 'a';
    if (!nxt[cur][j]) {
      tsz++;
      p[tsz] = cur;
      ch[tsz] = j;
      nxt[cur][j] = tsz;
    }
    cur = nxt[cur][j];
  }

  cnt[cur]++; //
  elem[cur].set(x);
}

void build() {
  queue<int> q;

  for(int i=0; i<26; ++i) {
    nxt[0][i] = 1;
    if (nxt[1][i]) q.push(nxt[1][i]);
  }

  while (!q.empty()) {
    int v = q.front(); q.pop();
    int u = f[p[v]];

    while (u and !nxt[u][ch[v]]) u = f[u];
    f[v] = nxt[u][ch[v]];
    cnt[v] += cnt[f[v]];
    elem[v] |= elem[f[v]];

    for (int i = 0; i < 26; ++i) {
      if (nxt[v][i]) q.push(nxt[v][i]);
      /* Pre-Computation of next states
      else {
        int ax = f[v];
        while(ax and !nxt[ax][i]) ax = f[ax];
        nxt[v][i] = nxt[ax][i];
      }
      */
    }
  }
}

// Return ans to get number of matches
// Return a map (or global array) if want to know how many of each string have matched
bitset<S> match(char *s) {
  int ans = 0;    // used to know the number of matches
  bitset<S> found; // used to know which strings matches

  int x = 1;
  for (int i = 0; s[i]; ++i) {
    int t = s[i] - 'a';
    while (x and !nxt[x][t]) x = f[x];
    x = nxt[x][t];

    // match found
    ans += cnt[x];
    found |= elem[x];
  }

  return found;
}

<|endoftext|>


<commit_before>/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 *
 *  Gearmand client and server library.
 *
 *  Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
 *  Copyright (C) 2008 Brian Aker, Eric Day
 *  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.
 *
 *      * The names of its contributors may not be used to endorse or
 *  promote products derived from this software without specific prior
 *  written permission.
 *
 *  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
 *  OWNER 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.
 *
 */

/**
 * @file
 * @brief libmemcached Queue Storage Definitions
 */

#include "gear_config.h"

#include <libgearman-server/common.h>

#include <libgearman-server/plugins/queue/base.h>
#include <libgearman-server/plugins/queue/libmemcached/queue.h>
#include <libmemcached/memcached.h>

#include "libgearman-server/log.h"

#include <cerrno>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wold-style-cast"

using namespace gearmand;

/**
 * @addtogroup gearmand::plugins::queue::Libmemcachedatic Static libmemcached Queue Storage Functions
 * @ingroup gearman_queue_libmemcached
 * @{
 */

/**
 * Default values.
 */
static constexpr const char GEARMAND_QUEUE_LIBMEMCACHED_DEFAULT_PREFIX[] = "gear_";

namespace gearmand { namespace plugins { namespace queue { class Libmemcached;  }}}

namespace gearmand {
namespace queue {

class LibmemcachedQueue : public gearmand::queue::Context
{
public:
  LibmemcachedQueue(memcached_server_st* servers):
    memc_(nullptr)
  {
    memc_= memcached_create(nullptr);

    memcached_server_push(memc_, servers);
  }

  bool init()
  {
    return bool(bool(memc_) and memcached_server_count(memc_));
  }

  ~LibmemcachedQueue()
  {
    memcached_free(memc_);
    memc_= nullptr;
  }

  gearmand_error_t add(gearman_server_st *server,
                       const char *unique, size_t unique_size,
                       const char *function_name, size_t function_name_size,
                       const void *data, size_t data_size,
                       gearman_job_priority_t priority,
                       int64_t when);

  gearmand_error_t flush(gearman_server_st *server);

  gearmand_error_t done(gearman_server_st *server,
                        const char *unique, size_t unique_size,
                        const char *function_name, size_t function_name_size);

  gearmand_error_t replay(gearman_server_st *server);

private:
  memcached_st* memc_;
};

} // namespace queue
} // namespace gearmand

namespace gearmand {
namespace plugins {
namespace queue {

class Libmemcached : public gearmand::plugins::Queue {
public:
  Libmemcached ();
  ~Libmemcached ();

  gearmand_error_t initialize();

  std::string server_list;
private:

};

Libmemcached::Libmemcached() :
  Queue("libmemcached")
{
  command_line_options().add_options()
    ("libmemcached-servers", boost::program_options::value(&server_list), "List of Memcached servers to use.");
}

Libmemcached::~Libmemcached()
{
}

gearmand_error_t Libmemcached::initialize()
{
  gearmand_info("Initializing libmemcached module");

  memcached_server_st *servers= memcached_servers_parse(server_list.c_str());
  if (!servers)
  {
    return gearmand_gerror("memcached_servers_parse", GEARMAND_QUEUE_ERROR);
  }

  gearmand::queue::LibmemcachedQueue* exec_queue= new gearmand::queue::LibmemcachedQueue(servers);
  if (exec_queue and exec_queue->init())
  {
    gearman_server_set_queue(Gearmand()->server, exec_queue);

    memcached_server_list_free(servers);

    return GEARMAND_SUCCESS;
  }

  return gearmand_gerror("Libmemcached::initialize()", GEARMAND_QUEUE_ERROR);
}

void initialize_libmemcached()
{
  static Libmemcached local_instance;
}

} // namespace queue
} // namespace plugins
} // namespace gearmand

/* Queue callback functions. */

namespace gearmand {
namespace queue {

gearmand_error_t LibmemcachedQueue::add(gearman_server_st *server,
                                        const char *unique,
                                        size_t unique_size,
                                        const char *function_name,
                                        size_t function_name_size,
                                        const void *data, size_t data_size,
                                        gearman_job_priority_t priority,
                                        int64_t when)
{
  if (when) // No support for EPOCH jobs
  {
    return gearmand_gerror("libmemcached queue does not support epoch jobs", GEARMAND_QUEUE_ERROR);
  }

  (void)server;

  gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "libmemcached add: %.*s", (uint32_t)unique_size, (char *)unique);

  char key[MEMCACHED_MAX_KEY];
  size_t key_length= (size_t)snprintf(key, MEMCACHED_MAX_KEY, "%s%.*s-%.*s",
                                      GEARMAND_QUEUE_LIBMEMCACHED_DEFAULT_PREFIX,
                                      (int)function_name_size,
                                      (const char *)function_name, (int)unique_size,
                                      (const char *)unique);

  memcached_return_t rc= memcached_set(memc_, (const char *)key, key_length,
                                     (const char *)data, data_size, 0, (uint32_t)priority);

  if (rc != MEMCACHED_SUCCESS)
  {
    return gearmand_gerror(memcached_last_error_message(memc_), GEARMAND_QUEUE_ERROR);
  }

  return GEARMAND_SUCCESS;
}

gearmand_error_t LibmemcachedQueue::flush(gearman_server_st *)
{
  gearmand_debug("libmemcached flush");

  return GEARMAND_SUCCESS;
}

gearmand_error_t LibmemcachedQueue::done(gearman_server_st*,
                                         const char *unique, size_t unique_size,
                                         const char *function_name, size_t function_name_size)
{
  char key[MEMCACHED_MAX_KEY];

  gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "libmemcached done: %.*s", (uint32_t)unique_size, (char *)unique);

  size_t key_length= (size_t)snprintf(key, MEMCACHED_MAX_KEY, "%s%.*s-%.*s",
                                      GEARMAND_QUEUE_LIBMEMCACHED_DEFAULT_PREFIX,
                                      (int)function_name_size,
                                      (const char *)function_name, (int)unique_size,
                                      (const char *)unique);

  /* For the moment we will assume it happened */
  memcached_return_t rc= memcached_delete(memc_, (const char *)key, key_length, 0);
  if (rc != MEMCACHED_SUCCESS)
  {
    return gearmand_gerror(memcached_last_error_message(memc_), GEARMAND_QUEUE_ERROR);
  }

  return GEARMAND_SUCCESS;
}

class Replay
{
public:
  Replay(gearman_server_st* server_arg, memcached_st* _memc) :
    server_(server_arg),
    memc_(nullptr)
  {
    memc_= memcached_clone(nullptr, _memc);
  }

  ~Replay()
  {
    memcached_free(memc_);
    memc_= nullptr;
  }

  bool init()
  {
    return bool(memc_);
  }

  memcached_st* memc()
  {
    assert(memc_);
    return memc_;
  }

  gearman_server_st* server()
  {
    return server_;
  }

private:
  gearman_server_st* server_;
  memcached_st* memc_;
};

static memcached_return_t callback_loader(const memcached_st*,
                                        memcached_result_st* result,
                                        void *context)
{
  Replay* replay= (Replay*)context;

  const char *key= memcached_result_key_value(result);
  if (strncmp(key, GEARMAND_QUEUE_LIBMEMCACHED_DEFAULT_PREFIX, strlen(GEARMAND_QUEUE_LIBMEMCACHED_DEFAULT_PREFIX)) != 0)
  {
    gearmand_debug("memcached key did not match GEARMAND_QUEUE_LIBMEMCACHED_DEFAULT_PREFIX");
    return MEMCACHED_SUCCESS;
  }

  const char* function= key +strlen(GEARMAND_QUEUE_LIBMEMCACHED_DEFAULT_PREFIX);

  const char* unique= index(function, '-');
  if (!unique)
  {
    gearmand_debug("memcached key was malformed was not found");
    return MEMCACHED_SUCCESS;
  }

  size_t function_len= size_t(unique -function);
  unique++;
  size_t unique_size= strlen(unique);

  assert(function);
  assert(function_len);

  /* need to make a copy here ... gearman_server_job_free will free it later */
  char* data= (char*)malloc(memcached_result_length(result));
  if (!data)
  {
    gearmand_perror(errno, "malloc");
    return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
  }
  memcpy(data, memcached_result_value(result), memcached_result_length(result));

  gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "libmemcached replay_add: %.*s", (uint32_t)unique_size, (char *)unique);

  /* Currently not looking at failure cases */
  LibmemcachedQueue::replay_add(replay->server(),
                                nullptr,
                                unique, unique_size,
                                function, function_len,
                                data, memcached_result_length(result),
                                static_cast<gearman_job_priority_t>(memcached_result_flags(result)), int64_t(0));

  return MEMCACHED_SUCCESS;
}

/* Grab the object and load it into the loader */
static memcached_return_t callback_for_key(const memcached_st*,
                                         const char *key, size_t key_length,
                                         void *context)
{
  Replay* replay= (Replay*)context;
  memcached_execute_fn callbacks{(memcached_execute_fn)&callback_loader};
  char *passable[1];

  passable[0]= (char *)key;
  if (memcached_success(memcached_mget(replay->memc(), passable, &key_length, 1)))
  {
    gearmand_debug(memcached_last_error_message(replay->memc()));
  }

  /* Just void errors for the moment, since other treads might have picked up the object. */
  (void)memcached_fetch_execute(replay->memc(), &callbacks, replay, 1);

  return MEMCACHED_SUCCESS;
}

/*
  If we have any failures for loading values back into replay we just ignore them.
*/
gearmand_error_t LibmemcachedQueue::replay(gearman_server_st *server)
{
  memcached_dump_fn callbacks{(memcached_dump_fn)&callback_for_key};

  gearmand_debug("libmemcached replay start");

  memcached_st* local_clone= memcached_clone(nullptr, memc_);

  if (local_clone)
  {
    Replay replay_exec(server, memc_);

    if (replay_exec.init())
    {
      (void)memcached_dump(local_clone, &callbacks, (void *)&replay_exec, 1);
    }
    else
    {
      gearmand_debug("libmemcached failed to init() Replay");
    }
    memcached_free(local_clone);
    local_clone= nullptr;
  }
  gearmand_debug("libmemcached replay stop");

  return GEARMAND_SUCCESS;
}

} // queue
} // gearmand

#pragma GCC diagnostic pop
<commit_msg>Use C++11 uniform variable initialization<commit_after>/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 *
 *  Gearmand client and server library.
 *
 *  Copyright (C) 2011-2012 Data Differential, http://datadifferential.com/
 *  Copyright (C) 2008 Brian Aker, Eric Day
 *  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.
 *
 *      * The names of its contributors may not be used to endorse or
 *  promote products derived from this software without specific prior
 *  written permission.
 *
 *  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
 *  OWNER 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.
 *
 */

/**
 * @file
 * @brief libmemcached Queue Storage Definitions
 */

#include "gear_config.h"

#include <libgearman-server/common.h>

#include <libgearman-server/plugins/queue/base.h>
#include <libgearman-server/plugins/queue/libmemcached/queue.h>
#include <libmemcached/memcached.h>

#include "libgearman-server/log.h"

#include <cerrno>

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wold-style-cast"

using namespace gearmand;

/**
 * @addtogroup gearmand::plugins::queue::Libmemcachedatic Static libmemcached Queue Storage Functions
 * @ingroup gearman_queue_libmemcached
 * @{
 */

/**
 * Default values.
 */
static constexpr const char GEARMAND_QUEUE_LIBMEMCACHED_DEFAULT_PREFIX[] = "gear_";

namespace gearmand { namespace plugins { namespace queue { class Libmemcached;  }}}

namespace gearmand {
namespace queue {

class LibmemcachedQueue : public gearmand::queue::Context
{
public:
  LibmemcachedQueue(memcached_server_st* servers):
    memc_(nullptr)
  {
    memc_= memcached_create(nullptr);

    memcached_server_push(memc_, servers);
  }

  bool init()
  {
    return bool(bool(memc_) and memcached_server_count(memc_));
  }

  ~LibmemcachedQueue()
  {
    memcached_free(memc_);
    memc_= nullptr;
  }

  gearmand_error_t add(gearman_server_st *server,
                       const char *unique, size_t unique_size,
                       const char *function_name, size_t function_name_size,
                       const void *data, size_t data_size,
                       gearman_job_priority_t priority,
                       int64_t when);

  gearmand_error_t flush(gearman_server_st *server);

  gearmand_error_t done(gearman_server_st *server,
                        const char *unique, size_t unique_size,
                        const char *function_name, size_t function_name_size);

  gearmand_error_t replay(gearman_server_st *server);

private:
  memcached_st* memc_;
};

} // namespace queue
} // namespace gearmand

namespace gearmand {
namespace plugins {
namespace queue {

class Libmemcached : public gearmand::plugins::Queue {
public:
  Libmemcached ();
  ~Libmemcached ();

  gearmand_error_t initialize();

  std::string server_list;
private:

};

Libmemcached::Libmemcached() :
  Queue("libmemcached")
{
  command_line_options().add_options()
    ("libmemcached-servers", boost::program_options::value(&server_list), "List of Memcached servers to use.");
}

Libmemcached::~Libmemcached()
{
}

gearmand_error_t Libmemcached::initialize()
{
  gearmand_info("Initializing libmemcached module");

  memcached_server_st *servers= memcached_servers_parse(server_list.c_str());
  if (!servers)
  {
    return gearmand_gerror("memcached_servers_parse", GEARMAND_QUEUE_ERROR);
  }

  gearmand::queue::LibmemcachedQueue* exec_queue= new gearmand::queue::LibmemcachedQueue(servers);
  if (exec_queue and exec_queue->init())
  {
    gearman_server_set_queue(Gearmand()->server, exec_queue);

    memcached_server_list_free(servers);

    return GEARMAND_SUCCESS;
  }

  return gearmand_gerror("Libmemcached::initialize()", GEARMAND_QUEUE_ERROR);
}

void initialize_libmemcached()
{
  static Libmemcached local_instance;
}

} // namespace queue
} // namespace plugins
} // namespace gearmand

/* Queue callback functions. */

namespace gearmand {
namespace queue {

gearmand_error_t LibmemcachedQueue::add(gearman_server_st *server,
                                        const char *unique,
                                        size_t unique_size,
                                        const char *function_name,
                                        size_t function_name_size,
                                        const void *data, size_t data_size,
                                        gearman_job_priority_t priority,
                                        int64_t when)
{
  if (when) // No support for EPOCH jobs
  {
    return gearmand_gerror("libmemcached queue does not support epoch jobs", GEARMAND_QUEUE_ERROR);
  }

  (void)server;

  gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "libmemcached add: %.*s", (uint32_t)unique_size, (char *)unique);

  char key[MEMCACHED_MAX_KEY];
  size_t key_length= (size_t)snprintf(key, MEMCACHED_MAX_KEY, "%s%.*s-%.*s",
                                      GEARMAND_QUEUE_LIBMEMCACHED_DEFAULT_PREFIX,
                                      (int)function_name_size,
                                      (const char *)function_name, (int)unique_size,
                                      (const char *)unique);

  memcached_return_t rc= memcached_set(memc_, (const char *)key, key_length,
                                     (const char *)data, data_size, 0, (uint32_t)priority);

  if (rc != MEMCACHED_SUCCESS)
  {
    return gearmand_gerror(memcached_last_error_message(memc_), GEARMAND_QUEUE_ERROR);
  }

  return GEARMAND_SUCCESS;
}

gearmand_error_t LibmemcachedQueue::flush(gearman_server_st *)
{
  gearmand_debug("libmemcached flush");

  return GEARMAND_SUCCESS;
}

gearmand_error_t LibmemcachedQueue::done(gearman_server_st*,
                                         const char *unique, size_t unique_size,
                                         const char *function_name, size_t function_name_size)
{
  char key[MEMCACHED_MAX_KEY];

  gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "libmemcached done: %.*s", (uint32_t)unique_size, (char *)unique);

  size_t key_length= (size_t)snprintf(key, MEMCACHED_MAX_KEY, "%s%.*s-%.*s",
                                      GEARMAND_QUEUE_LIBMEMCACHED_DEFAULT_PREFIX,
                                      (int)function_name_size,
                                      (const char *)function_name, (int)unique_size,
                                      (const char *)unique);

  /* For the moment we will assume it happened */
  memcached_return_t rc= memcached_delete(memc_, (const char *)key, key_length, 0);
  if (rc != MEMCACHED_SUCCESS)
  {
    return gearmand_gerror(memcached_last_error_message(memc_), GEARMAND_QUEUE_ERROR);
  }

  return GEARMAND_SUCCESS;
}

class Replay
{
public:
  Replay(gearman_server_st* server_arg, memcached_st* _memc) :
    server_(server_arg),
    memc_(nullptr)
  {
    memc_= memcached_clone(nullptr, _memc);
  }

  ~Replay()
  {
    memcached_free(memc_);
    memc_= nullptr;
  }

  bool init()
  {
    return bool(memc_);
  }

  memcached_st* memc()
  {
    assert(memc_);
    return memc_;
  }

  gearman_server_st* server()
  {
    return server_;
  }

private:
  gearman_server_st* server_;
  memcached_st* memc_;
};

static memcached_return_t callback_loader(const memcached_st*,
                                        memcached_result_st* result,
                                        void *context)
{
  Replay* replay= (Replay*)context;

  const char *key= memcached_result_key_value(result);
  if (strncmp(key, GEARMAND_QUEUE_LIBMEMCACHED_DEFAULT_PREFIX, strlen(GEARMAND_QUEUE_LIBMEMCACHED_DEFAULT_PREFIX)) != 0)
  {
    gearmand_debug("memcached key did not match GEARMAND_QUEUE_LIBMEMCACHED_DEFAULT_PREFIX");
    return MEMCACHED_SUCCESS;
  }

  const char* function= key +strlen(GEARMAND_QUEUE_LIBMEMCACHED_DEFAULT_PREFIX);

  const char* unique= index(function, '-');
  if (!unique)
  {
    gearmand_debug("memcached key was malformed was not found");
    return MEMCACHED_SUCCESS;
  }

  size_t function_len= size_t(unique -function);
  unique++;
  size_t unique_size= strlen(unique);

  assert(function);
  assert(function_len);

  /* need to make a copy here ... gearman_server_job_free will free it later */
  char* data= (char*)malloc(memcached_result_length(result));
  if (!data)
  {
    gearmand_perror(errno, "malloc");
    return MEMCACHED_MEMORY_ALLOCATION_FAILURE;
  }
  memcpy(data, memcached_result_value(result), memcached_result_length(result));

  gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "libmemcached replay_add: %.*s", (uint32_t)unique_size, (char *)unique);

  /* Currently not looking at failure cases */
  LibmemcachedQueue::replay_add(replay->server(),
                                nullptr,
                                unique, unique_size,
                                function, function_len,
                                data, memcached_result_length(result),
                                static_cast<gearman_job_priority_t>(memcached_result_flags(result)), int64_t(0));

  return MEMCACHED_SUCCESS;
}

/* Grab the object and load it into the loader */
static memcached_return_t callback_for_key(const memcached_st*,
                                         const char *key, size_t key_length,
                                         void *context)
{
  Replay* replay= (Replay*)context;
  memcached_execute_fn callbacks{(memcached_execute_fn)&callback_loader};
  char *passable{(char *)key};

  if (memcached_success(memcached_mget(replay->memc(), &passable, &key_length, 1)))
  {
    gearmand_debug(memcached_last_error_message(replay->memc()));
  }

  /* Just void errors for the moment, since other treads might have picked up the object. */
  (void)memcached_fetch_execute(replay->memc(), &callbacks, replay, 1);

  return MEMCACHED_SUCCESS;
}

/*
  If we have any failures for loading values back into replay we just ignore them.
*/
gearmand_error_t LibmemcachedQueue::replay(gearman_server_st *server)
{
  memcached_dump_fn callbacks{(memcached_dump_fn)&callback_for_key};

  gearmand_debug("libmemcached replay start");

  memcached_st* local_clone= memcached_clone(nullptr, memc_);

  if (local_clone)
  {
    Replay replay_exec(server, memc_);

    if (replay_exec.init())
    {
      (void)memcached_dump(local_clone, &callbacks, (void *)&replay_exec, 1);
    }
    else
    {
      gearmand_debug("libmemcached failed to init() Replay");
    }
    memcached_free(local_clone);
    local_clone= nullptr;
  }
  gearmand_debug("libmemcached replay stop");

  return GEARMAND_SUCCESS;
}

} // queue
} // gearmand

#pragma GCC diagnostic pop
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko
 *
 * This library 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 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/
//$Id: graphics.cpp 17 2005-03-08 23:58:43Z pavlenko $

// mapnik
#include <mapnik/graphics.hpp>

#include <mapnik/image_util.hpp>
// stl
#include <cassert>
#include <string.h>
#include <stack>
#include <iostream>

namespace mapnik
{
    Image32::Image32(int width,int height)
        :width_(width),
         height_(height),
         data_(width,height) {}

    Image32::Image32(const Image32& rhs)
        :width_(rhs.width_),
         height_(rhs.height_),
         data_(rhs.data_) {}

    Image32::~Image32() {}

    const ImageData32& Image32::data() const
    {
        return data_;
    }

    void Image32::setBackground(const Color& background)
    {
        background_=background;
        data_.set(background_.rgba());
    }

    const Color& Image32::getBackground() const
    {
        return background_;
    }
}
<commit_msg>removed unneeded headers  <commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2006 Artem Pavlenko
 *
 * This library 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 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/
//$Id: graphics.cpp 17 2005-03-08 23:58:43Z pavlenko $

// mapnik
#include <mapnik/graphics.hpp>
#include <mapnik/image_util.hpp>

namespace mapnik
{
    Image32::Image32(int width,int height)
        :width_(width),
         height_(height),
         data_(width,height) {}

    Image32::Image32(const Image32& rhs)
        :width_(rhs.width_),
         height_(rhs.height_),
         data_(rhs.data_)  {}

    Image32::~Image32() {}

    const ImageData32& Image32::data() const
    {
        return data_;
    }

    void Image32::setBackground(const Color& background)
    {
        background_=background;
        data_.set(background_.rgba());
    }

    const Color& Image32::getBackground() const
    {
        return background_;
    }
}
<|endoftext|>


<commit_before>#include "qmtopology.h"
#include "qmnblist.h"

QMTopology::QMTopology()
{}

QMTopology::~QMTopology()
{}

void QMTopology::Initialize(Topology& cg_top)
{
    CopyTopologyData(&cg_top);
    this->InitChargeUnits();
}

void QMTopology::Update(Topology& cg_top)
{
    BeadContainer::iterator iter;
    BeadContainer::iterator iter_cg;

    assert(cg_top.Beads().size() == _beads.size());

    _box = cg_top.getBox();
    _time = cg_top.getTime();
    _step = cg_top.getStep();

    iter_cg = cg_top.Beads().begin();
    for(iter=_beads.begin(); iter!=_beads.end(); ++iter) {
        (*iter)->setPos((*iter_cg)->getPos());
        (*iter)->setU((*iter_cg)->getU());
        (*iter)->setV((*iter_cg)->getV());
        (*iter)->setW((*iter_cg)->getW());
        QMBead * b = (QMBead*)(*iter);
        b->UpdateCrg();
    }
}

void QMTopology::LoadListCharges(const string &file)
{
    _jcalc.Init(file);
}

void QMTopology::AddAtomisticBeads(CrgUnit *crg, Topology * totop){

    mol_and_orb * atoms = crg->rotate_translate_beads();

    for (int i=0;i<atoms->getN();i++){
        vec pos = atoms->GetPos(i);
        string atomtype = "QMAT-"+string( atoms->gettype(i) );
        BeadType * bt= totop->GetOrCreateBeadType(atomtype);
        int nbead = totop-> BeadCount();
        Bead * bead = totop ->CreateBead(1, atomtype,bt,nbead, 0, 0.);
        bead->setPos(pos);
    }
    delete atoms;
}

Bead *QMTopology::CreateBead(byte_t symmetry, string name, BeadType *type, int resnr, double m, double q)
{
    QMBead *bead = new QMBead(this, _beads.size(), type, symmetry, name, resnr, m, q);
    _beads.push_back(bead);
    return bead;
}

void QMTopology::InitChargeUnits(){
    BeadContainer::iterator itb;
    for (itb = _beads.begin() ; itb< _beads.end(); ++itb){
        QMBead * bead = dynamic_cast<QMBead *>(*itb);
        //initialise the crgunit * only if appropriate extra info is in the cg.xml file
        if ( (bead->Options()).exists("qm.crgunitname")){
            string namecrgunittype = bead->getType()->getName();
            int intpos = (bead->Options()).get("qm.position").as<int>();
            string namecrgunit = (bead->Options()).get("qm.crgunitname").as<string>();

            CrgUnitType *crgtype  = _jcalc.GetCrgUnitTypeByName(namecrgunittype);

            //determine whether it  has been created already
            int molid= bead->getMolecule()->getId();
            string molandtype = lexical_cast<string>(molid)+":"+namecrgunit;
            map <string, CrgUnit*>::iterator  itm= _mcharges.find(molandtype);
            if (itm == _mcharges.end()){
                CrgUnit * acrg = new CrgUnit(_lcharges.size(), crgtype, molid);
                _mcharges.insert(make_pair(molandtype, acrg));
                _lcharges.push_back(acrg);
                bead->setCrg(acrg);
                bead->setiPos(intpos);
            }
        }
        else{
            bead->setCrg(NULL);
        }
    }
}
<commit_msg>fixed problem that residue was not created in AddAtomsticBeads<commit_after>#include "qmtopology.h"
#include "qmnblist.h"

QMTopology::QMTopology()
{}

QMTopology::~QMTopology()
{}

void QMTopology::Initialize(Topology& cg_top)
{
    CopyTopologyData(&cg_top);
    this->InitChargeUnits();
}

void QMTopology::Update(Topology& cg_top)
{
    BeadContainer::iterator iter;
    BeadContainer::iterator iter_cg;

    assert(cg_top.Beads().size() == _beads.size());

    _box = cg_top.getBox();
    _time = cg_top.getTime();
    _step = cg_top.getStep();

    iter_cg = cg_top.Beads().begin();
    for(iter=_beads.begin(); iter!=_beads.end(); ++iter) {
        (*iter)->setPos((*iter_cg)->getPos());
        (*iter)->setU((*iter_cg)->getU());
        (*iter)->setV((*iter_cg)->getV());
        (*iter)->setW((*iter_cg)->getW());
        QMBead * b = (QMBead*)(*iter);
        b->UpdateCrg();
    }
}

void QMTopology::LoadListCharges(const string &file)
{
    _jcalc.Init(file);
}

void QMTopology::AddAtomisticBeads(CrgUnit *crg, Topology * totop){

    mol_and_orb * atoms = crg->rotate_translate_beads();
    totop->CreateResidue("DUM");
    for (int i=0;i<atoms->getN();i++){
        vec pos = atoms->GetPos(i);
        string atomtype = "QMAT-"+string( atoms->gettype(i) );
        BeadType * bt= totop->GetOrCreateBeadType(atomtype);
        Bead * bead = totop ->CreateBead(1, atomtype,bt,0, 0, 0.);
        bead->setPos(pos);
    }
    delete atoms;
}

Bead *QMTopology::CreateBead(byte_t symmetry, string name, BeadType *type, int resnr, double m, double q)
{
    QMBead *bead = new QMBead(this, _beads.size(), type, symmetry, name, resnr, m, q);
    _beads.push_back(bead);
    return bead;
}

void QMTopology::InitChargeUnits(){
    BeadContainer::iterator itb;
    for (itb = _beads.begin() ; itb< _beads.end(); ++itb){
        QMBead * bead = dynamic_cast<QMBead *>(*itb);
        //initialise the crgunit * only if appropriate extra info is in the cg.xml file
        if ( (bead->Options()).exists("qm.crgunitname")){
            string namecrgunittype = bead->getType()->getName();
            int intpos = (bead->Options()).get("qm.position").as<int>();
            string namecrgunit = (bead->Options()).get("qm.crgunitname").as<string>();

            CrgUnitType *crgtype  = _jcalc.GetCrgUnitTypeByName(namecrgunittype);

            //determine whether it  has been created already
            int molid= bead->getMolecule()->getId();
            string molandtype = lexical_cast<string>(molid)+":"+namecrgunit;
            map <string, CrgUnit*>::iterator  itm= _mcharges.find(molandtype);
            if (itm == _mcharges.end()){
                CrgUnit * acrg = new CrgUnit(_lcharges.size(), crgtype, molid);
                _mcharges.insert(make_pair(molandtype, acrg));
                _lcharges.push_back(acrg);
                bead->setCrg(acrg);
                bead->setiPos(intpos);
            }
        }
        else{
            bead->setCrg(NULL);
        }
    }
}
<|endoftext|>


<commit_before>/**
 * Copyright 2013 Da Zheng
 *
 * This file is part of SA-GraphLib.
 *
 * SA-GraphLib is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * SA-GraphLib is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with SA-GraphLib.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <signal.h>
#include <google/profiler.h>

#include "thread.h"
#include "io_interface.h"

#include "graph_engine.h"
#include "graph_config.h"

const double BIN_SEARCH_RATIO = 100;

atomic_number<long> num_working_vertices;
atomic_number<long> num_completed_vertices;

class count_msg: public vertex_message
{
	int num;
public:
	count_msg(int num): vertex_message(sizeof(count_msg), false) {
		this->num = num;
	}

	int get_num() const {
		return num;
	}
};

class triangle_vertex: public compute_vertex
{
	// The number of required vertices to join with this vertex.
	int num_required;
	// The number of vertices that have joined with the vertex.
	int num_joined;
	// The number of vertices that have been asked to fetch.
	int num_fetched;
	// The number of triangles per vertex.
	atomic_integer num_pv_triangles;
	// It contains part of in-edges.
	// We only use the neighbors whose ID is smaller than this vertex.
	std::vector<vertex_id_t> *in_edges;
	// The vector contains the number of the neighbors' triangles shared
	// with this vertex. It only keeps the triangles of neighbors in the
	// in-edges.
	std::vector<int> *triangles;
	// It contains part of out-edges.
	// We only read neighbors whose ID is smaller than this vertex.
	std::vector<vertex_id_t> *out_edges;
public:
	triangle_vertex(): compute_vertex(-1, -1, 0) {
		num_required = 0;
		num_joined = 0;
		num_fetched = 0;
		in_edges = NULL;
		triangles = NULL;
		out_edges = NULL;
	}

	triangle_vertex(vertex_id_t id, off_t off, int size): compute_vertex(
			id, off, size) {
		num_required = 0;
		num_joined = 0;
		num_fetched = 0;
		in_edges = NULL;
		triangles = NULL;
		out_edges = NULL;
	}

	int count_triangles(const page_vertex *v) const;

	virtual bool has_required_vertices() const {
		return num_fetched < num_required;
	}

	virtual vertex_id_t get_next_required_vertex() {
		return out_edges->at(num_fetched++);
	}

	int get_num_triangles() const {
		return num_pv_triangles.get();
	}

	bool run(graph_engine &graph, const page_vertex *vertex);

	bool run_on_neighbors(graph_engine &graph,
			const page_vertex *vertices[], int num);

	void run_on_messages(graph_engine &graph,
			const vertex_message *msgs[], int num) {
		int sum = 0;
		for (int i = 0; i < num; i++)
			sum += ((count_msg *) msgs[i])->get_num();
		num_pv_triangles.inc(sum);
	}
};

int triangle_vertex::count_triangles(const page_vertex *v) const
{
	int num_local_triangles = 0;
	assert(v->get_id() != this->get_id());

	if (v->get_num_edges(edge_type::OUT_EDGE) == 0)
		return 0;

	/*
	 * We search for triangles with two different ways:
	 * binary search if two adjacency lists have very different sizes,
	 * scan otherwise.
	 *
	 * when binary search for multiple neighbors, we can reduce binary search
	 * overhead by using the new end in the search range. We can further reduce
	 * overhead by searching in a reverse order (start from the largest neighbor).
	 * Since vertices of smaller ID has more neighbors, it's more likely
	 * that a neighbor is in the beginning of the adjacency list, and
	 * the search range will be narrowed faster.
	 */

	assert(in_edges);
	// If the neighbor vertex has way more edges than this vertex.
	if (v->get_num_edges(edge_type::OUT_EDGE) / in_edges->size() > BIN_SEARCH_RATIO) {
		page_byte_array::const_iterator<vertex_id_t> other_it
			= v->get_neigh_begin(edge_type::OUT_EDGE);
		page_byte_array::const_iterator<vertex_id_t> other_end
			= v->get_neigh_end(edge_type::OUT_EDGE);
		for (int i = in_edges->size() - 1; i >= 0; i--) {
			vertex_id_t this_neighbor = in_edges->at(i);
			// We need to skip loops.
			if (this_neighbor != v->get_id()
					&& this_neighbor != this->get_id()) {
				page_byte_array::const_iterator<vertex_id_t> first
					= std::lower_bound(other_it, other_end, this_neighbor);
				if (first != other_end && this_neighbor == *first) {
					num_local_triangles++;
					(triangles->at(i))++;
				}
				other_end = first;
			}
		}
	}
	// If this vertex has way more edges than the neighbor vertex.
	else if (in_edges->size() / v->get_num_edges(edge_type::OUT_EDGE)
			> BIN_SEARCH_RATIO) {
		// TODO the same as above.
		page_byte_array::const_iterator<vertex_id_t> other_it
			= v->get_neigh_begin(edge_type::OUT_EDGE);
		page_byte_array::const_iterator<vertex_id_t> other_end
			= v->get_neigh_end(edge_type::OUT_EDGE);
		while (other_it != other_end) {
			vertex_id_t neigh_neighbor = *other_it;
			if (neigh_neighbor != v->get_id()
					&& neigh_neighbor != this->get_id()) {
				std::vector<vertex_id_t>::const_iterator first = std::lower_bound(
						in_edges->begin(), in_edges->end(), neigh_neighbor);
				if (first != in_edges->end() && neigh_neighbor == *first) {
					num_local_triangles++;
					int distance = first - in_edges->begin();
					(triangles->at(distance))++;
				}
			}
			++other_it;
		}
	}
	else {
		std::vector<vertex_id_t>::const_iterator this_it = in_edges->begin();
		std::vector<int>::iterator count_it = triangles->begin();
		std::vector<vertex_id_t>::const_iterator this_end = in_edges->end();
		page_byte_array::const_iterator<vertex_id_t> other_it
			= v->get_neigh_begin(edge_type::OUT_EDGE);
		page_byte_array::const_iterator<vertex_id_t> other_end
			= v->get_neigh_end(edge_type::OUT_EDGE);
		while (this_it != this_end && other_it != other_end) {
			vertex_id_t this_neighbor = *this_it;
			vertex_id_t neigh_neighbor = *other_it;
			if (this_neighbor == neigh_neighbor) {
				// skip loop
				if (neigh_neighbor != v->get_id()
						&& neigh_neighbor != this->get_id()) {
					num_local_triangles++;
					(*count_it)++;
				}
				++this_it;
				++other_it;
				++count_it;
			}
			else if (this_neighbor < neigh_neighbor) {
				++this_it;
				++count_it;
			}
			else
				++other_it;
		}
	}
	return num_local_triangles;
}

// We only use the neighbors whose ID is smaller than this vertex.
static int get_required_edges(const page_vertex *vertex, edge_type type,
		std::vector<vertex_id_t> &edges)
{
	page_byte_array::const_iterator<vertex_id_t> it
		= vertex->get_neigh_begin(type);
	page_byte_array::const_iterator<vertex_id_t> end
		= vertex->get_neigh_end(type);
	int num = 0;
	for (; it != end; ++it) {
		vertex_id_t id = *it;
		if (id < vertex->get_id()) {
			edges.push_back(id);
			num++;
		}
	}
	return num;
}

bool triangle_vertex::run(graph_engine &graph, const page_vertex *vertex)
{
	assert(in_edges == NULL);
	assert(out_edges == NULL);
	assert(num_joined == 0);
	assert(num_fetched == 0);

	long ret = num_working_vertices.inc(1);
	if (ret % 100000 == 0)
		printf("%ld working vertices\n", ret);
	// A vertex has to have in-edges and out-edges in order to form
	// a triangle. so we can simply skip the vertices that don't have
	// either of them.
	if (vertex->get_num_edges(edge_type::OUT_EDGE) == 0
			|| vertex->get_num_edges(edge_type::IN_EDGE) == 0) {
		long ret = num_completed_vertices.inc(1);
		if (ret % 100000 == 0)
			printf("%ld completed vertices\n", ret);
		return true;
	}

	in_edges = new std::vector<vertex_id_t>();
	out_edges = new std::vector<vertex_id_t>();
	get_required_edges(vertex, edge_type::IN_EDGE, *in_edges);
	get_required_edges(vertex, edge_type::OUT_EDGE, *out_edges);
	num_required = out_edges->size();

	if (in_edges->empty() || out_edges->empty()) {
		num_required = 0;
		long ret = num_completed_vertices.inc(1);
		if (ret % 100000 == 0)
			printf("%ld completed vertices\n", ret);
		delete in_edges;
		delete out_edges;
		in_edges = NULL;
		out_edges = NULL;
		return true;
	}
	else {
		triangles = new std::vector<int>(in_edges->size());
	}
	return false;
}

bool triangle_vertex::run_on_neighbors(graph_engine &graph,
		const page_vertex *vertices[], int num)
{
	num_joined++;
	for (int i = 0; i < num; i++) {
		int ret = count_triangles(vertices[i]);
		// If we find triangles with the neighbor, notify the neighbor
		// as well.
		if (ret > 0) {
			num_pv_triangles.inc(ret);
			count_msg msg(ret);
			graph.send_msg(vertices[i]->get_id(), msg);
		}
	}

	// If we have seen all required neighbors, we have complete
	// the computation. We can release the memory now.
	if (num_joined == num_required) {
		long ret = num_completed_vertices.inc(1);
		if (ret % 100000 == 0)
			printf("%ld completed vertices\n", ret);

		// Inform all neighbors in the in-edges.
		for (size_t i = 0; i < triangles->size(); i++) {
			// Inform the neighbor if they share triangles.
			if (triangles->at(i) > 0) {
				count_msg msg(triangles->at(i));
				graph.send_msg(in_edges->at(i), msg);
			}
		}

		delete triangles;
		delete in_edges;
		delete out_edges;
		in_edges = NULL;
		out_edges = NULL;
		return true;
	}
	return false;
}

void int_handler(int sig_num)
{
	if (!graph_conf.get_prof_file().empty())
		ProfilerStop();
	exit(0);
}

int main(int argc, char *argv[])
{
	if (argc < 5) {
		fprintf(stderr, "triangle-counting conf_file graph_file index_file directed\n");
		graph_conf.print_help();
		params.print_help();
		exit(-1);
	}

	std::string conf_file = argv[1];
	std::string graph_file = argv[2];
	std::string index_file = argv[3];
	bool directed = atoi(argv[4]);

	config_map configs(conf_file);
	configs.add_options(argv + 5, argc - 5);
	graph_conf.init(configs);
	graph_conf.print();

	signal(SIGINT, int_handler);
	init_io_system(configs);

	int min_vertex_size;
	if (directed)
		min_vertex_size = sizeof(ext_mem_directed_vertex);
	else
		min_vertex_size = sizeof(ext_mem_undirected_vertex);

	graph_index *index = graph_index_impl<triangle_vertex>::create(
			index_file, min_vertex_size);
	ext_mem_vertex_interpreter *interpreter;
	if (directed)
		interpreter = new ext_mem_directed_vertex_interpreter();
	else
		interpreter = new ext_mem_undirected_vertex_interpreter();
	graph_engine *graph = graph_engine::create(
			graph_conf.get_num_threads(), params.get_num_nodes(),
			graph_file, index, interpreter, directed);
	graph->set_required_neighbor_type(edge_type::OUT_EDGE);
	printf("triangle counting starts\n");
	printf("prof_file: %s\n", graph_conf.get_prof_file().c_str());
	if (!graph_conf.get_prof_file().empty())
		ProfilerStart(graph_conf.get_prof_file().c_str());

	struct timeval start, end;
	gettimeofday(&start, NULL);
	graph->start_all();
	graph->wait4complete();
	gettimeofday(&end, NULL);

	// Count the total number of triangles in the graph.
	graph_index::const_iterator it = index->begin();
	graph_index::const_iterator end_it = index->end();
	long num_triangles = 0;
	for (; it != end_it; ++it) {
		const triangle_vertex &v = (const triangle_vertex &) *it;
		num_triangles += v.get_num_triangles();
	}

	if (!graph_conf.get_prof_file().empty())
		ProfilerStop();
	if (graph_conf.get_print_io_stat())
		print_io_thread_stat();
	graph_engine::destroy(graph);
	printf("There are %ld vertices\n", index->get_num_vertices());
	printf("process %ld vertices and complete %ld vertices\n",
			num_working_vertices.get(), num_completed_vertices.get());
	printf("there are %ld triangles. It takes %f seconds\n",
			num_triangles, time_diff(start, end));
}
<commit_msg>[Graph]: measure the time of starting all vertices in triangle counting.<commit_after>/**
 * Copyright 2013 Da Zheng
 *
 * This file is part of SA-GraphLib.
 *
 * SA-GraphLib is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * SA-GraphLib is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with SA-GraphLib.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <signal.h>
#include <google/profiler.h>

#include "thread.h"
#include "io_interface.h"

#include "graph_engine.h"
#include "graph_config.h"

const double BIN_SEARCH_RATIO = 100;

atomic_number<long> num_working_vertices;
atomic_number<long> num_completed_vertices;

class count_msg: public vertex_message
{
	int num;
public:
	count_msg(int num): vertex_message(sizeof(count_msg), false) {
		this->num = num;
	}

	int get_num() const {
		return num;
	}
};

class triangle_vertex: public compute_vertex
{
	// The number of required vertices to join with this vertex.
	int num_required;
	// The number of vertices that have joined with the vertex.
	int num_joined;
	// The number of vertices that have been asked to fetch.
	int num_fetched;
	// The number of triangles per vertex.
	atomic_integer num_pv_triangles;
	// It contains part of in-edges.
	// We only use the neighbors whose ID is smaller than this vertex.
	std::vector<vertex_id_t> *in_edges;
	// The vector contains the number of the neighbors' triangles shared
	// with this vertex. It only keeps the triangles of neighbors in the
	// in-edges.
	std::vector<int> *triangles;
	// It contains part of out-edges.
	// We only read neighbors whose ID is smaller than this vertex.
	std::vector<vertex_id_t> *out_edges;
public:
	triangle_vertex(): compute_vertex(-1, -1, 0) {
		num_required = 0;
		num_joined = 0;
		num_fetched = 0;
		in_edges = NULL;
		triangles = NULL;
		out_edges = NULL;
	}

	triangle_vertex(vertex_id_t id, off_t off, int size): compute_vertex(
			id, off, size) {
		num_required = 0;
		num_joined = 0;
		num_fetched = 0;
		in_edges = NULL;
		triangles = NULL;
		out_edges = NULL;
	}

	int count_triangles(const page_vertex *v) const;

	virtual bool has_required_vertices() const {
		return num_fetched < num_required;
	}

	virtual vertex_id_t get_next_required_vertex() {
		return out_edges->at(num_fetched++);
	}

	int get_num_triangles() const {
		return num_pv_triangles.get();
	}

	bool run(graph_engine &graph, const page_vertex *vertex);

	bool run_on_neighbors(graph_engine &graph,
			const page_vertex *vertices[], int num);

	void run_on_messages(graph_engine &graph,
			const vertex_message *msgs[], int num) {
		int sum = 0;
		for (int i = 0; i < num; i++)
			sum += ((count_msg *) msgs[i])->get_num();
		num_pv_triangles.inc(sum);
	}
};

int triangle_vertex::count_triangles(const page_vertex *v) const
{
	int num_local_triangles = 0;
	assert(v->get_id() != this->get_id());

	if (v->get_num_edges(edge_type::OUT_EDGE) == 0)
		return 0;

	/*
	 * We search for triangles with two different ways:
	 * binary search if two adjacency lists have very different sizes,
	 * scan otherwise.
	 *
	 * when binary search for multiple neighbors, we can reduce binary search
	 * overhead by using the new end in the search range. We can further reduce
	 * overhead by searching in a reverse order (start from the largest neighbor).
	 * Since vertices of smaller ID has more neighbors, it's more likely
	 * that a neighbor is in the beginning of the adjacency list, and
	 * the search range will be narrowed faster.
	 */

	assert(in_edges);
	// If the neighbor vertex has way more edges than this vertex.
	if (v->get_num_edges(edge_type::OUT_EDGE) / in_edges->size() > BIN_SEARCH_RATIO) {
		page_byte_array::const_iterator<vertex_id_t> other_it
			= v->get_neigh_begin(edge_type::OUT_EDGE);
		page_byte_array::const_iterator<vertex_id_t> other_end
			= v->get_neigh_end(edge_type::OUT_EDGE);
		for (int i = in_edges->size() - 1; i >= 0; i--) {
			vertex_id_t this_neighbor = in_edges->at(i);
			// We need to skip loops.
			if (this_neighbor != v->get_id()
					&& this_neighbor != this->get_id()) {
				page_byte_array::const_iterator<vertex_id_t> first
					= std::lower_bound(other_it, other_end, this_neighbor);
				if (first != other_end && this_neighbor == *first) {
					num_local_triangles++;
					(triangles->at(i))++;
				}
				other_end = first;
			}
		}
	}
	// If this vertex has way more edges than the neighbor vertex.
	else if (in_edges->size() / v->get_num_edges(edge_type::OUT_EDGE)
			> BIN_SEARCH_RATIO) {
		// TODO the same as above.
		page_byte_array::const_iterator<vertex_id_t> other_it
			= v->get_neigh_begin(edge_type::OUT_EDGE);
		page_byte_array::const_iterator<vertex_id_t> other_end
			= v->get_neigh_end(edge_type::OUT_EDGE);
		while (other_it != other_end) {
			vertex_id_t neigh_neighbor = *other_it;
			if (neigh_neighbor != v->get_id()
					&& neigh_neighbor != this->get_id()) {
				std::vector<vertex_id_t>::const_iterator first = std::lower_bound(
						in_edges->begin(), in_edges->end(), neigh_neighbor);
				if (first != in_edges->end() && neigh_neighbor == *first) {
					num_local_triangles++;
					int distance = first - in_edges->begin();
					(triangles->at(distance))++;
				}
			}
			++other_it;
		}
	}
	else {
		std::vector<vertex_id_t>::const_iterator this_it = in_edges->begin();
		std::vector<int>::iterator count_it = triangles->begin();
		std::vector<vertex_id_t>::const_iterator this_end = in_edges->end();
		page_byte_array::const_iterator<vertex_id_t> other_it
			= v->get_neigh_begin(edge_type::OUT_EDGE);
		page_byte_array::const_iterator<vertex_id_t> other_end
			= v->get_neigh_end(edge_type::OUT_EDGE);
		while (this_it != this_end && other_it != other_end) {
			vertex_id_t this_neighbor = *this_it;
			vertex_id_t neigh_neighbor = *other_it;
			if (this_neighbor == neigh_neighbor) {
				// skip loop
				if (neigh_neighbor != v->get_id()
						&& neigh_neighbor != this->get_id()) {
					num_local_triangles++;
					(*count_it)++;
				}
				++this_it;
				++other_it;
				++count_it;
			}
			else if (this_neighbor < neigh_neighbor) {
				++this_it;
				++count_it;
			}
			else
				++other_it;
		}
	}
	return num_local_triangles;
}

// We only use the neighbors whose ID is smaller than this vertex.
static int get_required_edges(const page_vertex *vertex, edge_type type,
		std::vector<vertex_id_t> &edges)
{
	page_byte_array::const_iterator<vertex_id_t> it
		= vertex->get_neigh_begin(type);
	page_byte_array::const_iterator<vertex_id_t> end
		= vertex->get_neigh_end(type);
	int num = 0;
	for (; it != end; ++it) {
		vertex_id_t id = *it;
		if (id < vertex->get_id()) {
			edges.push_back(id);
			num++;
		}
	}
	return num;
}

bool triangle_vertex::run(graph_engine &graph, const page_vertex *vertex)
{
	assert(in_edges == NULL);
	assert(out_edges == NULL);
	assert(num_joined == 0);
	assert(num_fetched == 0);

	long ret = num_working_vertices.inc(1);
	if (ret % 100000 == 0)
		printf("%ld working vertices\n", ret);
	// A vertex has to have in-edges and out-edges in order to form
	// a triangle. so we can simply skip the vertices that don't have
	// either of them.
	if (vertex->get_num_edges(edge_type::OUT_EDGE) == 0
			|| vertex->get_num_edges(edge_type::IN_EDGE) == 0) {
		long ret = num_completed_vertices.inc(1);
		if (ret % 100000 == 0)
			printf("%ld completed vertices\n", ret);
		return true;
	}

	in_edges = new std::vector<vertex_id_t>();
	out_edges = new std::vector<vertex_id_t>();
	get_required_edges(vertex, edge_type::IN_EDGE, *in_edges);
	get_required_edges(vertex, edge_type::OUT_EDGE, *out_edges);
	num_required = out_edges->size();

	if (in_edges->empty() || out_edges->empty()) {
		num_required = 0;
		long ret = num_completed_vertices.inc(1);
		if (ret % 100000 == 0)
			printf("%ld completed vertices\n", ret);
		delete in_edges;
		delete out_edges;
		in_edges = NULL;
		out_edges = NULL;
		return true;
	}
	else {
		triangles = new std::vector<int>(in_edges->size());
	}
	return false;
}

bool triangle_vertex::run_on_neighbors(graph_engine &graph,
		const page_vertex *vertices[], int num)
{
	num_joined++;
	for (int i = 0; i < num; i++) {
		int ret = count_triangles(vertices[i]);
		// If we find triangles with the neighbor, notify the neighbor
		// as well.
		if (ret > 0) {
			num_pv_triangles.inc(ret);
			count_msg msg(ret);
			graph.send_msg(vertices[i]->get_id(), msg);
		}
	}

	// If we have seen all required neighbors, we have complete
	// the computation. We can release the memory now.
	if (num_joined == num_required) {
		long ret = num_completed_vertices.inc(1);
		if (ret % 100000 == 0)
			printf("%ld completed vertices\n", ret);

		// Inform all neighbors in the in-edges.
		for (size_t i = 0; i < triangles->size(); i++) {
			// Inform the neighbor if they share triangles.
			if (triangles->at(i) > 0) {
				count_msg msg(triangles->at(i));
				graph.send_msg(in_edges->at(i), msg);
			}
		}

		delete triangles;
		delete in_edges;
		delete out_edges;
		in_edges = NULL;
		out_edges = NULL;
		return true;
	}
	return false;
}

void int_handler(int sig_num)
{
	if (!graph_conf.get_prof_file().empty())
		ProfilerStop();
	exit(0);
}

int main(int argc, char *argv[])
{
	if (argc < 5) {
		fprintf(stderr, "triangle-counting conf_file graph_file index_file directed\n");
		graph_conf.print_help();
		params.print_help();
		exit(-1);
	}

	std::string conf_file = argv[1];
	std::string graph_file = argv[2];
	std::string index_file = argv[3];
	bool directed = atoi(argv[4]);

	config_map configs(conf_file);
	configs.add_options(argv + 5, argc - 5);
	graph_conf.init(configs);
	graph_conf.print();

	signal(SIGINT, int_handler);
	init_io_system(configs);

	int min_vertex_size;
	if (directed)
		min_vertex_size = sizeof(ext_mem_directed_vertex);
	else
		min_vertex_size = sizeof(ext_mem_undirected_vertex);

	graph_index *index = graph_index_impl<triangle_vertex>::create(
			index_file, min_vertex_size);
	ext_mem_vertex_interpreter *interpreter;
	if (directed)
		interpreter = new ext_mem_directed_vertex_interpreter();
	else
		interpreter = new ext_mem_undirected_vertex_interpreter();
	graph_engine *graph = graph_engine::create(
			graph_conf.get_num_threads(), params.get_num_nodes(),
			graph_file, index, interpreter, directed);
	graph->set_required_neighbor_type(edge_type::OUT_EDGE);
	printf("triangle counting starts\n");
	printf("prof_file: %s\n", graph_conf.get_prof_file().c_str());
	if (!graph_conf.get_prof_file().empty())
		ProfilerStart(graph_conf.get_prof_file().c_str());

	struct timeval start, end;
	gettimeofday(&start, NULL);
	graph->start_all();
	gettimeofday(&end, NULL);
	float activate_time = time_diff(start, end);

	start = end;
	graph->wait4complete();
	gettimeofday(&end, NULL);

	// Count the total number of triangles in the graph.
	graph_index::const_iterator it = index->begin();
	graph_index::const_iterator end_it = index->end();
	long num_triangles = 0;
	for (; it != end_it; ++it) {
		const triangle_vertex &v = (const triangle_vertex &) *it;
		num_triangles += v.get_num_triangles();
	}

	if (!graph_conf.get_prof_file().empty())
		ProfilerStop();
	if (graph_conf.get_print_io_stat())
		print_io_thread_stat();
	graph_engine::destroy(graph);
	printf("There are %ld vertices\n", index->get_num_vertices());
	printf("process %ld vertices and complete %ld vertices\n",
			num_working_vertices.get(), num_completed_vertices.get());
	printf("there are %ld triangles.\n", num_triangles);
	printf("It takes %f seconds to activate all and %f seconds to finish\n",
			activate_time, time_diff(start, end));
}
<|endoftext|>