<commit_before>#include <iostream>
#include <cmath>
#include <string>

#include "timer.h"
#include "matrix.h"

#if defined(AMATRIX_COMPARE_WITH_EIGEN)
#include "Eigen/Dense"
#endif

#if defined(AMATRIX_COMPARE_WITH_UBLAS)
#include <boost/numeric/ublas/matrix.hpp>
#endif

#define AMATRIX_MEASURE_ABC_OPERATION(name, operation)                   \
    void name() {                                                        \
        TMatrixType A(TSize1, TSize2);                                   \
        TMatrixType B(TSize1, TSize2);                                   \
        initialize(A);                                                   \
        initialize(B);                                                   \
        Timer timer;                                                     \
        for (std::size_t i_repeat = 0; i_repeat < mRepeat; i_repeat++) { \
            operation                                                    \
        }                                                                \
        auto elapsed = timer.elapsed().count();                          \
        std::cout << "\t\t" << elapsed;                                  \
    }

#define AMATRIX_MEASURE_ABCD_OPERATION(name, operation)                   \
    void name() {                                                         \
        TMatrixType A(TSize1, TSize2);                                    \
        TMatrixType B(TSize1, TSize2);                                    \
        initialize(A);                                                    \
        initializeInverse(B);                                             \
        initializeInverse(D);                                             \
        Timer timer;                                                      \
        for (std::size_t i_repeat = 0; i_repeat < mRepeat / (2 * TSize2); \
             i_repeat++) {                                                \
            operation                                                     \
        }                                                                 \
        auto elapsed = timer.elapsed().count();                           \
        std::cout << "\t\t" << elapsed;                                   \
    }

template <typename TMatrixType, std::size_t TSize1, std::size_t TSize2>
class ComparisonColumn {
   protected:
    static constexpr std::size_t mRepeat =
        static_cast<std::size_t>(1e8 / (TSize1 * TSize2));

    TMatrixType C;
    TMatrixType D;
    std::string mColumnName;

    void initialize(TMatrixType& TheMatrix) {
        for (std::size_t i = 0; i < TSize1; i++)
            for (std::size_t j = 0; j < TSize2; j++)
                TheMatrix(i, j) = j + 1.00;
    }

    void initializeInverse(TMatrixType& TheMatrix) {
        for (std::size_t i = 0; i < TSize1; i++)
            for (std::size_t j = 0; j < TSize2; j++)
                TheMatrix(i, j) = 1.00 / (i + 1);
    }

   public:
    ComparisonColumn() = delete;

    ComparisonColumn(std::string ColumnName)
        : C(TSize1, TSize2),
          D(TSize1, TSize2), mColumnName(ColumnName) {
        initialize(C);
    }
    std::string const& GetColumnName() { return mColumnName; }
    TMatrixType& GetResult() { return C; }

    template <typename TMatrixType2>
    bool CheckResult(TMatrixType2 const& Reference) {
        constexpr double tolerance = 1e-12;
        for (std::size_t i = 0; i < TSize1; i++)
            for (std::size_t j = 0; j < TSize2; j++)
                if (std::abs(C(i, j) != Reference(i, j)) > tolerance) {
                    std::cout << " " << C(i, j) << " != " << Reference(i, j);
                    return false;
                }

        return true;
    }

    AMATRIX_MEASURE_ABC_OPERATION(MeasureSumTime,C.noalias() = A + B; B.noalias() = C;)

    AMATRIX_MEASURE_ABCD_OPERATION(MeasureMultTime,C.noalias() = D * A; D.noalias() = B;)

    AMATRIX_MEASURE_ABCD_OPERATION(MeasureABAMultTime, C.noalias() = A * TMatrixType(D * A); D.noalias() = B;)

    AMATRIX_MEASURE_ABCD_OPERATION(MeasureATransposeBAMultTime,C.noalias() = A.transpose() * TMatrixType(D * A); D.noalias() = B;)

};

#if defined(AMATRIX_COMPARE_WITH_UBLAS)
using namespace boost::numeric::ublas;
template <typename TMatrixType, std::size_t TSize1,
    std::size_t TSize2>

class UblasComparisonColumn
    : public ComparisonColumn<TMatrixType, TSize1, TSize2> {
    void initialize(TMatrixType& TheMatrix) {
        for (std::size_t i = 0; i < TSize1; i++)
            for (std::size_t j = 0; j < TSize2; j++)
                TheMatrix(i, j) = j + 1.00;
    }

    void initializeInverse(TMatrixType& TheMatrix) {
        for (std::size_t i = 0; i < TSize1; i++)
            for (std::size_t j = 0; j < TSize2; j++)
                TheMatrix(i, j) = 1.00 / (i + 1);
    }
   public:
    using BaseType =
        ComparisonColumn<TMatrixType, TSize1, TSize2>;

    using BaseType::mRepeat;

    using BaseType::C;
    using BaseType::D;

    UblasComparisonColumn(std::string ColumnName)
        : ComparisonColumn<TMatrixType, TSize1, TSize2>(
              ColumnName) {}

    AMATRIX_MEASURE_ABC_OPERATION(MeasureSumTime, noalias(BaseType::C) =  A + B; noalias(B) = BaseType::C;)
    AMATRIX_MEASURE_ABCD_OPERATION(MeasureMultTime,noalias(BaseType::C) = prod(BaseType::D, A); noalias(BaseType::D) = B;)
    AMATRIX_MEASURE_ABCD_OPERATION(MeasureABAMultTime, noalias(BaseType::C) = prod(A, TMatrixType(prod(BaseType::D, A))); noalias(BaseType::D) = B;)
    AMATRIX_MEASURE_ABCD_OPERATION(MeasureATransposeBAMultTime, noalias(BaseType::C) = prod(trans(A), TMatrixType(prod(BaseType::D, A)));noalias(BaseType::D) = B;)

};
#endif

template <typename TMatrixType, std::size_t TSize1,
    std::size_t TSize2>
class EmptyComparisonColumn
    : public ComparisonColumn<TMatrixType, TSize1, TSize2> {
   public:
    EmptyComparisonColumn(std::string ColumnName)
        : ComparisonColumn<TMatrixType, TSize1, TSize2>("") {}
    void MeasureSumTime() { std::cout << "\t\t"; }
    void MeasureMultTime() { std::cout << "\t\t"; }
    void MeasureABAMultTime() { std::cout << "\t\t"; }
    void MeasureATransposeBAMultTime() { std::cout << "\t\t"; }

    template <typename TMatrixType2>
    bool CheckResult(TMatrixType2 const& Reference) {
        return true;
    }
};

#define RUN_BENCHMARK(name, function)                          \
    std::cout << name;                                         \
    mAMatrixColumn.function();                                 \
    mEigenColumn.function();                                   \
    if (!mEigenColumn.CheckResult(mAMatrixColumn.GetResult())) \
        std::cout << "(Failed!)";                              \
    mUblasColumn.function();                                   \
    if (!mUblasColumn.CheckResult(mAMatrixColumn.GetResult())) \
        std::cout << "(Failed!)";                              \
    std::cout << std::endl;

template <std::size_t TSize1, std::size_t TSize2>
class BenchmarkMatrix {
    ComparisonColumn<AMatrix::Matrix<double, TSize1, TSize2>,
        TSize1, TSize2>
        mAMatrixColumn;
#if defined(AMATRIX_COMPARE_WITH_EIGEN)
    ComparisonColumn<Eigen::Matrix<double, TSize1, TSize2>,
        TSize1, TSize2>
        mEigenColumn;
#else
    EmptyComparisonColumn<
        AMatrix::Matrix<double, TSize1, TSize2>, TSize1,
        TSize2>
        mEigenColumn;
#endif
#if defined(AMATRIX_COMPARE_WITH_UBLAS)
    UblasComparisonColumn<boost::numeric::ublas::bounded_matrix<double,
                              TSize1, TSize2>,
        TSize1, TSize2>
        mUblasColumn;
#else
    EmptyComparisonColumn<
        AMatrix::Matrix<double, TSize1, TSize2>, TSize1,
        TSize2>
        mUblasColumn;
#endif
   public:
    BenchmarkMatrix()
        : mAMatrixColumn("AMatrix"),
          mEigenColumn("Eigen"),
          mUblasColumn("Ublas") {
        std::cout << "Benchmark[" << TSize1 << "," << TSize2
                  << "]";
        std::cout << "\t\t" << mAMatrixColumn.GetColumnName();
        std::cout << "\t\t" << mEigenColumn.GetColumnName();
        std::cout << "\t\t" << mUblasColumn.GetColumnName();
        std::cout << std::endl;
    }

    ~BenchmarkMatrix() = default;
    void Run() {
        RUN_BENCHMARK("C = A + B", MeasureSumTime)
        RUN_BENCHMARK("C = A * B", MeasureMultTime)
        RUN_BENCHMARK("C = A * B * A", MeasureABAMultTime)
        RUN_BENCHMARK("C = A^T * B * A", MeasureATransposeBAMultTime)

        std::cout << std::endl;
    }
};

template <std::size_t TSize1, std::size_t TSize2>
class BenchmarkDynamicMatrix {
    ComparisonColumn<AMatrix::Matrix<double, 0, 0>, TSize1,
        TSize2>
        mAMatrixColumn;
#if defined(AMATRIX_COMPARE_WITH_EIGEN)
    ComparisonColumn<
        Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic>, TSize1,
        TSize2>
        mEigenColumn;
#else
    EmptyComparisonColumn<
        AMatrix::Matrix<double, TSize1, TSize2>, TSize1,
        TSize2>
        mEigenColumn;
#endif
#if defined(AMATRIX_COMPARE_WITH_UBLAS)
    UblasComparisonColumn<boost::numeric::ublas::matrix<double>,
        TSize1, TSize2>
        mUblasColumn;
#else
    EmptyComparisonColumn<
        AMatrix::Matrix<double, TSize1, TSize2>, TSize1,
        TSize2>
        mUblasColumn;
#endif
   public:
    BenchmarkDynamicMatrix()
        : mAMatrixColumn("AMatrix"),
          mEigenColumn("Eigen"),
          mUblasColumn("Ublas") {
        std::cout << "Benchmark[" << TSize1 << "," << TSize2
                  << "]";
        std::cout << "\t\t" << mAMatrixColumn.GetColumnName();
        std::cout << "\t\t" << mEigenColumn.GetColumnName();
        std::cout << "\t\t" << mUblasColumn.GetColumnName();
        std::cout << std::endl;
    }

    ~BenchmarkDynamicMatrix() = default;
    void Run() {
        RUN_BENCHMARK("C = A + B", MeasureSumTime)
        RUN_BENCHMARK("C = A * B", MeasureMultTime)
        RUN_BENCHMARK("C = A * B * A", MeasureABAMultTime)
        RUN_BENCHMARK("C = A^T * B * A", MeasureATransposeBAMultTime)

        std::cout << std::endl;
    }
};

int main() {
    BenchmarkMatrix<3, 3> benchmark_3_3;
    benchmark_3_3.Run();

    BenchmarkMatrix<4, 4> benchmark_4_4;
    benchmark_4_4.Run();

    BenchmarkMatrix<6, 6> benchmark_6_6;
    benchmark_6_6.Run();

    BenchmarkMatrix<12, 12> benchmark_12_12;
    benchmark_12_12.Run();

    BenchmarkMatrix<16, 16> benchmark_16_16;
    benchmark_16_16.Run();

    BenchmarkDynamicMatrix<3, 3> dynamic_bechmark_3_3;
    dynamic_bechmark_3_3.Run();

    BenchmarkDynamicMatrix<4, 4> dynamic_benchmark_4_4;
    dynamic_benchmark_4_4.Run();

    BenchmarkDynamicMatrix<6, 6> dynamic_benchmark_6_6;
    dynamic_benchmark_6_6.Run();

    BenchmarkDynamicMatrix<12, 12> dynamic_benchmark_12_12;
    dynamic_benchmark_12_12.Run();

    BenchmarkDynamicMatrix<16, 16> dynamic_benchmark_16_16;
    dynamic_benchmark_16_16.Run();

    return 0;
}
<commit_msg>Warning in benchmark fixed<commit_after>#include <iostream>
#include <cmath>
#include <string>

#include "timer.h"
#include "matrix.h"

#if defined(AMATRIX_COMPARE_WITH_EIGEN)
#include "Eigen/Dense"
#endif

#if defined(AMATRIX_COMPARE_WITH_UBLAS)
#include <boost/numeric/ublas/matrix.hpp>
#endif

#define AMATRIX_MEASURE_ABC_OPERATION(name, operation)                   \
    void name() {                                                        \
        TMatrixType A(TSize1, TSize2);                                   \
        TMatrixType B(TSize1, TSize2);                                   \
        initialize(A);                                                   \
        initialize(B);                                                   \
        Timer timer;                                                     \
        for (std::size_t i_repeat = 0; i_repeat < mRepeat; i_repeat++) { \
            operation                                                    \
        }                                                                \
        auto elapsed = timer.elapsed().count();                          \
        std::cout << "\t\t" << elapsed;                                  \
    }

#define AMATRIX_MEASURE_ABCD_OPERATION(name, operation)                   \
    void name() {                                                         \
        TMatrixType A(TSize1, TSize2);                                    \
        TMatrixType B(TSize1, TSize2);                                    \
        initialize(A);                                                    \
        initializeInverse(B);                                             \
        initializeInverse(D);                                             \
        Timer timer;                                                      \
        for (std::size_t i_repeat = 0; i_repeat < mRepeat / (2 * TSize2); \
             i_repeat++) {                                                \
            operation                                                     \
        }                                                                 \
        auto elapsed = timer.elapsed().count();                           \
        std::cout << "\t\t" << elapsed;                                   \
    }

