<commit_before>#include <memory>

#include <QHash>
#include <QDir>
#include <QLibrary>
#include <QSet>
#include <QDebug>

#include "../logger/Logging.h"
#include "../QzCoreContext.h"
#include "AbstractPlugin.h"
#include "IPluginAdapter.h"
#include "PluginManager.h"
#include "AbstractPluginBundle.h"
#include "BundleEnv.h"

namespace Quartz {

struct BundleInfo
{
    BundleInfo()
        : m_bundle{ nullptr }
        , m_library{}
    {

    }

    BundleInfo( AbstractPluginBundle *bundle,
                std::shared_ptr< QLibrary > library )
        : m_bundle{ bundle }
        , m_library{ library }
    {

    }

    bool isValid() const
    {
        return ! ( m_bundle == nullptr || m_library == nullptr );
    }

    AbstractPluginBundle *m_bundle;

    std::shared_ptr< QLibrary > m_library;
};

using PluginMap = QHash< QString, std::shared_ptr< AbstractPlugin >>;
using AdapterMap = QHash< QString, std::shared_ptr< IPluginAdapter >>;
using BundleInfoMap = QHash< QString, BundleInfo >;

typedef PluginBundleWrapper ( *PluginFunc )( BundleInputWrapper * );
typedef void ( *BundleDestroyerFunc )();

static const char * PLUGIN_GET_FUNC_NAME = "getBundleWrapper";
static const char * BUNDLE_DESTROY_FUNC_NAME = "destroy";

class PluginManager::Impl
{
public:
    bool load( const QDir &dir );

    bool destroy();

    std::size_t loadBundles( const QDir &pluginRoot,
                             QZ_OUT BundleInfoMap &bundleInfoOut );

    BundleInfo getBundle( const QString &pluginRoot,
                          const QString &pluginFilePath );
    bool processBundles( const BundleInfo &bundleInfo,
                         const BundleInfoMap &loadedBundles,
                         QZ_OUT QSet< QString > &processedBundles );

    bool initBundle( AbstractPluginBundle *bundle );

    void registerPluginAdapter( std::shared_ptr< IPluginAdapter > adapter );

    PluginMap m_plugins;

    AdapterMap m_adapters;

    BundleInfoMap m_bundles;

    bool m_active;
};

bool PluginManager::Impl::load( const QDir &dir )
{
    bool result = true;
    auto dirList = dir.entryInfoList( QDir::Dirs | QDir::NoDotAndDotDot,
                                      QDir::SortFlag::NoSort );
    BundleInfoMap loadedBundles;
    foreach(const QFileInfo &info, dirList) {
        if( info.isReadable() ) {
            QDir pluginDir{ info.absoluteFilePath() };
            auto numLoaded = loadBundles( pluginDir, loadedBundles );
            QZ_DEBUG( "Qz:Core:Ext" )
                    << "Loaded " << numLoaded << " plugins from "
                    << info.absoluteFilePath();
        }
        else {
            QZ_WARN( "Qz:Core:Ext" ) << "Could not read plugin directory at "
                                     << info.absoluteFilePath();
            result = false;
        }
    }
    QSet< QString > processed;
    for( auto it = loadedBundles.begin(); it != loadedBundles.end(); ++ it ) {
        const auto &binfo = it.value();
        if( ! processed.contains( binfo.m_bundle->bundleId() )) {
            result = processBundles( binfo,
                                     loadedBundles,
                                     processed ) && result;
        }
    }
    //unload failed bundles
    for( auto it = loadedBundles.begin();
         it != loadedBundles.end();
         ++ it ) {
        auto &binfo = it.value();
        if( ! m_bundles.contains( binfo.m_bundle->bundleId() )) {
            auto lib = binfo.m_library;
            if( lib != nullptr ) {
                auto destroyFunc = reinterpret_cast< BundleDestroyerFunc >(
                            lib->resolve( BUNDLE_DESTROY_FUNC_NAME ));
                if( destroyFunc != nullptr ) {
                    destroyFunc();
                }
                else {
                    QZ_DEBUG( "Qz:Core:Ext" )
                            << "Could not find symbol for destroy function in "
                               " library: " << lib->fileName();
                }
                result = result && lib->unload();
            }
            QZ_DEBUG( "Qz:Core:Ext" )
                    << "Unloaded library for bundle with id " <<
                       binfo.m_bundle->bundleId()
                    << " which failed to initialize";
        }
        else {
            initBundle( binfo.m_bundle );
        }
    }
    return result;
}

std::size_t PluginManager::Impl::loadBundles(
        const QDir &bundleRoot,
        QZ_OUT BundleInfoMap &bundleInfoOut )
{
    QStringList extensions;
#ifdef Q_OS_LINUX
    extensions << "*.so";
#elif defined Q_OS_WIN
    extensions << "*.dll";
#else
    extensions << "*.dylib" << "*.so";
#endif

#ifdef QT_DEBUG
    QDir bundleDir{ bundleRoot.absoluteFilePath( "debug" )};
#else
//    QDir pluginDir{ dirInfo.absoluteFilePath() };
        QDir pluginDir = pluginRoot;
#endif
    std::size_t numLoaded = 0;
    QZ_DEBUG( "Qz:Core:Ext" )
            << "Searching for plugins at " << bundleDir.absolutePath();
    auto fileList = bundleDir.entryInfoList( extensions,
                                             QDir::Files,
                                             QDir::NoSort );
    foreach( const auto &info, fileList ) {
        if( info.fileName().startsWith( "plugin_" )
                || info.fileName().startsWith( "libplugin_" )) {

            auto binfo = getBundle( bundleRoot.absolutePath(),
                                    info.absoluteFilePath() );
            if( binfo.isValid() ) {
                bundleInfoOut.insert( binfo.m_bundle->bundleId(), binfo );
                ++ numLoaded;
            }
        }
    }
    return numLoaded;
}

BundleInfo PluginManager::Impl::getBundle( const QString &bundleRoot,
                                           const QString &bundleFilePath )
{
    auto lib = std::make_shared< QLibrary >( bundleFilePath );
    lib->load();
    BundleInfo binfo{};
    if( lib->isLoaded() ) {
        auto func = reinterpret_cast< PluginFunc >(
                    lib->resolve( PLUGIN_GET_FUNC_NAME ));
        if( func != nullptr ) {
            auto bundleEnv = std::unique_ptr< BundleEnv >{
                new BundleEnv{ bundleRoot, lib->fileName(), "0.1.0000" }};
            BundleInputWrapper input{ std::move( bundleEnv ),
                                      QzCoreContext::get() };
            auto bundle = func( &input ).bundle;
            if( bundle != nullptr ) {
                binfo = BundleInfo{ bundle, lib };
            }
            else {
                QZ_WARN( "Qz:Core:Ext" )
                        << "Library at " << bundleFilePath << " does not "
                           "contain any bundle, unloading...";
                lib->unload();
            }
        }
        else {
            lib->unload();
            QZ_ERROR( "Qz:Core:Ext" )
                    << "Plugin library at " << bundleFilePath  << " does "
                    << "not export entry point";
        }
    }
    else {
        QZ_ERROR( "Qz:Core:Ext" )
                << "Failed to load plugin library at " << bundleFilePath;
    }
    return binfo;
}

bool PluginManager::Impl::processBundles(
        const BundleInfo &bundleInfo,
        const BundleInfoMap &loadedBundles,
        QZ_OUT QSet< QString > &processedBundles )
{
    if( processedBundles.contains( bundleInfo.m_bundle->bundleId() )) {
        return true;
    }
    bool result = true;
    const auto &hardDeps = bundleInfo.m_bundle->dependencies();
    for( int i = 0; i < hardDeps.size(); ++ i ) {
        const auto & depEntry = hardDeps.at( i );
        auto depInfo = m_bundles.value( depEntry.first );
        if( depInfo.isValid() ) {
            result = processBundles( depInfo,
                                     loadedBundles,
                                     processedBundles );
        }
        else {
            result = false;
        }
        if( ! result && depEntry.second == DependencyType::Optional ) {
            QZ_DEBUG( "Qz:Core:Ext" )
                    << "Optional dependency " << depEntry.first << " for "
                    << bundleInfo.m_bundle->bundleId() << " not present, "
                       "hence ignored.";
            continue;
        }
        else if( ! result ) {
            QZ_ERROR( "Qz:Core:Ext" )
                    << "Could not initialize bundle with id "
                    << bundleInfo.m_bundle->bundleId()
                    << "; could not find required dependncy with id "
                    << depEntry.first;
            break;
        }

    }

    if( result ) {
        m_bundles.insert( bundleInfo.m_bundle->bundleId(), bundleInfo );
        QZ_DEBUG( "Qz:Core:Ext" )
                << "Successfuly processed bundle with id "
                << bundleInfo.m_bundle->bundleId();
    }
    processedBundles.insert( bundleInfo.m_bundle->bundleId() );

    return result;
}

bool PluginManager::Impl::initBundle( AbstractPluginBundle *bundle )
{
    const auto &adapters = bundle->adapters();
    for( int i = 0; i < adapters.size(); ++ i ) {
        const auto adapter = adapters.at( i );
        if( ! m_adapters.contains( adapter->pluginType() )) {
            m_adapters.insert( adapter->pluginType(), adapter );
        }
    }
    auto result = true;
    const auto plugins = bundle->plugins();
    for( int i = 0; i < plugins.size(); ++ i ) {
        auto plugin = plugins.at( i );

            auto adapter = m_adapters.value( plugin->pluginType() );
            if( adapter != nullptr ) {
                result = adapter->handlePlugin( plugin.get() );
            }
            else {
                QZ_ERROR( "Qz:Core:Ext" )
                        << "Could not find adapter for plugin type "
                        << plugin->pluginType() << ", required by plugin "
                        << plugin->pluginId() << ". Ignoring...";
                result = false;
            }
    }
    return result;
}

void PluginManager::Impl::registerPluginAdapter(
        std::shared_ptr< IPluginAdapter > adapter )
{
    if( adapter ) {
        m_adapters[ adapter->pluginAdapterName() ] = adapter;
    }
}

bool PluginManager::Impl::destroy()
{
    if( ! m_active ) {
        return false;
    }
    bool result = true;
    for( auto it = m_adapters.begin();
         it != m_adapters.end();
         ++ it ) {
        auto &handler = it.value();
        result = result && handler->finalizePlugins();
    }
    foreach( auto &bundle, m_bundles ) {
        auto lib = bundle.m_library;
        if( lib != nullptr ) {
            auto destroyFunc = reinterpret_cast< BundleDestroyerFunc >(
                        lib->resolve( BUNDLE_DESTROY_FUNC_NAME ));
            if( destroyFunc != nullptr ) {
                destroyFunc();
            }
            else {
                QZ_DEBUG( "Qz:Core:Ext" )
                        << "Could not find symbol for destroy function in "
                           " library: " << lib->fileName();
            }
            result = result && lib->unload();
        }
    }
    m_active = false;
    return result;
}

//========================== PluginManager ====================================
PluginManager::PluginManager()
//    : m_data( std::make_unique< PluginManager::Data >() )
    : m_impl( std::unique_ptr< Impl >( new Impl() ))
{

}

PluginManager::~PluginManager()
{
    destroy();
}

AbstractPlugin * PluginManager::plugin( const QString &id ) const
{
    auto &plugin = m_impl->m_plugins.value( id );
    return plugin.get();
}

IPluginAdapter * PluginManager::adapter( const QString &id ) const
{
    return m_impl->m_adapters.value(
                id, std::shared_ptr< IPluginAdapter >{} ).get();
}

void PluginManager::registerPluginAdapter(
        std::shared_ptr< IPluginAdapter > adapter )
{
    m_impl->registerPluginAdapter( adapter );
}

void PluginManager::registerPluginAdapter( IPluginAdapter *adapter )
{
    std::shared_ptr< IPluginAdapter > adptr{ adapter,
                                             []( IPluginAdapter *){ }};
    m_impl->registerPluginAdapter(  adptr );
}

bool PluginManager::loadFrom( const QString &location )
{
    bool result = false;
    QFileInfo info{ location };
    if( info.isDir() && info.isReadable() ) {
        result = m_impl->load( QDir{ location });
    }
    else {
        QZ_ERROR( "Qz:Core:Ext" )
                << "Invalid plugin root directory " << location << " given";
    }
    return result;
}

bool PluginManager::destroy()
{
    return m_impl->destroy();
}

}
<commit_msg>Fixed plugin adapter registration<commit_after>#include <memory>

