<commit_before>//----------------------------------------------------------------------------
/// \file   base64.hpp
/// \author Serge Aleynikov
//----------------------------------------------------------------------------
/// \brief  Functions for base64 encoding/decoding
//----------------------------------------------------------------------------
// Copyright (c) 2018 Serge Aleynikov <saleyn@gmail.com>
// Created: 2018-04-10
//----------------------------------------------------------------------------
/*
***** BEGIN LICENSE BLOCK *****

This file is part of the utxx open-source project.

Copyright (C) 2018 Serge Aleynikov <saleyn@gmail.com>

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

***** END LICENSE BLOCK *****
*/
#pragma once

/*
#include <boost/archive/iterators/binary_from_base64.hpp>
#include <boost/archive/iterators/base64_from_binary.hpp>
#include <boost/archive/iterators/transform_width.hpp>
#include <boost/algorithm/string.hpp>
*/
#include <string>
#include <sstream>
#include <cmath>
#include <boost/utility.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/cstdint.hpp>
#include <vector>
#include <utxx/print.hpp>

//-----------------------------------------------------------------------------
// Base64
//-----------------------------------------------------------------------------

namespace utxx {

/*
//------------------------------------------------------------------------------
/// Base64 decoder
//------------------------------------------------------------------------------
inline std::string decode_base64(const std::string& str) {
    using namespace boost::archive::iterators;
    using cit = std::string::const_iterator;
    using it  = transform_width<binary_from_base64<cit>, 8, 6>;
    return boost::algorithm::trim_right_copy_if
        (std::string(it(std::begin(str)), it(std::end(str))), [](char c) {
            return c == '\0';
        });
}

//------------------------------------------------------------------------------
/// Base64 encoder
//------------------------------------------------------------------------------
inline std::string encode_base64(const std::string& str) {
    using namespace boost::archive::iterators;
    using cit = std::string::const_iterator;
    using it  = transform_width<binary_from_base64<cit>, 8, 6>;
    auto  tmp = std::string(it(std::begin(str)), it(std::end(str)));
    auto  n   = 3 - (str.size() & 3);
    return n && n < 3 ? tmp.append(n, '=') : tmp;
}
*/

class base64 : public boost::noncopyable {
public:
    enum encoding { STANDARD, URL };

    static std::string encode(
        const std::string& s, encoding enc = STANDARD, bool eq_trail = true)
    {
        return encode(
            reinterpret_cast<const uint8_t*>(s.c_str()), s.size(), enc, eq_trail);
    }

    static std::string encode(
        const uint8_t* s, unsigned int size, encoding enc = STANDARD, bool eq_trail = true)
    {
        buffered_print os;
        os.reserve(((4 * size / 3) + 3) & ~3);

        for (uint i=0; i < size;) {
            auto c1 = s[i++] & 0xff;
            if (i == size) {
                os << enctable(enc)[c1 >> 2] << enctable(enc)[(c1 & 0x3) << 4];
                if (eq_trail) os << "==";
                break;
            }
            auto c2 = s[i++];
            if (i == size) {
                os << enctable(enc)[  c1 >> 2]
                   << enctable(enc)[((c1 & 0x3) << 4)|((c2 & 0xf0) >> 4)]
                   << enctable(enc)[ (c2 & 0xf) << 2];
                if (eq_trail) os << '=';
                break;
            }
            auto c3 = s[i++];
            os << enctable(enc)[  c1 >> 2]
               << enctable(enc)[((c1 & 0x3) << 4) | ((c2 & 0xf0) >> 4)]
               << enctable(enc)[((c2 & 0xf) << 2) | ((c3 & 0xc0) >> 6)]
               << enctable(enc)[  c3 & 0x3f];
        }
        return os.to_string();
    }

    static std::vector<char> decode(const std::string& s, encoding enc = STANDARD) {
        std::vector<char> dest;
        decode(s, dest, enc);
        return dest;
    }

    static std::string decode_str(const std::string& s, encoding enc = STANDARD) {
        auto v = decode(s, enc);
        return std::string(v.begin(), v.end());
    }

    /// Decode base64 string into "dest"
    /// @param dest can be an STL container or string
    template <typename T>
    static void decode(const std::string& s, T& dest, encoding enc = STANDARD) {
        auto size = s.size();
        auto dest_sz = static_cast<float>(size * 3) / 4;

        dest.clear();
        dest.reserve(static_cast<unsigned int>(std::ceil(dest_sz)));

        for (uint i=0; i < size;) {
            char c1;
            do {c1 = dectable(enc)[s[i++] & 0xff];} while (i < size && c1 == -1);
            if (c1 == -1) break;

            char c2;
            do {c2 = dectable(enc)[s[i++] & 0xff];} while (i < size && c2 == -1);
            if (c2 == -1) break;

            dest.push_back(static_cast<uint8_t>(((c1 << 2)|((c2 & 0x30) >> 4)) & 0xff));

            char c3;
            do {
                c3 = s[i++] & 0xff;
                if (c3 == 61) return;
                c3 = dectable(enc)[int(c3)];
            } while (i < size && c3 == -1);

            if (c3 == -1) break;

            dest.push_back(static_cast<uint8_t>((((c2 & 0xf) << 4)|((c3 & 0x3c) >> 2)) & 0xff));

            char c4;
            do {
                c4 = s[i++] & 0xff;
                if (c4 == 61) return;
                c4 = dectable(enc)[int(c4)];
            } while (i < size && c4 == -1);
            if (c4 == -1) break;

            dest.push_back(static_cast<uint8_t>((((c3 & 0x03) << 6)| c4) & 0xff));
        }
    }

private:
    static const char* enctable(encoding enc) {
        static const char s_enctable[][65] =  {
            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", // STD
            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"  // URL
        };
        return s_enctable[enc];
    };

    static const char* dectable(encoding enc) {
        static const char s_dectable[][128] = {
            // STD
            {
                -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
                -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
                -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
                52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
                -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
                15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
                -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
                41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1
            },
            // URL
            {
                -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
                -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
                -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1,
                52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
                -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
                15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63,
                -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
                41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1
            }
        };
        return s_dectable[enc];
    }
};

} // namespace utxx
<commit_msg>Add unchecked base64 functions<commit_after>//----------------------------------------------------------------------------
/// \file   base64.hpp
/// \author Serge Aleynikov
//----------------------------------------------------------------------------
/// \brief  Functions for base64 encoding/decoding
//----------------------------------------------------------------------------
// Copyright (c) 2018 Serge Aleynikov <saleyn@gmail.com>
// Created: 2018-04-10
//----------------------------------------------------------------------------
/*
***** BEGIN LICENSE BLOCK *****

This file is part of the utxx open-source project.

Copyright (C) 2018 Serge Aleynikov <saleyn@gmail.com>

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

***** END LICENSE BLOCK *****
*/
#pragma once

/*
#include <boost/archive/iterators/binary_from_base64.hpp>
#include <boost/archive/iterators/base64_from_binary.hpp>
#include <boost/archive/iterators/transform_width.hpp>
#include <boost/algorithm/string.hpp>
*/
#include <string>
#include <sstream>
#include <cmath>
#include <boost/utility.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/cstdint.hpp>
#include <vector>
#include <utxx/print.hpp>

//-----------------------------------------------------------------------------
// Base64
//-----------------------------------------------------------------------------

namespace utxx {

/*
//------------------------------------------------------------------------------
/// Base64 decoder
//------------------------------------------------------------------------------
inline std::string decode_base64(const std::string& str) {
    using namespace boost::archive::iterators;
    using cit = std::string::const_iterator;
    using it  = transform_width<binary_from_base64<cit>, 8, 6>;
    return boost::algorithm::trim_right_copy_if
        (std::string(it(std::begin(str)), it(std::end(str))), [](char c) {
            return c == '\0';
        });
}

//------------------------------------------------------------------------------
/// Base64 encoder
//------------------------------------------------------------------------------
inline std::string encode_base64(const std::string& str) {
    using namespace boost::archive::iterators;
    using cit = std::string::const_iterator;
    using it  = transform_width<binary_from_base64<cit>, 8, 6>;
    auto  tmp = std::string(it(std::begin(str)), it(std::end(str)));
    auto  n   = 3 - (str.size() & 3);
    return n && n < 3 ? tmp.append(n, '=') : tmp;
}
*/

class base64 : public boost::noncopyable {
public:
    enum encoding { STANDARD, URL };

    static unsigned encode_size(unsigned input_sz) { return (((input_sz<<2) / 3) + 3) & ~3; }

    static std::string encode(
        const std::string& s, encoding enc = STANDARD, bool eq_trail = true)
    {
        return encode(
            reinterpret_cast<const uint8_t*>(s.c_str()), s.size(), enc, eq_trail);
    }

    static std::string encode(
        const uint8_t* s, unsigned int size, encoding enc = STANDARD, bool eq_trail = true)
    {
        buffered_print os;
        os.reserve(encode_size(size));
        auto n = encode_unchecked(s, size, os.str(), enc, eq_trail);
        os.advance(n);
        return os.to_string();
    }

    static unsigned encode_unchecked(
        const uint8_t* s, unsigned size, char* dest, encoding enc = STANDARD, bool eq_trail = true)
    {
        unsigned j = 0;

        for (unsigned i=0; i < size;) {
            auto c1 = s[i++] & 0xff;
            if (i == size) {
                dest[j++] = enctable(enc)[c1 >> 2];
                dest[j++] = enctable(enc)[(c1 & 0x3) << 4];
                if (eq_trail) { dest[j++] = '='; dest[j++] = '='; }
                break;
            }
            auto c2 = s[i++];
            if (i == size) {
                dest[j++] = enctable(enc)[  c1 >> 2];
                dest[j++] = enctable(enc)[((c1 & 0x3) << 4)|((c2 & 0xf0) >> 4)];
                dest[j++] = enctable(enc)[ (c2 & 0xf) << 2];
                if (eq_trail) dest[j++] = '=';
                break;
            }
            auto c3 = s[i++];
            dest[j++] = enctable(enc)[  c1 >> 2];
            dest[j++] = enctable(enc)[((c1 & 0x3) << 4) | ((c2 & 0xf0) >> 4)];
            dest[j++] = enctable(enc)[((c2 & 0xf) << 2) | ((c3 & 0xc0) >> 6)];
            dest[j++] = enctable(enc)[  c3 & 0x3f];
        }
        return j;
    }

    static std::vector<char> decode(const std::string& s, encoding enc = STANDARD) {
        std::vector<char> dest;
        decode(s, dest, enc);
        return dest;
    }

    static std::string decode_str(const std::string& s, encoding enc = STANDARD) {
        auto v = decode(s, enc);
        return std::string(v.begin(), v.end());
    }

    /// Decode base64 string into "dest"
    /// @param dest can be an STL container or string
    template <typename T>
    static unsigned decode(const std::string& s, T& dest, encoding enc = STANDARD) {
        auto size = s.size();
        auto dest_sz = static_cast<float>(size * 3) / 4;

        dest.clear();
        dest.resize(static_cast<unsigned int>(std::ceil(dest_sz)));

        auto len = decode_unchecked(s.c_str(), size, &dest[0], enc);
        dest.resize(len);

        return len;
    }

