<p>Every <strong>valid email</strong> consists of a <strong>local name</strong> and a <strong>domain name</strong>, separated by the <code>&#39;@&#39;</code> sign. Besides lowercase letters, the email may contain one or more <code>&#39;.&#39;</code> or <code>&#39;+&#39;</code>.</p>

<ul>
	<li>For example, in <code>&quot;alice@leetcode.com&quot;</code>, <code>&quot;alice&quot;</code> is the <strong>local name</strong>, and <code>&quot;leetcode.com&quot;</code> is the <strong>domain name</strong>.</li>
</ul>

<p>If you add periods <code>&#39;.&#39;</code> between some characters in the <strong>local name</strong> part of an email address, mail sent there will be forwarded to the same address without dots in the local name. Note that this rule <strong>does not apply</strong> to <strong>domain names</strong>.</p>

<ul>
	<li>For example, <code>&quot;alice.z@leetcode.com&quot;</code> and <code>&quot;alicez@leetcode.com&quot;</code> forward to the same email address.</li>
</ul>

<p>If you add a plus <code>&#39;+&#39;</code> in the <strong>local name</strong>, everything after the first plus sign <strong>will be ignored</strong>. This allows certain emails to be filtered. Note that this rule <strong>does not apply</strong> to <strong>domain names</strong>.</p>

<ul>
	<li>For example, <code>&quot;m.y+name@email.com&quot;</code> will be forwarded to <code>&quot;my@email.com&quot;</code>.</li>
</ul>

<p>It is possible to use both of these rules at the same time.</p>

<p>Given an array of strings <code>emails</code> where we send one email to each <code>emails[i]</code>, return <em>the number of different addresses that actually receive mails</em>.</p>

<p>&nbsp;</p>
<p><strong class="example">Example 1:</strong></p>

<pre>
<strong>Input:</strong> emails = [&quot;test.email+alex@leetcode.com&quot;,&quot;test.e.mail+bob.cathy@leetcode.com&quot;,&quot;testemail+david@lee.tcode.com&quot;]
<strong>Output:</strong> 2
<strong>Explanation:</strong> &quot;testemail@leetcode.com&quot; and &quot;testemail@lee.tcode.com&quot; actually receive mails.
</pre>

<p><strong class="example">Example 2:</strong></p>

<pre>
<strong>Input:</strong> emails = [&quot;a@leetcode.com&quot;,&quot;b@leetcode.com&quot;,&quot;c@leetcode.com&quot;]
<strong>Output:</strong> 3
</pre>

<p>&nbsp;</p>
<p><strong>Constraints:</strong></p>

<ul>
	<li><code>1 &lt;= emails.length &lt;= 100</code></li>
	<li><code>1 &lt;= emails[i].length &lt;= 100</code></li>
	<li><code>emails[i]</code> consist of lowercase English letters, <code>&#39;+&#39;</code>, <code>&#39;.&#39;</code> and <code>&#39;@&#39;</code>.</li>
	<li>Each <code>emails[i]</code> contains exactly one <code>&#39;@&#39;</code> character.</li>
	<li>All local and domain names are non-empty.</li>
	<li>Local names do not start with a <code>&#39;+&#39;</code> character.</li>
	<li>Domain names end with the <code>&quot;.com&quot;</code> suffix.</li>
</ul>

class Solution {
private:
    struct email_addr_hash {
        size_t operator()(const string *e) const {
            const string& s = *e;
            size_t res;
            string::const_reverse_iterator it;

            res = 0;
            for (it = rbegin(s); it != rend(s); ++it) {
                char c = *it;

                if (c == '@')
                    break;
                res ^= c;
            }

            return res;
        }
    };

    struct email_addr_cmp {
        bool operator()(const string *e1, const string *e2) const {
            const string& s1 = *e1;
            const string& s2 = *e2;
            int i, j;
            int n1, n2;

            cout << s1 << " vs. " << s2 << endl;

            n1 = s1.length();
            n2 = s2.length();

            i = j = 0;

            for (;;) {
                if (s1[i] == '.') {
                    for (i = i + 1; s1[i] == '.'; i++)
                        ;
                }
                if (s2[j] == '.') {
                    for (j = j + 1; s2[j] == '.'; j++)
                        ;
                }
                if (s1[i] == '+') {
                    for (i = i + 1; s1[i] != '@'; i++)
                        ;
                }
                if (s2[j] == '+') {
                    for (j = j + 1; s2[j] != '@'; j++)
                        ;
                }
                if (s1[i] == '@') {
                    if (s2[j] != '@')
                        return false;
                    ++i;
                    ++j;
                    break;
                }
                if (s2[j] == '@')
                    return false;
                cout << s1[i] << " vs. " << s2[j] << endl;
                if (s1[i] != s2[j])
                    return false;
                ++i;
                ++j;
            }

            for (;;) {
                cout << s1[i] << " vs. " << s2[j] << endl;
                if (s1[i] != s2[j])
                    return false;
                ++i;
                ++j;
                if (i == n1) {
                    if (j == n2)
                        break;
                    return false;
                }
                if (j == n2)
                    return false;
            }

            return true;
        }
    };

public:
    int numUniqueEmails(vector<string>& emails) {
        unordered_set<string *, email_addr_hash, email_addr_cmp> s;

        for (string& str : emails)
            s.insert(&str);

        for (string *str : s)
            cout << *str << endl;

        return s.size();
    }
};
16500