template <typename TMatrixType, std::size_t TSize1, std::size_t TSize2>
class ComparisonColumn {
   protected:
    static constexpr std::size_t mRepeat =
        static_cast<std::size_t>(1e8 / (TSize1 * TSize2));

    TMatrixType C;
    TMatrixType D;
    std::string mColumnName;

    void initialize(TMatrixType& TheMatrix) {
        for (std::size_t i = 0; i < TSize1; i++)
            for (std::size_t j = 0; j < TSize2; j++)
                TheMatrix(i, j) = j + 1.00;
    }

    void initializeInverse(TMatrixType& TheMatrix) {
        for (std::size_t i = 0; i < TSize1; i++)
            for (std::size_t j = 0; j < TSize2; j++)
                TheMatrix(i, j) = 1.00 / (i + 1);
    }

   public:
    ComparisonColumn() = delete;

    ComparisonColumn(std::string ColumnName)
        : C(TSize1, TSize2),
          D(TSize1, TSize2), mColumnName(ColumnName) {
        initialize(C);
    }
    std::string const& GetColumnName() { return mColumnName; }
    TMatrixType& GetResult() { return C; }

    template <typename TMatrixType2>
    bool CheckResult(TMatrixType2 const& Reference) {
        constexpr double tolerance = 1e-12;
        for (std::size_t i = 0; i < TSize1; i++)
            for (std::size_t j = 0; j < TSize2; j++)
                if (std::abs(C(i, j) - Reference(i, j)) > tolerance) {
                    std::cout << " " << C(i, j) << " != " << Reference(i, j);
                    return false;
                }

        return true;
    }

    AMATRIX_MEASURE_ABC_OPERATION(MeasureSumTime,C.noalias() = A + B; B.noalias() = C;)

    AMATRIX_MEASURE_ABCD_OPERATION(MeasureMultTime,C.noalias() = D * A; D.noalias() = B;)

    AMATRIX_MEASURE_ABCD_OPERATION(MeasureABAMultTime, C.noalias() = A * TMatrixType(D * A); D.noalias() = B;)

    AMATRIX_MEASURE_ABCD_OPERATION(MeasureATransposeBAMultTime,C.noalias() = A.transpose() * TMatrixType(D * A); D.noalias() = B;)

};

#if defined(AMATRIX_COMPARE_WITH_UBLAS)
using namespace boost::numeric::ublas;
template <typename TMatrixType, std::size_t TSize1,
    std::size_t TSize2>

class UblasComparisonColumn
    : public ComparisonColumn<TMatrixType, TSize1, TSize2> {
    void initialize(TMatrixType& TheMatrix) {
        for (std::size_t i = 0; i < TSize1; i++)
            for (std::size_t j = 0; j < TSize2; j++)
                TheMatrix(i, j) = j + 1.00;
    }

    void initializeInverse(TMatrixType& TheMatrix) {
        for (std::size_t i = 0; i < TSize1; i++)
            for (std::size_t j = 0; j < TSize2; j++)
                TheMatrix(i, j) = 1.00 / (i + 1);
    }
   public:
    using BaseType =
        ComparisonColumn<TMatrixType, TSize1, TSize2>;

    using BaseType::mRepeat;

    using BaseType::C;
    using BaseType::D;

    UblasComparisonColumn(std::string ColumnName)
        : ComparisonColumn<TMatrixType, TSize1, TSize2>(
              ColumnName) {}

    AMATRIX_MEASURE_ABC_OPERATION(MeasureSumTime, noalias(BaseType::C) =  A + B; noalias(B) = BaseType::C;)
    AMATRIX_MEASURE_ABCD_OPERATION(MeasureMultTime,noalias(BaseType::C) = prod(BaseType::D, A); noalias(BaseType::D) = B;)
    AMATRIX_MEASURE_ABCD_OPERATION(MeasureABAMultTime, noalias(BaseType::C) = prod(A, TMatrixType(prod(BaseType::D, A))); noalias(BaseType::D) = B;)
    AMATRIX_MEASURE_ABCD_OPERATION(MeasureATransposeBAMultTime, noalias(BaseType::C) = prod(trans(A), TMatrixType(prod(BaseType::D, A)));noalias(BaseType::D) = B;)

};
#endif

template <typename TMatrixType, std::size_t TSize1,
    std::size_t TSize2>
class EmptyComparisonColumn
    : public ComparisonColumn<TMatrixType, TSize1, TSize2> {
   public:
    EmptyComparisonColumn(std::string ColumnName)
        : ComparisonColumn<TMatrixType, TSize1, TSize2>("") {}
    void MeasureSumTime() { std::cout << "\t\t"; }
    void MeasureMultTime() { std::cout << "\t\t"; }
    void MeasureABAMultTime() { std::cout << "\t\t"; }
    void MeasureATransposeBAMultTime() { std::cout << "\t\t"; }

    template <typename TMatrixType2>
    bool CheckResult(TMatrixType2 const& Reference) {
        return true;
    }
};

#define RUN_BENCHMARK(name, function)                          \
    std::cout << name;                                         \
    mAMatrixColumn.function();                                 \
    mEigenColumn.function();                                   \
    if (!mEigenColumn.CheckResult(mAMatrixColumn.GetResult())) \
        std::cout << "(Failed!)";                              \
    mUblasColumn.function();                                   \
    if (!mUblasColumn.CheckResult(mAMatrixColumn.GetResult())) \
        std::cout << "(Failed!)";                              \
    std::cout << std::endl;

template <std::size_t TSize1, std::size_t TSize2>
class BenchmarkMatrix {
    ComparisonColumn<AMatrix::Matrix<double, TSize1, TSize2>,
        TSize1, TSize2>
        mAMatrixColumn;
#if defined(AMATRIX_COMPARE_WITH_EIGEN)
    ComparisonColumn<Eigen::Matrix<double, TSize1, TSize2>,
        TSize1, TSize2>
        mEigenColumn;
#else
    EmptyComparisonColumn<
        AMatrix::Matrix<double, TSize1, TSize2>, TSize1,
        TSize2>
        mEigenColumn;
#endif
#if defined(AMATRIX_COMPARE_WITH_UBLAS)
    UblasComparisonColumn<boost::numeric::ublas::bounded_matrix<double,
                              TSize1, TSize2>,
        TSize1, TSize2>
        mUblasColumn;
#else
    EmptyComparisonColumn<
        AMatrix::Matrix<double, TSize1, TSize2>, TSize1,
        TSize2>
        mUblasColumn;
#endif
   public:
    BenchmarkMatrix()
        : mAMatrixColumn("AMatrix"),
          mEigenColumn("Eigen"),
          mUblasColumn("Ublas") {
        std::cout << "Benchmark[" << TSize1 << "," << TSize2
                  << "]";
        std::cout << "\t\t" << mAMatrixColumn.GetColumnName();
        std::cout << "\t\t" << mEigenColumn.GetColumnName();
        std::cout << "\t\t" << mUblasColumn.GetColumnName();
        std::cout << std::endl;
    }

    ~BenchmarkMatrix() = default;
    void Run() {
        RUN_BENCHMARK("C = A + B", MeasureSumTime)
        RUN_BENCHMARK("C = A * B", MeasureMultTime)
        RUN_BENCHMARK("C = A * B * A", MeasureABAMultTime)
        RUN_BENCHMARK("C = A^T * B * A", MeasureATransposeBAMultTime)

        std::cout << std::endl;
    }
};

template <std::size_t TSize1, std::size_t TSize2>
class BenchmarkDynamicMatrix {
    ComparisonColumn<AMatrix::Matrix<double, 0, 0>, TSize1,
        TSize2>
        mAMatrixColumn;
#if defined(AMATRIX_COMPARE_WITH_EIGEN)
    ComparisonColumn<
        Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic>, TSize1,
        TSize2>
        mEigenColumn;
#else
    EmptyComparisonColumn<
        AMatrix::Matrix<double, TSize1, TSize2>, TSize1,
        TSize2>
        mEigenColumn;
#endif
#if defined(AMATRIX_COMPARE_WITH_UBLAS)
    UblasComparisonColumn<boost::numeric::ublas::matrix<double>,
        TSize1, TSize2>
        mUblasColumn;
#else
    EmptyComparisonColumn<
        AMatrix::Matrix<double, TSize1, TSize2>, TSize1,
        TSize2>
        mUblasColumn;
#endif
   public:
    BenchmarkDynamicMatrix()
        : mAMatrixColumn("AMatrix"),
          mEigenColumn("Eigen"),
          mUblasColumn("Ublas") {
        std::cout << "Benchmark[" << TSize1 << "," << TSize2
                  << "]";
        std::cout << "\t\t" << mAMatrixColumn.GetColumnName();
        std::cout << "\t\t" << mEigenColumn.GetColumnName();
        std::cout << "\t\t" << mUblasColumn.GetColumnName();
        std::cout << std::endl;
    }

    ~BenchmarkDynamicMatrix() = default;
    void Run() {
        RUN_BENCHMARK("C = A + B", MeasureSumTime)
        RUN_BENCHMARK("C = A * B", MeasureMultTime)
        RUN_BENCHMARK("C = A * B * A", MeasureABAMultTime)
        RUN_BENCHMARK("C = A^T * B * A", MeasureATransposeBAMultTime)

        std::cout << std::endl;
    }
};

int main() {
    BenchmarkMatrix<3, 3> benchmark_3_3;
    benchmark_3_3.Run();

    BenchmarkMatrix<4, 4> benchmark_4_4;
    benchmark_4_4.Run();

    BenchmarkMatrix<6, 6> benchmark_6_6;
    benchmark_6_6.Run();

    BenchmarkMatrix<12, 12> benchmark_12_12;
    benchmark_12_12.Run();

    BenchmarkMatrix<16, 16> benchmark_16_16;
    benchmark_16_16.Run();

    BenchmarkDynamicMatrix<3, 3> dynamic_bechmark_3_3;
    dynamic_bechmark_3_3.Run();

    BenchmarkDynamicMatrix<4, 4> dynamic_benchmark_4_4;
    dynamic_benchmark_4_4.Run();

    BenchmarkDynamicMatrix<6, 6> dynamic_benchmark_6_6;
    dynamic_benchmark_6_6.Run();

    BenchmarkDynamicMatrix<12, 12> dynamic_benchmark_12_12;
    dynamic_benchmark_12_12.Run();

    BenchmarkDynamicMatrix<16, 16> dynamic_benchmark_16_16;
    dynamic_benchmark_16_16.Run();

    return 0;
}
<|endoftext|>


<commit_before>#include <string>
#include <gtest/gtest.h>
#include <prophy/detail/decoder.hpp>
#include "generated/Arrays.pp.hpp"
#include "generated/Dynfields.pp.hpp"
#include "generated/Paddings.pp.hpp"
#include "generated/Unions.pp.hpp"
#include "util.hpp"

using namespace testing;
using namespace prophy;
using namespace prophy::detail;

TEST(encoding, decode_struct_failures)
{
    Builtin x;

    EXPECT_FALSE(x.decode(bytes("\x01\x00\x00\x00\x02\x00\x00")));
    EXPECT_EQ(1, x.x);
    EXPECT_EQ(0, x.y);

    EXPECT_FALSE(x.decode(bytes("\x03\x00\x00\x00\x04\x00\x00\x00\x00")));
    EXPECT_EQ(3, x.x);
    EXPECT_EQ(4, x.y);

    EXPECT_FALSE(x.decode(bytes("\x05\x00\x00\x00")));
    EXPECT_EQ(5, x.x);
    EXPECT_EQ(4, x.y);
}

TEST(encoding, decode_dynamic_failures)
{
    BuiltinDynamic x;
    std::vector<uint8_t> data = bytes("\x01\x00\x00"); //not enough to decode counter

    EXPECT_FALSE(x.decode(data.data(), data.size()));
    EXPECT_EQ(0, x.x.size());

    data = bytes("\x01\x00\x00\x00"); // no array elements

    EXPECT_FALSE(x.decode(data.data(), data.size()));
    EXPECT_EQ(1, x.x.size());
    EXPECT_EQ(0, x.x[0]);

    data = bytes("\x01\x00\x00\x00\x02\x00\x00"); // one byte short

    EXPECT_FALSE(x.decode(data.data(), data.size()));
    EXPECT_EQ(1, x.x.size());
    EXPECT_EQ(0, x.x[0]);

    data = bytes("\x01\x00\x00\x00\x02\x00\x00\x00\x00"); // one byte too much

    EXPECT_FALSE(x.decode(data.data(), data.size()));
    EXPECT_EQ(1, x.x.size());
    EXPECT_EQ(2, x.x[0]);
}

TEST(encoding, decode_limited_failures)
{
    BuiltinLimited x;

    EXPECT_FALSE(x.decode(bytes("\x01\x00\x00\x00")));
    EXPECT_EQ(1, x.x.size());
    EXPECT_EQ(0, x.x[0]);

    EXPECT_FALSE(x.decode(bytes("\x01\x00\x00\x00\x01\x00\x00\x00")));
    EXPECT_EQ(1, x.x.size());
    EXPECT_EQ(1, x.x[0]);

    EXPECT_FALSE(x.decode(bytes("\x02\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x03")));
    EXPECT_EQ(2, x.x.size());
    EXPECT_EQ(1, x.x[0]);
    EXPECT_EQ(2, x.x[1]);

    x.x.clear();
    EXPECT_FALSE(x.decode(bytes("\x03\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00")));
    EXPECT_EQ(0, x.x.size());
}