    template <typename Ch = uint8_t>
    static unsigned decode_unchecked(const char* s, size_t size, Ch* out, encoding enc = STANDARD) {
        auto j = 0u;

        for (uint i=0; i < size;) {
            char c1;
            do {c1 = dectable(enc)[s[i++] & 0xff];} while (i < size && c1 == -1);
            if (c1 == -1) break;

            char c2;
            do {c2 = dectable(enc)[s[i++] & 0xff];} while (i < size && c2 == -1);
            if (c2 == -1) break;

            out[j++] = static_cast<Ch>(((c1 << 2)|((c2 & 0x30) >> 4)) & 0xff);

            char c3;
            do {
                c3 = s[i++] & 0xff;
                if (c3 == 61) return j;
                c3 = dectable(enc)[int(c3)];
            } while (i < size && c3 == -1);

            if (c3 == -1) break;

            out[j++] = static_cast<Ch>((((c2 & 0xf) << 4)|((c3 & 0x3c) >> 2)) & 0xff);

            char c4;
            do {
                c4 = s[i++] & 0xff;
                if (c4 == 61) return j;
                c4 = dectable(enc)[int(c4)];
            } while (i < size && c4 == -1);
            if (c4 == -1) break;

            out[j++] = static_cast<Ch>((((c3 & 0x03) << 6)| c4) & 0xff);
        }
        return j;
    }

private:
    static const char* enctable(encoding enc) {
        static const char s_enctable[][65] =  {
            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", // STD
            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"  // URL
        };
        return s_enctable[enc];
    };

    static const char* dectable(encoding enc) {
        static const char s_dectable[][128] = {
            // STD
            {
                -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
                -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
                -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
                52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
                -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
                15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
                -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
                41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1
            },
            // URL
            {
                -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
                -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
                -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1,
                52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
                -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
                15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63,
                -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
                41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1
            }
        };
        return s_dectable[enc];
    }
};

} // namespace utxx
<|endoftext|>


<commit_before>// regex_search example
#include <iostream>
#include <string>
#include <regex>

int main ()
{
  std::string s ("this subject has a submarine as a subsequence");
  std::smatch m;
  std::regex e ("\\b(sub)([^ ]*)");   // matches words beginning by "sub"

  std::cout << "Target sequence: " << s << std::endl;
  std::cout << "Regular expression: /\\b(sub)([^ ]*)/" << std::endl;
  std::cout << "The following matches and submatches were found:" << std::endl;

  while (std::regex_search (s,m,e)) {
    for (auto x:m) std::cout << x << " ";
    std::cout << std::endl;
    s = m.suffix().str();
  }

  return 0;
}
<commit_msg>added some c<commit_after>// regex_search example
#include <iostream>
#include <string>
#include <regex>

//
//

int main ()
{
  std::string s ("this subject has a submarine as a subsequence");
  std::smatch m;
  std::regex e ("\\b(sub)([^ ]*)");   // matches words beginning by "sub"

  std::cout << "Target sequence: " << s << std::endl;
  std::cout << "Regular expression: /\\b(sub)([^ ]*)/" << std::endl;
  std::cout << "The following matches and submatches were found:" << std::endl;

  while (std::regex_search (s,m,e)) {
    for (auto x:m) std::cout << x << " ";
    std::cout << std::endl;
    s = m.suffix().str();
  }

  return 0;
}
<|endoftext|>


<commit_before>//----------------------------------------------------------------------------
/// \file  leb128.hpp
//----------------------------------------------------------------------------
/// \brief Little Endian Binary integer encoding
/// \see https://en.wikipedia.org/wiki/LEB128
//----------------------------------------------------------------------------
// Copyright (c) 2015 Serge Aleynikov <saleyn@gmail.com>
// Created: 2015-08-05
//----------------------------------------------------------------------------
/*
***** BEGIN LICENSE BLOCK *****

This file is part of the utxx open-source project.

Copyright (C) 2015 Serge Aleynikov <saleyn@gmail.com>

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

***** END LICENSE BLOCK *****
*/
#pragma once

namespace utxx {

/// Write an unsigned LEB-encoded integer to \a p
template <unsigned Padding = 0>
inline int encode_uleb128(uint64_t a_value, char* p) {
    auto* q = p;
    do {
        uint8_t byte = a_value & 0x7f;
        a_value >>= 7;
        if (a_value != 0 || Padding != 0)
            byte |= 0x80; // This bit means that more bytes will follow.
        *p++ = byte;
    } while (a_value);

    if (Padding) {
        // Pad with 0x80 and null-terminate it.
        for (int n=Padding; n != 1; --n)
            *(uint8_t*)p++ = '\x80';
        *p++ = '\x00';
    }
    return p - q;
}

/// Write a signed LEB128-encoded integer to \a p
inline int encode_sleb128(int64_t a_value, char* p) {
    bool  more;
    auto* q = p;
    do {
        uint8_t byte = a_value & 0x7f;
        a_value >>= 7;
        more = !((!a_value      && (byte & 0x40) == 0) ||
                 (a_value == -1 && (byte & 0x40) != 0));
        if (more)
            byte |= 0x80; // This bit means that more bytes will follow.
        *(uint8_t*)p++ = byte;
    } while (more);

    return p - q;
}

/// Decode an unsigned LEB128-encoded value.
inline uint64_t decode_uleb128(const char* p) {
    uint64_t   value = 0;
    unsigned   shift = 0;
    do {
        value += uint64_t(*(uint8_t*)p & 0x7f) << shift;
        shift += 7;
    } while (*(uint8_t*)p++ >= 128);
    return value;
}

inline uint64_t decode_uleb128(const char* p, int& sz) {
    auto         q = p;
    auto         e = sz < 0 ? p + 20 : p + sz;
    uint64_t value = 0;
    int      shift = 0;
    do {
        if (p >= e) { sz = -1; return 0; }
        value += uint64_t(*(uint8_t*)p & 0x7f) << shift;
        shift += 7;
    } while (*(uint8_t*)p++ >= 128);
    sz = p - q;
    return value;
}

/// Decode a signed LEB128-encoded value.
inline int64_t decode_sleb128(const char* p) {
    uint64_t value = 0;
    int      shift = 0;
    uint8_t  byte;
    do {
        byte = *(uint8_t*)p++;
        value |= ((byte & 0x7f) << shift);
        shift += 7;
    } while (byte >= 128);
    // Sign extend negative numbers.
    return (byte & 0x40) ? (value |= (-1ull) << shift) : value;
}

/// Decode a signed LEB128-encoded value.
inline int64_t decode_sleb128(const char* p, int& sz) {
    auto         q = p;
    auto         e = sz < 0 ? p + 20 : p + sz;
    uint64_t value = 0;
    int      shift = 0;
    uint8_t  byte;
    do {
        if (p >= e) { sz = -1; return 0; }
        byte = *(uint8_t*)p++;
        value |= ((byte & 0x7f) << shift);
        shift += 7;
    } while (byte >= 128);
    sz = p - q;
    // Sign extend negative numbers.
    return (byte & 0x40) ? (value |= (-1ull) << shift) : value;
}

/// Get the size of the ULEB128-encoded value.
inline int encoded_uleb128_size(uint64_t a_value) {
    int size = 0;
    do {
        a_value >>= 7;
        size += sizeof(int8_t);
    } while (a_value);
    return size;
}

/// Get the size of the SLEB128-encoded value.
inline int encoded_sleb128_size(int64_t a_value) {
    int  size = 0;
    int  sign = a_value >> (8 * sizeof(a_value) - 1);
    bool is_more;

    do {
        unsigned byte = a_value & 0x7f;
        a_value >>= 7;
        is_more   = a_value != sign || ((byte ^ sign) & 0x40) != 0;
        size     += sizeof(int8_t);
    } while (is_more);
    return size;
}

} // namespace utxx<commit_msg>Revert the leb128 change<commit_after>//----------------------------------------------------------------------------
/// \file  leb128.hpp
//----------------------------------------------------------------------------
/// \brief Little Endian Binary integer encoding
/// \see https://en.wikipedia.org/wiki/LEB128
//----------------------------------------------------------------------------
// Copyright (c) 2015 Serge Aleynikov <saleyn@gmail.com>
// Created: 2015-08-05
//----------------------------------------------------------------------------
/*
***** BEGIN LICENSE BLOCK *****

This file is part of the utxx open-source project.

Copyright (C) 2015 Serge Aleynikov <saleyn@gmail.com>

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

***** END LICENSE BLOCK *****
*/
#pragma once

namespace utxx {

/// Write an unsigned LEB-encoded integer to \a p
template <unsigned Padding = 0>
inline int encode_uleb128(uint64_t a_value, char* p) {
    auto* q = p;
    do {
        uint8_t byte = a_value & 0x7f;
        a_value >>= 7;
        if (a_value != 0 || Padding != 0)
            byte |= 0x80; // This bit means that more bytes will follow.
        *p++ = byte;
    } while (a_value);

    if (Padding) {
        // Pad with 0x80 and null-terminate it.
        for (int n=Padding; n != 1; --n)
            *(uint8_t*)p++ = '\x80';
        *p++ = '\x00';
    }
    return p - q;
}

/// Write a signed LEB128-encoded integer to \a p
inline int encode_sleb128(int64_t a_value, char* p) {
    bool  more;
    auto* q = p;
    do {
        uint8_t byte = a_value & 0x7f;
        a_value >>= 7;
        more = !((!a_value      && (byte & 0x40) == 0) ||
                 (a_value == -1 && (byte & 0x40) != 0));
        if (more)
            byte |= 0x80; // This bit means that more bytes will follow.
        *(uint8_t*)p++ = byte;
    } while (more);

    return p - q;
}

/// Decode an unsigned LEB128-encoded value.
inline uint64_t decode_uleb128(const char* p) {
    uint64_t   value = 0;
    unsigned   shift = 0;
    do {
        value += uint64_t(*(uint8_t*)p & 0x7f) << shift;
        shift += 7;
    } while (*(uint8_t*)p++ >= 128);
    return value;
}

inline uint64_t decode_uleb128(const char* p, int& sz) {
    auto         q = p;
    uint64_t value = 0;
    int      shift = 0;
    do {
        value += uint64_t(*(uint8_t*)p & 0x7f) << shift;
        shift += 7;
    } while (*(uint8_t*)p++ >= 128);
    sz = p - q;
    return value;
}

/// Decode a signed LEB128-encoded value.
inline int64_t decode_sleb128(const char* p) {
    uint64_t value = 0;
    int      shift = 0;
    uint8_t  byte;
    do {
        byte = *(uint8_t*)p++;
        value |= ((byte & 0x7f) << shift);
        shift += 7;
    } while (byte >= 128);
    // Sign extend negative numbers.
    return (byte & 0x40) ? (value |= (-1ull) << shift) : value;
}

/// Decode a signed LEB128-encoded value.
inline int64_t decode_sleb128(const char* p, int& sz) {
    auto         q = p;
    uint64_t value = 0;
    int      shift = 0;
    uint8_t  byte;
    do {
        byte = *(uint8_t*)p++;
        value |= ((byte & 0x7f) << shift);
        shift += 7;
    } while (byte >= 128);
    sz = p - q;
    // Sign extend negative numbers.
    return (byte & 0x40) ? (value |= (-1ull) << shift) : value;
}

/// Get the size of the ULEB128-encoded value.
inline int encoded_uleb128_size(uint64_t a_value) {
    int size = 0;
    do {
        a_value >>= 7;
        size += sizeof(int8_t);
    } while (a_value);
    return size;
}

/// Get the size of the SLEB128-encoded value.
inline int encoded_sleb128_size(int64_t a_value) {
    int  size = 0;
    int  sign = a_value >> (8 * sizeof(a_value) - 1);
    bool is_more;

    do {
        unsigned byte = a_value & 0x7f;
        a_value >>= 7;
        is_more   = a_value != sign || ((byte ^ sign) & 0x40) != 0;
        size     += sizeof(int8_t);
    } while (is_more);
    return size;
}

} // namespace utxx<|endoftext|>


