-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcommand.py
102 lines (76 loc) · 3.53 KB
/
command.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
class Command:
"""Class representing a filesystem command.
Properties:
- node: a Node object
- before: a Value object; the input value
- after: a Value object; the output value
- prev: an optional pointer to another command in a double-linked list
- next: an optional pointer to another command in a single-linked list
- up: an optional up pointer to another command
- order: an optional index used during ordering
- delete: optional bool flag used by get_any_merger(): whether the current command is discarded
Usage:
c = Command(node, before_value, after_value)
"""
def __init__(self, node, before, after):
"""Constructor.
Arguments:
- node: a Node object
- before: a Value object; the input value
- after: a Value object; the output value
"""
self.node = node
self.before = before
self.after = after
self.prev = None
self.next = None
self.up = None
self.order = None
self.delete = None
def as_string(self, color=False):
"""Return a string representation of the object"""
if color:
on = "\033[31;1m"
off = "\033[0m"
else:
on = ''
off = ''
return f"{on}<{off}{self.node.as_string()}{on}|{off}{self.before.as_string()}{on}|{off}{self.after.as_string()}{on}>{off}"
def clone(self):
"""Return a clone excluding the pointers specific to a command in a list"""
return Command(self.node, self.before, self.after)
def equals(self, other):
"""Whether the current object and another are equal"""
return (self.node.equals(other.node) and self.before.equals(other.before) and self.after.equals(other.after))
def is_null(self):
"""Whether this is a null command"""
return self.before.equals(self.after)
def is_constructor(self):
"""Whether this is a constructor command"""
return self.after.type_greater(self.before)
def is_destructor(self):
"""Whether this is a destructor command"""
return self.after.type_less(self.before)
def is_constructor_pair_with_next(self, other):
"""Whether this command forms a constructor pair with the next command, `other`"""
return (self.is_constructor() and self.after.is_dir() and other.is_constructor() and other.before.is_empty() and self.node.is_parent_of(other.node))
def is_destructor_pair_with_next(self, other):
"""Whether this command forms a destructor pair with the next command, `other`"""
return (self.is_destructor() and self.after.is_empty() and other.is_destructor() and other.before.is_dir() and other.node.is_parent_of(self.node))
def weak_conflict_with(self, other):
"""Whether this command is in conflict with another command, by the weak definition"""
if self.equals(other):
raise Exception("conflicts_with() should not be called on equal commands")
if self.node.equals(other.node):
return True
if self.node.is_ancestor_of(other.node):
ancestor = self
descendant = other
elif self.node.is_descendant_of(other.node):
ancestor = other
descendant = self
else:
return False
if (not ancestor.after.is_dir()) and (not descendant.after.is_empty()):
return True
return False