TEST(encoding, decode_greedy_failures)
{
    BuiltinGreedy x;

    EXPECT_FALSE(x.decode(bytes("\x01\x00\x00")));
    EXPECT_EQ(0, x.x.size());

    EXPECT_FALSE(x.decode(bytes("\x01\x00\x00\x00\x02")));
    EXPECT_EQ(1, x.x.size());
    EXPECT_EQ(1, x.x[0]);
}

TEST(encoding, decode_fixed_fixcomp_failures)
{
    FixcompFixed x;

    EXPECT_FALSE(x.decode(bytes("\x01\x00\x00\x00")));
    EXPECT_EQ(1, x.x[0].x);
    EXPECT_EQ(0, x.x[0].y);
    EXPECT_EQ(0, x.x[1].x);
    EXPECT_EQ(0, x.x[1].y);

    EXPECT_FALSE(x.decode(bytes("\x02\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00")));
    EXPECT_EQ(2, x.x[0].x);
    EXPECT_EQ(3, x.x[0].y);
    EXPECT_EQ(4, x.x[1].x);
    EXPECT_EQ(0, x.x[1].y);

    EXPECT_FALSE(x.decode(bytes("\x04\x00\x00\x00\x05\x00\x00\x00\x06\x00\x00\x00\x07\x00\x00\x00\x08")));
    EXPECT_EQ(4, x.x[0].x);
    EXPECT_EQ(5, x.x[0].y);
    EXPECT_EQ(6, x.x[1].x);
    EXPECT_EQ(7, x.x[1].y);
}

TEST(encoding, decode_greedy_dyncomp_failures)
{
    DyncompGreedy x;

    EXPECT_FALSE(x.decode(bytes("\x00")));
    EXPECT_EQ(0, x.x.size());

    EXPECT_FALSE(x.decode(bytes("\x00\x00\x00\x00\x00")));
    EXPECT_EQ(1, x.x.size());
    EXPECT_EQ(0, x.x[0].x.size());

    EXPECT_FALSE(x.decode(bytes("\x02\x00\x00\x00\x03\x00\x00\x00")));
    EXPECT_EQ(0, x.x.size());
}

TEST(encoding, decode_padding_failures)
{
    Endpad x;

    EXPECT_FALSE(x.decode(bytes("\x01\x00\x02")));
    EXPECT_EQ(1, x.x);
    EXPECT_EQ(2, x.y);

    EXPECT_FALSE(x.decode(bytes("\x03\x00\x04\x00\x00")));
    EXPECT_EQ(3, x.x);
    EXPECT_EQ(4, x.y);
}

TEST(encoding, decode_union_failures)
{
    Union x;

    EXPECT_FALSE(x.decode(bytes(
            "\x01\x00\x00\x00"
            "\x04\x00\x00\x00\x00\x00\x00")));
    EXPECT_EQ(Union::discriminator_a, x.discriminator);

    EXPECT_FALSE(x.decode(bytes(
            "\x01\x00\x00\x00"
            "\x04\x00\x00\x00\x00\x00\x00\x00\x00")));
    EXPECT_EQ(Union::discriminator_a, x.discriminator);
    EXPECT_EQ(4, x.a);

    EXPECT_FALSE(x.decode(bytes(
            "\x01\x00\x00\x00"
            "\x08\x00\x00\x00")));
    EXPECT_EQ(Union::discriminator_a, x.discriminator);
    EXPECT_EQ(8, x.a);

    EXPECT_FALSE(x.decode(bytes(
            "\x09\x00\x00\x00"
            "\x04\x00\x00\x00\x00\x00\x00\x00")));
}

TEST(encoding, decode_optional_failures)
{
    BuiltinOptional x;

    EXPECT_FALSE(x.decode(bytes(
            "\x01\x00\x00\x00"
            "\x01\x00\x00")));
    EXPECT_TRUE(x.has_x);

    EXPECT_FALSE(x.decode(bytes(
            "\x01\x00\x00\x00"
            "\x01\x00\x00\x00\x00")));
    EXPECT_TRUE(x.has_x);
    EXPECT_EQ(1, x.x);

    EXPECT_FALSE(x.decode(bytes(
            "\x00\x00\x00\x00"
            "\x08\x00\x00")));
    EXPECT_FALSE(x.has_x);
    EXPECT_EQ(1, x.x);

    EXPECT_FALSE(x.decode(bytes(
            "\x00\x00\x00\x00"
            "\x08\x00\x00\x00\x00")));
    EXPECT_FALSE(x.has_x);
    EXPECT_EQ(1, x.x);
}

TEST(encoding, endianness)
{
    DynfieldsScalarpartialpad x;
    x.x.x = bytes("abc");
    x.y.x = bytes("d");
    x.z.x = bytes("efghi");

    EXPECT_EQ(bytes(
            "\x03\x00\x00\x00" "abc" "\x00"
            "\x01\x00\x00\x00" "d" "\x00\x00\x00"
            "\x05\x00\x00\x00" "efghi" "\x00\x00\x00"),
            x.encode<native>());

    EXPECT_EQ(bytes(
            "\x03\x00\x00\x00" "abc" "\x00"
            "\x01\x00\x00\x00" "d" "\x00\x00\x00"
            "\x05\x00\x00\x00" "efghi" "\x00\x00\x00"),
            x.encode<little>());

    EXPECT_EQ(bytes(
            "\x00\x00\x00\x03" "abc" "\x00"
            "\x00\x00\x00\x01" "d" "\x00\x00\x00"
            "\x00\x00\x00\x05" "efghi" "\x00\x00\x00"),
            x.encode<big>());
}
<commit_msg>decoding complex message depending on endianness tested<commit_after>#include <string>
#include <gtest/gtest.h>
#include <prophy/detail/decoder.hpp>
#include "generated/Arrays.pp.hpp"
#include "generated/Dynfields.pp.hpp"
#include "generated/Paddings.pp.hpp"
#include "generated/Unions.pp.hpp"
#include "util.hpp"

using namespace testing;
using namespace prophy;
using namespace prophy::detail;

TEST(encoding, decode_struct_failures)
{
    Builtin x;

    EXPECT_FALSE(x.decode(bytes("\x01\x00\x00\x00\x02\x00\x00")));
    EXPECT_EQ(1, x.x);
    EXPECT_EQ(0, x.y);

    EXPECT_FALSE(x.decode(bytes("\x03\x00\x00\x00\x04\x00\x00\x00\x00")));
    EXPECT_EQ(3, x.x);
    EXPECT_EQ(4, x.y);

    EXPECT_FALSE(x.decode(bytes("\x05\x00\x00\x00")));
    EXPECT_EQ(5, x.x);
    EXPECT_EQ(4, x.y);
}

TEST(encoding, decode_dynamic_failures)
{
    BuiltinDynamic x;
    std::vector<uint8_t> data = bytes("\x01\x00\x00"); //not enough to decode counter

    EXPECT_FALSE(x.decode(data.data(), data.size()));
    EXPECT_EQ(0, x.x.size());

    data = bytes("\x01\x00\x00\x00"); // no array elements

    EXPECT_FALSE(x.decode(data.data(), data.size()));
    EXPECT_EQ(1, x.x.size());
    EXPECT_EQ(0, x.x[0]);

    data = bytes("\x01\x00\x00\x00\x02\x00\x00"); // one byte short

    EXPECT_FALSE(x.decode(data.data(), data.size()));
    EXPECT_EQ(1, x.x.size());
    EXPECT_EQ(0, x.x[0]);

    data = bytes("\x01\x00\x00\x00\x02\x00\x00\x00\x00"); // one byte too much

    EXPECT_FALSE(x.decode(data.data(), data.size()));
    EXPECT_EQ(1, x.x.size());
    EXPECT_EQ(2, x.x[0]);
}

TEST(encoding, decode_limited_failures)
{
    BuiltinLimited x;

    EXPECT_FALSE(x.decode(bytes("\x01\x00\x00\x00")));
    EXPECT_EQ(1, x.x.size());
    EXPECT_EQ(0, x.x[0]);

    EXPECT_FALSE(x.decode(bytes("\x01\x00\x00\x00\x01\x00\x00\x00")));
    EXPECT_EQ(1, x.x.size());
    EXPECT_EQ(1, x.x[0]);

    EXPECT_FALSE(x.decode(bytes("\x02\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x03")));
    EXPECT_EQ(2, x.x.size());
    EXPECT_EQ(1, x.x[0]);
    EXPECT_EQ(2, x.x[1]);

    x.x.clear();
    EXPECT_FALSE(x.decode(bytes("\x03\x00\x00\x00\x01\x00\x00\x00\x02\x00\x00\x00\x03\x00\x00\x00")));
    EXPECT_EQ(0, x.x.size());
}

TEST(encoding, decode_greedy_failures)
{
    BuiltinGreedy x;

    EXPECT_FALSE(x.decode(bytes("\x01\x00\x00")));
    EXPECT_EQ(0, x.x.size());

    EXPECT_FALSE(x.decode(bytes("\x01\x00\x00\x00\x02")));
    EXPECT_EQ(1, x.x.size());
    EXPECT_EQ(1, x.x[0]);
}

TEST(encoding, decode_fixed_fixcomp_failures)
{
    FixcompFixed x;

    EXPECT_FALSE(x.decode(bytes("\x01\x00\x00\x00")));
    EXPECT_EQ(1, x.x[0].x);
    EXPECT_EQ(0, x.x[0].y);
    EXPECT_EQ(0, x.x[1].x);
    EXPECT_EQ(0, x.x[1].y);

    EXPECT_FALSE(x.decode(bytes("\x02\x00\x00\x00\x03\x00\x00\x00\x04\x00\x00\x00")));
    EXPECT_EQ(2, x.x[0].x);
    EXPECT_EQ(3, x.x[0].y);
    EXPECT_EQ(4, x.x[1].x);
    EXPECT_EQ(0, x.x[1].y);

    EXPECT_FALSE(x.decode(bytes("\x04\x00\x00\x00\x05\x00\x00\x00\x06\x00\x00\x00\x07\x00\x00\x00\x08")));
    EXPECT_EQ(4, x.x[0].x);
    EXPECT_EQ(5, x.x[0].y);
    EXPECT_EQ(6, x.x[1].x);
    EXPECT_EQ(7, x.x[1].y);
}

TEST(encoding, decode_greedy_dyncomp_failures)
{
    DyncompGreedy x;

    EXPECT_FALSE(x.decode(bytes("\x00")));
    EXPECT_EQ(0, x.x.size());

    EXPECT_FALSE(x.decode(bytes("\x00\x00\x00\x00\x00")));
    EXPECT_EQ(1, x.x.size());
    EXPECT_EQ(0, x.x[0].x.size());

    EXPECT_FALSE(x.decode(bytes("\x02\x00\x00\x00\x03\x00\x00\x00")));
    EXPECT_EQ(0, x.x.size());
}

TEST(encoding, decode_padding_failures)
{
    Endpad x;

    EXPECT_FALSE(x.decode(bytes("\x01\x00\x02")));
    EXPECT_EQ(1, x.x);
    EXPECT_EQ(2, x.y);

    EXPECT_FALSE(x.decode(bytes("\x03\x00\x04\x00\x00")));
    EXPECT_EQ(3, x.x);
    EXPECT_EQ(4, x.y);
}

TEST(encoding, decode_union_failures)
{
    Union x;

    EXPECT_FALSE(x.decode(bytes(
            "\x01\x00\x00\x00"
            "\x04\x00\x00\x00\x00\x00\x00")));
    EXPECT_EQ(Union::discriminator_a, x.discriminator);

    EXPECT_FALSE(x.decode(bytes(
            "\x01\x00\x00\x00"
            "\x04\x00\x00\x00\x00\x00\x00\x00\x00")));
    EXPECT_EQ(Union::discriminator_a, x.discriminator);
    EXPECT_EQ(4, x.a);

    EXPECT_FALSE(x.decode(bytes(
            "\x01\x00\x00\x00"
            "\x08\x00\x00\x00")));
    EXPECT_EQ(Union::discriminator_a, x.discriminator);
    EXPECT_EQ(8, x.a);

    EXPECT_FALSE(x.decode(bytes(
            "\x09\x00\x00\x00"
            "\x04\x00\x00\x00\x00\x00\x00\x00")));
}

TEST(encoding, decode_optional_failures)
{
    BuiltinOptional x;

    EXPECT_FALSE(x.decode(bytes(
            "\x01\x00\x00\x00"
            "\x01\x00\x00")));
    EXPECT_TRUE(x.has_x);

    EXPECT_FALSE(x.decode(bytes(
            "\x01\x00\x00\x00"
            "\x01\x00\x00\x00\x00")));
    EXPECT_TRUE(x.has_x);
    EXPECT_EQ(1, x.x);

    EXPECT_FALSE(x.decode(bytes(
            "\x00\x00\x00\x00"
            "\x08\x00\x00")));
    EXPECT_FALSE(x.has_x);
    EXPECT_EQ(1, x.x);

    EXPECT_FALSE(x.decode(bytes(
            "\x00\x00\x00\x00"
            "\x08\x00\x00\x00\x00")));
    EXPECT_FALSE(x.has_x);
    EXPECT_EQ(1, x.x);
}

