text:
#include <boost/text/string_view.hpp>
#include <boost/text/utility.hpp>

#include <gtest/gtest.h>

using namespace boost;

TEST(utf_8, test_consecutive)
{
    // Unicode 9, 3.9/D90-D92
    uint32_t const utf32[] = {0x004d, 0x0430, 0x4e8c, 0x10302};
    uint16_t const utf16[] = {0x004d, 0x0430, 0x4e8c, 0xd800, 0xdf02};
    char const utf8[] = {0x4d,
                         char(0xd0),
                         char(0xb0),
                         char(0xe4),
                         char(0xba),
                         char(0x8c),
                         char(0xf0),
                         char(0x90),
                         char(0x8c),
                         char(0x82),
                         0};

    // UTF-8 -> UTF-32
    {
        auto it = text::utf8::
            to_utf32_iterator<char const *, text::utf8::null_sentinel>(
                utf8, utf8, text::utf8::null_sentinel{});

        auto const end = text::utf8::
            to_utf32_iterator<char const *, text::utf8::null_sentinel>(
                utf8, utf8 + 10, text::utf8::null_sentinel{});

        auto const zero = it;
        EXPECT_EQ(*it, utf32[0]);
        ++it;
        auto const one = it;
        EXPECT_EQ(*it, utf32[1]);
        ++it;
        auto const two = it;
        EXPECT_EQ(*it, utf32[2]);
        ++it;
        auto const three = it;
        EXPECT_EQ(*it, utf32[3]);
        ++it;
        auto const four = it;

        EXPECT_EQ(it, end);

        --it;
        EXPECT_EQ(it, three);
        EXPECT_EQ(*it, utf32[3]);
        --it;
        EXPECT_EQ(it, two);
        EXPECT_EQ(*it, utf32[2]);
        --it;
        EXPECT_EQ(it, one);
        EXPECT_EQ(*it, utf32[1]);
        --it;
        EXPECT_EQ(it, zero);
        EXPECT_EQ(*it, utf32[0]);

        it = end;

        EXPECT_EQ(it, four);

        --it;
        EXPECT_EQ(it, three);
        EXPECT_EQ(*it, utf32[3]);
        --it;
        EXPECT_EQ(it, two);
        EXPECT_EQ(*it, utf32[2]);
        --it;
        EXPECT_EQ(it, one);
        EXPECT_EQ(*it, utf32[1]);
        --it;
        EXPECT_EQ(it, zero);
        EXPECT_EQ(*it, utf32[0]);

        EXPECT_EQ(*it, utf32[0]);
        ++it;
        EXPECT_EQ(it, one);
        EXPECT_EQ(*it, utf32[1]);
        ++it;
        EXPECT_EQ(it, two);
        EXPECT_EQ(*it, utf32[2]);
        ++it;
        EXPECT_EQ(it, three);
        EXPECT_EQ(*it, utf32[3]);
        ++it;
        EXPECT_EQ(it, four);
    }

    // UTF-32 -> UTF-8
    {
        auto it = text::utf8::from_utf32_iterator<uint32_t const *>(
            utf32, utf32, utf32 + 4);

        auto const end = text::utf8::from_utf32_iterator<uint32_t const *>(
            utf32, utf32 + 4, utf32 + 4);

        auto const zero = it;
        EXPECT_EQ(*it, utf8[0]);
        it++;
        auto const one = it;
        EXPECT_EQ(*it, utf8[1]);
        it++;
        auto const two = it;
        EXPECT_EQ(*it, utf8[2]);
        it++;
        auto const three = it;
        EXPECT_EQ(*it, utf8[3]);
        it++;
        auto const four = it;
        EXPECT_EQ(*it, utf8[4]);
        it++;
        auto const five = it;
        EXPECT_EQ(*it, utf8[5]);
        it++;
        auto const six = it;
        EXPECT_EQ(*it, utf8[6]);
        it++;
        auto const seven = it;
        EXPECT_EQ(*it, utf8[7]);
        it++;
        auto const eight = it;
        EXPECT_EQ(*it, utf8[8]);
        it++;
        auto const nine = it;
        EXPECT_EQ(*it, utf8[9]);
        it++;
        auto const ten = it;

        EXPECT_EQ(ten, end);

        --it;
        EXPECT_EQ(it, nine);
        EXPECT_EQ(*it, utf8[9]);
        --it;
        EXPECT_EQ(it, eight);
        EXPECT_EQ(*it, utf8[8]);
        --it;
        EXPECT_EQ(it, seven);
        EXPECT_EQ(*it, utf8[7]);
        --it;
        EXPECT_EQ(it, six);
        EXPECT_EQ(*it, utf8[6]);
        --it;
        EXPECT_EQ(it, five);
        EXPECT_EQ(*it, utf8[5]);
        --it;
        EXPECT_EQ(it, four);
        EXPECT_EQ(*it, utf8[4]);
        --it;
        EXPECT_EQ(it, three);
        EXPECT_EQ(*it, utf8[3]);
        --it;
        EXPECT_EQ(it, two);
        EXPECT_EQ(*it, utf8[2]);
        --it;
        EXPECT_EQ(it, one);
        EXPECT_EQ(*it, utf8[1]);
        --it;
        EXPECT_EQ(it, zero);
        EXPECT_EQ(*it, utf8[0]);

        it = end;

        EXPECT_EQ(it, end);

        --it;
        EXPECT_EQ(it, nine);
        EXPECT_EQ(*it, utf8[9]);
        --it;
        EXPECT_EQ(it, eight);
        EXPECT_EQ(*it, utf8[8]);
        --it;
        EXPECT_EQ(it, seven);
        EXPECT_EQ(*it, utf8[7]);
        --it;
        EXPECT_EQ(it, six);
        EXPECT_EQ(*it, utf8[6]);
        --it;
        EXPECT_EQ(it, five);
        EXPECT_EQ(*it, utf8[5]);
        --it;
        EXPECT_EQ(it, four);
        EXPECT_EQ(*it, utf8[4]);
        --it;
        EXPECT_EQ(it, three);
        EXPECT_EQ(*it, utf8[3]);
        --it;
        EXPECT_EQ(it, two);
        EXPECT_EQ(*it, utf8[2]);
        --it;
        EXPECT_EQ(it, one);
        EXPECT_EQ(*it, utf8[1]);
        --it;
        EXPECT_EQ(it, zero);
        EXPECT_EQ(*it, utf8[0]);

        EXPECT_EQ(*it, utf8[0]);
        ++it;
        EXPECT_EQ(*it, utf8[1]);
        ++it;
        EXPECT_EQ(*it, utf8[2]);
        ++it;
        EXPECT_EQ(*it, utf8[3]);
        ++it;
        EXPECT_EQ(*it, utf8[4]);
        ++it;
        EXPECT_EQ(*it, utf8[5]);
        ++it;
        EXPECT_EQ(*it, utf8[6]);
        ++it;
        EXPECT_EQ(*it, utf8[7]);
        ++it;
        EXPECT_EQ(*it, utf8[8]);
        ++it;
        EXPECT_EQ(*it, utf8[9]);
        ++it;
    }

    // UTF-8 -> UTF-16
    {
        auto it = text::utf8::to_utf16_iterator<char const *>(
            utf8, utf8, utf8 + sizeof(utf8));

        auto const end = text::utf8::to_utf16_iterator<char const *>(
            utf8, utf8 + 10, utf8 + sizeof(utf8));

        auto const zero = it;
        EXPECT_EQ(*it, utf16[0]);
        ++it;
        auto const one = it;
        EXPECT_EQ(*it, utf16[1]);
        ++it;
        auto const two = it;
        EXPECT_EQ(*it, utf16[2]);
        ++it;
        auto const three = it;
        EXPECT_EQ(*it, utf16[3]);
        ++it;
        auto const four = it;
        EXPECT_EQ(*it, utf16[4]);
        ++it;
        auto const five = it;

        EXPECT_EQ(five, end);

        --it;
        EXPECT_EQ(it, four);
        EXPECT_EQ(*it, utf16[4]);
        --it;
        EXPECT_EQ(it, three);
        EXPECT_EQ(*it, utf16[3]);
        --it;
        EXPECT_EQ(it, two);
        EXPECT_EQ(*it, utf16[2]);
        --it;
        EXPECT_EQ(it, one);
        EXPECT_EQ(*it, utf16[1]);
        --it;
        EXPECT_EQ(it, zero);
        EXPECT_EQ(*it, utf16[0]);

        it = end;

        EXPECT_EQ(it, five);

        --it;
        EXPECT_EQ(it, four);
        EXPECT_EQ(*it, utf16[4]);
        --it;
        EXPECT_EQ(it, three);
        EXPECT_EQ(*it, utf16[3]);
        --it;
        EXPECT_EQ(it, two);
        EXPECT_EQ(*it, utf16[2]);
        --it;
        EXPECT_EQ(it, one);
        EXPECT_EQ(*it, utf16[1]);
        --it;
        EXPECT_EQ(it, zero);
        EXPECT_EQ(*it, utf16[0]);

        EXPECT_EQ(*it, utf16[0]);
        ++it;
        EXPECT_EQ(it, one);
        EXPECT_EQ(*it, utf16[1]);
        ++it;
        EXPECT_EQ(it, two);
        EXPECT_EQ(*it, utf16[2]);
        ++it;
        EXPECT_EQ(it, three);
        EXPECT_EQ(*it, utf16[3]);
        ++it;
        EXPECT_EQ(it, four);
        EXPECT_EQ(*it, utf16[4]);
        ++it;
        EXPECT_EQ(it, five);
    }

    // UTF-16 -> UTF-8
    {
        auto it = text::utf8::from_utf16_iterator<uint16_t const *>(
            utf16, utf16, utf16 + 5);

        auto const end = text::utf8::from_utf16_iterator<uint16_t const *>(
            utf16, utf16 + 5, utf16 + 5);

        auto const zero = it;
        EXPECT_EQ(*it, utf8[0]);
        ++it;
        auto const one = it;
        EXPECT_EQ(*it, utf8[1]);
        ++it;
        auto const two = it;
        EXPECT_EQ(*it, utf8[2]);
        ++it;
        auto const three = it;
        EXPECT_EQ(*it, utf8[3]);
        ++it;
        auto const four = it;
        EXPECT_EQ(*it, utf8[4]);
        ++it;
        auto const five = it;
        EXPECT_EQ(*it, utf8[5]);
        ++it;
        auto const six = it;
        EXPECT_EQ(*it, utf8[6]);
        ++it;
        auto const seven = it;
        EXPECT_EQ(*it, utf8[7]);
        ++it;
        auto const eight = it;
        EXPECT_EQ(*it, utf8[8]);
        ++it;
        auto const nine = it;
        EXPECT_EQ(*it, utf8[9]);
        ++it;
        auto const ten = it;

        EXPECT_EQ(ten, end);

        --it;
        EXPECT_EQ(it, nine);
        EXPECT_EQ(*it, utf8[9]);
        --it;
        EXPECT_EQ(it, eight);
        EXPECT_EQ(*it, utf8[8]);
        --it;
        EXPECT_EQ(it, seven);
        EXPECT_EQ(*it, utf8[7]);
        --it;
        EXPECT_EQ(it, six);
        EXPECT_EQ(*it, utf8[6]);
        --it;
        EXPECT_EQ(it, five);
        EXPECT_EQ(*it, utf8[5]);
        --it;
        EXPECT_EQ(it, four);
        EXPECT_EQ(*it, utf8[4]);
        --it;
        EXPECT_EQ(it, three);
        EXPECT_EQ(*it, utf8[3]);
        --it;
        EXPECT_EQ(it, two);
        EXPECT_EQ(*it, utf8[2]);
        --it;
        EXPECT_EQ(it, one);
        EXPECT_EQ(*it, utf8[1]);
        --it;
        EXPECT_EQ(it, zero);
        EXPECT_EQ(*it, utf8[0]);

        it = end;

        EXPECT_EQ(it, end);

        --it;
        EXPECT_EQ(it, nine);
        EXPECT_EQ(*it, utf8[9]);
        --it;
        EXPECT_EQ(it, eight);
        EXPECT_EQ(*it, utf8[8]);
        --it;
        EXPECT_EQ(it, seven);
        EXPECT_EQ(*it, utf8[7]);
        --it;
        EXPECT_EQ(it, six);
        EXPECT_EQ(*it, utf8[6]);
        --it;
        EXPECT_EQ(it, five);
        EXPECT_EQ(*it, utf8[5]);
        --it;
        EXPECT_EQ(it, four);
        EXPECT_EQ(*it, utf8[4]);
        --it;
        EXPECT_EQ(it, three);
        EXPECT_EQ(*it, utf8[3]);
        --it;
        EXPECT_EQ(it, two);
        EXPECT_EQ(*it, utf8[2]);
        --it;
        EXPECT_EQ(it, one);
        EXPECT_EQ(*it, utf8[1]);
        --it;
        EXPECT_EQ(it, zero);
        EXPECT_EQ(*it, utf8[0]);

        EXPECT_EQ(*it, utf8[0]);
        ++it;
        EXPECT_EQ(*it, utf8[1]);
        ++it;
        EXPECT_EQ(*it, utf8[2]);
        ++it;
        EXPECT_EQ(*it, utf8[3]);
        ++it;
        EXPECT_EQ(*it, utf8[4]);
        ++it;
        EXPECT_EQ(*it, utf8[5]);
        ++it;
        EXPECT_EQ(*it, utf8[6]);
        ++it;
        EXPECT_EQ(*it, utf8[7]);
        ++it;
        EXPECT_EQ(*it, utf8[8]);
        ++it;
        EXPECT_EQ(*it, utf8[9]);
        ++it;
    }
}

