<commit_before>/*
 *
 * MIT License
 *
 * Copyright (c) 2016-2017 The Cats Project
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 */

#ifndef CATS_CORECAT_STREAM_HPP
#define CATS_CORECAT_STREAM_HPP

#include <cstdint>
#include <cstdlib>

#include <algorithm>
#include <iostream>
#include <memory>
#include <system_error>
#include <type_traits>

namespace Cats {
namespace Corecat {
namespace Stream {

template <typename T = char>
struct Stream {

    using CharType = T;

    enum class SeekOrigin { Begin, Current, End };

    virtual bool isReadable() const { return false; };
    virtual T read() { T data; return read(&data, 1) ? data : 0; }
    virtual std::size_t read(T* /*data*/, std::size_t /*count*/) { throw std::runtime_error("not implemented"); }
    virtual T peek() { T data; return peek(&data, 1) ? data : 0; }
    virtual std::size_t peek(T* /*data*/, std::size_t /*count*/) { throw std::runtime_error("not implemented"); }

    virtual bool isWriteable() const { return false; };
    virtual void write(T data) { write(&data, 1); }
    virtual void write(const T* /*data*/, std::size_t /*count*/) { throw std::runtime_error("not implemented"); }
    virtual void flush() { throw std::runtime_error("not implemented"); }

    virtual bool isSeekable() const { return false; };
    virtual std::intmax_t seek(std::intmax_t /*offset*/, SeekOrigin /*method*/) { throw std::runtime_error("not implemented"); }
    virtual std::intmax_t getPosition() { throw std::runtime_error("not implemented"); }

};

template <typename T>
class StreamBuffer {

private:

    T* data;
    T* start;
    T* end;
    std::size_t size;

public:

    StreamBuffer(std::size_t size_ = 4096) : data(new T[size_]), start(data), end(data), size(size_) {}

    void read(Stream<T>& stream) {

        std::size_t count = stream.read(end, data + size - end);
        end += count;

    }
    std::size_t read(T* data_, std::size_t count) noexcept {

        count = std::min(count, end - start);
        std::copy(start, start + count, data_);
        start += count;
        if(start == end) start = end = data;
        return count;

    }

    void reset() noexcept {

        start = data;
        end = data;

    }

    std::size_t getAvail() const noexcept { return end - start; }

};

template <typename T>
class BufferedStream : public Stream<T> {

private:

    Stream<T>* stream;
    StreamBuffer<T> readBuffer;
    StreamBuffer<T> writeBuffer;

public:

    BufferedStream(Stream<T>& stream_) : stream(&stream), readBuffer(), writeBuffer() {}

    bool isReadable() const override { return stream->isReadable(); };

    bool isWriteable() const override { return stream->isWriteable(); };

    bool isSeekable() const override { return stream->isSeekable(); };

    Stream<T>& getStream() { return *stream; }
    void setStream(Stream<T>& stream_) { stream = &stream_; }

};

template <typename T, typename = void>
class WrapperStream;
template <>
class WrapperStream<std::FILE*> : public Stream<> {

private:

    std::FILE* file;

public:

    WrapperStream(std::FILE* file_) : file(file_) {}

    bool isReadable() const override { return true; };
    std::size_t read(char* data, std::size_t count) override {

        std::size_t ret = std::fread(data, 1, count, file);
        return ret;

    }

    bool isWriteable() const override { return true; };
    void write(const char* data, std::size_t count) override {

        std::fwrite(data, 1, count, file);

    }
    void flush() override { std::fflush(file); };

    bool isSeekable() const override { return true; };
    std::intmax_t seek(std::intmax_t offset, SeekOrigin origin) override {

        int ori;
        switch(origin) {

        case SeekOrigin::Begin: ori = SEEK_SET; break;
        case SeekOrigin::Current: ori = SEEK_CUR; break;
        case SeekOrigin::End: ori = SEEK_END; break;
        default: throw std::runtime_error("invalid origin");

        }
        std::fseek(file, offset, ori);
        return getPosition();

    }
    std::intmax_t getPosition() override {

        return std::ftell(file);

    }

};
template <typename T>
class WrapperStream<T, typename std::enable_if<std::is_base_of<std::istream, T>::value && !std::is_base_of<std::ostream, T>::value>::type> :
    public Stream<> {

private:

    std::istream* is;

public:

    WrapperStream(std::istream& is_) : is(&is_) {}

    bool isReadable() const override { return true; };
    std::size_t read(char* data, std::size_t count) override { is->read(data, count); return is->gcount(); }

    bool isSeekable() const override { return true; };
    std::intmax_t seek(std::intmax_t offset, SeekOrigin origin) override {

        std::ios_base::seekdir dir;
        switch(origin) {

        case SeekOrigin::Begin: dir = std::ios_base::beg; break;
        case SeekOrigin::Current: dir = std::ios_base::cur; break;
        case SeekOrigin::End: dir = std::ios_base::end; break;
        default: throw std::runtime_error("invalid origin");

        }
        is->seekg(offset, dir);
        return getPosition();

    }
    std::intmax_t getPosition() override { return is->tellg(); }

};
template <typename T>
class WrapperStream<T, typename std::enable_if<std::is_base_of<std::ostream, T>::value && !std::is_base_of<std::istream, T>::value>::type> :
    public Stream<> {

private:

    std::ostream* os;

public:

    WrapperStream(std::ostream& os_) : os(&os_) {}

    bool isWriteable() const override { return true; };
    void write(const char* data, std::size_t count) override { os->write(data, count); }
    void flush() override { os->flush(); };

    bool isSeekable() const override { return true; };
    std::intmax_t seek(std::intmax_t offset, SeekOrigin origin) override {

        std::ios_base::seekdir dir;
        switch(origin) {

        case SeekOrigin::Begin: dir = std::ios_base::beg; break;
        case SeekOrigin::Current: dir = std::ios_base::cur; break;
        case SeekOrigin::End: dir = std::ios_base::end; break;
        default: throw std::runtime_error("invalid origin");

        }
        os->seekp(offset, dir);
        return getPosition();

    }
    std::intmax_t getPosition() override { return os->tellp(); }

};
template <typename T>
class WrapperStream<T, typename std::enable_if<std::is_base_of<std::iostream, T>::value>::type> :
    public Stream<> {

private:

    std::iostream* ios;

public:

    WrapperStream(std::iostream& ios_) : ios(&ios_) {}

    bool isReadable() const override { return true; };
    std::size_t read(char* data, std::size_t count) override { ios->read(data, count); return ios->gcount(); }

    bool isWriteable() const override { return true; };
    void write(const char* data, std::size_t count) override { ios->write(data, count); }
    void flush() override { ios->flush(); };

    bool isSeekable() const override { return true; };
    std::intmax_t seek(std::intmax_t offset, SeekOrigin origin) override {

        std::ios_base::seekdir dir;
        switch(origin) {

        case SeekOrigin::Begin: dir = std::ios_base::beg; break;
        case SeekOrigin::Current: dir = std::ios_base::cur; break;
        case SeekOrigin::End: dir = std::ios_base::end; break;
        default: throw std::runtime_error("invalid origin");

        }
        return ios->rdbuf()->pubseekoff(static_cast<std::iostream::pos_type>(offset), dir);

    }
    std::intmax_t getPosition() override { return ios->tellg(); }

};

template <typename T>
inline WrapperStream<T> createWrapperStream(T& t) { return WrapperStream<T>(t); }

}
}
}

#endif
<commit_msg>remove StreamBuffer<commit_after>/*
 *
 * MIT License
 *
 * Copyright (c) 2016-2017 The Cats Project
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 */

#ifndef CATS_CORECAT_STREAM_HPP
#define CATS_CORECAT_STREAM_HPP

#include <cstdint>
#include <cstdlib>

#include <algorithm>
#include <iostream>
#include <memory>
#include <system_error>
#include <type_traits>

namespace Cats {
namespace Corecat {
namespace Stream {

template <typename T = char>
struct Stream {

    using CharType = T;

    enum class SeekOrigin { Begin, Current, End };

    virtual bool isReadable() const { return false; };
    virtual T read() { T data; return read(&data, 1) ? data : 0; }
    virtual std::size_t read(T* /*data*/, std::size_t /*count*/) { throw std::runtime_error("not implemented"); }
    virtual T peek() { T data; return peek(&data, 1) ? data : 0; }
    virtual std::size_t peek(T* /*data*/, std::size_t /*count*/) { throw std::runtime_error("not implemented"); }

    virtual bool isWriteable() const { return false; };
    virtual void write(T data) { write(&data, 1); }
    virtual void write(const T* /*data*/, std::size_t /*count*/) { throw std::runtime_error("not implemented"); }
    virtual void flush() { throw std::runtime_error("not implemented"); }

    virtual bool isSeekable() const { return false; };
    virtual std::intmax_t seek(std::intmax_t /*offset*/, SeekOrigin /*method*/) { throw std::runtime_error("not implemented"); }
    virtual std::intmax_t getPosition() { throw std::runtime_error("not implemented"); }

};

template <typename T>
class BufferedStream : public Stream<T> {

private:

    Stream<T>* stream;

    std::size_t bufferSize;

    T* readBufferData;
    T* readBufferStart;
    T* readBufferEnd;

    T* writeBufferData;
    T* writeBufferEnd;

private:

    std::size_t readToBuffer() {

        std::size_t res = stream->read(readBufferEnd, readBufferData + bufferSize - readBufferEnd);
        return res;

    }
    std::size_t readFromBuffer(T* data, std::size_t count) noexcept {

        std::copy(readBufferStart, readBufferStart + count, data);
        readBufferStart += count;
        if(readBufferStart == readBufferEnd) readBufferStart = readBufferEnd = readBufferData;
        return count;

    }

public:

    BufferedStream(Stream<T>& stream_, std::size_t bufferSize_ = 4096) :
        stream(&stream_), bufferSize(bufferSize_),
        readBufferData(), readBufferStart(), readBufferEnd(),
        writeBufferData(), writeBufferEnd() {}
    ~BufferedStream() {

        if(readBufferData) { delete[] readBufferData; readBufferData = nullptr; }
        if(writeBufferData) { delete[] writeBufferData; writeBufferData = nullptr; }

    }