TEST(encoding, endianness)
{
    DynfieldsScalarpartialpad x;
    x.x.x = bytes("abc");
    x.y.x = bytes("d");
    x.z.x = bytes("efghi");

    EXPECT_EQ(bytes(
            "\x03\x00\x00\x00" "abc" "\x00"
            "\x01\x00\x00\x00" "d" "\x00\x00\x00"
            "\x05\x00\x00\x00" "efghi" "\x00\x00\x00"),
            x.encode<native>());

    EXPECT_EQ(bytes(
            "\x03\x00\x00\x00" "abc" "\x00"
            "\x01\x00\x00\x00" "d" "\x00\x00\x00"
            "\x05\x00\x00\x00" "efghi" "\x00\x00\x00"),
            x.encode<little>());

    EXPECT_EQ(bytes(
            "\x00\x00\x00\x03" "abc" "\x00"
            "\x00\x00\x00\x01" "d" "\x00\x00\x00"
            "\x00\x00\x00\x05" "efghi" "\x00\x00\x00"),
            x.encode<big>());

    EXPECT_TRUE(x.decode<native>(bytes(
            "\x01\x00\x00\x00" "a" "\x00\x00\x00"
            "\x02\x00\x00\x00" "bc" "\x00\x00"
            "\x03\x00\x00\x00" "def" "\x00")));
    EXPECT_EQ(bytes("a"), x.x.x);
    EXPECT_EQ(bytes("bc"), x.y.x);
    EXPECT_EQ(bytes("def"), x.z.x);

    EXPECT_TRUE(x.decode<little>(bytes(
            "\x01\x00\x00\x00" "a" "\x00\x00\x00"
            "\x02\x00\x00\x00" "bc" "\x00\x00"
            "\x03\x00\x00\x00" "def" "\x00")));
    EXPECT_EQ(bytes("a"), x.x.x);
    EXPECT_EQ(bytes("bc"), x.y.x);
    EXPECT_EQ(bytes("def"), x.z.x);

    EXPECT_TRUE(x.decode<big>(bytes(
            "\x00\x00\x00\x01" "a" "\x00\x00\x00"
            "\x00\x00\x00\x02" "bc" "\x00\x00"
            "\x00\x00\x00\x03" "def" "\x00")));
    EXPECT_EQ(bytes("a"), x.x.x);
    EXPECT_EQ(bytes("bc"), x.y.x);
    EXPECT_EQ(bytes("def"), x.z.x);
}
<|endoftext|>


<commit_before>/*
 * Chrome Token Signing Native Host
 *
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "PKCS11Path.h"
#include "BinaryUtils.h"
#include "Logger.h"

#ifdef _WIN32
#undef UNICODE
#include <Shlobj.h>
#include <Shlwapi.h>
#include <Knownfolders.h>
#include <winscard.h>
#elif defined __APPLE__
#include <PCSC/winscard.h>
#include <PCSC/wintypes.h>
#include <unistd.h>
#else
#include <winscard.h>
#include <unistd.h>
#endif

#include <cstring>
#include <map>

std::vector<std::string> PKCS11Path::atrList() {
	SCARDCONTEXT hContext = 0;
	std::vector<std::string> result;
	LONG err = SCardEstablishContext(SCARD_SCOPE_USER, nullptr, nullptr, &hContext);
	if (err != SCARD_S_SUCCESS) {
		_log("SCardEstablishContext ERROR: %x", err);
		return result;
	}

	DWORD size = 0;
	err = SCardListReaders(hContext, nullptr, nullptr, &size);
	if (err != SCARD_S_SUCCESS || !size) {
		_log("SCardListReaders || !size ERROR: %x", err);
		SCardReleaseContext(hContext);
		return result;
	}

	std::string readers(size, 0);
	err = SCardListReaders(hContext, nullptr, &readers[0], &size);
	readers.resize(size);
	if (err != SCARD_S_SUCCESS) {
		_log("SCardListReaders ERROR: %x", err);
		SCardReleaseContext(hContext);
		return result;
	}

    std::vector<SCARD_READERSTATE> list;
    for (const char *name = readers.c_str(); *name; name += strlen(name) + 1) {
        _log("found reader: %s", name);
        list.push_back({ name, nullptr, 0, 0, 0, {} });
    }

    err = SCardGetStatusChange(hContext, 0, list.data(), DWORD(list.size()));
    if (err != SCARD_S_SUCCESS)
        _log("SCardGetStatusChange ERROR: %x", err);
    for(const SCARD_READERSTATE &state: list)
    {
        if (state.dwEventState & SCARD_STATE_PRESENT)
        {
            std::string atr = BinaryUtils::bin2hex(state.rgbAtr, state.cbAtr);
            result.push_back(atr);
            _log("Set ATR = %s for reader %s", atr.c_str(), state.szReader);
        }
    }

    SCardReleaseContext(hContext);
    return result;
}

PKCS11Path::Params PKCS11Path::getPkcs11ModulePath() {
#ifdef _WIN32
    // Use PKCS11 driver on windows to avoid PIN buffering
    static const std::string litPath = [] {
        PWSTR programFilesX86 = 0;
        SHGetKnownFolderPath(FOLDERID_ProgramFilesX86, 0, nullptr, &programFilesX86);
        std::wstring path = programFilesX86;
        CoTaskMemFree(programFilesX86);
        if (PathFileExistsW((path + L"\\PWPW\\pwpw-card-pkcs11.dll").c_str()))
            path += L"\\PWPW\\pwpw-card-pkcs11.dll";
        else
            path += L"\\CryptoTech\\CryptoCard\\CCPkiP11.dll";
        int size = WideCharToMultiByte(CP_UTF8, 0, path.c_str(), DWORD(path.size()), nullptr, 0, nullptr, nullptr);
        std::string result(size, 0);
        WideCharToMultiByte(CP_UTF8, 0, path.c_str(), DWORD(path.size()), &result[0], size, nullptr, nullptr);
        return result;
    }();
#elif defined __APPLE__
    static const std::string openscPath("/Library/OpenSC/lib/opensc-pkcs11.so");
    static const std::string estPath = openscPath;
    static const std::string latPath("/Library/latvia-eid/lib/otlv-pkcs11.so");
    static const std::string finPath("/Library/mPolluxDigiSign/libcryptoki.dylib");
    static const std::string lit1Path("/Library/Security/tokend/CCSuite.tokend/Contents/Frameworks/libccpkip11.dylib");
    static const std::string lit2Path("/Library/PWPW-Card/pwpw-card-pkcs11.so");
    static const std::string litPath = access(lit1Path.c_str(), F_OK) == 0 ? lit1Path : lit2Path;
    static const std::string belPath("/usr/local/lib/beid-pkcs11.bundle/Contents/MacOS/libbeidpkcs11.dylib");
    static const std::string eTokenPath("/Library/Frameworks/eToken.framework/Versions/Current/libeToken.dylib");
#else
    static const std::string openscPath("opensc-pkcs11.so");
    static const std::string estPath = openscPath;
    static const std::string latPath("otlv-pkcs11.so");
    static const std::string finPath("libcryptoki.so");
    static const std::string lit1Path("/usr/lib/ccs/libccpkip11.so");
    static const std::string lit2Path("pwpw-card-pkcs11.so");
    static const std::string litPath = access(lit1Path.c_str(), F_OK) == 0 ? lit1Path : lit2Path;
    static const std::string belPath("libbeidpkcs11.so.0");
    static const std::string eTokenPath("/usr/lib/libeTPkcs11.so");
#endif
    static const std::map<std::string, Params> m = {
#ifdef _WIN32
        {"3BFD1800008031FE4553434536302D43443134352D46CD", {"C:\\Windows\\System32\\aetpkss1.dll", "PIN", "PIN"}},
#else
        {"3BFE1800008031FE454573744549442076657220312E30A8", {estPath, "PIN1", "PIN2"}}, //ESTEID_V3_COLD_DEV1_ATR
        {"3BFE1800008031FE45803180664090A4561B168301900086", {estPath, "PIN1", "PIN2"}}, //ESTEID_V3_WARM_DEV1_ATR
        {"3BFE1800008031FE45803180664090A4162A0083019000E1", {estPath, "PIN1", "PIN2"}}, //ESTEID_V3_WARM_DEV2_ATR
        {"3BFE1800008031FE45803180664090A4162A00830F9000EF", {estPath, "PIN1", "PIN2"}}, //ESTEID_V3_WARM_DEV3_ATR
        {"3BFA1800008031FE45FE654944202F20504B4903", {estPath, "PIN1", "PIN2"}}, //ESTEID_V3.5_COLD_ATR
        {"3BDB960080B1FE451F830012233F536549440F9000F1", {estPath, "PIN1", "PIN2"}}, // IDEMIA 2018

        {"3BDD18008131FE45904C41545649412D65494490008C", {latPath, "PIN1", "PIN2"}},

        {"3B7B940000806212515646696E454944", {finPath, "PIN1", "PIN2"}},
        {"3B7F9600008031B865B0850300EF1200F6829000", {finPath, "PIN1", "PIN2"}},

        {"3B9813400AA503010101AD1311", {belPath, "PIN", "PIN"}},

        {"3BD5180081313A7D8073C8211030", {eTokenPath, "PIN", "PIN"}},
        {"3BD518008131FE7D8073C82110F4", {eTokenPath, "PIN", "PIN"}},
#endif
        {"3BF81300008131FE45536D617274417070F8", {litPath, "PIN", "PIN"}},
        {"3B7D94000080318065B08311C0A983009000", {litPath, "PIN", "PIN"}},
        {"3B7D94000080318065B0831100C883009000", {litPath, "PIN", "PIN"}},
        {"3B9F9681B1FE451F070064051EB20031B0739621DB00900050", {litPath, "PIN", "PIN"}},
        {"3B9F90801FC30068104405014649534531C800000000", {litPath, "PIN", "PIN"}},
    };

    const std::vector<std::string> list = atrList();
    for (const std::string &atr : list) {
        auto it = m.find(atr);
        if (it != m.end())
            return it->second;
    }
#ifdef _WIN32
    return Params();
#else
    if (!list.empty())
        _log("Unknown ATR '%s' using default module '%s'", list[0].c_str(), openscPath.c_str());
    return {openscPath, "PIN", "PIN"};
#endif
}
<commit_msg>ACOS and AKIS smart card support (#151)<commit_after>/*
 * Chrome Token Signing Native Host
 *
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "PKCS11Path.h"
#include "BinaryUtils.h"
#include "Logger.h"

#ifdef _WIN32
#undef UNICODE
#include <Shlobj.h>
#include <Shlwapi.h>
#include <Knownfolders.h>
#include <winscard.h>
#elif defined __APPLE__
#include <PCSC/winscard.h>
#include <PCSC/wintypes.h>
#include <unistd.h>
#else
#include <winscard.h>
#include <unistd.h>
#endif

#include <cstring>
#include <map>

std::vector<std::string> PKCS11Path::atrList() {
	SCARDCONTEXT hContext = 0;
	std::vector<std::string> result;
	LONG err = SCardEstablishContext(SCARD_SCOPE_USER, nullptr, nullptr, &hContext);
	if (err != SCARD_S_SUCCESS) {
		_log("SCardEstablishContext ERROR: %x", err);
		return result;
	}

	DWORD size = 0;
	err = SCardListReaders(hContext, nullptr, nullptr, &size);
	if (err != SCARD_S_SUCCESS || !size) {
		_log("SCardListReaders || !size ERROR: %x", err);
		SCardReleaseContext(hContext);
		return result;
	}

	std::string readers(size, 0);
	err = SCardListReaders(hContext, nullptr, &readers[0], &size);
	readers.resize(size);
	if (err != SCARD_S_SUCCESS) {
		_log("SCardListReaders ERROR: %x", err);
		SCardReleaseContext(hContext);
		return result;
	}

    std::vector<SCARD_READERSTATE> list;
    for (const char *name = readers.c_str(); *name; name += strlen(name) + 1) {
        _log("found reader: %s", name);
        list.push_back({ name, nullptr, 0, 0, 0, {} });
    }

    err = SCardGetStatusChange(hContext, 0, list.data(), DWORD(list.size()));
    if (err != SCARD_S_SUCCESS)
        _log("SCardGetStatusChange ERROR: %x", err);
    for(const SCARD_READERSTATE &state: list)
    {
        if (state.dwEventState & SCARD_STATE_PRESENT)
        {
            std::string atr = BinaryUtils::bin2hex(state.rgbAtr, state.cbAtr);
            result.push_back(atr);
            _log("Set ATR = %s for reader %s", atr.c_str(), state.szReader);
        }
    }

    SCardReleaseContext(hContext);
    return result;
}

PKCS11Path::Params PKCS11Path::getPkcs11ModulePath() {
#ifdef _WIN32
    // Use PKCS11 driver on windows to avoid PIN buffering
    static const std::string litPath = [] {
        PWSTR programFilesX86 = 0;
        SHGetKnownFolderPath(FOLDERID_ProgramFilesX86, 0, nullptr, &programFilesX86);
        std::wstring path = programFilesX86;
        CoTaskMemFree(programFilesX86);
        if (PathFileExistsW((path + L"\\PWPW\\pwpw-card-pkcs11.dll").c_str()))
            path += L"\\PWPW\\pwpw-card-pkcs11.dll";
        else
            path += L"\\CryptoTech\\CryptoCard\\CCPkiP11.dll";
        int size = WideCharToMultiByte(CP_UTF8, 0, path.c_str(), DWORD(path.size()), nullptr, 0, nullptr, nullptr);
        std::string result(size, 0);
        WideCharToMultiByte(CP_UTF8, 0, path.c_str(), DWORD(path.size()), &result[0], size, nullptr, nullptr);
        return result;
    }();
#elif defined __APPLE__
    static const std::string openscPath("/Library/OpenSC/lib/opensc-pkcs11.so");
    static const std::string estPath = openscPath;
    static const std::string latPath("/Library/latvia-eid/lib/otlv-pkcs11.so");
    static const std::string finPath("/Library/mPolluxDigiSign/libcryptoki.dylib");
    static const std::string lit1Path("/Library/Security/tokend/CCSuite.tokend/Contents/Frameworks/libccpkip11.dylib");
    static const std::string lit2Path("/Library/PWPW-Card/pwpw-card-pkcs11.so");
    static const std::string litPath = access(lit1Path.c_str(), F_OK) == 0 ? lit1Path : lit2Path;
    static const std::string belPath("/usr/local/lib/beid-pkcs11.bundle/Contents/MacOS/libbeidpkcs11.dylib");
    static const std::string eTokenPath("/Library/Frameworks/eToken.framework/Versions/Current/libeToken.dylib");
    static const std::string acsPath("/usr/local/lib/libacos5pkcs11.dylib");
    static const std::string akisPath("/usr/local/lib/libakisp11.dylib");
#else
    static const std::string openscPath("opensc-pkcs11.so");
    static const std::string estPath = openscPath;
    static const std::string latPath("otlv-pkcs11.so");
    static const std::string finPath("libcryptoki.so");
    static const std::string lit1Path("/usr/lib/ccs/libccpkip11.so");
    static const std::string lit2Path("pwpw-card-pkcs11.so");
    static const std::string litPath = access(lit1Path.c_str(), F_OK) == 0 ? lit1Path : lit2Path;
    static const std::string belPath("libbeidpkcs11.so.0");
    static const std::string eTokenPath("/usr/lib/libeTPkcs11.so");
    static const std::string acsPath("/lib/libacospkcs11.so");
    static const std::string akisPath("/usr/lib/libpkcs11wrapper.so");
#endif
    static const std::map<std::string, Params> m = {
#ifdef _WIN32
        {"3BFD1800008031FE4553434536302D43443134352D46CD", {"C:\\Windows\\System32\\aetpkss1.dll", "PIN", "PIN"}},
        {"3B9F968131FE45806755454B41451293318073B3A1806B", {"C:\\Windows\\System32\\akisp11.dll", "PIN", "PIN"}},
#else
        {"3BFE1800008031FE454573744549442076657220312E30A8", {estPath, "PIN1", "PIN2"}}, //ESTEID_V3_COLD_DEV1_ATR
        {"3BFE1800008031FE45803180664090A4561B168301900086", {estPath, "PIN1", "PIN2"}}, //ESTEID_V3_WARM_DEV1_ATR
        {"3BFE1800008031FE45803180664090A4162A0083019000E1", {estPath, "PIN1", "PIN2"}}, //ESTEID_V3_WARM_DEV2_ATR
        {"3BFE1800008031FE45803180664090A4162A00830F9000EF", {estPath, "PIN1", "PIN2"}}, //ESTEID_V3_WARM_DEV3_ATR
        {"3BFA1800008031FE45FE654944202F20504B4903", {estPath, "PIN1", "PIN2"}}, //ESTEID_V3.5_COLD_ATR
        {"3BDB960080B1FE451F830012233F536549440F9000F1", {estPath, "PIN1", "PIN2"}}, // IDEMIA 2018

        {"3BDD18008131FE45904C41545649412D65494490008C", {latPath, "PIN1", "PIN2"}},

        {"3B7B940000806212515646696E454944", {finPath, "PIN1", "PIN2"}},
        {"3B7F9600008031B865B0850300EF1200F6829000", {finPath, "PIN1", "PIN2"}},

        {"3B9813400AA503010101AD1311", {belPath, "PIN", "PIN"}},

        {"3BD5180081313A7D8073C8211030", {eTokenPath, "PIN", "PIN"}},
        {"3BD518008131FE7D8073C82110F4", {eTokenPath, "PIN", "PIN"}},
        {"3BBE9600004105200000000000000000009000", {acsPath, "PIN", "PIN" }},
        {"3B9F968131FE45806755454B41451293318073B3A1806B", {akisPath, "PIN", "PIN"}},
#endif
        {"3BF81300008131FE45536D617274417070F8", {litPath, "PIN", "PIN"}},
        {"3B7D94000080318065B08311C0A983009000", {litPath, "PIN", "PIN"}},
        {"3B7D94000080318065B0831100C883009000", {litPath, "PIN", "PIN"}},
        {"3B9F9681B1FE451F070064051EB20031B0739621DB00900050", {litPath, "PIN", "PIN"}},
        {"3B9F90801FC30068104405014649534531C800000000", {litPath, "PIN", "PIN"}},
    };

    const std::vector<std::string> list = atrList();
    for (const std::string &atr : list) {
        auto it = m.find(atr);
        if (it != m.end())
            return it->second;
    }
#ifdef _WIN32
    return Params();
#else
    if (!list.empty())
        _log("Unknown ATR '%s' using default module '%s'", list[0].c_str(), openscPath.c_str());
    return {openscPath, "PIN", "PIN"};
#endif
}
<|endoftext|>


<commit_before>/*******************************************************************************
 * c7a/api/sort.hpp
 *
 * Part of Project c7a.
 *
 * Copyright (C) 2015 Alexander Noe <aleexnoe@gmail.com>
 * Copyright (C) 2015 Timo Bingmann <tb@panthema.net>
 * Copyright (C) 2015 Michael Axtmann <michael.axtmann@kit.edu>
 *
 * This file has no license. Only Chuck Norris can compile it.
 ******************************************************************************/

