<commit_before>/*****************************************************************************
 * Media Library
 *****************************************************************************
 * Copyright (C) 2015 Hugo Beauzée-Luyssen, Videolabs
 *
 * Authors: Hugo Beauzée-Luyssen<hugo@beauzee.fr>
 *
 * This program 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 program 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 program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#if HAVE_CONFIG_H
# include "config.h"
#endif

#include "Directory.h"
#include "utils/Charsets.h"
#include "utils/Filename.h"
#include "factory/IFileSystem.h"
#include "File.h"
#include "logging/Logger.h"

#include <sys/types.h>
#include <sys/stat.h>
#include <windows.h>
#include <winapifamily.h>

namespace medialibrary
{

namespace fs
{

Directory::Directory( const std::string& mrl , factory::IFileSystem& fsFactory )
    : CommonDirectory( fsFactory )
    , m_mrl( mrl )
{
}

const std::string& Directory::mrl() const
{
    return m_mrl;
}

void Directory::read() const
{
    const auto path = toAbsolute( utils::file::toLocalPath( m_mrl ) );
#if WINAPI_FAMILY_PARTITION (WINAPI_PARTITION_DESKTOP)
    WIN32_FIND_DATA f;
    auto pattern = path + '*';
    auto wpattern = charset::ToWide( pattern.c_str() );
    auto h = FindFirstFile( wpattern.get(), &f );
    if ( h == INVALID_HANDLE_VALUE )
    {
        LOG_ERROR( "Failed to browse ", path );
        throw std::system_error( GetLastError(), std::generic_category(), "Failed to browse through directory" );
    }
    do
    {
        auto file = charset::FromWide( f.cFileName );
        if ( file[0] == '.' )
            continue;
        auto fullpath = path + file.get();
        if ( ( f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) != 0 )
            m_dirs.emplace_back( m_fsFactory.createDirectory( utils::file::toUri( fullpath ) ) );
        else
            m_files.emplace_back( std::make_shared<File>( fullpath ) );
    } while ( FindNextFile( h, &f ) != 0 );
    FindClose( h );
#else
    // We must remove the trailing /
    // https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx
    // «Do not use a trailing backslash (\), which indicates the root directory of a drive»
    assert( *path.rbegin() == '\\' );
    auto tmpPath = path.substr( 0, path.length() - 1 );
    auto wpath = charset::ToWide( tmpPath.c_str() );

    CREATEFILE2_EXTENDED_PARAMETERS params{};
    params.dwFileFlags = FILE_FLAG_BACKUP_SEMANTICS;
    auto handle = CreateFile2( wpath.get(), GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, &params );
    if ( handle == INVALID_HANDLE_VALUE )
    {
        LOG_ERROR( "Failed to open directory ", path );
        throw std::system_error( GetLastError(), std::generic_category(), "Failed to open directory" );
    }

    std::unique_ptr<typename std::remove_pointer<HANDLE>::type,
            decltype(&CloseHandle)> handlePtr( handle, &CloseHandle );

    // Allocating a 32 bytes buffer to contain the file name. If more is required, we'll allocate
    size_t buffSize = sizeof( FILE_FULL_DIR_INFO ) + 32;
    std::unique_ptr<FILE_FULL_DIR_INFO, void(*)(FILE_FULL_DIR_INFO*)> dirInfo(
                reinterpret_cast<FILE_FULL_DIR_INFO*>( malloc( buffSize ) ),
                [](FILE_FULL_DIR_INFO* ptr) { free( ptr ); } );
    if ( dirInfo == nullptr )
        throw std::bad_alloc();

    while ( true )
    {
        auto h = GetFileInformationByHandleEx( handle, FileFullDirectoryInfo, dirInfo.get(), buffSize );
        if ( h == 0 )
        {
            auto error = GetLastError();
            if ( error == ERROR_FILE_NOT_FOUND )
                break;
            else if ( error == ERROR_MORE_DATA )
            {
                buffSize *= 2;
                dirInfo.reset( reinterpret_cast<FILE_FULL_DIR_INFO*>( malloc( buffSize ) ) );
                if ( dirInfo == nullptr )
                    throw std::bad_alloc();
                continue;
            }
            LOG_ERROR( "Failed to browse ", path, ". GetLastError(): ", GetLastError() );
            throw std::system_error( GetLastError(), std::generic_category(), "Failed to browse through directory" );
        }

        auto file = charset::FromWide( dirInfo->FileName );
        if ( file[0] == '.' )
            continue;
        auto path = path + file.get();
        if ( ( dirInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY ) != 0 )
            m_dirs.emplace_back( m_fsFactory.createDirectory( utils::file::toMrl( path ) ) );
        else
            m_files.emplace_back( std::make_shared<File>( path ) );
    }
#endif
}

std::string Directory::toAbsolute( const std::string& path )
{
    TCHAR buff[MAX_PATH];
    auto wpath = charset::ToWide( path.c_str() );
    if ( GetFullPathName( wpath.get(), MAX_PATH, buff, nullptr ) == 0 )
    {
        LOG_ERROR( "Failed to convert ", path, " to absolute path" );
        std::system_error( GetLastError(), std::generic_category(), "Failed to convert to absolute path" );
    }
    auto upath = charset::FromWide( buff );
    return std::string( upath.get() );
}

}

}
<commit_msg>fs: win32: Don't exclude .nomedia from files list<commit_after>/*****************************************************************************
 * Media Library
 *****************************************************************************
 * Copyright (C) 2015 Hugo Beauzée-Luyssen, Videolabs
 *
 * Authors: Hugo Beauzée-Luyssen<hugo@beauzee.fr>
 *
 * This program 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 program 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 program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#if HAVE_CONFIG_H
# include "config.h"
#endif

#include "Directory.h"
#include "utils/Charsets.h"
#include "utils/Filename.h"
#include "factory/IFileSystem.h"
#include "File.h"
#include "logging/Logger.h"

#include <sys/types.h>
#include <sys/stat.h>
#include <windows.h>
#include <winapifamily.h>

namespace medialibrary
{

namespace fs
{

Directory::Directory( const std::string& mrl , factory::IFileSystem& fsFactory )
    : CommonDirectory( fsFactory )
    , m_mrl( mrl )
{
}

const std::string& Directory::mrl() const
{
    return m_mrl;
}

void Directory::read() const
{
    const auto path = toAbsolute( utils::file::toLocalPath( m_mrl ) );
#if WINAPI_FAMILY_PARTITION (WINAPI_PARTITION_DESKTOP)
    WIN32_FIND_DATA f;
    auto pattern = path + '*';
    auto wpattern = charset::ToWide( pattern.c_str() );
    auto h = FindFirstFile( wpattern.get(), &f );
    if ( h == INVALID_HANDLE_VALUE )
    {
        LOG_ERROR( "Failed to browse ", path );
        throw std::system_error( GetLastError(), std::generic_category(), "Failed to browse through directory" );
    }
    do
    {
        auto file = charset::FromWide( f.cFileName );
        if ( file[0] == '.' )
            continue;
        auto fullpath = path + file.get();
        if ( ( f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) != 0 )
            m_dirs.emplace_back( m_fsFactory.createDirectory( utils::file::toUri( fullpath ) ) );
        else
            m_files.emplace_back( std::make_shared<File>( fullpath ) );
    } while ( FindNextFile( h, &f ) != 0 );
    FindClose( h );
#else
    // We must remove the trailing /
    // https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx
    // «Do not use a trailing backslash (\), which indicates the root directory of a drive»
    assert( *path.rbegin() == '\\' );
    auto tmpPath = path.substr( 0, path.length() - 1 );
    auto wpath = charset::ToWide( tmpPath.c_str() );

    CREATEFILE2_EXTENDED_PARAMETERS params{};
    params.dwFileFlags = FILE_FLAG_BACKUP_SEMANTICS;
    auto handle = CreateFile2( wpath.get(), GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, &params );
    if ( handle == INVALID_HANDLE_VALUE )
    {
        LOG_ERROR( "Failed to open directory ", path );
        throw std::system_error( GetLastError(), std::generic_category(), "Failed to open directory" );
    }

    std::unique_ptr<typename std::remove_pointer<HANDLE>::type,
            decltype(&CloseHandle)> handlePtr( handle, &CloseHandle );

    // Allocating a 32 bytes buffer to contain the file name. If more is required, we'll allocate
    size_t buffSize = sizeof( FILE_FULL_DIR_INFO ) + 32;
    std::unique_ptr<FILE_FULL_DIR_INFO, void(*)(FILE_FULL_DIR_INFO*)> dirInfo(
                reinterpret_cast<FILE_FULL_DIR_INFO*>( malloc( buffSize ) ),
                [](FILE_FULL_DIR_INFO* ptr) { free( ptr ); } );
    if ( dirInfo == nullptr )
        throw std::bad_alloc();

    while ( true )
    {
        auto h = GetFileInformationByHandleEx( handle, FileFullDirectoryInfo, dirInfo.get(), buffSize );
        if ( h == 0 )
        {
            auto error = GetLastError();
            if ( error == ERROR_FILE_NOT_FOUND )
                break;
            else if ( error == ERROR_MORE_DATA )
            {
                buffSize *= 2;
                dirInfo.reset( reinterpret_cast<FILE_FULL_DIR_INFO*>( malloc( buffSize ) ) );
                if ( dirInfo == nullptr )
                    throw std::bad_alloc();
                continue;
            }
            LOG_ERROR( "Failed to browse ", path, ". GetLastError(): ", GetLastError() );
            throw std::system_error( GetLastError(), std::generic_category(), "Failed to browse through directory" );
        }

        auto file = charset::FromWide( dirInfo->FileName );
        if ( file[0] == '.' && strcasecmp( file.get(), ".nomedia" ) )
            continue;
        auto path = path + file.get();
        if ( ( dirInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY ) != 0 )
            m_dirs.emplace_back( m_fsFactory.createDirectory( utils::file::toMrl( path ) ) );
        else
            m_files.emplace_back( std::make_shared<File>( path ) );
    }
#endif
}

std::string Directory::toAbsolute( const std::string& path )
{
    TCHAR buff[MAX_PATH];
    auto wpath = charset::ToWide( path.c_str() );
    if ( GetFullPathName( wpath.get(), MAX_PATH, buff, nullptr ) == 0 )
    {
        LOG_ERROR( "Failed to convert ", path, " to absolute path" );
        std::system_error( GetLastError(), std::generic_category(), "Failed to convert to absolute path" );
    }
    auto upath = charset::FromWide( buff );
    return std::string( upath.get() );
}

}

}
<|endoftext|>


<commit_before>// UVa1587 - Box
// Time:  O(1)
// Space: O(1)

#include <iostream>
#include <set>
#include <unordered_map>
#include <algorithm>

using namespace std;

struct HashPair {
    size_t operator()(const pair<int, int>& p) const {
        return hash<int>()(p.first) ^ hash<int>()(p.second);
    }
};

int main() {
    int w, h;
    while (cin >> w >> h) {
        set<int> edge;
        unordered_map<pair<int, int>, int, HashPair> area;
        if (w > h) {
            swap(w, h);
        }
        edge.insert(w), edge.insert(h);
        ++area[make_pair(w, h)];

        int count = 5;
        while (count--) {
            cin >> w >> h;
            if (w > h) {
                swap(w, h);
            }
            edge.insert(w), edge.insert(h);
            ++area[make_pair(w, h)];
        }

        bool is_ok = false;
        // Make sure all of (w, h) has pairs and at most 3 different lengths of w, h, l.
        if (all_of(area.cbegin(), area.cend(), [](const pair<pair<int, int>, int>& i){ return i.second % 2 == 0; }) &&
            edge.size() <= 3) {
            is_ok = true;
            // Make sure all pairs of l, w, h exist.
            for (auto it = edge.cbegin(); is_ok && it != edge.cend(); ++it) {
                auto jt = it;
                ++jt;
                for (; is_ok && jt != edge.cend(); ++jt) {
                    if (area.find(make_pair(*it, *jt)) == area.cend()) { // Some of (w, h) does exist.
                        is_ok = false;
                    }
                }
            }
        }

        if (is_ok) {
            cout << "POSSIBLE" << endl;
        } else {
            cout << "IMPOSSIBLE" << endl;
        }
    }
    return 0;
}<commit_msg>update<commit_after>// UVa1587 - Box
// Time:  O(1)
// Space: O(1)

#include <iostream>
#include <set>
#include <unordered_map>
#include <algorithm>

using namespace std;

struct HashPair {
    size_t operator()(const pair<int, int>& p) const {
        return hash<int>()(p.first) ^ hash<int>()(p.second);
    }
};

int main() {
    int w, h;
    while (cin >> w >> h) {
        set<int> edge;
        unordered_map<pair<int, int>, int, HashPair> area;
        if (w > h) {
            swap(w, h);
        }
        edge.insert(w), edge.insert(h);
        ++area[make_pair(w, h)];

        int count = 5;
        while (count--) {
            cin >> w >> h;
            if (w > h) {
                swap(w, h);
            }
            edge.insert(w), edge.insert(h);
            ++area[make_pair(w, h)];
        }

        bool is_ok = false;
        // Make sure all of (w, h) has pairs and at most 3 different lengths of w, h, l.
        if (all_of(area.cbegin(), area.cend(), [](const pair<pair<int, int>, int>& i){ return i.second % 2 == 0; }) &&
            edge.size() <= 3) {
            is_ok = true;
            // Make sure all pairs of l, w, h exist.
            for (auto it = edge.cbegin(); is_ok && it != edge.cend(); ++it) {
                auto jt = it;
                ++jt;
                for (; is_ok && jt != edge.cend(); ++jt) {
                    if (area.find(make_pair(*it, *jt)) == area.cend()) { // Some of (w, h) does not exist.
                        is_ok = false;
                    }
                }
            }
        }

        if (is_ok) {
            cout << "POSSIBLE" << endl;
        } else {
            cout << "IMPOSSIBLE" << endl;
        }
    }
    return 0;
}<|endoftext|>


<commit_before>// Time:  O(n)
// Space: O(n)

class Solution {
public:
    /**
     * @param expression: a vector of strings;
     * @return: an integer
     */
    int evaluateExpression(vector<string> &expression) {
        stack<int> operands;
        stack<string> operators;
        if (expression.empty()) {
            return 0;
        }
        for (int i = expression.size() - 1; i >= 0; --i) {
            if (isdigit(expression[i][0])) {
                operands.emplace(stoi(expression[i]));
            } else if (expression[i] == ")" || expression[i] == "*" ||
                       expression[i] == "/") {
                operators.emplace(expression[i]);
            } else if (expression[i] == "+" || expression[i] == "-") {
                while (!operators.empty() && (operators.top() == "*" ||
                       operators.top() == "/")) {
                     compute(operands, operators);
                }
                operators.emplace(expression[i]);
            } else if (expression[i] == "(") {
                // operators at least one element, i.e. ")".
                while (operators.top() == "*" ||
                       operators.top() == "/") {
                     compute(operands, operators);
                }
                while (operators.top() == "+" ||
                       operators.top() == "-") {
                    compute(operands, operators);
                }
                operators.pop();
            }
        }
        while (!operators.empty() && (operators.top() == "*" ||
            operators.top() == "/")) {
            compute(operands, operators);
        }
        while (!operators.empty()) {
            compute(operands, operators);
        }
        return operands.top();
    }

    void compute(stack<int>& operands, stack<string>& operators) {
        const int left = operands.top();
        operands.pop();
        const int right = operands.top();
        operands.pop();
        const string op = operators.top();
        operators.pop();

        if (op == "+") {
            operands.push(left + right);
        } else if (op == "-") {
            operands.push(left - right);
        } else if (op == "*") {
            operands.push(left * right);
        } else if (op == "/") {
            operands.push(left / right);
        }
    }
};