TEST(utf_8, test_back_and_forth)
{
    // Unicode 9, 3.9/D90-D92
    uint32_t const utf32[] = {0x004d, 0x0430, 0x4e8c, 0x10302};
    uint16_t const utf16[] = {0x004d, 0x0430, 0x4e8c, 0xd800, 0xdf02};
    char const utf8[] = {0x4d,
                         char(0xd0),
                         char(0xb0),
                         char(0xe4),
                         char(0xba),
                         char(0x8c),
                         char(0xf0),
                         char(0x90),
                         char(0x8c),
                         char(0x82),
                         0};

    // UTF-8 -> UTF-32
    for (int iterations = 1; iterations <= 4; ++iterations) {
        auto it = text::utf8::
            to_utf32_iterator<char const *, text::utf8::null_sentinel>(
                utf8, utf8, text::utf8::null_sentinel{});
        for (int i = 0; i < iterations; ++i) {
            EXPECT_EQ(*it++, utf32[i])
                << "iterations=" << iterations << " i=" << i;
        }
        for (int i = iterations; i-- > 0;) {
            EXPECT_EQ(*--it, utf32[i])
                << "iterations=" << iterations << " i=" << i;
        }
    }

    for (int iterations = 0; iterations < 4; ++iterations) {
        auto it = text::utf8::
            to_utf32_iterator<char const *, text::utf8::null_sentinel>(
                utf8, utf8 + 10, text::utf8::null_sentinel{});
        int i = 4;
        for (; i-- > iterations;) {
            EXPECT_EQ(*--it, utf32[i])
                << "iterations=" << iterations << " i=" << i;
        }
        ++i;
        for (; i < 4; ++i) {
            EXPECT_EQ(*it++, utf32[i])
                << "iterations=" << iterations << " i=" << i;
        }
    }

    // UTF-32 -> UTF-8
    for (int iterations = 1; iterations <= 10; ++iterations) {
        auto it = text::utf8::from_utf32_iterator<uint32_t const *>(
            utf32, utf32, utf32 + 4);
        for (int i = 0; i < iterations; ++i) {
            EXPECT_EQ(*it++, utf8[i])
                << "iterations=" << iterations << " i=" << i;
        }
        for (int i = iterations; i-- > 0;) {
            EXPECT_EQ(*--it, utf8[i])
                << "iterations=" << iterations << " i=" << i;
        }
    }

    for (int iterations = 0; iterations < 10; ++iterations) {
        auto it = text::utf8::from_utf32_iterator<uint32_t const *>(
            utf32, utf32 + 4, utf32 + 4);
        int i = 10;
        for (; i-- > iterations;) {
            EXPECT_EQ(*--it, utf8[i])
                << "iterations=" << iterations << " i=" << i;
        }
        ++i;
        for (; i < 10; ++i) {
            EXPECT_EQ(*it++, utf8[i])
                << "iterations=" << iterations << " i=" << i;
        }
    }

    // UTF-8 -> UTF-16
    for (int iterations = 1; iterations <= 5; ++iterations) {
        auto it = text::utf8::to_utf16_iterator<char const *>(
            utf8, utf8, utf8 + sizeof(utf8));
        for (int i = 0; i < iterations; ++i) {
            EXPECT_EQ(*it++, utf16[i])
                << "iterations=" << iterations << " i=" << i;
        }
        for (int i = iterations; i-- > 0;) {
            EXPECT_EQ(*--it, utf16[i])
                << "iterations=" << iterations << " i=" << i;
        }
    }

    for (int iterations = 0; iterations < 5; ++iterations) {
        auto it = text::utf8::to_utf16_iterator<char const *>(
            utf8, utf8 + 10, utf8 + sizeof(utf8));
        int i = 5;
        for (; i-- > iterations;) {
            EXPECT_EQ(*--it, utf16[i])
                << "iterations=" << iterations << " i=" << i;
        }
        ++i;
        for (; i < 5; ++i) {
            EXPECT_EQ(*it++, utf16[i])
                << "iterations=" << iterations << " i=" << i;
        }
    }

    // UTF-16 -> UTF-8
    for (int iterations = 1; iterations <= 10; ++iterations) {
        auto it = text::utf8::from_utf16_iterator<uint16_t const *>(
            utf16, utf16, utf16 + 5);
        for (int i = 0; i < iterations; ++i) {
            EXPECT_EQ(*it++, utf8[i])
                << "iterations=" << iterations << " i=" << i;
        }
        for (int i = iterations; i-- > 0;) {
            EXPECT_EQ(*--it, utf8[i])
                << "iterations=" << iterations << " i=" << i;
        }
    }

    for (int iterations = 0; iterations < 10; ++iterations) {
        auto it = text::utf8::from_utf16_iterator<uint16_t const *>(
            utf16, utf16 + 5, utf16 + 5);
        int i = 10;
        for (; i-- > iterations;) {
            EXPECT_EQ(*--it, utf8[i])
                << "iterations=" << iterations << " i=" << i;
        }
        ++i;
        for (; i < 10; ++i) {
            EXPECT_EQ(*it++, utf8[i])
                << "iterations=" << iterations << " i=" << i;
        }
    }
}

// The tests using this struct cover the boundaries of all the cases in Table
// 3-7 in Unicode 9, 3.9/D92
template<int EncodingLength>
struct coverage_test_case
{
    char str_[EncodingLength + 4];
    uint32_t utf32_;
};

TEST(utf_8, test_utf8_coverage_length_1)
{
    coverage_test_case<1> const cases[] = {
        {{char(0x0)}, 0x0},
        {{char(0x7f)}, 0x7f},
        {{char(0x80)}, 0xfffd},
    };

    for (auto c : cases) {
        text::utf8::to_utf32_iterator<char const *, char const *> it(
            c.str_, c.str_, c.str_ + sizeof(c.str_));
        EXPECT_EQ(*it, c.utf32_);
    }
}

TEST(utf_8, test_utf8_coverage_length_2)
{
    coverage_test_case<2> const cases[] = {
        {{char(0xc1), char(0xbf)}, 0xfffd},
        {{char(0xc1), char(0xc0)}, 0xfffd},

        {{char(0xc2), char(0xbf)}, 0xbf},
        {{char(0xc2), char(0xc0)}, 0xfffd},

        {{char(0xdf), char(0xbf)}, 0x7ff},
        {{char(0xdf), char(0xc0)}, 0xfffd},
    };

    for (auto c : cases) {
        text::utf8::to_utf32_iterator<char const *, char const *> it(
            c.str_, c.str_, c.str_ + sizeof(c.str_));
        EXPECT_EQ(*it, c.utf32_);
    }
}

TEST(utf_8, test_utf8_coverage_length_3_a)
{
    coverage_test_case<3> const cases[] = {
        {{char(0xe0), char(0x9f), char(0xc0)}, 0xfffd},
        {{char(0xe0), char(0x9f), char(0xbf)}, 0xfffd},
        {{char(0xe0), char(0xa0), char(0xc0)}, 0xfffd},
        {{char(0xe0), char(0xa0), char(0xbf)}, 0x83f},
    };

    for (auto c : cases) {
        text::utf8::to_utf32_iterator<char const *, char const *> it(
            c.str_, c.str_, c.str_ + sizeof(c.str_));
        EXPECT_EQ(*it, c.utf32_);
    }
}

TEST(utf_8, test_utf8_coverage_length_3_b)
{
    coverage_test_case<3> const cases[] = {
        {{char(0xe1), char(0xc0), char(0xc0)}, 0xfffd},
        {{char(0xe1), char(0xc0), char(0xbf)}, 0xfffd},
        {{char(0xe1), char(0xbf), char(0xc0)}, 0xfffd},
        {{char(0xe1), char(0xbf), char(0xbf)}, 0x1fff},

        {{char(0xec), char(0xc0), char(0xc0)}, 0xfffd},
        {{char(0xec), char(0xc0), char(0xbf)}, 0xfffd},
        {{char(0xec), char(0xbf), char(0xc0)}, 0xfffd},
        {{char(0xec), char(0xbf), char(0xbf)}, 0xcfff},
    };

    for (auto c : cases) {
        text::utf8::to_utf32_iterator<char const *, char const *> it(
            c.str_, c.str_, c.str_ + sizeof(c.str_));
        EXPECT_EQ(*it, c.utf32_);
    }
}

TEST(utf_8, test_utf8_coverage_length_3_c)
{
    coverage_test_case<3> const cases[] = {
        {{char(0xed), char(0xa0), char(0xc0)}, 0xfffd},
        {{char(0xed), char(0xa0), char(0xbf)}, 0xfffd},
        {{char(0xed), char(0x9f), char(0xc0)}, 0xfffd},
        {{char(0xed), char(0x9f), char(0xbf)}, 0xd7ff},
    };

    for (auto c : cases) {
        text::utf8::to_utf32_iterator<char const *, char const *> it(
            c.str_, c.str_, c.str_ + sizeof(c.str_));
        EXPECT_EQ(*it, c.utf32_);
    }
}

TEST(utf_8, test_utf8_coverage_length_3_d)
{
    coverage_test_case<3> const cases[] = {
        {{char(0xee), char(0xc0), char(0xc0)}, 0xfffd},
        {{char(0xee), char(0xc0), char(0xbf)}, 0xfffd},
        {{char(0xee), char(0xbf), char(0xc0)}, 0xfffd},
        {{char(0xee), char(0xbf), char(0xbf)}, 0xefff},

        {{char(0xef), char(0xc0), char(0xc0)}, 0xfffd},
        {{char(0xef), char(0xc0), char(0xbf)}, 0xfffd},
        {{char(0xef), char(0xbf), char(0xc0)}, 0xfffd},
        {{char(0xef), char(0xbf), char(0xbf)}, 0xfffd},
    };

    for (auto c : cases) {
        text::utf8::to_utf32_iterator<char const *, char const *> it(
            c.str_, c.str_, c.str_ + sizeof(c.str_));
        EXPECT_EQ(*it, c.utf32_);
    }
}

TEST(utf_8, test_utf8_coverage_length_4_a)
{
    coverage_test_case<3> const cases[] = {
        {{char(0xf0), char(0x8f), char(0xc0), char(0xc0)}, 0xfffd},
        {{char(0xf0), char(0x8f), char(0xc0), char(0xbf)}, 0xfffd},
        {{char(0xf0), char(0x8f), char(0xbf), char(0xc0)}, 0xfffd},
        {{char(0xf0), char(0x8f), char(0xbf), char(0xbf)}, 0xfffd},

        {{char(0xf0), char(0x90), char(0xc0), char(0xc0)}, 0xfffd},
        {{char(0xf0), char(0x90), char(0xc0), char(0xbf)}, 0xfffd},
        {{char(0xf0), char(0x90), char(0xbf), char(0xc0)}, 0xfffd},
        {{char(0xf0), char(0x90), char(0xbf), char(0xbf)}, 0x10fff},
    };

    for (auto c : cases) {
        text::utf8::to_utf32_iterator<char const *, char const *> it(
            c.str_, c.str_, c.str_ + sizeof(c.str_));
        EXPECT_EQ(*it, c.utf32_);
    }
}

// Note that the only reason we're testing the lower end of the 0x80-0xbf
// range in these next two tests is that using the upper end produces a
// code point reserved for internal use (and thus a 0xfffd).

TEST(utf_8, test_utf8_coverage_length_4_b)
{
    coverage_test_case<3> const cases[] = {
        {{char(0xf1), char(0x7f), char(0x7f), char(0x7f)}, 0xfffd},
        {{char(0xf1), char(0x7f), char(0x7f), char(0x80)}, 0xfffd},
        {{char(0xf1), char(0x7f), char(0x80), char(0x7f)}, 0xfffd},
        {{char(0xf1), char(0x7f), char(0x80), char(0x80)}, 0xfffd},

        {{char(0xf1), char(0x80), char(0x7f), char(0x7f)}, 0xfffd},
        {{char(0xf1), char(0x80), char(0x7f), char(0x80)}, 0xfffd},
        {{char(0xf1), char(0x80), char(0x80), char(0x7f)}, 0xfffd},
        {{char(0xf1), char(0x80), char(0x80), char(0x80)}, 0x40000},

        {{char(0xf3), char(0x7f), char(0x7f), char(0x7f)}, 0xfffd},
        {{char(0xf3), char(0x7f), char(0x7f), char(0x80)}, 0xfffd},
        {{char(0xf3), char(0x7f), char(0x80), char(0x7f)}, 0xfffd},
        {{char(0xf3), char(0x7f), char(0x80), char(0x80)}, 0xfffd},

        {{char(0xf3), char(0x80), char(0x7f), char(0x7f)}, 0xfffd},
        {{char(0xf3), char(0x80), char(0x7f), char(0x80)}, 0xfffd},
        {{char(0xf3), char(0x80), char(0x80), char(0x7f)}, 0xfffd},
        {{char(0xf3), char(0x80), char(0x80), char(0x80)}, 0xc0000},
    };

    for (auto c : cases) {
        text::utf8::to_utf32_iterator<char const *, char const *> it(
            c.str_, c.str_, c.str_ + sizeof(c.str_));
        EXPECT_EQ(*it, c.utf32_);
    }
}

