<commit_before>#define BOOST_TEST_MODULE json test
#include <boost/test/unit_test.hpp>
#include <ten/json.hh>
#ifdef TEN_JSON_CXX11
#include <ten/jserial.hh>
#include <ten/jserial_maybe.hh>
#include <ten/jserial_seq.hh>
#include <ten/jserial_assoc.hh>
#include <ten/jserial_enum.hh>
#endif
#include <array>

using namespace std;
using namespace ten;

const char json_text[] =
"{ \"store\": {"
"    \"book\": ["
"      { \"category\": \"reference\","
"        \"author\": \"Nigel Rees\","
"        \"title\": \"Sayings of the Century\","
"        \"price\": 8.95"
"      },"
"      { \"category\": \"fiction\","
"        \"author\": \"Evelyn Waugh\","
"        \"title\": \"Sword of Honour\","
"        \"price\": 12.99"
"      },"
"      { \"category\": \"fiction\","
"        \"author\": \"Herman Melville\","
"        \"title\": \"Moby Dick\","
"        \"isbn\": \"0-553-21311-3\","
"        \"price\": 8.99"
"      },"
"      { \"category\": \"fiction\","
"        \"author\": \"J. R. R. Tolkien\","
"        \"title\": \"The Lord of the Rings\","
"        \"isbn\": \"0-395-19395-8\","
"        \"price\": 22.99"
"      }"
"    ],"
"    \"bicycle\": {"
"      \"color\": \"red\","
"      \"price\": 19.95"
"    }"
"  }"
"}";

BOOST_AUTO_TEST_CASE(json_test_path1) {
    json o(json::load(json_text));
    BOOST_REQUIRE(o.get());

    static const char a1[] = "[\"Nigel Rees\", \"Evelyn Waugh\", \"Herman Melville\", \"J. R. R. Tolkien\"]";
    json r1(o.path("/store/book/author"));
    BOOST_CHECK_EQUAL(json::load(a1), r1);

    json r2(o.path("//author"));
    BOOST_CHECK_EQUAL(json::load(a1), r2);

    // jansson hashtable uses size_t for hash
    // we think this is causing the buckets to change on 32bit vs. 64bit
#if (__SIZEOF_SIZE_T__ == 4)
    static const char a3[] = "[{\"category\": \"reference\", \"author\": \"Nigel Rees\", \"title\": \"Sayings of the Century\", \"price\": 8.95}, {\"category\": \"fiction\", \"author\": \"Evelyn Waugh\", \"title\": \"Sword of Honour\", \"price\": 12.99}, {\"category\": \"fiction\", \"author\": \"Herman Melville\", \"title\": \"Moby Dick\", \"isbn\": \"0-553-21311-3\", \"price\": 8.99}, {\"category\": \"fiction\", \"author\": \"J. R. R. Tolkien\", \"title\": \"The Lord of the Rings\", \"isbn\": \"0-395-19395-8\", \"price\": 22.99}, {\"color\": \"red\", \"price\": 19.95}]";
#elif (__SIZEOF_SIZE_T__ == 8)
    static const char a3[] = "[{\"color\": \"red\", \"price\": 19.95}, {\"category\": \"reference\", \"author\": \"Nigel Rees\", \"title\": \"Sayings of the Century\", \"price\": 8.95}, {\"category\": \"fiction\", \"author\": \"Evelyn Waugh\", \"title\": \"Sword of Honour\", \"price\": 12.99}, {\"category\": \"fiction\", \"author\": \"Herman Melville\", \"title\": \"Moby Dick\", \"isbn\": \"0-553-21311-3\", \"price\": 8.99}, {\"category\": \"fiction\", \"author\": \"J. R. R. Tolkien\", \"title\": \"The Lord of the Rings\", \"isbn\": \"0-395-19395-8\", \"price\": 22.99}]";
#endif
    json r3(o.path("/store/*"));
    json t3(json::load(a3));
    BOOST_CHECK_EQUAL(t3, r3);

#if (__SIZEOF_SIZE_T__ == 4)
    static const char a4[] = "[8.95, 12.99, 8.99, 22.99, 19.95]";
#elif (__SIZEOF_SIZE_T__ == 8)
    static const char a4[] = "[19.95, 8.95, 12.99, 8.99, 22.99]";
#endif
    json r4(o.path("/store//price"));
    BOOST_CHECK_EQUAL(json::load(a4), r4);

    static const char a5[] = "{\"category\": \"fiction\", \"author\": \"J. R. R. Tolkien\", \"title\": \"The Lord of the Rings\", \"isbn\": \"0-395-19395-8\", \"price\": 22.99}";
    json r5(o.path("//book[3]"));
    BOOST_CHECK_EQUAL(json::load(a5), r5);

    static const char a6[] = "\"J. R. R. Tolkien\"";
    json r6(o.path("/store/book[3]/author"));
    BOOST_CHECK_EQUAL(json::load(a6), r6);
    BOOST_CHECK(json::load(a6) == r6);

    static const char a7[] = "[{\"category\": \"fiction\", \"author\": \"Evelyn Waugh\", \"title\": \"Sword of Honour\", \"price\": 12.99}, {\"category\": \"fiction\", \"author\": \"Herman Melville\", \"title\": \"Moby Dick\", \"isbn\": \"0-553-21311-3\", \"price\": 8.99}, {\"category\": \"fiction\", \"author\": \"J. R. R. Tolkien\", \"title\": \"The Lord of the Rings\", \"isbn\": \"0-395-19395-8\", \"price\": 22.99}]";
    json r7(o.path("/store/book[category=\"fiction\"]"));
    BOOST_CHECK_EQUAL(json::load(a7), r7);
}

BOOST_AUTO_TEST_CASE(json_test_path2) {
    json o(json::load("[{\"type\": 0}, {\"type\": 1}]"));
    BOOST_CHECK_EQUAL(json::load("[{\"type\":1}]"), o.path("/[type=1]"));
}

BOOST_AUTO_TEST_CASE(json_test_filter_key_exists) {
    json o(json::load(json_text));
    BOOST_REQUIRE(o.get());

    static const char a[] = "["
"      { \"category\": \"fiction\","
"        \"author\": \"Herman Melville\","
"        \"title\": \"Moby Dick\","
"        \"isbn\": \"0-553-21311-3\","
"        \"price\": 8.99"
"      },"
"      { \"category\": \"fiction\","
"        \"author\": \"J. R. R. Tolkien\","
"        \"title\": \"The Lord of the Rings\","
"        \"isbn\": \"0-395-19395-8\","
"        \"price\": 22.99"
"      }]";
    json r(o.path("//book[isbn]"));
    BOOST_CHECK_EQUAL(json::load(a), r);

    json r1(o.path("//book[doesnotexist]"));
    BOOST_REQUIRE(r1.is_array());
    BOOST_CHECK_EQUAL(0, r1.asize());
}

BOOST_AUTO_TEST_CASE(json_test_truth) {
    json o(json::object());
    BOOST_CHECK(o.get("nothing").is_true() == false);
    BOOST_CHECK(o.get("nothing").is_false() == false);
    BOOST_CHECK(o.get("nothing").is_null() == false);
    BOOST_CHECK(!o.get("nothing"));
}

BOOST_AUTO_TEST_CASE(json_test_path3) {
    json o(json::load(json_text));
    BOOST_REQUIRE(o.get());

    BOOST_CHECK_EQUAL(o, o.path("/"));
    BOOST_CHECK_EQUAL("Sayings of the Century",
        o.path("/store/book[category=\"reference\"]/title"));

    static const char text[] = "["
    "{\"type\":\"a\", \"value\":0},"
    "{\"type\":\"b\", \"value\":1},"
    "{\"type\":\"c\", \"value\":2},"
    "{\"type\":\"c\", \"value\":3}"
    "]";

    BOOST_CHECK_EQUAL(json(1), json::load(text).path("/[type=\"b\"]/value"));
}

BOOST_AUTO_TEST_CASE(json_init_list) {
    json meta{
        { "foo", 17 },
        { "bar", 23 },
        { "baz", true },
        { "corge", json::array({ 1, 3.14159 }) },
        { "grault", json::array({ "hello", string("world") }) },
    };
    BOOST_REQUIRE(meta);
    BOOST_REQUIRE(meta.is_object());
    BOOST_CHECK_EQUAL(meta.osize(), 5);
    BOOST_CHECK_EQUAL(meta["foo"].integer(), 17);
    BOOST_CHECK_EQUAL(meta["corge"][0].integer(), 1);
    BOOST_CHECK_EQUAL(meta["grault"][1].str(), "world");
}

template <class T>
inline void test_conv(T val, json j, json_type t) {
    json j2 = to_json(val);
    BOOST_CHECK_EQUAL(j2.type(), t);
    BOOST_CHECK_EQUAL(j, j2);
    T val2 = json_cast<T>(j2);
    BOOST_CHECK_EQUAL(val, val2);
}

template <class T, json_type TYPE = JSON_INTEGER>
inline void test_conv_num() {
    typedef numeric_limits<T> lim;
    T range[5] = { lim::min(), T(-1), 0, T(1), lim::max() };
    for (unsigned i = 0; i < 5; ++i)
        test_conv<T>(range[i], json(range[i]), TYPE);
}

BOOST_AUTO_TEST_CASE(json_conversions) {
    test_conv<string>(string("hello"), json::str("hello"), JSON_STRING);
    BOOST_CHECK_EQUAL(to_json("world"), json::str("world"));

    test_conv_num<short>();
    test_conv_num<int>();
    test_conv_num<long>();
    test_conv_num<long long>();
    test_conv_num<unsigned short>();
    test_conv_num<unsigned>();
#if ULONG_MAX < LLONG_MAX
    test_conv_num<unsigned long>();
#endif

    test_conv_num<double, JSON_REAL>();
    test_conv_num<float,  JSON_REAL>();

    test_conv<bool>(true,  json::jtrue(),  JSON_TRUE);
    test_conv<bool>(false, json::jfalse(), JSON_FALSE);
}

BOOST_AUTO_TEST_CASE(json_create) {
    json obj1;
    obj1.set("test", "set");
    BOOST_CHECK(obj1);
    BOOST_CHECK(obj1.get("test"));
    json root{
        {"obj1", obj1}
    };
    BOOST_CHECK_EQUAL(root.get("obj1"), obj1);
    obj1.set("this", "that");
    BOOST_CHECK_EQUAL(root.get("obj1").get("this").str(), "that");
    json obj2{ {"answer", 42} };
    obj1.set("obj2", obj2);
    BOOST_CHECK_EQUAL(root.get("obj1").get("obj2"), obj2);
}

#ifdef TEN_JSON_CXX11

struct corge {
    int foo, bar;

    corge() : foo(), bar() {}
    corge(int foo_, int bar_) : foo(foo_), bar(bar_) {}
};
template <class AR>
inline void serialize(AR &ar, corge &c) {
    ar & kv("foo", c.foo) & kv("bar", c.bar);
}
inline bool operator == (const corge &a, const corge &b) {
    return a.foo == b.foo && a.bar == b.bar;
}

enum captain { kirk, picard, janeway, sisko };
const array<string, 4> captain_names = {{ "kirk", "picard", "janeway", "sisko" }};
template <class AR>
inline void serialize(AR &ar, captain &c) {
    serialize_enum(ar, c, captain_names);
}

BOOST_AUTO_TEST_CASE(json_serial) {
    corge c1(42, 17);
    auto j = jsave_all(c1);
    corge c2;
    json_loader(j) >> c2;
    BOOST_CHECK(c1 == c2);

    map<string, int> m;
    json_loader(j) >> m;
    BOOST_CHECK_EQUAL(m.size(), 2);
    BOOST_CHECK(m.find("foo") != m.end());
    BOOST_CHECK(m.find("bar") != m.end());
    BOOST_CHECK_EQUAL(m["foo"], 42);
    BOOST_CHECK_EQUAL(m["bar"], 17);

#if BOOST_VERSION >= 104800
    flat_map<string, int> f;
    json_loader(j) >> f;
    BOOST_CHECK_EQUAL(f.size(), 2);
    BOOST_CHECK(f.find("foo") != f.end());
    BOOST_CHECK(f.find("bar") != f.end());
    BOOST_CHECK_EQUAL(f["foo"], 42);
    BOOST_CHECK_EQUAL(f["bar"], 17);
#endif

    maybe<int> a;
    j = jsave_all(a);
    BOOST_CHECK(!j);
    a = 42;
    j = jsave_all(a);
    BOOST_CHECK_EQUAL(j, 42);

    a.reset();
    BOOST_CHECK(!a.ok());
    j = 17;
    json_loader(j) >> a;
    BOOST_CHECK(a.ok());
    BOOST_CHECK_EQUAL(a.get(), 17);

    captain c = janeway;
    j = jsave_all(c);
    BOOST_CHECK_EQUAL(j, "janeway");
    j = "kirk";
    json_loader(j) >> c;
    BOOST_CHECK_EQUAL(c, kirk);
}