// Time:  O(n)
// Space: O(n)
class Solution2 {
public:
    /**
     * @param expression: a vector of strings;
     * @return: an integer
     */
    int evaluateExpression(vector<string> &expression) {
        if (expression.empty()) {
            return 0;
        }
        vector<string> postfix;
        infixToPostfix(expression, postfix);
        return evaluatePostfixExpression(postfix);
    }

    // Evaluate Postfix Expression.
    int evaluatePostfixExpression(const vector<string> &postfix) {
        if (postfix.empty()) {
            return 0;
        }
        stack<string> s;
        for (const auto& tok : postfix) {
            if (!is_operator(tok)) {
                s.emplace(tok);
            } else {
                int y = stoi(s.top());
                s.pop();
                int x = stoi(s.top());
                s.pop();
                if (tok[0] == '+') {
                    x += y;
                } else if (tok[0] == '-') {
                    x -= y;
                } else if (tok[0] == '*') {
                    x *= y;
                } else {
                    x /= y;
                }
                s.emplace(to_string(x));
            }
        }
        return stoi(s.top());
    }

    bool is_operator(const string &op) {
        return op.length() == 1 && string("+-*/").find(op) != string::npos;
    }

    // Convert Infix to Postfix Expression.
    void infixToPostfix(vector<string>& infix, vector<string>& postfix) {
        stack<string> s;
        for (auto tok : infix) {
            // Any number would be pushed into stack.
            if (atoi(tok.c_str())) {
                postfix.emplace_back(tok);
            } else if (tok == "(") {
                s.emplace(tok);
            } else if (tok == ")") {
                // Meet ")", then pop until "(".
                while (!s.empty()) {
                    tok = s.top();
                    s.pop();
                    if (tok == "(") {
                        break;
                    }
                    postfix.emplace_back(tok);
                }
            } else {
                // Order of tokens in stack should be like "(-*",
                // The token will be added in an strictly increasing precedence order.
                while (!s.empty() && precedence(tok) <= precedence(s.top())) {
                    postfix.emplace_back(s.top());
                    s.pop();
                }
                s.emplace(tok);
            }
        }
        // Pop the remaining token and add them to the postfix.
        while (!s.empty()) {
            postfix.emplace_back(s.top());
            s.pop();
        }
    }

    int precedence(string x) {
        if (x == "(") {  // The least precedence.
            return 0;
        } else if (x == "+" || x == "-") {
            return 1;
        } else if (x == "*" || x == "/") {
            return 2;
        }
        return 3;
    }
};
<commit_msg>Update expression-evaluation.cpp<commit_after>// Time:  O(n)
// Space: O(n)

class Solution {
public:
    /**
     * @param expression: a vector of strings;
     * @return: an integer
     */
    int evaluateExpression(vector<string> &expression) {
        stack<int> operands;
        stack<string> operators;
        if (expression.empty()) {
            return 0;
        }
        for (int i = expression.size() - 1; i >= 0; --i) {
            if (isdigit(expression[i][0])) {
                operands.emplace(stoi(expression[i]));
            } else if (expression[i] == ")" || expression[i] == "*" ||
                       expression[i] == "/") {
                operators.emplace(expression[i]);
            } else if (expression[i] == "+" || expression[i] == "-") {
                while (!operators.empty() && (operators.top() == "*" ||
                       operators.top() == "/")) {
                     compute(operands, operators);
                }
                operators.emplace(expression[i]);
            } else if (expression[i] == "(") {
                // operators at least one element, i.e. ")".
                while (operators.top() != ")") {
                    compute(operands, operators);
                }
                operators.pop();
            }
        }
        while (!operators.empty() && (operators.top() == "*" ||
            operators.top() == "/")) {
            compute(operands, operators);
        }
        while (!operators.empty()) {
            compute(operands, operators);
        }
        return operands.top();
    }

    void compute(stack<int>& operands, stack<string>& operators) {
        const int left = operands.top();
        operands.pop();
        const int right = operands.top();
        operands.pop();
        const string op = operators.top();
        operators.pop();

        if (op == "+") {
            operands.push(left + right);
        } else if (op == "-") {
            operands.push(left - right);
        } else if (op == "*") {
            operands.push(left * right);
        } else if (op == "/") {
            operands.push(left / right);
        }
    }
};

// Time:  O(n)
// Space: O(n)
class Solution2 {
public:
    /**
     * @param expression: a vector of strings;
     * @return: an integer
     */
    int evaluateExpression(vector<string> &expression) {
        if (expression.empty()) {
            return 0;
        }
        vector<string> postfix;
        infixToPostfix(expression, postfix);
        return evaluatePostfixExpression(postfix);
    }

    // Evaluate Postfix Expression.
    int evaluatePostfixExpression(const vector<string> &postfix) {
        if (postfix.empty()) {
            return 0;
        }
        stack<string> s;
        for (const auto& tok : postfix) {
            if (!is_operator(tok)) {
                s.emplace(tok);
            } else {
                int y = stoi(s.top());
                s.pop();
                int x = stoi(s.top());
                s.pop();
                if (tok[0] == '+') {
                    x += y;
                } else if (tok[0] == '-') {
                    x -= y;
                } else if (tok[0] == '*') {
                    x *= y;
                } else {
                    x /= y;
                }
                s.emplace(to_string(x));
            }
        }
        return stoi(s.top());
    }

    bool is_operator(const string &op) {
        return op.length() == 1 && string("+-*/").find(op) != string::npos;
    }

    // Convert Infix to Postfix Expression.
    void infixToPostfix(vector<string>& infix, vector<string>& postfix) {
        stack<string> s;
        for (auto tok : infix) {
            // Any number would be pushed into stack.
            if (atoi(tok.c_str())) {
                postfix.emplace_back(tok);
            } else if (tok == "(") {
                s.emplace(tok);
            } else if (tok == ")") {
                // Meet ")", then pop until "(".
                while (!s.empty()) {
                    tok = s.top();
                    s.pop();
                    if (tok == "(") {
                        break;
                    }
                    postfix.emplace_back(tok);
                }
            } else {
                // Order of tokens in stack should be like "(-*",
                // The token will be added in an strictly increasing precedence order.
                while (!s.empty() && precedence(tok) <= precedence(s.top())) {
                    postfix.emplace_back(s.top());
                    s.pop();
                }
                s.emplace(tok);
            }
        }
        // Pop the remaining token and add them to the postfix.
        while (!s.empty()) {
            postfix.emplace_back(s.top());
            s.pop();
        }
    }

    int precedence(string x) {
        if (x == "(") {  // The least precedence.
            return 0;
        } else if (x == "+" || x == "-") {
            return 1;
        } else if (x == "*" || x == "/") {
            return 2;
        }
        return 3;
    }
};
<|endoftext|>


<commit_before>#include "gtest/gtest.h"
#include "gmock/gmock.h"

#include "micro_flyweight/flyweight.h"

#include <string>
#include <vector>

TEST(micro_flyweight, vector_of)
{
    using namespace micro_flyweight;

    factory<std::string> fact;
    std::vector<flyweight<std::string>> elems;

    for (int i=0; i < 10000; i++) {
        elems.emplace_back(fact("The quick brown fox"));
    }
}

TEST(micro_flyweight, contains)
{
    using namespace micro_flyweight;

    factory<std::string> fact;
    flyweight<std::string> fw = fact("abc");

    EXPECT_TRUE(fact.contains(fw.get()));
    EXPECT_TRUE(fact.contains("abc"));
}

TEST(micro_flyweight, counting)
{
    using namespace micro_flyweight;

    factory<int> fact;

    EXPECT_EQ(fact.count_unique(), 0u);
    EXPECT_EQ(fact.count_all(), 0u);

    flyweight<int> x = fact(123);

    EXPECT_EQ(fact.count_unique(), 1u);
    EXPECT_EQ(fact.count_all(), 1u);

    {
        flyweight<int> x2 = fact(123);

        EXPECT_EQ(fact.count_unique(), 1u);
        EXPECT_EQ(fact.count_all(), 2u);
    }

    EXPECT_EQ(fact.count_unique(), 1u);
    EXPECT_EQ(fact.count_all(), 1u);
}

TEST(micro_flyweight, copy)
{
    using namespace micro_flyweight;

    factory<std::string> fact;

    flyweight<std::string> a = fact("a");
    flyweight<std::string> b = a;

    EXPECT_EQ(fact.count_unique(), 1u);
    EXPECT_EQ(fact.count_all(), 2u);
}

TEST(micro_flyweight, equality)
{
    using namespace micro_flyweight;

    factory<int> fact;

    flyweight<int> x = fact(123);
    flyweight<int> x2 = fact(123);
    flyweight<int> x3 = fact(999);

    EXPECT_TRUE(x == x);
    EXPECT_TRUE(x == x2);
    EXPECT_TRUE(x != x3);

    factory<int> fact2;

    flyweight<int> z = fact2(123);
    flyweight<int> z2 = fact2(999);

    EXPECT_TRUE(z == x);
    EXPECT_TRUE(z2 != x);
}

TEST(micro_flyweight, const_equality)
{
    using namespace micro_flyweight;

    factory<int> fact;

    const flyweight<int> x = fact(123);
    const flyweight<int> x2 = fact(123);
    const flyweight<int> x3 = fact(999);

    EXPECT_TRUE(x == x);
    EXPECT_TRUE(x == x2);
    EXPECT_TRUE(x != x3);
}

struct foo {
    static int N;
    int x;

    foo(int x)        : x{x}   { N++; }
    foo(const foo& f) : x{f.x} { N++; }
    foo(foo&& f)      : x{f.x} { N++; f.x = 0; }
    foo() = delete;

    bool operator== (const foo& rhs) const { return x == rhs.x; }
};
int foo::N = 0;

namespace std {
    template <> struct hash<foo> {
        size_t operator() (const foo& f) const {
            return f.x;
        }
    };
}

TEST(micro_flyweight, move_semantics)
{
    using namespace micro_flyweight;

    factory<foo> fact;

    foo::N = 0;
    {
        /* construct and move = 2 */
        const flyweight<foo> x = fact(foo(123));
        EXPECT_EQ(foo::N, 2);
    }

    foo::N = 0;
    {
        /* construct and copy = 2 */
        foo f(124);
        const flyweight<foo> x = fact(f);

        EXPECT_EQ(foo::N, 2);
        EXPECT_EQ(f.x, 124);
    }
}<commit_msg>trailing whitespace<commit_after>#include "gtest/gtest.h"
#include "gmock/gmock.h"

#include "micro_flyweight/flyweight.h"

#include <string>
#include <vector>

TEST(micro_flyweight, vector_of)
{
    using namespace micro_flyweight;

    factory<std::string> fact;
    std::vector<flyweight<std::string>> elems;

    for (int i=0; i < 10000; i++) {
        elems.emplace_back(fact("The quick brown fox"));
    }
}

TEST(micro_flyweight, contains)
{
    using namespace micro_flyweight;

    factory<std::string> fact;
    flyweight<std::string> fw = fact("abc");

    EXPECT_TRUE(fact.contains(fw.get()));
    EXPECT_TRUE(fact.contains("abc"));
}

