diff --git a/Lib/enum.py b/Lib/enum.py index 06f42a97803..0be1b60cd6d 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -861,28 +861,20 @@ def _decompose(flag, value): # _decompose is only called if the value is not named not_covered = value negative = value < 0 - # issue29167: wrap accesses to _value2member_map_ in a list to avoid race - # conditions between iterating over it and having more pseudo- - # members added to it - if negative: - # only check for named flags - flags_to_check = [ - (m, v) - for v, m in list(flag._value2member_map_.items()) - if m.name is not None - ] - else: - # check for named flags and powers-of-two flags - flags_to_check = [ - (m, v) - for v, m in list(flag._value2member_map_.items()) - if m.name is not None or _power_of_two(v) - ] members = [] - for member, member_value in flags_to_check: + for member in flag: + member_value = member.value if member_value and member_value & value == member_value: members.append(member) not_covered &= ~member_value + if not negative: + tmp = not_covered + while tmp: + flag_value = 2 ** _high_bit(tmp) + if flag_value in flag._value2member_map_: + members.append(flag._value2member_map_[flag_value]) + not_covered &= ~flag_value + tmp &= ~flag_value if not members and value in flag._value2member_map_: members.append(flag._value2member_map_[value]) members.sort(key=lambda m: m._value_, reverse=True) @@ -890,8 +882,3 @@ def _decompose(flag, value): # we have the breakdown, don't need the value member itself members.pop(0) return members, not_covered - -def _power_of_two(value): - if value < 1: - return False - return value == 2 ** _high_bit(value) diff --git a/Misc/NEWS.d/next/Library/2019-09-30-12-09-41.bpo-38045.VDRtd3.rst b/Misc/NEWS.d/next/Library/2019-09-30-12-09-41.bpo-38045.VDRtd3.rst new file mode 100644 index 00000000000..e7e515f5c25 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2019-09-30-12-09-41.bpo-38045.VDRtd3.rst @@ -0,0 +1 @@ +Improve the performance of :func:`enum._decompose` in :mod:`enum`. Patch by hongweipeng.