marmoute created this revision.
Herald added a reviewer: hg-reviewers.
Herald added a subscriber: mercurial-patches.

REVISION SUMMARY
  Now that we know were we are going, we can update the C implementation.

REPOSITORY
  rHG Mercurial

BRANCH
  default

REVISION DETAIL
  https://phab.mercurial-scm.org/D11387

AFFECTED FILES
  mercurial/cext/charencode.c
  mercurial/cext/dirs.c
  mercurial/cext/parsers.c
  mercurial/cext/util.h

CHANGE DETAILS

diff --git a/mercurial/cext/util.h b/mercurial/cext/util.h
--- a/mercurial/cext/util.h
+++ b/mercurial/cext/util.h
@@ -24,13 +24,22 @@
 /* clang-format off */
 typedef struct {
        PyObject_HEAD
-       char state;
+       char flags;
        int mode;
        int size;
        int mtime;
 } dirstateItemObject;
 /* clang-format on */
 
+static const char dirstate_flag_wc_tracked = 1;
+static const char dirstate_flag_p1_tracked = 1 << 1;
+static const char dirstate_flag_p2_tracked = 1 << 2;
+static const char dirstate_flag_possibly_dirty = 1 << 3;
+static const char dirstate_flag_merged = 1 << 4;
+static const char dirstate_flag_clean_p1 = 1 << 5;
+static const char dirstate_flag_clean_p2 = 1 << 6;
+static const char dirstate_flag_rust_special = 1 << 7;
+
 extern PyTypeObject dirstateItemType;
 #define dirstate_tuple_check(op) (Py_TYPE(op) == &dirstateItemType)
 
diff --git a/mercurial/cext/parsers.c b/mercurial/cext/parsers.c
--- a/mercurial/cext/parsers.c
+++ b/mercurial/cext/parsers.c
@@ -89,60 +89,45 @@
        if (!t) {
                return NULL;
        }
-       t->state = 'r';
+
+       t->flags = 0;
+       if (wc_tracked) {
+               t->flags |= dirstate_flag_wc_tracked;
+       }
+       if (p1_tracked) {
+               t->flags |= dirstate_flag_p1_tracked;
+       }
+       if (p2_tracked) {
+               t->flags |= dirstate_flag_p2_tracked;
+       }
+       if (possibly_dirty) {
+               t->flags |= dirstate_flag_possibly_dirty;
+       }
+       if (merged) {
+               t->flags |= dirstate_flag_merged;
+       }
+       if (clean_p1) {
+               t->flags |= dirstate_flag_clean_p1;
+       }
+       if (clean_p2) {
+               t->flags |= dirstate_flag_clean_p2;
+       }
        t->mode = 0;
        t->size = dirstate_v1_nonnormal;
        t->mtime = ambiguous_time;
-       if (!(p1_tracked || p2_tracked || wc_tracked)) {
-               /* Nothing special to do, file is untracked */
-       } else if (merged) {
-               t->state = 'm';
-               t->size = dirstate_v1_from_p2;
-               t->mtime = ambiguous_time;
-       } else if (!(p1_tracked || p2_tracked) && wc_tracked) {
-               t->state = 'a';
-               t->size = dirstate_v1_nonnormal;
-               t->mtime = ambiguous_time;
-       } else if ((p1_tracked || p2_tracked) && !wc_tracked) {
-               t->state = 'r';
-               t->size = 0;
-               t->mtime = 0;
-       } else if (clean_p2 && wc_tracked) {
-               t->state = 'n';
-               t->size = dirstate_v1_from_p2;
-               t->mtime = ambiguous_time;
-       } else if (!p1_tracked && p2_tracked && wc_tracked) {
-               t->state = 'n';
-               t->size = dirstate_v1_from_p2;
-               t->mtime = ambiguous_time;
-       } else if (possibly_dirty) {
-               t->state = 'n';
-               t->size = dirstate_v1_nonnormal;
-               t->mtime = ambiguous_time;
-       } else if (wc_tracked) {
-               /* this is a "normal" file */
-               if (parentfiledata == Py_None) {
-                       PyErr_SetString(
-                           PyExc_RuntimeError,
-                           "failed to pass parentfiledata for a normal file");
-                       return NULL;
-               }
+       if (parentfiledata != Py_None) {
                if (!PyTuple_CheckExact(parentfiledata)) {
                        PyErr_SetString(
                            PyExc_TypeError,
                            "parentfiledata should be a Tuple or None");
                        return NULL;
                }
-               t->state = 'n';
                t->mode =
                    (int)PyLong_AsLong(PyTuple_GetItem(parentfiledata, 0));
                t->size =
                    (int)PyLong_AsLong(PyTuple_GetItem(parentfiledata, 1));
                t->mtime =
                    (int)PyLong_AsLong(PyTuple_GetItem(parentfiledata, 2));
-       } else {
-               PyErr_SetString(PyExc_RuntimeError, "unreachable");
-               return NULL;
        }
        return (PyObject *)t;
 }
