<commit_before>/*
 * Vulkan
 *
 * Copyright (C) 2015 LunarG, Inc.
 *
 * 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.
 */
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <map>
#include <unordered_map>
#include <vector>
#include "loader_platform.h"
#include "vk_dispatch_table_helper.h"
#include "vkLayer.h"
// The following is #included again to catch certain OS-specific functions
// being used:
#include "loader_platform.h"

#include "SPIRV/spirv.h"

static std::unordered_map<void *, VkLayerDispatchTable *> tableMap;

struct shader_source {
    std::vector<uint32_t> words;

    shader_source(VkShaderCreateInfo const *pCreateInfo) :
        words((uint32_t *)pCreateInfo->pCode, (uint32_t *)pCreateInfo->pCode + pCreateInfo->codeSize / sizeof(uint32_t)) {
    }
};

static std::unordered_map<void *, shader_source *> shader_map;

static VkLayerDispatchTable * initLayerTable(const VkBaseLayerObject *gpuw)
{
    VkLayerDispatchTable *pTable;

    assert(gpuw);
    std::unordered_map<void *, VkLayerDispatchTable *>::const_iterator it = tableMap.find((void *) gpuw->baseObject);
    if (it == tableMap.end())
    {
        pTable =  new VkLayerDispatchTable;
        tableMap[(void *) gpuw->baseObject] = pTable;
    } else
    {
        return it->second;
    }

    layer_initialize_dispatch_table(pTable, gpuw->pGPA, (VkPhysicalGpu) gpuw->nextObject);

    return pTable;
}

VK_LAYER_EXPORT VkResult VKAPI vkCreateDevice(VkPhysicalGpu gpu, const VkDeviceCreateInfo* pCreateInfo, VkDevice* pDevice)
{
    VkLayerDispatchTable* pTable = tableMap[gpu];
    VkResult result = pTable->CreateDevice(gpu, pCreateInfo, pDevice);
    // create a mapping for the device object into the dispatch table
    tableMap.emplace(*pDevice, pTable);
    return result;
}

VK_LAYER_EXPORT VkResult VKAPI vkEnumerateLayers(VkPhysicalGpu gpu, size_t maxLayerCount, size_t maxStringSize, size_t* pOutLayerCount, char* const* pOutLayers, void* pReserved)
{
    if (pOutLayerCount == NULL || pOutLayers == NULL || pOutLayers[0] == NULL || pOutLayers[1] == NULL || pReserved == NULL)
        return VK_ERROR_INVALID_POINTER;

    if (maxLayerCount < 1)
        return VK_ERROR_INITIALIZATION_FAILED;
    *pOutLayerCount = 1;
    strncpy((char *) pOutLayers[0], "ShaderChecker", maxStringSize);
    return VK_SUCCESS;
}

struct extProps {
    uint32_t version;
    const char * const name;
};
#define SHADER_CHECKER_LAYER_EXT_ARRAY_SIZE 1
static const struct extProps shaderCheckerExts[SHADER_CHECKER_LAYER_EXT_ARRAY_SIZE] = {
    // TODO what is the version?
    0x10, "ShaderChecker",
};

VK_LAYER_EXPORT VkResult VKAPI vkGetGlobalExtensionInfo(
                                               VkExtensionInfoType infoType,
                                               uint32_t extensionIndex,
                                               size_t*  pDataSize,
                                               void*    pData)
{
    VkResult result;

    /* This entrypoint is NOT going to init it's own dispatch table since loader calls here early */
    VkExtensionProperties *ext_props;
    uint32_t *count;

    if (pDataSize == NULL)
        return VK_ERROR_INVALID_POINTER;

    switch (infoType) {
        case VK_EXTENSION_INFO_TYPE_COUNT:
            *pDataSize = sizeof(uint32_t);
            if (pData == NULL)
                return VK_SUCCESS;
            count = (uint32_t *) pData;
            *count = SHADER_CHECKER_LAYER_EXT_ARRAY_SIZE;
            break;
        case VK_EXTENSION_INFO_TYPE_PROPERTIES:
            *pDataSize = sizeof(VkExtensionProperties);
            if (pData == NULL)
                return VK_SUCCESS;
            if (extensionIndex >= SHADER_CHECKER_LAYER_EXT_ARRAY_SIZE)
                return VK_ERROR_INVALID_VALUE;
            ext_props = (VkExtensionProperties *) pData;
            ext_props->version = shaderCheckerExts[extensionIndex].version;
            strncpy(ext_props->extName, shaderCheckerExts[extensionIndex].name,
                                        VK_MAX_EXTENSION_NAME);
            ext_props->extName[VK_MAX_EXTENSION_NAME - 1] = '\0';
            break;
        default:
            return VK_ERROR_INVALID_VALUE;
    };

    return VK_SUCCESS;
}

static int
value_or_default(std::unordered_map<unsigned, unsigned> const &map, unsigned id, int def)
{
    auto it = map.find(id);
    if (it == map.end())
        return def;
    else
        return it->second;
}

struct interface_var {
    uint32_t id;
    uint32_t type_id;
    /* TODO: collect the name, too? Isn't required to be present. */
};

static void
collect_interface_by_location(shader_source const *src, spv::StorageClass interface,
                              std::map<uint32_t, interface_var> &out,
                              std::map<uint32_t, interface_var> &builtins_out)
{
    unsigned int const *code = (unsigned int const *)&src->words[0];
    size_t size = src->words.size();

    if (code[0] != spv::MagicNumber) {
        printf("Invalid magic.\n");
        return;
    }

    std::unordered_map<unsigned, unsigned> var_locations;
    std::unordered_map<unsigned, unsigned> var_builtins;

    unsigned word = 5;
    while (word < size) {

        unsigned opcode = code[word] & 0x0ffffu;
        unsigned oplen = (code[word] & 0xffff0000u) >> 16;

        /* We consider two interface models: SSO rendezvous-by-location, and
         * builtins. Complain about anything that fits neither model.
         */
        if (opcode == spv::OpDecorate) {
            if (code[word+2] == spv::DecLocation) {
                var_locations[code[word+1]] = code[word+3];
            }

            if (code[word+2] == spv::DecBuiltIn) {
                var_builtins[code[word+1]] = code[word+3];
            }
        }

        /* TODO: handle grouped decorations */
        /* TODO: handle index=1 dual source outputs from FS -- two vars will
         * have the same location, and we DONT want to clobber. */

        if (opcode == spv::OpVariable && code[word+3] == interface) {
            int location = value_or_default(var_locations, code[word+2], -1);
            int builtin = value_or_default(var_builtins, code[word+2], -1);

            if (location == -1 && builtin == -1) {
                /* No location defined, and not bound to an API builtin.
                 * The spec says nothing about how this case works (or doesn't)
                 * for interface matching.
                 */
                printf("WARN: var %d (type %d) in %s interface has no Location or Builtin decoration\n",
                       code[word+2], code[word+1], interface == spv::StorageInput ? "input" : "output");
            }
            else if (location != -1) {
                /* A user-defined interface variable, with a location. */
                interface_var v;
                v.id = code[word+2];
                v.type_id = code[word+1];
                out[location] = v;
            }
            else {
                /* A builtin interface variable */
                interface_var v;
                v.id = code[word+2];
                v.type_id = code[word+1];
                builtins_out[builtin] = v;
            }
        }

        word += oplen;
    }
}

VK_LAYER_EXPORT VkResult VKAPI vkCreateShader(VkDevice device, const VkShaderCreateInfo *pCreateInfo,
                                                   VkShader *pShader)
{
    VkLayerDispatchTable* pTable = tableMap[(VkBaseLayerObject *)device];
    VkResult res = pTable->CreateShader(device, pCreateInfo, pShader);

    shader_map[(VkBaseLayerObject *) *pShader] = new shader_source(pCreateInfo);
    return res;
}

VK_LAYER_EXPORT VkResult VKAPI vkCreateGraphicsPipeline(VkDevice device,
                                                             const VkGraphicsPipelineCreateInfo *pCreateInfo,
                                                             VkPipeline *pPipeline)
{
    /* TODO: run cross-stage validation */
    /* - Validate vertex fetch -> VS interface */
    /* - Validate FS output -> CB */
    /* - Support GS, TCS, TES stages */

    VkLayerDispatchTable *pTable = tableMap[(VkBaseLayerObject *)device];
    VkResult res = pTable->CreateGraphicsPipeline(device, pCreateInfo, pPipeline);
    return res;
}