#pragma once
#ifndef C7A_API_SORT_HEADER
#define C7A_API_SORT_HEADER

#include <c7a/api/dia.hpp>
#include <c7a/api/dop_node.hpp>
#include <c7a/common/logger.hpp>
#include <c7a/common/math.hpp>
#include <c7a/net/flow_control_channel.hpp>
#include <c7a/net/flow_control_manager.hpp>
#include <c7a/net/group.hpp>

#include <algorithm>
#include <functional>
#include <string>
#include <vector>

namespace c7a {
namespace api {

//! \addtogroup api Interface
//! \{

/*!
 * A DIANode which performs a Sort operation. Sort sorts a DIA according to a given
 * compare function
 *
 * \tparam ValueType Type of DIA elements
 * \tparam Stack Function stack, which contains the chained lambdas between the last and this DIANode.
 * \tparam CompareFunction Type of the compare function
 */
template <typename ValueType, typename ParentDIARef, typename CompareFunction>
class SortNode : public DOpNode<ValueType>
{
    static const bool debug = false;

    using Super = DOpNode<ValueType>;
    using Super::context_;
    using Super::result_file_;

public:
    /*!
     * Constructor for a sort node.
     *
     * \param parent DIARef.
     * \param parent_stack Stack of lambda functions between parent and this node
     * \param compare_function Function comparing two elements.
     */
    SortNode(const ParentDIARef& parent,
             CompareFunction compare_function,
             StatsNode* stats_node)
        : DOpNode<ValueType>(parent.ctx(), { parent.node() }, "Sort", stats_node),
          compare_function_(compare_function),
          channel_id_samples_(parent.ctx().GetNewChannel()),
          emitters_samples_(channel_id_samples_->OpenWriters()),
          channel_id_data_(parent.ctx().GetNewChannel()),
          emitters_data_(channel_id_data_->OpenWriters())
    {
        // Hook PreOp(s)
        auto pre_op_fn = [=](const ValueType& input) {
                             PreOp(input);
                         };

        auto lop_chain = parent.stack().push(pre_op_fn).emit();
        parent.node()->RegisterChild(lop_chain);
    }

    virtual ~SortNode() { }

    //! Executes the sum operation.
    void Execute() final {
        MainOp();
    }

    void PushData() final {

        for (size_t i = 0; i < data_.size(); i++) {
            for (auto func : DIANode<ValueType>::callbacks_) {
                func(data_[i]);
            }
        }
    }

    void Dispose() final { }

    /*!
     * Produces an 'empty' function stack, which only contains the identity
     * emitter function.
     *
     * \return Empty function stack
     */
    auto ProduceStack() {
        return FunctionStack<ValueType>();
    }

    /*!
     * Returns "[SortNode]" as a string.
     * \return "[SortNode]"
     */
    std::string ToString() final {
        return "[SortNode] Id:" + result_file_.ToString();
    }

private:
    //! The sum function which is applied to two elements.
    CompareFunction compare_function_;
    //! Local data
    std::vector<ValueType> data_;

    //!Emitter to send samples to process 0
    data::ChannelPtr channel_id_samples_;
    std::vector<data::BlockWriter> emitters_samples_;

    //!Emitters to send data to other workers specified by splitters.
    data::ChannelPtr channel_id_data_;
    std::vector<data::BlockWriter> emitters_data_;

    // epsilon
    static constexpr double desired_imbalance_ = 0.25;

    void PreOp(ValueType input) {
        data_.push_back(input);
    }

    void FindAndSendSplitters(
        std::vector<ValueType>& splitters, size_t sample_size) {
        // Get samples from other workers
        size_t num_total_workers = context_.num_workers();

        std::vector<ValueType> samples;
        samples.reserve(sample_size * num_total_workers);
        auto reader = channel_id_samples_->OpenReader();

        while (reader.HasNext()) {
            samples.push_back(reader.template Next<ValueType>());
        }

        // Find splitters
        std::sort(samples.begin(), samples.end(), compare_function_);

        size_t splitting_size = samples.size() / num_total_workers;

        // Send splitters to other workers
        for (size_t i = 1; i < num_total_workers; i++) {
            splitters.push_back(samples[i * splitting_size]);
            for (size_t j = 1; j < num_total_workers; j++) {
                emitters_samples_[j](samples[i * splitting_size]);
            }
        }

        for (size_t j = 1; j < num_total_workers; j++) {
            emitters_samples_[j].Close();
        }
    }

    class TreeBuilder
    {
    public:
        ValueType* tree_;
        ValueType* samples_;
        size_t index_ = 0;
        size_t ssplitter;

        /*!
         * Target: tree. Size of 'number of splitter'
         * Source: sorted splitters. Size of 'number of splitter'
         * Number of splitter
         */
        TreeBuilder(ValueType* splitter_tree,
                    ValueType* samples,
                    size_t ssplitter)
            : tree_(splitter_tree),
              samples_(samples),
              ssplitter(ssplitter) {
            recurse(samples, samples + ssplitter, 1);
        }

        void recurse(ValueType* lo, ValueType* hi, unsigned int treeidx) {

            // pick middle element as splitter
            ValueType* mid = lo + (ssize_t)(hi - lo) / 2;
            tree_[treeidx] = *mid;

            ValueType* midlo = mid, * midhi = mid + 1;

            if (2 * treeidx < ssplitter)
            {
                recurse(lo, midlo, 2 * treeidx + 0);
                recurse(midhi, hi, 2 * treeidx + 1);
            }
        }
    };

    bool Equal(const ValueType& ele1, const ValueType& ele2) {
        return !(compare_function_(ele1, ele2) || compare_function_(ele2, ele1));
    }

    //! round n down by k where k is a power of two.
    template <typename Integral>
    static inline size_t RoundDown(Integral n, Integral k) {
        return (n & ~(k - 1));
    }

    void EmitToBuckets(
        // Tree of splitters, sizeof |splitter|
        const ValueType* const tree,
        // Number of buckets: k = 2^{log_k}
        size_t k,
        size_t log_k,
        // Number of actual workers to send to
        size_t actual_k,
        const ValueType* const sorted_splitters,
        size_t prefix_elem,
        size_t total_elem) {

        // enlarge emitters array to next power of two to have direct access,
        // because we fill the splitter set up with sentinels == last splitter,
        // hence all items land in the last bucket.
        assert(emitters_data_.size() == actual_k);
        assert(actual_k <= k);

        while (emitters_data_.size() < k)
            emitters_data_.emplace_back(nullptr);

        std::swap(emitters_data_[actual_k - 1], emitters_data_[k - 1]);

        // classify all items (take two at once) and immediately transmit them.

        const size_t stepsize = 2;

        size_t i = 0;
        for ( ; i < RoundDown(data_.size(), stepsize); i += stepsize)
        {
            // take two items
            size_t j0 = 1;
            const ValueType& el0 = data_[i];

            size_t j1 = 1;
            const ValueType& el1 = data_[i + 1];

            // run items down the tree
            for (size_t l = 0; l < log_k; l++)
            {
                j0 = j0 * 2 + !(compare_function_(el0, tree[j0]));
                j1 = j1 * 2 + !(compare_function_(el1, tree[j1]));
            }

            size_t b0 = j0 - k;
            size_t b1 = j1 - k;

            while (b0 && Equal(el0, sorted_splitters[b0 - 1])
                   && (prefix_elem + i) * actual_k >= b0 * total_elem) {
                b0--;
            }
            assert(emitters_data_[b0].IsValid());
            emitters_data_[b0](el0);

            while (b1 && Equal(el1, sorted_splitters[b1 - 1])
                   && (prefix_elem + i + 1) * actual_k >= b1 * total_elem) {
                b1--;
            }
            assert(emitters_data_[b1].IsValid());
            emitters_data_[b1](el1);
        }

        // last iteration of loop if we have an odd number of items.
        for ( ; i < data_.size(); i++)
        {
            size_t j = 1;
            for (size_t l = 0; l < log_k; l++)
            {
                j = j * 2 + !(compare_function_(data_[i], tree[j]));
            }

            size_t b = j - k;

            while (b && Equal(data_[i], sorted_splitters[b - 1])
                   && (prefix_elem + i) * actual_k >= b * total_elem) {
                b--;
            }
            assert(emitters_data_[b].IsValid());
            emitters_data_[b](data_[i]);
        }
    }