<commit_before>//
// Copyright (c) 2014 CNRS
// Authors: Florent Lamiraux
//
// This file is part of hpp-core
// hpp-core is free software: you can redistribute it
// and/or modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation, either version
// 3 of the License, or (at your option) any later version.
//
// hpp-core is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Lesser Public License for more details.  You should have
// received a copy of the GNU Lesser General Public License along with
// hpp-core  If not, see
// <http://www.gnu.org/licenses/>.

#include <hpp/core/straight-path.hh>

#include <hpp/util/debug.hh>

#include <hpp/pinocchio/device.hh>
#include <hpp/pinocchio/liegroup.hh>
#include <hpp/pinocchio/configuration.hh>
#include <hpp/util/exception.hh>
#include <hpp/core/config-projector.hh>
#include <hpp/core/projection-error.hh>

namespace hpp {
  namespace core {
    StraightPath::StraightPath (const DevicePtr_t& device,
				ConfigurationIn_t init,
				ConfigurationIn_t end,
				value_type length) :
      parent_t (interval_t (0, length), device->configSize (),
		device->numberDof ()),
      device_ (device), initial_ (init), end_ (end)
    {
      assert (device);
      assert (length >= 0);
      assert (!constraints ());
    }

    StraightPath::StraightPath (const DevicePtr_t& device,
				ConfigurationIn_t init,
				ConfigurationIn_t end,
				value_type length,
				ConstraintSetPtr_t constraints) :
      parent_t (interval_t (0, length), device->configSize (),
		device->numberDof (), constraints),
      device_ (device), initial_ (init), end_ (end)
    {
      assert (device);
      assert (length >= 0);
    }

    StraightPath::StraightPath (const StraightPath& path) :
      parent_t (path), device_ (path.device_), initial_ (path.initial_),
      end_ (path.end_)
    {
    }

    StraightPath::StraightPath (const StraightPath& path,
				const ConstraintSetPtr_t& constraints) :
      parent_t (path, constraints), device_ (path.device_),
      initial_ (path.initial_), end_ (path.end_)
    {
      assert (constraints->isSatisfied (initial_));
      assert (constraints->isSatisfied (end_));
    }

    bool StraightPath::impl_compute (ConfigurationOut_t result,
				     value_type param) const
    {
      if (param == timeRange ().first || timeRange ().second == 0) {
	result = initial_;
	return true;
      }
      if (param == timeRange ().second) {
	result = end_;
	return true;
      }
      value_type u = param/timeRange ().second;
      if (timeRange ().second == 0)
	u = 0;
      pinocchio::interpolate<hpp::pinocchio::LieGroupTpl> (device_, initial_, end_, u, result);
      return true;
    }

    void StraightPath::impl_derivative (vectorOut_t result, const value_type&,
					size_type order) const
    {
      if (order > 1) {
	result.setZero ();
	return;
      }
      if (order == 1) {
	if (timeRange ().first == timeRange ().second) {
	  result.setZero ();
	  return;
	}
	pinocchio::difference <hpp::pinocchio::LieGroupTpl>
	  (device_, end_, initial_, result);
	result = (1/timeRange ().second) * result;
	return;
      }
      std::ostringstream oss;
      oss << "order of derivative (" << order << ") should be positive.";
      HPP_THROW_EXCEPTION (hpp::Exception, oss.str ());
    }

    PathPtr_t StraightPath::extract (const interval_t& subInterval) const
      throw (projection_error)
    {
      // Length is assumed to be proportional to interval range
      value_type l = fabs (subInterval.second - subInterval.first);

      bool success;
      Configuration_t q1 ((*this) (subInterval.first, success));
      if (!success) throw projection_error
		      ("Failed to apply constraints in StraightPath::extract");
      Configuration_t q2 ((*this) (subInterval.second, success));
      if (!success) throw projection_error
		      ("Failed to apply constraints in StraightPath::extract");
      PathPtr_t result = StraightPath::create (device_, q1, q2, l,
					       constraints ());
      return result;
    }

    DevicePtr_t StraightPath::device () const
    {
      return device_;
    }
  } //   namespace core
} // namespace hpp

<commit_msg>Fix StraightPath::impl_derivative<commit_after>//
// Copyright (c) 2014 CNRS
// Authors: Florent Lamiraux
//
// This file is part of hpp-core
// hpp-core is free software: you can redistribute it
// and/or modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation, either version
// 3 of the License, or (at your option) any later version.
//
// hpp-core is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Lesser Public License for more details.  You should have
// received a copy of the GNU Lesser General Public License along with
// hpp-core  If not, see
// <http://www.gnu.org/licenses/>.

#include <hpp/core/straight-path.hh>

#include <hpp/util/debug.hh>

#include <hpp/pinocchio/device.hh>
#include <hpp/pinocchio/liegroup.hh>
#include <hpp/pinocchio/configuration.hh>
#include <hpp/util/exception.hh>
#include <hpp/core/config-projector.hh>
#include <hpp/core/projection-error.hh>

namespace hpp {
  namespace core {
    StraightPath::StraightPath (const DevicePtr_t& device,
				ConfigurationIn_t init,
				ConfigurationIn_t end,
				value_type length) :
      parent_t (interval_t (0, length), device->configSize (),
		device->numberDof ()),
      device_ (device), initial_ (init), end_ (end)
    {
      assert (device);
      assert (length >= 0);
      assert (!constraints ());
    }

    StraightPath::StraightPath (const DevicePtr_t& device,
				ConfigurationIn_t init,
				ConfigurationIn_t end,
				value_type length,
				ConstraintSetPtr_t constraints) :
      parent_t (interval_t (0, length), device->configSize (),
		device->numberDof (), constraints),
      device_ (device), initial_ (init), end_ (end)
    {
      assert (device);
      assert (length >= 0);
    }

    StraightPath::StraightPath (const StraightPath& path) :
      parent_t (path), device_ (path.device_), initial_ (path.initial_),
      end_ (path.end_)
    {
    }

    StraightPath::StraightPath (const StraightPath& path,
				const ConstraintSetPtr_t& constraints) :
      parent_t (path, constraints), device_ (path.device_),
      initial_ (path.initial_), end_ (path.end_)
    {
      assert (constraints->isSatisfied (initial_));
      assert (constraints->isSatisfied (end_));
    }

    bool StraightPath::impl_compute (ConfigurationOut_t result,
				     value_type param) const
    {
      if (param == timeRange ().first || timeRange ().second == 0) {
	result = initial_;
	return true;
      }
      if (param == timeRange ().second) {
	result = end_;
	return true;
      }
      value_type u = param/timeRange ().second;
      if (timeRange ().second == 0)
	u = 0;
      pinocchio::interpolate<hpp::pinocchio::LieGroupTpl> (device_, initial_, end_, u, result);
      return true;
    }

    void StraightPath::impl_derivative (vectorOut_t result, const value_type&,
					size_type order) const
    {
      if (order > 1) {
	result.setZero ();
	return;
      }
      if (order == 1) {
	if (timeRange ().first == timeRange ().second) {
	  result.setZero ();
	  return;
	}
	pinocchio::difference <hpp::pinocchio::LieGroupTpl>
	  (device_, end_, initial_, result);
	result /= length();
	return;
      }
      std::ostringstream oss;
      oss << "order of derivative (" << order << ") should be positive.";
      HPP_THROW_EXCEPTION (hpp::Exception, oss.str ());
    }

    PathPtr_t StraightPath::extract (const interval_t& subInterval) const
      throw (projection_error)
    {
      // Length is assumed to be proportional to interval range
      value_type l = fabs (subInterval.second - subInterval.first);

      bool success;
      Configuration_t q1 ((*this) (subInterval.first, success));
      if (!success) throw projection_error
		      ("Failed to apply constraints in StraightPath::extract");
      Configuration_t q2 ((*this) (subInterval.second, success));
      if (!success) throw projection_error
		      ("Failed to apply constraints in StraightPath::extract");
      PathPtr_t result = StraightPath::create (device_, q1, q2, l,
					       constraints ());
      return result;
    }

    DevicePtr_t StraightPath::device () const
    {
      return device_;
    }
  } //   namespace core
} // namespace hpp

<|endoftext|>


<commit_before>#include "string_utils.h"
#include "exception.h"
#include <algorithm>
#include <string>

namespace inicpp
{
	namespace string_utils
	{
		std::string left_trim(const std::string &str)
		{
			auto front = std::find_if(str.begin(), str.end(), [](int c) { return !std::isspace(c); });
			return std::string(front, str.end());
		}

		std::string right_trim(const std::string &str)
		{
			auto back = std::find_if(str.rbegin(), str.rend(), [](int c) { return !std::isspace(c); }).base();
			return std::string(str.begin(), back);
		}

		std::string trim(const std::string &str)
		{
			auto front = std::find_if(str.begin(), str.end(), [](int c) { return !std::isspace(c); });
			auto back = std::find_if(str.rbegin(), str.rend(), [](int c) { return !std::isspace(c); }).base();

			if (back <= front) { return ""; }
			return std::string(front, back);
		}

		bool find_needle(const std::string &haystack, const std::string &needle)
		{
			return (haystack.find(needle) == std::string::npos ? false : true);
		}

		bool starts_with(const std::string &str, const std::string &search_str)
		{
			size_t search_str_length = search_str.length();

			if (search_str_length > str.length()) { return false; }

			for (size_t i = 0; i < search_str_length; ++i) {
				if (str[i] != search_str[i]) { return false; }
			}

			return true;
		}

		bool ends_with(const std::string &str, const std::string &search_str)
		{
			size_t search_str_length = search_str.length();
			size_t str_length = str.length();

			if (search_str_length > str.length()) { return false; }

			for (size_t i = 0; i < search_str_length; ++i) {
				if (str[str_length - i - 1] != search_str[search_str_length - i - 1]) { return false; }
			}

			return true;
		}

		std::vector<std::string> split(const std::string &str, char delim)
		{
			std::vector<std::string> result;
			std::stringstream stream(str);
			std::string item;

			while (std::getline(stream, item, delim)) { result.push_back(item); }
			return result;
		}

		template <> string_ini_t parse_string<string_ini_t>(const std::string &value, const std::string &)
		{
			return value;
		}
		template <> boolean_ini_t parse_string<boolean_ini_t>(const std::string &value, const std::string &option_name)
		{
			if (value == "0" || value == "f" || value == "n" || value == "off" || value == "no" ||
				value == "disabled") {
				return false;
			} else if (value == "1" || value == "t" || value == "y" || value == "on" || value == "yes" ||
				value == "enabled") {
				return true;
			} else {
				throw invalid_type_exception(
					"Option '" + option_name + "' parsing failed: String '" + value + "' is not valid boolean type.");
			}
		}

		template <> enum_ini_t parse_string<enum_ini_t>(const std::string &value, const std::string &)
		{
			return enum_ini_t(value);
		}

		template <> float_ini_t parse_string<float_ini_t>(const std::string &value, const std::string &option_name)
		{
			try {
				return std::stod(value);
			} catch (std::exception &e) {
				throw invalid_type_exception("Option '" + option_name + "' parsing failed: " + e.what());
			}
		}

		template <> signed_ini_t parse_string<signed_ini_t>(const std::string &value, const std::string &option_name)
		{
			try {
				std::string binary_prefix = "0b";
				if (value.size() > binary_prefix.size() && std::equal(binary_prefix.begin(), binary_prefix.end(), value.begin())) {
					// this is binary number
					return std::stoll(value.substr(2), 0, 2);
				} else {
					// decimal and hexadecimal number can handle stoll itself
					return std::stoll(value, 0, 0);
				}
			} catch (std::exception &e) {
				throw invalid_type_exception("Option '" + option_name + "' parsing failed: " + e.what());
			}
		}

