<commit_before>/////////////////////////////////////////////////////////////////////////
// $Id: iodebug.cc,v 1.31 2009/02/08 09:05:52 vruppert Exp $
/////////////////////////////////////////////////////////////////////////
//
//  Copyright (C) 2008  MandrakeSoft S.A.
//
//    MandrakeSoft S.A.
//    43, rue d'Aboukir
//    75002 Paris - France
//    http://www.linux-mandrake.com/
//    http://www.mandrakesoft.com/
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
/////////////////////////////////////////////////////////////////////////

// Define BX_PLUGGABLE in files that can be compiled into plugins.  For
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
// is used to know when we are exporting symbols and when we are importing.
#define BX_PLUGGABLE

#include "iodev.h"

#if BX_SUPPORT_IODEBUG

#include "cpu/cpu.h"
#include "iodebug.h"

#define BX_IODEBUG_THIS this->

bx_iodebug_c *theIODebugDevice = NULL;

int libiodebug_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
{
  theIODebugDevice = new bx_iodebug_c();
  bx_devices.pluginIODebug = theIODebugDevice;
  BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theIODebugDevice, BX_PLUGIN_IODEBUG);
  return(0); // Success
}

void libiodebug_LTX_plugin_fini(void)
{
  delete theIODebugDevice;
}

struct bx_iodebug_s_type {
  bx_bool enabled;
  unsigned register_select;
  Bit32u registers[2];
  bx_phy_address monitored_mem_areas_start[BX_IODEBUG_MAX_AREAS];
  bx_phy_address monitored_mem_areas_end[BX_IODEBUG_MAX_AREAS];
} bx_iodebug_s;

bx_iodebug_c::bx_iodebug_c()
{
  put("IODBG");
}

void bx_iodebug_c::init(void)
{
  DEV_register_ioread_handler(this, read_handler, 0x8A00,"BOCHS IODEBUG", 2);
  DEV_register_iowrite_handler(this, write_handler, 0x8A00,"BOCHS IODEBUG", 2);
  DEV_register_iowrite_handler(this, write_handler, 0x8A01,"BOCHS IODEBUG", 2);

  bx_iodebug_s.enabled = 0;
  bx_iodebug_s.register_select = 0;

  for(int i=0;i<BX_IODEBUG_MAX_AREAS;i++) {
    bx_iodebug_s.monitored_mem_areas_start[i] = 0;
    bx_iodebug_s.monitored_mem_areas_end[i] = 0;
  }
}

Bit32u bx_iodebug_c::read_handler(void *this_ptr, Bit32u addr, unsigned io_len)
{
  bx_iodebug_c *bx_iodebug_ptr = (bx_iodebug_c *) this_ptr;
  return bx_iodebug_ptr->read(addr, io_len);
}

Bit32u bx_iodebug_c::read(Bit32u addr, unsigned io_len)
{
  if (bx_iodebug_s.enabled) return 0x8A00;
  return(0);
}

void bx_iodebug_c::write_handler(void *this_ptr, Bit32u addr, Bit32u dvalue, unsigned io_len)
{
  bx_iodebug_c *bx_iodebug_ptr = (bx_iodebug_c *) this_ptr;
  bx_iodebug_ptr->write(addr, dvalue, io_len);
}

void bx_iodebug_c::write(Bit32u addr, Bit32u dvalue, unsigned io_len)
{
//fprintf(stderr, "IODEBUG addr: %4x\tdvalue: %8x\tio_len: %8x\n", (unsigned) addr, (unsigned) dvalue, io_len);

  if (addr == 0x8A01)
  {
    bx_iodebug_s.registers[bx_iodebug_s.register_select] =
        (bx_iodebug_s.registers[bx_iodebug_s.register_select] << 16) +
	(dvalue & 0xFFFF);
  }

  if (addr != 0x8A00) return;

  if (!bx_iodebug_s.enabled)
  {
    if(dvalue == 0x8A00)
    {
      bx_iodebug_s.enabled = 1;
//    fprintf(stderr, "IODEBUG enabled\n");
      bx_iodebug_s.registers[0] = 0;
      bx_iodebug_s.registers[1] = 0;
    }
    return;
  }

  switch(dvalue)
  {
    case 0x8A01:
      bx_iodebug_s.register_select = 0;
//    fprintf(stderr, "IODEBUG register 0 selected\n");
      break;

    case 0x8A02:
      bx_iodebug_s.register_select = 1;
//    fprintf(stderr, "IODEBUG register 1 selected\n");
      break;

    case 0x8A80:
      bx_iodebug_s.register_select = 0;
      bx_iodebug_c::add_range(bx_iodebug_s.registers[0],
	  bx_iodebug_s.registers[1]);
      bx_iodebug_s.registers[0] = 0;
      bx_iodebug_s.registers[1] = 0;
      break;

#if BX_DEBUGGER
    case 0x8AE0:
      fprintf(stderr, "request return to dbg prompt received, 0x8AE0 command (iodebug)\n");
      bx_guard.interrupt_requested=1;
      break;

    case 0x8AE2:
      fprintf(stderr, "request made by the guest os to disable tracing, iodebug port 0x8A00->0x8AE2\n");
      BX_CPU(dbg_cpu)->trace = 0;
      break;

    case 0x8AE3:
      fprintf(stderr, "request made by the guest os to enable tracing, iodebug port 0x8A00->0x8AE3\n");
      BX_CPU(dbg_cpu)->trace = 1;
      break;

    case 0x8AE4:
      fprintf(stderr, "request made by the guest os to disable register tracing, iodebug port 0x8A00->0x8AE4\n");
      BX_CPU(dbg_cpu)->trace_reg = 0;
      break;

    case 0x8AE5:
      fprintf(stderr, "request made by the guest os to enable register tracing, iodebug port 0x8A00->0x8AE5\n");
      BX_CPU(dbg_cpu)->trace_reg = 1;
      break;
#endif
    case 0x8AFF:
      bx_iodebug_s.enabled = 0;
//      fprintf(stderr, "IODEBUG device deactivated\n");
//      break;

//    default:
//      fprintf(stderr,"IODEBUG unsupported register code\n");
  }
}

// Static function
void bx_iodebug_c::mem_write(BX_CPU_C *cpu, bx_phy_address addr, unsigned len, void *data)
{
  if(! bx_iodebug_s.enabled) return;

  unsigned area = bx_iodebug_c::range_test(addr, len);
  // Device is enabled, testing address ranges
  if(area)
  {
    area--;

#if BX_DEBUGGER
    if (cpu != NULL) {
      fprintf(stdout, "IODEBUG %s @ eip: " FMT_ADDRX " write at monitored memory location %8X\n",
         cpu->name, cpu->get_instruction_pointer(), addr);
    }
    else {
      fprintf(stdout, "IODEBUG write at monitored memory location %8X\n", addr);
    }
    bx_guard.interrupt_requested=1;
#else
    fprintf(stderr, "IODEBUG write to monitored memory area: %2i\t", area);

    if (cpu != NULL)
      fprintf(stderr, "by EIP:\t\t" FMT_ADDRX "\n\t", cpu->get_instruction_pointer());
    else
      fprintf(stderr, "(device origin)\t");

    fprintf(stderr, "range start: \t\t%08X\trange end:\t%08X\n\taddress accessed:\t%08X\tdata written:\t",
            bx_iodebug_s.monitored_mem_areas_start[area],
            bx_iodebug_s.monitored_mem_areas_end[area],
            (unsigned) addr);

    switch(len)
    {
      case 1: {
        Bit8u data8 = * ((Bit8u *) data);
        fprintf(stderr,"%02X\n", (unsigned) data8);
	break;
      }
      case 2: {
        Bit16u data16 = * ((Bit16u *) data);
        fprintf(stderr,"%04X\n", (unsigned) data16);
	break;
      }
      case 4: {
        Bit32u data32 = * ((Bit32u *) data);
        fprintf(stderr,"%08X\n", (unsigned) data32);
	break;
      }
      case 8: {
        Bit64u data64 = * ((Bit64u *) data);
        fprintf(stderr,"%08X%08x\n",
            (unsigned) (data64 >> 32),
            (unsigned) (data64 & 0xffffffff));
	break;
      }
      default:
        fprintf(stderr, "unsupported write size\n");
    }
#endif
  }
}

void bx_iodebug_c::mem_read(BX_CPU_C *cpu, bx_phy_address addr, unsigned len, void *data)
{
  if(! bx_iodebug_s.enabled) return;

  unsigned area = bx_iodebug_c::range_test(addr, len);
  // Device is enabled, testing address ranges
  if(area)
  {
    area--;

#if BX_DEBUGGER
    if (cpu != NULL) {
      fprintf(stdout, "IODEBUG %s @ eip: " FMT_ADDRX " read at monitored memory location %8X\n",
        cpu->name, cpu->get_instruction_pointer(), addr);
    }
    else {
      fprintf(stdout, "IODEBUG read at monitored memory location %8X\n", addr);
    }
    bx_guard.interrupt_requested=1;
#else
    fprintf(stderr, "IODEBUG read at monitored memory area: %2i\t", area);

    if (cpu != NULL)
      fprintf(stderr, "by EIP:\t\t" FMT_ADDRX "\n\t", cpu->get_instruction_pointer());
    else
      fprintf(stderr, "(device origin)\t");

    fprintf(stderr, "range start: \t\t%08X\trange end:\t%08X\n\taddress accessed:\t%08X\tdata written:\t",
	     bx_iodebug_s.monitored_mem_areas_start[area],
	     bx_iodebug_s.monitored_mem_areas_end[area],
	     (unsigned) addr);

    switch(len)
    {
      case 1: {
        Bit8u data8 = * ((Bit8u *) data);
        fprintf(stderr,"%02X\n", (unsigned) data8);
	break;
      }
      case 2: {
        Bit16u data16 = * ((Bit16u *) data);
        fprintf(stderr,"%04X\n", (unsigned) data16);
	break;
      }
      case 4: {
        Bit32u data32 = * ((Bit32u *) data);
        fprintf(stderr,"%08X\n", (unsigned) data32);
	break;
      }
      case 8: {
        Bit64u data64 = * ((Bit64u *) data);
        fprintf(stderr,"%08X%08x\n",
            (unsigned) (data64 >> 32),
            (unsigned) (data64 & 0xffffffff));
	break;
      }
      default:
        fprintf(stderr, "unsupported read size\n");
    }
#endif
  }
}

unsigned bx_iodebug_c::range_test(bx_phy_address addr, unsigned len)
{
  for(unsigned i=0;i<BX_IODEBUG_MAX_AREAS;i++)
  {
    if(bx_iodebug_s.monitored_mem_areas_start[i] != 0 ||
       bx_iodebug_s.monitored_mem_areas_end[i] != 0)
    {
      if((Bit32u)(addr+len-1) < bx_iodebug_s.monitored_mem_areas_start[i])
        continue;

      if(addr < bx_iodebug_s.monitored_mem_areas_end[i])
      {
        return(++i);
      }
    }
  }

  return(0);
}