    bool isReadable() const override { return stream->isReadable(); };
    std::size_t read(char* data, std::size_t count) override {

        if(!readBufferData) {

            readBufferData = new T[bufferSize];
            readBufferStart = readBufferEnd = readBufferData;

        }

    }

    bool isWriteable() const override { return stream->isWriteable(); };

    bool isSeekable() const override { return stream->isSeekable(); };

    Stream<T>& getStream() { return *stream; }
    void setStream(Stream<T>& stream_) { stream = &stream_; }

};

template <typename T, typename = void>
class WrapperStream;
template <>
class WrapperStream<std::FILE*> : public Stream<> {

private:

    std::FILE* file;

public:

    WrapperStream(std::FILE* file_) : file(file_) {}

    bool isReadable() const override { return true; };
    std::size_t read(char* data, std::size_t count) override {

        std::size_t ret = std::fread(data, 1, count, file);
        return ret;

    }

    bool isWriteable() const override { return true; };
    void write(const char* data, std::size_t count) override {

        std::fwrite(data, 1, count, file);

    }
    void flush() override { std::fflush(file); };

    bool isSeekable() const override { return true; };
    std::intmax_t seek(std::intmax_t offset, SeekOrigin origin) override {

        int ori;
        switch(origin) {

        case SeekOrigin::Begin: ori = SEEK_SET; break;
        case SeekOrigin::Current: ori = SEEK_CUR; break;
        case SeekOrigin::End: ori = SEEK_END; break;
        default: throw std::runtime_error("invalid origin");

        }
        std::fseek(file, offset, ori);
        return getPosition();

    }
    std::intmax_t getPosition() override {

        return std::ftell(file);

    }

};
template <typename T>
class WrapperStream<T, typename std::enable_if<std::is_base_of<std::istream, T>::value && !std::is_base_of<std::ostream, T>::value>::type> :
    public Stream<> {

private:

    std::istream* is;

public:

    WrapperStream(std::istream& is_) : is(&is_) {}

    bool isReadable() const override { return true; };
    std::size_t read(char* data, std::size_t count) override { is->read(data, count); return is->gcount(); }

    bool isSeekable() const override { return true; };
    std::intmax_t seek(std::intmax_t offset, SeekOrigin origin) override {

        std::ios_base::seekdir dir;
        switch(origin) {

        case SeekOrigin::Begin: dir = std::ios_base::beg; break;
        case SeekOrigin::Current: dir = std::ios_base::cur; break;
        case SeekOrigin::End: dir = std::ios_base::end; break;
        default: throw std::runtime_error("invalid origin");

        }
        is->seekg(offset, dir);
        return getPosition();

    }
    std::intmax_t getPosition() override { return is->tellg(); }

};
template <typename T>
class WrapperStream<T, typename std::enable_if<std::is_base_of<std::ostream, T>::value && !std::is_base_of<std::istream, T>::value>::type> :
    public Stream<> {

private:

    std::ostream* os;

public:

    WrapperStream(std::ostream& os_) : os(&os_) {}

    bool isWriteable() const override { return true; };
    void write(const char* data, std::size_t count) override { os->write(data, count); }
    void flush() override { os->flush(); };

    bool isSeekable() const override { return true; };
    std::intmax_t seek(std::intmax_t offset, SeekOrigin origin) override {

        std::ios_base::seekdir dir;
        switch(origin) {

        case SeekOrigin::Begin: dir = std::ios_base::beg; break;
        case SeekOrigin::Current: dir = std::ios_base::cur; break;
        case SeekOrigin::End: dir = std::ios_base::end; break;
        default: throw std::runtime_error("invalid origin");

        }
        os->seekp(offset, dir);
        return getPosition();

    }
    std::intmax_t getPosition() override { return os->tellp(); }

};
template <typename T>
class WrapperStream<T, typename std::enable_if<std::is_base_of<std::iostream, T>::value>::type> :
    public Stream<> {

private:

    std::iostream* ios;

public:

    WrapperStream(std::iostream& ios_) : ios(&ios_) {}

    bool isReadable() const override { return true; };
    std::size_t read(char* data, std::size_t count) override { ios->read(data, count); return ios->gcount(); }

    bool isWriteable() const override { return true; };
    void write(const char* data, std::size_t count) override { ios->write(data, count); }
    void flush() override { ios->flush(); };

    bool isSeekable() const override { return true; };
    std::intmax_t seek(std::intmax_t offset, SeekOrigin origin) override {

        std::ios_base::seekdir dir;
        switch(origin) {

        case SeekOrigin::Begin: dir = std::ios_base::beg; break;
        case SeekOrigin::Current: dir = std::ios_base::cur; break;
        case SeekOrigin::End: dir = std::ios_base::end; break;
        default: throw std::runtime_error("invalid origin");

        }
        return ios->rdbuf()->pubseekoff(static_cast<std::iostream::pos_type>(offset), dir);

    }
    std::intmax_t getPosition() override { return ios->tellg(); }

};

template <typename T>
inline WrapperStream<T> createWrapperStream(T& t) { return WrapperStream<T>(t); }

}
}
}

#endif
<|endoftext|>


<commit_before>/*
 *
 * MIT License
 *
 * Copyright (c) 2016-2017 The Cats Project
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 */

#ifndef CATS_CORECAT_STRING_HPP
#define CATS_CORECAT_STRING_HPP

#include <cstdlib>

#include <algorithm>
#include <iostream>
#include <iterator>
#include <string>
#include <type_traits>

#include "Charset.hpp"

namespace Cats {
namespace Corecat {

template <typename C>
class StringViewBase;

template <typename C>
class StringBase {

public:

    static constexpr std::size_t BUFFER_SIZE = 32;

    using CharType = typename C::CharType;
    using CharsetType = C;

    using Iterator = CharType*;
    using ConstIterator = const CharType*;
    using ReverseIterator = std::reverse_iterator<Iterator>;
    using ConstReverseIterator = std::reverse_iterator<ConstIterator>;

    using View = StringViewBase<C>;

private:

    union {

        struct {

            CharType* data;
            std::size_t length;
            std::size_t capacity;

        };
        struct {

            CharType data[BUFFER_SIZE - 1];
            CharType length;

        } buffer;

    } storage;

private:

    bool isSmall() const noexcept { return static_cast<std::size_t>(storage.buffer.length) < BUFFER_SIZE; }

public:

    StringBase(const StringBase& src) : StringBase() { append(src); }
    StringBase(StringBase&& src) noexcept : StringBase() { swap(src); }
    ~StringBase() noexcept { if(!isSmall()) delete[] storage.data; }

    StringBase() noexcept { storage.buffer.data[0] = 0; storage.buffer.length = BUFFER_SIZE - 1; }
    StringBase(CharType ch, std::size_t count = 1) : StringBase() { append(ch, count); }
    StringBase(const CharType* data_) : StringBase() { append(data_); }
    StringBase(const CharType* data_, std::size_t length_) : StringBase() { append(data_, length_); }
    StringBase(const View& sv) : StringBase() { append(sv); }

    StringBase& operator =(const StringBase& src) { clear(); append(src); return *this; }
    StringBase& operator =(StringBase&& src) noexcept { swap(src); return *this; }

    StringBase& operator =(const CharType* data_) { clear(); append(data_); return *this; }
    StringBase& operator =(const View& sv) { clear(); append(sv); return *this; }

    StringBase& operator +=(CharType ch) { append(ch); return *this; }
    StringBase& operator +=(const CharType* data_) { append(data_); return *this; }
    StringBase& operator +=(const StringBase& str) { append(str); return *this; }
    StringBase& operator +=(const View& sv) { append(sv); return *this; }

    friend StringBase operator +(const StringBase& a, CharType b) { StringBase t(a); t += b; return t; }
    friend StringBase operator +(const StringBase& a, const CharType* b) { StringBase t(a); t += b; return t; }
    friend StringBase operator +(const StringBase& a, const StringBase& b) { StringBase t(a); t += b; return t; }
    friend StringBase operator +(const StringBase& a, const View& b) { StringBase t(a); t += b; return t; }
    friend StringBase operator +(CharType a, const StringBase& b) { StringBase t(a); t += b; return t; }
    friend StringBase operator +(const CharType* a, const StringBase& b) { StringBase t(a); t += b; return t; }
    friend StringBase operator +(const View& a, const StringBase& b) { StringBase t(a); t += b; return t; }

    CharType& operator [](std::size_t index) noexcept { return getData()[index]; };
    const CharType& operator [](std::size_t index) const noexcept { return getData()[index]; };

    operator View() const noexcept { return { getData(), getLength() }; }

    friend std::basic_ostream<CharType>& operator <<(std::basic_ostream<CharType>& stream, const StringBase<C>& str) {

        stream.write(str.getData(), str.getLength());
        return stream;

    }

    CharType* getData() noexcept { return isSmall() ? storage.buffer.data : storage.data; }
    const CharType* getData() const noexcept { return const_cast<StringBase*>(this)->getData(); }
    std::size_t getLength() const noexcept { return isSmall() ? BUFFER_SIZE - storage.buffer.length - 1 : storage.length; }
    std::size_t getCapacity() const noexcept { return isSmall() ? BUFFER_SIZE - 1 : storage.capacity; }

    bool isEmpty() const noexcept { return getLength() == 0; }

    void clear() noexcept {

        if(isSmall()) { storage.buffer.data[0] = 0; storage.buffer.length = BUFFER_SIZE - 1; }
        else { storage.data[0] = 0; storage.length = 0; }

    }

    void reserve(std::size_t cap) {

        if(cap > getCapacity()) {

            auto length = getLength();
            auto oldData = getData();
            auto newData = new CharType[cap + 1];
            std::copy(oldData, oldData + length + 1, newData);
            storage.data = newData;
            storage.capacity = cap;
            if(isSmall()) storage.buffer.length = BUFFER_SIZE;
            else delete[] oldData;

        }

    }

