Hi there,

I've basically got the string_token class working now. Thanks to everyone who
helped. It still needs some work as memmove works with bytes so I need the
equivalent of 'sizeof' in D for this.

'squeeze' doesn't work with wide chars, so I will write my own version.

When I shrink or grow char arrays, I'd like to know if I should re-set my
pointers into them accordingly.

If anyone can point out any other obvious issues, bad style etc. that would be
appreciated. Please bear in mind that I'd like the code to be as fast as 
possible.

Here's the source:

Regards,

Ben

module main;

import std.algorithm;
import std.array;
import std.c.string;
import std.string;

import std.stdio;

template regex(CharT)
{
struct basic_string_token
{
        bool _negated = false;
        CharT[] _charset;
        enum size_t MAX_CHARS = CharT.max + 1;
        enum size_t START_CHAR = cast(CharT) 0x80 < 0 ? 0x80 : 0;

        this(const bool negated_, ref CharT[] charset_)
        {
                _negated = negated_;
                _charset = charset_;
        }

        void remove_duplicates()
        {
                _charset.sort;
                _charset = squeeze(_charset.idup).dup;
        }

        void normalise()
        {
                if (_charset.length == MAX_CHARS)
                {
                        _negated = !_negated;
                        _charset.clear();
                }
                else if (_charset.length > MAX_CHARS / 2)
                {
                        negate();
                }
        }

        void negate()
        {
                CharT curr_char_ = START_CHAR;
                CharT[] temp_;
                CharT *ptr_;
                CharT *curr_ = _charset.ptr;
                CharT *end_ = curr_ + _charset.length;
                size_t i_ = 0;

                _negated = !_negated;
                temp_.length = MAX_CHARS - _charset.length;
                ptr_ = temp_.ptr;

                while (curr_ < end_)
                {
                        while (*curr_ > curr_char_)
                        {
                                *ptr_ = curr_char_;
                                ++ptr_;
                                ++curr_char_;
                                ++i_;
                        }

                        ++curr_char_;
                        ++curr_;
                        ++i_;
                }

                for (; i_ < MAX_CHARS; ++i_)
                {
                        *ptr_ = curr_char_;
                        ++ptr_;
                        ++curr_char_;
                }

                _charset = temp_;
        }

        bool empty()
        {
                return _charset.length == 0 && !_negated;
        }

        bool any()
        {
                return _charset.length == 0 && _negated;
        }

        void clear()
        {
                _negated = false;
                _charset.length = 0;
        }

        void intersect(ref basic_string_token rhs_,
                ref basic_string_token overlap_)
        {
                if ((any() && rhs_.any()) || (_negated == rhs_._negated &&
                        !any() && !rhs_.any()))
                {
                        intersect_same_types(rhs_, overlap_);
                }
                else
                {
                        intersect_diff_types(rhs_, overlap_);
                }
        }

private:
        void intersect_same_types(ref basic_string_token rhs_,
                ref basic_string_token overlap_)
        {
                if (any())
                {
                        clear();
                        overlap_._negated = true;
                        rhs_.clear();
                }
                else
                {
                        CharT *iter_ = _charset.ptr;
                        CharT *end_ = iter_ + _charset.length;
                        CharT *rhs_iter_ = rhs_._charset.ptr;
                        CharT *rhs_end_ = rhs_iter_ + rhs_._charset.length;

                        overlap_._negated = _negated;

                        while (iter_ != end_ && rhs_iter_ != rhs_end_)
                        {
                                if (*iter_ < *rhs_iter_)
                                {
                                        ++iter_;
                                }
                                else if (*iter_ > *rhs_iter_)
                                {
                                        ++rhs_iter_;
                                }
                                else
                                {
                                        overlap_._charset ~= *iter_;
                                        memmove(iter_, iter_ + 1, _charset.ptr 
+ _charset.length - iter_);
                                        --end_;
                                        _charset.length -= 1;
                                        memmove(rhs_iter_, rhs_iter_ + 1, 
rhs_._charset.ptr +
                                                rhs_._charset.length - 
rhs_iter_);
                                        --rhs_end_;
                                        rhs_._charset.length -= 1;
                                }
                        }

                        if (_negated)
                        {
                                // duplicates already merged
                                // src, dest
                                merge(_charset, overlap_._charset);
                                // duplicates already merged
                                // src, dest
                                merge(rhs_._charset, overlap_._charset);
                                _negated = false;
                                rhs_._negated = false;
                                swap(_charset, rhs_._charset);
                                normalise();
                                overlap_.normalise();
                                rhs_.normalise();
                        }
                        else if (!overlap_._charset.length == 0)
                        {
                                normalise();
                                overlap_.normalise();
                                rhs_.normalise();
                        }
                }
        }

        void intersect_diff_types(ref basic_string_token rhs_,
                ref basic_string_token overlap_)
        {
                if (any())
                {
                        intersect_any(rhs_, overlap_);
                }
                else if (_negated)
                {
                        intersect_negated(rhs_, overlap_);
                }
                else // _negated == false
                {
                        intersect_charset(rhs_, overlap_);
                }
        }

        void intersect_any(ref basic_string_token rhs_, ref basic_string_token 
overlap_)
        {
                if (rhs_._negated)
                {
                        rhs_.intersect_negated(this, overlap_);
                }
                else // rhs._negated == false
                {
                        rhs_.intersect_charset(this, overlap_);
                }
        }

        void intersect_negated(ref basic_string_token rhs_,
                ref basic_string_token overlap_)
        {
                if (rhs_.any())
                {
                        overlap_._negated = true;
                        overlap_._charset = _charset;
                        rhs_._negated = false;
                        rhs_._charset = _charset;
                        clear();
                }
                else // rhs._negated == false
                {
                        rhs_.intersect_charset(this, overlap_);
                }
        }

        void intersect_charset(ref basic_string_token rhs_,
                ref basic_string_token overlap_)
        {
                if (rhs_.any())
                {
                        overlap_._charset = _charset;
                        rhs_._negated = true;
                        rhs_._charset = _charset;
                        clear();
                }
                else // rhs_._negated == true
                {
                        CharT *iter_ = _charset.ptr;
                        CharT *end_ = iter_ + _charset.length;
                        CharT *rhs_iter_ = rhs_._charset.ptr;
                        CharT *rhs_end_ = rhs_iter_ + rhs_._charset.length;

                        while (iter_ != end_ && rhs_iter_ != rhs_end_)
                        {
                                if (*iter_ < *rhs_iter_)
                                {
                                        overlap_._charset ~= *iter_;
                                        rhs_._charset.length += 1;
                                        rhs_iter_ = rhs_._charset.ptr;
                                        rhs_end_ = rhs_iter_ + 
rhs_._charset.length;
                                        memmove(rhs_iter_ + 1, rhs_iter_, 
rhs_._charset.length -
                                                (rhs_end_ - rhs_iter_ - 1));
                                        ++rhs_iter_;
                                        memmove(iter_, iter_ + 1, _charset.ptr 
+ _charset.length - iter_);
                                        _charset.length -= 1;
                                        --end_;
                                }
                                else if (*iter_ > *rhs_iter_)
                                {
                                        ++rhs_iter_;
                                }
                                else
                                {
                                        ++iter_;
                                        ++rhs_iter_;
                                }
                        }

                        if (iter_ != end_)
                        {
                                CharT[] temp_;

                                temp_.length = end_ - iter_;
                                memmove(temp_.ptr, iter_, temp_.length);

                                // nothing bigger in rhs_ than iter_
                                // src, dest
                                merge(temp_, overlap_._charset);
                                memmove(iter_, iter_ + 1, _charset.ptr + 
_charset.length - iter_);
                                _charset.length -= 1;
                        }

                        if (!overlap_._charset.empty())
                        {
                                merge(overlap_._charset, rhs_._charset);
                                // possible duplicates, so check for any and 
erase.
                                rhs_._charset = squeeze(rhs_._charset.idup).dup;
                                normalise();
                                overlap_.normalise();
                                rhs_.normalise();
                        }
                }
        }

        void merge(ref CharT[] src_, ref CharT[] dest_)
        {
                CharT[] temp_;
                CharT *ptr_;
                CharT *iter_ = src_.ptr;
                CharT *end_ = iter_ + src_.length;
                CharT *dest_iter_ = dest_.ptr;
                CharT *dest_end_ = dest_iter_ + dest_.length;

                temp_.length = src_.length + dest_.length;
                ptr_ = temp_.ptr;

                while (iter_ != end_ && dest_iter_ != dest_end_)
                {
                        if (*iter_ < *dest_iter_)
                        {
                                *ptr_++ = *iter_++;
                        }
                        else
                        {
                                *ptr_++ = *dest_iter_++;
                        }
                }

                while (iter_ != end_)
                {
                        *ptr_++ = *iter_++;
                }

                while (dest_iter_ != dest_end_)
                {
                        *ptr_++ = *dest_iter_++;
                }

                dest_ = temp_;
        }
};
}

int main(char[][]argv)
{
        regex!(char).basic_string_token lhs_;
        regex!(char).basic_string_token rhs_;
        regex!(char).basic_string_token intersect_;

        lhs_._charset = "abc".dup;
        lhs_._negated = true;
        rhs_._charset = "bcd".dup;
        rhs_._negated = true;
        writeln(lhs_._charset, '(', lhs_._negated, ") intersect ",
                rhs_._charset, '(', rhs_._negated, ") =");
        lhs_.intersect(rhs_, intersect_);
        writeln(lhs_._charset, '(', lhs_._negated, "), ",
                rhs_._charset, '(', rhs_._negated, "), ",
                intersect_._charset, '(', intersect_._negated, ')');
        return 0;
}

Reply via email to