    void MainOp() {
        net::FlowControlChannel& channel = context_.flow_control_channel();

        size_t prefix_elem = channel.PrefixSum(data_.size());
        size_t total_elem = channel.AllReduce(data_.size());

        size_t num_total_workers = context_.num_workers();
        size_t sample_size =
            common::IntegerLog2Ceil(total_elem) *
            (1 / (desired_imbalance_ * desired_imbalance_));

        LOG << prefix_elem << " elements, out of " << total_elem;

        std::default_random_engine generator({ std::random_device()() });
        std::uniform_int_distribution<int> distribution(0, data_.size() - 1);

        // Send samples to worker 0
        for (size_t i = 0; i < sample_size; i++) {
            size_t sample = distribution(generator);
            emitters_samples_[0](data_[sample]);
        }
        emitters_samples_[0].Close();

        // Get the ceiling of log(num_total_workers), as SSSS needs 2^n buckets.
        size_t ceil_log = common::IntegerLog2Ceil(num_total_workers);
        size_t workers_algo = 1 << ceil_log;
        size_t splitter_count_algo = workers_algo - 1;

        std::vector<ValueType> splitters;
        splitters.reserve(workers_algo);

        if (context_.my_rank() == 0) {
            FindAndSendSplitters(splitters, sample_size);
        }
        else {
            // Close unused emitters
            for (size_t j = 1; j < num_total_workers; j++) {
                emitters_samples_[j].Close();
            }
            auto reader = channel_id_samples_->OpenReader();
            while (reader.HasNext()) {
                splitters.push_back(reader.template Next<ValueType>());
            }
        }
        channel_id_samples_->Close();

        //code from SS2NPartition, slightly altered

        ValueType* splitter_tree = new ValueType[workers_algo + 1];

        // add sentinel splitters if fewer nodes than splitters.
        for (size_t i = num_total_workers; i < workers_algo; i++) {
            splitters.push_back(splitters.back());
        }

        TreeBuilder(splitter_tree,
                    splitters.data(),
                    splitter_count_algo);

        EmitToBuckets(
            splitter_tree, // Tree. sizeof |splitter|
            workers_algo,  // Number of buckets
            ceil_log,
            num_total_workers,
            splitters.data(),
            prefix_elem,
            total_elem);

        delete[] splitter_tree;

        //end of SS2N

        for (size_t i = 0; i < emitters_data_.size(); i++)
            emitters_data_[i].Close();

        data_.clear();

        auto reader = channel_id_data_->OpenReader();

        while (reader.HasNext()) {
            data_.push_back(reader.template Next<ValueType>());
        }
        channel_id_data_->Close();

        LOG << "node " << context_.my_rank() << " : " << data_.size();

        std::sort(data_.begin(), data_.end(), compare_function_);
        this->WriteChannelStats(channel_id_data_);
        this->WriteChannelStats(channel_id_samples_);
    }

    void PostOp() { }
};

template <typename ValueType, typename Stack>
template <typename CompareFunction>
auto DIARef<ValueType, Stack>::Sort(const CompareFunction &compare_function) const {

    using SortResultNode
              = SortNode<ValueType, DIARef, CompareFunction>;

    static_assert(
        std::is_convertible<
            ValueType,
            typename FunctionTraits<CompareFunction>::template arg<0>
            >::value ||
        std::is_same<CompareFunction, std::less<ValueType> >::value,
        "CompareFunction has the wrong input type");

    static_assert(
        std::is_convertible<
            ValueType,
            typename FunctionTraits<CompareFunction>::template arg<1> >::value ||
        std::is_same<CompareFunction, std::less<ValueType> >::value,
        "CompareFunction has the wrong input type");

    static_assert(
        std::is_convertible<
            typename FunctionTraits<CompareFunction>::result_type,
            bool>::value,
        "CompareFunction has the wrong output type (should be bool)");

    StatsNode* stats_node = AddChildStatsNode("Sort", NodeType::DOP);
    auto shared_node
        = std::make_shared<SortResultNode>(*this, compare_function, stats_node);

    auto sort_stack = shared_node->ProduceStack();

    return DIARef<ValueType, decltype(sort_stack)>(
        shared_node,
        sort_stack,
        { stats_node });
}

//! \}

} // namespace api
} // namespace c7a

#endif // !C7A_API_SORT_HEADER

/******************************************************************************/
<commit_msg>Fixing AddressSanitizer problem in SortNode with 1 worker.<commit_after>/*******************************************************************************
 * c7a/api/sort.hpp
 *
 * Part of Project c7a.
 *
 * Copyright (C) 2015 Alexander Noe <aleexnoe@gmail.com>
 * Copyright (C) 2015 Timo Bingmann <tb@panthema.net>
 * Copyright (C) 2015 Michael Axtmann <michael.axtmann@kit.edu>
 *
 * This file has no license. Only Chuck Norris can compile it.
 ******************************************************************************/

#pragma once
#ifndef C7A_API_SORT_HEADER
#define C7A_API_SORT_HEADER

#include <c7a/api/dia.hpp>
#include <c7a/api/dop_node.hpp>
#include <c7a/common/logger.hpp>
#include <c7a/common/math.hpp>
#include <c7a/net/flow_control_channel.hpp>
#include <c7a/net/flow_control_manager.hpp>
#include <c7a/net/group.hpp>

#include <algorithm>
#include <functional>
#include <string>
#include <vector>

namespace c7a {
namespace api {

//! \addtogroup api Interface
//! \{

/*!
 * A DIANode which performs a Sort operation. Sort sorts a DIA according to a given
 * compare function
 *
 * \tparam ValueType Type of DIA elements
 * \tparam Stack Function stack, which contains the chained lambdas between the last and this DIANode.
 * \tparam CompareFunction Type of the compare function
 */
template <typename ValueType, typename ParentDIARef, typename CompareFunction>
class SortNode : public DOpNode<ValueType>
{
    static const bool debug = false;

    using Super = DOpNode<ValueType>;
    using Super::context_;
    using Super::result_file_;

public:
    /*!
     * Constructor for a sort node.
     *
     * \param parent DIARef.
     * \param parent_stack Stack of lambda functions between parent and this node
     * \param compare_function Function comparing two elements.
     */
    SortNode(const ParentDIARef& parent,
             CompareFunction compare_function,
             StatsNode* stats_node)
        : DOpNode<ValueType>(parent.ctx(), { parent.node() }, "Sort", stats_node),
          compare_function_(compare_function),
          channel_id_samples_(parent.ctx().GetNewChannel()),
          emitters_samples_(channel_id_samples_->OpenWriters()),
          channel_id_data_(parent.ctx().GetNewChannel()),
          emitters_data_(channel_id_data_->OpenWriters())
    {
        // Hook PreOp(s)
        auto pre_op_fn = [=](const ValueType& input) {
                             PreOp(input);
                         };

        auto lop_chain = parent.stack().push(pre_op_fn).emit();
        parent.node()->RegisterChild(lop_chain);
    }

    virtual ~SortNode() { }

    //! Executes the sum operation.
    void Execute() final {
        MainOp();
    }

    void PushData() final {

        for (size_t i = 0; i < data_.size(); i++) {
            for (auto func : DIANode<ValueType>::callbacks_) {
                func(data_[i]);
            }
        }
    }

    void Dispose() final { }

    /*!
     * Produces an 'empty' function stack, which only contains the identity
     * emitter function.
     *
     * \return Empty function stack
     */
    auto ProduceStack() {
        return FunctionStack<ValueType>();
    }

    /*!
     * Returns "[SortNode]" as a string.
     * \return "[SortNode]"
     */
    std::string ToString() final {
        return "[SortNode] Id:" + result_file_.ToString();
    }

private:
    //! The sum function which is applied to two elements.
    CompareFunction compare_function_;
    //! Local data
    std::vector<ValueType> data_;

    //!Emitter to send samples to process 0
    data::ChannelPtr channel_id_samples_;
    std::vector<data::BlockWriter> emitters_samples_;

    //!Emitters to send data to other workers specified by splitters.
    data::ChannelPtr channel_id_data_;
    std::vector<data::BlockWriter> emitters_data_;

    // epsilon
    static constexpr double desired_imbalance_ = 0.25;

    void PreOp(ValueType input) {
        data_.push_back(input);
    }

    void FindAndSendSplitters(
        std::vector<ValueType>& splitters, size_t sample_size) {
        // Get samples from other workers
        size_t num_total_workers = context_.num_workers();

        std::vector<ValueType> samples;
        samples.reserve(sample_size * num_total_workers);
        auto reader = channel_id_samples_->OpenReader();

        while (reader.HasNext()) {
            samples.push_back(reader.template Next<ValueType>());
        }

        // Find splitters
        std::sort(samples.begin(), samples.end(), compare_function_);

        size_t splitting_size = samples.size() / num_total_workers;

        // Send splitters to other workers
        for (size_t i = 1; i < num_total_workers; i++) {
            splitters.push_back(samples[i * splitting_size]);
            for (size_t j = 1; j < num_total_workers; j++) {
                emitters_samples_[j](samples[i * splitting_size]);
            }
        }

        for (size_t j = 1; j < num_total_workers; j++) {
            emitters_samples_[j].Close();
        }
    }

    class TreeBuilder
    {
    public:
        ValueType* tree_;
        ValueType* samples_;
        size_t index_ = 0;
        size_t ssplitter_;

        /*!
         * Target: tree. Size of 'number of splitter'
         * Source: sorted splitters. Size of 'number of splitter'
         * Number of splitter
         */
        TreeBuilder(ValueType* splitter_tree,
                    ValueType* samples,
                    size_t ssplitter)
            : tree_(splitter_tree),
              samples_(samples),
              ssplitter_(ssplitter) {
            if (ssplitter != 0)
                recurse(samples, samples + ssplitter, 1);
        }

        void recurse(ValueType* lo, ValueType* hi, unsigned int treeidx) {

            // pick middle element as splitter
            ValueType* mid = lo + (ssize_t)(hi - lo) / 2;
            assert(mid < samples_ + ssplitter_);
            tree_[treeidx] = *mid;

            ValueType* midlo = mid, * midhi = mid + 1;

            if (2 * treeidx < ssplitter_)
            {
                recurse(lo, midlo, 2 * treeidx + 0);
                recurse(midhi, hi, 2 * treeidx + 1);
            }
        }
    };

    bool Equal(const ValueType& ele1, const ValueType& ele2) {
        return !(compare_function_(ele1, ele2) || compare_function_(ele2, ele1));
    }

    //! round n down by k where k is a power of two.
    template <typename Integral>
    static inline size_t RoundDown(Integral n, Integral k) {
        return (n & ~(k - 1));
    }

    void EmitToBuckets(
        // Tree of splitters, sizeof |splitter|
        const ValueType* const tree,
        // Number of buckets: k = 2^{log_k}
        size_t k,
        size_t log_k,
        // Number of actual workers to send to
        size_t actual_k,
        const ValueType* const sorted_splitters,
        size_t prefix_elem,
        size_t total_elem) {

        // enlarge emitters array to next power of two to have direct access,
        // because we fill the splitter set up with sentinels == last splitter,
        // hence all items land in the last bucket.
        assert(emitters_data_.size() == actual_k);
        assert(actual_k <= k);

        while (emitters_data_.size() < k)
            emitters_data_.emplace_back(nullptr);

        std::swap(emitters_data_[actual_k - 1], emitters_data_[k - 1]);

        // classify all items (take two at once) and immediately transmit them.

        const size_t stepsize = 2;

        size_t i = 0;
        for ( ; i < RoundDown(data_.size(), stepsize); i += stepsize)
        {
            // take two items
            size_t j0 = 1;
            const ValueType& el0 = data_[i];

            size_t j1 = 1;
            const ValueType& el1 = data_[i + 1];

            // run items down the tree
            for (size_t l = 0; l < log_k; l++)
            {
                j0 = j0 * 2 + !(compare_function_(el0, tree[j0]));
                j1 = j1 * 2 + !(compare_function_(el1, tree[j1]));
            }

            size_t b0 = j0 - k;
            size_t b1 = j1 - k;

            while (b0 && Equal(el0, sorted_splitters[b0 - 1])
                   && (prefix_elem + i) * actual_k >= b0 * total_elem) {
                b0--;
            }
            assert(emitters_data_[b0].IsValid());
            emitters_data_[b0](el0);

            while (b1 && Equal(el1, sorted_splitters[b1 - 1])
                   && (prefix_elem + i + 1) * actual_k >= b1 * total_elem) {
                b1--;
            }
            assert(emitters_data_[b1].IsValid());
            emitters_data_[b1](el1);
        }

        // last iteration of loop if we have an odd number of items.
        for ( ; i < data_.size(); i++)
        {
            size_t j = 1;
            for (size_t l = 0; l < log_k; l++)
            {
                j = j * 2 + !(compare_function_(data_[i], tree[j]));
            }

            size_t b = j - k;

            while (b && Equal(data_[i], sorted_splitters[b - 1])
                   && (prefix_elem + i) * actual_k >= b * total_elem) {
                b--;
            }
            assert(emitters_data_[b].IsValid());
            emitters_data_[b](data_[i]);
        }
    }

