--- /dev/null
+////////////////////////////////////////////////////////////////////////////
+//
+// Copyright 2015 Realm Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////
+
+#ifndef REALM_PROPERTY_HPP
+#define REALM_PROPERTY_HPP
+
+#include "util/tagged_bool.hpp"
+
+#include <realm/util/features.h>
+
+#include <string>
+
+namespace realm {
+namespace util {
+ template<typename> class Optional;
+}
+class StringData;
+class BinaryData;
+class Timestamp;
+class Table;
+
+template<typename> class BasicRowExpr;
+using RowExpr = BasicRowExpr<Table>;
+
+enum class PropertyType : unsigned char {
+ Int = 0,
+ Bool = 1,
+ String = 2,
+ Data = 3,
+ Date = 4,
+ Float = 5,
+ Double = 6,
+ Object = 7, // currently must be either Array xor Nullable
+ LinkingObjects = 8, // currently must be Array and not Nullable
+
+ // deprecated and remains only for reading old files
+ Any = 9,
+
+ // Flags which can be combined with any of the above types except as noted
+ Required = 0,
+ Nullable = 64,
+ Array = 128,
+ Flags = Nullable | Array
+};
+
+struct Property {
+ using IsPrimary = util::TaggedBool<class IsPrimaryTag>;
+ using IsIndexed = util::TaggedBool<class IsIndexedTag>;
+
+ std::string name;
+ PropertyType type = PropertyType::Int;
+ std::string object_type;
+ std::string link_origin_property_name;
+ IsPrimary is_primary = false;
+ IsIndexed is_indexed = false;
+
+ size_t table_column = -1;
+
+ Property() = default;
+
+ Property(std::string name, PropertyType type, IsPrimary primary = false, IsIndexed indexed = false);
+
+ Property(std::string name, PropertyType type, std::string object_type,
+ std::string link_origin_property_name = "");
+
+ Property(Property const&) = default;
+ Property(Property&&) = default;
+ Property& operator=(Property const&) = default;
+ Property& operator=(Property&&) = default;
+
+ bool requires_index() const { return is_primary || is_indexed; }
+
+ bool type_is_indexable() const;
+ bool type_is_nullable() const;
+
+ std::string type_string() const;
+};
+
+template<typename E>
+constexpr auto to_underlying(E e)
+{
+ return static_cast<typename std::underlying_type<E>::type>(e);
+}
+
+inline constexpr PropertyType operator&(PropertyType a, PropertyType b)
+{
+ return static_cast<PropertyType>(to_underlying(a) & to_underlying(b));
+}
+
+inline constexpr PropertyType operator|(PropertyType a, PropertyType b)
+{
+ return static_cast<PropertyType>(to_underlying(a) | to_underlying(b));
+}
+
+inline constexpr PropertyType operator^(PropertyType a, PropertyType b)
+{
+ return static_cast<PropertyType>(to_underlying(a) ^ to_underlying(b));
+}
+
+inline constexpr PropertyType operator~(PropertyType a)
+{
+ return static_cast<PropertyType>(~to_underlying(a));
+}
+
+inline constexpr bool operator==(PropertyType a, PropertyType b)
+{
+ return to_underlying(a & ~PropertyType::Flags) == to_underlying(b & ~PropertyType::Flags);
+}
+
+inline constexpr bool operator!=(PropertyType a, PropertyType b)
+{
+ return !(a == b);
+}
+
+inline PropertyType& operator&=(PropertyType & a, PropertyType b)
+{
+ a = a & b;
+ return a;
+}
+
+inline PropertyType& operator|=(PropertyType & a, PropertyType b)
+{
+ a = a | b;
+ return a;
+}
+
+inline PropertyType& operator^=(PropertyType & a, PropertyType b)
+{
+ a = a ^ b;
+ return a;
+}
+
+inline constexpr bool is_array(PropertyType a)
+{
+ return to_underlying(a & PropertyType::Array) == to_underlying(PropertyType::Array);
+}
+
+inline constexpr bool is_nullable(PropertyType a)
+{
+ return to_underlying(a & PropertyType::Nullable) == to_underlying(PropertyType::Nullable);
+}
+
+template<typename Fn>
+static auto switch_on_type(PropertyType type, Fn&& fn)
+{
+ using PT = PropertyType;
+ bool is_optional = is_nullable(type);
+ switch (type & ~PropertyType::Flags) {
+ case PT::Int: return is_optional ? fn((util::Optional<int64_t>*)0) : fn((int64_t*)0);
+ case PT::Bool: return is_optional ? fn((util::Optional<bool>*)0) : fn((bool*)0);
+ case PT::Float: return is_optional ? fn((util::Optional<float>*)0) : fn((float*)0);
+ case PT::Double: return is_optional ? fn((util::Optional<double>*)0) : fn((double*)0);
+ case PT::String: return fn((StringData*)0);
+ case PT::Data: return fn((BinaryData*)0);
+ case PT::Date: return fn((Timestamp*)0);
+ case PT::Object: return fn((RowExpr*)0);
+ default: REALM_COMPILER_HINT_UNREACHABLE();
+ }
+}
+
+static const char *string_for_property_type(PropertyType type)
+{
+ if (is_array(type)) {
+ if (type == PropertyType::LinkingObjects)
+ return "linking objects";
+ return "array";
+ }
+ switch (type & ~PropertyType::Flags) {
+ case PropertyType::String: return "string";
+ case PropertyType::Int: return "int";
+ case PropertyType::Bool: return "bool";
+ case PropertyType::Date: return "date";
+ case PropertyType::Data: return "data";
+ case PropertyType::Double: return "double";
+ case PropertyType::Float: return "float";
+ case PropertyType::Object: return "object";
+ case PropertyType::Any: return "any";
+ case PropertyType::LinkingObjects: return "linking objects";
+ default: REALM_COMPILER_HINT_UNREACHABLE();
+ }
+}
+
+inline Property::Property(std::string name, PropertyType type,
+ IsPrimary primary, IsIndexed indexed)
+: name(std::move(name))
+, type(type)
+, is_primary(primary)
+, is_indexed(indexed)
+{
+}
+
+inline Property::Property(std::string name, PropertyType type,
+ std::string object_type,
+ std::string link_origin_property_name)
+: name(std::move(name))
+, type(type)
+, object_type(std::move(object_type))
+, link_origin_property_name(std::move(link_origin_property_name))
+{
+}
+
+inline bool Property::type_is_indexable() const
+{
+ return type == PropertyType::Int
+ || type == PropertyType::Bool
+ || type == PropertyType::Date
+ || type == PropertyType::String;
+}
+
+inline bool Property::type_is_nullable() const
+{
+ return !(is_array(type) && type == PropertyType::Object) && type != PropertyType::LinkingObjects;
+}
+
+inline std::string Property::type_string() const
+{
+ if (is_array(type)) {
+ if (type == PropertyType::Object)
+ return "array<" + object_type + ">";
+ if (type == PropertyType::LinkingObjects)
+ return "linking objects<" + object_type + ">";
+ return std::string("array<") + string_for_property_type(type & ~PropertyType::Flags) + ">";
+ }
+ switch (auto base_type = (type & ~PropertyType::Flags)) {
+ case PropertyType::Object:
+ return "<" + object_type + ">";
+ case PropertyType::LinkingObjects:
+ return "linking objects<" + object_type + ">";
+ default:
+ return string_for_property_type(base_type);
+ }
+}
+
+inline bool operator==(Property const& lft, Property const& rgt)
+{
+ // note: not checking table_column
+ // ordered roughly by the cost of the check
+ return to_underlying(lft.type) == to_underlying(rgt.type)
+ && lft.is_primary == rgt.is_primary
+ && lft.requires_index() == rgt.requires_index()
+ && lft.name == rgt.name
+ && lft.object_type == rgt.object_type
+ && lft.link_origin_property_name == rgt.link_origin_property_name;
+}
+} // namespace realm
+
+#endif // REALM_PROPERTY_HPP