#include <QHash>
#include <QDir>
#include <QLibrary>
#include <QSet>
#include <QDebug>

#include "../logger/Logging.h"
#include "../QzCoreContext.h"
#include "AbstractPlugin.h"
#include "IPluginAdapter.h"
#include "PluginManager.h"
#include "AbstractPluginBundle.h"
#include "BundleEnv.h"

namespace Quartz {

struct BundleInfo
{
    BundleInfo()
        : m_bundle{ nullptr }
        , m_library{}
    {

    }

    BundleInfo( AbstractPluginBundle *bundle,
                std::shared_ptr< QLibrary > library )
        : m_bundle{ bundle }
        , m_library{ library }
    {

    }

    bool isValid() const
    {
        return ! ( m_bundle == nullptr || m_library == nullptr );
    }

    AbstractPluginBundle *m_bundle;

    std::shared_ptr< QLibrary > m_library;
};

using PluginMap = QHash< QString, std::shared_ptr< AbstractPlugin >>;
using AdapterMap = QHash< QString, std::shared_ptr< IPluginAdapter >>;
using BundleInfoMap = QHash< QString, BundleInfo >;

typedef PluginBundleWrapper ( *PluginFunc )( BundleInputWrapper * );
typedef void ( *BundleDestroyerFunc )();

static const char * PLUGIN_GET_FUNC_NAME = "getBundleWrapper";
static const char * BUNDLE_DESTROY_FUNC_NAME = "destroy";

class PluginManager::Impl
{
public:
    bool load( const QDir &dir );

    bool destroy();

    std::size_t loadBundles( const QDir &pluginRoot,
                             QZ_OUT BundleInfoMap &bundleInfoOut );

    BundleInfo getBundle( const QString &pluginRoot,
                          const QString &pluginFilePath );
    bool processBundles( const BundleInfo &bundleInfo,
                         const BundleInfoMap &loadedBundles,
                         QZ_OUT QSet< QString > &processedBundles );

    bool initBundle( AbstractPluginBundle *bundle );

    void registerPluginAdapter( std::shared_ptr< IPluginAdapter > adapter );

    PluginMap m_plugins;

    AdapterMap m_adapters;

    BundleInfoMap m_bundles;

    bool m_active;
};

bool PluginManager::Impl::load( const QDir &dir )
{
    bool result = true;
    auto dirList = dir.entryInfoList( QDir::Dirs | QDir::NoDotAndDotDot,
                                      QDir::SortFlag::NoSort );
    BundleInfoMap loadedBundles;
    foreach(const QFileInfo &info, dirList) {
        if( info.isReadable() ) {
            QDir pluginDir{ info.absoluteFilePath() };
            auto numLoaded = loadBundles( pluginDir, loadedBundles );
            QZ_DEBUG( "Qz:Core:Ext" )
                    << "Loaded " << numLoaded << " plugins from "
                    << info.absoluteFilePath();
        }
        else {
            QZ_WARN( "Qz:Core:Ext" ) << "Could not read plugin directory at "
                                     << info.absoluteFilePath();
            result = false;
        }
    }
    QSet< QString > processed;
    for( auto it = loadedBundles.begin(); it != loadedBundles.end(); ++ it ) {
        const auto &binfo = it.value();
        if( ! processed.contains( binfo.m_bundle->bundleId() )) {
            result = processBundles( binfo,
                                     loadedBundles,
                                     processed ) && result;
        }
    }
    //unload failed bundles
    for( auto it = loadedBundles.begin();
         it != loadedBundles.end();
         ++ it ) {
        auto &binfo = it.value();
        if( ! m_bundles.contains( binfo.m_bundle->bundleId() )) {
            auto lib = binfo.m_library;
            if( lib != nullptr ) {
                auto destroyFunc = reinterpret_cast< BundleDestroyerFunc >(
                            lib->resolve( BUNDLE_DESTROY_FUNC_NAME ));
                if( destroyFunc != nullptr ) {
                    destroyFunc();
                }
                else {
                    QZ_DEBUG( "Qz:Core:Ext" )
                            << "Could not find symbol for destroy function in "
                               " library: " << lib->fileName();
                }
                result = result && lib->unload();
            }
            QZ_DEBUG( "Qz:Core:Ext" )
                    << "Unloaded library for bundle with id " <<
                       binfo.m_bundle->bundleId()
                    << " which failed to initialize";
        }
        else {
            initBundle( binfo.m_bundle );
        }
    }
    return result;
}

std::size_t PluginManager::Impl::loadBundles(
        const QDir &bundleRoot,
        QZ_OUT BundleInfoMap &bundleInfoOut )
{
    QStringList extensions;
#ifdef Q_OS_LINUX
    extensions << "*.so";
#elif defined Q_OS_WIN
    extensions << "*.dll";
#else
    extensions << "*.dylib" << "*.so";
#endif

#ifdef QT_DEBUG
    QDir bundleDir{ bundleRoot.absoluteFilePath( "debug" )};
#else
//    QDir pluginDir{ dirInfo.absoluteFilePath() };
        QDir pluginDir = pluginRoot;
#endif
    std::size_t numLoaded = 0;
    QZ_DEBUG( "Qz:Core:Ext" )
            << "Searching for plugins at " << bundleDir.absolutePath();
    auto fileList = bundleDir.entryInfoList( extensions,
                                             QDir::Files,
                                             QDir::NoSort );
    foreach( const auto &info, fileList ) {
        if( info.fileName().startsWith( "plugin_" )
                || info.fileName().startsWith( "libplugin_" )) {

            auto binfo = getBundle( bundleRoot.absolutePath(),
                                    info.absoluteFilePath() );
            if( binfo.isValid() ) {
                bundleInfoOut.insert( binfo.m_bundle->bundleId(), binfo );
                ++ numLoaded;
            }
        }
    }
    return numLoaded;
}

BundleInfo PluginManager::Impl::getBundle( const QString &bundleRoot,
                                           const QString &bundleFilePath )
{
    auto lib = std::make_shared< QLibrary >( bundleFilePath );
    lib->load();
    BundleInfo binfo{};
    if( lib->isLoaded() ) {
        auto func = reinterpret_cast< PluginFunc >(
                    lib->resolve( PLUGIN_GET_FUNC_NAME ));
        if( func != nullptr ) {
            auto bundleEnv = std::unique_ptr< BundleEnv >{
                new BundleEnv{ bundleRoot, lib->fileName(), "0.1.0000" }};
            BundleInputWrapper input{ std::move( bundleEnv ),
                                      QzCoreContext::get() };
            auto bundle = func( &input ).bundle;
            if( bundle != nullptr ) {
                binfo = BundleInfo{ bundle, lib };
            }
            else {
                QZ_WARN( "Qz:Core:Ext" )
                        << "Library at " << bundleFilePath << " does not "
                           "contain any bundle, unloading...";
                lib->unload();
            }
        }
        else {
            lib->unload();
            QZ_ERROR( "Qz:Core:Ext" )
                    << "Plugin library at " << bundleFilePath  << " does "
                    << "not export entry point";
        }
    }
    else {
        QZ_ERROR( "Qz:Core:Ext" )
                << "Failed to load plugin library at " << bundleFilePath;
    }
    return binfo;
}

bool PluginManager::Impl::processBundles(
        const BundleInfo &bundleInfo,
        const BundleInfoMap &loadedBundles,
        QZ_OUT QSet< QString > &processedBundles )
{
    if( processedBundles.contains( bundleInfo.m_bundle->bundleId() )) {
        return true;
    }
    bool result = true;
    const auto &hardDeps = bundleInfo.m_bundle->dependencies();
    for( int i = 0; i < hardDeps.size(); ++ i ) {
        const auto & depEntry = hardDeps.at( i );
        auto depInfo = m_bundles.value( depEntry.first );
        if( depInfo.isValid() ) {
            result = processBundles( depInfo,
                                     loadedBundles,
                                     processedBundles );
        }
        else {
            result = false;
        }
        if( ! result && depEntry.second == DependencyType::Optional ) {
            QZ_DEBUG( "Qz:Core:Ext" )
                    << "Optional dependency " << depEntry.first << " for "
                    << bundleInfo.m_bundle->bundleId() << " not present, "
                       "hence ignored.";
            continue;
        }
        else if( ! result ) {
            QZ_ERROR( "Qz:Core:Ext" )
                    << "Could not initialize bundle with id "
                    << bundleInfo.m_bundle->bundleId()
                    << "; could not find required dependncy with id "
                    << depEntry.first;
            break;
        }

    }

    if( result ) {
        m_bundles.insert( bundleInfo.m_bundle->bundleId(), bundleInfo );
        QZ_DEBUG( "Qz:Core:Ext" )
                << "Successfuly processed bundle with id "
                << bundleInfo.m_bundle->bundleId();
    }
    processedBundles.insert( bundleInfo.m_bundle->bundleId() );

    return result;
}

bool PluginManager::Impl::initBundle( AbstractPluginBundle *bundle )
{
    const auto &adapters = bundle->adapters();
    for( int i = 0; i < adapters.size(); ++ i ) {
        const auto adapter = adapters.at( i );
        if( ! m_adapters.contains( adapter->pluginType() )) {
            m_adapters.insert( adapter->pluginType(), adapter );
        }
    }
    auto result = true;
    const auto plugins = bundle->plugins();
    for( int i = 0; i < plugins.size(); ++ i ) {
        auto plugin = plugins.at( i );

            auto adapter = m_adapters.value( plugin->pluginType() );
            if( adapter != nullptr ) {
                result = adapter->handlePlugin( plugin.get() );
            }
            else {
                QZ_ERROR( "Qz:Core:Ext" )
                        << "Could not find adapter for plugin type "
                        << plugin->pluginType() << ", required by plugin "
                        << plugin->pluginId() << ". Ignoring...";
                result = false;
            }
    }
    return result;
}

void PluginManager::Impl::registerPluginAdapter(
        std::shared_ptr< IPluginAdapter > adapter )
{
    if( adapter ) {
        m_adapters[ adapter->pluginType() ] = adapter;
    }
}

bool PluginManager::Impl::destroy()
{
    if( ! m_active ) {
        return false;
    }
    bool result = true;
    for( auto it = m_adapters.begin();
         it != m_adapters.end();
         ++ it ) {
        auto &handler = it.value();
        result = result && handler->finalizePlugins();
    }
    foreach( auto &bundle, m_bundles ) {
        auto lib = bundle.m_library;
        if( lib != nullptr ) {
            auto destroyFunc = reinterpret_cast< BundleDestroyerFunc >(
                        lib->resolve( BUNDLE_DESTROY_FUNC_NAME ));
            if( destroyFunc != nullptr ) {
                destroyFunc();
            }
            else {
                QZ_DEBUG( "Qz:Core:Ext" )
                        << "Could not find symbol for destroy function in "
                           " library: " << lib->fileName();
            }
            result = result && lib->unload();
        }
    }
    m_active = false;
    return result;
}

//========================== PluginManager ====================================
PluginManager::PluginManager()
//    : m_data( std::make_unique< PluginManager::Data >() )
    : m_impl( std::unique_ptr< Impl >( new Impl() ))
{

}

PluginManager::~PluginManager()
{
    destroy();
}

AbstractPlugin * PluginManager::plugin( const QString &id ) const
{
    auto &plugin = m_impl->m_plugins.value( id );
    return plugin.get();
}

IPluginAdapter * PluginManager::adapter( const QString &id ) const
{
    return m_impl->m_adapters.value(
                id, std::shared_ptr< IPluginAdapter >{} ).get();
}

void PluginManager::registerPluginAdapter(
        std::shared_ptr< IPluginAdapter > adapter )
{
    m_impl->registerPluginAdapter( adapter );
}

void PluginManager::registerPluginAdapter( IPluginAdapter *adapter )
{
    std::shared_ptr< IPluginAdapter > adptr{ adapter,
                                             []( IPluginAdapter *){ }};
    m_impl->registerPluginAdapter(  adptr );
}

bool PluginManager::loadFrom( const QString &location )
{
    bool result = false;
    QFileInfo info{ location };
    if( info.isDir() && info.isReadable() ) {
        result = m_impl->load( QDir{ location });
    }
    else {
        QZ_ERROR( "Qz:Core:Ext" )
                << "Invalid plugin root directory " << location << " given";
    }
    return result;
}

bool PluginManager::destroy()
{
    return m_impl->destroy();
}

}
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2015, Nagoya University
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  * Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 *
 *  * Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 *  * Neither the name of Autoware nor the names of its
 *    contributors may be used to endorse or promote products derived from
 *    this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 *  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 *  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 *  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 *  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <cstddef>