void bx_iodebug_c::add_range(bx_phy_address addr_start, bx_phy_address addr_end)
{
  for(unsigned i=0;i<BX_IODEBUG_MAX_AREAS;i++)
  {
    if(!bx_iodebug_s.monitored_mem_areas_start[i] &&
       !bx_iodebug_s.monitored_mem_areas_end[i])
    {
	bx_iodebug_s.monitored_mem_areas_start[i] = addr_start;
	bx_iodebug_s.monitored_mem_areas_end[i] = addr_end;
//	fprintf(stderr, "IODEBUG added range successfully in slot: %i\n",i);
	return;
    }
  }
//fprintf(stderr, "IODEBUG unable to register memory range, all slots taken\n");
}

#endif /* if BX_SUPPORT_IODEBUG */
<commit_msg>iodebug compilation fix<commit_after>/////////////////////////////////////////////////////////////////////////
// $Id: iodebug.cc,v 1.32 2009/05/12 15:03:07 sshwarts Exp $
/////////////////////////////////////////////////////////////////////////
//
//  Copyright (C) 2008  MandrakeSoft S.A.
//
//    MandrakeSoft S.A.
//    43, rue d'Aboukir
//    75002 Paris - France
//    http://www.linux-mandrake.com/
//    http://www.mandrakesoft.com/
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
/////////////////////////////////////////////////////////////////////////

// Define BX_PLUGGABLE in files that can be compiled into plugins.  For
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
// is used to know when we are exporting symbols and when we are importing.
#define BX_PLUGGABLE

#include "iodev.h"

#if BX_SUPPORT_IODEBUG

#include "cpu/cpu.h"
#include "iodebug.h"

#define BX_IODEBUG_THIS this->

bx_iodebug_c *theIODebugDevice = NULL;

int libiodebug_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
{
  theIODebugDevice = new bx_iodebug_c();
  bx_devices.pluginIODebug = theIODebugDevice;
  BX_REGISTER_DEVICE_DEVMODEL(plugin, type, theIODebugDevice, BX_PLUGIN_IODEBUG);
  return(0); // Success
}

void libiodebug_LTX_plugin_fini(void)
{
  delete theIODebugDevice;
}

struct bx_iodebug_s_type {
  bx_bool enabled;
  unsigned register_select;
  Bit32u registers[2];
  bx_phy_address monitored_mem_areas_start[BX_IODEBUG_MAX_AREAS];
  bx_phy_address monitored_mem_areas_end[BX_IODEBUG_MAX_AREAS];
} bx_iodebug_s;

bx_iodebug_c::bx_iodebug_c()
{
  put("IODBG");
}

void bx_iodebug_c::init(void)
{
  DEV_register_ioread_handler(this, read_handler, 0x8A00,"BOCHS IODEBUG", 2);
  DEV_register_iowrite_handler(this, write_handler, 0x8A00,"BOCHS IODEBUG", 2);
  DEV_register_iowrite_handler(this, write_handler, 0x8A01,"BOCHS IODEBUG", 2);

  bx_iodebug_s.enabled = 0;
  bx_iodebug_s.register_select = 0;

  for(int i=0;i<BX_IODEBUG_MAX_AREAS;i++) {
    bx_iodebug_s.monitored_mem_areas_start[i] = 0;
    bx_iodebug_s.monitored_mem_areas_end[i] = 0;
  }
}

Bit32u bx_iodebug_c::read_handler(void *this_ptr, Bit32u addr, unsigned io_len)
{
  bx_iodebug_c *bx_iodebug_ptr = (bx_iodebug_c *) this_ptr;
  return bx_iodebug_ptr->read(addr, io_len);
}

Bit32u bx_iodebug_c::read(Bit32u addr, unsigned io_len)
{
  if (bx_iodebug_s.enabled) return 0x8A00;
  return(0);
}

void bx_iodebug_c::write_handler(void *this_ptr, Bit32u addr, Bit32u dvalue, unsigned io_len)
{
  bx_iodebug_c *bx_iodebug_ptr = (bx_iodebug_c *) this_ptr;
  bx_iodebug_ptr->write(addr, dvalue, io_len);
}

void bx_iodebug_c::write(Bit32u addr, Bit32u dvalue, unsigned io_len)
{
//fprintf(stderr, "IODEBUG addr: %4x\tdvalue: %8x\tio_len: %8x\n", (unsigned) addr, (unsigned) dvalue, io_len);

  if (addr == 0x8A01)
  {
    bx_iodebug_s.registers[bx_iodebug_s.register_select] =
        (bx_iodebug_s.registers[bx_iodebug_s.register_select] << 16) +
	(dvalue & 0xFFFF);
  }

  if (addr != 0x8A00) return;

  if (!bx_iodebug_s.enabled)
  {
    if(dvalue == 0x8A00)
    {
      bx_iodebug_s.enabled = 1;
//    fprintf(stderr, "IODEBUG enabled\n");
      bx_iodebug_s.registers[0] = 0;
      bx_iodebug_s.registers[1] = 0;
    }
    return;
  }

  switch(dvalue)
  {
    case 0x8A01:
      bx_iodebug_s.register_select = 0;
//    fprintf(stderr, "IODEBUG register 0 selected\n");
      break;

    case 0x8A02:
      bx_iodebug_s.register_select = 1;
//    fprintf(stderr, "IODEBUG register 1 selected\n");
      break;

    case 0x8A80:
      bx_iodebug_s.register_select = 0;
      bx_iodebug_c::add_range(bx_iodebug_s.registers[0],
	  bx_iodebug_s.registers[1]);
      bx_iodebug_s.registers[0] = 0;
      bx_iodebug_s.registers[1] = 0;
      break;

#if BX_DEBUGGER
    case 0x8AE0:
      fprintf(stderr, "request return to dbg prompt received, 0x8AE0 command (iodebug)\n");
      bx_guard.interrupt_requested=1;
      break;

    case 0x8AE2:
      fprintf(stderr, "request made by the guest os to disable tracing, iodebug port 0x8A00->0x8AE2\n");
      BX_CPU(dbg_cpu)->trace = 0;
      break;

    case 0x8AE3:
      fprintf(stderr, "request made by the guest os to enable tracing, iodebug port 0x8A00->0x8AE3\n");
      BX_CPU(dbg_cpu)->trace = 1;
      break;

    case 0x8AE4:
      fprintf(stderr, "request made by the guest os to disable register tracing, iodebug port 0x8A00->0x8AE4\n");
      BX_CPU(dbg_cpu)->trace_reg = 0;
      break;

    case 0x8AE5:
      fprintf(stderr, "request made by the guest os to enable register tracing, iodebug port 0x8A00->0x8AE5\n");
      BX_CPU(dbg_cpu)->trace_reg = 1;
      break;
#endif
    case 0x8AFF:
      bx_iodebug_s.enabled = 0;
//      fprintf(stderr, "IODEBUG device deactivated\n");
//      break;

//    default:
//      fprintf(stderr,"IODEBUG unsupported register code\n");
  }
}

// Static function
void bx_iodebug_c::mem_write(BX_CPU_C *cpu, bx_phy_address addr, unsigned len, void *data)
{
  if(! bx_iodebug_s.enabled) return;

  unsigned area = bx_iodebug_c::range_test(addr, len);
  // Device is enabled, testing address ranges
  if(area)
  {
    area--;

#if BX_DEBUGGER
    if (cpu != NULL) {
      fprintf(stdout, "IODEBUG CPU %d @ eip: " FMT_ADDRX " write at monitored memory location %8X\n",
         cpu->bx_cpuid, cpu->get_instruction_pointer(), addr);
    }
    else {
      fprintf(stdout, "IODEBUG write at monitored memory location %8X\n", addr);
    }
    bx_guard.interrupt_requested=1;
#else
    fprintf(stderr, "IODEBUG write to monitored memory area: %2i\t", area);

    if (cpu != NULL)
      fprintf(stderr, "by EIP:\t\t" FMT_ADDRX "\n\t", cpu->get_instruction_pointer());
    else
      fprintf(stderr, "(device origin)\t");

    fprintf(stderr, "range start: \t\t%08X\trange end:\t%08X\n\taddress accessed:\t%08X\tdata written:\t",
            bx_iodebug_s.monitored_mem_areas_start[area],
            bx_iodebug_s.monitored_mem_areas_end[area],
            (unsigned) addr);

    switch(len)
    {
      case 1: {
        Bit8u data8 = * ((Bit8u *) data);
        fprintf(stderr,"%02X\n", (unsigned) data8);
	break;
      }
      case 2: {
        Bit16u data16 = * ((Bit16u *) data);
        fprintf(stderr,"%04X\n", (unsigned) data16);
	break;
      }
      case 4: {
        Bit32u data32 = * ((Bit32u *) data);
        fprintf(stderr,"%08X\n", (unsigned) data32);
	break;
      }
      case 8: {
        Bit64u data64 = * ((Bit64u *) data);
        fprintf(stderr,"%08X%08x\n",
            (unsigned) (data64 >> 32),
            (unsigned) (data64 & 0xffffffff));
	break;
      }
      default:
        fprintf(stderr, "unsupported write size\n");
    }
#endif
  }
}

void bx_iodebug_c::mem_read(BX_CPU_C *cpu, bx_phy_address addr, unsigned len, void *data)
{
  if(! bx_iodebug_s.enabled) return;

  unsigned area = bx_iodebug_c::range_test(addr, len);
  // Device is enabled, testing address ranges
  if(area)
  {
    area--;

#if BX_DEBUGGER
    if (cpu != NULL) {
      fprintf(stdout, "IODEBUG CPU %d @ eip: " FMT_ADDRX " read at monitored memory location %8X\n",
        cpu->bx_cpuid, cpu->get_instruction_pointer(), addr);
    }
    else {
      fprintf(stdout, "IODEBUG read at monitored memory location %8X\n", addr);
    }
    bx_guard.interrupt_requested=1;
#else
    fprintf(stderr, "IODEBUG read at monitored memory area: %2i\t", area);

    if (cpu != NULL)
      fprintf(stderr, "by EIP:\t\t" FMT_ADDRX "\n\t", cpu->get_instruction_pointer());
    else
      fprintf(stderr, "(device origin)\t");

    fprintf(stderr, "range start: \t\t%08X\trange end:\t%08X\n\taddress accessed:\t%08X\tdata written:\t",
	     bx_iodebug_s.monitored_mem_areas_start[area],
	     bx_iodebug_s.monitored_mem_areas_end[area],
	     (unsigned) addr);

    switch(len)
    {
      case 1: {
        Bit8u data8 = * ((Bit8u *) data);
        fprintf(stderr,"%02X\n", (unsigned) data8);
	break;
      }
      case 2: {
        Bit16u data16 = * ((Bit16u *) data);
        fprintf(stderr,"%04X\n", (unsigned) data16);
	break;
      }
      case 4: {
        Bit32u data32 = * ((Bit32u *) data);
        fprintf(stderr,"%08X\n", (unsigned) data32);
	break;
      }
      case 8: {
        Bit64u data64 = * ((Bit64u *) data);
        fprintf(stderr,"%08X%08x\n",
            (unsigned) (data64 >> 32),
            (unsigned) (data64 & 0xffffffff));
	break;
      }
      default:
        fprintf(stderr, "unsupported read size\n");
    }
#endif
  }
}