TEST(utf_8, test_utf8_coverage_length_4_c)
{
    coverage_test_case<3> const cases[] = {
        {{char(0xf4), char(0x90), char(0x7f), char(0x7f)}, 0xfffd},
        {{char(0xf4), char(0x90), char(0x7f), char(0x80)}, 0xfffd},
        {{char(0xf4), char(0x90), char(0x80), char(0x7f)}, 0xfffd},
        {{char(0xf4), char(0x90), char(0x80), char(0x80)}, 0xfffd},

        {{char(0xf4), char(0x8f), char(0x7f), char(0x7f)}, 0xfffd},
        {{char(0xf4), char(0x8f), char(0x7f), char(0x80)}, 0xfffd},
        {{char(0xf4), char(0x8f), char(0x80), char(0x7f)}, 0xfffd},
        {{char(0xf4), char(0x8f), char(0x80), char(0x80)}, 0x10f000},

        {{char(0xf5), char(0x90), char(0x7f), char(0x7f)}, 0xfffd},
        {{char(0xf5), char(0x90), char(0x7f), char(0x80)}, 0xfffd},
        {{char(0xf5), char(0x90), char(0x80), char(0x7f)}, 0xfffd},
        {{char(0xf5), char(0x90), char(0x80), char(0x80)}, 0xfffd},

        {{char(0xf5), char(0x8f), char(0x7f), char(0x7f)}, 0xfffd},
        {{char(0xf5), char(0x8f), char(0x7f), char(0x80)}, 0xfffd},
        {{char(0xf5), char(0x8f), char(0x80), char(0x7f)}, 0xfffd},
        {{char(0xf5), char(0x8f), char(0x80), char(0x80)}, 0xfffd},
    };

    for (auto c : cases) {
        text::utf8::to_utf32_iterator<char const *, char const *> it(
            c.str_, c.str_, c.str_ + sizeof(c.str_));
        EXPECT_EQ(*it, c.utf32_);
    }
}

// Unicode 9, 3.9/D93b
// Table 3-8. Use of U+FFFD in UTF-8 Conversion
TEST(utf_8, test_0xfffd)
{
    char const bad_utf8[] = {0x61,
                             char(0xf1),
                             char(0x80),
                             char(0x80),
                             char(0xe1),
                             char(0x80),
                             char(0xc2),
                             0x62,
                             char(0x80),
                             0x63,
                             char(0x80),
                             char(0xbf),
                             0x64,
                             0};
    uint32_t const expected[] = {0x0061,
                                 0xfffd,
                                 0xfffd,
                                 0xfffd,
                                 0x0062,
                                 0xfffd,
                                 0x0063,
                                 0xfffd,
                                 0xfffd,
                                 0x0064};

    auto it =
        text::utf8::to_utf32_iterator<char const *, text::utf8::null_sentinel>(
            bad_utf8, bad_utf8, text::utf8::null_sentinel{});

    EXPECT_EQ(*it++, expected[0]);
    EXPECT_EQ(*it++, expected[1]);
    EXPECT_EQ(*it++, expected[2]);
    EXPECT_EQ(*it++, expected[3]);
    EXPECT_EQ(*it++, expected[4]);
    EXPECT_EQ(*it++, expected[5]);
    EXPECT_EQ(*it++, expected[6]);
    EXPECT_EQ(*it++, expected[7]);
    EXPECT_EQ(*it++, expected[8]);
    EXPECT_EQ(*it++, expected[9]);

    it = text::utf8::to_utf32_iterator<char const *, text::utf8::null_sentinel>(
        bad_utf8, bad_utf8 + 13, text::utf8::null_sentinel{});

    EXPECT_EQ(*--it, expected[9]);
    EXPECT_EQ(*--it, expected[8]);
    EXPECT_EQ(*--it, expected[7]);
    EXPECT_EQ(*--it, expected[6]);
    EXPECT_EQ(*--it, expected[5]);
    EXPECT_EQ(*--it, expected[4]);
    EXPECT_EQ(*--it, expected[3]);
    EXPECT_EQ(*--it, expected[2]);
    EXPECT_EQ(*--it, expected[1]);
    EXPECT_EQ(*--it, expected[0]);
}

TEST(utf_8, test_end_of_invalid_utf8)
{
    auto const none = text::utf8::detail::optional_iter<char const *>{};

    {
        char const bad_utf8[] = {0x61,
                                 char(0xf1),
                                 char(0x80),
                                 char(0x80),
                                 char(0xe1),
                                 char(0x80),
                                 char(0xc2),
                                 0x62,
                                 char(0x80),
                                 0x63,
                                 char(0x80),
                                 char(0xbf),
                                 0x64};
        // uint32_t const expected[] = {0x0061, 0xfffd, 0xfffd, 0xfffd, 0x0062,
        // 0xfffd, 0x0063, 0xfffd, 0xfffd, 0x0064};

        EXPECT_EQ(
            text::utf8::detail::end_of_invalid_utf8(bad_utf8 + 0), none);
        EXPECT_EQ(
            *text::utf8::detail::end_of_invalid_utf8(bad_utf8 + 1),
            bad_utf8 + 4);
        EXPECT_EQ(
            *text::utf8::detail::end_of_invalid_utf8(bad_utf8 + 4),
            bad_utf8 + 6);
        EXPECT_EQ(
            *text::utf8::detail::end_of_invalid_utf8(bad_utf8 + 6),
            bad_utf8 + 7);
        EXPECT_EQ(
            text::utf8::detail::end_of_invalid_utf8(bad_utf8 + 7), none);
        EXPECT_EQ(
            text::utf8::detail::end_of_invalid_utf8(bad_utf8 + 9), none);
        EXPECT_EQ(
            text::utf8::detail::end_of_invalid_utf8(bad_utf8 + 12), none);
    }
    {
        // Unicode 9, 3.9/D90-D92
        // uint32_t const utf32[] = {0x004d, 0x0430, 0x4e8c, 0x10302};
        char const utf8[] = {0x4d,
                             char(0xd0),
                             char(0xb0),
                             char(0xe4),
                             char(0xba),
                             char(0x8c),
                             char(0xf0),
                             char(0x90),
                             char(0x8c),
                             char(0x82)};

        EXPECT_EQ(text::utf8::detail::end_of_invalid_utf8(utf8 + 0), none);
        EXPECT_EQ(text::utf8::detail::end_of_invalid_utf8(utf8 + 1), none);
        EXPECT_EQ(text::utf8::detail::end_of_invalid_utf8(utf8 + 3), none);
        EXPECT_EQ(text::utf8::detail::end_of_invalid_utf8(utf8 + 6), none);
    }
}

TEST(utf_8, iterator_covnersions)
{
    uint32_t utf32[] = {0x004d, 0x0430, 0x4e8c, 0x10302};
    uint16_t utf16[] = {0x004d, 0x0430, 0x4e8c, 0xd800, 0xdf02};
    char utf8[] = {0x4d,
                   char(0xd0),
                   char(0xb0),
                   char(0xe4),
                   char(0xba),
                   char(0x8c),
                   char(0xf0),
                   char(0x90),
                   char(0x8c),
                   char(0x82),
                   0};

    {
        text::utf8::to_utf32_iterator<char *, text::utf8::null_sentinel> const it =
            text::utf8::to_utf32_iterator<char *, text::utf8::null_sentinel>(
                utf8, utf8, text::utf8::null_sentinel{});

        text::utf8::to_utf32_iterator<
            char const *,
            text::utf8::null_sentinel> const it_const = it;

        EXPECT_EQ(it_const, it);
    }

    {
        text::utf8::from_utf32_iterator<uint32_t *> const it =
            text::utf8::from_utf32_iterator<uint32_t *>(
                utf32, utf32, utf32 + 4);

        text::utf8::from_utf32_iterator<uint32_t const *> const it_const = it;

        EXPECT_EQ(it_const, it);
    }

    {
        text::utf8::to_utf16_iterator<char *> it =
            text::utf8::to_utf16_iterator<char *>(
                utf8, utf8, utf8 + sizeof(utf8));

        text::utf8::to_utf16_iterator<char const *> it_const = it;

        EXPECT_EQ(it_const, it);
    }
    {
        text::utf8::from_utf16_iterator<uint16_t *> const it =
            text::utf8::from_utf16_iterator<uint16_t *>(
                utf16, utf16, utf16 + 5);

        text::utf8::from_utf16_iterator<uint16_t const *> const it_const = it;

        EXPECT_EQ(it_const, it);
    }
}

TEST(utf_8, make_range)
{
    // Unicode 9, 3.9/D90-D92
    std::array<uint32_t, 4> const utf32 = {{0x004d, 0x0430, 0x4e8c, 0x10302}};
    std::array<uint16_t, 5> const utf16 = {
        {0x004d, 0x0430, 0x4e8c, 0xd800, 0xdf02}};
    std::array<char, 10> const utf8 = {{
        0x4d,
        char(0xd0),
        char(0xb0),
        char(0xe4),
        char(0xba),
        char(0x8c),
        char(0xf0),
        char(0x90),
        char(0x8c),
        char(0x82),
    }};

    {
        int i = 0;
        for (auto cp : text::make_to_utf32_range(utf8)) {
            EXPECT_EQ(cp, utf32[i]) << "i=" << i;
            ++i;
        }
    }

    {
        int i = 0;
        for (auto cp : text::make_from_utf32_range(utf32)) {
            EXPECT_EQ(cp, utf8[i]) << "i=" << i;
            ++i;
        }
    }

    {
        int i = 0;
        for (auto cp : text::make_to_utf16_range(utf8)) {
            EXPECT_EQ(cp, utf16[i]) << "i=" << i;
            ++i;
        }
    }

    {
        int i = 0;
        for (auto cp : text::make_from_utf16_range(utf16)) {
            EXPECT_EQ(cp, utf8[i]) << "i=" << i;
            ++i;
        }
    }
}

max_stars_repo_name: jan-moeller/text

max_issues_repo_name: jan-moeller/text

max_forks_repo_name: jan-moeller/text


text:
/*
Copyright 2012, 2014, 2015 Rogier van Dalen.

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.
*/

/** \file
Define an exception class for parses.
*/

#ifndef PARSE_LL_BASE_ERROR_HPP_INCLUDED
#define PARSE_LL_BASE_ERROR_HPP_INCLUDED

#include <stdexcept>
#include <string>
#include <boost/exception/all.hpp>

namespace parse_ll {

/**
Exception class that represents a parse error.
*/
struct error
: public virtual boost::exception, public virtual std::exception {};

typedef boost::error_info <struct parse_error_tag, std::string>
    error_description;

template <class Input> struct error_position_tag;

template <class Input> struct error_position
{ typedef boost::error_info <error_position_tag <Input>, Input> type; };

/**
Return a marker of the position where a parser error occurred.
\todo For some types of errors, the actual range should possibly not be kept:
it possibly keeps too much information, yet does not naturally allow one to
show the text of the whole line where the error occurred.
\todo Provide a facility that outputs something helpful to a stream.
*/
template <class Input> inline
    typename error_position <Input>::type error_at (Input position)
{ return typename error_position <Input>::type (std::move (position)); }

} // namespace parse_ll

#endif  // PARSE_LL_BASE_ERROR_HPP_INCLUDED

ext: hpp


text:
#ifndef _GREGORIAN__CONVERSION_HPP___
#define _GREGORIAN__CONVERSION_HPP___

/* Copyright (c) 2004-2005 CrystalClear Software, Inc.
 * Use, modification and distribution is subject to the
 * Boost Software License, Version 1.0. (See accompanying
 * file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
 * Author: Jeff Garland, Bart Garst
 * $Date: 2008-11-12 14:37:53 -0500 (Wed, 12 Nov 2008) $
 */

#include <string>
#include <stdexcept>
#include <boost/throw_exception.hpp>
#include <boost/date_time/gregorian/gregorian_types.hpp>
#include <boost/date_time/c_time.hpp>
#if defined(USE_DATE_TIME_PRE_1_33_FACET_IO)
#  if defined(BOOST_DATE_TIME_INCLUDE_LIMITED_HEADERS)
#    include <boost/date_time/gregorian/formatters_limited.hpp>
#  else
#    include <boost/date_time/gregorian/formatters.hpp>
#  endif // BOOST_DATE_TIME_INCLUDE_LIMITED_HEADERS
#else
#  include <sstream>
#  include <boost/date_time/gregorian/gregorian_io.hpp>
#endif // USE_DATE_TIME_PRE_1_33_FACET_IO

namespace boost {

namespace gregorian {