TEST(micro_flyweight, counting)
{
    using namespace micro_flyweight;

    factory<int> fact;

    EXPECT_EQ(fact.count_unique(), 0u);
    EXPECT_EQ(fact.count_all(), 0u);

    flyweight<int> x = fact(123);

    EXPECT_EQ(fact.count_unique(), 1u);
    EXPECT_EQ(fact.count_all(), 1u);

    {
        flyweight<int> x2 = fact(123);

        EXPECT_EQ(fact.count_unique(), 1u);
        EXPECT_EQ(fact.count_all(), 2u);
    }

    EXPECT_EQ(fact.count_unique(), 1u);
    EXPECT_EQ(fact.count_all(), 1u);
}

TEST(micro_flyweight, copy)
{
    using namespace micro_flyweight;

    factory<std::string> fact;

    flyweight<std::string> a = fact("a");
    flyweight<std::string> b = a;

    EXPECT_EQ(fact.count_unique(), 1u);
    EXPECT_EQ(fact.count_all(), 2u);
}

TEST(micro_flyweight, equality)
{
    using namespace micro_flyweight;

    factory<int> fact;

    flyweight<int> x = fact(123);
    flyweight<int> x2 = fact(123);
    flyweight<int> x3 = fact(999);

    EXPECT_TRUE(x == x);
    EXPECT_TRUE(x == x2);
    EXPECT_TRUE(x != x3);

    factory<int> fact2;

    flyweight<int> z = fact2(123);
    flyweight<int> z2 = fact2(999);

    EXPECT_TRUE(z == x);
    EXPECT_TRUE(z2 != x);
}

TEST(micro_flyweight, const_equality)
{
    using namespace micro_flyweight;

    factory<int> fact;

    const flyweight<int> x = fact(123);
    const flyweight<int> x2 = fact(123);
    const flyweight<int> x3 = fact(999);

    EXPECT_TRUE(x == x);
    EXPECT_TRUE(x == x2);
    EXPECT_TRUE(x != x3);
}

struct foo {
    static int N;
    int x;

    foo(int x)        : x{x}   { N++; }
    foo(const foo& f) : x{f.x} { N++; }
    foo(foo&& f)      : x{f.x} { N++; f.x = 0; }
    foo() = delete;

    bool operator== (const foo& rhs) const { return x == rhs.x; }
};
int foo::N = 0;

namespace std {
    template <> struct hash<foo> {
        size_t operator() (const foo& f) const {
            return f.x;
        }
    };
}

TEST(micro_flyweight, move_semantics)
{
    using namespace micro_flyweight;

    factory<foo> fact;

    foo::N = 0;
    {
        /* construct and move = 2 */
        const flyweight<foo> x = fact(foo(123));
        EXPECT_EQ(foo::N, 2);
    }

    foo::N = 0;
    {
        /* construct and copy = 2 */
        foo f(124);
        const flyweight<foo> x = fact(f);

        EXPECT_EQ(foo::N, 2);
        EXPECT_EQ(f.x, 124);
    }
}<|endoftext|>


<commit_before>#include <tests/Base.hh>

#include <aleph/containers/PointCloud.hh>

#include <aleph/geometry/BruteForce.hh>
#include <aleph/geometry/CechComplex.hh>
#include <aleph/geometry/VietorisRipsComplex.hh>

#include <aleph/geometry/distances/Euclidean.hh>

#include <aleph/persistentHomology/Calculation.hh>
#include <aleph/persistentHomology/PhiPersistence.hh>

#include <aleph/topology/BarycentricSubdivision.hh>
#include <aleph/topology/Simplex.hh>
#include <aleph/topology/SimplicialComplex.hh>
#include <aleph/topology/Skeleton.hh>
#include <aleph/topology/Spine.hh>

#include <aleph/topology/filtrations/Data.hh>

#include <aleph/topology/io/LinesAndPoints.hh>

#include <random>
#include <vector>

#include <cmath>

template <class T> void testDisk()
{
  ALEPH_TEST_BEGIN( "Spine: disk" );

  using DataType   = bool;
  using VertexType = T;

  using Simplex           = aleph::topology::Simplex<DataType, VertexType>;
  using SimplicialComplex = aleph::topology::SimplicialComplex<Simplex>;

  std::vector<Simplex> simplices;

  unsigned n = 7;
  for( unsigned i = 0; i < n; i++ )
  {
    if( i+1 < n )
      simplices.push_back( Simplex( {T(0),T(i+1),T(i+2)} ) );
    else
      simplices.push_back( Simplex( {T(0),T(i+1),T(  1)} ) );
  }

  SimplicialComplex K( simplices.begin(), simplices.end() );

  K.createMissingFaces();
  K.sort();

  auto L = aleph::topology::spine( K );
  auto M = aleph::topology::dumb::spine( K );

  ALEPH_ASSERT_THROW( L.size() < K.size() );
  ALEPH_ASSERT_EQUAL( L.size(), 1 );
  ALEPH_ASSERT_EQUAL( M.size(), 1 );

  // Note that it does not make sense to check whether both spines
  // resulted in the *same* vertex. Every vertex is equally likely
  // to be left over; and every result is equally valid.

  ALEPH_TEST_END();
}

template <class T> void testPinchedTorus()
{
  using DataType   = T;
  using PointCloud = aleph::containers::PointCloud<DataType>;

  ALEPH_TEST_BEGIN( "Spine: pinched torus" );

  unsigned n =  40;
  unsigned m =  20;
  PointCloud pc( n*m, 3 );

  auto g = [] ( T x, T y )
  {
    return T(2) + std::sin(x/2) * std::cos(y);
  };

  std::random_device rd;
  std::mt19937 rng( rd() );

  std::normal_distribution<DataType> noise( T(0), T(0.05) );

  unsigned k = 0;
  for( unsigned i = 0; i < n; i++ )
  {
    auto x = T( 2*M_PI / n * i );
    for( unsigned j = 0; j < m; j++ )
    {
      auto y = T( 2*M_PI / m * j );

      auto x0 = g(x,y) * std::cos(x)        + noise( rng );
      auto x1 = g(x,y) * std::sin(x)        + noise( rng );
      auto x2 = std::sin(x/2) * std::sin(y) + noise( rng );

      pc.set(k++, {x0,x1,x2} );
    }
  }

  using Distance          = aleph::geometry::distances::Euclidean<DataType>;
  using NearestNeighbours = aleph::geometry::BruteForce<PointCloud, Distance>;

  auto K
    = aleph::geometry::buildVietorisRipsComplex(
      NearestNeighbours( pc ),
      DataType( 0.700 ),
      2
  );

  std::ofstream out( "/tmp/Pinched_torus.txt" );
  aleph::topology::io::LinesAndPoints lap;
  lap( out, K, pc );

  auto D1 = aleph::calculatePersistenceDiagrams( K );

  ALEPH_ASSERT_EQUAL( D1.size(), 2 );
  ALEPH_ASSERT_EQUAL( D1[0].dimension(), 0 );
  ALEPH_ASSERT_EQUAL( D1[1].dimension(), 1 );
  ALEPH_ASSERT_EQUAL( D1[1].betti(),     1 );

#if 0
  // FIXME: this is still too large to be easily processed by the
  // algorithm...

  auto L  = aleph::topology::spine( K );

  ALEPH_ASSERT_THROW( L.size() < K.size() );

  auto K0 = aleph::topology::Skeleton()(0, K);
  auto K1 = K0;
  auto K2 = K;
  auto D2 = aleph::calculateIntersectionHomology( L, {K0,K1,K2}, aleph::PerversityGM( {0} ) );

  ALEPH_ASSERT_EQUAL( D2.size(), 3 );

#endif

  ALEPH_TEST_END();
}

template <class T> void testS1vS1()
{
  using DataType   = T;
  using PointCloud = aleph::containers::PointCloud<DataType>;

  ALEPH_TEST_BEGIN( "Spine: S^1 v S^1" );

  unsigned n = 8;

  PointCloud pc( 2*n - 1 + n/2, 2 );

  unsigned k = 0;
  for( unsigned i = 0; i < n; i++ )
  {
    auto x0 = DataType( std::cos( 2*M_PI / n * i ) );
    auto y0 = DataType( std::sin( 2*M_PI / n * i ) );

    if( x0 > -1 )
    {
      auto x1 = x0 + 2;
      auto y1 = y0;

      pc.set(k++, {x0, y0});
      pc.set(k++, {x1, y1});
    }

    // prevent duplication of singular point
    else
      pc.set(k++, {x0, y0} );
  }

  // Improve sampling density around the singularity in order to ensure
  // that is stands out from other points.

  {
    auto m = n /2;
    auto a = 2.0 * std::tan( M_PI / n );
    auto r = DataType( 0.5 * a );

    for( unsigned i = 0; i < m; i++ )
    {
      auto x0 = r * DataType( std::cos( 2*M_PI / m * i ) ) + 1;
      auto y0 = r * DataType( std::sin( 2*M_PI / m * i ) );

      pc.set(k++, {x0, y0} );
    }
  }

  auto K
    = aleph::geometry::buildCechComplex(
      pc,
      DataType( 0.75 )
  );

  {
    std::ofstream out( "/tmp/SimplicialComplex.txt" );
    out << K << "\n";
  }

  {
    std::ofstream out( "/tmp/K.txt" );
    aleph::topology::io::LinesAndPoints lap;
    lap( out, K, pc );
  }

  auto D1 = aleph::calculatePersistenceDiagrams( K );

  // Persistent homology -----------------------------------------------
  //
  // This should not be surprising: it is possible to extract the two
  // circles from the data set. They form one connected component.

  ALEPH_ASSERT_THROW( D1.size() >=   2 );
  ALEPH_ASSERT_EQUAL( D1[0].betti(), 1 );
  ALEPH_ASSERT_EQUAL( D1[1].betti(), 2 );

  // Persistent intersection homology ----------------------------------
  //
  // Regardless of the stratification, it is impossible to detect the
  // singularity in dimension 0.

  auto L  = aleph::topology::BarycentricSubdivision()( aleph::topology::Skeleton()( 2, K), [] ( std::size_t dimension ) { return dimension == 0 ? 0 : 0.5; } );
  auto K0 = aleph::topology::Skeleton()( 0, K );
  auto D2 = aleph::calculateIntersectionHomology( L, {K0, aleph::topology::Skeleton()(2, K) }, aleph::Perversity( {-1} ) );

  ALEPH_ASSERT_THROW( D2.size() >=       1 );
  ALEPH_ASSERT_EQUAL( D2[0].dimension(), 0 );
  ALEPH_ASSERT_EQUAL( D2[0].betti(),     1 );

  {
    // This is the stratification with prior knowledge about the data
    // set, where we place the singularity in the lowest stratum.

    auto L  = aleph::topology::BarycentricSubdivision()( aleph::topology::Skeleton()( 2, K), [] ( std::size_t dimension ) { return dimension == 0 ? 0 : 0.5; } );
    auto D2 = aleph::calculateIntersectionHomology( L, { {0}, aleph::topology::Skeleton()(2, K) }, aleph::Perversity( {-1} ) );

    ALEPH_ASSERT_THROW( D2.size() >=       1 );
    ALEPH_ASSERT_EQUAL( D2[0].dimension(), 0 );
    ALEPH_ASSERT_EQUAL( D2[0].betti(),     1 );
  }

  // Spine calculation -------------------------------------------------

  auto M = aleph::topology::spine( K );
  K.sort( aleph::topology::filtrations::Data<typename decltype(K)::ValueType>() );

  {
    std::ofstream out( "/tmp/M.txt" );
    aleph::topology::io::LinesAndPoints lap;
    lap.addVertexLabels( true );
    lap( out, M, pc );
  }

  {
    std::ofstream out( "/tmp/Spine_complex.txt" );
    out << M << "\n";
  }

  {
    bool dualize                    = true;
    bool includeAllUnpairedCreators = true;

    auto D
      = aleph::calculatePersistenceDiagrams(
          M,
          dualize,
          includeAllUnpairedCreators
    );

    ALEPH_ASSERT_THROW( D.size() >=       2 );
    ALEPH_ASSERT_EQUAL( D[0].dimension(), 0 );
    ALEPH_ASSERT_EQUAL( D[1].dimension(), 1 );
    ALEPH_ASSERT_EQUAL( D[0].betti(),     1 );
    ALEPH_ASSERT_EQUAL( D[1].betti(),     2 );
  }

  ALEPH_ASSERT_THROW( M.size() < K .size() );
  ALEPH_TEST_END();

  L = aleph::topology::BarycentricSubdivision()( M, [] ( std::size_t dimension ) { return dimension == 0 ? 0 : 0.5; } );
  L.sort( aleph::topology::filtrations::Data<typename decltype(L)::ValueType>() );

  K0      = { {9}, {17} };
  auto D3 = aleph::calculateIntersectionHomology( L, {K0,M}, aleph::Perversity( {-1,0} ) );

  ALEPH_ASSERT_THROW( D3.empty() == false );
  ALEPH_ASSERT_EQUAL( D3[0].dimension(), 0 );
  ALEPH_ASSERT_EQUAL( D3[0].betti(),     3 );
}

template <class T> void testTriangle()
{
  ALEPH_TEST_BEGIN( "Triangle" );

  using DataType   = bool;
  using VertexType = T;

  using Simplex           = aleph::topology::Simplex<DataType, VertexType>;
  using SimplicialComplex = aleph::topology::SimplicialComplex<Simplex>;

  SimplicialComplex K = {
    {0,1,2},
    {0,1}, {0,2}, {1,2},
    {0}, {1}, {2}
  };

  auto L = aleph::topology::spine( K );
  auto M = aleph::topology::dumb::spine( K );

  ALEPH_ASSERT_THROW( L.size() < K.size() );
  ALEPH_ASSERT_EQUAL( L.size(), 1 );
  ALEPH_ASSERT_EQUAL( M.size(), 1 );

  ALEPH_TEST_END();
}