unsigned bx_iodebug_c::range_test(bx_phy_address addr, unsigned len)
{
  for(unsigned i=0;i<BX_IODEBUG_MAX_AREAS;i++)
  {
    if(bx_iodebug_s.monitored_mem_areas_start[i] != 0 ||
       bx_iodebug_s.monitored_mem_areas_end[i] != 0)
    {
      if((Bit32u)(addr+len-1) < bx_iodebug_s.monitored_mem_areas_start[i])
        continue;

      if(addr < bx_iodebug_s.monitored_mem_areas_end[i])
      {
        return(++i);
      }
    }
  }

  return(0);
}

void bx_iodebug_c::add_range(bx_phy_address addr_start, bx_phy_address addr_end)
{
  for(unsigned i=0;i<BX_IODEBUG_MAX_AREAS;i++)
  {
    if(!bx_iodebug_s.monitored_mem_areas_start[i] &&
       !bx_iodebug_s.monitored_mem_areas_end[i])
    {
	bx_iodebug_s.monitored_mem_areas_start[i] = addr_start;
	bx_iodebug_s.monitored_mem_areas_end[i] = addr_end;
//	fprintf(stderr, "IODEBUG added range successfully in slot: %i\n",i);
	return;
    }
  }
//fprintf(stderr, "IODEBUG unable to register memory range, all slots taken\n");
}

#endif /* if BX_SUPPORT_IODEBUG */
<|endoftext|>


<commit_before>#include <cerrno>
#include <algorithm>
#include <vector>
#include <map>

#include <strings.h> // for strcasecmp

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <fcntl.h>

#include "archive.hh"
#include "util.hh"
#include "config.hh"

namespace nix {

struct ArchiveSettings : Config
{
    Setting<bool> useCaseHack{this,
        #if __APPLE__
            true,
        #else
            false,
        #endif
        "use-case-hack",
        "Whether to enable a Darwin-specific hack for dealing with file name collisions."};
};

static ArchiveSettings archiveSettings;

static GlobalConfig::Register r1(&archiveSettings);

const std::string narVersionMagic1 = "nix-archive-1";

static string caseHackSuffix = "~nix~case~hack~";

PathFilter defaultPathFilter = [](const Path &) { return true; };

static void dumpContents(const Path & path, size_t size,
    Sink & sink)
{
    sink << "contents" << size;

    AutoCloseFD fd = open(path.c_str(), O_RDONLY | O_CLOEXEC);
    if (!fd) throw SysError(format("opening file '%1%'") % path);

    std::vector<unsigned char> buf(65536);
    size_t left = size;

    while (left > 0) {
        auto n = std::min(left, buf.size());
        readFull(fd.get(), buf.data(), n);
        left -= n;
        sink(buf.data(), n);
    }

    writePadding(size, sink);
}

static void dump(const Path & path, Sink & sink, PathFilter & filter)
{
    checkInterrupt();

    struct stat st;
    if (lstat(path.c_str(), &st))
        throw SysError(format("getting attributes of path '%1%'") % path);

    sink << "(";

    if (S_ISREG(st.st_mode)) {
        sink << "type" << "regular";
        if (st.st_mode & S_IXUSR)
            sink << "executable" << "";
        dumpContents(path, (size_t) st.st_size, sink);
    }

    else if (S_ISDIR(st.st_mode)) {
        sink << "type" << "directory";

        /* If we're on a case-insensitive system like macOS, undo
           the case hack applied by restorePath(). */
        std::map<string, string> unhacked;
        for (auto & i : readDirectory(path))
            if (archiveSettings.useCaseHack) {
                string name(i.name);
                size_t pos = i.name.find(caseHackSuffix);
                if (pos != string::npos) {
                    debug(format("removing case hack suffix from '%1%'") % (path + "/" + i.name));
                    name.erase(pos);
                }
                if (unhacked.find(name) != unhacked.end())
                    throw Error(format("file name collision in between '%1%' and '%2%'")
                        % (path + "/" + unhacked[name]) % (path + "/" + i.name));
                unhacked[name] = i.name;
            } else
                unhacked[i.name] = i.name;

        for (auto & i : unhacked)
            if (filter(path + "/" + i.first)) {
                sink << "entry" << "(" << "name" << i.first << "node";
                dump(path + "/" + i.second, sink, filter);
                sink << ")";
            }
    }

    else if (S_ISLNK(st.st_mode))
        sink << "type" << "symlink" << "target" << readLink(path);

    else throw Error(format("file '%1%' has an unsupported type") % path);

    sink << ")";
}

void dumpPath(const Path & path, Sink & sink, PathFilter & filter)
{
    sink << narVersionMagic1;
    dump(path, sink, filter);
}

void dumpString(const std::string & s, Sink & sink)
{
    sink << narVersionMagic1 << "(" << "type" << "regular" << "contents" << s << ")";
}

static SerialisationError badArchive(string s)
{
    return SerialisationError("bad archive: " + s);
}

#if 0
static void skipGeneric(Source & source)
{
    if (readString(source) == "(") {
        while (readString(source) != ")")
            skipGeneric(source);
    }
}
#endif

static void parseContents(ParseSink & sink, Source & source, const Path & path)
{
    unsigned long long size = readLongLong(source);

    sink.preallocateContents(size);

    unsigned long long left = size;
    std::vector<unsigned char> buf(65536);

    while (left) {
        checkInterrupt();
        auto n = buf.size();
        if ((unsigned long long)n > left) n = left;
        source(buf.data(), n);
        sink.receiveContents(buf.data(), n);
        left -= n;
    }

    readPadding(size, source);
}

struct CaseInsensitiveCompare
{
    bool operator() (const string & a, const string & b) const
    {
        return strcasecmp(a.c_str(), b.c_str()) < 0;
    }
};

static void parse(ParseSink & sink, Source & source, const Path & path)
{
    string s;

    s = readString(source);
    if (s != "(") throw badArchive("expected open tag");

    enum { tpUnknown, tpRegular, tpDirectory, tpSymlink } type = tpUnknown;

    std::map<Path, int, CaseInsensitiveCompare> names;

    while (1) {
        checkInterrupt();

        s = readString(source);

        if (s == ")") {
            break;
        }

        else if (s == "type") {
            if (type != tpUnknown)
                throw badArchive("multiple type fields");
            string t = readString(source);

            if (t == "regular") {
                type = tpRegular;
                sink.createRegularFile(path);
            }

            else if (t == "directory") {
                sink.createDirectory(path);
                type = tpDirectory;
            }

            else if (t == "symlink") {
                type = tpSymlink;
            }

            else throw badArchive("unknown file type " + t);

        }

        else if (s == "contents" && type == tpRegular) {
            parseContents(sink, source, path);
        }

        else if (s == "executable" && type == tpRegular) {
            auto s = readString(source);
            if (s != "") throw badArchive("executable marker has non-empty value");
            sink.isExecutable();
        }

        else if (s == "entry" && type == tpDirectory) {
            string name, prevName;

            s = readString(source);
            if (s != "(") throw badArchive("expected open tag");

            while (1) {
                checkInterrupt();

                s = readString(source);

                if (s == ")") {
                    break;
                } else if (s == "name") {
                    name = readString(source);
                    if (name.empty() || name == "." || name == ".." || name.find('/') != string::npos || name.find((char) 0) != string::npos)
                        throw Error(format("NAR contains invalid file name '%1%'") % name);
                    if (name <= prevName)
                        throw Error("NAR directory is not sorted");
                    prevName = name;
                    if (archiveSettings.useCaseHack) {
                        auto i = names.find(name);
                        if (i != names.end()) {
                            debug(format("case collision between '%1%' and '%2%'") % i->first % name);
                            name += caseHackSuffix;
                            name += std::to_string(++i->second);
                        } else
                            names[name] = 0;
                    }
                } else if (s == "node") {
                    if (s.empty()) throw badArchive("entry name missing");
                    parse(sink, source, path + "/" + name);
                } else
                    throw badArchive("unknown field " + s);
            }
        }

        else if (s == "target" && type == tpSymlink) {
            string target = readString(source);
            sink.createSymlink(path, target);
        }

        else
            throw badArchive("unknown field " + s);
    }
}

void parseDump(ParseSink & sink, Source & source)
{
    string version;
    try {
        version = readString(source, narVersionMagic1.size());
    } catch (SerialisationError & e) {
        /* This generally means the integer at the start couldn't be
           decoded.  Ignore and throw the exception below. */
    }
    if (version != narVersionMagic1)
        throw badArchive("input doesn't look like a Nix archive");
    parse(sink, source, "");
}

struct RestoreSink : ParseSink
{
    Path dstPath;
    AutoCloseFD fd;

    void createDirectory(const Path & path)
    {
        Path p = dstPath + path;
        if (mkdir(p.c_str(), 0777) == -1)
            throw SysError(format("creating directory '%1%'") % p);
    };

    void createRegularFile(const Path & path)
    {
        Path p = dstPath + path;
        fd = open(p.c_str(), O_CREAT | O_EXCL | O_WRONLY | O_CLOEXEC, 0666);
        if (!fd) throw SysError(format("creating file '%1%'") % p);
    }

    void isExecutable()
    {
        struct stat st;
        if (fstat(fd.get(), &st) == -1)
            throw SysError("fstat");
        if (fchmod(fd.get(), st.st_mode | (S_IXUSR | S_IXGRP | S_IXOTH)) == -1)
            throw SysError("fchmod");
    }

    void preallocateContents(unsigned long long len)
    {
#if HAVE_POSIX_FALLOCATE
        if (len) {
            errno = posix_fallocate(fd.get(), 0, len);
            /* Note that EINVAL may indicate that the underlying
               filesystem doesn't support preallocation (e.g. on
               OpenSolaris).  Since preallocation is just an
               optimisation, ignore it. */
            if (errno && errno != EINVAL && errno != EOPNOTSUPP && errno != ENOSYS)
                throw SysError(format("preallocating file of %1% bytes") % len);
        }
#endif
    }

    void receiveContents(unsigned char * data, unsigned int len)
    {
        writeFull(fd.get(), data, len);
    }