    void MainOp() {
        net::FlowControlChannel& channel = context_.flow_control_channel();

        size_t prefix_elem = channel.PrefixSum(data_.size());
        size_t total_elem = channel.AllReduce(data_.size());

        size_t num_total_workers = context_.num_workers();
        size_t sample_size =
            common::IntegerLog2Ceil(total_elem) *
            (1 / (desired_imbalance_ * desired_imbalance_));

        LOG << prefix_elem << " elements, out of " << total_elem;

        std::default_random_engine generator({ std::random_device()() });
        std::uniform_int_distribution<int> distribution(0, data_.size() - 1);

        // Send samples to worker 0
        for (size_t i = 0; i < sample_size; i++) {
            size_t sample = distribution(generator);
            emitters_samples_[0](data_[sample]);
        }
        emitters_samples_[0].Close();

        // Get the ceiling of log(num_total_workers), as SSSS needs 2^n buckets.
        size_t ceil_log = common::IntegerLog2Ceil(num_total_workers);
        size_t workers_algo = 1 << ceil_log;
        size_t splitter_count_algo = workers_algo - 1;

        std::vector<ValueType> splitters;
        splitters.reserve(workers_algo);

        if (context_.my_rank() == 0) {
            FindAndSendSplitters(splitters, sample_size);
        }
        else {
            // Close unused emitters
            for (size_t j = 1; j < num_total_workers; j++) {
                emitters_samples_[j].Close();
            }
            auto reader = channel_id_samples_->OpenReader();
            while (reader.HasNext()) {
                splitters.push_back(reader.template Next<ValueType>());
            }
        }
        channel_id_samples_->Close();

        //code from SS2NPartition, slightly altered

        ValueType* splitter_tree = new ValueType[workers_algo + 1];

        // add sentinel splitters if fewer nodes than splitters.
        for (size_t i = num_total_workers; i < workers_algo; i++) {
            splitters.push_back(splitters.back());
        }

        TreeBuilder(splitter_tree,
                    splitters.data(),
                    splitter_count_algo);

        EmitToBuckets(
            splitter_tree, // Tree. sizeof |splitter|
            workers_algo,  // Number of buckets
            ceil_log,
            num_total_workers,
            splitters.data(),
            prefix_elem,
            total_elem);

        delete[] splitter_tree;

        //end of SS2N

        for (size_t i = 0; i < emitters_data_.size(); i++)
            emitters_data_[i].Close();

        data_.clear();

        auto reader = channel_id_data_->OpenReader();

        while (reader.HasNext()) {
            data_.push_back(reader.template Next<ValueType>());
        }
        channel_id_data_->Close();

        LOG << "node " << context_.my_rank() << " : " << data_.size();

        std::sort(data_.begin(), data_.end(), compare_function_);
        this->WriteChannelStats(channel_id_data_);
        this->WriteChannelStats(channel_id_samples_);
    }

    void PostOp() { }
};

template <typename ValueType, typename Stack>
template <typename CompareFunction>
auto DIARef<ValueType, Stack>::Sort(const CompareFunction &compare_function) const {

    using SortResultNode
              = SortNode<ValueType, DIARef, CompareFunction>;

    static_assert(
        std::is_convertible<
            ValueType,
            typename FunctionTraits<CompareFunction>::template arg<0>
            >::value ||
        std::is_same<CompareFunction, std::less<ValueType> >::value,
        "CompareFunction has the wrong input type");

    static_assert(
        std::is_convertible<
            ValueType,
            typename FunctionTraits<CompareFunction>::template arg<1> >::value ||
        std::is_same<CompareFunction, std::less<ValueType> >::value,
        "CompareFunction has the wrong input type");

    static_assert(
        std::is_convertible<
            typename FunctionTraits<CompareFunction>::result_type,
            bool>::value,
        "CompareFunction has the wrong output type (should be bool)");

    StatsNode* stats_node = AddChildStatsNode("Sort", NodeType::DOP);
    auto shared_node
        = std::make_shared<SortResultNode>(*this, compare_function, stats_node);

    auto sort_stack = shared_node->ProduceStack();

    return DIARef<ValueType, decltype(sort_stack)>(
        shared_node,
        sort_stack,
        { stats_node });
}

//! \}

} // namespace api
} // namespace c7a

#endif // !C7A_API_SORT_HEADER

/******************************************************************************/
<|endoftext|>


<commit_before><commit_msg>Add some more operator overloads<commit_after><|endoftext|>


<commit_before>/***************************************************************************
 *   Copyright (C) 2009   Peter Krusche, The University of Warwick         *
 *   peter@dcs.warwick.ac.uk                                               *
 ***************************************************************************/

#include "bsp_cpp/bsp_cpp.h"

#include <iostream>

#include <tbb/spin_mutex.h>

/** this is a helper to make sure output doesn't get garbled */
tbb::spin_mutex output_mutex;

/** When declaring BSP computations, we first declare a
 *  Context. A context holds all variables which persist
 *  over multiple supersteps.
 *
 *  Inside a Context we have access to bspwww primitives, except
 *  for bsp_sync. The reason is that bsp_sync needs to be called
 *  at node level, and our virtual processors are implemented as
 *  TBB tasks. To do this, we split the code into chunks which
 *  are run through the scheduler. This splitting is done using
 *  the BSP_BEGIN(), BSP_SYNC() and BSP_END() mechanism shown
 *  in the run() method.
 *
 */

class MyContext : public bsp::Context {
public:
	MyContext() : counter (0) { }

	void init() {
		counter = ((MyContext*)get_parent_context())->counter;
	}

	/**
	 * We can make functions which are called from within the
	 * supersteps, but they need to be class member to get access
	 * to the correct bsp_... functions.
	 */
	void print_info () {
		using namespace std;
		tbb::spin_mutex::scoped_lock l (output_mutex);
		cout << "Hi, I am processor " << bsp_pid()+1 << " of " << bsp_nprocs() << endl;
	}

	/**
	 * Run function to start execution
	 *
	 * Here are a few things to note.
	 *
	 * - the code in this function does not have to be inside the class.
	 *   Once MyContext is declared as a subclass of bsp::Context,
	 *   BSP_SCOPE(...); BSP_BEGIN() works IN ANY SCOPE.
	 *
	 *   We do these things in a static member function to
	 *
	 *    a) make things look C++-ish
	 *    b) allow static member handdown (see below)
	 *
	 * - Debugging this is a little non-obvious. The code for each
	 *   superstep is injected into local subclasses of MyContext,
	 *   and run on the MyContext objects belonging to each task.
	 *   Therefore, the scope after BSP_BEGIN is actually not the same
	 *   scope as the one before. This is done as a workaround for until
	 *   all C++ compilers support lambda functions/contexts.
	 * - BSP_SYNC also creates a new scope, so you can't just do this
	 *   within a BSP_BEGIN() block:
	 *	 @code
	 *	 while ( j > 0 ) {
	 *	    // do some BSP stuff
	 *
	 *	 	BSP_SYNC();
	 *	 }
	 *	 @endcode
	 *
	 *	 The right way to reproduce this behaviour is to end the block
	 *	 first and do the loop at node level:
	 *
	 *	 @code
	 *	 BSP_END()
	 *	 while ( j > 0 ) {
	 *	    BSP_BEGIN()
	 *	    // do some BSP stuff
	 *
	 *	    BSP_END()
	 *	 }
	 *	 BSP_BEGIN(MyContext, tm)
	 *	 @endcode
	 *
	 *   Things get tricky if you need variable j shown above inside the BSP_BEGIN() block.
	 *
	 *   On new GCC you can hand it down by making it static within the block. Really,
	 *   we'd want to use a lambda function here (these allow for scope transfer), but
	 *   not all compilers support these yet. So until they do, we're stuck with the
	 *   static approach (static class members always work, but have some pitfalls,
	 *   like multiple tasks being able to write to them).
	 *
	 *   Needless to say, to minimize overhead, try avoiding this, or if you
	 *   do it, put the while loop as far out as possible.
	 *
	 */
	static void run( int processors ) {
		using namespace std;
		MyContext c;
		BSP_SCOPE (MyContext, c, processors);

		/** we can still do stuff on node level here. like allocate
		 *  global memory. Note that bsp_pushreg doesn't fall into
		 *  this category, this, we want to do after BSP_BEGIN (if
		 *  the memory should be local to tasks rather than nodes,
		 *  that is).
		 */
		h = bsp_global_alloc(processors * sizeof(int));
		::bsp_sync();

		BSP_BEGIN();
		// Things from here on are task-level SPMD.
		// You'll have as many processes as allocated in the task mapper
		// also, we inject all members of MyContext into the current
		// scope
		//
		print_info();
		counter = bsp_pid();

		bsp_global_put(&counter, h, sizeof(int) * (bsp_nprocs()-1-bsp_pid()), sizeof(int));

		BSP_SYNC();

		bsp_global_get(h, sizeof(int) * (bsp_pid()), &counter, sizeof(int));

		BSP_SYNC();

		{
			tbb::spin_mutex::scoped_lock l (output_mutex);
			cout << "Hi, I am processor " << bsp_pid()+1 << " of " << bsp_nprocs() << ", I have read value " <<
				counter << " from the global memory " << endl;
		}

		BSP_END();

		bsp_global_free(h);
	}

protected:
	/** Members must be public or protected, since BSP_BEGIN et al.
	 *  rely on them being accessible to subclasses */
	int counter;
	bsp_global_handle_t h;
};

/**
 * Main function
 */
int main (int argc, char** argv) {
	using namespace std;
	bsp_init (&argc, &argv);

	// Things from here on are node-level SPMD.
	// You'll have as many processes as there are
	// available via MPI.
	int recursive_processors = 2;

	/** This is how we read and parse command line options */
	try {
		using namespace bsp;
		using namespace boost::program_options;
		options_description opts;
		opts.add_options()
			("help", "produce a help message")
			("procs,p", value<int>()->default_value(2),
			"How many processors to recursively create.")
			;
		variables_map vm;

		bsp_command_line(argc, argv, opts, vm);

		recursive_processors = vm["procs"].as<int>();
	} catch (std::exception e) {
		string s = e.what();
		s+= "\n";
		bsp_abort(s.c_str());
	}
	MyContext::run( recursive_processors );

	bsp_end();
}
<commit_msg><commit_after>/***************************************************************************
 *   Copyright (C) 2009   Peter Krusche, The University of Warwick         *
 *   peter@dcs.warwick.ac.uk                                               *
 ***************************************************************************/

#include "bsp_cpp/bsp_cpp.h"

#include <iostream>

#include <tbb/spin_mutex.h>

/** this is a helper to make sure output doesn't get garbled */
tbb::spin_mutex output_mutex;

/** When declaring BSP computations, we first declare a
 *  Context. A context holds all variables which persist
 *  over multiple supersteps.
 *
 *  Inside a Context we have access to bspwww primitives, except
 *  for bsp_sync. The reason is that bsp_sync needs to be called
 *  at node level, and our virtual processors are implemented as
 *  TBB tasks. To do this, we split the code into chunks which
 *  are run through the scheduler. This splitting is done using
 *  the BSP_BEGIN(), BSP_SYNC() and BSP_END() mechanism shown
 *  in the run() method.
 *
 */

class MyContext : public bsp::Context {
public:
	MyContext() : counter (0) { }

	void init() {
		counter = ((MyContext*)get_parent_context())->counter;
	}

	/**
	 * We can make functions which are called from within the
	 * supersteps, but they need to be class member to get access
	 * to the correct bsp_... functions.
	 */
	void print_info () {
		using namespace std;
		tbb::spin_mutex::scoped_lock l (output_mutex);
		cout << "Hi, I am processor " << bsp_pid()+1 << " of " << bsp_nprocs() << endl;
	}