#include <cstring>

#include <sys/socket.h>

#include <udon_socket/udon.hpp>

namespace udon_socket {

namespace udon {

namespace {

constexpr std::int32_t TYPE_BEACON	= 0;
constexpr std::int32_t TYPE_MODE	= 3;
constexpr std::int32_t TYPE_LOCATION	= 6;

constexpr std::size_t SIZE_REQUEST	= 0x08;
constexpr std::size_t SIZE_RESPONSE	= 0x04;
constexpr std::size_t SIZE_MODE		= 0x08;
constexpr std::size_t SIZE_LOCATION	= 0x28;

constexpr std::ptrdiff_t OFFSET_TYPE		= 0x00;
constexpr std::ptrdiff_t OFFSET_VALUE		= 0x04;
constexpr std::ptrdiff_t OFFSET_LENGTH		= 0x04;
constexpr std::ptrdiff_t OFFSET_LOCATION_X	= 0x08;
constexpr std::ptrdiff_t OFFSET_LOCATION_Y	= 0x10;
constexpr std::ptrdiff_t OFFSET_LOCATION_Z	= 0x18;
constexpr std::ptrdiff_t OFFSET_LOCATION_D	= 0x20;

void set_type(std::uint8_t *buf, std::int32_t type)
{
	std::memcpy(buf + OFFSET_TYPE, &type, sizeof(type));
}

void set_value(std::uint8_t *buf, std::int32_t value)
{
	std::memcpy(buf + OFFSET_VALUE, &value, sizeof(value));
}

void set_length(std::uint8_t *buf, std::int32_t length)
{
	std::memcpy(buf + OFFSET_LENGTH, &length, sizeof(length));
}

void set_location_x(std::uint8_t *buf, double x)
{
	std::memcpy(buf + OFFSET_LOCATION_X, &x, sizeof(x));
}

void set_location_y(std::uint8_t *buf, double y)
{
	std::memcpy(buf + OFFSET_LOCATION_Y, &y, sizeof(y));
}

void set_location_z(std::uint8_t *buf, double z)
{
	std::memcpy(buf + OFFSET_LOCATION_Z, &z, sizeof(z));
}

void set_location_d(std::uint8_t *buf, double d)
{
	std::memcpy(buf + OFFSET_LOCATION_D, &d, sizeof(d));
}

} // namespace

bool Location::operator !=(const Location& location) const
{
	return !(x == location.x && y == location.y && z == location.z && d == location.d);
}

ssize_t send_request(int fd)
{
	std::uint8_t buf[SIZE_REQUEST];
	set_type(buf, TYPE_BEACON);
	set_value(buf, 0);

	return send(fd, &buf, sizeof(buf), 0);
}

ssize_t send_response(int fd)
{
	std::uint8_t buf[SIZE_RESPONSE];
	set_type(buf, TYPE_BEACON);

	return send(fd, &buf, sizeof(buf), 0);
}

ssize_t send_mode(int fd, std::int32_t mode)
{
	std::uint8_t buf[SIZE_MODE];
	set_type(buf, TYPE_MODE);
	set_value(buf, mode);

	return send(fd, &buf, sizeof(buf), 0);
}

ssize_t send_location(int fd, const Location& location)
{
	std::uint8_t buf[SIZE_LOCATION];
	set_type(buf, TYPE_LOCATION);
	set_length(buf, sizeof(double) * 4);
	set_location_x(buf, location.x);
	set_location_y(buf, location.y);
	set_location_z(buf, location.z);
	set_location_d(buf, location.d);

	return send(fd, &buf, sizeof(buf), 0);
}

} // namespace udon

} // namespace udon_socket
<commit_msg>Handle both STR and DRV mode as automatic cruise mode in udon_socket<commit_after>/*
 *  Copyright (c) 2015, Nagoya University
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  * Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 *
 *  * Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 *  * Neither the name of Autoware nor the names of its
 *    contributors may be used to endorse or promote products derived from
 *    this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 *  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 *  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 *  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 *  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <cstddef>
#include <cstring>

#include <sys/socket.h>

#include <udon_socket/udon.hpp>

namespace udon_socket {

namespace udon {

namespace {

constexpr std::int32_t TYPE_BEACON	= 0;
constexpr std::int32_t TYPE_MODE	= 3;
constexpr std::int32_t TYPE_LOCATION	= 6;

constexpr std::size_t SIZE_REQUEST	= 0x08;
constexpr std::size_t SIZE_RESPONSE	= 0x04;
constexpr std::size_t SIZE_MODE		= 0x08;
constexpr std::size_t SIZE_LOCATION	= 0x28;

constexpr std::ptrdiff_t OFFSET_TYPE		= 0x00;
constexpr std::ptrdiff_t OFFSET_VALUE		= 0x04;
constexpr std::ptrdiff_t OFFSET_LENGTH		= 0x04;
constexpr std::ptrdiff_t OFFSET_LOCATION_X	= 0x08;
constexpr std::ptrdiff_t OFFSET_LOCATION_Y	= 0x10;
constexpr std::ptrdiff_t OFFSET_LOCATION_Z	= 0x18;
constexpr std::ptrdiff_t OFFSET_LOCATION_D	= 0x20;

void set_type(std::uint8_t *buf, std::int32_t type)
{
	std::memcpy(buf + OFFSET_TYPE, &type, sizeof(type));
}

void set_value(std::uint8_t *buf, std::int32_t value)
{
	std::memcpy(buf + OFFSET_VALUE, &value, sizeof(value));
}

void set_length(std::uint8_t *buf, std::int32_t length)
{
	std::memcpy(buf + OFFSET_LENGTH, &length, sizeof(length));
}

void set_location_x(std::uint8_t *buf, double x)
{
	std::memcpy(buf + OFFSET_LOCATION_X, &x, sizeof(x));
}

void set_location_y(std::uint8_t *buf, double y)
{
	std::memcpy(buf + OFFSET_LOCATION_Y, &y, sizeof(y));
}

void set_location_z(std::uint8_t *buf, double z)
{
	std::memcpy(buf + OFFSET_LOCATION_Z, &z, sizeof(z));
}

void set_location_d(std::uint8_t *buf, double d)
{
	std::memcpy(buf + OFFSET_LOCATION_D, &d, sizeof(d));
}

} // namespace

bool Location::operator !=(const Location& location) const
{
	return !(x == location.x && y == location.y && z == location.z && d == location.d);
}

ssize_t send_request(int fd)
{
	std::uint8_t buf[SIZE_REQUEST];
	set_type(buf, TYPE_BEACON);
	set_value(buf, 0);

	return send(fd, &buf, sizeof(buf), 0);
}

ssize_t send_response(int fd)
{
	std::uint8_t buf[SIZE_RESPONSE];
	set_type(buf, TYPE_BEACON);

	return send(fd, &buf, sizeof(buf), 0);
}

ssize_t send_mode(int fd, std::int32_t mode)
{
	std::uint8_t buf[SIZE_MODE];
	set_type(buf, TYPE_MODE);
	set_value(buf, (mode > 0) ? 1:0);

	return send(fd, &buf, sizeof(buf), 0);
}

ssize_t send_location(int fd, const Location& location)
{
	std::uint8_t buf[SIZE_LOCATION];
	set_type(buf, TYPE_LOCATION);
	set_length(buf, sizeof(double) * 4);
	set_location_x(buf, location.x);
	set_location_y(buf, location.y);
	set_location_z(buf, location.z);
	set_location_d(buf, location.d);

	return send(fd, &buf, sizeof(buf), 0);
}

} // namespace udon

} // namespace udon_socket
<|endoftext|>


<commit_before>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "bucketdb.h"
#include <cassert>
#include <algorithm>

using document::GlobalId;
using storage::spi::BucketChecksum;

namespace proton {

BucketDB::BucketDB()
    : _map(),
      _cachedBucketId(),
      _cachedBucketState()
{
}

BucketDB::~BucketDB()
{
    checkEmpty();
    clear();
}

void
BucketDB::add(const BucketId &bucketId, const BucketState & state) {
    _map[bucketId] += state;
}

bucketdb::BucketState *
BucketDB::getBucketStatePtr(const BucketId &bucket)
{
    auto it(_map.find(bucket));
    if (it != _map.end()) {
        return &it->second;
    }
    return nullptr;
}

void
BucketDB::unloadBucket(const BucketId &bucket, const BucketState &delta)
{
    BucketState *state = getBucketStatePtr(bucket);
    assert(state);
    *state -= delta;
}

const bucketdb::BucketState &
BucketDB::add(const GlobalId &gid,
              const BucketId &bucketId, const Timestamp &timestamp, uint32_t docSize,
              SubDbType subDbType)
{
    BucketState &state = _map[bucketId];
    state.add(gid, timestamp, docSize, subDbType);
    return state;
}

void
BucketDB::remove(const GlobalId &gid,
                 const BucketId &bucketId, const Timestamp &timestamp, uint32_t docSize,
                 SubDbType subDbType)
{
    BucketState &state = _map[bucketId];
    state.remove(gid, timestamp, docSize, subDbType);
}

void
BucketDB::modify(const GlobalId &gid,
                 const BucketId &oldBucketId, const Timestamp &oldTimestamp, uint32_t oldDocSize,
                 const BucketId &newBucketId, const Timestamp &newTimestamp, uint32_t newDocSize,
                 SubDbType subDbType)
{
    if (oldBucketId == newBucketId) {
        BucketState &state = _map[oldBucketId];
        state.modify(gid, oldTimestamp, oldDocSize, newTimestamp, newDocSize, subDbType);
    } else {
        remove(gid, oldBucketId, oldTimestamp, oldDocSize, subDbType);
        add(gid, newBucketId, newTimestamp, newDocSize, subDbType);
    }
}

bucketdb::BucketState
BucketDB::get(const BucketId &bucketId) const
{
    auto itr = _map.find(bucketId);
    if (itr != _map.end()) {
        return itr->second;
    }
    return BucketState();
}

void
BucketDB::cacheBucket(const BucketId &bucketId)
{
    _cachedBucketId = bucketId;
    _cachedBucketState = get(bucketId);
}

void
BucketDB::uncacheBucket()
{
    _cachedBucketId = BucketId();
    _cachedBucketState = BucketState();
}

bool
BucketDB::isCachedBucket(const BucketId &bucketId) const
{
    return _cachedBucketId == bucketId;
}

bucketdb::BucketState
BucketDB::cachedGet(const BucketId &bucketId) const
{
    if (isCachedBucket(bucketId)) {
        return _cachedBucketState;
    }
    return get(bucketId);
}

bool
BucketDB::hasBucket(const BucketId &bucketId) const
{
    return (_map.find(bucketId) != _map.end());
}

bool
BucketDB::isActiveBucket(const BucketId &bucketId) const
{
    Map::const_iterator itr = _map.find(bucketId);
    if (itr != _map.end()) {
        return itr->second.isActive();
    }
    return false;
}

void
BucketDB::getBuckets(BucketId::List &buckets) const
{
    buckets.reserve(_map.size());
    for (const auto & entry : _map) {
        buckets.push_back(entry.first);
    }
}

bool
BucketDB::empty() const
{
    return _map.empty();
}

void
BucketDB::clear()
{
    _map.clear();
}

void
BucketDB::checkEmpty() const
{
    for (auto &entry : _map) {
        const BucketState &state = entry.second;
        assert(state.empty());
        (void) state;
    }
}

void
BucketDB::setBucketState(const BucketId &bucketId, bool active)
{
    BucketState &state = _map[bucketId];
    state.setActive(active);
}

void
BucketDB::createBucket(const BucketId &bucketId)
{
    BucketState &state = _map[bucketId];
    (void) state;
}

void
BucketDB::deleteEmptyBucket(const BucketId &bucketId)
{
    Map::iterator itr = _map.find(bucketId);
    if (itr == _map.end()) {
        return;
    }
    const BucketState &state = itr->second;
    if (state.empty()) {
        _map.erase(itr);
    }
}

void
BucketDB::getActiveBuckets(BucketId::List &buckets) const
{
    for (const auto & entry : _map) {
        if (entry.second.isActive()) {
            buckets.push_back(entry.first);
        }
    }
}

void
BucketDB::populateActiveBuckets(const BucketId::List &buckets,
                                BucketId::List &fixupBuckets)
{
    typedef BucketId::List BIV;
    BIV sorted(buckets);
    BIV toAdd;
    std::sort(sorted.begin(), sorted.end());
    BIV::const_iterator si(sorted.begin());
    BIV::const_iterator se(sorted.end());
    for (const auto & entry : _map) {
        for (; si != se && !(entry.first < *si); ++si) {
            if (*si < entry.first) {
                toAdd.push_back(*si);
            } else if (!entry.second.isActive()) {
                fixupBuckets.push_back(*si);
                setBucketState(*si, true);
            }
        }
    }
    for (; si != se; ++si) {
        toAdd.push_back(*si);
    }
    BucketState activeState;
    activeState.setActive(true);
    for (const BucketId & bucketId : toAdd) {
        InsertResult ins(_map.insert(std::make_pair(bucketId, activeState)));
        assert(ins.second);
    }
}

}
<commit_msg>Simplify with emplace and auto<commit_after>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "bucketdb.h"
#include <cassert>
#include <algorithm>

using document::GlobalId;
using storage::spi::BucketChecksum;

namespace proton {

BucketDB::BucketDB()
    : _map(),
      _cachedBucketId(),
      _cachedBucketState()
{
}

BucketDB::~BucketDB()
{
    checkEmpty();
    clear();
}

void
BucketDB::add(const BucketId &bucketId, const BucketState & state) {
    _map[bucketId] += state;
}

bucketdb::BucketState *
BucketDB::getBucketStatePtr(const BucketId &bucket)
{
    auto it(_map.find(bucket));
    if (it != _map.end()) {
        return &it->second;
    }
    return nullptr;
}

void
BucketDB::unloadBucket(const BucketId &bucket, const BucketState &delta)
{
    BucketState *state = getBucketStatePtr(bucket);
    assert(state);
    *state -= delta;
}

const bucketdb::BucketState &
BucketDB::add(const GlobalId &gid,
              const BucketId &bucketId, const Timestamp &timestamp, uint32_t docSize,
              SubDbType subDbType)
{
    BucketState &state = _map[bucketId];
    state.add(gid, timestamp, docSize, subDbType);
    return state;
}

void
BucketDB::remove(const GlobalId &gid,
                 const BucketId &bucketId, const Timestamp &timestamp, uint32_t docSize,
                 SubDbType subDbType)
{
    BucketState &state = _map[bucketId];
    state.remove(gid, timestamp, docSize, subDbType);
}

void
BucketDB::modify(const GlobalId &gid,
                 const BucketId &oldBucketId, const Timestamp &oldTimestamp, uint32_t oldDocSize,
                 const BucketId &newBucketId, const Timestamp &newTimestamp, uint32_t newDocSize,
                 SubDbType subDbType)
{
    if (oldBucketId == newBucketId) {
        BucketState &state = _map[oldBucketId];
        state.modify(gid, oldTimestamp, oldDocSize, newTimestamp, newDocSize, subDbType);
    } else {
        remove(gid, oldBucketId, oldTimestamp, oldDocSize, subDbType);
        add(gid, newBucketId, newTimestamp, newDocSize, subDbType);
    }
}

bucketdb::BucketState
BucketDB::get(const BucketId &bucketId) const
{
    auto itr = _map.find(bucketId);
    if (itr != _map.end()) {
        return itr->second;
    }
    return BucketState();
}

void
BucketDB::cacheBucket(const BucketId &bucketId)
{
    _cachedBucketId = bucketId;
    _cachedBucketState = get(bucketId);
}

void
BucketDB::uncacheBucket()
{
    _cachedBucketId = BucketId();
    _cachedBucketState = BucketState();
}

bool
BucketDB::isCachedBucket(const BucketId &bucketId) const
{
    return _cachedBucketId == bucketId;
}

bucketdb::BucketState
BucketDB::cachedGet(const BucketId &bucketId) const
{
    if (isCachedBucket(bucketId)) {
        return _cachedBucketState;
    }
    return get(bucketId);
}

bool
BucketDB::hasBucket(const BucketId &bucketId) const
{
    return (_map.find(bucketId) != _map.end());
}

bool
BucketDB::isActiveBucket(const BucketId &bucketId) const
{
    auto itr = _map.find(bucketId);
    return (itr != _map.end()) && itr->second.isActive();
}

void
BucketDB::getBuckets(BucketId::List &buckets) const
{
    buckets.reserve(_map.size());
    for (const auto & entry : _map) {
        buckets.push_back(entry.first);
    }
}

bool
BucketDB::empty() const
{
    return _map.empty();
}

void
BucketDB::clear()
{
    _map.clear();
}

void
BucketDB::checkEmpty() const
{
    for (auto &entry : _map) {
        const BucketState &state = entry.second;
        assert(state.empty());
        (void) state;
    }
}

void
BucketDB::setBucketState(const BucketId &bucketId, bool active)
{
    BucketState &state = _map[bucketId];
    state.setActive(active);
}

void
BucketDB::createBucket(const BucketId &bucketId)
{
    BucketState &state = _map[bucketId];
    (void) state;
}

void
BucketDB::deleteEmptyBucket(const BucketId &bucketId)
{
    auto itr = _map.find(bucketId);
    if (itr == _map.end()) {
        return;
    }
    const BucketState &state = itr->second;
    if (state.empty()) {
        _map.erase(itr);
    }
}

void
BucketDB::getActiveBuckets(BucketId::List &buckets) const
{
    for (const auto & entry : _map) {
        if (entry.second.isActive()) {
            buckets.push_back(entry.first);
        }
    }
}

void
BucketDB::populateActiveBuckets(const BucketId::List &buckets, BucketId::List &fixupBuckets)
{
    typedef BucketId::List BIV;
    BIV sorted(buckets);
    BIV toAdd;
    std::sort(sorted.begin(), sorted.end());
    BIV::const_iterator si(sorted.begin());
    BIV::const_iterator se(sorted.end());
    for (const auto & entry : _map) {
        for (; si != se && !(entry.first < *si); ++si) {
            if (*si < entry.first) {
                toAdd.push_back(*si);
            } else if (!entry.second.isActive()) {
                fixupBuckets.push_back(*si);
                setBucketState(*si, true);
            }
        }
    }
    for (; si != se; ++si) {
        toAdd.push_back(*si);
    }
    BucketState activeState;
    activeState.setActive(true);
    for (const BucketId & bucketId : toAdd) {
        InsertResult ins(_map.emplace(bucketId, activeState));
        assert(ins.second);
    }
}

}
<|endoftext|>


<commit_before>//
// Copyright (c) 2017 The nanoFramework project contributors
// Portions Copyright (c) Microsoft Corporation.  All rights reserved.
// See LICENSE file in the project root for full license information.
//
#include "CorLib.h"

HRESULT Library_corlib_native_System_Reflection_FieldInfo::SetValue___VOID__OBJECT__OBJECT( CLR_RT_StackFrame& stack )
{
    NATIVE_PROFILE_CLR_CORE();
    NANOCLR_HEADER();

    CLR_RT_FieldDef_Instance   instFD;
    CLR_RT_TypeDef_Instance    instTD;
    CLR_RT_TypeDescriptor      instTDescObj;
    CLR_RT_TypeDef_Instance    instTDField;
    const CLR_RECORD_FIELDDEF* fd;
    CLR_RT_HeapBlock*          obj;
    bool                       fValueType;
    CLR_RT_HeapBlock&          srcVal = stack.Arg2();
    CLR_RT_HeapBlock           val; val.Assign( srcVal );
    CLR_RT_ProtectFromGC       gc( val );

    NANOCLR_CHECK_HRESULT(Library_corlib_native_System_Reflection_FieldInfo::Initialize( stack, instFD, instTD, obj ));

    fd = instFD.m_target;

    if(fd->flags & CLR_RECORD_FIELDDEF::FD_NoReflection) // don't allow reflection for fields with NoReflection attribute
    {
        NANOCLR_SET_AND_LEAVE(CLR_E_NOT_SUPPORTED);
    }

    NANOCLR_CHECK_HRESULT(instTDescObj.InitializeFromFieldDefinition(instFD));

    // make sure the right side object is of the same type as the left side
    if(NULL != val.Dereference() && !CLR_RT_ExecutionEngine::IsInstanceOf(val, instTDescObj.m_handlerCls)) NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE);

    fValueType = obj->IsAValueType();
    if(fValueType || (c_CLR_RT_DataTypeLookup[ obj->DataType() ].m_flags & CLR_RT_DataTypeLookup::c_OptimizedValueType))
    {
        if(val.Dereference() == NULL || !val.Dereference()->IsBoxed()) NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE);

        if(fValueType)
        {
            _ASSERTE(NULL != obj->Dereference());
            if(NULL == obj->Dereference()) NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER);
            instTDField.InitializeFromIndex( obj->Dereference()->ObjectCls() );
        }
        else
        {
            instTDField.InitializeFromIndex( *c_CLR_RT_DataTypeLookup[ obj->DataType() ].m_cls );
        }

        NANOCLR_CHECK_HRESULT(val.PerformUnboxing( instTDField ));
    }
    else
    {
#if defined(NANOCLR_APPDOMAINS)
        CLR_RT_HeapBlock&          srcObj = stack.Arg1();

        if(srcObj.IsTransparentProxy())
        {
            _ASSERTE(srcObj.DataType() == DATATYPE_OBJECT);
            _ASSERTE(srcObj.Dereference() != NULL && srcObj.Dereference()->DataType() == DATATYPE_TRANSPARENT_PROXY);

            NANOCLR_CHECK_HRESULT(srcObj.Dereference()->TransparentProxyValidate());
            NANOCLR_CHECK_HRESULT(srcObj.Dereference()->TransparentProxyAppDomain()->MarshalObject( val, val ));
        }
#endif
    }

    switch(obj->DataType())
    {
        case DATATYPE_DATETIME: // Special case.
        case DATATYPE_TIMESPAN: // Special case.
            obj->NumericByRef().s8 = val.NumericByRefConst().s8;
            break;

        default:
            obj->Assign( val );
            break;
    }

    NANOCLR_NOCLEANUP();
}

//--//

HRESULT Library_corlib_native_System_Reflection_FieldInfo::Initialize( CLR_RT_StackFrame& stack, CLR_RT_FieldDef_Instance& instFD, CLR_RT_TypeDef_Instance& instTD, CLR_RT_HeapBlock*& obj )
{
    NATIVE_PROFILE_CLR_CORE();
    NANOCLR_HEADER();
    CLR_RT_HeapBlock* hbField = stack.Arg0().Dereference();

    if(CLR_RT_ReflectionDef_Index::Convert( *hbField, instFD ) == false ||
       instTD.InitializeFromField         (           instFD ) == false  )
    {
        NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE);
    }

    if(instFD.m_target->flags & CLR_RECORD_FIELDDEF::FD_Static)
    {
        obj = CLR_RT_ExecutionEngine::AccessStaticField( instFD );

        if(obj == NULL) NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE);
    }
    else
    {
        NANOCLR_CHECK_HRESULT(stack.Arg1().EnsureObjectReference( obj ));

        if(CLR_RT_ExecutionEngine::IsInstanceOf( *obj, instTD ) == false)
        {
            NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE);
        }

        obj = &obj[ instFD.CrossReference().m_offset ];
    }

    NANOCLR_NOCLEANUP();
}

HRESULT Library_corlib_native_System_Reflection_FieldInfo::GetCustomAttributes___SZARRAY_OBJECT__BOOLEAN( CLR_RT_StackFrame& stack )
{
    NANOCLR_HEADER();

    NANOCLR_SET_AND_LEAVE(stack.NotImplementedStub());

    NANOCLR_NOCLEANUP();
}
<commit_msg>Add implementation of GetCustomAttributes for fields (#1394)<commit_after>//
// Copyright (c) 2017 The nanoFramework project contributors
// Portions Copyright (c) Microsoft Corporation.  All rights reserved.
// See LICENSE file in the project root for full license information.
//
#include "CorLib.h"

HRESULT Library_corlib_native_System_Reflection_FieldInfo::SetValue___VOID__OBJECT__OBJECT( CLR_RT_StackFrame& stack )
{
    NATIVE_PROFILE_CLR_CORE();
    NANOCLR_HEADER();

    CLR_RT_FieldDef_Instance   instFD;
    CLR_RT_TypeDef_Instance    instTD;
    CLR_RT_TypeDescriptor      instTDescObj;
    CLR_RT_TypeDef_Instance    instTDField;
    const CLR_RECORD_FIELDDEF* fd;
    CLR_RT_HeapBlock*          obj;
    bool                       fValueType;
    CLR_RT_HeapBlock&          srcVal = stack.Arg2();
    CLR_RT_HeapBlock           val; val.Assign( srcVal );
    CLR_RT_ProtectFromGC       gc( val );

    NANOCLR_CHECK_HRESULT(Library_corlib_native_System_Reflection_FieldInfo::Initialize( stack, instFD, instTD, obj ));

    fd = instFD.m_target;

    if(fd->flags & CLR_RECORD_FIELDDEF::FD_NoReflection) // don't allow reflection for fields with NoReflection attribute
    {
        NANOCLR_SET_AND_LEAVE(CLR_E_NOT_SUPPORTED);
    }

    NANOCLR_CHECK_HRESULT(instTDescObj.InitializeFromFieldDefinition(instFD));

    // make sure the right side object is of the same type as the left side
    if(NULL != val.Dereference() && !CLR_RT_ExecutionEngine::IsInstanceOf(val, instTDescObj.m_handlerCls)) NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE);

    fValueType = obj->IsAValueType();
    if(fValueType || (c_CLR_RT_DataTypeLookup[ obj->DataType() ].m_flags & CLR_RT_DataTypeLookup::c_OptimizedValueType))
    {
        if(val.Dereference() == NULL || !val.Dereference()->IsBoxed()) NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE);

        if(fValueType)
        {
            _ASSERTE(NULL != obj->Dereference());
            if(NULL == obj->Dereference()) NANOCLR_SET_AND_LEAVE(CLR_E_INVALID_PARAMETER);
            instTDField.InitializeFromIndex( obj->Dereference()->ObjectCls() );
        }
        else
        {
            instTDField.InitializeFromIndex( *c_CLR_RT_DataTypeLookup[ obj->DataType() ].m_cls );
        }

        NANOCLR_CHECK_HRESULT(val.PerformUnboxing( instTDField ));
    }
    else
    {
#if defined(NANOCLR_APPDOMAINS)
        CLR_RT_HeapBlock&          srcObj = stack.Arg1();

        if(srcObj.IsTransparentProxy())
        {
            _ASSERTE(srcObj.DataType() == DATATYPE_OBJECT);
            _ASSERTE(srcObj.Dereference() != NULL && srcObj.Dereference()->DataType() == DATATYPE_TRANSPARENT_PROXY);

            NANOCLR_CHECK_HRESULT(srcObj.Dereference()->TransparentProxyValidate());
            NANOCLR_CHECK_HRESULT(srcObj.Dereference()->TransparentProxyAppDomain()->MarshalObject( val, val ));
        }
#endif
    }

    switch(obj->DataType())
    {
        case DATATYPE_DATETIME: // Special case.
        case DATATYPE_TIMESPAN: // Special case.
            obj->NumericByRef().s8 = val.NumericByRefConst().s8;
            break;

        default:
            obj->Assign( val );
            break;
    }

    NANOCLR_NOCLEANUP();
}

//--//

HRESULT Library_corlib_native_System_Reflection_FieldInfo::Initialize( CLR_RT_StackFrame& stack, CLR_RT_FieldDef_Instance& instFD, CLR_RT_TypeDef_Instance& instTD, CLR_RT_HeapBlock*& obj )
{
    NATIVE_PROFILE_CLR_CORE();
    NANOCLR_HEADER();
    CLR_RT_HeapBlock* hbField = stack.Arg0().Dereference();

    if(CLR_RT_ReflectionDef_Index::Convert( *hbField, instFD ) == false ||
       instTD.InitializeFromField         (           instFD ) == false  )
    {
        NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE);
    }

    if(instFD.m_target->flags & CLR_RECORD_FIELDDEF::FD_Static)
    {
        obj = CLR_RT_ExecutionEngine::AccessStaticField( instFD );

        if(obj == NULL) NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE);
    }
    else
    {
        NANOCLR_CHECK_HRESULT(stack.Arg1().EnsureObjectReference( obj ));

        if(CLR_RT_ExecutionEngine::IsInstanceOf( *obj, instTD ) == false)
        {
            NANOCLR_SET_AND_LEAVE(CLR_E_WRONG_TYPE);
        }

        obj = &obj[ instFD.CrossReference().m_offset ];
    }

    NANOCLR_NOCLEANUP();
}

HRESULT Library_corlib_native_System_Reflection_FieldInfo::GetCustomAttributes___SZARRAY_OBJECT__BOOLEAN( CLR_RT_StackFrame& stack )
{
    NANOCLR_HEADER();

    CLR_RT_HeapBlock*           callerField;
    CLR_RT_HeapBlock*           returnArray = NULL;
    CLR_RT_FieldDef_Instance    fieldDefinition;
    int count = 0;

    // put the return array on the stack
    CLR_RT_HeapBlock& top = stack.PushValueAndClear();

    // get the caller field
    callerField = stack.Arg0().Dereference();

    NANOCLR_CHECK_HRESULT(Library_corlib_native_System_Reflection_RuntimeFieldInfo::GetFieldDescriptor( stack, *callerField, fieldDefinition ));

    // setup attribute enumerator
    CLR_RT_AttributeEnumerator attributeEnumerator;
    attributeEnumerator.Initialize( fieldDefinition );

    // 1st pass: count attributes
    do
    {
        // move to the next attribute in the collection, if any
        if(attributeEnumerator.Advance())
        {
            count++;
        }
        else
        {
            // done sweeping attributes

            // create the result array
            NANOCLR_CHECK_HRESULT(CLR_RT_HeapBlock_Array::CreateInstance( top, count, g_CLR_RT_WellKnownTypes.m_TypeStatic ));

            // use this to skip the 2nd pass if no attribute was found
            if (count == 0) break;

            // get the pointer to the first element
            returnArray = (CLR_RT_HeapBlock*)top.DereferenceArray()->GetFirstElement();

            // reset attribute enumerator
            attributeEnumerator.Initialize( fieldDefinition );

            break;
        }
    }
    while(true);

    // 2nd pass: fill the array with the attributes types, if any
    while(count > 0)
    {
        // move to the next attribute in the collection, if any
        if(attributeEnumerator.Advance())
        {
            CLR_RT_TypeDef_Instance instanceTypeDef;
            CLR_RT_HeapBlock*     hbObj;

            // get the type def for the current attribute
            attributeEnumerator.GetCurrent(&instanceTypeDef);

            CLR_RT_TypeDef_Index attributeType;
            attributeType.Set(instanceTypeDef.Assembly(), instanceTypeDef.Type());

            // create a new object for the attribute type and put it on the return array
            NANOCLR_CHECK_HRESULT(g_CLR_RT_ExecutionEngine.NewObjectFromIndex(*returnArray, g_CLR_RT_WellKnownTypes.m_TypeStatic));
            hbObj = returnArray->Dereference();
            // make sure the reflection is pointing to the attribute type
            hbObj->SetReflection( attributeType );

            returnArray++;
            count--;
        }
        else
        {
            // no more attributes
            break;
        }
    }

    NANOCLR_NOCLEANUP();
}
<|endoftext|>


<commit_before>#ifndef UPDATE_RULE_AMS_SIMD_HPP
#define UPDATE_RULE_AMS_SIMD_HPP

#include <vector>
#include <limits>
#include <string>
#include <mipp.h>

#include "Tools/Math/max.h"

namespace aff3ct
{
namespace tools
{
template <typename R = float, proto_min_i<R> MIN = min_star_linear2_i>
class Update_rule_AMS_simd // Approximate Min Star
{
protected:
	const std::string name;
	const mipp::Msk<mipp::N<R>()> false_msk;
	const mipp::Reg<R> max;
	const mipp::Reg<R> zero;
	mipp::Msk<mipp::N<R>()> sign;
	mipp::Reg<R> min;
	mipp::Reg<R> delta_min;
	mipp::Reg<R> delta;

	int n_ite;
	int ite;

public:
	Update_rule_AMS_simd()
	: name("AMS"), false_msk(false), max(std::numeric_limits<R>::max()), zero((R)0), sign(false), min(max),
	  delta_min(max), delta(max), n_ite(0), ite(0)
	{
	}

	virtual ~Update_rule_AMS_simd()
	{
	}

	std::string get_name() const
	{
		return this->name;
	}

	// ----------------------------------------------------------------------------------------------------------------
	// ----------------------------------------------------------------------------------------------------------------

	inline void begin_decoding(const int n_ite)
	{
		this->n_ite = n_ite;
	}

	inline void begin_ite(const int ite)
	{
		this->ite = ite;
	}

	// incoming values from the variable nodes into the check nodes
	inline void begin_chk_node_in(const int chk_id, const int chk_degree)
	{
		assert(chk_degree <= (int)this->values.size());

		this->sign      = this->false_msk;
		this->min       = this->max;
		this->delta_min = this->max;
	}

	inline void compute_chk_node_in(const int var_id, const mipp::Reg<R> var_val)
	{
		const auto var_abs = mipp::abs(var_val);
		const auto var_sgn = mipp::sign(var_val);
		const auto tmp     = this->min;

		this->sign     ^= var_sgn;
		this->min       = mipp::min(this->min, var_abs);
		this->delta_min = MIN(this->delta_min, mipp::blend(tmp, var_abs, var_abs == this->min));
	}

	inline void end_chk_node_in()
	{
		this->delta     = mipp::max(zero, MIN(this->delta_min, this->min));
		this->delta_min = mipp::max(zero, this->delta_min);
	}

	// outcomming values from the check nodes into the variable nodes
	inline void begin_chk_node_out(const int chk_id, const int chk_degree)
	{
	}

	inline mipp::Reg<R> compute_chk_node_out(const int var_id, const mipp::Reg<R> var_val)
	{
		const auto var_abs = mipp::abs(var_val);
		      auto res_abs = mipp::blend(this->delta_min, this->delta, var_abs == this->min);
		const auto res_sgn = this->sign ^ mipp::sign(var_val);

		return mipp::copysign(res_abs, res_sgn);
	}

	inline void end_chk_node_out()
	{
	}

	inline void end_ite()
	{
	}

	inline void end_decoding()
	{
	}
};
}
}

#endif /* UPDATE_RULE_AMS_SIMD_HPP */
<commit_msg>Fix compilation error.<commit_after>#ifndef UPDATE_RULE_AMS_SIMD_HPP
#define UPDATE_RULE_AMS_SIMD_HPP