int main( int, char** )
{
  testDisk<short>   ();
  testDisk<unsigned>();

  testPinchedTorus<float> ();
  testPinchedTorus<double>();

  testS1vS1<float> ();
  testS1vS1<double>();

  testTriangle<short>   ();
  testTriangle<unsigned>();
}
<commit_msg>Semi-solid version of dumb spine calculation<commit_after>#include <tests/Base.hh>

#include <aleph/containers/PointCloud.hh>

#include <aleph/geometry/BruteForce.hh>
#include <aleph/geometry/CechComplex.hh>
#include <aleph/geometry/VietorisRipsComplex.hh>

#include <aleph/geometry/distances/Euclidean.hh>

#include <aleph/persistentHomology/Calculation.hh>
#include <aleph/persistentHomology/PhiPersistence.hh>

#include <aleph/topology/BarycentricSubdivision.hh>
#include <aleph/topology/Simplex.hh>
#include <aleph/topology/SimplicialComplex.hh>
#include <aleph/topology/Skeleton.hh>
#include <aleph/topology/Spine.hh>

#include <aleph/topology/filtrations/Data.hh>

#include <aleph/topology/io/LinesAndPoints.hh>

#include <random>
#include <vector>

#include <cmath>

template <class T> void testDisk()
{
  ALEPH_TEST_BEGIN( "Spine: disk" );

  using DataType   = bool;
  using VertexType = T;

  using Simplex           = aleph::topology::Simplex<DataType, VertexType>;
  using SimplicialComplex = aleph::topology::SimplicialComplex<Simplex>;

  std::vector<Simplex> simplices;

  unsigned n = 7;
  for( unsigned i = 0; i < n; i++ )
  {
    if( i+1 < n )
      simplices.push_back( Simplex( {T(0),T(i+1),T(i+2)} ) );
    else
      simplices.push_back( Simplex( {T(0),T(i+1),T(  1)} ) );
  }

  SimplicialComplex K( simplices.begin(), simplices.end() );

  K.createMissingFaces();
  K.sort();

  auto L = aleph::topology::spine( K );
  auto M = aleph::topology::dumb::spine( K );

  ALEPH_ASSERT_THROW( L.size() < K.size() );
  ALEPH_ASSERT_EQUAL( L.size(), 1 );
  ALEPH_ASSERT_EQUAL( M.size(), 1 );

  // Note that it does not make sense to check whether both spines
  // resulted in the *same* vertex. Every vertex is equally likely
  // to be left over; and every result is equally valid.

  ALEPH_TEST_END();
}

template <class T> void testPinchedTorus()
{
  using DataType   = T;
  using PointCloud = aleph::containers::PointCloud<DataType>;

  ALEPH_TEST_BEGIN( "Spine: pinched torus" );

  unsigned n =  40;
  unsigned m =  20;
  PointCloud pc( n*m, 3 );

  auto g = [] ( T x, T y )
  {
    return T(2) + std::sin(x/2) * std::cos(y);
  };

  std::random_device rd;
  std::mt19937 rng( rd() );

  std::normal_distribution<DataType> noise( T(0), T(0.05) );

  unsigned k = 0;
  for( unsigned i = 0; i < n; i++ )
  {
    auto x = T( 2*M_PI / n * i );
    for( unsigned j = 0; j < m; j++ )
    {
      auto y = T( 2*M_PI / m * j );

      auto x0 = g(x,y) * std::cos(x)        + noise( rng );
      auto x1 = g(x,y) * std::sin(x)        + noise( rng );
      auto x2 = std::sin(x/2) * std::sin(y) + noise( rng );

      pc.set(k++, {x0,x1,x2} );
    }
  }

  using Distance          = aleph::geometry::distances::Euclidean<DataType>;
  using NearestNeighbours = aleph::geometry::BruteForce<PointCloud, Distance>;

  auto K
    = aleph::geometry::buildVietorisRipsComplex(
      NearestNeighbours( pc ),
      DataType( 0.700 ),
      2
  );

  std::ofstream out( "/tmp/Pinched_torus.txt" );
  aleph::topology::io::LinesAndPoints lap;
  lap( out, K, pc );

  auto D1 = aleph::calculatePersistenceDiagrams( K );

  ALEPH_ASSERT_EQUAL( D1.size(), 2 );
  ALEPH_ASSERT_EQUAL( D1[0].dimension(), 0 );
  ALEPH_ASSERT_EQUAL( D1[1].dimension(), 1 );
  ALEPH_ASSERT_EQUAL( D1[1].betti(),     1 );

#if 0
  // FIXME: this is still too large to be easily processed by the
  // algorithm...

  auto L  = aleph::topology::spine( K );

  ALEPH_ASSERT_THROW( L.size() < K.size() );

  auto K0 = aleph::topology::Skeleton()(0, K);
  auto K1 = K0;
  auto K2 = K;
  auto D2 = aleph::calculateIntersectionHomology( L, {K0,K1,K2}, aleph::PerversityGM( {0} ) );

  ALEPH_ASSERT_EQUAL( D2.size(), 3 );

#endif

  ALEPH_TEST_END();
}

template <class T> void testS1vS1()
{
  using DataType   = T;
  using PointCloud = aleph::containers::PointCloud<DataType>;

  ALEPH_TEST_BEGIN( "Spine: S^1 v S^1" );

  unsigned n = 8;

  PointCloud pc( 2*n - 1 + n/2, 2 );

  unsigned k = 0;
  for( unsigned i = 0; i < n; i++ )
  {
    auto x0 = DataType( std::cos( 2*M_PI / n * i ) );
    auto y0 = DataType( std::sin( 2*M_PI / n * i ) );

    if( x0 > -1 )
    {
      auto x1 = x0 + 2;
      auto y1 = y0;

      pc.set(k++, {x0, y0});
      pc.set(k++, {x1, y1});
    }

    // prevent duplication of singular point
    else
      pc.set(k++, {x0, y0} );
  }

  // Improve sampling density around the singularity in order to ensure
  // that is stands out from other points.

  {
    auto m = n / 2;
    auto a = 2.0 * std::sin( M_PI / n );
    auto r = DataType( 0.40 * a );

    std::cerr << "* Side length is " << a << "\n"
              << "* Using radius r=" << r << "\n";

    for( unsigned i = 0; i < m; i++ )
    {
      auto x0 = r * DataType( std::cos( 2*M_PI / m * i ) ) + 1;
      auto y0 = r * DataType( std::sin( 2*M_PI / m * i ) );

      pc.set(k++, {x0, y0} );
    }
  }

  auto K
    = aleph::geometry::buildCechComplex(
      pc,
      DataType( 0.50 )
  );

  {
    std::ofstream out( "/tmp/SimplicialComplex.txt" );
    out << K << "\n";
  }

  {
    std::ofstream out( "/tmp/K.txt" );
    aleph::topology::io::LinesAndPoints lap;
    lap( out, K, pc );
  }

  auto D1 = aleph::calculatePersistenceDiagrams( K );

  // Persistent homology -----------------------------------------------
  //
  // This should not be surprising: it is possible to extract the two
  // circles from the data set. They form one connected component.

  ALEPH_ASSERT_THROW( D1.size() >=   2 );
  ALEPH_ASSERT_EQUAL( D1[0].betti(), 1 );
  ALEPH_ASSERT_EQUAL( D1[1].betti(), 2 );

  // Persistent intersection homology ----------------------------------
  //
  // Regardless of the stratification, it is impossible to detect the
  // singularity in dimension 0.

  auto L  = aleph::topology::BarycentricSubdivision()( aleph::topology::Skeleton()( 2, K), [] ( std::size_t dimension ) { return dimension == 0 ? 0 : 0.5; } );
  auto K0 = aleph::topology::Skeleton()( 0, K );
  auto D2 = aleph::calculateIntersectionHomology( L, {K0, aleph::topology::Skeleton()(2, K) }, aleph::Perversity( {-1} ) );

  ALEPH_ASSERT_THROW( D2.size() >=       1  );
  ALEPH_ASSERT_EQUAL( D2[0].dimension(), 0  );
  ALEPH_ASSERT_EQUAL( D2[0].betti(),     13 ); // Warning: this depends on $n$

  // Spine calculation -------------------------------------------------

  auto M = aleph::topology::dumb::spine( K );
  K.sort( aleph::topology::filtrations::Data<typename decltype(K)::ValueType>() );

  {
    std::ofstream out( "/tmp/M.txt" );
    aleph::topology::io::LinesAndPoints lap;
    lap.addVertexLabels( true );
    lap( out, M, pc );
  }

  {
    std::ofstream out( "/tmp/Spine_complex.txt" );
    out << M << "\n";
  }

  {
    bool dualize                    = true;
    bool includeAllUnpairedCreators = true;

    auto D
      = aleph::calculatePersistenceDiagrams(
          M,
          dualize,
          includeAllUnpairedCreators
    );

    ALEPH_ASSERT_THROW( D.size() >=       2 );
    ALEPH_ASSERT_EQUAL( D[0].dimension(), 0 );
    ALEPH_ASSERT_EQUAL( D[1].dimension(), 1 );
    ALEPH_ASSERT_EQUAL( D[0].betti(),     1 );
    ALEPH_ASSERT_EQUAL( D[1].betti(),     2 );
  }

  ALEPH_ASSERT_THROW( M.size() < K .size() );
  ALEPH_TEST_END();

  L = aleph::topology::BarycentricSubdivision()( M, [] ( std::size_t dimension ) { return dimension == 0 ? 0 : 0.5; } );
  L.sort( aleph::topology::filtrations::Data<typename decltype(L)::ValueType>() );

  K0      = { {9}, {17} };
  auto D3 = aleph::calculateIntersectionHomology( L, {K0,M}, aleph::Perversity( {-1,0} ) );

  ALEPH_ASSERT_THROW( D3.empty() == false );
  ALEPH_ASSERT_EQUAL( D3[0].dimension(), 0 );
  ALEPH_ASSERT_EQUAL( D3[0].betti(),     2 );

  {
    // This is the stratification with prior knowledge about the data
    // set, where we place the singularity in the lowest stratum.

    auto N = aleph::topology::BarycentricSubdivision()( aleph::topology::Skeleton()( 2, M), [] ( std::size_t dimension ) { return dimension == 0 ? 0 : 0.5; } );
    auto D = aleph::calculateIntersectionHomology( N, { { {0} }, aleph::topology::Skeleton()(2, M) }, aleph::Perversity( {-1} ) );

    std::cerr << N << std::endl;

    ALEPH_ASSERT_THROW( D.size() >=       1 );
    ALEPH_ASSERT_EQUAL( D[0].dimension(), 0 );
    ALEPH_ASSERT_EQUAL( D[0].betti(),     1 );
  }
}

template <class T> void testTriangle()
{
  ALEPH_TEST_BEGIN( "Triangle" );

  using DataType   = bool;
  using VertexType = T;

  using Simplex           = aleph::topology::Simplex<DataType, VertexType>;
  using SimplicialComplex = aleph::topology::SimplicialComplex<Simplex>;

  SimplicialComplex K = {
    {0,1,2},
    {0,1}, {0,2}, {1,2},
    {0}, {1}, {2}
  };

  auto L = aleph::topology::spine( K );
  auto M = aleph::topology::dumb::spine( K );

  ALEPH_ASSERT_THROW( L.size() < K.size() );
  ALEPH_ASSERT_EQUAL( L.size(), 1 );
  ALEPH_ASSERT_EQUAL( M.size(), 1 );

  ALEPH_TEST_END();
}

int main( int, char** )
{
  testDisk<short>   ();
  testDisk<unsigned>();

  testPinchedTorus<float> ();
  testPinchedTorus<double>();

  testS1vS1<float> ();
  testS1vS1<double>();

  testTriangle<short>   ();
  testTriangle<unsigned>();
}
<|endoftext|>


<commit_before>// Copyright (C) 2014 Oliver Schulz <oschulz@mpp.mpg.de>

// This 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 software is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

#include "Props.h"

#include <iostream>
#include <fstream>
#include <sstream>

#include "external/rapidjson/reader.h"
#include "external/rapidjson/genericstream.h"

#include <TString.h>

using namespace std;

