<commit_before>#include "domains/messaging/encoding.hpp"
#include <kerchow/kerchow.h>
#if __has_include(<catch / catch.hpp>)
#include <catch/catch.hpp>
#elif __has_include(<catch.hpp>)
#include <catch.hpp>
#endif

using namespace domains;
using kerchow::picker;

using ENCODING = domains::native_endian_encoding;

namespace {

bool const is_big_endian = [] {
   short const x = 0xABCD;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wtype-limits"
   return 0xAB == reinterpret_cast<char const *>(&x)[0];
#pragma GCC diagnostic pop
}();

TEST_CASE("Encoding and decoding", "[encoding]") {
   alignas(std::max_align_t) uint8_t same_memory[sizeof(std::uintmax_t)] = {0};
   alignas(std::max_align_t) uint8_t diff_memory[sizeof(std::uintmax_t)] = {0};
   alignas(std::max_align_t) uint8_t native_memory[sizeof(std::uintmax_t)] = {0};
   uint8_t u8 = picker.pick<uint8_t>();
   uint16_t u16 = picker.pick<uint16_t>();
   uint32_t u32 = picker.pick<uint32_t>();
   uint64_t u64 = picker.pick<uint64_t>();

   auto encode_and_test = [&](auto const value) {
      native_endian_encoding::encode(value, native_memory);
      if (is_big_endian) {
         big_endian_encoding::encode(value, same_memory);
         little_endian_encoding::encode(value, diff_memory);
      } else {
         big_endian_encoding::encode(value, diff_memory);
         little_endian_encoding::encode(value, same_memory);
      }
      REQUIRE(std::equal(&native_memory[0], &native_memory[sizeof(value)], &same_memory[0],
                         &same_memory[sizeof(value)]));
      REQUIRE(std::equal(&native_memory[0], &native_memory[sizeof(value)],
                         std::make_reverse_iterator(&diff_memory[sizeof(value)]),
                         std::make_reverse_iterator(&diff_memory[0])));
   };

   auto native_decode_test = [&](auto const value) {
      std::remove_const_t<decltype(value)> new_value = ~value;
      native_endian_encoding::encode(value, native_memory);
      if (is_big_endian) {
         big_endian_encoding::decode(new_value, &native_memory[0]);
      } else {
         little_endian_encoding::decode(new_value, &native_memory[0]);
      }
      REQUIRE(value == new_value);
   };

   auto encode_decode_test = [&](auto const value, auto encoding) {
      std::remove_const_t<decltype(value)> new_value = ~value;
      decltype(encoding)::encode(value, &native_memory[0]);
      decltype(encoding)::decode(new_value, &native_memory[0]);
      REQUIRE(value == new_value);
   };

   SECTION("encodeting is encoded properly") {
      encode_and_test(u8);
      encode_and_test(u16);
      encode_and_test(u32);
      encode_and_test(u64);
   }

   SECTION("decodeing from encode value returns same value") {
      native_decode_test(u8);
      native_decode_test(u16);
      native_decode_test(u32);
      native_decode_test(u64);
   }

   SECTION("decodeing from encode value returns same value") {
      encode_decode_test(u8, big_endian_encoding{});
      encode_decode_test(u16, big_endian_encoding{});
      encode_decode_test(u32, big_endian_encoding{});
      encode_decode_test(u64, big_endian_encoding{});
      encode_decode_test(u8, little_endian_encoding{});
      encode_decode_test(u16, little_endian_encoding{});
      encode_decode_test(u32, little_endian_encoding{});
      encode_decode_test(u64, little_endian_encoding{});
      encode_decode_test(u8, native_endian_encoding{});
      encode_decode_test(u16, native_endian_encoding{});
      encode_decode_test(u32, native_endian_encoding{});
      encode_decode_test(u64, native_endian_encoding{});
   }
}
}
<commit_msg>Use byte type in test<commit_after>#include "domains/messaging/encoding.hpp"
#include <kerchow/kerchow.h>
#if __has_include(<catch / catch.hpp>)
#include <catch/catch.hpp>
#elif __has_include(<catch.hpp>)
#include <catch.hpp>
#endif

using namespace domains;
using kerchow::picker;

using ENCODING = domains::native_endian_encoding;

namespace {

bool const is_big_endian = [] {
   short const x = 0xABCD;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wtype-limits"
   return 0xAB == reinterpret_cast<char const *>(&x)[0];
#pragma GCC diagnostic pop
}();

TEST_CASE("Encoding and decoding", "[encoding]") {
   alignas(std::max_align_t) byte same_memory[sizeof(std::uintmax_t)] = {static_cast<byte>(0)};
   alignas(std::max_align_t) byte diff_memory[sizeof(std::uintmax_t)] = {static_cast<byte>(0)};
   alignas(std::max_align_t) byte native_memory[sizeof(std::uintmax_t)] = {static_cast<byte>(0)};
   uint8_t u8 = picker.pick<uint8_t>();
   uint16_t u16 = picker.pick<uint16_t>();
   uint32_t u32 = picker.pick<uint32_t>();
   uint64_t u64 = picker.pick<uint64_t>();

   auto encode_and_test = [&](auto const value) {
      native_endian_encoding::encode(value, native_memory);
      if (is_big_endian) {
         big_endian_encoding::encode(value, same_memory);
         little_endian_encoding::encode(value, diff_memory);
      } else {
         big_endian_encoding::encode(value, diff_memory);
         little_endian_encoding::encode(value, same_memory);
      }
      REQUIRE(std::equal(&native_memory[0], &native_memory[sizeof(value)], &same_memory[0],
                         &same_memory[sizeof(value)]));
      REQUIRE(std::equal(&native_memory[0], &native_memory[sizeof(value)],
                         std::make_reverse_iterator(&diff_memory[sizeof(value)]),
                         std::make_reverse_iterator(&diff_memory[0])));
   };

   auto native_decode_test = [&](auto const value) {
      std::remove_const_t<decltype(value)> new_value = ~value;
      native_endian_encoding::encode(value, native_memory);
      if (is_big_endian) {
         big_endian_encoding::decode(new_value, &native_memory[0]);
      } else {
         little_endian_encoding::decode(new_value, &native_memory[0]);
      }
      REQUIRE(value == new_value);
   };

   auto encode_decode_test = [&](auto const value, auto encoding) {
      std::remove_const_t<decltype(value)> new_value = ~value;
      decltype(encoding)::encode(value, &native_memory[0]);
      decltype(encoding)::decode(new_value, &native_memory[0]);
      REQUIRE(value == new_value);
   };

   SECTION("encodeting is encoded properly") {
      encode_and_test(u8);
      encode_and_test(u16);
      encode_and_test(u32);
      encode_and_test(u64);
   }

   SECTION("decodeing from encode value returns same value") {
      native_decode_test(u8);
      native_decode_test(u16);
      native_decode_test(u32);
      native_decode_test(u64);
   }

   SECTION("decodeing from encode value returns same value") {
      encode_decode_test(u8, big_endian_encoding{});
      encode_decode_test(u16, big_endian_encoding{});
      encode_decode_test(u32, big_endian_encoding{});
      encode_decode_test(u64, big_endian_encoding{});
      encode_decode_test(u8, little_endian_encoding{});
      encode_decode_test(u16, little_endian_encoding{});
      encode_decode_test(u32, little_endian_encoding{});
      encode_decode_test(u64, little_endian_encoding{});
      encode_decode_test(u8, native_endian_encoding{});
      encode_decode_test(u16, native_endian_encoding{});
      encode_decode_test(u32, native_endian_encoding{});
      encode_decode_test(u64, native_endian_encoding{});
   }
}
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: acccfg.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: pb $ $Date: 2001-06-28 13:39:21 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _ACCCFG_HXX
#define _ACCCFG_HXX

// #include *****************************************************************

#ifndef _SV_FIXED_HXX //autogen
#include <vcl/fixed.hxx>
#endif
#ifndef _SV_BUTTON_HXX //autogen
#include <vcl/button.hxx>
#endif
#ifndef _SV_DIALOG_HXX //autogen
#include <vcl/dialog.hxx>
#endif
#ifndef _SV_LSTBOX_HXX //autogen
#include <vcl/lstbox.hxx>
#endif
#include "minarray.hxx"

// forward ******************************************************************

class SfxAcceleratorManager;

// class SfxAcceleratorConfigListBox *************************************************

class SfxAcceleratorConfigListBox : public ListBox
{
    void KeyInput( const KeyEvent &rKEvt );

public:

    SfxAcceleratorConfigListBox( Window *pParent, ResId &rResId ) :
        ListBox( pParent, rResId ) {}

    void ReplaceEntry( USHORT nPos, const String &rStr );
    void ExpandEntry ( USHORT nPos, const String &rStr );
};

// class USHORTArr **********************************************************

#if !defined(_MNUCFG_HXX) && !defined(_TBXCFG_HXX)
DECL_2BYTEARRAY(USHORTArr, USHORT, 10, 10);
#endif

// class SfxAcceleratorConfigDialog **************************************************

class SfxAcceleratorConfigDialog : public ModalDialog
{
    OKButton           aOKButton;
    CancelButton       aCancelButton;
    PushButton         aChangeButton;
    PushButton         aRemoveButton;
    SfxAcceleratorConfigListBox aEntriesBox;
    FixedText          aDescriptionTextText;
    FixedText          aDescriptionInfoText;
    FixedLine          aKeyboardGroup;
    FixedText          aGroupText;
    ListBox            aGroupLBox;
    FixedText          aFunctionText;
    ListBox            aFunctionBox;
    FixedText          aKeyText;
    ListBox            aKeyBox;
    FixedLine          aFunctionsGroup;

    SfxAcceleratorManager *pMgr;

    USHORTArr     aAccelArr;
    USHORTArr     aFunctionArr;
    USHORTArr     aKeyArr;

    void OKHdl    ( Button  * );
    void ChangeHdl( Button  * );
    void RemoveHdl( Button  * );
    void SelectHdl( ListBox *pListBox );

    KeyCode PosToKeyCode   ( USHORT nPos )          const;
    USHORT  KeyCodeToPos   ( const KeyCode &rCode ) const;
    String  GetFunctionName( KeyFuncType eType )    const;

public:

    SfxAcceleratorConfigDialog( Window *pParent );
};

#endif

<commit_msg>INTEGRATION: CWS ooo19126 (1.3.1070); FILE MERGED 2005/09/06 13:05:20 rt 1.3.1070.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: acccfg.hxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-07 18:53:32 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _ACCCFG_HXX
#define _ACCCFG_HXX

// #include *****************************************************************

#ifndef _SV_FIXED_HXX //autogen
#include <vcl/fixed.hxx>
#endif
#ifndef _SV_BUTTON_HXX //autogen
#include <vcl/button.hxx>
#endif
#ifndef _SV_DIALOG_HXX //autogen
#include <vcl/dialog.hxx>
#endif
#ifndef _SV_LSTBOX_HXX //autogen
#include <vcl/lstbox.hxx>
#endif
#include "minarray.hxx"

// forward ******************************************************************

class SfxAcceleratorManager;

// class SfxAcceleratorConfigListBox *************************************************

class SfxAcceleratorConfigListBox : public ListBox
{
    void KeyInput( const KeyEvent &rKEvt );

public:

    SfxAcceleratorConfigListBox( Window *pParent, ResId &rResId ) :
        ListBox( pParent, rResId ) {}