#include <vector>
#include <limits>
#include <string>
#include <mipp.h>

#include "Tools/Math/max.h"

namespace aff3ct
{
namespace tools
{
template <typename R = float, proto_min_i<R> MIN = min_star_linear2_i>
class Update_rule_AMS_simd // Approximate Min Star
{
protected:
	const std::string name;
	const mipp::Msk<mipp::N<R>()> false_msk;
	const mipp::Reg<R> max;
	const mipp::Reg<R> zero;
	mipp::Msk<mipp::N<R>()> sign;
	mipp::Reg<R> min;
	mipp::Reg<R> delta_min;
	mipp::Reg<R> delta;

	int n_ite;
	int ite;

public:
	Update_rule_AMS_simd()
	: name("AMS"), false_msk(false), max(std::numeric_limits<R>::max()), zero((R)0), sign(false), min(max),
	  delta_min(max), delta(max), n_ite(0), ite(0)
	{
	}

	virtual ~Update_rule_AMS_simd()
	{
	}

	std::string get_name() const
	{
		return this->name;
	}

	// ----------------------------------------------------------------------------------------------------------------
	// ----------------------------------------------------------------------------------------------------------------

	inline void begin_decoding(const int n_ite)
	{
		this->n_ite = n_ite;
	}

	inline void begin_ite(const int ite)
	{
		this->ite = ite;
	}