    StringBase& append(CharType ch, std::size_t count = 1) {

        auto length = getLength();
        reserve(length + count);
        auto data = getData();
        std::fill(data + length, data + length + count, ch);
        length += count;
        data[length] = 0;
        if(isSmall()) storage.buffer.length = BUFFER_SIZE - length - 1;
        else storage.length = length;
        return *this;

    }
    StringBase& append(const CharType* data_, std::size_t length_) {

        auto length = getLength();
        reserve(length + length_);
        auto data = getData();
        *std::copy(data_, data_ + length_, data + length) = 0;
        length += length_;
        if(isSmall()) storage.buffer.length = BUFFER_SIZE - length - 1;
        else storage.length = length;
        return *this;

    }
    StringBase& append(const CharType* data_) { return append(data_, std::char_traits<CharType>::length(data_)); }
    StringBase& append(const StringBase& str) { return append(str.getData(), str.getLength()); }
    StringBase& append(const View& sv) { return append(sv.getData(), sv.getLength()); }

    void swap(StringBase& src) noexcept { std::swap(storage, src.storage); }

    Iterator begin() noexcept { return getData(); }
    ConstIterator begin() const noexcept { return getData(); }
    ConstIterator cbegin() const noexcept { return getData(); }

    Iterator end() noexcept { return getData() + getLength(); }
    ConstIterator end() const noexcept { return getData() + getLength(); }
    ConstIterator cend() const noexcept { return getData() + getLength(); }

    ReverseIterator rbegin() noexcept { return ReverseIterator(end()); }
    ConstReverseIterator rbegin() const noexcept { return ConstReverseIterator(end()); }
    ConstReverseIterator crbegin() const noexcept { return ConstReverseIterator(cend()); }

    ReverseIterator rend() noexcept { return ReverseIterator(begin()); }
    ConstReverseIterator rend() const noexcept { return ConstReverseIterator(begin()); }
    ConstReverseIterator crend() const noexcept { return ConstReverseIterator(cbegin()); }

};

using String = StringBase<Charset::UTF8<>>;
using String16 = StringBase<Charset::UTF16<>>;
using String32 = StringBase<Charset::UTF32<>>;

template <typename C>
class StringViewBase {

public:

    using CharType = typename C::CharType;
    using CharsetType = C;

    using Iterator = const CharType*;
    using ReverseIterator = std::reverse_iterator<Iterator>;

private:

    const CharType* data;
    std::size_t length;

public:

    StringViewBase(const StringViewBase& src) = default;
    ~StringViewBase() = default;

    StringViewBase() : data(""), length() {}
    StringViewBase(const CharType* data_) : data(data_), length(std::char_traits<CharType>::length(data_)) {}
    StringViewBase(const CharType* data_, std::size_t length_) : data(data_), length(length_) {}

    StringViewBase& operator =(const StringViewBase& src) = default;

    const CharType& operator [](std::size_t index) const noexcept { return data[index]; }

    bool operator ==(StringViewBase sv) const noexcept {

        if(length != sv.length) return false;
        const CharType* p = data;
        const CharType* q = sv.data;
        for(const CharType* end = data + length; p != end; ++p, ++q) if(*p != *q) return false;
        return true;

    }
    bool operator !=(StringViewBase sv) const noexcept { return !(*this == sv); }

    friend std::basic_ostream<CharType>& operator <<(std::basic_ostream<CharType>& stream, const StringViewBase& sv) {

        stream.write(sv.getData(), sv.getLength());
        return stream;

    }

    const CharType* getData() const noexcept { return data; }
    void setData(const CharType* data_) noexcept { data = data_; }
    std::size_t getLength() const noexcept { return length; }
    void setLength(std::size_t length_) noexcept { length = length_; }

    Iterator begin() const noexcept { return getData(); }

    Iterator end() const noexcept { return getData() + getLength(); }

    ReverseIterator rbegin() const noexcept { return ReverseIterator(end()); }

    ReverseIterator rend() const noexcept { return ReverseIterator(begin()); }

};

using StringView = StringViewBase<Charset::UTF8<>>;
using StringView16 = StringViewBase<Charset::UTF16<>>;
using StringView32 = StringViewBase<Charset::UTF32<>>;

}
}

#endif
<commit_msg>Update String<commit_after>/*
 *
 * MIT License
 *
 * Copyright (c) 2016-2017 The Cats Project
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 */

#ifndef CATS_CORECAT_STRING_HPP
#define CATS_CORECAT_STRING_HPP

#include <cstdlib>

#include <algorithm>
#include <iostream>
#include <iterator>
#include <string>
#include <type_traits>

#include "Charset.hpp"

namespace Cats {
namespace Corecat {

template <typename C>
class StringViewBase;

template <typename C>
class StringBase {

public:

    static constexpr std::size_t BUFFER_SIZE = 32;

    using CharType = typename C::CharType;
    using CharsetType = C;

    using Iterator = CharType*;
    using ConstIterator = const CharType*;
    using ReverseIterator = std::reverse_iterator<Iterator>;
    using ConstReverseIterator = std::reverse_iterator<ConstIterator>;

    using View = StringViewBase<C>;

private:

    union {

        struct {

            CharType* data;
            std::size_t length;
            std::size_t capacity;

        };
        struct {

            CharType data[BUFFER_SIZE - 1];
            CharType length;

        } buffer;

    } storage;

private:

    bool isSmall() const noexcept { return static_cast<std::size_t>(storage.buffer.length) < BUFFER_SIZE; }

public:

    StringBase(const StringBase& src) : StringBase() { append(src); }
    StringBase(StringBase&& src) noexcept : StringBase() { swap(src); }
    ~StringBase() noexcept { if(!isSmall()) delete[] storage.data; }

    StringBase() noexcept { storage.buffer.data[0] = 0; storage.buffer.length = BUFFER_SIZE - 1; }
    StringBase(CharType ch, std::size_t count = 1) : StringBase() { append(ch, count); }
    StringBase(const CharType* data_) : StringBase() { append(data_); }
    StringBase(const CharType* data_, std::size_t length_) : StringBase() { append(data_, length_); }
    StringBase(const View& sv) : StringBase() { append(sv); }

    StringBase& operator =(const StringBase& src) { clear(); append(src); return *this; }
    StringBase& operator =(StringBase&& src) noexcept { swap(src); return *this; }

    StringBase& operator =(const CharType* data_) { clear(); append(data_); return *this; }
    StringBase& operator =(const View& sv) { clear(); append(sv); return *this; }

    StringBase& operator +=(CharType ch) { append(ch); return *this; }
    StringBase& operator +=(const CharType* data_) { append(data_); return *this; }
    StringBase& operator +=(const StringBase& str) { append(str); return *this; }
    StringBase& operator +=(const View& sv) { append(sv); return *this; }

    friend StringBase operator +(const StringBase& a, CharType b) { StringBase t(a); t += b; return t; }
    friend StringBase operator +(const StringBase& a, const CharType* b) { StringBase t(a); t += b; return t; }
    friend StringBase operator +(const StringBase& a, const StringBase& b) { StringBase t(a); t += b; return t; }
    friend StringBase operator +(const StringBase& a, const View& b) { StringBase t(a); t += b; return t; }
    friend StringBase operator +(CharType a, const StringBase& b) { StringBase t(a); t += b; return t; }
    friend StringBase operator +(const CharType* a, const StringBase& b) { StringBase t(a); t += b; return t; }
    friend StringBase operator +(const View& a, const StringBase& b) { StringBase t(a); t += b; return t; }

    CharType& operator [](std::size_t index) noexcept { return getData()[index]; };
    const CharType& operator [](std::size_t index) const noexcept { return getData()[index]; };

    operator View() const noexcept { return getView(); }

    friend std::basic_ostream<CharType>& operator <<(std::basic_ostream<CharType>& stream, const StringBase<C>& str) {

        stream.write(str.getData(), str.getLength());
        return stream;

    }

    CharType* getData() noexcept { return isSmall() ? storage.buffer.data : storage.data; }
    const CharType* getData() const noexcept { return const_cast<StringBase*>(this)->getData(); }
    std::size_t getLength() const noexcept { return isSmall() ? BUFFER_SIZE - storage.buffer.length - 1 : storage.length; }
    std::size_t getCapacity() const noexcept { return isSmall() ? BUFFER_SIZE - 1 : storage.capacity; }

    View getView() const noexcept { return View(getData(), getLength()); }

    bool isEmpty() const noexcept { return getLength() == 0; }

    void clear() noexcept {

        if(isSmall()) { storage.buffer.data[0] = 0; storage.buffer.length = BUFFER_SIZE - 1; }
        else { storage.data[0] = 0; storage.length = 0; }

    }

    void reserve(std::size_t cap) {

        if(cap > getCapacity()) {

            auto length = getLength();
            auto oldData = getData();
            auto newData = new CharType[cap + 1];
            std::copy(oldData, oldData + length + 1, newData);
            storage.data = newData;
            storage.length = length;
            storage.capacity = cap;
            if(isSmall()) storage.buffer.length = BUFFER_SIZE;
            else delete[] oldData;

        }

    }

    StringBase& append(CharType ch, std::size_t count = 1) {

        auto length = getLength();
        reserve(length + count);
        auto data = getData();
        std::fill(data + length, data + length + count, ch);
        length += count;
        data[length] = 0;
        if(isSmall()) storage.buffer.length = BUFFER_SIZE - length - 1;
        else storage.length = length;
        return *this;

    }
    StringBase& append(const CharType* data_, std::size_t length_) {

        auto length = getLength();
        reserve(length + length_);
        auto data = getData();
        *std::copy(data_, data_ + length_, data + length) = 0;
        length += length_;
        if(isSmall()) storage.buffer.length = BUFFER_SIZE - length - 1;
        else storage.length = length;
        return *this;

    }
    StringBase& append(const CharType* data_) { return append(data_, std::char_traits<CharType>::length(data_)); }
    StringBase& append(const StringBase& str) { return append(str.getData(), str.getLength()); }
    StringBase& append(const View& sv) { return append(sv.getData(), sv.getLength()); }

    void swap(StringBase& src) noexcept { std::swap(storage, src.storage); }

    StringBase repeat(std::size_t count) const { return getView().repeat(count); }

    View substr(std::size_t pos) const noexcept { return getView().substr(pos); }
    View substr(std::size_t pos, std::size_t count) const noexcept { return getView().substr(pos, count); }

    Iterator begin() noexcept { return getData(); }
    ConstIterator begin() const noexcept { return getData(); }
    ConstIterator cbegin() const noexcept { return getData(); }

    Iterator end() noexcept { return getData() + getLength(); }
    ConstIterator end() const noexcept { return getData() + getLength(); }
    ConstIterator cend() const noexcept { return getData() + getLength(); }