#endif // TEN_JSON_CXX11
<commit_msg>empty init list is spelled ({})<commit_after>#define BOOST_TEST_MODULE json test
#include <boost/test/unit_test.hpp>
#include <ten/json.hh>
#ifdef TEN_JSON_CXX11
#include <ten/jserial.hh>
#include <ten/jserial_maybe.hh>
#include <ten/jserial_seq.hh>
#include <ten/jserial_assoc.hh>
#include <ten/jserial_enum.hh>
#endif
#include <array>

using namespace std;
using namespace ten;

const char json_text[] =
"{ \"store\": {"
"    \"book\": ["
"      { \"category\": \"reference\","
"        \"author\": \"Nigel Rees\","
"        \"title\": \"Sayings of the Century\","
"        \"price\": 8.95"
"      },"
"      { \"category\": \"fiction\","
"        \"author\": \"Evelyn Waugh\","
"        \"title\": \"Sword of Honour\","
"        \"price\": 12.99"
"      },"
"      { \"category\": \"fiction\","
"        \"author\": \"Herman Melville\","
"        \"title\": \"Moby Dick\","
"        \"isbn\": \"0-553-21311-3\","
"        \"price\": 8.99"
"      },"
"      { \"category\": \"fiction\","
"        \"author\": \"J. R. R. Tolkien\","
"        \"title\": \"The Lord of the Rings\","
"        \"isbn\": \"0-395-19395-8\","
"        \"price\": 22.99"
"      }"
"    ],"
"    \"bicycle\": {"
"      \"color\": \"red\","
"      \"price\": 19.95"
"    }"
"  }"
"}";

BOOST_AUTO_TEST_CASE(json_test_path1) {
    json o(json::load(json_text));
    BOOST_REQUIRE(o.get());

    static const char a1[] = "[\"Nigel Rees\", \"Evelyn Waugh\", \"Herman Melville\", \"J. R. R. Tolkien\"]";
    json r1(o.path("/store/book/author"));
    BOOST_CHECK_EQUAL(json::load(a1), r1);

    json r2(o.path("//author"));
    BOOST_CHECK_EQUAL(json::load(a1), r2);

    // jansson hashtable uses size_t for hash
    // we think this is causing the buckets to change on 32bit vs. 64bit
#if (__SIZEOF_SIZE_T__ == 4)
    static const char a3[] = "[{\"category\": \"reference\", \"author\": \"Nigel Rees\", \"title\": \"Sayings of the Century\", \"price\": 8.95}, {\"category\": \"fiction\", \"author\": \"Evelyn Waugh\", \"title\": \"Sword of Honour\", \"price\": 12.99}, {\"category\": \"fiction\", \"author\": \"Herman Melville\", \"title\": \"Moby Dick\", \"isbn\": \"0-553-21311-3\", \"price\": 8.99}, {\"category\": \"fiction\", \"author\": \"J. R. R. Tolkien\", \"title\": \"The Lord of the Rings\", \"isbn\": \"0-395-19395-8\", \"price\": 22.99}, {\"color\": \"red\", \"price\": 19.95}]";
#elif (__SIZEOF_SIZE_T__ == 8)
    static const char a3[] = "[{\"color\": \"red\", \"price\": 19.95}, {\"category\": \"reference\", \"author\": \"Nigel Rees\", \"title\": \"Sayings of the Century\", \"price\": 8.95}, {\"category\": \"fiction\", \"author\": \"Evelyn Waugh\", \"title\": \"Sword of Honour\", \"price\": 12.99}, {\"category\": \"fiction\", \"author\": \"Herman Melville\", \"title\": \"Moby Dick\", \"isbn\": \"0-553-21311-3\", \"price\": 8.99}, {\"category\": \"fiction\", \"author\": \"J. R. R. Tolkien\", \"title\": \"The Lord of the Rings\", \"isbn\": \"0-395-19395-8\", \"price\": 22.99}]";
#endif
    json r3(o.path("/store/*"));
    json t3(json::load(a3));
    BOOST_CHECK_EQUAL(t3, r3);

#if (__SIZEOF_SIZE_T__ == 4)
    static const char a4[] = "[8.95, 12.99, 8.99, 22.99, 19.95]";
#elif (__SIZEOF_SIZE_T__ == 8)
    static const char a4[] = "[19.95, 8.95, 12.99, 8.99, 22.99]";
#endif
    json r4(o.path("/store//price"));
    BOOST_CHECK_EQUAL(json::load(a4), r4);

    static const char a5[] = "{\"category\": \"fiction\", \"author\": \"J. R. R. Tolkien\", \"title\": \"The Lord of the Rings\", \"isbn\": \"0-395-19395-8\", \"price\": 22.99}";
    json r5(o.path("//book[3]"));
    BOOST_CHECK_EQUAL(json::load(a5), r5);

    static const char a6[] = "\"J. R. R. Tolkien\"";
    json r6(o.path("/store/book[3]/author"));
    BOOST_CHECK_EQUAL(json::load(a6), r6);
    BOOST_CHECK(json::load(a6) == r6);

    static const char a7[] = "[{\"category\": \"fiction\", \"author\": \"Evelyn Waugh\", \"title\": \"Sword of Honour\", \"price\": 12.99}, {\"category\": \"fiction\", \"author\": \"Herman Melville\", \"title\": \"Moby Dick\", \"isbn\": \"0-553-21311-3\", \"price\": 8.99}, {\"category\": \"fiction\", \"author\": \"J. R. R. Tolkien\", \"title\": \"The Lord of the Rings\", \"isbn\": \"0-395-19395-8\", \"price\": 22.99}]";
    json r7(o.path("/store/book[category=\"fiction\"]"));
    BOOST_CHECK_EQUAL(json::load(a7), r7);
}

BOOST_AUTO_TEST_CASE(json_test_path2) {
    json o(json::load("[{\"type\": 0}, {\"type\": 1}]"));
    BOOST_CHECK_EQUAL(json::load("[{\"type\":1}]"), o.path("/[type=1]"));
}

BOOST_AUTO_TEST_CASE(json_test_filter_key_exists) {
    json o(json::load(json_text));
    BOOST_REQUIRE(o.get());

    static const char a[] = "["
"      { \"category\": \"fiction\","
"        \"author\": \"Herman Melville\","
"        \"title\": \"Moby Dick\","
"        \"isbn\": \"0-553-21311-3\","
"        \"price\": 8.99"
"      },"
"      { \"category\": \"fiction\","
"        \"author\": \"J. R. R. Tolkien\","
"        \"title\": \"The Lord of the Rings\","
"        \"isbn\": \"0-395-19395-8\","
"        \"price\": 22.99"
"      }]";
    json r(o.path("//book[isbn]"));
    BOOST_CHECK_EQUAL(json::load(a), r);

    json r1(o.path("//book[doesnotexist]"));
    BOOST_REQUIRE(r1.is_array());
    BOOST_CHECK_EQUAL(0, r1.asize());
}

BOOST_AUTO_TEST_CASE(json_test_truth) {
    json o({}); // empty init list
    BOOST_CHECK(o.get("nothing").is_true() == false);
    BOOST_CHECK(o.get("nothing").is_false() == false);
    BOOST_CHECK(o.get("nothing").is_null() == false);
    BOOST_CHECK(!o.get("nothing"));
}

BOOST_AUTO_TEST_CASE(json_test_path3) {
    json o(json::load(json_text));
    BOOST_REQUIRE(o.get());

    BOOST_CHECK_EQUAL(o, o.path("/"));
    BOOST_CHECK_EQUAL("Sayings of the Century",
        o.path("/store/book[category=\"reference\"]/title"));

    static const char text[] = "["
    "{\"type\":\"a\", \"value\":0},"
    "{\"type\":\"b\", \"value\":1},"
    "{\"type\":\"c\", \"value\":2},"
    "{\"type\":\"c\", \"value\":3}"
    "]";

    BOOST_CHECK_EQUAL(json(1), json::load(text).path("/[type=\"b\"]/value"));
}

BOOST_AUTO_TEST_CASE(json_init_list) {
    json meta{
        { "foo", 17 },
        { "bar", 23 },
        { "baz", true },
        { "corge", json::array({ 1, 3.14159 }) },
        { "grault", json::array({ "hello", string("world") }) },
    };
    BOOST_REQUIRE(meta);
    BOOST_REQUIRE(meta.is_object());
    BOOST_CHECK_EQUAL(meta.osize(), 5);
    BOOST_CHECK_EQUAL(meta["foo"].integer(), 17);
    BOOST_CHECK_EQUAL(meta["corge"][0].integer(), 1);
    BOOST_CHECK_EQUAL(meta["grault"][1].str(), "world");
}

template <class T>
inline void test_conv(T val, json j, json_type t) {
    json j2 = to_json(val);
    BOOST_CHECK_EQUAL(j2.type(), t);
    BOOST_CHECK_EQUAL(j, j2);
    T val2 = json_cast<T>(j2);
    BOOST_CHECK_EQUAL(val, val2);
}

template <class T, json_type TYPE = JSON_INTEGER>
inline void test_conv_num() {
    typedef numeric_limits<T> lim;
    T range[5] = { lim::min(), T(-1), 0, T(1), lim::max() };
    for (unsigned i = 0; i < 5; ++i)
        test_conv<T>(range[i], json(range[i]), TYPE);
}

BOOST_AUTO_TEST_CASE(json_conversions) {
    test_conv<string>(string("hello"), json::str("hello"), JSON_STRING);
    BOOST_CHECK_EQUAL(to_json("world"), json::str("world"));

    test_conv_num<short>();
    test_conv_num<int>();
    test_conv_num<long>();
    test_conv_num<long long>();
    test_conv_num<unsigned short>();
    test_conv_num<unsigned>();
#if ULONG_MAX < LLONG_MAX
    test_conv_num<unsigned long>();
#endif

    test_conv_num<double, JSON_REAL>();
    test_conv_num<float,  JSON_REAL>();

    test_conv<bool>(true,  json::jtrue(),  JSON_TRUE);
    test_conv<bool>(false, json::jfalse(), JSON_FALSE);
}

BOOST_AUTO_TEST_CASE(json_create) {
    json obj1({});
    BOOST_CHECK(obj1);
    obj1.set("test", "set");
    BOOST_CHECK(obj1.get("test"));
    json root{
        {"obj1", obj1}
    };
    BOOST_CHECK_EQUAL(root.get("obj1"), obj1);
    obj1.set("this", "that");
    BOOST_CHECK_EQUAL(root.get("obj1").get("this").str(), "that");
    json obj2{ {"answer", 42} };
    obj1.set("obj2", obj2);
    BOOST_CHECK_EQUAL(root.get("obj1").get("obj2"), obj2);
}

#ifdef TEN_JSON_CXX11

struct corge {
    int foo, bar;

    corge() : foo(), bar() {}
    corge(int foo_, int bar_) : foo(foo_), bar(bar_) {}
};
template <class AR>
inline void serialize(AR &ar, corge &c) {
    ar & kv("foo", c.foo) & kv("bar", c.bar);
}
inline bool operator == (const corge &a, const corge &b) {
    return a.foo == b.foo && a.bar == b.bar;
}

enum captain { kirk, picard, janeway, sisko };
const array<string, 4> captain_names = {{ "kirk", "picard", "janeway", "sisko" }};
template <class AR>
inline void serialize(AR &ar, captain &c) {
    serialize_enum(ar, c, captain_names);
}

BOOST_AUTO_TEST_CASE(json_serial) {
    corge c1(42, 17);
    auto j = jsave_all(c1);
    corge c2;
    json_loader(j) >> c2;
    BOOST_CHECK(c1 == c2);

    map<string, int> m;
    json_loader(j) >> m;
    BOOST_CHECK_EQUAL(m.size(), 2);
    BOOST_CHECK(m.find("foo") != m.end());
    BOOST_CHECK(m.find("bar") != m.end());
    BOOST_CHECK_EQUAL(m["foo"], 42);
    BOOST_CHECK_EQUAL(m["bar"], 17);

#if BOOST_VERSION >= 104800
    flat_map<string, int> f;
    json_loader(j) >> f;
    BOOST_CHECK_EQUAL(f.size(), 2);
    BOOST_CHECK(f.find("foo") != f.end());
    BOOST_CHECK(f.find("bar") != f.end());
    BOOST_CHECK_EQUAL(f["foo"], 42);
    BOOST_CHECK_EQUAL(f["bar"], 17);
#endif

    maybe<int> a;
    j = jsave_all(a);
    BOOST_CHECK(!j);
    a = 42;
    j = jsave_all(a);
    BOOST_CHECK_EQUAL(j, 42);

    a.reset();
    BOOST_CHECK(!a.ok());
    j = 17;
    json_loader(j) >> a;
    BOOST_CHECK(a.ok());
    BOOST_CHECK_EQUAL(a.get(), 17);

    captain c = janeway;
    j = jsave_all(c);
    BOOST_CHECK_EQUAL(j, "janeway");
    j = "kirk";
    json_loader(j) >> c;
    BOOST_CHECK_EQUAL(c, kirk);
}

#endif // TEN_JSON_CXX11
<|endoftext|>


<commit_before>#include <limits>

#include <scomplex/types.hpp>
#include <scomplex/simplicial_complex.hpp>
#include <scomplex/chain_calc.hpp>
#include <scomplex/coeff_flow.hpp>
#include <scomplex/path_snapper.hpp>
#include <scomplex/clusterer.hpp>