	// incoming values from the variable nodes into the check nodes
	inline void begin_chk_node_in(const int chk_id, const int chk_degree)
	{
		this->sign      = this->false_msk;
		this->min       = this->max;
		this->delta_min = this->max;
	}

	inline void compute_chk_node_in(const int var_id, const mipp::Reg<R> var_val)
	{
		const auto var_abs = mipp::abs(var_val);
		const auto var_sgn = mipp::sign(var_val);
		const auto tmp     = this->min;

		this->sign     ^= var_sgn;
		this->min       = mipp::min(this->min, var_abs);
		this->delta_min = MIN(this->delta_min, mipp::blend(tmp, var_abs, var_abs == this->min));
	}

	inline void end_chk_node_in()
	{
		this->delta     = mipp::max(zero, MIN(this->delta_min, this->min));
		this->delta_min = mipp::max(zero, this->delta_min);
	}

	// outcomming values from the check nodes into the variable nodes
	inline void begin_chk_node_out(const int chk_id, const int chk_degree)
	{
	}

	inline mipp::Reg<R> compute_chk_node_out(const int var_id, const mipp::Reg<R> var_val)
	{
		const auto var_abs = mipp::abs(var_val);
		      auto res_abs = mipp::blend(this->delta_min, this->delta, var_abs == this->min);
		const auto res_sgn = this->sign ^ mipp::sign(var_val);

		return mipp::copysign(res_abs, res_sgn);
	}