@@ -154,42 +139,69 @@
 
 static inline bool dirstate_item_c_tracked(dirstateItemObject *self)
 {
-       return (self->state == 'a' || self->state == 'm' || self->state == 'n');
+       return (self->flags & dirstate_flag_wc_tracked);
 }
 
 static inline bool dirstate_item_c_added(dirstateItemObject *self)
 {
-       return (self->state == 'a');
+       char mask = (dirstate_flag_wc_tracked | dirstate_flag_p1_tracked |
+                    dirstate_flag_p2_tracked);
+       char target = dirstate_flag_wc_tracked;
+       return (self->flags & mask) == target;
 }
 
 static inline bool dirstate_item_c_removed(dirstateItemObject *self)
 {
-       return (self->state == 'r');
+       if (self->flags & dirstate_flag_wc_tracked) {
+               return false;
+       }
+       return (self->flags &
+               (dirstate_flag_p1_tracked | dirstate_flag_p2_tracked));
 }
 
 static inline bool dirstate_item_c_merged(dirstateItemObject *self)
 {
-       return (self->state == 'm');
+       return ((self->flags & dirstate_flag_wc_tracked) &&
+               (self->flags & dirstate_flag_merged));
 }
 
 static inline bool dirstate_item_c_merged_removed(dirstateItemObject *self)
 {
-       return (self->state == 'r' && self->size == dirstate_v1_nonnormal);
+       if (!dirstate_item_c_removed(self)) {
+               return false;
+       }
+       return (self->flags & dirstate_flag_merged);
 }
 
 static inline bool dirstate_item_c_from_p2(dirstateItemObject *self)
 {
-       return (self->state == 'n' && self->size == dirstate_v1_from_p2);
+       if (!dirstate_item_c_tracked(self)) {
+               return false;
+       }
+       return (self->flags & dirstate_flag_clean_p2);
 }
 
 static inline bool dirstate_item_c_from_p2_removed(dirstateItemObject *self)
 {
-       return (self->state == 'r' && self->size == dirstate_v1_from_p2);
+       if (!dirstate_item_c_removed(self)) {
+               return false;
+       }
+       return (self->flags & dirstate_flag_clean_p2);
 }
 
 static inline char dirstate_item_c_v1_state(dirstateItemObject *self)
 {
-       return self->state;
+       if (self->flags & dirstate_flag_rust_special) {
+               return ' ';
+       } else if (dirstate_item_c_removed(self)) {
+               return 'r';
+       } else if (dirstate_item_c_merged(self)) {
+               return 'm';
+       } else if (dirstate_item_c_added(self)) {
+               return 'a';
+       } else {
+               return 'n';
+       }
 }
 
 static inline int dirstate_item_c_v1_mode(dirstateItemObject *self)
@@ -199,12 +211,44 @@
 
 static inline int dirstate_item_c_v1_size(dirstateItemObject *self)
 {
-       return self->size;
+       if (self->flags & dirstate_flag_rust_special) {
+               return self->size;
+       } else if (dirstate_item_c_merged_removed(self)) {
+               return dirstate_v1_nonnormal;
+       } else if (dirstate_item_c_from_p2_removed(self)) {
+               return dirstate_v1_from_p2;
+       } else if (dirstate_item_c_removed(self)) {
+               return 0;
+       } else if (dirstate_item_c_merged(self)) {
+               return dirstate_v1_from_p2;
+       } else if (dirstate_item_c_added(self)) {
+               return dirstate_v1_nonnormal;
+       } else if (dirstate_item_c_from_p2(self)) {
+               return dirstate_v1_from_p2;
+       } else if (self->flags & dirstate_flag_possibly_dirty) {
+               return self->size; /* NON NORMAL ? */
+       } else {
+               return self->size;
+       }
 }
 
 static inline int dirstate_item_c_v1_mtime(dirstateItemObject *self)
 {
-       return self->mtime;
+       if (self->flags & dirstate_flag_rust_special) {
+               return self->mtime;
+       } else if (dirstate_item_c_removed(self)) {
+               return 0;
+       } else if (self->flags & dirstate_flag_possibly_dirty) {
+               return ambiguous_time;
+       } else if (dirstate_item_c_merged(self)) {
+               return ambiguous_time;
+       } else if (dirstate_item_c_added(self)) {
+               return ambiguous_time;
+       } else if (dirstate_item_c_from_p2(self)) {
+               return ambiguous_time;
+       } else {
+               return self->mtime;
+       }
 }
 
 static PyObject *dirstate_item_v1_state(dirstateItemObject *self)