  //! Converts a date to a tm struct. Throws out_of_range exception if date is a special value
  inline
  std::tm to_tm(const date& d)
  {
    if(d.is_pos_infinity() || d.is_neg_infinity() || d.is_not_a_date()){
      std::string s = "tm unable to handle date value of ";
#if defined(USE_DATE_TIME_PRE_1_33_FACET_IO)
      s += to_simple_string(d);
#else
      std::ostringstream ss;
      ss << d;
      s += ss.str();
#endif // USE_DATE_TIME_PRE_1_33_FACET_IO
      boost::throw_exception(std::out_of_range(s));
    }
    std::tm datetm;
    boost::gregorian::date::ymd_type ymd = d.year_month_day();
    datetm.tm_year = ymd.year-1900;
    datetm.tm_mon = ymd.month-1;
    datetm.tm_mday = ymd.day;
    datetm.tm_wday = d.day_of_week();
    datetm.tm_yday = d.day_of_year()-1;
    datetm.tm_hour = datetm.tm_min = datetm.tm_sec = 0;
    datetm.tm_isdst = -1; // negative because not enough info to set tm_isdst
    return datetm;
  }

  //! Converts a tm structure into a date dropping the any time values.
  inline
  date date_from_tm(const std::tm& datetm)
  {
    return date(static_cast<unsigned short>(datetm.tm_year+1900),
                static_cast<unsigned short>(datetm.tm_mon+1),
                static_cast<unsigned short>(datetm.tm_mday));
  }

} } //namespace boost::gregorian

#endif


text:
#include <cassert>      // assert
#include <iterator>     // iterator
#include <utility>      // swap
#include <Eigen/Dense>

#include "partition.hpp"

template <class uint>
class PartitionList {
	private:
		class PartitionIterator : std::iterator< std::bidirectional_iterator_tag, Partition<uint> > {
			private:
				Partition<uint>* current;
				bool invalid;

			public:
				PartitionIterator() : current(nullptr), invalid(true) {}
				PartitionIterator(const PartitionIterator& other) : invalid(other.invalid) {
					current = new Partition<uint>(*other);
				}
				PartitionIterator(const Partition<uint>& other) : invalid(false) {
					current = new Partition<uint>(other);
				}
				~PartitionIterator() {
					if (current != nullptr)
						delete current;
				}

				void swap(PartitionIterator& other) noexcept {
					std::swap(invalid, other.invalid);
					std::swap(current, other.current);
				}

				PartitionIterator& operator++() {
					assert(current != nullptr);
					assert(!invalid);
					if (!current->next())
						invalid = true;

					return *this;
				}
				PartitionIterator& operator--() {
					assert(current != nullptr);
					assert(!current->isMin());
					if (invalid) {
						current->setMax();
						invalid = false;
					}
					else
						current->prev();
					return *this;
				}

				PartitionIterator operator++(int) {
					PartitionIterator response(*this);
					this->operator++();
					return response;
				}
				PartitionIterator operator--(int) {
					PartitionIterator response(*this);
					this->operator--;
					return response;
				}

				bool operator==(const PartitionIterator& rhs) const {
					return (invalid && rhs.invalid) || (!(invalid || rhs.invalid) && *current == *(rhs.current));
				}
				bool operator!=(const PartitionIterator& rhs) const {
					return (invalid != rhs.invalid) || (!(invalid || rhs.invalid) && *current != *(rhs.current));
				}
				bool operator<(const PartitionIterator& rhs) const {
					if (invalid) {
						return false;
					}
					if (rhs.invalid) {
						return true;
					}
					return *current < *(rhs.current);
				}
				bool operator<=(const PartitionIterator& rhs) const {
					if (invalid) {
						return rhs.invalid;
					}
					if (rhs.invalid) {
						return true;
					}
					return *current <= *(rhs.current);
				}
				bool operator>(const PartitionIterator& rhs) const {
					return !(*this <= rhs);
				}
				bool operator>=(const PartitionIterator& rhs) const {
					return !(*this < rhs);
				}

				const Partition<uint>& operator*() const {
					return *current;
				}
				const Partition<uint>& operator->() const {
					return *current;
				}

		};

		PartitionIterator *m_first, *m_last;

		Eigen::Array<uint, Eigen::Dynamic, Eigen::Dynamic> sizes;

		// helper function for finding the partition offset
		uint getIndex(const Partition<uint>& n) const {
			uint index = 0;

			uint k = n.getLength();
			uint m = n.getMass();

			for (uint i = k; i > 2; i--) {
				for (uint j = 0; j < n.get(i); j++) {
					index += sizes(m - i*j, i-3);
				}
				m -= i * n.get(i);
			}
			index += n.get(2);
			return index;
		}
	public:
		typedef PartitionIterator iterator;
		typedef PartitionIterator const_iterator;

		PartitionList() : m_first(nullptr), m_last(nullptr) {}
		PartitionList(size_t len, uint mass) {
			Partition<uint> a(len, mass);
		  	m_first = new PartitionIterator(a);
			a.setMax();
			m_last = new PartitionIterator(a);
			++(*m_last);

			uint num = (uint) (len*(len+1)/2+1);
			Eigen::Array<uint, Eigen::Dynamic, 1> c;
			c = decltype(c)::Zero(num);
			sizes = decltype(sizes)::Zero(mass+1, len-1);
			sizes.row(0).setConstant(1);
			sizes.col(0) = decltype(c)::LinSpaced(mass+1,0,mass) / 2 + 1;
			c(0) = 1; c(1) = -1; c(2) = -1; c(3) = 1;

			for (size_t i = 3; i <= len; i++) {
				uint cnum = (uint) (i*(i+1)/2);
				c.segment(i, cnum+1-i) -= c.head(cnum+1-i).eval();

				if (cnum > mass) {
					for (uint j = 1; j <= mass; j++)
						sizes(j, i-2) = -c.segment(1, j).reverse().matrix().dot(sizes.col(i-2).head(j).matrix());
				}
				else {
					for (uint j = 1; j < cnum; j++)
						sizes(j, i-2) = -c.segment(1, j).reverse().matrix().dot(sizes.col(i-2).head(j).matrix());
					for (uint j = cnum; j <= mass; j++)
						sizes(j, i-2) = -c.segment(1, cnum).reverse().matrix().dot(sizes.col(i-2).segment(j-cnum,cnum).matrix());
				}
			}

		}
		~PartitionList() {
			if (m_first != nullptr)
				delete m_first;
			if (m_last != nullptr)
				delete m_last;
		}

		uint indexOf(const Partition<uint>& n) const {
			uint index = 0;
			uint m = n.getMass();
			for (uint i = n.getLength(); i > 2; i--) {
				for (uint j = 0; j < n.get(i); j++) {
					index += sizes(m - i*j, i-3);
				}
				m -= i * n.get(i);
			}
			index += n.get(2);
			return index;
		}
		uint size() const {
			uint mass = (**m_first).getMass();
			uint len = (**m_first).getLength();
			return sizes(mass, len-2);
		}

		const_iterator begin() const {
			return iterator(*m_first);
		}
		const_iterator end() const {
			return iterator(*m_last);
		}
		const_iterator cbegin() const {
			return const_iterator(*m_first);
		}
		const_iterator cend() const {
			return const_iterator(*m_last);
		}
};

max_stars_repo_name: jasondark/dissertation

max_issues_repo_name: jasondark/dissertation

max_forks_repo_name: jasondark/dissertation


text: #include <boost/log/utility/unique_identifier_name.hpp>

max_stars_repo_name: miathedev/BoostForArduino

max_issues_repo_name: miathedev/BoostForArduino

max_forks_repo_name: miathedev/BoostForArduino


text:
/*
 Copyright (C) 2016 Quaternion Risk Management Ltd
 All rights reserved.

 This file is part of ORE, a free-software/open-source library
 for transparent pricing and risk analysis - http://opensourcerisk.org

 ORE is free software: you can redistribute it and/or modify it
 under the terms of the Modified BSD License.  You should have received a
 copy of the license along with this program.
 The license is also available online at <http://opensourcerisk.org>

 This program is distributed on the basis that it will form a useful
 contribution to risk analytics and model standardisation, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 FITNESS FOR A PARTICULAR PURPOSE. See the license for more details.
*/

#include "swaptionmarketdata.hpp"
#include "toplevelfixture.hpp"
#include "yieldcurvemarketdata.hpp"
#include <boost/test/unit_test.hpp>

#include <qle/termstructures/swaptionvolatilityconverter.hpp>
#include <qle/termstructures/swaptionvolcube2.hpp>

#include <ql/indexes/swap/euriborswap.hpp>
#include <ql/pricingengines/blackformula.hpp>

#include <boost/assign/list_of.hpp>

using namespace QuantExt;
using namespace QuantLib;
using namespace boost::unit_test_framework;
using namespace boost::assign;

namespace {
// Variables to be used in the test
struct CommonVars {
    // Constructor
    CommonVars() : referenceDate(5, Feb, 2016) {
        // Reference date
        Settings::instance().evaluationDate() = referenceDate;

        // Link ibor index to correct forward curve
        boost::shared_ptr<IborIndex> iborIndex = conventions.floatIndex->clone(yieldCurves.forward6M);

        // Create underlying swap conventions
        swapConventions = boost::make_shared<SwapConventions>(conventions.settlementDays, conventions.fixedTenor,
                                                              conventions.fixedCalendar, conventions.fixedConvention,
                                                              conventions.fixedDayCounter, iborIndex);

        // Set up the various swaption matrices
        atmNormalVolMatrix = boost::make_shared<SwaptionVolatilityMatrix>(
            referenceDate, conventions.fixedCalendar, conventions.fixedConvention, atmVols.optionTenors,
            atmVols.swapTenors, atmVols.nVols, Actual365Fixed(), true, Normal);

        atmLogNormalVolMatrix = boost::make_shared<SwaptionVolatilityMatrix>(
            referenceDate, conventions.fixedCalendar, conventions.fixedConvention, atmVols.optionTenors,
            atmVols.swapTenors, atmVols.lnVols, Actual365Fixed(), true, ShiftedLognormal);

        // boost::make_shared can only handle 9 parameters
        atmShiftedLogNormalVolMatrix_1 = boost::shared_ptr<SwaptionVolatilityMatrix>(new SwaptionVolatilityMatrix(
            referenceDate, conventions.fixedCalendar, conventions.fixedConvention, atmVols.optionTenors,
            atmVols.swapTenors, atmVols.slnVols_1, Actual365Fixed(), true, ShiftedLognormal, atmVols.shifts_1));

        atmShiftedLogNormalVolMatrix_2 = boost::shared_ptr<SwaptionVolatilityMatrix>(new SwaptionVolatilityMatrix(
            referenceDate, conventions.fixedCalendar, conventions.fixedConvention, atmVols.optionTenors,
            atmVols.swapTenors, atmVols.slnVols_2, Actual365Fixed(), true, ShiftedLognormal, atmVols.shifts_2));
    }

    // Members
    Date referenceDate;
    SwaptionConventionsEUR conventions;
    SwaptionVolatilityEUR atmVols;
    YieldCurveEUR yieldCurves;
    boost::shared_ptr<SwapConventions> swapConventions;
    boost::shared_ptr<SwaptionVolatilityStructure> atmNormalVolMatrix;
    boost::shared_ptr<SwaptionVolatilityStructure> atmLogNormalVolMatrix;
    boost::shared_ptr<SwaptionVolatilityStructure> atmShiftedLogNormalVolMatrix_1;
    boost::shared_ptr<SwaptionVolatilityStructure> atmShiftedLogNormalVolMatrix_2;
    SavedSettings backup;
};
} // namespace

BOOST_FIXTURE_TEST_SUITE(QuantExtTestSuite, qle::test::TopLevelFixture)

BOOST_AUTO_TEST_SUITE(SwaptionVolatilityConverterTest)

BOOST_AUTO_TEST_CASE(testNormalToLognormal) {
    BOOST_TEST_MESSAGE("Testing conversion of swaption vols from normal to lognormal...");

    CommonVars vars;

    // Tolerance used in boost check
    Real tolerance = 0.00001;

    // Set up the converter (Normal -> Lognormal with no shifts)
    SwaptionVolatilityConverter converter(vars.referenceDate, vars.atmNormalVolMatrix, vars.yieldCurves.discountEonia,
                                          vars.yieldCurves.discountEonia, vars.swapConventions, vars.swapConventions,
                                          1 * Years, 30 * Years, ShiftedLognormal);

    // Get back converted volatility structure and test result on pillar points
    boost::shared_ptr<SwaptionVolatilityStructure> convertedsvs = converter.convert();
    Volatility targetVol = 0.0;
    Volatility outVol = 0.0;
    Real dummyStrike = 0.0;
    for (Size i = 0; i < vars.atmVols.optionTenors.size(); ++i) {
        for (Size j = 0; j < vars.atmVols.swapTenors.size(); ++j) {
            Period optionTenor = vars.atmVols.optionTenors[i];
            Period swapTenor = vars.atmVols.swapTenors[j];
            targetVol = vars.atmVols.lnVols[i][j];
            outVol = convertedsvs->volatility(optionTenor, swapTenor, dummyStrike);
            BOOST_CHECK_SMALL(outVol - targetVol, tolerance);
        }
    }
}