    ReverseIterator rbegin() noexcept { return ReverseIterator(end()); }
    ConstReverseIterator rbegin() const noexcept { return ConstReverseIterator(end()); }
    ConstReverseIterator crbegin() const noexcept { return ConstReverseIterator(cend()); }

    ReverseIterator rend() noexcept { return ReverseIterator(begin()); }
    ConstReverseIterator rend() const noexcept { return ConstReverseIterator(begin()); }
    ConstReverseIterator crend() const noexcept { return ConstReverseIterator(cbegin()); }

};

using String = StringBase<Charset::UTF8<>>;
using String16 = StringBase<Charset::UTF16<>>;
using String32 = StringBase<Charset::UTF32<>>;

template <typename C>
class StringViewBase {

public:

    using CharType = typename C::CharType;
    using CharsetType = C;

    using Iterator = const CharType*;
    using ReverseIterator = std::reverse_iterator<Iterator>;

    using String = StringBase<C>;

private:

    const CharType* data;
    std::size_t length;

public:

    StringViewBase(const StringViewBase& src) = default;
    ~StringViewBase() = default;

    StringViewBase() : data(""), length() {}
    StringViewBase(const CharType* data_) : data(data_), length(std::char_traits<CharType>::length(data_)) {}
    StringViewBase(const CharType* data_, std::size_t length_) : data(data_), length(length_) {}

    StringViewBase& operator =(const StringViewBase& src) = default;

    const CharType& operator [](std::size_t index) const noexcept { return data[index]; }

    bool operator ==(StringViewBase sv) const noexcept {

        if(length != sv.length) return false;
        const CharType* p = data;
        const CharType* q = sv.data;
        for(const CharType* end = data + length; p != end; ++p, ++q) if(*p != *q) return false;
        return true;

    }
    bool operator !=(StringViewBase sv) const noexcept { return !(*this == sv); }

    friend std::basic_ostream<CharType>& operator <<(std::basic_ostream<CharType>& stream, const StringViewBase& sv) {

        stream.write(sv.getData(), sv.getLength());
        return stream;

    }

    const CharType* getData() const noexcept { return data; }
    void setData(const CharType* data_) noexcept { data = data_; }
    std::size_t getLength() const noexcept { return length; }
    void setLength(std::size_t length_) noexcept { length = length_; }

    String repeat(std::size_t count) const {

        String t;
        t.reserve(getLength() * count);
        for(std::size_t i = 0; i < count; ++i) { t += *this; }
        return t;

    }

    StringViewBase substr(std::size_t pos) const noexcept {

        if(pos <= length) return {data + pos, length - pos};
        else return {};

    }
    StringViewBase substr(std::size_t pos, std::size_t count) const noexcept {

        if(pos <= length) return {data + pos, std::min(count, length - pos)};
        else return {};

    }

    Iterator begin() const noexcept { return getData(); }

    Iterator end() const noexcept { return getData() + getLength(); }

    ReverseIterator rbegin() const noexcept { return ReverseIterator(end()); }

    ReverseIterator rend() const noexcept { return ReverseIterator(begin()); }

};

using StringView = StringViewBase<Charset::UTF8<>>;
using StringView16 = StringViewBase<Charset::UTF16<>>;
using StringView32 = StringViewBase<Charset::UTF32<>>;

}
}

#endif
<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2010, Image Engine Design Inc. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions are
//  met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
//     * Neither the name of Image Engine Design nor the names of any
//	     other contributors to this software may be used to endorse or
//       promote products derived from this software without specific prior
//       written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#ifndef IECORE_COMPOUNDDATA_INL
#define IECORE_COMPOUNDDATA_INL

#include "boost/format.hpp"

#include "IECore/Exception.h"

namespace IECore
{

template<typename T>
T *CompoundData::member( const InternedString &name, bool throwExceptions )
{
	return member<T>( name, throwExceptions, false );
}

template<typename T>
const T *CompoundData::member( const InternedString &name, bool throwExceptions ) const
{
	CompoundDataMap::const_iterator it = readable().find( name );
	if( it!=readable().end() )
	{
		const T *result = runTimeCast<const T>( it->second.get() );
		if( result )
		{
			return result;
		}
		else
		{
			if( throwExceptions )
			{
				throw Exception( boost::str( boost::format( "CompoundData child \"%s\" is not of type \"%s\"." ) % T::staticTypeName() ) );
			}
			else
			{
				return 0;
			}
		}
	}
	else
	{
		if( throwExceptions )
		{
			throw Exception( boost::str( boost::format( "CompoundData has no child named \"%s\"." ) % name.value() ) );
		}
		else
		{
			return 0;
		}
	}
	return 0; // shouldn't get here anyway
}

template<typename T>
T *CompoundData::member( const InternedString &name, bool throwExceptions, bool createIfMissing )
{
	CompoundDataMap::const_iterator it = readable().find( name );
	if( it!=readable().end() )
	{
		T *result = runTimeCast<T>( it->second.get() );
		if( result )
		{
			return result;
		}
		else
		{
			if( throwExceptions )
			{
				throw Exception( boost::str( boost::format( "CompoundData child \"%s\" is not of type \"%s\"." ) % T::staticTypeName() ) );
			}
			else
			{
				return 0;
			}
		}
	}
	else
	{
		if( createIfMissing )
		{
			typename T::Ptr member = staticPointerCast<T>( Object::create( T::staticTypeId() ) );
			writable()[name] = member;
			return member;
		}
		else if( throwExceptions )
		{
			throw Exception( boost::str( boost::format( "CompoundData has no child named \"%s\"." ) % name.value() ) );
		}
		else
		{
			return 0;
		}
	}
	return 0; // shouldn't get here anyway
}

}; // namespace IECore

#endif // IECORE_COMPOUNDDATA_INL
<commit_msg>Fixing bug which caused wrong exception to be thrown.<commit_after>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2010, Image Engine Design Inc. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions are
//  met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
//     * Neither the name of Image Engine Design nor the names of any
//	     other contributors to this software may be used to endorse or
//       promote products derived from this software without specific prior
//       written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#ifndef IECORE_COMPOUNDDATA_INL
#define IECORE_COMPOUNDDATA_INL

#include "boost/format.hpp"

#include "IECore/Exception.h"

namespace IECore
{

template<typename T>
T *CompoundData::member( const InternedString &name, bool throwExceptions )
{
	return member<T>( name, throwExceptions, false );
}

template<typename T>
const T *CompoundData::member( const InternedString &name, bool throwExceptions ) const
{
	CompoundDataMap::const_iterator it = readable().find( name );
	if( it!=readable().end() )
	{
		const T *result = runTimeCast<const T>( it->second.get() );
		if( result )
		{
			return result;
		}
		else
		{
			if( throwExceptions )
			{
				throw Exception( boost::str( boost::format( "CompoundData child \"%s\" is not of type \"%s\"." ) % name.value() % T::staticTypeName() ) );
			}
			else
			{
				return 0;
			}
		}
	}
	else
	{
		if( throwExceptions )
		{
			throw Exception( boost::str( boost::format( "CompoundData has no child named \"%s\"." ) % name.value() ) );
		}
		else
		{
			return 0;
		}
	}
	return 0; // shouldn't get here anyway
}

template<typename T>
T *CompoundData::member( const InternedString &name, bool throwExceptions, bool createIfMissing )
{
	CompoundDataMap::const_iterator it = readable().find( name );
	if( it!=readable().end() )
	{
		T *result = runTimeCast<T>( it->second.get() );
		if( result )
		{
			return result;
		}
		else
		{
			if( throwExceptions )
			{
				throw Exception( boost::str( boost::format( "CompoundData child \"%s\" is not of type \"%s\"." ) % T::staticTypeName() ) );
			}
			else
			{
				return 0;
			}
		}
	}
	else
	{
		if( createIfMissing )
		{
			typename T::Ptr member = staticPointerCast<T>( Object::create( T::staticTypeId() ) );
			writable()[name] = member;
			return member;
		}
		else if( throwExceptions )
		{
			throw Exception( boost::str( boost::format( "CompoundData has no child named \"%s\"." ) % name.value() ) );
		}
		else
		{
			return 0;
		}
	}
	return 0; // shouldn't get here anyway
}

}; // namespace IECore

#endif // IECORE_COMPOUNDDATA_INL
<|endoftext|>


<commit_before>extern "C" {
#include "q.h"
}

#include <gtest/gtest.h>
#include <deque>
#include <functional>
#include <algorithm>
#include <random>
#include <chrono>
#include <limits>
#include <iterator>

class Model : public ::testing::Test
{
    protected:
        virtual void SetUp()
        {
            seed = std::chrono::system_clock::now().time_since_epoch().count();
            rng.seed(seed);
        }

        virtual void TearDown()
        {
        }

        std::mt19937 rng;
        size_t seed;
};

template <typename RNG, typename D>
bool run_isolated_test(int ninserts, int npops, int nreinserts, D dist, RNG entropy)
{
    Q q;
    InitQ(&q);
    std::deque<int> model;
    auto result(true);

    for(auto n = 0; n < ninserts; ++n)
    {
        auto d = dist(entropy);
        model.push_back(d);
        AddQ(&q, &d);
    }
    for(auto n = 0; n < npops; ++n)
    {
        model.pop_front();
        DelQ(&q);
    }
    for(auto n = 0; n < nreinserts; ++n)
    {
        auto d = dist(entropy);
        model.push_back(d);
        AddQ(&q, &d);
    }

    for(auto r : model)
    {
        auto u = *DelQ(&q);
        //std::cout << "Actual: " << r << " Expected: " << u <<'\n';

        if(r != u)
        {
            result = false;
        }
    }
    FreeQ(&q);
    return result;
}
bool run_isolated_test(int ninserts, int npops, int nreinserts)
{
    std::mt19937 rng(0);
    std::uniform_int_distribution<int> input_data(std::numeric_limits<int>::min(), std::numeric_limits<int>::max());
    return run_isolated_test(ninserts, npops, nreinserts, input_data, rng);
}

