diff --git a/VCMakefile b/VCMakefile index 45d2cb8..8918bce 100644 --- a/VCMakefile +++ b/VCMakefile @@ -20,7 +20,7 @@ LIBEXECDIR = $(BASEDIR)\bin HEADERFILES = tkrzw_lib_common.h tkrzw_str_util.h tkrzw_hash_util.h tkrzw_time_util.h tkrzw_thread_util.h tkrzw_logger.h tkrzw_compress.h tkrzw_containers.h tkrzw_key_comparators.h tkrzw_file.h tkrzw_file_util.h tkrzw_file_std.h tkrzw_file_mmap.h tkrzw_file_pos.h tkrzw_file_poly.h tkrzw_message_queue.h tkrzw_dbm.h tkrzw_dbm_ulog.h tkrzw_dbm_common_impl.h tkrzw_dbm_hash_impl.h tkrzw_dbm_hash.h tkrzw_dbm_tree_impl.h tkrzw_dbm_tree.h tkrzw_dbm_skip_impl.h tkrzw_dbm_skip.h tkrzw_dbm_tiny.h tkrzw_dbm_baby.h tkrzw_dbm_cache.h tkrzw_dbm_std.h tkrzw_dbm_poly.h tkrzw_dbm_shard.h tkrzw_dbm_async.h tkrzw_index.h tkrzw_cmd_util.h tkrzw_langc.h IMPLHEADERFILES = tkrzw_sys_config.h tkrzw_sys_util_windows.h tkrzw_sys_file_mmap_std.h tkrzw_sys_file_mmap_windows.h tkrzw_sys_file_pos_std.h tkrzw_sys_file_pos_windows.h tkrzw_sys_compress_aes.h LIBRARYFILES = tkrzw.lib -LIBOBJFILES = tkrzw_lib_common.obj tkrzw_str_util.obj tkrzw_hash_util.obj tkrzw_time_util.obj tkrzw_compress.obj tkrzw_file_util.obj tkrzw_file_std.obj tkrzw_file_mmap.obj tkrzw_file_pos.obj tkrzw_file_poly.obj tkrzw_message_queue.obj tkrzw_dbm.obj tkrzw_dbm_ulog.obj tkrzw_dbm_common_impl.obj tkrzw_dbm_hash_impl.obj tkrzw_dbm_hash.obj tkrzw_dbm_tree_impl.obj tkrzw_dbm_tree.obj tkrzw_dbm_skip_impl.obj tkrzw_dbm_skip.obj tkrzw_dbm_tiny.obj tkrzw_dbm_baby.obj tkrzw_dbm_cache.obj tkrzw_dbm_std.obj tkrzw_dbm_poly.obj tkrzw_dbm_shard.obj tkrzw_dbm_async.obj tkrzw_cmd_util.obj tkrzw_langc.obj +LIBOBJFILES = tkrzw_lib_common.obj tkrzw_str_util.obj tkrzw_hash_util.obj tkrzw_time_util.obj tkrzw_compress.obj tkrzw_key_comparators.obj tkrzw_file.obj tkrzw_file_util.obj tkrzw_file_std.obj tkrzw_file_mmap.obj tkrzw_file_pos.obj tkrzw_file_poly.obj tkrzw_message_queue.obj tkrzw_dbm.obj tkrzw_dbm_ulog.obj tkrzw_dbm_common_impl.obj tkrzw_dbm_hash_impl.obj tkrzw_dbm_hash.obj tkrzw_dbm_tree_impl.obj tkrzw_dbm_tree.obj tkrzw_dbm_skip_impl.obj tkrzw_dbm_skip.obj tkrzw_dbm_tiny.obj tkrzw_dbm_baby.obj tkrzw_dbm_cache.obj tkrzw_dbm_std.obj tkrzw_dbm_poly.obj tkrzw_dbm_shard.obj tkrzw_dbm_async.obj tkrzw_cmd_util.obj tkrzw_langc.obj COMMANDFILES = tkrzw_build_util.exe tkrzw_str_perf.exe tkrzw_file_perf.exe tkrzw_dbm_util.exe tkrzw_dbm_perf.exe tkrzw_dbm_tran.exe tkrzw_ulog_util.exe tkrzw_langc_check.exe CMDLIBRARIES = tkrzw.lib EXTRALIBRARIES = diff --git a/configure b/configure index 3701db2..40f19c2 100755 --- a/configure +++ b/configure @@ -2142,7 +2142,7 @@ MYLIBFMT=0 # Targets MYHEADERFILES="tkrzw_lib_common.h tkrzw_str_util.h tkrzw_hash_util.h tkrzw_time_util.h tkrzw_thread_util.h tkrzw_logger.h tkrzw_compress.h tkrzw_containers.h tkrzw_key_comparators.h tkrzw_file.h tkrzw_file_util.h tkrzw_file_std.h tkrzw_file_mmap.h tkrzw_file_pos.h tkrzw_file_poly.h tkrzw_message_queue.h tkrzw_dbm.h tkrzw_dbm_ulog.h tkrzw_dbm_common_impl.h tkrzw_dbm_hash_impl.h tkrzw_dbm_hash.h tkrzw_dbm_tree_impl.h tkrzw_dbm_tree.h tkrzw_dbm_skip_impl.h tkrzw_dbm_skip.h tkrzw_dbm_tiny.h tkrzw_dbm_baby.h tkrzw_dbm_cache.h tkrzw_dbm_std.h tkrzw_dbm_poly.h tkrzw_dbm_shard.h tkrzw_dbm_async.h tkrzw_index.h tkrzw_cmd_util.h tkrzw_langc.h" MYLIBRARYFILES="libtkrzw.a" -MYLIBOBJFILES="tkrzw_lib_common.o tkrzw_str_util.o tkrzw_hash_util.o tkrzw_time_util.o tkrzw_compress.o tkrzw_file_util.o tkrzw_file_std.o tkrzw_file_mmap.o tkrzw_file_pos.o tkrzw_file_poly.o tkrzw_message_queue.o tkrzw_dbm.o tkrzw_dbm_ulog.o tkrzw_dbm_common_impl.o tkrzw_dbm_hash_impl.o tkrzw_dbm_hash.o tkrzw_dbm_tree_impl.o tkrzw_dbm_tree.o tkrzw_dbm_skip_impl.o tkrzw_dbm_skip.o tkrzw_dbm_tiny.o tkrzw_dbm_baby.o tkrzw_dbm_cache.o tkrzw_dbm_std.o tkrzw_dbm_poly.o tkrzw_dbm_shard.o tkrzw_dbm_async.o tkrzw_cmd_util.o tkrzw_langc.o" +MYLIBOBJFILES="tkrzw_lib_common.o tkrzw_str_util.o tkrzw_hash_util.o tkrzw_time_util.o tkrzw_compress.o tkrzw_key_comparators.o tkrzw_file.o tkrzw_file_util.o tkrzw_file_std.o tkrzw_file_mmap.o tkrzw_file_pos.o tkrzw_file_poly.o tkrzw_message_queue.o tkrzw_dbm.o tkrzw_dbm_ulog.o tkrzw_dbm_common_impl.o tkrzw_dbm_hash_impl.o tkrzw_dbm_hash.o tkrzw_dbm_tree_impl.o tkrzw_dbm_tree.o tkrzw_dbm_skip_impl.o tkrzw_dbm_skip.o tkrzw_dbm_tiny.o tkrzw_dbm_baby.o tkrzw_dbm_cache.o tkrzw_dbm_std.o tkrzw_dbm_poly.o tkrzw_dbm_shard.o tkrzw_dbm_async.o tkrzw_cmd_util.o tkrzw_langc.o" MYCOMMANDFILES="tkrzw_build_util tkrzw_str_perf tkrzw_file_perf tkrzw_dbm_util tkrzw_dbm_perf tkrzw_dbm_tran tkrzw_ulog_util tkrzw_langc_check" MYTESTFILES="tkrzw_sys_config_test tkrzw_lib_common_test tkrzw_str_util_test tkrzw_hash_util_test tkrzw_time_util_test tkrzw_thread_util_test tkrzw_logger_test tkrzw_compress_test tkrzw_containers_test tkrzw_key_comparators_test tkrzw_file_util_test tkrzw_file_std_test tkrzw_file_mmap_test tkrzw_file_pos_test tkrzw_file_poly_test tkrzw_message_queue_test tkrzw_dbm_common_impl_test tkrzw_dbm_ulog_test tkrzw_dbm_hash_impl_test tkrzw_dbm_tree_impl_test tkrzw_dbm_tree_test tkrzw_dbm_hash_test tkrzw_dbm_skip_impl_test tkrzw_dbm_skip_test tkrzw_dbm_tiny_test tkrzw_dbm_baby_test tkrzw_dbm_cache_test tkrzw_dbm_std_test tkrzw_dbm_poly_test tkrzw_dbm_shard_test tkrzw_dbm_async_test tkrzw_index_test tkrzw_cmd_util_test tkrzw_langc_test" MYPCFILES="tkrzw.pc" diff --git a/configure.in b/configure.in index 46e6de5..4feef12 100644 --- a/configure.in +++ b/configure.in @@ -15,7 +15,7 @@ MYLIBFMT=0 # Targets MYHEADERFILES="tkrzw_lib_common.h tkrzw_str_util.h tkrzw_hash_util.h tkrzw_time_util.h tkrzw_thread_util.h tkrzw_logger.h tkrzw_compress.h tkrzw_containers.h tkrzw_key_comparators.h tkrzw_file.h tkrzw_file_util.h tkrzw_file_std.h tkrzw_file_mmap.h tkrzw_file_pos.h tkrzw_file_poly.h tkrzw_message_queue.h tkrzw_dbm.h tkrzw_dbm_ulog.h tkrzw_dbm_common_impl.h tkrzw_dbm_hash_impl.h tkrzw_dbm_hash.h tkrzw_dbm_tree_impl.h tkrzw_dbm_tree.h tkrzw_dbm_skip_impl.h tkrzw_dbm_skip.h tkrzw_dbm_tiny.h tkrzw_dbm_baby.h tkrzw_dbm_cache.h tkrzw_dbm_std.h tkrzw_dbm_poly.h tkrzw_dbm_shard.h tkrzw_dbm_async.h tkrzw_index.h tkrzw_cmd_util.h tkrzw_langc.h" MYLIBRARYFILES="libtkrzw.a" -MYLIBOBJFILES="tkrzw_lib_common.o tkrzw_str_util.o tkrzw_hash_util.o tkrzw_time_util.o tkrzw_compress.o tkrzw_file_util.o tkrzw_file_std.o tkrzw_file_mmap.o tkrzw_file_pos.o tkrzw_file_poly.o tkrzw_message_queue.o tkrzw_dbm.o tkrzw_dbm_ulog.o tkrzw_dbm_common_impl.o tkrzw_dbm_hash_impl.o tkrzw_dbm_hash.o tkrzw_dbm_tree_impl.o tkrzw_dbm_tree.o tkrzw_dbm_skip_impl.o tkrzw_dbm_skip.o tkrzw_dbm_tiny.o tkrzw_dbm_baby.o tkrzw_dbm_cache.o tkrzw_dbm_std.o tkrzw_dbm_poly.o tkrzw_dbm_shard.o tkrzw_dbm_async.o tkrzw_cmd_util.o tkrzw_langc.o" +MYLIBOBJFILES="tkrzw_lib_common.o tkrzw_str_util.o tkrzw_hash_util.o tkrzw_time_util.o tkrzw_compress.o tkrzw_key_comparators.o tkrzw_file.o tkrzw_file_util.o tkrzw_file_std.o tkrzw_file_mmap.o tkrzw_file_pos.o tkrzw_file_poly.o tkrzw_message_queue.o tkrzw_dbm.o tkrzw_dbm_ulog.o tkrzw_dbm_common_impl.o tkrzw_dbm_hash_impl.o tkrzw_dbm_tree_impl.o tkrzw_dbm_tree.o tkrzw_dbm_skip_impl.o tkrzw_dbm_skip.o tkrzw_dbm_tiny.o tkrzw_dbm_baby.o tkrzw_dbm_cache.o tkrzw_dbm_std.o tkrzw_dbm_poly.o tkrzw_dbm_shard.o tkrzw_dbm_async.o tkrzw_cmd_util.o tkrzw_langc.o" MYCOMMANDFILES="tkrzw_build_util tkrzw_str_perf tkrzw_file_perf tkrzw_dbm_util tkrzw_dbm_perf tkrzw_dbm_tran tkrzw_ulog_util tkrzw_langc_check" MYTESTFILES="tkrzw_sys_config_test tkrzw_lib_common_test tkrzw_str_util_test tkrzw_hash_util_test tkrzw_time_util_test tkrzw_thread_util_test tkrzw_logger_test tkrzw_compress_test tkrzw_containers_test tkrzw_key_comparators_test tkrzw_file_util_test tkrzw_file_std_test tkrzw_file_mmap_test tkrzw_file_pos_test tkrzw_file_poly_test tkrzw_message_queue_test tkrzw_dbm_common_impl_test tkrzw_dbm_ulog_test tkrzw_dbm_hash_impl_test tkrzw_dbm_tree_impl_test tkrzw_dbm_tree_test tkrzw_dbm_hash_test tkrzw_dbm_skip_impl_test tkrzw_dbm_skip_test tkrzw_dbm_tiny_test tkrzw_dbm_baby_test tkrzw_dbm_cache_test tkrzw_dbm_std_test tkrzw_dbm_poly_test tkrzw_dbm_shard_test tkrzw_dbm_async_test tkrzw_index_test tkrzw_cmd_util_test tkrzw_langc_test" MYPCFILES="tkrzw.pc" diff --git a/tkrzw_compress.cc b/tkrzw_compress.cc index 016f5c7..9fb8a06 100644 --- a/tkrzw_compress.cc +++ b/tkrzw_compress.cc @@ -45,6 +45,12 @@ extern "C" { namespace tkrzw { +const std::type_info& Compressor::GetType() const { + const auto& entity = *this; + return typeid(entity); +} + + DummyCompressor::DummyCompressor(bool checksum) : checksum_(checksum) {} DummyCompressor::~DummyCompressor() {} diff --git a/tkrzw_compress.h b/tkrzw_compress.h index ece9082..d277056 100644 --- a/tkrzw_compress.h +++ b/tkrzw_compress.h @@ -75,10 +75,7 @@ class Compressor { * Gets the type information of the actual class. * @return The type information of the actual class. */ - const std::type_info& GetType() const { - const auto& entity = *this; - return typeid(entity); - } + const std::type_info& GetType() const; }; /** diff --git a/tkrzw_dbm.cc b/tkrzw_dbm.cc index 7624e92..4953116 100644 --- a/tkrzw_dbm.cc +++ b/tkrzw_dbm.cc @@ -26,6 +26,349 @@ const std::string_view DBM::RecordProcessor::NOOP("\x00\xBE\xEF\x02\x11", 5); const std::string_view DBM::RecordProcessor::REMOVE("\x00\xDE\xAD\x02\x11", 5); +std::string_view DBM::RecordProcessor::ProcessFull(std::string_view key, std::string_view value) { + return NOOP; +} + +std::string_view DBM::RecordProcessor::ProcessEmpty(std::string_view key) { + return NOOP; +} + + +DBM::RecordProcessorLambda::RecordProcessorLambda(RecordLambdaType proc_lambda) + : proc_lambda_(proc_lambda) {} + +std::string_view DBM::RecordProcessorLambda::ProcessFull(std::string_view key, std::string_view value) { + return proc_lambda_(key, value); +} + +std::string_view DBM::RecordProcessorLambda::ProcessEmpty(std::string_view key) { + return proc_lambda_(key, NOOP); +} + + +DBM::RecordProcessorGet::RecordProcessorGet(Status* status, std::string* value) + : status_(status), value_(value) {} + +std::string_view DBM::RecordProcessorGet::ProcessFull(std::string_view key, std::string_view value) { + if (value_ != nullptr) { + *value_ = value; + } + return NOOP; +} + + +std::string_view DBM::RecordProcessorGet::ProcessEmpty(std::string_view key) { + status_->Set(Status::NOT_FOUND_ERROR); + return NOOP; +} + +DBM::RecordProcessorSet::RecordProcessorSet(Status* status, std::string_view value, + bool overwrite, std::string* old_value) + : status_(status), value_(value), overwrite_(overwrite), old_value_(old_value) {} + + +std::string_view DBM::RecordProcessorSet::ProcessFull(std::string_view key, std::string_view value) { + if (old_value_ != nullptr) { + *old_value_ = value; + } + if (overwrite_) { + return value_; + } + status_->Set(Status::DUPLICATION_ERROR); + return NOOP; +} + +std::string_view DBM::RecordProcessorSet::ProcessEmpty(std::string_view key) { + return value_; +} + + +DBM::RecordProcessorRemove::RecordProcessorRemove(Status* status, + std::string* old_value) + : status_(status), old_value_(old_value) {} + +std::string_view DBM::RecordProcessorRemove::ProcessFull(std::string_view key, std::string_view value) { + if (old_value_ != nullptr) { + *old_value_ = value; + } + return REMOVE; +} + +std::string_view DBM::RecordProcessorRemove::ProcessEmpty(std::string_view key) { + status_->Set(Status::NOT_FOUND_ERROR); + return NOOP; +} + + +DBM::RecordProcessorAppend::RecordProcessorAppend(std::string_view value, std::string_view delim) + : value_(value), delim_(delim) {} + + +std::string_view DBM::RecordProcessorAppend::ProcessFull(std::string_view key, std::string_view value) { + if (delim_.empty()) { + new_value_.reserve(value.size() + value_.size()); + new_value_.append(value); + new_value_.append(value_); + } else { + new_value_.reserve(value.size() + delim_.size() + value_.size()); + new_value_.append(value); + new_value_.append(delim_); + new_value_.append(value_); + } + return new_value_; +} + +std::string_view DBM::RecordProcessorAppend::ProcessEmpty(std::string_view key) { + return value_; +} + + +DBM::RecordProcessorCompareExchange::RecordProcessorCompareExchange( + Status* status, std::string_view expected, std::string_view desired, std::string* actual, + bool* found) + : status_(status), expected_(expected), desired_(desired), actual_(actual), found_(found) {} + +std::string_view DBM::RecordProcessorCompareExchange::ProcessFull( + std::string_view key, std::string_view value) { + if (actual_ != nullptr) { + *actual_ = value; + } + if (found_ != nullptr) { + *found_ = true; + } + if (expected_.data() != nullptr && (expected_.data() == ANY_DATA.data() || expected_ == value)) { + return desired_.data() == nullptr ? REMOVE : + desired_.data() == ANY_DATA.data() ? NOOP : desired_; + } + status_->Set(Status::INFEASIBLE_ERROR); + return NOOP; +} + +std::string_view DBM::RecordProcessorCompareExchange::ProcessEmpty(std::string_view key) { + if (actual_ != nullptr) { + *actual_ = ""; + } + if (found_ != nullptr) { + *found_ = false; + } + if (expected_.data() == nullptr) { + return desired_.data() == nullptr || desired_.data() == ANY_DATA.data() ? NOOP : desired_; + } + status_->Set(Status::INFEASIBLE_ERROR); + return NOOP; +} + + +DBM::RecordProcessorIncrement::RecordProcessorIncrement(int64_t increment, + int64_t* current, int64_t initial) + : increment_(increment), current_(current), initial_(initial) {} + +std::string_view DBM::RecordProcessorIncrement::ProcessFull(std::string_view key, std::string_view value) { + if (increment_ == INT64MIN) { + if (current_ != nullptr) { + *current_ = StrToIntBigEndian(value); + } + return NOOP; + } + const int64_t num = StrToIntBigEndian(value) + increment_; + if (current_ != nullptr) { + *current_ = num; + } + value_ = IntToStrBigEndian(num); + return value_; +} + +std::string_view DBM::RecordProcessorIncrement::ProcessEmpty(std::string_view key) { + if (increment_ == INT64MIN) { + if (current_ != nullptr) { + *current_ = initial_; + } + return NOOP; + } + const int64_t num = initial_ + increment_; + if (current_ != nullptr) { + *current_ = num; + } + value_ = IntToStrBigEndian(num); + return value_; +} + + +DBM::RecordCheckerCompareExchangeMulti::RecordCheckerCompareExchangeMulti( + bool* noop, std::string_view expected) + : noop_(noop), expected_(expected) {} + +std::string_view DBM::RecordCheckerCompareExchangeMulti::ProcessFull( + std::string_view key, std::string_view value) { + if (expected_.data() == nullptr || (expected_.data() != ANY_DATA.data() && expected_ != value)) { + *noop_ = true; + } + return NOOP; +} + + +std::string_view DBM::RecordCheckerCompareExchangeMulti::ProcessEmpty(std::string_view key) { + if (expected_.data() != nullptr) { + *noop_ = true; + } + return NOOP; +} + + +DBM::RecordSetterCompareExchangeMulti::RecordSetterCompareExchangeMulti( + bool* noop, std::string_view desired) + : noop_(noop), desired_(desired) {} + +std::string_view DBM::RecordSetterCompareExchangeMulti::ProcessFull(std::string_view key, std::string_view value) { + if (*noop_) { + return NOOP; + } + return desired_.data() == nullptr ? REMOVE : desired_; +} + +std::string_view DBM::RecordSetterCompareExchangeMulti::ProcessEmpty(std::string_view key) { + if (*noop_) { + return NOOP; + } + return desired_.data() == nullptr ? NOOP : desired_; +} + + +DBM::RecordCheckerRekey::RecordCheckerRekey(Status* status) : status_(status) {} + +std::string_view DBM::RecordCheckerRekey::ProcessFull(std::string_view key, std::string_view value) { + status_->Set(Status::DUPLICATION_ERROR); + return NOOP; +} + +std::string_view DBM::RecordCheckerRekey::ProcessEmpty(std::string_view key) { + return NOOP; +} + + +DBM::RecordRemoverRekey::RecordRemoverRekey(Status* status, std::string* old_value, bool copying) + : status_(status), old_value_(old_value), copying_(copying) {} + +std::string_view DBM::RecordRemoverRekey::ProcessFull(std::string_view key, std::string_view value) { + if (*status_ != Status::SUCCESS) { + return NOOP; + } + *old_value_ = value; + return copying_ ? NOOP : REMOVE; +} + +std::string_view DBM::RecordRemoverRekey::ProcessEmpty(std::string_view key) { + status_->Set(Status::NOT_FOUND_ERROR); + return NOOP; +} + + +DBM::RecordSetterRekey::RecordSetterRekey(Status* status, const std::string* new_value) + : status_(status), new_value_(new_value) {} + +std::string_view DBM::RecordSetterRekey::ProcessFull(std::string_view key, std::string_view value) { + if (*status_ != Status::SUCCESS) { + return NOOP; + } + return *new_value_; +} + +std::string_view DBM::RecordSetterRekey::ProcessEmpty(std::string_view key) { + if (*status_ != Status::SUCCESS) { + return NOOP; + } + return *new_value_; +} + +DBM::RecordProcessorPopFirst::RecordProcessorPopFirst(std::string* key, std::string* value) + : key_(key), value_(value) {} + +std::string_view DBM::RecordProcessorPopFirst::ProcessFull(std::string_view key, + std::string_view value) { + if (key_ != nullptr) { + *key_ = key; + } + if (value_ != nullptr) { + *value_ = value; + } + return REMOVE; +} + + +DBM::RecordProcessorExport::RecordProcessorExport(Status* status, DBM* dbm) + : status_(status), dbm_(dbm) {} + +std::string_view DBM::RecordProcessorExport::ProcessFull( + std::string_view key, std::string_view value) { + *status_ |= dbm_->Set(key, value); + return NOOP; +} + + +DBM::RecordProcessorIterator::RecordProcessorIterator( + std::string_view new_value, std::string* cur_key, std::string* cur_value) + : new_value_(new_value), cur_key_(cur_key), cur_value_(cur_value) {} + +std::string_view DBM::RecordProcessorIterator::ProcessFull( + std::string_view key, std::string_view value) { + if (cur_key_ != nullptr) { + *cur_key_ = key; + } + if (cur_value_ != nullptr) { + *cur_value_ = value; + } + return new_value_; +} + + +Status DBM::Iterator::Process(RecordLambdaType rec_lambda, bool writable) { + RecordProcessorLambda proc(rec_lambda); + return Process(&proc, writable); +} + +Status DBM::Iterator::Get(std::string* key, std::string* value) { + RecordProcessorIterator proc(RecordProcessor::NOOP, key, value); + return Process(&proc, false); +} + +std::string DBM::Iterator::GetKey(std::string_view default_value) { + std::string key; + return Get(&key, nullptr) == Status::SUCCESS ? key : std::string(default_value); +} + +std::string DBM::Iterator::GetValue(std::string_view default_value) { + std::string value; + return Get(nullptr, &value) == Status::SUCCESS ? value : std::string(default_value); +} + +Status DBM::Iterator::Set(std::string_view value, std::string* old_key, + std::string* old_value) { + RecordProcessorIterator proc(value, old_key, old_value); + return Process(&proc, true); +} + +Status DBM::Iterator::Remove(std::string* old_key, std::string* old_value) { + RecordProcessorIterator proc(RecordProcessor::REMOVE, old_key, old_value); + return Process(&proc, true); +} + +Status DBM::Iterator::Step(std::string* key, std::string* value) { + Status status = Get(key, value); + if (status != Status::SUCCESS) { + return status; + } + status = Next(); + if (status == Status::NOT_FOUND_ERROR) { + status.Set(Status::SUCCESS); + } + return status; +} + + +void DBM::FileProcessor::Process(const std::string& path) {} + + DBM::FileProcessorCopyFileData::FileProcessorCopyFileData( Status* status, const std::string dest_path) : status_(status), dest_path_(dest_path) {} @@ -34,6 +377,336 @@ void DBM::FileProcessorCopyFileData::Process(const std::string& path) { *status_ = tkrzw::CopyFileData(path, dest_path_); } + +Status DBM::UpdateLogger::Synchronize(bool hard) { + return Status(Status::SUCCESS); +} + + +Status DBM::Process(std::string_view key, RecordLambdaType rec_lambda, bool writable) { + RecordProcessorLambda proc(rec_lambda); + return Process(key, &proc, writable); +} + +Status DBM::Get(std::string_view key, std::string* value) { + Status impl_status(Status::SUCCESS); + RecordProcessorGet proc(&impl_status, value); + const Status status = Process(key, &proc, false); + if (status != Status::SUCCESS) { + return status; + } + return impl_status; +} + +std::string DBM::GetSimple(std::string_view key, std::string_view default_value) { + std::string value; + return Get(key, &value) == Status::SUCCESS ? value : std::string(default_value); +} + +Status DBM::GetMulti( + const std::vector& keys, std::map* records) { + Status status(Status::SUCCESS); + for (const auto& key : keys) { + std::string value; + const Status tmp_status = Get(key, &value); + if (tmp_status == Status::SUCCESS) { + records->emplace(key, std::move(value)); + } else { + status |= tmp_status; + } + } + return status; +} + +Status DBM::GetMulti(const std::initializer_list& keys, + std::map* records) { + std::vector vector_keys(keys.begin(), keys.end()); + return GetMulti(vector_keys, records); +} + +Status DBM::GetMulti( + const std::vector& keys, std::map* records) { + return GetMulti(MakeStrViewVectorFromValues(keys), records); +} + +Status DBM::Set(std::string_view key, std::string_view value, bool overwrite, + std::string* old_value) { + Status impl_status(Status::SUCCESS); + RecordProcessorSet proc(&impl_status, value, overwrite, old_value); + const Status status = Process(key, &proc, true); + if (status != Status::SUCCESS) { + return status; + } + return impl_status; +} + +Status DBM::SetMulti( + const std::map& records, bool overwrite) { + Status status(Status::SUCCESS); + for (const auto& record : records) { + status |= Set(record.first, record.second, overwrite); + if (status != Status::SUCCESS && status != Status::DUPLICATION_ERROR) { + break; + } + } + return status; +} + +Status DBM::SetMulti( + const std::initializer_list>& records, + bool overwrite) { + std::map map_records; + for (const auto& record : records) { + map_records.emplace(std::pair( + std::string_view(record.first), std::string_view(record.second))); + } + return SetMulti(map_records, overwrite); +} + +Status DBM::SetMulti( + const std::map& records, bool overwrite) { + return SetMulti(MakeStrViewMapFromRecords(records), overwrite); +} + +Status DBM::Remove(std::string_view key, std::string* old_value) { + Status impl_status(Status::SUCCESS); + RecordProcessorRemove proc(&impl_status, old_value); + const Status status = Process(key, &proc, true); + if (status != Status::SUCCESS) { + return status; + } + return impl_status; +} + +Status DBM::RemoveMulti(const std::vector& keys) { + Status status(Status::SUCCESS); + for (const auto& key : keys) { + status |= Remove(key); + if (status != Status::Status::SUCCESS && status != Status::Status::NOT_FOUND_ERROR) { + break; + } + } + return status; +} + +Status DBM::RemoveMulti(const std::initializer_list& keys) { + std::vector vector_keys(keys.begin(), keys.end()); + return RemoveMulti(vector_keys); +} + +Status DBM::RemoveMulti(const std::vector& keys) { + return RemoveMulti(MakeStrViewVectorFromValues(keys)); +} + +Status DBM::Append( + std::string_view key, std::string_view value, std::string_view delim) { + RecordProcessorAppend proc(value, delim); + return Process(key, &proc, true); +} + +Status DBM::AppendMulti( + const std::map& records, std::string_view delim) { + Status status(Status::SUCCESS); + for (const auto& record : records) { + status |= Append(record.first, record.second, delim); + if (status != Status::SUCCESS) { + break; + } + } + return status; +} + +Status DBM::AppendMulti( + const std::initializer_list>& records, + std::string_view delim) { + std::map map_records; + for (const auto& record : records) { + map_records.emplace(std::pair( + std::string_view(record.first), std::string_view(record.second))); + } + return AppendMulti(map_records, delim); +} + + Status DBM::AppendMulti( + const std::map& records, std::string_view delim) { + return AppendMulti(MakeStrViewMapFromRecords(records), delim); +} + +Status DBM::CompareExchange(std::string_view key, std::string_view expected, + std::string_view desired, std::string* actual, bool* found) { + Status impl_status(Status::SUCCESS); + RecordProcessorCompareExchange proc(&impl_status, expected, desired, actual, found); + const Status status = Process(key, &proc, desired.data() != ANY_DATA.data()); + if (status != Status::SUCCESS) { + return status; + } + return impl_status; +} + +Status DBM::Increment(std::string_view key, int64_t increment, + int64_t* current, int64_t initial) { + RecordProcessorIncrement proc(increment, current, initial); + return Process(key, &proc, increment != INT64MIN); +} + +int64_t DBM::IncrementSimple(std::string_view key, int64_t increment, int64_t initial) { + int64_t current = 0; + return Increment(key, increment, ¤t, initial) == Status::SUCCESS ? current : INT64MIN; +} + +Status DBM::ProcessMulti( + const std::vector>& key_lambda_pairs, + bool writable) { + std::vector> key_proc_pairs; + key_proc_pairs.reserve(key_lambda_pairs.size()); + std::vector procs; + procs.reserve(key_lambda_pairs.size()); + for (const auto& key_lambda : key_lambda_pairs) { + procs.emplace_back(key_lambda.second); + key_proc_pairs.emplace_back(std::make_pair(key_lambda.first, &procs.back())); + } + return ProcessMulti(key_proc_pairs, writable); +} + +Status DBM::CompareExchangeMulti( + const std::vector>& expected, + const std::vector>& desired) { + std::vector> key_proc_pairs; + key_proc_pairs.reserve(expected.size() + desired.size()); + bool noop = false; + std::vector checkers; + checkers.reserve(expected.size()); + for (const auto& key_value : expected) { + checkers.emplace_back(RecordCheckerCompareExchangeMulti(&noop, key_value.second)); + key_proc_pairs.emplace_back(std::pair(key_value.first, &checkers.back())); + } + std::vector setters; + setters.reserve(desired.size()); + for (const auto& key_value : desired) { + setters.emplace_back(RecordSetterCompareExchangeMulti(&noop, key_value.second)); + key_proc_pairs.emplace_back(std::pair(key_value.first, &setters.back())); + } + const Status status = ProcessMulti(key_proc_pairs, true); + if (status != Status::SUCCESS) { + return status; + } + return noop ? Status(Status::INFEASIBLE_ERROR) : Status(Status::SUCCESS); +} + +Status DBM::Rekey(std::string_view old_key, std::string_view new_key, + bool overwrite, bool copying, std::string* value) { + std::vector> key_proc_pairs; + key_proc_pairs.reserve(3); + Status proc_status(Status::SUCCESS); + RecordCheckerRekey checker(&proc_status); + if (!overwrite) { + key_proc_pairs.emplace_back(std::pair(new_key, &checker)); + } + std::string rec_value; + RecordRemoverRekey remover(&proc_status, &rec_value, copying); + key_proc_pairs.emplace_back(std::pair(old_key, &remover)); + RecordSetterRekey setter(&proc_status, &rec_value); + key_proc_pairs.emplace_back(std::pair(new_key, &setter)); + const Status status = ProcessMulti(key_proc_pairs, true); + if (status != Status::SUCCESS) { + return status; + } + if (proc_status == Status::SUCCESS && value != nullptr) { + *value = std::move(rec_value); + } + return proc_status; +} + +Status DBM::ProcessFirst(RecordLambdaType rec_lambda, bool writable) { + RecordProcessorLambda proc(rec_lambda); + return ProcessFirst(&proc, writable); +} + +Status DBM::PopFirst(std::string* key, std::string* value) { + RecordProcessorPopFirst proc(key, value); + return ProcessFirst(&proc, true); +} + +Status DBM::PushLast(std::string_view value, double wtime, std::string* key) { + for (uint64_t seq = 0; true; seq++) { + const uint64_t timestamp = + static_cast((wtime < 0 ? GetWallTime() : wtime) * 100000000 + seq); + const std::string& time_key = IntToStrBigEndian(timestamp); + const Status status = Set(time_key, value, false); + if (status != Status::DUPLICATION_ERROR) { + if (key != nullptr) { + *key = time_key; + } + return status; + } + } + return Status(Status::UNKNOWN_ERROR); +} + +Status DBM::ProcessEach(RecordLambdaType rec_lambda, bool writable) { + RecordProcessorLambda proc(rec_lambda); + return ProcessEach(&proc, writable); +} + +int64_t DBM::CountSimple() { + int64_t count = 0; + return Count(&count) == Status::SUCCESS ? count : -1; +} + +int64_t DBM::GetFileSizeSimple() { + int64_t size = 0; + return GetFileSize(&size) == Status::SUCCESS ? size : -1; +} + +std::string DBM::GetFilePathSimple() { + std::string path; + return GetFilePath(&path) == Status::SUCCESS ? path : std::string(""); +} + +double DBM::GetTimestampSimple() { + double timestamp = 0; + return GetTimestamp(×tamp) == Status::SUCCESS ? timestamp : DOUBLENAN; +} + +bool DBM::ShouldBeRebuiltSimple() { + bool tobe = false; + return ShouldBeRebuilt(&tobe) == Status::SUCCESS ? tobe : false; +} + +Status DBM::CopyFileData(const std::string& dest_path, bool sync_hard) { + Status impl_status(Status::SUCCESS); + FileProcessorCopyFileData proc(&impl_status, dest_path); + if (IsWritable()) { + const Status status = Synchronize(sync_hard, &proc); + if (status != Status::SUCCESS) { + return status; + } + } else { + std::string path; + const Status status = GetFilePath(&path); + if (status != Status::SUCCESS) { + return status; + } + proc.Process(path); + } + return impl_status; +} + +Status DBM::Export(DBM* dest_dbm) { + Status impl_status(Status::SUCCESS); + RecordProcessorExport proc(&impl_status, dest_dbm); + const Status status = ProcessEach(&proc, false); + if (status != Status::SUCCESS) { + return status; + } + return impl_status; +} + +const std::type_info& DBM::GetType() const { + const auto& entity = *this; + return typeid(entity); +} + } // namespace tkrzw // END OF FILE diff --git a/tkrzw_dbm.h b/tkrzw_dbm.h index 61d13d2..ec61d3f 100644 --- a/tkrzw_dbm.h +++ b/tkrzw_dbm.h @@ -72,9 +72,7 @@ class DBM { * @details The memory referred to by the return value must be alive until the end of * the life-span of this object or until this function is called next time. */ - virtual std::string_view ProcessFull(std::string_view key, std::string_view value) { - return NOOP; - } + virtual std::string_view ProcessFull(std::string_view key, std::string_view value); /** * Processes an empty record space. @@ -83,9 +81,7 @@ class DBM { * @details The memory referred to by the return value must be alive until the end of * the life-span of this object or until this function is called next time. */ - virtual std::string_view ProcessEmpty(std::string_view key) { - return NOOP; - } + virtual std::string_view ProcessEmpty(std::string_view key); }; /** @@ -105,21 +101,17 @@ class DBM { * Constructor. * @param proc_lambda A lambda function to process a record. */ - explicit RecordProcessorLambda(RecordLambdaType proc_lambda) : proc_lambda_(proc_lambda) {} + explicit RecordProcessorLambda(RecordLambdaType proc_lambda); /** * Processes an existing record. */ - std::string_view ProcessFull(std::string_view key, std::string_view value) override { - return proc_lambda_(key, value); - } + std::string_view ProcessFull(std::string_view key, std::string_view value) override; /** * Processes an empty record space. */ - std::string_view ProcessEmpty(std::string_view key) override { - return proc_lambda_(key, NOOP); - } + std::string_view ProcessEmpty(std::string_view key) override; private: // Lambda function to process a record. @@ -136,25 +128,17 @@ class DBM { * @param status The pointer to a status object to contain the result status. * @param value The pointer to a string object to contain the result value. */ - RecordProcessorGet(Status* status, std::string* value) : status_(status), value_(value) {} + RecordProcessorGet(Status* status, std::string* value); /** * Processes an existing record. */ - std::string_view ProcessFull(std::string_view key, std::string_view value) override { - if (value_ != nullptr) { - *value_ = value; - } - return NOOP; - } + std::string_view ProcessFull(std::string_view key, std::string_view value) override; /** * Processes an empty record space. */ - std::string_view ProcessEmpty(std::string_view key) override { - status_->Set(Status::NOT_FOUND_ERROR); - return NOOP; - } + std::string_view ProcessEmpty(std::string_view key) override; private: /** Status to report. */ @@ -176,29 +160,17 @@ class DBM { * @param old_value The pointer to a string object to contain the existing value. */ RecordProcessorSet(Status* status, std::string_view value, bool overwrite, - std::string* old_value) - : status_(status), value_(value), overwrite_(overwrite), old_value_(old_value) {} + std::string* old_value); /** * Processes an existing record. */ - std::string_view ProcessFull(std::string_view key, std::string_view value) override { - if (old_value_ != nullptr) { - *old_value_ = value; - } - if (overwrite_) { - return value_; - } - status_->Set(Status::DUPLICATION_ERROR); - return NOOP; - } + std::string_view ProcessFull(std::string_view key, std::string_view value) override; /** * Processes an empty record space. */ - std::string_view ProcessEmpty(std::string_view key) override { - return value_; - } + std::string_view ProcessEmpty(std::string_view key) override; private: /** Status to report. */ @@ -221,26 +193,17 @@ class DBM { * @param status The pointer to a status object to contain the result status. * @param old_value The pointer to a string object to contain the existing value. */ - explicit RecordProcessorRemove(Status* status, std::string* old_value) - : status_(status), old_value_(old_value) {} + explicit RecordProcessorRemove(Status* status, std::string* old_value); /** * Processes an existing record. */ - std::string_view ProcessFull(std::string_view key, std::string_view value) override { - if (old_value_ != nullptr) { - *old_value_ = value; - } - return REMOVE; - } + std::string_view ProcessFull(std::string_view key, std::string_view value) override; /** * Processes an empty record space. */ - std::string_view ProcessEmpty(std::string_view key) override { - status_->Set(Status::NOT_FOUND_ERROR); - return NOOP; - } + std::string_view ProcessEmpty(std::string_view key) override; private: /** Status to report. */ @@ -259,32 +222,17 @@ class DBM { * @param value A string of the value to set. * @param delim A string of the delimiter. */ - RecordProcessorAppend(std::string_view value, std::string_view delim) - : value_(value), delim_(delim) {} + RecordProcessorAppend(std::string_view value, std::string_view delim); /** * Processes an existing record. */ - std::string_view ProcessFull(std::string_view key, std::string_view value) override { - if (delim_.empty()) { - new_value_.reserve(value.size() + value_.size()); - new_value_.append(value); - new_value_.append(value_); - } else { - new_value_.reserve(value.size() + delim_.size() + value_.size()); - new_value_.append(value); - new_value_.append(delim_); - new_value_.append(value_); - } - return new_value_; - } + std::string_view ProcessFull(std::string_view key, std::string_view value) override; /** * Processes an empty record space. */ - std::string_view ProcessEmpty(std::string_view key) override { - return value_; - } + std::string_view ProcessEmpty(std::string_view key) override; private: /** Value to store. */ @@ -311,46 +259,17 @@ class DBM { * it is nullptr, it is ignored. */ RecordProcessorCompareExchange(Status* status, std::string_view expected, - std::string_view desired, std::string* actual, bool* found) - : status_(status), expected_(expected), desired_(desired), - actual_(actual), found_(found) {} + std::string_view desired, std::string* actual, bool* found); /** * Processes an existing record. */ - std::string_view ProcessFull(std::string_view key, std::string_view value) override { - if (actual_ != nullptr) { - *actual_ = value; - } - if (found_ != nullptr) { - *found_ = true; - } - if (expected_.data() != nullptr && - (expected_.data() == ANY_DATA.data() || expected_ == value)) { - return desired_.data() == nullptr ? REMOVE : - desired_.data() == ANY_DATA.data() ? NOOP : desired_; - } - status_->Set(Status::INFEASIBLE_ERROR); - return NOOP; - } + std::string_view ProcessFull(std::string_view key, std::string_view value) override; /** * Processes an empty record space. */ - std::string_view ProcessEmpty(std::string_view key) override { - if (actual_ != nullptr) { - *actual_ = ""; - } - if (found_ != nullptr) { - *found_ = false; - } - if (expected_.data() == nullptr) { - return desired_.data() == nullptr || desired_.data() == ANY_DATA.data() ? - NOOP : desired_; - } - status_->Set(Status::INFEASIBLE_ERROR); - return NOOP; - } + std::string_view ProcessEmpty(std::string_view key) override; private: /** Status to report. */ @@ -376,44 +295,17 @@ class DBM { * @param current The pointer to a string object to contain the current value. * @param initial The initial value. */ - RecordProcessorIncrement(int64_t increment, int64_t* current, int64_t initial) - : increment_(increment), current_(current), initial_(initial) {} + RecordProcessorIncrement(int64_t increment, int64_t* current, int64_t initial); /** * Processes an existing record. */ - std::string_view ProcessFull(std::string_view key, std::string_view value) override { - if (increment_ == INT64MIN) { - if (current_ != nullptr) { - *current_ = StrToIntBigEndian(value); - } - return NOOP; - } - const int64_t num = StrToIntBigEndian(value) + increment_; - if (current_ != nullptr) { - *current_ = num; - } - value_ = IntToStrBigEndian(num); - return value_; - } + std::string_view ProcessFull(std::string_view key, std::string_view value) override; /** * Processes an empty record space. */ - std::string_view ProcessEmpty(std::string_view key) override { - if (increment_ == INT64MIN) { - if (current_ != nullptr) { - *current_ = initial_; - } - return NOOP; - } - const int64_t num = initial_ + increment_; - if (current_ != nullptr) { - *current_ = num; - } - value_ = IntToStrBigEndian(num); - return value_; - } + std::string_view ProcessEmpty(std::string_view key) override; private: /** The incrementing value. */ @@ -436,29 +328,17 @@ class DBM { * @param noop Whether to do no operation. * @param expected A string of the expected value. */ - RecordCheckerCompareExchangeMulti(bool* noop, std::string_view expected) - : noop_(noop), expected_(expected) {} + RecordCheckerCompareExchangeMulti(bool* noop, std::string_view expected); /** * Processes an existing record. */ - std::string_view ProcessFull(std::string_view key, std::string_view value) override { - if (expected_.data() == nullptr || - (expected_.data() != ANY_DATA.data() && expected_ != value)) { - *noop_ = true; - } - return NOOP; - } + std::string_view ProcessFull(std::string_view key, std::string_view value) override; /** * Processes an empty record space. */ - std::string_view ProcessEmpty(std::string_view key) override { - if (expected_.data() != nullptr) { - *noop_ = true; - } - return NOOP; - } + std::string_view ProcessEmpty(std::string_view key) override; private: /** Whether to do no operation. */ @@ -477,28 +357,17 @@ class DBM { * @param noop True to do no operation. * @param desired A string of the expected value. */ - RecordSetterCompareExchangeMulti(bool* noop, std::string_view desired) - : noop_(noop), desired_(desired) {} + RecordSetterCompareExchangeMulti(bool* noop, std::string_view desired); /** * Processes an existing record. */ - std::string_view ProcessFull(std::string_view key, std::string_view value) override { - if (*noop_) { - return NOOP; - } - return desired_.data() == nullptr ? REMOVE : desired_; - } + std::string_view ProcessFull(std::string_view key, std::string_view value) override; /** * Processes an empty record space. */ - std::string_view ProcessEmpty(std::string_view key) override { - if (*noop_) { - return NOOP; - } - return desired_.data() == nullptr ? NOOP : desired_; - } + std::string_view ProcessEmpty(std::string_view key) override; private: /** Whether to do no operation. */ @@ -516,22 +385,17 @@ class DBM { * Constructor. * @param status The pointer to a status object. */ - RecordCheckerRekey(Status* status) : status_(status) {} + RecordCheckerRekey(Status* status); /** * Processes an existing record. */ - std::string_view ProcessFull(std::string_view key, std::string_view value) override { - status_->Set(Status::DUPLICATION_ERROR); - return NOOP; - } + std::string_view ProcessFull(std::string_view key, std::string_view value) override; /** * Processes an empty record space. */ - std::string_view ProcessEmpty(std::string_view key) override { - return NOOP; - } + std::string_view ProcessEmpty(std::string_view key) override; private: /** The pointer to a status object. */ @@ -549,27 +413,17 @@ class DBM { * @param old_value The pointer to a string object to store the old value. * @param copying Whether to retain the record of the old key. */ - RecordRemoverRekey(Status* status, std::string* old_value, bool copying) - : status_(status), old_value_(old_value), copying_(copying) {} + RecordRemoverRekey(Status* status, std::string* old_value, bool copying); /** * Processes an existing record. */ - std::string_view ProcessFull(std::string_view key, std::string_view value) override { - if (*status_ != Status::SUCCESS) { - return NOOP; - } - *old_value_ = value; - return copying_ ? NOOP : REMOVE; - } + std::string_view ProcessFull(std::string_view key, std::string_view value) override; /** * Processes an empty record space. */ - std::string_view ProcessEmpty(std::string_view key) override { - status_->Set(Status::NOT_FOUND_ERROR); - return NOOP; - } + std::string_view ProcessEmpty(std::string_view key) override; private: /** The pointer to a status object. */ @@ -590,28 +444,17 @@ class DBM { * @param status The pointer to a status object. * @param new_value The pointer to a string object to store the old value. */ - RecordSetterRekey(Status* status, const std::string* new_value) - : status_(status), new_value_(new_value) {} + RecordSetterRekey(Status* status, const std::string* new_value); /** * Processes an existing record. */ - std::string_view ProcessFull(std::string_view key, std::string_view value) override { - if (*status_ != Status::SUCCESS) { - return NOOP; - } - return *new_value_; - } + std::string_view ProcessFull(std::string_view key, std::string_view value) override; /** * Processes an empty record space. */ - std::string_view ProcessEmpty(std::string_view key) override { - if (*status_ != Status::SUCCESS) { - return NOOP; - } - return *new_value_; - } + std::string_view ProcessEmpty(std::string_view key) override; private: /** The pointer to a status object. */ @@ -630,21 +473,12 @@ class DBM { * @param key The pointer to a string object to contain the existing value. * @param value The pointer to a string object to contain the existing value. */ - explicit RecordProcessorPopFirst(std::string* key, std::string* value) - : key_(key), value_(value) {} + explicit RecordProcessorPopFirst(std::string* key, std::string* value); /** * Processes an existing record. */ - std::string_view ProcessFull(std::string_view key, std::string_view value) override { - if (key_ != nullptr) { - *key_ = key; - } - if (value_ != nullptr) { - *value_ = value; - } - return REMOVE; - } + std::string_view ProcessFull(std::string_view key, std::string_view value) override; private: /** String to store the key. */ @@ -661,15 +495,12 @@ class DBM { /** * Constructor. */ - RecordProcessorExport(Status* status, DBM* dbm) : status_(status), dbm_(dbm) {} + RecordProcessorExport(Status* status, DBM* dbm); /** * Processes an existing record. */ - std::string_view ProcessFull(std::string_view key, std::string_view value) override { - *status_ |= dbm_->Set(key, value); - return NOOP; - } + std::string_view ProcessFull(std::string_view key, std::string_view value) override; private: /** Status to report. */ @@ -690,21 +521,12 @@ class DBM { * @param cur_value The pointer to a string object to contain the current value. */ RecordProcessorIterator( - std::string_view new_value, std::string* cur_key, std::string* cur_value) - : new_value_(new_value), cur_key_(cur_key), cur_value_(cur_value) {} + std::string_view new_value, std::string* cur_key, std::string* cur_value); /** * Processes an existing record. */ - std::string_view ProcessFull(std::string_view key, std::string_view value) override { - if (cur_key_ != nullptr) { - *cur_key_ = key; - } - if (cur_value_ != nullptr) { - *cur_value_ = value; - } - return new_value_; - } + std::string_view ProcessFull(std::string_view key, std::string_view value) override; private: /** The new value returned to the database. */ @@ -806,10 +628,7 @@ class DBM { * @param writable True if the processor can edit the record. * @return The result status. */ - virtual Status Process(RecordLambdaType rec_lambda, bool writable) { - RecordProcessorLambda proc(rec_lambda); - return Process(&proc, writable); - } + virtual Status Process(RecordLambdaType rec_lambda, bool writable); /** * Gets the key and the value of the current record of the iterator. @@ -819,30 +638,21 @@ class DBM { * the value data is ignored. * @return The result status. */ - virtual Status Get(std::string* key = nullptr, std::string* value = nullptr) { - RecordProcessorIterator proc(RecordProcessor::NOOP, key, value); - return Process(&proc, false); - } + virtual Status Get(std::string* key = nullptr, std::string* value = nullptr); /** * Gets the key of the current record, in a simple way. * @param default_value The value to be returned on failure. * @return The key of the current record on success, or the default value on failure. */ - virtual std::string GetKey(std::string_view default_value = "") { - std::string key; - return Get(&key, nullptr) == Status::SUCCESS ? key : std::string(default_value); - } + virtual std::string GetKey(std::string_view default_value = ""); /** * Gets the value of the current record, in a simple way. * @param default_value The value to be returned on failure. * @return The value of the current record on success, or the default value on failure. */ - virtual std::string GetValue(std::string_view default_value = "") { - std::string value; - return Get(nullptr, &value) == Status::SUCCESS ? value : std::string(default_value); - } + virtual std::string GetValue(std::string_view default_value = ""); /** * Sets the value of the current record. @@ -854,10 +664,7 @@ class DBM { * @return The result status. */ virtual Status Set(std::string_view value, std::string* old_key = nullptr, - std::string* old_value = nullptr) { - RecordProcessorIterator proc(value, old_key, old_value); - return Process(&proc, true); - } + std::string* old_value = nullptr); /** * Removes the current record. @@ -868,10 +675,7 @@ class DBM { * @return The result status. * @details If possible, the iterator moves to the next record. */ - virtual Status Remove(std::string* old_key = nullptr, std::string* old_value = nullptr) { - RecordProcessorIterator proc(RecordProcessor::REMOVE, old_key, old_value); - return Process(&proc, true); - } + virtual Status Remove(std::string* old_key = nullptr, std::string* old_value = nullptr); /** * Gets the current record and moves the iterator to the next record. @@ -881,17 +685,7 @@ class DBM { * the value data is ignored. * @return The result status. */ - virtual Status Step(std::string* key = nullptr, std::string* value = nullptr) { - Status status = Get(key, value); - if (status != Status::SUCCESS) { - return status; - } - status = Next(); - if (status == Status::NOT_FOUND_ERROR) { - status.Set(Status::SUCCESS); - } - return status; - } + virtual Status Step(std::string* key = nullptr, std::string* value = nullptr); }; /** @@ -908,7 +702,7 @@ class DBM { * Process a file. * @param path The path of the file. */ - virtual void Process(const std::string& path) {} + virtual void Process(const std::string& path); }; /** @@ -976,9 +770,7 @@ class DBM { * @return The result status. * @details This is called by the Synchronize method. */ - virtual Status Synchronize(bool hard) { - return Status(Status::SUCCESS); - } + virtual Status Synchronize(bool hard); }; /** @@ -1023,10 +815,7 @@ class DBM { * @param writable True if the processor can edit the record. * @return The result status. */ - virtual Status Process(std::string_view key, RecordLambdaType rec_lambda, bool writable) { - RecordProcessorLambda proc(rec_lambda); - return Process(key, &proc, writable); - } + virtual Status Process(std::string_view key, RecordLambdaType rec_lambda, bool writable); /** * Gets the value of a record of a key. @@ -1035,15 +824,7 @@ class DBM { * the value data is ignored. * @return The result status. If there's no matching record, NOT_FOUND_ERROR is returned. */ - virtual Status Get(std::string_view key, std::string* value = nullptr) { - Status impl_status(Status::SUCCESS); - RecordProcessorGet proc(&impl_status, value); - const Status status = Process(key, &proc, false); - if (status != Status::SUCCESS) { - return status; - } - return impl_status; - } + virtual Status Get(std::string_view key, std::string* value = nullptr); /** * Gets the value of a record of a key, in a simple way. @@ -1051,10 +832,7 @@ class DBM { * @param default_value The value to be returned on failure. * @return The value of the matching record on success, or the default value on failure. */ - virtual std::string GetSimple(std::string_view key, std::string_view default_value = "") { - std::string value; - return Get(key, &value) == Status::SUCCESS ? value : std::string(default_value); - } + virtual std::string GetSimple(std::string_view key, std::string_view default_value = ""); /** * Gets the values of multiple records of keys, with a string view vector. @@ -1066,19 +844,7 @@ class DBM { * code, the result map can have elements. */ virtual Status GetMulti( - const std::vector& keys, std::map* records) { - Status status(Status::SUCCESS); - for (const auto& key : keys) { - std::string value; - const Status tmp_status = Get(key, &value); - if (tmp_status == Status::SUCCESS) { - records->emplace(key, std::move(value)); - } else { - status |= tmp_status; - } - } - return status; - } + const std::vector& keys, std::map* records); /** * Gets the values of multiple records of keys, with an initializer list. @@ -1090,10 +856,7 @@ class DBM { * code, the result map can have elements. */ virtual Status GetMulti(const std::initializer_list& keys, - std::map* records) { - std::vector vector_keys(keys.begin(), keys.end()); - return GetMulti(vector_keys, records); - } + std::map* records); /** * Gets the values of multiple records of keys, with a string vector. @@ -1105,9 +868,7 @@ class DBM { * code, the result map can have elements. */ virtual Status GetMulti( - const std::vector& keys, std::map* records) { - return GetMulti(MakeStrViewVectorFromValues(keys), records); - } + const std::vector& keys, std::map* records); /** * Sets a record of a key and a value. @@ -1121,15 +882,7 @@ class DBM { * @return The result status. If overwriting is abandoned, DUPLICATION_ERROR is returned. */ virtual Status Set(std::string_view key, std::string_view value, bool overwrite = true, - std::string* old_value = nullptr) { - Status impl_status(Status::SUCCESS); - RecordProcessorSet proc(&impl_status, value, overwrite, old_value); - const Status status = Process(key, &proc, true); - if (status != Status::SUCCESS) { - return status; - } - return impl_status; - } + std::string* old_value = nullptr); /** * Sets multiple records, with a map of string views. @@ -1141,16 +894,7 @@ class DBM { * is returned. */ virtual Status SetMulti( - const std::map& records, bool overwrite = true) { - Status status(Status::SUCCESS); - for (const auto& record : records) { - status |= Set(record.first, record.second, overwrite); - if (status != Status::SUCCESS && status != Status::DUPLICATION_ERROR) { - break; - } - } - return status; - } + const std::map& records, bool overwrite = true); /** * Sets multiple records, with an initializer list. @@ -1163,14 +907,7 @@ class DBM { */ virtual Status SetMulti( const std::initializer_list>& records, - bool overwrite = true) { - std::map map_records; - for (const auto& record : records) { - map_records.emplace(std::pair( - std::string_view(record.first), std::string_view(record.second))); - } - return SetMulti(map_records, overwrite); - } + bool overwrite = true); /** * Sets multiple records, with a map of strings. @@ -1182,9 +919,7 @@ class DBM { * is returned. */ virtual Status SetMulti( - const std::map& records, bool overwrite = true) { - return SetMulti(MakeStrViewMapFromRecords(records), overwrite); - } + const std::map& records, bool overwrite = true); /** * Removes a record of a key. @@ -1193,50 +928,28 @@ class DBM { * it is ignored. * @return The result status. If there's no matching record, NOT_FOUND_ERROR is returned. */ - virtual Status Remove(std::string_view key, std::string* old_value = nullptr) { - Status impl_status(Status::SUCCESS); - RecordProcessorRemove proc(&impl_status, old_value); - const Status status = Process(key, &proc, true); - if (status != Status::SUCCESS) { - return status; - } - return impl_status; - } + virtual Status Remove(std::string_view key, std::string* old_value = nullptr); /** * Removes records of keys, with a string view vector. * @param keys The keys of records to remove. * @return The result status. If there are missing records, NOT_FOUND_ERROR is returned. */ - virtual Status RemoveMulti(const std::vector& keys) { - Status status(Status::SUCCESS); - for (const auto& key : keys) { - status |= Remove(key); - if (status != Status::Status::SUCCESS && status != Status::Status::NOT_FOUND_ERROR) { - break; - } - } - return status; - } + virtual Status RemoveMulti(const std::vector& keys); /** * Removes records of keys, with an initializer list. * @param keys The keys of records to remove. * @return The result status. */ - virtual Status RemoveMulti(const std::initializer_list& keys) { - std::vector vector_keys(keys.begin(), keys.end()); - return RemoveMulti(vector_keys); - } + virtual Status RemoveMulti(const std::initializer_list& keys); /** * Removes records of keys, with a string vector. * @param keys The keys of records to remove. * @return The result status. If there are missing records, NOT_FOUND_ERROR is returned. */ - virtual Status RemoveMulti(const std::vector& keys) { - return RemoveMulti(MakeStrViewVectorFromValues(keys)); - } + virtual Status RemoveMulti(const std::vector& keys); /** * Appends data at the end of a record of a key. @@ -1247,10 +960,7 @@ class DBM { * @details If there's no existing record, the value is set without the delimiter. */ virtual Status Append( - std::string_view key, std::string_view value, std::string_view delim = "") { - RecordProcessorAppend proc(value, delim); - return Process(key, &proc, true); - } + std::string_view key, std::string_view value, std::string_view delim = ""); /** * Appends data to multiple records, with a map of string views. @@ -1260,16 +970,7 @@ class DBM { * @details If there's no existing record, the value is set without the delimiter. */ virtual Status AppendMulti( - const std::map& records, std::string_view delim = "") { - Status status(Status::SUCCESS); - for (const auto& record : records) { - status |= Append(record.first, record.second, delim); - if (status != Status::SUCCESS) { - break; - } - } - return status; - } + const std::map& records, std::string_view delim = ""); /** * Appends data to multiple records, with an initializer list. @@ -1280,14 +981,7 @@ class DBM { */ virtual Status AppendMulti( const std::initializer_list>& records, - std::string_view delim = "") { - std::map map_records; - for (const auto& record : records) { - map_records.emplace(std::pair( - std::string_view(record.first), std::string_view(record.second))); - } - return AppendMulti(map_records, delim); - } + std::string_view delim = ""); /** * Appends data to multiple records, with a map of strings. @@ -1297,9 +991,7 @@ class DBM { * @details If there's no existing record, the value is set without the delimiter. */ virtual Status AppendMulti( - const std::map& records, std::string_view delim = "") { - return AppendMulti(MakeStrViewMapFromRecords(records), delim); - } + const std::map& records, std::string_view delim = ""); /** * Compares the value of a record and exchanges if the condition meets. @@ -1316,15 +1008,7 @@ class DBM { */ virtual Status CompareExchange(std::string_view key, std::string_view expected, std::string_view desired, std::string* actual = nullptr, - bool* found = nullptr) { - Status impl_status(Status::SUCCESS); - RecordProcessorCompareExchange proc(&impl_status, expected, desired, actual, found); - const Status status = Process(key, &proc, desired.data() != ANY_DATA.data()); - if (status != Status::SUCCESS) { - return status; - } - return impl_status; - } + bool* found = nullptr); /** * Increments the numeric value of a record. @@ -1339,10 +1023,7 @@ class DBM { * supported. */ virtual Status Increment(std::string_view key, int64_t increment = 1, - int64_t* current = nullptr, int64_t initial = 0) { - RecordProcessorIncrement proc(increment, current, initial); - return Process(key, &proc, increment != INT64MIN); - } + int64_t* current = nullptr, int64_t initial = 0); /** * Increments the numeric value of a record, in a simple way. @@ -1353,10 +1034,7 @@ class DBM { * @details The record value is treated as a decimal integer. Negative is also supported. */ virtual int64_t IncrementSimple( - std::string_view key, int64_t increment = 1, int64_t initial = 0) { - int64_t current = 0; - return Increment(key, increment, ¤t, initial) == Status::SUCCESS ? current : INT64MIN; - } + std::string_view key, int64_t increment = 1, int64_t initial = 0); /** * Processes multiple records with processors. @@ -1381,17 +1059,7 @@ class DBM { */ virtual Status ProcessMulti( const std::vector>& key_lambda_pairs, - bool writable) { - std::vector> key_proc_pairs; - key_proc_pairs.reserve(key_lambda_pairs.size()); - std::vector procs; - procs.reserve(key_lambda_pairs.size()); - for (const auto& key_lambda : key_lambda_pairs) { - procs.emplace_back(key_lambda.second); - key_proc_pairs.emplace_back(std::make_pair(key_lambda.first, &procs.back())); - } - return ProcessMulti(key_proc_pairs, writable); - } + bool writable); /** * Compares the values of records and exchanges if the condition meets. @@ -1404,28 +1072,7 @@ class DBM { */ virtual Status CompareExchangeMulti( const std::vector>& expected, - const std::vector>& desired) { - std::vector> key_proc_pairs; - key_proc_pairs.reserve(expected.size() + desired.size()); - bool noop = false; - std::vector checkers; - checkers.reserve(expected.size()); - for (const auto& key_value : expected) { - checkers.emplace_back(RecordCheckerCompareExchangeMulti(&noop, key_value.second)); - key_proc_pairs.emplace_back(std::pair(key_value.first, &checkers.back())); - } - std::vector setters; - setters.reserve(desired.size()); - for (const auto& key_value : desired) { - setters.emplace_back(RecordSetterCompareExchangeMulti(&noop, key_value.second)); - key_proc_pairs.emplace_back(std::pair(key_value.first, &setters.back())); - } - const Status status = ProcessMulti(key_proc_pairs, true); - if (status != Status::SUCCESS) { - return status; - } - return noop ? Status(Status::INFEASIBLE_ERROR) : Status(Status::SUCCESS); - } + const std::vector>& desired); /** * Changes the key of a record. @@ -1443,28 +1090,7 @@ class DBM { */ virtual Status Rekey(std::string_view old_key, std::string_view new_key, bool overwrite = true, bool copying = false, - std::string* value = nullptr) { - std::vector> key_proc_pairs; - key_proc_pairs.reserve(3); - Status proc_status(Status::SUCCESS); - RecordCheckerRekey checker(&proc_status); - if (!overwrite) { - key_proc_pairs.emplace_back(std::pair(new_key, &checker)); - } - std::string rec_value; - RecordRemoverRekey remover(&proc_status, &rec_value, copying); - key_proc_pairs.emplace_back(std::pair(old_key, &remover)); - RecordSetterRekey setter(&proc_status, &rec_value); - key_proc_pairs.emplace_back(std::pair(new_key, &setter)); - const Status status = ProcessMulti(key_proc_pairs, true); - if (status != Status::SUCCESS) { - return status; - } - if (proc_status == Status::SUCCESS && value != nullptr) { - *value = std::move(rec_value); - } - return proc_status; - } + std::string* value = nullptr); /** * Processes the first record with a processor. @@ -1486,10 +1112,7 @@ class DBM { * @param writable True if the processor can edit the record. * @return The result status. */ - virtual Status ProcessFirst(RecordLambdaType rec_lambda, bool writable) { - RecordProcessorLambda proc(rec_lambda); - return ProcessFirst(&proc, writable); - } + virtual Status ProcessFirst(RecordLambdaType rec_lambda, bool writable); /** * Gets the first record and removes it. @@ -1499,10 +1122,7 @@ class DBM { * it is nullptr, it is ignored. * @return The result status. */ - virtual Status PopFirst(std::string* key = nullptr, std::string* value = nullptr) { - RecordProcessorPopFirst proc(key, value); - return ProcessFirst(&proc, true); - } + virtual Status PopFirst(std::string* key = nullptr, std::string* value = nullptr); /** * Adds a record with a key of the current timestamp. @@ -1516,21 +1136,7 @@ class DBM { * there is an existing record matching the generated key, the key is regenerated and the * attempt is repeated until it succeeds. */ - virtual Status PushLast(std::string_view value, double wtime = -1, std::string* key = nullptr) { - for (uint64_t seq = 0; true; seq++) { - const uint64_t timestamp = - static_cast((wtime < 0 ? GetWallTime() : wtime) * 100000000 + seq); - const std::string& time_key = IntToStrBigEndian(timestamp); - const Status status = Set(time_key, value, false); - if (status != Status::DUPLICATION_ERROR) { - if (key != nullptr) { - *key = time_key; - } - return status; - } - } - return Status(Status::UNKNOWN_ERROR); - } + virtual Status PushLast(std::string_view value, double wtime = -1, std::string* key = nullptr); /** * Processes each and every record in the database with a processor. @@ -1555,10 +1161,7 @@ class DBM { * before the iteration and once after the iteration with both the key and the value being * RecordProcessor::NOOP. */ - virtual Status ProcessEach(RecordLambdaType rec_lambda, bool writable) { - RecordProcessorLambda proc(rec_lambda); - return ProcessEach(&proc, writable); - } + virtual Status ProcessEach(RecordLambdaType rec_lambda, bool writable); /** * Gets the number of records. @@ -1571,10 +1174,7 @@ class DBM { * Gets the number of records, in a simple way. * @return The number of records on success, or -1 on failure. */ - virtual int64_t CountSimple() { - int64_t count = 0; - return Count(&count) == Status::SUCCESS ? count : -1; - } + virtual int64_t CountSimple(); /** * Gets the current file size of the database. @@ -1587,10 +1187,7 @@ class DBM { * Gets the current file size of the database, in a simple way. * @return The current file size of the database, or -1 on failure. */ - virtual int64_t GetFileSizeSimple() { - int64_t size = 0; - return GetFileSize(&size) == Status::SUCCESS ? size : -1; - } + virtual int64_t GetFileSizeSimple(); /** * Gets the path of the database file. @@ -1603,10 +1200,7 @@ class DBM { * Gets the path of the database file, in a simple way. * @return The file path of the database, or an empty string on failure. */ - virtual std::string GetFilePathSimple() { - std::string path; - return GetFilePath(&path) == Status::SUCCESS ? path : std::string(""); - } + virtual std::string GetFilePathSimple(); /** * Gets the timestamp in seconds of the last modified time. @@ -1621,10 +1215,7 @@ class DBM { * Gets the timestamp of the last modified time, in a simple way. * @return The timestamp of the last modified time, or NaN on failure. */ - virtual double GetTimestampSimple() { - double timestamp = 0; - return GetTimestamp(×tamp) == Status::SUCCESS ? timestamp : DOUBLENAN; - } + virtual double GetTimestampSimple(); /** * Removes all records. @@ -1649,10 +1240,7 @@ class DBM { * Checks whether the database should be rebuilt, in a simple way. * @return True if the database should be rebuilt or false if not or on failure. */ - virtual bool ShouldBeRebuiltSimple() { - bool tobe = false; - return ShouldBeRebuilt(&tobe) == Status::SUCCESS ? tobe : false; - } + virtual bool ShouldBeRebuiltSimple(); /** * Synchronizes the content of the database to the file system. @@ -1672,39 +1260,14 @@ class DBM { * @details Copying is done while the content is synchronized and stable. So, this method is * suitable for making a backup file while running a database service. */ - virtual Status CopyFileData(const std::string& dest_path, bool sync_hard = false) { - Status impl_status(Status::SUCCESS); - FileProcessorCopyFileData proc(&impl_status, dest_path); - if (IsWritable()) { - const Status status = Synchronize(sync_hard, &proc); - if (status != Status::SUCCESS) { - return status; - } - } else { - std::string path; - const Status status = GetFilePath(&path); - if (status != Status::SUCCESS) { - return status; - } - proc.Process(path); - } - return impl_status; - } + virtual Status CopyFileData(const std::string& dest_path, bool sync_hard = false); /** * Exports all records to another database. * @param dest_dbm The pointer to the destination database. * @return The result status. */ - virtual Status Export(DBM* dest_dbm) { - Status impl_status(Status::SUCCESS); - RecordProcessorExport proc(&impl_status, dest_dbm); - const Status status = ProcessEach(&proc, false); - if (status != Status::SUCCESS) { - return status; - } - return impl_status; - } + virtual Status Export(DBM* dest_dbm); /** * Inspects the database. @@ -1765,10 +1328,7 @@ class DBM { * Gets the type information of the actual class. * @return The type information of the actual class. */ - const std::type_info& GetType() const { - const auto& entity = *this; - return typeid(entity); - } + const std::type_info& GetType() const; }; } // namespace tkrzw diff --git a/tkrzw_dbm_baby.cc b/tkrzw_dbm_baby.cc index 7dcff20..b9c6bdc 100644 --- a/tkrzw_dbm_baby.cc +++ b/tkrzw_dbm_baby.cc @@ -1534,6 +1534,15 @@ Status BabyDBM::Clear() { return impl_->Clear(); } +Status BabyDBM::Rebuild() { + return Status(Status::SUCCESS); +} + +Status BabyDBM::ShouldBeRebuilt(bool* tobe) { + *tobe = false; + return Status(Status::SUCCESS); +} + Status BabyDBM::Synchronize(bool hard, FileProcessor* proc) { return impl_->Synchronize(hard, proc); } @@ -1550,6 +1559,14 @@ bool BabyDBM::IsWritable() const { return impl_->IsWritable(); } +bool BabyDBM::IsHealthy() const { + return true; +} + +bool BabyDBM::IsOrdered() const { + return true; +} + std::unique_ptr BabyDBM::MakeIterator() { std::unique_ptr iter(new BabyDBM::Iterator(impl_)); return iter; diff --git a/tkrzw_dbm_baby.h b/tkrzw_dbm_baby.h index 0b93476..0cf3adc 100644 --- a/tkrzw_dbm_baby.h +++ b/tkrzw_dbm_baby.h @@ -285,9 +285,7 @@ class BabyDBM final : public DBM { * @return The result status. * @details This method does nothing. */ - Status Rebuild() override { - return Status(Status::SUCCESS); - } + Status Rebuild() override; /** * Checks whether the database should be rebuilt. @@ -295,10 +293,7 @@ class BabyDBM final : public DBM { * @return The result status. * @details There's no need for the database to be rebuilt. */ - Status ShouldBeRebuilt(bool* tobe) override { - *tobe = false; - return Status(Status::SUCCESS); - } + Status ShouldBeRebuilt(bool* tobe) override; /** * Synchronizes the content of the database to the file system. @@ -333,17 +328,13 @@ class BabyDBM final : public DBM { * Checks whether the database condition is healthy. * @return Always true. On-memory databases never cause system errors. */ - bool IsHealthy() const override { - return true; - } + bool IsHealthy() const override; /** * Checks whether ordered operations are supported. * @return Always true. Ordered operations are supported. */ - bool IsOrdered() const override { - return true; - } + bool IsOrdered() const override; /** * Makes an iterator for each record. diff --git a/tkrzw_dbm_cache.cc b/tkrzw_dbm_cache.cc index 80caf5c..aadad34 100644 --- a/tkrzw_dbm_cache.cc +++ b/tkrzw_dbm_cache.cc @@ -1178,10 +1178,19 @@ Status CacheDBM::Clear() { return impl_->Clear(); } +Status CacheDBM::Rebuild() { + return RebuildAdvanced(-1); +} + Status CacheDBM::RebuildAdvanced(int64_t cap_rec_num, int64_t cap_mem_size) { return impl_->Rebuild(cap_rec_num, cap_mem_size); } +Status CacheDBM::ShouldBeRebuilt(bool* tobe) { + *tobe = false; + return Status(Status::SUCCESS); +} + Status CacheDBM::Synchronize(bool hard, FileProcessor* proc) { return impl_->Synchronize(hard, proc); } @@ -1198,6 +1207,14 @@ bool CacheDBM::IsWritable() const { return impl_->IsWritable(); } +bool CacheDBM::IsHealthy() const { + return true; +} + +bool CacheDBM::IsOrdered() const { + return false; +} + std::unique_ptr CacheDBM::MakeIterator() { std::unique_ptr iter(new CacheDBM::Iterator(impl_)); return iter; @@ -1239,14 +1256,30 @@ Status CacheDBM::Iterator::First() { return impl_->First(); } +Status CacheDBM::Iterator::Last() { + return Status(Status::NOT_IMPLEMENTED_ERROR); +} + Status CacheDBM::Iterator::Jump(std::string_view key) { return impl_->Jump(key); } +Status CacheDBM::Iterator::JumpLower(std::string_view key, bool inclusive) { + return Status(Status::NOT_IMPLEMENTED_ERROR); +} + +Status CacheDBM::Iterator::JumpUpper(std::string_view key, bool inclusive) { + return Status(Status::NOT_IMPLEMENTED_ERROR); +} + Status CacheDBM::Iterator::Next() { return impl_->Next(); } +Status CacheDBM::Iterator::Previous() { + return Status(Status::NOT_IMPLEMENTED_ERROR); +} + Status CacheDBM::Iterator::Process(RecordProcessor* proc, bool writable) { assert(proc != nullptr); return impl_->Process(proc, writable); diff --git a/tkrzw_dbm_cache.h b/tkrzw_dbm_cache.h index efb9f6d..899e144 100644 --- a/tkrzw_dbm_cache.h +++ b/tkrzw_dbm_cache.h @@ -73,9 +73,7 @@ class CacheDBM final : public DBM { * @return The result status. * @details This method is not supported. */ - Status Last() override { - return Status(Status::NOT_IMPLEMENTED_ERROR); - } + Status Last() override; /** * Initializes the iterator to indicate a specific record. @@ -93,9 +91,7 @@ class CacheDBM final : public DBM { * @return The result status. * @details This method is not supported. */ - Status JumpLower(std::string_view key, bool inclusive = false) override { - return Status(Status::NOT_IMPLEMENTED_ERROR); - } + Status JumpLower(std::string_view key, bool inclusive = false) override; /** * Initializes the iterator to indicate the first record whose key is upper than a given key. @@ -104,9 +100,7 @@ class CacheDBM final : public DBM { * @return The result status. * @details This method is not supported. */ - Status JumpUpper(std::string_view key, bool inclusive = false) override { - return Status(Status::NOT_IMPLEMENTED_ERROR); - } + Status JumpUpper(std::string_view key, bool inclusive = false) override; /** * Moves the iterator to the next record. @@ -121,9 +115,7 @@ class CacheDBM final : public DBM { * @return The result status. * @details This method is not suppoerted. */ - Status Previous() override { - return Status(Status::NOT_IMPLEMENTED_ERROR); - } + Status Previous() override; /** * Processes the current record with a processor. @@ -287,9 +279,7 @@ class CacheDBM final : public DBM { * @return The result status. * @details The number of buckets is calculated implicitly. */ - Status Rebuild() override { - return RebuildAdvanced(-1); - } + Status Rebuild() override; /** * Rebuilds the entire database, in an advanced way. @@ -305,10 +295,7 @@ class CacheDBM final : public DBM { * @return The result status. * @details There's no need for the database to be rebuilt. */ - Status ShouldBeRebuilt(bool* tobe) override { - *tobe = false; - return Status(Status::SUCCESS); - } + Status ShouldBeRebuilt(bool* tobe) override; /** * Synchronizes the content of the database to the file system. @@ -343,17 +330,13 @@ class CacheDBM final : public DBM { * Checks whether the database condition is healthy. * @return Always true. On-memory databases never cause system errors. */ - bool IsHealthy() const override { - return true; - } + bool IsHealthy() const override; /** * Checks whether ordered operations are supported. * @return Always false. Ordered operations are not supported. */ - bool IsOrdered() const override { - return false; - } + bool IsOrdered() const override; /** * Makes an iterator for each record. diff --git a/tkrzw_dbm_hash.cc b/tkrzw_dbm_hash.cc index d1ce92d..555d7d1 100644 --- a/tkrzw_dbm_hash.cc +++ b/tkrzw_dbm_hash.cc @@ -2398,6 +2398,8 @@ Status HashDBMIteratorImpl::ReadKeys() { return Status(Status::SUCCESS); } +HashDBM::TuningParameters::TuningParameters() {} + HashDBM::HashDBM() { impl_ = new HashDBMImpl(std::make_unique()); } @@ -2410,6 +2412,10 @@ HashDBM::~HashDBM() { delete impl_; } +Status HashDBM::Open(const std::string& path, bool writable, int32_t options) { + return OpenAdvanced(path, writable, options); +} + Status HashDBM::OpenAdvanced(const std::string& path, bool writable, int32_t options, const TuningParameters& tuning_params) { return impl_->Open(path, writable, options, tuning_params); @@ -2495,6 +2501,10 @@ Status HashDBM::Clear() { return impl_->Clear(); } +Status HashDBM::Rebuild() { + return RebuildAdvanced(); +} + Status HashDBM::RebuildAdvanced( const TuningParameters& tuning_params, bool skip_broken_records, bool sync_hard) { return impl_->Rebuild(tuning_params, skip_broken_records, sync_hard); @@ -2529,6 +2539,10 @@ bool HashDBM::IsAutoRestored() const { return impl_->IsAutoRestored(); } +bool HashDBM::IsOrdered() const { + return false; +} + std::unique_ptr HashDBM::MakeIterator() { std::unique_ptr iter(new HashDBM::Iterator(impl_)); return iter; @@ -2632,10 +2646,22 @@ Status HashDBM::Iterator::Jump(std::string_view key) { return impl_->Jump(key); } +Status HashDBM::Iterator::JumpLower(std::string_view key, bool inclusive) { + return Status(Status::NOT_IMPLEMENTED_ERROR); +} + +Status HashDBM::Iterator::JumpUpper(std::string_view key, bool inclusive) { + return Status(Status::NOT_IMPLEMENTED_ERROR); +} + Status HashDBM::Iterator::Next() { return impl_->Next(); } +Status HashDBM::Iterator::Previous() { + return Status(Status::NOT_IMPLEMENTED_ERROR); +} + Status HashDBM::Iterator::Process(RecordProcessor* proc, bool writable) { assert(proc != nullptr); return impl_->Process(proc, writable); diff --git a/tkrzw_dbm_hash.h b/tkrzw_dbm_hash.h index 4bf0d18..7e0f46a 100644 --- a/tkrzw_dbm_hash.h +++ b/tkrzw_dbm_hash.h @@ -106,9 +106,7 @@ class HashDBM final : public DBM { * @return The result status. * @details This method is not supported. */ - Status JumpLower(std::string_view key, bool inclusive = false) override { - return Status(Status::NOT_IMPLEMENTED_ERROR); - } + Status JumpLower(std::string_view key, bool inclusive = false) override; /** * Initializes the iterator to indicate the first record whose key is upper than a given key. @@ -117,9 +115,7 @@ class HashDBM final : public DBM { * @return The result status. * @details This method is not supported. */ - Status JumpUpper(std::string_view key, bool inclusive = false) override { - return Status(Status::NOT_IMPLEMENTED_ERROR); - } + Status JumpUpper(std::string_view key, bool inclusive = false) override; /** * Moves the iterator to the next record. @@ -135,9 +131,7 @@ class HashDBM final : public DBM { * @return The result status. * @details This method is not suppoerted. */ - Status Previous() override { - return Status(Status::NOT_IMPLEMENTED_ERROR); - } + Status Previous() override; /** * Processes the current record with a processor. @@ -319,7 +313,7 @@ class HashDBM final : public DBM { /** * Constructor */ - TuningParameters() {} + TuningParameters(); }; /** @@ -354,9 +348,7 @@ class HashDBM final : public DBM { * @details Precondition: The database is not opened. */ Status Open(const std::string& path, bool writable, - int32_t options = File::OPEN_DEFAULT) override { - return OpenAdvanced(path, writable, options); - } + int32_t options = File::OPEN_DEFAULT) override; /** * Opens a database file, in an advanced way. @@ -514,9 +506,7 @@ class HashDBM final : public DBM { * @details Rebuilding a database is useful to reduce the size of the file by solving * fragmentation. All tuning parameters are succeeded or calculated implicitly. */ - Status Rebuild() override { - return RebuildAdvanced(); - } + Status Rebuild() override; /** * Rebuilds the entire database, in an advanced way. @@ -590,9 +580,7 @@ class HashDBM final : public DBM { * Checks whether ordered operations are supported. * @return Always false. Ordered operations are not supported. */ - bool IsOrdered() const override { - return false; - } + bool IsOrdered() const override; /** * Makes an iterator for each record. diff --git a/tkrzw_dbm_poly.cc b/tkrzw_dbm_poly.cc index b147305..ea5b2b2 100644 --- a/tkrzw_dbm_poly.cc +++ b/tkrzw_dbm_poly.cc @@ -803,6 +803,42 @@ Status PolyDBM::SynchronizeAdvanced( return dbm_->Synchronize(hard, proc); } +Status PolyDBM::Iterator::First() { + return iter_->First(); +} + +Status PolyDBM::Iterator::Last() { + return iter_->Last(); +} + +Status PolyDBM::Iterator::Jump(std::string_view key) { + return iter_->Jump(key); +} + +Status PolyDBM::Iterator::JumpLower(std::string_view key, bool inclusive) { + return iter_->JumpLower(key, inclusive); +} + +Status PolyDBM::Iterator::JumpUpper(std::string_view key, bool inclusive = false) { + return iter_->JumpUpper(key, inclusive); +} + +Status PolyDBM::Iterator::Next() { + return iter_->Next(); +} + +Status PolyDBM::Iterator::Previous() { + return iter_->Previous(); +} + +Status PolyDBM::Iterator::Process(RecordProcessor* proc, bool writable) { + return iter_->Process(proc, writable); +} + +Status PolyDBM::Iterator::Get(std::string* key, std::string* value) { + return iter_->Get(key, value); +} + std::vector> PolyDBM::Inspect() { if (dbm_ == nullptr) { return std::vector>(); diff --git a/tkrzw_dbm_poly.h b/tkrzw_dbm_poly.h index e3fc6a8..f1f7cae 100644 --- a/tkrzw_dbm_poly.h +++ b/tkrzw_dbm_poly.h @@ -109,9 +109,7 @@ class PolyDBM final : public ParamDBM { * @return The result status. * @details Even if there's no record, the operation doesn't fail. */ - Status First() override { - return iter_->First(); - } + Status First() override; /** * Initializes the iterator to indicate the last record. @@ -119,9 +117,7 @@ class PolyDBM final : public ParamDBM { * @details Even if there's no record, the operation doesn't fail. This method is suppoerted * only by ordered databases. */ - Status Last() override { - return iter_->Last(); - } + Status Last() override; /** * Initializes the iterator to indicate a specific record. @@ -131,9 +127,7 @@ class PolyDBM final : public ParamDBM { * same key, the iterator refers to the first record whose key is greater than the given key. * The operation fails with unordered databases if there's no record with the same key. */ - Status Jump(std::string_view key) override { - return iter_->Jump(key); - } + Status Jump(std::string_view key) override; /** * Initializes the iterator to indicate the last record whose key is lower than a given key. @@ -143,9 +137,7 @@ class PolyDBM final : public ParamDBM { * @details Even if there's no matching record, the operation doesn't fail. This method is * suppoerted only by ordered databases. */ - Status JumpLower(std::string_view key, bool inclusive = false) override { - return iter_->JumpLower(key, inclusive); - } + Status JumpLower(std::string_view key, bool inclusive = false) override; /** * Initializes the iterator to indicate the first record whose key is upper than a given key. @@ -155,9 +147,7 @@ class PolyDBM final : public ParamDBM { * @details Even if there's no matching record, the operation doesn't fail. This method is * suppoerted only by ordered databases. */ - Status JumpUpper(std::string_view key, bool inclusive = false) override { - return iter_->JumpUpper(key, inclusive); - } + Status JumpUpper(std::string_view key, bool inclusive = false) override; /** * Moves the iterator to the next record. @@ -165,9 +155,7 @@ class PolyDBM final : public ParamDBM { * @details If the current record is missing, the operation fails. Even if there's no next * record, the operation doesn't fail. */ - Status Next() override { - return iter_->Next(); - } + Status Next() override; /** * Moves the iterator to the previous record. @@ -175,9 +163,7 @@ class PolyDBM final : public ParamDBM { * @details If the current record is missing, the operation fails. Even if there's no previous * record, the operation doesn't fail. This method is suppoerted only by ordered databases. */ - Status Previous() override { - return iter_->Previous(); - } + Status Previous() override; /** * Processes the current record with a processor. @@ -188,9 +174,7 @@ class PolyDBM final : public ParamDBM { * Otherwise, this method fails and no method of the processor is called. If the current * record is removed, the iterator is moved to the next record. */ - Status Process(RecordProcessor* proc, bool writable) override { - return iter_->Process(proc, writable); - } + Status Process(RecordProcessor* proc, bool writable) override; /** * Gets the key and the value of the current record of the iterator. @@ -200,9 +184,7 @@ class PolyDBM final : public ParamDBM { * the value data is ignored. * @return The result status. */ - Status Get(std::string* key = nullptr, std::string* value = nullptr) override { - return iter_->Get(key, value); - } + Status Get(std::string* key = nullptr, std::string* value = nullptr) override; /** * Sets the value of the current record. diff --git a/tkrzw_dbm_skip.cc b/tkrzw_dbm_skip.cc index 05bec97..ccbeb78 100644 --- a/tkrzw_dbm_skip.cc +++ b/tkrzw_dbm_skip.cc @@ -1760,6 +1760,8 @@ void SkipDBMIteratorImpl::ClearPosition() { const std::string SkipDBM::REMOVING_VALUE("\xDE\xAD\x00\x19\x78\x02\x11", 7); +SkipDBM::TuningParameters::TuningParameters() {} + SkipDBM::SkipDBM() { impl_ = new SkipDBMImpl(std::make_unique()); } @@ -1772,6 +1774,10 @@ SkipDBM::~SkipDBM() { delete impl_; } +Status SkipDBM::Open(const std::string& path, bool writable, int32_t options) { + return OpenAdvanced(path, writable, options); +} + Status SkipDBM::OpenAdvanced(const std::string& path, bool writable, int32_t options, const TuningParameters& tuning_params) { return impl_->Open(path, writable, options, tuning_params); @@ -1846,6 +1852,10 @@ Status SkipDBM::Clear() { return impl_->Clear(); } +Status SkipDBM::Rebuild() { + return RebuildAdvanced(); +} + Status SkipDBM::RebuildAdvanced( const TuningParameters& tuning_params, bool skip_broken_records, bool sync_hard) { return impl_->Rebuild(tuning_params, skip_broken_records, sync_hard); @@ -1856,6 +1866,10 @@ Status SkipDBM::ShouldBeRebuilt(bool* tobe) { return impl_->ShouldBeRebuilt(tobe); } +Status SkipDBM::Synchronize(bool hard, FileProcessor* proc) { + return SynchronizeAdvanced(hard, proc, nullptr); +} + Status SkipDBM::SynchronizeAdvanced( bool hard, FileProcessor* proc, SkipDBM::ReducerType reducer) { return impl_->Synchronize(hard, proc, reducer); @@ -1881,6 +1895,10 @@ bool SkipDBM::IsAutoRestored() const { return impl_->IsAutoRestored(); } +bool SkipDBM::IsOrdered() const { + return true; +} + std::unique_ptr SkipDBM::MakeIterator() { std::unique_ptr iter(new SkipDBM::Iterator(impl_)); return iter; diff --git a/tkrzw_dbm_skip.h b/tkrzw_dbm_skip.h index 2035f17..92f0285 100644 --- a/tkrzw_dbm_skip.h +++ b/tkrzw_dbm_skip.h @@ -258,7 +258,7 @@ class SkipDBM final : public DBM { /** * Constructor */ - TuningParameters() {} + TuningParameters(); }; /** @@ -293,9 +293,7 @@ class SkipDBM final : public DBM { * @details Precondition: The database is not opened. */ Status Open(const std::string& path, bool writable, - int32_t options = File::OPEN_DEFAULT) override { - return OpenAdvanced(path, writable, options); - } + int32_t options = File::OPEN_DEFAULT) override; /** * Opens a database file, in an advanced way. @@ -460,9 +458,7 @@ class SkipDBM final : public DBM { * @details Rebuilding a database is useful to optimize the size of the file. * All tuning parameters are succeeded or calculated implicitly. */ - Status Rebuild() override { - return RebuildAdvanced(); - } + Status Rebuild() override; /** * Rebuilds the entire database, in an advanced way. @@ -501,9 +497,7 @@ class SkipDBM final : public DBM { * records. No reducer is applied to records so that all records with duplicated keys are * kept intact. */ - Status Synchronize(bool hard, FileProcessor* proc = nullptr) override { - return SynchronizeAdvanced(hard, proc, nullptr); - } + Status Synchronize(bool hard, FileProcessor* proc = nullptr) override; /** * Synchronizes the content of the database to the file system. @@ -562,9 +556,7 @@ class SkipDBM final : public DBM { * Checks whether ordered operations are supported. * @return Always true. Ordered operations are supported. */ - bool IsOrdered() const override { - return true; - } + bool IsOrdered() const override; /** * Makes an iterator for each record. diff --git a/tkrzw_dbm_std.cc b/tkrzw_dbm_std.cc index 3a2ecae..68a6211 100644 --- a/tkrzw_dbm_std.cc +++ b/tkrzw_dbm_std.cc @@ -892,6 +892,14 @@ bool StdHashDBM::IsWritable() const { return impl_->IsWritable(); } +bool StdHashDBM::IsHealthy() const { + return true; +} + +bool StdHashDBM::IsOrdered() const { + return false; +} + std::unique_ptr StdHashDBM::MakeIterator() { std::unique_ptr iter(new StdHashDBM::Iterator(impl_)); return iter; @@ -1058,6 +1066,14 @@ bool StdTreeDBM::IsWritable() const { return impl_->IsWritable(); } +bool StdTreeDBM::IsHealthy() const { + return true; +} + +bool StdTreeDBM::IsOrdered() const { + return true; +} + std::unique_ptr StdTreeDBM::MakeIterator() { std::unique_ptr iter(new StdTreeDBM::Iterator(impl_)); return iter; diff --git a/tkrzw_dbm_std.h b/tkrzw_dbm_std.h index 6af19dd..99defcd 100644 --- a/tkrzw_dbm_std.h +++ b/tkrzw_dbm_std.h @@ -313,17 +313,13 @@ class StdHashDBM final : public DBM { * Checks whether the database condition is healthy. * @return Always true. On-memory databases never cause system errors. */ - bool IsHealthy() const override { - return true; - } + bool IsHealthy() const override; /** * Checks whether ordered operations are supported. * @return Always false. Ordered operations are not supported. */ - bool IsOrdered() const override { - return false; - } + bool IsOrdered() const override; /** * Makes an iterator for each record. @@ -644,17 +640,13 @@ class StdTreeDBM final : public DBM { * Checks whether the database condition is healthy. * @return Always true. On-memory databases never cause system errors. */ - bool IsHealthy() const override { - return true; - } + bool IsHealthy() const override; /** * Checks whether ordered operations are supported. * @return Always true. Ordered operations are supported. */ - bool IsOrdered() const override { - return true; - } + bool IsOrdered() const override; /** * Makes an iterator for each record. diff --git a/tkrzw_dbm_tiny.cc b/tkrzw_dbm_tiny.cc index c05e1ca..4c98cb4 100644 --- a/tkrzw_dbm_tiny.cc +++ b/tkrzw_dbm_tiny.cc @@ -930,6 +930,10 @@ Status TinyDBM::Clear() { return impl_->Clear(); } +Status TinyDBM::Rebuild() { + return RebuildAdvanced(-1); +} + Status TinyDBM::RebuildAdvanced(int64_t num_buckets) { return impl_->Rebuild(num_buckets); } @@ -955,6 +959,14 @@ bool TinyDBM::IsWritable() const { return impl_->IsWritable(); } +bool TinyDBM::IsHealthy() const { + return true; +} + +bool TinyDBM::IsOrdered() const { + return false; +} + std::unique_ptr TinyDBM::MakeIterator() { std::unique_ptr iter(new TinyDBM::Iterator(impl_)); return iter; @@ -988,14 +1000,30 @@ Status TinyDBM::Iterator::First() { return impl_->First(); } +Status TinyDBM::Iterator::Last() { + return Status(Status::NOT_IMPLEMENTED_ERROR); +} + Status TinyDBM::Iterator::Jump(std::string_view key) { return impl_->Jump(key); } +Status TinyDBM::Iterator::JumpLower(std::string_view key, bool inclusive) { + return Status(Status::NOT_IMPLEMENTED_ERROR); +} + +Status TinyDBM::Iterator::JumpUpper(std::string_view key, bool inclusive) { + return Status(Status::NOT_IMPLEMENTED_ERROR); +} + Status TinyDBM::Iterator::Next() { return impl_->Next(); } +Status TinyDBM::Iterator::Previous() { + return Status(Status::NOT_IMPLEMENTED_ERROR); +} + Status TinyDBM::Iterator::Process(RecordProcessor* proc, bool writable) { assert(proc != nullptr); return impl_->Process(proc, writable); diff --git a/tkrzw_dbm_tiny.h b/tkrzw_dbm_tiny.h index 1e5c58d..6741040 100644 --- a/tkrzw_dbm_tiny.h +++ b/tkrzw_dbm_tiny.h @@ -73,9 +73,7 @@ class TinyDBM final : public DBM { * @return The result status. * @details This method is not supported. */ - Status Last() override { - return Status(Status::NOT_IMPLEMENTED_ERROR); - } + Status Last() override; /** * Initializes the iterator to indicate a specific record. @@ -93,9 +91,7 @@ class TinyDBM final : public DBM { * @return The result status. * @details This method is not supported. */ - Status JumpLower(std::string_view key, bool inclusive = false) override { - return Status(Status::NOT_IMPLEMENTED_ERROR); - } + Status JumpLower(std::string_view key, bool inclusive = false) override; /** * Initializes the iterator to indicate the first record whose key is upper than a given key. @@ -104,9 +100,7 @@ class TinyDBM final : public DBM { * @return The result status. * @details This method is not supported. */ - Status JumpUpper(std::string_view key, bool inclusive = false) override { - return Status(Status::NOT_IMPLEMENTED_ERROR); - } + Status JumpUpper(std::string_view key, bool inclusive = false) override; /** * Moves the iterator to the next record. @@ -121,9 +115,7 @@ class TinyDBM final : public DBM { * @return The result status. * @details This method is not suppoerted. */ - Status Previous() override { - return Status(Status::NOT_IMPLEMENTED_ERROR); - } + Status Previous() override; /** * Processes the current record with a processor. @@ -291,9 +283,7 @@ class TinyDBM final : public DBM { * @return The result status. * @details The number of buckets is calculated implicitly. */ - Status Rebuild() override { - return RebuildAdvanced(-1); - } + Status Rebuild() override; /** * Rebuilds the entire database, in an advanced way. @@ -343,17 +333,13 @@ class TinyDBM final : public DBM { * Checks whether the database condition is healthy. * @return Always true. On-memory databases never cause system errors. */ - bool IsHealthy() const override { - return true; - } + bool IsHealthy() const override; /** * Checks whether ordered operations are supported. * @return Always false. Ordered operations are not supported. */ - bool IsOrdered() const override { - return false; - } + bool IsOrdered() const override; /** * Makes an iterator for each record. diff --git a/tkrzw_dbm_tree.cc b/tkrzw_dbm_tree.cc index 9faa4d3..89ce8d8 100644 --- a/tkrzw_dbm_tree.cc +++ b/tkrzw_dbm_tree.cc @@ -2551,6 +2551,10 @@ Status TreeDBMIteratorImpl::ProcessImpl( return Status(Status::SUCCESS); } + +TreeDBM::TuningParameters::TuningParameters() {} + + TreeDBM::TreeDBM() { impl_ = new TreeDBMImpl(std::make_unique()); } @@ -2563,6 +2567,10 @@ TreeDBM::~TreeDBM() { delete impl_; } +Status TreeDBM::Open(const std::string& path, bool writable, int32_t options) { + return OpenAdvanced(path, writable, options); +} + Status TreeDBM::OpenAdvanced(const std::string& path, bool writable, int32_t options, const TuningParameters& tuning_params) { return impl_->Open(path, writable, options, tuning_params); @@ -2617,6 +2625,10 @@ Status TreeDBM::Clear() { return impl_->Clear(); } +Status TreeDBM::Rebuild() { + return RebuildAdvanced(); +} + Status TreeDBM::RebuildAdvanced( const TuningParameters& tuning_params, bool skip_broken_records, bool sync_hard) { return impl_->Rebuild(tuning_params, skip_broken_records, sync_hard); @@ -2651,6 +2663,10 @@ bool TreeDBM::IsAutoRestored() const { return impl_->IsAutoRestored(); } +bool TreeDBM::IsOrdered() const { + return true; +} + std::unique_ptr TreeDBM::MakeIterator() { std::unique_ptr iter(new TreeDBM::Iterator(impl_)); return iter; diff --git a/tkrzw_dbm_tree.h b/tkrzw_dbm_tree.h index d0b6c9d..ef7d25a 100644 --- a/tkrzw_dbm_tree.h +++ b/tkrzw_dbm_tree.h @@ -222,7 +222,7 @@ class TreeDBM final : public DBM { /** * Constructor */ - TuningParameters() {} + TuningParameters(); }; /** @@ -257,9 +257,7 @@ class TreeDBM final : public DBM { * @details Precondition: The database is not opened. */ Status Open(const std::string& path, bool writable, - int32_t options = File::OPEN_DEFAULT) override { - return OpenAdvanced(path, writable, options); - } + int32_t options = File::OPEN_DEFAULT) override; /** * Opens a database file, in an advanced way. @@ -382,9 +380,7 @@ class TreeDBM final : public DBM { * @details Rebuilding a database is useful to reduce the size of the file by solving * fragmentation. All tuning parameters are succeeded or calculated implicitly. */ - Status Rebuild() override { - return RebuildAdvanced(); - } + Status Rebuild() override; /** * Rebuilds the entire database, in an advanced way. @@ -460,9 +456,7 @@ class TreeDBM final : public DBM { * Checks whether ordered operations are supported. * @return Always true. Ordered operations are supported. */ - bool IsOrdered() const override { - return true; - } + bool IsOrdered() const override; /** * Makes an iterator for each record. diff --git a/tkrzw_file.cc b/tkrzw_file.cc new file mode 100644 index 0000000..d38d99c --- /dev/null +++ b/tkrzw_file.cc @@ -0,0 +1,57 @@ +/************************************************************************************************* + * File system utilities + * + * Copyright 2020 Google LLC + * 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 + * https://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. + *************************************************************************************************/ + +#include "tkrzw_file.h" + +namespace tkrzw { + +std::string File::ReadSimple(int64_t off, size_t size) { + std::string data(size, 0); + if (Read(off, const_cast(data.data()), size) != Status::SUCCESS) { + data.clear(); + } + return data; +} + +bool File::WriteSimple(int64_t off, std::string_view data) { + return Write(off, data.data(), data.size()) == Status::SUCCESS; +} + +int64_t File::AppendSimple(const std::string& data) { + int64_t off = 0; + return Append(data.data(), data.size(), &off) == Status::SUCCESS ? off : -1; +} + +int64_t File::ExpandSimple(size_t inc_size) { + int64_t old_size = 0; + return Expand(inc_size, &old_size) == Status::SUCCESS ? old_size : -1; +} + +int64_t File::GetSizeSimple() { + int64_t size = 0; + return GetSize(&size) == Status::SUCCESS ? size : -1; +} + +std::string File::GetPathSimple() { + std::string path; + return GetPath(&path) == Status::SUCCESS ? path : ""; +} + +const std::type_info& File::GetType() const { + const auto& entity = *this; + return typeid(entity); +} + +} // namespace tkrzw + +// END OF FILE \ No newline at end of file diff --git a/tkrzw_file.h b/tkrzw_file.h index e7f916e..6aa4309 100644 --- a/tkrzw_file.h +++ b/tkrzw_file.h @@ -89,13 +89,7 @@ class File { * @param size The size of the data to be read. * @return A string of the read data. It is empty on failure. */ - virtual std::string ReadSimple(int64_t off, size_t size) { - std::string data(size, 0); - if (Read(off, const_cast(data.data()), size) != Status::SUCCESS) { - data.clear(); - } - return data; - } + virtual std::string ReadSimple(int64_t off, size_t size); /** * Writes data. @@ -112,9 +106,7 @@ class File { * @param data The data to be written. * @return True on success or false on failure. */ - virtual bool WriteSimple(int64_t off, std::string_view data) { - return Write(off, data.data(), data.size()) == Status::SUCCESS; - } + virtual bool WriteSimple(int64_t off, std::string_view data); /** * Appends data at the end of the file. @@ -131,10 +123,7 @@ class File { * @param data The data to be written. * @return The offset at which the data has been put, or -1 on failure. */ - virtual int64_t AppendSimple(const std::string& data) { - int64_t off = 0; - return Append(data.data(), data.size(), &off) == Status::SUCCESS ? off : -1; - } + virtual int64_t AppendSimple(const std::string& data); /** * Expands the file size without writing data. @@ -150,10 +139,7 @@ class File { * @param inc_size The size to increment the file size by. * @return The old size of the file, or -1 on failure. */ - virtual int64_t ExpandSimple(size_t inc_size) { - int64_t old_size = 0; - return Expand(inc_size, &old_size) == Status::SUCCESS ? old_size : -1; - } + virtual int64_t ExpandSimple(size_t inc_size); /** * Truncates the file. @@ -200,10 +186,7 @@ class File { * Gets the size of the file, in a simple way. * @return The size of the on success, or -1 on failure. */ - virtual int64_t GetSizeSimple() { - int64_t size = 0; - return GetSize(&size) == Status::SUCCESS ? size : -1; - } + virtual int64_t GetSizeSimple(); /** * Sets allocation strategy. @@ -233,10 +216,7 @@ class File { * Gets the path of the file, in a simple way. * @return The path of the file on success, or an empty string on failure. */ - virtual std::string GetPathSimple() { - std::string path; - return GetPath(&path) == Status::SUCCESS ? path : ""; - } + virtual std::string GetPathSimple(); /** * Renames the file. @@ -281,10 +261,7 @@ class File { * Gets the type information of the actual class. * @return The type information of the actual class. */ - const std::type_info& GetType() const { - const auto& entity = *this; - return typeid(entity); - } + const std::type_info& GetType() const; }; } // namespace tkrzw diff --git a/tkrzw_key_comparators.cc b/tkrzw_key_comparators.cc new file mode 100644 index 0000000..74ee2ac --- /dev/null +++ b/tkrzw_key_comparators.cc @@ -0,0 +1,152 @@ +/************************************************************************************************* + * Built-in comparators for record keys + * + * Copyright 2020 Google LLC + * 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 + * https://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. + *************************************************************************************************/ + +#include "tkrzw_key_comparators.h" + +namespace tkrzw { + +int32_t LexicalKeyComparator(std::string_view a, std::string_view b) { + return a.compare(b); +} + +int32_t LexicalCaseKeyComparator(std::string_view a, std::string_view b) { + return StrCaseCompare(a, b); +} + +int32_t DecimalKeyComparator(std::string_view a, std::string_view b) { + const int64_t a_num = StrToInt(a); + const int64_t b_num = StrToInt(b); + return a_num < b_num ? -1 : (a_num > b_num ? 1 : 0); +} + +int32_t HexadecimalKeyComparator(std::string_view a, std::string_view b) { + const int64_t a_num = StrToIntHex(a); + const int64_t b_num = StrToIntHex(b); + return a_num < b_num ? -1 : (a_num > b_num ? 1 : 0); +} + +int32_t RealNumberKeyComparator(std::string_view a, std::string_view b) { + const double a_num = StrToDouble(a); + const double b_num = StrToDouble(b); + return a_num < b_num ? -1 : (a_num > b_num ? 1 : 0); +} + +int32_t SignedBigEndianKeyComparator(std::string_view a, std::string_view b) { + auto cast = [](std::string_view str) -> int64_t { + uint64_t num = StrToIntBigEndian(str); + switch(str.size()) { + case sizeof(int8_t): + num = static_cast(num); + break; + case sizeof(int16_t): + num = static_cast(num); + break; + case sizeof(int32_t): + num = static_cast(num); + break; + } + return static_cast(num); + }; + const int64_t a_num = cast(a); + const int64_t b_num = cast(b); + return a_num < b_num ? -1 : (a_num > b_num ? 1 : 0); +} + +int32_t FloatBigEndianKeyComparator(std::string_view a, std::string_view b) { + const long double a_num = StrToFloatBigEndian(a); + const long double b_num = StrToFloatBigEndian(b); + if (std::isnan(a_num)) return std::isnan(b_num) ? 0 : -1; + if (std::isnan(b_num)) return 1; + return a_num < b_num ? -1 : (a_num > b_num ? 1 : 0); +} + +int32_t PairLexicalKeyComparator(std::string_view a, std::string_view b) { + std::string_view a_key, a_value, b_key, b_value; + DeserializeStrPair(a, &a_key, &a_value); + DeserializeStrPair(b, &b_key, &b_value); + const int32_t key_cmp = LexicalKeyComparator(a_key, b_key); + if (key_cmp != 0) { + return key_cmp; + } + return LexicalKeyComparator(a_value, b_value); +} + +int32_t PairLexicalCaseKeyComparator(std::string_view a, std::string_view b) { + std::string_view a_key, a_value, b_key, b_value; + DeserializeStrPair(a, &a_key, &a_value); + DeserializeStrPair(b, &b_key, &b_value); + const int32_t key_cmp = LexicalCaseKeyComparator(a_key, b_key); + if (key_cmp != 0) { + return key_cmp; + } + return LexicalKeyComparator(a_value, b_value); +} + +int32_t PairDecimalKeyComparator(std::string_view a, std::string_view b) { + std::string_view a_key, a_value, b_key, b_value; + DeserializeStrPair(a, &a_key, &a_value); + DeserializeStrPair(b, &b_key, &b_value); + const int32_t key_cmp = DecimalKeyComparator(a_key, b_key); + if (key_cmp != 0) { + return key_cmp; + } + return LexicalKeyComparator(a_value, b_value); +} + +int32_t PairHexadecimalKeyComparator(std::string_view a, std::string_view b) { + std::string_view a_key, a_value, b_key, b_value; + DeserializeStrPair(a, &a_key, &a_value); + DeserializeStrPair(b, &b_key, &b_value); + const int32_t key_cmp = HexadecimalKeyComparator(a_key, b_key); + if (key_cmp != 0) { + return key_cmp; + } + return LexicalKeyComparator(a_value, b_value); +} + +int32_t PairRealNumberKeyComparator(std::string_view a, std::string_view b) { + std::string_view a_key, a_value, b_key, b_value; + DeserializeStrPair(a, &a_key, &a_value); + DeserializeStrPair(b, &b_key, &b_value); + const int32_t key_cmp = RealNumberKeyComparator(a_key, b_key); + if (key_cmp != 0) { + return key_cmp; + } + return LexicalKeyComparator(a_value, b_value); +} + +int32_t PairSignedBigEndianKeyComparator(std::string_view a, std::string_view b) { + std::string_view a_key, a_value, b_key, b_value; + DeserializeStrPair(a, &a_key, &a_value); + DeserializeStrPair(b, &b_key, &b_value); + const int32_t key_cmp = SignedBigEndianKeyComparator(a_key, b_key); + if (key_cmp != 0) { + return key_cmp; + } + return LexicalKeyComparator(a_value, b_value); +} + +int32_t PairFloatBigEndianKeyComparator(std::string_view a, std::string_view b) { + std::string_view a_key, a_value, b_key, b_value; + DeserializeStrPair(a, &a_key, &a_value); + DeserializeStrPair(b, &b_key, &b_value); + const int32_t key_cmp = FloatBigEndianKeyComparator(a_key, b_key); + if (key_cmp != 0) { + return key_cmp; + } + return LexicalKeyComparator(a_value, b_value); +} + +} // namespace tkrzw + +// END OF FILE \ No newline at end of file diff --git a/tkrzw_key_comparators.h b/tkrzw_key_comparators.h index 2dbc680..e21868e 100644 --- a/tkrzw_key_comparators.h +++ b/tkrzw_key_comparators.h @@ -40,9 +40,7 @@ typedef int32_t (*KeyComparator)(std::string_view, std::string_view); * @param b The other key. * @return -1 if "a" is less, 1 if "a" is greater, and 0 if both are equivalent. */ -inline int32_t LexicalKeyComparator(std::string_view a, std::string_view b) { - return a.compare(b); -} +int32_t LexicalKeyComparator(std::string_view a, std::string_view b); /** * Key comparator in the lexical order ignoring case. @@ -50,9 +48,7 @@ inline int32_t LexicalKeyComparator(std::string_view a, std::string_view b) { * @param b The other key. * @return -1 if "a" is less, 1 if "a" is greater, and 0 if both are equivalent. */ -inline int32_t LexicalCaseKeyComparator(std::string_view a, std::string_view b) { - return StrCaseCompare(a, b); -} +int32_t LexicalCaseKeyComparator(std::string_view a, std::string_view b); /** * Key comparator in the order of decimal integer numeric expressions. @@ -60,11 +56,7 @@ inline int32_t LexicalCaseKeyComparator(std::string_view a, std::string_view b) * @param b The other key. * @return -1 if "a" is less, 1 if "a" is greater, and 0 if both are equivalent. */ -inline int32_t DecimalKeyComparator(std::string_view a, std::string_view b) { - const int64_t a_num = StrToInt(a); - const int64_t b_num = StrToInt(b); - return a_num < b_num ? -1 : (a_num > b_num ? 1 : 0); -} +int32_t DecimalKeyComparator(std::string_view a, std::string_view b); /** * Key comparator in the order of hexadecimal integer numeric expressions. @@ -72,11 +64,7 @@ inline int32_t DecimalKeyComparator(std::string_view a, std::string_view b) { * @param b The other key. * @return -1 if "a" is less, 1 if "a" is greater, and 0 if both are equivalent. */ -inline int32_t HexadecimalKeyComparator(std::string_view a, std::string_view b) { - const int64_t a_num = StrToIntHex(a); - const int64_t b_num = StrToIntHex(b); - return a_num < b_num ? -1 : (a_num > b_num ? 1 : 0); -} +int32_t HexadecimalKeyComparator(std::string_view a, std::string_view b); /** * Key comparator in the order of decimal real number expressions. @@ -84,11 +72,7 @@ inline int32_t HexadecimalKeyComparator(std::string_view a, std::string_view b) * @param b The other key. * @return -1 if "a" is less, 1 if "a" is greater, and 0 if both are equivalent. */ -inline int32_t RealNumberKeyComparator(std::string_view a, std::string_view b) { - const double a_num = StrToDouble(a); - const double b_num = StrToDouble(b); - return a_num < b_num ? -1 : (a_num > b_num ? 1 : 0); -} +int32_t RealNumberKeyComparator(std::string_view a, std::string_view b); /** * Key comparator in the order of big-endian binaries of signed integer numbers. @@ -96,26 +80,7 @@ inline int32_t RealNumberKeyComparator(std::string_view a, std::string_view b) { * @param b The other key. * @return -1 if "a" is less, 1 if "a" is greater, and 0 if both are equivalent. */ -inline int32_t SignedBigEndianKeyComparator(std::string_view a, std::string_view b) { - auto cast = [](std::string_view str) -> int64_t { - uint64_t num = StrToIntBigEndian(str); - switch(str.size()) { - case sizeof(int8_t): - num = static_cast(num); - break; - case sizeof(int16_t): - num = static_cast(num); - break; - case sizeof(int32_t): - num = static_cast(num); - break; - } - return static_cast(num); - }; - const int64_t a_num = cast(a); - const int64_t b_num = cast(b); - return a_num < b_num ? -1 : (a_num > b_num ? 1 : 0); -} +int32_t SignedBigEndianKeyComparator(std::string_view a, std::string_view b); /** * Key comparator in the order of big-endian binaries of floating-point numbers. @@ -123,13 +88,7 @@ inline int32_t SignedBigEndianKeyComparator(std::string_view a, std::string_view * @param b The other key. * @return -1 if "a" is less, 1 if "a" is greater, and 0 if both are equivalent. */ -inline int32_t FloatBigEndianKeyComparator(std::string_view a, std::string_view b) { - const long double a_num = StrToFloatBigEndian(a); - const long double b_num = StrToFloatBigEndian(b); - if (std::isnan(a_num)) return std::isnan(b_num) ? 0 : -1; - if (std::isnan(b_num)) return 1; - return a_num < b_num ? -1 : (a_num > b_num ? 1 : 0); -} +int32_t FloatBigEndianKeyComparator(std::string_view a, std::string_view b); /** * Key comparator for serialized pair strings in the lexical order. @@ -137,16 +96,7 @@ inline int32_t FloatBigEndianKeyComparator(std::string_view a, std::string_view * @param b The other key. * @return -1 if "a" is less, 1 if "a" is greater, and 0 if both are equivalent. */ -inline int32_t PairLexicalKeyComparator(std::string_view a, std::string_view b) { - std::string_view a_key, a_value, b_key, b_value; - DeserializeStrPair(a, &a_key, &a_value); - DeserializeStrPair(b, &b_key, &b_value); - const int32_t key_cmp = LexicalKeyComparator(a_key, b_key); - if (key_cmp != 0) { - return key_cmp; - } - return LexicalKeyComparator(a_value, b_value); -} +int32_t PairLexicalKeyComparator(std::string_view a, std::string_view b); /** * Key comparator for serialized pair strings in the lexical order ignoring case. @@ -154,16 +104,7 @@ inline int32_t PairLexicalKeyComparator(std::string_view a, std::string_view b) * @param b The other key. * @return -1 if "a" is less, 1 if "a" is greater, and 0 if both are equivalent. */ -inline int32_t PairLexicalCaseKeyComparator(std::string_view a, std::string_view b) { - std::string_view a_key, a_value, b_key, b_value; - DeserializeStrPair(a, &a_key, &a_value); - DeserializeStrPair(b, &b_key, &b_value); - const int32_t key_cmp = LexicalCaseKeyComparator(a_key, b_key); - if (key_cmp != 0) { - return key_cmp; - } - return LexicalKeyComparator(a_value, b_value); -} +int32_t PairLexicalCaseKeyComparator(std::string_view a, std::string_view b); /** * Key comparator for serialized pair strings in the decimal integer order. @@ -171,16 +112,7 @@ inline int32_t PairLexicalCaseKeyComparator(std::string_view a, std::string_view * @param b The other key. * @return -1 if "a" is less, 1 if "a" is greater, and 0 if both are equivalent. */ -inline int32_t PairDecimalKeyComparator(std::string_view a, std::string_view b) { - std::string_view a_key, a_value, b_key, b_value; - DeserializeStrPair(a, &a_key, &a_value); - DeserializeStrPair(b, &b_key, &b_value); - const int32_t key_cmp = DecimalKeyComparator(a_key, b_key); - if (key_cmp != 0) { - return key_cmp; - } - return LexicalKeyComparator(a_value, b_value); -} +int32_t PairDecimalKeyComparator(std::string_view a, std::string_view b); /** * Key comparator for serialized pair strings in the hexadecimal integer order. @@ -188,16 +120,7 @@ inline int32_t PairDecimalKeyComparator(std::string_view a, std::string_view b) * @param b The other key. * @return -1 if "a" is less, 1 if "a" is greater, and 0 if both are equivalent. */ -inline int32_t PairHexadecimalKeyComparator(std::string_view a, std::string_view b) { - std::string_view a_key, a_value, b_key, b_value; - DeserializeStrPair(a, &a_key, &a_value); - DeserializeStrPair(b, &b_key, &b_value); - const int32_t key_cmp = HexadecimalKeyComparator(a_key, b_key); - if (key_cmp != 0) { - return key_cmp; - } - return LexicalKeyComparator(a_value, b_value); -} +int32_t PairHexadecimalKeyComparator(std::string_view a, std::string_view b); /** * Key comparator for serialized pair strings in the decimal real number order. @@ -205,16 +128,7 @@ inline int32_t PairHexadecimalKeyComparator(std::string_view a, std::string_view * @param b The other key. * @return -1 if "a" is less, 1 if "a" is greater, and 0 if both are equivalent. */ -inline int32_t PairRealNumberKeyComparator(std::string_view a, std::string_view b) { - std::string_view a_key, a_value, b_key, b_value; - DeserializeStrPair(a, &a_key, &a_value); - DeserializeStrPair(b, &b_key, &b_value); - const int32_t key_cmp = RealNumberKeyComparator(a_key, b_key); - if (key_cmp != 0) { - return key_cmp; - } - return LexicalKeyComparator(a_value, b_value); -} +int32_t PairRealNumberKeyComparator(std::string_view a, std::string_view b); /** * Key comparator for serialized pair strings in the big-endian binary signed integer order. @@ -222,16 +136,7 @@ inline int32_t PairRealNumberKeyComparator(std::string_view a, std::string_view * @param b The other key. * @return -1 if "a" is less, 1 if "a" is greater, and 0 if both are equivalent. */ -inline int32_t PairSignedBigEndianKeyComparator(std::string_view a, std::string_view b) { - std::string_view a_key, a_value, b_key, b_value; - DeserializeStrPair(a, &a_key, &a_value); - DeserializeStrPair(b, &b_key, &b_value); - const int32_t key_cmp = SignedBigEndianKeyComparator(a_key, b_key); - if (key_cmp != 0) { - return key_cmp; - } - return LexicalKeyComparator(a_value, b_value); -} +int32_t PairSignedBigEndianKeyComparator(std::string_view a, std::string_view b); /** * Key comparator for serialized pair strings in the big-endian binary floating-point number order. @@ -239,16 +144,7 @@ inline int32_t PairSignedBigEndianKeyComparator(std::string_view a, std::string_ * @param b The other key. * @return -1 if "a" is less, 1 if "a" is greater, and 0 if both are equivalent. */ -inline int32_t PairFloatBigEndianKeyComparator(std::string_view a, std::string_view b) { - std::string_view a_key, a_value, b_key, b_value; - DeserializeStrPair(a, &a_key, &a_value); - DeserializeStrPair(b, &b_key, &b_value); - const int32_t key_cmp = FloatBigEndianKeyComparator(a_key, b_key); - if (key_cmp != 0) { - return key_cmp; - } - return LexicalKeyComparator(a_value, b_value); -} +int32_t PairFloatBigEndianKeyComparator(std::string_view a, std::string_view b); } // namespace tkrzw diff --git a/tkrzw_lib_common.cc b/tkrzw_lib_common.cc index 54861af..2033313 100644 --- a/tkrzw_lib_common.cc +++ b/tkrzw_lib_common.cc @@ -39,6 +39,42 @@ const bool IS_BIG_ENDIAN = _IS_BIG_ENDIAN; #endif +void* xmalloc(size_t size) { + void* ptr = std::malloc(size); + if (ptr == nullptr) { + throw std::bad_alloc(); + } + return ptr; +} + +void* xcalloc(size_t nmemb, size_t size) { + void* ptr = std::calloc(nmemb, size); + if (ptr == nullptr) { + throw std::bad_alloc(); + } + return ptr; +} + +void* xrealloc(void* ptr, size_t size) { + ptr = std::realloc(ptr, size); + if (ptr == nullptr) { + throw std::bad_alloc(); + } + return ptr; +} + +void xfree(void* ptr) { + std::free(ptr); +} + +void* xreallocappend(void* ptr, size_t size) { + size_t aligned_size = 8; + while (aligned_size < size) { + aligned_size += aligned_size >> 1; + } + return xrealloc(ptr, aligned_size); +} + void* xmallocaligned(size_t alignment, size_t size) { #if defined(_SYS_LINUX_) assert(alignment >= sizeof(void*)); @@ -237,6 +273,160 @@ int64_t GetMemoryUsage() { return StrToInt(tkrzw::SearchMap(records, "mem_rss", "-1")); } +Status::Status() + : code_(Code::SUCCESS), message_(nullptr) {} + +Status::Status(Code code) : code_(code), message_(nullptr) {} + +Status::Status(Code code, std::string_view message) : code_(code), message_(nullptr) { + message_ = static_cast(xmalloc(message.size() + 1)); + std::memcpy(message_, message.data(), message.size()); + message_[message.size()] = '\0'; +} + +Status::Status(const Status& rhs) : code_(rhs.code_), message_(nullptr) { + if (rhs.message_ != nullptr) { + const size_t message_size = std::strlen(rhs.message_); + message_ = static_cast(xrealloc(message_, message_size + 1)); + std::memcpy(message_, rhs.message_, message_size); + message_[message_size] = '\0'; + } +} + +Status::Status(Status&& rhs) : code_(rhs.code_), message_(rhs.message_) { + rhs.message_ = nullptr; +} + +Status::~Status() { + xfree(message_); +} + +Status& Status::operator =(const Status& rhs) { + if (this != &rhs) { + code_ = rhs.code_; + if (rhs.message_ == nullptr) { + xfree(message_); + message_ = nullptr; + } else { + const size_t message_size = std::strlen(rhs.message_); + message_ = static_cast(xrealloc(message_, message_size + 1)); + std::memcpy(message_, rhs.message_, message_size); + message_[message_size] = '\0'; + } + } + return *this; +} + +Status& Status::operator =(Status&& rhs) { + if (this != &rhs) { + code_ = rhs.code_; + xfree(message_); + message_ = rhs.message_; + rhs.message_ = nullptr; + } + return *this; +} + +Status& Status::operator |=(const Status& rhs) { + if (this != &rhs && code_ == SUCCESS && rhs.code_ != SUCCESS) { + code_ = rhs.code_; + if (rhs.message_ == nullptr) { + xfree(message_); + message_ = nullptr; + } else { + const size_t message_size = std::strlen(rhs.message_); + message_ = static_cast(xrealloc(message_, message_size + 1)); + std::memcpy(message_, rhs.message_, message_size); + message_[message_size] = '\0'; + } + } + return *this; +} + +Status& Status::operator |=(Status&& rhs) { + if (this != &rhs && code_ == SUCCESS && rhs.code_ != SUCCESS) { + code_ = rhs.code_; + xfree(message_); + message_ = rhs.message_; + rhs.message_ = nullptr; + } + return *this; +} + +Status::Code Status::GetCode() const { + return code_; +} + +std::string Status::GetMessage() const { + return message_ == nullptr ? "" : message_; +} + +bool Status::HasMessage() const { + return message_ != nullptr && *message_ != '\0'; +} + +char* Status::MakeMessageC() const { + if (message_ == nullptr) { + char* str = static_cast(xmalloc(1)); + *str = '\0'; + return str; + } + const size_t size = std::strlen(message_); + char* str = static_cast(xmalloc(size + 1)); + std::memcpy(str, message_, size + 1); + return str; +} + +void Status::Set(Code code) { + code_ = code; + xfree(message_); + message_ = nullptr; +} + +void Status::Set(Code code, std::string_view message) { + code_ = code; + message_ = static_cast(xrealloc(message_, message.size() + 1)); + std::memcpy(message_, message.data(), message.size()); + message_[message.size()] = '\0'; +} + +bool Status::operator ==(const Status& rhs) const { + return code_ == rhs.code_; +} + +bool Status::operator !=(const Status& rhs) const { + return code_ != rhs.code_; +} + +bool Status::operator ==(const Code& code) const { + return code_ == code; +} + +bool Status::operator !=(const Code& code) const { + return code_ != code; +} + +bool Status::operator <(const Status& rhs) const { + if (code_ != rhs.code_) { + return code_ < rhs.code_; + } + return std::strcmp(message_ != nullptr ? message_ : "", + rhs.message_ != nullptr ? rhs.message_ : ""); +} + +Status::operator std::string() const { + std::string expr(CodeName(code_)); + if (message_ != nullptr) { + expr += ": "; + expr += message_; + } + return expr; +} + +bool Status::IsOK() const { + return code_ == SUCCESS; +} + const Status& Status::OrDie() const { if (code_ != SUCCESS) { throw StatusException(*this); @@ -244,6 +434,56 @@ const Status& Status::OrDie() const { return *this; } +const char* Status::CodeName(Code code) { + switch (code) { + case SUCCESS: return "SUCCESS"; + case UNKNOWN_ERROR: return "UNKNOWN_ERROR"; + case SYSTEM_ERROR: return "SYSTEM_ERROR"; + case NOT_IMPLEMENTED_ERROR: return "NOT_IMPLEMENTED_ERROR"; + case PRECONDITION_ERROR: return "PRECONDITION_ERROR"; + case INVALID_ARGUMENT_ERROR: return "INVALID_ARGUMENT_ERROR"; + case CANCELED_ERROR : return "CANCELED_ERROR"; + case NOT_FOUND_ERROR: return "NOT_FOUND_ERROR"; + case PERMISSION_ERROR: return "PERMISSION_ERROR"; + case INFEASIBLE_ERROR: return "INFEASIBLE_ERROR"; + case DUPLICATION_ERROR: return "DUPLICATION_ERROR"; + case BROKEN_DATA_ERROR: return "BROKEN_DATA_ERROR"; + case NETWORK_ERROR: return "NETWORK_ERROR"; + case APPLICATION_ERROR: return "APPLICATION_ERROR"; + } + return "unnamed error"; +} + +bool operator ==(const Status::Code& lhs, const Status& rhs) { + return lhs == rhs.GetCode(); +} + +bool operator !=(const Status::Code& lhs, const Status& rhs) { + return lhs != rhs.GetCode(); +} + +std::string ToString(const Status& status) { + return std::string(status); +} + +std::ostream& operator<<(std::ostream& os, const Status& status) { + return os << std::string(status); +} + + + +StatusException::StatusException(const Status& status) + : std::runtime_error(ToString(status)), status_(status) {} + +Status StatusException::GetStatus() const { + return status_; +} + +StatusException::operator std::string() const { + return std::string(status_); +} + + Status GetErrnoStatus(const char* call_name, int32_t sys_err_num) { auto msg = [&](const char* message) { return std::string(call_name) + ": " + message; diff --git a/tkrzw_lib_common.h b/tkrzw_lib_common.h index 1a87a91..076851a 100644 --- a/tkrzw_lib_common.h +++ b/tkrzw_lib_common.h @@ -147,13 +147,7 @@ extern const bool IS_BIG_ENDIAN; * @param size The size of the region. * @return The pointer to the allocated region. */ -inline void* xmalloc(size_t size) { - void* ptr = std::malloc(size); - if (ptr == nullptr) { - throw std::bad_alloc(); - } - return ptr; -} +void* xmalloc(size_t size); /** * Allocates a nullified region on memory. @@ -161,13 +155,7 @@ inline void* xmalloc(size_t size) { * @param size The size of each element. * @return The pointer to the allocated region. */ -inline void* xcalloc(size_t nmemb, size_t size) { - void* ptr = std::calloc(nmemb, size); - if (ptr == nullptr) { - throw std::bad_alloc(); - } - return ptr; -} +void* xcalloc(size_t nmemb, size_t size); /** * Re-allocates a region on memory. @@ -175,13 +163,7 @@ inline void* xcalloc(size_t nmemb, size_t size) { * @param size The size of the region. * @return The pointer to the re-allocated region. */ -inline void* xrealloc(void* ptr, size_t size) { - ptr = std::realloc(ptr, size); - if (ptr == nullptr) { - throw std::bad_alloc(); - } - return ptr; -} +void* xrealloc(void* ptr, size_t size); /** * Re-allocates a region on memory for appending operations. @@ -189,21 +171,13 @@ inline void* xrealloc(void* ptr, size_t size) { * @param size The size of the region. * @return The pointer to the re-allocated region. */ -inline void* xreallocappend(void* ptr, size_t size) { - size_t aligned_size = 8; - while (aligned_size < size) { - aligned_size += aligned_size >> 1; - } - return xrealloc(ptr, aligned_size); -} +void* xreallocappend(void* ptr, size_t size); /** * Frees a region on memory. * @param ptr The pointer to the region. */ -inline void xfree(void* ptr) { - std::free(ptr); -} +void xfree(void* ptr); /** * Allocates an aligned region on memory. @@ -332,252 +306,145 @@ class Status final { /** * Default constructor representing the success code. */ - Status() : code_(Code::SUCCESS), message_(nullptr) {} + Status(); /** * Constructor representing a specific status. * @param code The status code. */ - explicit Status(Code code) : code_(code), message_(nullptr) {} + explicit Status(Code code); /** * Constructor representing a specific status with a message. * @param code The status code. * @param message An arbitrary status message. */ - Status(Code code, std::string_view message) : code_(code), message_(nullptr) { - message_ = static_cast(xmalloc(message.size() + 1)); - std::memcpy(message_, message.data(), message.size()); - message_[message.size()] = '\0'; - } + Status(Code code, std::string_view message); /** * Copy constructor. * @param rhs The right-hand-side object. */ - Status(const Status& rhs) : code_(rhs.code_), message_(nullptr) { - if (rhs.message_ != nullptr) { - const size_t message_size = std::strlen(rhs.message_); - message_ = static_cast(xrealloc(message_, message_size + 1)); - std::memcpy(message_, rhs.message_, message_size); - message_[message_size] = '\0'; - } - } + Status(const Status& rhs); /** * Move constructor. * @param rhs The right-hand-side object. */ - Status(Status&& rhs) : code_(rhs.code_), message_(rhs.message_) { - rhs.message_ = nullptr; - } + Status(Status&& rhs); /** * Destructor. */ - ~Status() { - xfree(message_); - } + ~Status(); /** * Assigns the internal state from another status object. * @param rhs The status object. */ - Status& operator =(const Status& rhs) { - if (this != &rhs) { - code_ = rhs.code_; - if (rhs.message_ == nullptr) { - xfree(message_); - message_ = nullptr; - } else { - const size_t message_size = std::strlen(rhs.message_); - message_ = static_cast(xrealloc(message_, message_size + 1)); - std::memcpy(message_, rhs.message_, message_size); - message_[message_size] = '\0'; - } - } - return *this; - } + Status& operator =(const Status& rhs); /** * Assigns the internal state from another moved status object. * @param rhs The status object. */ - Status& operator =(Status&& rhs) { - if (this != &rhs) { - code_ = rhs.code_; - xfree(message_); - message_ = rhs.message_; - rhs.message_ = nullptr; - } - return *this; - } + Status& operator =(Status&& rhs); /** * Assigns the internal state from another status object only if the current state is success. * @param rhs The status object. */ - Status& operator |=(const Status& rhs) { - if (this != &rhs && code_ == SUCCESS && rhs.code_ != SUCCESS) { - code_ = rhs.code_; - if (rhs.message_ == nullptr) { - xfree(message_); - message_ = nullptr; - } else { - const size_t message_size = std::strlen(rhs.message_); - message_ = static_cast(xrealloc(message_, message_size + 1)); - std::memcpy(message_, rhs.message_, message_size); - message_[message_size] = '\0'; - } - } - return *this; - } + Status& operator |=(const Status& rhs); /** * Assigns the internal state from another status object only if the current state is success. * @param rhs The status object. */ - Status& operator |=(Status&& rhs) { - if (this != &rhs && code_ == SUCCESS && rhs.code_ != SUCCESS) { - code_ = rhs.code_; - xfree(message_); - message_ = rhs.message_; - rhs.message_ = nullptr; - } - return *this; - } + Status& operator |=(Status&& rhs); /** * Gets the status code. * @return The status code. */ - Code GetCode() const { - return code_; - } + Code GetCode() const; /** * Gets the status message. * @return The status message. */ - std::string GetMessage() const { - return message_ == nullptr ? "" : message_; - } + std::string GetMessage() const; /** * Checks whether the status has a non-empty message. * @return True if the status has a non-empty message. */ - bool HasMessage() const { - return message_ != nullptr && *message_ != '\0'; - } + bool HasMessage() const; /** * Makes a C string of the message. * @return The C message string, which should be released by the free function. */ - char* MakeMessageC() const { - if (message_ == nullptr) { - char* str = static_cast(xmalloc(1)); - *str = '\0'; - return str; - } - const size_t size = std::strlen(message_); - char* str = static_cast(xmalloc(size + 1)); - std::memcpy(str, message_, size + 1); - return str; - } + char* MakeMessageC() const; /** * Sets the code and an empty message. * @param code The status code. */ - void Set(Code code) { - code_ = code; - xfree(message_); - message_ = nullptr; - } + void Set(Code code); /** * Sets the code and the message. * @param code The status code. * @param message An arbitrary status message. */ - void Set(Code code, std::string_view message) { - code_ = code; - message_ = static_cast(xrealloc(message_, message.size() + 1)); - std::memcpy(message_, message.data(), message.size()); - message_[message.size()] = '\0'; - } + void Set(Code code, std::string_view message); /** * Checks whether the internal status code is equal to a given status. * @param rhs The status to compare. * @return True if the internal status code is equal to the given status. */ - bool operator ==(const Status& rhs) const { - return code_ == rhs.code_; - } + bool operator ==(const Status& rhs) const; /** * Checks whether the internal status code is not equal to a given status. * @param rhs The status to compare. * @return True if the internal status code is not equal to the given status. */ - bool operator !=(const Status& rhs) const { - return code_ != rhs.code_; - } + bool operator !=(const Status& rhs) const; /** * Checks whether the internal status code is equal to a given code. * @param code The code to compare. * @return True if the internal status code is equal to the given code. */ - bool operator ==(const Code& code) const { - return code_ == code; - } + bool operator ==(const Code& code) const; /** * Checks whether the internal status code is not equal to a given code. * @param code The code to compare. * @return True if the internal status code is not equal to the given code. */ - bool operator !=(const Code& code) const { - return code_ != code; - } + bool operator !=(const Code& code) const; /** * Compares this object with another status object. * @param rhs The status to compare. * @return True if this object is considered less than the given object. */ - bool operator <(const Status& rhs) const { - if (code_ != rhs.code_) { - return code_ < rhs.code_; - } - return std::strcmp(message_ != nullptr ? message_ : "", - rhs.message_ != nullptr ? rhs.message_ : ""); - } + bool operator <(const Status& rhs) const; /** * Gets a string expression of the status. * @return The string expression */ - operator std::string() const { - std::string expr(CodeName(code_)); - if (message_ != nullptr) { - expr += ": "; - expr += message_; - } - return expr; - } + operator std::string() const; /** * Returns true if the status is success. * @return True if the status is success, or false on failure. */ - bool IsOK() const { - return code_ == SUCCESS; - } + bool IsOK() const; /** * Throws an exception if the status is not success. @@ -590,25 +457,7 @@ class Status final { * @param code The status code. * @return The name of the status code. */ - static const char* CodeName(Code code) { - switch (code) { - case SUCCESS: return "SUCCESS"; - case UNKNOWN_ERROR: return "UNKNOWN_ERROR"; - case SYSTEM_ERROR: return "SYSTEM_ERROR"; - case NOT_IMPLEMENTED_ERROR: return "NOT_IMPLEMENTED_ERROR"; - case PRECONDITION_ERROR: return "PRECONDITION_ERROR"; - case INVALID_ARGUMENT_ERROR: return "INVALID_ARGUMENT_ERROR"; - case CANCELED_ERROR : return "CANCELED_ERROR"; - case NOT_FOUND_ERROR: return "NOT_FOUND_ERROR"; - case PERMISSION_ERROR: return "PERMISSION_ERROR"; - case INFEASIBLE_ERROR: return "INFEASIBLE_ERROR"; - case DUPLICATION_ERROR: return "DUPLICATION_ERROR"; - case BROKEN_DATA_ERROR: return "BROKEN_DATA_ERROR"; - case NETWORK_ERROR: return "NETWORK_ERROR"; - case APPLICATION_ERROR: return "APPLICATION_ERROR"; - } - return "unnamed error"; - } + static const char* CodeName(Code code); private: /** Status code. */ @@ -623,9 +472,7 @@ class Status final { * @param rhs The status object to compare. * @return True if The status code is equal to the status object. */ -inline bool operator ==(const Status::Code& lhs, const Status& rhs) { - return lhs == rhs.GetCode(); -} +bool operator ==(const Status::Code& lhs, const Status& rhs); /** * Checks whether a status code is not equal to another status object. @@ -633,18 +480,14 @@ inline bool operator ==(const Status::Code& lhs, const Status& rhs) { * @param rhs The status object to compare. * @return True if The status code is equal to the status object. */ -inline bool operator !=(const Status::Code& lhs, const Status& rhs) { - return lhs != rhs.GetCode(); -} +bool operator !=(const Status::Code& lhs, const Status& rhs); /** * Converts a status into a string. * @param status The status object. * @return The converted string. */ -inline std::string ToString(const Status& status) { - return std::string(status); -} +std::string ToString(const Status& status); /** * Outputs a status string into an output stream. @@ -652,9 +495,7 @@ inline std::string ToString(const Status& status) { * @param status The status. * @return The output stream. */ -inline std::ostream& operator<<(std::ostream& os, const Status& status) { - return os << std::string(status); -} +std::ostream& operator<<(std::ostream& os, const Status& status); /** * Exception to convey the status of operations. @@ -665,24 +506,19 @@ class StatusException final : public std::runtime_error { * Constructor. * @param status The status to convey. */ - explicit StatusException(const Status& status) - : std::runtime_error(ToString(status)), status_(status) {} + explicit StatusException(const Status& status); /** * Gets the status object. * @return The status object. */ - Status GetStatus() const { - return status_; - } + Status GetStatus() const; /** * Gets a string expression of the status. * @return The string expression */ - operator std::string() const { - return std::string(status_); - } + operator std::string() const; private: /** The status object. */