    void createSymlink(const Path & path, const string & target)
    {
        Path p = dstPath + path;
        nix::createSymlink(target, p);
    }
};

void restorePath(const Path & path, Source & source)
{
    RestoreSink sink;
    sink.dstPath = path;
    parseDump(sink, source);
}

void copyNAR(Source & source, Sink & sink)
{
    // FIXME: if 'source' is the output of dumpPath() followed by EOF,
    // we should just forward all data directly without parsing.

    ParseSink parseSink; /* null sink; just parse the NAR */

    LambdaSource wrapper([&](unsigned char * data, size_t len) {
        auto n = source.read(data, len);
        sink(data, n);
        return n;
    });

    parseDump(parseSink, wrapper);
}

}
<commit_msg>nix: preserve inner SerialisationError, never ignore<commit_after>#include <cerrno>
#include <algorithm>
#include <vector>
#include <map>

#include <strings.h> // for strcasecmp

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <fcntl.h>

#include "archive.hh"
#include "util.hh"
#include "config.hh"

namespace nix {

struct ArchiveSettings : Config
{
    Setting<bool> useCaseHack{this,
        #if __APPLE__
            true,
        #else
            false,
        #endif
        "use-case-hack",
        "Whether to enable a Darwin-specific hack for dealing with file name collisions."};
};

static ArchiveSettings archiveSettings;

static GlobalConfig::Register r1(&archiveSettings);

const std::string narVersionMagic1 = "nix-archive-1";

static string caseHackSuffix = "~nix~case~hack~";

PathFilter defaultPathFilter = [](const Path &) { return true; };

static void dumpContents(const Path & path, size_t size,
    Sink & sink)
{
    sink << "contents" << size;

    AutoCloseFD fd = open(path.c_str(), O_RDONLY | O_CLOEXEC);
    if (!fd) throw SysError(format("opening file '%1%'") % path);

    std::vector<unsigned char> buf(65536);
    size_t left = size;

    while (left > 0) {
        auto n = std::min(left, buf.size());
        readFull(fd.get(), buf.data(), n);
        left -= n;
        sink(buf.data(), n);
    }

    writePadding(size, sink);
}

static void dump(const Path & path, Sink & sink, PathFilter & filter)
{
    checkInterrupt();

    struct stat st;
    if (lstat(path.c_str(), &st))
        throw SysError(format("getting attributes of path '%1%'") % path);

    sink << "(";

    if (S_ISREG(st.st_mode)) {
        sink << "type" << "regular";
        if (st.st_mode & S_IXUSR)
            sink << "executable" << "";
        dumpContents(path, (size_t) st.st_size, sink);
    }

    else if (S_ISDIR(st.st_mode)) {
        sink << "type" << "directory";

        /* If we're on a case-insensitive system like macOS, undo
           the case hack applied by restorePath(). */
        std::map<string, string> unhacked;
        for (auto & i : readDirectory(path))
            if (archiveSettings.useCaseHack) {
                string name(i.name);
                size_t pos = i.name.find(caseHackSuffix);
                if (pos != string::npos) {
                    debug(format("removing case hack suffix from '%1%'") % (path + "/" + i.name));
                    name.erase(pos);
                }
                if (unhacked.find(name) != unhacked.end())
                    throw Error(format("file name collision in between '%1%' and '%2%'")
                        % (path + "/" + unhacked[name]) % (path + "/" + i.name));
                unhacked[name] = i.name;
            } else
                unhacked[i.name] = i.name;

        for (auto & i : unhacked)
            if (filter(path + "/" + i.first)) {
                sink << "entry" << "(" << "name" << i.first << "node";
                dump(path + "/" + i.second, sink, filter);
                sink << ")";
            }
    }

    else if (S_ISLNK(st.st_mode))
        sink << "type" << "symlink" << "target" << readLink(path);

    else throw Error(format("file '%1%' has an unsupported type") % path);

    sink << ")";
}

void dumpPath(const Path & path, Sink & sink, PathFilter & filter)
{
    sink << narVersionMagic1;
    dump(path, sink, filter);
}

void dumpString(const std::string & s, Sink & sink)
{
    sink << narVersionMagic1 << "(" << "type" << "regular" << "contents" << s << ")";
}

static SerialisationError badArchive(string s)
{
    return SerialisationError("bad archive: " + s);
}

#if 0
static void skipGeneric(Source & source)
{
    if (readString(source) == "(") {
        while (readString(source) != ")")
            skipGeneric(source);
    }
}
#endif

static void parseContents(ParseSink & sink, Source & source, const Path & path)
{
    unsigned long long size = readLongLong(source);

    sink.preallocateContents(size);

    unsigned long long left = size;
    std::vector<unsigned char> buf(65536);

    while (left) {
        checkInterrupt();
        auto n = buf.size();
        if ((unsigned long long)n > left) n = left;
        source(buf.data(), n);
        sink.receiveContents(buf.data(), n);
        left -= n;
    }

    readPadding(size, source);
}

struct CaseInsensitiveCompare
{
    bool operator() (const string & a, const string & b) const
    {
        return strcasecmp(a.c_str(), b.c_str()) < 0;
    }
};

static void parse(ParseSink & sink, Source & source, const Path & path)
{
    string s;

    s = readString(source);
    if (s != "(") throw badArchive("expected open tag");

    enum { tpUnknown, tpRegular, tpDirectory, tpSymlink } type = tpUnknown;

    std::map<Path, int, CaseInsensitiveCompare> names;

    while (1) {
        checkInterrupt();

        s = readString(source);

        if (s == ")") {
            break;
        }

        else if (s == "type") {
            if (type != tpUnknown)
                throw badArchive("multiple type fields");
            string t = readString(source);

            if (t == "regular") {
                type = tpRegular;
                sink.createRegularFile(path);
            }

            else if (t == "directory") {
                sink.createDirectory(path);
                type = tpDirectory;
            }

            else if (t == "symlink") {
                type = tpSymlink;
            }

            else throw badArchive("unknown file type " + t);

        }

        else if (s == "contents" && type == tpRegular) {
            parseContents(sink, source, path);
        }

        else if (s == "executable" && type == tpRegular) {
            auto s = readString(source);
            if (s != "") throw badArchive("executable marker has non-empty value");
            sink.isExecutable();
        }

        else if (s == "entry" && type == tpDirectory) {
            string name, prevName;

            s = readString(source);
            if (s != "(") throw badArchive("expected open tag");

            while (1) {
                checkInterrupt();

                s = readString(source);

                if (s == ")") {
                    break;
                } else if (s == "name") {
                    name = readString(source);
                    if (name.empty() || name == "." || name == ".." || name.find('/') != string::npos || name.find((char) 0) != string::npos)
                        throw Error(format("NAR contains invalid file name '%1%'") % name);
                    if (name <= prevName)
                        throw Error("NAR directory is not sorted");
                    prevName = name;
                    if (archiveSettings.useCaseHack) {
                        auto i = names.find(name);
                        if (i != names.end()) {
                            debug(format("case collision between '%1%' and '%2%'") % i->first % name);
                            name += caseHackSuffix;
                            name += std::to_string(++i->second);
                        } else
                            names[name] = 0;
                    }
                } else if (s == "node") {
                    if (s.empty()) throw badArchive("entry name missing");
                    parse(sink, source, path + "/" + name);
                } else
                    throw badArchive("unknown field " + s);
            }
        }

        else if (s == "target" && type == tpSymlink) {
            string target = readString(source);
            sink.createSymlink(path, target);
        }

        else
            throw badArchive("unknown field " + s);
    }
}

void parseDump(ParseSink & sink, Source & source)
{
    string version;
    try {
        version = readString(source, narVersionMagic1.size());
    } catch (SerialisationError & e) {
        /* This generally means the integer at the start couldn't be
           decoded.  Ignore and throw the exception below. */
      if (version != narVersionMagic1)
        e.addPrefix("bad archive: input doesn't look like a Nix archive");
      throw;
    }
    if (version != narVersionMagic1)
        throw badArchive("input doesn't look like a Nix archive");
    parse(sink, source, "");
}

struct RestoreSink : ParseSink
{
    Path dstPath;
    AutoCloseFD fd;

    void createDirectory(const Path & path)
    {
        Path p = dstPath + path;
        if (mkdir(p.c_str(), 0777) == -1)
            throw SysError(format("creating directory '%1%'") % p);
    };

    void createRegularFile(const Path & path)
    {
        Path p = dstPath + path;
        fd = open(p.c_str(), O_CREAT | O_EXCL | O_WRONLY | O_CLOEXEC, 0666);
        if (!fd) throw SysError(format("creating file '%1%'") % p);
    }

    void isExecutable()
    {
        struct stat st;
        if (fstat(fd.get(), &st) == -1)
            throw SysError("fstat");
        if (fchmod(fd.get(), st.st_mode | (S_IXUSR | S_IXGRP | S_IXOTH)) == -1)
            throw SysError("fchmod");
    }

    void preallocateContents(unsigned long long len)
    {
#if HAVE_POSIX_FALLOCATE
        if (len) {
            errno = posix_fallocate(fd.get(), 0, len);
            /* Note that EINVAL may indicate that the underlying
               filesystem doesn't support preallocation (e.g. on
               OpenSolaris).  Since preallocation is just an
               optimisation, ignore it. */
            if (errno && errno != EINVAL && errno != EOPNOTSUPP && errno != ENOSYS)
                throw SysError(format("preallocating file of %1% bytes") % len);
        }
#endif
    }

    void receiveContents(unsigned char * data, unsigned int len)
    {
        writeFull(fd.get(), data, len);
    }

    void createSymlink(const Path & path, const string & target)
    {
        Path p = dstPath + path;
        nix::createSymlink(target, p);
    }
};

void restorePath(const Path & path, Source & source)
{
    RestoreSink sink;
    sink.dstPath = path;
    parseDump(sink, source);
}

void copyNAR(Source & source, Sink & sink)
{
    // FIXME: if 'source' is the output of dumpPath() followed by EOF,
    // we should just forward all data directly without parsing.

    ParseSink parseSink; /* null sink; just parse the NAR */

    LambdaSource wrapper([&](unsigned char * data, size_t len) {
        auto n = source.read(data, len);
        sink(data, n);
        return n;
    });

    parseDump(parseSink, wrapper);
}

}
<|endoftext|>


<commit_before>#ifndef ALEPH_TOPOLOGY_BARYCENTRIC_SUBDIVISION_HH__
#define ALEPH_TOPOLOGY_BARYCENTRIC_SUBDIVISION_HH__

#include <aleph/utilities/EmptyFunctor.hh>

#include <iterator>
#include <set>
#include <stdexcept>
#include <type_traits>
#include <unordered_map>
#include <vector>