	inline void end_chk_node_out()
	{
	}

	inline void end_ite()
	{
	}

	inline void end_decoding()
	{
	}
};
}
}

#endif /* UPDATE_RULE_AMS_SIMD_HPP */
<|endoftext|>


<commit_before>
//
// This source file is part of appleseed.
// Visit http://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2010-2013 Francois Beaune, Jupiter Jazz Limited
// Copyright (c) 2014-2015 Francois Beaune, The appleseedhq Organization
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

// Interface header.
#include "genericmaterial.h"

// appleseed.renderer headers.
#include "renderer/modeling/material/material.h"

// appleseed.foundation headers.
#include "foundation/utility/containers/dictionary.h"
#include "foundation/utility/containers/specializedarrays.h"

using namespace foundation;

namespace renderer
{

namespace
{
    //
    // Generic Material.
    //

    const char* Model = "generic_material";

    class GenericMaterial
      : public Material
    {
      public:
        GenericMaterial(
            const char*                 name,
            const ParamArray&           params)
          : Material(name, params)
        {
            m_inputs.declare("bsdf", InputFormatEntity, "");
            m_inputs.declare("edf", InputFormatEntity, "");
            m_inputs.declare("alpha_map", InputFormatScalar, "");
            m_inputs.declare("displacement_map", InputFormatSpectralReflectance, "");
        }

        virtual void release() APPLESEED_OVERRIDE
        {
            delete this;
        }

        virtual const char* get_model() const APPLESEED_OVERRIDE
        {
            return Model;
        }

        virtual bool on_frame_begin(
            const Project&              project,
            const Assembly&             assembly,
            foundation::IAbortSwitch*   abort_switch = 0) APPLESEED_OVERRIDE
        {
            if (!Material::on_frame_begin(project, assembly, abort_switch))
                return false;

            m_bsdf = get_uncached_bsdf();
            m_edf = get_uncached_edf();

            const EntityDefMessageContext context("material", this);
            if (!create_basis_modifier(context))
                return false;

            if (m_edf && m_alpha_map)
            {
                RENDERER_LOG_WARNING(
                    "%s: material is emitting light but may be partially or entirely transparent; "
                    "this may lead to unexpected or unphysical results.",
                    context.get());
            }

            return true;
        }

        virtual void on_frame_end(
            const Project&              project,
            const Assembly&             assembly) APPLESEED_OVERRIDE
        {
            Material::on_frame_end(project, assembly);
        }
    };
}

//
// GenericMaterialFactory class implementation.
//

const char* GenericMaterialFactory::get_model() const
{
    return Model;
}

const char* GenericMaterialFactory::get_human_readable_model() const
{
    return "Generic Material";
}

DictionaryArray GenericMaterialFactory::get_input_metadata() const
{
    DictionaryArray metadata;

    add_common_input_metadata(metadata);

    metadata.push_back(
        Dictionary()
            .insert("name", "bsdf")
            .insert("label", "BSDF")
            .insert("type", "entity")
            .insert("entity_types", Dictionary().insert("bsdf", "BSDF"))
            .insert("use", "optional"));

    metadata.push_back(
        Dictionary()
            .insert("name", "edf")
            .insert("label", "EDF")
            .insert("type", "entity")
            .insert("entity_types", Dictionary().insert("edf", "EDF"))
            .insert("use", "optional"));

    metadata.push_back(
        Dictionary()
            .insert("name", "alpha_map")
            .insert("label", "Alpha Map")
            .insert("type", "colormap")
            .insert("entity_types",
                Dictionary()
                    .insert("color", "Colors")
                    .insert("texture_instance", "Textures"))
            .insert("use", "optional"));

    metadata.push_back(
        Dictionary()
            .insert("name", "displacement_map")
            .insert("label", "Displacement Map")
            .insert("type", "colormap")
            .insert("entity_types",
                Dictionary().insert("texture_instance", "Textures"))
            .insert("use", "optional"));

    metadata.push_back(
        Dictionary()
            .insert("name", "displacement_method")
            .insert("label", "Displacement Method")
            .insert("type", "enumeration")
            .insert("items",
                Dictionary()
                    .insert("Bump Mapping", "bump")
                    .insert("Normal Mapping", "normal"))
            .insert("use", "required")
            .insert("default", "bump"));

    metadata.push_back(
        Dictionary()
            .insert("name", "bump_amplitude")
            .insert("label", "Bump Amplitude")
            .insert("type", "text")
            .insert("use", "optional")
            .insert("default", "1.0"));

    metadata.push_back(
        Dictionary()
            .insert("name", "normal_map_up")
            .insert("label", "Normal Map Up Vector")
            .insert("type", "enumeration")
            .insert("items",
                Dictionary()
                    .insert("Green Channel (Y)", "y")
                    .insert("Blue Channel (Z)", "z"))
            .insert("use", "optional")
            .insert("default", "z"));

    return metadata;
}

auto_release_ptr<Material> GenericMaterialFactory::create(
    const char*         name,
    const ParamArray&   params) const
{
    return
        auto_release_ptr<Material>(
            new GenericMaterial(name, params));
}

}   // namespace renderer
<commit_msg>bump amplitude is now a numeric widget.<commit_after>
//
// This source file is part of appleseed.
// Visit http://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2010-2013 Francois Beaune, Jupiter Jazz Limited
// Copyright (c) 2014-2015 Francois Beaune, The appleseedhq Organization
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

