diff --git a/object_store.cpp b/object_store.cpp index 3e32b98c..3aed85c5 100644 --- a/object_store.cpp +++ b/object_store.cpp @@ -30,6 +30,7 @@ using namespace realm; +namespace { const char * const c_metadataTableName = "metadata"; const char * const c_versionColumnName = "version"; const size_t c_versionColumnIndex = 0; @@ -42,8 +43,8 @@ const size_t c_primaryKeyPropertyNameColumnIndex = 1; const size_t c_zeroRowIndex = 0; -const std::string c_object_table_prefix = "class_"; -const size_t c_object_table_prefix_length = c_object_table_prefix.length(); +const char c_object_table_prefix[] = "class_"; +} const uint64_t ObjectStore::NotVersioned = std::numeric_limits::max(); @@ -119,15 +120,15 @@ void ObjectStore::set_primary_key_for_object(Group *group, StringData object_typ } } -std::string ObjectStore::object_type_for_table_name(const std::string &table_name) { - if (table_name.size() >= c_object_table_prefix_length && table_name.compare(0, c_object_table_prefix_length, c_object_table_prefix) == 0) { - return table_name.substr(c_object_table_prefix_length, table_name.length() - c_object_table_prefix_length); +StringData ObjectStore::object_type_for_table_name(StringData table_name) { + if (table_name.begins_with(c_object_table_prefix)) { + return table_name.substr(sizeof(c_object_table_prefix) - 1); } - return std::string(); + return StringData(); } -std::string ObjectStore::table_name_for_object_type(const std::string &object_type) { - return c_object_table_prefix + object_type; +std::string ObjectStore::table_name_for_object_type(StringData object_type) { + return std::string(c_object_table_prefix) + object_type.data(); } TableRef ObjectStore::table_for_object_type(Group *group, StringData object_type) { @@ -138,7 +139,7 @@ ConstTableRef ObjectStore::table_for_object_type(const Group *group, StringData return group->get_table(table_name_for_object_type(object_type)); } -TableRef ObjectStore::table_for_object_type_create_if_needed(Group *group, const StringData &object_type, bool &created) { +TableRef ObjectStore::table_for_object_type_create_if_needed(Group *group, StringData object_type, bool &created) { return group->get_or_add_table(table_name_for_object_type(object_type), &created); } @@ -494,7 +495,7 @@ void ObjectStore::validate_primary_column_uniqueness(const Group *group, Schema } } -void ObjectStore::delete_data_for_object(Group *group, const StringData &object_type) { +void ObjectStore::delete_data_for_object(Group *group, StringData object_type) { TableRef table = table_for_object_type(group, object_type); if (table) { group->remove_table(table->get_index_in_group()); diff --git a/object_store.hpp b/object_store.hpp index 60671f55..d41ec3fd 100644 --- a/object_store.hpp +++ b/object_store.hpp @@ -68,11 +68,14 @@ namespace realm { static Schema schema_from_group(const Group *group); // deletes the table for the given type - static void delete_data_for_object(Group *group, const StringData &object_type); + static void delete_data_for_object(Group *group, StringData object_type); // indicates if this group contains any objects static bool is_empty(const Group *group); + static std::string table_name_for_object_type(StringData class_name); + static StringData object_type_for_table_name(StringData table_name); + private: // set a new schema version static void set_schema_version(Group *group, uint64_t version); @@ -102,9 +105,7 @@ namespace realm { // must be in write transaction to set static void set_primary_key_for_object(Group *group, StringData object_type, StringData primary_key); - static TableRef table_for_object_type_create_if_needed(Group *group, const StringData &object_type, bool &created); - static std::string table_name_for_object_type(const std::string &class_name); - static std::string object_type_for_table_name(const std::string &table_name); + static TableRef table_for_object_type_create_if_needed(Group *group, StringData object_type, bool &created); // returns if any indexes were changed static bool update_indexes(Group *group, Schema &schema); diff --git a/results.cpp b/results.cpp index 3b3654d8..42956d37 100644 --- a/results.cpp +++ b/results.cpp @@ -52,17 +52,17 @@ Results::Results(SharedRealm r, Table& table) void Results::validate_read() const { - if (m_realm && !m_realm->check_thread()) - throw Error::IncorrectThread; + if (m_realm) + m_realm->verify_thread(); if (m_table && !m_table->is_attached()) - throw Error::Invalidated; + throw InvalidatedException(); } void Results::validate_write() const { validate_read(); if (!m_realm || !m_realm->is_in_transaction()) - throw Error::NotInWrite; + throw InvalidTransactionException("Must be in a write transaction"); } size_t Results::size() @@ -96,7 +96,7 @@ RowExpr Results::get(size_t row_ndx) break; } - throw Error::OutOfBoundsIndex; + throw OutOfBoundsIndexException{row_ndx, size()}; } util::Optional Results::first() @@ -157,10 +157,10 @@ size_t Results::index_of(Row const& row) { validate_read(); if (!row) { - throw Error::DetachedAccessor; + throw DetatchedAccessorException{}; } if (m_table && row.get_table() != m_table) { - throw Error::IncorrectTable; + throw IncorrectTableException{m_table, row.get_table()}; } return index_of(row.get_index()); } @@ -193,7 +193,7 @@ util::Optional Results::aggregate(size_t column, bool return_none_for_emp if (!m_table) return none; if (column > m_table->get_column_count()) - throw Error::OutOfBoundsIndex; + throw OutOfBoundsIndexException{column, m_table->get_column_count()}; auto do_agg = [&](auto const& getter) -> util::Optional { switch (m_mode) { @@ -220,7 +220,7 @@ util::Optional Results::aggregate(size_t column, bool return_none_for_emp case type_Float: return do_agg(agg_float); case type_Int: return do_agg(agg_int); default: - throw Error::UnsupportedColumnType; + throw UnsupportedColumnTypeException{column, m_table}; } } @@ -248,7 +248,7 @@ util::Optional Results::sum(size_t column) [=](auto const& table) { return table.sum_int(column); }, [=](auto const& table) { return table.sum_float(column); }, [=](auto const& table) { return table.sum_double(column); }, - [=](auto const&) -> util::None { throw Error::UnsupportedColumnType; }); + [=](auto const&) -> util::None { throw UnsupportedColumnTypeException{column, m_table}; }); } util::Optional Results::average(size_t column) @@ -257,7 +257,7 @@ util::Optional Results::average(size_t column) [=](auto const& table) { return table.average_int(column); }, [=](auto const& table) { return table.average_float(column); }, [=](auto const& table) { return table.average_double(column); }, - [=](auto const&) -> util::None { throw Error::UnsupportedColumnType; }); + [=](auto const&) -> util::None { throw UnsupportedColumnTypeException{column, m_table}; }); } void Results::clear() @@ -319,3 +319,9 @@ Results Results::filter(Query&& q) const { return Results(m_realm, get_query().and_query(q), get_sort()); } + +Results::UnsupportedColumnTypeException::UnsupportedColumnTypeException(size_t column, const Table* table) { + column_index = column; + column_name = table->get_column_name(column); + column_type = table->get_column_type(column); +} diff --git a/results.hpp b/results.hpp index ef941b03..895c084c 100644 --- a/results.hpp +++ b/results.hpp @@ -70,7 +70,7 @@ public: size_t size(); // Get the row accessor for the given index - // Throws OutOfBoundsIndex if index >= size() + // Throws OutOfBoundsIndexException if index >= size() RowExpr get(size_t index); // Get a row accessor for the first/last row, or none if the results are empty @@ -79,14 +79,14 @@ public: util::Optional last(); // Get the first index of the given row in this results, or not_found - // Throws DetachedAccessor if row is not attached - // Throws IncorrectTable if row belongs to a different table + // Throws DetachedAccessorException if row is not attached + // Throws IncorrectTableException if row belongs to a different table size_t index_of(size_t row_ndx); size_t index_of(Row const& row); // Delete all of the rows in this Results from the Realm // size() will always be zero afterwards - // Throws NotInWrite + // Throws InvalidTransactionException if not in a write transaction void clear(); // Create a new Results by further filtering or sorting this Results @@ -96,8 +96,8 @@ public: // Get the min/max/average/sum of the given column // All but sum() returns none when there are zero matching rows // sum() returns 0, except for when it returns none - // Throws UnsupportedColumnType for sum/average on datetime or non-numeric column - // Throws OutOfBoundsIndex for an out-of-bounds column + // Throws UnsupportedColumnTypeException for sum/average on datetime or non-numeric column + // Throws OutOfBoundsIndexException for an out-of-bounds column util::Optional max(size_t column); util::Optional min(size_t column); util::Optional average(size_t column); @@ -113,25 +113,32 @@ public: // Ideally this would not be public but it's needed for some KVO stuff Mode get_mode() const { return m_mode; } - // All errors thrown by Results are one of the following error codes - // Invalidated and IncorrectThread can be thrown by all non-noexcept functions - // Other errors are thrown only where indicated - enum class Error { - // The Results object has been invalidated (due to the Realm being invalidated) - Invalidated, - // The Results object is being accessed from the wrong thread - IncorrectThread, - // The containing Realm is not in a write transaction - NotInWrite, + // The Results object has been invalidated (due to the Realm being invalidated) + // All non-noexcept functions can throw this + struct InvalidatedException {}; - // The input index parameter was out of bounds - OutOfBoundsIndex, - // The input Row object belongs to a different table - IncorrectTable, - // The input Row object is not attached - DetachedAccessor, - // The requested aggregate operation is not supported for the column type - UnsupportedColumnType + // The input index parameter was out of bounds + struct OutOfBoundsIndexException { + size_t requested; + size_t valid_count; + }; + + // The input Row object is not attached + struct DetatchedAccessorException { }; + + // The input Row object belongs to a different table + struct IncorrectTableException { + const Table* expected; + const Table* actual; + }; + + // The requested aggregate operation is not supported for the column type + struct UnsupportedColumnTypeException { + size_t column_index; + StringData column_name; + DataType column_type; + + UnsupportedColumnTypeException(size_t column, const Table* table); }; private: diff --git a/shared_realm.cpp b/shared_realm.cpp index 1a670563..28bb81b6 100644 --- a/shared_realm.cpp +++ b/shared_realm.cpp @@ -236,15 +236,17 @@ static void check_read_write(Realm *realm) } } -bool Realm::check_thread() const noexcept -{ - return m_thread_id == std::this_thread::get_id(); -} - void Realm::verify_thread() const { - if (!check_thread()) { - throw IncorrectThreadException("Realm accessed from incorrect thread."); + if (m_thread_id != std::this_thread::get_id()) { + throw IncorrectThreadException(); + } +} + +void Realm::verify_in_write() const +{ + if (!is_in_transaction()) { + throw InvalidTransactionException("Cannot modify persisted objects outside of a write transaction."); } } diff --git a/shared_realm.hpp b/shared_realm.hpp index ef848fcb..0503282a 100644 --- a/shared_realm.hpp +++ b/shared_realm.hpp @@ -98,8 +98,8 @@ namespace realm { bool compact(); std::thread::id thread_id() const { return m_thread_id; } - bool check_thread() const noexcept; void verify_thread() const; + void verify_in_write() const; // Close this Realm and remove it from the cache. Continuing to use a // Realm after closing it will produce undefined behavior. @@ -145,11 +145,9 @@ namespace realm { std::mutex m_mutex; }; - class RealmFileException : public std::runtime_error - { - public: - enum class Kind - { + class RealmFileException : public std::runtime_error { + public: + enum class Kind { /** Thrown for any I/O related exception scenarios when a realm is opened. */ AccessError, /** Thrown if the user does not have permission to open or create @@ -169,32 +167,28 @@ namespace realm { Kind kind() const { return m_kind; } const std::string& path() const { return m_path; } - private: + private: Kind m_kind; std::string m_path; }; - class MismatchedConfigException : public std::runtime_error - { - public: + class MismatchedConfigException : public std::runtime_error { + public: MismatchedConfigException(std::string message) : std::runtime_error(message) {} }; - class InvalidTransactionException : public std::runtime_error - { - public: + class InvalidTransactionException : public std::runtime_error { + public: InvalidTransactionException(std::string message) : std::runtime_error(message) {} }; - class IncorrectThreadException : public std::runtime_error - { - public: - IncorrectThreadException(std::string message) : std::runtime_error(message) {} + class IncorrectThreadException : public std::runtime_error { + public: + IncorrectThreadException() : std::runtime_error("Realm accessed from incorrect thread.") {} }; - class UnitializedRealmException : public std::runtime_error - { - public: + class UnitializedRealmException : public std::runtime_error { + public: UnitializedRealmException(std::string message) : std::runtime_error(message) {} }; }