pnuts/gikomonaとともにビルドする場合は、
$(GIKOMONA_ROOT)/build/HOW-TO-BUILD.txt を参照してください。
+なお、このビルドによって生成されるライブラリは必ず静的ライブラリ (*.a, *.lib) になります。
+動的ライブラリ (*.so, *.dylib, *.dll) の生成法は用意されていません。
*テスト方法
libcore単体でテストするときは、ターミナル上で、
*ビルド後の pnuts/gikomona のフォルダの構造
+@ Windows {
$(GIKOMONA_ROOT)/
resource/
icon/
...
-==== pnuts のみ ====
- pnuts.xrc
-
-==== gikomona のみ ====
- gikomona.xrc
+ pnuts.xrc (pnuts only)
+ gikomona.xrc(gikomona only)
doc/
- README.txt
- LICENSE.txt
+ README.html
+ LICENSE.html
+
+ pnuts.exe (pnuts only)
+ gikomona.exe (gikomona only)
+ update-utility.exe
thread/
board-list/
history.db
config.xml
favorite.xml
+}
-==== pnuts のみ ====
- pnuts(.exe)
+@ Linux {
+$(GIKOMONA_ROOT)/
+ resource/
+ doc/
-==== gikomona のみ ====
- twitter/
- gikomona(.exe)
+}
+@ Mac OS X {
+$(GIKOMONA_ROOT)/
+ Contents/
+ Frameworks/
+ Resources/
+ MacOS/
+ pnuts
+ gikomona
+ update-utility
+ Info.plist
+ version.plist
+ PkgInfo
+}
/// @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/"
#ifndef GIKOMONA_CORE_CONFIG_HPP
#define GIKOMONA_CORE_CONFIG_HPP
-#include <tuple>
#include <unordered_map>
+#include <boost/fusion/include/vector.hpp>
#include <boost/mpl/bool.hpp>
#include <boost/any.hpp>
namespace monazilla { namespace GikoMona { namespace core {
-class config final {
+class config final : public query {
public:
typedef config self_type;
+ typedef query base_type;
config() noexcept {}
~config() {}
- template <typename ...ValueType>
- void insert(const mona_string& into,
- const std::tuple<ValueType...>& value) {}
-
+ /**
+ * @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>
- std::tuple<ValueType...>
+ boost::fusion::vector<ValueType...>
select_all(const mona_string& from) const noexcept {}
-
private:
std::unordered_map<mona_string, boost::any> map;
};
#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 final {
-public:
- template <typename T, typename ...U>
- class sql_executer final {
- friend database;
+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(const mona_string& sql) {}
- ~sql_executer() {}
+ sql_executer(db_object_type db,
+ const sql_stmt_type stmt,
+ boost::system::error_code& ec) noexcept {}
+ ~sql_executer() {}
- public:
- void operator()() {}
- };
+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("") {}
~database() { close(); }
- /// @brief 受け取った SQL を実行する。ただし、実行できる文は返り値の無いものに限られる。
+ /// @brief 受け取った SQL を実行する。ただし、実行できる文は引数と返り値が共に無いものに限られる。
/**
* @return SQL が正常に実行された場合は true、それ以外の場合は false を返す。
* @note この関数は SQL の実行結果を返さない。したがって、実行結果が必要な場合は、
* 実行した SQL の実行結果が不要である (あるいはそもそも実行結果が無い) 場合は、
* run_sql() を用いるべきである。
*/
- template <typename T, typename ...U>
- sql_executer<T, U...> compile_sql(const mona_string& sql) {
- return sql_executer<T>(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);
+ }
}
- template <typename ...ValueType>
- void insert(const mona_string& into,
- const std::tuple<ValueType...>& value) {}
+ /**
+ * @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>
- std::tuple<ValueType...>
+ boost::fusion::vector<ValueType...>
select_all(const mona_string& from) const noexcept {}
-
+
/// @brief データベースの最適化を行う。
/**
* @note 内部では以下のコマンドが実行され、データベースの不要データの圧縮と再構築が行われる。
-#ifndef core_extension_hpp
-#define core_extension_hpp
+#ifndef GIKOMONA_CORE_EXTENSION_HPP
+#define GIKOMONA_CORE_EXTENSION_HPP
#include <unordered_map>
#include <functional>
#include <unistd.h>
#include <memory>
-#include <tuple>
+#include <boost/fusion/include/vector.hpp>
#include <boost/any.hpp>
#include <boost/lockfree/queue.hpp>
#include <boost/filesystem/path.hpp>
namespace monazilla { namespace GikoMona { namespace core {
-class model {
+class model : public query {
public:
typedef model self_type;
- typedef std::tuple<mona_string, boost::any> inserted_query_type;
- typedef inserted_query_type *inserted_query_triv_copyable_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();
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 ...ValueType>
+ template <typename T>
bool insert(const mona_string& into,
- const std::tuple<ValueType...>& values) {
- /*
- auto any_value = boost::any(values);
- auto obj = std::make_tuple(into, any_value);
- return inserted_query_queue.push();
- */
- }
+ 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>
- std::tuple<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);
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_query_triv_copyable_type> inserted_query_queue;
+ boost::lockfree::queue<inserted_value_triv_copyable_type> query_queue;
};
template <>
#ifndef GIKOMONA_CORE_QUERY_HPP_INCLUDED
#define GIKOMONA_CORE_QUERY_HPP_INCLUDED
-#include <tuple>
-#include <vector>
-
+#include <boost/fusion/include/vector.hpp>
#include <boost/mpl/bool.hpp>
#include "GikoMona.hpp"
struct is_satisfied_with_query_concept : public boost::mpl::false_ {};
/**
- * @brief ã\81\93ã\81®ã\82¯ã\83©ã\82¹ã\81§ã\81¯ query_concept ã\81\8cæº\80ã\81\9fã\81\99ã\81¹ã\81\8dç\94¨ä»¶ã\81\8cè¨\98è¿°ã\81\95ã\82\8cã\81¦ã\81\84ã\82\8b。
+ * @brief ã\81\93ã\81®ã\82¯ã\83©ã\82¹ã\81¯ query_concept ã\82\92æº\80ã\81\9fã\81\99å\85¨ã\81¦ã\81®ã\82¯ã\83©ã\82¹ã\81\8cç¶\99æ\89¿ã\81\97ã\81ªã\81\91ã\82\8cã\81°ã\81ªã\82\89ã\81ªã\81\84。
*/
-class query_concept final {
+class query {
public:
/// query_concept を満たすクラスは自分自身の型を self_type として表明しなければならない。
- typedef 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_concept() {}
+ query() {}
/// query_concept を満たすクラスは外部から解体可能でなければならない。
- ~query_concept() {}
+ ~query() {}
/**
* @breif query_concept を満たすクラスはこの関数と同じ型、名前を持つ関数を持っていなければならない。
* @note さらに、最大限 multi-threading な環境を考慮しなければならない。
*/
template <typename T, typename U, typename ...ValueType>
+ virtual
bool insert(const mona_string& into,
- const std::tuple<T, U, ValueType...>& value) {}
+ const boost::fusion::vector<T, U, ValueType...>& value) override {}
template <typename T>
+ virtual
bool insert(const mona_string& into,
- const std::tuple<T>& value) {}
+ 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) {}
+ 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 {}
+ 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) {}
+ enable_if_T_is_U<T, boost::any>*& = enabler) const noexcept override {}
template <typename ...ValueType>
- std::tuple<ValueType...>
- select_all(const mona_string& from) const noexcept {}
+ virtual
+ boost::fusion::vector<ValueType...>
+ select_all(const mona_string& from) const noexcept override {}
};
-template <>
-
} } }
#endif
\ No newline at end of file
// Created by caprice on 2013/08/05.
//
-#ifndef core_string_hpp
-#define core_string_hpp
+#ifndef GIKOMONA_CORE_STRING_HPP
+#define GIKOMONA_CORE_STRING_HPP
#include <string>
// このコンパイラの char16_t、char32_t を UTF-16/32 を表現するか?
#if !(__STDC_UTF_16__)
- #error "sorry, this compiler does not support utf-16."
+ #error "[GikoMona.libcore @pp-time] : sorry, this compiler does not support utf-16."
#endif
#if !(__STDC_UTF_32__)
- #error "sorry, this compiler does not support utf-32."
+ #error "[GikoMona.libcore @pp-time] : sorry, this compiler does not support utf-32."
#endif
namespace monazilla { namespace GikoMona {
#include <wx/xrc/xmlres.h>
+#include <exception>
+
+#include <boost/filesystem.hpp>
+
#include <wx/msgdlg.h>
#include "GikoMona.hpp"
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 {
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();
}
+#include <boost/filesystem/path.hpp>
#include "model.hpp"
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()|bbs-name()|board-name()|thread-id()|thread-name()
+ * date(TEXT)|bbs-name(TEXT)|board-name(TEXT)|thread-id(TEXT)|thread-name(TEXT)
*/
database history_db;
// application
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() {}
}
void model::exec_inserted_query() {
- inserted_query_triv_copyable_type q;
- if(inserted_query_queue.empty()) {
+ inserted_value_triv_copyable_type q;
+ if(query_queue.empty()) {
return;
} else {
- inserted_query_queue.pop(q);
+ query_queue.pop(q);
}
mona_string into;
- boost::any tup;
- std::tie(*q, into, tup);
+ 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) {
- pimpl->history_db.insert(into, tup);
+ ;
} else if(into.find("tab-window") != mona_string::npos != mona_string::npos) {
pimpl->tab_db.insert(into, tup);
}
namespace gm_core = monazilla::GikoMona::core;
-BOOST_AUTO_TEST_CASE(type_concept) {
- BOOST_REQUIRE_EQUAL(std::is_trivially_copyable<gm_core::query>::value, true);
-}
-/*
-BOOST_AUTO_TEST_CASE(selecting) {
- BOOST_CHECK_MESSAGE(
- false,
- gm_core::query().define()
- .select(gm_core::all_columnes, "test")
- .dump()
- );
- BOOST_CHECK_MESSAGE(
- false,
- gm_core::query().define()
- .select({"name", "birthday", "mail"}, "test")
- .dump()
- );
-}
-*/
-
-
BOOST_AUTO_TEST_SUITE_END // query
BOOST_AUTO_TEST_SUITE_END // CORE