namespace dbrx {

void PropKey::toJSON(std::ostream &out, const String &x) {
	out << "\"";
    for (char c: x) {
        switch (c) {
            case '\\': out << "\\\\"; break;
            case '\f': out << "\\f"; break;
            case '\n': out << "\\n"; break;
            case '\r': out << "\\r"; break;
            case '"': out << "\\\""; break;
            default: out << c; break;
        }
    }
	out << "\"";
}

void PropKey::toJSON(std::ostream &out) const {
	switch (m_type) {
		case Type::INTEGER: out << "\"" << m_content.i << "\""; break;
		case Type::NAME: toJSON(out, m_content.n.str()); break;
		default: assert(false);
	}
}

std::string PropKey::toJSON() const {
	stringstream tmp;
	toJSON(tmp);
	return tmp.str();
}

std::ostream& PropKey::print(std::ostream &os) const {
	switch (m_type) {
		case Type::INTEGER: os << m_content.i; break;
		case Type::NAME: os << m_content.n; break;
		default: assert(false);
	}
	return os;
}

std::string PropKey::toString() const {
	stringstream out;
	print(out);
	return out.str();
}

PropKey::PropKey(const std::string &value) {
	try {
		long long i = stoll(value);
		m_content.i = Integer(i);
		if (m_content.i != i) throw std::out_of_range("Integer key out of range");
	}
	catch (std::invalid_argument &e) {
		m_content.n = value;
		m_type = Type::NAME;
	}
}

bool PropVal::comparisonImpl(const PropVal &other) const {
	switch (m_type) {
		case Type::NAME:
			switch (other.m_type) {
				case Type::NAME: return m_content.n == other.m_content.n;
				case Type::STRING: return m_content.n.str() == other.m_content.s;
				default: return false;
			}
		case Type::STRING:
			switch (other.m_type) {
				case Type::STRING: return m_content.s == other.m_content.s;
				case Type::NAME: return m_content.s == other.m_content.n.str();
				default: return false;
			}
		case Type::ARRAY: return (other.m_type == Type::ARRAY) && (*m_content.a == *other.m_content.a);
		case Type::PROPS: return (other.m_type == Type::PROPS) && (*m_content.o == *other.m_content.o);
		default: assert(false);
	}
}

bool operator==(const Props &a, const Props &b) {
	auto itA = a.begin(), itB = b.begin();

	while ((itA != a.end()) && (itB != b.end())) {
		const auto &keyA = itA->first;
		const auto &valA = itA->second;
		const auto &keyB = itB->first;
		const auto &valB = itB->second;

		if (keyA == keyB) {
			if (valA != valB) return false;
			++itA; ++itB;
		} else if (PropKey::CompareById()(keyA, keyB)) {
			if (! valA.isNone()) return false;
			++itA;
		} else {
			if (! valB.isNone()) return false;
			++itB;
		}
	}

	while (itA != a.end()) {
		const auto &valA = itA->second;
		if (! valA.isNone()) return false;
		++itA;
	}

	while (itB != b.end()) {
		const auto &valB = itB->second;
		if (! valB.isNone()) return false;
		++itB;
	}

	return true;
}

void PropVal::toJSON(std::ostream &out, Real x) {
	out.precision(17);
	out << x;
}

void PropVal::toJSON(std::ostream &out, Name x) {
	toJSON(out, x.str());
}

void PropVal::toJSON(std::ostream &out, const Array &x) {
	out << "[";
	bool first = true;
	for (auto const &v: x) {
		if (!first) out << ", ";
		v.toJSON(out);
		first = false;
	}
	out << "]";
}

void PropVal::toJSON(std::ostream &out, const Props &x) {
	using CPRef = std::pair<PropKey, const PropVal*>;
	vector<CPRef> props;
	props.reserve(x.size());

	for (auto const &e: x) props.push_back({e.first, &e.second});
	auto compare = [](const CPRef &a, const CPRef &b) { return a.first < b.first; };
	sort(props.begin(), props.end(), compare);

	out << "{";
	bool first = true;
	for (auto const &e: props) {
		if (!first) out << ", ";
		e.first.toJSON(out);
		out << ": ";
		e.second->toJSON(out);
		first = false;
	}
	out << "}";
}

void PropVal::toJSON(std::ostream &out) const {
	switch (m_type) {
		case Type::NONE: toJSON(out, m_content.e); break;
		case Type::BOOL: toJSON(out, m_content.b); break;
		case Type::INTEGER: toJSON(out, m_content.i); break;
		case Type::REAL: toJSON(out, m_content.r); break;
		case Type::NAME: toJSON(out, m_content.n); break;
		case Type::STRING: toJSON(out, m_content.s); break;
		case Type::ARRAY: toJSON(out, *m_content.a); break;
		case Type::PROPS: toJSON(out, *m_content.o); break;
		default: assert(false);
	}
}

PropVal PropVal::fromJSON(std::istream &in) {
	using Encoding = typename rapidjson::UTF8<>;
	using rapidjson::SizeType;

	class JSONHandler {
	protected:
		std::vector<PropVal> m_valueStack;

		void popCurrent() { m_valueStack.pop_back(); }

		void store(PropVal &&pIn) {
			if (m_valueStack.capacity() == m_valueStack.size())
				m_valueStack.reserve(m_valueStack.size() * 2);
			m_valueStack.push_back(std::move(pIn));
		}

	public:
		using Ch = typename Encoding::Ch;

		void Null_() { store(PropVal()); }

		void Bool_(bool b) { store(b); }

		void Int(int i) { store(int64_t(i)); }
		void Uint(unsigned i) { store(int64_t(i)); }
		void Int64(int64_t i) { store(i); }
		void Uint64(uint64_t i) { store(int64_t(i)); }

		void Double(double d) { store(d); }

		void String(const Ch* str, SizeType length, bool copy) { store(string(str, length)); }

		void StartObject() {}

		void EndObject(SizeType memberCount) {
			if (m_valueStack.size() < memberCount * 2) throw logic_error("Parsing stack size mismatch on object");
			PropVal objProp = PropVal::props();
			Props obj = objProp.asProps();
			for (auto p = m_valueStack.end() - memberCount * 2; p < m_valueStack.end();) {
				PropKey k(std::move(*p++));
				obj[std::move(k)] = std::move(*p++);
			}
			m_valueStack.resize(m_valueStack.size() - 2 * memberCount);
			store(std::move(obj));
		}

		void StartArray() {}

		void EndArray(SizeType elementCount) {
			if (m_valueStack.size() < elementCount) throw logic_error("Parsing stack size mismatch on array");
			PropVal arrayProp = PropVal::array();
			Array arr = arrayProp.asArray();
			arr.reserve(elementCount);
			for (auto p = m_valueStack.end() - elementCount; p < m_valueStack.end(); ++p)
				arr.push_back(std::move(*p));
			m_valueStack.resize(m_valueStack.size() - elementCount);
			store(std::move(arr));
		}

		PropVal& getResult() {
			if (m_valueStack.size() != 1) throw logic_error("Parsing stack size mismatch - expected size 1");
			return m_valueStack.front();
		}

		JSONHandler() {
			m_valueStack.reserve(8);
		}
	};

	rapidjson::GenericReadStream genericIn(in);

	rapidjson::GenericReader<Encoding> reader;
	JSONHandler handler;

	if (! reader.Parse<rapidjson::kParseDefaultFlags, rapidjson::GenericReadStream, JSONHandler> (genericIn, handler))
		throw runtime_error("JSON parse error");

	return PropVal( std::move(handler.getResult()) );
}

std::string PropVal::toJSON() const {
	stringstream tmp;
	toJSON(tmp);
	return tmp.str();
}

PropVal PropVal::fromJSON(const std::string &in) {
	stringstream tmp(in);
	return fromJSON(tmp);
}

void PropVal::toFile(const std::string &outFileName) const {
	TString fileName(outFileName);

	if (fileName.EndsWith(".json")) {
		ofstream out(fileName.Data());
		toJSON(out);
		out << "\n";
	} else throw runtime_error("Unsupported input file type for PropVal");
}

PropVal PropVal::fromFile(const std::string &inFileName) {
	TString fileName(inFileName);

	if (fileName.EndsWith(".json")) {
		ifstream in(fileName.Data());
		return fromJSON(in);
	} else throw runtime_error("Unsupported input file type for PropVal");
}

std::ostream& PropVal::print(std::ostream &os) const {
	switch (m_type) {
		case Type::NAME: os << m_content.n; break;
		case Type::STRING: os << m_content.s; break;
		default: toJSON(os);
	}
	return os;
}

std::string PropVal::toString() const {
	stringstream out;
	print(out);
	return out.str();
}

Props PropVal::diff(const Props &a, const Props &b) {
	auto itA = a.begin(), itB = b.begin();

	Props result;

	while ((itA != a.end()) && (itB != b.end())) {
		const auto &keyA = itA->first;
		const auto &valA = itA->second;
		const auto &keyB = itB->first;
		const auto &valB = itB->second;

		if (keyA == keyB) {
			if (valA.isProps() && valB.isProps()) {
				Props d = operator-(valA.asProps(), valB.asProps());
				if (! d.empty()) result[keyA] = PropVal(std::move(d));
			}
			else if (valA != valB) result[keyA] = valA;
			++itA; ++itB;
		} else if (PropKey::CompareById()(keyA, keyB)) {
			result[keyA] = valA;
			++itA;
		} else {
			result[keyB] = PropVal();
			++itB;
		}
	}

	while (itA != a.end()) {
		const auto &keyA = itA->first;
		const auto &valA = itA->second;
		result[keyA] = valA;
		++itA;
	}

	while (itB != b.end()) {
		const auto &keyB = itB->first;
		const auto &valB = itB->second;
		result[keyB] = PropVal();
		++itB;
	}

	return result;
}

Props& PropVal::patchMerge(Props &a, Props b, bool merge) {
	auto itA = a.begin(), itB = b.begin();

	while ((itA != a.end()) && (itB != b.end())) {
		const auto &keyA = itA->first;
		auto &valA = itA->second;
		const auto &keyB = itB->first;
		auto &valB = itB->second;

		if (keyA == keyB) {
			if (valA.isProps() && valB.isProps())
				patchMerge(valA.asProps(), std::move(valB.asProps()), merge);
			else {
				if ((merge) && (valA != valB))
					throw invalid_argument("Can't merge Props with conflicting contents");
				else valA = std::move(valB);
			}
			++itA; ++itB;
		} else if (PropKey::CompareById()(keyA, keyB)) {
			++itA;
		} else {
			a[keyB] = std::move(valB);
			++itB;
		}
	}

	while (itB != b.end()) {
		const auto &keyB = itB->first;
		auto &valB = itB->second;
		a[keyB] = std::move(valB);
		++itB;
	}

	return a;
}

} // namespace dbrxq
<commit_msg>Fixed "unused value" in Props.cxx<commit_after>// Copyright (C) 2014 Oliver Schulz <oschulz@mpp.mpg.de>

// This 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 software is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

#include "Props.h"

#include <iostream>
#include <fstream>
#include <sstream>

#include "external/rapidjson/reader.h"
#include "external/rapidjson/genericstream.h"

#include <TString.h>

using namespace std;