		template <>
		unsigned_ini_t parse_string<unsigned_ini_t>(const std::string &value, const std::string &option_name)
		{
			try {
				std::string binary_prefix = "0b";
				if (value.size() > binary_prefix.size() &&
					std::equal(binary_prefix.begin(), binary_prefix.end(), value.begin())) {
					// this is binary number
					return std::stoull(value.substr(2), 0, 2);
				} else {
					// decimal and hexadecimal number can handle stoull itself
					return std::stoull(value, 0, 0);
				}
			} catch (std::exception &e) {
				throw invalid_type_exception("Option '" + option_name + "' parsing failed: " + e.what());
			}
		}
	} // namespace string_utils

	namespace inistd
	{
		std::string to_string(const enum_ini_t &value)
		{
			return static_cast<std::string>(value);
		}
	} // namespace inistd
} // namespace inicpp
<commit_msg>re format code<commit_after>#include "string_utils.h"
#include "exception.h"
#include <algorithm>
#include <string>

namespace inicpp
{
	namespace string_utils
	{
		std::string left_trim(const std::string &str)
		{
			auto front = std::find_if(str.begin(), str.end(), [](int c) { return !std::isspace(c); });
			return std::string(front, str.end());
		}

		std::string right_trim(const std::string &str)
		{
			auto back = std::find_if(str.rbegin(), str.rend(), [](int c) { return !std::isspace(c); }).base();
			return std::string(str.begin(), back);
		}

		std::string trim(const std::string &str)
		{
			auto front = std::find_if(str.begin(), str.end(), [](int c) { return !std::isspace(c); });
			auto back = std::find_if(str.rbegin(), str.rend(), [](int c) { return !std::isspace(c); }).base();

			if (back <= front) { return ""; }
			return std::string(front, back);
		}

		bool find_needle(const std::string &haystack, const std::string &needle)
		{
			return (haystack.find(needle) == std::string::npos ? false : true);
		}

		bool starts_with(const std::string &str, const std::string &search_str)
		{
			size_t search_str_length = search_str.length();

			if (search_str_length > str.length()) { return false; }

			for (size_t i = 0; i < search_str_length; ++i) {
				if (str[i] != search_str[i]) { return false; }
			}

			return true;
		}

		bool ends_with(const std::string &str, const std::string &search_str)
		{
			size_t search_str_length = search_str.length();
			size_t str_length = str.length();

			if (search_str_length > str.length()) { return false; }

			for (size_t i = 0; i < search_str_length; ++i) {
				if (str[str_length - i - 1] != search_str[search_str_length - i - 1]) { return false; }
			}

			return true;
		}

		std::vector<std::string> split(const std::string &str, char delim)
		{
			std::vector<std::string> result;
			std::stringstream stream(str);
			std::string item;

			while (std::getline(stream, item, delim)) { result.push_back(item); }
			return result;
		}

		template <> string_ini_t parse_string<string_ini_t>(const std::string &value, const std::string &)
		{
			return value;
		}
		template <> boolean_ini_t parse_string<boolean_ini_t>(const std::string &value, const std::string &option_name)
		{
			if (value == "0" || value == "f" || value == "n" || value == "off" || value == "no" ||
				value == "disabled") {
				return false;
			} else if (value == "1" || value == "t" || value == "y" || value == "on" || value == "yes" ||
				value == "enabled") {
				return true;
			} else {
				throw invalid_type_exception(
					"Option '" + option_name + "' parsing failed: String '" + value + "' is not valid boolean type.");
			}
		}

		template <> enum_ini_t parse_string<enum_ini_t>(const std::string &value, const std::string &)
		{
			return enum_ini_t(value);
		}

		template <> float_ini_t parse_string<float_ini_t>(const std::string &value, const std::string &option_name)
		{
			try {
				return std::stod(value);
			} catch (std::exception &e) {
				throw invalid_type_exception("Option '" + option_name + "' parsing failed: " + e.what());
			}
		}

		template <> signed_ini_t parse_string<signed_ini_t>(const std::string &value, const std::string &option_name)
		{
			try {
				std::string binary_prefix = "0b";
				if (value.size() > binary_prefix.size() &&
				    	std::equal(binary_prefix.begin(), binary_prefix.end(), value.begin())) {
					// this is binary number
					return std::stoll(value.substr(2), 0, 2);
				} else {
					// decimal and hexadecimal number can handle stoll itself
					return std::stoll(value, 0, 0);
				}
			} catch (std::exception &e) {
				throw invalid_type_exception("Option '" + option_name + "' parsing failed: " + e.what());
			}
		}

		template <>
		unsigned_ini_t parse_string<unsigned_ini_t>(const std::string &value, const std::string &option_name)
		{
			try {
				std::string binary_prefix = "0b";
				if (value.size() > binary_prefix.size() &&
					std::equal(binary_prefix.begin(), binary_prefix.end(), value.begin())) {
					// this is binary number
					return std::stoull(value.substr(2), 0, 2);
				} else {
					// decimal and hexadecimal number can handle stoull itself
					return std::stoull(value, 0, 0);
				}
			} catch (std::exception &e) {
				throw invalid_type_exception("Option '" + option_name + "' parsing failed: " + e.what());
			}
		}
	} // namespace string_utils

	namespace inistd
	{
		std::string to_string(const enum_ini_t &value)
		{
			return static_cast<std::string>(value);
		}
	} // namespace inistd
} // namespace inicpp
<|endoftext|>


<commit_before>// TRENTO: Reduced Thickness Event-by-event Nuclear Topology
// Copyright 2015 Jonah E. Bernhard, J. Scott Moreland
// MIT License

#include "../src/nucleus.h"

#include <algorithm>
#include <cmath>
#include <iterator>
#include <map>
#include <sstream>

#include "catch.hpp"

using namespace trento;

TEST_CASE( "nucleus" ) {

  SECTION( "proton" ) {

    auto nucleus = NucleusBase::create("p");

    CHECK( std::distance(nucleus->begin(), nucleus->end()) == 1 );
    CHECK( std::distance(nucleus->cbegin(), nucleus->cend()) == 1 );

    CHECK( nucleus->radius() == 0. );

    nucleus->sample_nucleons(0.);

    auto proton = *(nucleus->begin());
    auto coord = std::get<0>(proton);
    auto part = std::get<1>(proton);
    auto x = std::get<0>(coord);
    auto y = std::get<1>(coord);

    CHECK( x == 0. );
    CHECK( y == 0. );
    CHECK( part == false );

  }

  SECTION( "lead" ) {

    auto nucleus = NucleusBase::create("Pb");

    CHECK( std::distance(nucleus->begin(), nucleus->end()) == 208 );
    CHECK( std::distance(nucleus->cbegin(), nucleus->cend()) == 208 );

    CHECK( nucleus->radius() > 6. );

    nucleus->sample_nucleons(0.);

    auto initial_participants = std::any_of(
        nucleus->cbegin(), nucleus->cend(),
        [](const NucleusBase::NucleonAttr& n) { return std::get<1>(n); });
    CHECK( initial_participants == false );

    constexpr auto n_events = 1000;
    constexpr auto n_samples = n_events*208;
    constexpr auto dr = 1.;
    std::map<int, int> hist{};

    for (auto i = 0; i < n_events; ++i) {
      nucleus->sample_nucleons(0.);
      for (const auto& nucleon : *nucleus) {
        auto coord = std::get<0>(nucleon);
        auto x = std::get<0>(coord);
        auto y = std::get<1>(coord);
        auto r = std::sqrt(x*x + y*y);
        ++hist[r/dr];
      }
    }

    std::ostringstream hist_output{};
    for (const auto& bin : hist) {
      hist_output << dr*bin.first << ": "
                  << std::string(300*bin.second/n_samples/dr, '*') << '\n';
    }
    INFO( hist_output.str() );
    CHECK( true );

  }

  SECTION( "unknown species" ) {
    CHECK_THROWS_AS( NucleusBase::create("hello"), std::invalid_argument );
  }

}
<commit_msg>Test Woods-Saxon dist (needs refinement?).<commit_after>// TRENTO: Reduced Thickness Event-by-event Nuclear Topology
// Copyright 2015 Jonah E. Bernhard, J. Scott Moreland
// MIT License

#include "../src/nucleus.h"

#include <algorithm>
#include <cmath>
#include <iterator>
#include <map>

#include "catch.hpp"

#include "../src/random.h"

using namespace trento;

TEST_CASE( "nucleon data" ) {

  NucleonData nucleon_data{};

  // should not be a participant initially
  CHECK( !nucleon_data.is_participant() );

  // set and retrieve position
  nucleon_data.set_position({1, 2});
  std::array<double, 2> correct_position{1, 2};
  CHECK( nucleon_data.position() == correct_position );

  // should still not be a participant
  CHECK( !nucleon_data.is_participant() );

  // set and retrieve participant
  nucleon_data.set_participant();
  CHECK( nucleon_data.is_participant() );

  // setting new position resets participant
  nucleon_data.set_position({3, 4});
  CHECK( !nucleon_data.is_participant() );

}

TEST_CASE( "proton" ) {

  auto nucleus = NucleusBase::create("p");

  // contains one nucleon
  CHECK( std::distance(nucleus->begin(), nucleus->end()) == 1 );
  CHECK( std::distance(nucleus->cbegin(), nucleus->cend()) == 1 );

  CHECK( nucleus->radius() == 0. );

  double offset = random::canonical<>();
  nucleus->sample_nucleons(offset);

  auto&& proton = *(nucleus->begin());
  std::array<double, 2> correct_position{-offset, 0.};

  CHECK( proton.position() == correct_position );
  CHECK( !proton.is_participant() );

}

TEST_CASE( "lead nucleus" ) {

  auto nucleus = NucleusBase::create("Pb");

  constexpr auto A = 208;

  CHECK( std::distance(nucleus->begin(), nucleus->end()) == A );
  CHECK( std::distance(nucleus->cbegin(), nucleus->cend()) == A );

  CHECK( nucleus->radius() > 6. );

  double offset = nucleus->radius() * random::canonical<>();
  nucleus->sample_nucleons(offset);

  // average nucleon position
  double x = 0., y = 0.;
  for (const auto& nucleon : *nucleus) {
    auto coord = nucleon.position();
    x += std::get<0>(coord);
    y += std::get<1>(coord);
  }
  x /= A;
  y /= A;
  auto tolerance = .6;
  CHECK( std::abs(x + offset) < tolerance );
  CHECK( std::abs(y) < tolerance );

  // no initial participants
  bool initial_participants = std::any_of(
      nucleus->cbegin(), nucleus->cend(),
      [](const NucleonData& n) { return n.is_participant(); });
  CHECK( !initial_participants );

  // sample a bunch of nuclei and bin all the nucleon positions
  // using "p" for cylindrical radius to distinguish from spherical "r"
  constexpr auto dp = .2;
  std::map<int, int> hist{};
  for (auto i = 0; i < 5000; ++i) {
    nucleus->sample_nucleons(0.);
    for (const auto& nucleon : *nucleus) {
      auto coord = nucleon.position();
      auto x = std::get<0>(coord);
      auto y = std::get<1>(coord);
      auto p = std::sqrt(x*x + y*y);
      ++hist[p/dp];
    }
  }

  // calculate the W-S distribution at radius p by numerically integrating
  // through the z-direction
  auto woods_saxon = [](double p) -> double {
    double R = 6.67, a = 0.44;
    double zmax = R + 10.*a;
    int nstep = 1000;
    double result = 0.;
    for (auto i = 0; i < nstep; ++i) {
      auto z = (i+.5)*zmax/nstep;
      result += p/(1.+std::exp((std::sqrt(p*p + z*z) - R)/a));
    }
    return result;
  };

  // normalize the histogram and the numerical W-S dist by their values at a
  // point near their peaks
  double norm_point = 5.;
  double hist_norm = hist[norm_point/dp];
  double ws_norm = woods_saxon(norm_point);

  // check all histogram bins agree with the numerical dist within stat error
  auto all_bins_correct = true;
  std::ostringstream bin_output{};
  bin_output << std::fixed << std::boolalpha
             << "p        samples  dist     pass\n";
  for (const auto& bin : hist) {
    double p = (bin.first + .5)*dp;
    double hist_result = bin.second/hist_norm;
    double ws_result = woods_saxon(p)/ws_norm;
    double tolerance = 3/std::sqrt(hist_result);
    bool within_tol = std::abs(hist_result - ws_result) < tolerance;
    all_bins_correct = within_tol;
    bin_output << p << ' '
               << hist_result << ' '
               << ws_result << ' '
               << within_tol << '\n';
  }
  INFO( bin_output.str() );
  CHECK( all_bins_correct );
}