BOOST_AUTO_TEST_CASE(testLognormalToNormal) {
    BOOST_TEST_MESSAGE("Testing conversion of swaption vols from lognormal to normal...");

    CommonVars vars;

    // Tolerance used in boost check
    Real tolerance = 0.00001;

    // Set up the converter (Lognormal with no shifts -> Normal)
    SwaptionVolatilityConverter converter(vars.referenceDate, vars.atmLogNormalVolMatrix,
                                          vars.yieldCurves.discountEonia, vars.yieldCurves.discountEonia,
                                          vars.swapConventions, vars.swapConventions, 1 * Years, 30 * Years, Normal);

    // Get back converted volatility structure and test result on pillar points
    boost::shared_ptr<SwaptionVolatilityStructure> convertedsvs = converter.convert();
    Volatility targetVol = 0.0;
    Volatility outVol = 0.0;
    Real dummyStrike = 0.0;
    for (Size i = 0; i < vars.atmVols.optionTenors.size(); ++i) {
        for (Size j = 0; j < vars.atmVols.swapTenors.size(); ++j) {
            Period optionTenor = vars.atmVols.optionTenors[i];
            Period swapTenor = vars.atmVols.swapTenors[j];
            targetVol = vars.atmVols.nVols[i][j];
            outVol = convertedsvs->volatility(optionTenor, swapTenor, dummyStrike);
            BOOST_CHECK_SMALL(outVol - targetVol, tolerance);
        }
    }
}

BOOST_AUTO_TEST_CASE(testNormalToShiftedLognormal) {
    BOOST_TEST_MESSAGE("Testing conversion of swaption vols from normal to shifted lognormal...");

    CommonVars vars;

    // Tolerance used in boost check
    Real tolerance = 0.00001;

    // Set up the converter (Normal -> Shifted Lognormal with shift set 1)
    SwaptionVolatilityConverter converter(vars.referenceDate, vars.atmNormalVolMatrix, vars.yieldCurves.discountEonia,
                                          vars.yieldCurves.discountEonia, vars.swapConventions, vars.swapConventions,
                                          1 * Years, 30 * Years, ShiftedLognormal, vars.atmVols.shifts_1);

    // Get back converted volatility structure and test result on pillar points
    boost::shared_ptr<SwaptionVolatilityStructure> convertedsvs = converter.convert();
    Volatility targetVol = 0.0;
    Volatility outVol = 0.0;
    Real dummyStrike = 0.0;
    for (Size i = 0; i < vars.atmVols.optionTenors.size(); ++i) {
        for (Size j = 0; j < vars.atmVols.swapTenors.size(); ++j) {
            Period optionTenor = vars.atmVols.optionTenors[i];
            Period swapTenor = vars.atmVols.swapTenors[j];
            targetVol = vars.atmVols.slnVols_1[i][j];
            outVol = convertedsvs->volatility(optionTenor, swapTenor, dummyStrike);
            BOOST_CHECK_SMALL(outVol - targetVol, tolerance);
        }
    }
}

BOOST_AUTO_TEST_CASE(testShiftedLognormalToShiftedLognormal) {
    BOOST_TEST_MESSAGE("Testing conversion of swaption vols from shifted lognormal to shifted lognormal...");

    CommonVars vars;

    // Tolerance used in boost check
    Real tolerance = 0.00001;

    // Set up the converter (Normal -> Shifted Lognormal with shift set 1)
    SwaptionVolatilityConverter converter(vars.referenceDate, vars.atmShiftedLogNormalVolMatrix_1,
                                          vars.yieldCurves.discountEonia, vars.yieldCurves.discountEonia,
                                          vars.swapConventions, vars.swapConventions, 1 * Years, 30 * Years,
                                          ShiftedLognormal, vars.atmVols.shifts_2);

    // Get back converted volatility structure and test result on pillar points
    boost::shared_ptr<SwaptionVolatilityStructure> convertedsvs = converter.convert();
    Volatility targetVol = 0.0;
    Volatility outVol = 0.0;
    Real dummyStrike = 0.0;
    for (Size i = 0; i < vars.atmVols.optionTenors.size(); ++i) {
        for (Size j = 0; j < vars.atmVols.swapTenors.size(); ++j) {
            Period optionTenor = vars.atmVols.optionTenors[i];
            Period swapTenor = vars.atmVols.swapTenors[j];
            targetVol = vars.atmVols.slnVols_2[i][j];
            outVol = convertedsvs->volatility(optionTenor, swapTenor, dummyStrike);
            BOOST_CHECK_SMALL(outVol - targetVol, tolerance);
        }
    }
}

BOOST_AUTO_TEST_CASE(testShiftedLognormalToNormal) {
    BOOST_TEST_MESSAGE("Testing conversion of swaption vols from shifted lognormal to normal...");

    CommonVars vars;

    // Tolerance used in boost check
    Real tolerance = 0.00001;

    // Set up the converter (Shifted Lognormal with shift set 2 -> Normal)
    SwaptionVolatilityConverter converter(vars.referenceDate, vars.atmShiftedLogNormalVolMatrix_2,
                                          vars.yieldCurves.discountEonia, vars.yieldCurves.discountEonia,
                                          vars.swapConventions, vars.swapConventions, 1 * Years, 30 * Years, Normal);

    // Get back converted volatility structure and test result on pillar points
    boost::shared_ptr<SwaptionVolatilityStructure> convertedsvs = converter.convert();
    Volatility targetVol = 0.0;
    Volatility outVol = 0.0;
    Real dummyStrike = 0.0;
    for (Size i = 0; i < vars.atmVols.optionTenors.size(); ++i) {
        for (Size j = 0; j < vars.atmVols.swapTenors.size(); ++j) {
            Period optionTenor = vars.atmVols.optionTenors[i];
            Period swapTenor = vars.atmVols.swapTenors[j];
            targetVol = vars.atmVols.nVols[i][j];
            outVol = convertedsvs->volatility(optionTenor, swapTenor, dummyStrike);
            BOOST_CHECK_SMALL(outVol - targetVol, tolerance);
        }
    }
}

BOOST_AUTO_TEST_CASE(testFailureImplyingVol) {
    BOOST_TEST_MESSAGE("Testing failure to imply lognormal vol from normal vol...");

    CommonVars vars;

    // Normal volatility matrix where we cannot imply lognormal vol at 3M x 1Y point
    vector<Period> optionTenors = list_of(Period(3, Months))(Period(1, Years));
    vector<Period> swapTenors = list_of(Period(1, Years))(Period(5, Years));
    Matrix normalVols(2, 2);
    normalVols[0][0] = 0.003340;
    normalVols[0][1] = 0.004973;
    normalVols[1][0] = 0.003543;
    normalVols[1][1] = 0.005270;

    boost::shared_ptr<SwaptionVolatilityStructure> volMatrix = boost::make_shared<SwaptionVolatilityMatrix>(
        vars.referenceDate, vars.conventions.fixedCalendar, vars.conventions.fixedConvention, optionTenors, swapTenors,
        normalVols, Actual365Fixed(), true, Normal);

    // Set up the converter (Normal -> Lognormal)
    SwaptionVolatilityConverter converter(vars.referenceDate, volMatrix, vars.yieldCurves.discountEonia,
                                          vars.yieldCurves.discountEonia, vars.swapConventions, vars.swapConventions,
                                          1 * Years, 30 * Years, ShiftedLognormal);

    // We expect the conversion to fail
    BOOST_CHECK_THROW(converter.convert(), QuantLib::Error);
}

BOOST_AUTO_TEST_CASE(testNormalShiftsIgnored) {
    BOOST_TEST_MESSAGE("Testing shifts supplied to normal converter ignored...");

    CommonVars vars;

    // Tolerance used in boost check
    Real tolerance = 0.00001;

    // Set up the converter (Lognormal with no shifts -> Normal)
    // We supply target shifts but they are ignored since target type is Normal
    SwaptionVolatilityConverter converter(
        vars.referenceDate, vars.atmLogNormalVolMatrix, vars.yieldCurves.discountEonia, vars.yieldCurves.discountEonia,
        vars.swapConventions, vars.swapConventions, 1 * Years, 30 * Years, Normal, vars.atmVols.shifts_1);

    // Get back converted volatility structure and test result on pillar points
    boost::shared_ptr<SwaptionVolatilityStructure> convertedsvs = converter.convert();
    Volatility targetVol = 0.0;
    Volatility outVol = 0.0;
    Real dummyStrike = 0.0;
    for (Size i = 0; i < vars.atmVols.optionTenors.size(); ++i) {
        for (Size j = 0; j < vars.atmVols.swapTenors.size(); ++j) {
            Period optionTenor = vars.atmVols.optionTenors[i];
            Period swapTenor = vars.atmVols.swapTenors[j];
            targetVol = vars.atmVols.nVols[i][j];
            outVol = convertedsvs->volatility(optionTenor, swapTenor, dummyStrike);
            BOOST_CHECK_SMALL(outVol - targetVol, tolerance);
        }
    }
}

BOOST_AUTO_TEST_CASE(testConstructionFromSwapIndex) {
    BOOST_TEST_MESSAGE("Testing construction of SwaptionVolatilityConverter from SwapIndex...");

    CommonVars vars;

    // Tolerance used in boost check
    Real tolerance = 0.00001;

    // Set up a SwapIndex
    boost::shared_ptr<SwapIndex> swapIndex =
        boost::make_shared<EuriborSwapIsdaFixA>(2 * Years, vars.yieldCurves.forward6M, vars.yieldCurves.discountEonia);

    // Set up the converter using swap index (Shifted Lognormal with shift set 2 -> Normal)
    SwaptionVolatilityConverter converter(vars.referenceDate, vars.atmShiftedLogNormalVolMatrix_2, swapIndex, swapIndex,
                                          Normal);

    // Test that the results are still ok
    boost::shared_ptr<SwaptionVolatilityStructure> convertedsvs = converter.convert();
    Volatility targetVol = 0.0;
    Volatility outVol = 0.0;
    Real dummyStrike = 0.0;
    for (Size i = 0; i < vars.atmVols.optionTenors.size(); ++i) {
        for (Size j = 0; j < vars.atmVols.swapTenors.size(); ++j) {
            Period optionTenor = vars.atmVols.optionTenors[i];
            Period swapTenor = vars.atmVols.swapTenors[j];
            targetVol = vars.atmVols.nVols[i][j];
            outVol = convertedsvs->volatility(optionTenor, swapTenor, dummyStrike);
            BOOST_CHECK_SMALL(outVol - targetVol, tolerance);
        }
    }
}

BOOST_AUTO_TEST_CASE(testConstructionFromSwapIndexNoDiscount) {
    BOOST_TEST_MESSAGE("Testing construction from SwapIndex with no exogenous discount curve...");

    CommonVars vars;

    // Set up a SwapIndex
    boost::shared_ptr<SwapIndex> swapIndex =
        boost::make_shared<EuriborSwapIsdaFixA>(2 * Years, vars.yieldCurves.forward6M);

    // Set up the converter using swap index (Shifted Lognormal with shift set 2 -> Normal)
    SwaptionVolatilityConverter converter(vars.referenceDate, vars.atmShiftedLogNormalVolMatrix_2, swapIndex, swapIndex,
                                          Normal);

    // Test that calling convert() still works
    BOOST_CHECK_NO_THROW(converter.convert());
}

BOOST_AUTO_TEST_CASE(testCube) {
    BOOST_TEST_MESSAGE("Testing lognormal to normal conversion for cube...");

    CommonVars vars;

    // Set up Swap Indices
    boost::shared_ptr<SwapIndex> shortSwapIndex =
        boost::make_shared<EuriborSwapIsdaFixA>(1 * Years, vars.yieldCurves.forward3M, vars.yieldCurves.discountEonia);
    boost::shared_ptr<SwapIndex> swapIndex =
        boost::make_shared<EuriborSwapIsdaFixA>(30 * Years, vars.yieldCurves.forward6M, vars.yieldCurves.discountEonia);

    // Set up a lognormal cube
    boost::shared_ptr<SwaptionVolatilityCube> cube = boost::make_shared<QuantExt::SwaptionVolCube2>(
        Handle<SwaptionVolatilityStructure>(vars.atmLogNormalVolMatrix), vars.atmVols.optionTenors,
        vars.atmVols.swapTenors, vars.atmVols.strikeSpreads, vars.atmVols.lnVolSpreads, swapIndex, shortSwapIndex,
        false, true);

    // Convert the cube to normal
    SwaptionVolatilityConverter converter(vars.referenceDate, cube, swapIndex, shortSwapIndex, Normal);
    boost::shared_ptr<SwaptionVolatilityStructure> convertedsvs = converter.convert();

    // Price swaptions in the lognormal and normal cube and comare their premiums
    for (Size i = 0; i < vars.atmVols.optionTenors.size(); ++i) {
        for (Size j = 0; j < vars.atmVols.swapTenors.size(); ++j) {
            for (Size k = 0; k < vars.atmVols.strikeSpreads.size(); ++k) {
                Period optionTenor = vars.atmVols.optionTenors[i];
                Period swapTenor = vars.atmVols.swapTenors[j];
                Real atmStrike = cube->atmStrike(optionTenor, swapTenor);
                Real strikeSpread = vars.atmVols.strikeSpreads[k];
                Real strike = atmStrike + strikeSpread;
                if (strike > 0.0) {
                    Real inVol = cube->volatility(optionTenor, swapTenor, atmStrike + strikeSpread);
                    Real outVol = convertedsvs->volatility(optionTenor, swapTenor, atmStrike + strikeSpread);
                    Option::Type type = strikeSpread < 0.0 ? Option::Put : Option::Call;
                    Real tte = cube->optionTimes()[i];
                    Real inPrem = blackFormula(type, strike, atmStrike, inVol * std::sqrt(tte));
                    Real outPrem = bachelierBlackFormula(type, strike, atmStrike, outVol * std::sqrt(tte));
                    BOOST_CHECK_CLOSE(inPrem, outPrem, 0.01);
                }
            }
        }
    }
}

