--- /dev/null
+# Created by http://gitignore.io
+
+### Linux ###
+.*
+!.gitignore
+!.git*
+*~
+
+### OSX ###
+.DS_Store
+.AppleDouble
+.LSOverride
+Icon
+
+# Thumbnails
+._*
+
+# Files that might appear on external disk
+.Spotlight-V100
+.Trashes
+
+### Windows ###
+# Windows image file caches
+Thumbs.db
+ehthumbs.db
+
+# Folder config file
+Desktop.ini
+
+# Recycle Bin used on file shares
+$RECYCLE.BIN/
+
+### C++ ###
+# Compiled Object files
+*.slo
+*.lo
+*.o
+
+# Compiled Dynamic libraries
+*.so
+*.dylib
+
+# Compiled Static libraries
+*.lai
+*.la
+*.a
+
+### Xcode ###
+*.xcodeproj/*
+
+### Eclipse ###
+*.pydevproject
+.project
+.metadata
+bin/**
+tmp/**
+tmp/**/*
+*.tmp
+*.bak
+*.swp
+*~.nib
+local.properties
+.classpath
+.settings/
+.loadpath
+
+# External tool builders
+.externalToolBuilders/
+
+# Locally stored "Eclipse launch configurations"
+*.launch
+
+# CDT-specific
+.cproject
+
+# PDT-specific
+.buildpath
+
+### VisualStudio ###
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+
+# User-specific files
+*.suo
+*.user
+*.sln.docstates
+
+# Build results
+
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+x64/
+#build/
+[Bb]in/
+[Oo]bj/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+*_i.c
+*_p.c
+*.ilk
+*.meta
+*.obj
+*.pch
+*.pdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*.log
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.log
+*.scc
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opensdf
+*.sdf
+*.cachefile
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# NCrunch
+*.ncrunch*
+.*crunch*.local.xml
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.Publish.xml
+*.pubxml
+
+# NuGet Packages Directory
+## TODO: If you have NuGet Package Restore enabled, uncomment the next line
+#packages/
+
+# Windows Azure Build Output
+csx
+*.build.csdef
+
+# Windows Store app package directory
+AppPackages/
+
+# Others
+sql/
+*.Cache
+ClientBin/
+[Ss]tyle[Cc]op.*
+~$*
+*~
+*.dbmdl
+*.[Pp]ublish.xml
+*.pfx
+*.publishsettings
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file to a newer
+# Visual Studio version. Backup files are not needed, because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+
+# SQL Server files
+App_Data/*.mdf
+App_Data/*.ldf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+
+# =========================
+# Windows detritus
+# =========================
+
+# Windows image file caches
+Thumbs.db
+ehthumbs.db
+
+# Folder config file
+Desktop.ini
+
+# Recycle Bin used on file shares
+$RECYCLE.BIN/
+
+# Mac crap
+.DS_Store
+
+### CMake ###
+CMakeCache.txt
+CMakeFiles
+Makefile
+cmake_install.cmake
+install_manifest.txt
--- /dev/null
+*ビルド方法
+libcore単体でビルドする場合は、ターミナル上で、
+ cd $(LIBCORE_ROOT)
+ make standalone
+
+pnuts/gikomonaとともにビルドする場合は、
+$(GIKOMONA_ROOT)/build/HOW-TO-BUILD.txt を参照してください。
+なお、このビルドによって生成されるライブラリは必ず静的ライブラリ (*.a, *.lib) になります。
+動的ライブラリ (*.so, *.dylib, *.dll) の生成法は用意されていません。
+
+*テスト方法
+libcore単体でテストするときは、ターミナル上で、
+ cd $(LIBCORE_ROOT)
+ make test
+
+pnuts/gikomonaとともにテストする際には、自動でlibcoreのテストも行われるので、
+いちいち指定してテストする必要はありません。
+
+*ビルド後の pnuts/gikomona のフォルダの構造
+
+@ Windows {
+$(GIKOMONA_ROOT)/
+ resource/
+ icon/
+ ...
+ pnuts.xrc (pnuts only)
+ gikomona.xrc(gikomona only)
+
+ doc/
+ README.html
+ LICENSE.html
+
+ pnuts.exe (pnuts only)
+ gikomona.exe (gikomona only)
+ update-utility.exe
+
+ thread/
+ board-list/
+
+ history.db
+ config.xml
+ favorite.xml
+}
+
+@ Linux {
+$(GIKOMONA_ROOT)/
+ resource/
+ doc/
+
+}
+
+@ Mac OS X {
+$(GIKOMONA_ROOT)/
+ Contents/
+ Frameworks/
+ Resources/
+ MacOS/
+ pnuts
+ gikomona
+ update-utility
+ Info.plist
+ version.plist
+ PkgInfo
+}
--- /dev/null
+#ifndef GIKOMONA_CORE_GIKOMONA_HPP
+#define GIKOMONA_CORE_GIKOMONA_HPP
+
+#include <type_traits>
+
+#include <boost/filesystem/path.hpp>
+
+#include "string.hpp"
+
+namespace monazilla { namespace GikoMona {
+
+namespace core {
+
+bool init_core();
+void done_core() noexcept ;
+void optimize_database(const boost::filesystem::path& db_path);
+
+extern void *enabler;
+
+}
+
+} }
+
+/// @breif libbbs で string に関わる typedef を抑制する。@link libbbs/settings.hpp @endlink を見よ。
+#define LIBBBS_PRAGMA_USED_BY_GIKOMONA
+#define LIBSQLITEXX_PRAGMA_USED_BY_GIKOMONA
+
+#define PROJECT_NAME "GikoMona project, powered by monazilla.org."
+#define PROJECT_URL "http://sourceforge.jp/projects/gikomona/"
+
+#endif
--- /dev/null
+#ifndef GIKOMONA_CORE_CONFIG_HPP
+#define GIKOMONA_CORE_CONFIG_HPP
+
+#include <unordered_map>
+
+#include <boost/fusion/include/vector.hpp>
+#include <boost/mpl/bool.hpp>
+#include <boost/any.hpp>
+
+#include "GikoMona.hpp"
+#include "query.hpp"
+
+namespace monazilla { namespace GikoMona { namespace core {
+
+class config final : public query {
+public:
+ typedef config self_type;
+ typedef query base_type;
+
+ config() noexcept {}
+ ~config() {}
+
+ /**
+ * @breif query_concept を満たすクラスはこの関数と同じ型、名前を持つ関数を持っていなければならない。
+ * @retval true insert 操作が成功した
+ * false insert 操作に失敗した
+ * @param[in] into どのテーブルのどの要素に対し insertion query を実行するかを記述する。
+ * 記述の仕方は次の通り:(テーブル名)/[(サブテーブル名)/]*(要素名)
+ * @param[in] value テーブルに対して代入する値を記述する。
+ * @note さらに、最大限 multi-threading な環境を考慮しなければならない。
+ */
+ template <typename T, typename U, typename ...ValueType>
+ bool insert(const mona_string& into,
+ const boost::fusion::vector<T, U, ValueType...>& value) {}
+
+ template <typename T>
+ bool insert(const mona_string& into,
+ const boost::fusion::vector<T>& value) {}
+
+ template <typename T>
+ bool insert(const mona_string& into,
+ const boost::any& value,
+ base_type::enable_if_T_is_U<T, boost::any>*& = enabler) {}
+
+ /**
+ * @brief query_concept を満たすクラスはこの関数と同じ型、名前を持つ関数を持っていなければならない。
+ * @return 引数で指定したテーブルの要素から、テンプレートで指定した方に変換された値が返される。
+ */
+ template <typename T>
+ T select(const mona_string& column,
+ const mona_string& from) const noexcept {}
+
+ template <typename T>
+ boost::any select(const mona_string& column,
+ const mona_string& from,
+ base_type::enable_if_T_is_U<T, boost::any>*& = enabler) const noexcept {}
+
+ template <typename ...ValueType>
+ boost::fusion::vector<ValueType...>
+ select_all(const mona_string& from) const noexcept {}
+private:
+ std::unordered_map<mona_string, boost::any> map;
+};
+
+template <>
+struct is_satisfied_with_query_concept<config> : public boost::mpl::true_ {};
+
+} } }
+
+#endif
--- /dev/null
+#ifndef GIKOMONA_CORE_DATABASE_HPP
+#define GIKOMONA_CORE_DATABASE_HPP
+
+#include <memory>
+
+#include <sqlite3.h>
+
+#include <boost/system/system_error.hpp>
+#include <boost/filesystem.hpp>
+#include <boost/fusion/include/vector.hpp>
+
+#include "GikoMona.hpp"
+#include "query.hpp"
+
+namespace monazilla { namespace GikoMona { namespace core {
+
+class database;
+
+template <typename ReturnTypeList, typename ArgTypeList>
+class sql_executer final {
+ friend database;
+
+ typedef ReturnTypeList result_type;
+ typedef ArgTypeList arg_type;
+ typedef ::sqlite3 *db_object_type;
+ typedef ::sqlite3_stmt *sql_stmt_type;
+
+ const ::sqlite3_stmt *stmt;
+
+ sql_executer(db_object_type db,
+ const sql_stmt_type stmt,
+ boost::system::error_code& ec) noexcept {}
+ ~sql_executer() {}
+
+public:
+ typename <typename T>
+ void bind(const mona_string& param_name, const T& val) {}
+ result_type operator()() {}
+};
+
+class database final : public query {
+public:
+ typedef ::sqlite3 *db_object_type;
+ typedef database self_type;
+ typedef query base_type;
+
+ database() : database("") {}
+
+ /// @brief すでに存在するデータベースファイルを開く。まだファイルが存在しない場合は、新たに作成する。
+ database(const boost::filesystem::path& db_path) {
+ if(db_path.empty()) {
+ is_opened_db = false;
+ } else {
+ if(!boost::filesystem::exists(db_path)) {
+ create(db_path);
+ } else {
+ open(db_path);
+ }
+ }
+ }
+
+ database(const self_type& other) = delete;
+
+ ~database() { close(); }
+
+ /// @brief 受け取った SQL を実行する。ただし、実行できる文は引数と返り値が共に無いものに限られる。
+ /**
+ * @return SQL が正常に実行された場合は true、それ以外の場合は false を返す。
+ * @note この関数は SQL の実行結果を返さない。したがって、実行結果が必要な場合は、
+ * compile_sql() を用いるべきである。
+ */
+ bool run_sql(const mona_string& sql) {
+ return (::sqlite3_exec(db, sql.c_str(), NULL, NULL, NULL) != SQLITE_OK);
+ }
+
+ /// @brief 受け取った SQL を sql_executer へと変換して返す。
+ /**
+ * @note 返された sql_executer を実行することで、ここで渡した SQL の実行結果を得ることができる。
+ * 実行した SQL の実行結果が不要である (あるいはそもそも実行結果が無い) 場合は、
+ * run_sql() を用いるべきである。
+ */
+ template <typename ...T>
+ sql_executer<T...> compile_sql(const mona_string& sql) {
+ /**
+ * @note sqlite3_prepare(db,zSql,nByte,ppStmtpzTail) で nByte に "sql.length() + 1" を
+ * 渡すのはなぜか?詳しくは次を参照 : http://www.sqlite.org/c3ref/prepare.html
+ * ページ中程、"If the nByte argument is less than zero, ~" の先、関係あるところを
+ * かいつまんで訳すと「もしも関数を呼び出した側が、zSql が NULL-terminated な文字列
+ * (\0、\u0 が終端であるような文字列) であることを知っている場合、nByte に文字列のバイト長
+ * (ただしここで言うバイト長には終端文字である\0または\u0も「含んだ」ものである) を渡すことで、
+ * 若干パフォーマンスが上がる」という記述がある。C++のstd::string::length()/size()は文字列の
+ * 終端文字を除いた長さを返すので、わざわざ1を加えている。
+ */
+ int result = ::sqlite3_prepare_v2(db.get_sqlite3_obj(),
+ sql.c_str(),
+ sql.length() + 1,
+ &stmt,
+ NULL);
+ if (result != ::SQLITE_OK && !stmt) {
+
+ } else {
+ return sql_executer<T...>(sql);
+ }
+ }
+
+ /**
+ * @brief
+ * @retval true insert 操作が成功した
+ * false insert 操作に失敗した
+ * @param[in] into どのテーブルのどの要素に対し insertion query を実行するかを記述する。
+ * 記述の仕方は次の通り:(テーブル名)/[(サブテーブル名)/]*(要素名)
+ * @param[in] value テーブルに対して代入する値を記述する。
+ * @note さらに、最大限 multi-threading な環境を考慮しなければならない。
+ */
+ template <typename T, typename U, typename ...ValueType>
+ bool insert(const mona_string& into,
+ const boost::fusion::vector<T, U, ValueType...>& value) {}
+
+ template <typename T>
+ bool insert(const mona_string& into,
+ const boost::fusion::vector<T>& value) {}
+
+ template <typename T>
+ bool insert(const mona_string& into,
+ const boost::any& value,
+ base_type::enable_if_T_is_U<T, boost::any>*& = enabler) {}
+
+ /**
+ * @brief query_concept を満たすクラスはこの関数と同じ型、名前を持つ関数を持っていなければならない。
+ * @return 引数で指定したテーブルの要素から、テンプレートで指定した方に変換された値が返される。
+ */
+ template <typename T>
+ T select(const mona_string& column,
+ const mona_string& from) const noexcept {}
+
+ template <typename T>
+ boost::any select(const mona_string& column,
+ const mona_string& from,
+ base_type::enable_if_T_is_U<T, boost::any>*& = enabler) const noexcept {}
+
+ template <typename ...ValueType>
+ boost::fusion::vector<ValueType...>
+ select_all(const mona_string& from) const noexcept {}
+
+ /// @brief データベースの最適化を行う。
+ /**
+ * @note 内部では以下のコマンドが実行され、データベースの不要データの圧縮と再構築が行われる。
+ * VACUUM; REINDEX;
+ */
+ void optimize() {
+ run_sql("VACUUM;");
+ run_sql("REINDEX;");
+ }
+
+ /// @brief すでに存在するデータベースファイルを開く。
+ bool open(const boost::filesystem::path& db_path) {
+ if (is_opened_db) {
+ close();
+ } else if (!boost::filesystem::exists(db_path)) {
+ is_opened_db = false;
+ return is_opened_db;
+ }
+
+ is_opened_db = (::sqlite3_open(db_path.c_str(), &db) != SQLITE_OK);
+
+ return is_opened_db;
+ }
+
+ /// @brief まだ存在しないデータベースファイルを新たに作成する。
+ /**
+ * @retval true ファイルが存在せず、かつ新たにデータベースファイルを作成することに成功した
+ * false ファイルが存在する、あるいは存在しないが新規データベースファイルの作成に失敗した
+ */
+ bool create(const boost::filesystem::path& db_path) {
+ if(boost::filesystem::exists(db_path)) {
+ return false;
+ }
+
+ return open(db_path);
+ }
+
+ /// @brief 開いていたデータベースファイルを閉じる。
+ void close() noexcept {
+ ::sqlite3_close(db);
+ }
+
+private:
+ db_object_type db;
+ bool is_opened_db;
+
+ void begin_sql_statement() { run_sql("BEGIN;"); }
+ void end_sql_statement() { run_sql("END;"); }
+};
+
+template <>
+struct is_responsible_to_query<database> : public boost::mpl::true_ {};
+
+} } }
+
+#endif
--- /dev/null
+#ifndef GIKOMONA_CORE_EXTENSION_HPP
+#define GIKOMONA_CORE_EXTENSION_HPP
+
+#include <unordered_map>
+#include <functional>
+
+#include <boost/filesystem.hpp>
+
+#include <lua.hpp>
+
+#include "GikoMona.hpp"
+
+namespace monazilla { namespace GikoMona { namespace core {
+
+class extension final {
+public:
+ typedef mona_string extension_id_type;
+ const static extension_id_type inavailable_id = "";
+ typedef extension self_type;
+ typedef ::lua_State* vm_type;
+
+ typedef std::function<void (const vm_type*)> initialize_handler_type;
+ typedef std::function<void () noexcept> finalize_handler_type;
+
+ struct information {
+ const mona_string name;
+ const vm_type lua_obj;
+ bool is_packaged;
+ };
+
+ extension() {
+ if(boost::filesystem::exists(unpacked_extension_path)) {
+ boost::filesystem::create_directories(unpacked_extension_path);
+ }
+ instance = this;
+ }
+
+ ~extension() {
+ boost::system::error_code dummy;
+ boost::filesystem::remove_all(unpacked_extension_path, dummy);
+ }
+
+ static extension *get_instance() { return instance; }
+ void add_initialize_handler(const initialize_handler_type& handler) { init_func = handler; }
+ void add_finalize_handler(const finalize_handler_type& handler) { fin_func = handler; }
+
+ extension_id_type load(const boost::filesystem::path& ext_path) {
+ if(ext_path.get_ext() == "gep") {
+ // エクステンションはパッケージ化されている
+
+ information ext_info = {"", luaL_newstate(), true};
+
+ extension_table[ext_info.name] = ext_info;
+ } else if(ext_path.get_ext() == "gex") {
+ // エクステンションは単体のファイルである
+ } else { return inavailable_id; }
+ }
+private:
+ std::unordered_map<extension_id_type, information> extension_table;
+ const boost::filesystem::path unpacked_extension_path = ".tmp/unpacked-ext";
+ static self_type *instance;
+
+ initialize_handler_type init_func;
+ finalize_handler_type fin_func;
+};
+
+} } }
+
+#endif
--- /dev/null
+#ifndef GIKOMONA_CORE_MODEL_HPP
+#define GIKOMONA_CORE_MODEL_HPP
+
+#include <unistd.h>
+#include <memory>
+
+#include <boost/fusion/include/vector.hpp>
+#include <boost/any.hpp>
+#include <boost/lockfree/queue.hpp>
+#include <boost/filesystem/path.hpp>
+
+#include "GikoMona.hpp"
+#include "query.hpp"
+#include "database.hpp"
+#include "config.hpp"
+
+namespace monazilla { namespace GikoMona { namespace core {
+
+class model : public query {
+public:
+ typedef model self_type;
+ typedef query base_type;
+ typedef boost::fusion::vector<mona_string, boost::any> inserted_value_type;
+ typedef inserted_value_type *inserted_value_triv_copyable_type;
+
+ model() noexcept;
+ ~model();
+
+ static
+ model *get_instance() {
+ return instance;
+ }
+
+ /**
+ * @breif query_concept を満たすクラスはこの関数と同じ型、名前を持つ関数を持っていなければならない。
+ * @retval true insert 操作が成功した
+ * false insert 操作に失敗した
+ * @param[in] into どのテーブルのどの要素に対し insertion query を実行するかを記述する。
+ * 記述の仕方は次の通り:(テーブル名)/[(サブテーブル名)/]*(要素名)
+ * @param[in] value テーブルに対して代入する値を記述する。
+ * @note さらに、最大限 multi-threading な環境を考慮しなければならない。
+ */
+ template <typename T, typename U, typename ...ValueType>
+ bool insert(const mona_string& into,
+ const boost::fusion::vector<T, U, ValueType...>& value) {}
+
+ template <typename T>
+ bool insert(const mona_string& into,
+ const boost::fusion::vector<T>& value) {}
+
+ template <typename T>
+ virtual
+ bool insert(const mona_string& into,
+ const boost::any& value,
+ base_type::enable_if_T_is_U<T, boost::any>*& = enabler) {}
+
+ /**
+ * @brief query_concept を満たすクラスはこの関数と同じ型、名前を持つ関数を持っていなければならない。
+ * @return 引数で指定したテーブルの要素から、テンプレートで指定した方に変換された値が返される。
+ */
+ template <typename T>
+ T select(const mona_string& column,
+ const mona_string& from) const noexcept {}
+
+ template <typename T>
+ boost::any select(const mona_string& column,
+ const mona_string& from,
+ base_type::enable_if_T_is_U<T, boost::any>*& = enabler) const noexcept {}
+
+ template <typename ...ValueType>
+ boost::fusion::vector<ValueType...>
+ select_all(const mona_string& from) const noexcept {}
+
+ void exec_inserted_query();
+ bool load_file(const boost::filesystem::path& file_path,
+ const mona_string& loaded_table_name);
+ bool save_to_file(const boost::filesystem::path& file_path,
+ const mona_string& saved_table_name);
+
+private:
+ void get_object_expressing_into_path_in_query(const mona_string& src,
+ const boost::any& value);
+ void analyze_into_path_in_query(const mona_string& into_path_in_query);
+
+ static self_type *instance;
+ struct model_pimpl;
+
+ std::shared_ptr<model_pimpl> pimpl;
+ boost::lockfree::queue<inserted_value_triv_copyable_type> query_queue;
+};
+
+template <>
+struct is_satisfied_with_query_concept<model> : public boost::mpl::true_ {};
+
+void exec_insert_query() {
+ model::get_instance()->exec_inserted_query();
+}
+
+} } }
+
+#endif
--- /dev/null
+#ifndef GIKOMONA_CORE_QUERY_HPP_INCLUDED
+#define GIKOMONA_CORE_QUERY_HPP_INCLUDED
+
+#include <boost/fusion/include/vector.hpp>
+#include <boost/mpl/bool.hpp>
+
+#include "GikoMona.hpp"
+
+namespace monazilla { namespace GikoMona { namespace core {
+
+template <typename T>
+struct is_satisfied_with_query_concept : public boost::mpl::false_ {};
+
+/**
+ * @brief このクラスは query_concept を満たす全てのクラスが継承しなければならない。
+ */
+class query {
+public:
+ /// query_concept を満たすクラスは自分自身の型を self_type として表明しなければならない。
+ typedef query self_type;
+
+ template <typename T, typename U>
+ using enable_if_T_is_U = typename std::enable_if<std::is_same<T, U>::value>::type;
+
+ /// query_concept を満たすクラスは外部から構築可能でなければならない。
+ query() {}
+ /// query_concept を満たすクラスは外部から解体可能でなければならない。
+ ~query() {}
+
+ /**
+ * @breif query_concept を満たすクラスはこの関数と同じ型、名前を持つ関数を持っていなければならない。
+ * @retval true insert 操作が成功した
+ * false insert 操作に失敗した
+ * @param[in] into どのテーブルのどの要素に対し insertion query を実行するかを記述する。
+ * 記述の仕方は次の通り:(テーブル名)/[(サブテーブル名)/]*(要素名)
+ * @param[in] value テーブルに対して代入する値を記述する。
+ * @note さらに、最大限 multi-threading な環境を考慮しなければならない。
+ */
+ template <typename T, typename U, typename ...ValueType>
+ virtual
+ bool insert(const mona_string& into,
+ const boost::fusion::vector<T, U, ValueType...>& value) override {}
+
+ template <typename T>
+ virtual
+ bool insert(const mona_string& into,
+ const boost::fusion::vector<T>& value) override {}
+
+ template <typename T>
+ virtual
+ bool insert(const mona_string& into,
+ const boost::any& value,
+ enable_if_T_is_U<T, boost::any>*& = enabler) override {}
+
+ /**
+ * @brief query_concept を満たすクラスはこの関数と同じ型、名前を持つ関数を持っていなければならない。
+ * @return 引数で指定したテーブルの要素から、テンプレートで指定した方に変換された値が返される。
+ */
+ template <typename T>
+ virtual
+ T select(const mona_string& column,
+ const mona_string& from) const noexcept override {}
+
+ template <typename T>
+ virtual
+ boost::any select(const mona_string& column,
+ const mona_string& from,
+ enable_if_T_is_U<T, boost::any>*& = enabler) const noexcept override {}
+
+ template <typename ...ValueType>
+ virtual
+ boost::fusion::vector<ValueType...>
+ select_all(const mona_string& from) const noexcept override {}
+};
+
+} } }
+
+#endif
\ No newline at end of file
--- /dev/null
+//
+// string.hpp
+// core
+//
+// Created by caprice on 2013/08/05.
+//
+
+#ifndef GIKOMONA_CORE_STRING_HPP
+#define GIKOMONA_CORE_STRING_HPP
+
+#include <string>
+
+#include <boost/utility/string_ref.hpp>
+
+#include <wx/string.h>
+
+// このコンパイラの char16_t、char32_t を UTF-16/32 を表現するか?
+#if !(__STDC_UTF_16__)
+ #error "[GikoMona.libcore @pp-time] : sorry, this compiler does not support utf-16."
+#endif
+
+#if !(__STDC_UTF_32__)
+ #error "[GikoMona.libcore @pp-time] : sorry, this compiler does not support utf-32."
+#endif
+
+namespace monazilla { namespace GikoMona {
+
+template <typename CharT>
+using basic_string_ref = boost::basic_string_ref<CharT, std::char_traits<CharT>>;
+
+typedef char u8_char;
+typedef std::basic_string<u8_char> u8_string;
+typedef basic_string_ref<u8_char> u8_string_ref;
+
+typedef u8_string mona_string;
+typedef basic_string_ref<u8_char> mona_string_ref;
+
+typedef char sjis_char;
+typedef std::basic_string<sjis_char> sjis_string;
+typedef basic_string_ref<sjis_char> sjis_string_ref;
+
+// to...
+u8_string convert_to_u8(const mona_string_ref& src);
+sjis_string convert_to_sjis(const mona_string_ref& src);
+
+std::u16string convert_to_u16(const mona_string_ref& src);
+std::u32string convert_to_u32(const mona_string_ref& src);
+std::string convert_to_std_str(const mona_string_ref& src);
+std::wstring convert_to_std_wstr(const mona_string_ref& src);
+
+wxString convert_to_wx(const mona_string_ref& src) {
+ return wxString(src.data());
+}
+
+// from...
+mona_string convert_from(const u8_string_ref& src);
+mona_string convert_from(const sjis_string_ref& src);
+
+mona_string convert_from(const basic_string_ref<char16_t>& src);
+mona_string convert_from(const basic_string_ref<char32_t>& src);
+mona_string convert_from(const basic_string_ref<std::string::value_type>& src);
+mona_string convert_from(const basic_string_ref<std::wstring::value_type>& src);
+
+mona_string convert_from(const wxString& src);
+
+// converter
+template <typename Other>
+class converter_impl {
+public:
+ typedef typename Other::value_type char_type;
+ typedef basic_string_ref<char_type> string_ref_type;
+
+ mona_string from(const string_ref_type& src) const { return convert_from(src); }
+};
+
+template <typename Other, bool U8_is_Sjis = std::is_same<u8_string, sjis_string>::value>
+class converter {};
+
+template <>
+class converter <u8_string, false> : public converter_impl<u8_string> {
+public:
+ char_type to(const mona_string_ref& src) const { return convert_to_u8(src); }
+};
+
+template <>
+class converter <sjis_string, false> : public converter_impl<sjis_string> {
+public:
+ char_type to(const mona_string_ref& src) const { return convert_to_sjis(src); }
+};
+
+template <>
+class converter <u8_string, true> : public converter_impl<u8_string> {
+public:
+ char_type to_u8(const mona_string_ref& src) const { return convert_to_u8(src); }
+ char_type to_sjis(const mona_string_ref& src) const { return convert_to_sjis(src); }
+ char_type to(const mona_string_ref&) const {
+ static_assert(false, "std::is_same<u8_string, sjis_string>::value == true.");
+ }
+};
+
+template <bool Value>
+class converter <std::u16string, Value> : public converter_impl<std::u16string> {
+public:
+ char_type to(const mona_string_ref& src) const { return convert_to_u16(src); }
+};
+
+template <bool Value>
+class converter <std::u32string, Value> : public converter_impl<std::u32string> {
+public:
+ char_type to(const mona_string_ref& src) const { return convert_to_u32(src); }
+};
+
+}
+}
+#endif
--- /dev/null
+#include <wx/xrc/xmlres.h>
+#include <exception>
+
+#include <boost/filesystem.hpp>
+
+#include <wx/msgdlg.h>
+
+#include "GikoMona.hpp"
+#include "database.hpp"
+#include "model.hpp"
+
+#include "extension.hpp"
+
+namespace monazilla { namespace GikoMona { namespace core {
+
+namespace {
+
+model *app_model;
+extension *app_extension;
+
+}
+
+bool init_core() {
+ wxXmlResource::Get()->InitAllHandlers();
+ wxXmlResource::Get()->LoadAllFiles(wxT("resouce"));
+
+ boost::system::error_code reason;
+ if(!boost::filesystem::create_directory(".tmp", reason) || reason) {
+ // log
+ std::terminate();
+ }
+
+ app_model = new model;
+ app_extension = new extension;
+
+ return true;
+}
+
+void done_core() noexcept {
+ delete app_extension;
+ delete app_model;
+
+ optimize_database("./history.db");
+}
+
+void optimize_database(const boost::filesystem::path& db_path) {
+ database db(db_path);
+ /*
+ auto value = db.compile(u8"SELECT * FROM file-information;");
+ value.execute();
+ value.get_result<int>();
+ */
+ if(db.select<int>("count-of-deleting-values", "file-infomation") >= 1000) {
+ db.optimize();
+ }
+}
+
+} } }
--- /dev/null
+#include <boost/filesystem/path.hpp>
+
+#include "model.hpp"
+
+namespace monazilla { namespace GikoMona { namespace core {
+
+struct model::model_pimpl {
+ // session/tab-window
+ /* 構造
+ * bbs-name(TEXT)|board-name(TEXT)|thread-id(TEXT)|thread-name(TEXT)|is_fixed(INTEGAR)
+ */
+ database tab_db;
+ // session/history
+ /* 構造
+ * date(TEXT)|bbs-name(TEXT)|board-name(TEXT)|thread-id(TEXT)|thread-name(TEXT)
+ */
+ database history_db;
+ // application
+ config app_config;
+};
+
+model::model() noexcept {
+ instance = this;
+ pimpl = std::make_shared<model_pimpl>();
+
+ auto config_path = pimpl->app_config.select<boost::filesystem::path>("config", "file-path");
+
+ pimpl->tab_db.create(config_path);
+}
+
+model::~model() {}
+
+bool model::load_file(const boost::filesystem::path& file_path,
+ const mona_string& loaded_table_name) {
+ if(!boost::filesystem::exists(file_path)) {
+ return false;
+ }
+
+ return true;
+}
+
+void model::exec_inserted_query() {
+ inserted_value_triv_copyable_type q;
+ if(query_queue.empty()) {
+ return;
+ } else {
+ query_queue.pop(q);
+ }
+
+ mona_string into;
+ boost::any value;
+ std::tie(*q, into, value);
+
+ analyze_into_path_in_query(into);
+
+ if(into.find_first_of("application", 0, into.length()) != mona_string::npos) {
+ // application/*
+ } else if (into.find_first_of("session", 0, into.length()) != mona_string::npos) {
+ // session/*
+ if(into.find("history", 0, into.length()) != mona_string::npos) {
+ ;
+ } else if(into.find("tab-window") != mona_string::npos != mona_string::npos) {
+ pimpl->tab_db.insert(into, tup);
+ }
+ } else if(into.find_first_of("extension", 0, into.length()) != mona_string::npos) {
+ // extension/*
+ } else {
+ // ?
+ }
+}
+
+} } }
--- /dev/null
+#ifndef GIKOMONA_CORE_TEST_QUERY_HPP_INCLUDED
+#define GIKOMONA_CORE_TEST_QUERY_HPP_INCLUDED
+
+#include <type_traits>
+
+#include <boost/test/test_unit.hpp>
+
+#include "../include/query.hpp"
+
+BOOST_AUTO_TEST_SUITE(CORE)
+BOOST_AUTO_TEST_SUITE(query)
+
+namespace gm_core = monazilla::GikoMona::core;
+
+BOOST_AUTO_TEST_SUITE_END // query
+BOOST_AUTO_TEST_SUITE_END // CORE
+
+#endif // GIKOMONA_CORE_TEST_QUERY_HPP_INCLUDED
--- /dev/null
+#define BOOST_TEST_MODULE gikomona_core_test_module
+#include <boost/test/unit_test.hpp>
+
+/**
+ * @note ここでunittestを行う。
+ * テストされる項目は以下の通り:
+ * class query :
+ * trivially-copyable な型であるかどうか
+ * query は selecter の呼び出し順序に従って、query-tree を形成できているか
+ *
+ */