TEST_CASE( "unknown nucleus species" ) {
  CHECK_THROWS_AS( NucleusBase::create("hello"), std::invalid_argument );
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2013, Arvid Norberg
All rights reserved.

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

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

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

*/

#include "test.hpp"
#include "setup_transfer.hpp"
#include "dht_server.hpp"
#include "peer_server.hpp"
#include "udp_tracker.hpp"
#include "libtorrent/alert.hpp"
#include "libtorrent/alert_types.hpp"

#include <fstream>

using namespace libtorrent;
namespace lt = libtorrent;

char const* proxy_name[] = {
	"none",
	"socks4",
	"socks5",
	"socks5_pw",
	"http",
	"http_pw",
	"i2p_proxy"
};

std::vector<std::string> rejected_trackers;

bool alert_predicate(libtorrent::alert* a)
{
	anonymous_mode_alert* am = alert_cast<anonymous_mode_alert>(a);
	if (am == NULL) return false;

	if (am->kind == anonymous_mode_alert::tracker_not_anonymous)
		rejected_trackers.push_back(am->str);

	return false;
}

enum flags_t
{
	force_proxy_mode = 1,
	expect_http_connection = 2,
	expect_udp_connection = 4,
	expect_http_reject = 8,
	expect_udp_reject = 16,
	expect_dht_msg = 32,
	expect_peer_connection = 64,
	expect_possible_udp_connection = 128,
};

session_proxy test_proxy(settings_pack::proxy_type_t proxy_type, int flags)
{
#ifdef TORRENT_DISABLE_DHT
	// if DHT is disabled, we won't get any requests to it
	flags &= ~expect_dht_msg;
#endif
	fprintf(stderr, "\n=== TEST == proxy: %s anonymous-mode: %s\n\n", proxy_name[proxy_type], (flags & force_proxy_mode) ? "yes" : "no");
	int http_port = start_web_server();
	int udp_port = start_udp_tracker();
	int dht_port = start_dht();
	int peer_port = start_peer();

	int prev_udp_announces = num_udp_announces();

	int const alert_mask = alert::all_categories
		& ~alert::progress_notification
		& ~alert::stats_notification;

	settings_pack sett;
	sett.set_int(settings_pack::stop_tracker_timeout, 2);
	sett.set_int(settings_pack::tracker_completion_timeout, 2);
	sett.set_int(settings_pack::tracker_receive_timeout, 2);
#ifndef TORRENT_NO_DEPRECATE
	sett.set_int(settings_pack::half_open_limit, 2);
#endif
	sett.set_bool(settings_pack::announce_to_all_trackers, true);
	sett.set_bool(settings_pack::announce_to_all_tiers, true);
	sett.set_bool(settings_pack::force_proxy, flags & force_proxy_mode);
	sett.set_int(settings_pack::alert_mask, alert_mask);
	sett.set_bool(settings_pack::enable_upnp, false);
	sett.set_bool(settings_pack::enable_natpmp, false);

	// since multiple sessions may exist simultaneously (because of the
	// pipelining of the tests) they actually need to use different ports
	static int listen_port = 10000 + random() % 50000;
	char iface[200];
	snprintf(iface, sizeof(iface), "127.0.0.1:%d", listen_port);
	listen_port += (random() % 10) + 1;
	sett.set_str(settings_pack::listen_interfaces, iface);
	sett.set_bool(settings_pack::enable_dht, true);

	// if we don't do this, the peer connection test
	// will be delayed by several seconds, by first
	// trying uTP
	sett.set_bool(settings_pack::enable_outgoing_utp, false);

	// in non-anonymous mode we circumvent/ignore the proxy if it fails
	// wheras in anonymous mode, we just fail
	sett.set_str(settings_pack::proxy_hostname, "non-existing.com");
	sett.set_int(settings_pack::proxy_type, (settings_pack::proxy_type_t)proxy_type);
	sett.set_int(settings_pack::proxy_port, 4444);

	lt::session* s = new lt::session(sett);

	error_code ec;
	remove_all("tmp1_privacy", ec);
	create_directory("tmp1_privacy", ec);
	std::ofstream file(combine_path("tmp1_privacy", "temporary").c_str());
	boost::shared_ptr<torrent_info> t = ::create_torrent(&file, 16 * 1024, 13, false);
	file.close();

	char http_tracker_url[200];
	snprintf(http_tracker_url, sizeof(http_tracker_url), "http://127.0.0.1:%d/announce", http_port);
	t->add_tracker(http_tracker_url, 0);

	char udp_tracker_url[200];
	snprintf(udp_tracker_url, sizeof(udp_tracker_url), "udp://127.0.0.1:%d/announce", udp_port);
	t->add_tracker(udp_tracker_url, 1);

	add_torrent_params addp;
	addp.flags &= ~add_torrent_params::flag_paused;
	addp.flags &= ~add_torrent_params::flag_auto_managed;

	// we don't want to waste time checking the torrent, just go straight into
	// seeding it, announcing to trackers and connecting to peers
	addp.flags |= add_torrent_params::flag_seed_mode;

	addp.ti = t;
	addp.save_path = "tmp1_privacy";
	addp.dht_nodes.push_back(std::pair<std::string, int>("127.0.0.1", dht_port));
	torrent_handle h = s->add_torrent(addp);

	printf("connect_peer: 127.0.0.1:%d\n", peer_port);
	h.connect_peer(tcp::endpoint(address_v4::from_string("127.0.0.1"), peer_port));

	rejected_trackers.clear();

#ifdef TORRENT_USE_VALGRIND
	const int timeout = 100;
#else
	const int timeout = 20;
#endif

	for (int i = 0; i < timeout; ++i)
	{
		print_alerts(*s, "s", false, false, false, &alert_predicate);
		test_sleep(100);

		if (num_udp_announces() >= prev_udp_announces + 1
			&& num_peer_hits() > 0)
			break;
	}

	// we should have announced to the tracker by now
	if (flags & expect_possible_udp_connection)
	{
		// this flag is true if we may fail open, but also might not have had
		// enough time to fail yet
		TEST_CHECK(num_udp_announces() == prev_udp_announces
			|| num_udp_announces() == prev_udp_announces + 1);
	}
	else
	{
		TEST_EQUAL(num_udp_announces(), prev_udp_announces + bool(flags & expect_udp_connection));
	}
	if (flags & expect_dht_msg)
	{
		TEST_CHECK(num_dht_hits() > 0);
	}
	else
	{
		TEST_EQUAL(num_dht_hits(), 0);
	}

	if (flags & expect_peer_connection)
	{
		TEST_CHECK(num_peer_hits() > 0);
	}
	else
	{
		TEST_EQUAL(num_peer_hits(), 0);
	}

	if (flags & expect_udp_reject)
		TEST_CHECK(std::find(rejected_trackers.begin(), rejected_trackers.end(), udp_tracker_url) != rejected_trackers.end());

	if (flags & expect_http_reject)
		TEST_CHECK(std::find(rejected_trackers.begin(), rejected_trackers.end(), http_tracker_url) != rejected_trackers.end());

	fprintf(stderr, "%s: ~session\n", time_now_string());
	session_proxy pr = s->abort();
	delete s;

	stop_peer();
	stop_dht();
	stop_udp_tracker();
	stop_web_server();
	return pr;
}

int test_main()
{
	session_proxy pr[20];
	// not using anonymous mode
	// UDP fails open if we can't connect to the proxy
	// or if the proxy doesn't support UDP
	pr[0] = test_proxy(settings_pack::none, expect_udp_connection | expect_http_connection | expect_dht_msg | expect_peer_connection);
	pr[1] = test_proxy(settings_pack::socks4, expect_udp_connection | expect_dht_msg);
	pr[2] = test_proxy(settings_pack::socks5, expect_possible_udp_connection | expect_dht_msg);
	pr[3] = test_proxy(settings_pack::socks5_pw,expect_possible_udp_connection | expect_dht_msg);
	pr[4] = test_proxy(settings_pack::http, expect_udp_connection | expect_dht_msg);
	pr[5] = test_proxy(settings_pack::http_pw, expect_udp_connection | expect_dht_msg);
	pr[6] = test_proxy(settings_pack::i2p_proxy, expect_udp_connection | expect_dht_msg);

	// using anonymous mode

	// anonymous mode doesn't require a proxy when one isn't configured. It could be
	// used with a VPN for instance. This will all changed in 1.0, where anonymous
	// mode is separated from force_proxy
	pr[7] = test_proxy(settings_pack::none, force_proxy_mode | expect_peer_connection);
	pr[8] = test_proxy(settings_pack::socks4, force_proxy_mode | expect_udp_reject);
	pr[9] = test_proxy(settings_pack::socks5, force_proxy_mode);
	pr[10] = test_proxy(settings_pack::socks5_pw, force_proxy_mode);
	pr[11] = test_proxy(settings_pack::http, force_proxy_mode | expect_udp_reject);
	pr[12] = test_proxy(settings_pack::http_pw, force_proxy_mode | expect_udp_reject);
	pr[13] = test_proxy(settings_pack::i2p_proxy, force_proxy_mode);
	return 0;
}

<commit_msg>fix test_privacy build<commit_after>/*

Copyright (c) 2013, Arvid Norberg
All rights reserved.

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

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

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

*/

#include "test.hpp"
#include "setup_transfer.hpp"
#include "dht_server.hpp"
#include "peer_server.hpp"
#include "udp_tracker.hpp"
#include "libtorrent/alert.hpp"
#include "libtorrent/random.hpp"
#include "libtorrent/alert_types.hpp"

#include <fstream>

using namespace libtorrent;
namespace lt = libtorrent;

char const* proxy_name[] = {
	"none",
	"socks4",
	"socks5",
	"socks5_pw",
	"http",
	"http_pw",
	"i2p_proxy"
};

std::vector<std::string> rejected_trackers;

bool alert_predicate(libtorrent::alert* a)
{
	anonymous_mode_alert* am = alert_cast<anonymous_mode_alert>(a);
	if (am == NULL) return false;

	if (am->kind == anonymous_mode_alert::tracker_not_anonymous)
		rejected_trackers.push_back(am->str);

	return false;
}

enum flags_t
{
	force_proxy_mode = 1,
	expect_http_connection = 2,
	expect_udp_connection = 4,
	expect_http_reject = 8,
	expect_udp_reject = 16,
	expect_dht_msg = 32,
	expect_peer_connection = 64,
	expect_possible_udp_connection = 128,
};

session_proxy test_proxy(settings_pack::proxy_type_t proxy_type, int flags)
{
#ifdef TORRENT_DISABLE_DHT
	// if DHT is disabled, we won't get any requests to it
	flags &= ~expect_dht_msg;
#endif
	fprintf(stderr, "\n=== TEST == proxy: %s anonymous-mode: %s\n\n", proxy_name[proxy_type], (flags & force_proxy_mode) ? "yes" : "no");
	int http_port = start_web_server();
	int udp_port = start_udp_tracker();
	int dht_port = start_dht();
	int peer_port = start_peer();

	int prev_udp_announces = num_udp_announces();

	int const alert_mask = alert::all_categories
		& ~alert::progress_notification
		& ~alert::stats_notification;

	settings_pack sett;
	sett.set_int(settings_pack::stop_tracker_timeout, 2);
	sett.set_int(settings_pack::tracker_completion_timeout, 2);
	sett.set_int(settings_pack::tracker_receive_timeout, 2);
#ifndef TORRENT_NO_DEPRECATE
	sett.set_int(settings_pack::half_open_limit, 2);
#endif
	sett.set_bool(settings_pack::announce_to_all_trackers, true);
	sett.set_bool(settings_pack::announce_to_all_tiers, true);
	sett.set_bool(settings_pack::force_proxy, flags & force_proxy_mode);
	sett.set_int(settings_pack::alert_mask, alert_mask);
	sett.set_bool(settings_pack::enable_upnp, false);
	sett.set_bool(settings_pack::enable_natpmp, false);

	// since multiple sessions may exist simultaneously (because of the
	// pipelining of the tests) they actually need to use different ports
	static int listen_port = 10000 + random() % 50000;
	char iface[200];
	snprintf(iface, sizeof(iface), "127.0.0.1:%d", listen_port);
	listen_port += (random() % 10) + 1;
	sett.set_str(settings_pack::listen_interfaces, iface);
	sett.set_bool(settings_pack::enable_dht, true);

	// if we don't do this, the peer connection test
	// will be delayed by several seconds, by first
	// trying uTP
	sett.set_bool(settings_pack::enable_outgoing_utp, false);

	// in non-anonymous mode we circumvent/ignore the proxy if it fails
	// wheras in anonymous mode, we just fail
	sett.set_str(settings_pack::proxy_hostname, "non-existing.com");
	sett.set_int(settings_pack::proxy_type, (settings_pack::proxy_type_t)proxy_type);
	sett.set_int(settings_pack::proxy_port, 4444);

	lt::session* s = new lt::session(sett);

	error_code ec;
	remove_all("tmp1_privacy", ec);
	create_directory("tmp1_privacy", ec);
	std::ofstream file(combine_path("tmp1_privacy", "temporary").c_str());
	boost::shared_ptr<torrent_info> t = ::create_torrent(&file, 16 * 1024, 13, false);
	file.close();

	char http_tracker_url[200];
	snprintf(http_tracker_url, sizeof(http_tracker_url), "http://127.0.0.1:%d/announce", http_port);
	t->add_tracker(http_tracker_url, 0);

	char udp_tracker_url[200];
	snprintf(udp_tracker_url, sizeof(udp_tracker_url), "udp://127.0.0.1:%d/announce", udp_port);
	t->add_tracker(udp_tracker_url, 1);

	add_torrent_params addp;
	addp.flags &= ~add_torrent_params::flag_paused;
	addp.flags &= ~add_torrent_params::flag_auto_managed;

	// we don't want to waste time checking the torrent, just go straight into
	// seeding it, announcing to trackers and connecting to peers
	addp.flags |= add_torrent_params::flag_seed_mode;

	addp.ti = t;
	addp.save_path = "tmp1_privacy";
	addp.dht_nodes.push_back(std::pair<std::string, int>("127.0.0.1", dht_port));
	torrent_handle h = s->add_torrent(addp);

	printf("connect_peer: 127.0.0.1:%d\n", peer_port);
	h.connect_peer(tcp::endpoint(address_v4::from_string("127.0.0.1"), peer_port));

	rejected_trackers.clear();

#ifdef TORRENT_USE_VALGRIND
	const int timeout = 100;
#else
	const int timeout = 20;
#endif

	for (int i = 0; i < timeout; ++i)
	{
		print_alerts(*s, "s", false, false, false, &alert_predicate);
		test_sleep(100);

		if (num_udp_announces() >= prev_udp_announces + 1
			&& num_peer_hits() > 0)
			break;
	}

	// we should have announced to the tracker by now
	if (flags & expect_possible_udp_connection)
	{
		// this flag is true if we may fail open, but also might not have had
		// enough time to fail yet
		TEST_CHECK(num_udp_announces() == prev_udp_announces
			|| num_udp_announces() == prev_udp_announces + 1);
	}
	else
	{
		TEST_EQUAL(num_udp_announces(), prev_udp_announces + bool(flags & expect_udp_connection));
	}
	if (flags & expect_dht_msg)
	{
		TEST_CHECK(num_dht_hits() > 0);
	}
	else
	{
		TEST_EQUAL(num_dht_hits(), 0);
	}

	if (flags & expect_peer_connection)
	{
		TEST_CHECK(num_peer_hits() > 0);
	}
	else
	{
		TEST_EQUAL(num_peer_hits(), 0);
	}

	if (flags & expect_udp_reject)
		TEST_CHECK(std::find(rejected_trackers.begin(), rejected_trackers.end(), udp_tracker_url) != rejected_trackers.end());

	if (flags & expect_http_reject)
		TEST_CHECK(std::find(rejected_trackers.begin(), rejected_trackers.end(), http_tracker_url) != rejected_trackers.end());

	fprintf(stderr, "%s: ~session\n", time_now_string());
	session_proxy pr = s->abort();
	delete s;

	stop_peer();
	stop_dht();
	stop_udp_tracker();
	stop_web_server();
	return pr;
}

int test_main()
{
	session_proxy pr[20];
	// not using anonymous mode
	// UDP fails open if we can't connect to the proxy
	// or if the proxy doesn't support UDP
	pr[0] = test_proxy(settings_pack::none, expect_udp_connection | expect_http_connection | expect_dht_msg | expect_peer_connection);
	pr[1] = test_proxy(settings_pack::socks4, expect_udp_connection | expect_dht_msg);
	pr[2] = test_proxy(settings_pack::socks5, expect_possible_udp_connection | expect_dht_msg);
	pr[3] = test_proxy(settings_pack::socks5_pw,expect_possible_udp_connection | expect_dht_msg);
	pr[4] = test_proxy(settings_pack::http, expect_udp_connection | expect_dht_msg);
	pr[5] = test_proxy(settings_pack::http_pw, expect_udp_connection | expect_dht_msg);
	pr[6] = test_proxy(settings_pack::i2p_proxy, expect_udp_connection | expect_dht_msg);

	// using anonymous mode

	// anonymous mode doesn't require a proxy when one isn't configured. It could be
	// used with a VPN for instance. This will all changed in 1.0, where anonymous
	// mode is separated from force_proxy
	pr[7] = test_proxy(settings_pack::none, force_proxy_mode | expect_peer_connection);
	pr[8] = test_proxy(settings_pack::socks4, force_proxy_mode | expect_udp_reject);
	pr[9] = test_proxy(settings_pack::socks5, force_proxy_mode);
	pr[10] = test_proxy(settings_pack::socks5_pw, force_proxy_mode);
	pr[11] = test_proxy(settings_pack::http, force_proxy_mode | expect_udp_reject);
	pr[12] = test_proxy(settings_pack::http_pw, force_proxy_mode | expect_udp_reject);
	pr[13] = test_proxy(settings_pack::i2p_proxy, force_proxy_mode);
	return 0;
}

<|endoftext|>


<commit_before>#include "utest.hpp"
#include "tensor.h"
#include "math/softmax.hpp"
#include "math/epsilon.hpp"

NANO_BEGIN_MODULE(test_softmax)

NANO_CASE(value)
{
        using namespace nano;

        for (auto test = 0; test < 10; ++ test)
        {
                const auto dims = 10;
                const vector_t v = vector_t::Random(dims).array().abs();

                auto last_diff = std::numeric_limits<scalar_t>::max();
                for (auto beta = scalar_t(1); beta < scalar_t(65); beta *= 2)
                {
                        const auto s = nano::softmax_value(v, beta);
                        NANO_CHECK(std::isfinite(s));

                        const auto m = v.lpNorm<Eigen::Infinity>();
                        const auto diff = std::fabs(m - s) / m;
                        NANO_CHECK_LESS(diff, last_diff);
                        last_diff = diff;
                }
                NANO_CHECK_LESS(last_diff, nano::epsilon3<scalar_t>());
        }
}

NANO_CASE(vgrad)
{
        // todo: check gradient
        using namespace nano;

        for (auto test = 0; test < 10; ++ test)
        {
                const auto dims = 10;
                const vector_t v = vector_t::Random(dims).array().abs();

                auto last_diff = std::numeric_limits<scalar_t>::max();
                for (auto beta = scalar_t(1); beta < scalar_t(65); beta *= 2)
                {
                        const auto s = nano::softmax_value(v, beta);
                        NANO_CHECK(std::isfinite(s));

                        const auto m = v.lpNorm<Eigen::Infinity>();
                        const auto diff = std::fabs(m - s) / m;
                        NANO_CHECK_LESS(diff, last_diff);
                        last_diff = diff;
                }
                NANO_CHECK_LESS(last_diff, nano::epsilon3<scalar_t>());
        }
}

NANO_END_MODULE()
<commit_msg>finish the softmax-based unit tests<commit_after>#include "utest.hpp"
#include "tensor.h"
#include "math/softmax.hpp"
#include "math/epsilon.hpp"

using scalar_t = double;//nano::scalar_t;
using vector_t = tensor::vector_t<scalar_t>;

namespace
{
        template <typename tsize>
        vector_t make_vector(const tsize dims)
        {
                return vector_t::Random(dims).array().abs();
        }

        vector_t make_gradient(const vector_t& v)
        {
                int index = 0;
                v.maxCoeff(&index);
                vector_t g = vector_t::Zero(v.size());
                g(index) = 1;
                return g;
        }
}

NANO_BEGIN_MODULE(test_softmax)

NANO_CASE(value)
{
        for (auto test = 0; test < 10; ++ test)
        {
                const auto dims = 10;
                const auto v = make_vector(dims);

                // check that softmax approaches max at the limit
                auto last_diff = std::numeric_limits<scalar_t>::max();
                for (auto beta = scalar_t(1); beta < scalar_t(1025); beta *= scalar_t(1.1))
                {
                        const auto s = nano::softmax_value(v, beta);
                        if (!std::isfinite(s))
                        {
                                break;
                        }

                        const auto m = v.lpNorm<Eigen::Infinity>();
                        const auto diff = std::fabs(m - s) / m;
                        NANO_CHECK_LESS(diff, last_diff + nano::epsilon1<scalar_t>());
                        last_diff = diff;
                }
                NANO_CHECK_LESS(last_diff, nano::epsilon3<scalar_t>());
        }
}

NANO_CASE(vgrad)
{
        for (auto test = 0; test < 10; ++ test)
        {
                const auto dims = 10;
                const auto v = make_vector(dims);
                const auto g = make_gradient(v);

                // check that softmax's gradient approches max's gradient at the limit
                auto last_diff = std::numeric_limits<scalar_t>::max();
                for (auto beta = scalar_t(1); beta < scalar_t(1025); beta *= scalar_t(1.1))
                {
                        const vector_t x = nano::softmax_vgrad(v, beta);
                        if (!std::isfinite(x.sum()))
                        {
                                break;
                        }

                        const auto diff = (g - x).lpNorm<Eigen::Infinity>();
                        NANO_CHECK_LESS(diff, last_diff + nano::epsilon1<scalar_t>());
                        last_diff = diff;
                }
                NANO_CHECK_LESS(last_diff, scalar_t(0.1));//nano::epsilon3<scalar_t>());
        }
}

NANO_END_MODULE()
<|endoftext|>


<commit_before>#include "libtorrent/storage.hpp"
#include "libtorrent/file_pool.hpp"
#include "libtorrent/hasher.hpp"
#include "libtorrent/session.hpp"
#include "libtorrent/aux_/session_impl.hpp"

#include <boost/utility.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/convenience.hpp>
#include <boost/thread/mutex.hpp>

#include "test.hpp"
#include "setup_transfer.hpp"

using namespace libtorrent;
using namespace boost::filesystem;

const int piece_size = 16;

void on_read_piece(int ret, disk_io_job const& j, char const* data, int size)
{
	std::cerr << "on_read_piece piece: " << j.piece << std::endl;
	TEST_CHECK(ret == size);
	TEST_CHECK(std::equal(j.buffer, j.buffer + ret, data));
}

void run_storage_tests(boost::intrusive_ptr<torrent_info> info
	, path const& test_path
	, libtorrent::storage_mode_t storage_mode)
{
	const int half = piece_size / 2;

	char piece0[piece_size] =
	{ 6, 6, 6, 6, 6, 6, 6, 6
	, 9, 9, 9, 9, 9, 9, 9, 9};

	char piece1[piece_size] =
	{ 0, 0, 0, 0, 0, 0, 0, 0
	, 1, 1, 1, 1, 1, 1, 1, 1};

	char piece2[piece_size] =
	{ 0, 0, 1, 0, 0, 0, 0, 0
	, 1, 1, 1, 1, 1, 1, 1, 1};

	info->set_hash(0, hasher(piece0, piece_size).final());
	info->set_hash(1, hasher(piece1, piece_size).final());
	info->set_hash(2, hasher(piece2, piece_size).final());

	info->create_torrent();

	create_directory(test_path / "temp_storage");

	int num_pieces = (1 + 612 + 17 + piece_size - 1) / piece_size;
	TEST_CHECK(info->num_pieces() == num_pieces);

	char piece[piece_size];

	{ // avoid having two storages use the same files
	file_pool fp;
	boost::scoped_ptr<storage_interface> s(
		default_storage_constructor(info, test_path, fp));

	// write piece 1 (in slot 0)
	s->write(piece1, 0, 0, half);
	s->write(piece1 + half, 0, half, half);

	// verify piece 1
	TEST_CHECK(s->read(piece, 0, 0, piece_size) == piece_size);
	TEST_CHECK(std::equal(piece, piece + piece_size, piece1));

	// do the same with piece 0 and 2 (in slot 1 and 2)
	s->write(piece0, 1, 0, piece_size);
	s->write(piece2, 2, 0, piece_size);

	// verify piece 0 and 2
	TEST_CHECK(s->read(piece, 1, 0, piece_size) == piece_size);
	TEST_CHECK(std::equal(piece, piece + piece_size, piece0));

	s->read(piece, 2, 0, piece_size);
	TEST_CHECK(std::equal(piece, piece + piece_size, piece2));

	s->release_files();
	}

	// make sure the piece_manager can identify the pieces
	{
	file_pool fp;
	disk_io_thread io;
	boost::shared_ptr<int> dummy(new int);
	boost::intrusive_ptr<piece_manager> pm = new piece_manager(dummy, info
		, test_path, fp, io, default_storage_constructor);
	boost::mutex lock;
	libtorrent::aux::piece_checker_data d;

	std::vector<bool> pieces;
	num_pieces = 0;
	std::string error_msg;
	TEST_CHECK(pm->check_fastresume(d, pieces, num_pieces
		, storage_mode, error_msg) == false);
	bool finished = false;
	float progress;
	num_pieces = 0;
	boost::recursive_mutex mutex;
	while (!finished)
		boost::tie(finished, progress) = pm->check_files(pieces, num_pieces, mutex);

	TEST_CHECK(num_pieces == std::count(pieces.begin(), pieces.end()
		, true));

	boost::function<void(int, disk_io_job const&)> none;
	TEST_CHECK(exists(test_path / "temp_storage"));
	pm->async_move_storage(test_path / "temp_storage2", none);
	test_sleep(2000);
	TEST_CHECK(!exists(test_path / "temp_storage"));
	TEST_CHECK(exists(test_path / "temp_storage2/temp_storage"));
	pm->async_move_storage(test_path , none);
	test_sleep(2000);
	TEST_CHECK(!exists(test_path / "temp_storage2/temp_storage"));
	remove_all(test_path / "temp_storage2");

	peer_request r;
	r.piece = 0;
	r.start = 0;
	r.length = piece_size;
	pm->async_read(r, bind(&on_read_piece, _1, _2, piece0, piece_size));
	r.piece = 1;
	pm->async_read(r, bind(&on_read_piece, _1, _2, piece1, piece_size));
	r.piece = 2;
	pm->async_read(r, bind(&on_read_piece, _1, _2, piece2, piece_size));
	pm->async_release_files(none);

	}
}

void run_test(path const& test_path)
{
	std::cerr << "\n=== " << test_path << " ===\n" << std::endl;

	boost::intrusive_ptr<torrent_info> info(new torrent_info());
	info->set_piece_size(piece_size);
	info->add_file("temp_storage/test1.tmp", 17);
	info->add_file("temp_storage/test2.tmp", 612);
	info->add_file("temp_storage/test3.tmp", 0);
	info->add_file("temp_storage/test4.tmp", 0);
	info->add_file("temp_storage/test5.tmp", 1);

	std::cerr << "=== test 1 ===" << std::endl;

	run_storage_tests(info, test_path, storage_mode_compact);

	// make sure the files have the correct size
	std::cerr << file_size(test_path / "temp_storage" / "test1.tmp") << std::endl;
	TEST_CHECK(file_size(test_path / "temp_storage" / "test1.tmp") == 17);
	std::cerr << file_size(test_path / "temp_storage" / "test2.tmp") << std::endl;
	TEST_CHECK(file_size(test_path / "temp_storage" / "test2.tmp") == 31);
	TEST_CHECK(exists(test_path / "temp_storage/test3.tmp"));
	TEST_CHECK(exists(test_path / "temp_storage/test4.tmp"));
	remove_all(test_path / "temp_storage");

// ==============================================

	// make sure remap_files works
	std::vector<std::pair<std::string, libtorrent::size_type> > map;
	map.push_back(std::make_pair(std::string("temp_storage/test.tmp"), 17 + 612 + 1));
	bool ret = info->remap_files(map);
	TEST_CHECK(ret);

	std::cerr << "=== test 2 ===" << std::endl;

	run_storage_tests(info, test_path, storage_mode_compact);

	std::cerr << file_size(test_path / "temp_storage" / "test.tmp") << std::endl;
	TEST_CHECK(file_size(test_path / "temp_storage" / "test.tmp") == 48);

	remove_all(test_path / "temp_storage");

// ==============================================

	info = new torrent_info();
	info->set_piece_size(piece_size);
	info->add_file("temp_storage/test1.tmp", 17 + 612 + 1);

	std::cerr << "=== test 3 ===" << std::endl;

	run_storage_tests(info, test_path, storage_mode_compact);

	// 48 = piece_size * 3
	TEST_CHECK(file_size(test_path / "temp_storage" / "test1.tmp") == 48);
	remove_all(test_path / "temp_storage");

// ==============================================

	std::cerr << "=== test 4 ===" << std::endl;

	run_storage_tests(info, test_path, storage_mode_allocate);

	std::cerr << file_size(test_path / "temp_storage" / "test1.tmp") << std::endl;
	TEST_CHECK(file_size(test_path / "temp_storage" / "test1.tmp") == 17 + 612 + 1);

	remove_all(test_path / "temp_storage");
}

int test_main()
{
	std::vector<path> test_paths;
	char* env = std::getenv("TORRENT_TEST_PATHS");
	if (env == 0)
	{
		test_paths.push_back(initial_path());
	}
	else
	{
		char* p = std::strtok(env, ";");
		while (p != 0)
		{
			test_paths.push_back(complete(p));
			p = std::strtok(0, ";");
		}
	}

	std::for_each(test_paths.begin(), test_paths.end(), bind(&run_test, _1));
	return 0;
}

<commit_msg>made test_storage build with boost 1.33. Fixes #183<commit_after>#include "libtorrent/storage.hpp"
#include "libtorrent/file_pool.hpp"
#include "libtorrent/hasher.hpp"
#include "libtorrent/session.hpp"
#include "libtorrent/aux_/session_impl.hpp"

#include <boost/utility.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/convenience.hpp>
#include <boost/thread/mutex.hpp>

#include "test.hpp"
#include "setup_transfer.hpp"

using namespace libtorrent;
using namespace boost::filesystem;

const int piece_size = 16;

void on_read_piece(int ret, disk_io_job const& j, char const* data, int size)
{
	std::cerr << "on_read_piece piece: " << j.piece << std::endl;
	TEST_CHECK(ret == size);
	TEST_CHECK(std::equal(j.buffer, j.buffer + ret, data));
}

void run_storage_tests(boost::intrusive_ptr<torrent_info> info
	, path const& test_path
	, libtorrent::storage_mode_t storage_mode)
{
	const int half = piece_size / 2;

	char piece0[piece_size] =
	{ 6, 6, 6, 6, 6, 6, 6, 6
	, 9, 9, 9, 9, 9, 9, 9, 9};

	char piece1[piece_size] =
	{ 0, 0, 0, 0, 0, 0, 0, 0
	, 1, 1, 1, 1, 1, 1, 1, 1};

	char piece2[piece_size] =
	{ 0, 0, 1, 0, 0, 0, 0, 0
	, 1, 1, 1, 1, 1, 1, 1, 1};

	info->set_hash(0, hasher(piece0, piece_size).final());
	info->set_hash(1, hasher(piece1, piece_size).final());
	info->set_hash(2, hasher(piece2, piece_size).final());

	info->create_torrent();

	create_directory(test_path / "temp_storage");

	int num_pieces = (1 + 612 + 17 + piece_size - 1) / piece_size;
	TEST_CHECK(info->num_pieces() == num_pieces);

	char piece[piece_size];

	{ // avoid having two storages use the same files
	file_pool fp;
	boost::scoped_ptr<storage_interface> s(
		default_storage_constructor(info, test_path, fp));

	// write piece 1 (in slot 0)
	s->write(piece1, 0, 0, half);
	s->write(piece1 + half, 0, half, half);

	// verify piece 1
	TEST_CHECK(s->read(piece, 0, 0, piece_size) == piece_size);
	TEST_CHECK(std::equal(piece, piece + piece_size, piece1));

	// do the same with piece 0 and 2 (in slot 1 and 2)
	s->write(piece0, 1, 0, piece_size);
	s->write(piece2, 2, 0, piece_size);

	// verify piece 0 and 2
	TEST_CHECK(s->read(piece, 1, 0, piece_size) == piece_size);
	TEST_CHECK(std::equal(piece, piece + piece_size, piece0));

	s->read(piece, 2, 0, piece_size);
	TEST_CHECK(std::equal(piece, piece + piece_size, piece2));

	s->release_files();
	}

	// make sure the piece_manager can identify the pieces
	{
	file_pool fp;
	disk_io_thread io;
	boost::shared_ptr<int> dummy(new int);
	boost::intrusive_ptr<piece_manager> pm = new piece_manager(dummy, info
		, test_path, fp, io, default_storage_constructor);
	boost::mutex lock;
	libtorrent::aux::piece_checker_data d;

	std::vector<bool> pieces;
	num_pieces = 0;
	std::string error_msg;
	TEST_CHECK(pm->check_fastresume(d, pieces, num_pieces
		, storage_mode, error_msg) == false);
	bool finished = false;
	float progress;
	num_pieces = 0;
	boost::recursive_mutex mutex;
	while (!finished)
		boost::tie(finished, progress) = pm->check_files(pieces, num_pieces, mutex);

	TEST_CHECK(num_pieces == std::count(pieces.begin(), pieces.end()
		, true));

	boost::function<void(int, disk_io_job const&)> none;
	TEST_CHECK(exists(test_path / "temp_storage"));
	pm->async_move_storage(test_path / "temp_storage2", none);
	test_sleep(2000);
	TEST_CHECK(!exists(test_path / "temp_storage"));
	TEST_CHECK(exists(test_path / "temp_storage2/temp_storage"));
	pm->async_move_storage(test_path , none);
	test_sleep(2000);
	TEST_CHECK(!exists(test_path / "temp_storage2/temp_storage"));
	remove_all(test_path / "temp_storage2");

	peer_request r;
	r.piece = 0;
	r.start = 0;
	r.length = piece_size;
	pm->async_read(r, bind(&on_read_piece, _1, _2, piece0, piece_size));
	r.piece = 1;
	pm->async_read(r, bind(&on_read_piece, _1, _2, piece1, piece_size));
	r.piece = 2;
	pm->async_read(r, bind(&on_read_piece, _1, _2, piece2, piece_size));
	pm->async_release_files(none);

	}
}

void run_test(path const& test_path)
{
	std::cerr << "\n=== " << test_path.string() << " ===\n" << std::endl;

	boost::intrusive_ptr<torrent_info> info(new torrent_info());
	info->set_piece_size(piece_size);
	info->add_file("temp_storage/test1.tmp", 17);
	info->add_file("temp_storage/test2.tmp", 612);
	info->add_file("temp_storage/test3.tmp", 0);
	info->add_file("temp_storage/test4.tmp", 0);
	info->add_file("temp_storage/test5.tmp", 1);

	std::cerr << "=== test 1 ===" << std::endl;

	run_storage_tests(info, test_path, storage_mode_compact);

	// make sure the files have the correct size
	std::cerr << file_size(test_path / "temp_storage" / "test1.tmp") << std::endl;
	TEST_CHECK(file_size(test_path / "temp_storage" / "test1.tmp") == 17);
	std::cerr << file_size(test_path / "temp_storage" / "test2.tmp") << std::endl;
	TEST_CHECK(file_size(test_path / "temp_storage" / "test2.tmp") == 31);
	TEST_CHECK(exists(test_path / "temp_storage/test3.tmp"));
	TEST_CHECK(exists(test_path / "temp_storage/test4.tmp"));
	remove_all(test_path / "temp_storage");

// ==============================================

	// make sure remap_files works
	std::vector<std::pair<std::string, libtorrent::size_type> > map;
	map.push_back(std::make_pair(std::string("temp_storage/test.tmp"), 17 + 612 + 1));
	bool ret = info->remap_files(map);
	TEST_CHECK(ret);

	std::cerr << "=== test 2 ===" << std::endl;

	run_storage_tests(info, test_path, storage_mode_compact);

	std::cerr << file_size(test_path / "temp_storage" / "test.tmp") << std::endl;
	TEST_CHECK(file_size(test_path / "temp_storage" / "test.tmp") == 48);

	remove_all(test_path / "temp_storage");

// ==============================================

	info = new torrent_info();
	info->set_piece_size(piece_size);
	info->add_file("temp_storage/test1.tmp", 17 + 612 + 1);

	std::cerr << "=== test 3 ===" << std::endl;

	run_storage_tests(info, test_path, storage_mode_compact);

	// 48 = piece_size * 3
	TEST_CHECK(file_size(test_path / "temp_storage" / "test1.tmp") == 48);
	remove_all(test_path / "temp_storage");

// ==============================================

	std::cerr << "=== test 4 ===" << std::endl;

	run_storage_tests(info, test_path, storage_mode_allocate);

	std::cerr << file_size(test_path / "temp_storage" / "test1.tmp") << std::endl;
	TEST_CHECK(file_size(test_path / "temp_storage" / "test1.tmp") == 17 + 612 + 1);

	remove_all(test_path / "temp_storage");
}

int test_main()
{
	std::vector<path> test_paths;
	char* env = std::getenv("TORRENT_TEST_PATHS");
	if (env == 0)
	{
		test_paths.push_back(initial_path());
	}
	else
	{
		char* p = std::strtok(env, ";");
		while (p != 0)
		{
			test_paths.push_back(complete(p));
			p = std::strtok(0, ";");
		}
	}

	std::for_each(test_paths.begin(), test_paths.end(), bind(&run_test, _1));
	return 0;
}

<|endoftext|>


<commit_before>#include "test.hpp"
#include "setup_transfer.hpp"
#include "libtorrent/alert.hpp"
#include "libtorrent/session.hpp"
#include "libtorrent/error_code.hpp"

#include <fstream>

using namespace libtorrent;

int test_main()
{
	int http_port = start_web_server();
	int udp_port = start_tracker();

	int prev_udp_announces = g_udp_tracker_requests;
	int prev_http_announces = g_http_tracker_requests;

	int const alert_mask = alert::all_categories
		& ~alert::progress_notification
		& ~alert::stats_notification;

	session* s = new libtorrent::session(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48875, 49800), "0.0.0.0", 0, alert_mask);

	session_settings sett;
	sett.half_open_limit = 1;
	sett.announce_to_all_trackers = true;
	sett.announce_to_all_tiers = true;
	s->set_settings(sett);

	error_code ec;
	create_directory("./tmp1_tracker", ec);
	std::ofstream file("./tmp1_tracker/temporary");
	boost::intrusive_ptr<torrent_info> t = ::create_torrent(&file, 16 * 1024, 13, false);
	file.close();

	char tracker_url[200];
	snprintf(tracker_url, sizeof(tracker_url), "http://127.0.0.1:%d/announce", http_port);
	t->add_tracker(tracker_url);

	snprintf(tracker_url, sizeof(tracker_url), "udp://127.0.0.1:%d/announce", udp_port);
	t->add_tracker(tracker_url);

	add_torrent_params addp;
	addp.paused = false;
	addp.auto_managed = false;
	addp.ti = t;
	addp.save_path = "./tmp1_tracker";
	torrent_handle h = s->add_torrent(addp);

	test_sleep(2000);

	// we should have announced to the tracker by now
	TEST_EQUAL(g_udp_tracker_requests, prev_udp_announces + 1);
	TEST_EQUAL(g_http_tracker_requests, prev_http_announces + 1);

	delete s;

	// we should have announced the stopped event now
	TEST_EQUAL(g_udp_tracker_requests, prev_udp_announces + 2);
	TEST_EQUAL(g_http_tracker_requests, prev_http_announces + 2);

	stop_tracker();
	stop_web_server();
}

