Cleanup: Split some code out of rna_access.c
authorBastien Montagne <montagne29@wanadoo.fr>
Thu, 22 Aug 2019 13:31:07 +0000 (15:31 +0200)
committerBastien Montagne <montagne29@wanadoo.fr>
Thu, 22 Aug 2019 13:33:44 +0000 (15:33 +0200)
That file was getting out of control, now comparison/override RNA code is
in `rna_access_compare_override.c`. 1K lines of code for now, but that
area is likely to grow more in the future...

Note that we can probably split more out of `rna_access.c`, but for now
that will do.

source/blender/makesrna/intern/CMakeLists.txt
source/blender/makesrna/intern/rna_access.c
source/blender/makesrna/intern/rna_access_compare_override.c [new file with mode: 0644]
source/blender/makesrna/intern/rna_access_internal.h [new file with mode: 0644]

index 7c31f078b6df7f108647ef2f8b640d2454e30acd..2745cfa9740dafdbfa2d276a2acc5b60a290c3e7 100644 (file)
@@ -364,9 +364,11 @@ add_custom_command(
 # Build bf_rna
 set(SRC
   rna_access.c
+  rna_access_compare_override.c
   ${GENSRC}
 
   ${SRC_RNA_INC}
+  rna_access_internal.h
   rna_internal.h
   rna_internal_types.h
   rna_mesh_utils.h
index 7b7af5c12db882262a505319b213572f96311d15..c4b0e43fd706d4efec39d2e2ac7a675716a95d01 100644 (file)
 #include "BLI_ghash.h"
 #include "BLI_math.h"
 
-#ifdef DEBUG_OVERRIDE_TIMEIT
-#  include "PIL_time_utildefines.h"
-#endif
-
 #include "BLF_api.h"
 #include "BLT_translation.h"
 
@@ -49,7 +45,6 @@
 #include "BKE_idcode.h"
 #include "BKE_idprop.h"
 #include "BKE_fcurve.h"
-#include "BKE_library_override.h"
 #include "BKE_main.h"
 #include "BKE_report.h"
 
@@ -67,6 +62,7 @@
 #include "WM_types.h"
 
 #include "rna_internal.h"
+#include "rna_access_internal.h"
 
 const PointerRNA PointerRNA_NULL = {{NULL}};
 
@@ -249,7 +245,7 @@ void RNA_pointer_recast(PointerRNA *ptr, PointerRNA *r_ptr)
 
 /* ID Properties */
 
-static void rna_idproperty_touch(IDProperty *idprop)
+void rna_idproperty_touch(IDProperty *idprop)
 {
   /* so the property is seen as 'set' by rna */
   idprop->flag &= ~IDP_FLAG_GHOST;
@@ -619,7 +615,7 @@ PropertyRNA *rna_ensure_property_realdata(PropertyRNA **prop, PointerRNA *ptr)
   return rna_idproperty_check_ex(prop, ptr, true);
 }
 
-static PropertyRNA *rna_ensure_property(PropertyRNA *prop)
+PropertyRNA *rna_ensure_property(PropertyRNA *prop)
 {
   /* the quick version if we don't need the idproperty */
 
@@ -1171,11 +1167,6 @@ int RNA_property_flag(PropertyRNA *prop)
   return rna_ensure_property(prop)->flag;
 }
 
-int RNA_property_override_flag(PropertyRNA *prop)
-{
-  return rna_ensure_property(prop)->flag_override;
-}
-
 /**
  * Get the tags set for \a prop as int bitfield.
  * \note Doesn't perform any validity check on the set bits. #RNA_def_property_tags does this
@@ -2194,77 +2185,6 @@ bool RNA_property_animated(PointerRNA *ptr, PropertyRNA *prop)
 
   return false;
 }
-
-/** \note Does not take into account editable status, this has to be checked separately
- * (using #RNA_property_editable_flag() usually). */
-bool RNA_property_overridable_get(PointerRNA *ptr, PropertyRNA *prop)
-{
-  if (prop->magic == RNA_MAGIC) {
-    /* Special handling for insertions of constraints or modifiers... */
-    /* TODO Note We may want to add a more generic system to RNA
-     * (like a special property in struct of items)
-     * if we get more overrideable collections,
-     * for now we can live with those special-cases handling I think. */
-    if (RNA_struct_is_a(ptr->type, &RNA_Constraint)) {
-      bConstraint *con = ptr->data;
-      if (con->flag & CONSTRAINT_OVERRIDE_LIBRARY_LOCAL) {
-        return true;
-      }
-    }
-    else if (RNA_struct_is_a(ptr->type, &RNA_Modifier)) {
-      ModifierData *mod = ptr->data;
-      if (mod->flag & eModifierFlag_OverrideLibrary_Local) {
-        return true;
-      }
-    }
-    /* If this is a RNA-defined property (real or 'virtual' IDProp),
-     * we want to use RNA prop flag. */
-    return !(prop->flag_override & PROPOVERRIDE_NO_COMPARISON) &&
-           (prop->flag_override & PROPOVERRIDE_OVERRIDABLE_LIBRARY);
-  }
-  else {
-    /* If this is a real 'pure' IDProp (aka custom property), we want to use the IDProp flag. */
-    return !(prop->flag_override & PROPOVERRIDE_NO_COMPARISON) &&
-           (((IDProperty *)prop)->flag & IDP_FLAG_OVERRIDABLE_LIBRARY);
-  }
-}
-
-/* Should only be used for custom properties */
-bool RNA_property_overridable_library_set(PointerRNA *UNUSED(ptr),
-                                          PropertyRNA *prop,
-                                          const bool is_overridable)
-{
-  /* Only works for pure custom properties IDProps. */
-  if (prop->magic != RNA_MAGIC) {
-    IDProperty *idprop = (IDProperty *)prop;
-
-    idprop->flag = is_overridable ? (idprop->flag | IDP_FLAG_OVERRIDABLE_LIBRARY) :
-                                    (idprop->flag & ~IDP_FLAG_OVERRIDABLE_LIBRARY);
-    return true;
-  }
-
-  return false;
-}
-
-bool RNA_property_overridden(PointerRNA *ptr, PropertyRNA *prop)
-{
-  char *rna_path = RNA_path_from_ID_to_property(ptr, prop);
-  ID *id = ptr->id.data;
-
-  if (rna_path == NULL || id == NULL || id->override_library == NULL) {
-    return false;
-  }
-
-  return (BKE_override_library_property_find(id->override_library, rna_path) != NULL);
-}
-
-bool RNA_property_comparable(PointerRNA *UNUSED(ptr), PropertyRNA *prop)
-{
-  prop = rna_ensure_property(prop);
-
-  return !(prop->flag_override & PROPOVERRIDE_NO_COMPARISON);
-}
-
 /* this function is to check if its possible to create a valid path from the ID
  * its slow so don't call in a loop */
 bool RNA_property_path_from_ID_check(PointerRNA *ptr, PropertyRNA *prop)
@@ -8115,59 +8035,6 @@ bool RNA_property_assign_default(PointerRNA *ptr, PropertyRNA *prop)
   }
 }
 
-static bool rna_property_override_operation_apply(Main *bmain,
-                                                  PointerRNA *ptr_local,
-                                                  PointerRNA *ptr_override,
-                                                  PointerRNA *ptr_storage,
-                                                  PropertyRNA *prop_local,
-                                                  PropertyRNA *prop_override,
-                                                  PropertyRNA *prop_storage,
-                                                  PointerRNA *ptr_item_local,
-                                                  PointerRNA *ptr_item_override,
-                                                  PointerRNA *ptr_item_storage,
-                                                  IDOverrideLibraryPropertyOperation *opop);
-
-bool RNA_property_copy(
-    Main *bmain, PointerRNA *ptr, PointerRNA *fromptr, PropertyRNA *prop, int index)
-{
-  if (!RNA_property_editable(ptr, prop)) {
-    return false;
-  }
-
-  PropertyRNA *prop_dst = prop;
-  PropertyRNA *prop_src = prop;
-
-  /* Ensure we get real property data,
-   * be it an actual RNA property, or an IDProperty in disguise. */
-  prop_dst = rna_ensure_property_realdata(&prop_dst, ptr);
-  prop_src = rna_ensure_property_realdata(&prop_src, fromptr);
-
-  /* IDprops: destination may not exist, if source does and is set, try to create it. */
-  /* Note: this is sort of quick hack/bandage to fix the issue,
-   * we need to rethink how IDProps are handled in 'diff' RNA code completely, imho... */
-  if (prop_src != NULL && prop_dst == NULL && RNA_property_is_set(fromptr, prop)) {
-    BLI_assert(prop_src->magic != RNA_MAGIC);
-    IDProperty *idp_dst = RNA_struct_idprops(ptr, true);
-    IDProperty *prop_idp_dst = IDP_CopyProperty((IDProperty *)prop_src);
-    IDP_AddToGroup(idp_dst, prop_idp_dst);
-    rna_idproperty_touch(prop_idp_dst);
-    /* Nothing else to do here... */
-    return true;
-  }
-
-  if (ELEM(NULL, prop_dst, prop_src)) {
-    return false;
-  }
-
-  IDOverrideLibraryPropertyOperation opop = {
-      .operation = IDOVERRIDE_LIBRARY_OP_REPLACE,
-      .subitem_reference_index = index,
-      .subitem_local_index = index,
-  };
-  return rna_property_override_operation_apply(
-      bmain, ptr, fromptr, NULL, prop_dst, prop_src, NULL, NULL, NULL, NULL, &opop);
-}
-
 /* use RNA_warning macro which includes __func__ suffix */
 void _RNA_warning(const char *format, ...)
 {
@@ -8190,934 +8057,6 @@ void _RNA_warning(const char *format, ...)
 #endif
 }
 