namespace dbrx {

void PropKey::toJSON(std::ostream &out, const String &x) {
	out << "\"";
    for (char c: x) {
        switch (c) {
            case '\\': out << "\\\\"; break;
            case '\f': out << "\\f"; break;
            case '\n': out << "\\n"; break;
            case '\r': out << "\\r"; break;
            case '"': out << "\\\""; break;
            default: out << c; break;
        }
    }
	out << "\"";
}

void PropKey::toJSON(std::ostream &out) const {
	switch (m_type) {
		case Type::INTEGER: out << "\"" << m_content.i << "\""; break;
		case Type::NAME: toJSON(out, m_content.n.str()); break;
		default: assert(false);
	}
}

std::string PropKey::toJSON() const {
	stringstream tmp;
	toJSON(tmp);
	return tmp.str();
}

std::ostream& PropKey::print(std::ostream &os) const {
	switch (m_type) {
		case Type::INTEGER: os << m_content.i; break;
		case Type::NAME: os << m_content.n; break;
		default: assert(false);
	}
	return os;
}

std::string PropKey::toString() const {
	stringstream out;
	print(out);
	return out.str();
}

PropKey::PropKey(const std::string &value) {
	try {
		long long i = stoll(value);
		m_content.i = Integer(i);
		if (m_content.i != i) throw std::out_of_range("Integer key out of range");
	}
	catch (std::invalid_argument &e) {
		m_content.n = value;
		m_type = Type::NAME;
	}
}

bool PropVal::comparisonImpl(const PropVal &other) const {
	switch (m_type) {
		case Type::NAME:
			switch (other.m_type) {
				case Type::NAME: return m_content.n == other.m_content.n;
				case Type::STRING: return m_content.n.str() == other.m_content.s;
				default: return false;
			}
		case Type::STRING:
			switch (other.m_type) {
				case Type::STRING: return m_content.s == other.m_content.s;
				case Type::NAME: return m_content.s == other.m_content.n.str();
				default: return false;
			}
		case Type::ARRAY: return (other.m_type == Type::ARRAY) && (*m_content.a == *other.m_content.a);
		case Type::PROPS: return (other.m_type == Type::PROPS) && (*m_content.o == *other.m_content.o);
		default: assert(false);
	}
}

bool operator==(const Props &a, const Props &b) {
	auto itA = a.begin(), itB = b.begin();

	while ((itA != a.end()) && (itB != b.end())) {
		const auto &keyA = itA->first;
		const auto &valA = itA->second;
		const auto &keyB = itB->first;
		const auto &valB = itB->second;

		if (keyA == keyB) {
			if (valA != valB) return false;
			++itA; ++itB;
		} else if (PropKey::CompareById()(keyA, keyB)) {
			if (! valA.isNone()) return false;
			++itA;
		} else {
			if (! valB.isNone()) return false;
			++itB;
		}
	}

	while (itA != a.end()) {
		const auto &valA = itA->second;
		if (! valA.isNone()) return false;
		++itA;
	}

	while (itB != b.end()) {
		const auto &valB = itB->second;
		if (! valB.isNone()) return false;
		++itB;
	}

	return true;
}

void PropVal::toJSON(std::ostream &out, Real x) {
	out.precision(17);
	out << x;
}

void PropVal::toJSON(std::ostream &out, Name x) {
	toJSON(out, x.str());
}

void PropVal::toJSON(std::ostream &out, const Array &x) {
	out << "[";
	bool first = true;
	for (auto const &v: x) {
		if (!first) out << ", ";
		v.toJSON(out);
		first = false;
	}
	out << "]";
}

void PropVal::toJSON(std::ostream &out, const Props &x) {
	using CPRef = std::pair<PropKey, const PropVal*>;
	vector<CPRef> props;
	props.reserve(x.size());

	for (auto const &e: x) props.push_back({e.first, &e.second});
	auto compare = [](const CPRef &a, const CPRef &b) { return a.first < b.first; };
	sort(props.begin(), props.end(), compare);

	out << "{";
	bool first = true;
	for (auto const &e: props) {
		if (!first) out << ", ";
		e.first.toJSON(out);
		out << ": ";
		e.second->toJSON(out);
		first = false;
	}
	out << "}";
}

void PropVal::toJSON(std::ostream &out) const {
	switch (m_type) {
		case Type::NONE: toJSON(out, m_content.e); break;
		case Type::BOOL: toJSON(out, m_content.b); break;
		case Type::INTEGER: toJSON(out, m_content.i); break;
		case Type::REAL: toJSON(out, m_content.r); break;
		case Type::NAME: toJSON(out, m_content.n); break;
		case Type::STRING: toJSON(out, m_content.s); break;
		case Type::ARRAY: toJSON(out, *m_content.a); break;
		case Type::PROPS: toJSON(out, *m_content.o); break;
		default: assert(false);
	}
}

PropVal PropVal::fromJSON(std::istream &in) {
	using Encoding = typename rapidjson::UTF8<>;
	using rapidjson::SizeType;

	class JSONHandler {
	protected:
		std::vector<PropVal> m_valueStack;

		void popCurrent() { m_valueStack.pop_back(); }

		void store(PropVal &&pIn) {
			if (m_valueStack.capacity() == m_valueStack.size())
				m_valueStack.reserve(m_valueStack.size() * 2);
			m_valueStack.push_back(std::move(pIn));
		}

	public:
		using Ch = typename Encoding::Ch;

		void Null_() { store(PropVal()); }

		void Bool_(bool b) { store(b); }

		void Int(int i) { store(int64_t(i)); }
		void Uint(unsigned i) { store(int64_t(i)); }
		void Int64(int64_t i) { store(i); }
		void Uint64(uint64_t i) { store(int64_t(i)); }

		void Double(double d) { store(d); }

		void String(const Ch* str, SizeType length, bool copy) { store(string(str, length)); }

		void StartObject() {}

		void EndObject(SizeType memberCount) {
			if (m_valueStack.size() < memberCount * 2) throw logic_error("Parsing stack size mismatch on object");
			PropVal objProp = PropVal::props();
			Props obj = objProp.asProps();
			for (auto p = m_valueStack.end() - memberCount * 2; p < m_valueStack.end();) {
				PropKey k(std::move(*p++));
				obj[std::move(k)] = std::move(*p++);
			}
			m_valueStack.resize(m_valueStack.size() - 2 * memberCount);
			store(std::move(obj));
		}

		void StartArray() {}

		void EndArray(SizeType elementCount) {
			if (m_valueStack.size() < elementCount) throw logic_error("Parsing stack size mismatch on array");
			PropVal arrayProp = PropVal::array();
			Array arr = arrayProp.asArray();
			arr.reserve(elementCount);
			for (auto p = m_valueStack.end() - elementCount; p < m_valueStack.end(); ++p)
				arr.push_back(std::move(*p));
			m_valueStack.resize(m_valueStack.size() - elementCount);
			store(std::move(arr));
		}

		PropVal& getResult() {
			if (m_valueStack.size() != 1) throw logic_error("Parsing stack size mismatch - expected size 1");
			return m_valueStack.front();
		}

		JSONHandler() {
			m_valueStack.reserve(8);
		}
	};

	rapidjson::GenericReadStream genericIn(in);

	rapidjson::GenericReader<Encoding> reader;
	JSONHandler handler;

	if (! reader.Parse<rapidjson::kParseDefaultFlags, rapidjson::GenericReadStream, JSONHandler> (genericIn, handler))
		throw runtime_error("JSON parse error");

	return PropVal( std::move(handler.getResult()) );
}

std::string PropVal::toJSON() const {
	stringstream tmp;
	toJSON(tmp);
	return tmp.str();
}

PropVal PropVal::fromJSON(const std::string &in) {
	stringstream tmp(in);
	return fromJSON(tmp);
}

void PropVal::toFile(const std::string &outFileName) const {
	TString fileName(outFileName);

	if (fileName.EndsWith(".json")) {
		ofstream out(fileName.Data());
		toJSON(out);
		out << "\n";
	} else throw runtime_error("Unsupported input file type for PropVal");
}

PropVal PropVal::fromFile(const std::string &inFileName) {
	TString fileName(inFileName);

	if (fileName.EndsWith(".json")) {
		ifstream in(fileName.Data());
		return fromJSON(in);
	} else throw runtime_error("Unsupported input file type for PropVal");
}

std::ostream& PropVal::print(std::ostream &os) const {
	switch (m_type) {
		case Type::NAME: os << m_content.n; break;
		case Type::STRING: os << m_content.s; break;
		default: toJSON(os);
	}
	return os;
}

std::string PropVal::toString() const {
	stringstream out;
	print(out);
	return out.str();
}

Props PropVal::diff(const Props &a, const Props &b) {
	auto itA = a.begin(), itB = b.begin();

	Props result;

	while ((itA != a.end()) && (itB != b.end())) {
		const auto &keyA = itA->first;
		const auto &valA = itA->second;
		const auto &keyB = itB->first;
		const auto &valB = itB->second;

		if (keyA == keyB) {
			if (valA.isProps() && valB.isProps()) {
				Props d = operator-(valA.asProps(), valB.asProps());
				if (! d.empty()) result[keyA] = PropVal(std::move(d));
			}
			else if (valA != valB) result[keyA] = valA;
			++itA; ++itB;
		} else if (PropKey::CompareById()(keyA, keyB)) {
			result[keyA] = valA;
			++itA;
		} else {
			result[keyB] = PropVal();
			++itB;
		}
	}

	while (itA != a.end()) {
		const auto &keyA = itA->first;
		const auto &valA = itA->second;
		result[keyA] = valA;
		++itA;
	}

	while (itB != b.end()) {
		const auto &keyB = itB->first;
		result[keyB] = PropVal();
		++itB;
	}

	return result;
}

Props& PropVal::patchMerge(Props &a, Props b, bool merge) {
	auto itA = a.begin(), itB = b.begin();

	while ((itA != a.end()) && (itB != b.end())) {
		const auto &keyA = itA->first;
		auto &valA = itA->second;
		const auto &keyB = itB->first;
		auto &valB = itB->second;

		if (keyA == keyB) {
			if (valA.isProps() && valB.isProps())
				patchMerge(valA.asProps(), std::move(valB.asProps()), merge);
			else {
				if ((merge) && (valA != valB))
					throw invalid_argument("Can't merge Props with conflicting contents");
				else valA = std::move(valB);
			}
			++itA; ++itB;
		} else if (PropKey::CompareById()(keyA, keyB)) {
			++itA;
		} else {
			a[keyB] = std::move(valB);
			++itB;
		}
	}

	while (itB != b.end()) {
		const auto &keyB = itB->first;
		auto &valB = itB->second;
		a[keyB] = std::move(valB);
		++itB;
	}

	return a;
}

} // namespace dbrxq
<|endoftext|>


<commit_before>#include "utils.h"
#include <gtest/gtest.h>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_int_distribution.hpp>
#include <boost/random/uniform_smallint.hpp>
#include <fstream>
#include <set>

bool CharOk(char c) {
  if (('a' <= c) && (c <= 'z')) {
    return true;
  } else if (('0' <= c) && (c <= '9')) {
    return true;
  } else if (c == '-') {
    return true;
  } else {
    return false;
  }
}

bool PrettyNameOk(const std::string &name) {
  if (name.size() < 5) {
    return false;
  }
  for (std::string::const_iterator c = name.begin(); c != name.end(); ++c) {
    if (!CharOk(*c)) {
      return false;
    }
  }
  return true;
}

TEST(Utils, PrettyNameOk) {
  EXPECT_TRUE(PrettyNameOk("foo-bar-123"));
  EXPECT_FALSE(PrettyNameOk("NoCapitals"));
  EXPECT_FALSE(PrettyNameOk(""));
  EXPECT_FALSE(PrettyNameOk("foo-bar-123&"));
}

TEST(Utils, GenPrettyNameSane) {
  std::set<std::string> names;
  for (int i = 0; i < 100; i++) {
    std::string name = Utils::genPrettyName();
    EXPECT_EQ(0, names.count(name));
    names.insert(name);
    EXPECT_EQ(1, names.count(name));
  }
}

TEST(Utils, RandomUuidSane) {
  std::set<std::string> uuids;
  for (int i = 0; i < 1000; i++) {
    std::string uuid = Utils::randomUuid();
    EXPECT_EQ(0, uuids.count(uuid));
    uuids.insert(uuid);
    EXPECT_EQ(1, uuids.count(uuid));
  }
}

TEST(Utils, FromBase64) {
  // Generated using python's base64.b64encode
  EXPECT_EQ("aGVsbG8=", Utils::toBase64("hello"));
  EXPECT_EQ("", Utils::toBase64(""));
  EXPECT_EQ("CQ==", Utils::toBase64("\t"));
  EXPECT_EQ("YWI=", Utils::toBase64("ab"));
  EXPECT_EQ("YWJj", Utils::toBase64("abc"));
}

TEST(Utils, Base64RoundTrip) {
  boost::mt19937 gen;
  boost::random::uniform_smallint<char> chars(std::numeric_limits<char>::min(), std::numeric_limits<char>::max());

  boost::random::uniform_smallint<int> length(0, 20);

  for (int test = 0; test < 100; test++) {
    int len = length(gen);
    std::string original;
    for (int i = 0; i < len; i++) {
      original += chars(gen);
    }
    std::string b64 = Utils::toBase64(original);
    std::string output = Utils::fromBase64(b64);
    EXPECT_EQ(original, output);
  }
}

TEST(Utils, TemporaryFile) {
  boost::filesystem::path p;
  {
    TemporaryFile f("ahint");
    p = f.Path();
    EXPECT_FALSE(boost::filesystem::exists(p));  // The file shouldn't already exist
    std::ofstream file(p.c_str());
    file << "test";
    file.close();
    EXPECT_TRUE(file);                                       // The write succeeded
    EXPECT_TRUE(boost::filesystem::exists(p));               // The file should exist here
    EXPECT_NE(p.string().find("ahint"), std::string::npos);  // The hint is included in the filename
  }
  EXPECT_FALSE(boost::filesystem::exists(p));  // The file gets deleted by the RAII dtor
}

TEST(Utils, TemporaryFilePutContents) {
  TemporaryFile f("ahint");
  f.PutContents("thecontents");
  EXPECT_TRUE(boost::filesystem::exists(f.Path()));
  std::ifstream a(f.Path().c_str());
  std::string b;
  a >> b;
  EXPECT_EQ(b, "thecontents");
}

TEST(Utils, copyDir) {
  if (boost::filesystem::exists("tests/test_data/test_copy_dir"))
    boost::filesystem::remove_all("tests/test_data/test_copy_dir");

  boost::filesystem::create_directories("tests/test_data/test_copy_dir");
  boost::filesystem::create_directories("tests/test_data/test_copy_dir/from/1/2");
  Utils::writeFile("tests/test_data/test_copy_dir/from/1/foo", std::string("foo"));
  Utils::writeFile("tests/test_data/test_copy_dir/from/1/2/bar", std::string("bar"));
  Utils::writeFile("tests/test_data/test_copy_dir/from/1/2/baz", std::string("baz"));

  Utils::copyDir("tests/test_data/test_copy_dir/from", "tests/test_data/test_copy_dir/to");
  EXPECT_TRUE(boost::filesystem::exists("tests/test_data/test_copy_dir/to"));
  EXPECT_TRUE(boost::filesystem::exists("tests/test_data/test_copy_dir/to/1"));
  EXPECT_TRUE(boost::filesystem::exists("tests/test_data/test_copy_dir/to/1/foo"));
  EXPECT_TRUE(boost::filesystem::exists("tests/test_data/test_copy_dir/to/1/2"));
  EXPECT_TRUE(boost::filesystem::exists("tests/test_data/test_copy_dir/to/1/2/bar"));
  EXPECT_TRUE(boost::filesystem::exists("tests/test_data/test_copy_dir/to/1/2/baz"));
  EXPECT_EQ(Utils::readFile("tests/test_data/test_copy_dir/to/1/foo"), "foo");
  EXPECT_EQ(Utils::readFile("tests/test_data/test_copy_dir/to/1/2/bar"), "bar");
  EXPECT_EQ(Utils::readFile("tests/test_data/test_copy_dir/to/1/2/baz"), "baz");
}

#ifndef __NO_MAIN__
int main(int argc, char **argv) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}
#endif
<commit_msg>Associate test with requirement test case TST-144.<commit_after>#include "utils.h"
#include <gtest/gtest.h>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_int_distribution.hpp>
#include <boost/random/uniform_smallint.hpp>
#include <fstream>
#include <set>

bool CharOk(char c) {
  if (('a' <= c) && (c <= 'z')) {
    return true;
  } else if (('0' <= c) && (c <= '9')) {
    return true;
  } else if (c == '-') {
    return true;
  } else {
    return false;
  }
}