// Since the data type of the simplex class is allowed to be a boolean
// as well, there will be a multiplication involved in the functor and
// the compiler rightfully warns about this because two boolean values
// are part of the calculation.
_Pragma( "GCC diagnostic push" )
_Pragma( "GCC diagnostic ignored \"-Wint-in-bool-context\"" )

namespace aleph
{

namespace topology
{

/**
  A functor for calculating the barycentric subdivision of
  a combinatorial simplicial complex. The interface of the
  functor is just like a regular function call in order to
  permit chaining multiple subdivisions.

  The following code is thus valid:

  \code{.cpp}
  aleph::topology::BarycentricSubdivision f;
  aleph::topology::SimplicialComplex K;

  auto L = f(K);      // first barycentric subdivision
  auto M = f( f(K) ); // second barycentric subdivision

  \endcode
*/

class BarycentricSubdivision
{
public:

  /**
    Performs a barycentric subdivision of the given simplicial complex
    and returns the result.
  */

  template <class SimplicialComplex, class Functor = aleph::utilities::EmptyFunctor> SimplicialComplex operator()( const SimplicialComplex& K, Functor&& functor = Functor() ) const
  {
    using Simplex    = typename SimplicialComplex::ValueType;
    using VertexType = typename Simplex::VertexType;
    using DataType   = typename Simplex::DataType;

    // Stores the new vertex index of the next barycentre vertex that
    // is to be added to the subdivided complex. Initially, this uses
    // the largest vertex index stored in the input data.
    VertexType barycentreVertex = VertexType();

    {
      std::set<VertexType> vertices;
      K.vertices( std::inserter( vertices, vertices.begin() ) );

      if( vertices.empty() )
        return {};

      barycentreVertex = static_cast<VertexType>( *vertices.rbegin() + 1 );
    }

    // Stores the barycentric subdivision of a given simplex. This map
    // contains copies of the 0-simplices. For the other simplices, we
    // store the resulting subdivision as an (unordered) vector.
    std::unordered_map<Simplex, std::vector<Simplex> > subdivision;

    // Stores the subdivided simplicial complex. Initially, this complex
    // only contains the new barycentre vertices. Later on, it will also
    // contain the subdivided skeletons.
    SimplicialComplex L;

    for( auto itDimension = K.begin_dimension(); itDimension != K.end_dimension(); ++itDimension )
    {
      auto&& s = *itDimension;

      if( s.dimension() == 0 )
        subdivision[s] = { s };
      else
      {
        // Copy the data of the old simplex for its barycentric
        // subdivision. Since the subdivision is a _refinement_
        // of the original complex, this makes sense.
        auto data = s.data() * DataType( functor( 0 ) );
        L.push_back( Simplex( barycentreVertex, data ) );

        // Contains all subdivided simplices of the boundary of
        // the current simplex.
        std::vector<Simplex> subdividedBoundary;

        for( auto itBoundary = s.begin_boundary(); itBoundary != s.end_boundary(); ++itBoundary )
        {
          auto pos = K.find( *itBoundary );

          if( pos == K.end() )
            throw std::runtime_error( "Unable to find boundary simplex" );

          auto&& t = *pos;

          subdividedBoundary.insert( subdividedBoundary.end(),
                                     subdivision.at(t).begin(), subdivision.at(t).end() );
        }

        // Cone over the new barycentre vertex and the subdivided
        // boundary of the current simplex. This cone will become
        // the new subdivision of the current simplex.
        std::vector<Simplex> cone;

        for( auto&& t : subdividedBoundary )
        {
          std::vector<VertexType> vertices( t.begin(), t.end() );
          vertices.push_back( barycentreVertex );

          // The new cone simplex needs to use the same weight as the
          // barycentre simplex.
          cone.emplace_back( Simplex( vertices.begin(), vertices.end(),
                                      s.data() * DataType( functor( vertices.size() ) ) ) );
        }

       // Cone boundaries; required in order to ensure consistency of
       // the resulting simplicial complex.
        std::vector<Simplex> boundaries
          = collectBoundaries( subdividedBoundary.begin(), subdividedBoundary.end() );

        for( auto&& t : boundaries )
        {
          std::vector<VertexType> vertices( t.begin(), t.end() );
          vertices.push_back( barycentreVertex );

          // The new simplex is directly inserted into the boundary of
          // the resulting simplicial complex---it will not be used by
          // any other simplex during the subdivision.
          L.push_back( Simplex( vertices.begin(), vertices.end(),
                                s.data() ) );
        }

        subdivision[s] = cone;

        // Choose new barycentre vertex for the next simplex. All
        // barycentres will thus be numbered sequentially.
        ++barycentreVertex;
      }
    }

    for( auto&& pair : subdivision )
      L.insert( pair.second.begin(), pair.second.end() );

    return L;
  }
private:

  /**
    Collects all boundaries of the given simplex and returns them. This
    is required in order to update lower-dimensional simplices of cones
    correctly.

    Note that the algorithm is rather stupid and slow; it iterates over
    all faces until the set of all simplices remains fixed.
  */

  template <class Simplex> static std::vector<Simplex> collectBoundaries( const Simplex& s )
  {
    std::set<Simplex> simplices;

    for( auto itBoundary = s.begin_boundary(); itBoundary != s.end_boundary(); ++itBoundary )
      simplices.insert( *itBoundary );

    bool newSimplices = false;
    do
    {
      std::set<Simplex> boundaries;

      for( auto&& s : simplices )
      {
        for( auto itBoundary = s.begin_boundary(); itBoundary != s.end_boundary(); ++itBoundary )
          boundaries.insert( *itBoundary );
      }

      auto oldSize = simplices.size();

      simplices.insert( boundaries.begin(),
                        boundaries.end() );

      auto newSize = simplices.size();
      newSimplices = newSize != oldSize;
    }
    while( newSimplices );

    return { simplices.begin(), simplices.end() };
  }

  /**
    Overloaded variant of the function above. It permits the collection
    of all boundaries of a range of simplices.
  */

  template <class InputIterator> static auto collectBoundaries( InputIterator begin, InputIterator end ) -> std::vector<typename std::iterator_traits<InputIterator>::value_type>
  {
    using Simplex = typename std::iterator_traits<InputIterator>::value_type;
    std::set<Simplex> simplices;

    for( auto it = begin; it != end; ++it )
    {
      auto&& boundaries = collectBoundaries( *it );

      simplices.insert( boundaries.begin(),
                        boundaries.end() );
    }

    return { simplices.begin(), simplices.end() };
  }
};

} // namespace topology

} // namespace aleph

_Pragma( "GCC diagnostic pop" )

#endif
<commit_msg>Fixed weight assignment for subdivided boundaries<commit_after>#ifndef ALEPH_TOPOLOGY_BARYCENTRIC_SUBDIVISION_HH__
#define ALEPH_TOPOLOGY_BARYCENTRIC_SUBDIVISION_HH__

#include <aleph/utilities/EmptyFunctor.hh>

#include <iterator>
#include <set>
#include <stdexcept>
#include <type_traits>
#include <unordered_map>
#include <vector>

// Since the data type of the simplex class is allowed to be a boolean
// as well, there will be a multiplication involved in the functor and
// the compiler rightfully warns about this because two boolean values
// are part of the calculation.
_Pragma( "GCC diagnostic push" )
_Pragma( "GCC diagnostic ignored \"-Wint-in-bool-context\"" )

namespace aleph
{

namespace topology
{

/**
  A functor for calculating the barycentric subdivision of
  a combinatorial simplicial complex. The interface of the
  functor is just like a regular function call in order to
  permit chaining multiple subdivisions.

  The following code is thus valid:

  \code{.cpp}
  aleph::topology::BarycentricSubdivision f;
  aleph::topology::SimplicialComplex K;

  auto L = f(K);      // first barycentric subdivision
  auto M = f( f(K) ); // second barycentric subdivision

  \endcode
*/

class BarycentricSubdivision
{
public:

  /**
    Performs a barycentric subdivision of the given simplicial complex
    and returns the result.
  */

  template <class SimplicialComplex, class Functor = aleph::utilities::EmptyFunctor> SimplicialComplex operator()( const SimplicialComplex& K, Functor&& functor = Functor() ) const
  {
    using Simplex    = typename SimplicialComplex::ValueType;
    using VertexType = typename Simplex::VertexType;
    using DataType   = typename Simplex::DataType;

    // Stores the new vertex index of the next barycentre vertex that
    // is to be added to the subdivided complex. Initially, this uses
    // the largest vertex index stored in the input data.
    VertexType barycentreVertex = VertexType();

    {
      std::set<VertexType> vertices;
      K.vertices( std::inserter( vertices, vertices.begin() ) );

      if( vertices.empty() )
        return {};

      barycentreVertex = static_cast<VertexType>( *vertices.rbegin() + 1 );
    }

    // Stores the barycentric subdivision of a given simplex. This map
    // contains copies of the 0-simplices. For the other simplices, we
    // store the resulting subdivision as an (unordered) vector.
    std::unordered_map<Simplex, std::vector<Simplex> > subdivision;

    // Stores the subdivided simplicial complex. Initially, this complex
    // only contains the new barycentre vertices. Later on, it will also
    // contain the subdivided skeletons.
    SimplicialComplex L;

    for( auto itDimension = K.begin_dimension(); itDimension != K.end_dimension(); ++itDimension )
    {
      auto&& s = *itDimension;

      if( s.dimension() == 0 )
        subdivision[s] = { s };
      else
      {
        // Copy the data of the old simplex for its barycentric
        // subdivision. Since the subdivision is a _refinement_
        // of the original complex, this makes sense.
        auto data = s.data() * DataType( functor( 0 ) );
        L.push_back( Simplex( barycentreVertex, data ) );

        // Contains all subdivided simplices of the boundary of
        // the current simplex.
        std::vector<Simplex> subdividedBoundary;

        for( auto itBoundary = s.begin_boundary(); itBoundary != s.end_boundary(); ++itBoundary )
        {
          auto pos = K.find( *itBoundary );

          if( pos == K.end() )
            throw std::runtime_error( "Unable to find boundary simplex" );

          auto&& t = *pos;

          subdividedBoundary.insert( subdividedBoundary.end(),
                                     subdivision.at(t).begin(), subdivision.at(t).end() );
        }

        // Cone over the new barycentre vertex and the subdivided
        // boundary of the current simplex. This cone will become
        // the new subdivision of the current simplex.
        std::vector<Simplex> cone;

        for( auto&& t : subdividedBoundary )
        {
          std::vector<VertexType> vertices( t.begin(), t.end() );
          vertices.push_back( barycentreVertex );

          // The new cone simplex needs to use the same weight as the
          // barycentre simplex.
          cone.emplace_back( Simplex( vertices.begin(), vertices.end(),
                                      s.data() * DataType( functor( vertices.size() ) ) ) );
        }

       // Cone boundaries; required in order to ensure consistency of
       // the resulting simplicial complex.
        std::vector<Simplex> boundaries
          = collectBoundaries( subdividedBoundary.begin(), subdividedBoundary.end() );

        for( auto&& t : boundaries )
        {
          std::vector<VertexType> vertices( t.begin(), t.end() );
          vertices.push_back( barycentreVertex );

          // The new simplex is directly inserted into the boundary of
          // the resulting simplicial complex---it will not be used by
          // any other simplex during the subdivision.
          L.push_back( Simplex( vertices.begin(), vertices.end(),
                                s.data() * DataType( functor( vertices.size() ) ) ) );
        }

        subdivision[s] = cone;

        // Choose new barycentre vertex for the next simplex. All
        // barycentres will thus be numbered sequentially.
        ++barycentreVertex;
      }
    }

    for( auto&& pair : subdivision )
      L.insert( pair.second.begin(), pair.second.end() );

    return L;
  }
private:

  /**
    Collects all boundaries of the given simplex and returns them. This
    is required in order to update lower-dimensional simplices of cones
    correctly.

    Note that the algorithm is rather stupid and slow; it iterates over
    all faces until the set of all simplices remains fixed.
  */

  template <class Simplex> static std::vector<Simplex> collectBoundaries( const Simplex& s )
  {
    std::set<Simplex> simplices;

    for( auto itBoundary = s.begin_boundary(); itBoundary != s.end_boundary(); ++itBoundary )
      simplices.insert( *itBoundary );

    bool newSimplices = false;
    do
    {
      std::set<Simplex> boundaries;

      for( auto&& s : simplices )
      {
        for( auto itBoundary = s.begin_boundary(); itBoundary != s.end_boundary(); ++itBoundary )
          boundaries.insert( *itBoundary );
      }

      auto oldSize = simplices.size();

      simplices.insert( boundaries.begin(),
                        boundaries.end() );

      auto newSize = simplices.size();
      newSimplices = newSize != oldSize;
    }
    while( newSimplices );

    return { simplices.begin(), simplices.end() };
  }

  /**
    Overloaded variant of the function above. It permits the collection
    of all boundaries of a range of simplices.
  */

  template <class InputIterator> static auto collectBoundaries( InputIterator begin, InputIterator end ) -> std::vector<typename std::iterator_traits<InputIterator>::value_type>
  {
    using Simplex = typename std::iterator_traits<InputIterator>::value_type;
    std::set<Simplex> simplices;

    for( auto it = begin; it != end; ++it )
    {
      auto&& boundaries = collectBoundaries( *it );

      simplices.insert( boundaries.begin(),
                        boundaries.end() );
    }

    return { simplices.begin(), simplices.end() };
  }
};

} // namespace topology

} // namespace aleph

_Pragma( "GCC diagnostic pop" )

#endif
<|endoftext|>