-static int rna_property_override_diff(Main *bmain,
-                                      PointerRNA *ptr_a,
-                                      PointerRNA *ptr_b,
-                                      PropertyRNA *prop,
-                                      PropertyRNA *prop_a,
-                                      PropertyRNA *prop_b,
-                                      const char *rna_path,
-                                      eRNACompareMode mode,
-                                      IDOverrideLibrary *override,
-                                      const int flags,
-                                      eRNAOverrideMatchResult *r_report_flags);
-
-bool RNA_property_equals(
-    Main *bmain, PointerRNA *ptr_a, PointerRNA *ptr_b, PropertyRNA *prop, eRNACompareMode mode)
-{
-  BLI_assert(ELEM(mode, RNA_EQ_STRICT, RNA_EQ_UNSET_MATCH_ANY, RNA_EQ_UNSET_MATCH_NONE));
-
-  return (rna_property_override_diff(
-              bmain, ptr_a, ptr_b, prop, NULL, NULL, NULL, mode, NULL, 0, NULL) == 0);
-}
-
-bool RNA_struct_equals(Main *bmain, PointerRNA *ptr_a, PointerRNA *ptr_b, eRNACompareMode mode)
-{
-  CollectionPropertyIterator iter;
-  PropertyRNA *iterprop;
-  bool equals = true;
-
-  if (ptr_a == NULL && ptr_b == NULL) {
-    return true;
-  }
-  else if (ptr_a == NULL || ptr_b == NULL) {
-    return false;
-  }
-  else if (ptr_a->type != ptr_b->type) {
-    return false;
-  }
-
-  iterprop = RNA_struct_iterator_property(ptr_a->type);
-
-  RNA_property_collection_begin(ptr_a, iterprop, &iter);
-  for (; iter.valid; RNA_property_collection_next(&iter)) {
-    PropertyRNA *prop = iter.ptr.data;
-
-    if (!RNA_property_equals(bmain, ptr_a, ptr_b, prop, mode)) {
-      equals = false;
-      break;
-    }
-  }
-  RNA_property_collection_end(&iter);
-
-  return equals;
-}
-
-/* Low-level functions, also used by non-override RNA API like copy or equality check. */
-
-/** Generic RNA property diff function.
- *
- * \note about \a prop and \a prop_a/prop_b parameters:
- * the former is expected to be an 'un-resolved' one,
- * while the two later are expected to be fully resolved ones
- * (i.e. to be the IDProps when they should be, etc.).
- * When \a prop is given, \a prop_a and \a prop_b should always be NULL, and vice-versa.
- * This is necessary, because we cannot perform 'set/unset' checks on resolved properties
- * (unset IDProps would merely be NULL then).
- *
- * \note When there is no equality,
- * but we cannot determine an order (greater than/lesser than), we return 1.
- */
-static int rna_property_override_diff(Main *bmain,
-                                      PointerRNA *ptr_a,
-                                      PointerRNA *ptr_b,
-                                      PropertyRNA *prop,
-                                      PropertyRNA *prop_a,
-                                      PropertyRNA *prop_b,
-                                      const char *rna_path,
-                                      eRNACompareMode mode,
-                                      IDOverrideLibrary *override,
-                                      const int flags,
-                                      eRNAOverrideMatchResult *r_report_flags)
-{
-  if (prop != NULL) {
-    BLI_assert(prop_a == NULL && prop_b == NULL);
-    prop_a = prop;
-    prop_b = prop;
-  }
-
-  if (ELEM(NULL, prop_a, prop_b)) {
-    return (prop_a == prop_b) ? 0 : 1;
-  }
-
-  if (!RNA_property_comparable(ptr_a, prop_a) || !RNA_property_comparable(ptr_b, prop_b)) {
-    return 0;
-  }
-
-  if (mode == RNA_EQ_UNSET_MATCH_ANY) {
-    /* uninitialized properties are assumed to match anything */
-    if (!RNA_property_is_set(ptr_a, prop_a) || !RNA_property_is_set(ptr_b, prop_b)) {
-      return 0;
-    }
-  }
-  else if (mode == RNA_EQ_UNSET_MATCH_NONE) {
-    /* unset properties never match set properties */
-    if (RNA_property_is_set(ptr_a, prop_a) != RNA_property_is_set(ptr_b, prop_b)) {
-      return 1;
-    }
-  }
-
-  if (prop != NULL) {
-    /* Ensure we get real property data, be it an actual RNA property,
-     * or an IDProperty in disguise. */
-    prop_a = rna_ensure_property_realdata(&prop_a, ptr_a);
-    prop_b = rna_ensure_property_realdata(&prop_b, ptr_b);
-
-    if (ELEM(NULL, prop_a, prop_b)) {
-      return (prop_a == prop_b) ? 0 : 1;
-    }
-  }
-
-  /* Check if we are working with arrays. */
-  const bool is_array_a = RNA_property_array_check(prop_a);
-  const bool is_array_b = RNA_property_array_check(prop_b);
-
-  if (is_array_a != is_array_b) {
-    /* Should probably never happen actually... */
-    BLI_assert(0);
-    return is_array_a ? 1 : -1;
-  }
-
-  /* Get the length of the array to work with. */
-  const int len_a = RNA_property_array_length(ptr_a, prop_a);
-  const int len_b = RNA_property_array_length(ptr_b, prop_b);
-
-  if (len_a != len_b) {
-    /* Do not handle override in that case,
-     * we do not support insertion/deletion from arrays for now. */
-    return len_a > len_b ? 1 : -1;
-  }
-
-  if (is_array_a && len_a == 0) {
-    /* Empty arrays, will happen in some case with dynamic ones. */
-    return 0;
-  }
-
-  RNAPropOverrideDiff override_diff = NULL;
-  /* Special case for IDProps, we use default callback then. */
-  if (prop_a->magic != RNA_MAGIC) {
-    override_diff = rna_property_override_diff_default;
-    if (prop_b->magic == RNA_MAGIC && prop_b->override_diff != override_diff) {
-      override_diff = NULL;
-    }
-  }
-  else if (prop_b->magic != RNA_MAGIC) {
-    override_diff = rna_property_override_diff_default;
-    if (prop_a->override_diff != override_diff) {
-      override_diff = NULL;
-    }
-  }
-  else if (prop_a->override_diff == prop_b->override_diff) {
-    override_diff = prop_a->override_diff;
-  }
-
-  if (override_diff == NULL) {
-#ifndef NDEBUG
-    printf("'%s' gives unmatching or NULL RNA diff callbacks, should not happen (%d vs. %d).\n",
-           rna_path ?
-               rna_path :
-               (prop_a->magic != RNA_MAGIC ? ((IDProperty *)prop_a)->name : prop_a->identifier),
-           prop_a->magic == RNA_MAGIC,
-           prop_b->magic == RNA_MAGIC);
-#endif
-    BLI_assert(0);
-    return 1;
-  }
-
-  bool override_changed = false;
-  int diff_flags = flags;
-  if (!RNA_property_overridable_get(ptr_a, prop_a)) {
-    diff_flags &= ~RNA_OVERRIDE_COMPARE_CREATE;
-  }
-  const int diff = override_diff(bmain,
-                                 ptr_a,
-                                 ptr_b,
-                                 prop_a,
-                                 prop_b,
-                                 len_a,
-                                 len_b,
-                                 mode,
-                                 override,
-                                 rna_path,
-                                 diff_flags,
-                                 &override_changed);
-  if (override_changed && r_report_flags) {
-    *r_report_flags |= RNA_OVERRIDE_MATCH_RESULT_CREATED;
-  }
-
-  return diff;
-}
-
-/* Modify local data-block to make it ready for override application
- * (only needed for diff operations, where we use
- * the local data-block's data as second operand). */
-static bool rna_property_override_operation_store(Main *bmain,
-                                                  PointerRNA *ptr_local,
-                                                  PointerRNA *ptr_reference,
-                                                  PointerRNA *ptr_storage,
-                                                  PropertyRNA *prop_local,
-                                                  PropertyRNA *prop_reference,
-                                                  PropertyRNA *prop_storage,
-                                                  IDOverrideLibraryProperty *op)
-{
-  int len_local, len_reference, len_storage = 0;
-  bool changed = false;
-
-  if (ptr_storage == NULL) {
-    return changed;
-  }
-
-  /* get the length of the array to work with */
-  len_local = RNA_property_array_length(ptr_local, prop_local);
-  len_reference = RNA_property_array_length(ptr_reference, prop_reference);
-  if (prop_storage) {
-    len_storage = RNA_property_array_length(ptr_storage, prop_storage);
-  }
-
-  if (len_local != len_reference || len_local != len_storage) {
-    /* Do not handle override in that case,
-     * we do not support insertion/deletion from arrays for now. */
-    return changed;
-  }
-
-  BLI_assert(prop_local->override_store == prop_reference->override_store &&
-             (!ptr_storage || prop_local->override_store == prop_storage->override_store) &&
-             prop_local->override_store != NULL);
-
-  for (IDOverrideLibraryPropertyOperation *opop = op->operations.first; opop; opop = opop->next) {
-    /* Only needed for diff operations. */
-    if (!ELEM(opop->operation,
-              IDOVERRIDE_LIBRARY_OP_ADD,
-              IDOVERRIDE_LIBRARY_OP_SUBTRACT,
-              IDOVERRIDE_LIBRARY_OP_MULTIPLY)) {
-      continue;
-    }
-
-    if (prop_local->override_store(bmain,
-                                   ptr_local,
-                                   ptr_reference,
-                                   ptr_storage,
-                                   prop_local,
-                                   prop_reference,
-                                   prop_storage,
-                                   len_local,
-                                   len_reference,
-                                   len_storage,
-                                   opop)) {
-      changed = true;
-    }
-  }
-
-  return changed;
-}
-
-static bool rna_property_override_operation_apply(Main *bmain,
-                                                  PointerRNA *ptr_dst,
-                                                  PointerRNA *ptr_src,
-                                                  PointerRNA *ptr_storage,
-                                                  PropertyRNA *prop_dst,
-                                                  PropertyRNA *prop_src,
-                                                  PropertyRNA *prop_storage,
-                                                  PointerRNA *ptr_item_dst,
-                                                  PointerRNA *ptr_item_src,
-                                                  PointerRNA *ptr_item_storage,
-                                                  IDOverrideLibraryPropertyOperation *opop)
-{
-  int len_dst, len_src, len_storage = 0;
-
-  const short override_op = opop->operation;
-
-  if (override_op == IDOVERRIDE_LIBRARY_OP_NOOP) {
-    return true;
-  }
-
-  if (ELEM(override_op,
-           IDOVERRIDE_LIBRARY_OP_ADD,
-           IDOVERRIDE_LIBRARY_OP_SUBTRACT,
-           IDOVERRIDE_LIBRARY_OP_MULTIPLY) &&
-      !ptr_storage) {
-    /* We cannot apply 'diff' override operations without some reference storage.
-     * This should typically only happen at read time of .blend file... */
-    return false;
-  }
-
-  if (ELEM(override_op,
-           IDOVERRIDE_LIBRARY_OP_ADD,
-           IDOVERRIDE_LIBRARY_OP_SUBTRACT,
-           IDOVERRIDE_LIBRARY_OP_MULTIPLY) &&
-      !prop_storage) {
-    /* We cannot apply 'diff' override operations without some reference storage.
-     * This should typically only happen at read time of .blend file... */
-    return false;
-  }
-
-  RNAPropOverrideApply override_apply = NULL;
-  /* Special case for IDProps, we use default callback then. */
-  if (prop_dst->magic != RNA_MAGIC) {
-    override_apply = rna_property_override_apply_default;
-    if (prop_src->magic == RNA_MAGIC && prop_src->override_apply != override_apply) {
-      override_apply = NULL;
-    }
-  }
-  else if (prop_src->magic != RNA_MAGIC) {
-    override_apply = rna_property_override_apply_default;
-    if (prop_dst->override_apply != override_apply) {
-      override_apply = NULL;
-    }
-  }
-  else if (prop_dst->override_apply == prop_src->override_apply) {
-    override_apply = prop_dst->override_apply;
-  }
-
-  if (ptr_storage && prop_storage->magic == RNA_MAGIC &&
-      prop_storage->override_apply != override_apply) {
-    override_apply = NULL;
-  }
-
-  if (override_apply == NULL) {
-#ifndef NDEBUG
-    printf("'%s' gives unmatching or NULL RNA copy callbacks, should not happen (%d vs. %d).\n",
-           prop_dst->magic != RNA_MAGIC ? ((IDProperty *)prop_dst)->name : prop_dst->identifier,
-           prop_dst->magic == RNA_MAGIC,
-           prop_src->magic == RNA_MAGIC);
-#endif
-    BLI_assert(0);
-    return false;
-  }
-
-  /* get the length of the array to work with */
-  len_dst = RNA_property_array_length(ptr_dst, prop_dst);
-  len_src = RNA_property_array_length(ptr_src, prop_src);
-  if (ptr_storage) {
-    len_storage = RNA_property_array_length(ptr_storage, prop_storage);
-  }
-
-  if (len_dst != len_src || (ptr_storage && len_dst != len_storage)) {
-    /* Do not handle override in that case,
-     * we do not support insertion/deletion from arrays for now. */
-    return false;
-  }
-
-  /* get and set the default values as appropriate for the various types */
-  return override_apply(bmain,
-                        ptr_dst,
-                        ptr_src,
-                        ptr_storage,
-                        prop_dst,
-                        prop_src,
-                        prop_storage,
-                        len_dst,
-                        len_src,
-                        len_storage,
-                        ptr_item_dst,
-                        ptr_item_src,
-                        ptr_item_storage,
-                        opop);
-}
-
-/**
- * Check whether reference and local overridden data match (are the same),
- * with respect to given restrictive sets of properties.
- * If requested, will generate needed new property overrides, and/or restore values from reference.
- *
- * \param r_report_flags: If given,
- * will be set with flags matching actions taken by the function on \a ptr_local.
- *
- * \return True if _resulting_ \a ptr_local does match \a ptr_reference.
- */
-bool RNA_struct_override_matches(Main *bmain,
-                                 PointerRNA *ptr_local,
-                                 PointerRNA *ptr_reference,
-                                 const char *root_path,
-                                 IDOverrideLibrary *override,
-                                 const eRNAOverrideMatch flags,
-                                 eRNAOverrideMatchResult *r_report_flags)
-{
-  CollectionPropertyIterator iter;
-  PropertyRNA *iterprop;
-  bool matching = true;
-
-  BLI_assert(ptr_local->type == ptr_reference->type);
-  BLI_assert(ptr_local->id.data && ptr_reference->id.data);
-
-  const bool ignore_non_overridable = (flags & RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE) != 0;
-  const bool ignore_overridden = (flags & RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN) != 0;
-  const bool do_create = (flags & RNA_OVERRIDE_COMPARE_CREATE) != 0;
-  const bool do_restore = (flags & RNA_OVERRIDE_COMPARE_RESTORE) != 0;
-
-//#define DEBUG_OVERRIDE_TIMEIT
-#ifdef DEBUG_OVERRIDE_TIMEIT
-  static float _sum_time_global = 0.0f;
-  static float _num_time_global = 0.0f;
-  double _timeit_time_global;
-  static float _sum_time_diffing = 0.0f;
-  static float _delta_time_diffing = 0.0f;
-  static int _num_delta_time_diffing = 0.0f;
-  static float _num_time_diffing = 0.0f;
-  double _timeit_time_diffing;
-
-  if (!root_path) {
-    _delta_time_diffing = 0.0f;
-    _num_delta_time_diffing = 0;
-    _timeit_time_global = PIL_check_seconds_timer();
-  }
-#endif
-
-  iterprop = RNA_struct_iterator_property(ptr_local->type);
-
-  for (RNA_property_collection_begin(ptr_local, iterprop, &iter); iter.valid;
-       RNA_property_collection_next(&iter)) {
-    PropertyRNA *prop_local = iter.ptr.data;
-    PropertyRNA *prop_reference = iter.ptr.data;
-
-    /* Ensure we get real property data, be it an actual RNA property,
-     * or an IDProperty in disguise. */
-    prop_local = rna_ensure_property_realdata(&prop_local, ptr_local);
-    prop_reference = rna_ensure_property_realdata(&prop_reference, ptr_reference);
-
-    if (ELEM(NULL, prop_local, prop_reference)) {
-      continue;
-    }
-
-    if (ignore_non_overridable && !RNA_property_overridable_get(ptr_local, prop_local)) {
-      continue;
-    }
-
-#if 0 /* This actually makes things slower, since it has to check for animation paths etc! */
-    if (RNA_property_animated(ptr_local, prop_local)) {
-      /* We cannot do anything here really, animation is some kind of dynamic overrides that has
-       * precedence over static one... */
-      continue;
-    }
-#endif
-
-#define RNA_PATH_BUFFSIZE 8192
-#define RNA_PATH_PRINTF(_str, ...) \
-  if (BLI_snprintf(rna_path, RNA_PATH_BUFFSIZE, (_str), __VA_ARGS__) >= RNA_PATH_BUFFSIZE) { \
-    rna_path = BLI_sprintfN((_str), __VA_ARGS__); \
-  } \
-  (void)0
-#define RNA_PATH_FREE \
-  if (rna_path != rna_path_buffer) \
-  MEM_freeN(rna_path)
-
-    char rna_path_buffer[RNA_PATH_BUFFSIZE];
-    char *rna_path = rna_path_buffer;
-
-    /* XXX TODO this will have to be refined to handle collections insertions, and array items */
-    if (root_path) {
-      /* Inlined building, much much more efficient. */
-      if (prop_local->magic == RNA_MAGIC) {
-        RNA_PATH_PRINTF("%s.%s", root_path, RNA_property_identifier(prop_local));
-      }
-      else {
-        RNA_PATH_PRINTF("%s[\"%s\"]", root_path, RNA_property_identifier(prop_local));
-      }
-    }
-    else {
-      /* This is rather slow, but is not much called, so not really worth optimizing. */
-      rna_path = RNA_path_from_ID_to_property(ptr_local, prop_local);
-    }
-    if (rna_path == NULL) {
-      continue;
-    }
-
-    //    printf("Override Checking %s\n", rna_path);
-
-    if (ignore_overridden && BKE_override_library_property_find(override, rna_path) != NULL) {
-      RNA_PATH_FREE;
-      continue;
-    }
-
-#ifdef DEBUG_OVERRIDE_TIMEIT
-    if (!root_path) {
-      _timeit_time_diffing = PIL_check_seconds_timer();
-    }
-#endif
-
-    eRNAOverrideMatchResult report_flags = 0;
-    const int diff = rna_property_override_diff(bmain,
-                                                ptr_local,
-                                                ptr_reference,
-                                                NULL,
-                                                prop_local,
-                                                prop_reference,
-                                                rna_path,
-                                                RNA_EQ_STRICT,
-                                                override,
-                                                flags,
-                                                &report_flags);
-
-#ifdef DEBUG_OVERRIDE_TIMEIT
-    if (!root_path) {
-      const float _delta_time = (float)(PIL_check_seconds_timer() - _timeit_time_diffing);
-      _delta_time_diffing += _delta_time;
-      _num_delta_time_diffing++;
-    }
-#endif
-
-    matching = matching && diff == 0;
-    if (r_report_flags) {
-      *r_report_flags |= report_flags;
-    }
-
-    if (diff != 0) {
-      /* XXX TODO: refine this for per-item overriding of arrays... */
-      IDOverrideLibraryProperty *op = BKE_override_library_property_find(override, rna_path);
-      IDOverrideLibraryPropertyOperation *opop = op ? op->operations.first : NULL;
-
-      if (do_restore && (report_flags & RNA_OVERRIDE_MATCH_RESULT_CREATED) == 0) {
-        /* We are allowed to restore to reference's values. */
-        if (ELEM(NULL, op, opop) || opop->operation == IDOVERRIDE_LIBRARY_OP_NOOP) {
-          /* We should restore that property to its reference value */
-          if (RNA_property_editable(ptr_local, prop_local)) {
-            IDOverrideLibraryPropertyOperation opop_tmp = {
-                .operation = IDOVERRIDE_LIBRARY_OP_REPLACE,
-                .subitem_reference_index = -1,
-                .subitem_local_index = -1,
-            };
-            rna_property_override_operation_apply(bmain,
-                                                  ptr_local,
-                                                  ptr_reference,
-                                                  NULL,
-                                                  prop_local,
-                                                  prop_reference,
-                                                  NULL,
-                                                  NULL,
-                                                  NULL,
-                                                  NULL,
-                                                  &opop_tmp);
-            if (r_report_flags) {
-              *r_report_flags |= RNA_OVERRIDE_MATCH_RESULT_RESTORED;
-            }
-          }
-          else {
-            /* Too noisy for now, this triggers on runtime props like transform matrices etc. */
-#if 0
-            BLI_assert(!"We have differences between reference and "
-                       "overriding data on non-editable property.");
-#endif
-            matching = false;
-          }
-        }
-      }
-      else if ((report_flags & RNA_OVERRIDE_MATCH_RESULT_CREATED) == 0 && ELEM(NULL, op, opop)) {
-        /* This property is not overridden, and differs from reference, so we have no match. */
-        matching = false;
-        if (!(do_create || do_restore)) {
-          /* Since we have no 'changing' action allowed, we can break here. */
-          MEM_SAFE_FREE(rna_path);
-          break;
-        }
-      }
-    }
-
-    RNA_PATH_FREE;
-
-#undef RNA_PATH_BUFFSIZE
-#undef RNA_PATH_PRINTF
-#undef RNA_PATH_FREE
-  }
-  RNA_property_collection_end(&iter);
-
-#ifdef DEBUG_OVERRIDE_TIMEIT
-  if (!root_path) {
-    const float _delta_time = (float)(PIL_check_seconds_timer() - _timeit_time_global);
-    _sum_time_global += _delta_time;
-    _num_time_global++;
-    _sum_time_diffing += _delta_time_diffing;
-    _num_time_diffing++;
-    printf("ID: %s\n", ((ID *)ptr_local->id.data)->name);
-    printf("time end      (%s): %.6f\n", __func__, _delta_time);
-    printf("time averaged (%s): %.6f (total: %.6f, in %d runs)\n",
-           __func__,
-           (_sum_time_global / _num_time_global),
-           _sum_time_global,
-           (int)_num_time_global);
-    printf("diffing time end      (%s): %.6f (in %d runs)\n",
-           __func__,
-           _delta_time_diffing,
-           _num_delta_time_diffing);
-    printf("diffing time averaged (%s): %.6f (total: %.6f, in %d runs)\n",
-           __func__,
-           (_sum_time_diffing / _num_time_diffing),
-           _sum_time_diffing,
-           (int)_num_time_diffing);
-  }
-#endif
-
-  return matching;
-}
-
-/** Store needed second operands into \a storage data-block
- * for differential override operations. */
-bool RNA_struct_override_store(Main *bmain,
-                               PointerRNA *ptr_local,
-                               PointerRNA *ptr_reference,
-                               PointerRNA *ptr_storage,
-                               IDOverrideLibrary *override)
-{
-  bool changed = false;
-
-#ifdef DEBUG_OVERRIDE_TIMEIT
-  TIMEIT_START_AVERAGED(RNA_struct_override_store);
-#endif
-  for (IDOverrideLibraryProperty *op = override->properties.first; op; op = op->next) {
-    /* Simplified for now! */
-    PointerRNA data_reference, data_local;
-    PropertyRNA *prop_reference, *prop_local;
-
-    if (RNA_path_resolve_property(ptr_local, op->rna_path, &data_local, &prop_local) &&
-        RNA_path_resolve_property(ptr_reference, op->rna_path, &data_reference, &prop_reference)) {
-      PointerRNA data_storage;
-      PropertyRNA *prop_storage = NULL;
-
-      /* It is totally OK if this does not success,
-       * only a subset of override operations actually need storage. */
-      if (ptr_storage && (ptr_storage->id.data != NULL)) {
-        RNA_path_resolve_property(ptr_storage, op->rna_path, &data_storage, &prop_storage);
-      }
-
-      if (rna_property_override_operation_store(bmain,
-                                                &data_local,
-                                                &data_reference,
-                                                &data_storage,
-                                                prop_reference,
-                                                prop_local,
-                                                prop_storage,
-                                                op)) {
-        changed = true;
-      }
-    }
-  }
-#ifdef DEBUG_OVERRIDE_TIMEIT
-  TIMEIT_END_AVERAGED(RNA_struct_override_store);
-#endif
-
-  return changed;
-}
-
-static void rna_property_override_apply_ex(Main *bmain,
-                                           PointerRNA *ptr_dst,
-                                           PointerRNA *ptr_src,
-                                           PointerRNA *ptr_storage,
-                                           PropertyRNA *prop_dst,
-                                           PropertyRNA *prop_src,
-                                           PropertyRNA *prop_storage,
-                                           PointerRNA *ptr_item_dst,
-                                           PointerRNA *ptr_item_src,
-                                           PointerRNA *ptr_item_storage,
-                                           IDOverrideLibraryProperty *op,
-                                           const bool do_insert)
-{
-  for (IDOverrideLibraryPropertyOperation *opop = op->operations.first; opop; opop = opop->next) {
-    if (!do_insert != !ELEM(opop->operation,
-                            IDOVERRIDE_LIBRARY_OP_INSERT_AFTER,
-                            IDOVERRIDE_LIBRARY_OP_INSERT_BEFORE)) {
-      if (!do_insert) {
-        printf("Skipping insert override operations in first pass (%s)!\n", op->rna_path);
-      }
-      continue;
-    }
-
-    /* Note: will have to think about putting that logic into its own function maybe?
-     * Would be nice to have it in a single place...
-     * Note that here, src is the local saved ID, and dst is a copy of the linked ID (since we use
-     * local ID as storage to apply local changes on top of a clean copy of the linked data). */
-    PointerRNA private_ptr_item_dst, private_ptr_item_src, private_ptr_item_storage;
-    if (opop->subitem_local_name != NULL || opop->subitem_reference_name != NULL ||
-        opop->subitem_local_index != -1 || opop->subitem_reference_index != -1) {
-      RNA_POINTER_INVALIDATE(&private_ptr_item_dst);
-      RNA_POINTER_INVALIDATE(&private_ptr_item_src);
-      RNA_POINTER_INVALIDATE(&private_ptr_item_storage);
-      if (opop->subitem_local_name != NULL) {
-        RNA_property_collection_lookup_string(
-            ptr_src, prop_src, opop->subitem_local_name, &private_ptr_item_src);
-        if (opop->subitem_reference_name != NULL) {
-          RNA_property_collection_lookup_string(
-              ptr_dst, prop_dst, opop->subitem_reference_name, &private_ptr_item_dst);
-        }
-        else {
-          RNA_property_collection_lookup_string(
-              ptr_dst, prop_dst, opop->subitem_local_name, &private_ptr_item_dst);
-        }
-      }
-      else if (opop->subitem_reference_name != NULL) {
-        RNA_property_collection_lookup_string(
-            ptr_src, prop_src, opop->subitem_reference_name, &private_ptr_item_src);
-        RNA_property_collection_lookup_string(
-            ptr_dst, prop_dst, opop->subitem_reference_name, &private_ptr_item_dst);
-      }
-      else if (opop->subitem_local_index != -1) {
-        RNA_property_collection_lookup_int(
-            ptr_src, prop_src, opop->subitem_local_index, &private_ptr_item_src);
-        if (opop->subitem_reference_index != -1) {
-          RNA_property_collection_lookup_int(
-              ptr_dst, prop_dst, opop->subitem_reference_index, &private_ptr_item_dst);
-        }
-        else {
-          RNA_property_collection_lookup_int(
-              ptr_dst, prop_dst, opop->subitem_local_index, &private_ptr_item_dst);
-        }
-      }
-      else if (opop->subitem_reference_index != -1) {
-        RNA_property_collection_lookup_int(
-            ptr_src, prop_src, opop->subitem_reference_index, &private_ptr_item_src);
-        RNA_property_collection_lookup_int(
-            ptr_dst, prop_dst, opop->subitem_reference_index, &private_ptr_item_dst);
-      }
-      if (prop_storage != NULL) {
-        if (opop->subitem_local_name != NULL) {
-          RNA_property_collection_lookup_string(
-              ptr_storage, prop_storage, opop->subitem_local_name, &private_ptr_item_storage);
-        }
-        else if (opop->subitem_reference_name != NULL) {
-          RNA_property_collection_lookup_string(
-              ptr_storage, prop_storage, opop->subitem_reference_name, &private_ptr_item_storage);
-        }
-        else if (opop->subitem_local_index != -1) {
-          RNA_property_collection_lookup_int(
-              ptr_storage, prop_storage, opop->subitem_local_index, &private_ptr_item_storage);
-        }
-        else if (opop->subitem_reference_index != -1) {
-          RNA_property_collection_lookup_int(
-              ptr_storage, prop_storage, opop->subitem_reference_index, &private_ptr_item_storage);
-        }
-      }
-      ptr_item_dst = &private_ptr_item_dst;
-      ptr_item_src = &private_ptr_item_src;
-      ptr_item_storage = &private_ptr_item_storage;
-    }
-
-    if (!rna_property_override_operation_apply(bmain,
-                                               ptr_dst,
-                                               ptr_src,
-                                               ptr_storage,
-                                               prop_dst,
-                                               prop_src,
-                                               prop_storage,
-                                               ptr_item_dst,
-                                               ptr_item_src,
-                                               ptr_item_storage,
-                                               opop)) {
-      /* TODO No assert here, would be much much better to just report as warning,
-       * failing override applications will probably be fairly common! */
-      BLI_assert(0);
-    }
-  }
-}
-
-/** Apply given \a override operations on \a ptr_dst, using \a ptr_src
- * (and \a ptr_storage for differential ops) as source. */
-void RNA_struct_override_apply(Main *bmain,
-                               PointerRNA *ptr_dst,
-                               PointerRNA *ptr_src,
-                               PointerRNA *ptr_storage,
-                               IDOverrideLibrary *override)
-{
-#ifdef DEBUG_OVERRIDE_TIMEIT
-  TIMEIT_START_AVERAGED(RNA_struct_override_apply);
-#endif
-  /* Note: Applying insert operations in a separate pass is mandatory.
-   * We could optimize this later, but for now, as inefficient as it is,
-   * don't think this is a critical point.
-   */
-  bool do_insert = false;
-  for (int i = 0; i < 2; i++, do_insert = true) {
-    for (IDOverrideLibraryProperty *op = override->properties.first; op; op = op->next) {
-      /* Simplified for now! */
-      PointerRNA data_src, data_dst;
-      PointerRNA data_item_src, data_item_dst;
-      PropertyRNA *prop_src, *prop_dst;
-
-      if (RNA_path_resolve_property_and_item_pointer(
-              ptr_dst, op->rna_path, &data_dst, &prop_dst, &data_item_dst) &&
-          RNA_path_resolve_property_and_item_pointer(
-              ptr_src, op->rna_path, &data_src, &prop_src, &data_item_src)) {
-        PointerRNA data_storage, data_item_storage;
-        PropertyRNA *prop_storage = NULL;
-
-        /* It is totally OK if this does not success,
-         * only a subset of override operations actually need storage. */
-        if (ptr_storage && (ptr_storage->id.data != NULL)) {
-          RNA_path_resolve_property_and_item_pointer(
-              ptr_storage, op->rna_path, &data_storage, &prop_storage, &data_item_storage);
-        }
-
-        rna_property_override_apply_ex(bmain,
-                                       &data_dst,
-                                       &data_src,
-                                       prop_storage ? &data_storage : NULL,
-                                       prop_dst,
-                                       prop_src,
-                                       prop_storage,
-                                       &data_item_dst,
-                                       &data_item_src,
-                                       prop_storage ? &data_item_storage : NULL,
-                                       op,
-                                       do_insert);
-      }
-#ifndef NDEBUG
-      else {
-        printf(
-            "Failed to apply library override operation to '%s.%s' "
-            "(could not resolve some properties, local:  %d, override: %d)\n",
-            ((ID *)ptr_src->id.data)->name,
-            op->rna_path,
-            RNA_path_resolve_property(ptr_dst, op->rna_path, &data_dst, &prop_dst),
-            RNA_path_resolve_property(ptr_src, op->rna_path, &data_src, &prop_src));
-      }
-#endif
-    }
-  }
-#ifdef DEBUG_OVERRIDE_TIMEIT
-  TIMEIT_END_AVERAGED(RNA_struct_override_apply);
-#endif
-}
-
-IDOverrideLibraryProperty *RNA_property_override_property_find(PointerRNA *ptr, PropertyRNA *prop)
-{
-  ID *id = ptr->id.data;
-
-  if (!id || !id->override_library) {
-    return NULL;
-  }
-
-  char *rna_path = RNA_path_from_ID_to_property(ptr, prop);
-  if (rna_path) {
-    IDOverrideLibraryProperty *op = BKE_override_library_property_find(id->override_library,
-                                                                       rna_path);
-    MEM_freeN(rna_path);
-    return op;
-  }
-  return NULL;
-}
-
-IDOverrideLibraryProperty *RNA_property_override_property_get(PointerRNA *ptr,
-                                                              PropertyRNA *prop,
-                                                              bool *r_created)
-{
-  ID *id = ptr->id.data;
-
-  if (!id || !id->override_library) {
-    return NULL;
-  }
-
-  char *rna_path = RNA_path_from_ID_to_property(ptr, prop);
-  if (rna_path) {
-    IDOverrideLibraryProperty *op = BKE_override_library_property_get(
-        id->override_library, rna_path, r_created);
-    MEM_freeN(rna_path);
-    return op;
-  }
-  return NULL;
-}
-
-IDOverrideLibraryPropertyOperation *RNA_property_override_property_operation_find(
-    PointerRNA *ptr, PropertyRNA *prop, const int index, const bool strict, bool *r_strict)
-{
-  IDOverrideLibraryProperty *op = RNA_property_override_property_find(ptr, prop);
-
-  if (!op) {
-    return NULL;
-  }
-
-  return BKE_override_library_property_operation_find(
-      op, NULL, NULL, index, index, strict, r_strict);
-}
-
-IDOverrideLibraryPropertyOperation *RNA_property_override_property_operation_get(
-    PointerRNA *ptr,
-    PropertyRNA *prop,
-    const short operation,
-    const int index,
-    const bool strict,
-    bool *r_strict,
-    bool *r_created)
-{
-  IDOverrideLibraryProperty *op = RNA_property_override_property_get(ptr, prop, NULL);
-
-  if (!op) {
-    return NULL;
-  }
-
-  return BKE_override_library_property_operation_get(
-      op, operation, NULL, NULL, index, index, strict, r_strict, r_created);
-}
-
-eRNAOverrideStatus RNA_property_override_library_status(PointerRNA *ptr,
-                                                        PropertyRNA *prop,
-                                                        const int index)
-{
-  int override_status = 0;
-
-  if (!BKE_override_library_is_enabled()) {
-    return override_status;
-  }
-
-  if (!ptr || !prop || !ptr->id.data || !((ID *)ptr->id.data)->override_library) {
-    return override_status;
-  }
-
-  if (RNA_property_overridable_get(ptr, prop) && RNA_property_editable_flag(ptr, prop)) {
-    override_status |= RNA_OVERRIDE_STATUS_OVERRIDABLE;
-  }
-
-  IDOverrideLibraryPropertyOperation *opop = RNA_property_override_property_operation_find(
-      ptr, prop, index, false, NULL);
-  if (opop != NULL) {
-    override_status |= RNA_OVERRIDE_STATUS_OVERRIDDEN;
-    if (opop->flag & IDOVERRIDE_LIBRARY_FLAG_MANDATORY) {
-      override_status |= RNA_OVERRIDE_STATUS_MANDATORY;
-    }
-    if (opop->flag & IDOVERRIDE_LIBRARY_FLAG_LOCKED) {
-      override_status |= RNA_OVERRIDE_STATUS_LOCKED;
-    }
-  }
-
-  return override_status;
-}
-
 bool RNA_path_resolved_create(PointerRNA *ptr,
                               struct PropertyRNA *prop,
                               const int prop_index,
diff --git a/source/blender/makesrna/intern/rna_access_compare_override.c b/source/blender/makesrna/intern/rna_access_compare_override.c
new file mode 100644 (file)
index 0000000..4ee0622
--- /dev/null
@@ -0,0 +1,1099 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup RNA
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_ID.h"
+#include "DNA_constraint_types.h"
+#include "DNA_modifier_types.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_string.h"
+
+#ifdef DEBUG_OVERRIDE_TIMEIT
+#  include "PIL_time_utildefines.h"
+#endif
+
+#include "BKE_idprop.h"
+#include "BKE_library_override.h"
+#include "BKE_main.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "rna_internal.h"
+#include "rna_access_internal.h"
+
+int RNA_property_override_flag(PropertyRNA *prop)
+{
+  return rna_ensure_property(prop)->flag_override;
+}
+
+/** \note Does not take into account editable status, this has to be checked separately
+ * (using #RNA_property_editable_flag() usually). */
+bool RNA_property_overridable_get(PointerRNA *ptr, PropertyRNA *prop)
+{
+  if (prop->magic == RNA_MAGIC) {
+    /* Special handling for insertions of constraints or modifiers... */
+    /* TODO Note We may want to add a more generic system to RNA
+     * (like a special property in struct of items)
+     * if we get more overrideable collections,
+     * for now we can live with those special-cases handling I think. */
+    if (RNA_struct_is_a(ptr->type, &RNA_Constraint)) {
+      bConstraint *con = ptr->data;
+      if (con->flag & CONSTRAINT_OVERRIDE_LIBRARY_LOCAL) {
+        return true;
+      }
+    }
+    else if (RNA_struct_is_a(ptr->type, &RNA_Modifier)) {
+      ModifierData *mod = ptr->data;
+      if (mod->flag & eModifierFlag_OverrideLibrary_Local) {
+        return true;
+      }
+    }
+    /* If this is a RNA-defined property (real or 'virtual' IDProp),
+     * we want to use RNA prop flag. */
+    return !(prop->flag_override & PROPOVERRIDE_NO_COMPARISON) &&
+           (prop->flag_override & PROPOVERRIDE_OVERRIDABLE_LIBRARY);
+  }
+  else {
+    /* If this is a real 'pure' IDProp (aka custom property), we want to use the IDProp flag. */
+    return !(prop->flag_override & PROPOVERRIDE_NO_COMPARISON) &&
+           (((IDProperty *)prop)->flag & IDP_FLAG_OVERRIDABLE_LIBRARY);
+  }
+}
+
+/* Should only be used for custom properties */
+bool RNA_property_overridable_library_set(PointerRNA *UNUSED(ptr),
+                                          PropertyRNA *prop,
+                                          const bool is_overridable)
+{
+  /* Only works for pure custom properties IDProps. */
+  if (prop->magic != RNA_MAGIC) {
+    IDProperty *idprop = (IDProperty *)prop;
+
+    idprop->flag = is_overridable ? (idprop->flag | IDP_FLAG_OVERRIDABLE_LIBRARY) :
+                                    (idprop->flag & ~IDP_FLAG_OVERRIDABLE_LIBRARY);
+    return true;
+  }
+
+  return false;
+}
+
+bool RNA_property_overridden(PointerRNA *ptr, PropertyRNA *prop)
+{
+  char *rna_path = RNA_path_from_ID_to_property(ptr, prop);
+  ID *id = ptr->id.data;
+
+  if (rna_path == NULL || id == NULL || id->override_library == NULL) {
+    return false;
+  }
+
+  return (BKE_override_library_property_find(id->override_library, rna_path) != NULL);
+}
+
+bool RNA_property_comparable(PointerRNA *UNUSED(ptr), PropertyRNA *prop)
+{
+  prop = rna_ensure_property(prop);
+
+  return !(prop->flag_override & PROPOVERRIDE_NO_COMPARISON);
+}
+
+static bool rna_property_override_operation_apply(Main *bmain,
+                                                  PointerRNA *ptr_local,
+                                                  PointerRNA *ptr_override,
+                                                  PointerRNA *ptr_storage,
+                                                  PropertyRNA *prop_local,
+                                                  PropertyRNA *prop_override,
+                                                  PropertyRNA *prop_storage,
+                                                  PointerRNA *ptr_item_local,
+                                                  PointerRNA *ptr_item_override,
+                                                  PointerRNA *ptr_item_storage,
+                                                  IDOverrideLibraryPropertyOperation *opop);
+
+bool RNA_property_copy(
+    Main *bmain, PointerRNA *ptr, PointerRNA *fromptr, PropertyRNA *prop, int index)
+{
+  if (!RNA_property_editable(ptr, prop)) {
+    return false;
+  }
+
+  PropertyRNA *prop_dst = prop;
+  PropertyRNA *prop_src = prop;
+
+  /* Ensure we get real property data,
+   * be it an actual RNA property, or an IDProperty in disguise. */
+  prop_dst = rna_ensure_property_realdata(&prop_dst, ptr);
+  prop_src = rna_ensure_property_realdata(&prop_src, fromptr);
+
+  /* IDprops: destination may not exist, if source does and is set, try to create it. */
+  /* Note: this is sort of quick hack/bandage to fix the issue,
+   * we need to rethink how IDProps are handled in 'diff' RNA code completely, imho... */
+  if (prop_src != NULL && prop_dst == NULL && RNA_property_is_set(fromptr, prop)) {
+    BLI_assert(prop_src->magic != RNA_MAGIC);
+    IDProperty *idp_dst = RNA_struct_idprops(ptr, true);
+    IDProperty *prop_idp_dst = IDP_CopyProperty((IDProperty *)prop_src);
+    IDP_AddToGroup(idp_dst, prop_idp_dst);
+    rna_idproperty_touch(prop_idp_dst);
+    /* Nothing else to do here... */
+    return true;
+  }
+
+  if (ELEM(NULL, prop_dst, prop_src)) {
+    return false;
+  }
+
+  IDOverrideLibraryPropertyOperation opop = {
+      .operation = IDOVERRIDE_LIBRARY_OP_REPLACE,
+      .subitem_reference_index = index,
+      .subitem_local_index = index,
+  };
+  return rna_property_override_operation_apply(
+      bmain, ptr, fromptr, NULL, prop_dst, prop_src, NULL, NULL, NULL, NULL, &opop);
+}
+
+static int rna_property_override_diff(Main *bmain,
+                                      PointerRNA *ptr_a,
+                                      PointerRNA *ptr_b,
+                                      PropertyRNA *prop,
+                                      PropertyRNA *prop_a,
+                                      PropertyRNA *prop_b,
+                                      const char *rna_path,
+                                      eRNACompareMode mode,
+                                      IDOverrideLibrary *override,
+                                      const int flags,
+                                      eRNAOverrideMatchResult *r_report_flags);
+
+bool RNA_property_equals(
+    Main *bmain, PointerRNA *ptr_a, PointerRNA *ptr_b, PropertyRNA *prop, eRNACompareMode mode)
+{
+  BLI_assert(ELEM(mode, RNA_EQ_STRICT, RNA_EQ_UNSET_MATCH_ANY, RNA_EQ_UNSET_MATCH_NONE));
+
+  return (rna_property_override_diff(
+              bmain, ptr_a, ptr_b, prop, NULL, NULL, NULL, mode, NULL, 0, NULL) == 0);
+}
+
+bool RNA_struct_equals(Main *bmain, PointerRNA *ptr_a, PointerRNA *ptr_b, eRNACompareMode mode)
+{
+  CollectionPropertyIterator iter;
+  PropertyRNA *iterprop;
+  bool equals = true;
+
+  if (ptr_a == NULL && ptr_b == NULL) {
+    return true;
+  }
+  else if (ptr_a == NULL || ptr_b == NULL) {
+    return false;
+  }
+  else if (ptr_a->type != ptr_b->type) {
+    return false;
+  }
+
+  iterprop = RNA_struct_iterator_property(ptr_a->type);
+
+  RNA_property_collection_begin(ptr_a, iterprop, &iter);
+  for (; iter.valid; RNA_property_collection_next(&iter)) {
+    PropertyRNA *prop = iter.ptr.data;
+
+    if (!RNA_property_equals(bmain, ptr_a, ptr_b, prop, mode)) {
+      equals = false;
+      break;
+    }
+  }
+  RNA_property_collection_end(&iter);
+
+  return equals;
+}
+
+/* Low-level functions, also used by non-override RNA API like copy or equality check. */
+
+/** Generic RNA property diff function.
+ *
+ * \note about \a prop and \a prop_a/prop_b parameters:
+ * the former is expected to be an 'un-resolved' one,
+ * while the two later are expected to be fully resolved ones
+ * (i.e. to be the IDProps when they should be, etc.).
+ * When \a prop is given, \a prop_a and \a prop_b should always be NULL, and vice-versa.
+ * This is necessary, because we cannot perform 'set/unset' checks on resolved properties
+ * (unset IDProps would merely be NULL then).
+ *
+ * \note When there is no equality,
+ * but we cannot determine an order (greater than/lesser than), we return 1.
+ */
+static int rna_property_override_diff(Main *bmain,
+                                      PointerRNA *ptr_a,
+                                      PointerRNA *ptr_b,
+                                      PropertyRNA *prop,
+                                      PropertyRNA *prop_a,
+                                      PropertyRNA *prop_b,
+                                      const char *rna_path,
+                                      eRNACompareMode mode,
+                                      IDOverrideLibrary *override,
+                                      const int flags,
+                                      eRNAOverrideMatchResult *r_report_flags)
+{
+  if (prop != NULL) {
+    BLI_assert(prop_a == NULL && prop_b == NULL);
+    prop_a = prop;
+    prop_b = prop;
+  }
+
+  if (ELEM(NULL, prop_a, prop_b)) {
+    return (prop_a == prop_b) ? 0 : 1;
+  }
+
+  if (!RNA_property_comparable(ptr_a, prop_a) || !RNA_property_comparable(ptr_b, prop_b)) {
+    return 0;
+  }
+
+  if (mode == RNA_EQ_UNSET_MATCH_ANY) {
+    /* uninitialized properties are assumed to match anything */
+    if (!RNA_property_is_set(ptr_a, prop_a) || !RNA_property_is_set(ptr_b, prop_b)) {
+      return 0;
+    }
+  }
+  else if (mode == RNA_EQ_UNSET_MATCH_NONE) {
+    /* unset properties never match set properties */
+    if (RNA_property_is_set(ptr_a, prop_a) != RNA_property_is_set(ptr_b, prop_b)) {
+      return 1;
+    }
+  }
+
+  if (prop != NULL) {
+    /* Ensure we get real property data, be it an actual RNA property,
+     * or an IDProperty in disguise. */
+    prop_a = rna_ensure_property_realdata(&prop_a, ptr_a);
+    prop_b = rna_ensure_property_realdata(&prop_b, ptr_b);
+
+    if (ELEM(NULL, prop_a, prop_b)) {
+      return (prop_a == prop_b) ? 0 : 1;
+    }
+  }
+
+  /* Check if we are working with arrays. */
+  const bool is_array_a = RNA_property_array_check(prop_a);
+  const bool is_array_b = RNA_property_array_check(prop_b);
+
+  if (is_array_a != is_array_b) {
+    /* Should probably never happen actually... */
+    BLI_assert(0);
+    return is_array_a ? 1 : -1;
+  }
+
+  /* Get the length of the array to work with. */
+  const int len_a = RNA_property_array_length(ptr_a, prop_a);
+  const int len_b = RNA_property_array_length(ptr_b, prop_b);
+
+  if (len_a != len_b) {
+    /* Do not handle override in that case,
+     * we do not support insertion/deletion from arrays for now. */
+    return len_a > len_b ? 1 : -1;
+  }
+
+  if (is_array_a && len_a == 0) {
+    /* Empty arrays, will happen in some case with dynamic ones. */
+    return 0;
+  }
+
+  RNAPropOverrideDiff override_diff = NULL;
+  /* Special case for IDProps, we use default callback then. */
+  if (prop_a->magic != RNA_MAGIC) {
+    override_diff = rna_property_override_diff_default;
+    if (prop_b->magic == RNA_MAGIC && prop_b->override_diff != override_diff) {
+      override_diff = NULL;
+    }
+  }
+  else if (prop_b->magic != RNA_MAGIC) {
+    override_diff = rna_property_override_diff_default;
+    if (prop_a->override_diff != override_diff) {
+      override_diff = NULL;
+    }
+  }
+  else if (prop_a->override_diff == prop_b->override_diff) {
+    override_diff = prop_a->override_diff;
+  }
+
+  if (override_diff == NULL) {
+#ifndef NDEBUG
+    printf("'%s' gives unmatching or NULL RNA diff callbacks, should not happen (%d vs. %d).\n",
+           rna_path ?
+               rna_path :
+               (prop_a->magic != RNA_MAGIC ? ((IDProperty *)prop_a)->name : prop_a->identifier),
+           prop_a->magic == RNA_MAGIC,
+           prop_b->magic == RNA_MAGIC);
+#endif
+    BLI_assert(0);
+    return 1;
+  }
+
+  bool override_changed = false;
+  int diff_flags = flags;
+  if (!RNA_property_overridable_get(ptr_a, prop_a)) {
+    diff_flags &= ~RNA_OVERRIDE_COMPARE_CREATE;
+  }
+  const int diff = override_diff(bmain,
+                                 ptr_a,
+                                 ptr_b,
+                                 prop_a,
+                                 prop_b,
+                                 len_a,
+                                 len_b,
+                                 mode,
+                                 override,
+                                 rna_path,
+                                 diff_flags,
+                                 &override_changed);
+  if (override_changed && r_report_flags) {
+    *r_report_flags |= RNA_OVERRIDE_MATCH_RESULT_CREATED;
+  }
+
+  return diff;
+}
+
+/* Modify local data-block to make it ready for override application
+ * (only needed for diff operations, where we use
+ * the local data-block's data as second operand). */
+static bool rna_property_override_operation_store(Main *bmain,
+                                                  PointerRNA *ptr_local,
+                                                  PointerRNA *ptr_reference,
+                                                  PointerRNA *ptr_storage,
+                                                  PropertyRNA *prop_local,
+                                                  PropertyRNA *prop_reference,
+                                                  PropertyRNA *prop_storage,
+                                                  IDOverrideLibraryProperty *op)
+{
+  int len_local, len_reference, len_storage = 0;
+  bool changed = false;
+
+  if (ptr_storage == NULL) {
+    return changed;
+  }
+
+  /* get the length of the array to work with */
+  len_local = RNA_property_array_length(ptr_local, prop_local);
+  len_reference = RNA_property_array_length(ptr_reference, prop_reference);
+  if (prop_storage) {
+    len_storage = RNA_property_array_length(ptr_storage, prop_storage);
+  }
+
+  if (len_local != len_reference || len_local != len_storage) {
+    /* Do not handle override in that case,
+     * we do not support insertion/deletion from arrays for now. */
+    return changed;
+  }
+
+  BLI_assert(prop_local->override_store == prop_reference->override_store &&
+             (!ptr_storage || prop_local->override_store == prop_storage->override_store) &&
+             prop_local->override_store != NULL);
+
+  for (IDOverrideLibraryPropertyOperation *opop = op->operations.first; opop; opop = opop->next) {
+    /* Only needed for diff operations. */
+    if (!ELEM(opop->operation,
+              IDOVERRIDE_LIBRARY_OP_ADD,
+              IDOVERRIDE_LIBRARY_OP_SUBTRACT,
+              IDOVERRIDE_LIBRARY_OP_MULTIPLY)) {
+      continue;
+    }
+
+    if (prop_local->override_store(bmain,
+                                   ptr_local,
+                                   ptr_reference,
+                                   ptr_storage,
+                                   prop_local,
+                                   prop_reference,
+                                   prop_storage,
+                                   len_local,
+                                   len_reference,
+                                   len_storage,
+                                   opop)) {
+      changed = true;
+    }
+  }
+
+  return changed;
+}
+
+static bool rna_property_override_operation_apply(Main *bmain,
+                                                  PointerRNA *ptr_dst,
+                                                  PointerRNA *ptr_src,
+                                                  PointerRNA *ptr_storage,
+                                                  PropertyRNA *prop_dst,
+                                                  PropertyRNA *prop_src,
+                                                  PropertyRNA *prop_storage,
+                                                  PointerRNA *ptr_item_dst,
+                                                  PointerRNA *ptr_item_src,
+                                                  PointerRNA *ptr_item_storage,
+                                                  IDOverrideLibraryPropertyOperation *opop)
+{
+  int len_dst, len_src, len_storage = 0;
+
+  const short override_op = opop->operation;
+
+  if (override_op == IDOVERRIDE_LIBRARY_OP_NOOP) {
+    return true;
+  }
+
+  if (ELEM(override_op,
+           IDOVERRIDE_LIBRARY_OP_ADD,
+           IDOVERRIDE_LIBRARY_OP_SUBTRACT,
+           IDOVERRIDE_LIBRARY_OP_MULTIPLY) &&
+      !ptr_storage) {
+    /* We cannot apply 'diff' override operations without some reference storage.
+     * This should typically only happen at read time of .blend file... */
+    return false;
+  }
+
+  if (ELEM(override_op,
+           IDOVERRIDE_LIBRARY_OP_ADD,
+           IDOVERRIDE_LIBRARY_OP_SUBTRACT,
+           IDOVERRIDE_LIBRARY_OP_MULTIPLY) &&
+      !prop_storage) {
+    /* We cannot apply 'diff' override operations without some reference storage.
+     * This should typically only happen at read time of .blend file... */
+    return false;
+  }
+
+  RNAPropOverrideApply override_apply = NULL;
+  /* Special case for IDProps, we use default callback then. */
+  if (prop_dst->magic != RNA_MAGIC) {
+    override_apply = rna_property_override_apply_default;
+    if (prop_src->magic == RNA_MAGIC && prop_src->override_apply != override_apply) {
+      override_apply = NULL;
+    }
+  }
+  else if (prop_src->magic != RNA_MAGIC) {
+    override_apply = rna_property_override_apply_default;
+    if (prop_dst->override_apply != override_apply) {
+      override_apply = NULL;
+    }
+  }
+  else if (prop_dst->override_apply == prop_src->override_apply) {
+    override_apply = prop_dst->override_apply;
+  }
+
+  if (ptr_storage && prop_storage->magic == RNA_MAGIC &&
+      prop_storage->override_apply != override_apply) {
+    override_apply = NULL;
+  }
+
+  if (override_apply == NULL) {
+#ifndef NDEBUG
+    printf("'%s' gives unmatching or NULL RNA copy callbacks, should not happen (%d vs. %d).\n",
+           prop_dst->magic != RNA_MAGIC ? ((IDProperty *)prop_dst)->name : prop_dst->identifier,
+           prop_dst->magic == RNA_MAGIC,
+           prop_src->magic == RNA_MAGIC);
+#endif
+    BLI_assert(0);
+    return false;
+  }
+
+  /* get the length of the array to work with */
+  len_dst = RNA_property_array_length(ptr_dst, prop_dst);
+  len_src = RNA_property_array_length(ptr_src, prop_src);
+  if (ptr_storage) {
+    len_storage = RNA_property_array_length(ptr_storage, prop_storage);
+  }
+
+  if (len_dst != len_src || (ptr_storage && len_dst != len_storage)) {
+    /* Do not handle override in that case,
+     * we do not support insertion/deletion from arrays for now. */
+    return false;
+  }
+
+  /* get and set the default values as appropriate for the various types */
+  return override_apply(bmain,
+                        ptr_dst,
+                        ptr_src,
+                        ptr_storage,
+                        prop_dst,
+                        prop_src,
+                        prop_storage,
+                        len_dst,
+                        len_src,
+                        len_storage,
+                        ptr_item_dst,
+                        ptr_item_src,
+                        ptr_item_storage,
+                        opop);
+}
+
+/**
+ * Check whether reference and local overridden data match (are the same),
+ * with respect to given restrictive sets of properties.
+ * If requested, will generate needed new property overrides, and/or restore values from reference.
+ *
+ * \param r_report_flags: If given,
+ * will be set with flags matching actions taken by the function on \a ptr_local.
+ *
+ * \return True if _resulting_ \a ptr_local does match \a ptr_reference.
+ */
+bool RNA_struct_override_matches(Main *bmain,
+                                 PointerRNA *ptr_local,
+                                 PointerRNA *ptr_reference,
+                                 const char *root_path,
+                                 IDOverrideLibrary *override,
+                                 const eRNAOverrideMatch flags,
+                                 eRNAOverrideMatchResult *r_report_flags)
+{
+  CollectionPropertyIterator iter;
+  PropertyRNA *iterprop;
+  bool matching = true;
+
+  BLI_assert(ptr_local->type == ptr_reference->type);
+  BLI_assert(ptr_local->id.data && ptr_reference->id.data);
+
+  const bool ignore_non_overridable = (flags & RNA_OVERRIDE_COMPARE_IGNORE_NON_OVERRIDABLE) != 0;
+  const bool ignore_overridden = (flags & RNA_OVERRIDE_COMPARE_IGNORE_OVERRIDDEN) != 0;
+  const bool do_create = (flags & RNA_OVERRIDE_COMPARE_CREATE) != 0;
+  const bool do_restore = (flags & RNA_OVERRIDE_COMPARE_RESTORE) != 0;
+
+//#define DEBUG_OVERRIDE_TIMEIT
+#ifdef DEBUG_OVERRIDE_TIMEIT
+  static float _sum_time_global = 0.0f;
+  static float _num_time_global = 0.0f;
+  double _timeit_time_global;
+  static float _sum_time_diffing = 0.0f;
+  static float _delta_time_diffing = 0.0f;
+  static int _num_delta_time_diffing = 0.0f;
+  static float _num_time_diffing = 0.0f;
+  double _timeit_time_diffing;
+
+  if (!root_path) {
+    _delta_time_diffing = 0.0f;
+    _num_delta_time_diffing = 0;
+    _timeit_time_global = PIL_check_seconds_timer();
+  }
+#endif
+
+  iterprop = RNA_struct_iterator_property(ptr_local->type);
+
+  for (RNA_property_collection_begin(ptr_local, iterprop, &iter); iter.valid;
+       RNA_property_collection_next(&iter)) {
+    PropertyRNA *prop_local = iter.ptr.data;
+    PropertyRNA *prop_reference = iter.ptr.data;
+
+    /* Ensure we get real property data, be it an actual RNA property,
+     * or an IDProperty in disguise. */
+    prop_local = rna_ensure_property_realdata(&prop_local, ptr_local);
+    prop_reference = rna_ensure_property_realdata(&prop_reference, ptr_reference);
+
+    if (ELEM(NULL, prop_local, prop_reference)) {
+      continue;
+    }
+
+    if (ignore_non_overridable && !RNA_property_overridable_get(ptr_local, prop_local)) {
+      continue;
+    }
+
+#if 0 /* This actually makes things slower, since it has to check for animation paths etc! */
+    if (RNA_property_animated(ptr_local, prop_local)) {
+      /* We cannot do anything here really, animation is some kind of dynamic overrides that has
+       * precedence over static one... */
+      continue;
+    }
+#endif
+
+#define RNA_PATH_BUFFSIZE 8192
+#define RNA_PATH_PRINTF(_str, ...) \
+  if (BLI_snprintf(rna_path, RNA_PATH_BUFFSIZE, (_str), __VA_ARGS__) >= RNA_PATH_BUFFSIZE) { \
+    rna_path = BLI_sprintfN((_str), __VA_ARGS__); \
+  } \
+  (void)0
+#define RNA_PATH_FREE \
+  if (rna_path != rna_path_buffer) \
+  MEM_freeN(rna_path)
+
+    char rna_path_buffer[RNA_PATH_BUFFSIZE];
+    char *rna_path = rna_path_buffer;
+
+    /* XXX TODO this will have to be refined to handle collections insertions, and array items */
+    if (root_path) {
+      /* Inlined building, much much more efficient. */
+      if (prop_local->magic == RNA_MAGIC) {
+        RNA_PATH_PRINTF("%s.%s", root_path, RNA_property_identifier(prop_local));
+      }
+      else {
+        RNA_PATH_PRINTF("%s[\"%s\"]", root_path, RNA_property_identifier(prop_local));
+      }
+    }
+    else {
+      /* This is rather slow, but is not much called, so not really worth optimizing. */
+      rna_path = RNA_path_from_ID_to_property(ptr_local, prop_local);
+    }
+    if (rna_path == NULL) {
+      continue;
+    }
+
+    //    printf("Override Checking %s\n", rna_path);
+
+    if (ignore_overridden && BKE_override_library_property_find(override, rna_path) != NULL) {
+      RNA_PATH_FREE;
+      continue;
+    }
+
+#ifdef DEBUG_OVERRIDE_TIMEIT
+    if (!root_path) {
+      _timeit_time_diffing = PIL_check_seconds_timer();
+    }
+#endif
+
+    eRNAOverrideMatchResult report_flags = 0;
+    const int diff = rna_property_override_diff(bmain,
+                                                ptr_local,
+                                                ptr_reference,
+                                                NULL,
+                                                prop_local,
+                                                prop_reference,
+                                                rna_path,
+                                                RNA_EQ_STRICT,
+                                                override,
+                                                flags,
+                                                &report_flags);
+
+#ifdef DEBUG_OVERRIDE_TIMEIT
+    if (!root_path) {
+      const float _delta_time = (float)(PIL_check_seconds_timer() - _timeit_time_diffing);
+      _delta_time_diffing += _delta_time;
+      _num_delta_time_diffing++;
+    }
+#endif
+
+    matching = matching && diff == 0;
+    if (r_report_flags) {
+      *r_report_flags |= report_flags;
+    }
+
+    if (diff != 0) {
+      /* XXX TODO: refine this for per-item overriding of arrays... */
+      IDOverrideLibraryProperty *op = BKE_override_library_property_find(override, rna_path);
+      IDOverrideLibraryPropertyOperation *opop = op ? op->operations.first : NULL;
+
+      if (do_restore && (report_flags & RNA_OVERRIDE_MATCH_RESULT_CREATED) == 0) {
+        /* We are allowed to restore to reference's values. */
+        if (ELEM(NULL, op, opop) || opop->operation == IDOVERRIDE_LIBRARY_OP_NOOP) {
+          /* We should restore that property to its reference value */
+          if (RNA_property_editable(ptr_local, prop_local)) {
+            IDOverrideLibraryPropertyOperation opop_tmp = {
+                .operation = IDOVERRIDE_LIBRARY_OP_REPLACE,
+                .subitem_reference_index = -1,
+                .subitem_local_index = -1,
+            };
+            rna_property_override_operation_apply(bmain,
+                                                  ptr_local,
+                                                  ptr_reference,
+                                                  NULL,
+                                                  prop_local,
+                                                  prop_reference,
+                                                  NULL,
+                                                  NULL,
+                                                  NULL,
+                                                  NULL,
+                                                  &opop_tmp);
+            if (r_report_flags) {
+              *r_report_flags |= RNA_OVERRIDE_MATCH_RESULT_RESTORED;
+            }
+          }
+          else {
+            /* Too noisy for now, this triggers on runtime props like transform matrices etc. */
+#if 0
+            BLI_assert(!"We have differences between reference and "
+                       "overriding data on non-editable property.");
+#endif
+            matching = false;
+          }
+        }
+      }
+      else if ((report_flags & RNA_OVERRIDE_MATCH_RESULT_CREATED) == 0 && ELEM(NULL, op, opop)) {
+        /* This property is not overridden, and differs from reference, so we have no match. */
+        matching = false;
+        if (!(do_create || do_restore)) {
+          /* Since we have no 'changing' action allowed, we can break here. */
+          MEM_SAFE_FREE(rna_path);
+          break;
+        }
+      }
+    }
+
+    RNA_PATH_FREE;
+
+#undef RNA_PATH_BUFFSIZE
+#undef RNA_PATH_PRINTF
+#undef RNA_PATH_FREE
+  }
+  RNA_property_collection_end(&iter);
+
+#ifdef DEBUG_OVERRIDE_TIMEIT
+  if (!root_path) {
+    const float _delta_time = (float)(PIL_check_seconds_timer() - _timeit_time_global);
+    _sum_time_global += _delta_time;
+    _num_time_global++;
+    _sum_time_diffing += _delta_time_diffing;
+    _num_time_diffing++;
+    printf("ID: %s\n", ((ID *)ptr_local->id.data)->name);
+    printf("time end      (%s): %.6f\n", __func__, _delta_time);
+    printf("time averaged (%s): %.6f (total: %.6f, in %d runs)\n",
+           __func__,
+           (_sum_time_global / _num_time_global),
+           _sum_time_global,
+           (int)_num_time_global);
+    printf("diffing time end      (%s): %.6f (in %d runs)\n",
+           __func__,
+           _delta_time_diffing,
+           _num_delta_time_diffing);
+    printf("diffing time averaged (%s): %.6f (total: %.6f, in %d runs)\n",
+           __func__,
+           (_sum_time_diffing / _num_time_diffing),
+           _sum_time_diffing,
+           (int)_num_time_diffing);
+  }
+#endif
+
+  return matching;
+}
+
+/** Store needed second operands into \a storage data-block
+ * for differential override operations. */
+bool RNA_struct_override_store(Main *bmain,
+                               PointerRNA *ptr_local,
+                               PointerRNA *ptr_reference,
+                               PointerRNA *ptr_storage,
+                               IDOverrideLibrary *override)
+{
+  bool changed = false;
+
+#ifdef DEBUG_OVERRIDE_TIMEIT
+  TIMEIT_START_AVERAGED(RNA_struct_override_store);
+#endif
+  for (IDOverrideLibraryProperty *op = override->properties.first; op; op = op->next) {
+    /* Simplified for now! */
+    PointerRNA data_reference, data_local;
+    PropertyRNA *prop_reference, *prop_local;
+
+    if (RNA_path_resolve_property(ptr_local, op->rna_path, &data_local, &prop_local) &&
+        RNA_path_resolve_property(ptr_reference, op->rna_path, &data_reference, &prop_reference)) {
+      PointerRNA data_storage;
+      PropertyRNA *prop_storage = NULL;
+
+      /* It is totally OK if this does not success,
+       * only a subset of override operations actually need storage. */
+      if (ptr_storage && (ptr_storage->id.data != NULL)) {
+        RNA_path_resolve_property(ptr_storage, op->rna_path, &data_storage, &prop_storage);
+      }
+
+      if (rna_property_override_operation_store(bmain,
+                                                &data_local,
+                                                &data_reference,
+                                                &data_storage,
+                                                prop_reference,
+                                                prop_local,
+                                                prop_storage,
+                                                op)) {
+        changed = true;
+      }
+    }
+  }
+#ifdef DEBUG_OVERRIDE_TIMEIT
+  TIMEIT_END_AVERAGED(RNA_struct_override_store);
+#endif
+
+  return changed;
+}
+
+static void rna_property_override_apply_ex(Main *bmain,
+                                           PointerRNA *ptr_dst,
+                                           PointerRNA *ptr_src,
+                                           PointerRNA *ptr_storage,
+                                           PropertyRNA *prop_dst,
+                                           PropertyRNA *prop_src,
+                                           PropertyRNA *prop_storage,
+                                           PointerRNA *ptr_item_dst,
+                                           PointerRNA *ptr_item_src,
+                                           PointerRNA *ptr_item_storage,
+                                           IDOverrideLibraryProperty *op,
+                                           const bool do_insert)
+{
+  for (IDOverrideLibraryPropertyOperation *opop = op->operations.first; opop; opop = opop->next) {
+    if (!do_insert != !ELEM(opop->operation,
+                            IDOVERRIDE_LIBRARY_OP_INSERT_AFTER,
+                            IDOVERRIDE_LIBRARY_OP_INSERT_BEFORE)) {
+      if (!do_insert) {
+        printf("Skipping insert override operations in first pass (%s)!\n", op->rna_path);
+      }
+      continue;
+    }
+
+    /* Note: will have to think about putting that logic into its own function maybe?
+     * Would be nice to have it in a single place...
+     * Note that here, src is the local saved ID, and dst is a copy of the linked ID (since we use
+     * local ID as storage to apply local changes on top of a clean copy of the linked data). */
+    PointerRNA private_ptr_item_dst, private_ptr_item_src, private_ptr_item_storage;
+    if (opop->subitem_local_name != NULL || opop->subitem_reference_name != NULL ||
+        opop->subitem_local_index != -1 || opop->subitem_reference_index != -1) {
+      RNA_POINTER_INVALIDATE(&private_ptr_item_dst);
+      RNA_POINTER_INVALIDATE(&private_ptr_item_src);
+      RNA_POINTER_INVALIDATE(&private_ptr_item_storage);
+      if (opop->subitem_local_name != NULL) {
+        RNA_property_collection_lookup_string(
+            ptr_src, prop_src, opop->subitem_local_name, &private_ptr_item_src);
+        if (opop->subitem_reference_name != NULL) {
+          RNA_property_collection_lookup_string(
+              ptr_dst, prop_dst, opop->subitem_reference_name, &private_ptr_item_dst);
+        }
+        else {
+          RNA_property_collection_lookup_string(
+              ptr_dst, prop_dst, opop->subitem_local_name, &private_ptr_item_dst);
+        }
+      }
+      else if (opop->subitem_reference_name != NULL) {
+        RNA_property_collection_lookup_string(
+            ptr_src, prop_src, opop->subitem_reference_name, &private_ptr_item_src);
+        RNA_property_collection_lookup_string(
+            ptr_dst, prop_dst, opop->subitem_reference_name, &private_ptr_item_dst);
+      }
+      else if (opop->subitem_local_index != -1) {
+        RNA_property_collection_lookup_int(
+            ptr_src, prop_src, opop->subitem_local_index, &private_ptr_item_src);
+        if (opop->subitem_reference_index != -1) {
+          RNA_property_collection_lookup_int(
+              ptr_dst, prop_dst, opop->subitem_reference_index, &private_ptr_item_dst);
+        }
+        else {
+          RNA_property_collection_lookup_int(
+              ptr_dst, prop_dst, opop->subitem_local_index, &private_ptr_item_dst);
+        }
+      }
+      else if (opop->subitem_reference_index != -1) {
+        RNA_property_collection_lookup_int(
+            ptr_src, prop_src, opop->subitem_reference_index, &private_ptr_item_src);
+        RNA_property_collection_lookup_int(
+            ptr_dst, prop_dst, opop->subitem_reference_index, &private_ptr_item_dst);
+      }
+      if (prop_storage != NULL) {
+        if (opop->subitem_local_name != NULL) {
+          RNA_property_collection_lookup_string(
+              ptr_storage, prop_storage, opop->subitem_local_name, &private_ptr_item_storage);
+        }
+        else if (opop->subitem_reference_name != NULL) {
+          RNA_property_collection_lookup_string(
+              ptr_storage, prop_storage, opop->subitem_reference_name, &private_ptr_item_storage);
+        }
+        else if (opop->subitem_local_index != -1) {
+          RNA_property_collection_lookup_int(
+              ptr_storage, prop_storage, opop->subitem_local_index, &private_ptr_item_storage);
+        }
+        else if (opop->subitem_reference_index != -1) {
+          RNA_property_collection_lookup_int(
+              ptr_storage, prop_storage, opop->subitem_reference_index, &private_ptr_item_storage);
+        }
+      }
+      ptr_item_dst = &private_ptr_item_dst;
+      ptr_item_src = &private_ptr_item_src;
+      ptr_item_storage = &private_ptr_item_storage;
+    }
+
+    if (!rna_property_override_operation_apply(bmain,
+                                               ptr_dst,
+                                               ptr_src,
+                                               ptr_storage,
+                                               prop_dst,
+                                               prop_src,
+                                               prop_storage,
+                                               ptr_item_dst,
+                                               ptr_item_src,
+                                               ptr_item_storage,
+                                               opop)) {
+      /* TODO No assert here, would be much much better to just report as warning,
+       * failing override applications will probably be fairly common! */
+      BLI_assert(0);
+    }
+  }
+}
+
+/** Apply given \a override operations on \a ptr_dst, using \a ptr_src
+ * (and \a ptr_storage for differential ops) as source. */
+void RNA_struct_override_apply(Main *bmain,
+                               PointerRNA *ptr_dst,
+                               PointerRNA *ptr_src,
+                               PointerRNA *ptr_storage,
+                               IDOverrideLibrary *override)
+{
+#ifdef DEBUG_OVERRIDE_TIMEIT
+  TIMEIT_START_AVERAGED(RNA_struct_override_apply);
+#endif
+  /* Note: Applying insert operations in a separate pass is mandatory.
+   * We could optimize this later, but for now, as inefficient as it is,
+   * don't think this is a critical point.
+   */
+  bool do_insert = false;
+  for (int i = 0; i < 2; i++, do_insert = true) {
+    for (IDOverrideLibraryProperty *op = override->properties.first; op; op = op->next) {
+      /* Simplified for now! */
+      PointerRNA data_src, data_dst;
+      PointerRNA data_item_src, data_item_dst;
+      PropertyRNA *prop_src, *prop_dst;
+
+      if (RNA_path_resolve_property_and_item_pointer(
+              ptr_dst, op->rna_path, &data_dst, &prop_dst, &data_item_dst) &&
+          RNA_path_resolve_property_and_item_pointer(
+              ptr_src, op->rna_path, &data_src, &prop_src, &data_item_src)) {
+        PointerRNA data_storage, data_item_storage;
+        PropertyRNA *prop_storage = NULL;
+
+        /* It is totally OK if this does not success,
+         * only a subset of override operations actually need storage. */
+        if (ptr_storage && (ptr_storage->id.data != NULL)) {
+          RNA_path_resolve_property_and_item_pointer(
+              ptr_storage, op->rna_path, &data_storage, &prop_storage, &data_item_storage);
+        }
+
+        rna_property_override_apply_ex(bmain,
+                                       &data_dst,
+                                       &data_src,
+                                       prop_storage ? &data_storage : NULL,
+                                       prop_dst,
+                                       prop_src,
+                                       prop_storage,
+                                       &data_item_dst,
+                                       &data_item_src,
+                                       prop_storage ? &data_item_storage : NULL,
+                                       op,
+                                       do_insert);
+      }
+#ifndef NDEBUG
+      else {
+        printf(
+            "Failed to apply library override operation to '%s.%s' "
+            "(could not resolve some properties, local:  %d, override: %d)\n",
+            ((ID *)ptr_src->id.data)->name,
+            op->rna_path,
+            RNA_path_resolve_property(ptr_dst, op->rna_path, &data_dst, &prop_dst),
+            RNA_path_resolve_property(ptr_src, op->rna_path, &data_src, &prop_src));
+      }
+#endif
+    }
+  }
+#ifdef DEBUG_OVERRIDE_TIMEIT
+  TIMEIT_END_AVERAGED(RNA_struct_override_apply);
+#endif
+}
+
+IDOverrideLibraryProperty *RNA_property_override_property_find(PointerRNA *ptr, PropertyRNA *prop)
+{
+  ID *id = ptr->id.data;
+
+  if (!id || !id->override_library) {
+    return NULL;
+  }
+
+  char *rna_path = RNA_path_from_ID_to_property(ptr, prop);
+  if (rna_path) {
+    IDOverrideLibraryProperty *op = BKE_override_library_property_find(id->override_library,
+                                                                       rna_path);
+    MEM_freeN(rna_path);
+    return op;
+  }
+  return NULL;
+}
+
+IDOverrideLibraryProperty *RNA_property_override_property_get(PointerRNA *ptr,
+                                                              PropertyRNA *prop,
+                                                              bool *r_created)
+{
+  ID *id = ptr->id.data;
+
+  if (!id || !id->override_library) {
+    return NULL;
+  }
+
+  char *rna_path = RNA_path_from_ID_to_property(ptr, prop);
+  if (rna_path) {
+    IDOverrideLibraryProperty *op = BKE_override_library_property_get(
+        id->override_library, rna_path, r_created);
+    MEM_freeN(rna_path);
+    return op;
+  }
+  return NULL;
+}
+
+IDOverrideLibraryPropertyOperation *RNA_property_override_property_operation_find(
+    PointerRNA *ptr, PropertyRNA *prop, const int index, const bool strict, bool *r_strict)
+{
+  IDOverrideLibraryProperty *op = RNA_property_override_property_find(ptr, prop);
+
+  if (!op) {
+    return NULL;
+  }
+
+  return BKE_override_library_property_operation_find(
+      op, NULL, NULL, index, index, strict, r_strict);
+}
+
+IDOverrideLibraryPropertyOperation *RNA_property_override_property_operation_get(
+    PointerRNA *ptr,
+    PropertyRNA *prop,
+    const short operation,
+    const int index,
+    const bool strict,
+    bool *r_strict,
+    bool *r_created)
+{
+  IDOverrideLibraryProperty *op = RNA_property_override_property_get(ptr, prop, NULL);
+
+  if (!op) {
+    return NULL;
+  }
+
+  return BKE_override_library_property_operation_get(
+      op, operation, NULL, NULL, index, index, strict, r_strict, r_created);
+}
+
+eRNAOverrideStatus RNA_property_override_library_status(PointerRNA *ptr,
+                                                        PropertyRNA *prop,
+                                                        const int index)
+{
+  int override_status = 0;
+
+  if (!BKE_override_library_is_enabled()) {
+    return override_status;
+  }
+
+  if (!ptr || !prop || !ptr->id.data || !((ID *)ptr->id.data)->override_library) {
+    return override_status;
+  }
+
+  if (RNA_property_overridable_get(ptr, prop) && RNA_property_editable_flag(ptr, prop)) {
+    override_status |= RNA_OVERRIDE_STATUS_OVERRIDABLE;
+  }
+
+  IDOverrideLibraryPropertyOperation *opop = RNA_property_override_property_operation_find(
+      ptr, prop, index, false, NULL);
+  if (opop != NULL) {
+    override_status |= RNA_OVERRIDE_STATUS_OVERRIDDEN;
+    if (opop->flag & IDOVERRIDE_LIBRARY_FLAG_MANDATORY) {
+      override_status |= RNA_OVERRIDE_STATUS_MANDATORY;
+    }
+    if (opop->flag & IDOVERRIDE_LIBRARY_FLAG_LOCKED) {
+      override_status |= RNA_OVERRIDE_STATUS_LOCKED;
+    }
+  }
+
+  return override_status;
+}
diff --git a/source/blender/makesrna/intern/rna_access_internal.h b/source/blender/makesrna/intern/rna_access_internal.h
new file mode 100644 (file)
index 0000000..28ec504
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup RNA
+ */
+
+#ifndef __RNA_ACCESS_INTERNAL_H__
+#define __RNA_ACCESS_INTERNAL_H__
+
+#include "BLI_utildefines.h"
+
+#include "rna_internal_types.h"
+
+struct IDProperty;
+
+PropertyRNA *rna_ensure_property(PropertyRNA *prop);
+
+void rna_idproperty_touch(struct IDProperty *idprop);
+
+#endif /* __ACCESS_RNA_INTERNAL_H__ */