@@ -253,10 +297,76 @@
        if (!t) {
                return NULL;
        }
-       t->state = state;
-       t->mode = mode;
-       t->size = size;
-       t->mtime = mtime;
+
+       if (state == 'm') {
+               t->flags =
+                   (dirstate_flag_wc_tracked | dirstate_flag_p1_tracked |
+                    dirstate_flag_p2_tracked | dirstate_flag_merged);
+               t->mode = 0;
+               t->size = dirstate_v1_from_p2;
+               t->mtime = ambiguous_time;
+       } else if (state == 'a') {
+               t->flags = dirstate_flag_wc_tracked;
+               t->mode = 0;
+               t->size = dirstate_v1_nonnormal;
+               t->mtime = ambiguous_time;
+       } else if (state == 'r') {
+               t->mode = 0;
+               t->size = 0;
+               t->mtime = 0;
+               if (size == dirstate_v1_nonnormal) {
+                       t->flags =
+                           (dirstate_flag_p1_tracked |
+                            dirstate_flag_p2_tracked | dirstate_flag_merged);
+               } else if (size == dirstate_v1_from_p2) {
+                       t->flags =
+                           (dirstate_flag_p2_tracked | dirstate_flag_clean_p2);
+               } else {
+                       t->flags = dirstate_flag_p1_tracked;
+               }
+       } else if (state == 'n') {
+               if (size == dirstate_v1_from_p2) {
+                       t->flags =
+                           (dirstate_flag_wc_tracked |
+                            dirstate_flag_p2_tracked | dirstate_flag_clean_p2);
+                       t->mode = 0;
+                       t->size = dirstate_v1_from_p2;
+                       t->mtime = ambiguous_time;
+               } else if (size == dirstate_v1_nonnormal) {
+                       t->flags = (dirstate_flag_wc_tracked |
+                                   dirstate_flag_p1_tracked |
+                                   dirstate_flag_possibly_dirty);
+                       t->mode = 0;
+                       t->size = dirstate_v1_nonnormal;
+                       t->mtime = ambiguous_time;
+               } else if (mtime == ambiguous_time) {
+                       t->flags = (dirstate_flag_wc_tracked |
+                                   dirstate_flag_p1_tracked |
+                                   dirstate_flag_possibly_dirty);
+                       t->mode = mode;
+                       t->size = size;
+                       t->mtime = 0;
+               } else {
+                       t->flags = (dirstate_flag_wc_tracked |
+                                   dirstate_flag_p1_tracked);
+                       t->mode = mode;
+                       t->size = size;
+                       t->mtime = mtime;
+               }
+       } else if (state == ' ') {
+               /* XXX Rust is using this special case, it should be clean up
+                * later. */
+               t->flags = dirstate_flag_rust_special;
+               t->mode = mode;
+               t->size = size;
+               t->mtime = mtime;
+       } else {
+               PyErr_Format(PyExc_RuntimeError,
+                            "unknown state: `%c` (%d, %d, %d)", state, mode,
+                            size, mtime, NULL);
+               return NULL;
+       }
+
        return t;
 }
 
@@ -284,7 +394,7 @@
        if (!t) {
                return NULL;
        }
-       t->state = 'a';
+       t->flags = dirstate_flag_wc_tracked;
        t->mode = 0;
        t->size = dirstate_v1_nonnormal;
        t->mtime = ambiguous_time;
@@ -301,7 +411,8 @@
        if (!t) {
                return NULL;
        }
-       t->state = 'm';
+       t->flags = (dirstate_flag_wc_tracked | dirstate_flag_p1_tracked |
+                   dirstate_flag_p2_tracked | dirstate_flag_merged);
        t->mode = 0;
        t->size = dirstate_v1_from_p2;
        t->mtime = ambiguous_time;
@@ -320,7 +431,8 @@
        if (!t) {
                return NULL;
        }