<commit_before>/*
 *            Copyright 2009-2020 The VOTCA Development Team
 *                       (http://www.votca.org)
 *
 *      Licensed under the Apache License, Version 2.0 (the "License")
 *
 * You may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *              http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
#include "votca/xtp/basisset.h"
#include <votca/tools/property.h>

namespace votca {
namespace xtp {

Index FindLmax(const std::string& type) {

  assert(!type.empty() && "Shelltype most be non empty!");
  const char t = type.back();
  Index lmax = 0;
  if (t == 'S') {
    lmax = 0;
  } else if (t == 'P') {
    lmax = 1;
  } else if (t == 'D') {
    lmax = 2;
  } else if (t == 'F') {
    lmax = 3;
  } else if (t == 'G') {
    lmax = 4;
  } else if (t == 'H') {
    lmax = 5;
  } else if (t == 'I') {
    lmax = 6;
  } else {
    throw std::runtime_error("FindLmax: Shelltype not known");
  }
  return lmax;
}

Index FindLmin(const std::string& type) {
  assert(!type.empty() && "Shelltype most be non empty!");
  Index lmin = std::numeric_limits<Index>::max();
  const char t = type[0];
  if (t == 'S') {
    lmin = 0;
  } else if (t == 'P') {
    lmin = 1;
  } else if (t == 'D') {
    lmin = 2;
  } else if (t == 'F') {
    lmin = 3;
  } else if (t == 'G') {
    lmin = 4;
  } else if (t == 'H') {
    lmin = 5;
  } else if (t == 'I') {
    lmin = 6;
  } else {
    throw std::runtime_error("FindLmax: Shelltype not known");
  }
  return lmin;
}

Index OffsetFuncShell(const std::string& shell_type) {
  Index nbf = std::numeric_limits<Index>::max();
  assert(!shell_type.empty() && "Shelltype most be non empty!");
  const char t = shell_type[0];
  if (t == 'S') {
    nbf = 0;
  } else if (t == 'P') {
    nbf = 1;
  } else if (t == 'D') {
    nbf = 4;
  } else if (t == 'F') {
    nbf = 9;
  } else if (t == 'G') {
    nbf = 16;
  } else if (t == 'H') {
    nbf = 25;
  } else if (t == 'I') {
    nbf = 36;
  } else {
    throw std::runtime_error("OffsetFuncShell: Shelltype not known");
  }
  return nbf;
}

Index NumFuncShell(const std::string& shell_type) {
  Index nbf = 0;
  assert(!shell_type.empty() && "Shelltype most be non empty!");
  // single type shells
  for (const char& t : shell_type) {
    if (t == 'S') {
      nbf += 1;
    } else if (t == 'P') {
      nbf += 3;
    } else if (t == 'D') {
      nbf += 5;
    } else if (t == 'F') {
      nbf += 7;
    } else if (t == 'G') {
      nbf += 9;
    } else if (t == 'H') {
      nbf += 11;
    } else if (t == 'I') {
      nbf += 13;
    } else {
      throw std::runtime_error("FindnumofFunc: Shelltype not known");
    }
  }
  return nbf;
}

std::vector<Index> NumFuncSubShell(const std::string& shell_type) {
  std::vector<Index> subshells;
  // single type shells
  if (shell_type.length() == 1) {
    subshells.push_back(NumFuncShell(shell_type));
    // for combined shells, go over all contributions and add functions
  } else {
    for (Index i = 0; i < Index(shell_type.length()); ++i) {
      std::string local_shell = std::string(shell_type, i, 1);
      subshells.push_back(NumFuncShell(local_shell));
    }
  }
  return subshells;
}

Index NumFuncShell_cartesian(const std::string& shell_type) {
  Index nbf = 0;
  assert(!shell_type.empty() && "Shelltype most be non empty!");
  // single type shells defined here
  for (const char& t : shell_type) {
    if (t == 'S') {
      nbf += 1;
    } else if (t == 'P') {
      nbf += 3;
    } else if (t == 'D') {
      nbf += 6;
    } else if (t == 'F') {
      nbf += 10;
    } else if (t == 'G') {
      nbf += 15;
    } else if (t == 'H') {
      nbf += 21;
    } else if (t == 'I') {
      nbf += 28;
    } else {
      throw std::runtime_error("NumFuncShell_cartesian shell_type not known");
    }
  }
  return nbf;
}

Index OffsetFuncShell_cartesian(const std::string& shell_type) {
  Index nbf = std::numeric_limits<Index>::max();
  assert(!shell_type.empty() && "Shelltype most be non empty!");
  const char t = shell_type[0];
  if (t == 'S') {
    nbf = 0;
  } else if (t == 'P') {
    nbf = 1;
  } else if (t == 'D') {
    nbf = 4;
  } else if (t == 'F') {
    nbf = 10;
  } else if (t == 'G') {
    nbf = 20;
  } else if (t == 'H') {
    nbf = 35;
  } else if (t == 'I') {
    nbf = 56;
  } else {
    throw std::runtime_error("OffsetFuncShell_cartesian shell_type not known");
  }

  return nbf;
}

void BasisSet::Load(const std::string& name) {

  _name = name;
  // if name contains .xml, assume a basisset .xml file is located in the
  // working directory
  std::size_t found_xml = name.find(".xml");
  std::string xmlFile;
  if (found_xml != std::string::npos) {
    xmlFile = name;
  } else {
    // get the path to the shared folders with xml files
    char* votca_share = getenv("VOTCASHARE");
    if (votca_share == nullptr) {
      throw std::runtime_error("VOTCASHARE not set, cannot open help files.");
    }
    xmlFile = std::string(getenv("VOTCASHARE")) +
              std::string("/xtp/basis_sets/") + name + std::string(".xml");
  }
  tools::Property basis_property;
  basis_property.LoadFromXML(xmlFile);
  std::vector<tools::Property*> elementProps =
      basis_property.Select("basis.element");

  for (tools::Property* elementProp : elementProps) {
    std::string elementName = elementProp->getAttribute<std::string>("name");
    Element& element = addElement(elementName);
    std::vector<tools::Property*> shellProps = elementProp->Select("shell");
    for (tools::Property* shellProp : shellProps) {
      std::string shellType = shellProp->getAttribute<std::string>("type");
      double shellScale = shellProp->getAttribute<double>("scale");

      Shell& shell = element.addShell(shellType, shellScale);
      std::vector<tools::Property*> constProps = shellProp->Select("constant");
      for (tools::Property* constProp : constProps) {
        double decay = constProp->getAttribute<double>("decay");
        std::vector<double> contraction =
            std::vector<double>(shell.getLmax() + 1, 0.0);
        std::vector<tools::Property*> contrProps =
            constProp->Select("contractions");
        for (tools::Property* contrProp : contrProps) {
          std::string contrType = contrProp->getAttribute<std::string>("type");
          double contrFactor = contrProp->getAttribute<double>("factor");
          if (contrType == "S") {
            contraction[0] = contrFactor;
          } else if (contrType == "P") {
            contraction[1] = contrFactor;
          } else if (contrType == "D") {
            contraction[2] = contrFactor;
          } else if (contrType == "F") {
            contraction[3] = contrFactor;
          } else if (contrType == "G") {
            contraction[4] = contrFactor;
          } else if (contrType == "H") {
            contraction[5] = contrFactor;
          } else if (contrType == "I") {
            contraction[6] = contrFactor;
          } else {
            throw std::runtime_error("LoadBasiset:Contractiontype not known");
          }
        }
        shell.addGaussian(decay, contraction);
      }
    }
  }
  return;
}

// adding an Element to a Basis Set
Element& BasisSet::addElement(std::string elementType) {
  auto e = _elements.insert({elementType, Element(elementType)});
  if (!e.second) {
    throw std::runtime_error("Inserting element into basisset failed!");
  }
  return e.first->second;
}

const Element& BasisSet::getElement(std::string element_type) const {
  std::map<std::string, Element>::const_iterator itm =
      _elements.find(element_type);
  if (itm == _elements.end()) {
    throw std::runtime_error("Basis set " + _name +
                             " does not have element of type " + element_type);
  }
  return itm->second;
}

std::ostream& operator<<(std::ostream& out, const Shell& shell) {

  out << "Type:" << shell.getType() << " Scale:" << shell.getScale()
      << " Func: " << shell.getnumofFunc() << "\n";
  for (const auto& gaussian : shell._gaussians) {
    out << " Gaussian Decay: " << gaussian.decay();
    out << " Contractions:";
    for (const double& contraction : gaussian.Contractions()) {
      out << " " << contraction;
    }
    out << "\n";
  }
  return out;
}

std::ostream& operator<<(std::ostream& out, const Element& element) {
  out << "Element:" << element.getType() << "\n";
  for (const auto& shell : element) {
    out << shell;
  }
  return out;
}

std::ostream& operator<<(std::ostream& out, const BasisSet& basis) {
  out << "BasisSet:" << basis._name << "\n";
  for (const auto& element : basis) {
    out << element.second;
  }
  out << std::flush;
  return out;
}

GaussianPrimitive& Shell::addGaussian(double decay,
                                      std::vector<double> contraction) {
  _gaussians.push_back(GaussianPrimitive(decay, contraction));
  return _gaussians.back();
}

}  // namespace xtp
}  // namespace votca
<commit_msg>fixed typos<commit_after>/*
 *            Copyright 2009-2020 The VOTCA Development Team
 *                       (http://www.votca.org)
 *
 *      Licensed under the Apache License, Version 2.0 (the "License")
 *
 * You may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *              http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
#include "votca/xtp/basisset.h"
#include <votca/tools/property.h>

namespace votca {
namespace xtp {

Index FindLmax(const std::string& type) {

  assert(!type.empty() && "Shelltype must be non empty!");
  const char t = type.back();
  Index lmax = 0;
  if (t == 'S') {
    lmax = 0;
  } else if (t == 'P') {
    lmax = 1;
  } else if (t == 'D') {
    lmax = 2;
  } else if (t == 'F') {
    lmax = 3;
  } else if (t == 'G') {
    lmax = 4;
  } else if (t == 'H') {
    lmax = 5;
  } else if (t == 'I') {
    lmax = 6;
  } else {
    throw std::runtime_error("FindLmax: Shelltype not known");
  }
  return lmax;
}

Index FindLmin(const std::string& type) {
  assert(!type.empty() && "Shelltype must be non empty!");
  Index lmin = std::numeric_limits<Index>::max();
  const char t = type[0];
  if (t == 'S') {
    lmin = 0;
  } else if (t == 'P') {
    lmin = 1;
  } else if (t == 'D') {
    lmin = 2;
  } else if (t == 'F') {
    lmin = 3;
  } else if (t == 'G') {
    lmin = 4;
  } else if (t == 'H') {
    lmin = 5;
  } else if (t == 'I') {
    lmin = 6;
  } else {
    throw std::runtime_error("FindLmin: Shelltype not known");
  }
  return lmin;
}

Index OffsetFuncShell(const std::string& shell_type) {
  Index nbf = std::numeric_limits<Index>::max();
  assert(!shell_type.empty() && "Shelltype must be non empty!");
  const char t = shell_type[0];
  if (t == 'S') {
    nbf = 0;
  } else if (t == 'P') {
    nbf = 1;
  } else if (t == 'D') {
    nbf = 4;
  } else if (t == 'F') {
    nbf = 9;
  } else if (t == 'G') {
    nbf = 16;
  } else if (t == 'H') {
    nbf = 25;
  } else if (t == 'I') {
    nbf = 36;
  } else {
    throw std::runtime_error("OffsetFuncShell: Shelltype not known");
  }
  return nbf;
}

Index NumFuncShell(const std::string& shell_type) {
  Index nbf = 0;
  assert(!shell_type.empty() && "Shelltype must be non empty!");
  // single type shells
  for (const char& t : shell_type) {
    if (t == 'S') {
      nbf += 1;
    } else if (t == 'P') {
      nbf += 3;
    } else if (t == 'D') {
      nbf += 5;
    } else if (t == 'F') {
      nbf += 7;
    } else if (t == 'G') {
      nbf += 9;
    } else if (t == 'H') {
      nbf += 11;
    } else if (t == 'I') {
      nbf += 13;
    } else {
      throw std::runtime_error("FindnumofFunc: Shelltype not known");
    }
  }
  return nbf;
}

std::vector<Index> NumFuncSubShell(const std::string& shell_type) {
  std::vector<Index> subshells;
  // single type shells
  if (shell_type.length() == 1) {
    subshells.push_back(NumFuncShell(shell_type));
    // for combined shells, go over all contributions and add functions
  } else {
    for (Index i = 0; i < Index(shell_type.length()); ++i) {
      std::string local_shell = std::string(shell_type, i, 1);
      subshells.push_back(NumFuncShell(local_shell));
    }
  }
  return subshells;
}

Index NumFuncShell_cartesian(const std::string& shell_type) {
  Index nbf = 0;
  assert(!shell_type.empty() && "Shelltype must be non empty!");
  // single type shells defined here
  for (const char& t : shell_type) {
    if (t == 'S') {
      nbf += 1;
    } else if (t == 'P') {
      nbf += 3;
    } else if (t == 'D') {
      nbf += 6;
    } else if (t == 'F') {
      nbf += 10;
    } else if (t == 'G') {
      nbf += 15;
    } else if (t == 'H') {
      nbf += 21;
    } else if (t == 'I') {
      nbf += 28;
    } else {
      throw std::runtime_error("NumFuncShell_cartesian shell_type not known");
    }
  }
  return nbf;
}

Index OffsetFuncShell_cartesian(const std::string& shell_type) {
  Index nbf = std::numeric_limits<Index>::max();
  assert(!shell_type.empty() && "Shelltype must be non empty!");
  const char t = shell_type[0];
  if (t == 'S') {
    nbf = 0;
  } else if (t == 'P') {
    nbf = 1;
  } else if (t == 'D') {
    nbf = 4;
  } else if (t == 'F') {
    nbf = 10;
  } else if (t == 'G') {
    nbf = 20;
  } else if (t == 'H') {
    nbf = 35;
  } else if (t == 'I') {
    nbf = 56;
  } else {
    throw std::runtime_error("OffsetFuncShell_cartesian shell_type not known");
  }

  return nbf;
}

void BasisSet::Load(const std::string& name) {

  _name = name;
  // if name contains .xml, assume a basisset .xml file is located in the
  // working directory
  std::size_t found_xml = name.find(".xml");
  std::string xmlFile;
  if (found_xml != std::string::npos) {
    xmlFile = name;
  } else {
    // get the path to the shared folders with xml files
    char* votca_share = getenv("VOTCASHARE");
    if (votca_share == nullptr) {
      throw std::runtime_error("VOTCASHARE not set, cannot open help files.");
    }
    xmlFile = std::string(getenv("VOTCASHARE")) +
              std::string("/xtp/basis_sets/") + name + std::string(".xml");
  }
  tools::Property basis_property;
  basis_property.LoadFromXML(xmlFile);
  std::vector<tools::Property*> elementProps =
      basis_property.Select("basis.element");

  for (tools::Property* elementProp : elementProps) {
    std::string elementName = elementProp->getAttribute<std::string>("name");
    Element& element = addElement(elementName);
    std::vector<tools::Property*> shellProps = elementProp->Select("shell");
    for (tools::Property* shellProp : shellProps) {
      std::string shellType = shellProp->getAttribute<std::string>("type");
      double shellScale = shellProp->getAttribute<double>("scale");

      Shell& shell = element.addShell(shellType, shellScale);
      std::vector<tools::Property*> constProps = shellProp->Select("constant");
      for (tools::Property* constProp : constProps) {
        double decay = constProp->getAttribute<double>("decay");
        std::vector<double> contraction =
            std::vector<double>(shell.getLmax() + 1, 0.0);
        std::vector<tools::Property*> contrProps =
            constProp->Select("contractions");
        for (tools::Property* contrProp : contrProps) {
          std::string contrType = contrProp->getAttribute<std::string>("type");
          double contrFactor = contrProp->getAttribute<double>("factor");
          if (contrType == "S") {
            contraction[0] = contrFactor;
          } else if (contrType == "P") {
            contraction[1] = contrFactor;
          } else if (contrType == "D") {
            contraction[2] = contrFactor;
          } else if (contrType == "F") {
            contraction[3] = contrFactor;
          } else if (contrType == "G") {
            contraction[4] = contrFactor;
          } else if (contrType == "H") {
            contraction[5] = contrFactor;
          } else if (contrType == "I") {
            contraction[6] = contrFactor;
          } else {
            throw std::runtime_error("LoadBasiset:Contractiontype not known");
          }
        }
        shell.addGaussian(decay, contraction);
      }
    }
  }
  return;
}

// adding an Element to a Basis Set
Element& BasisSet::addElement(std::string elementType) {
  auto e = _elements.insert({elementType, Element(elementType)});
  if (!e.second) {
    throw std::runtime_error("Inserting element into basisset failed!");
  }
  return e.first->second;
}

const Element& BasisSet::getElement(std::string element_type) const {
  std::map<std::string, Element>::const_iterator itm =
      _elements.find(element_type);
  if (itm == _elements.end()) {
    throw std::runtime_error("Basis set " + _name +
                             " does not have element of type " + element_type);
  }
  return itm->second;
}

std::ostream& operator<<(std::ostream& out, const Shell& shell) {

  out << "Type:" << shell.getType() << " Scale:" << shell.getScale()
      << " Func: " << shell.getnumofFunc() << "\n";
  for (const auto& gaussian : shell._gaussians) {
    out << " Gaussian Decay: " << gaussian.decay();
    out << " Contractions:";
    for (const double& contraction : gaussian.Contractions()) {
      out << " " << contraction;
    }
    out << "\n";
  }
  return out;
}

std::ostream& operator<<(std::ostream& out, const Element& element) {
  out << "Element:" << element.getType() << "\n";
  for (const auto& shell : element) {
    out << shell;
  }
  return out;
}

std::ostream& operator<<(std::ostream& out, const BasisSet& basis) {
  out << "BasisSet:" << basis._name << "\n";
  for (const auto& element : basis) {
    out << element.second;
  }
  out << std::flush;
  return out;
}

GaussianPrimitive& Shell::addGaussian(double decay,
                                      std::vector<double> contraction) {
  _gaussians.push_back(GaussianPrimitive(decay, contraction));
  return _gaussians.back();
}

}  // namespace xtp
}  // namespace votca
<|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2014-2020 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

/*!
 * \file
 * \brief Contains generators for state dropout mask
 */

#pragma once

#include <chrono> //for std::time

#include "etl/impl/egblas/dropout.hpp"