BOOST_AUTO_TEST_SUITE_END()

BOOST_AUTO_TEST_SUITE_END()

ext: cpp

max_stars_repo_name: mrslezak/Engine

max_issues_repo_name: mrslezak/Engine

max_forks_repo_name: mrslezak/Engine


text:
/* Copyright Institue of Sound and Vibration Research - All rights reserved. */

#include <librrl/audio_signal_flow.hpp>
#include <librrl/integrity_checking.hpp>

#include <libvisr/audio_input.hpp>
#include <libvisr/audio_output.hpp>
#include <libvisr/atomic_component.hpp>
#include <libvisr/composite_component.hpp>
#include <libvisr/signal_flow_context.hpp>

#include <boost/test/unit_test.hpp>

#include <ciso646>
#include <cstddef>
#include <iostream>
#include <memory>
#include <string>
#include <sstream>
#include <vector>

namespace visr
{
namespace rrl
{
namespace test
{

namespace // unnamed
{

static std::size_t const audioWidth = 4;

/**
 * Object to hold a name constructed of a string and a number
 */
struct numberedItem
{
public:
  explicit numberedItem( std::string const & base, std::size_t index)
  {
    std::stringstream res;
    res << base << "_" << index;
    mVal = res.str();
  }

  /**
   * Implicit conversion to char const *
   */
  operator char const*() const
  {
    return mVal.c_str();
  }
private:
  std::string mVal;
};

class MyAtom: public AtomicComponent
{
public:
  MyAtom( SignalFlowContext & context, char const * componentName, CompositeComponent * parent,
          std::size_t numInputs, std::size_t numOutputs)
   : AtomicComponent( context, componentName, parent )
  {
    for( std::size_t portIdx( 0 ); portIdx < numInputs; ++portIdx )
    {
      mInputs.push_back( std::unique_ptr<AudioInput>( new AudioInput( numberedItem( "in", portIdx ), *this, audioWidth ) ) );
    }
    for( std::size_t portIdx( 0 ); portIdx < numOutputs; ++portIdx )
    {
      mOutputs.push_back( std::unique_ptr<AudioOutput>( new AudioOutput( numberedItem( "out", portIdx ), *this, audioWidth ) ) );
    }
   }
  void process() override {}
private:
  std::vector< std::unique_ptr<AudioInput> > mInputs;
  std::vector<std::unique_ptr<AudioOutput> > mOutputs;

};

class MyComposite: public CompositeComponent
{
public:
  MyComposite( SignalFlowContext & context, char const * componentName, CompositeComponent * parent,
               std::size_t numInputs, std::size_t numOutputs )
    : CompositeComponent( context, componentName, parent )
    , mAtom( context, "SecondLevelAtom", this, numInputs, numOutputs )
  {
    ChannelRange const indices( 0, audioWidth );

    for( std::size_t portIdx( 0 ); portIdx < numInputs; ++portIdx )
    {
      mExtInputs.push_back( std::unique_ptr<AudioInput>( new AudioInput( numberedItem( "placeholder_in", portIdx ), *this ) ) );
      mExtInputs[portIdx]->setWidth( audioWidth );
      audioConnection( "this", numberedItem( "placeholder_in", portIdx ), indices,
                               "SecondLevelAtom", numberedItem( "in", portIdx ), indices );

    }
    for( std::size_t portIdx( 0 ); portIdx < numOutputs; ++portIdx )
    {
      mExtOutputs.push_back( std::unique_ptr<AudioOutput>( new AudioOutput( numberedItem( "placeholder_out", portIdx ), *this ) ) );
      mExtOutputs[portIdx]->setWidth( audioWidth );
      audioConnection( "SecondLevelAtom", numberedItem( "out", portIdx ), indices,
                               "this", numberedItem( "placeholder_out", portIdx ), indices );
    }
  }
private:
  MyAtom mAtom;

  std::vector< std::unique_ptr<AudioInput> > mExtInputs;
  std::vector<std::unique_ptr<AudioOutput> > mExtOutputs;
};

class MyRecursiveComposite: public CompositeComponent
{
public:
  MyRecursiveComposite( SignalFlowContext & context, char const * componentName, CompositeComponent * parent,
                        std::size_t numInputs, std::size_t numOutputs, std::size_t recursionCount, bool insertAtom )
    : CompositeComponent( context, componentName, parent )
  {
    if( (not insertAtom) and( numInputs != numOutputs ) )
    {
      throw std::invalid_argument( "If \"insertAtom\" is false, then the number of inputs must match the number of outputs." );
    }
    ChannelRange const indices( 0, audioWidth, 1 );
    std::stringstream childNameStr;
    if( (recursionCount > 0) or insertAtom )
    {
      if( recursionCount > 0 )
      {
        childNameStr << "level" << recursionCount-1 << "composite";
        mChild.reset( new MyRecursiveComposite( context, childNameStr.str().c_str(), this, numInputs, numOutputs, recursionCount - 1, insertAtom ) );
        for( std::size_t portIdx( 0 ); portIdx < numInputs; ++portIdx )
        {
          mExtInputs.push_back( std::unique_ptr<AudioInput>( new AudioInput( numberedItem( "placeholder_in", portIdx ), *this ) ) );
          mExtInputs[portIdx]->setWidth( audioWidth );
          audioConnection( "this", numberedItem( "placeholder_in", portIdx ), indices,
            childNameStr.str( ).c_str( ), numberedItem( "placeholder_in", portIdx ), indices );
        }
        for( std::size_t portIdx( 0 ); portIdx < numOutputs; ++portIdx )
        {
          mExtOutputs.push_back( std::unique_ptr<AudioOutput>( new AudioOutput( numberedItem( "placeholder_out", portIdx ), *this ) ) );
          mExtOutputs[portIdx]->setWidth( audioWidth );
          audioConnection( childNameStr.str( ).c_str( ), numberedItem( "placeholder_out", portIdx ), indices,
            "this", numberedItem( "placeholder_out", portIdx ), indices );
        }
      }
      else
      {
        childNameStr << "level" << recursionCount << "atom";
        mChild.reset( new MyAtom( context, childNameStr.str( ).c_str( ), this, numInputs, numOutputs ) );
        for( std::size_t portIdx( 0 ); portIdx < numInputs; ++portIdx )
        {
          mExtInputs.push_back( std::unique_ptr<AudioInput>( new AudioInput( numberedItem( "placeholder_in", portIdx ), *this ) ) );
          mExtInputs[portIdx]->setWidth( audioWidth );
          audioConnection( "this", numberedItem( "placeholder_in", portIdx ), indices,
            childNameStr.str( ).c_str( ), numberedItem( "in", portIdx ), indices );
        }
        for( std::size_t portIdx( 0 ); portIdx < numOutputs; ++portIdx )
        {
          mExtOutputs.push_back( std::unique_ptr<AudioOutput>( new AudioOutput( numberedItem( "placeholder_out", portIdx ), *this ) ) );
          mExtOutputs[portIdx]->setWidth( audioWidth );
          audioConnection( childNameStr.str( ).c_str(), numberedItem( "out", portIdx ), indices,
            "this", numberedItem( "placeholder_out", portIdx ), indices );
        }
      }
    }
    else // no atom at the lowest level, just connect the composite input to the output
    {
      for( std::size_t portIdx( 0 ); portIdx < numInputs; ++portIdx )
      {
        mExtInputs.push_back( std::unique_ptr<AudioInput>( new AudioInput( numberedItem( "placeholder_in", portIdx ), *this ) ) );
        mExtOutputs.push_back( std::unique_ptr<AudioOutput>( new AudioOutput( numberedItem( "placeholder_out", portIdx ), *this ) ) );
        mExtInputs[portIdx]->setWidth( audioWidth );
        mExtOutputs[portIdx]->setWidth( audioWidth );
        audioConnection( "this", numberedItem( "placeholder_in", portIdx ), indices,
          "this", numberedItem( "placeholder_out", portIdx ), indices );
      }

    }
    }
private:
  std::unique_ptr<Component> mChild;

  std::vector< std::unique_ptr<AudioInput> > mExtInputs;
  std::vector<std::unique_ptr<AudioOutput> > mExtOutputs;
};

class MyTopLevel: public CompositeComponent
{
public:
  MyTopLevel( SignalFlowContext & context, char const * componentName, CompositeComponent * parent,
              std::size_t numInputs, std::size_t numOutputs )
   : CompositeComponent( context, componentName, parent )
   , mComposite1( context, "FirstLevelComposite", this, numInputs, numOutputs )
   , mAtomTopLevel( context, "FirstLevelAtom", this, numOutputs, numOutputs )
  {
     ChannelRange const indices( 0, audioWidth, 1 );

     for( std::size_t portIdx( 0 ); portIdx < numInputs; ++portIdx )
     {
       mExtInputs.push_back( std::unique_ptr<AudioInput>( new AudioInput( numberedItem( "ext_in", portIdx ), *this ) ) );
       mExtInputs[portIdx]->setWidth( audioWidth );
       audioConnection( "this", numberedItem( "ext_in", portIdx ), indices,
         "FirstLevelComposite", numberedItem( "placeholder_in", portIdx ), indices );

     }
     for( std::size_t portIdx( 0 ); portIdx < numOutputs; ++portIdx )
     {
       mExtOutputs.push_back( std::unique_ptr<AudioOutput>( new AudioOutput( numberedItem( "ext_out", portIdx ), *this ) ) );
       mExtOutputs[portIdx]->setWidth( audioWidth );
       audioConnection( "FirstLevelComposite", numberedItem( "placeholder_out", portIdx ), indices,
         "FirstLevelAtom", numberedItem( "in", portIdx ), indices );
       audioConnection( "FirstLevelAtom", numberedItem( "out", portIdx ), indices,
         "this", numberedItem( "ext_out", portIdx ), indices );
     }
  }
private:
  MyComposite mComposite1;
  MyAtom mAtomTopLevel;

  std::vector< std::unique_ptr<AudioInput> > mExtInputs;
  std::vector<std::unique_ptr<AudioOutput> > mExtOutputs;
};

class MyTopLevelRecursive: public CompositeComponent
{
public:
  MyTopLevelRecursive( SignalFlowContext & context, char const * componentName, CompositeComponent * parent,
    std::size_t numInputs, std::size_t numOutputs, std::size_t recursionLevels, bool insertAtom )
    : CompositeComponent( context, componentName, parent )
    , mComposite( context, "FirstLevelComposite", this, numInputs, numOutputs, recursionLevels, insertAtom )
  {
      ChannelRange const indices( 0, audioWidth );

      for( std::size_t portIdx( 0 ); portIdx < numInputs; ++portIdx )
      {
        mExtInputs.push_back( std::unique_ptr<AudioInput>( new AudioInput( numberedItem( "ext_in", portIdx ), *this ) ) );
        mExtInputs[portIdx]->setWidth( audioWidth );
        audioConnection( "this", numberedItem( "ext_in", portIdx ), indices,
          "FirstLevelComposite", numberedItem( "placeholder_in", portIdx ), indices );

      }
      for( std::size_t portIdx( 0 ); portIdx < numOutputs; ++portIdx )
      {
        mExtOutputs.push_back( std::unique_ptr<AudioOutput>( new AudioOutput( numberedItem( "ext_out", portIdx ), *this ) ) );
        mExtOutputs[portIdx]->setWidth( audioWidth );
        audioConnection( "FirstLevelComposite", numberedItem( "placeholder_out", portIdx ), indices,
          "this", numberedItem( "ext_out", portIdx ), indices );
      }
    }
private:
  MyRecursiveComposite mComposite;