// Interface header.
#include "genericmaterial.h"

// appleseed.renderer headers.
#include "renderer/modeling/material/material.h"

// appleseed.foundation headers.
#include "foundation/utility/containers/dictionary.h"
#include "foundation/utility/containers/specializedarrays.h"

using namespace foundation;

namespace renderer
{

namespace
{
    //
    // Generic Material.
    //

    const char* Model = "generic_material";

    class GenericMaterial
      : public Material
    {
      public:
        GenericMaterial(
            const char*                 name,
            const ParamArray&           params)
          : Material(name, params)
        {
            m_inputs.declare("bsdf", InputFormatEntity, "");
            m_inputs.declare("edf", InputFormatEntity, "");
            m_inputs.declare("alpha_map", InputFormatScalar, "");
            m_inputs.declare("displacement_map", InputFormatSpectralReflectance, "");
        }

        virtual void release() APPLESEED_OVERRIDE
        {
            delete this;
        }

        virtual const char* get_model() const APPLESEED_OVERRIDE
        {
            return Model;
        }

        virtual bool on_frame_begin(
            const Project&              project,
            const Assembly&             assembly,
            foundation::IAbortSwitch*   abort_switch = 0) APPLESEED_OVERRIDE
        {
            if (!Material::on_frame_begin(project, assembly, abort_switch))
                return false;

            m_bsdf = get_uncached_bsdf();
            m_edf = get_uncached_edf();

            const EntityDefMessageContext context("material", this);
            if (!create_basis_modifier(context))
                return false;

            if (m_edf && m_alpha_map)
            {
                RENDERER_LOG_WARNING(
                    "%s: material is emitting light but may be partially or entirely transparent; "
                    "this may lead to unexpected or unphysical results.",
                    context.get());
            }

            return true;
        }

        virtual void on_frame_end(
            const Project&              project,
            const Assembly&             assembly) APPLESEED_OVERRIDE
        {
            Material::on_frame_end(project, assembly);
        }
    };
}

//
// GenericMaterialFactory class implementation.
//

const char* GenericMaterialFactory::get_model() const
{
    return Model;
}

const char* GenericMaterialFactory::get_human_readable_model() const
{
    return "Generic Material";
}

DictionaryArray GenericMaterialFactory::get_input_metadata() const
{
    DictionaryArray metadata;

    add_common_input_metadata(metadata);

    metadata.push_back(
        Dictionary()
            .insert("name", "bsdf")
            .insert("label", "BSDF")
            .insert("type", "entity")
            .insert("entity_types", Dictionary().insert("bsdf", "BSDF"))
            .insert("use", "optional"));

    metadata.push_back(
        Dictionary()
            .insert("name", "edf")
            .insert("label", "EDF")
            .insert("type", "entity")
            .insert("entity_types", Dictionary().insert("edf", "EDF"))
            .insert("use", "optional"));

    metadata.push_back(
        Dictionary()
            .insert("name", "alpha_map")
            .insert("label", "Alpha Map")
            .insert("type", "colormap")
            .insert("entity_types",
                Dictionary()
                    .insert("color", "Colors")
                    .insert("texture_instance", "Textures"))
            .insert("use", "optional"));

    metadata.push_back(
        Dictionary()
            .insert("name", "displacement_map")
            .insert("label", "Displacement Map")
            .insert("type", "colormap")
            .insert("entity_types",
                Dictionary().insert("texture_instance", "Textures"))
            .insert("use", "optional"));

    metadata.push_back(
        Dictionary()
            .insert("name", "displacement_method")
            .insert("label", "Displacement Method")
            .insert("type", "enumeration")
            .insert("items",
                Dictionary()
                    .insert("Bump Mapping", "bump")
                    .insert("Normal Mapping", "normal"))
            .insert("use", "required")
            .insert("default", "bump"));

    metadata.push_back(
        Dictionary()
            .insert("name", "bump_amplitude")
            .insert("label", "Bump Amplitude")
            .insert("type", "numeric")
            .insert("min_value", "0.0")
            .insert("max_value", "1.0")
            .insert("use", "optional")
            .insert("default", "1.0"));

    metadata.push_back(
        Dictionary()
            .insert("name", "normal_map_up")
            .insert("label", "Normal Map Up Vector")
            .insert("type", "enumeration")
            .insert("items",
                Dictionary()
                    .insert("Green Channel (Y)", "y")
                    .insert("Blue Channel (Z)", "z"))
            .insert("use", "optional")
            .insert("default", "z"));

    return metadata;
}

auto_release_ptr<Material> GenericMaterialFactory::create(
    const char*         name,
    const ParamArray&   params) const
{
    return
        auto_release_ptr<Material>(
            new GenericMaterial(name, params));
}

}   // namespace renderer
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2015 Couchbase, Inc
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

#include "config.h"

#include <atomic>
#include <cstring>
#include <platform/cb_malloc.h>
#include <string>

#include "daemon/alloc_hooks.h"

#include <gtest/gtest.h>

#if defined(HAVE_MALLOC_USABLE_SIZE)
#include <malloc.h>
#endif

// Test pointer in global scope to prevent compiler optimizing malloc/free away
// via DCE.
char* p;

class MemoryTrackerTest : public ::testing::Test {
public:
    // callback function for when memory is allocated.
    static void NewHook(const void* ptr, size_t) {
        if (ptr != NULL) {
            void* p = const_cast<void*>(ptr);
            alloc_size += AllocHooks::get_allocation_size(p);
        }
    }

    // callback function for when memory is deleted.
    static void DeleteHook(const void* ptr) {
        if (ptr != NULL) {
            void* p = const_cast<void*>(ptr);
            alloc_size -= AllocHooks::get_allocation_size(p);
        }
    }

    // function executed by our accounting test thread.
    static void AccountingTestThread(void* arg);

    // Helper function to lookup a symbol in a plugin and return a correctly-typed
    // function pointer.
    template <typename T>
    static T get_plugin_symbol(cb_dlhandle_t handle, const char* symbol_name) {
        char* errmsg;
        T symbol = reinterpret_cast<T>(cb_dlsym(handle, symbol_name, &errmsg));
        cb_assert(symbol != nullptr);
        return symbol;
    }

    static std::atomic_size_t alloc_size;
};

std::atomic_size_t MemoryTrackerTest::alloc_size;

void MemoryTrackerTest::AccountingTestThread(void* arg) {
    alloc_size = 0;

    // Test new & delete //////////////////////////////////////////////////
    p = new char();
    EXPECT_GT(alloc_size, 0);
    delete p;
    EXPECT_EQ(0, alloc_size);

    // Test sized delete //////////////////////////////////////////////////
    p = new char();
    EXPECT_GT(alloc_size, 0);
    operator delete(p, sizeof(char));
    EXPECT_EQ(0, alloc_size);

    // Test new[] & delete[] //////////////////////////////////////////////
    p = new char[100];
    EXPECT_GE(alloc_size, 100);
    delete []p;
    EXPECT_EQ(0, alloc_size);

    // Test sized delete[] ////////////////////////////////////////////////
    p = new char[100];
    EXPECT_GE(alloc_size, 100);
    operator delete[](p, sizeof(char) * 100);
    EXPECT_EQ(0, alloc_size);

    // Test cb_malloc() / cb_free() /////////////////////////////////////////////
    p = static_cast<char*>(cb_malloc(sizeof(char) * 10));
    EXPECT_GE(alloc_size, 10);
    cb_free(p);
    EXPECT_EQ(0, alloc_size);

    // Test cb_realloc() /////////////////////////////////////////////////////
    p = static_cast<char*>(cb_malloc(1));
    EXPECT_GE(alloc_size, 1);

    // Allocator may round up allocation sizes; so it's hard to
    // accurately predict how much alloc_size will increase. Hence
    // we just increase by a "large" amount and check at least half that
    // increment.
    size_t prev_size = alloc_size;
    p = static_cast<char*>(cb_realloc(p, sizeof(char) * 100));
    EXPECT_GE(alloc_size, (prev_size + 50));

    prev_size = alloc_size;
    p = static_cast<char*>(cb_realloc(p, 1));
    EXPECT_LT(alloc_size, prev_size);

    prev_size = alloc_size;
    char* q = static_cast<char*>(cb_realloc(NULL, 10));
    EXPECT_GE(alloc_size, prev_size + 10);

    cb_free(p);
    cb_free(q);
    EXPECT_EQ(0, alloc_size);

    // Test cb_calloc() //////////////////////////////////////////////////////
    p = static_cast<char*>(cb_calloc(sizeof(char), 20));
    EXPECT_GE(alloc_size, 20);
    cb_free(p);
    EXPECT_EQ(0, alloc_size);

    // Test indirect use of malloc() via cb_strdup() /////////////////////////
    p = cb_strdup("random string");
    EXPECT_GE(alloc_size, sizeof("random string"));
    cb_free(p);
    EXPECT_EQ(0, alloc_size);

    // Test memory allocations performed from another shared library loaded
    // at runtime.
    char* errmsg = nullptr;
    cb_dlhandle_t plugin = cb_dlopen("memcached_memory_tracking_plugin",
                                     &errmsg);
    EXPECT_NE(plugin, nullptr);

    // dlopen()ing a plugin can allocate memory. Reset alloc_size.
    alloc_size = 0;

    typedef void* (*plugin_malloc_t)(size_t);
    auto plugin_malloc =
        get_plugin_symbol<plugin_malloc_t>(plugin, "plugin_malloc");
    p = static_cast<char*>(plugin_malloc(100));
    EXPECT_GE(alloc_size, 100);

    typedef void (*plugin_free_t)(void*);
    auto plugin_free =
        get_plugin_symbol<plugin_free_t>(plugin, "plugin_free");
    plugin_free(p);
    EXPECT_EQ(0, alloc_size);

    typedef char* (*plugin_new_char_t)(size_t);
    auto plugin_new_char =
        get_plugin_symbol<plugin_new_char_t>(plugin, "plugin_new_char_array");
    p = plugin_new_char(200);
    EXPECT_GE(alloc_size, 200);

    typedef void (*plugin_delete_array_t)(char*);
    auto plugin_delete_char =
        get_plugin_symbol<plugin_delete_array_t>(plugin, "plugin_delete_array");
    plugin_delete_char(p);
    EXPECT_EQ(0, alloc_size);

    typedef std::string* (*plugin_new_string_t)(const char*);
    auto plugin_new_string =
        get_plugin_symbol<plugin_new_string_t>(plugin, "plugin_new_string");
    auto* string = plugin_new_string("duplicate_string");
    EXPECT_GE(alloc_size, 16);

    typedef void(*plugin_delete_string_t)(std::string* ptr);
    auto plugin_delete_string =
        get_plugin_symbol<plugin_delete_string_t>(plugin, "plugin_delete_string");
    plugin_delete_string(string);
    EXPECT_EQ(0, alloc_size);

    cb_dlclose(plugin);
}