bool PrettyNameOk(const std::string &name) {
  if (name.size() < 5) {
    return false;
  }
  for (std::string::const_iterator c = name.begin(); c != name.end(); ++c) {
    if (!CharOk(*c)) {
      return false;
    }
  }
  return true;
}

TEST(Utils, PrettyNameOk) {
  EXPECT_TRUE(PrettyNameOk("foo-bar-123"));
  EXPECT_FALSE(PrettyNameOk("NoCapitals"));
  EXPECT_FALSE(PrettyNameOk(""));
  EXPECT_FALSE(PrettyNameOk("foo-bar-123&"));
}

/**
 * \verify{\tst{144}} Check that aktualizr can generate a pet name
 */
TEST(Utils, GenPrettyNameSane) {
  std::set<std::string> names;
  for (int i = 0; i < 100; i++) {
    std::string name = Utils::genPrettyName();
    EXPECT_EQ(0, names.count(name));
    names.insert(name);
    EXPECT_EQ(1, names.count(name));
  }
}

TEST(Utils, RandomUuidSane) {
  std::set<std::string> uuids;
  for (int i = 0; i < 1000; i++) {
    std::string uuid = Utils::randomUuid();
    EXPECT_EQ(0, uuids.count(uuid));
    uuids.insert(uuid);
    EXPECT_EQ(1, uuids.count(uuid));
  }
}

TEST(Utils, FromBase64) {
  // Generated using python's base64.b64encode
  EXPECT_EQ("aGVsbG8=", Utils::toBase64("hello"));
  EXPECT_EQ("", Utils::toBase64(""));
  EXPECT_EQ("CQ==", Utils::toBase64("\t"));
  EXPECT_EQ("YWI=", Utils::toBase64("ab"));
  EXPECT_EQ("YWJj", Utils::toBase64("abc"));
}

TEST(Utils, Base64RoundTrip) {
  boost::mt19937 gen;
  boost::random::uniform_smallint<char> chars(std::numeric_limits<char>::min(), std::numeric_limits<char>::max());

  boost::random::uniform_smallint<int> length(0, 20);

  for (int test = 0; test < 100; test++) {
    int len = length(gen);
    std::string original;
    for (int i = 0; i < len; i++) {
      original += chars(gen);
    }
    std::string b64 = Utils::toBase64(original);
    std::string output = Utils::fromBase64(b64);
    EXPECT_EQ(original, output);
  }
}

TEST(Utils, TemporaryFile) {
  boost::filesystem::path p;
  {
    TemporaryFile f("ahint");
    p = f.Path();
    EXPECT_FALSE(boost::filesystem::exists(p));  // The file shouldn't already exist
    std::ofstream file(p.c_str());
    file << "test";
    file.close();
    EXPECT_TRUE(file);                                       // The write succeeded
    EXPECT_TRUE(boost::filesystem::exists(p));               // The file should exist here
    EXPECT_NE(p.string().find("ahint"), std::string::npos);  // The hint is included in the filename
  }
  EXPECT_FALSE(boost::filesystem::exists(p));  // The file gets deleted by the RAII dtor
}

TEST(Utils, TemporaryFilePutContents) {
  TemporaryFile f("ahint");
  f.PutContents("thecontents");
  EXPECT_TRUE(boost::filesystem::exists(f.Path()));
  std::ifstream a(f.Path().c_str());
  std::string b;
  a >> b;
  EXPECT_EQ(b, "thecontents");
}

TEST(Utils, copyDir) {
  if (boost::filesystem::exists("tests/test_data/test_copy_dir"))
    boost::filesystem::remove_all("tests/test_data/test_copy_dir");

  boost::filesystem::create_directories("tests/test_data/test_copy_dir");
  boost::filesystem::create_directories("tests/test_data/test_copy_dir/from/1/2");
  Utils::writeFile("tests/test_data/test_copy_dir/from/1/foo", std::string("foo"));
  Utils::writeFile("tests/test_data/test_copy_dir/from/1/2/bar", std::string("bar"));
  Utils::writeFile("tests/test_data/test_copy_dir/from/1/2/baz", std::string("baz"));

  Utils::copyDir("tests/test_data/test_copy_dir/from", "tests/test_data/test_copy_dir/to");
  EXPECT_TRUE(boost::filesystem::exists("tests/test_data/test_copy_dir/to"));
  EXPECT_TRUE(boost::filesystem::exists("tests/test_data/test_copy_dir/to/1"));
  EXPECT_TRUE(boost::filesystem::exists("tests/test_data/test_copy_dir/to/1/foo"));
  EXPECT_TRUE(boost::filesystem::exists("tests/test_data/test_copy_dir/to/1/2"));
  EXPECT_TRUE(boost::filesystem::exists("tests/test_data/test_copy_dir/to/1/2/bar"));
  EXPECT_TRUE(boost::filesystem::exists("tests/test_data/test_copy_dir/to/1/2/baz"));
  EXPECT_EQ(Utils::readFile("tests/test_data/test_copy_dir/to/1/foo"), "foo");
  EXPECT_EQ(Utils::readFile("tests/test_data/test_copy_dir/to/1/2/bar"), "bar");
  EXPECT_EQ(Utils::readFile("tests/test_data/test_copy_dir/to/1/2/baz"), "baz");
}

#ifndef __NO_MAIN__
int main(int argc, char **argv) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}
#endif
<|endoftext|>


<commit_before>/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2015. All Rights Reserved.                             */
/* Open Source Software - may be modified and shared by FRC teams. The code   */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project.                                                               */
/*----------------------------------------------------------------------------*/

#include "nt_Value.h"
#include "Value_internal.h"

using namespace nt;

Value::Value() { m_val.type = NT_UNASSIGNED; }

Value::Value(NT_Type type, const private_init&) {
  m_val.type = type;
  if (m_val.type == NT_BOOLEAN_ARRAY)
    m_val.data.arr_boolean.arr = nullptr;
  else if (m_val.type == NT_DOUBLE_ARRAY)
    m_val.data.arr_double.arr = nullptr;
  else if (m_val.type == NT_STRING_ARRAY)
    m_val.data.arr_string.arr = nullptr;
}

Value::~Value() {
  if (m_val.type == NT_BOOLEAN_ARRAY)
    delete[] m_val.data.arr_boolean.arr;
  else if (m_val.type == NT_DOUBLE_ARRAY)
    delete[] m_val.data.arr_double.arr;
  else if (m_val.type == NT_STRING_ARRAY)
    delete[] m_val.data.arr_string.arr;
}

std::shared_ptr<Value> Value::MakeBooleanArray(llvm::ArrayRef<int> value) {
  auto val = std::make_shared<Value>(NT_BOOLEAN_ARRAY, private_init());
  val->m_val.data.arr_boolean.arr = new int[value.size()];
  val->m_val.data.arr_boolean.size = value.size();
  std::copy(value.begin(), value.end(), val->m_val.data.arr_boolean.arr);
  return val;
}

std::shared_ptr<Value> Value::MakeDoubleArray(llvm::ArrayRef<double> value) {
  auto val = std::make_shared<Value>(NT_DOUBLE_ARRAY, private_init());
  val->m_val.data.arr_double.arr = new double[value.size()];
  val->m_val.data.arr_double.size = value.size();
  std::copy(value.begin(), value.end(), val->m_val.data.arr_double.arr);
  return val;
}

std::shared_ptr<Value> Value::MakeStringArray(
    llvm::ArrayRef<std::string> value) {
  auto val = std::make_shared<Value>(NT_STRING_ARRAY, private_init());
  val->m_string_array = value;
  // point NT_Value to the contents in the vector.
  val->m_val.data.arr_string.arr = new NT_String[value.size()];
  for (std::size_t i=0; i<value.size(); ++i) {
    val->m_val.data.arr_string.arr[i].str = const_cast<char*>(value[i].c_str());
    val->m_val.data.arr_string.arr[i].len = value[i].size();
  }
  return val;
}

std::shared_ptr<Value> Value::MakeStringArray(
    std::vector<std::string>&& value) {
  auto val = std::make_shared<Value>(NT_STRING_ARRAY, private_init());
  val->m_string_array = std::move(value);
  value.clear();
  // point NT_Value to the contents in the vector.
  val->m_val.data.arr_string.arr = new NT_String[val->m_string_array.size()];
  for (std::size_t i=0; i<val->m_string_array.size(); ++i) {
    val->m_val.data.arr_string.arr[i].str =
        const_cast<char*>(val->m_string_array[i].c_str());
    val->m_val.data.arr_string.arr[i].len = val->m_string_array[i].size();
  }
  return val;
}

void nt::ConvertToC(const Value& in, NT_Value* out) {
  NT_DisposeValue(out);
  switch (in.type()) {
    case NT_UNASSIGNED:
      return;
    case NT_BOOLEAN:
      out->data.v_boolean = in.GetBoolean() ? 1 : 0;
      break;
    case NT_DOUBLE:
      out->data.v_double = in.GetDouble();
      break;
    case NT_STRING:
      NT_InitString(&out->data.v_string);
      ConvertToC(in.GetString(), &out->data.v_string);
      break;
    case NT_RAW:
      NT_InitString(&out->data.v_raw);
      ConvertToC(in.GetRaw(), &out->data.v_raw);
      break;
    case NT_RPC:
      NT_InitString(&out->data.v_raw);
      ConvertToC(in.GetRpc(), &out->data.v_raw);
      break;
    case NT_BOOLEAN_ARRAY: {
      auto v = in.GetBooleanArray();
      out->data.arr_boolean.arr =
          static_cast<int*>(std::malloc(v.size() * sizeof(int)));
      out->data.arr_boolean.size = v.size();
      std::copy(v.begin(), v.end(), out->data.arr_boolean.arr);
      break;
    }
    case NT_DOUBLE_ARRAY: {
      auto v = in.GetDoubleArray();
      out->data.arr_double.arr =
          static_cast<double*>(std::malloc(v.size() * sizeof(double)));
      out->data.arr_double.size = v.size();
      std::copy(v.begin(), v.end(), out->data.arr_double.arr);
      break;
    }
    case NT_STRING_ARRAY: {
      auto v = in.GetStringArray();
      out->data.arr_string.arr =
          static_cast<NT_String*>(std::malloc(v.size()*sizeof(NT_String)));
      for (size_t i=0; i<v.size(); ++i) {
        NT_InitString(&out->data.arr_string.arr[i]);
        ConvertToC(v[i], &out->data.arr_string.arr[i]);
      }
      out->data.arr_string.size = v.size();
      break;
    }
    default:
      // assert(false && "unknown value type");
      return;
  }
  out->type = in.type();
}

void nt::ConvertToC(llvm::StringRef in, NT_String* out) {
  NT_DisposeString(out);
  out->len = in.size();
  out->str = static_cast<char*>(std::malloc(in.size()+1));
  std::memcpy(out->str, in.data(), in.size());
  out->str[in.size()] = '\0';
}

std::shared_ptr<Value> nt::ConvertFromC(const NT_Value& value) {
  switch (value.type) {
    case NT_UNASSIGNED:
      return nullptr;
    case NT_BOOLEAN:
      return Value::MakeBoolean(value.data.v_boolean != 0);
    case NT_DOUBLE:
      return Value::MakeDouble(value.data.v_double);
    case NT_STRING:
      return Value::MakeString(ConvertFromC(value.data.v_string));
    case NT_RAW:
      return Value::MakeRaw(ConvertFromC(value.data.v_raw));
    case NT_RPC:
      return Value::MakeRpc(ConvertFromC(value.data.v_raw));
    case NT_BOOLEAN_ARRAY:
      return Value::MakeBooleanArray(llvm::ArrayRef<int>(
          value.data.arr_boolean.arr, value.data.arr_boolean.size));
    case NT_DOUBLE_ARRAY:
      return Value::MakeDoubleArray(llvm::ArrayRef<double>(
          value.data.arr_double.arr, value.data.arr_double.size));
    case NT_STRING_ARRAY: {
      std::vector<std::string> v;
      v.reserve(value.data.arr_string.size);
      for (size_t i=0; i<value.data.arr_string.size; ++i)
        v.push_back(ConvertFromC(value.data.arr_string.arr[i]));
      return Value::MakeStringArray(std::move(v));
    }
    default:
      // assert(false && "unknown value type");
      return nullptr;
  }
}

bool nt::operator==(const Value& lhs, const Value& rhs) {
  if (lhs.type() != rhs.type()) return false;
  switch (lhs.type()) {
    case NT_UNASSIGNED:
      return true;  // XXX: is this better being false instead?
    case NT_BOOLEAN:
      return lhs.m_val.data.v_boolean == rhs.m_val.data.v_boolean;
    case NT_DOUBLE:
      return lhs.m_val.data.v_double == rhs.m_val.data.v_double;
    case NT_STRING:
    case NT_RAW:
    case NT_RPC:
      return lhs.m_string == rhs.m_string;
    case NT_BOOLEAN_ARRAY:
      if (lhs.m_val.data.arr_boolean.size != rhs.m_val.data.arr_boolean.size)
        return false;
      return std::memcmp(lhs.m_val.data.arr_boolean.arr,
                         rhs.m_val.data.arr_boolean.arr,
                         lhs.m_val.data.arr_boolean.size *
                             sizeof(lhs.m_val.data.arr_boolean.arr[0])) == 0;
    case NT_DOUBLE_ARRAY:
      if (lhs.m_val.data.arr_double.size != rhs.m_val.data.arr_double.size)
        return false;
      return std::memcmp(lhs.m_val.data.arr_double.arr,
                         rhs.m_val.data.arr_double.arr,
                         lhs.m_val.data.arr_double.size *
                             sizeof(lhs.m_val.data.arr_double.arr[0])) == 0;
    case NT_STRING_ARRAY:
      return lhs.m_string_array == rhs.m_string_array;
    default:
      // assert(false && "unknown value type");
      return false;
  }
}
<commit_msg>Value: Set last_change field.<commit_after>/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2015. All Rights Reserved.                             */
/* Open Source Software - may be modified and shared by FRC teams. The code   */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project.                                                               */
/*----------------------------------------------------------------------------*/