  std::vector< std::unique_ptr<AudioInput> > mExtInputs;
  std::vector<std::unique_ptr<AudioOutput> > mExtOutputs;
};

} // namespace unnamed

BOOST_AUTO_TEST_CASE( CheckAtomicComponent )
{
  SignalFlowContext context( 128, 48000 );

  std::size_t numInputs = 2;
  std::size_t numOutputs = 4;

  MyAtom atomicComp( context, "", nullptr, numInputs, numOutputs );

  std::stringstream msg;
  bool const res = checkConnectionIntegrity( atomicComp, true, msg );
  BOOST_CHECK( res and msg.str().empty() );

  rrl::AudioSignalFlow flow( atomicComp );

  // Perform basic tests of the external I/O interface
  BOOST_CHECK( flow.numberOfAudioCapturePorts() == numInputs );
  BOOST_CHECK( flow.numberOfAudioPlaybackPorts() == numOutputs );
  BOOST_CHECK( flow.numberOfCaptureChannels() == audioWidth * numInputs );
  BOOST_CHECK( flow.numberOfPlaybackChannels() == audioWidth * numOutputs );
}

BOOST_AUTO_TEST_CASE( CheckCompositeComponent )
{
  SignalFlowContext context( 128, 48000 );

  MyComposite composite( context, "top", nullptr, 2, 3 );

  std::stringstream msg;
  bool const res = checkConnectionIntegrity( composite, true, msg );
  BOOST_CHECK( res and msg.str().empty() );
  if( not res )
  {
    std::cout << "Error messages:\n" << msg.str() << std::endl;
  }

  rrl::AudioSignalFlow flow( composite );

  // Perform basic tests of the external I/O interface
}

BOOST_AUTO_TEST_CASE( CheckTwoLevelCompositeComponent )
{
  SignalFlowContext context( 1024, 48000 );

  MyTopLevel composite( context, "", nullptr, 1, 1 );

  std::stringstream msg;
  bool const res = checkConnectionIntegrity( composite, true, msg );
  if( not res )
  {
    std::cout << "Connection check failed, message: " << msg.str() << std::endl;
  }
  BOOST_CHECK( res and msg.str().empty() );

  BOOST_CHECK_NO_THROW( rrl::AudioSignalFlow flow( composite ) );

  // Perform basic tests of the external I/O interface
}

/**
 * Check the instantiation of a recursive hierachical signal flow that hast a composite component at the lowest level which
 * interconnect the input to the output. The flattening algorithms results in a direct interconnection of the top-level capture
 * to the top-level playback port.
 */
BOOST_AUTO_TEST_CASE( CheckRecursiveCompositeComponentNoAtom )
{
  SignalFlowContext context( 1024, 48000 );

  std::size_t const recursionLimit = 1;
  bool const insertAtom = false;

  MyTopLevelRecursive composite( context, "", nullptr, 1, 1, recursionLimit, insertAtom );

  std::stringstream msg;
  bool const res = checkConnectionIntegrity( composite, true, msg );
  BOOST_CHECK( res and msg.str().empty() );

  rrl::AudioSignalFlow flow( composite );

  // Perform basic tests of the external I/O interface
  BOOST_CHECK( flow.numberOfAudioCapturePorts() == 1 );

}

/**
 * Check the instantiation of a recursive hierachical signal flow that instantiates a single component
 * at the lowest level and interconnects the inputs and outputs through all composite levels.
 */
BOOST_AUTO_TEST_CASE( CheckRecursiveCompositeComponent )
{
  SignalFlowContext context( 1024, 48000 );

  std::size_t const recursionLimit = 3;
  bool const insertAtom = true;

  MyTopLevelRecursive composite( context, "", nullptr, 3, 4, recursionLimit, insertAtom );

  rrl::AudioSignalFlow flow( composite );

  // Perform basic tests of the external I/O interface
}

} // namespace test
} // namespace rrl
} // namespace visr


text:
/*
 * Sarus
 *
 * Copyright (c) 2018-2020, ETH Zurich. All rights reserved.
 *
 * Please, refer to the LICENSE file in the root directory.
 * SPDX-License-Identifier: BSD-3-Clause
 *
 */

#ifndef sarus_hooks_ssh_SshHook_hpp
#define sarus_hooks_ssh_SshHook_hpp

#include <tuple>
#include <memory>
#include <unordered_set>
#include <sys/types.h>
#include <boost/filesystem.hpp>
#include <boost/format.hpp>

#include <common/Error.hpp>
#include <common/Logger.hpp>

namespace sarus {
namespace hooks {
namespace ssh {

class SshHook {
public:
    void generateSshKeys(bool overwriteSshKeysIfExist);
    void checkUserHasSshKeys();
    void startSshd();

private:
    void parseConfigJSONOfBundle();
    bool userHasSshKeys() const;
    boost::filesystem::path getSshKeysDir() const;
    void sshKeygen(const boost::filesystem::path& outputFile) const;
    void checkThatOpenSshIsUntamperable() const;
    void copyKeysIntoBundle() const;
    void bindMountSshBinary() const;
    void patchPasswdIfNecessary() const;
    void startSshdInContainer() const;
    void log(const boost::format& message, sarus::common::LogLevel level) const;
    void log(const std::string& message, sarus::common::LogLevel level) const;

private:
    bool isHookEnabled = false;
    boost::filesystem::path sshKeysDir;
    boost::filesystem::path opensshDirInHost;
    boost::filesystem::path opensshDirInBundle;
    boost::filesystem::path bundleDir;
    boost::filesystem::path rootfsDir;
    pid_t pidOfContainer;
    uid_t uidOfUser;
    gid_t gidOfUser;
};

}}} // namespace

#endif

max_stars_repo_name: haampie/sarus

max_issues_repo_name: haampie/sarus

max_forks_repo_name: haampie/sarus


text:
#include <atomic>
#include <mutex>
#include <condition_variable>
#include <vector>
#include <functional>
#include <iostream>
#include <thread>

#include <boost/timer/timer.hpp>

#include "GarbageCollector.h"
#include "CollectedHeap.h"
#include "BlockingQueue.h"
#include "DataTypes/Ops/Ops.h"

namespace FPTL
{
	namespace Runtime
	{
		typedef std::vector<const DataValue *> MarkList;

		ObjectMarker::~ObjectMarker() = default;

		//-------------------------------------------------------------------------------
		class RootMarker : public ObjectMarker
		{
		public:
			explicit RootMarker(const Collectable::Age maxAge)
				: mMaxAge(maxAge)
			{}

			bool markAlive(Collectable * object, size_t size) override
			{
				if (ObjectMarker::checkAge(object, mMaxAge))
				{
					// Т.к. корни помечаются из потоков мутатора, то в этом методе
					// мы не маркируем объекты, а лишь заносим их в список для
					// дальнейшей маркировки, чтобы избежать гонки со сборщиком.
					mRoots.emplace_back(object, size);
					return true;
				}

				return false;
			}

			void addChild(const DataValue * child) override
			{
				mMarkStack.push_back(child);
			}

			std::vector<std::pair<Collectable *, size_t>> mRoots;
			MarkList mMarkStack;
			Collectable::Age mMaxAge;
		};

		//-------------------------------------------------------------------------------
		class HeapMarker : public ObjectMarker
		{
		public:
			HeapMarker()
				: mAliveSize(0), mMaxAge()
			{
			}

			HeapMarker(RootMarker & rootMarker, const size_t aliveSize)
				: mAliveSize(aliveSize),
				mMaxAge(rootMarker.mMaxAge)
			{
				mMarkStack.swap(rootMarker.mMarkStack);
			}

			bool markAlive(Collectable * object, const size_t size) override
			{
				if (!object->isMarked() && ObjectMarker::checkAge(object, mMaxAge))
				{
					ObjectMarker::setMarked(object, 1);
					mAliveSize += size;
					return true;
				}

				return false;
			}

			void addChild(const DataValue * child) override
			{
				mMarkStack.push_back(child);
			}

			size_t aliveSize() const
			{
				return mAliveSize;
			}

			size_t traceDataRecursively()
			{
				size_t count = 0;

				while (!mMarkStack.empty())
				{
					const auto val = mMarkStack.back();
					mMarkStack.pop_back();

					val->getOps()->mark(*val, this);
					count++;
				}

				return count;
			}

		private:
			size_t mAliveSize;
			MarkList mMarkStack;
			Collectable::Age mMaxAge;
		};

		//-------------------------------------------------------------------------------
		class GarbageCollectorImpl : public GarbageCollector
		{
		private:
			struct GcJob
			{
				RootMarker marker;
				CollectedHeap::MemList allocated;
				size_t allocatedSize;
				bool fullGc;

				GcJob() :
					marker(Collectable::YOUNG),
					allocatedSize(0),
					fullGc(false)
				{}

				explicit GcJob(const bool fullGc)
					: marker(fullGc ? Collectable::OLD : Collectable::YOUNG),
					allocatedSize(0),
					fullGc(fullGc)
				{}
			};

		public:
			GarbageCollectorImpl(const size_t numMutatorThreads, DataRootExplorer * rootExplorer, const GcConfig & config)
				: mConfig(config),
				mStopped(0),
				mThreads(numMutatorThreads),
				mRootExplorer(rootExplorer),
				mOldGenSize(0),
				mStop(false),
				mQuit(false),
				mCollectOld(false)
			{
				mCollectorThread = std::thread(std::bind(&GarbageCollectorImpl::collectorThreadLoop, this));
			}

			virtual ~GarbageCollectorImpl()
			{
				mQuit = true;
				mQueue.quit();
				mCollectorThread.join();
				mAllocated.clear_and_dispose([](Collectable * obj) { delete obj; });
			}

			void runGc() override
			{
				if (!mConfig.enabled())
				{
					return;
				}

				// Проверяем, не начал ли кто-нибудь другой сборку мусора.
				while (!mGcMutex.try_lock())
				{
					if (needGC()) safePoint();
				}

				boost::timer::cpu_timer pauseTimer;

				{
					std::unique_lock<std::mutex> lock(mRunMutex);

					// Посылаем команду на остановку других потоков.
					mStop.store(true, std::memory_order_release);
					mStopped++;

					// Ждем, пока они остановятся.
					mRunCond.wait(lock, [this] { return mStopped == mThreads; });
					mStopped--;
				}

				std::unique_ptr<GcJob> job(new GcJob(mCollectOld));

				// Сканируем корни.
				mRootExplorer->markRoots(&job->marker);

				// Сбрасываем списке выделенной памяти во всех кучах.
				for (auto heap : mHeaps)
				{
					job->allocatedSize += heap->heapSize();
					//XXX buf added because temporary lvalue can't be passed to non const refference
					auto buf = heap->reset();
					job->allocated.splice(job->allocated.end(), buf);
				}

				// Добавляем задание на сборку мусора.
				mQueue.push(std::move(job));

				{
					std::unique_lock<std::mutex> lock(mRunMutex);

					// Возобновляем работу других потоков.
					mStop.store(false, std::memory_order_relaxed);
					mRunCond.notify_all();
				}

				if (mConfig.verbose())
				{
					std::cout
						<< "GC Pause. Time: " << boost::timer::format(pauseTimer.elapsed());
				}

				mGcMutex.unlock();
			}

			// Этот метод выполняется другими потоками для ожидании сканирования корней.
			bool needGC() override
			{
				return mStop.load(std::memory_order_acquire) == 1;
			}

			// Этот метод выполняется другими потоками для ожидании сканирования корней.
			void safePoint() override
			{
				std::unique_lock<std::mutex> lock(mRunMutex);

				mStopped++;
				mRunCond.notify_all();

				mRunCond.wait(lock, [this] { return mStop.load(std::memory_order_relaxed) == 0; });
				mStopped--;
			}

			void registerHeap(CollectedHeap * heap) override
			{
				mHeaps.push_back(heap);
				heap->setLimit(mConfig.youngGenSize());
			}

		private:
			void collectorThreadLoop()
			{
				while (!mQuit)
				{
					auto deqJob = mQueue.pop();

					if (!deqJob.is_initialized())
					{
						break;
					}

					auto job = std::move(deqJob.get());

					boost::timer::cpu_timer gcTimer;

					// Маркируем корневые объекты.
					size_t aliveSize = 0;
					for (const auto object : job->marker.mRoots)
					{
						const auto root = object.first;
						if (!root->isMarked())
						{
							ObjectMarker::setMarked(root, 1);
							aliveSize += object.second;
						}
					}

					HeapMarker marker(job->marker, aliveSize);

					// Помечаем доступные вершины.
					auto count = marker.traceDataRecursively();

					if (job->fullGc)
					{
						job->allocated.splice(job->allocated.end(), mAllocated);
						job->allocatedSize += mOldGenSize;
						mOldGenSize = 0;
						mCollectOld = false;
					}

					// Очищаем память.
					job->allocated.remove_and_dispose_if([](const Collectable & obj) { return !obj.isMarked(); },
						[](Collectable * obj) {	delete obj;	});

					// Сбрасываем флаги.
					for (auto & object : job->allocated)
					{
						ObjectMarker::setObjectAge(&object, Collectable::OLD);
						ObjectMarker::setMarked(&object, 0);
					}

					mOldGenSize += marker.aliveSize();
					mAllocated.splice(mAllocated.end(), job->allocated);

					if (mConfig.verbose())
					{
						std::cout
							<< "GC time : " << boost::timer::format(gcTimer.elapsed())
							<< "Reclaimed: " << (job->allocatedSize - marker.aliveSize()) / (1024 * 1024) << " MiB. OldGen: "
							<< mOldGenSize / (1024 * 1024) << " MiB \n";
					}

					/*if (mOldGenSize > mConfig.oldGenSize())
					{
						std::cout << "\n\nGC ERROR: out of memory\n";
						::exit(1);
					}*/

					if (mOldGenSize > mConfig.oldGenGCThreshold())
					{
						mCollectOld = true;
					}
				}
			}

		private:
			GcConfig mConfig;

			// Количество остановившихся потоков.
			size_t mStopped;

			// Количество потоков мутатора.
			size_t mThreads;

			std::mutex mGcMutex;
			std::mutex mRunMutex;
			std::condition_variable mRunCond;

			DataRootExplorer * mRootExplorer;
			std::vector<CollectedHeap *> mHeaps;
			size_t mOldGenSize;

			// Общие структуры данных.
			BlockingQueue<std::unique_ptr<GcJob>> mQueue;

			// Флаг, сигнализирующий о необходимости остановки.
			std::atomic<bool> mStop;

			bool mQuit;
			bool mCollectOld;

			// Структуры данных потока сборки мусора.
			std::thread mCollectorThread;
			CollectedHeap::MemList mAllocated;
		};

		//-------------------------------------------------------------------------------
		GarbageCollector * GarbageCollector::getCollector(const size_t numThreads, DataRootExplorer * rootExplorer, const GcConfig & config)
		{
			return new GarbageCollectorImpl(numThreads, rootExplorer, config);
		}

	}

