#include "../include/dchat/OutgoingMessage.hpp" #include namespace dchat { namespace OutgoingMessage { enum class Token { NONE, END_OF_FILE, TEXT, BIND }; struct Tokenizer { Tokenizer(const char *_text, usize _size, const EmojiBindMap *_emojiBindMap) { assert(_text); assert(_emojiBindMap); text = _text; size = _size; index = 0; emoji = nullptr; emojiBindMap = _emojiBindMap; textRange = { 0, 0 }; } // returns -1 if character can't be found in the string usize find(const char *str, usize size, char c) const { for(usize i = 0; i < size; ++i) { if(str[i] == c) return i; } return -1; } // Return nullptr if bind is not found const std::string* getBindEmoji(const char *text, usize size) const { // TODO: unecessary conversion to string, convert emojibindmap to const char* and uses custom hasher auto it = emojiBindMap->find(std::string(text, size)); if(it != emojiBindMap->end()) return &it->second; return nullptr; } Token next() { if(index >= size) return Token::END_OF_FILE; char c = getChar(); usize start = index; ++index; if(c == ':') { while(index < size) { c = getChar(); ++index; if(c == ':') { usize end = index - 1; const std::string *_emoji = getBindEmoji(text + start + 1, end - (start + 1)); if(_emoji) { emoji = _emoji; return Token::BIND; } break; } } textRange.start = start; textRange.end = index; return Token::TEXT; } else { while(index < size) { c = getChar(); if(c == ':') break; ++index; } textRange.start = start; textRange.end = index; return Token::TEXT; } assert(false); return Token::NONE; } char getChar() const { assert(index < size); return text[index]; } const char *text; usize size; usize index; const std::string *emoji; const EmojiBindMap *emojiBindMap; Range textRange; }; } void parseOutgoingMessage(const char *text, usize size, const EmojiBindMap &emojiBindMap, std::function callbackFunc) { OutgoingMessage::Tokenizer tokenizer(text, size, &emojiBindMap); OutgoingMessage::Token token = tokenizer.next(); while(token != OutgoingMessage::Token::END_OF_FILE) { if(token == OutgoingMessage::Token::TEXT) { callbackFunc(OutgoingMessagePart { OutgoingMessagePart::Type::TEXT, tokenizer.textRange }); token = tokenizer.next(); } else if(token == OutgoingMessage::Token::BIND) { callbackFunc(OutgoingMessagePart { OutgoingMessagePart::Type::EMOJI, tokenizer.emoji }); token = tokenizer.next(); } } } }