namespace gsimp {
struct clusterer::impl {
    std::shared_ptr<simplicial_complex> s_comp;
    std::shared_ptr<path_snapper> p_snap;
    std::shared_ptr<bounding_chain> b_calc;

    std::vector<std::vector<point_t>> paths;
    std::vector<chain_t> path_chains;

    std::vector<int> homology_clusters;

    impl(simplicial_complex& sc) {
        s_comp =
            std::shared_ptr<simplicial_complex>(new simplicial_complex(sc));
        p_snap = std::shared_ptr<path_snapper>(new path_snapper(s_comp));
    }

    impl(path_snapper& psnap) {
        p_snap = std::shared_ptr<path_snapper>(new path_snapper(psnap));
        s_comp = p_snap->get_underlying_complex();
    }

    impl(std::shared_ptr<path_snapper> psnap) {
        p_snap = psnap;
        s_comp = p_snap->get_underlying_complex();
    }

    impl(std::shared_ptr<simplicial_complex> sc) {
        s_comp = sc;
        p_snap = std::shared_ptr<path_snapper>(new path_snapper(s_comp));
    }

    ~impl() {}

    bool have_homologies() { return homology_clusters.size() == paths.size(); }

    void calculate_homologies() {}

    void calculate_chains() {
        // get the bounding chain if it isn't there already
        b_calc = std::shared_ptr<bounding_chain>(new bounding_chain(s_comp));
        for (size_t i = 0; i < paths.size(); ++i) {
            for (size_t j = i + 1; j < paths.size(); ++j) {
                chain_t chain = subtract(path_chains[i], path_chains[i]);
                b_calc->get_bounding_chain(chain);
            }
        }
    }

    void add_path(std::vector<point_t> path) {
        paths.push_back(path);
        path_chains.push_back(p_snap->snap_path_to_chain(path));
    }
};

clusterer::clusterer(simplicial_complex& sc) {
    p_impl = std::shared_ptr<impl>(new impl(sc));
}
clusterer::clusterer(path_snapper& ps) {
    p_impl = std::shared_ptr<impl>(new impl(ps));
}

clusterer::clusterer(std::shared_ptr<simplicial_complex> sc) {
    p_impl = std::shared_ptr<impl>(new impl(sc));
}
clusterer::clusterer(std::shared_ptr<path_snapper> ps) {
    p_impl = std::shared_ptr<impl>(new impl(ps));
}

clusterer::clusterer(clusterer& other) { p_impl = other.p_impl; }
clusterer::~clusterer() {}

clusterer& clusterer::operator=(const clusterer& other) {
    p_impl = other.p_impl;
    return *this;
}

// adds a path to the clusterer object
void clusterer::add_path(std::vector<point_t> path) { p_impl->add_path(path); }

// returns a vector where the i-th entry, is the number of the homology
// cluster the i-th path is in
std::vector<int> clusterer::get_homology_clusters() {
    if (!p_impl->have_homologies()) p_impl->calculate_homologies();
    return p_impl->homology_clusters;
}

// returns the vector of pairwise distances between the paths in the
// clusterer object
std::vector<double> clusterer::get_dist_array() {}

std::vector<point_t> clusterer::get_path(size_t i) { return p_impl->paths[i]; }

chain_t clusterer::get_chain(size_t) { }

chain_t clusterer::get_bounding_chain(size_t, size_t) {}

};
<commit_msg>cleaning<commit_after><|endoftext|>


<commit_before>#ifndef VEXCL_UTIL_HPP
#define VEXCL_UTIL_HPP

/*
The MIT License

Copyright (c) 2012-2013 Denis Demidov <ddemidov@ksu.ru>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

/**
 * \file   vexcl/util.hpp
 * \author Denis Demidov <ddemidov@ksu.ru>
 * \brief  OpenCL general utilities.
 */

#ifdef WIN32
#  pragma warning(push)
#  pragma warning(disable : 4267 4290)
#  define NOMINMAX
#endif

#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
#include <type_traits>
#include <functional>
#include <climits>
#include <stdexcept>
#include <boost/config.hpp>

#ifndef __CL_ENABLE_EXCEPTIONS
#  define __CL_ENABLE_EXCEPTIONS
#endif
#include <CL/cl.hpp>
#include <vexcl/types.hpp>

typedef unsigned int  uint;
typedef unsigned char uchar;

namespace vex {

/// Convert typename to string.
template <class T> inline std::string type_name() {
    throw std::logic_error("Trying to use an undefined type in a kernel.");
}

/// Declares a type as CL native, allows using it as a literal.
template <class T> struct is_cl_native : std::false_type {};

#define STRINGIFY(type) \
template <> inline std::string type_name<cl_##type>() { return #type; } \
template <> struct is_cl_native<cl_##type> : std::true_type {};

// enable use of OpenCL vector types as literals
#define CL_VEC_TYPE(type, len) \
template <> inline std::string type_name<cl_##type##len>() { return #type #len; } \
template <> struct is_cl_native<cl_##type##len> : std::true_type {};

#define CL_TYPES(type) \
STRINGIFY(type); \
CL_VEC_TYPE(type, 2); \
CL_VEC_TYPE(type, 4); \
CL_VEC_TYPE(type, 8); \
CL_VEC_TYPE(type, 16);

CL_TYPES(float);
CL_TYPES(double);
CL_TYPES(char);  CL_TYPES(uchar);
CL_TYPES(short); CL_TYPES(ushort);
CL_TYPES(int);   CL_TYPES(uint);
CL_TYPES(long);  CL_TYPES(ulong);
#undef CL_TYPES
#undef CL_VEC_TYPE
#undef STRINGIFY

const std::string standard_kernel_header = std::string(
        "#if defined(cl_khr_fp64)\n"
        "#  pragma OPENCL EXTENSION cl_khr_fp64: enable\n"
        "#elif defined(cl_amd_fp64)\n"
        "#  pragma OPENCL EXTENSION cl_amd_fp64: enable\n"
        "#endif\n"
        );

/// \cond INTERNAL

/// Binary operations with their traits.
namespace binop {
    enum kind {
        Add,
        Subtract,
        Multiply,
        Divide,
        Remainder,
        Greater,
        Less,
        GreaterEqual,
        LessEqual,
        Equal,
        NotEqual,
        BitwiseAnd,
        BitwiseOr,
        BitwiseXor,
        LogicalAnd,
        LogicalOr,
        RightShift,
        LeftShift
    };

    template <kind> struct traits {};

#define BOP_TRAITS(kind, op, nm)   \
    template <> struct traits<kind> {  \
        static std::string oper() { return op; } \
        static std::string name() { return nm; } \
    };

    BOP_TRAITS(Add,          "+",  "Add_")
    BOP_TRAITS(Subtract,     "-",  "Sub_")
    BOP_TRAITS(Multiply,     "*",  "Mul_")
    BOP_TRAITS(Divide,       "/",  "Div_")
    BOP_TRAITS(Remainder,    "%",  "Mod_")
    BOP_TRAITS(Greater,      ">",  "Gtr_")
    BOP_TRAITS(Less,         "<",  "Lss_")
    BOP_TRAITS(GreaterEqual, ">=", "Geq_")
    BOP_TRAITS(LessEqual,    "<=", "Leq_")
    BOP_TRAITS(Equal,        "==", "Equ_")
    BOP_TRAITS(NotEqual,     "!=", "Neq_")
    BOP_TRAITS(BitwiseAnd,   "&",  "BAnd_")
    BOP_TRAITS(BitwiseOr,    "|",  "BOr_")
    BOP_TRAITS(BitwiseXor,   "^",  "BXor_")
    BOP_TRAITS(LogicalAnd,   "&&", "LAnd_")
    BOP_TRAITS(LogicalOr,    "||", "LOr_")
    BOP_TRAITS(RightShift,   ">>", "Rsh_")
    BOP_TRAITS(LeftShift,    "<<", "Lsh_")

#undef BOP_TRAITS
}

/// \endcond

/// Return next power of 2.
inline size_t nextpow2(size_t x) {
    --x;
    x |= x >> 1U;
    x |= x >> 2U;
    x |= x >> 4U;
    x |= x >> 8U;
    x |= x >> 16U;
    return ++x;
}

/// Align n to the next multiple of m.
inline size_t alignup(size_t n, size_t m = 16U) {
    return n % m ? n - n % m + m : n;
}

/// Iterate over tuple elements.
template <size_t I, class Function, class Tuple>
typename std::enable_if<(I == std::tuple_size<Tuple>::value), void>::type
for_each(const Tuple &, Function &)
{ }

/// Iterate over tuple elements.
template <size_t I, class Function, class Tuple>
typename std::enable_if<(I < std::tuple_size<Tuple>::value), void>::type
for_each(const Tuple &v, Function &f)
{
    f( std::get<I>(v) );

    for_each<I + 1>(v, f);
}

/// Create and build a program from source string.
inline cl::Program build_sources(
        const cl::Context &context, const std::string &source
        )
{
    cl::Program program(context, cl::Program::Sources(
                1, std::make_pair(source.c_str(), source.size())
                ));

    auto device = context.getInfo<CL_CONTEXT_DEVICES>();

    try {
        program.build(device);
    } catch(const cl::Error&) {
        std::cerr << source
                  << std::endl
                  << program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(device[0])
                  << std::endl;
        throw;
    }

    return program;
}

/// Get maximum possible workgroup size for given kernel.
inline uint kernel_workgroup_size(
        const cl::Kernel &kernel,
        const cl::Device &device
        )
{
    size_t wgsz = 1024U;

    uint dev_wgsz = kernel.getWorkGroupInfo<CL_KERNEL_WORK_GROUP_SIZE>(device);
    while(wgsz > dev_wgsz) wgsz /= 2;

    return wgsz;
}

/// Shortcut for q.getInfo<CL_QUEUE_CONTEXT>()
inline cl::Context qctx(const cl::CommandQueue& q) {
    cl::Context ctx;
    q.getInfo(CL_QUEUE_CONTEXT, &ctx);
    return ctx;
}

/// Shortcut for q.getInfo<CL_QUEUE_DEVICE>()
inline cl::Device qdev(const cl::CommandQueue& q) {
    cl::Device dev;
    q.getInfo(CL_QUEUE_DEVICE, &dev);
    return dev;
}

struct column_owner {
    const std::vector<size_t> ∂

    column_owner(const std::vector<size_t> &part) : part(part) {}

    size_t operator()(size_t c) const {
        return std::upper_bound(part.begin(), part.end(), c)
            - part.begin() - 1;
    }
};

} // namespace vex

/// Output description of an OpenCL error to a stream.
inline std::ostream& operator<<(std::ostream &os, const cl::Error &e) {
    os << e.what() << "(";

    switch (e.err()) {
        case 0:
            os << "Success";
            break;
        case -1:
            os << "Device not found";
            break;
        case -2:
            os << "Device not available";
            break;
        case -3:
            os << "Compiler not available";
            break;
        case -4:
            os << "Mem object allocation failure";
            break;
        case -5:
            os << "Out of resources";
            break;
        case -6:
            os << "Out of host memory";
            break;
        case -7:
            os << "Profiling info not available";
            break;
        case -8:
            os << "Mem copy overlap";
            break;
        case -9:
            os << "Image format mismatch";
            break;
        case -10:
            os << "Image format not supported";
            break;
        case -11:
            os << "Build program failure";
            break;
        case -12:
            os << "Map failure";
            break;
        case -13:
            os << "Misaligned sub buffer offset";
            break;
        case -14:
            os << "Exec status error for events in wait list";
            break;
        case -30:
            os << "Invalid value";
            break;
        case -31:
            os << "Invalid device type";
            break;
        case -32:
            os << "Invalid platform";
            break;
        case -33:
            os << "Invalid device";
            break;
        case -34:
            os << "Invalid context";
            break;
        case -35:
            os << "Invalid queue properties";
            break;
        case -36:
            os << "Invalid command queue";
            break;
        case -37:
            os << "Invalid host ptr";
            break;
        case -38:
            os << "Invalid mem object";
            break;
        case -39:
            os << "Invalid image format descriptor";
            break;
        case -40:
            os << "Invalid image size";
            break;
        case -41:
            os << "Invalid sampler";
            break;
        case -42:
            os << "Invalid binary";
            break;
        case -43:
            os << "Invalid build options";
            break;
        case -44:
            os << "Invalid program";
            break;
        case -45:
            os << "Invalid program executable";
            break;
        case -46:
            os << "Invalid kernel name";
            break;
        case -47:
            os << "Invalid kernel definition";
            break;
        case -48:
            os << "Invalid kernel";
            break;
        case -49:
            os << "Invalid arg index";
            break;
        case -50:
            os << "Invalid arg value";
            break;
        case -51:
            os << "Invalid arg size";
            break;
        case -52:
            os << "Invalid kernel args";
            break;
        case -53:
            os << "Invalid work dimension";
            break;
        case -54:
            os << "Invalid work group size";
            break;
        case -55:
            os << "Invalid work item size";
            break;
        case -56:
            os << "Invalid global offset";
            break;
        case -57:
            os << "Invalid event wait list";
            break;
        case -58:
            os << "Invalid event";
            break;
        case -59:
            os << "Invalid operation";
            break;
        case -60:
            os << "Invalid gl object";
            break;
        case -61:
            os << "Invalid buffer size";
            break;
        case -62:
            os << "Invalid mip level";
            break;
        case -63:
            os << "Invalid global work size";
            break;
        case -64:
            os << "Invalid property";
            break;
        default:
            os << "Unknown error";
            break;
    }

    return os << ")";
}