	/**
	 * Run function to start execution
	 *
	 * Here are a few things to note.
	 *
	 * - the code in this function does not have to be inside the class.
	 *   Once MyContext is declared as a subclass of bsp::Context,
	 *   BSP_SCOPE(...); BSP_BEGIN() works IN ANY SCOPE.
	 *
	 *   We do these things in a static member function to
	 *
	 *    a) make things look C++-ish
	 *    b) allow static member handdown (see below)
	 *
	 * - Debugging this is a little non-obvious. The code for each
	 *   superstep is injected into local subclasses of MyContext,
	 *   and run on the MyContext objects belonging to each task.
	 *   Therefore, the scope after BSP_BEGIN is actually not the same
	 *   scope as the one before. This is done as a workaround for until
	 *   all C++ compilers support lambda functions/contexts.
	 * - BSP_SYNC also creates a new scope, so you can't just do this
	 *   within a BSP_BEGIN() block:
	 *	 @code
	 *	 while ( j > 0 ) {
	 *	    // do some BSP stuff
	 *
	 *	 	BSP_SYNC();
	 *	 }
	 *	 @endcode
	 *
	 *	 The right way to reproduce this behaviour is to end the block
	 *	 first and do the loop at node level:
	 *
	 *	 @code
	 *	 BSP_END()
	 *	 while ( j > 0 ) {
	 *	    BSP_BEGIN()
	 *	    // do some BSP stuff
	 *
	 *	    BSP_END()
	 *	 }
	 *	 BSP_BEGIN(MyContext, tm)
	 *	 @endcode
	 *
	 *   Things get tricky if you need variable j shown above inside the BSP_BEGIN() block.
	 *
	 *   On new GCC you can hand it down by making it static within the block. Really,
	 *   we'd want to use a lambda function here (these allow for scope transfer), but
	 *   not all compilers support these yet. So until they do, we're stuck with the
	 *   static approach (static class members always work, but have some pitfalls,
	 *   like multiple tasks being able to write to them).
	 *
	 *   Needless to say, to minimize overhead, try avoiding this, or if you
	 *   do it, put the while loop as far out as possible.
	 *
	 */
	static void run( int processors ) {
		using namespace std;
		MyContext c;
		BSP_SCOPE (MyContext, c, processors);

		/** we can still do stuff on node level here. like allocate
		 *  global memory. Note that bsp_pushreg doesn't fall into
		 *  this category, this, we want to do after BSP_BEGIN (if
		 *  the memory should be local to tasks rather than nodes,
		 *  that is).
		 */
		h = bsp_global_alloc(processors * sizeof(int));
		::bsp_sync();

		BSP_BEGIN();
		// Things from here on are task-level SPMD.
		// You'll have as many processes as allocated in the task mapper
		// also, we inject all members of MyContext into the current
		// scope
		//
		print_info();
		counter = bsp_pid();

		bsp_global_put(&counter, h, sizeof(int) * (bsp_nprocs()-1-bsp_pid()), sizeof(int));

		BSP_SYNC();

		bsp_global_get(h, sizeof(int) * (bsp_pid()), &counter, sizeof(int));

		BSP_SYNC();

		{
			tbb::spin_mutex::scoped_lock l (output_mutex);
			cout << "Hi, I am processor " << bsp_pid()+1 << " of " << bsp_nprocs() << ", I have read value " <<
				counter << " from the global memory " << endl;
		}

		BSP_END();

		bsp_global_free(h);
	}

protected:
	/** Members must be public or protected, since BSP_BEGIN et al.
	 *  rely on them being accessible to subclasses */
	int counter;
	static bsp_global_handle_t h;
};

/**
 * Main function
 */
int main (int argc, char** argv) {
	using namespace std;
	bsp_init (&argc, &argv);

	// Things from here on are node-level SPMD.
	// You'll have as many processes as there are
	// available via MPI.
	int recursive_processors = 2;

	/** This is how we read and parse command line options */
	try {
		using namespace bsp;
		using namespace boost::program_options;
		options_description opts;
		opts.add_options()
			("help", "produce a help message")
			("procs,p", value<int>()->default_value(2),
			"How many processors to recursively create.")
			;
		variables_map vm;

		bsp_command_line(argc, argv, opts, vm);

		recursive_processors = vm["procs"].as<int>();
	} catch (std::exception e) {
		string s = e.what();
		s+= "\n";
		bsp_abort(s.c_str());
	}
	MyContext::run( recursive_processors );

	bsp_end();
}
<|endoftext|>


<commit_before>#include <string>
#include <vector>
#include <unistd.h>
#include <gtest/gtest.h>
#include <scxcorelib/scxstrencodingconv.h>
#include "getusername.h"

class GetUserNameTest : public ::testing::Test {
protected:
	DWORD lpnSize;
	std::vector<WCHAR_T> lpBuffer;
	BOOL result;
	std::string userName;

	GetUserNameTest(): userName(std::string(getlogin())) {}

	void GetUserNameWithSize(DWORD size) {
		lpnSize = size;
		// allocate a WCHAR_T buffer to receive username
		lpBuffer.assign(lpnSize, '\0');
		result = GetUserName(&lpBuffer[0], &lpnSize);
	}
};

TEST_F(GetUserNameTest, NormalUse) {
	GetUserNameWithSize(L_cuserid);

	// GetUserName returns 1 on success
	ASSERT_EQ(1, result);

	// GetUserName sets lpnSize to length of username including null
	ASSERT_EQ(userName.size()+1, lpnSize);

	// copy UTF-16 bytes (excluding null) from lpBuffer to vector for conversion
	unsigned char *begin = reinterpret_cast<unsigned char *>(&lpBuffer[0]);
	// -1 to skip null; *2 because UTF-16 encodes two bytes per character
	unsigned char *end = begin + (lpnSize-1)*2;
	std::vector<unsigned char> input(begin, end);
	// convert to UTF-8 for assertion
	std::string output;
	SCXCoreLib::Utf16leToUtf8(input, output);

	EXPECT_EQ(userName, output);
}
<commit_msg>Add more unit test coverage for GetUserName<commit_after>#include <string>
#include <vector>
#include <unistd.h>
#include <gtest/gtest.h>
#include <scxcorelib/scxstrencodingconv.h>
#include "getusername.h"

class GetUserNameTest : public ::testing::Test {
protected:
	DWORD lpnSize;
	std::vector<WCHAR_T> lpBuffer;
	BOOL result;
	std::string userName;

	GetUserNameTest(): userName(std::string(getlogin())) {}

	void TestWithSize(DWORD size) {
		lpnSize = size;
		// allocate a WCHAR_T buffer to receive username
		lpBuffer.assign(lpnSize, '\0');
		result = GetUserName(&lpBuffer[0], &lpnSize);
	}

	void TestSuccess() {
		SCOPED_TRACE("");
		// returns 1 on success
		EXPECT_EQ(1, result);

		// sets lpnSize to length of username + null
		ASSERT_EQ(userName.size()+1, lpnSize);

		// copy UTF-16 bytes (excluding null) from lpBuffer to vector for conversion
		unsigned char *begin = reinterpret_cast<unsigned char *>(&lpBuffer[0]);
		// -1 to skip null; *2 because UTF-16 encodes two bytes per character
		unsigned char *end = begin + (lpnSize-1)*2;
		std::vector<unsigned char> input(begin, end);
		// convert to UTF-8 for comparison
		std::string output;
		SCXCoreLib::Utf16leToUtf8(input, output);

		EXPECT_EQ(userName, output);
	}

	void TestInvalidParameter() {
		SCOPED_TRACE("");

		// returns 0 on failure
		EXPECT_EQ(0, result);

		// sets errno to ERROR_INVALID_PARAMETER when lpBuffer is null
		// (which is the case for an empty vector)
		EXPECT_EQ(errno, ERROR_INVALID_PARAMETER);
	}

	void TestInsufficientBuffer() {
		SCOPED_TRACE("");

		// returns 0 on failure
		EXPECT_EQ(0, result);

		// sets errno to ERROR_INSUFFICIENT_BUFFER
		EXPECT_EQ(errno, ERROR_INSUFFICIENT_BUFFER);

		// sets lpnSize to length of username + null
		EXPECT_EQ(userName.size()+1, lpnSize);
	}
};

TEST_F(GetUserNameTest, BufferAsNullButNotBufferSize) {
	lpnSize = 1;
	result = GetUserName(NULL, &lpnSize);

	TestInvalidParameter();
	// does not reset lpnSize
	EXPECT_EQ(1, lpnSize);
}

TEST_F(GetUserNameTest, BufferSizeAsNullButNotBuffer) {
	lpBuffer.push_back('\0');
	result = GetUserName(&lpBuffer[0], NULL);

	TestInvalidParameter();
}

TEST_F(GetUserNameTest, BufferSizeAsZero) {
	TestWithSize(0);
	TestInvalidParameter();
	// does not reset lpnSize
	EXPECT_EQ(0, lpnSize);
}

TEST_F(GetUserNameTest, BufferSizeAsOne) {
	// theoretically this should never fail because any non-empty
	// username length will be >1 with trailing null
	TestWithSize(1);
	TestInsufficientBuffer();
}

TEST_F(GetUserNameTest, BufferSizeAsUserName) {
	// the buffer is too small because this does not include null
	TestWithSize(userName.size());
	TestInsufficientBuffer();
}

TEST_F(GetUserNameTest, BufferSizeAsUserNameMinusOne) {
	// the buffer is also too small
	TestWithSize(userName.size()-1);
	TestInsufficientBuffer();
}

TEST_F(GetUserNameTest, BufferSizeAsUserNamePlusOne) {
	// the buffer is exactly big enough will null
	TestWithSize(userName.size()+1);
	TestSuccess();
}

TEST_F(GetUserNameTest, L_cuseridSize) {
	// L_cuserid is big enough to hold any username
	TestWithSize(L_cuserid);
	TestSuccess();
}
<|endoftext|>


<commit_before>#include "../quick.hpp"
#include "../swap.hpp"

void quick(int *data, const int size_of_data)
{
    return quick(data, 0, size_of_data - 1);
}

void quick(int *data, const int start, const int end)
{
    if(start >= end) return; /* Base case */

    /* Conquer */
    int pivot = partition(data, start, end);

    /* Divide */
    quick(data, start, pivot - 1);
    quick(data, pivot + 1, end);
}

int partition(int *data, const int start, const int end)
{
    int pivot = end; /* Set pivot */

    int ps = start,
        pe = end - 1;

    while(ps != pe)
    {
        while(ps < pe && data[ps] <= data[pivot]) ++ps;
        while(ps < pe && data[pe] >= data[pivot]) --pe;

        if(ps < pe) swap(data[ps], data[pe]);
    }

    if(data[pivot] < data[pe])
    {
        swap(data[pivot], data[pe]);
        pivot = pe;
    }

    return pivot;
}
<commit_msg>Rename variables<commit_after>#include "../quick.hpp"
#include "../swap.hpp"

void quick(int *data, const int size_of_data)
{
    return quick(data, 0, size_of_data - 1);
}

void quick(int *data, const int start, const int end)
{
    if(start >= end) return; /* Base case */

    /* Conquer */
    int pivot = partition(data, start, end);

    /* Divide */
    quick(data, start, pivot - 1);
    quick(data, pivot + 1, end);
}

int partition(int *data, const int start, const int end)
{
    int pivot = end; /* Set pivot */

    int pleft = start,
        pright = end - 1;

    while(pleft != pright)
    {
        while(pleft < pright && data[pleft] <= data[pivot]) ++pleft;
        while(pleft < pright && data[pright] >= data[pivot]) --pright;

        if(pleft < pright) swap(data[pleft], data[pright]);
    }

    if(data[pivot] < data[pright])
    {
        swap(data[pivot], data[pright]);
        pivot = pright;
    }

    return pivot;
}
<|endoftext|>


<commit_before>// Copyright (c) 2009-2014 The Bitcoin developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <cstddef>
#include <istream>
#include <stdexcept>
#include <typeinfo>

#ifndef _GLIBCXX_USE_NOEXCEPT
#define _GLIBCXX_USE_NOEXCEPT throw()
#endif

namespace std
{
const char* bad_exception::what() const throw()
{
    return "std::bad_exception";
}

const char* bad_cast::what() const throw()
{
    return "std::bad_cast";
}

const char* bad_alloc::what() const throw()
{
    return "std::bad_alloc";
}

namespace __detail
{
struct _List_node_base {
    void _M_hook(std::__detail::_List_node_base* const __position) throw() __attribute__((used))
    {
        _M_next = __position;
        _M_prev = __position->_M_prev;
        __position->_M_prev->_M_next = this;
        __position->_M_prev = this;
    }

    void _M_unhook() __attribute__((used))
    {
        _List_node_base* const __next_node = _M_next;
        _List_node_base* const __prev_node = _M_prev;
        __prev_node->_M_next = __next_node;
        __next_node->_M_prev = __prev_node;
    }

    _List_node_base* _M_next;
    _List_node_base* _M_prev;
};
} // namespace detail

template ostream& ostream::_M_insert(bool);
template ostream& ostream::_M_insert(long);
template ostream& ostream::_M_insert(double);
template ostream& ostream::_M_insert(unsigned long);
template ostream& ostream::_M_insert(const void*);
template ostream& __ostream_insert(ostream&, const char*, streamsize);
template istream& istream::_M_extract(long&);
template istream& istream::_M_extract(unsigned short&);

out_of_range::~out_of_range() _GLIBCXX_USE_NOEXCEPT {}

length_error::~length_error() _GLIBCXX_USE_NOEXCEPT {}

// Used with permission.
// See: https://github.com/madlib/madlib/commit/c3db418c0d34d6813608f2137fef1012ce03043d

void ctype<char>::_M_widen_init() const
{
    char __tmp[sizeof(_M_widen)];
    for (unsigned __i = 0; __i < sizeof(_M_widen); ++__i)
        __tmp[__i] = __i;
    do_widen(__tmp, __tmp + sizeof(__tmp), _M_widen);

    _M_widen_ok = 1;
    // Set _M_widen_ok to 2 if memcpy can't be used.
    for (unsigned __i = 0; __i < sizeof(_M_widen); ++__i)
        if (__tmp[__i] != _M_widen[__i]) {
            _M_widen_ok = 2;
            break;
        }
}

void __throw_out_of_range_fmt(const char*, ...) __attribute__((__noreturn__));
void __throw_out_of_range_fmt(const char* err, ...)
{
    // Safe and over-simplified version. Ignore the format and print it as-is.
    __throw_out_of_range(err);
}

} // namespace std
<commit_msg>Delete glibcxx_compat.cpp<commit_after><|endoftext|>


<commit_before><commit_msg>Move object_mapper per dbus path conventions.<commit_after><|endoftext|>