diff options
| author | Stefan Monnier | 2013-11-29 14:47:58 -0500 |
|---|---|---|
| committer | Stefan Monnier | 2013-11-29 14:47:58 -0500 |
| commit | 9f4ffeee436f71fc1253b27151c087fe5d0d3e45 (patch) | |
| tree | 767702294872ed28ea434b8c3f7556f22c8c545f | |
| parent | 1659fa3fbd9c0d644930d4e7c8efb2c2e55467dc (diff) | |
| download | emacs-9f4ffeee436f71fc1253b27151c087fe5d0d3e45.tar.gz emacs-9f4ffeee436f71fc1253b27151c087fe5d0d3e45.zip | |
* src/fns.c (internal_equal): Add a hash_table argument to handle cycles.
| -rw-r--r-- | src/ChangeLog | 2 | ||||
| -rw-r--r-- | src/fns.c | 54 |
2 files changed, 44 insertions, 12 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index 02a3f4eb21d..a626c2b1963 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,5 +1,7 @@ | |||
| 1 | 2013-11-29 Stefan Monnier <monnier@iro.umontreal.ca> | 1 | 2013-11-29 Stefan Monnier <monnier@iro.umontreal.ca> |
| 2 | 2 | ||
| 3 | * fns.c (internal_equal): Add a hash_table argument to handle cycles. | ||
| 4 | |||
| 3 | * xdisp.c (REDISPLAY_SOME_P): New macro. | 5 | * xdisp.c (REDISPLAY_SOME_P): New macro. |
| 4 | (redisplay_internal): Use it (bug#15999). | 6 | (redisplay_internal): Use it (bug#15999). |
| 5 | (prepare_menu_bars, redisplay_window): Use it as well. | 7 | (prepare_menu_bars, redisplay_window): Use it as well. |
| @@ -48,7 +48,7 @@ static Lisp_Object Qcodeset, Qdays, Qmonths, Qpaper; | |||
| 48 | 48 | ||
| 49 | static Lisp_Object Qmd5, Qsha1, Qsha224, Qsha256, Qsha384, Qsha512; | 49 | static Lisp_Object Qmd5, Qsha1, Qsha224, Qsha256, Qsha384, Qsha512; |
| 50 | 50 | ||
| 51 | static bool internal_equal (Lisp_Object, Lisp_Object, int, bool); | 51 | static bool internal_equal (Lisp_Object, Lisp_Object, int, bool, Lisp_Object); |
| 52 | 52 | ||
| 53 | DEFUN ("identity", Fidentity, Sidentity, 1, 1, 0, | 53 | DEFUN ("identity", Fidentity, Sidentity, 1, 1, 0, |
| 54 | doc: /* Return the argument unchanged. */) | 54 | doc: /* Return the argument unchanged. */) |
| @@ -1355,7 +1355,7 @@ The value is actually the tail of LIST whose car is ELT. */) | |||
| 1355 | register Lisp_Object tem; | 1355 | register Lisp_Object tem; |
| 1356 | CHECK_LIST_CONS (tail, list); | 1356 | CHECK_LIST_CONS (tail, list); |
| 1357 | tem = XCAR (tail); | 1357 | tem = XCAR (tail); |
| 1358 | if (FLOATP (tem) && internal_equal (elt, tem, 0, 0)) | 1358 | if (FLOATP (tem) && internal_equal (elt, tem, 0, 0, Qnil)) |
| 1359 | return tail; | 1359 | return tail; |
| 1360 | QUIT; | 1360 | QUIT; |
| 1361 | } | 1361 | } |
| @@ -1959,7 +1959,7 @@ Floating-point numbers of equal value are `eql', but they may not be `eq'. */) | |||
| 1959 | (Lisp_Object obj1, Lisp_Object obj2) | 1959 | (Lisp_Object obj1, Lisp_Object obj2) |
| 1960 | { | 1960 | { |
| 1961 | if (FLOATP (obj1)) | 1961 | if (FLOATP (obj1)) |
| 1962 | return internal_equal (obj1, obj2, 0, 0) ? Qt : Qnil; | 1962 | return internal_equal (obj1, obj2, 0, 0, Qnil) ? Qt : Qnil; |
| 1963 | else | 1963 | else |
| 1964 | return EQ (obj1, obj2) ? Qt : Qnil; | 1964 | return EQ (obj1, obj2) ? Qt : Qnil; |
| 1965 | } | 1965 | } |
| @@ -1974,7 +1974,7 @@ Numbers are compared by value, but integers cannot equal floats. | |||
| 1974 | Symbols must match exactly. */) | 1974 | Symbols must match exactly. */) |
| 1975 | (register Lisp_Object o1, Lisp_Object o2) | 1975 | (register Lisp_Object o1, Lisp_Object o2) |
| 1976 | { | 1976 | { |
| 1977 | return internal_equal (o1, o2, 0, 0) ? Qt : Qnil; | 1977 | return internal_equal (o1, o2, 0, 0, Qnil) ? Qt : Qnil; |
| 1978 | } | 1978 | } |
| 1979 | 1979 | ||
| 1980 | DEFUN ("equal-including-properties", Fequal_including_properties, Sequal_including_properties, 2, 2, 0, | 1980 | DEFUN ("equal-including-properties", Fequal_including_properties, Sequal_including_properties, 2, 2, 0, |
| @@ -1983,7 +1983,7 @@ This is like `equal' except that it compares the text properties | |||
| 1983 | of strings. (`equal' ignores text properties.) */) | 1983 | of strings. (`equal' ignores text properties.) */) |
| 1984 | (register Lisp_Object o1, Lisp_Object o2) | 1984 | (register Lisp_Object o1, Lisp_Object o2) |
| 1985 | { | 1985 | { |
| 1986 | return internal_equal (o1, o2, 0, 1) ? Qt : Qnil; | 1986 | return internal_equal (o1, o2, 0, 1, Qnil) ? Qt : Qnil; |
| 1987 | } | 1987 | } |
| 1988 | 1988 | ||
| 1989 | /* DEPTH is current depth of recursion. Signal an error if it | 1989 | /* DEPTH is current depth of recursion. Signal an error if it |
| @@ -1991,10 +1991,39 @@ of strings. (`equal' ignores text properties.) */) | |||
| 1991 | PROPS means compare string text properties too. */ | 1991 | PROPS means compare string text properties too. */ |
| 1992 | 1992 | ||
| 1993 | static bool | 1993 | static bool |
| 1994 | internal_equal (Lisp_Object o1, Lisp_Object o2, int depth, bool props) | 1994 | internal_equal (Lisp_Object o1, Lisp_Object o2, int depth, bool props, |
| 1995 | Lisp_Object ht) | ||
| 1995 | { | 1996 | { |
| 1996 | if (depth > 200) | 1997 | if (depth > 10) |
| 1997 | error ("Stack overflow in equal"); | 1998 | { |
| 1999 | if (depth > 200) | ||
| 2000 | error ("Stack overflow in equal"); | ||
| 2001 | if (NILP (ht)) | ||
| 2002 | { | ||
| 2003 | Lisp_Object args[2] = { QCtest, Qeq }; | ||
| 2004 | ht = Fmake_hash_table (2, args); | ||
| 2005 | } | ||
| 2006 | switch (XTYPE (o1)) | ||
| 2007 | { | ||
| 2008 | case Lisp_Cons: case Lisp_Misc: case Lisp_Vectorlike: | ||
| 2009 | { | ||
| 2010 | struct Lisp_Hash_Table *h = XHASH_TABLE (ht); | ||
| 2011 | EMACS_UINT hash; | ||
| 2012 | ptrdiff_t i = hash_lookup (h, o1, &hash); | ||
| 2013 | if (i >= 0) | ||
| 2014 | { /* `o1' was seen already. */ | ||
| 2015 | Lisp_Object o2s = HASH_VALUE (h, i); | ||
| 2016 | if (!NILP (Fmemq (o2, o2s))) | ||
| 2017 | return 1; | ||
| 2018 | else | ||
| 2019 | set_hash_value_slot (h, i, Fcons (o2, o2s)); | ||
| 2020 | } | ||
| 2021 | else | ||
| 2022 | hash_put (h, o1, Fcons (o2, Qnil), hash); | ||
| 2023 | } | ||
| 2024 | default: ; | ||
| 2025 | } | ||
| 2026 | } | ||
| 1998 | 2027 | ||
| 1999 | tail_recurse: | 2028 | tail_recurse: |
| 2000 | QUIT; | 2029 | QUIT; |
| @@ -2017,10 +2046,11 @@ internal_equal (Lisp_Object o1, Lisp_Object o2, int depth, bool props) | |||
| 2017 | } | 2046 | } |
| 2018 | 2047 | ||
| 2019 | case Lisp_Cons: | 2048 | case Lisp_Cons: |
| 2020 | if (!internal_equal (XCAR (o1), XCAR (o2), depth + 1, props)) | 2049 | if (!internal_equal (XCAR (o1), XCAR (o2), depth + 1, props, ht)) |
| 2021 | return 0; | 2050 | return 0; |
| 2022 | o1 = XCDR (o1); | 2051 | o1 = XCDR (o1); |
| 2023 | o2 = XCDR (o2); | 2052 | o2 = XCDR (o2); |
| 2053 | /* FIXME: This inf-loops in a circular list! */ | ||
| 2024 | goto tail_recurse; | 2054 | goto tail_recurse; |
| 2025 | 2055 | ||
| 2026 | case Lisp_Misc: | 2056 | case Lisp_Misc: |
| @@ -2029,9 +2059,9 @@ internal_equal (Lisp_Object o1, Lisp_Object o2, int depth, bool props) | |||
| 2029 | if (OVERLAYP (o1)) | 2059 | if (OVERLAYP (o1)) |
| 2030 | { | 2060 | { |
| 2031 | if (!internal_equal (OVERLAY_START (o1), OVERLAY_START (o2), | 2061 | if (!internal_equal (OVERLAY_START (o1), OVERLAY_START (o2), |
| 2032 | depth + 1, props) | 2062 | depth + 1, props, ht) |
| 2033 | || !internal_equal (OVERLAY_END (o1), OVERLAY_END (o2), | 2063 | || !internal_equal (OVERLAY_END (o1), OVERLAY_END (o2), |
| 2034 | depth + 1, props)) | 2064 | depth + 1, props, ht)) |
| 2035 | return 0; | 2065 | return 0; |
| 2036 | o1 = XOVERLAY (o1)->plist; | 2066 | o1 = XOVERLAY (o1)->plist; |
| 2037 | o2 = XOVERLAY (o2)->plist; | 2067 | o2 = XOVERLAY (o2)->plist; |
| @@ -2083,7 +2113,7 @@ internal_equal (Lisp_Object o1, Lisp_Object o2, int depth, bool props) | |||
| 2083 | Lisp_Object v1, v2; | 2113 | Lisp_Object v1, v2; |
| 2084 | v1 = AREF (o1, i); | 2114 | v1 = AREF (o1, i); |
| 2085 | v2 = AREF (o2, i); | 2115 | v2 = AREF (o2, i); |
| 2086 | if (!internal_equal (v1, v2, depth + 1, props)) | 2116 | if (!internal_equal (v1, v2, depth + 1, props, ht)) |
| 2087 | return 0; | 2117 | return 0; |
| 2088 | } | 2118 | } |
| 2089 | return 1; | 2119 | return 1; |