#ifdef WIN32
#  pragma warning(pop)
#endif

// vim: et
#endif
<commit_msg>MacOSX's size_t is defined differently<commit_after>#ifndef VEXCL_UTIL_HPP
#define VEXCL_UTIL_HPP

/*
The MIT License

Copyright (c) 2012-2013 Denis Demidov <ddemidov@ksu.ru>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

/**
 * \file   vexcl/util.hpp
 * \author Denis Demidov <ddemidov@ksu.ru>
 * \brief  OpenCL general utilities.
 */

#ifdef WIN32
#  pragma warning(push)
#  pragma warning(disable : 4267 4290)
#  define NOMINMAX
#endif

#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
#include <type_traits>
#include <functional>
#include <climits>
#include <stdexcept>
#include <limits>
#include <boost/config.hpp>
#include <boost/type_traits/is_same.hpp>

#ifndef __CL_ENABLE_EXCEPTIONS
#  define __CL_ENABLE_EXCEPTIONS
#endif
#include <CL/cl.hpp>
#include <vexcl/types.hpp>

typedef unsigned int  uint;
typedef unsigned char uchar;

namespace vex {

/// Convert typename to string.
template <class T, class E = void> inline std::string type_name() {
    throw std::logic_error("Trying to use an undefined type in a kernel.");
}

/// Declares a type as CL native, allows using it as a literal.
template <class T> struct is_cl_native : std::false_type {};

#define STRINGIFY(type) \
template <> inline std::string type_name<cl_##type>() { return #type; } \
template <> struct is_cl_native<cl_##type> : std::true_type {};

// enable use of OpenCL vector types as literals
#define CL_VEC_TYPE(type, len) \
template <> inline std::string type_name<cl_##type##len>() { return #type #len; } \
template <> struct is_cl_native<cl_##type##len> : std::true_type {};

#define CL_TYPES(type) \
STRINGIFY(type); \
CL_VEC_TYPE(type, 2); \
CL_VEC_TYPE(type, 4); \
CL_VEC_TYPE(type, 8); \
CL_VEC_TYPE(type, 16);

CL_TYPES(float);
CL_TYPES(double);
CL_TYPES(char);  CL_TYPES(uchar);
CL_TYPES(short); CL_TYPES(ushort);
CL_TYPES(int);   CL_TYPES(uint);
CL_TYPES(long);  CL_TYPES(ulong);
#undef CL_TYPES
#undef CL_VEC_TYPE
#undef STRINGIFY

template <> inline std::string type_name<size_t, typename
    std::enable_if<!boost::is_same<size_t, cl_uint>::value
    && !boost::is_same<size_t, cl_ulong>::value>::type>() {
    return std::numeric_limits<std::size_t>::max() ==
        std::numeric_limits<uint>::max() ? "uint" : "ulong";
}
template <> struct is_cl_native<size_t> : std::true_type {};

const std::string standard_kernel_header = std::string(
        "#if defined(cl_khr_fp64)\n"
        "#  pragma OPENCL EXTENSION cl_khr_fp64: enable\n"
        "#elif defined(cl_amd_fp64)\n"
        "#  pragma OPENCL EXTENSION cl_amd_fp64: enable\n"
        "#endif\n"
        );

/// \cond INTERNAL

/// Binary operations with their traits.
namespace binop {
    enum kind {
        Add,
        Subtract,
        Multiply,
        Divide,
        Remainder,
        Greater,
        Less,
        GreaterEqual,
        LessEqual,
        Equal,
        NotEqual,
        BitwiseAnd,
        BitwiseOr,
        BitwiseXor,
        LogicalAnd,
        LogicalOr,
        RightShift,
        LeftShift
    };

    template <kind> struct traits {};

#define BOP_TRAITS(kind, op, nm)   \
    template <> struct traits<kind> {  \
        static std::string oper() { return op; } \
        static std::string name() { return nm; } \
    };

    BOP_TRAITS(Add,          "+",  "Add_")
    BOP_TRAITS(Subtract,     "-",  "Sub_")
    BOP_TRAITS(Multiply,     "*",  "Mul_")
    BOP_TRAITS(Divide,       "/",  "Div_")
    BOP_TRAITS(Remainder,    "%",  "Mod_")
    BOP_TRAITS(Greater,      ">",  "Gtr_")
    BOP_TRAITS(Less,         "<",  "Lss_")
    BOP_TRAITS(GreaterEqual, ">=", "Geq_")
    BOP_TRAITS(LessEqual,    "<=", "Leq_")
    BOP_TRAITS(Equal,        "==", "Equ_")
    BOP_TRAITS(NotEqual,     "!=", "Neq_")
    BOP_TRAITS(BitwiseAnd,   "&",  "BAnd_")
    BOP_TRAITS(BitwiseOr,    "|",  "BOr_")
    BOP_TRAITS(BitwiseXor,   "^",  "BXor_")
    BOP_TRAITS(LogicalAnd,   "&&", "LAnd_")
    BOP_TRAITS(LogicalOr,    "||", "LOr_")
    BOP_TRAITS(RightShift,   ">>", "Rsh_")
    BOP_TRAITS(LeftShift,    "<<", "Lsh_")

#undef BOP_TRAITS
}

/// \endcond

/// Return next power of 2.
inline size_t nextpow2(size_t x) {
    --x;
    x |= x >> 1U;
    x |= x >> 2U;
    x |= x >> 4U;
    x |= x >> 8U;
    x |= x >> 16U;
    return ++x;
}

/// Align n to the next multiple of m.
inline size_t alignup(size_t n, size_t m = 16U) {
    return n % m ? n - n % m + m : n;
}

/// Iterate over tuple elements.
template <size_t I, class Function, class Tuple>
typename std::enable_if<(I == std::tuple_size<Tuple>::value), void>::type
for_each(const Tuple &, Function &)
{ }

/// Iterate over tuple elements.
template <size_t I, class Function, class Tuple>
typename std::enable_if<(I < std::tuple_size<Tuple>::value), void>::type
for_each(const Tuple &v, Function &f)
{
    f( std::get<I>(v) );

    for_each<I + 1>(v, f);
}

/// Create and build a program from source string.
inline cl::Program build_sources(
        const cl::Context &context, const std::string &source
        )
{
    cl::Program program(context, cl::Program::Sources(
                1, std::make_pair(source.c_str(), source.size())
                ));

    auto device = context.getInfo<CL_CONTEXT_DEVICES>();

    try {
        program.build(device);
    } catch(const cl::Error&) {
        std::cerr << source
                  << std::endl
                  << program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(device[0])
                  << std::endl;
        throw;
    }

    return program;
}

/// Get maximum possible workgroup size for given kernel.
inline uint kernel_workgroup_size(
        const cl::Kernel &kernel,
        const cl::Device &device
        )
{
    size_t wgsz = 1024U;

    uint dev_wgsz = kernel.getWorkGroupInfo<CL_KERNEL_WORK_GROUP_SIZE>(device);
    while(wgsz > dev_wgsz) wgsz /= 2;

    return wgsz;
}

/// Shortcut for q.getInfo<CL_QUEUE_CONTEXT>()
inline cl::Context qctx(const cl::CommandQueue& q) {
    cl::Context ctx;
    q.getInfo(CL_QUEUE_CONTEXT, &ctx);
    return ctx;
}

/// Shortcut for q.getInfo<CL_QUEUE_DEVICE>()
inline cl::Device qdev(const cl::CommandQueue& q) {
    cl::Device dev;
    q.getInfo(CL_QUEUE_DEVICE, &dev);
    return dev;
}

struct column_owner {
    const std::vector<size_t> ∂

    column_owner(const std::vector<size_t> &part) : part(part) {}

    size_t operator()(size_t c) const {
        return std::upper_bound(part.begin(), part.end(), c)
            - part.begin() - 1;
    }
};

} // namespace vex

/// Output description of an OpenCL error to a stream.
inline std::ostream& operator<<(std::ostream &os, const cl::Error &e) {
    os << e.what() << "(";

    switch (e.err()) {
        case 0:
            os << "Success";
            break;
        case -1:
            os << "Device not found";
            break;
        case -2:
            os << "Device not available";
            break;
        case -3:
            os << "Compiler not available";
            break;
        case -4:
            os << "Mem object allocation failure";
            break;
        case -5:
            os << "Out of resources";
            break;
        case -6:
            os << "Out of host memory";
            break;
        case -7:
            os << "Profiling info not available";
            break;
        case -8:
            os << "Mem copy overlap";
            break;
        case -9:
            os << "Image format mismatch";
            break;
        case -10:
            os << "Image format not supported";
            break;
        case -11:
            os << "Build program failure";
            break;
        case -12:
            os << "Map failure";
            break;
        case -13:
            os << "Misaligned sub buffer offset";
            break;
        case -14:
            os << "Exec status error for events in wait list";
            break;
        case -30:
            os << "Invalid value";
            break;
        case -31:
            os << "Invalid device type";
            break;
        case -32:
            os << "Invalid platform";
            break;
        case -33:
            os << "Invalid device";
            break;
        case -34:
            os << "Invalid context";
            break;
        case -35:
            os << "Invalid queue properties";
            break;
        case -36:
            os << "Invalid command queue";
            break;
        case -37:
            os << "Invalid host ptr";
            break;
        case -38:
            os << "Invalid mem object";
            break;
        case -39:
            os << "Invalid image format descriptor";
            break;
        case -40:
            os << "Invalid image size";
            break;
        case -41:
            os << "Invalid sampler";
            break;
        case -42:
            os << "Invalid binary";
            break;
        case -43:
            os << "Invalid build options";
            break;
        case -44:
            os << "Invalid program";
            break;
        case -45:
            os << "Invalid program executable";
            break;
        case -46:
            os << "Invalid kernel name";
            break;
        case -47:
            os << "Invalid kernel definition";
            break;
        case -48:
            os << "Invalid kernel";
            break;
        case -49:
            os << "Invalid arg index";
            break;
        case -50:
            os << "Invalid arg value";
            break;
        case -51:
            os << "Invalid arg size";
            break;
        case -52:
            os << "Invalid kernel args";
            break;
        case -53:
            os << "Invalid work dimension";
            break;
        case -54:
            os << "Invalid work group size";
            break;
        case -55:
            os << "Invalid work item size";
            break;
        case -56:
            os << "Invalid global offset";
            break;
        case -57:
            os << "Invalid event wait list";
            break;
        case -58:
            os << "Invalid event";
            break;
        case -59:
            os << "Invalid operation";
            break;
        case -60:
            os << "Invalid gl object";
            break;
        case -61:
            os << "Invalid buffer size";
            break;
        case -62:
            os << "Invalid mip level";
            break;
        case -63:
            os << "Invalid global work size";
            break;
        case -64:
            os << "Invalid property";
            break;
        default:
            os << "Unknown error";
            break;
    }

    return os << ")";
}

#ifdef WIN32
#  pragma warning(pop)
#endif

// vim: et
#endif
<|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2014-2020 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#pragma once

// Handle master flags first

#ifdef ETL_CUDA
static_assert(false, "ETL_CUDA should never be set directly");
#endif

#ifdef ETL_VECTORIZE_FULL

//VECTORIZE_FULL enables VECTORIZE_EXPR
#ifndef ETL_VECTORIZE_EXPR
#define ETL_VECTORIZE_EXPR
#endif

//VECTORIZE_FULL enables VECTORIZE_IMPL
#ifndef ETL_VECTORIZE_IMPL
#define ETL_VECTORIZE_IMPL
#endif

#endif //ETL_VECTORIZE_FULL

//MKL mode enables BLAS mode
#ifdef ETL_MKL_MODE
#ifndef ETL_BLAS_MODE
#define ETL_BLAS_MODE
#endif
#endif

// ETL_GPU enabled all GPU flags
#ifdef ETL_GPU

#ifndef ETL_CUBLAS_MODE
#define ETL_CUBLAS_MODE
#endif

#ifndef ETL_CUFFT_MODE
#define ETL_CUFFT_MODE
#endif

#ifndef ETL_CURAND_MODE
#define ETL_CURAND_MODE
#endif

#ifndef ETL_CUDNN_MODE
#define ETL_CUDNN_MODE
#endif

#endif

// ETL_PARALLEL defines ETL_PARALLEL_SUPPORT
#ifdef ETL_PARALLEL
#ifndef ETL_PARALLEL_SUPPORT
#define ETL_PARALLEL_SUPPORT
#endif
#endif

// EGBLAS does not make sense without CUBLAS
#ifdef ETL_EGBLAS_MODE
#ifndef ETL_CUBLAS_MODE
static_assert(false, "EGBLAS is only intended to work with CUBLAS, not alone");
#endif
#endif

// Convert all the defines to booleans