    void ReplaceEntry( USHORT nPos, const String &rStr );
    void ExpandEntry ( USHORT nPos, const String &rStr );
};

// class USHORTArr **********************************************************

#if !defined(_MNUCFG_HXX) && !defined(_TBXCFG_HXX)
DECL_2BYTEARRAY(USHORTArr, USHORT, 10, 10);
#endif

// class SfxAcceleratorConfigDialog **************************************************

class SfxAcceleratorConfigDialog : public ModalDialog
{
    OKButton           aOKButton;
    CancelButton       aCancelButton;
    PushButton         aChangeButton;
    PushButton         aRemoveButton;
    SfxAcceleratorConfigListBox aEntriesBox;
    FixedText          aDescriptionTextText;
    FixedText          aDescriptionInfoText;
    FixedLine          aKeyboardGroup;
    FixedText          aGroupText;
    ListBox            aGroupLBox;
    FixedText          aFunctionText;
    ListBox            aFunctionBox;
    FixedText          aKeyText;
    ListBox            aKeyBox;
    FixedLine          aFunctionsGroup;

    SfxAcceleratorManager *pMgr;

    USHORTArr     aAccelArr;
    USHORTArr     aFunctionArr;
    USHORTArr     aKeyArr;

    void OKHdl    ( Button  * );
    void ChangeHdl( Button  * );
    void RemoveHdl( Button  * );
    void SelectHdl( ListBox *pListBox );

    KeyCode PosToKeyCode   ( USHORT nPos )          const;
    USHORT  KeyCodeToPos   ( const KeyCode &rCode ) const;
    String  GetFunctionName( KeyFuncType eType )    const;

public:

    SfxAcceleratorConfigDialog( Window *pParent );
};

#endif

<|endoftext|>


<commit_before>/*
 * jsonrpc.c
 *
 * =========================================================================
 * Copyright (c) 2016-2019 Daniele De Sensi (d.desensi.software@gmail.com)
 *
 * 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 <peafowl/inspectors/inspectors.h>
#include <peafowl/peafowl.h>

#include "../external/rapidjson/document.h"
#include "../external/rapidjson/error/en.h"

#include <iostream>
#include "../external/rapidjson/stringbuffer.h"
#include "../external/rapidjson/writer.h"

#define PFWL_DEBUG_DISS_JSONRPC 0
#define debug_print(fmt, ...)                                                  \
  do {                                                                         \
    if (PFWL_DEBUG_DISS_JSONRPC)                                               \
      fprintf(stdout, fmt, __VA_ARGS__);                                       \
  } while (0)

using namespace rapidjson;

bool hasField(Document& d, const char* field){
  auto it = d.FindMember(field);
  return it != d.MemberEnd();
}

const unsigned char* getFieldAsString(Document& d, pfwl_field_id_t fieldId, const char* field, int persistent, pfwl_flow_info_private_t* flow_info_private){
  auto it = d.FindMember(field);
  if(it != d.MemberEnd()){
    if(it->value.IsString() || it->value.IsNumber()){
      return reinterpret_cast<const unsigned char*>(it->value.GetString());
    }else{
      if(persistent){
        size_t position = fieldId - PFWL_FIELDS_L7_JSON_RPC_FIRST - 1;
        StringBuffer* sb;
        if(!flow_info_private->json_stringbuffers[position]){
          sb = new StringBuffer();
          flow_info_private->json_stringbuffers[position] = static_cast<void*>(sb);
        }else{
          sb = static_cast<StringBuffer*>(flow_info_private->json_stringbuffers[position]);
          sb->Clear();
        }
        Writer<StringBuffer> writer(*sb);
        it->value.Accept(writer);
        return reinterpret_cast<const unsigned char*>(sb->GetString());
      }else{
        StringBuffer sb;
        Writer<StringBuffer> writer(sb);
        it->value.Accept(writer);
        return reinterpret_cast<const unsigned char*>(sb.GetString());
      }
    }
  }else{
    return NULL;
  }
}

void setIfPresent(Document& d, pfwl_field_t* fields, pfwl_field_id_t fieldId, const char* fieldName, pfwl_flow_info_private_t* flow_info_private){
  const unsigned char* fieldValue = getFieldAsString(d, fieldId, fieldName, 1, flow_info_private);
  if(fieldValue){
    pfwl_field_string_set(fields, fieldId, fieldValue, strlen((const char*) fieldValue));
  }
}

typedef enum{
  PFWL_JSONRPC_MSG_TYPE_REQUEST = 0,
  PFWL_JSONRPC_MSG_TYPE_RESPONSE,
  PFWL_JSONRPC_MSG_TYPE_NOTIFICATION,
  PFWL_JSONRPC_MSG_TYPE_NONE, /// Not jsonrpc
}pfwl_jsonrpc_msg_type_t;

static void jsonrpc_flow_cleaner(pfwl_flow_info_private_t *flow_info_private){
  for(size_t i = PFWL_FIELDS_L7_JSON_RPC_FIRST + 1; i < PFWL_FIELDS_L7_JSON_RPC_LAST; i++){
    size_t position = i - PFWL_FIELDS_L7_JSON_RPC_FIRST - 1;
    if(flow_info_private->json_stringbuffers[position]){
      delete static_cast<StringBuffer*>(flow_info_private->json_stringbuffers[position]);
    }
  }
  if(flow_info_private->json_parser){
    delete static_cast<Document*>(flow_info_private->json_parser);
  }
}

static bool isJsonCt(const pfwl_string_t& ct){
  return !strncmp(reinterpret_cast<const char*>(ct.value), "application/json-rpc"   , ct.length) ||
         !strncmp(reinterpret_cast<const char*>(ct.value), "application/json"       , ct.length) ||
         !strncmp(reinterpret_cast<const char*>(ct.value), "application/jsonrequest", ct.length);
}

typedef enum{
  JRPC_HTTP_MAYBE = 0,
  JRPC_HTTP_NO,
  JRPC_HTTP_MORE_DATA,
}JsonRpcOverHttpCheck;

JsonRpcOverHttpCheck check_jsonrpc_over_http(pfwl_dissection_info_t *pkt_info,
                                             pfwl_flow_info_private_t *flow_info_private,
                                             const unsigned char* &http_body,
                                             size_t& http_body_length){
  debug_print("%s", "Checking json over http\n");
  if(flow_info_private->l7_protocols[flow_info_private->l7_protocols_num - 1] == PFWL_PROTO_L7_HTTP){
    // Previous protocol was HTTP, let's check if it was carrying json stuff
    debug_print("%s", "Previous proto was HTTP\n");
    int64_t http_method;
    if(!pfwl_field_number_get(pkt_info->l7.protocol_fields, PFWL_FIELDS_L7_HTTP_METHOD, &http_method) &&
       http_method == HTTP_POST){
      debug_print("%s", "HTTP Method is POST\n");
      pfwl_string_t http_ct;
      if(!pfwl_http_get_header(pkt_info, "Content-Type", &http_ct) && isJsonCt(http_ct)){
        debug_print("%s", "HTTP content type was json\n");
        pfwl_string_t http_body_string;
        if(!pfwl_field_string_get(pkt_info->l7.protocol_fields, PFWL_FIELDS_L7_HTTP_BODY, &http_body_string)){
          debug_print("%s", "HTTP has body, checking if it is jsonrpc\n");
          http_body = http_body_string.value;
          http_body_length = http_body_string.length;
          return JRPC_HTTP_MAYBE;
        }else{
          debug_print("%s", "HTTP has not body\n");
          return JRPC_HTTP_NO;
        }
      }else{
        debug_print("%s", "HTTP content type was not json\n");
        return JRPC_HTTP_MORE_DATA;
      }
    }else{
      debug_print("%s", "HTTP method was not POST but may be POST in the future\n");
      return JRPC_HTTP_MORE_DATA;
    }
  }else if(BITTEST(flow_info_private->possible_matching_protocols, PFWL_PROTO_L7_HTTP) &&
           flow_info_private->l7_protocols[flow_info_private->l7_protocols_num - 1] == PFWL_PROTO_L7_NOT_DETERMINED){
    // Could still become HTTP
    debug_print("%s", "Previous proto may still be HTTP\n");
    return JRPC_HTTP_MORE_DATA;
  }else{
    debug_print("%s", "Previous proto was not HTTP\n");
    return JRPC_HTTP_NO;
  }
}

uint8_t check_jsonrpc(pfwl_state_t *state, const unsigned char *app_data,
                      size_t data_length, pfwl_dissection_info_t *pkt_info,
                      pfwl_flow_info_private_t *flow_info_private) {
  // TODO: Check if 'in-situ' parsing is faster (https://github.com/Tencent/rapidjson/blob/master/doc/dom.md)
  // TODO: Manage segmented jsons (some in stratum.pcap)
  Document* d = NULL;
  if(!flow_info_private->json_parser){
    d = new Document();
    flow_info_private->json_parser = static_cast<void*>(d);
    flow_info_private->flow_cleaners_dissectors[PFWL_PROTO_L7_JSON_RPC] = &jsonrpc_flow_cleaner;
  }else{
    d = static_cast<Document*>(flow_info_private->json_parser);
  }

  ParseResult ok = d->Parse<kParseNumbersAsStringsFlag>((const char*) app_data, data_length);
  if(!ok &&
     ok != kParseErrorDocumentRootNotSingular) { // to avoid errors for newlines at the end of the json (ndjson)
    debug_print("%s\n", "It is not json-RPC");
    if(PFWL_DEBUG_DISS_JSONRPC)
      fprintf(stderr, "JSON parse error: %s (%lu)\n", GetParseError_En(ok.Code()), ok.Offset());
    // Check if JSON over HTTP
    const unsigned char* http_body;
    size_t http_body_length;
    switch(check_jsonrpc_over_http(pkt_info, flow_info_private, http_body, http_body_length)){
    case JRPC_HTTP_MAYBE:{
      app_data = http_body;
      data_length = http_body_length;
      ok = d->Parse<kParseNumbersAsStringsFlag>((const char*) app_data, data_length);
      if (!ok &&
          ok != kParseErrorDocumentRootNotSingular) { // to avoid errors for CRLF at the end of HTTP body
        debug_print("%s\n", "It is not json-RPC");
        if(PFWL_DEBUG_DISS_JSONRPC)
          fprintf(stderr, "JSON parse error: %s (%lu)\n", GetParseError_En(ok.Code()), ok.Offset());
        return PFWL_PROTOCOL_NO_MATCHES;
      }
    }break;
    case JRPC_HTTP_NO:{
      return PFWL_PROTOCOL_NO_MATCHES;
    }
    case JRPC_HTTP_MORE_DATA:{
      return PFWL_PROTOCOL_MORE_DATA_NEEDED;
    }
    }
  }

  enum protocol_check_statuses to_return = PFWL_PROTOCOL_NO_MATCHES;
  uint8_t version = 0;
  pfwl_jsonrpc_msg_type_t type = PFWL_JSONRPC_MSG_TYPE_NONE;
  const unsigned char* jsonrpc = getFieldAsString(*d, PFWL_FIELDS_L7_NUM, "jsonrpc", 0, flow_info_private);
  bool hasId = false;

  //const char *id = NULL, *method = NULL, *params = NULL, *result = NULL, *error = NULL;
  if(jsonrpc && !strcmp((const char*) jsonrpc, "2.0")){
    debug_print("%s\n", "It seems JSON-RPC v2.0.");
    // JSON-RPC v2 check
    version = 2;
    hasId = hasField(*d, "id");
    if(hasField(*d, "method")){
      debug_print("%s\n", "Method field found.");
      if(hasId){
        debug_print("%s\n", "Id found, is a request.");
        type = PFWL_JSONRPC_MSG_TYPE_REQUEST;
      }else{
        debug_print("%s\n", "Id not found, is a notification.");
        type = PFWL_JSONRPC_MSG_TYPE_NOTIFICATION; // In 2.0 notifications are requests without id
      }
      to_return = PFWL_PROTOCOL_MATCHES;
    }else{
      if(hasId && (hasField(*d, "result") || hasField(*d, "error"))){
        debug_print("%s\n", "Result or error found, is a response.");
        type = PFWL_JSONRPC_MSG_TYPE_RESPONSE;
        to_return = PFWL_PROTOCOL_MATCHES;
      }
    }
  }else{
    // JSON-RPC v1 check
    debug_print("%s\n", "It seems JSON-RPC v1.0.");
    version = 1;
    hasId = hasField(*d, "id");
    if(hasId && hasField(*d, "method") && hasField(*d, "params")){
      debug_print("%s\n", "Id, method and params found, is a request.");
      type = PFWL_JSONRPC_MSG_TYPE_REQUEST;
      to_return = PFWL_PROTOCOL_MATCHES;
    }else{
      if(hasId && hasField(*d, "result") && hasField(*d, "error")){
        debug_print("%s\n", "Id, result and error found, is a response.");
        type = PFWL_JSONRPC_MSG_TYPE_RESPONSE;
        to_return = PFWL_PROTOCOL_MATCHES;
      }else if(hasId){
        debug_print("%s\n", "Id found, is a notification.");
        type = PFWL_JSONRPC_MSG_TYPE_NOTIFICATION;
        to_return = PFWL_PROTOCOL_MATCHES;
      }else{
        debug_print("%s\n", "Nothing found, it is not JSON-RPC.");
      }
    }
  }

  // Set any required field
  if(to_return == PFWL_PROTOCOL_MATCHES){
    if(pfwl_protocol_field_required(state, flow_info_private, PFWL_FIELDS_L7_JSON_RPC_VERSION)){
      pfwl_field_number_set(pkt_info->l7.protocol_fields, PFWL_FIELDS_L7_JSON_RPC_VERSION, version);
    }
    if(pfwl_protocol_field_required(state, flow_info_private,PFWL_FIELDS_L7_JSON_RPC_MSG_TYPE)){
      pfwl_field_number_set(pkt_info->l7.protocol_fields, PFWL_FIELDS_L7_JSON_RPC_MSG_TYPE, type);
    }
    if(pfwl_protocol_field_required(state, flow_info_private,PFWL_FIELDS_L7_JSON_RPC_ID)){
      setIfPresent(*d, pkt_info->l7.protocol_fields, PFWL_FIELDS_L7_JSON_RPC_ID, "id", flow_info_private);
    }
    if(pfwl_protocol_field_required(state, flow_info_private,PFWL_FIELDS_L7_JSON_RPC_METHOD)){
      setIfPresent(*d, pkt_info->l7.protocol_fields, PFWL_FIELDS_L7_JSON_RPC_METHOD, "method", flow_info_private);
    }
    if(pfwl_protocol_field_required(state, flow_info_private,PFWL_FIELDS_L7_JSON_RPC_PARAMS)){
      setIfPresent(*d, pkt_info->l7.protocol_fields, PFWL_FIELDS_L7_JSON_RPC_PARAMS, "params", flow_info_private);
    }
    if(pfwl_protocol_field_required(state, flow_info_private,PFWL_FIELDS_L7_JSON_RPC_RESULT)){
      setIfPresent(*d, pkt_info->l7.protocol_fields, PFWL_FIELDS_L7_JSON_RPC_RESULT, "result", flow_info_private);
    }
    if(pfwl_protocol_field_required(state, flow_info_private,PFWL_FIELDS_L7_JSON_RPC_ERROR)){
      setIfPresent(*d, pkt_info->l7.protocol_fields, PFWL_FIELDS_L7_JSON_RPC_ERROR, "error", flow_info_private);
    }
    return PFWL_PROTOCOL_MATCHES;
  }else{
    return to_return;
  }
}
<commit_msg>[FIX] Possible bug on json parsing.<commit_after>/*
 * jsonrpc.c
 *
 * =========================================================================
 * Copyright (c) 2016-2019 Daniele De Sensi (d.desensi.software@gmail.com)
 *
 * 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 <peafowl/inspectors/inspectors.h>
#include <peafowl/peafowl.h>

#include "../external/rapidjson/document.h"
#include "../external/rapidjson/error/en.h"

#include <iostream>
#include "../external/rapidjson/stringbuffer.h"
#include "../external/rapidjson/writer.h"

#define PFWL_DEBUG_DISS_JSONRPC 0
#define debug_print(fmt, ...)                                                  \
  do {                                                                         \
    if (PFWL_DEBUG_DISS_JSONRPC)                                               \
      fprintf(stdout, fmt, __VA_ARGS__);                                       \
  } while (0)

using namespace rapidjson;

bool hasField(Document& d, const char* field){
  auto it = d.FindMember(field);
  return it != d.MemberEnd();
}

const unsigned char* getFieldAsString(Document& d, pfwl_field_id_t fieldId, const char* field, int persistent, pfwl_flow_info_private_t* flow_info_private){
  auto it = d.FindMember(field);
  if(it != d.MemberEnd()){
    if(it->value.IsString() || it->value.IsNumber()){
      return reinterpret_cast<const unsigned char*>(it->value.GetString());
    }else{
      if(persistent){
        size_t position = fieldId - PFWL_FIELDS_L7_JSON_RPC_FIRST - 1;
        StringBuffer* sb;
        if(!flow_info_private->json_stringbuffers[position]){
          sb = new StringBuffer();
          flow_info_private->json_stringbuffers[position] = static_cast<void*>(sb);
        }else{
          sb = static_cast<StringBuffer*>(flow_info_private->json_stringbuffers[position]);
          sb->Clear();
        }
        Writer<StringBuffer> writer(*sb);
        it->value.Accept(writer);
        return reinterpret_cast<const unsigned char*>(sb->GetString());
      }else{
        StringBuffer sb;
        Writer<StringBuffer> writer(sb);
        it->value.Accept(writer);
        return reinterpret_cast<const unsigned char*>(sb.GetString());
      }
    }
  }else{
    return NULL;
  }
}

void setIfPresent(Document& d, pfwl_field_t* fields, pfwl_field_id_t fieldId, const char* fieldName, pfwl_flow_info_private_t* flow_info_private){
  const unsigned char* fieldValue = getFieldAsString(d, fieldId, fieldName, 1, flow_info_private);
  if(fieldValue){
    pfwl_field_string_set(fields, fieldId, fieldValue, strlen((const char*) fieldValue));
  }
}

typedef enum{
  PFWL_JSONRPC_MSG_TYPE_REQUEST = 0,
  PFWL_JSONRPC_MSG_TYPE_RESPONSE,
  PFWL_JSONRPC_MSG_TYPE_NOTIFICATION,
  PFWL_JSONRPC_MSG_TYPE_NONE, /// Not jsonrpc
}pfwl_jsonrpc_msg_type_t;

static void jsonrpc_flow_cleaner(pfwl_flow_info_private_t *flow_info_private){
  for(size_t i = PFWL_FIELDS_L7_JSON_RPC_FIRST + 1; i < PFWL_FIELDS_L7_JSON_RPC_LAST; i++){
    size_t position = i - PFWL_FIELDS_L7_JSON_RPC_FIRST - 1;
    if(flow_info_private->json_stringbuffers[position]){
      delete static_cast<StringBuffer*>(flow_info_private->json_stringbuffers[position]);
    }
  }
  if(flow_info_private->json_parser){
    delete static_cast<Document*>(flow_info_private->json_parser);
  }
}

static bool isJsonCt(const pfwl_string_t& ct){
  return !strncmp(reinterpret_cast<const char*>(ct.value), "application/json-rpc"   , ct.length) ||
         !strncmp(reinterpret_cast<const char*>(ct.value), "application/json"       , ct.length) ||
         !strncmp(reinterpret_cast<const char*>(ct.value), "application/jsonrequest", ct.length);
}

typedef enum{
  JRPC_HTTP_MAYBE = 0,
  JRPC_HTTP_NO,
  JRPC_HTTP_MORE_DATA,
}JsonRpcOverHttpCheck;

JsonRpcOverHttpCheck check_jsonrpc_over_http(pfwl_dissection_info_t *pkt_info,
                                             pfwl_flow_info_private_t *flow_info_private,
                                             const unsigned char* &http_body,
                                             size_t& http_body_length){
  debug_print("%s", "Checking json over http\n");
  if(flow_info_private->l7_protocols[flow_info_private->l7_protocols_num - 1] == PFWL_PROTO_L7_HTTP){
    // Previous protocol was HTTP, let's check if it was carrying json stuff
    debug_print("%s", "Previous proto was HTTP\n");
    int64_t http_method;
    if(!pfwl_field_number_get(pkt_info->l7.protocol_fields, PFWL_FIELDS_L7_HTTP_METHOD, &http_method) &&
       http_method == HTTP_POST){
      debug_print("%s", "HTTP Method is POST\n");
      pfwl_string_t http_ct;
      if(!pfwl_http_get_header(pkt_info, "Content-Type", &http_ct) && isJsonCt(http_ct)){
        debug_print("%s", "HTTP content type was json\n");
        pfwl_string_t http_body_string;
        if(!pfwl_field_string_get(pkt_info->l7.protocol_fields, PFWL_FIELDS_L7_HTTP_BODY, &http_body_string)){
          debug_print("%s", "HTTP has body, checking if it is jsonrpc\n");
          http_body = http_body_string.value;
          http_body_length = http_body_string.length;
          return JRPC_HTTP_MAYBE;
        }else{
          debug_print("%s", "HTTP has not body\n");
          return JRPC_HTTP_NO;
        }
      }else{
        debug_print("%s", "HTTP content type was not json\n");
        return JRPC_HTTP_MORE_DATA;
      }
    }else{
      debug_print("%s", "HTTP method was not POST but may be POST in the future\n");
      return JRPC_HTTP_MORE_DATA;
    }
  }else if(BITTEST(flow_info_private->possible_matching_protocols, PFWL_PROTO_L7_HTTP) &&
           flow_info_private->l7_protocols[flow_info_private->l7_protocols_num - 1] == PFWL_PROTO_L7_NOT_DETERMINED){
    // Could still become HTTP
    debug_print("%s", "Previous proto may still be HTTP\n");
    return JRPC_HTTP_MORE_DATA;
  }else{
    debug_print("%s", "Previous proto was not HTTP\n");
    return JRPC_HTTP_NO;
  }
}

uint8_t check_jsonrpc(pfwl_state_t *state, const unsigned char *app_data,
                      size_t data_length, pfwl_dissection_info_t *pkt_info,
                      pfwl_flow_info_private_t *flow_info_private) {
  // TODO: Check if 'in-situ' parsing is faster (https://github.com/Tencent/rapidjson/blob/master/doc/dom.md)
  // TODO: Manage segmented jsons (some in stratum.pcap)
  Document* d = NULL;
  if(!flow_info_private->json_parser){
    d = new Document();
    flow_info_private->json_parser = static_cast<void*>(d);
    flow_info_private->flow_cleaners_dissectors[PFWL_PROTO_L7_JSON_RPC] = &jsonrpc_flow_cleaner;
  }else{
    d = static_cast<Document*>(flow_info_private->json_parser);
  }

  ParseResult ok = d->Parse<kParseNumbersAsStringsFlag>((const char*) app_data, data_length);
  if(!ok){
    debug_print("%s\n", "It is not json-RPC");
    if(PFWL_DEBUG_DISS_JSONRPC)
      fprintf(stderr, "JSON parse error: %s (%lu)\n", GetParseError_En(ok.Code()), ok.Offset());
    // Check if JSON over HTTP
    const unsigned char* http_body;
    size_t http_body_length;
    switch(check_jsonrpc_over_http(pkt_info, flow_info_private, http_body, http_body_length)){
    case JRPC_HTTP_MAYBE:{
      app_data = http_body;
      data_length = http_body_length;
      ok = d->Parse<kParseNumbersAsStringsFlag>((const char*) app_data, data_length);
      if(!ok){
        debug_print("%s\n", "It is not json-RPC");
        if(PFWL_DEBUG_DISS_JSONRPC)
          fprintf(stderr, "JSON parse error: %s (%lu)\n", GetParseError_En(ok.Code()), ok.Offset());
        return PFWL_PROTOCOL_NO_MATCHES;
      }
    }break;
    case JRPC_HTTP_NO:{
      return PFWL_PROTOCOL_NO_MATCHES;
    }
    case JRPC_HTTP_MORE_DATA:{
      return PFWL_PROTOCOL_MORE_DATA_NEEDED;
    }
    }
  }

  enum protocol_check_statuses to_return = PFWL_PROTOCOL_NO_MATCHES;
  uint8_t version = 0;
  pfwl_jsonrpc_msg_type_t type = PFWL_JSONRPC_MSG_TYPE_NONE;
  const unsigned char* jsonrpc = getFieldAsString(*d, PFWL_FIELDS_L7_NUM, "jsonrpc", 0, flow_info_private);
  bool hasId = false;

  //const char *id = NULL, *method = NULL, *params = NULL, *result = NULL, *error = NULL;
  if(jsonrpc && !strcmp((const char*) jsonrpc, "2.0")){
    debug_print("%s\n", "It seems JSON-RPC v2.0.");
    // JSON-RPC v2 check
    version = 2;
    hasId = hasField(*d, "id");
    if(hasField(*d, "method")){
      debug_print("%s\n", "Method field found.");
      if(hasId){
        debug_print("%s\n", "Id found, is a request.");
        type = PFWL_JSONRPC_MSG_TYPE_REQUEST;
      }else{
        debug_print("%s\n", "Id not found, is a notification.");
        type = PFWL_JSONRPC_MSG_TYPE_NOTIFICATION; // In 2.0 notifications are requests without id
      }
      to_return = PFWL_PROTOCOL_MATCHES;
    }else{
      if(hasId && (hasField(*d, "result") || hasField(*d, "error"))){
        debug_print("%s\n", "Result or error found, is a response.");
        type = PFWL_JSONRPC_MSG_TYPE_RESPONSE;
        to_return = PFWL_PROTOCOL_MATCHES;
      }
    }
  }else{
    // JSON-RPC v1 check
    debug_print("%s\n", "It seems JSON-RPC v1.0.");
    version = 1;
    hasId = hasField(*d, "id");
    if(hasId && hasField(*d, "method") && hasField(*d, "params")){
      debug_print("%s\n", "Id, method and params found, is a request.");
      type = PFWL_JSONRPC_MSG_TYPE_REQUEST;
      to_return = PFWL_PROTOCOL_MATCHES;
    }else{
      if(hasId && hasField(*d, "result") && hasField(*d, "error")){
        debug_print("%s\n", "Id, result and error found, is a response.");
        type = PFWL_JSONRPC_MSG_TYPE_RESPONSE;
        to_return = PFWL_PROTOCOL_MATCHES;
      }else if(hasId){
        debug_print("%s\n", "Id found, is a notification.");
        type = PFWL_JSONRPC_MSG_TYPE_NOTIFICATION;
        to_return = PFWL_PROTOCOL_MATCHES;
      }else{
        debug_print("%s\n", "Nothing found, it is not JSON-RPC.");
      }
    }
  }

  // Set any required field
  if(to_return == PFWL_PROTOCOL_MATCHES){
    if(pfwl_protocol_field_required(state, flow_info_private, PFWL_FIELDS_L7_JSON_RPC_VERSION)){
      pfwl_field_number_set(pkt_info->l7.protocol_fields, PFWL_FIELDS_L7_JSON_RPC_VERSION, version);
    }
    if(pfwl_protocol_field_required(state, flow_info_private,PFWL_FIELDS_L7_JSON_RPC_MSG_TYPE)){
      pfwl_field_number_set(pkt_info->l7.protocol_fields, PFWL_FIELDS_L7_JSON_RPC_MSG_TYPE, type);
    }
    if(pfwl_protocol_field_required(state, flow_info_private,PFWL_FIELDS_L7_JSON_RPC_ID)){
      setIfPresent(*d, pkt_info->l7.protocol_fields, PFWL_FIELDS_L7_JSON_RPC_ID, "id", flow_info_private);
    }
    if(pfwl_protocol_field_required(state, flow_info_private,PFWL_FIELDS_L7_JSON_RPC_METHOD)){
      setIfPresent(*d, pkt_info->l7.protocol_fields, PFWL_FIELDS_L7_JSON_RPC_METHOD, "method", flow_info_private);
    }
    if(pfwl_protocol_field_required(state, flow_info_private,PFWL_FIELDS_L7_JSON_RPC_PARAMS)){
      setIfPresent(*d, pkt_info->l7.protocol_fields, PFWL_FIELDS_L7_JSON_RPC_PARAMS, "params", flow_info_private);
    }
    if(pfwl_protocol_field_required(state, flow_info_private,PFWL_FIELDS_L7_JSON_RPC_RESULT)){
      setIfPresent(*d, pkt_info->l7.protocol_fields, PFWL_FIELDS_L7_JSON_RPC_RESULT, "result", flow_info_private);
    }
    if(pfwl_protocol_field_required(state, flow_info_private,PFWL_FIELDS_L7_JSON_RPC_ERROR)){
      setIfPresent(*d, pkt_info->l7.protocol_fields, PFWL_FIELDS_L7_JSON_RPC_ERROR, "error", flow_info_private);
    }
    return PFWL_PROTOCOL_MATCHES;
  }else{
    return to_return;
  }
}
<|endoftext|>


<commit_before>/*
 * tkAppInit.c --
 *
 *	Provides a default version of the Tcl_AppInit procedure for
 *	use in wish and similar Tk-based applications.
 *
 * Copyright (c) 1993 The Regents of the University of California.
 * Copyright (c) 1994 Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 */

#include "tk.h"

#include "vtkSystemIncludes.h"
#include "vtkToolkits.h"

/*
 *----------------------------------------------------------------------
 *
 * main --
 *
 *	This is the main program for the application.
 *
 * Results:
 *	None: Tk_Main never returns here, so this procedure never
 *	returns either.
 *
 * Side effects:
 *	Whatever the application does.
 *
 *----------------------------------------------------------------------
 */
int
main(int argc, char **argv)
{
  ios::sync_with_stdio();
  Tk_Main(argc, argv, Tcl_AppInit);
  return 0;			/* Needed only to prevent compiler warning. */
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_AppInit --
 *
 *	This procedure performs application-specific initialization.
 *	Most applications, especially those that incorporate additional
 *	packages, will have their own version of this procedure.
 *
 * Results:
 *	Returns a standard Tcl completion code, and leaves an error
 *	message in interp->result if an error occurs.
 *
 * Side effects:
 *	Depends on the startup script.
 *
 *----------------------------------------------------------------------
 */

extern "C" int Vtkcommontcl_Init(Tcl_Interp *interp);
extern "C" int Vtkfilteringtcl_Init(Tcl_Interp *interp);
extern "C" int Vtkimagingtcl_Init(Tcl_Interp *interp);
extern "C" int Vtkgraphicstcl_Init(Tcl_Interp *interp);
extern "C" int Vtkiotcl_Init(Tcl_Interp *interp);

#ifdef VTK_USE_RENDERING
extern "C" int Vtkrenderingtcl_Init(Tcl_Interp *interp);
#ifdef VTK_USE_TKWIDGET
extern "C" int Vtktkrenderwidget_Init(Tcl_Interp *interp);
extern "C" int Vtktkimageviewerwidget_Init(Tcl_Interp *interp);
extern "C" int Vtktkimagewindowwidget_Init(Tcl_Interp *interp);
#endif
#endif

#ifdef VTK_USE_PATENTED
extern "C" int Vtkpatentedtcl_Init(Tcl_Interp *interp);
#endif

#ifdef VTK_USE_HYBRID
extern "C" int Vtkhybridtcl_Init(Tcl_Interp *interp);
#endif

#ifdef VTK_USE_PARALLEL
extern "C" int Vtkparalleltcl_Init(Tcl_Interp *interp);
#endif

int Tcl_AppInit(Tcl_Interp *interp)
{
  if (Tcl_Init(interp) == TCL_ERROR) {
  return TCL_ERROR;
  }
  if (Tk_Init(interp) == TCL_ERROR) {
  return TCL_ERROR;
  }

  /* init the core vtk stuff */
  if (Vtkcommontcl_Init(interp) == TCL_ERROR)
    {
    return TCL_ERROR;
    }
  if (Vtkfilteringtcl_Init(interp) == TCL_ERROR)
    {
    return TCL_ERROR;
    }
  if (Vtkimagingtcl_Init(interp) == TCL_ERROR)
    {
    return TCL_ERROR;
    }
  if (Vtkgraphicstcl_Init(interp) == TCL_ERROR)
    {
    return TCL_ERROR;
    }
  if (Vtkiotcl_Init(interp) == TCL_ERROR)
    {
    return TCL_ERROR;
    }

#ifdef VTK_USE_RENDERING
  if (Vtkrenderingtcl_Init(interp) == TCL_ERROR)
    {
    return TCL_ERROR;
    }
#ifdef VTK_USE_TKWIDGET
  if (Vtktkrenderwidget_Init(interp) == TCL_ERROR)
    {
    return TCL_ERROR;
    }
  if (Vtktkimagewindowwidget_Init(interp) == TCL_ERROR)
    {
    return TCL_ERROR;
    }
  if (Vtktkimageviewerwidget_Init(interp) == TCL_ERROR)
    {
    return TCL_ERROR;
    }
#endif
#endif

#ifdef VTK_USE_PATENTED
  if (Vtkpatentedtcl_Init(interp) == TCL_ERROR)
    {
    return TCL_ERROR;
    }
#endif

#ifdef VTK_USE_HYBRID
  if (Vtkhybridtcl_Init(interp) == TCL_ERROR)
    {
    return TCL_ERROR;
    }
#endif

#ifdef VTK_USE_PARALLEL
  if (Vtkparalleltcl_Init(interp) == TCL_ERROR)
    {
    return TCL_ERROR;
    }
#endif

  /*
   * Specify a user-specific startup file to invoke if the application
   * is run interactively.  Typically the startup file is "~/.apprc"
   * where "app" is the name of the application.  If this line is deleted
   * then no user-specific startup file will be run under any conditions.
   */

#if (((TK_MAJOR_VERSION == 4)&&(TK_MINOR_VERSION >= 1))||((TK_MAJOR_VERSION == 8)&&(TK_MINOR_VERSION >= 0)))
  Tcl_SetVar(interp,
	     (char *) "tcl_rcFileName",
	     (char *) "~/.vtkrc",
	     TCL_GLOBAL_ONLY);
#else
    tcl_RcFileName = (char *) "~/.vtkrc";
#endif
    return TCL_OK;
}

<commit_msg>added support for having no DISPLAY<commit_after>/*
 * tkAppInit.c --
 *
 *	Provides a default version of the Tcl_AppInit procedure for
 *	use in wish and similar Tk-based applications.
 *
 * Copyright (c) 1993 The Regents of the University of California.
 * Copyright (c) 1994 Sun Microsystems, Inc.
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 */

#include "tk.h"

#include "vtkSystemIncludes.h"
#include "vtkToolkits.h"

/*
 *----------------------------------------------------------------------
 *
 * main --
 *
 *	This is the main program for the application.
 *
 * Results:
 *	None: Tk_Main never returns here, so this procedure never
 *	returns either.
 *
 * Side effects:
 *	Whatever the application does.
 *
 *----------------------------------------------------------------------
 */
int
main(int argc, char **argv)
{
  ios::sync_with_stdio();
#ifdef VTK_USE_RENDERING
  Tk_Main(argc, argv, Tcl_AppInit);
#else
  Tcl_Main(argc, argv, Tcl_AppInit);
#endif
  return 0;			/* Needed only to prevent compiler warning. */
}

/*
 *----------------------------------------------------------------------
 *
 * Tcl_AppInit --
 *
 *	This procedure performs application-specific initialization.
 *	Most applications, especially those that incorporate additional
 *	packages, will have their own version of this procedure.
 *
 * Results:
 *	Returns a standard Tcl completion code, and leaves an error
 *	message in interp->result if an error occurs.
 *
 * Side effects:
 *	Depends on the startup script.
 *
 *----------------------------------------------------------------------
 */

extern "C" int Vtkcommontcl_Init(Tcl_Interp *interp);
extern "C" int Vtkfilteringtcl_Init(Tcl_Interp *interp);
extern "C" int Vtkimagingtcl_Init(Tcl_Interp *interp);
extern "C" int Vtkgraphicstcl_Init(Tcl_Interp *interp);
extern "C" int Vtkiotcl_Init(Tcl_Interp *interp);

#ifdef VTK_USE_RENDERING
extern "C" int Vtkrenderingtcl_Init(Tcl_Interp *interp);
#ifdef VTK_USE_TKWIDGET
extern "C" int Vtktkrenderwidget_Init(Tcl_Interp *interp);
extern "C" int Vtktkimageviewerwidget_Init(Tcl_Interp *interp);
extern "C" int Vtktkimagewindowwidget_Init(Tcl_Interp *interp);
#endif
#endif

#ifdef VTK_USE_PATENTED
extern "C" int Vtkpatentedtcl_Init(Tcl_Interp *interp);
#endif

#ifdef VTK_USE_HYBRID
extern "C" int Vtkhybridtcl_Init(Tcl_Interp *interp);
#endif

#ifdef VTK_USE_PARALLEL
extern "C" int Vtkparalleltcl_Init(Tcl_Interp *interp);
#endif

int Tcl_AppInit(Tcl_Interp *interp)
{
  if (Tcl_Init(interp) == TCL_ERROR) {
  return TCL_ERROR;
  }
#ifdef VTK_USE_RENDERING
  if (Tk_Init(interp) == TCL_ERROR) {
  return TCL_ERROR;
  }
#endif
  /* init the core vtk stuff */
  if (Vtkcommontcl_Init(interp) == TCL_ERROR)
    {
    return TCL_ERROR;
    }
  if (Vtkfilteringtcl_Init(interp) == TCL_ERROR)
    {
    return TCL_ERROR;
    }
  if (Vtkimagingtcl_Init(interp) == TCL_ERROR)
    {
    return TCL_ERROR;
    }
  if (Vtkgraphicstcl_Init(interp) == TCL_ERROR)
    {
    return TCL_ERROR;
    }
  if (Vtkiotcl_Init(interp) == TCL_ERROR)
    {
    return TCL_ERROR;
    }

#ifdef VTK_USE_RENDERING
  if (Vtkrenderingtcl_Init(interp) == TCL_ERROR)
    {
    return TCL_ERROR;
    }
#ifdef VTK_USE_TKWIDGET
  if (Vtktkrenderwidget_Init(interp) == TCL_ERROR)
    {
    return TCL_ERROR;
    }
  if (Vtktkimagewindowwidget_Init(interp) == TCL_ERROR)
    {
    return TCL_ERROR;
    }
  if (Vtktkimageviewerwidget_Init(interp) == TCL_ERROR)
    {
    return TCL_ERROR;
    }
#endif
#endif

#ifdef VTK_USE_PATENTED
  if (Vtkpatentedtcl_Init(interp) == TCL_ERROR)
    {
    return TCL_ERROR;
    }
#endif

#ifdef VTK_USE_HYBRID
  if (Vtkhybridtcl_Init(interp) == TCL_ERROR)
    {
    return TCL_ERROR;
    }
#endif

#ifdef VTK_USE_PARALLEL
  if (Vtkparalleltcl_Init(interp) == TCL_ERROR)
    {
    return TCL_ERROR;
    }
#endif

  /*
   * Specify a user-specific startup file to invoke if the application
   * is run interactively.  Typically the startup file is "~/.apprc"
   * where "app" is the name of the application.  If this line is deleted
   * then no user-specific startup file will be run under any conditions.
   */

#if (((TK_MAJOR_VERSION == 4)&&(TK_MINOR_VERSION >= 1))||((TK_MAJOR_VERSION == 8)&&(TK_MINOR_VERSION >= 0)))
  Tcl_SetVar(interp,
	     (char *) "tcl_rcFileName",
	     (char *) "~/.vtkrc",
	     TCL_GLOBAL_ONLY);
#else
    tcl_RcFileName = (char *) "~/.vtkrc";
#endif
    return TCL_OK;
}

<|endoftext|>


<commit_before>//
// client.hpp
// aegis.cpp
//
// Copyright (c) 2017 Sara W (sara at xandium dot net)
//
// This file is part of aegis.cpp .
//
// 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.

#pragma once

#include <string>
#include <chrono>
#include <sstream>
#include "config.hpp"

#include <websocketpp/config/asio_client.hpp>
#include <websocketpp/client.hpp>
#include <websocketpp/common/connection_hdl.hpp>

namespace aegis
{

class Aegis;

class client
{
public:
    client(Aegis & main)
        : m_heartbeatack(0)
        , m_lastheartbeat(0)
        , m_sequence(0)
        , m_state(aegis::UNINITIALIZED)
        , m_main(main)
    {
        starttime = std::chrono::steady_clock::now();
    }

    void do_reset()
    {
        m_heartbeatack = 0;
        m_connection.reset();
        m_keepalivetimer->cancel();
        m_keepalivetimer.reset();
    }

    // Websocket++ socket connection
    websocketpp::client<websocketpp::config::asio_tls_client>::connection_type::ptr m_connection;
    websocketpp::connection_hdl hdl;

    int64_t m_heartbeatack;
    int64_t m_lastheartbeat;

    int16_t m_shardid;

    // Timer for heartbeats
    std::shared_ptr<asio::steady_timer> m_keepalivetimer;

    uint64_t m_sequence;

    int16_t m_state;

    std::shared_ptr<asio::steady_timer> m_reconnect_timer;

    std::string m_sessionId;

    Aegis & m_main;

    std::chrono::steady_clock::time_point starttime;
    std::string uptime() const
    {
        std::stringstream ss;
        std::chrono::steady_clock::time_point timenow = std::chrono::steady_clock::now();

        int64_t ms = std::chrono::duration_cast<std::chrono::milliseconds>(timenow - starttime).count();

        int64_t seconds = (ms / 1000) % 60;
        int64_t minutes = (((ms / 1000) - seconds) / 60) % 60;
        int64_t hours = (((((ms / 1000) - seconds) / 60) - minutes) / 60) % 24;
        int64_t days = (((((((ms / 1000) - seconds) / 60) - minutes) / 60) - hours) / 24);

        if (days > 0)
            ss << days << "d ";
        if (hours > 0)
            ss << hours << "h ";
        if (minutes > 0)
            ss << minutes << "m ";
        if (seconds > 0)
            ss << seconds << "s";
        return ss.str();
    }

};

}
<commit_msg>Fix socket closing crash<commit_after>//
// client.hpp
// aegis.cpp
//
// Copyright (c) 2017 Sara W (sara at xandium dot net)
//
// This file is part of aegis.cpp .
//
// 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.

#pragma once

#include <string>
#include <chrono>
#include <sstream>
#include "config.hpp"

#include <websocketpp/config/asio_client.hpp>
#include <websocketpp/client.hpp>
#include <websocketpp/common/connection_hdl.hpp>

namespace aegis
{

class Aegis;

class client
{
public:
    client(Aegis & main)
        : m_heartbeatack(0)
        , m_lastheartbeat(0)
        , m_sequence(0)
        , m_state(aegis::UNINITIALIZED)
        , m_main(main)
    {
        starttime = std::chrono::steady_clock::now();
    }

    void do_reset()
    {
        m_heartbeatack = 0;
        if (m_connection != nullptr)
            m_connection.reset();
        if (m_keepalivetimer != nullptr)
        {
            m_keepalivetimer->cancel();
            m_keepalivetimer.reset();
        }
    }

    // Websocket++ socket connection
    websocketpp::client<websocketpp::config::asio_tls_client>::connection_type::ptr m_connection;
    websocketpp::connection_hdl hdl;

    int64_t m_heartbeatack;
    int64_t m_lastheartbeat;

    int16_t m_shardid;

    // Timer for heartbeats
    std::shared_ptr<asio::steady_timer> m_keepalivetimer;

    uint64_t m_sequence;

    int16_t m_state;

    std::shared_ptr<asio::steady_timer> m_reconnect_timer;

    std::string m_sessionId;

    Aegis & m_main;

    std::chrono::steady_clock::time_point starttime;
    std::string uptime() const
    {
        std::stringstream ss;
        std::chrono::steady_clock::time_point timenow = std::chrono::steady_clock::now();

        int64_t ms = std::chrono::duration_cast<std::chrono::milliseconds>(timenow - starttime).count();

        int64_t seconds = (ms / 1000) % 60;
        int64_t minutes = (((ms / 1000) - seconds) / 60) % 60;
        int64_t hours = (((((ms / 1000) - seconds) / 60) - minutes) / 60) % 24;
        int64_t days = (((((((ms / 1000) - seconds) / 60) - minutes) / 60) - hours) / 24);

        if (days > 0)
            ss << days << "d ";
        if (hours > 0)
            ss << hours << "h ";
        if (minutes > 0)
            ss << minutes << "m ";
        if (seconds > 0)
            ss << seconds << "s";
        return ss.str();
    }

};

}
<|endoftext|>


<commit_before>// Part of the apollo library -- Copyright (c) Christian Neumüller 2015
// This file is subject to the terms of the BSD 2-Clause License.
// See LICENSE.txt or http://opensource.org/licenses/BSD-2-Clause

#ifndef APOLLO_CLASS_HPP_INCLUDED
#define APOLLO_CLASS_HPP_INCLUDED APOLLO_CLASS_HPP_INCLUDED

#include <apollo/config.hpp>
#include <apollo/converters.hpp>
#include <apollo/gc.hpp> // For push_bare_udata().
#include <apollo/detail/smart_ptr.hpp>
#include <apollo/typeid.hpp>
#include <apollo/detail/class_info.hpp>
#include <apollo/detail/instance_holder.hpp>
#include <apollo/detail/light_key.hpp>
#include <apollo/detail/ref_binder.hpp>

namespace apollo {

namespace detail {

APOLLO_API void push_instance_metatable(
    lua_State* L,
    class_info const& cls) BOOST_NOEXCEPT;

template <typename Ptr>
void push_instance_ptr(lua_State* L, Ptr&& ptr)
{
    using ptr_t = typename remove_cvr<Ptr>::type;
    using holder_t = ptr_instance_holder<ptr_t>;
    using cls_t = typename remove_cvr<
        typename pointer_traits<ptr_t>::pointee_type>::type;

    class_info const& cls = registered_class(L,
        boost::typeindex::type_id<cls_t>().type_info());
    emplace_bare_udata<holder_t>(L, std::forward<Ptr>(ptr), cls);
    push_instance_metatable(L, cls);
    lua_setmetatable(L, -2);
}

template <typename T>
void push_instance_val(lua_State* L, T&& val)
{
    using obj_t = typename std::remove_reference<T>::type;
    using holder_t = value_instance_holder<obj_t>;

    using cls_t = typename remove_cvr<obj_t>::type;
    class_info const& cls = registered_class(L,
        boost::typeindex::type_id<cls_t>().type_info());
    emplace_bare_udata<holder_t>(L, std::forward<T>(val), cls);
    push_instance_metatable(L, cls);
    lua_setmetatable(L, -2);
}

APOLLO_API bool is_apollo_instance(lua_State* L, int idx);

inline instance_holder* as_holder(lua_State* L, int idx)
{
    BOOST_ASSERT(lua_isnil(L, idx) || is_apollo_instance(L, idx));
    return static_cast<instance_holder*>(lua_touserdata(L, idx));
}

static char const* err_noinst
    = "Value is neither nil nor an apollo instance userdata.";

template <typename T, typename Enable=void>
struct object_converter: object_converter<T const&>
{};

template <typename T>
struct object_converter<T const&, typename std::enable_if<
        !detail::pointer_traits<T>::is_valid
    >::type>: converter_base<converter<T const&>, ref_binder<T const>> {
private:
    static implicit_ctor* get_ctor_opt(lua_State* L, int idx)
    {
        auto const& cls = registered_class(L,
            boost::typeindex::type_id<T>().type_info());
        auto const& ctors = cls.implicit_ctors;
        auto i_ctor = ctors.find(ltypeid(L, idx));
        return i_ctor == ctors.end() ? nullptr : i_ctor->second.get();
    }

public:
    static unsigned n_conversion_steps(lua_State* L, int idx)
    {
        auto n_steps = object_converter<T const*>::n_conversion_steps(L, idx);
        if (n_steps == no_conversion)
            return get_ctor_opt(L, idx) ? 1 : no_conversion;

        // Reject null pointers.
        return object_converter<T const*>::to(L, idx) ?
            n_steps : no_conversion;
    }

    static ref_binder<T const> to(lua_State* L, int idx)
    {
        char const* err;
        auto ptr = object_converter<T const*>::detail_try_safe_to(L, idx, err);
        if (BOOST_UNLIKELY(err != nullptr)) {
            return {
                static_cast<T*>(get_ctor_opt(L, idx)->to(L, idx)),
                true};
        }
        return {ptr, false};
    }

    static ref_binder<T const> safe_to(lua_State* L, int idx)
    {
        char const* err;
        auto ptr = object_converter<T const*>::detail_try_safe_to(L, idx, err);
        if (BOOST_UNLIKELY(err != nullptr)) {
            auto ctor = get_ctor_opt(L, idx);
            if (!ctor) {
                BOOST_THROW_EXCEPTION(to_cpp_conversion_error()
                    << errinfo::msg(err));
            }
            return {
                static_cast<T*>(ctor->to(L, idx)),
                true};
        }
        return {ptr, false};
    }
};

template <typename T>
struct object_converter<T&, typename std::enable_if<
           !detail::pointer_traits<T>::is_valid
        && !std::is_const<T>::value
    >::type>: converter_base<converter<T&>> {
public:

    static unsigned n_conversion_steps(lua_State* L, int idx)
    {
        auto n_steps = object_converter<T*>::n_conversion_steps(L, idx);
        if (n_steps == no_conversion)
            return no_conversion;

        // Reject null pointers.
        return object_converter<T*>::to(L, idx) ?
            n_steps : no_conversion;
    }

    static T& to(lua_State* L, int idx)
    {
        return *object_converter<T*>::to(L, idx);
    }

    static T& safe_to(lua_State* L, int idx)
    {
        auto ptr = object_converter<T*>::safe_to(L, idx);
        if (!ptr) {
            BOOST_THROW_EXCEPTION(to_cpp_conversion_error() << errinfo::msg(
                "Attempt to convert nullptr to reference."));
        }
        return *ptr;
    }
};

template <typename Ptr>
struct object_converter<
        Ptr,
        typename std::enable_if<pointer_traits<Ptr>::is_smart>::type
    >: converter_base<converter<Ptr>> {
private:
    using ptr_t = typename remove_cvr<Ptr>::type;
    using is_ref = std::is_reference<Ptr>;

    static Ptr make_nil_smart_ptr(std::true_type) {
        BOOST_THROW_EXCEPTION(to_cpp_conversion_error()
                << errinfo::msg(
                    "Attempt to convert nil to smart pointer ref."));
    }

    static Ptr make_nil_smart_ptr(std::false_type) {
        return Ptr();
    }

public:
    static unsigned n_conversion_steps(lua_State* L, int idx)
    {
        APOLLO_DETAIL_CONSTCOND_BEGIN
        if (!is_ref::value && lua_isnil(L, idx))
            return no_conversion - 1;
        APOLLO_DETAIL_CONSTCOND_END

        if (!is_apollo_instance(L, idx))
            return no_conversion;
        if (boost::typeindex::type_id<ptr_instance_holder<ptr_t>>()
            == boost::typeindex::type_id_runtime(*as_holder(L, idx)))
            return 0;
        return no_conversion;
    }

    static Ptr to(lua_State* L, int idx)
    {
        if (lua_isnil(L, idx))
            return make_nil_smart_ptr(is_ref());

        return static_cast<ptr_instance_holder<ptr_t>*>(
            lua_touserdata(L, idx))->get_outer_ptr();
    }

    static Ptr safe_to(lua_State* L, int idx)
    {
        if (BOOST_LIKELY(is_apollo_instance(L, idx))) {
            auto holder = as_holder(L, idx);
            if (boost::typeindex::type_id<ptr_instance_holder<ptr_t>>()
                != boost::typeindex::type_id_runtime(*holder)
            ) {
                BOOST_THROW_EXCEPTION(to_cpp_conversion_error()
                    << errinfo::msg(
                        "Invalid pointer type (when casting to smart pointers,"
                        " conversion to base or const variants"
                        " are not supported)."));
            }
            return static_cast<ptr_instance_holder<ptr_t>*>(
                lua_touserdata(L, idx))->get_outer_ptr();
        }

        if (lua_isnil(L, idx))
            return make_nil_smart_ptr(is_ref());

        BOOST_THROW_EXCEPTION(to_cpp_conversion_error()
            << errinfo::msg(err_noinst));
    }
};

template <typename Ptr>
struct object_converter<
        Ptr,
        typename std::enable_if<std::is_pointer<Ptr>::value>::type
    >: converter_base<converter<Ptr>> {
private:
    using ptr_traits = pointer_traits<Ptr>;
    using pointee_t = typename ptr_traits::pointee_type;
    using obj_t = typename remove_cvr<pointee_t>::type;
public:
    static unsigned n_conversion_steps(lua_State* L, int idx)
    {
        if (lua_isnil(L, idx))
            return no_conversion - 1;
        if (!is_apollo_instance(L, idx))
            return no_conversion;

        auto holder = as_holder(L, idx);

        if (!is_const_correct(holder))
            return no_conversion;

        return n_class_conversion_steps(
            holder->type(), static_class_id<obj_t>::id);
    }

    static Ptr to(lua_State* L, int idx)
    {
        auto holder = as_holder(L, idx);
        if (!holder) // This means not a userdata, so assume nil.
            return nullptr;
        return static_cast<Ptr>(cast_class(
            holder->get(),
            holder->type(),
            static_class_id<obj_t>::id));
    }

    static Ptr safe_to(lua_State* L, int idx)
    {
        char const* err;
        Ptr result = detail_try_safe_to(L, idx, err);
        if (BOOST_UNLIKELY(err != nullptr)) {
            BOOST_THROW_EXCEPTION(to_cpp_conversion_error()
                << errinfo::msg(err));
        }
        return result;
    }

    // For use by object_converter<T const&>.
    static Ptr detail_try_safe_to(lua_State* L, int idx, char const*& err)
    {
        err = nullptr;
        if (BOOST_LIKELY(is_apollo_instance(L, idx))) {
            auto holder = as_holder(L, idx);
            if (!is_const_correct(holder)) {
                err = "Class conversion loses const.";
                return nullptr;
            }

            return static_cast<Ptr>(try_cast_class(
                holder->get(),
                holder->type(),
                static_class_id<obj_t>::id,
                err));
        }
        if (lua_isnil(L, idx)) {
            return nullptr;
        }

        err = err_noinst;
        return nullptr;
    }

private:
    static bool is_const_correct(instance_holder const* holder)
    {
        // MSVC complains that holder is unused if ptr_traits::is_const is true.
        (void)holder;
        return ptr_traits::is_const || !holder->is_const();
    }
};

} // namespace detail

template <typename T>
typename std::enable_if<!detail::pointer_traits<T>::is_valid>::type
push_object(lua_State* L, T&& v)
{
    detail::push_instance_val(L, std::forward<T>(v));
}

template <typename T, typename... Args>
void emplace_object(lua_State* L, Args&&... args)
{
    using obj_t = typename std::remove_reference<T>::type;
    using holder_t = detail::value_instance_holder<obj_t>;
    using cls_t = typename detail::remove_cvr<obj_t>::type;

    detail::class_info const& cls = detail::registered_class(L,
        boost::typeindex::type_id<cls_t>().type_info());
    emplace_bare_udata<holder_t>(L, cls, std::forward<Args>(args)...);
    detail::push_instance_metatable(L, cls);
    lua_setmetatable(L, -2);

}

template <typename Ptr>
typename std::enable_if<detail::pointer_traits<Ptr>::is_valid>::type
push_object(lua_State* L, Ptr&& p)
{
    detail::push_instance_ptr(L, std::forward<Ptr>(p));
}

template <typename T>
void push_class_metatable(lua_State* L)
{
    using obj_t = typename detail::remove_cvr<T>::type;
    detail::push_instance_metatable(L, detail::registered_class(L,
        boost::typeindex::type_id<obj_t>().type_info()));
}

template <typename T, typename... Bases>
void register_class(lua_State* L)
{
    auto& registry = detail::registered_classes(L);
    auto index = boost::typeindex::type_id<T>();
    if (registry.find(index) != registry.end()) {
        BOOST_ASSERT_MSG(false, "Class already registered!");
    }
    registry.insert(std::make_pair(
        index, detail::make_class_info<T, Bases...>(registry)));
}

// Userdata converters //

template<typename T, typename Enable>
struct converter: detail::object_converter<T>
{
    static_assert(detail::lua_type_id<T>::value == LUA_TUSERDATA,
        "Builtin type treated as object.");
    // Did you forget to #include <apollo/function.hpp>?

    template <typename U>
    static int push(lua_State* L, U&& v)
    {
        static_assert(std::is_same<
            typename detail::remove_cvr<U>::type , T>::value, "");
        push_object(L, std::forward<U>(v));
        return 1;
    }
};

template <typename T>
unsigned n_object_conversion_steps(lua_State* L, int idx)
{
    return detail::object_converter<
        typename std::remove_cv<T>::type>::n_conversion_steps(L, idx);
}

template <typename T>
auto to_object(lua_State* L, int idx)
-> decltype(detail::object_converter<
    typename std::remove_cv<T>::type>::to(L, idx))
{
    return detail::object_converter<
        typename std::remove_cv<T>::type>::to(L, idx);
}

} // namespace apollo

#endif // APOLLO_CLASS_HPP_INCLUDED
<commit_msg>Fix err_noinst being nonconst.<commit_after>// Part of the apollo library -- Copyright (c) Christian Neumüller 2015
// This file is subject to the terms of the BSD 2-Clause License.
// See LICENSE.txt or http://opensource.org/licenses/BSD-2-Clause

#ifndef APOLLO_CLASS_HPP_INCLUDED
#define APOLLO_CLASS_HPP_INCLUDED APOLLO_CLASS_HPP_INCLUDED

#include <apollo/config.hpp>
#include <apollo/converters.hpp>
#include <apollo/gc.hpp> // For push_bare_udata().
#include <apollo/detail/smart_ptr.hpp>
#include <apollo/typeid.hpp>
#include <apollo/detail/class_info.hpp>
#include <apollo/detail/instance_holder.hpp>
#include <apollo/detail/light_key.hpp>
#include <apollo/detail/ref_binder.hpp>

namespace apollo {

namespace detail {

APOLLO_API void push_instance_metatable(
    lua_State* L,
    class_info const& cls) BOOST_NOEXCEPT;

template <typename Ptr>
void push_instance_ptr(lua_State* L, Ptr&& ptr)
{
    using ptr_t = typename remove_cvr<Ptr>::type;
    using holder_t = ptr_instance_holder<ptr_t>;
    using cls_t = typename remove_cvr<
        typename pointer_traits<ptr_t>::pointee_type>::type;

    class_info const& cls = registered_class(L,
        boost::typeindex::type_id<cls_t>().type_info());
    emplace_bare_udata<holder_t>(L, std::forward<Ptr>(ptr), cls);
    push_instance_metatable(L, cls);
    lua_setmetatable(L, -2);
}

template <typename T>
void push_instance_val(lua_State* L, T&& val)
{
    using obj_t = typename std::remove_reference<T>::type;
    using holder_t = value_instance_holder<obj_t>;

    using cls_t = typename remove_cvr<obj_t>::type;
    class_info const& cls = registered_class(L,
        boost::typeindex::type_id<cls_t>().type_info());
    emplace_bare_udata<holder_t>(L, std::forward<T>(val), cls);
    push_instance_metatable(L, cls);
    lua_setmetatable(L, -2);
}

APOLLO_API bool is_apollo_instance(lua_State* L, int idx);

inline instance_holder* as_holder(lua_State* L, int idx)
{
    BOOST_ASSERT(lua_isnil(L, idx) || is_apollo_instance(L, idx));
    return static_cast<instance_holder*>(lua_touserdata(L, idx));
}

char const err_noinst[]
    = "Value is neither nil nor an apollo instance userdata.";

template <typename T, typename Enable=void>
struct object_converter: object_converter<T const&>
{};

template <typename T>
struct object_converter<T const&, typename std::enable_if<
        !detail::pointer_traits<T>::is_valid
    >::type>: converter_base<converter<T const&>, ref_binder<T const>> {
private:
    static implicit_ctor* get_ctor_opt(lua_State* L, int idx)
    {
        auto const& cls = registered_class(L,
            boost::typeindex::type_id<T>().type_info());
        auto const& ctors = cls.implicit_ctors;
        auto i_ctor = ctors.find(ltypeid(L, idx));
        return i_ctor == ctors.end() ? nullptr : i_ctor->second.get();
    }

public:
    static unsigned n_conversion_steps(lua_State* L, int idx)
    {
        auto n_steps = object_converter<T const*>::n_conversion_steps(L, idx);
        if (n_steps == no_conversion)
            return get_ctor_opt(L, idx) ? 1 : no_conversion;

        // Reject null pointers.
        return object_converter<T const*>::to(L, idx) ?
            n_steps : no_conversion;
    }

    static ref_binder<T const> to(lua_State* L, int idx)
    {
        char const* err;
        auto ptr = object_converter<T const*>::detail_try_safe_to(L, idx, err);
        if (BOOST_UNLIKELY(err != nullptr)) {
            return {
                static_cast<T*>(get_ctor_opt(L, idx)->to(L, idx)),
                true};
        }
        return {ptr, false};
    }

    static ref_binder<T const> safe_to(lua_State* L, int idx)
    {
        char const* err;
        auto ptr = object_converter<T const*>::detail_try_safe_to(L, idx, err);
        if (BOOST_UNLIKELY(err != nullptr)) {
            auto ctor = get_ctor_opt(L, idx);
            if (!ctor) {
                BOOST_THROW_EXCEPTION(to_cpp_conversion_error()
                    << errinfo::msg(err));
            }
            return {
                static_cast<T*>(ctor->to(L, idx)),
                true};
        }
        return {ptr, false};
    }
};

template <typename T>
struct object_converter<T&, typename std::enable_if<
           !detail::pointer_traits<T>::is_valid
        && !std::is_const<T>::value
    >::type>: converter_base<converter<T&>> {
public:

    static unsigned n_conversion_steps(lua_State* L, int idx)
    {
        auto n_steps = object_converter<T*>::n_conversion_steps(L, idx);
        if (n_steps == no_conversion)
            return no_conversion;

        // Reject null pointers.
        return object_converter<T*>::to(L, idx) ?
            n_steps : no_conversion;
    }

    static T& to(lua_State* L, int idx)
    {
        return *object_converter<T*>::to(L, idx);
    }

    static T& safe_to(lua_State* L, int idx)
    {
        auto ptr = object_converter<T*>::safe_to(L, idx);
        if (!ptr) {
            BOOST_THROW_EXCEPTION(to_cpp_conversion_error() << errinfo::msg(
                "Attempt to convert nullptr to reference."));
        }
        return *ptr;
    }
};

template <typename Ptr>
struct object_converter<
        Ptr,
        typename std::enable_if<pointer_traits<Ptr>::is_smart>::type
    >: converter_base<converter<Ptr>> {
private:
    using ptr_t = typename remove_cvr<Ptr>::type;
    using is_ref = std::is_reference<Ptr>;

    static Ptr make_nil_smart_ptr(std::true_type) {
        BOOST_THROW_EXCEPTION(to_cpp_conversion_error()
                << errinfo::msg(
                    "Attempt to convert nil to smart pointer ref."));
    }

    static Ptr make_nil_smart_ptr(std::false_type) {
        return Ptr();
    }

public:
    static unsigned n_conversion_steps(lua_State* L, int idx)
    {
        APOLLO_DETAIL_CONSTCOND_BEGIN
        if (!is_ref::value && lua_isnil(L, idx))
            return no_conversion - 1;
        APOLLO_DETAIL_CONSTCOND_END

        if (!is_apollo_instance(L, idx))
            return no_conversion;
        if (boost::typeindex::type_id<ptr_instance_holder<ptr_t>>()
            == boost::typeindex::type_id_runtime(*as_holder(L, idx)))
            return 0;
        return no_conversion;
    }

    static Ptr to(lua_State* L, int idx)
    {
        if (lua_isnil(L, idx))
            return make_nil_smart_ptr(is_ref());

        return static_cast<ptr_instance_holder<ptr_t>*>(
            lua_touserdata(L, idx))->get_outer_ptr();
    }

    static Ptr safe_to(lua_State* L, int idx)
    {
        if (BOOST_LIKELY(is_apollo_instance(L, idx))) {
            auto holder = as_holder(L, idx);
            if (boost::typeindex::type_id<ptr_instance_holder<ptr_t>>()
                != boost::typeindex::type_id_runtime(*holder)
            ) {
                BOOST_THROW_EXCEPTION(to_cpp_conversion_error()
                    << errinfo::msg(
                        "Invalid pointer type (when casting to smart pointers,"
                        " conversion to base or const variants"
                        " are not supported)."));
            }
            return static_cast<ptr_instance_holder<ptr_t>*>(
                lua_touserdata(L, idx))->get_outer_ptr();
        }

        if (lua_isnil(L, idx))
            return make_nil_smart_ptr(is_ref());

        BOOST_THROW_EXCEPTION(to_cpp_conversion_error()
            << errinfo::msg(err_noinst));
    }
};

template <typename Ptr>
struct object_converter<
        Ptr,
        typename std::enable_if<std::is_pointer<Ptr>::value>::type
    >: converter_base<converter<Ptr>> {
private:
    using ptr_traits = pointer_traits<Ptr>;
    using pointee_t = typename ptr_traits::pointee_type;
    using obj_t = typename remove_cvr<pointee_t>::type;
public:
    static unsigned n_conversion_steps(lua_State* L, int idx)
    {
        if (lua_isnil(L, idx))
            return no_conversion - 1;
        if (!is_apollo_instance(L, idx))
            return no_conversion;

        auto holder = as_holder(L, idx);

        if (!is_const_correct(holder))
            return no_conversion;

        return n_class_conversion_steps(
            holder->type(), static_class_id<obj_t>::id);
    }

    static Ptr to(lua_State* L, int idx)
    {
        auto holder = as_holder(L, idx);
        if (!holder) // This means not a userdata, so assume nil.
            return nullptr;
        return static_cast<Ptr>(cast_class(
            holder->get(),
            holder->type(),
            static_class_id<obj_t>::id));
    }

    static Ptr safe_to(lua_State* L, int idx)
    {
        char const* err;
        Ptr result = detail_try_safe_to(L, idx, err);
        if (BOOST_UNLIKELY(err != nullptr)) {
            BOOST_THROW_EXCEPTION(to_cpp_conversion_error()
                << errinfo::msg(err));
        }
        return result;
    }

    // For use by object_converter<T const&>.
    static Ptr detail_try_safe_to(lua_State* L, int idx, char const*& err)
    {
        err = nullptr;
        if (BOOST_LIKELY(is_apollo_instance(L, idx))) {
            auto holder = as_holder(L, idx);
            if (!is_const_correct(holder)) {
                err = "Class conversion loses const.";
                return nullptr;
            }

            return static_cast<Ptr>(try_cast_class(
                holder->get(),
                holder->type(),
                static_class_id<obj_t>::id,
                err));
        }
        if (lua_isnil(L, idx)) {
            return nullptr;
        }

        err = err_noinst;
        return nullptr;
    }

private:
    static bool is_const_correct(instance_holder const* holder)
    {
        // MSVC complains that holder is unused if ptr_traits::is_const is true.
        (void)holder;
        return ptr_traits::is_const || !holder->is_const();
    }
};

} // namespace detail

template <typename T>
typename std::enable_if<!detail::pointer_traits<T>::is_valid>::type
push_object(lua_State* L, T&& v)
{
    detail::push_instance_val(L, std::forward<T>(v));
}

template <typename T, typename... Args>
void emplace_object(lua_State* L, Args&&... args)
{
    using obj_t = typename std::remove_reference<T>::type;
    using holder_t = detail::value_instance_holder<obj_t>;
    using cls_t = typename detail::remove_cvr<obj_t>::type;

    detail::class_info const& cls = detail::registered_class(L,
        boost::typeindex::type_id<cls_t>().type_info());
    emplace_bare_udata<holder_t>(L, cls, std::forward<Args>(args)...);
    detail::push_instance_metatable(L, cls);
    lua_setmetatable(L, -2);

}

template <typename Ptr>
typename std::enable_if<detail::pointer_traits<Ptr>::is_valid>::type
push_object(lua_State* L, Ptr&& p)
{
    detail::push_instance_ptr(L, std::forward<Ptr>(p));
}

template <typename T>
void push_class_metatable(lua_State* L)
{
    using obj_t = typename detail::remove_cvr<T>::type;
    detail::push_instance_metatable(L, detail::registered_class(L,
        boost::typeindex::type_id<obj_t>().type_info()));
}

template <typename T, typename... Bases>
void register_class(lua_State* L)
{
    auto& registry = detail::registered_classes(L);
    auto index = boost::typeindex::type_id<T>();
    if (registry.find(index) != registry.end()) {
        BOOST_ASSERT_MSG(false, "Class already registered!");
    }
    registry.insert(std::make_pair(
        index, detail::make_class_info<T, Bases...>(registry)));
}

// Userdata converters //

template<typename T, typename Enable>
struct converter: detail::object_converter<T>
{
    static_assert(detail::lua_type_id<T>::value == LUA_TUSERDATA,
        "Builtin type treated as object.");
    // Did you forget to #include <apollo/function.hpp>?

    template <typename U>
    static int push(lua_State* L, U&& v)
    {
        static_assert(std::is_same<
            typename detail::remove_cvr<U>::type , T>::value, "");
        push_object(L, std::forward<U>(v));
        return 1;
    }
};

template <typename T>
unsigned n_object_conversion_steps(lua_State* L, int idx)
{
    return detail::object_converter<
        typename std::remove_cv<T>::type>::n_conversion_steps(L, idx);
}

template <typename T>
auto to_object(lua_State* L, int idx)
-> decltype(detail::object_converter<
    typename std::remove_cv<T>::type>::to(L, idx))
{
    return detail::object_converter<
        typename std::remove_cv<T>::type>::to(L, idx);
}

} // namespace apollo

#endif // APOLLO_CLASS_HPP_INCLUDED
<|endoftext|>


<commit_before>/**
 * @file   bayesoptcont.hpp
 * @brief  Sequential Krigging Optimization (SKO)
 *
 * This file implements Sequential Krigging Optimization using different
 * non-parametric processes as surrogate (krigging) functions.
 */

/*
-----------------------------------------------------------------------------
   This file is part of BayesOptimization, an efficient C++ library for
   Bayesian optimization.

   Copyright (C) 2011 Ruben Martinez-Cantin <rmcantin@unizar.es>

   BayesOptimization is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   BayesOptimization 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 General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with BayesOptimization.  If not, see <http://www.gnu.org/licenses/>.
-----------------------------------------------------------------------------
*/

#ifndef  _BAYESOPTCONT_HPP_
#define  _BAYESOPTCONT_HPP_

#include "specialtypes.hpp"
#include "elementwiseUblas.hpp"

#include "inneroptimization.hpp"
#include "nonparametricprocess.hpp"

#include "ctypes.h"
#include "criteria.hpp"

// Included here to simplify the C++-API
#include "gaussprocess.hpp"
#include "basicgaussprocess.hpp"
#include "studenttprocess.hpp"

/** \addtogroup BayesOptimization */
/**@{*/

/**
 * \brief Sequential Kriging Optimization using different non-parametric
 * processes as surrogate (kriging) functions.
 */
class SKO: public InnerOptimization
{
 public:

  /**
   * Constructor
   *
   * @param gp        Pointer to the surrogate model
   */
  SKO( NonParametricProcess* gp = NULL );

  /**
   * Default destructor
   *
   * @return
   */
  virtual ~SKO();

  /**
   * Execute the optimization process of the function defined in evaluateSample.
   * We assume that the function is defined in the [0,1] hypercube, as a
   * normalized representation of the bound constrains.
   *
   * @see scaleInput
   * @see evaluateSample
   *
   * @param bestPoint returns the optimum value in a ublas::vector defined in
   * the hypercube [0,1], it might also be used as an initial point
   * @param nIterations number of iterations (budget)
   *
   * @return 1 if terminate successfully, 0 otherwise
   */
  inline int optimize( vectord &bestPoint,
		       size_t nIterations )
  {
    size_t dim = bestPoint.size();
    vectord lowerBound = zvectord(dim);
    vectord upperBound = svectord(dim,1.0);

    return optimize(bestPoint,lowerBound,upperBound,nIterations);
  }

  /**
   * Execute the optimization process of the function defined in evaluateSample.
   * We assume that the function is defined in the hypercube defined by
   * the lower and upper vectors.
   *
   * @param bestPoint returns the optimum value in a ublas::vector x,
   * it might also be used as an initial point
   * @param lowerBound vector with the lower bounds of the hypercube
   * @param upperBound vector with the upper bounds of the hypercube
   * @param nIterations number of iterations (budget)
   *
   * @return 1 if terminate successfully, 0 otherwise
   */
  int optimize( vectord &bestPoint,
		vectord &lowerBound,
		vectord &upperBound,
		size_t nIterations );

  /**
   * Chooses which criterium to optimize in the inner loop.
   *
   * @param c criterium name
   */
  void setCriteria (criterium_name c)
  {crit_name = c;}

  /**
   * Function that defines the actual mathematical function to be optimized.
   * Virtual function for polymorphism. This function must need to be modified
   * according to the specific problem.
   *
   * @param query point to be evaluated.
   *
   * @return value of the function at the point evaluated.
   */
  virtual double evaluateSample( const vectord &query )
  { return 0.0; };

  /**
   * This function checks if the query is valid or not. It can be used
   * to introduce arbitrary constrains. Since the Gaussian process
   * assumes smoothness, constrains are managed by DIRECT, being highly
   * time consuming. If the constrain is very tricky, DIRECT will need
   * much more function evaluations.
   *
   * Note: This function is experimental.
   *
   * @param query point to be evaluated.
   *
   * @return boolean value showing if the the function is valid at
   *         the query point or not.
   */
  virtual bool checkReachability( const vectord &query )
  { return true; };

  /**
   * Function that returns the corresponding criteria of a series
   * of queries in the hypercube [0,1] in order to choose the best point to try
   * the next iteration.
   *
   * @param query point in the hypercube [0,1] to evaluate the Gaussian process
   *
   * @return negative criteria (Expected Improvement, LCB, A-optimality, etc.).
   */

  virtual double innerEvaluate( const vectord &query,
				vectord &grad )
  {   return evaluateCriteria(query); }

protected:

  inline double evaluateCriteria( const vectord &query )
  {
    bool reachable = checkReachability(query);
    if (!reachable)  return 0.0;
    return crit.evaluate(*mGP,query);
  }  // evaluateCriteria

  inline double evaluateNormalizedSample( const vectord &query)
  {
    vectord unnormalizedQuery = ublas_elementwise_prod(query,
						       mRangeBound);

    unnormalizedQuery = ublas_elementwise_add(unnormalizedQuery,
					      mLowerBound);

    return evaluateSample(unnormalizedQuery);
  } // evaluateNormalizedSample

  int sampleInitialPoints( size_t nSamples, size_t nDims, bool useLatinBox );
  int nextPoint( vectord &Xnext );

protected:

  NonParametricProcess* mGP;           /// Pointer to surrogate model
  Criteria crit;                       /// Criteria model
  criterium_name crit_name;            /// Name of the criteria
  size_t mMaxIterations;               /// Maximum SKO evaluations (budget)
  vectord mLowerBound, mRangeBound;    /// Lower bound and range of the input space
  int mVerbose;                        /// Verbose level

};

/**@}*/

#endif
<commit_msg>Minor bug in matlab interface. Some clean up.<commit_after>/**
 * @file   bayesoptcont.hpp
 * @brief  Sequential Krigging Optimization (SKO)
 *
 * This file implements Sequential Krigging Optimization using different
 * non-parametric processes as surrogate (krigging) functions.
 */

/*
-----------------------------------------------------------------------------
   This file is part of BayesOptimization, an efficient C++ library for
   Bayesian optimization.

   Copyright (C) 2011 Ruben Martinez-Cantin <rmcantin@unizar.es>

   BayesOptimization is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   BayesOptimization 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 General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with BayesOptimization.  If not, see <http://www.gnu.org/licenses/>.
-----------------------------------------------------------------------------
*/

#ifndef  _BAYESOPTCONT_HPP_
#define  _BAYESOPTCONT_HPP_

#include "specialtypes.hpp"
#include "elementwiseUblas.hpp"

#include "inneroptimization.hpp"
#include "nonparametricprocess.hpp"

#include "ctypes.h"
#include "criteria.hpp"

// Included here to simplify the C++-API
#include "gaussprocess.hpp"
#include "basicgaussprocess.hpp"
#include "studenttprocess.hpp"

/** \addtogroup BayesOptimization */
/**@{*/

/**
 * \brief Sequential Kriging Optimization using different non-parametric
 * processes as surrogate (kriging) functions.
 */
class SKO: public InnerOptimization
{
 public:

  /**
   * Constructor
   *
   * @param gp        Pointer to the surrogate model
   */
  SKO( NonParametricProcess* gp = NULL );

  /**
   * Default destructor
   *
   * @return
   */
  virtual ~SKO();

  /**
   * Execute the optimization process of the function defined in evaluateSample.
   * We assume that the function is defined in the [0,1] hypercube, as a
   * normalized representation of the bound constrains.
   *
   * @see scaleInput
   * @see evaluateSample
   *
   * @param bestPoint returns the optimum value in a ublas::vector defined in
   * the hypercube [0,1], it might also be used as an initial point
   * @param nIterations number of iterations (budget)
   *
   * @return 1 if terminate successfully, 0 otherwise
   */
  inline int optimize( vectord &bestPoint,
		       size_t nIterations )
  {
    size_t dim = bestPoint.size();
    vectord lowerBound = zvectord(dim);
    vectord upperBound = svectord(dim,1.0);

    return optimize(bestPoint,lowerBound,upperBound,nIterations);
  }

  /**
   * Execute the optimization process of the function defined in evaluateSample.
   * We assume that the function is defined in the hypercube defined by
   * the lower and upper vectors.
   *
   * @param bestPoint returns the optimum value in a ublas::vector x,
   * it might also be used as an initial point
   * @param lowerBound vector with the lower bounds of the hypercube
   * @param upperBound vector with the upper bounds of the hypercube
   * @param nIterations number of iterations (budget)
   *
   * @return 1 if terminate successfully, 0 otherwise
   */
  int optimize( vectord &bestPoint,
		vectord &lowerBound,
		vectord &upperBound,
		size_t nIterations );

  /**
   * Chooses which criterium to optimize in the inner loop.
   *
   * @param c criterium name
   */
  void setCriteria (criterium_name c)
  {crit_name = c;}

  /**
   * Function that defines the actual mathematical function to be optimized.
   * Virtual function for polymorphism. This function must need to be modified
   * according to the specific problem.
   *
   * @param query point to be evaluated.
   *
   * @return value of the function at the point evaluated.
   */
  virtual double evaluateSample( const vectord &query )
  { return 0.0; };

  /**
   * This function checks if the query is valid or not. It can be used
   * to introduce arbitrary constrains. Since the Gaussian process
   * assumes smoothness, constrains are managed by DIRECT, being highly
   * time consuming. If the constrain is very tricky, DIRECT will need
   * much more function evaluations.
   *
   * Note: This function is experimental.
   *
   * @param query point to be evaluated.
   *
   * @return boolean value showing if the the function is valid at
   *         the query point or not.
   */
  virtual bool checkReachability( const vectord &query )
  { return true; };

  /**
   * Function that returns the corresponding criteria of a series
   * of queries in the hypercube [0,1] in order to choose the best point to try
   * the next iteration.
   *
   * @param query point in the hypercube [0,1] to evaluate the Gaussian process
   *
   * @return negative criteria (Expected Improvement, LCB, A-optimality, etc.).
   */

  virtual double innerEvaluate( const vectord &query,
				vectord &grad )
  {   return evaluateCriteria(query); }

protected:

  inline double evaluateCriteria( const vectord &query )
  {
    bool reachable = checkReachability(query);
    if (!reachable)  return 0.0;
    return crit.evaluate(*mGP,query);
  }  // evaluateCriteria

  inline double evaluateNormalizedSample( const vectord &query)
  {
    vectord unnormalizedQuery = ublas_elementwise_prod(query,
						       mRangeBound);

    unnormalizedQuery = ublas_elementwise_add(unnormalizedQuery,
					      mLowerBound);

    return evaluateSample(unnormalizedQuery);
  } // evaluateNormalizedSample

  int sampleInitialPoints( size_t nSamples, size_t nDims, bool useLatinBox );
  int nextPoint( vectord &Xnext );

protected:

  NonParametricProcess* mGP;        ///< Pointer to surrogate model
  Criteria crit;                    ///< Criteria model
  criterium_name crit_name;         ///< Name of the criteria
  size_t mMaxIterations;            ///< Maximum SKO evaluations (budget)
  vectord mLowerBound, mRangeBound; ///< Lower bound and range of the input space
  int mVerbose;                     ///< Verbose level

};

/**@}*/

#endif
<|endoftext|>