	//-------------------------------------------------------------------------------
	void Runtime::ObjectMarker::setObjectAge(Collectable * object, int age)
	{
		object->meta.age = static_cast<Collectable::Age>(age);
	}

	//-------------------------------------------------------------------------------
	bool Runtime::ObjectMarker::checkAge(const Collectable * object, const int age)
	{
		return object->meta.age <= age;
	}

	void Runtime::ObjectMarker::setMarked(Collectable * object, const unsigned int flag)
	{
		object->meta.marked = flag;
	}
}

max_stars_repo_name: Zumisha/FPTL

max_issues_repo_name: Zumisha/FPTL

max_forks_repo_name: Zumisha/FPTL


text:
/******************************************************************************
 * Copyright (c) 2017 Philipp Schubert.
 * All rights reserved. This program and the accompanying materials are made
 * available under the terms of LICENSE.txt.
 *
 * Contributors:
 *     Philipp Schubert and others
 *****************************************************************************/

/*
 * LazyLazyTypeGraph.cpp
 *
 *  Created on: 28.06.2018
 *      Author: nicolas bellec
 */

#include <boost/graph/depth_first_search.hpp>
#include <boost/graph/graph_utility.hpp>
#include <boost/graph/graphviz.hpp>
#include <boost/property_map/dynamic_property_map.hpp>

#include <llvm/IR/DerivedTypes.h>

#include <phasar/PhasarLLVM/Pointer/TypeGraphs/LazyTypeGraph.h>

#include <phasar/Utils/Logger.h>
#include <phasar/Utils/Macros.h>

using namespace std;
using namespace psr;

namespace psr {

struct LazyTypeGraph::dfs_visitor : public boost::default_dfs_visitor {
  dfs_visitor(std::set<const llvm::StructType *> &_result) : result(_result) {}

  void finish_edge(edge_t e, graph_t const &u) {
    LazyTypeGraph::vertex_t src = boost::source(e, u);
    LazyTypeGraph::vertex_t target = boost::target(e, u);

    result.insert(u[target].type);
  }

  std::set<const llvm::StructType *> &result;
};

LazyTypeGraph::vertex_t
LazyTypeGraph::addType(const llvm::StructType *new_type) {
  auto name = new_type->getName().str();

  if (type_vertex_map.find(name) == type_vertex_map.end()) {
    auto vertex = boost::add_vertex(g);
    type_vertex_map[name] = vertex;
    g[vertex].name = name;
    g[vertex].type = new_type;
  }

  return type_vertex_map[name];
}

bool LazyTypeGraph::addLink(const llvm::StructType *from,
                            const llvm::StructType *to) {
  if (already_visited)
    return false;

  already_visited = true;

  auto from_vertex = addType(from);
  auto to_vertex = addType(to);

  auto result_edge = boost::add_edge(from_vertex, to_vertex, g);

  already_visited = false;
  return result_edge.second;
}

void LazyTypeGraph::printAsDot(const std::string &path) const {
  std::ofstream ofs(path);
  boost::write_graphviz(ofs, g,
                        boost::make_label_writer(boost::get(
                            &LazyTypeGraph::VertexProperties::name, g)));
}

std::set<const llvm::StructType *>
LazyTypeGraph::getTypes(const llvm::StructType *struct_type) {
  auto struct_ty_vertex = addType(struct_type);

  std::vector<boost::default_color_type> color_map(boost::num_vertices(g));

  std::set<const llvm::StructType *> results;
  results.insert(struct_type);

  dfs_visitor vis(results);

  boost::depth_first_visit(
      g, struct_ty_vertex, vis,
      boost::make_iterator_property_map(
          color_map.begin(), boost::get(boost::vertex_index, g), color_map[0]));

  return results;
}

} // namespace psr

max_stars_repo_name: flix-/phasar

max_issues_repo_name: flix-/phasar

max_forks_repo_name: flix-/phasar


text:
//
// $Id$
//
//
// Original author: Matt Chambers <matt.chambers .@. vanderbilt.edu>
//
// Copyright 2011 Vanderbilt University - Nashville, TN 37232
//
// 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 _SHARED_MAP_HPP_
#define _SHARED_MAP_HPP_

#include <map>
#include <boost/shared_ptr.hpp>

namespace pwiz {
namespace util {

/// copy semantics of shared_ptr<map<K,V> > with a std::map interface
template<class keyT,
         class valueT,
         class _Pr = std::less<keyT>,
         class _Alloc = std::allocator<std::pair<const keyT, valueT> > >
class shared_map
{
    public:

    typedef std::map<keyT, valueT, _Pr, _Alloc> BaseType;
    typedef typename BaseType::allocator_type allocator_type;
    typedef typename BaseType::key_type key_type;
    typedef typename BaseType::value_type value_type;
    typedef typename BaseType::key_compare key_compare;
    typedef typename BaseType::value_compare value_compare;
    typedef typename BaseType::size_type size_type;
    typedef typename BaseType::mapped_type mapped_type;
    typedef typename BaseType::difference_type difference_type;
    typedef typename BaseType::pointer pointer;
    typedef typename BaseType::const_pointer const_pointer;
    typedef typename BaseType::reference reference;
    typedef typename BaseType::const_reference const_reference;
    typedef typename BaseType::iterator iterator;
    typedef typename BaseType::const_iterator const_iterator;
    typedef typename BaseType::reverse_iterator reverse_iterator;
    typedef typename BaseType::const_reverse_iterator const_reverse_iterator;

    private:
    boost::shared_ptr<BaseType> _base;

    public:

    /// Constructs an empty map that uses the predicate _Pred to order keys, if it is supplied. The map uses the allocator _Alloc for all storage management, if it is supplied.
    explicit shared_map(const key_compare& predicate = key_compare(), const allocator_type& allocator = allocator_type())
        : _base(new BaseType(predicate, allocator))
    {
    }

    /// Constructs a map containing values in the range [_First, _Last). Creation of the new map is only guaranteed to succeed if the iterators start and finish return values of type pair<class Key, class Value> and all values of Key in the range [_First, _Last) are unique. The map uses the predicate _Pred to order keys, and the allocator _Alloc for all storage management.
    template<class _Iter>
    shared_map(_Iter _First, _Iter _Last)
        : _base(new BaseType(key_compare(), allocator_type()))
    {
        for (; _First != _Last; ++_First)
            this->insert(*_First);
    }

    /// Constructs a map containing values in the range [_First, _Last). Creation of the new map is only guaranteed to succeed if the iterators start and finish return values of type pair<class Key, class Value> and all values of Key in the range [_First, _Last) are unique. The map uses the predicate _Pred to order keys, and the allocator _Alloc for all storage management.
    template<class _Iter>
    shared_map(_Iter _First, _Iter _Last, const key_compare& _Pred)
        : _base(new BaseType(_Pred, allocator_type()))
    {
        for (; _First != _Last; ++_First)
            this->insert(*_First);
    }

    /// Constructs a map containing values in the range [_First, _Last). Creation of the new map is only guaranteed to succeed if the iterators start and finish return values of type pair<class Key, class Value> and all values of Key in the range [_First, _Last) are unique. The map uses the predicate _Pred to order keys, and the allocator _Alloc for all storage management.
    template<class _Iter>
    shared_map(_Iter _First, _Iter _Last, const key_compare& _Pred, const allocator_type& _Al)
        : _base(new BaseType(_Pred, _Al))
    {
        for (; _First != _Last; ++_First)
            this->insert(*_First);
    }

    ~shared_map() {}

    /// Returns a copy of the allocator used by self for storage management.
    allocator_type get_allocator() const
	{return _base->get_allocator();}

    /// Returns an iterator pointing to the first element stored in the map. First is defined by the map's comparison operator, Compare.
    iterator begin()
	{return _base->begin();}

    /// Returns a const_iterator pointing to the first element stored in the map.
    const_iterator begin() const
	{return _base->begin();}

    /// Returns an iterator pointing to the last element stored in the map; in other words, to the off-the-end value.
    iterator end()
	{return _base->end();}

    /// Returns a const_iterator pointing to the last element stored in the map.
    const_iterator end() const
	{return _base->end();}

    /// Returns a reverse_iterator pointing to the first element stored in the map. First is defined by the map's comparison operator, Compare.
    reverse_iterator rbegin()
	{return _base->rbegin();}

    /// Returns a const_reverse_iterator pointing to the first element stored in the map.
    const_reverse_iterator rbegin() const
	{return _base->rbegin();}

    /// Returns a reverse_iterator pointing to the last element stored in the map; in other words, to the off-the-end value).
    reverse_iterator rend()
	{return _base->rend();}

    /// Returns a const_reverse_iterator pointing to the last element stored in the map.
    const_reverse_iterator rend() const
	{return _base->rend();}

    /// Replaces the contents of *this with a copy of the map x.
    shared_map<keyT, valueT, key_compare, allocator_type>& operator=(const shared_map<keyT, valueT, key_compare, allocator_type>& x)
    {_base = x._base; return *this;}

    /// If an element with the key x exists in the map, then a reference to its associated value is returned. Otherwise the pair x,T() is inserted into the map and a reference to the default object T() is returned.
    mapped_type& operator[](const key_type& x)
    {return (*_base)[x];}

    /// Erases all elements from the self.
    void clear()
	{_base->clear();}

    /// Returns a 1 if a value with the key x exists in the map. Otherwise returns a 0.
    size_type count(const key_type& x) const
	{return _base->count(x);}

    /// Returns true if the map is empty, false otherwise.
    bool empty() const
	{return _base->empty();}

    /// Returns the pair (lower_bound(x), upper_bound(x)).
    std::pair<iterator, iterator> equal_range(const key_type& x)
    {return _base->equal_range(x);}

    /// Returns the pair (lower_bound(x), upper_bound(x)).
    std::pair<const_iterator,const_iterator> equal_range(const key_type& x) const
    {return _base->equal_range(x);}

    /// Deletes the map element pointed to by the iterator position.
    void erase(iterator position)
	{_base->erase(position);}

    /// If the iterators start and finish point to the same map and last is reachable from first, all elements in the range [start, finish) are deleted from the map.
    void erase(iterator start, iterator finish)
	{_base->erase(start, finish);}

    /// Deletes the element with the key value x from the map, if one exists. Returns 1 if x existed in the map, 0 otherwise.
    size_type erase(const key_type& x)
	{return _base->erase(x);}

    /// Searches the map for a pair with the key value x and returns an iterator to that pair if it is found. If such a pair is not found the value end() is returned.
    iterator find(const key_type& x)
	{return _base->find(x);}

    /// Same as find above but returns a const_iterator.
    const_iterator find(const key_type& x) const
	{return _base->find(x);}

    /// If a value_type with the same key as x is not present in the map, then x is inserted into the map. Otherwise, the pair is not inserted. A position may be supplied as a hint regarding where to do the insertion. If the insertion is done right after position, then it takes amortized constant time. Otherwise it takes O(log N) time.
    std::pair<iterator, bool> insert(const value_type& x)
    {return _base->insert(x);}

    /// If a value_type with the same key as x is not present in the map, then x is inserted into the map. Otherwise, the pair is not inserted. A position may be supplied as a hint regarding where to do the insertion. If the insertion is done right after position, then it takes amortized constant time. Otherwise it takes O(log N) time.
    iterator insert(iterator position, const value_type& x)
	{return _base->insert(position, x);}

    /// Copies of each element in the range [start, finish) that possess a unique key (one not already in the map) are inserted into the map. The iterators start and finish must return values of type pair<T1,T2>. This operation takes approximately O(N*log(size()+N)) time.
    template <class InputIterator>
    void insert(InputIterator start, InputIterator finish)
	{_base->insert(start, finish);}

    /// Returns a function object capable of comparing key values using the comparison operation, Compare, of the current map.
    key_compare key_comp() const
	{return _base->key_comp();}

    /// Returns a reference to the first entry with a key greater than or equal to x.
    iterator lower_bound(const key_type& x)
	{return _base->lower_bound(x);}

    /// Same as lower_bound above but returns a const_iterator.
    const_iterator lower_bound(const key_type& x) const
	{return _base->lower_bound(x);}

    /// Returns the maximum possible size of the map. This size is only constrained by the number of unique keys that can be represented by the type Key.
    size_type max_size() const
	{return _base->max_size();}

    /// Returns the number of elements in the map.
    size_type size() const
	{return _base->size();}

    /// Swaps the contents of the map x with the current map, *this.
    void swap(shared_map<keyT, valueT, key_compare, allocator_type>& x)
	{_base->swap(x._base);}

    /// Returns an iterator for the first entry with a key greater than x.
    iterator upper_bound(const key_type& x)
	{return _base->upper_bound(x);}

    /// Same as upper_bound above, but returns a const_iterator.
    const_iterator upper_bound(const key_type& x) const
	{return _base->upper_bound(x);}

    /// Returns a function object capable of comparing pair<const Key, T> values using the comparison operation, Compare, of the current map. This function is identical to key_comp for sets.
    value_compare value_comp() const
	{return _base->value_comp();}
};

} // namespace util
} // namespace pwiz

#endif // _SHARED_MAP_HPP_

max_stars_repo_name: toppic-suite/topmsv

max_issues_repo_name: toppic-suite/topmsv

max_forks_repo_name: toppic-suite/topmsv