#ifdef ETL_MANUAL_SELECT
#define ETL_MANUAL_SELECT_BOOL true
#define constexpr_select
#else
#define ETL_MANUAL_SELECT_BOOL false
#define constexpr_select constexpr
#endif

#ifdef ETL_VECTORIZE_EXPR
#define ETL_VECTORIZE_EXPR_BOOL true
#else
#define ETL_VECTORIZE_EXPR_BOOL false
#endif

#ifdef ETL_VECTORIZE_IMPL
#define ETL_VECTORIZE_IMPL_BOOL true
#else
#define ETL_VECTORIZE_IMPL_BOOL false
#endif

#ifdef ETL_CONV_VALID_FFT
#define ETL_CONV_VALID_FFT_BOOL true
#else
#define ETL_CONV_VALID_FFT_BOOL false
#endif

#ifdef ETL_PARALLEL_SUPPORT
#define ETL_PARALLEL_SUPPORT_BOOL true
#else
#define ETL_PARALLEL_SUPPORT_BOOL false
#endif

#ifdef ETL_PARALLEL
#define ETL_PARALLEL_BOOL true
#else
#define ETL_PARALLEL_BOOL false
#endif

#ifdef ETL_MKL_MODE
#define ETL_MKL_MODE_BOOL true
#else
#define ETL_MKL_MODE_BOOL false
#endif

#ifdef ETL_BLAS_MODE
#define ETL_BLAS_MODE_BOOL true
#else
#define ETL_BLAS_MODE_BOOL false
#endif

#ifdef ETL_BLAS_THREADS
#define ETL_BLAS_THREADS_BOOL true
#else
#define ETL_BLAS_THREADS_BOOL false
#endif

#ifdef ETL_CUBLAS_MODE
#define ETL_CUDA
#define ETL_CUBLAS_MODE_BOOL true
#else
#define ETL_CUBLAS_MODE_BOOL false
#endif

#ifdef ETL_CURAND_MODE
#define ETL_CUDA
#define ETL_CURAND_MODE_BOOL true
#else
#define ETL_CURAND_MODE_BOOL false
#endif

#ifdef ETL_CUFFT_MODE
#define ETL_CUDA
#define ETL_CUFFT_MODE_BOOL true
#else
#define ETL_CUFFT_MODE_BOOL false
#endif

#ifdef ETL_CUDNN_MODE
#define ETL_CUDA
#define ETL_CUDNN_MODE_BOOL true
#else
#define ETL_CUDNN_MODE_BOOL false
#endif

#ifdef ETL_CUDA
#define ETL_CUDA_BOOL true
#else
#define ETL_CUDA_BOOL false
#endif

#ifdef ETL_EGBLAS_MODE
#define ETL_EGBLAS_MODE_BOOL true
#else
#define ETL_EGBLAS_MODE_BOOL false
#endif

#ifdef ETL_STRICT_DIV
#define ETL_STRICT_DIV_BOOL true
#else
#define ETL_STRICT_DIV_BOOL false
#endif

#ifdef ETL_NO_STREAMING
#define ETL_NO_STREAMING_BOOL true
#else
#define ETL_NO_STREAMING_BOOL false
#endif

#ifdef ETL_NO_PADDING
#define ETL_NO_PADDING_BOOL true
#else
#define ETL_NO_PADDING_BOOL false
#endif

#ifdef ETL_ADVANCED_PADDING
#define ETL_ADVANCED_PADDING_BOOL true
#else
#define ETL_ADVANCED_PADDING_BOOL false
#endif

#ifdef ETL_NO_PADDING_IMPL
#define ETL_NO_PADDING_IMPL_BOOL true
#else
#define ETL_NO_PADDING_IMPL_BOOL false
#endif

#ifdef ETL_NO_UNROLL_NON_VECT
#define ETL_NO_UNROLL_NON_VECT_BOOL true
#else
#define ETL_NO_UNROLL_NON_VECT_BOOL false
#endif

#ifdef __INTEL_COMPILER
#define ETL_INTEL_COMPILER_BOOL true
#else
#define ETL_INTEL_COMPILER_BOOL false
#endif

// Vectorization detection

#ifdef __AVX512F__
#define ETL_VECTOR_MODE vector_mode_t::AVX512
#elif defined(__AVX__)
#define ETL_VECTOR_MODE vector_mode_t::AVX
#elif defined(__SSE3__)
#define ETL_VECTOR_MODE vector_mode_t::SSE3
#else
#define ETL_VECTOR_MODE vector_mode_t::NONE
#endif

#ifdef __AVX512F__
#define ETL_AVX512_BOOL true
#else
#define ETL_AVX512_BOOL false
#endif

#ifdef __AVX2__
#define ETL_AVX2_BOOL true
#else
#define ETL_AVX2_BOOL false
#endif

#ifdef __AVX__
#define ETL_AVX_BOOL true
#else
#define ETL_AVX_BOOL false
#endif

#ifdef __SSE3__
#define ETL_SSE3_BOOL true
#else
#define ETL_SSE3_BOOL false
#endif

// Configuration flags with values

#define ETL_DEFAULT_CACHE_SIZE 3UL * 1024 * 1024
#define ETL_DEFAULT_MAX_WORKSPACE 2UL * 1024 * 1024 * 1024
#define ETL_DEFAULT_CUDNN_MAX_WORKSPACE 2UL * 1024 * 1024 * 1024
#define ETL_DEFAULT_PARALLEL_THREADS std::thread::hardware_concurrency()

#ifndef ETL_CACHE_SIZE
#define ETL_CACHE_SIZE ETL_DEFAULT_CACHE_SIZE
#endif

#ifndef ETL_MAX_WORKSPACE
#define ETL_MAX_WORKSPACE ETL_DEFAULT_MAX_WORKSPACE
#endif

#ifndef ETL_CUDNN_MAX_WORKSPACE
#define ETL_CUDNN_MAX_WORKSPACE ETL_DEFAULT_CUDNN_MAX_WORKSPACE
#endif

#ifndef ETL_PARALLEL_THREADS
#define ETL_PARALLEL_THREADS ETL_DEFAULT_PARALLEL_THREADS
#endif
<commit_msg>Review config for egblas<commit_after>//=======================================================================
// Copyright (c) 2014-2020 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#pragma once

// Handle master flags first

#ifdef ETL_CUDA
static_assert(false, "ETL_CUDA should never be set directly");
#endif

#ifdef ETL_VECTORIZE_FULL

//VECTORIZE_FULL enables VECTORIZE_EXPR
#ifndef ETL_VECTORIZE_EXPR
#define ETL_VECTORIZE_EXPR
#endif

//VECTORIZE_FULL enables VECTORIZE_IMPL
#ifndef ETL_VECTORIZE_IMPL
#define ETL_VECTORIZE_IMPL
#endif

#endif //ETL_VECTORIZE_FULL

//MKL mode enables BLAS mode
#ifdef ETL_MKL_MODE
#ifndef ETL_BLAS_MODE
#define ETL_BLAS_MODE
#endif
#endif

// ETL_GPU enabled all GPU flags
#ifdef ETL_GPU

#ifndef ETL_CUBLAS_MODE
#define ETL_CUBLAS_MODE
#endif

#ifndef ETL_CUFFT_MODE
#define ETL_CUFFT_MODE
#endif

#ifndef ETL_CURAND_MODE
#define ETL_CURAND_MODE
#endif

#ifndef ETL_CUDNN_MODE
#define ETL_CUDNN_MODE
#endif

#endif

// ETL_PARALLEL defines ETL_PARALLEL_SUPPORT
#ifdef ETL_PARALLEL
#ifndef ETL_PARALLEL_SUPPORT
#define ETL_PARALLEL_SUPPORT
#endif
#endif

// EGBLAS does not make sense without CUBLAS
#ifdef ETL_EGBLAS_MODE
#ifndef ETL_CUBLAS_MODE
static_assert(false, "EGBLAS is only intended to work with CUBLAS, not alone");
#endif
#endif

// Convert all the defines to booleans

#ifdef ETL_MANUAL_SELECT
#define ETL_MANUAL_SELECT_BOOL true
#define constexpr_select
#else
#define ETL_MANUAL_SELECT_BOOL false
#define constexpr_select constexpr
#endif

#ifdef ETL_VECTORIZE_EXPR
#define ETL_VECTORIZE_EXPR_BOOL true
#else
#define ETL_VECTORIZE_EXPR_BOOL false
#endif

#ifdef ETL_VECTORIZE_IMPL
#define ETL_VECTORIZE_IMPL_BOOL true
#else
#define ETL_VECTORIZE_IMPL_BOOL false
#endif

#ifdef ETL_CONV_VALID_FFT
#define ETL_CONV_VALID_FFT_BOOL true
#else
#define ETL_CONV_VALID_FFT_BOOL false
#endif

#ifdef ETL_PARALLEL_SUPPORT
#define ETL_PARALLEL_SUPPORT_BOOL true
#else
#define ETL_PARALLEL_SUPPORT_BOOL false
#endif

#ifdef ETL_PARALLEL
#define ETL_PARALLEL_BOOL true
#else
#define ETL_PARALLEL_BOOL false
#endif

#ifdef ETL_MKL_MODE
#define ETL_MKL_MODE_BOOL true
#else
#define ETL_MKL_MODE_BOOL false
#endif

#ifdef ETL_BLAS_MODE
#define ETL_BLAS_MODE_BOOL true
#else
#define ETL_BLAS_MODE_BOOL false
#endif

#ifdef ETL_BLAS_THREADS
#define ETL_BLAS_THREADS_BOOL true
#else
#define ETL_BLAS_THREADS_BOOL false
#endif

#ifdef ETL_CUBLAS_MODE
#define ETL_CUDA
#define ETL_CUBLAS_MODE_BOOL true
#else
#define ETL_CUBLAS_MODE_BOOL false
#endif

#ifdef ETL_CURAND_MODE
#define ETL_CUDA
#define ETL_CURAND_MODE_BOOL true
#else
#define ETL_CURAND_MODE_BOOL false
#endif

#ifdef ETL_CUFFT_MODE
#define ETL_CUDA
#define ETL_CUFFT_MODE_BOOL true
#else
#define ETL_CUFFT_MODE_BOOL false
#endif

#ifdef ETL_CUDNN_MODE
#define ETL_CUDA
#define ETL_CUDNN_MODE_BOOL true
#else
#define ETL_CUDNN_MODE_BOOL false
#endif

#ifdef ETL_EGBLAS_MODE
#define ETL_CUDA
#define ETL_EGBLAS_MODE_BOOL true
#else
#define ETL_EGBLAS_MODE_BOOL false
#endif

#ifdef ETL_CUDA
#define ETL_CUDA_BOOL true
#else
#define ETL_CUDA_BOOL false
#endif

#ifdef ETL_STRICT_DIV
#define ETL_STRICT_DIV_BOOL true
#else
#define ETL_STRICT_DIV_BOOL false
#endif

#ifdef ETL_NO_STREAMING
#define ETL_NO_STREAMING_BOOL true
#else
#define ETL_NO_STREAMING_BOOL false
#endif

#ifdef ETL_NO_PADDING
#define ETL_NO_PADDING_BOOL true
#else
#define ETL_NO_PADDING_BOOL false
#endif

#ifdef ETL_ADVANCED_PADDING
#define ETL_ADVANCED_PADDING_BOOL true
#else
#define ETL_ADVANCED_PADDING_BOOL false
#endif

#ifdef ETL_NO_PADDING_IMPL
#define ETL_NO_PADDING_IMPL_BOOL true
#else
#define ETL_NO_PADDING_IMPL_BOOL false
#endif

#ifdef ETL_NO_UNROLL_NON_VECT
#define ETL_NO_UNROLL_NON_VECT_BOOL true
#else
#define ETL_NO_UNROLL_NON_VECT_BOOL false
#endif

#ifdef __INTEL_COMPILER
#define ETL_INTEL_COMPILER_BOOL true
#else
#define ETL_INTEL_COMPILER_BOOL false
#endif

// Vectorization detection

#ifdef __AVX512F__
#define ETL_VECTOR_MODE vector_mode_t::AVX512
#elif defined(__AVX__)
#define ETL_VECTOR_MODE vector_mode_t::AVX
#elif defined(__SSE3__)
#define ETL_VECTOR_MODE vector_mode_t::SSE3
#else
#define ETL_VECTOR_MODE vector_mode_t::NONE
#endif

#ifdef __AVX512F__
#define ETL_AVX512_BOOL true
#else
#define ETL_AVX512_BOOL false
#endif

#ifdef __AVX2__
#define ETL_AVX2_BOOL true
#else
#define ETL_AVX2_BOOL false
#endif

#ifdef __AVX__
#define ETL_AVX_BOOL true
#else
#define ETL_AVX_BOOL false
#endif

#ifdef __SSE3__
#define ETL_SSE3_BOOL true
#else
#define ETL_SSE3_BOOL false
#endif

// Configuration flags with values

#define ETL_DEFAULT_CACHE_SIZE 3UL * 1024 * 1024
#define ETL_DEFAULT_MAX_WORKSPACE 2UL * 1024 * 1024 * 1024
#define ETL_DEFAULT_CUDNN_MAX_WORKSPACE 2UL * 1024 * 1024 * 1024
#define ETL_DEFAULT_PARALLEL_THREADS std::thread::hardware_concurrency()