VK_LAYER_EXPORT void * VKAPI vkGetProcAddr(VkPhysicalGpu gpu, const char* pName)
{
    if (gpu == NULL)
        return NULL;

    initLayerTable((const VkBaseLayerObject *) gpu);

#define ADD_HOOK(fn)    \
    if (!strncmp(#fn, pName, sizeof(#fn))) \
        return (void *) fn

    ADD_HOOK(vkGetProcAddr);
    ADD_HOOK(vkEnumerateLayers);
    ADD_HOOK(vkCreateDevice);
    ADD_HOOK(vkCreateShader);
    ADD_HOOK(vkCreateGraphicsPipeline);

    VkBaseLayerObject* gpuw = (VkBaseLayerObject *) gpu;
    if (gpuw->pGPA == NULL)
        return NULL;
    return gpuw->pGPA((VkPhysicalGpu) gpuw->nextObject, pName);
}
<commit_msg>shader_checker: collect pipeline stages in vkCreateGraphicsPipeline<commit_after>/*
 * Vulkan
 *
 * Copyright (C) 2015 LunarG, Inc.
 *
 * 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.
 */
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <map>
#include <unordered_map>
#include <vector>
#include "loader_platform.h"
#include "vk_dispatch_table_helper.h"
#include "vkLayer.h"
// The following is #included again to catch certain OS-specific functions
// being used:
#include "loader_platform.h"

#include "SPIRV/spirv.h"

static std::unordered_map<void *, VkLayerDispatchTable *> tableMap;

struct shader_source {
    std::vector<uint32_t> words;

    shader_source(VkShaderCreateInfo const *pCreateInfo) :
        words((uint32_t *)pCreateInfo->pCode, (uint32_t *)pCreateInfo->pCode + pCreateInfo->codeSize / sizeof(uint32_t)) {
    }
};

static std::unordered_map<void *, shader_source *> shader_map;

static VkLayerDispatchTable * initLayerTable(const VkBaseLayerObject *gpuw)
{
    VkLayerDispatchTable *pTable;

    assert(gpuw);
    std::unordered_map<void *, VkLayerDispatchTable *>::const_iterator it = tableMap.find((void *) gpuw->baseObject);
    if (it == tableMap.end())
    {
        pTable =  new VkLayerDispatchTable;
        tableMap[(void *) gpuw->baseObject] = pTable;
    } else
    {
        return it->second;
    }

    layer_initialize_dispatch_table(pTable, gpuw->pGPA, (VkPhysicalGpu) gpuw->nextObject);

    return pTable;
}

VK_LAYER_EXPORT VkResult VKAPI vkCreateDevice(VkPhysicalGpu gpu, const VkDeviceCreateInfo* pCreateInfo, VkDevice* pDevice)
{
    VkLayerDispatchTable* pTable = tableMap[gpu];
    VkResult result = pTable->CreateDevice(gpu, pCreateInfo, pDevice);
    // create a mapping for the device object into the dispatch table
    tableMap.emplace(*pDevice, pTable);
    return result;
}

VK_LAYER_EXPORT VkResult VKAPI vkEnumerateLayers(VkPhysicalGpu gpu, size_t maxLayerCount, size_t maxStringSize, size_t* pOutLayerCount, char* const* pOutLayers, void* pReserved)
{
    if (pOutLayerCount == NULL || pOutLayers == NULL || pOutLayers[0] == NULL || pOutLayers[1] == NULL || pReserved == NULL)
        return VK_ERROR_INVALID_POINTER;

    if (maxLayerCount < 1)
        return VK_ERROR_INITIALIZATION_FAILED;
    *pOutLayerCount = 1;
    strncpy((char *) pOutLayers[0], "ShaderChecker", maxStringSize);
    return VK_SUCCESS;
}

struct extProps {
    uint32_t version;
    const char * const name;
};
#define SHADER_CHECKER_LAYER_EXT_ARRAY_SIZE 1
static const struct extProps shaderCheckerExts[SHADER_CHECKER_LAYER_EXT_ARRAY_SIZE] = {
    // TODO what is the version?
    0x10, "ShaderChecker",
};

VK_LAYER_EXPORT VkResult VKAPI vkGetGlobalExtensionInfo(
                                               VkExtensionInfoType infoType,
                                               uint32_t extensionIndex,
                                               size_t*  pDataSize,
                                               void*    pData)
{
    VkResult result;

    /* This entrypoint is NOT going to init it's own dispatch table since loader calls here early */
    VkExtensionProperties *ext_props;
    uint32_t *count;

    if (pDataSize == NULL)
        return VK_ERROR_INVALID_POINTER;

    switch (infoType) {
        case VK_EXTENSION_INFO_TYPE_COUNT:
            *pDataSize = sizeof(uint32_t);
            if (pData == NULL)
                return VK_SUCCESS;
            count = (uint32_t *) pData;
            *count = SHADER_CHECKER_LAYER_EXT_ARRAY_SIZE;
            break;
        case VK_EXTENSION_INFO_TYPE_PROPERTIES:
            *pDataSize = sizeof(VkExtensionProperties);
            if (pData == NULL)
                return VK_SUCCESS;
            if (extensionIndex >= SHADER_CHECKER_LAYER_EXT_ARRAY_SIZE)
                return VK_ERROR_INVALID_VALUE;
            ext_props = (VkExtensionProperties *) pData;
            ext_props->version = shaderCheckerExts[extensionIndex].version;
            strncpy(ext_props->extName, shaderCheckerExts[extensionIndex].name,
                                        VK_MAX_EXTENSION_NAME);
            ext_props->extName[VK_MAX_EXTENSION_NAME - 1] = '\0';
            break;
        default:
            return VK_ERROR_INVALID_VALUE;
    };

    return VK_SUCCESS;
}

static int
value_or_default(std::unordered_map<unsigned, unsigned> const &map, unsigned id, int def)
{
    auto it = map.find(id);
    if (it == map.end())
        return def;
    else
        return it->second;
}

struct interface_var {
    uint32_t id;
    uint32_t type_id;
    /* TODO: collect the name, too? Isn't required to be present. */
};

static void
collect_interface_by_location(shader_source const *src, spv::StorageClass interface,
                              std::map<uint32_t, interface_var> &out,
                              std::map<uint32_t, interface_var> &builtins_out)
{
    unsigned int const *code = (unsigned int const *)&src->words[0];
    size_t size = src->words.size();

    if (code[0] != spv::MagicNumber) {
        printf("Invalid magic.\n");
        return;
    }

    std::unordered_map<unsigned, unsigned> var_locations;
    std::unordered_map<unsigned, unsigned> var_builtins;

    unsigned word = 5;
    while (word < size) {

        unsigned opcode = code[word] & 0x0ffffu;
        unsigned oplen = (code[word] & 0xffff0000u) >> 16;

        /* We consider two interface models: SSO rendezvous-by-location, and
         * builtins. Complain about anything that fits neither model.
         */
        if (opcode == spv::OpDecorate) {
            if (code[word+2] == spv::DecLocation) {
                var_locations[code[word+1]] = code[word+3];
            }

            if (code[word+2] == spv::DecBuiltIn) {
                var_builtins[code[word+1]] = code[word+3];
            }
        }

        /* TODO: handle grouped decorations */
        /* TODO: handle index=1 dual source outputs from FS -- two vars will
         * have the same location, and we DONT want to clobber. */

        if (opcode == spv::OpVariable && code[word+3] == interface) {
            int location = value_or_default(var_locations, code[word+2], -1);
            int builtin = value_or_default(var_builtins, code[word+2], -1);

            if (location == -1 && builtin == -1) {
                /* No location defined, and not bound to an API builtin.
                 * The spec says nothing about how this case works (or doesn't)
                 * for interface matching.
                 */
                printf("WARN: var %d (type %d) in %s interface has no Location or Builtin decoration\n",
                       code[word+2], code[word+1], interface == spv::StorageInput ? "input" : "output");
            }
            else if (location != -1) {
                /* A user-defined interface variable, with a location. */
                interface_var v;
                v.id = code[word+2];
                v.type_id = code[word+1];
                out[location] = v;
            }
            else {
                /* A builtin interface variable */
                interface_var v;
                v.id = code[word+2];
                v.type_id = code[word+1];
                builtins_out[builtin] = v;
            }
        }

        word += oplen;
    }
}

VK_LAYER_EXPORT VkResult VKAPI vkCreateShader(VkDevice device, const VkShaderCreateInfo *pCreateInfo,
                                                   VkShader *pShader)
{
    VkLayerDispatchTable* pTable = tableMap[(VkBaseLayerObject *)device];
    VkResult res = pTable->CreateShader(device, pCreateInfo, pShader);

    shader_map[(VkBaseLayerObject *) *pShader] = new shader_source(pCreateInfo);
    return res;
}

VK_LAYER_EXPORT VkResult VKAPI vkCreateGraphicsPipeline(VkDevice device,
                                                             const VkGraphicsPipelineCreateInfo *pCreateInfo,
                                                             VkPipeline *pPipeline)
{
    /* TODO: run cross-stage validation */
    /* - Validate vertex fetch -> VS interface */
    /* - Validate FS output -> CB */
    /* - Support GS, TCS, TES stages */

    /* We seem to allow pipeline stages to be specified out of order, so collect and identify them
     * before trying to do anything more: */

    shader_source const *vs_source = 0;
    shader_source const *fs_source = 0;
    VkPipelineCbStateCreateInfo const *cb = 0;
    VkPipelineVertexInputCreateInfo const *vi = 0;

    for (auto stage = pCreateInfo; stage; stage = (decltype(stage))stage->pNext) {
        if (stage->sType == VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO) {
            auto shader_stage = (VkPipelineShaderStageCreateInfo const *)stage;

            if (shader_stage->shader.stage == VK_SHADER_STAGE_VERTEX)
                vs_source = shader_map[(void *)(shader_stage->shader.shader)];
            else if (shader_stage->shader.stage == VK_SHADER_STAGE_FRAGMENT)
                fs_source = shader_map[(void *)(shader_stage->shader.shader)];
            else
                printf("Unknown shader stage %d\n", shader_stage->shader.stage);
        }
        else if (stage->sType == VK_STRUCTURE_TYPE_PIPELINE_CB_STATE_CREATE_INFO) {
            cb = (VkPipelineCbStateCreateInfo const *)stage;
        }
        else if (stage->sType == VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_CREATE_INFO) {
            vi = (VkPipelineVertexInputCreateInfo const *)stage;
        }
    }

    printf("Pipeline: vi=%p vs=%p fs=%p cb=%p\n", vi, vs_source, fs_source, cb);

    VkLayerDispatchTable *pTable = tableMap[(VkBaseLayerObject *)device];
    VkResult res = pTable->CreateGraphicsPipeline(device, pCreateInfo, pPipeline);
    return res;
}

VK_LAYER_EXPORT void * VKAPI vkGetProcAddr(VkPhysicalGpu gpu, const char* pName)
{
    if (gpu == NULL)
        return NULL;

    initLayerTable((const VkBaseLayerObject *) gpu);

#define ADD_HOOK(fn)    \
    if (!strncmp(#fn, pName, sizeof(#fn))) \
        return (void *) fn

    ADD_HOOK(vkGetProcAddr);
    ADD_HOOK(vkEnumerateLayers);
    ADD_HOOK(vkCreateDevice);
    ADD_HOOK(vkCreateShader);
    ADD_HOOK(vkCreateGraphicsPipeline);

    VkBaseLayerObject* gpuw = (VkBaseLayerObject *) gpu;
    if (gpuw->pGPA == NULL)
        return NULL;
    return gpuw->pGPA((VkPhysicalGpu) gpuw->nextObject, pName);
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2018 Abit More, and contributors.
 *
 * The MIT License
 *
 * 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.
 */

#include <graphene/app/util.hpp>

namespace graphene { namespace app {

u256 to256( const fc::uint128& t )
{
   u256 v(t.hi);
   v <<= 64;
   v += t.lo;
   return v;
}

fc::uint128 to_capped128( const u256& t )
{
   static u256 max128 = to256( fc::uint128::max_value() );
   if( t >= max128 )
      return fc::uint128::max_value();
   fc::uint128 result;
   u256 hi(t);
   hi >>= 64;
   result.hi = static_cast< uint64_t >( hi );
   u256 lo(t);
   hi <<= 64;
   lo -= hi;
   result.lo = static_cast< uint64_t >( lo );
   return result;
}

string uint128_amount_to_string( const fc::uint128& amount, const uint8_t precision )
{ try {
   string s = string( amount );
   if( precision == 0 || amount == 0 )
      return s;

   std::stringstream ss;
   uint8_t pos = s.find_last_not_of( '0' ); // should be >= 0
   uint8_t len = s.size();
   if( len > precision )
   {
      uint8_t left_len = len - precision;
      ss << s.substr( 0, left_len );
      if( pos >= left_len )
         ss << '.' << s.substr( left_len, pos - left_len + 1 );
   }
   else
   {
      ss << "0.";
      for( uint8_t i = precision - len; i > 0; --i )
         ss << '0';
      ss << s.substr( 0, pos + 1 );
   }
   return ss.str();
} FC_CAPTURE_AND_RETHROW( (amount)(precision) ) }

string price_to_string( const price& _price, const uint8_t base_precision, const uint8_t quote_precision )
{ try {
   if( _price.base.amount == 0 )
      return "0";
   FC_ASSERT( _price.base.amount >= 0 );
   FC_ASSERT( _price.quote.amount >= 0 );
   FC_ASSERT( base_precision <= 19 );
   FC_ASSERT( quote_precision <= 19 );
   price new_price = _price;
   if( new_price.quote.amount == 0 )
   {
      new_price.base.amount = std::numeric_limits<int64_t>::max();
      new_price.quote.amount = 1;
   }

   // times (10**19) so won't overflow but have good accuracy
   fc::uint128 price128 = fc::uint128( new_price.base.amount.value ) * uint64_t(10000000000000000000ULL)
                                                                     / new_price.quote.amount.value;

   return uint128_amount_to_string( price128, 19 + base_precision - quote_precision );
} FC_CAPTURE_AND_RETHROW( (_price)(base_precision)(quote_precision) ) }

string price_diff_percent_string( const price& old_price, const price& new_price )
{ try {
   FC_ASSERT( old_price.base.asset_id == new_price.base.asset_id );
   FC_ASSERT( old_price.quote.asset_id == new_price.quote.asset_id );
   FC_ASSERT( old_price.base.amount >= 0 );
   FC_ASSERT( old_price.quote.amount >= 0 );
   FC_ASSERT( new_price.base.amount >= 0 );
   FC_ASSERT( new_price.quote.amount >= 0 );
   price old_price1 = old_price;
   if( old_price.base.amount == 0 )
   {
      old_price1.base.amount = 1;
      old_price1.quote.amount = std::numeric_limits<int64_t>::max();
   }
   else if( old_price.quote.amount == 0 )
   {
      old_price1.base.amount = std::numeric_limits<int64_t>::max();
      old_price1.quote.amount = 1;
   }
   price new_price1 = new_price;
   if( new_price.base.amount == 0 )
   {
      new_price1.base.amount = 1;
      new_price1.quote.amount = std::numeric_limits<int64_t>::max();
   }
   else if( new_price.quote.amount == 0 )
   {
      new_price1.base.amount = std::numeric_limits<int64_t>::max();
      new_price1.quote.amount = 1;
   }

   // change = new/old - 1 = (new_base/new_quote)/(old_base/old_quote) - 1
   //        = (new_base * old_quote) / (new_quote * old_base) - 1
   //        = (new_base * old_quote - new_quote * old_base) / (new_quote * old_base)
   fc::uint128 new128 = fc::uint128( new_price1.base.amount.value ) * old_price1.quote.amount.value;
   fc::uint128 old128 = fc::uint128( old_price1.base.amount.value ) * new_price1.quote.amount.value;
   bool non_negative = (new128 >= old128);
   fc::uint128 diff128;
   if( non_negative )
      diff128 = new128 - old128;
   else
      diff128 = old128 - new128;
   static fc::uint128 max = fc::uint128::max_value() / 10000;
   if( diff128 <= max )
      diff128 = diff128 * 10000 / old128;
   else
   {
      u256 diff256 = to256( diff128 );
      diff256 *= 10000;
      diff256 /= to256( old128 );
      diff128 = to_capped128( diff256 );
   }
   string diff_str = uint128_amount_to_string( diff128, 2 ); // at most 2 decimal digits
   if( non_negative || diff_str == "0" )
      return diff_str;
   else
      return "-" + diff_str;
} FC_CAPTURE_AND_RETHROW( (old_price)(new_price) ) }

} } // graphene::app
<commit_msg>Fix Windows build<commit_after>/*
 * Copyright (c) 2018 Abit More, and contributors.
 *
 * The MIT License
 *
 * 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.
 */

#include <graphene/app/util.hpp>

namespace graphene { namespace app {

u256 to256( const fc::uint128& t )
{
   u256 v(t.hi);
   v <<= 64;
   v += t.lo;
   return v;
}

fc::uint128 to_capped128( const u256& t )
{
   static u256 max128 = to256( fc::uint128::max_value() );
   if( t >= max128 )
      return fc::uint128::max_value();
   fc::uint128 result;
   u256 hi(t);
   hi >>= 64;
   result.hi = static_cast< uint64_t >( hi );
   u256 lo(t);
   hi <<= 64;
   lo -= hi;
   result.lo = static_cast< uint64_t >( lo );
   return result;
}

string uint128_amount_to_string( const fc::uint128& amount, const uint8_t precision )
{ try {
   string s = string( amount );
   if( precision == 0 || amount == fc::uint128() )
      return s;

   std::stringstream ss;
   uint8_t pos = s.find_last_not_of( '0' ); // should be >= 0
   uint8_t len = s.size();
   if( len > precision )
   {
      uint8_t left_len = len - precision;
      ss << s.substr( 0, left_len );
      if( pos >= left_len )
         ss << '.' << s.substr( left_len, pos - left_len + 1 );
   }
   else
   {
      ss << "0.";
      for( uint8_t i = precision - len; i > 0; --i )
         ss << '0';
      ss << s.substr( 0, pos + 1 );
   }
   return ss.str();
} FC_CAPTURE_AND_RETHROW( (amount)(precision) ) }

string price_to_string( const price& _price, const uint8_t base_precision, const uint8_t quote_precision )
{ try {
   if( _price.base.amount == 0 )
      return "0";
   FC_ASSERT( _price.base.amount >= 0 );
   FC_ASSERT( _price.quote.amount >= 0 );
   FC_ASSERT( base_precision <= 19 );
   FC_ASSERT( quote_precision <= 19 );
   price new_price = _price;
   if( new_price.quote.amount == 0 )
   {
      new_price.base.amount = std::numeric_limits<int64_t>::max();
      new_price.quote.amount = 1;
   }

   // times (10**19) so won't overflow but have good accuracy
   fc::uint128 price128 = fc::uint128( new_price.base.amount.value ) * uint64_t(10000000000000000000ULL)
                                                                     / new_price.quote.amount.value;

   return uint128_amount_to_string( price128, 19 + base_precision - quote_precision );
} FC_CAPTURE_AND_RETHROW( (_price)(base_precision)(quote_precision) ) }

string price_diff_percent_string( const price& old_price, const price& new_price )
{ try {
   FC_ASSERT( old_price.base.asset_id == new_price.base.asset_id );
   FC_ASSERT( old_price.quote.asset_id == new_price.quote.asset_id );
   FC_ASSERT( old_price.base.amount >= 0 );
   FC_ASSERT( old_price.quote.amount >= 0 );
   FC_ASSERT( new_price.base.amount >= 0 );
   FC_ASSERT( new_price.quote.amount >= 0 );
   price old_price1 = old_price;
   if( old_price.base.amount == 0 )
   {
      old_price1.base.amount = 1;
      old_price1.quote.amount = std::numeric_limits<int64_t>::max();
   }
   else if( old_price.quote.amount == 0 )
   {
      old_price1.base.amount = std::numeric_limits<int64_t>::max();
      old_price1.quote.amount = 1;
   }
   price new_price1 = new_price;
   if( new_price.base.amount == 0 )
   {
      new_price1.base.amount = 1;
      new_price1.quote.amount = std::numeric_limits<int64_t>::max();
   }
   else if( new_price.quote.amount == 0 )
   {
      new_price1.base.amount = std::numeric_limits<int64_t>::max();
      new_price1.quote.amount = 1;
   }

   // change = new/old - 1 = (new_base/new_quote)/(old_base/old_quote) - 1
   //        = (new_base * old_quote) / (new_quote * old_base) - 1
   //        = (new_base * old_quote - new_quote * old_base) / (new_quote * old_base)
   fc::uint128 new128 = fc::uint128( new_price1.base.amount.value ) * old_price1.quote.amount.value;
   fc::uint128 old128 = fc::uint128( old_price1.base.amount.value ) * new_price1.quote.amount.value;
   bool non_negative = (new128 >= old128);
   fc::uint128 diff128;
   if( non_negative )
      diff128 = new128 - old128;
   else
      diff128 = old128 - new128;
   static fc::uint128 max = fc::uint128::max_value() / 10000;
   if( diff128 <= max )
      diff128 = diff128 * 10000 / old128;
   else
   {
      u256 diff256 = to256( diff128 );
      diff256 *= 10000;
      diff256 /= to256( old128 );
      diff128 = to_capped128( diff256 );
   }
   string diff_str = uint128_amount_to_string( diff128, 2 ); // at most 2 decimal digits
   if( non_negative || diff_str == "0" )
      return diff_str;
   else
      return "-" + diff_str;
} FC_CAPTURE_AND_RETHROW( (old_price)(new_price) ) }

} } // graphene::app
<|endoftext|>


<commit_before><commit_msg>Fix TestShell to forward-delete on eventSender.keyDown('delete') to match upstream WebKit http://trac.webkit.org/changeset/61153<commit_after><|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */

/*!
 * \file elemwise_binary_broadcast_op_extended.cc
 * \brief CPU Implementation of extended functions for elementwise binary broadcast operator.
 */
#include "./elemwise_unary_op.h"
#include "./elemwise_binary_op.h"
#include "./elemwise_binary_broadcast_op.h"

namespace mxnet {
namespace op {
MXNET_OPERATOR_REGISTER_BINARY_BROADCAST(broadcast_power)
    .describe(
        R"code(Returns result of first array elements raised to powers from second array, element-wise with broadcasting.

Example::

   x = [[ 1.,  1.,  1.],
        [ 1.,  1.,  1.]]

   y = [[ 0.],
        [ 1.]]

   broadcast_power(x, y) = [[ 2.,  2.,  2.],
                            [ 4.,  4.,  4.]]

)code" ADD_FILELINE)
    .set_attr<FCompute>("FCompute<cpu>", BinaryBroadcastCompute<cpu, mshadow_op::power>)
    .set_attr<nnvm::FGradient>("FGradient", ElemwiseGradUseIn{"_backward_broadcast_power"});

NNVM_REGISTER_OP(_backward_broadcast_power)
    .set_num_inputs(3)
    .set_num_outputs(2)
    .set_attr<nnvm::TIsBackward>("TIsBackward", true)
    .set_attr<nnvm::FInplaceOption>("FInplaceOption",
                                    [](const NodeAttrs& attrs) {
                                      return std::vector<std::pair<int, int> >{{0, 1}};
                                    })
    .set_attr<FResourceRequest>("FResourceRequest",
                                [](const NodeAttrs& attrs) {
                                  return std::vector<ResourceRequest>{ResourceRequest::kTempSpace};
                                })
    .set_attr<FCompute>(
        "FCompute<cpu>",
        BinaryBroadcastBackwardUseIn<cpu, mshadow_op::power_grad, mshadow_op::power_rgrad>);

MXNET_OPERATOR_REGISTER_BINARY_BROADCAST(broadcast_maximum)
    .add_alias("_npi_maximum")
    .describe(R"code(Returns element-wise maximum of the input arrays with broadcasting.

This function compares two input arrays and returns a new array having the element-wise maxima.

Example::

   x = [[ 1.,  1.,  1.],
        [ 1.,  1.,  1.]]

   y = [[ 0.],
        [ 1.]]

   broadcast_maximum(x, y) = [[ 1.,  1.,  1.],
                              [ 1.,  1.,  1.]]

)code" ADD_FILELINE)
    .set_attr<FCompute>("FCompute<cpu>", BinaryBroadcastCompute<cpu, mshadow_op::maximum>)
    .set_attr<nnvm::FGradient>("FGradient", ElemwiseGradUseIn{"_backward_broadcast_maximum"});

NNVM_REGISTER_OP(_backward_broadcast_maximum)
    .set_num_inputs(3)
    .set_num_outputs(2)
    .set_attr<nnvm::TIsBackward>("TIsBackward", true)
    .set_attr<nnvm::FInplaceOption>("FInplaceOption",
                                    [](const NodeAttrs& attrs) {
                                      return std::vector<std::pair<int, int> >{{0, 1}};
                                    })
    .set_attr<FResourceRequest>("FResourceRequest",
                                [](const NodeAttrs& attrs) {
                                  return std::vector<ResourceRequest>{ResourceRequest::kTempSpace};
                                })
    .set_attr<FCompute>("FCompute<cpu>",
                        BinaryBroadcastBackwardUseIn<cpu, mshadow_op::ge, mshadow_op::lt>);

MXNET_OPERATOR_REGISTER_BINARY_BROADCAST(broadcast_minimum)
    .add_alias("_npi_minimum")
    .describe(R"code(Returns element-wise minimum of the input arrays with broadcasting.

This function compares two input arrays and returns a new array having the element-wise minima.

Example::

   x = [[ 1.,  1.,  1.],
        [ 1.,  1.,  1.]]

   y = [[ 0.],
        [ 1.]]

   broadcast_maximum(x, y) = [[ 0.,  0.,  0.],
                              [ 1.,  1.,  1.]]

)code" ADD_FILELINE)
    .set_attr<FCompute>("FCompute<cpu>", BinaryBroadcastCompute<cpu, mshadow_op::minimum>)
    .set_attr<nnvm::FGradient>("FGradient", ElemwiseGradUseIn{"_backward_broadcast_minimum"});

NNVM_REGISTER_OP(_backward_broadcast_minimum)
    .set_num_inputs(3)
    .set_num_outputs(2)
    .set_attr<nnvm::TIsBackward>("TIsBackward", true)
    .set_attr<nnvm::FInplaceOption>("FInplaceOption",
                                    [](const NodeAttrs& attrs) {
                                      return std::vector<std::pair<int, int> >{{0, 1}};
                                    })
    .set_attr<FResourceRequest>("FResourceRequest",
                                [](const NodeAttrs& attrs) {
                                  return std::vector<ResourceRequest>{ResourceRequest::kTempSpace};
                                })
    .set_attr<FCompute>("FCompute<cpu>",
                        BinaryBroadcastBackwardUseIn<cpu, mshadow_op::le, mshadow_op::gt>);

MXNET_OPERATOR_REGISTER_BINARY_BROADCAST(broadcast_hypot)
    .describe(R"code( Returns the hypotenuse of a right angled triangle, given its "legs"
with broadcasting.

It is equivalent to doing :math:`sqrt(x_1^2 + x_2^2)`.

Example::

   x = [[ 3.,  3.,  3.]]

   y = [[ 4.],
        [ 4.]]

   broadcast_hypot(x, y) = [[ 5.,  5.,  5.],
                            [ 5.,  5.,  5.]]

   z = [[ 0.],
        [ 4.]]

   broadcast_hypot(x, z) = [[ 3.,  3.,  3.],
                            [ 5.,  5.,  5.]]

)code" ADD_FILELINE)
    .set_attr<FCompute>("FCompute<cpu>", BinaryBroadcastCompute<cpu, mshadow_op::hypot>)
    .set_attr<nnvm::FGradient>("FGradient", ElemwiseGradUseIn{"_backward_broadcast_hypot"});

NNVM_REGISTER_OP(_backward_broadcast_hypot)
    .set_num_inputs(3)
    .set_num_outputs(2)
    .set_attr<nnvm::TIsBackward>("TIsBackward", true)
    .set_attr<nnvm::FInplaceOption>("FInplaceOption",
                                    [](const NodeAttrs& attrs) {
                                      return std::vector<std::pair<int, int> >{{0, 1}};
                                    })
    .set_attr<FResourceRequest>("FResourceRequest",
                                [](const NodeAttrs& attrs) {
                                  return std::vector<ResourceRequest>{ResourceRequest::kTempSpace};
                                })
    .set_attr<FCompute>("FCompute<cpu>",
                        BinaryBroadcastBackwardUseIn<cpu,
                                                     mshadow_op::hypot_grad_left,
                                                     mshadow_op::hypot_grad_right>);

}  // namespace op
}  // namespace mxnet
<commit_msg>Fix broadcast ops descriptions (#21087)<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 */

/*!
 * \file elemwise_binary_broadcast_op_extended.cc
 * \brief CPU Implementation of extended functions for elementwise binary broadcast operator.
 */
#include "./elemwise_unary_op.h"
#include "./elemwise_binary_op.h"
#include "./elemwise_binary_broadcast_op.h"

namespace mxnet {
namespace op {
MXNET_OPERATOR_REGISTER_BINARY_BROADCAST(broadcast_power)
    .describe(
        R"code(Returns result of first array elements raised to powers from second array, element-wise with broadcasting.

Example::

   x = [[ 1.,  1.,  1.],
        [ 1.,  1.,  1.]]

   y = [[ 0.],
        [ 1.]]

   broadcast_power(x, y) = [[ 1.,  1.,  1.],
                            [ 1.,  1.,  1.]]

)code" ADD_FILELINE)
    .set_attr<FCompute>("FCompute<cpu>", BinaryBroadcastCompute<cpu, mshadow_op::power>)
    .set_attr<nnvm::FGradient>("FGradient", ElemwiseGradUseIn{"_backward_broadcast_power"});

NNVM_REGISTER_OP(_backward_broadcast_power)
    .set_num_inputs(3)
    .set_num_outputs(2)
    .set_attr<nnvm::TIsBackward>("TIsBackward", true)
    .set_attr<nnvm::FInplaceOption>("FInplaceOption",
                                    [](const NodeAttrs& attrs) {
                                      return std::vector<std::pair<int, int> >{{0, 1}};
                                    })
    .set_attr<FResourceRequest>("FResourceRequest",
                                [](const NodeAttrs& attrs) {
                                  return std::vector<ResourceRequest>{ResourceRequest::kTempSpace};
                                })
    .set_attr<FCompute>(
        "FCompute<cpu>",
        BinaryBroadcastBackwardUseIn<cpu, mshadow_op::power_grad, mshadow_op::power_rgrad>);

MXNET_OPERATOR_REGISTER_BINARY_BROADCAST(broadcast_maximum)
    .add_alias("_npi_maximum")
    .describe(R"code(Returns element-wise maximum of the input arrays with broadcasting.

This function compares two input arrays and returns a new array having the element-wise maxima.

Example::

   x = [[ 1.,  1.,  1.],
        [ 1.,  1.,  1.]]

   y = [[ 0.],
        [ 1.]]

   broadcast_maximum(x, y) = [[ 1.,  1.,  1.],
                              [ 1.,  1.,  1.]]

)code" ADD_FILELINE)
    .set_attr<FCompute>("FCompute<cpu>", BinaryBroadcastCompute<cpu, mshadow_op::maximum>)
    .set_attr<nnvm::FGradient>("FGradient", ElemwiseGradUseIn{"_backward_broadcast_maximum"});

NNVM_REGISTER_OP(_backward_broadcast_maximum)
    .set_num_inputs(3)
    .set_num_outputs(2)
    .set_attr<nnvm::TIsBackward>("TIsBackward", true)
    .set_attr<nnvm::FInplaceOption>("FInplaceOption",
                                    [](const NodeAttrs& attrs) {
                                      return std::vector<std::pair<int, int> >{{0, 1}};
                                    })
    .set_attr<FResourceRequest>("FResourceRequest",
                                [](const NodeAttrs& attrs) {
                                  return std::vector<ResourceRequest>{ResourceRequest::kTempSpace};
                                })
    .set_attr<FCompute>("FCompute<cpu>",
                        BinaryBroadcastBackwardUseIn<cpu, mshadow_op::ge, mshadow_op::lt>);

MXNET_OPERATOR_REGISTER_BINARY_BROADCAST(broadcast_minimum)
    .add_alias("_npi_minimum")
    .describe(R"code(Returns element-wise minimum of the input arrays with broadcasting.

This function compares two input arrays and returns a new array having the element-wise minima.

Example::

   x = [[ 1.,  1.,  1.],
        [ 1.,  1.,  1.]]

   y = [[ 0.],
        [ 1.]]

   broadcast_minimum(x, y) = [[ 0.,  0.,  0.],
                              [ 1.,  1.,  1.]]

)code" ADD_FILELINE)
    .set_attr<FCompute>("FCompute<cpu>", BinaryBroadcastCompute<cpu, mshadow_op::minimum>)
    .set_attr<nnvm::FGradient>("FGradient", ElemwiseGradUseIn{"_backward_broadcast_minimum"});

NNVM_REGISTER_OP(_backward_broadcast_minimum)
    .set_num_inputs(3)
    .set_num_outputs(2)
    .set_attr<nnvm::TIsBackward>("TIsBackward", true)
    .set_attr<nnvm::FInplaceOption>("FInplaceOption",
                                    [](const NodeAttrs& attrs) {
                                      return std::vector<std::pair<int, int> >{{0, 1}};
                                    })
    .set_attr<FResourceRequest>("FResourceRequest",
                                [](const NodeAttrs& attrs) {
                                  return std::vector<ResourceRequest>{ResourceRequest::kTempSpace};
                                })
    .set_attr<FCompute>("FCompute<cpu>",
                        BinaryBroadcastBackwardUseIn<cpu, mshadow_op::le, mshadow_op::gt>);

MXNET_OPERATOR_REGISTER_BINARY_BROADCAST(broadcast_hypot)
    .describe(R"code( Returns the hypotenuse of a right angled triangle, given its "legs"
with broadcasting.

It is equivalent to doing :math:`sqrt(x_1^2 + x_2^2)`.

Example::

   x = [[ 3.,  3.,  3.]]

   y = [[ 4.],
        [ 4.]]

   broadcast_hypot(x, y) = [[ 5.,  5.,  5.],
                            [ 5.,  5.,  5.]]

   z = [[ 0.],
        [ 4.]]

   broadcast_hypot(x, z) = [[ 3.,  3.,  3.],
                            [ 5.,  5.,  5.]]

)code" ADD_FILELINE)
    .set_attr<FCompute>("FCompute<cpu>", BinaryBroadcastCompute<cpu, mshadow_op::hypot>)
    .set_attr<nnvm::FGradient>("FGradient", ElemwiseGradUseIn{"_backward_broadcast_hypot"});

NNVM_REGISTER_OP(_backward_broadcast_hypot)
    .set_num_inputs(3)
    .set_num_outputs(2)
    .set_attr<nnvm::TIsBackward>("TIsBackward", true)
    .set_attr<nnvm::FInplaceOption>("FInplaceOption",
                                    [](const NodeAttrs& attrs) {
                                      return std::vector<std::pair<int, int> >{{0, 1}};
                                    })
    .set_attr<FResourceRequest>("FResourceRequest",
                                [](const NodeAttrs& attrs) {
                                  return std::vector<ResourceRequest>{ResourceRequest::kTempSpace};
                                })
    .set_attr<FCompute>("FCompute<cpu>",
                        BinaryBroadcastBackwardUseIn<cpu,
                                                     mshadow_op::hypot_grad_left,
                                                     mshadow_op::hypot_grad_right>);

}  // namespace op
}  // namespace mxnet
<|endoftext|>


<commit_before><commit_msg>Add "local functions" header in dynamicThreadBlinker.cpp<commit_after><|endoftext|>


<commit_before>#include "evpp/inner_pre.h"

#include "sync_udp_client.h"
#include "evpp/libevent_headers.h"
#include "evpp/sockets.h"

namespace evpp {
namespace udp {
namespace sync {
Client::Client() {
    sockfd_ = INVALID_SOCKET;
    memset(&remote_addr_, 0, sizeof(remote_addr_));
}

Client::~Client(void) {
    Close();
}

bool Client::Connect(const struct sockaddr_in& addr) {
    memcpy(&remote_addr_, &addr, sizeof(remote_addr_));
    return Connect();
}

bool Client::Connect(const char* host, int port) {
    char buf[32] = {};
    snprintf(buf, sizeof buf, "%s:%d", host, port);
    return Connect(buf);
}

bool Client::Connect(const char* addr/*host:port*/) {
    struct sockaddr_in raddr = sock::ParseFromIPPort(addr);
    return Connect(raddr);
}

bool Client::Connect(const struct sockaddr& addr) {
    memcpy(&remote_addr_, &addr, sizeof(remote_addr_));
    return Connect();
}

bool Client::Connect() {
    sockfd_ = ::socket(AF_INET, SOCK_DGRAM, 0);
    sock::SetReuseAddr(sockfd_);

    socklen_t addrlen = sizeof(remote_addr_);
    int ret = ::connect(sockfd_, (struct sockaddr*)&remote_addr_, addrlen);

    if (ret != 0) {
        Close();
        struct sockaddr_in *paddr = (struct sockaddr_in*)&remote_addr_;
        LOG_ERROR << "Failed to connect to remote IP="
            << inet_ntoa(paddr->sin_addr)
            << ", port=" << ::ntohs(paddr->sin_port)
            << ", errno=" << errno << " " << strerror(errno);
        return false;
    }

    return true;
}

void Client::Close() {
    EVUTIL_CLOSESOCKET(sockfd_);
}

std::string Client::DoRequest(const std::string& data, uint32_t timeout_ms) {
    if (!Send(data)) {
        LOG_ERROR << "sent failed, errno=" << errno << " , dlen=" << data.size();
        return "";
    }

    sock::SetTimeout(sockfd_, timeout_ms);

    size_t buf_size = 1472; // The UDP max payload size
    MessagePtr msg(new Message(sockfd_, buf_size));
    socklen_t m_nAddrLen = sizeof(remote_addr_);
    int readn = ::recvfrom(sockfd_, msg->WriteBegin(), buf_size, 0, msg->mutable_remote_addr(), &m_nAddrLen);
    int err = errno;
    if (readn >= 0) {
        msg->WriteBytes(readn);
        return std::string(msg->data(), msg->size());
    } else {
        LOG_ERROR << "errno=" << err << " " << strerror(err) << " recvfrom return -1";
    }

    return "";
}

std::string Client::DoRequest(const std::string& remote_ip, int port, const std::string& udp_package_data, uint32_t timeout_ms) {
    Client c;
    if (!c.Connect(remote_ip.data(), port)) {
        return "";
    }

    return c.DoRequest(udp_package_data, timeout_ms);
}

bool Client::Send(const char* msg, size_t len) {
    int sentn = ::sendto(sockfd(),
                            msg,
                            len, 0, &remote_addr_, sizeof(remote_addr_));
    return sentn > 0;
}

bool Client::Send(const std::string& msg) {
    return Send(msg.data(), msg.size());
}

bool Client::Send(const std::string& msg, const struct sockaddr_in& addr) {
    return Client::Send(msg.data(), msg.size(), addr);
}

bool Client::Send(const char* msg, size_t len, const struct sockaddr_in& addr) {
    Client c;
    if (!c.Connect(addr)) {
        return false;
    }

    return c.Send(msg, len);
}

bool Client::Send(const MessagePtr& msg) {
    return Client::Send(msg->data(), msg->size(), *(const struct sockaddr_in*)(msg->remote_addr()));
}

bool Client::Send(const Message* msg) {
    return Client::Send(msg->data(), msg->size(), *(const struct sockaddr_in*)(msg->remote_addr()));
}

}
}
}

<commit_msg>Add comments<commit_after>#include "evpp/inner_pre.h"

#include "sync_udp_client.h"
#include "evpp/libevent_headers.h"
#include "evpp/sockets.h"

namespace evpp {
namespace udp {
namespace sync {
Client::Client() {
    sockfd_ = INVALID_SOCKET;
    memset(&remote_addr_, 0, sizeof(remote_addr_));
}

Client::~Client(void) {
    Close();
}

bool Client::Connect(const struct sockaddr_in& addr) {
    memcpy(&remote_addr_, &addr, sizeof(remote_addr_));
    return Connect();
}

bool Client::Connect(const char* host, int port) {
    char buf[32] = {};
    snprintf(buf, sizeof buf, "%s:%d", host, port);
    return Connect(buf);
}

bool Client::Connect(const char* addr/*host:port*/) {
    struct sockaddr_in raddr = sock::ParseFromIPPort(addr);
    return Connect(raddr);
}

bool Client::Connect(const struct sockaddr& addr) {
    memcpy(&remote_addr_, &addr, sizeof(remote_addr_));
    return Connect();
}

bool Client::Connect() {
    sockfd_ = ::socket(AF_INET, SOCK_DGRAM, 0);
    sock::SetReuseAddr(sockfd_);

    socklen_t addrlen = sizeof(remote_addr_);
    int ret = ::connect(sockfd_, (struct sockaddr*)&remote_addr_, addrlen);

    if (ret != 0) {
        Close();
        struct sockaddr_in *paddr = (struct sockaddr_in*)&remote_addr_;
        LOG_ERROR << "Failed to connect to remote IP="
            << inet_ntoa(paddr->sin_addr)
            << ", port=" << ::ntohs(paddr->sin_port)
            << ", errno=" << errno << " " << strerror(errno);
        return false;
    }

    return true;
}

void Client::Close() {
    EVUTIL_CLOSESOCKET(sockfd_);
}

std::string Client::DoRequest(const std::string& data, uint32_t timeout_ms) {
    if (!Send(data)) {
        LOG_ERROR << "sent failed, errno=" << errno << " , dlen=" << data.size();
        return "";
    }

    sock::SetTimeout(sockfd_, timeout_ms);

    size_t buf_size = 1472; // The UDP max payload size
    MessagePtr msg(new Message(sockfd_, buf_size));
    socklen_t m_nAddrLen = sizeof(remote_addr_);
    int readn = ::recvfrom(sockfd_, msg->WriteBegin(), buf_size, 0, msg->mutable_remote_addr(), &m_nAddrLen);
    int err = errno;
    if (readn >= 0) {
        msg->WriteBytes(readn);
        return std::string(msg->data(), msg->size());
    } else {
        LOG_ERROR << "errno=" << err << " " << strerror(err) << " recvfrom return -1";
    }

    return "";
}

std::string Client::DoRequest(const std::string& remote_ip, int port, const std::string& udp_package_data, uint32_t timeout_ms) {
    Client c;
    if (!c.Connect(remote_ip.data(), port)) {
        return "";
    }

    return c.DoRequest(udp_package_data, timeout_ms);
}

bool Client::Send(const char* msg, size_t len) {
    // TODO use 'send' to improve performance??
    int sentn = ::sendto(sockfd(),
                            msg,
                            len, 0, &remote_addr_, sizeof(remote_addr_));
    return sentn > 0;
}

bool Client::Send(const std::string& msg) {
    return Send(msg.data(), msg.size());
}

bool Client::Send(const std::string& msg, const struct sockaddr_in& addr) {
    return Client::Send(msg.data(), msg.size(), addr);
}

bool Client::Send(const char* msg, size_t len, const struct sockaddr_in& addr) {
    Client c;
    if (!c.Connect(addr)) {
        return false;
    }

    return c.Send(msg, len);
}

bool Client::Send(const MessagePtr& msg) {
    return Client::Send(msg->data(), msg->size(), *(const struct sockaddr_in*)(msg->remote_addr()));
}

bool Client::Send(const Message* msg) {
    return Client::Send(msg->data(), msg->size(), *(const struct sockaddr_in*)(msg->remote_addr()));
}

}
}
}

<|endoftext|>


<commit_before><commit_msg>BUG: returning from parsing for invalid filename<commit_after><|endoftext|>


<commit_before>

#include <time.h>
#include <sys/time.h>
#include <signal.h>   // SIGKILL

#include "logMsg/logMsg.h"                          // LM_X

#include "au/string.h"                             // au::xml_...
#include "au/TokenTaker.h"                          // au::TokenTake
#include "au/ErrorManager.h"                       // au::ErrorManager
#include "au/Token.h"                       // au::Token
#include "au/xml.h"         // au::xml...

#include "Notification.h"                           // engine::Notification

#include "engine/EngineElement.h"					// engine::EngineElement
#include "engine/ProcessItem.h"                     // engine::ProcessItem
#include "engine/DiskOperation.h"					// engine::DiskOperation
#include "engine/NotificationElement.h"       // engine::EngineNotificationElement

#include "engine/MemoryManager.h"
#include "engine/DiskManager.h"
#include "engine/ProcessManager.h"

#include "engine/Engine.h"							// Own interface

// Goyo. From 60 to 60000
#define ENGINE_MAX_RUNNING_TIME     60000

NAMESPACE_BEGIN(engine)

// Common engine
Engine *engine = NULL;

void* runEngineBakground(void* e )
{
    engine->run();
    return NULL;
}

Engine::Engine() :  EngineService("Engine") , token("EngineToken")
{
    running_element = NULL;                         // Initially, no running element
    flag_finish_threads = false;                    // Put this to "true" when destroying Engine
}

Engine::~Engine()
{
    // Remove pending elements in Engine
    elements.clearList();
}

Engine* Engine::shared()
{
    if (!engine )
        LM_X(1,("Please init Engine with Engine::init()"));
    return engine;
}

void Engine::quitEngineService()
{
    LM_V(("Quiting Engine..."));
    flag_finish_threads = true;   // Flag to indicate main thread should finish
    pthread_join(t, NULL);
    LM_V(("Quiting Engine... DONE"));
}

void Engine::init()
{
    if ( engine )
    {
        LM_W(("Init engine twice... just ignoring"));
        return;
    }

    // Create the unique engine entity
    engine = new Engine();

    // Add a simple periodic element to not die inmediatelly
    EngineElement *element = new NotificationElement( new Notification("alive") , 10 );
    engine->elements.push_back( element );

    LM_T( LmtEngine , ("Running engine in background...") );
    pthread_create(&engine->t, 0, runEngineBakground, NULL);

    // Function to remove this engine and all EngineServices like MemoryMamager, DiskManager, ProcessManager etc...
    atexit( destroy_engine_services );
}

void sleep_select( double time )
{
	fd_set          fds;
	struct timeval  timeVal;

    timeVal.tv_sec  = 0;
    timeVal.tv_usec = 0;

    if( time >= 1.0 )
    {
        timeVal.tv_sec = (long) fabs(time);
        time -= timeVal.tv_sec;
    }

    timeVal.tv_usec = time*1000000;

    FD_ZERO(&fds);
    int r = select( 1 , NULL, &fds, NULL, &timeVal);

    if( r != 0 )
        LM_W(("Select returned %d in sleep_select [ timeval %l %l ]",r  , timeVal.tv_sec , timeVal.tv_usec ));

}

void Engine::run()
{

    LM_T( LmtEngine , ("Engine run"));

    counter = 0;            // Init the counter to elements managed by this run-time

    au::Cronometer engine_cronometer;

    while( true )
    {

        if( engine_cronometer.diffTime() > 5.0 )
        {
            //LM_M(("Engine alive..."));
            engine_cronometer.reset();
        }

        // Keep a total counter of loops
        counter++;

        // Finish this thread if necessary
        if( flag_finish_threads )
            return;

        // Check if there are elements in the list
        bool isEmpty;
        {
            // Mutex protection
            au::TokenTaker tt(&token , "Engine::getNextElement");
            isEmpty = ( elements.size() == 0);
        }

        if( isEmpty )
        {
            LM_T( LmtEngine, ("SamsonEngine: No more elements to process in the engine. Quitting ..."));
            return;
        }

        // Get time for the next engine element
        double t;
        {
            // Mutex protection to access elements
            au::TokenTaker tt(&token , "Engine::getNextElement");
            t = elements.front()->getTimeToTrigger();
        }

        if( t > 0.01 ) // It not necessary to sleep less than 1/100 secs
        {
            if ( t > 0.1 )
                t = 0.1; // Max time to sleep to avoid locks...

            // Sleeping a bit for the next engine element...
            LM_T( LmtEngine, ("Engine: Sleeping %.2f secs ..." , t));

            /*
            {
                // Mutex protection to show list
                au::TokenTaker tt(&token , "Engine::getNextElement");
                LM_T( LmtEngine, ("--------------------------------------------------------" ));
                au::list<EngineElement>::iterator it_elements;
                for (it_elements = elements.begin() ; it_elements != elements.end() ; it_elements++ )
                {
                    EngineElement *element = *it_elements;
                    LM_T( LmtEngine, ("%s" , element->getShortDescription().c_str() ));
                }
                LM_T( LmtEngine, ("--------------------------------------------------------" ));
            }
             */

            {
                au::ExecesiveTimeAlarm alarm( "Engine sleep2" , 2*t );
                sleep_select( t );
            }

            /*
            {
                int microsecons = t*1000000;
                au::ExecesiveTimeAlarm alarm( "Engine sleep" , 2*t );
                usleep( microsecons );
            }
             */
            continue; // Loop again to check again...
        }

        // Get the top element to be executed
        {
            // Mutex protection to access elements
            au::TokenTaker tt(&token , "Engine::getNextElement");

            running_element = elements.front();
            elements.pop_front();
        }

        // Run or sleep
        if ( !running_element )
            LM_X(1,("Internal error at Engine"));

        {
            // Execute the item selected as running_element
            LM_T( LmtEngine, ("[START] Engine executing %s" , running_element->getDescription().c_str() ));

            int excesive_time = - running_element->getTimeToTrigger();
            if ( excesive_time > 10 )
            {
                LM_W(("Task %s delayed %d seconds in starting. This should not be more than 10"
                      , running_element->getDescription().c_str()
                      , excesive_time
                      ));
            }

            {
                // Run the item controlling excesive time
                au::ExecesiveTimeAlarm alarm( au::str("ProcessItem run '%s'",running_element->getDescription().c_str() ));
                running_element->run();
            }

            LM_T( LmtEngine, ("[DONE] Engine executing %s" , running_element->getDescription().c_str()));

            EngineElement * _running_element = running_element;
            running_element = NULL; // Put running element to NULL

            if( _running_element->isRepeated() )
            {
                // Insert again
                _running_element->Reschedule();
                add( _running_element );
            }
            else
                delete _running_element;

        }
    }
}

std::list<EngineElement*>::iterator Engine::_find_pos( EngineElement *e)
{
    for (std::list<EngineElement*>::iterator i = elements.begin() ; i != elements.end() ; i++)
    {
        if ( (*i)->getTimeToTrigger() > e->getTimeToTrigger() )
            return i;
    }

    return elements.end();
}

#pragma mark ----

// get xml information
void Engine::getInfo( std::ostringstream& output)
{
    // Mutex protection
    au::TokenTaker tt(&token , "Engine::str");

    au::xml_open(output, "engine");

    au::xml_simple(output , "loops" , counter );

    if( running_element )
        au::xml_simple( output , "running_element" , running_element->getDescription() );
    else
        au::xml_simple( output , "running_element" , "No running element" );

    au::xml_iterate_list( output , "elements" , elements );

    au::xml_simple( output , "uptime" , uptime.diffTimeInSeconds() );

    au::xml_close(output , "engine");

}

// Functions to register objects ( general and for a particular notification )
void Engine::register_object( Object* object )
{
    // Mutex protection
    au::TokenTaker tt(&token , "Engine::register_object" );

    objectsManager.add( object );
}

void Engine::register_object_for_channel( Object* object, const char* channel )
{
    // Mutex protection
    au::TokenTaker tt(&token,"Engine::register_object_for_channel");

    objectsManager.add( object , channel );
}

// Generic method to unregister an object
void Engine::unregister_object( Object* object )
{
    // Mutex protection
    au::TokenTaker tt(&token , "Engine::unregister_object");

    objectsManager.remove( object );
}

// Run a particular notification
// Only executed from friend class "NotificationElement"
void Engine::send( Notification * notification )
{
    objectsManager.send( notification );
}

// Add a notification
void Engine::notify( Notification*  notification )
{
    // Push a notification element with the notification
    add( new NotificationElement( notification ) );
}

void Engine::notify( Notification*  notification , int seconds )
{
    // Push a notification element with the notification ( in this case with periodic time )
    add( new NotificationElement( notification , seconds ) );
}

// Function to add a simple foreground tasks
void Engine::add( EngineElement *element )
{
    // Mutex protection
    au::TokenTaker tt(&token);

    // Insert an element in the engine
    elements.insert( _find_pos( element ) ,  element );

    // Wake up main thread if sleeping
    tt.wakeUp();
}

// Get an object by its registry names
Object* Engine::getObjectByName( const char *name )
{
    // Mutex protection
    au::TokenTaker tt(&token);

    return objectsManager.getObjectByName(name);

}

NAMESPACE_END
<commit_msg>Replacing an LM_X for an LM_E and a 'return NULL' This is needed for unit testing and might produce some confusion (and SIGSEGVs if engine not correctly initialized ...) But I don't think this is a problem as we initialize correctly<commit_after>

#include <time.h>
#include <sys/time.h>
#include <signal.h>   // SIGKILL

#include "logMsg/logMsg.h"                          // LM_X

#include "au/string.h"                             // au::xml_...
#include "au/TokenTaker.h"                          // au::TokenTake
#include "au/ErrorManager.h"                       // au::ErrorManager
#include "au/Token.h"                       // au::Token
#include "au/xml.h"         // au::xml...

#include "Notification.h"                           // engine::Notification

#include "engine/EngineElement.h"					// engine::EngineElement
#include "engine/ProcessItem.h"                     // engine::ProcessItem
#include "engine/DiskOperation.h"					// engine::DiskOperation
#include "engine/NotificationElement.h"       // engine::EngineNotificationElement

#include "engine/MemoryManager.h"
#include "engine/DiskManager.h"
#include "engine/ProcessManager.h"

#include "engine/Engine.h"							// Own interface

// Goyo. From 60 to 60000
#define ENGINE_MAX_RUNNING_TIME     60000

NAMESPACE_BEGIN(engine)

// Common engine
Engine *engine = NULL;

void* runEngineBakground(void* e )
{
    engine->run();
    return NULL;
}

Engine::Engine() :  EngineService("Engine") , token("EngineToken")
{
    running_element = NULL;                         // Initially, no running element
    flag_finish_threads = false;                    // Put this to "true" when destroying Engine
}

Engine::~Engine()
{
    // Remove pending elements in Engine
    elements.clearList();
}

Engine* Engine::shared()
{
    if (!engine)
    {
	   LM_E(("Please initialize Engine before using it, calling Engine::init()"));
	   return NULL;
	}

    return engine;
}

void Engine::quitEngineService()
{
    LM_V(("Quiting Engine..."));
    flag_finish_threads = true;   // Flag to indicate main thread should finish
    pthread_join(t, NULL);
    LM_V(("Quiting Engine... DONE"));
}

void Engine::init()
{
    if ( engine )
    {
        LM_W(("Init engine twice... just ignoring"));
        return;
    }

    // Create the unique engine entity
    engine = new Engine();

    // Add a simple periodic element to not die inmediatelly
    EngineElement *element = new NotificationElement( new Notification("alive") , 10 );
    engine->elements.push_back( element );

    LM_T( LmtEngine , ("Running engine in background...") );
    pthread_create(&engine->t, 0, runEngineBakground, NULL);

    // Function to remove this engine and all EngineServices like MemoryMamager, DiskManager, ProcessManager etc...
    atexit( destroy_engine_services );
}

void sleep_select( double time )
{
	fd_set          fds;
	struct timeval  timeVal;

    timeVal.tv_sec  = 0;
    timeVal.tv_usec = 0;

    if( time >= 1.0 )
    {
        timeVal.tv_sec = (long) fabs(time);
        time -= timeVal.tv_sec;
    }

    timeVal.tv_usec = time*1000000;

    FD_ZERO(&fds);
    int r = select( 1 , NULL, &fds, NULL, &timeVal);

    if( r != 0 )
        LM_W(("Select returned %d in sleep_select [ timeval %l %l ]",r  , timeVal.tv_sec , timeVal.tv_usec ));

}

void Engine::run()
{

    LM_T( LmtEngine , ("Engine run"));

    counter = 0;            // Init the counter to elements managed by this run-time

    au::Cronometer engine_cronometer;

    while( true )
    {

        if( engine_cronometer.diffTime() > 5.0 )
        {
            //LM_M(("Engine alive..."));
            engine_cronometer.reset();
        }

        // Keep a total counter of loops
        counter++;

        // Finish this thread if necessary
        if( flag_finish_threads )
            return;

        // Check if there are elements in the list
        bool isEmpty;
        {
            // Mutex protection
            au::TokenTaker tt(&token , "Engine::getNextElement");
            isEmpty = ( elements.size() == 0);
        }

        if( isEmpty )
        {
            LM_T( LmtEngine, ("SamsonEngine: No more elements to process in the engine. Quitting ..."));
            return;
        }

        // Get time for the next engine element
        double t;
        {
            // Mutex protection to access elements
            au::TokenTaker tt(&token , "Engine::getNextElement");
            t = elements.front()->getTimeToTrigger();
        }

        if( t > 0.01 ) // It not necessary to sleep less than 1/100 secs
        {
            if ( t > 0.1 )
                t = 0.1; // Max time to sleep to avoid locks...

            // Sleeping a bit for the next engine element...
            LM_T( LmtEngine, ("Engine: Sleeping %.2f secs ..." , t));

            /*
            {
                // Mutex protection to show list
                au::TokenTaker tt(&token , "Engine::getNextElement");
                LM_T( LmtEngine, ("--------------------------------------------------------" ));
                au::list<EngineElement>::iterator it_elements;
                for (it_elements = elements.begin() ; it_elements != elements.end() ; it_elements++ )
                {
                    EngineElement *element = *it_elements;
                    LM_T( LmtEngine, ("%s" , element->getShortDescription().c_str() ));
                }
                LM_T( LmtEngine, ("--------------------------------------------------------" ));
            }
             */

            {
                au::ExecesiveTimeAlarm alarm( "Engine sleep2" , 2*t );
                sleep_select( t );
            }

            /*
            {
                int microsecons = t*1000000;
                au::ExecesiveTimeAlarm alarm( "Engine sleep" , 2*t );
                usleep( microsecons );
            }
             */
            continue; // Loop again to check again...
        }

        // Get the top element to be executed
        {
            // Mutex protection to access elements
            au::TokenTaker tt(&token , "Engine::getNextElement");

            running_element = elements.front();
            elements.pop_front();
        }

        // Run or sleep
        if ( !running_element )
            LM_X(1,("Internal error at Engine"));

        {
            // Execute the item selected as running_element
            LM_T( LmtEngine, ("[START] Engine executing %s" , running_element->getDescription().c_str() ));

            int excesive_time = - running_element->getTimeToTrigger();
            if ( excesive_time > 10 )
            {
                LM_W(("Task %s delayed %d seconds in starting. This should not be more than 10"
                      , running_element->getDescription().c_str()
                      , excesive_time
                      ));
            }

            {
                // Run the item controlling excesive time
                au::ExecesiveTimeAlarm alarm( au::str("ProcessItem run '%s'",running_element->getDescription().c_str() ));
                running_element->run();
            }

            LM_T( LmtEngine, ("[DONE] Engine executing %s" , running_element->getDescription().c_str()));

            EngineElement * _running_element = running_element;
            running_element = NULL; // Put running element to NULL

            if( _running_element->isRepeated() )
            {
                // Insert again
                _running_element->Reschedule();
                add( _running_element );
            }
            else
                delete _running_element;

        }
    }
}

std::list<EngineElement*>::iterator Engine::_find_pos( EngineElement *e)
{
    for (std::list<EngineElement*>::iterator i = elements.begin() ; i != elements.end() ; i++)
    {
        if ( (*i)->getTimeToTrigger() > e->getTimeToTrigger() )
            return i;
    }

    return elements.end();
}

#pragma mark ----

// get xml information
void Engine::getInfo( std::ostringstream& output)
{
    // Mutex protection
    au::TokenTaker tt(&token , "Engine::str");

    au::xml_open(output, "engine");

    au::xml_simple(output , "loops" , counter );

    if( running_element )
        au::xml_simple( output , "running_element" , running_element->getDescription() );
    else
        au::xml_simple( output , "running_element" , "No running element" );

    au::xml_iterate_list( output , "elements" , elements );

    au::xml_simple( output , "uptime" , uptime.diffTimeInSeconds() );

    au::xml_close(output , "engine");

}

// Functions to register objects ( general and for a particular notification )
void Engine::register_object( Object* object )
{
    // Mutex protection
    au::TokenTaker tt(&token , "Engine::register_object" );

    objectsManager.add( object );
}

void Engine::register_object_for_channel( Object* object, const char* channel )
{
    // Mutex protection
    au::TokenTaker tt(&token,"Engine::register_object_for_channel");

    objectsManager.add( object , channel );
}

// Generic method to unregister an object
void Engine::unregister_object( Object* object )
{
    // Mutex protection
    au::TokenTaker tt(&token , "Engine::unregister_object");

    objectsManager.remove( object );
}

// Run a particular notification
// Only executed from friend class "NotificationElement"
void Engine::send( Notification * notification )
{
    objectsManager.send( notification );
}

// Add a notification
void Engine::notify( Notification*  notification )
{
    // Push a notification element with the notification
    add( new NotificationElement( notification ) );
}

void Engine::notify( Notification*  notification , int seconds )
{
    // Push a notification element with the notification ( in this case with periodic time )
    add( new NotificationElement( notification , seconds ) );
}

// Function to add a simple foreground tasks
void Engine::add( EngineElement *element )
{
    // Mutex protection
    au::TokenTaker tt(&token);

    // Insert an element in the engine
    elements.insert( _find_pos( element ) ,  element );

    // Wake up main thread if sleeping
    tt.wakeUp();
}

// Get an object by its registry names
Object* Engine::getObjectByName( const char *name )
{
    // Mutex protection
    au::TokenTaker tt(&token);

    return objectsManager.getObjectByName(name);

}

NAMESPACE_END
<|endoftext|>


<commit_before>/* Numenta Platform for Intelligent Computing (NuPIC)
 * Copyright (C) 2017, Numenta, Inc.  Unless you have an agreement
 * with Numenta, Inc., for a separate license for this software code, the
 * following terms and conditions apply:
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero Public License version 3 as
 * published by the Free Software Foundation.
 *
 * 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 Affero Public License for more details.
 *
 * You should have received a copy of the GNU Affero Public License
 * along with this program.  If not, see http://www.gnu.org/licenses.
 *
 * http://numenta.org/licenses/
 * ---------------------------------------------------------------------
 */

#ifndef NUPIC_UTIL_SLIDING_WINDOW_HPP
#define NUPIC_UTIL_SLIDING_WINDOW_HPP

#include <vector>
#include <algorithm>
#include <iterator>
#include <cmath>
#include <string>

#include <nupic/types/Types.hpp>
#include <nupic/utils/Log.hpp>
#include <nupic/math/Math.hpp> //for macro ASSERT_INPUT_ITERATOR

namespace nupic {
  namespace util {

template<class T>
class SlidingWindow {
  public:
    SlidingWindow(UInt maxCapacity, std::string id="SlidingWindow", int debug=0) :
      maxCapacity(maxCapacity),
      ID(id),
      DEBUG(debug)
{
      buffer_.reserve(maxCapacity);
      idxNext_ = 0;
}

    template<class IteratorT>
    SlidingWindow(UInt maxCapacity, IteratorT initialData_begin,
      IteratorT initialData_end, std::string id="SlidingWindow", int debug=0):
      SlidingWindow(maxCapacity, id, debug) {
      // Assert that It obeys the STL forward iterator concept
      ASSERT_INPUT_ITERATOR(IteratorT);
      for(IteratorT it = initialData_begin; it != initialData_end; ++it) {
        append(*it);
      }
    }

    const UInt maxCapacity;
    const std::string ID; //name of this object
    const int DEBUG;

    size_t size() const {
      NTA_ASSERT(buffer_.size() <= maxCapacity);
      return buffer_.size();
    }

    /** append new value to the end of the buffer and handle the
       "overflows"-may pop the oldest element if full.
      */
    void append(T newValue) {
      if(size() < maxCapacity) {
        buffer_.push_back(newValue);
      } else {
        buffer_[idxNext_] = newValue;
      }
      idxNext_ = (idxNext_ +1 ) %maxCapacity;
    }

      /** like append, but return the dropped value if it was dropped.
        :param T newValue - new value to append to the sliding window
        :param T* - a return pass-by-value with the removed element,
          if this function returns false, this value will remain unchanged.
        :return bool if some value has been dropped (and updated as
          droppedValue)
      */
      bool append(T newValue, T* droppedValue) {
        //only in this case we drop oldest; this happens always after
        //first maxCap steps ; must be checked before append()
        bool isFull = (buffer_.size()==maxCapacity);
        if(isFull) {
          *droppedValue = buffer_[idxNext_];
        }
        append(newValue);
        return isFull;
      }

      /**
        :return unordered content (data ) of this sl. window;
          call getLinearizedData() if you need them oredered from
          oldest->newest
        This direct access method is fast.
      */
      const std::vector<T>& getData() const {
        return buffer_;
      }

      /** linearize method for the internal buffer; this is slower than
        the pure getData() but ensures that the data are ordered (oldest at
        the beginning, newest at the end of the vector
        This handles case of |5,6;1,2,3,4| => |1,2,3,4,5,6|
        :return new linearized vector
      */
      std::vector<T> getLinearizedData() const {
        std::vector<T> lin;
        lin.reserve(buffer_.size());

        //insert the "older" part at the beginning
        lin.insert(std::begin(lin), std::begin(buffer_) + idxNext_, std::end(buffer_));
        //append the "newer" part to the end of the constructed vect
        lin.insert(std::end(lin), std::begin(buffer_), std::begin(buffer_) + idxNext_);
        return lin;
      }

      bool operator==(const SlidingWindow& r2) const {
        return ((this->size() == r2.size()) && (this->maxCapacity == r2.maxCapacity) &&
          (this->getData()== r2.getData()) && getLinearizedData() == r2.getLinearizedData());
        //FIXME review the ==, on my machine it randomly passes/fails the test!
      }

      bool operator!=(const SlidingWindow& r2) const {
        return !operator==(r2);
      }

      /** operator[] provides fast access to the elements indexed relatively
        to the oldest element. So slidingWindow[0] returns oldest element,
        slidingWindow[size()] returns the newest.
      :param UInt index - index/offset from the oldest element, values 0..size()
      :return T - i-th oldest value in the buffer
      :throws 0<=index<=size()
      */
      T& operator[](UInt index) {
        NTA_ASSERT(index <= size());
        NTA_ASSERT(size() > 0);
        //get last updated position, "current"+index(offset)
        //avoid calling getLinearizeData() as it involves copy()
        if (size() == maxCapacity) {
          return &buffer_[(idxNext_ + index) % maxCapacity];
        } else {
          return &buffer_[index];
        }
      }

      const T& operator[](UInt index) const {
        return this->operator[](index); //call the overloaded operator[] above
      }

      std::ostream& operator<<(std::ostream& os) {
        return os << ID << std::endl;
      }

      private:
        std::vector<T> buffer_;
        UInt idxNext_;
};
}} //end ns
#endif //header
<commit_msg>SlidingWindow: use const for internal variables<commit_after>/* Numenta Platform for Intelligent Computing (NuPIC)
 * Copyright (C) 2017, Numenta, Inc.  Unless you have an agreement
 * with Numenta, Inc., for a separate license for this software code, the
 * following terms and conditions apply:
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero Public License version 3 as
 * published by the Free Software Foundation.
 *
 * 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 Affero Public License for more details.
 *
 * You should have received a copy of the GNU Affero Public License
 * along with this program.  If not, see http://www.gnu.org/licenses.
 *
 * http://numenta.org/licenses/
 * ---------------------------------------------------------------------
 */

#ifndef NUPIC_UTIL_SLIDING_WINDOW_HPP
#define NUPIC_UTIL_SLIDING_WINDOW_HPP

#include <vector>
#include <algorithm>
#include <iterator>
#include <cmath>
#include <string>

#include <nupic/types/Types.hpp>
#include <nupic/utils/Log.hpp>
#include <nupic/math/Math.hpp> //for macro ASSERT_INPUT_ITERATOR

namespace nupic {
  namespace util {

template<class T>
class SlidingWindow {
  public:
    SlidingWindow(UInt maxCapacity, std::string id="SlidingWindow", int debug=0) :
      maxCapacity(maxCapacity),
      ID(id),
      DEBUG(debug)
{
      buffer_.reserve(maxCapacity);
      idxNext_ = 0;
}

    template<class IteratorT>
    SlidingWindow(UInt maxCapacity, IteratorT initialData_begin,
      IteratorT initialData_end, std::string id="SlidingWindow", int debug=0):
      SlidingWindow(maxCapacity, id, debug) {
      // Assert that It obeys the STL forward iterator concept
      ASSERT_INPUT_ITERATOR(IteratorT);
      for(IteratorT it = initialData_begin; it != initialData_end; ++it) {
        append(*it);
      }
    }

    const UInt maxCapacity;
    const std::string ID; //name of this object
    const int DEBUG;

    size_t size() const {
      NTA_ASSERT(buffer_.size() <= maxCapacity);
      return buffer_.size();
    }

    /** append new value to the end of the buffer and handle the
       "overflows"-may pop the oldest element if full.
      */
    void append(T newValue) {
      if(size() < maxCapacity) {
        buffer_.push_back(newValue);
      } else {
        buffer_[idxNext_] = newValue;
      }
      idxNext_ = (idxNext_ +1 ) %maxCapacity;
    }

      /** like append, but return the dropped value if it was dropped.
        :param T newValue - new value to append to the sliding window
        :param T* - a return pass-by-value with the removed element,
          if this function returns false, this value will remain unchanged.
        :return bool if some value has been dropped (and updated as
          droppedValue)
      */
      bool append(T newValue, T* droppedValue) {
        //only in this case we drop oldest; this happens always after
        //first maxCap steps ; must be checked before append()
        const bool isFull = (buffer_.size()==maxCapacity);
        if(isFull) {
          *droppedValue = buffer_[idxNext_];
        }
        append(newValue);
        return isFull;
      }

      /**
        :return unordered content (data ) of this sl. window;
          call getLinearizedData() if you need them oredered from
          oldest->newest
        This direct access method is fast.
      */
      const std::vector<T>& getData() const {
        return buffer_;
      }

      /** linearize method for the internal buffer; this is slower than
        the pure getData() but ensures that the data are ordered (oldest at
        the beginning, newest at the end of the vector
        This handles case of |5,6;1,2,3,4| => |1,2,3,4,5,6|
        :return new linearized vector
      */
      std::vector<T> getLinearizedData() const {
        std::vector<T> lin;
        lin.reserve(buffer_.size());

        //insert the "older" part at the beginning
        lin.insert(std::begin(lin), std::begin(buffer_) + idxNext_, std::end(buffer_));
        //append the "newer" part to the end of the constructed vect
        lin.insert(std::end(lin), std::begin(buffer_), std::begin(buffer_) + idxNext_);
        return lin;
      }

      bool operator==(const SlidingWindow& r2) const {
        return ((this->size() == r2.size()) && (this->maxCapacity == r2.maxCapacity) &&
          (this->getData()== r2.getData()) && getLinearizedData() == r2.getLinearizedData());
        //FIXME review the ==, on my machine it randomly passes/fails the test!
      }

      bool operator!=(const SlidingWindow& r2) const {
        return !operator==(r2);
      }

      /** operator[] provides fast access to the elements indexed relatively
        to the oldest element. So slidingWindow[0] returns oldest element,
        slidingWindow[size()] returns the newest.
      :param UInt index - index/offset from the oldest element, values 0..size()
      :return T - i-th oldest value in the buffer
      :throws 0<=index<=size()
      */
      T& operator[](UInt index) {
        NTA_ASSERT(index <= size());
        NTA_ASSERT(size() > 0);
        //get last updated position, "current"+index(offset)
        //avoid calling getLinearizeData() as it involves copy()
        if (size() == maxCapacity) {
          return &buffer_[(idxNext_ + index) % maxCapacity];
        } else {
          return &buffer_[index];
        }
      }

      const T& operator[](UInt index) const {
        return this->operator[](index); //call the overloaded operator[] above
      }

      std::ostream& operator<<(std::ostream& os) {
        return os << ID << std::endl;
      }

      private:
        std::vector<T> buffer_;
        UInt idxNext_;
};
}} //end ns
#endif //header
<|endoftext|>