#include "nt_Value.h"
#include "Value_internal.h"
#include "support/timestamp.h"

using namespace nt;

Value::Value() {
  m_val.type = NT_UNASSIGNED;
  m_val.last_change = Now();
}

Value::Value(NT_Type type, const private_init&) {
  m_val.type = type;
  m_val.last_change = Now();
  if (m_val.type == NT_BOOLEAN_ARRAY)
    m_val.data.arr_boolean.arr = nullptr;
  else if (m_val.type == NT_DOUBLE_ARRAY)
    m_val.data.arr_double.arr = nullptr;
  else if (m_val.type == NT_STRING_ARRAY)
    m_val.data.arr_string.arr = nullptr;
}

Value::~Value() {
  if (m_val.type == NT_BOOLEAN_ARRAY)
    delete[] m_val.data.arr_boolean.arr;
  else if (m_val.type == NT_DOUBLE_ARRAY)
    delete[] m_val.data.arr_double.arr;
  else if (m_val.type == NT_STRING_ARRAY)
    delete[] m_val.data.arr_string.arr;
}

std::shared_ptr<Value> Value::MakeBooleanArray(llvm::ArrayRef<int> value) {
  auto val = std::make_shared<Value>(NT_BOOLEAN_ARRAY, private_init());
  val->m_val.data.arr_boolean.arr = new int[value.size()];
  val->m_val.data.arr_boolean.size = value.size();
  std::copy(value.begin(), value.end(), val->m_val.data.arr_boolean.arr);
  return val;
}

std::shared_ptr<Value> Value::MakeDoubleArray(llvm::ArrayRef<double> value) {
  auto val = std::make_shared<Value>(NT_DOUBLE_ARRAY, private_init());
  val->m_val.data.arr_double.arr = new double[value.size()];
  val->m_val.data.arr_double.size = value.size();
  std::copy(value.begin(), value.end(), val->m_val.data.arr_double.arr);
  return val;
}

std::shared_ptr<Value> Value::MakeStringArray(
    llvm::ArrayRef<std::string> value) {
  auto val = std::make_shared<Value>(NT_STRING_ARRAY, private_init());
  val->m_string_array = value;
  // point NT_Value to the contents in the vector.
  val->m_val.data.arr_string.arr = new NT_String[value.size()];
  for (std::size_t i=0; i<value.size(); ++i) {
    val->m_val.data.arr_string.arr[i].str = const_cast<char*>(value[i].c_str());
    val->m_val.data.arr_string.arr[i].len = value[i].size();
  }
  return val;
}

std::shared_ptr<Value> Value::MakeStringArray(
    std::vector<std::string>&& value) {
  auto val = std::make_shared<Value>(NT_STRING_ARRAY, private_init());
  val->m_string_array = std::move(value);
  value.clear();
  // point NT_Value to the contents in the vector.
  val->m_val.data.arr_string.arr = new NT_String[val->m_string_array.size()];
  for (std::size_t i=0; i<val->m_string_array.size(); ++i) {
    val->m_val.data.arr_string.arr[i].str =
        const_cast<char*>(val->m_string_array[i].c_str());
    val->m_val.data.arr_string.arr[i].len = val->m_string_array[i].size();
  }
  return val;
}

void nt::ConvertToC(const Value& in, NT_Value* out) {
  NT_DisposeValue(out);
  switch (in.type()) {
    case NT_UNASSIGNED:
      return;
    case NT_BOOLEAN:
      out->data.v_boolean = in.GetBoolean() ? 1 : 0;
      break;
    case NT_DOUBLE:
      out->data.v_double = in.GetDouble();
      break;
    case NT_STRING:
      NT_InitString(&out->data.v_string);
      ConvertToC(in.GetString(), &out->data.v_string);
      break;
    case NT_RAW:
      NT_InitString(&out->data.v_raw);
      ConvertToC(in.GetRaw(), &out->data.v_raw);
      break;
    case NT_RPC:
      NT_InitString(&out->data.v_raw);
      ConvertToC(in.GetRpc(), &out->data.v_raw);
      break;
    case NT_BOOLEAN_ARRAY: {
      auto v = in.GetBooleanArray();
      out->data.arr_boolean.arr =
          static_cast<int*>(std::malloc(v.size() * sizeof(int)));
      out->data.arr_boolean.size = v.size();
      std::copy(v.begin(), v.end(), out->data.arr_boolean.arr);
      break;
    }
    case NT_DOUBLE_ARRAY: {
      auto v = in.GetDoubleArray();
      out->data.arr_double.arr =
          static_cast<double*>(std::malloc(v.size() * sizeof(double)));
      out->data.arr_double.size = v.size();
      std::copy(v.begin(), v.end(), out->data.arr_double.arr);
      break;
    }
    case NT_STRING_ARRAY: {
      auto v = in.GetStringArray();
      out->data.arr_string.arr =
          static_cast<NT_String*>(std::malloc(v.size()*sizeof(NT_String)));
      for (size_t i=0; i<v.size(); ++i) {
        NT_InitString(&out->data.arr_string.arr[i]);
        ConvertToC(v[i], &out->data.arr_string.arr[i]);
      }
      out->data.arr_string.size = v.size();
      break;
    }
    default:
      // assert(false && "unknown value type");
      return;
  }
  out->type = in.type();
}

void nt::ConvertToC(llvm::StringRef in, NT_String* out) {
  NT_DisposeString(out);
  out->len = in.size();
  out->str = static_cast<char*>(std::malloc(in.size()+1));
  std::memcpy(out->str, in.data(), in.size());
  out->str[in.size()] = '\0';
}

std::shared_ptr<Value> nt::ConvertFromC(const NT_Value& value) {
  switch (value.type) {
    case NT_UNASSIGNED:
      return nullptr;
    case NT_BOOLEAN:
      return Value::MakeBoolean(value.data.v_boolean != 0);
    case NT_DOUBLE:
      return Value::MakeDouble(value.data.v_double);
    case NT_STRING:
      return Value::MakeString(ConvertFromC(value.data.v_string));
    case NT_RAW:
      return Value::MakeRaw(ConvertFromC(value.data.v_raw));
    case NT_RPC:
      return Value::MakeRpc(ConvertFromC(value.data.v_raw));
    case NT_BOOLEAN_ARRAY:
      return Value::MakeBooleanArray(llvm::ArrayRef<int>(
          value.data.arr_boolean.arr, value.data.arr_boolean.size));
    case NT_DOUBLE_ARRAY:
      return Value::MakeDoubleArray(llvm::ArrayRef<double>(
          value.data.arr_double.arr, value.data.arr_double.size));
    case NT_STRING_ARRAY: {
      std::vector<std::string> v;
      v.reserve(value.data.arr_string.size);
      for (size_t i=0; i<value.data.arr_string.size; ++i)
        v.push_back(ConvertFromC(value.data.arr_string.arr[i]));
      return Value::MakeStringArray(std::move(v));
    }
    default:
      // assert(false && "unknown value type");
      return nullptr;
  }
}

bool nt::operator==(const Value& lhs, const Value& rhs) {
  if (lhs.type() != rhs.type()) return false;
  switch (lhs.type()) {
    case NT_UNASSIGNED:
      return true;  // XXX: is this better being false instead?
    case NT_BOOLEAN:
      return lhs.m_val.data.v_boolean == rhs.m_val.data.v_boolean;
    case NT_DOUBLE:
      return lhs.m_val.data.v_double == rhs.m_val.data.v_double;
    case NT_STRING:
    case NT_RAW:
    case NT_RPC:
      return lhs.m_string == rhs.m_string;
    case NT_BOOLEAN_ARRAY:
      if (lhs.m_val.data.arr_boolean.size != rhs.m_val.data.arr_boolean.size)
        return false;
      return std::memcmp(lhs.m_val.data.arr_boolean.arr,
                         rhs.m_val.data.arr_boolean.arr,
                         lhs.m_val.data.arr_boolean.size *
                             sizeof(lhs.m_val.data.arr_boolean.arr[0])) == 0;
    case NT_DOUBLE_ARRAY:
      if (lhs.m_val.data.arr_double.size != rhs.m_val.data.arr_double.size)
        return false;
      return std::memcmp(lhs.m_val.data.arr_double.arr,
                         rhs.m_val.data.arr_double.arr,
                         lhs.m_val.data.arr_double.size *
                             sizeof(lhs.m_val.data.arr_double.arr[0])) == 0;
    case NT_STRING_ARRAY:
      return lhs.m_string_array == rhs.m_string_array;
    default:
      // assert(false && "unknown value type");
      return false;
  }
}
<|endoftext|>


<commit_before>#ifndef STAN_MATH_FWD_MAT_FUN_TRACE_QUAD_FORM_HPP
#define STAN_MATH_FWD_MAT_FUN_TRACE_QUAD_FORM_HPP

#include <boost/type_traits.hpp>
#include <stan/math/prim/mat/err/check_multiplicable.hpp>
#include <stan/math/prim/mat/err/check_square.hpp>
#include <stan/math/fwd/mat/fun/multiply.hpp>
#include <stan/math/prim/mat/fun/multiply.hpp>
#include <stan/math/prim/mat/fun/transpose.hpp>
#include <stan/math/prim/mat/fun/trace.hpp>
#include <stan/math/fwd/core.hpp>

namespace stan {
  namespace math {

    template<int RA, int CA, int RB, int CB, typename T>
    inline fvar<T>
    trace_quad_form(const Eigen::Matrix<fvar<T>, RA, CA> &A,
                    const Eigen::Matrix<fvar<T>, RB, CB> &B) {
      check_square("trace_quad_form", "A", A);
      check_multiplicable("trace_quad_form",
                                      "A", A,
                                      "B", B);
      return trace(multiply(transpose(B),
                                        multiply(A, B)));
    }

    template<int RA, int CA, int RB, int CB, typename T>
    inline fvar<T>
    trace_quad_form(const Eigen::Matrix<fvar<T>, RA, CA> &A,
                    const Eigen::Matrix<double, RB, CB> &B) {
      check_square("trace_quad_form", "A", A);
      check_multiplicable("trace_quad_form",
                                      "A", A,
                                      "B", B);
      return trace(multiply(transpose(B),
                                        multiply(A, B)));
    }

    template<int RA, int CA, int RB, int CB, typename T>
    inline fvar<T>
    trace_quad_form(const Eigen::Matrix<double, RA, CA> &A,
                    const Eigen::Matrix<fvar<T>, RB, CB> &B) {
      check_square("trace_quad_form", "A", A);
      check_multiplicable("trace_quad_form",
                                      "A", A,
                                      "B", B);
      return trace(multiply(transpose(B),
                                        multiply(A, B)));
    }
  }
}

#endif

<commit_msg>indenting code<commit_after>#ifndef STAN_MATH_FWD_MAT_FUN_TRACE_QUAD_FORM_HPP
#define STAN_MATH_FWD_MAT_FUN_TRACE_QUAD_FORM_HPP

#include <boost/type_traits.hpp>
#include <stan/math/prim/mat/err/check_multiplicable.hpp>
#include <stan/math/prim/mat/err/check_square.hpp>
#include <stan/math/fwd/mat/fun/multiply.hpp>
#include <stan/math/prim/mat/fun/multiply.hpp>
#include <stan/math/prim/mat/fun/transpose.hpp>
#include <stan/math/prim/mat/fun/trace.hpp>
#include <stan/math/fwd/core.hpp>

namespace stan {
  namespace math {

    template<int RA, int CA, int RB, int CB, typename T>
    inline fvar<T>
    trace_quad_form(const Eigen::Matrix<fvar<T>, RA, CA> &A,
                    const Eigen::Matrix<fvar<T>, RB, CB> &B) {
      check_square("trace_quad_form", "A", A);
      check_multiplicable("trace_quad_form",
                          "A", A,
                          "B", B);
      return trace(multiply(transpose(B),
                            multiply(A, B)));
    }

    template<int RA, int CA, int RB, int CB, typename T>
    inline fvar<T>
    trace_quad_form(const Eigen::Matrix<fvar<T>, RA, CA> &A,
                    const Eigen::Matrix<double, RB, CB> &B) {
      check_square("trace_quad_form", "A", A);
      check_multiplicable("trace_quad_form",
                          "A", A,
                          "B", B);
      return trace(multiply(transpose(B),
                            multiply(A, B)));
    }

    template<int RA, int CA, int RB, int CB, typename T>
    inline fvar<T>
    trace_quad_form(const Eigen::Matrix<double, RA, CA> &A,
                    const Eigen::Matrix<fvar<T>, RB, CB> &B) {
      check_square("trace_quad_form", "A", A);
      check_multiplicable("trace_quad_form",
                          "A", A,
                          "B", B);
      return trace(multiply(transpose(B),
                            multiply(A, B)));
    }
  }
}

#endif

<|endoftext|>