namespace etl {

/*!
 * \brief Generator from an uniform distribution
 */
template <typename T = double>
struct state_dropout_mask_generator_op {
    using value_type = T; ///< The value type

    const T probability; ///< The dropout probability
    std::shared_ptr<void*> states;
    random_engine rand_engine;                     ///< The random engine
    dropout_distribution<value_type> distribution; ///< The used distribution

    /*!
     * \brief Indicates if the operator can be computed on GPU
     */
    static constexpr bool gpu_computable =
        impl::egblas::has_dropout_prepare && impl::egblas::has_dropout_release
        && ((is_single_precision_t<T> && impl::egblas::has_sdropout_states) || (is_double_precision_t<T> && impl::egblas::has_ddropout_states));

    /*!
     * \brief Construct a new generator with the given start and end of the range
     */
    state_dropout_mask_generator_op(T probability) : probability(probability), rand_engine(std::time(nullptr)), distribution(T(0), T(1)) {
        if /* constexpr*/ (impl::egblas::has_dropout_prepare) {
            states  = std::make_shared<void*>();
            *states = impl::egblas::dropout_prepare();
        }
    }

    /*!
     * \brief Generate a new value
     * \return the newly generated value
     */
    value_type operator()() {
        if (distribution(rand_engine) < probability) {
            return T(0);
        } else {
            return T(1);
        }
    }

    /*!
     * \brief Compute the result of the operation using the GPU
     *
     * \param x The expression of the unary operation
     *
     * \return The result of applying the unary operator on x. The result must be a GPU computed expression.
     */
    template <typename Y>
    auto gpu_compute_hint(Y& y) noexcept {
        decltype(auto) t1 = force_temporary_gpu_dim_only(y);

        impl::egblas::dropout_states(etl::size(y), probability, T(1), t1.gpu_memory(), 1, *states);

        return t1;
    }
    /*!
     * \brief Compute the result of the operation using the GPU
     *
     * \param x The expression of the unary operation
     * \param y The expression into which to store the reuslt
     */
    template <typename Y>
    Y& gpu_compute(Y& y) noexcept {
        impl::egblas::dropout_states(etl::size(y), probability, T(1), y.gpu_memory(), 1, *states);

        y.validate_gpu();
        y.invalidate_cpu();

        return y;
    }

    /*!
     * \brief Outputs the given generator to the given stream
     * \param os The output stream
     * \param s The generator
     * \return the output stream
     */
    friend std::ostream& operator<<(std::ostream& os, const state_dropout_mask_generator_op& s) {
        return os << "dropout(p=" << s.probability << ")";
    }
};

/*!
 * \brief Generator from an uniform distribution using a custom random engine.
 */
template <typename G, typename T = double>
struct state_dropout_mask_generator_g_op {
    using value_type = T; ///< The value type

    const T probability; ///< The dropout probability
    G& rand_engine;      ///< The random engine
    std::shared_ptr<void*> states;
    dropout_distribution<value_type> distribution; ///< The used distribution

    /*!
     * \brief Indicates if the operator can be computed on GPU
     */
    static constexpr bool gpu_computable =
        impl::egblas::has_dropout_prepare_seed && impl::egblas::has_dropout_release
        && ((is_single_precision_t<T> && impl::egblas::has_sdropout_states) || (is_double_precision_t<T> && impl::egblas::has_ddropout_states));

    /*!
     * \brief Construct a new generator with the given start and end of the range
     * \param start The beginning of the range
     * \param end The end of the range
     */
    state_dropout_mask_generator_g_op(G& g, T probability) : probability(probability), rand_engine(g), distribution(T(0), T(1)) {
        if /* constexpr*/ (impl::egblas::has_dropout_prepare) {
            states = std::make_shared<void*>();

            std::uniform_int_distribution<long> seed_dist;
            *states = impl::egblas::dropout_prepare_seed(seed_dist(rand_engine));
        }
    }

    /*!
     * \brief Generate a new value
     * \return the newly generated value
     */
    value_type operator()() {
        if (distribution(rand_engine) < probability) {
            return T(0);
        } else {
            return T(1);
        }
    }

    /*!
     * \brief Compute the result of the operation using the GPU
     *
     * \param x The expression of the unary operation
     *
     * \return The result of applying the unary operator on x. The result must be a GPU computed expression.
     */
    template <typename Y>
    auto gpu_compute_hint(Y& y) noexcept {
        decltype(auto) t1 = force_temporary_gpu_dim_only(y);

        impl::egblas::dropout_states(etl::size(y), probability, T(1), t1.gpu_memory(), 1, states);

        return t1;
    }
    /*!
     * \brief Compute the result of the operation using the GPU
     *
     * \param x The expression of the unary operation
     * \param y The expression into which to store the reuslt
     */
    template <typename Y>
    Y& gpu_compute(Y& y) noexcept {
        impl::egblas::dropout_states(etl::size(y), probability, T(1), y.gpu_memory(), 1, states);

        y.validate_gpu();
        y.invalidate_cpu();

        return y;
    }

    /*!
     * \brief Outputs the given generator to the given stream
     * \param os The output stream
     * \param s The generator
     * \return the output stream
     */
    friend std::ostream& operator<<(std::ostream& os, const state_dropout_mask_generator_g_op& s) {
        return os << "dropout(p=" << s.probability << ")";
    }
};

} //end of namespace etl
<commit_msg>Cleanup legacy code<commit_after>//=======================================================================
// Copyright (c) 2014-2020 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

/*!
 * \file
 * \brief Contains generators for state dropout mask
 */

#pragma once

#include <chrono> //for std::time

#include "etl/impl/egblas/dropout.hpp"

namespace etl {

/*!
 * \brief Generator from an uniform distribution
 */
template <typename T = double>
struct state_dropout_mask_generator_op {
    using value_type = T; ///< The value type

    const T probability; ///< The dropout probability
    std::shared_ptr<void*> states;
    random_engine rand_engine;                     ///< The random engine
    dropout_distribution<value_type> distribution; ///< The used distribution

    /*!
     * \brief Indicates if the operator can be computed on GPU
     */
    static constexpr bool gpu_computable =
        impl::egblas::has_dropout_prepare && impl::egblas::has_dropout_release
        && ((is_single_precision_t<T> && impl::egblas::has_sdropout_states) || (is_double_precision_t<T> && impl::egblas::has_ddropout_states));

    /*!
     * \brief Construct a new generator with the given start and end of the range
     */
    state_dropout_mask_generator_op(T probability) : probability(probability), rand_engine(std::time(nullptr)), distribution(T(0), T(1)) {
        if constexpr (impl::egblas::has_dropout_prepare) {
            states  = std::make_shared<void*>();
            *states = impl::egblas::dropout_prepare();
        }
    }

    /*!
     * \brief Generate a new value
     * \return the newly generated value
     */
    value_type operator()() {
        if (distribution(rand_engine) < probability) {
            return T(0);
        } else {
            return T(1);
        }
    }

    /*!
     * \brief Compute the result of the operation using the GPU
     *
     * \param x The expression of the unary operation
     *
     * \return The result of applying the unary operator on x. The result must be a GPU computed expression.
     */
    template <typename Y>
    auto gpu_compute_hint(Y& y) noexcept {
        decltype(auto) t1 = force_temporary_gpu_dim_only(y);

        impl::egblas::dropout_states(etl::size(y), probability, T(1), t1.gpu_memory(), 1, *states);

        return t1;
    }
    /*!
     * \brief Compute the result of the operation using the GPU
     *
     * \param x The expression of the unary operation
     * \param y The expression into which to store the reuslt
     */
    template <typename Y>
    Y& gpu_compute(Y& y) noexcept {
        impl::egblas::dropout_states(etl::size(y), probability, T(1), y.gpu_memory(), 1, *states);

        y.validate_gpu();
        y.invalidate_cpu();

        return y;
    }

    /*!
     * \brief Outputs the given generator to the given stream
     * \param os The output stream
     * \param s The generator
     * \return the output stream
     */
    friend std::ostream& operator<<(std::ostream& os, const state_dropout_mask_generator_op& s) {
        return os << "dropout(p=" << s.probability << ")";
    }
};

/*!
 * \brief Generator from an uniform distribution using a custom random engine.
 */
template <typename G, typename T = double>
struct state_dropout_mask_generator_g_op {
    using value_type = T; ///< The value type

    const T probability; ///< The dropout probability
    G& rand_engine;      ///< The random engine
    std::shared_ptr<void*> states;
    dropout_distribution<value_type> distribution; ///< The used distribution

    /*!
     * \brief Indicates if the operator can be computed on GPU
     */
    static constexpr bool gpu_computable =
        impl::egblas::has_dropout_prepare_seed && impl::egblas::has_dropout_release
        && ((is_single_precision_t<T> && impl::egblas::has_sdropout_states) || (is_double_precision_t<T> && impl::egblas::has_ddropout_states));

    /*!
     * \brief Construct a new generator with the given start and end of the range
     * \param start The beginning of the range
     * \param end The end of the range
     */
    state_dropout_mask_generator_g_op(G& g, T probability) : probability(probability), rand_engine(g), distribution(T(0), T(1)) {
        if constexpr (impl::egblas::has_dropout_prepare) {
            states = std::make_shared<void*>();

            std::uniform_int_distribution<long> seed_dist;
            *states = impl::egblas::dropout_prepare_seed(seed_dist(rand_engine));
        }
    }

    /*!
     * \brief Generate a new value
     * \return the newly generated value
     */
    value_type operator()() {
        if (distribution(rand_engine) < probability) {
            return T(0);
        } else {
            return T(1);
        }
    }

    /*!
     * \brief Compute the result of the operation using the GPU
     *
     * \param x The expression of the unary operation
     *
     * \return The result of applying the unary operator on x. The result must be a GPU computed expression.
     */
    template <typename Y>
    auto gpu_compute_hint(Y& y) noexcept {
        decltype(auto) t1 = force_temporary_gpu_dim_only(y);

        impl::egblas::dropout_states(etl::size(y), probability, T(1), t1.gpu_memory(), 1, states);

        return t1;
    }
    /*!
     * \brief Compute the result of the operation using the GPU
     *
     * \param x The expression of the unary operation
     * \param y The expression into which to store the reuslt
     */
    template <typename Y>
    Y& gpu_compute(Y& y) noexcept {
        impl::egblas::dropout_states(etl::size(y), probability, T(1), y.gpu_memory(), 1, states);

        y.validate_gpu();
        y.invalidate_cpu();

        return y;
    }

    /*!
     * \brief Outputs the given generator to the given stream
     * \param os The output stream
     * \param s The generator
     * \return the output stream
     */
    friend std::ostream& operator<<(std::ostream& os, const state_dropout_mask_generator_g_op& s) {
        return os << "dropout(p=" << s.probability << ")";
    }
};

} //end of namespace etl
<|endoftext|>