TEST_F(Model, TheIDontHaveAllFuckingDaySoMakeTheComputerDoMyHomeworkTest)
{
    std::uniform_int_distribution<int> ntests(0, 1000);
    std::uniform_int_distribution<int> input_data(std::numeric_limits<int>::min(), std::numeric_limits<int>::max());

    //Generate a random number of inserts
    auto ninserts = ntests(rng);

    //Generate a random number of reads/pops
    auto npops = ntests(rng);

    //Generate a random number of more inserts to verify circular
    //dynamic functionality.  Verify we can write, read, write and read
    //again in any amount.
    auto nreinserts = ntests(rng);

     std::cout << "Test:\n"
    << "\tSeed: " << seed << '\n'
    << "\tInserts: " << ninserts << '\n'
    << "\tDeletes: " << npops << '\n'
    << "\tReinserts: " << nreinserts << '\n';
    //Verify from the model
    if(!run_isolated_test(ninserts, npops, nreinserts, input_data, rng))
    {
        std::cout << "Test Failed, minimizing.\n";
        while(ninserts > 0 && run_isolated_test(ninserts, npops, nreinserts, input_data, rng) == false)
        {
            --ninserts;
        }
        ++ninserts; //Make it fail again.
        while(npops > 0 && run_isolated_test(ninserts, npops, nreinserts, input_data, rng) == false)
        {
            --npops;
        }
        ++npops; //Make it fail again.
        while(nreinserts > 0 && run_isolated_test(ninserts, npops, nreinserts, input_data, rng) == false)
        {
            --nreinserts;
        }
        ++nreinserts; //Make it fail again.

        ADD_FAILURE();
        std::cout << "Test:\n"
            << "\tInserts: " << ninserts << '\n'
            << "\tDeletes: " << npops << '\n'
            << "\tReinserts: " << nreinserts << '\n';
    }
}

class Directed : public ::testing::Test
{
    protected:
        virtual void SetUp()
        {
            InitQ(&q);
        }

        virtual void TearDown()
        {
            FreeQ(&q);
        }

        Q q;
};

TEST_F(Directed, RandomMinimizedTest)
{
    ASSERT_TRUE(run_isolated_test(1, 0, 9)); //Random test generator found this test case
}
TEST_F(Directed, Weirdness)
{
    ASSERT_TRUE(run_isolated_test(10240, 0, 0)); //10 straight inserts don't fail, but 1 and 9 do.
}
TEST_F(Directed, RandomMinimizedTest2)
{
    ASSERT_TRUE(run_isolated_test(1, 1, 8));
}
TEST_F(Directed, RandomMinimizedTest3)
{
    ASSERT_TRUE(run_isolated_test(1, 1, 9));
}

TEST_F(Directed, Add)
{
    for(int i = 1; i < 100; ++i)
    {
        AddQ(&q, &i);
        ASSERT_EQ(i, size_(&q));
    }
    ASSERT_EQ(99, size_(&q));
    for(int i = 1; i < 100; ++i)
    {
        ASSERT_EQ(i, *DelQ(&q));
    }
    ASSERT_EQ(0, size_(&q));
}

TEST_F(Directed, PutGet)
{
    int i = 8;
    AddQ(&q, &i);
    ASSERT_EQ(8, *DelQ(&q));
}

TEST_F(Directed, DeleteEmpty)
{
    Q q;
    InitQ(&q);

    DelQ(&q);
}

<commit_msg>Working on another minimized test case.<commit_after>extern "C" {
#include "q.h"
}

#include <gtest/gtest.h>
#include <deque>
#include <functional>
#include <algorithm>
#include <random>
#include <chrono>
#include <limits>
#include <iterator>

class Model : public ::testing::Test
{
    protected:
        virtual void SetUp()
        {
            seed = std::chrono::system_clock::now().time_since_epoch().count();
            rng.seed(seed);
        }

        virtual void TearDown()
        {
        }

        std::mt19937 rng;
        size_t seed;
};

template <typename RNG, typename D>
bool run_isolated_test(int ninserts, int npops, int nreinserts, D dist, RNG entropy)
{
    Q q;
    InitQ(&q);
    std::deque<int> model;
    auto result(true);

    for(auto n = 0; n < ninserts; ++n)
    {
        auto d = dist(entropy);
        model.push_back(d);
        AddQ(&q, &d);
    }
    for(auto n = 0; n < npops; ++n)
    {
        model.pop_front();
        DelQ(&q);
    }
    for(auto n = 0; n < nreinserts; ++n)
    {
        auto d = dist(entropy);
        model.push_back(d);
        AddQ(&q, &d);
    }

    for(auto r : model)
    {
        auto u = DelQ(&q);
        if(u == 0)
        {
            result = false;
#if 0
            std::cout << "Queue Ended Early.\n";
#endif
        }
        else
        {

        if(r != *u)
        {
            result = false;
#if 0
            std::cout << "Actual: " << r << " Expected: " << *u <<'\n';
            std::cout << "Test:\n"
                << "\tInserts: " << ninserts << '\n'
                << "\tDeletes: " << npops << '\n'
                << "\tReinserts: " << nreinserts << '\n';
#endif
        }
        }
    }
    FreeQ(&q);
    return result;
}
bool run_isolated_test(int ninserts, int npops, int nreinserts)
{
    std::mt19937 rng(0);
    std::uniform_int_distribution<int> input_data(std::numeric_limits<int>::min(), std::numeric_limits<int>::max());
    return run_isolated_test(ninserts, npops, nreinserts, input_data, rng);
}

TEST_F(Model, TheIDontHaveAllFuckingDaySoMakeTheComputerDoMyHomeworkTest)
{
    std::uniform_int_distribution<int> ntests(0, 1000);
    std::uniform_int_distribution<int> input_data(std::numeric_limits<int>::min(), std::numeric_limits<int>::max());

    //Generate a random number of inserts
    auto ninserts = ntests(rng);

    //Generate a random number of reads/pops
    auto npops = ntests(rng);

    //Generate a random number of more inserts to verify circular
    //dynamic functionality.  Verify we can write, read, write and read
    //again in any amount.
    auto nreinserts = ntests(rng);

     std::cout << "Test:\n"
    << "\tSeed: " << seed << '\n'
    << "\tInserts: " << ninserts << '\n'
    << "\tDeletes: " << npops << '\n'
    << "\tReinserts: " << nreinserts << '\n';
    //Verify from the model
    if(!run_isolated_test(ninserts, npops, nreinserts, input_data, rng))
    {
        std::cout << "Test Failed, minimizing.\n";
        while(ninserts > 0 && run_isolated_test(ninserts, npops, nreinserts, input_data, rng) == false)
        {
            --ninserts;
        }
        ++ninserts; //Make it fail again.
        while(npops > 0 && run_isolated_test(ninserts, npops, nreinserts, input_data, rng) == false)
        {
            --npops;
        }
        ++npops; //Make it fail again.
        while(nreinserts > 0 && run_isolated_test(ninserts, npops, nreinserts, input_data, rng) == false)
        {
            --nreinserts;
        }
        ++nreinserts; //Make it fail again.

        ADD_FAILURE();
        std::cout << "Test:\n"
            << "\tInserts: " << ninserts << '\n'
            << "\tDeletes: " << npops << '\n'
            << "\tReinserts: " << nreinserts << '\n';
    }
}

class Directed : public ::testing::Test
{
    protected:
        virtual void SetUp()
        {
            InitQ(&q);
        }

        virtual void TearDown()
        {
            FreeQ(&q);
        }

        Q q;
};

TEST_F(Directed, RandomMinimizedTest)
{
    ASSERT_TRUE(run_isolated_test(1, 0, 9)); //Random test generator found this test case
}
TEST_F(Directed, Weirdness)
{
    ASSERT_TRUE(run_isolated_test(10240, 0, 0));
}
TEST_F(Directed, RandomMinimizedTest2)
{
    ASSERT_TRUE(run_isolated_test(1, 1, 8));
}
TEST_F(Directed, RandomMinimizedTest3)
{
    ASSERT_TRUE(run_isolated_test(1, 1, 9));
}
TEST_F(Directed, RandomMinimizedTest4)
{
    ASSERT_TRUE(run_isolated_test(1, 2, 2));
}

TEST_F(Directed, Add)
{
    for(int i = 1; i < 100; ++i)
    {
        AddQ(&q, &i);
        ASSERT_EQ(i, size_(&q));
    }
    ASSERT_EQ(99, size_(&q));
    for(int i = 1; i < 100; ++i)
    {
        ASSERT_EQ(i, *DelQ(&q));
    }
    ASSERT_EQ(0, size_(&q));
}

TEST_F(Directed, PutGet)
{
    int i = 8;
    AddQ(&q, &i);
    ASSERT_EQ(8, *DelQ(&q));
}

TEST_F(Directed, DeleteEmpty)
{
    Q q;
    InitQ(&q);

    DelQ(&q);
}

<|endoftext|>