-       t->state = 'n';
+       t->flags = (dirstate_flag_wc_tracked | dirstate_flag_p2_tracked |
+                   dirstate_flag_clean_p2);
        t->mode = 0;
        t->size = dirstate_v1_from_p2;
        t->mtime = ambiguous_time;
@@ -339,7 +451,8 @@
        if (!t) {
                return NULL;
        }
-       t->state = 'n';
+       t->flags = (dirstate_flag_wc_tracked | dirstate_flag_p1_tracked |
+                   dirstate_flag_possibly_dirty);
        t->mode = 0;
        t->size = dirstate_v1_nonnormal;
        t->mtime = ambiguous_time;
@@ -363,7 +476,7 @@
        if (!t) {
                return NULL;
        }
-       t->state = 'n';
+       t->flags = (dirstate_flag_wc_tracked | dirstate_flag_p1_tracked);
        t->mode = mode;
        t->size = size;
        t->mtime = mtime;
@@ -374,22 +487,17 @@
    to make sure it is correct. */
 static PyObject *dirstate_item_set_possibly_dirty(dirstateItemObject *self)
 {
-       self->mtime = ambiguous_time;
-       Py_RETURN_NONE;
+       if (self->flags |= dirstate_flag_possibly_dirty) {
+               Py_RETURN_NONE;
+       }
 }
 
 static PyObject *dirstate_item_set_untracked(dirstateItemObject *self)
 {
-       if (self->state == 'm') {
-               self->size = dirstate_v1_nonnormal;
-       } else if (self->state == 'n' && self->size == dirstate_v1_from_p2) {
-               self->size = dirstate_v1_from_p2;
-       } else {
-               self->size = 0;
-       }
-       self->state = 'r';
+       self->flags &= ~dirstate_flag_wc_tracked;
        self->mode = 0;
        self->mtime = 0;
+       self->size = 0;
        Py_RETURN_NONE;
 }
 
@@ -713,17 +821,19 @@
                }
                t = (dirstateItemObject *)v;
 
-               if (t->state == 'n' && t->size == -2) {
+               if (dirstate_item_c_from_p2(t)) {
                        if (PySet_Add(otherpset, fname) == -1) {
                                goto bail;
                        }
                }
-
-               if (t->state == 'n' && t->mtime != -1) {
-                       continue;
-               }
-               if (PySet_Add(nonnset, fname) == -1) {
-                       goto bail;
+               if (!(t->flags & dirstate_flag_wc_tracked) ||
+                   !(t->flags &
+                     (dirstate_flag_p1_tracked | dirstate_flag_p2_tracked)) ||
+                   (t->flags &
+                    (dirstate_flag_possibly_dirty | dirstate_flag_merged))) {
+                       if (PySet_Add(nonnset, fname) == -1) {
+                               goto bail;
+                       }
                }
        }
 
@@ -820,10 +930,10 @@
                }
                tuple = (dirstateItemObject *)v;
 
-               state = tuple->state;
-               mode = tuple->mode;
-               size = tuple->size;
-               mtime = tuple->mtime;
+               state = dirstate_item_c_v1_state(tuple);
+               mode = dirstate_item_c_v1_mode(tuple);
+               size = dirstate_item_c_v1_size(tuple);
+               mtime = dirstate_item_c_v1_mtime(tuple);
                if (state == 'n' && mtime == now) {
                        /* See pure/parsers.py:pack_dirstate for why we do
                         * this. */
diff --git a/mercurial/cext/dirs.c b/mercurial/cext/dirs.c
--- a/mercurial/cext/dirs.c
+++ b/mercurial/cext/dirs.c
@@ -177,7 +177,8 @@
                                                "expected a dirstate tuple");
                                return -1;
                        }
-                       if (((dirstateItemObject *)value)->state == 'r')
+                       if (!(((dirstateItemObject *)value)->flags &
+                             dirstate_flag_wc_tracked))
                                continue;
                }
 
diff --git a/mercurial/cext/charencode.c b/mercurial/cext/charencode.c
--- a/mercurial/cext/charencode.c
+++ b/mercurial/cext/charencode.c
@@ -264,7 +264,7 @@
                }
 
                tuple = (dirstateItemObject *)v;
-               if (tuple->state != 'r') {
+               if (tuple->flags | dirstate_flag_wc_tracked) {
                        PyObject *normed;
                        if (table != NULL) {
                                normed = _asciitransform(k, table,



To: marmoute, #hg-reviewers
Cc: mercurial-patches, mercurial-devel
_______________________________________________
Mercurial-devel mailing list
Mercurial-devel@mercurial-scm.org
https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel

Reply via email to