1313from heapq import merge
1414from bisect import bisect
1515from sys import intern
16+ import re
1617
1718User = str
1819Timestamp = float
1920HashAndSalt = Tuple [bytes , bytes ]
21+ HashTag = str
2022
2123class Post (NamedTuple ):
2224 timestamp : float
@@ -32,16 +34,21 @@ class UserInfo(NamedTuple):
3234
3335posts = deque () # type: Deque[Post] # Posts from newest to oldest
3436user_posts = defaultdict (deque ) # type: DefaultDict[User, Deque[Post]]
37+ hashtag_index = defaultdict (deque ) # type: DefaultDict[HashTag, Deque[Post]]
3538following = defaultdict (set ) # type: DefaultDict[User, Set[User]]
3639followers = defaultdict (set ) # type: DefaultDict[User, Set[User]]
3740user_info = dict () # type: Dict[User, UserInfo]
3841
42+ hashtag_pattern = re .compile (r'#\w+' )
43+
3944def post_message (user : User , text : str , timestamp : Optional [Timestamp ]= None ) -> None :
4045 user = intern (user )
4146 timestamp = timestamp or time ()
4247 post = Post (timestamp , user , text )
4348 posts .appendleft (post )
4449 user_posts [user ].appendleft (post )
50+ for hashtag in hashtag_pattern .findall (text ):
51+ hashtag_index [hashtag ].appendleft (post )
4552
4653def follow (user : User , followed_user : User ) -> None :
4754 user , followed_user = intern (user ), intern (followed_user )
@@ -62,7 +69,8 @@ def get_followed(user: User) -> List[User]:
6269 return sorted (following [user ])
6370
6471def search (phrase :str , limit : Optional [int ] = None ) -> List [Post ]:
65- # XXX this could benefit from caching and from preindexing
72+ if hashtag_pattern .match (phrase ):
73+ return list (islice (hashtag_index [phrase ], limit ))
6674 return list (islice ((post for post in posts if phrase in post .text ), limit ))
6775
6876def hash_password (password : str , salt : Optional [bytes ] = None ) -> HashAndSalt :
0 commit comments