<commit_before>/*

Copyright (c) 2008-2012, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#ifndef TORRENT_BITFIELD_HPP_INCLUDED
#define TORRENT_BITFIELD_HPP_INCLUDED

#include "libtorrent/assert.hpp"
#include "libtorrent/config.hpp"
#include <cstring> // for memset and memcpy
#include <cstdlib> // for malloc, free and realloc
#include <boost/cstdint.hpp> // uint32_t

namespace libtorrent
{
	// The bitfiled type stores any number of bits as a bitfield in an array.
	struct TORRENT_EXPORT bitfield
	{
		bitfield(): m_bytes(0), m_size(0), m_own(false) {}
		bitfield(int bits): m_bytes(0), m_size(0), m_own(false)
		{ resize(bits); }
		bitfield(int bits, bool val): m_bytes(0), m_size(0), m_own(false)
		{ resize(bits, val); }
		bitfield(char const* b, int bits): m_bytes(0), m_size(0), m_own(false)
		{ assign(b, bits); }
		bitfield(bitfield const& rhs): m_bytes(0), m_size(0), m_own(false)
		{ assign(rhs.bytes(), rhs.size()); }

		void borrow_bytes(char* b, int bits)
		{
			dealloc();
			m_bytes = (unsigned char*)b;
			m_size = bits;
			m_own = false;
		}
		~bitfield() { dealloc(); }

		void assign(char const* b, int bits)
		{ resize(bits); std::memcpy(m_bytes, b, (bits + 7) / 8); clear_trailing_bits(); }

		bool operator[](int index) const
		{ return get_bit(index); }

		bool get_bit(int index) const
		{
			TORRENT_ASSERT(index >= 0);
			TORRENT_ASSERT(index < m_size);
			return (m_bytes[index / 8] & (0x80 >> (index & 7))) != 0;
		}

		void clear_bit(int index)
		{
			TORRENT_ASSERT(index >= 0);
			TORRENT_ASSERT(index < m_size);
			m_bytes[index / 8] &= ~(0x80 >> (index & 7));
		}

		// returns true if all bits in the bitfield are set
		bool all_set() const
		{
			const int num_words = m_size / 32;
			const int num_bytes = m_size / 8;
			boost::uint32_t* bits = (boost::uint32_t*)m_bytes;
			for (int i = 0; i < num_words; ++i)
			{
				if (bits[i] != 0xffffffff) return false;
			}

			for (int i = num_words * 4; i < num_bytes; ++i)
			{
				if (m_bytes[i] != 0xff) return false;
			}
			int rest = m_size - num_bytes * 8;
			boost::uint8_t mask = 0xff << (8-rest);
			if (rest > 0 && (m_bytes[num_bytes] & mask) != mask)
				return false;
			return true;
		}

		void set_bit(int index)
		{
			TORRENT_ASSERT(index >= 0);
			TORRENT_ASSERT(index < m_size);
			m_bytes[index / 8] |= (0x80 >> (index & 7));
		}

		std::size_t size() const { return m_size; }
		bool empty() const { return m_size == 0; }

		char const* bytes() const { return (char*)m_bytes; }

		bitfield& operator=(bitfield const& rhs)
		{
			assign(rhs.bytes(), rhs.size());
			return *this;
		}

		int count() const
		{
			// 0000, 0001, 0010, 0011, 0100, 0101, 0110, 0111,
			// 1000, 1001, 1010, 1011, 1100, 1101, 1110, 1111
			const static char num_bits[] =
			{
				0, 1, 1, 2, 1, 2, 2, 3,
				1, 2, 2, 3, 2, 3, 3, 4
			};

			int ret = 0;
			const int num_bytes = m_size / 8;
			for (int i = 0; i < num_bytes; ++i)
			{
				ret += num_bits[m_bytes[i] & 0xf] + num_bits[m_bytes[i] >> 4];
			}

			int rest = m_size - num_bytes * 8;
			for (int i = 0; i < rest; ++i)
			{
				ret += (m_bytes[num_bytes] >> (7-i)) & 1;
			}
			TORRENT_ASSERT(ret <= m_size);
			TORRENT_ASSERT(ret >= 0);
			return ret;
		}

		struct const_iterator
		{
		friend struct bitfield;

			typedef bool value_type;
			typedef ptrdiff_t difference_type;
			typedef bool const* pointer;
			typedef bool& reference;
			typedef std::forward_iterator_tag iterator_category;

			bool operator*() { return (*byte & bit) != 0; }
			const_iterator& operator++() { inc(); return *this; }
			const_iterator operator++(int)
			{ const_iterator ret(*this); inc(); return ret; }
			const_iterator& operator--() { dec(); return *this; }
			const_iterator operator--(int)
			{ const_iterator ret(*this); dec(); return ret; }

			const_iterator(): byte(0), bit(0x80) {}
			bool operator==(const_iterator const& rhs) const
			{ return byte == rhs.byte && bit == rhs.bit; }

			bool operator!=(const_iterator const& rhs) const
			{ return byte != rhs.byte || bit != rhs.bit; }

		private:
			void inc()
			{
				TORRENT_ASSERT(byte);
				if (bit == 0x01)
				{
					bit = 0x80;
					++byte;
				}
				else
				{
					bit >>= 1;
				}
			}
			void dec()
			{
				TORRENT_ASSERT(byte);
				if (bit == 0x80)
				{
					bit = 0x01;
					--byte;
				}
				else
				{
					bit <<= 1;
				}
			}
			const_iterator(unsigned char const* ptr, int offset)
				: byte(ptr), bit(0x80 >> offset) {}
			unsigned char const* byte;
			int bit;
		};

		const_iterator begin() const { return const_iterator(m_bytes, 0); }
		const_iterator end() const { return const_iterator(m_bytes + m_size / 8, m_size & 7); }

		void resize(int bits, bool val)
		{
			int s = m_size;
			int b = m_size & 7;
			resize(bits);
			if (s >= m_size) return;
			int old_size_bytes = (s + 7) / 8;
			int new_size_bytes = (m_size + 7) / 8;
			if (val)
			{
				if (old_size_bytes && b) m_bytes[old_size_bytes - 1] |= (0xff >> b);
				if (old_size_bytes < new_size_bytes)
					std::memset(m_bytes + old_size_bytes, 0xff, new_size_bytes - old_size_bytes);
				clear_trailing_bits();
			}
			else
			{
				if (old_size_bytes < new_size_bytes)
					std::memset(m_bytes + old_size_bytes, 0x00, new_size_bytes - old_size_bytes);
			}
		}

		void set_all()
		{
			std::memset(m_bytes, 0xff, (m_size + 7) / 8);
			clear_trailing_bits();
		}

		void clear_all()
		{
			std::memset(m_bytes, 0x00, (m_size + 7) / 8);
		}

		void resize(int bits)
		{
			TORRENT_ASSERT(bits >= 0);
			const int b = (bits + 7) / 8;
			if (m_bytes)
			{
				if (m_own)
				{
					m_bytes = (unsigned char*)std::realloc(m_bytes, b);
					m_own = true;
				}
				else if (bits > m_size)
				{
					unsigned char* tmp = (unsigned char*)std::malloc(b);
					std::memcpy(tmp, m_bytes, (std::min)(int(m_size + 7)/ 8, b));
					m_bytes = tmp;
					m_own = true;
				}
			}
			else if (bits > 0)
			{
				m_bytes = (unsigned char*)std::malloc(b);
				m_own = true;
			}
			m_size = bits;
			clear_trailing_bits();
		}

		void free() { dealloc(); m_size = 0; }

	private:

		void clear_trailing_bits()
		{
			// clear the tail bits in the last byte
			if (m_size & 7) m_bytes[(m_size + 7) / 8 - 1] &= 0xff << (8 - (m_size & 7));
		}

		void dealloc() { if (m_own) std::free(m_bytes); m_bytes = 0; }
		unsigned char* m_bytes;
		int m_size:31; // in bits
		bool m_own:1;
	};

}

#endif // TORRENT_BITFIELD_HPP_INCLUDED

<commit_msg>documented bitfield<commit_after>/*

Copyright (c) 2008-2012, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#ifndef TORRENT_BITFIELD_HPP_INCLUDED
#define TORRENT_BITFIELD_HPP_INCLUDED

#include "libtorrent/assert.hpp"
#include "libtorrent/config.hpp"
#include <cstring> // for memset and memcpy
#include <cstdlib> // for malloc, free and realloc
#include <boost/cstdint.hpp> // uint32_t

namespace libtorrent
{
	// The bitfiled type stores any number of bits as a bitfield
	// in a heap allocated or borrowed array.
	struct TORRENT_EXPORT bitfield
	{
		// constructs a new bitfield. The default constructor creates an empty
		// bitfield. ``bits`` is the size of the bitfield (specified in bits).
		// `` val`` is the value to initialize the bits to. If not specified
		// all bits are initialized to 0.
		//
		// The constructor taking a pointer ``b`` and ``bits`` copies a bitfield
		// from the specified buffer, and ``bits`` number of bits (rounded up to
		// the nearest byte boundry).
		bitfield(): m_bytes(0), m_size(0), m_own(false) {}
		bitfield(int bits): m_bytes(0), m_size(0), m_own(false)
		{ resize(bits); }
		bitfield(int bits, bool val): m_bytes(0), m_size(0), m_own(false)
		{ resize(bits, val); }
		bitfield(char const* b, int bits): m_bytes(0), m_size(0), m_own(false)
		{ assign(b, bits); }
		bitfield(bitfield const& rhs): m_bytes(0), m_size(0), m_own(false)
		{ assign(rhs.bytes(), rhs.size()); }

		// assigns a bitfield pointed to ``b`` of ``bits`` number of bits, without
		// taking ownership of the buffer. This is a way to avoid copying data and
		// yet provide a raw buffer to functions that may operate on the bitfield
		// type. It is the user's responsibility to make sure the passed-in buffer's
		// life time exceeds all uses of the bitfield.
		void borrow_bytes(char* b, int bits)
		{
			dealloc();
			m_bytes = (unsigned char*)b;
			m_size = bits;
			m_own = false;
		}

		// hidden
		~bitfield() { dealloc(); }

		// copy bitfield from buffer ``b`` of ``bits`` number of bits, rounded up to
		// the nearest byte boundary.
		void assign(char const* b, int bits)
		{ resize(bits); std::memcpy(m_bytes, b, (bits + 7) / 8); clear_trailing_bits(); }

		// query bit at ``index``. Returns true if bit is 1, otherwise false.
		bool operator[](int index) const
		{ return get_bit(index); }
		bool get_bit(int index) const
		{
			TORRENT_ASSERT(index >= 0);
			TORRENT_ASSERT(index < m_size);
			return (m_bytes[index / 8] & (0x80 >> (index & 7))) != 0;
		}

		// set bit at ``index`` to 0 (clear_bit) or 1 (set_bit).
		void clear_bit(int index)
		{
			TORRENT_ASSERT(index >= 0);
			TORRENT_ASSERT(index < m_size);
			m_bytes[index / 8] &= ~(0x80 >> (index & 7));
		}
		void set_bit(int index)
		{
			TORRENT_ASSERT(index >= 0);
			TORRENT_ASSERT(index < m_size);
			m_bytes[index / 8] |= (0x80 >> (index & 7));
		}

		// returns true if all bits in the bitfield are set
		bool all_set() const
		{
			const int num_words = m_size / 32;
			const int num_bytes = m_size / 8;
			boost::uint32_t* bits = (boost::uint32_t*)m_bytes;
			for (int i = 0; i < num_words; ++i)
			{
				if (bits[i] != 0xffffffff) return false;
			}

			for (int i = num_words * 4; i < num_bytes; ++i)
			{
				if (m_bytes[i] != 0xff) return false;
			}
			int rest = m_size - num_bytes * 8;
			boost::uint8_t mask = 0xff << (8-rest);
			if (rest > 0 && (m_bytes[num_bytes] & mask) != mask)
				return false;
			return true;
		}

		// returns the size of the bitfield in bits.
		std::size_t size() const { return m_size; }

		// returns true if the bitfield has zero size.
		bool empty() const { return m_size == 0; }

		// returns a pointer to the internal buffer of the bitfield.
		char const* bytes() const { return (char*)m_bytes; }

		// copy operator
		bitfield& operator=(bitfield const& rhs)
		{
			assign(rhs.bytes(), rhs.size());
			return *this;
		}

		// count the number of bits in the bitfield that are set to 1.
		int count() const
		{
			// 0000, 0001, 0010, 0011, 0100, 0101, 0110, 0111,
			// 1000, 1001, 1010, 1011, 1100, 1101, 1110, 1111
			const static char num_bits[] =
			{
				0, 1, 1, 2, 1, 2, 2, 3,
				1, 2, 2, 3, 2, 3, 3, 4
			};

			int ret = 0;
			const int num_bytes = m_size / 8;
			for (int i = 0; i < num_bytes; ++i)
			{
				ret += num_bits[m_bytes[i] & 0xf] + num_bits[m_bytes[i] >> 4];
			}

			int rest = m_size - num_bytes * 8;
			for (int i = 0; i < rest; ++i)
			{
				ret += (m_bytes[num_bytes] >> (7-i)) & 1;
			}
			TORRENT_ASSERT(ret <= m_size);
			TORRENT_ASSERT(ret >= 0);
			return ret;
		}

		struct const_iterator
		{
		friend struct bitfield;

			typedef bool value_type;
			typedef ptrdiff_t difference_type;
			typedef bool const* pointer;
			typedef bool& reference;
			typedef std::forward_iterator_tag iterator_category;

			bool operator*() { return (*byte & bit) != 0; }
			const_iterator& operator++() { inc(); return *this; }
			const_iterator operator++(int)
			{ const_iterator ret(*this); inc(); return ret; }
			const_iterator& operator--() { dec(); return *this; }
			const_iterator operator--(int)
			{ const_iterator ret(*this); dec(); return ret; }

			const_iterator(): byte(0), bit(0x80) {}
			bool operator==(const_iterator const& rhs) const
			{ return byte == rhs.byte && bit == rhs.bit; }

			bool operator!=(const_iterator const& rhs) const
			{ return byte != rhs.byte || bit != rhs.bit; }

		private:
			void inc()
			{
				TORRENT_ASSERT(byte);
				if (bit == 0x01)
				{
					bit = 0x80;
					++byte;
				}
				else
				{
					bit >>= 1;
				}
			}
			void dec()
			{
				TORRENT_ASSERT(byte);
				if (bit == 0x80)
				{
					bit = 0x01;
					--byte;
				}
				else
				{
					bit <<= 1;
				}
			}
			const_iterator(unsigned char const* ptr, int offset)
				: byte(ptr), bit(0x80 >> offset) {}
			unsigned char const* byte;
			int bit;
		};

		const_iterator begin() const { return const_iterator(m_bytes, 0); }
		const_iterator end() const { return const_iterator(m_bytes + m_size / 8, m_size & 7); }

		// set the size of the bitfield to ``bits`` length. If the bitfield is extended,
		// the new bits are initialized to ``val``.
		void resize(int bits, bool val)
		{
			int s = m_size;
			int b = m_size & 7;
			resize(bits);
			if (s >= m_size) return;
			int old_size_bytes = (s + 7) / 8;
			int new_size_bytes = (m_size + 7) / 8;
			if (val)
			{
				if (old_size_bytes && b) m_bytes[old_size_bytes - 1] |= (0xff >> b);
				if (old_size_bytes < new_size_bytes)
					std::memset(m_bytes + old_size_bytes, 0xff, new_size_bytes - old_size_bytes);
				clear_trailing_bits();
			}
			else
			{
				if (old_size_bytes < new_size_bytes)
					std::memset(m_bytes + old_size_bytes, 0x00, new_size_bytes - old_size_bytes);
			}
		}
		void resize(int bits)
		{
			TORRENT_ASSERT(bits >= 0);
			const int b = (bits + 7) / 8;
			if (m_bytes)
			{
				if (m_own)
				{
					m_bytes = (unsigned char*)std::realloc(m_bytes, b);
					m_own = true;
				}
				else if (bits > m_size)
				{
					unsigned char* tmp = (unsigned char*)std::malloc(b);
					std::memcpy(tmp, m_bytes, (std::min)(int(m_size + 7)/ 8, b));
					m_bytes = tmp;
					m_own = true;
				}
			}
			else if (bits > 0)
			{
				m_bytes = (unsigned char*)std::malloc(b);
				m_own = true;
			}
			m_size = bits;
			clear_trailing_bits();
		}

		// set all bits in the bitfield to 1 (set_all) or 0 (clear_all).
		void set_all()
		{
			std::memset(m_bytes, 0xff, (m_size + 7) / 8);
			clear_trailing_bits();
		}
		void clear_all()
		{
			std::memset(m_bytes, 0x00, (m_size + 7) / 8);
		}

		// make the bitfield empty, of zero size.
		void clear() { dealloc(); m_size = 0; }

	private:

		void clear_trailing_bits()
		{
			// clear the tail bits in the last byte
			if (m_size & 7) m_bytes[(m_size + 7) / 8 - 1] &= 0xff << (8 - (m_size & 7));
		}

		void dealloc() { if (m_own) std::free(m_bytes); m_bytes = 0; }
		unsigned char* m_bytes;
		int m_size:31; // in bits
		bool m_own:1;
	};

}

#endif // TORRENT_BITFIELD_HPP_INCLUDED

<|endoftext|>


<commit_before>//
// MessagePack for C++ static resolution routine
//
// Copyright (C) 2015 KONDO Takatoshi
//
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//
//        http://www.apache.org/licenses/LICENSE-2.0
//
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.
//
#ifndef MSGPACK_TYPE_EXT_HPP
#define MSGPACK_TYPE_EXT_HPP

#include "msgpack/versioning.hpp"
#include "msgpack/adaptor/adaptor_base.hpp"
#include <cstring>
#include <string>
#include <cassert>

namespace msgpack {

/// @cond
MSGPACK_API_VERSION_NAMESPACE(v1) {
/// @endcond

namespace type {
class ext_ref;

class ext {
public:
    ext() : m_data(1, 0) {}
    ext(int8_t t, const char* p, uint32_t s) {
        detail::check_container_size_for_ext<sizeof(std::size_t)>(s);
        m_data.reserve(static_cast<std::size_t>(s) + 1);
        m_data.push_back(static_cast<char>(t));
        m_data.insert(m_data.end(), p, p + s);
    }
    ext(int8_t t, uint32_t s) {
        detail::check_container_size_for_ext<sizeof(std::size_t)>(s);
        m_data.resize(static_cast<std::size_t>(s) + 1);
        m_data[0] = static_cast<char>(t);
    }
    ext(ext_ref const&);
    int8_t type() const {
        return static_cast<int8_t>(m_data[0]);
    }
    const char* data() const {
        return &m_data[1];
    }
    char* data() {
        return &m_data[1];
    }
    uint32_t size() const {
        return m_data.size() - 1;
    }
    bool operator== (const ext& x) const {
        return m_data == x.m_data;
    }

    bool operator!= (const ext& x) const {
        return !(*this == x);
    }

    bool operator< (const ext& x) const {
        return m_data < x.m_data;
    }

    bool operator> (const ext& x) const {
        return m_data > x.m_data;
    }
private:
    std::vector<char> m_data;
    friend class ext_ref;
};

} // namespace type

namespace adaptor {

template <>
struct convert<msgpack::type::ext> {
    msgpack::object const& operator()(msgpack::object const& o, msgpack::type::ext& v) const {
        if(o.type != msgpack::type::EXT) {
            throw msgpack::type_error();
        }
        v = msgpack::type::ext(o.via.ext.type(), o.via.ext.data(), o.via.ext.size);
        return o;
    }
};

template <>
struct pack<msgpack::type::ext> {
    template <typename Stream>
    msgpack::packer<Stream>& operator()(msgpack::packer<Stream>& o, const msgpack::type::ext& v) const {
        // size limit has aleady been checked at ext's constructor
        uint32_t size = v.size();
        o.pack_ext(size, v.type());
        o.pack_ext_body(v.data(), size);
        return o;
    }
};

template <>
struct object_with_zone<msgpack::type::ext> {
    void operator()(msgpack::object::with_zone& o, const msgpack::type::ext& v) const {
        // size limit has aleady been checked at ext's constructor
        uint32_t size = v.size();
        o.type = msgpack::type::EXT;
        char* ptr = static_cast<char*>(o.zone.allocate_align(size + 1));
        o.via.ext.ptr = ptr;
        o.via.ext.size = size;
        ptr[0] = static_cast<char>(v.type());
        std::memcpy(ptr + 1, v.data(), size);
    }
};

} // namespace adaptor

namespace type {

class ext_ref {
public:
    // ext_ref should be default constructible to support 'convert'.
    // A default constructed ext_ref object::m_ptr doesn't have the buffer to point to.
    // In order to avoid nullptr checking branches, m_ptr points to m_size.
    // So type() returns unspecified but valid value. It might be a zero because m_size
    // is initialized as zero, but shoudn't assume that.
    ext_ref() : m_ptr(static_cast<char*>(static_cast<void*>(&m_size))), m_size(0) {}
    ext_ref(const char* p, uint32_t s) :
        m_ptr(s == 0 ? static_cast<char*>(static_cast<void*>(&m_size)) : p),
        m_size(s == 0 ? 0 : s - 1) {
        detail::check_container_size_for_ext<sizeof(std::size_t)>(s);
    }

    // size limit has aleady been checked at ext's constructor
    ext_ref(ext const& x) : m_ptr(&x.m_data[0]), m_size(x.size()) {}

    const char* data() const {
        return m_ptr + 1;
    }

    uint32_t size() const {
        return m_size;
    }

    int8_t type() const {
        return static_cast<int8_t>(m_ptr[0]);
    }

    std::string str() const {
        return std::string(m_ptr + 1, m_size);
    }

    bool operator== (const ext_ref& x) const {
        return m_size == x.m_size && std::memcmp(m_ptr, x.m_ptr, m_size) == 0;
    }

    bool operator!= (const ext_ref& x) const {
        return !(*this == x);
    }

    bool operator< (const ext_ref& x) const {
        if (m_size < x.m_size) return true;
        if (m_size > x.m_size) return false;
        return std::memcmp(m_ptr, x.m_ptr, m_size) < 0;
    }

    bool operator> (const ext_ref& x) const {
        if (m_size > x.m_size) return true;
        if (m_size < x.m_size) return false;
        return std::memcmp(m_ptr, x.m_ptr, m_size) > 0;
    }
private:
    const char* m_ptr;
    uint32_t m_size;
    friend struct msgpack::adaptor::object<msgpack::type::ext_ref>;
};

ext::ext(ext_ref const& x) {
    // size limit has aleady been checked at ext_ref's constructor
    m_data.reserve(x.size() + 1);

    m_data.push_back(x.type());
    m_data.insert(m_data.end(), x.data(), x.data() + x.size());
}

} // namespace type

namespace adaptor {

template <>
struct convert<msgpack::type::ext_ref> {
    msgpack::object const& operator()(msgpack::object const& o, msgpack::type::ext_ref& v) const {
        if(o.type != msgpack::type::EXT) { throw msgpack::type_error(); }
        v = msgpack::type::ext_ref(o.via.ext.ptr, o.via.ext.size + 1);
        return o;
    }
};

template <>
struct pack<msgpack::type::ext_ref> {
    template <typename Stream>
    msgpack::packer<Stream>& operator()(msgpack::packer<Stream>& o, const msgpack::type::ext_ref& v) const {
        // size limit has aleady been checked at ext_ref's constructor
        uint32_t size = v.size();
        o.pack_ext(size, v.type());
        o.pack_ext_body(v.data(), size);
        return o;
    }
};

template <>
struct object<msgpack::type::ext_ref> {
    void operator()(msgpack::object& o, const msgpack::type::ext_ref& v) const {
        // size limit has aleady been checked at ext_ref's constructor
        uint32_t size = v.size();
        o.type = msgpack::type::EXT;
        o.via.ext.ptr = v.m_ptr;
        o.via.ext.size = size;
    }
};

template <>
struct object_with_zone<msgpack::type::ext_ref> {
    void operator()(msgpack::object::with_zone& o, const msgpack::type::ext_ref& v) const {
        static_cast<msgpack::object&>(o) << v;
    }
};

} // namespace adaptor

/// @cond
} // MSGPACK_API_VERSION_NAMESPACE(v1)
/// @endcond

} // namespace msgpack

#endif // MSGPACK_TYPE_EXT_HPP
<commit_msg>Fixed #307. Added 'inline' keyword to ext's constructor that defined at outside of the class definition.<commit_after>//
// MessagePack for C++ static resolution routine
//
// Copyright (C) 2015 KONDO Takatoshi
//
//    Licensed under the Apache License, Version 2.0 (the "License");
//    you may not use this file except in compliance with the License.
//    You may obtain a copy of the License at
//
//        http://www.apache.org/licenses/LICENSE-2.0
//
//    Unless required by applicable law or agreed to in writing, software
//    distributed under the License is distributed on an "AS IS" BASIS,
//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//    See the License for the specific language governing permissions and
//    limitations under the License.
//
#ifndef MSGPACK_TYPE_EXT_HPP
#define MSGPACK_TYPE_EXT_HPP

#include "msgpack/versioning.hpp"
#include "msgpack/adaptor/adaptor_base.hpp"
#include <cstring>
#include <string>
#include <cassert>

namespace msgpack {

/// @cond
MSGPACK_API_VERSION_NAMESPACE(v1) {
/// @endcond

namespace type {
class ext_ref;

class ext {
public:
    ext() : m_data(1, 0) {}
    ext(int8_t t, const char* p, uint32_t s) {
        detail::check_container_size_for_ext<sizeof(std::size_t)>(s);
        m_data.reserve(static_cast<std::size_t>(s) + 1);
        m_data.push_back(static_cast<char>(t));
        m_data.insert(m_data.end(), p, p + s);
    }
    ext(int8_t t, uint32_t s) {
        detail::check_container_size_for_ext<sizeof(std::size_t)>(s);
        m_data.resize(static_cast<std::size_t>(s) + 1);
        m_data[0] = static_cast<char>(t);
    }
    ext(ext_ref const&);
    int8_t type() const {
        return static_cast<int8_t>(m_data[0]);
    }
    const char* data() const {
        return &m_data[1];
    }
    char* data() {
        return &m_data[1];
    }
    uint32_t size() const {
        return m_data.size() - 1;
    }
    bool operator== (const ext& x) const {
        return m_data == x.m_data;
    }

    bool operator!= (const ext& x) const {
        return !(*this == x);
    }

    bool operator< (const ext& x) const {
        return m_data < x.m_data;
    }

    bool operator> (const ext& x) const {
        return m_data > x.m_data;
    }
private:
    std::vector<char> m_data;
    friend class ext_ref;
};

} // namespace type

namespace adaptor {

template <>
struct convert<msgpack::type::ext> {
    msgpack::object const& operator()(msgpack::object const& o, msgpack::type::ext& v) const {
        if(o.type != msgpack::type::EXT) {
            throw msgpack::type_error();
        }
        v = msgpack::type::ext(o.via.ext.type(), o.via.ext.data(), o.via.ext.size);
        return o;
    }
};

template <>
struct pack<msgpack::type::ext> {
    template <typename Stream>
    msgpack::packer<Stream>& operator()(msgpack::packer<Stream>& o, const msgpack::type::ext& v) const {
        // size limit has aleady been checked at ext's constructor
        uint32_t size = v.size();
        o.pack_ext(size, v.type());
        o.pack_ext_body(v.data(), size);
        return o;
    }
};

template <>
struct object_with_zone<msgpack::type::ext> {
    void operator()(msgpack::object::with_zone& o, const msgpack::type::ext& v) const {
        // size limit has aleady been checked at ext's constructor
        uint32_t size = v.size();
        o.type = msgpack::type::EXT;
        char* ptr = static_cast<char*>(o.zone.allocate_align(size + 1));
        o.via.ext.ptr = ptr;
        o.via.ext.size = size;
        ptr[0] = static_cast<char>(v.type());
        std::memcpy(ptr + 1, v.data(), size);
    }
};

} // namespace adaptor

namespace type {

class ext_ref {
public:
    // ext_ref should be default constructible to support 'convert'.
    // A default constructed ext_ref object::m_ptr doesn't have the buffer to point to.
    // In order to avoid nullptr checking branches, m_ptr points to m_size.
    // So type() returns unspecified but valid value. It might be a zero because m_size
    // is initialized as zero, but shoudn't assume that.
    ext_ref() : m_ptr(static_cast<char*>(static_cast<void*>(&m_size))), m_size(0) {}
    ext_ref(const char* p, uint32_t s) :
        m_ptr(s == 0 ? static_cast<char*>(static_cast<void*>(&m_size)) : p),
        m_size(s == 0 ? 0 : s - 1) {
        detail::check_container_size_for_ext<sizeof(std::size_t)>(s);
    }

    // size limit has aleady been checked at ext's constructor
    ext_ref(ext const& x) : m_ptr(&x.m_data[0]), m_size(x.size()) {}

    const char* data() const {
        return m_ptr + 1;
    }

    uint32_t size() const {
        return m_size;
    }

    int8_t type() const {
        return static_cast<int8_t>(m_ptr[0]);
    }

    std::string str() const {
        return std::string(m_ptr + 1, m_size);
    }

    bool operator== (const ext_ref& x) const {
        return m_size == x.m_size && std::memcmp(m_ptr, x.m_ptr, m_size) == 0;
    }

    bool operator!= (const ext_ref& x) const {
        return !(*this == x);
    }

    bool operator< (const ext_ref& x) const {
        if (m_size < x.m_size) return true;
        if (m_size > x.m_size) return false;
        return std::memcmp(m_ptr, x.m_ptr, m_size) < 0;
    }

    bool operator> (const ext_ref& x) const {
        if (m_size > x.m_size) return true;
        if (m_size < x.m_size) return false;
        return std::memcmp(m_ptr, x.m_ptr, m_size) > 0;
    }
private:
    const char* m_ptr;
    uint32_t m_size;
    friend struct msgpack::adaptor::object<msgpack::type::ext_ref>;
};

inline ext::ext(ext_ref const& x) {
    // size limit has aleady been checked at ext_ref's constructor
    m_data.reserve(x.size() + 1);

    m_data.push_back(x.type());
    m_data.insert(m_data.end(), x.data(), x.data() + x.size());
}

} // namespace type

namespace adaptor {

template <>
struct convert<msgpack::type::ext_ref> {
    msgpack::object const& operator()(msgpack::object const& o, msgpack::type::ext_ref& v) const {
        if(o.type != msgpack::type::EXT) { throw msgpack::type_error(); }
        v = msgpack::type::ext_ref(o.via.ext.ptr, o.via.ext.size + 1);
        return o;
    }
};

template <>
struct pack<msgpack::type::ext_ref> {
    template <typename Stream>
    msgpack::packer<Stream>& operator()(msgpack::packer<Stream>& o, const msgpack::type::ext_ref& v) const {
        // size limit has aleady been checked at ext_ref's constructor
        uint32_t size = v.size();
        o.pack_ext(size, v.type());
        o.pack_ext_body(v.data(), size);
        return o;
    }
};

template <>
struct object<msgpack::type::ext_ref> {
    void operator()(msgpack::object& o, const msgpack::type::ext_ref& v) const {
        // size limit has aleady been checked at ext_ref's constructor
        uint32_t size = v.size();
        o.type = msgpack::type::EXT;
        o.via.ext.ptr = v.m_ptr;
        o.via.ext.size = size;
    }
};

template <>
struct object_with_zone<msgpack::type::ext_ref> {
    void operator()(msgpack::object::with_zone& o, const msgpack::type::ext_ref& v) const {
        static_cast<msgpack::object&>(o) << v;
    }
};

} // namespace adaptor

/// @cond
} // MSGPACK_API_VERSION_NAMESPACE(v1)
/// @endcond

} // namespace msgpack

#endif // MSGPACK_TYPE_EXT_HPP
<|endoftext|>