#ifndef ETL_CACHE_SIZE
#define ETL_CACHE_SIZE ETL_DEFAULT_CACHE_SIZE
#endif

#ifndef ETL_MAX_WORKSPACE
#define ETL_MAX_WORKSPACE ETL_DEFAULT_MAX_WORKSPACE
#endif

#ifndef ETL_CUDNN_MAX_WORKSPACE
#define ETL_CUDNN_MAX_WORKSPACE ETL_DEFAULT_CUDNN_MAX_WORKSPACE
#endif

#ifndef ETL_PARALLEL_THREADS
#define ETL_PARALLEL_THREADS ETL_DEFAULT_PARALLEL_THREADS
#endif
<|endoftext|>


<commit_before>// Copyright (C) 2013 by Antonio El Khoury, CNRS.
//
// This file is part of the hpp-util.
//
// This software is provided "as is" without warranty of any kind,
// either expressed or implied, including but not limited to the
// implied warranties of fitness for a particular purpose.
//
// See the COPYING file for more information.

#ifndef HPP_UTIL_KITELAB_HH
# define HPP_UTIL_KITELAB_HH

/** Defines the four types of smart pointers associated with type <tt>\a t</tt>.
*   If <tt>\a t</tt> is \c CMyClass then
*   - the type of a shared pointer to <tt>\a t</tt> is \c CMyClassShPtr
*   - the type of a weak pointer to <tt>\a t</tt> is \c CMyClassWkPtr
*   - the type of a shared pointer to <tt>\a t const</tt> is \c CMyClassConstShPtr
*   - the type of a weak pointer to <tt>\a t const</tt> is \c CMyClassConstWkPtr
*/
# define HPP_KIT_POINTER_DEFS(t)		 \
  typedef KIT_SHARED_PTR(t) t##ShPtr;		 \
  typedef KIT_WEAK_PTR(t) t##WkPtr;		 \
  typedef KIT_SHARED_PTR_CONST(t) t##ConstShPtr; \
  typedef KIT_WEAK_PTR_CONST(t) t##ConstWkPtr;	 \
  struct e_n_d__w_i_t_h__s_e_m_i_c_o_l_o_n

/** Makes a forward declaration of class <tt>\a t</tt> and of the four
*   types of shared pointers associated with it.
*/
# define HPP_KIT_PREDEF_CLASS(t)		\
  class t;					\
  HPP_KIT_POINTER_DEFS(t);			\
  struct e_n_d__w_i_t_h__s_e_m_i_c_o_l_o_n

/** Macro used to add a CkcdDetector to the default detector list
 *		\param detectorClass Name of a subclass of CkcdDetector.
 *			This class must define a create() static method that
 *			returns a shared pointer to the newly created detector.
 *		\note do not use this macro in the detector's cpp if no reference
 *			to the detector is made outside the class : if linking the library
 *			as a static library, the class may be removed entirely by the linker !
 */
#define HPP_KCD_REGISTER_DETECTOR(detectorClass)	\
  size_t detectorClass##DummyFunctionReturn =		\
    CkcdGlobal::instance().registerDetector		\
    (&CkcdGlobal::createDetector<detectorClass>);	\
  struct e_n_d__w_i_t_h__s_e_m_i_c_o_l_o_n

/** Macro used to add a CkcdTestTreeLocked to the default tree list
*		\param treeClass Name of a subclass of CkcdTestTreeLocked.
*			This class must define a create(const CkcdObjectShPtr&) static method
*			that takes the collision entity as a parameter
*			and returns a shared pointer to the newly created tree.
*		\note do not use this macro in the tree's cpp if no reference
*			to the tree is made outside the class : if linking the library
*			as a static library, the class may be removed entirely by the linker !
*/
#define HPP_KCD_REGISTER_TEST_TREE_LOCKED(treeClass)	\
  size_t treeClass##DummyFunctionReturn =		\
    CkcdGlobal::instance().registerTestTreeLocked	\
    (&CkcdGlobal::createTestTreeLocked<treeClass>);	\
  struct e_n_d__w_i_t_h__s_e_m_i_c_o_l_o_n

#define HPP_KPP_DECLARE_PROPERTY( P )		       \
  static const CkppProperty::TPropertyID P##_PROPERTY; \
  static const std::string P##_PROPERTY_STRING_ID;     \
  struct e_n_d__w_i_t_h__s_e_m_i_c_o_l_o_n

#endif //! HPP_UTIL_KITELAB_HH
<commit_msg>Redefine additionnal kitelab macros.<commit_after>// Copyright (C) 2013 by Antonio El Khoury, CNRS.
//
// This file is part of the hpp-util.
//
// This software is provided "as is" without warranty of any kind,
// either expressed or implied, including but not limited to the
// implied warranties of fitness for a particular purpose.
//
// See the COPYING file for more information.

#ifndef HPP_UTIL_KITELAB_HH
# define HPP_UTIL_KITELAB_HH

/** Defines the four types of smart pointers associated with type <tt>\a t</tt>.
*   If <tt>\a t</tt> is \c CMyClass then
*   - the type of a shared pointer to <tt>\a t</tt> is \c CMyClassShPtr
*   - the type of a weak pointer to <tt>\a t</tt> is \c CMyClassWkPtr
*   - the type of a shared pointer to <tt>\a t const</tt> is \c CMyClassConstShPtr
*   - the type of a weak pointer to <tt>\a t const</tt> is \c CMyClassConstWkPtr
*/
# define HPP_KIT_POINTER_DEFS(t)		 \
  typedef KIT_SHARED_PTR(t) t##ShPtr;		 \
  typedef KIT_WEAK_PTR(t) t##WkPtr;		 \
  typedef KIT_SHARED_PTR_CONST(t) t##ConstShPtr; \
  typedef KIT_WEAK_PTR_CONST(t) t##ConstWkPtr;	 \
  struct e_n_d__w_i_t_h__s_e_m_i_c_o_l_o_n

/** Makes a forward declaration of class <tt>\a t</tt> and of the four
*   types of shared pointers associated with it.
*/
# define HPP_KIT_PREDEF_CLASS(t)		\
  class t;					\
  HPP_KIT_POINTER_DEFS(t);			\
  struct e_n_d__w_i_t_h__s_e_m_i_c_o_l_o_n

# define HPP_KIT_DECLARE_CLASS()		    \
  public: static const CkitClassShPtr CLASS;	    \
  virtual CkitClassShPtr classObject() const;	    \
  static CkitObjectShPtr alloc();		    \
  struct e_n_d__w_i_t_h__s_e_m_i_c_o_l_o_n

