Change internal representation of roles in Member and Emoji.

Introduce a new internal type, SnowflakeList, which has better memory
footprint over a regular list or set of roles. It is suspected that
there will be a 9x reduction of memory for every Emoji instance and a
48 byte saving per Member instance. However, these savings will
probably only be evident on larger bots.

As a consequence of this change, Member.roles is now computed lazily.

Currently I am not sure if I want to do the initial sorting on the
SnowflakeList for Member, as this comes with a O(n log n) cost when
creating a Member for little purpose since SnowflakeList.has is not
overly relied on. If CPU time becomes an issue this might change.
This commit is contained in:
Rapptz
2018-09-24 22:06:49 -04:00
parent 3d03dbc451
commit 95d8bb2e85
5 changed files with 67 additions and 21 deletions

View File

@ -136,10 +136,6 @@ class Member(discord.abc.Messageable, _BaseUser):
Attributes
----------
roles: List[:class:`Role`]
A :class:`list` of :class:`Role` that the member belongs to. Note that the first element of this
list is always the default '@everyone' role. These roles are sorted by their position
in the role hierarchy.
joined_at: `datetime.datetime`
A datetime object that specifies the date and time in UTC that the member joined the guild for
the first time.
@ -154,7 +150,7 @@ class Member(discord.abc.Messageable, _BaseUser):
The guild specific nickname of the user.
"""
__slots__ = ('roles', 'joined_at', 'status', 'activity', 'guild', 'nick', '_user', '_state')
__slots__ = ('_roles', 'joined_at', 'status', 'activity', 'guild', 'nick', '_user', '_state')
def __init__(self, *, data, guild, state):
self._state = state
@ -187,15 +183,7 @@ class Member(discord.abc.Messageable, _BaseUser):
return ch
def _update_roles(self, data):
# update the roles
self.roles = [self.guild.default_role]
for role_id in map(int, data['roles']):
role = self.guild.get_role(role_id)
if role is not None:
self.roles.append(role)
# sort the roles by hierarchy since they can be "randomised"
self.roles.sort()
self._roles = utils.SnowflakeList(map(int, data['roles']))
def _update(self, data, user=None):
if user:
@ -248,6 +236,24 @@ class Member(discord.abc.Messageable, _BaseUser):
color = colour
@property
def roles(self):
"""A :class:`list` of :class:`Role` that the member belongs to. Note
that the first element of this list is always the default '@everyone'
role.
These roles are sorted by their position in the role hierarchy.
"""
result = []
g = self.guild
for role_id in self._roles:
role = g.get_role(role_id)
if role:
result.append(role)
result.append(g.default_role)
result.sort()
return result
@property
def mention(self):
"""Returns a string that mentions the member."""