<commit_msg>add unit test to make sure the next tier is tried in the tracker list when the one ahead of it fails<commit_after>#include "test.hpp"
#include "setup_transfer.hpp"
#include "libtorrent/alert.hpp"
#include "libtorrent/session.hpp"
#include "libtorrent/error_code.hpp"

#include <fstream>

using namespace libtorrent;

int test_main()
{
	int http_port = start_web_server();
	int udp_port = start_tracker();

	int prev_udp_announces = g_udp_tracker_requests;
	int prev_http_announces = g_http_tracker_requests;

	int const alert_mask = alert::all_categories
		& ~alert::progress_notification
		& ~alert::stats_notification;

	session* s = new libtorrent::session(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48875, 49800), "0.0.0.0", 0, alert_mask);

	session_settings sett;
	sett.half_open_limit = 1;
	sett.announce_to_all_trackers = true;
	sett.announce_to_all_tiers = true;
	s->set_settings(sett);

	error_code ec;
	create_directory("./tmp1_tracker", ec);
	std::ofstream file("./tmp1_tracker/temporary");
	boost::intrusive_ptr<torrent_info> t = ::create_torrent(&file, 16 * 1024, 13, false);
	file.close();

	char tracker_url[200];
	snprintf(tracker_url, sizeof(tracker_url), "http://127.0.0.1:%d/announce", http_port);
	t->add_tracker(tracker_url);

	snprintf(tracker_url, sizeof(tracker_url), "udp://127.0.0.1:%d/announce", udp_port);
	t->add_tracker(tracker_url);

	add_torrent_params addp;
	addp.paused = false;
	addp.auto_managed = false;
	addp.ti = t;
	addp.save_path = "./tmp1_tracker";
	torrent_handle h = s->add_torrent(addp);

	test_sleep(2000);

	// we should have announced to the tracker by now
	TEST_EQUAL(g_udp_tracker_requests, prev_udp_announces + 1);
	TEST_EQUAL(g_http_tracker_requests, prev_http_announces + 1);

	delete s;

	// we should have announced the stopped event now
	TEST_EQUAL(g_udp_tracker_requests, prev_udp_announces + 2);
	TEST_EQUAL(g_http_tracker_requests, prev_http_announces + 2);

	// ========================================
	// test that we move on to try the next tier if the first one fails
	// ========================================

	s = new libtorrent::session(fingerprint("LT", 0, 1, 0, 0), std::make_pair(39775, 39800), "0.0.0.0", 0, alert_mask);

	sett.half_open_limit = 1;
	sett.announce_to_all_trackers = true;
	sett.announce_to_all_tiers = false;
	sett.tracker_completion_timeout = 4;
	sett.tracker_receive_timeout = 2;
	s->set_settings(sett);

	create_directory("./tmp2_tracker", ec);
	file.open("./tmp2_tracker/temporary");
	t = ::create_torrent(&file, 16 * 1024, 13, false);
	file.close();

	// this should fail
	snprintf(tracker_url, sizeof(tracker_url), "udp://www.google.com:80/announce");
	t->add_tracker(tracker_url, 0);

	// and this should fail
	snprintf(tracker_url, sizeof(tracker_url), "http://127.0.0.2:3/announce");
	t->add_tracker(tracker_url, 1);

	// this should be announced to
	// udp trackers are prioritized if they're on the same host as an http one
	// so this must be before the http one on 127.0.0.1
	snprintf(tracker_url, sizeof(tracker_url), "udp://127.0.0.1:%d/announce", udp_port);
	t->add_tracker(tracker_url, 2);

	// and this should not be announced to (since the one before it succeeded)
	snprintf(tracker_url, sizeof(tracker_url), "http://127.0.0.1:%d/announce", http_port);
	t->add_tracker(tracker_url, 3);

	prev_udp_announces = g_udp_tracker_requests;
	prev_http_announces = g_http_tracker_requests;

	addp.paused = false;
	addp.auto_managed = false;
	addp.ti = t;
	addp.save_path = "./tmp2_tracker";
	h = s->add_torrent(addp);

	for (int i = 0; i < 10; ++i)
	{
		test_sleep(1000);
		print_alerts(*s, "s");
		if (g_udp_tracker_requests == prev_udp_announces + 1) break;
	}

	test_sleep(1000);

	TEST_EQUAL(g_udp_tracker_requests, prev_udp_announces + 1);
	TEST_EQUAL(g_http_tracker_requests, prev_http_announces);

	delete s;

	stop_tracker();
	stop_web_server();

	return 0;
}

<|endoftext|>