#define HPP_KIT_DEFINE_CLASS( C )						\
  const CkitClassShPtr C::CLASS(CkitRuntime::registerClassObject	\
				(CkitClass::create< C >(#C)));		\
  CkitClassShPtr C::classObject() const					\
  {									\
    KIT_ASSERT( isMemberOfClass(CLASS) );				\
    return CLASS;							\
  }									\
  CkitObjectShPtr C::alloc()						\
  {									\
    return CkitObjectShPtr(new C());					\
  }									\
  struct e_n_d__w_i_t_h__s_e_m_i_c_o_l_o_n

/** Macro used to add a CkcdDetector to the default detector list
 *		\param detectorClass Name of a subclass of CkcdDetector.
 *			This class must define a create() static method that
 *			returns a shared pointer to the newly created detector.
 *		\note do not use this macro in the detector's cpp if no reference
 *			to the detector is made outside the class : if linking the library
 *			as a static library, the class may be removed entirely by the linker !
 */
#define HPP_KCD_REGISTER_DETECTOR(detectorClass)	\
  size_t detectorClass##DummyFunctionReturn =		\
    CkcdGlobal::instance().registerDetector		\
    (&CkcdGlobal::createDetector<detectorClass>);	\
  struct e_n_d__w_i_t_h__s_e_m_i_c_o_l_o_n

/** Macro used to add a CkcdTestTreeLocked to the default tree list
*		\param treeClass Name of a subclass of CkcdTestTreeLocked.
*			This class must define a create(const CkcdObjectShPtr&) static method
*			that takes the collision entity as a parameter
*			and returns a shared pointer to the newly created tree.
*		\note do not use this macro in the tree's cpp if no reference
*			to the tree is made outside the class : if linking the library
*			as a static library, the class may be removed entirely by the linker !
*/
#define HPP_KCD_REGISTER_TEST_TREE_LOCKED(treeClass)	\
  size_t treeClass##DummyFunctionReturn =		\
    CkcdGlobal::instance().registerTestTreeLocked	\
    (&CkcdGlobal::createTestTreeLocked<treeClass>);	\
  struct e_n_d__w_i_t_h__s_e_m_i_c_o_l_o_n

#define HPP_KPP_DECLARE_PROPERTY( P )		       \
  static const CkppProperty::TPropertyID P##_PROPERTY; \
  static const std::string P##_PROPERTY_STRING_ID;     \
  struct e_n_d__w_i_t_h__s_e_m_i_c_o_l_o_n

#endif //! HPP_UTIL_KITELAB_HH
<|endoftext|>


<commit_before>/*
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "Client.hxx"
#include "Protocol.hxx"
#include "Builder.hxx"
#include "Parser.hxx"
#include "Prepared.hxx"
#include "mount_list.hxx"
#include "ExitListener.hxx"
#include "system/Error.hxx"
#include "util/RuntimeError.hxx"
#include "util/ScopeExit.hxx"

#include <daemon/log.h>

#include <glib.h>

#include <array>

#include <assert.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>

static constexpr size_t MAX_FDS = 8;

gcc_const
static inline GQuark
spawn_quark(void)
{
    return g_quark_from_static_string("spawn");
}

SpawnServerClient::SpawnServerClient(EventLoop &event_loop,
                                     const SpawnConfig &_config, int _fd)
    :config(_config), fd(_fd),
     read_event(event_loop, fd, EV_READ|EV_PERSIST,
                BIND_THIS_METHOD(OnSocketEvent))
{
    read_event.Add();
}

SpawnServerClient::~SpawnServerClient()
{
    if (fd >= 0)
        Close();
}

void
SpawnServerClient::ReplaceSocket(int new_fd)
{
    assert(fd >= 0);
    assert(new_fd >= 0);
    assert(fd != new_fd);
    assert(!shutting_down);

    processes.clear();

    Close();

    fd = new_fd;

    read_event.Set(fd, EV_READ|EV_PERSIST);
    read_event.Add();
}

void
SpawnServerClient::Close()
{
    assert(fd >= 0);

    read_event.Delete();
    close(fd);
    fd = -1;
}

void
SpawnServerClient::Shutdown()
{
    shutting_down = true;

    if (processes.empty() && fd >= 0)
        Close();
}

void
SpawnServerClient::CheckOrAbort()
{
    if (fd < 0) {
        daemon_log(1, "SpawnChildProcess: the spawner is gone, emergency!\n");
        exit(EXIT_FAILURE);
    }
}

inline void
SpawnServerClient::Send(ConstBuffer<void> payload, ConstBuffer<int> fds)
{
    ::Send<MAX_FDS>(fd, payload, fds);
}

inline void
SpawnServerClient::Send(const SpawnSerializer &s)
{
    ::Send<MAX_FDS>(fd, s);
}

int
SpawnServerClient::Connect()
{
    CheckOrAbort();

    int sv[2];
    if (socketpair(AF_LOCAL, SOCK_SEQPACKET|SOCK_CLOEXEC|SOCK_NONBLOCK,
                   0, sv) < 0)
        throw MakeErrno("socketpair() failed");

    const int local_fd = sv[0];
    const int remote_fd = sv[1];

    AtScopeExit(remote_fd){ close(remote_fd); };

    static constexpr SpawnRequestCommand cmd = SpawnRequestCommand::CONNECT;

    try {
        Send(ConstBuffer<void>(&cmd, sizeof(cmd)), {&remote_fd, 1});
    } catch (...) {
        close(local_fd);
        std::throw_with_nested(std::runtime_error("Spawn server failed"));
    }

    return local_fd;
}

static void
Serialize(SpawnSerializer &s, const CgroupOptions &c)
{
    s.WriteOptionalString(SpawnExecCommand::CGROUP, c.name);

    for (const auto *set = c.set_head; set != nullptr; set = set->next) {
        s.Write(SpawnExecCommand::CGROUP_SET);
        s.WriteString(set->name);
        s.WriteString(set->value);
    }
}

static void
Serialize(SpawnSerializer &s, const RefenceOptions &_r)
{
    const auto r = _r.Get();
    if (!r.IsNull()) {
        s.Write(SpawnExecCommand::REFENCE);
        s.Write(r.ToVoid());
        s.WriteByte(0);
    }
}

static void
Serialize(SpawnSerializer &s, const NamespaceOptions &ns)
{
    s.WriteOptional(SpawnExecCommand::USER_NS, ns.enable_user);
    s.WriteOptional(SpawnExecCommand::PID_NS, ns.enable_pid);
    s.WriteOptional(SpawnExecCommand::NETWORK_NS, ns.enable_network);
    s.WriteOptional(SpawnExecCommand::IPC_NS, ns.enable_ipc);
    s.WriteOptional(SpawnExecCommand::MOUNT_NS, ns.enable_mount);
    s.WriteOptional(SpawnExecCommand::MOUNT_PROC, ns.mount_proc);
    s.WriteOptionalString(SpawnExecCommand::PIVOT_ROOT, ns.pivot_root);

    if (ns.mount_home != nullptr) {
        s.Write(SpawnExecCommand::MOUNT_HOME);
        s.WriteString(ns.mount_home);
        s.WriteString(ns.home);
    }

    s.WriteOptionalString(SpawnExecCommand::MOUNT_TMP_TMPFS, ns.mount_tmp_tmpfs);
    s.WriteOptionalString(SpawnExecCommand::MOUNT_TMPFS, ns.mount_tmpfs);

    for (auto i = ns.mounts; i != nullptr; i = i->next) {
        s.Write(SpawnExecCommand::BIND_MOUNT);
        s.WriteString(i->source);
        s.WriteString(i->target);
        s.WriteByte(i->writable);
    }

    s.WriteOptionalString(SpawnExecCommand::HOSTNAME, ns.hostname);
}

static void
Serialize(SpawnSerializer &s, unsigned i, const ResourceLimit &rlimit)
{
    if (rlimit.IsEmpty())
        return;

    s.Write(SpawnExecCommand::RLIMIT);
    s.WriteByte(i);

    const struct rlimit &data = rlimit;
    s.WriteT(data);
}

static void
Serialize(SpawnSerializer &s, const ResourceLimits &rlimits)
{
    for (unsigned i = 0; i < RLIM_NLIMITS; ++i)
        Serialize(s, i, rlimits.values[i]);
}

static void
Serialize(SpawnSerializer &s, const UidGid &uid_gid)
{
    if (uid_gid.IsEmpty())
        return;

    s.Write(SpawnExecCommand::UID_GID);
    s.WriteT(uid_gid.uid);
    s.WriteT(uid_gid.gid);

    const size_t n_groups = uid_gid.CountGroups();
    s.WriteByte(n_groups);
    for (size_t i = 0; i < n_groups; ++i)
        s.WriteT(uid_gid.groups[i]);
}

static void
Serialize(SpawnSerializer &s, const PreparedChildProcess &p)
{
    for (const char *i : p.args)
        s.WriteString(SpawnExecCommand::ARG, i);

    for (const char *i : p.env)
        s.WriteString(SpawnExecCommand::SETENV, i);

    s.CheckWriteFd(SpawnExecCommand::STDIN, p.stdin_fd);
    s.CheckWriteFd(SpawnExecCommand::STDOUT, p.stdout_fd);
    s.CheckWriteFd(SpawnExecCommand::STDERR, p.stderr_fd);
    s.CheckWriteFd(SpawnExecCommand::CONTROL, p.control_fd);

    if (p.priority != 0) {
        s.Write(SpawnExecCommand::PRIORITY);
        s.WriteInt(p.priority);
    }

    Serialize(s, p.cgroup);
    Serialize(s, p.refence);
    Serialize(s, p.ns);
    Serialize(s, p.rlimits);
    Serialize(s, p.uid_gid);

    s.WriteOptionalString(SpawnExecCommand::CHROOT, p.chroot);

    if (p.no_new_privs)
        s.Write(SpawnExecCommand::NO_NEW_PRIVS);
}

int
SpawnServerClient::SpawnChildProcess(const char *name,
                                     PreparedChildProcess &&p,
                                     ExitListener *listener)
{
    assert(!shutting_down);

    /* this check is performed again on the server (which is obviously
       necessary, and the only way to have it secure); this one is
       only here for the developer to see the error earlier in the
       call chain */
    if (!p.uid_gid.IsEmpty() && !config.Verify(p.uid_gid))
        throw FormatRuntimeError("uid/gid not allowed: %d/%d",
                                 int(p.uid_gid.uid), int(p.uid_gid.gid));

    CheckOrAbort();

    const int pid = MakePid();

    SpawnSerializer s(SpawnRequestCommand::EXEC);

    try {
        s.WriteInt(pid);
        s.WriteString(name);

        Serialize(s, p);
    } catch (SpawnPayloadTooLargeError) {
        throw std::runtime_error("Spawn payload is too large");
    }

    try {
        Send(s.GetPayload(), s.GetFds());
    } catch (const std::runtime_error &e) {
        std::throw_with_nested(std::runtime_error("Spawn server failed"));
    }

    processes.emplace(std::piecewise_construct,
                      std::forward_as_tuple(pid),
                      std::forward_as_tuple(listener));
    return pid;
}

void
SpawnServerClient::SetExitListener(int pid, ExitListener *listener)
{
    auto i = processes.find(pid);
    assert(i != processes.end());

    assert(i->second.listener == nullptr);
    i->second.listener = listener;
}

void
SpawnServerClient::KillChildProcess(int pid, int signo)
{
    CheckOrAbort();

    auto i = processes.find(pid);
    assert(i != processes.end());
    assert(i->second.listener != nullptr);
    processes.erase(i);

    SpawnSerializer s(SpawnRequestCommand::KILL);
    s.WriteInt(pid);
    s.WriteInt(signo);

    try {
        Send(s.GetPayload(), s.GetFds());
    } catch (const std::runtime_error &e) {
        daemon_log(1, "failed to send KILL(%d) to spawner: %s\n",
                   pid,e.what());
    }

    if (shutting_down && processes.empty())
        Close();
}

inline void
SpawnServerClient::HandleExitMessage(SpawnPayload payload)
{
    int pid, status;
    payload.ReadInt(pid);
    payload.ReadInt(status);
    if (!payload.IsEmpty())
        throw MalformedSpawnPayloadError();

    auto i = processes.find(pid);
    if (i == processes.end())
        return;

    auto *listener = i->second.listener;
    processes.erase(i);

    if (listener != nullptr)
        listener->OnChildProcessExit(status);

    if (shutting_down && processes.empty())
        Close();
}

inline void
SpawnServerClient::HandleMessage(ConstBuffer<uint8_t> payload)
{
    const auto cmd = (SpawnResponseCommand)payload.shift();

    switch (cmd) {
    case SpawnResponseCommand::EXIT:
        HandleExitMessage(SpawnPayload(payload));
        break;
    }
}

inline void
SpawnServerClient::OnSocketEvent(gcc_unused short events)
{
    constexpr size_t N = 64;
    std::array<uint8_t[16], N> payloads;
    std::array<struct iovec, N> iovs;
    std::array<struct mmsghdr, N> msgs;

    for (size_t i = 0; i < N; ++i) {
        auto &iov = iovs[i];
        iov.iov_base = payloads[i];
        iov.iov_len = sizeof(payloads[i]);

        auto &msg = msgs[i].msg_hdr;
        msg.msg_name = nullptr;
        msg.msg_namelen = 0;
        msg.msg_iov = &iov;
        msg.msg_iovlen = 1;
        msg.msg_control = nullptr;
        msg.msg_controllen = 0;
    }

    int n = recvmmsg(fd, &msgs.front(), msgs.size(),
                     MSG_DONTWAIT|MSG_CMSG_CLOEXEC, nullptr);
    if (n <= 0) {
        if (n < 0)
            daemon_log(2, "recvmsg() from spawner failed: %s\n",
                       strerror(errno));
        else
            daemon_log(2, "spawner closed the socket\n");
        Close();
        return;
    }

    for (int i = 0; i < n; ++i) {
        if (msgs[i].msg_len == 0) {
            /* when the peer closes the socket, recvmmsg() doesn't
               return 0; insteaed, it fills the mmsghdr array with
               empty packets */
            daemon_log(2, "spawner closed the socket\n");
            Close();
            return;
        }

        HandleMessage({payloads[i], msgs[i].msg_len});
    }
}
<commit_msg>spawn/Client: include cleanup<commit_after>/*
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "Client.hxx"
#include "Protocol.hxx"
#include "Builder.hxx"
#include "Parser.hxx"
#include "Prepared.hxx"
#include "mount_list.hxx"
#include "ExitListener.hxx"
#include "system/Error.hxx"
#include "util/RuntimeError.hxx"
#include "util/ScopeExit.hxx"

#include <daemon/log.h>

#include <array>

#include <assert.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>

static constexpr size_t MAX_FDS = 8;

SpawnServerClient::SpawnServerClient(EventLoop &event_loop,
                                     const SpawnConfig &_config, int _fd)
    :config(_config), fd(_fd),
     read_event(event_loop, fd, EV_READ|EV_PERSIST,
                BIND_THIS_METHOD(OnSocketEvent))
{
    read_event.Add();
}

SpawnServerClient::~SpawnServerClient()
{
    if (fd >= 0)
        Close();
}

void
SpawnServerClient::ReplaceSocket(int new_fd)
{
    assert(fd >= 0);
    assert(new_fd >= 0);
    assert(fd != new_fd);
    assert(!shutting_down);

    processes.clear();

    Close();

    fd = new_fd;

    read_event.Set(fd, EV_READ|EV_PERSIST);
    read_event.Add();
}

void
SpawnServerClient::Close()
{
    assert(fd >= 0);

    read_event.Delete();
    close(fd);
    fd = -1;
}

void
SpawnServerClient::Shutdown()
{
    shutting_down = true;

    if (processes.empty() && fd >= 0)
        Close();
}

void
SpawnServerClient::CheckOrAbort()
{
    if (fd < 0) {
        daemon_log(1, "SpawnChildProcess: the spawner is gone, emergency!\n");
        exit(EXIT_FAILURE);
    }
}

inline void
SpawnServerClient::Send(ConstBuffer<void> payload, ConstBuffer<int> fds)
{
    ::Send<MAX_FDS>(fd, payload, fds);
}

inline void
SpawnServerClient::Send(const SpawnSerializer &s)
{
    ::Send<MAX_FDS>(fd, s);
}

int
SpawnServerClient::Connect()
{
    CheckOrAbort();

    int sv[2];
    if (socketpair(AF_LOCAL, SOCK_SEQPACKET|SOCK_CLOEXEC|SOCK_NONBLOCK,
                   0, sv) < 0)
        throw MakeErrno("socketpair() failed");

    const int local_fd = sv[0];
    const int remote_fd = sv[1];

    AtScopeExit(remote_fd){ close(remote_fd); };

    static constexpr SpawnRequestCommand cmd = SpawnRequestCommand::CONNECT;

    try {
        Send(ConstBuffer<void>(&cmd, sizeof(cmd)), {&remote_fd, 1});
    } catch (...) {
        close(local_fd);
        std::throw_with_nested(std::runtime_error("Spawn server failed"));
    }

    return local_fd;
}

static void
Serialize(SpawnSerializer &s, const CgroupOptions &c)
{
    s.WriteOptionalString(SpawnExecCommand::CGROUP, c.name);

    for (const auto *set = c.set_head; set != nullptr; set = set->next) {
        s.Write(SpawnExecCommand::CGROUP_SET);
        s.WriteString(set->name);
        s.WriteString(set->value);
    }
}

static void
Serialize(SpawnSerializer &s, const RefenceOptions &_r)
{
    const auto r = _r.Get();
    if (!r.IsNull()) {
        s.Write(SpawnExecCommand::REFENCE);
        s.Write(r.ToVoid());
        s.WriteByte(0);
    }
}

static void
Serialize(SpawnSerializer &s, const NamespaceOptions &ns)
{
    s.WriteOptional(SpawnExecCommand::USER_NS, ns.enable_user);
    s.WriteOptional(SpawnExecCommand::PID_NS, ns.enable_pid);
    s.WriteOptional(SpawnExecCommand::NETWORK_NS, ns.enable_network);
    s.WriteOptional(SpawnExecCommand::IPC_NS, ns.enable_ipc);
    s.WriteOptional(SpawnExecCommand::MOUNT_NS, ns.enable_mount);
    s.WriteOptional(SpawnExecCommand::MOUNT_PROC, ns.mount_proc);
    s.WriteOptionalString(SpawnExecCommand::PIVOT_ROOT, ns.pivot_root);

    if (ns.mount_home != nullptr) {
        s.Write(SpawnExecCommand::MOUNT_HOME);
        s.WriteString(ns.mount_home);
        s.WriteString(ns.home);
    }

    s.WriteOptionalString(SpawnExecCommand::MOUNT_TMP_TMPFS, ns.mount_tmp_tmpfs);
    s.WriteOptionalString(SpawnExecCommand::MOUNT_TMPFS, ns.mount_tmpfs);

    for (auto i = ns.mounts; i != nullptr; i = i->next) {
        s.Write(SpawnExecCommand::BIND_MOUNT);
        s.WriteString(i->source);
        s.WriteString(i->target);
        s.WriteByte(i->writable);
    }

    s.WriteOptionalString(SpawnExecCommand::HOSTNAME, ns.hostname);
}

static void
Serialize(SpawnSerializer &s, unsigned i, const ResourceLimit &rlimit)
{
    if (rlimit.IsEmpty())
        return;

    s.Write(SpawnExecCommand::RLIMIT);
    s.WriteByte(i);

    const struct rlimit &data = rlimit;
    s.WriteT(data);
}

static void
Serialize(SpawnSerializer &s, const ResourceLimits &rlimits)
{
    for (unsigned i = 0; i < RLIM_NLIMITS; ++i)
        Serialize(s, i, rlimits.values[i]);
}

static void
Serialize(SpawnSerializer &s, const UidGid &uid_gid)
{
    if (uid_gid.IsEmpty())
        return;

    s.Write(SpawnExecCommand::UID_GID);
    s.WriteT(uid_gid.uid);
    s.WriteT(uid_gid.gid);

    const size_t n_groups = uid_gid.CountGroups();
    s.WriteByte(n_groups);
    for (size_t i = 0; i < n_groups; ++i)
        s.WriteT(uid_gid.groups[i]);
}

static void
Serialize(SpawnSerializer &s, const PreparedChildProcess &p)
{
    for (const char *i : p.args)
        s.WriteString(SpawnExecCommand::ARG, i);

    for (const char *i : p.env)
        s.WriteString(SpawnExecCommand::SETENV, i);

    s.CheckWriteFd(SpawnExecCommand::STDIN, p.stdin_fd);
    s.CheckWriteFd(SpawnExecCommand::STDOUT, p.stdout_fd);
    s.CheckWriteFd(SpawnExecCommand::STDERR, p.stderr_fd);
    s.CheckWriteFd(SpawnExecCommand::CONTROL, p.control_fd);

    if (p.priority != 0) {
        s.Write(SpawnExecCommand::PRIORITY);
        s.WriteInt(p.priority);
    }

    Serialize(s, p.cgroup);
    Serialize(s, p.refence);
    Serialize(s, p.ns);
    Serialize(s, p.rlimits);
    Serialize(s, p.uid_gid);

    s.WriteOptionalString(SpawnExecCommand::CHROOT, p.chroot);

    if (p.no_new_privs)
        s.Write(SpawnExecCommand::NO_NEW_PRIVS);
}

int
SpawnServerClient::SpawnChildProcess(const char *name,
                                     PreparedChildProcess &&p,
                                     ExitListener *listener)
{
    assert(!shutting_down);

    /* this check is performed again on the server (which is obviously
       necessary, and the only way to have it secure); this one is
       only here for the developer to see the error earlier in the
       call chain */
    if (!p.uid_gid.IsEmpty() && !config.Verify(p.uid_gid))
        throw FormatRuntimeError("uid/gid not allowed: %d/%d",
                                 int(p.uid_gid.uid), int(p.uid_gid.gid));

    CheckOrAbort();

    const int pid = MakePid();

    SpawnSerializer s(SpawnRequestCommand::EXEC);

    try {
        s.WriteInt(pid);
        s.WriteString(name);

        Serialize(s, p);
    } catch (SpawnPayloadTooLargeError) {
        throw std::runtime_error("Spawn payload is too large");
    }

    try {
        Send(s.GetPayload(), s.GetFds());
    } catch (const std::runtime_error &e) {
        std::throw_with_nested(std::runtime_error("Spawn server failed"));
    }

    processes.emplace(std::piecewise_construct,
                      std::forward_as_tuple(pid),
                      std::forward_as_tuple(listener));
    return pid;
}

void
SpawnServerClient::SetExitListener(int pid, ExitListener *listener)
{
    auto i = processes.find(pid);
    assert(i != processes.end());

    assert(i->second.listener == nullptr);
    i->second.listener = listener;
}

void
SpawnServerClient::KillChildProcess(int pid, int signo)
{
    CheckOrAbort();

    auto i = processes.find(pid);
    assert(i != processes.end());
    assert(i->second.listener != nullptr);
    processes.erase(i);

    SpawnSerializer s(SpawnRequestCommand::KILL);
    s.WriteInt(pid);
    s.WriteInt(signo);

    try {
        Send(s.GetPayload(), s.GetFds());
    } catch (const std::runtime_error &e) {
        daemon_log(1, "failed to send KILL(%d) to spawner: %s\n",
                   pid,e.what());
    }

    if (shutting_down && processes.empty())
        Close();
}

inline void
SpawnServerClient::HandleExitMessage(SpawnPayload payload)
{
    int pid, status;
    payload.ReadInt(pid);
    payload.ReadInt(status);
    if (!payload.IsEmpty())
        throw MalformedSpawnPayloadError();

    auto i = processes.find(pid);
    if (i == processes.end())
        return;

    auto *listener = i->second.listener;
    processes.erase(i);

    if (listener != nullptr)
        listener->OnChildProcessExit(status);

    if (shutting_down && processes.empty())
        Close();
}

inline void
SpawnServerClient::HandleMessage(ConstBuffer<uint8_t> payload)
{
    const auto cmd = (SpawnResponseCommand)payload.shift();

    switch (cmd) {
    case SpawnResponseCommand::EXIT:
        HandleExitMessage(SpawnPayload(payload));
        break;
    }
}

inline void
SpawnServerClient::OnSocketEvent(gcc_unused short events)
{
    constexpr size_t N = 64;
    std::array<uint8_t[16], N> payloads;
    std::array<struct iovec, N> iovs;
    std::array<struct mmsghdr, N> msgs;

    for (size_t i = 0; i < N; ++i) {
        auto &iov = iovs[i];
        iov.iov_base = payloads[i];
        iov.iov_len = sizeof(payloads[i]);

        auto &msg = msgs[i].msg_hdr;
        msg.msg_name = nullptr;
        msg.msg_namelen = 0;
        msg.msg_iov = &iov;
        msg.msg_iovlen = 1;
        msg.msg_control = nullptr;
        msg.msg_controllen = 0;
    }

    int n = recvmmsg(fd, &msgs.front(), msgs.size(),
                     MSG_DONTWAIT|MSG_CMSG_CLOEXEC, nullptr);
    if (n <= 0) {
        if (n < 0)
            daemon_log(2, "recvmsg() from spawner failed: %s\n",
                       strerror(errno));
        else
            daemon_log(2, "spawner closed the socket\n");
        Close();
        return;
    }

    for (int i = 0; i < n; ++i) {
        if (msgs[i].msg_len == 0) {
            /* when the peer closes the socket, recvmmsg() doesn't
               return 0; insteaed, it fills the mmsghdr array with
               empty packets */
            daemon_log(2, "spawner closed the socket\n");
            Close();
            return;
        }

        HandleMessage({payloads[i], msgs[i].msg_len});
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2008-2010, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */

/// \file libport/compiler.hh
/// \brief Specific features from some compilers.

#ifndef LIBPORT_COMPILER_HH
# define LIBPORT_COMPILER_HH

# include <libport/config.h>

/*----------------.
| __attribute__.  |
`----------------*/

# ifdef _MSC_VER

#  define __attribute__(a)
#  define ATTRIBUTE_ALWAYS_INLINE __forceinline
#  define ATTRIBUTE_DEPRECATED __declspec(deprecated)
#  if defined STATIC_BUILD
#    define ATTRIBUTE_DLLEXPORT
#    define ATTRIBUTE_DLLIMPORT
#  else
#    define ATTRIBUTE_DLLEXPORT __declspec(dllexport)
#    define ATTRIBUTE_DLLIMPORT __declspec(dllimport)
#  endif
#  define ATTRIBUTE_NOINLINE __declspec(noinline)
#  define ATTRIBUTE_NORETURN __declspec(noreturn)
#  define ATTRIBUTE_NOTHROW  __declspec(nothrow)
#  define ATTRIBUTE_STDCALL  __stdcall
#  define ATTRIBUTE_UNUSED_RESULT /* FILLME */

# endif // _MSC_VER

# if !defined __attribute__
/* This feature is available in gcc versions 2.5 and later.  */
#  if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || __STRICT_ANSI__
#   define __attribute__(Spec) /* empty */
#  else
     // GCC 3.4 does not support "always_inline" without "inline".
#    define ATTRIBUTE_ALWAYS_INLINE inline __attribute__((__always_inline__))
#    define ATTRIBUTE_DEPRECATED __attribute__((__deprecated__))

// GCC 3 does not seem to support visibility, and generates tons of
// annoying error messages.
//
// See also http://gcc.gnu.org/wiki/Visibility.
#    if 4 <= __GNUC__
#      define ATTRIBUTE_DLLEXPORT __attribute__((visibility("default")))
#    else
#      define ATTRIBUTE_DLLEXPORT
#    endif
#    define ATTRIBUTE_DLLIMPORT ATTRIBUTE_DLLEXPORT

#    define ATTRIBUTE_NOINLINE __attribute__((__noinline__))
#    define ATTRIBUTE_NORETURN __attribute__((__noreturn__))
#    define ATTRIBUTE_NOTHROW  __attribute__((__nothrow__))
#    define ATTRIBUTE_STDCALL __attribute__((__stdcall__))
#    define ATTRIBUTE_UNUSED_RESULT __attribute__((warn_unused_result))
#  endif
# endif // !defined __attribute__

// For throw() vs. nothrow, see
// http://www.nabble.com/Rest-of-trivial-decorations-td23114765.html
# ifdef __cplusplus
#  undef ATTRIBUTE_NOTHROW
#  define ATTRIBUTE_NOTHROW throw()
# endif

/*----------------------.
| __PRETTY_FUNCTION__.  |
`----------------------*/

// __PRETTY_FUNCTION__ is a GNU extension.  MSVC has something somewhat
// similar although it's less pretty.
# ifdef _MSC_VER
#  define __PRETTY_FUNCTION__ __FUNCTION__
# endif // _MSC_VER

#endif // !LIBPORT_COMPILER_HH
<commit_msg>ATTRIBUTE_PRINTF.<commit_after>/*
 * Copyright (C) 2008-2010, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */

/// \file libport/compiler.hh
/// \brief Specific features from some compilers.

#ifndef LIBPORT_COMPILER_HH
# define LIBPORT_COMPILER_HH

# include <libport/config.h>

/*----------------.
| __attribute__.  |
`----------------*/

# ifdef _MSC_VER

#  define __attribute__(a)
#  define ATTRIBUTE_ALWAYS_INLINE __forceinline
#  define ATTRIBUTE_DEPRECATED __declspec(deprecated)
#  if defined STATIC_BUILD
#    define ATTRIBUTE_DLLEXPORT
#    define ATTRIBUTE_DLLIMPORT
#  else
#    define ATTRIBUTE_DLLEXPORT __declspec(dllexport)
#    define ATTRIBUTE_DLLIMPORT __declspec(dllimport)
#  endif
#  define ATTRIBUTE_NOINLINE __declspec(noinline)
#  define ATTRIBUTE_NORETURN __declspec(noreturn)
#  define ATTRIBUTE_NOTHROW  __declspec(nothrow)

/// Declare a function whose features printf-like arguments.
/// \param Format   the number of the printf-like format string.
///                 First argument is numbered 1, not 0.
///                 In a class, argument 1 is "this", so first visible
///                 argument is 2.
/// \param FirstArg The number of the first varargs.  Should point to
///                 the "..." in the argument list.
#  define ATTRIBUTE_PRINTF(Format, FirstArg)
#  define ATTRIBUTE_STDCALL  __stdcall
#  define ATTRIBUTE_UNUSED_RESULT /* FILLME */

# endif // _MSC_VER

# if !defined __attribute__
/* This feature is available in gcc versions 2.5 and later.  */
#  if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || __STRICT_ANSI__
#   define __attribute__(Spec) /* empty */
#  else
     // GCC 3.4 does not support "always_inline" without "inline".
#    define ATTRIBUTE_ALWAYS_INLINE inline __attribute__((__always_inline__))
#    define ATTRIBUTE_DEPRECATED __attribute__((__deprecated__))

// GCC 3 does not seem to support visibility, and generates tons of
// annoying error messages.
//
// See also http://gcc.gnu.org/wiki/Visibility.
#    if 4 <= __GNUC__
#      define ATTRIBUTE_DLLEXPORT __attribute__((visibility("default")))
#    else
#      define ATTRIBUTE_DLLEXPORT
#    endif
#    define ATTRIBUTE_DLLIMPORT ATTRIBUTE_DLLEXPORT

#    define ATTRIBUTE_NOINLINE __attribute__((__noinline__))
#    define ATTRIBUTE_NORETURN __attribute__((__noreturn__))
#    define ATTRIBUTE_NOTHROW  __attribute__((__nothrow__))
#    define ATTRIBUTE_PRINTF(Format, FirstArg) \
         __attribute__((format(printf, Format, FirstArg)))
#    define ATTRIBUTE_STDCALL __attribute__((__stdcall__))
#    define ATTRIBUTE_UNUSED_RESULT __attribute__((warn_unused_result))
#  endif
# endif // !defined __attribute__

// For throw() vs. nothrow, see
// http://www.nabble.com/Rest-of-trivial-decorations-td23114765.html
# ifdef __cplusplus
#  undef ATTRIBUTE_NOTHROW
#  define ATTRIBUTE_NOTHROW throw()
# endif

/*----------------------.
| __PRETTY_FUNCTION__.  |
`----------------------*/

// __PRETTY_FUNCTION__ is a GNU extension.  MSVC has something somewhat
// similar although it's less pretty.
# ifdef _MSC_VER
#  define __PRETTY_FUNCTION__ __FUNCTION__
# endif // _MSC_VER

#endif // !LIBPORT_COMPILER_HH
<|endoftext|>