// Test that the various memory allocation / deletion functions are correctly
// accounted for, when run in a parallel thread.
TEST_F(MemoryTrackerTest, Accounting) {
    AllocHooks::add_new_hook(NewHook);
    AllocHooks::add_delete_hook(DeleteHook);

    cb_thread_t tid;
    ASSERT_EQ(0, cb_create_thread(&tid, AccountingTestThread, 0, 0));
    ASSERT_EQ(0, cb_join_thread(tid));

    AllocHooks::remove_new_hook(NewHook);
    AllocHooks::remove_delete_hook(DeleteHook);
}

/* Test that malloc_usable_size is correctly interposed when using a
 * non-system allocator, as otherwise, our global new replacement could
 * lead to memory being allocated with jemalloc, but the system
 * malloc_usable_size being called with it.
 * We compare the result of malloc_usable_size to the result of
 * AllocHooks::get_allocation_size, which under jemalloc
 * maps to je_malloc_usable_size.
 * If these differ, or this test segfaults, it is suspicious and
 * worth investigating.
 * NB: ASAN is not helpful here as it does not work well with jemalloc
 */
#if defined(HAVE_MALLOC_USABLE_SIZE)
TEST_F(MemoryTrackerTest, mallocUsableSize) {
    // Allocate some data
    auto* ptr = new char[1];

    size_t allocHooksResult = AllocHooks::get_allocation_size(ptr);
    size_t directCallResult = malloc_usable_size(ptr);

    EXPECT_EQ(allocHooksResult, directCallResult);

    delete[] ptr;
}
#endif

int main(int argc, char** argv) {
    ::testing::InitGoogleTest(&argc, argv);

    AllocHooks::initialize();

    return RUN_ALL_TESTS();
}
<commit_msg>Revert "MB-32009: Add sized delete operator tests"<commit_after>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2015 Couchbase, Inc
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

#include "config.h"

#include <atomic>
#include <cstring>
#include <platform/cb_malloc.h>
#include <string>

#include "daemon/alloc_hooks.h"

#include <gtest/gtest.h>

#if defined(HAVE_MALLOC_USABLE_SIZE)
#include <malloc.h>
#endif

// Test pointer in global scope to prevent compiler optimizing malloc/free away
// via DCE.
char* p;

class MemoryTrackerTest : public ::testing::Test {
public:
    // callback function for when memory is allocated.
    static void NewHook(const void* ptr, size_t) {
        if (ptr != NULL) {
            void* p = const_cast<void*>(ptr);
            alloc_size += AllocHooks::get_allocation_size(p);
        }
    }

    // callback function for when memory is deleted.
    static void DeleteHook(const void* ptr) {
        if (ptr != NULL) {
            void* p = const_cast<void*>(ptr);
            alloc_size -= AllocHooks::get_allocation_size(p);
        }
    }

    // function executed by our accounting test thread.
    static void AccountingTestThread(void* arg);

    // Helper function to lookup a symbol in a plugin and return a correctly-typed
    // function pointer.
    template <typename T>
    static T get_plugin_symbol(cb_dlhandle_t handle, const char* symbol_name) {
        char* errmsg;
        T symbol = reinterpret_cast<T>(cb_dlsym(handle, symbol_name, &errmsg));
        cb_assert(symbol != nullptr);
        return symbol;
    }

    static std::atomic_size_t alloc_size;
};

std::atomic_size_t MemoryTrackerTest::alloc_size;

void MemoryTrackerTest::AccountingTestThread(void* arg) {
    alloc_size = 0;

    // Test new & delete //////////////////////////////////////////////////
    p = new char();
    EXPECT_GT(alloc_size, 0);
    delete p;
    EXPECT_EQ(0, alloc_size);

    // Test new[] & delete[] //////////////////////////////////////////////
    p = new char[100];
    EXPECT_GE(alloc_size, 100);
    delete []p;
    EXPECT_EQ(0, alloc_size);

    // Test cb_malloc() / cb_free() /////////////////////////////////////////////
    p = static_cast<char*>(cb_malloc(sizeof(char) * 10));
    EXPECT_GE(alloc_size, 10);
    cb_free(p);
    EXPECT_EQ(0, alloc_size);

    // Test cb_realloc() /////////////////////////////////////////////////////
    p = static_cast<char*>(cb_malloc(1));
    EXPECT_GE(alloc_size, 1);

    // Allocator may round up allocation sizes; so it's hard to
    // accurately predict how much alloc_size will increase. Hence
    // we just increase by a "large" amount and check at least half that
    // increment.
    size_t prev_size = alloc_size;
    p = static_cast<char*>(cb_realloc(p, sizeof(char) * 100));
    EXPECT_GE(alloc_size, (prev_size + 50));

    prev_size = alloc_size;
    p = static_cast<char*>(cb_realloc(p, 1));
    EXPECT_LT(alloc_size, prev_size);

    prev_size = alloc_size;
    char* q = static_cast<char*>(cb_realloc(NULL, 10));
    EXPECT_GE(alloc_size, prev_size + 10);

    cb_free(p);
    cb_free(q);
    EXPECT_EQ(0, alloc_size);

    // Test cb_calloc() //////////////////////////////////////////////////////
    p = static_cast<char*>(cb_calloc(sizeof(char), 20));
    EXPECT_GE(alloc_size, 20);
    cb_free(p);
    EXPECT_EQ(0, alloc_size);

    // Test indirect use of malloc() via cb_strdup() /////////////////////////
    p = cb_strdup("random string");
    EXPECT_GE(alloc_size, sizeof("random string"));
    cb_free(p);
    EXPECT_EQ(0, alloc_size);

    // Test memory allocations performed from another shared library loaded
    // at runtime.
    char* errmsg = nullptr;
    cb_dlhandle_t plugin = cb_dlopen("memcached_memory_tracking_plugin",
                                     &errmsg);
    EXPECT_NE(plugin, nullptr);

    // dlopen()ing a plugin can allocate memory. Reset alloc_size.
    alloc_size = 0;

    typedef void* (*plugin_malloc_t)(size_t);
    auto plugin_malloc =
        get_plugin_symbol<plugin_malloc_t>(plugin, "plugin_malloc");
    p = static_cast<char*>(plugin_malloc(100));
    EXPECT_GE(alloc_size, 100);

    typedef void (*plugin_free_t)(void*);
    auto plugin_free =
        get_plugin_symbol<plugin_free_t>(plugin, "plugin_free");
    plugin_free(p);
    EXPECT_EQ(0, alloc_size);

    typedef char* (*plugin_new_char_t)(size_t);
    auto plugin_new_char =
        get_plugin_symbol<plugin_new_char_t>(plugin, "plugin_new_char_array");
    p = plugin_new_char(200);
    EXPECT_GE(alloc_size, 200);

    typedef void (*plugin_delete_array_t)(char*);
    auto plugin_delete_char =
        get_plugin_symbol<plugin_delete_array_t>(plugin, "plugin_delete_array");
    plugin_delete_char(p);
    EXPECT_EQ(0, alloc_size);

    typedef std::string* (*plugin_new_string_t)(const char*);
    auto plugin_new_string =
        get_plugin_symbol<plugin_new_string_t>(plugin, "plugin_new_string");
    auto* string = plugin_new_string("duplicate_string");
    EXPECT_GE(alloc_size, 16);

    typedef void(*plugin_delete_string_t)(std::string* ptr);
    auto plugin_delete_string =
        get_plugin_symbol<plugin_delete_string_t>(plugin, "plugin_delete_string");
    plugin_delete_string(string);
    EXPECT_EQ(0, alloc_size);

    cb_dlclose(plugin);
}

// Test that the various memory allocation / deletion functions are correctly
// accounted for, when run in a parallel thread.
TEST_F(MemoryTrackerTest, Accounting) {
    AllocHooks::add_new_hook(NewHook);
    AllocHooks::add_delete_hook(DeleteHook);

    cb_thread_t tid;
    ASSERT_EQ(0, cb_create_thread(&tid, AccountingTestThread, 0, 0));
    ASSERT_EQ(0, cb_join_thread(tid));

    AllocHooks::remove_new_hook(NewHook);
    AllocHooks::remove_delete_hook(DeleteHook);
}

/* Test that malloc_usable_size is correctly interposed when using a
 * non-system allocator, as otherwise, our global new replacement could
 * lead to memory being allocated with jemalloc, but the system
 * malloc_usable_size being called with it.
 * We compare the result of malloc_usable_size to the result of
 * AllocHooks::get_allocation_size, which under jemalloc
 * maps to je_malloc_usable_size.
 * If these differ, or this test segfaults, it is suspicious and
 * worth investigating.
 * NB: ASAN is not helpful here as it does not work well with jemalloc
 */
#if defined(HAVE_MALLOC_USABLE_SIZE)
TEST_F(MemoryTrackerTest, mallocUsableSize) {
    // Allocate some data
    auto* ptr = new char[1];

    size_t allocHooksResult = AllocHooks::get_allocation_size(ptr);
    size_t directCallResult = malloc_usable_size(ptr);

    EXPECT_EQ(allocHooksResult, directCallResult);

    delete[] ptr;
}
#endif

int main(int argc, char** argv) {
    ::testing::InitGoogleTest(&argc, argv);

    AllocHooks::initialize();

    return RUN_ALL_TESTS();
}
<|endoftext|>