<commit_before>#include "Via.h"
#include "BitOps.h"
#include "MemoryMap.h"

namespace {
    enum class ShiftRegisterMode {
        // There are actually many more modes, but I think Vectrex only uses one
        ShiftOutUnder02
    };

    namespace PortB {
        const uint8_t MuxDisabled = BITS(0);
        const uint8_t MuxSelMask = BITS(1, 2);
        const uint8_t MuxSelShift = 1;
        const uint8_t RampDisabled = BITS(7);
    } // namespace PortB

    namespace AuxCntl {
        const uint8_t ShiftRegisterModeMask = BITS(2, 3, 4);
        const uint8_t ShiftRegisterModeShift = 2;
        const uint8_t Timer2PulseCounting = BITS(5); // 1=pulse counting, 0=one-shot
        const uint8_t Timer1FreeRunning = BITS(6);   // 1=free running, 0=one-shot
        const uint8_t PB7Flag = BITS(7);             // 1=enable PB7 output

        inline ShiftRegisterMode GetShiftRegisterMode(uint8_t auxCntrl) {
            uint8_t result =
                ReadBitsWithShift(auxCntrl, ShiftRegisterModeMask, ShiftRegisterModeShift);
            ASSERT_MSG(result == 0b110,
                       "ShiftRegisterMode expected to only support ShiftOutUnder02");
            return ShiftRegisterMode::ShiftOutUnder02;
        }

        inline TimerMode GetTimer1Mode(uint8_t auxCntl) {
            return TestBits(auxCntl, Timer1FreeRunning) ? TimerMode::FreeRunning
                                                        : TimerMode::OneShot;
        }

        inline TimerMode GetTimer2Mode(uint8_t auxCntl) {
            return TestBits(auxCntl, Timer2PulseCounting) ? TimerMode::PulseCounting
                                                          : TimerMode::OneShot;
        }
    } // namespace AuxCntl

    namespace PeriphCntl {
        // CA1 -> SW7, 0=IRQ on low, 1=IRQ on high
        const uint8_t CA1 = BITS(0);

        // CA2 -> /ZERO, 110=low, 111=high
        const uint8_t CA2Mask = BITS(1, 2, 3);
        const uint8_t CA2Shift = 1;

        // CB1 -> nc, 0=IRQ on low, 1=IRQ on high
        const uint8_t CB1 = BITS(4);

        // CB2 -> /BLANK, 110=low, 111=high
        const uint8_t CB2Mask = BITS(5, 6, 7);
        const uint8_t CB2Shift = 5;

        inline bool IsZeroEnabled(uint8_t periphCntrl) {
            const uint8_t value = ReadBitsWithShift(periphCntrl, CA2Mask, CA2Shift);
            return value == 0b110;
        }

        inline bool IsBlankEnabled(uint8_t periphCntrl) {
            const uint8_t value = ReadBitsWithShift(periphCntrl, CB2Mask, CB2Shift);
            return value == 0b110;
        }
    } // namespace PeriphCntl

    namespace InterruptFlag {
        const uint8_t Timer2 = BITS(5);
        const uint8_t Timer1 = BITS(6);
    }; // namespace InterruptFlag

} // namespace

void Via::Init(MemoryBus& memoryBus) {
    memoryBus.ConnectDevice(*this, MemoryMap::Via.range);
    m_portB = m_portA = 0;
    m_dataDirB = m_dataDirA = 0;
    m_shift = 0;
    m_periphCntl = 0;
    m_interruptEnable = 0;

    SetBits(m_portB, PortB::RampDisabled, true);
}

void Via::Update(cycles_t cycles) {
    // For cycle-accurate drawing, we update our timers, shift register, and beam movement 1 cycle
    // at a time
    cycles_t cyclesLeft = cycles;
    cycles = 1;
    while (cyclesLeft-- > 0) {
        m_timer1.Update(cycles);
        m_timer2.Update(cycles);
        UpdateShift(cycles);

        // If the Timer1 PB7 flag is set, then PB7 drives /RAMP
        //@TODO: This is wrong, we need to account for how many cycles PB7 was enabled
        // for before we turn off drawing.
        if (m_timer1.PB7Flag()) {
            SetBits(m_portB, PortB::RampDisabled, !m_timer1.PB7SignalLow());
        }

        if (PeriphCntl::IsZeroEnabled(m_periphCntl)) {
            //@TODO: move beam towards 0,0 over time
            m_pos = {0.f, 0.f};
        }

        // Integrators are enabled while RAMP line is active (low)
        bool integratorsEnabled = !TestBits(m_portB, PortB::RampDisabled);
        if (integratorsEnabled) {
            //@TODO: float offset = 0; // m_xyOffset;
            Vector2 delta = {0.f, 0.f};

            delta.x = ((m_velocity.x + m_xyOffset) / 128.f) * cycles;
            delta.y = ((m_velocity.y + m_xyOffset) / 128.f) * cycles;

            bool drawEnabled = !m_blank && (m_brightness > 0.f && m_brightness <= 128.f);
            if (drawEnabled) {
                m_lines.emplace_back(Line{m_pos, m_pos + delta});
            }

            m_pos += delta;
        }
    }
}

uint8_t Via::Read(uint16_t address) const {
    const uint16_t index = MemoryMap::Via.MapAddress(address);
    switch (index) {
    case 0x0:
        return m_portB;
    case 0x1:
        return m_portA;
    case 0x2:
        return m_dataDirB;
    case 0x3:
        return m_dataDirA;
    case 0x4:
        return m_timer1.ReadCounterLow();
    case 0x5:
        return m_timer1.ReadCounterHigh();
    case 0x6:
        return m_timer1.ReadLatchLow();
    case 0x7:
        return m_timer1.ReadLatchHigh();
    case 0x8:
        return m_timer2.ReadCounterLow();
    case 0x9:
        return m_timer2.ReadCounterHigh();
    case 0xA:
        return m_shift;
    case 0xB: {
        uint8_t auxCntl = 0;
        SetBits(auxCntl, 0b110 << AuxCntl::ShiftRegisterModeShift, true); //@HACK
        SetBits(auxCntl, AuxCntl::Timer1FreeRunning,
                m_timer1.TimerMode() == TimerMode::FreeRunning);
        SetBits(auxCntl, AuxCntl::Timer2PulseCounting,
                m_timer2.TimerMode() == TimerMode::PulseCounting);
        SetBits(auxCntl, AuxCntl::PB7Flag, m_timer1.PB7Flag());
        return auxCntl;
    }
    case 0xC:
        return m_periphCntl;
    case 0xD: {
        uint8_t interruptFlag = 0;
        SetBits(interruptFlag, InterruptFlag::Timer1, m_timer1.InterruptFlag());
        SetBits(interruptFlag, InterruptFlag::Timer2, m_timer2.InterruptFlag());
        return interruptFlag;
    }
    case 0xE:
        FAIL_MSG("Not implemented");
        return m_interruptEnable;
    case 0xF:
        FAIL_MSG("A without handshake not implemented yet");
        break;
    default:
        FAIL();
        break;
    }
    return 0;
}

void Via::Write(uint16_t address, uint8_t value) {

    auto UpdateIntegrators = [&] {
        const bool muxEnabled = !TestBits(m_portB, PortB::MuxDisabled);
        if (muxEnabled) {
            switch (ReadBitsWithShift(m_portB, PortB::MuxSelMask, PortB::MuxSelShift)) {
            case 0: // Y-axis integrator
                m_velocity.y = static_cast<int8_t>(m_portA);
                break;
            case 1: // X,Y Axis integrator offset
                m_xyOffset = static_cast<int8_t>(m_portA);
                break;
            case 2: // Z Axis (Vector Brightness) level
                m_brightness = m_portA;
                break;
            case 3: // Connected to sound output line via divider network
                //@TODO
                break;
            default:
                FAIL();
                break;
            }
        }
        // Always output to X-axis integrator
        m_velocity.x = static_cast<int8_t>(m_portA);
    };

    const uint16_t index = MemoryMap::Via.MapAddress(address);
    switch (index) {
    case 0x0:
        m_portB = value;
        UpdateIntegrators();
        break;
    case 0x1:
        // Port A is connected directly to the DAC, which in turn is connected to both a MUX with 4
        // outputs, and to the X-axis integrator.
        m_portA = value;
        UpdateIntegrators();
        break;
    case 0x2:
        m_dataDirB = value;
        break;
    case 0x3:
        m_dataDirA = value;
        break;
    case 0x4:
        m_timer1.WriteCounterLow(value);
        break;
    case 0x5:
        m_timer1.WriteCounterHigh(value);
        break;
    case 0x6:
        m_timer1.WriteLatchLow(value);
        break;
    case 0x7:
        m_timer1.WriteLatchHigh(value);
        break;
    case 0x8:
        m_timer2.WriteCounterLow(value);
        break;
    case 0x9:
        m_timer2.WriteCounterHigh(value);
        break;
    case 0xA:
        m_shift = value;
        m_shiftCycle = true;
        UpdateShift(2);
        break;
    case 0xB: {
        // For now just read the shift register mode, which will assert if it's invalid/unexpected
        auto shiftRegisterMode = AuxCntl::GetShiftRegisterMode(value);
        (void)shiftRegisterMode;

        ASSERT_MSG(AuxCntl::GetTimer1Mode(value) == TimerMode::OneShot,
                   "t1 assumed always on one-shot mode");
        ASSERT_MSG(AuxCntl::GetTimer2Mode(value) == TimerMode::OneShot,
                   "t2 assumed always on one-shot mode");
        m_timer1.SetTimerMode(AuxCntl::GetTimer1Mode(value));
        m_timer2.SetTimerMode(AuxCntl::GetTimer2Mode(value));

        m_timer1.SetPB7Flag(TestBits(value, AuxCntl::PB7Flag));

    } break;
    case 0xC: {
        ASSERT_MSG(ReadBitsWithShift(value, PeriphCntl::CA2Mask, PeriphCntl::CA2Shift) == 0b110 ||
                       ReadBitsWithShift(value, PeriphCntl::CA2Mask, PeriphCntl::CA2Shift) == 0b111,
                   "Unexpected value for Zero bits");

        ASSERT_MSG(ReadBitsWithShift(value, PeriphCntl::CB2Mask, PeriphCntl::CB2Shift) == 0b110 ||
                       ReadBitsWithShift(value, PeriphCntl::CB2Mask, PeriphCntl::CB2Shift) == 0b111,
                   "Top 2 bits should always be 1 (right?)");

        m_periphCntl = value;
        m_blank = PeriphCntl::IsBlankEnabled(m_periphCntl);
    } break;
    case 0xD:
        //@TODO: handle setting all other interrupt flags
        m_timer1.SetInterruptFlag(TestBits(value, InterruptFlag::Timer1));
        break;
    case 0xE:
        // FAIL_MSG("Not implemented");
        m_interruptEnable = value;
        break;
    case 0xF:
        FAIL_MSG("A without handshake not implemented yet");
        break;
    default:
        FAIL();
        break;
    }
}

void Via::UpdateShift(cycles_t cycles) {
    for (int i = 0; i < cycles; ++i) {
        m_shiftCycle = !m_shiftCycle;
        if (m_shiftCycle) {
            m_blank = !TestBits(m_shift, BITS(7));
            m_shift <<= 1;
        }
    }
}
<commit_msg>Via: respect DataDirA values (only update integrators if in "write mode")<commit_after>#include "Via.h"
#include "BitOps.h"
#include "MemoryMap.h"

namespace {
    enum class ShiftRegisterMode {
        // There are actually many more modes, but I think Vectrex only uses one
        ShiftOutUnder02
    };

    namespace PortB {
        const uint8_t MuxDisabled = BITS(0);
        const uint8_t MuxSelMask = BITS(1, 2);
        const uint8_t MuxSelShift = 1;
        const uint8_t RampDisabled = BITS(7);
    } // namespace PortB

    namespace AuxCntl {
        const uint8_t ShiftRegisterModeMask = BITS(2, 3, 4);
        const uint8_t ShiftRegisterModeShift = 2;
        const uint8_t Timer2PulseCounting = BITS(5); // 1=pulse counting, 0=one-shot
        const uint8_t Timer1FreeRunning = BITS(6);   // 1=free running, 0=one-shot
        const uint8_t PB7Flag = BITS(7);             // 1=enable PB7 output

        inline ShiftRegisterMode GetShiftRegisterMode(uint8_t auxCntrl) {
            uint8_t result =
                ReadBitsWithShift(auxCntrl, ShiftRegisterModeMask, ShiftRegisterModeShift);
            ASSERT_MSG(result == 0b110,
                       "ShiftRegisterMode expected to only support ShiftOutUnder02");
            return ShiftRegisterMode::ShiftOutUnder02;
        }

        inline TimerMode GetTimer1Mode(uint8_t auxCntl) {
            return TestBits(auxCntl, Timer1FreeRunning) ? TimerMode::FreeRunning
                                                        : TimerMode::OneShot;
        }

        inline TimerMode GetTimer2Mode(uint8_t auxCntl) {
            return TestBits(auxCntl, Timer2PulseCounting) ? TimerMode::PulseCounting
                                                          : TimerMode::OneShot;
        }
    } // namespace AuxCntl

    namespace PeriphCntl {
        // CA1 -> SW7, 0=IRQ on low, 1=IRQ on high
        const uint8_t CA1 = BITS(0);

        // CA2 -> /ZERO, 110=low, 111=high
        const uint8_t CA2Mask = BITS(1, 2, 3);
        const uint8_t CA2Shift = 1;

        // CB1 -> nc, 0=IRQ on low, 1=IRQ on high
        const uint8_t CB1 = BITS(4);

        // CB2 -> /BLANK, 110=low, 111=high
        const uint8_t CB2Mask = BITS(5, 6, 7);
        const uint8_t CB2Shift = 5;

        inline bool IsZeroEnabled(uint8_t periphCntrl) {
            const uint8_t value = ReadBitsWithShift(periphCntrl, CA2Mask, CA2Shift);
            return value == 0b110;
        }

        inline bool IsBlankEnabled(uint8_t periphCntrl) {
            const uint8_t value = ReadBitsWithShift(periphCntrl, CB2Mask, CB2Shift);
            return value == 0b110;
        }
    } // namespace PeriphCntl

    namespace InterruptFlag {
        const uint8_t Timer2 = BITS(5);
        const uint8_t Timer1 = BITS(6);
    }; // namespace InterruptFlag

} // namespace

void Via::Init(MemoryBus& memoryBus) {
    memoryBus.ConnectDevice(*this, MemoryMap::Via.range);
    m_portB = m_portA = 0;
    m_dataDirB = m_dataDirA = 0;
    m_shift = 0;
    m_periphCntl = 0;
    m_interruptEnable = 0;

    SetBits(m_portB, PortB::RampDisabled, true);
}

void Via::Update(cycles_t cycles) {
    // For cycle-accurate drawing, we update our timers, shift register, and beam movement 1 cycle
    // at a time
    cycles_t cyclesLeft = cycles;
    cycles = 1;
    while (cyclesLeft-- > 0) {
        m_timer1.Update(cycles);
        m_timer2.Update(cycles);
        UpdateShift(cycles);

        // If the Timer1 PB7 flag is set, then PB7 drives /RAMP
        //@TODO: This is wrong, we need to account for how many cycles PB7 was enabled
        // for before we turn off drawing.
        if (m_timer1.PB7Flag()) {
            SetBits(m_portB, PortB::RampDisabled, !m_timer1.PB7SignalLow());
        }

        if (PeriphCntl::IsZeroEnabled(m_periphCntl)) {
            //@TODO: move beam towards 0,0 over time
            m_pos = {0.f, 0.f};
        }

        // Integrators are enabled while RAMP line is active (low)
        bool integratorsEnabled = !TestBits(m_portB, PortB::RampDisabled);
        if (integratorsEnabled) {
            //@TODO: float offset = 0; // m_xyOffset;
            Vector2 delta = {0.f, 0.f};

            delta.x = ((m_velocity.x + m_xyOffset) / 128.f) * cycles;
            delta.y = ((m_velocity.y + m_xyOffset) / 128.f) * cycles;

            bool drawEnabled = !m_blank && (m_brightness > 0.f && m_brightness <= 128.f);
            if (drawEnabled) {
                m_lines.emplace_back(Line{m_pos, m_pos + delta});
            }

            m_pos += delta;
        }
    }
}

uint8_t Via::Read(uint16_t address) const {
    const uint16_t index = MemoryMap::Via.MapAddress(address);
    switch (index) {
    case 0x0:
        return m_portB;
    case 0x1:
        return m_portA;
    case 0x2:
        return m_dataDirB;
    case 0x3:
        return m_dataDirA;
    case 0x4:
        return m_timer1.ReadCounterLow();
    case 0x5:
        return m_timer1.ReadCounterHigh();
    case 0x6:
        return m_timer1.ReadLatchLow();
    case 0x7:
        return m_timer1.ReadLatchHigh();
    case 0x8:
        return m_timer2.ReadCounterLow();
    case 0x9:
        return m_timer2.ReadCounterHigh();
    case 0xA:
        return m_shift;
    case 0xB: {
        uint8_t auxCntl = 0;
        SetBits(auxCntl, 0b110 << AuxCntl::ShiftRegisterModeShift, true); //@HACK
        SetBits(auxCntl, AuxCntl::Timer1FreeRunning,
                m_timer1.TimerMode() == TimerMode::FreeRunning);
        SetBits(auxCntl, AuxCntl::Timer2PulseCounting,
                m_timer2.TimerMode() == TimerMode::PulseCounting);
        SetBits(auxCntl, AuxCntl::PB7Flag, m_timer1.PB7Flag());
        return auxCntl;
    }
    case 0xC:
        return m_periphCntl;
    case 0xD: {
        uint8_t interruptFlag = 0;
        SetBits(interruptFlag, InterruptFlag::Timer1, m_timer1.InterruptFlag());
        SetBits(interruptFlag, InterruptFlag::Timer2, m_timer2.InterruptFlag());
        return interruptFlag;
    }
    case 0xE:
        FAIL_MSG("Not implemented");
        return m_interruptEnable;
    case 0xF:
        FAIL_MSG("A without handshake not implemented yet");
        break;
    default:
        FAIL();
        break;
    }
    return 0;
}

void Via::Write(uint16_t address, uint8_t value) {

    auto UpdateIntegrators = [&] {
        const bool muxEnabled = !TestBits(m_portB, PortB::MuxDisabled);
        if (muxEnabled) {
            switch (ReadBitsWithShift(m_portB, PortB::MuxSelMask, PortB::MuxSelShift)) {
            case 0: // Y-axis integrator
                m_velocity.y = static_cast<int8_t>(m_portA);
                break;
            case 1: // X,Y Axis integrator offset
                m_xyOffset = static_cast<int8_t>(m_portA);
                break;
            case 2: // Z Axis (Vector Brightness) level
                m_brightness = m_portA;
                break;
            case 3: // Connected to sound output line via divider network
                //@TODO
                break;
            default:
                FAIL();
                break;
            }
        }
        // Always output to X-axis integrator
        m_velocity.x = static_cast<int8_t>(m_portA);
    };

    const uint16_t index = MemoryMap::Via.MapAddress(address);
    switch (index) {
    case 0x0:
        m_portB = value;
        UpdateIntegrators();
        break;
    case 0x1:
        // Port A is connected directly to the DAC, which in turn is connected to both a MUX with 4
        // outputs, and to the X-axis integrator.
        m_portA = value;
        if (m_dataDirA == 0xFF) {
            UpdateIntegrators();
        }
        break;
    case 0x2:
        m_dataDirB = value;
        break;
    case 0x3:
        m_dataDirA = value;
        ASSERT_MSG(m_dataDirA == 0 || m_dataDirA == 0xFF,
                   "Expecting DDR for A to be either all 0s or all 1s");
        break;
    case 0x4:
        m_timer1.WriteCounterLow(value);
        break;
    case 0x5:
        m_timer1.WriteCounterHigh(value);
        break;
    case 0x6:
        m_timer1.WriteLatchLow(value);
        break;
    case 0x7:
        m_timer1.WriteLatchHigh(value);
        break;
    case 0x8:
        m_timer2.WriteCounterLow(value);
        break;
    case 0x9:
        m_timer2.WriteCounterHigh(value);
        break;
    case 0xA:
        m_shift = value;
        m_shiftCycle = true;
        UpdateShift(2);
        break;
    case 0xB: {
        // For now just read the shift register mode, which will assert if it's invalid/unexpected
        auto shiftRegisterMode = AuxCntl::GetShiftRegisterMode(value);
        (void)shiftRegisterMode;

        ASSERT_MSG(AuxCntl::GetTimer1Mode(value) == TimerMode::OneShot,
                   "t1 assumed always on one-shot mode");
        ASSERT_MSG(AuxCntl::GetTimer2Mode(value) == TimerMode::OneShot,
                   "t2 assumed always on one-shot mode");
        m_timer1.SetTimerMode(AuxCntl::GetTimer1Mode(value));
        m_timer2.SetTimerMode(AuxCntl::GetTimer2Mode(value));

        m_timer1.SetPB7Flag(TestBits(value, AuxCntl::PB7Flag));

    } break;
    case 0xC: {
        ASSERT_MSG(ReadBitsWithShift(value, PeriphCntl::CA2Mask, PeriphCntl::CA2Shift) == 0b110 ||
                       ReadBitsWithShift(value, PeriphCntl::CA2Mask, PeriphCntl::CA2Shift) == 0b111,
                   "Unexpected value for Zero bits");

        ASSERT_MSG(ReadBitsWithShift(value, PeriphCntl::CB2Mask, PeriphCntl::CB2Shift) == 0b110 ||
                       ReadBitsWithShift(value, PeriphCntl::CB2Mask, PeriphCntl::CB2Shift) == 0b111,
                   "Top 2 bits should always be 1 (right?)");

        m_periphCntl = value;
        m_blank = PeriphCntl::IsBlankEnabled(m_periphCntl);
    } break;
    case 0xD:
        //@TODO: handle setting all other interrupt flags
        m_timer1.SetInterruptFlag(TestBits(value, InterruptFlag::Timer1));
        break;
    case 0xE:
        // FAIL_MSG("Not implemented");
        m_interruptEnable = value;
        break;
    case 0xF:
        FAIL_MSG("A without handshake not implemented yet");
        break;
    default:
        FAIL();
        break;
    }
}

void Via::UpdateShift(cycles_t cycles) {
    for (int i = 0; i < cycles; ++i) {
        m_shiftCycle = !m_shiftCycle;
        if (m_shiftCycle) {
            m_blank = !TestBits(m_shift, BITS(7));
            m_shift <<= 1;
        }
    }
}
<|endoftext|>


<commit_before>/* This is free and unencumbered software released into the public domain. */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "error.h"
#include "sysv_segment.h"

#include <cassert>      /* for assert() */
#include <cerrno>       /* for errno */
#include <sys/types.h>  /* for key_t */
#include <sys/ipc.h>    /* for shm*() on BSD */
#include <sys/shm.h>    /* for struct shmid_ds, shm*() */

using namespace posix;

void
sysv_segment::for_each(std::function<void (sysv_segment segment)> callback) {
#ifdef __linux__
  struct shm_info shminfo;
  const int max_shmidx = shmctl(0, SHM_INFO, reinterpret_cast<struct shmid_ds*>(&shminfo));
  if (max_shmidx == -1) {
    throw posix::runtime_error(errno);
  }

  for (int shmidx = 0; shmidx <= max_shmidx; shmidx++) {
    shmid_ds ds;
    const int shmid = shmctl(shmidx, SHM_STAT, &ds);
    if (shmid == -1) {
      switch (errno) {
        case EINVAL: /* Invalid argument */
        case EACCES: /* Permission denied */
          continue;
        default:
          assert(errno != EFAULT);
          throw posix::runtime_error(errno);
      }
    }
    callback(sysv_segment(shmid));
  }
#else
  throw posix::runtime_error(ENOSYS); /* Function not implemented */
#endif /* __linux__ */
}

/**
 * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/shmget.html
 * @see http://man7.org/linux/man-pages/man2/shmget.2.html
 * @see http://www.freebsd.org/cgi/man.cgi?query=shmget&sektion=2
 * @see http://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man2/shmget.2.html
 */
sysv_segment
sysv_segment::create(const key_t key,
                     const std::size_t size,
                     const int flags) {
  int shmid;
  if ((shmid = shmget(key, size, IPC_CREAT | flags)) == -1) {
    switch (errno) {
      case EINVAL: /* Invalid argument */
        throw posix::invalid_argument();
      case ENOMEM: /* Cannot allocate memory in kernel */
      case ENOSPC: /* No space left on device */
        throw posix::fatal_error(errno);
      default:
        throw posix::runtime_error(errno);
    }
  }
  return sysv_segment(shmid);
}

/**
 * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/shmget.html
 * @see http://man7.org/linux/man-pages/man2/shmget.2.html
 * @see http://www.freebsd.org/cgi/man.cgi?query=shmget&sektion=2
 * @see http://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man2/shmget.2.html
 */
sysv_segment
sysv_segment::open(const key_t key) {
  int shmid;
  if ((shmid = shmget(key, 0, 0)) == -1) {
    switch (errno) {
      case EINVAL: /* Invalid argument */
        throw posix::invalid_argument();
      case ENOMEM: /* Cannot allocate memory in kernel */
        throw posix::fatal_error(errno);
      default:
        assert(errno != ENOSPC);
        throw posix::runtime_error(errno);
    }
  }
  return sysv_segment(shmid);
}

sysv_segment::~sysv_segment() noexcept {
  if (_addr) {
    if (shmdt(_addr) == -1) {
      /* Ignore any errors from shmdt(). */
    }
    _addr = nullptr;
  }
  if (_id != -1) {
#if 0 // TODO: think this through.
    if (shmctl(_id, IPC_RMID, nullptr) == -1) {
      /* Ignore any errors from shmctl(). */
    }
#endif
    _id = -1;
  }
}

shmid_ds
sysv_segment::stat() const {
  shmid_ds ds;
  if (shmctl(_id, IPC_STAT, &ds) == -1) {
    switch (errno) {
      case EINVAL: /* Invalid argument */
        throw posix::invalid_argument();
      default:
        assert(errno != EFAULT);
        throw posix::runtime_error(errno);
    }
  }
  return ds;
}

/**
 * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/shmat.html
 * @see http://man7.org/linux/man-pages/man2/shmat.2.html
 * @see http://www.freebsd.org/cgi/man.cgi?query=shmat&sektion=2
 * @see http://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man2/shmat.2.html
 */
void*
sysv_segment::attach(const int flags) {
  if (!_addr) {
    if ((_addr = shmat(_id, nullptr, flags)) == reinterpret_cast<void*>(-1)) {
      switch (errno) {
        case EINVAL: /* Invalid argument */
          throw posix::invalid_argument();
        case EMFILE: /* Too many open segments */
        case ENOMEM: /* Cannot allocate memory in kernel */
          throw posix::fatal_error(errno);
        default:
          throw posix::runtime_error(errno);
      }
    }
    assert(_addr != nullptr);
  }
  return _addr;
}

/**
 * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/shmdt.html
 * @see http://man7.org/linux/man-pages/man2/shmdt.2.html
 * @see http://www.freebsd.org/cgi/man.cgi?query=shmdt&sektion=2
 * @see http://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man2/shmdt.2.html
 */
void
sysv_segment::detach() {
  if (_addr) {
    if (shmdt(_addr) == -1) {
      switch (errno) {
        case EINVAL: /* Invalid argument */
          throw posix::invalid_argument();
        default:
          throw posix::runtime_error(errno);
      }
    }
    _addr = nullptr;
  }
}

/**
 * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/shmctl.html
 * @see http://man7.org/linux/man-pages/man2/shmctl.2.html
 * @see http://www.freebsd.org/cgi/man.cgi?query=shmctl&sektion=2
 * @see http://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man2/shmctl.2.html
 */
void
sysv_segment::remove() {
  if (_id != -1) {
    if (shmctl(_id, IPC_RMID, nullptr) == -1) {
      switch (errno) {
        case EINVAL: /* Invalid argument */
          throw posix::invalid_argument();
        default:
          assert(errno != EFAULT);
          throw posix::runtime_error(errno);
      }
    }
    _id = -1;
  }
}

void
sysv_segment::lock() {
#ifdef SHM_LOCK
  if (shmctl(_id, SHM_LOCK, nullptr) == -1) {
    switch (errno) {
      case EINVAL: /* Invalid argument */
        throw posix::invalid_argument();
      case ENOMEM: /* Cannot allocate memory in kernel */
        throw posix::fatal_error(errno);
      default:
        assert(errno != EFAULT);
        throw posix::runtime_error(errno);
    }
  }
#else
  throw posix::runtime_error(ENOSYS); /* Not implemented */
#endif
}

void
sysv_segment::unlock() {
#ifdef SHM_UNLOCK
  if (shmctl(_id, SHM_UNLOCK, nullptr) == -1) {
    switch (errno) {
      case EINVAL: /* Invalid argument */
        throw posix::invalid_argument();
      default:
        assert(errno != ENOMEM);
        assert(errno != EFAULT);
        throw posix::runtime_error(errno);
    }
  }
#else
  throw posix::runtime_error(ENOSYS); /* Not implemented */
#endif
}
<commit_msg>Retrofitted posix::sysv_segment to utilize posix::throw_error().<commit_after>/* This is free and unencumbered software released into the public domain. */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "error.h"
#include "sysv_segment.h"

#include <cassert>      /* for assert() */
#include <cerrno>       /* for errno */
#include <sys/types.h>  /* for key_t */
#include <sys/ipc.h>    /* for shm*() on BSD */
#include <sys/shm.h>    /* for struct shmid_ds, shm*() */

using namespace posix;

void
sysv_segment::for_each(std::function<void (sysv_segment segment)> callback) {
#ifdef __linux__
  struct shm_info shminfo;
  const int max_shmidx = shmctl(0, SHM_INFO, reinterpret_cast<struct shmid_ds*>(&shminfo));
  if (max_shmidx == -1) {
    throw_error(errno);
  }

  for (int shmidx = 0; shmidx <= max_shmidx; shmidx++) {
    shmid_ds ds;
    const int shmid = shmctl(shmidx, SHM_STAT, &ds);
    if (shmid == -1) {
      switch (errno) {
        case EINVAL: /* Invalid argument */
        case EACCES: /* Permission denied */
          continue;
        default:
          assert(errno != EFAULT);
          throw posix::runtime_error(errno);
      }
    }
    callback(sysv_segment(shmid));
  }
#else
  throw_error(ENOSYS); /* Function not implemented */
#endif /* __linux__ */
}

/**
 * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/shmget.html
 * @see http://man7.org/linux/man-pages/man2/shmget.2.html
 * @see http://www.freebsd.org/cgi/man.cgi?query=shmget&sektion=2
 * @see http://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man2/shmget.2.html
 */
sysv_segment
sysv_segment::create(const key_t key,
                     const std::size_t size,
                     const int flags) {
  int shmid;
  if ((shmid = shmget(key, size, IPC_CREAT | flags)) == -1) {
    switch (errno) {
      case EINVAL: /* Invalid argument */
        throw posix::invalid_argument();
      case ENOMEM: /* Cannot allocate memory in kernel */
      case ENOSPC: /* No space left on device */
        throw posix::fatal_error(errno);
      default:
        throw_error(errno);
    }
  }
  return sysv_segment(shmid);
}

/**
 * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/shmget.html
 * @see http://man7.org/linux/man-pages/man2/shmget.2.html
 * @see http://www.freebsd.org/cgi/man.cgi?query=shmget&sektion=2
 * @see http://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man2/shmget.2.html
 */
sysv_segment
sysv_segment::open(const key_t key) {
  int shmid;
  if ((shmid = shmget(key, 0, 0)) == -1) {
    switch (errno) {
      case EINVAL: /* Invalid argument */
        throw posix::invalid_argument();
      case ENOMEM: /* Cannot allocate memory in kernel */
        throw posix::fatal_error(errno);
      default:
        assert(errno != ENOSPC);
        throw_error(errno);
    }
  }
  return sysv_segment(shmid);
}

sysv_segment::~sysv_segment() noexcept {
  if (_addr) {
    if (shmdt(_addr) == -1) {
      /* Ignore any errors from shmdt(). */
    }
    _addr = nullptr;
  }
  if (_id != -1) {
#if 0 // TODO: think this through.
    if (shmctl(_id, IPC_RMID, nullptr) == -1) {
      /* Ignore any errors from shmctl(). */
    }
#endif
    _id = -1;
  }
}

shmid_ds
sysv_segment::stat() const {
  shmid_ds ds;
  if (shmctl(_id, IPC_STAT, &ds) == -1) {
    switch (errno) {
      case EINVAL: /* Invalid argument */
        throw posix::invalid_argument();
      default:
        assert(errno != EFAULT);
        throw_error(errno);
    }
  }
  return ds;
}

/**
 * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/shmat.html
 * @see http://man7.org/linux/man-pages/man2/shmat.2.html
 * @see http://www.freebsd.org/cgi/man.cgi?query=shmat&sektion=2
 * @see http://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man2/shmat.2.html
 */
void*
sysv_segment::attach(const int flags) {
  if (!_addr) {
    if ((_addr = shmat(_id, nullptr, flags)) == reinterpret_cast<void*>(-1)) {
      switch (errno) {
        case EINVAL: /* Invalid argument */
          throw posix::invalid_argument();
        case EMFILE: /* Too many open segments */
        case ENOMEM: /* Cannot allocate memory in kernel */
          throw posix::fatal_error(errno);
        default:
          throw_error(errno);
      }
    }
    assert(_addr != nullptr);
  }
  return _addr;
}

/**
 * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/shmdt.html
 * @see http://man7.org/linux/man-pages/man2/shmdt.2.html
 * @see http://www.freebsd.org/cgi/man.cgi?query=shmdt&sektion=2
 * @see http://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man2/shmdt.2.html
 */
void
sysv_segment::detach() {
  if (_addr) {
    if (shmdt(_addr) == -1) {
      switch (errno) {
        case EINVAL: /* Invalid argument */
          throw posix::invalid_argument();
        default:
          throw_error(errno);
      }
    }
    _addr = nullptr;
  }
}

/**
 * @see http://pubs.opengroup.org/onlinepubs/9699919799/functions/shmctl.html
 * @see http://man7.org/linux/man-pages/man2/shmctl.2.html
 * @see http://www.freebsd.org/cgi/man.cgi?query=shmctl&sektion=2
 * @see http://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man2/shmctl.2.html
 */
void
sysv_segment::remove() {
  if (_id != -1) {
    if (shmctl(_id, IPC_RMID, nullptr) == -1) {
      switch (errno) {
        case EINVAL: /* Invalid argument */
          throw posix::invalid_argument();
        default:
          assert(errno != EFAULT);
          throw_error(errno);
      }
    }
    _id = -1;
  }
}

void
sysv_segment::lock() {
#ifdef SHM_LOCK
  if (shmctl(_id, SHM_LOCK, nullptr) == -1) {
    switch (errno) {
      case EINVAL: /* Invalid argument */
        throw posix::invalid_argument();
      case ENOMEM: /* Cannot allocate memory in kernel */
        throw posix::fatal_error(errno);
      default:
        assert(errno != EFAULT);
        throw_error(errno);
    }
  }
#else
  throw_error(ENOSYS); /* Function not implemented */
#endif
}

void
sysv_segment::unlock() {
#ifdef SHM_UNLOCK
  if (shmctl(_id, SHM_UNLOCK, nullptr) == -1) {
    switch (errno) {
      case EINVAL: /* Invalid argument */
        throw posix::invalid_argument();
      default:
        assert(errno != ENOMEM);
        assert(errno != EFAULT);
        throw_error(errno);
    }
  }
#else
  throw_error(ENOSYS); /* Function not implemented */
#endif
}
<|endoftext|>


<commit_before>#include "meshoptimizer.hpp"

#include <cassert>
#include <cmath>
#include <vector>

namespace
{
	const size_t max_cache_size = 32;

	const float valence_boost_scale = 2.0f;
	const float last_triangle_score = 0.75f;

	// The table is for max_cache_size = 32, cache_decay_power = 1.5,
	// Equation is ((position - 3) / (max_cache_size - 3)) ^ cache_decay_power
	static const float cache_scores[max_cache_size] =
	{
		last_triangle_score, last_triangle_score, last_triangle_score,
		// perl -e "for ($i = 32; $i > 3; --$i) {print sqrt(($i - 3) / 29)*(($i-3)/29);print 'f, ';}"
		1, 0.948724356160999f, 0.898356365398566f, 0.84891268884993f, 0.800410940418327f,
		0.752869781209394f, 0.706309027617917f, 0.660749775712085f, 0.616214545218346f,
		0.572727447267172f, 0.530314381193352f, 0.489003267201725f, 0.448824323769283f,
		0.409810401494183f, 0.371997389083488f, 0.335424712859142f, 0.300135959460546f,
		0.266179663821797f, 0.233610323536753f, 0.202489730867139f, 0.172888763130359f,
		0.144889856948659f, 0.118590544520125f, 0.0941087226511742f, 0.0715909309083965f,
		0.0512263001867729f, 0.0332724579777247f, 0.0181112321185824f, 0.00640328752334662f,
	};

	template <typename T>
	struct face_t
	{
		T a, b, c;
	};

	struct Vertex
	{
		Vertex(): cache_position(-1), score(0), triangles_total(0), triangles_not_added(0), triangles(0)
		{
		}

		int cache_position;
		float score;
		unsigned int triangles_total;
		unsigned int triangles_not_added;
		unsigned int* triangles;
	};

	static float vertexScore(const Vertex& vertex)
	{
		// check if there are any triangles needed
		if (vertex.triangles_not_added == 0) return -1;

		float score = vertex.cache_position == -1 ? 0 : cache_scores[vertex.cache_position];

		// Bonus points for having a low number of tris still to use the vert, so we get rid of lone verts quickly.
		// return score + valence_boost_scale * powf(vertex.triangles_not_added, -valence_boost_power);
		// for valence_boost_power = 0.5f
		return score + valence_boost_scale / sqrtf((float)vertex.triangles_not_added);
	}

	template <typename T> static void optimizeLinear(T* destination, const T* indices, size_t index_count, size_t vertex_count, unsigned int cache_size)
	{
		assert(destination != indices);
		assert(cache_size <= max_cache_size);

		const float m_inf = -1e32f;

		const face_t<T>* faces = reinterpret_cast<const face_t<T>*>(indices);

		assert(index_count % 3 == 0);
		size_t face_count = index_count / 3;

		std::vector<Vertex> vertices(vertex_count);

		// initializing vertex data
		for (size_t i = 0; i < face_count; ++i)
		{
			const face_t<T>& f = faces[i];

			vertices[f.a].triangles_total++;
			vertices[f.b].triangles_total++;
			vertices[f.c].triangles_total++;
		}

		// calculate total triangle number
		std::vector<unsigned int> triangle_indices(index_count); // total triangle indices count == index count
		unsigned int* triangle_indices_ptr = &triangle_indices[0];

		// allocate storage for triangle indices
		for (size_t i = 0; i < vertex_count; ++i)
		{
			Vertex& v = vertices[i];

			v.triangles = triangle_indices_ptr;
			triangle_indices_ptr += v.triangles_total;
		}

		// fill triangle indices
		for (size_t i = 0; i < face_count; ++i)
		{
			const face_t<T>& f = faces[i];

			Vertex& a = vertices[f.a];
			a.triangles[a.triangles_not_added++] = static_cast<unsigned int>(i);

			Vertex& b = vertices[f.b];
			b.triangles[b.triangles_not_added++] = static_cast<unsigned int>(i);

			Vertex& c = vertices[f.c];
			c.triangles[c.triangles_not_added++] = static_cast<unsigned int>(i);
		}

		// compute initial vertex scores
		for (size_t i = 0; i < vertex_count; ++i)
		{
			Vertex& v = vertices[i];

			v.score = vertexScore(v);
		}

		// compute triangle scores
		std::vector<float> triangle_scores(face_count);

		for (size_t i = 0; i < face_count; ++i)
		{
			const face_t<T>& t = faces[i];

			triangle_scores[i] = vertices[t.a].score + vertices[t.b].score + vertices[t.c].score;
		}

		T* destination_end = destination + index_count;

		unsigned int cache_holder[2 * (max_cache_size + 3)];
		unsigned int* cache = cache_holder;
		unsigned int* cache_end = cache;
		unsigned int* cache_new = cache + max_cache_size + 3;
		unsigned int* cache_new_end = cache_new;

		int min_tri = -1;

		// main body
		while (destination != destination_end)
		{
			// find triangle with the best score if it was not found on previous step
			if (min_tri < 0)
			{
				float min_score = m_inf;

				for (size_t i = 0; i < face_count; ++i)
				{
					float tri_score = triangle_scores[i];

					if (min_score < tri_score)
					{
						min_tri = int(i);
						min_score = tri_score;
					}
				}
			}

			unsigned int tri_a = faces[min_tri].a;
			unsigned int tri_b = faces[min_tri].b;
			unsigned int tri_c = faces[min_tri].c;

			// add it to drawing sequence
			*destination++ = tri_a;
			*destination++ = tri_b;
			*destination++ = tri_c;

			triangle_scores[min_tri] = m_inf;

			// construct new cache
			cache_new_end = cache_new;

			// new triangle
			*cache_new_end++ = tri_a;
			*cache_new_end++ = tri_b;
			*cache_new_end++ = tri_c;

			// old parts
			int cp_a = vertices[tri_a].cache_position;
			int cp_b = vertices[tri_b].cache_position;
			int cp_c = vertices[tri_c].cache_position;

			// order indices
			if (cp_a > cp_b) std::swap(cp_a, cp_b);
			if (cp_a > cp_c) std::swap(cp_a, cp_c);
			if (cp_b > cp_c) std::swap(cp_b, cp_c);

			if (cp_c == -1) // largest is -1 => all 3 are -1
			{
				cache_new_end = std::copy(cache, cache_end, cache_new_end);
			}
			else if (cp_b == -1) // cp_a == -1, cp_b == -1
			{
				cache_new_end = std::copy(cache, cache + cp_c, cache_new_end);
				cache_new_end = std::copy(cache + cp_c + 1, cache_end, cache_new_end);
			}
			else if (cp_a == -1) // only cp_a == -1
			{
				cache_new_end = std::copy(cache, cache + cp_b, cache_new_end);
				cache_new_end = std::copy(cache + cp_b + 1, cache + cp_c, cache_new_end);
				cache_new_end = std::copy(cache + cp_c + 1, cache_end, cache_new_end);
			}
			else
			{
				cache_new_end = std::copy(cache, cache + cp_a, cache_new_end);
				cache_new_end = std::copy(cache + cp_a + 1, cache + cp_b, cache_new_end);
				cache_new_end = std::copy(cache + cp_b + 1, cache + cp_c, cache_new_end);
				cache_new_end = std::copy(cache + cp_c + 1, cache_end, cache_new_end);
			}

			size_t cache_new_size = cache_new_end - cache_new;

			if (cache_new_size > cache_size) cache_new_end = cache_new + cache_size;

			std::swap(cache, cache_new);
			std::swap(cache_end, cache_new_end);

			// modify vertices
			vertices[tri_a].triangles_not_added--;
			vertices[tri_b].triangles_not_added--;
			vertices[tri_c].triangles_not_added--;

			min_tri = -1;
			float min_score = m_inf;

			// update cache positions, vertices scores and triangle scores, and find new min_face
			for (size_t i = 0; i < cache_new_size; ++i)
			{
				Vertex& v = vertices[cache[i]];

				v.cache_position = i >= cache_size ? -1 : (int)i;

				float score = vertexScore(v);
				float score_diff = score - v.score;

				// update scores of vertex triangles
				for (size_t j = 0; j < v.triangles_total; ++j)
				{
					unsigned int tri = v.triangles[j];

					triangle_scores[tri] += score_diff;

					float tri_score = triangle_scores[tri];

					if (min_score < tri_score)
					{
						min_tri = tri;
						min_score = tri_score;
					}
				}

				v.score = score;
			}
		}
	}
}

void optimizePostTransformTomF(unsigned short* destination, const unsigned short* indices, size_t index_count, size_t vertex_count, unsigned int cache_size)
{
	optimizeLinear(destination, indices, index_count, vertex_count, cache_size);
}

void optimizePostTransformTomF(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, unsigned int cache_size)
{
	optimizeLinear(destination, indices, index_count, vertex_count, cache_size);
}
<commit_msg>TomF: Remove face_t type<commit_after>#include "meshoptimizer.hpp"

#include <cassert>
#include <cmath>
#include <vector>

namespace
{
	const size_t max_cache_size = 32;

	const float valence_boost_scale = 2.0f;
	const float last_triangle_score = 0.75f;

	// The table is for max_cache_size = 32, cache_decay_power = 1.5,
	// Equation is ((position - 3) / (max_cache_size - 3)) ^ cache_decay_power
	static const float cache_scores[max_cache_size] =
	{
		last_triangle_score, last_triangle_score, last_triangle_score,
		// perl -e "for ($i = 32; $i > 3; --$i) {print sqrt(($i - 3) / 29)*(($i-3)/29);print 'f, ';}"
		1, 0.948724356160999f, 0.898356365398566f, 0.84891268884993f, 0.800410940418327f,
		0.752869781209394f, 0.706309027617917f, 0.660749775712085f, 0.616214545218346f,
		0.572727447267172f, 0.530314381193352f, 0.489003267201725f, 0.448824323769283f,
		0.409810401494183f, 0.371997389083488f, 0.335424712859142f, 0.300135959460546f,
		0.266179663821797f, 0.233610323536753f, 0.202489730867139f, 0.172888763130359f,
		0.144889856948659f, 0.118590544520125f, 0.0941087226511742f, 0.0715909309083965f,
		0.0512263001867729f, 0.0332724579777247f, 0.0181112321185824f, 0.00640328752334662f,
	};

	struct Vertex
	{
		Vertex(): cache_position(-1), score(0), triangles_total(0), triangles_not_added(0), triangles(0)
		{
		}

		int cache_position;
		float score;
		unsigned int triangles_total;
		unsigned int triangles_not_added;
		unsigned int* triangles;
	};

	static float vertexScore(const Vertex& vertex)
	{
		// check if there are any triangles needed
		if (vertex.triangles_not_added == 0) return -1;

		float score = vertex.cache_position == -1 ? 0 : cache_scores[vertex.cache_position];

		// Bonus points for having a low number of tris still to use the vert, so we get rid of lone verts quickly.
		// return score + valence_boost_scale * powf(vertex.triangles_not_added, -valence_boost_power);
		// for valence_boost_power = 0.5f
		return score + valence_boost_scale / sqrtf((float)vertex.triangles_not_added);
	}

	template <typename T> static void optimizeLinear(T* destination, const T* indices, size_t index_count, size_t vertex_count, unsigned int cache_size)
	{
		assert(destination != indices);
		assert(cache_size <= max_cache_size);

		const float m_inf = -1e32f;

		assert(index_count % 3 == 0);
		size_t face_count = index_count / 3;

		std::vector<Vertex> vertices(vertex_count);

		// initializing vertex data
		for (size_t i = 0; i < index_count; ++i)
		{
			vertices[indices[i]].triangles_total++;
		}

		// calculate total triangle number
		std::vector<unsigned int> triangle_indices(index_count); // total triangle indices count == index count
		unsigned int* triangle_indices_ptr = &triangle_indices[0];

		// allocate storage for triangle indices
		for (size_t i = 0; i < vertex_count; ++i)
		{
			Vertex& v = vertices[i];

			v.triangles = triangle_indices_ptr;
			triangle_indices_ptr += v.triangles_total;
		}

		// fill triangle indices
		for (size_t i = 0; i < face_count; ++i)
		{
			Vertex& a = vertices[indices[i * 3 + 0]];
			a.triangles[a.triangles_not_added++] = static_cast<unsigned int>(i);

			Vertex& b = vertices[indices[i * 3 + 1]];
			b.triangles[b.triangles_not_added++] = static_cast<unsigned int>(i);

			Vertex& c = vertices[indices[i * 3 + 2]];
			c.triangles[c.triangles_not_added++] = static_cast<unsigned int>(i);
		}

		// compute initial vertex scores
		for (size_t i = 0; i < vertex_count; ++i)
		{
			Vertex& v = vertices[i];

			v.score = vertexScore(v);
		}

		// compute triangle scores
		std::vector<float> triangle_scores(face_count);

		for (size_t i = 0; i < face_count; ++i)
		{
			unsigned int tri_a = indices[i * 3 + 0];
			unsigned int tri_b = indices[i * 3 + 1];
			unsigned int tri_c = indices[i * 3 + 2];

			triangle_scores[i] = vertices[tri_a].score + vertices[tri_b].score + vertices[tri_c].score;
		}

		T* destination_end = destination + index_count;

		unsigned int cache_holder[2 * (max_cache_size + 3)];
		unsigned int* cache = cache_holder;
		unsigned int* cache_end = cache;
		unsigned int* cache_new = cache + max_cache_size + 3;
		unsigned int* cache_new_end = cache_new;

		int min_tri = -1;

		// main body
		while (destination != destination_end)
		{
			// find triangle with the best score if it was not found on previous step
			if (min_tri < 0)
			{
				float min_score = m_inf;

				for (size_t i = 0; i < face_count; ++i)
				{
					float tri_score = triangle_scores[i];

					if (min_score < tri_score)
					{
						min_tri = int(i);
						min_score = tri_score;
					}
				}
			}

			unsigned int tri_a = indices[min_tri * 3 + 0];
			unsigned int tri_b = indices[min_tri * 3 + 1];
			unsigned int tri_c = indices[min_tri * 3 + 2];

			// add it to drawing sequence
			*destination++ = tri_a;
			*destination++ = tri_b;
			*destination++ = tri_c;

			triangle_scores[min_tri] = m_inf;

			// construct new cache
			cache_new_end = cache_new;

			// new triangle
			*cache_new_end++ = tri_a;
			*cache_new_end++ = tri_b;
			*cache_new_end++ = tri_c;

			// old parts
			int cp_a = vertices[tri_a].cache_position;
			int cp_b = vertices[tri_b].cache_position;
			int cp_c = vertices[tri_c].cache_position;

			// order indices
			if (cp_a > cp_b) std::swap(cp_a, cp_b);
			if (cp_a > cp_c) std::swap(cp_a, cp_c);
			if (cp_b > cp_c) std::swap(cp_b, cp_c);

			if (cp_c == -1) // largest is -1 => all 3 are -1
			{
				cache_new_end = std::copy(cache, cache_end, cache_new_end);
			}
			else if (cp_b == -1) // cp_a == -1, cp_b == -1
			{
				cache_new_end = std::copy(cache, cache + cp_c, cache_new_end);
				cache_new_end = std::copy(cache + cp_c + 1, cache_end, cache_new_end);
			}
			else if (cp_a == -1) // only cp_a == -1
			{
				cache_new_end = std::copy(cache, cache + cp_b, cache_new_end);
				cache_new_end = std::copy(cache + cp_b + 1, cache + cp_c, cache_new_end);
				cache_new_end = std::copy(cache + cp_c + 1, cache_end, cache_new_end);
			}
			else
			{
				cache_new_end = std::copy(cache, cache + cp_a, cache_new_end);
				cache_new_end = std::copy(cache + cp_a + 1, cache + cp_b, cache_new_end);
				cache_new_end = std::copy(cache + cp_b + 1, cache + cp_c, cache_new_end);
				cache_new_end = std::copy(cache + cp_c + 1, cache_end, cache_new_end);
			}

			size_t cache_new_size = cache_new_end - cache_new;

			if (cache_new_size > cache_size) cache_new_end = cache_new + cache_size;

			std::swap(cache, cache_new);
			std::swap(cache_end, cache_new_end);

			// modify vertices
			vertices[tri_a].triangles_not_added--;
			vertices[tri_b].triangles_not_added--;
			vertices[tri_c].triangles_not_added--;

			min_tri = -1;
			float min_score = m_inf;

			// update cache positions, vertices scores and triangle scores, and find new min_face
			for (size_t i = 0; i < cache_new_size; ++i)
			{
				Vertex& v = vertices[cache[i]];

				v.cache_position = i >= cache_size ? -1 : (int)i;

				float score = vertexScore(v);
				float score_diff = score - v.score;

				// update scores of vertex triangles
				for (size_t j = 0; j < v.triangles_total; ++j)
				{
					unsigned int tri = v.triangles[j];

					triangle_scores[tri] += score_diff;

					float tri_score = triangle_scores[tri];

					if (min_score < tri_score)
					{
						min_tri = tri;
						min_score = tri_score;
					}
				}

				v.score = score;
			}
		}
	}
}

void optimizePostTransformTomF(unsigned short* destination, const unsigned short* indices, size_t index_count, size_t vertex_count, unsigned int cache_size)
{
	optimizeLinear(destination, indices, index_count, vertex_count, cache_size);
}

void optimizePostTransformTomF(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, unsigned int cache_size)
{
	optimizeLinear(destination, indices, index_count, vertex_count, cache_size);
}
<|endoftext|>


<commit_before>///
/// @file  nthPrime.cpp
///
/// Copyright (C) 2017 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primesieve/config.hpp>
#include <primesieve/PrimeSieve.hpp>
#include <primesieve/pmath.hpp>
#include <primesieve.hpp>

#include <stdint.h>
#include <algorithm>
#include <cassert>
#include <cmath>

using namespace std;
using namespace primesieve;

namespace {

void checkLimit(uint64_t start)
{
  if (start >= get_max_stop())
    throw primesieve_error("nth prime > 2^64");
}

void checkLowerLimit(uint64_t stop)
{
  if (stop == 0)
    throw primesieve_error("nth prime < 2 is impossible, n is too small");
}

bool sieveBackwards(int64_t n, int64_t count, uint64_t stop)
{
  return (count >= n) &&
        !(count == n && stop < 2);
}

// Prime count approximation
int64_t pix(int64_t n)
{
  double x = (double) n;
  double logx = log(max(4.0, x));
  double pix = x / logx;
  return (int64_t) pix;
}

uint64_t nthPrimeDist(int64_t n, int64_t count, uint64_t start)
{
  double x = (double) (n - count);

  x = abs(x);
  x = max(x, 4.0);

  // rough pi(x) approximation
  double logx = log(x);
  double loglogx = log(logx);
  double pix = x * (logx + loglogx - 1);

  // correct start if sieving backwards to get
  // a more accurate approximation
  if (count >= n)
    start -= (uint64_t) pix;

  // approximate the nth prime using:
  // start + n * log(start + pi(n) / loglog(n))
  double startPix = start + pix / loglogx;
  startPix = max(4.0, startPix);
  double logStartPix = log(startPix);
  double dist = max(pix, x * logStartPix);

  // ensure (start + dist) <= nth prime
  if (count < n) dist -= sqrt(dist) * log(logStartPix) * 2;
  // ensure (start + dist) >= nth prime
  if (count > n) dist += sqrt(dist) * log(logStartPix) * 2;

  // if n is very small:
  // ensure (start + dist) >= nth prime
  double maxPrimeGap = logStartPix * logStartPix;
  dist = max(dist, maxPrimeGap);

  return (uint64_t) dist;
}

} // namespace

namespace primesieve {

uint64_t PrimeSieve::nthPrime(uint64_t n)
{
  return nthPrime(0, n);
}

uint64_t PrimeSieve::nthPrime(int64_t n, uint64_t start)
{
  setStart(start);
  double t1 = getWallTime();

  if (n == 0)
    n = 1; // like Mathematica
  else if (n > 0)
    start = add_overflow_safe(start, 1);
  else if (n < 0)
    start = sub_underflow_safe(start, 1);

  uint64_t stop = start;
  uint64_t dist = nthPrimeDist(n, 0, start);
  uint64_t nthPrimeGuess = add_overflow_safe(start, dist);

  int64_t count = 0;
  int64_t tinyN = 100000;
  tinyN = max(tinyN, pix(isqrt(nthPrimeGuess)));

  while ((n - count) > tinyN ||
         sieveBackwards(n, count, stop))
  {
    if (count < n)
    {
      checkLimit(start);
      dist = nthPrimeDist(n, count, start);
      stop = add_overflow_safe(start, dist);
      count += countPrimes(start, stop);
      start = add_overflow_safe(stop, 1);
    }
    if (sieveBackwards(n, count, stop))
    {
      checkLowerLimit(stop);
      dist = nthPrimeDist(n, count, stop);
      start = sub_underflow_safe(start, dist);
      count -= countPrimes(start, stop);
      stop = sub_underflow_safe(start, 1);
    }
  }

  if (n < 0)
    count -= 1;

  // here start < nth prime,
  // hence we can sieve forward the remaining
  // distance and find the nth prime
  assert(count < n);

  try
  {
    checkLimit(start);
    dist = nthPrimeDist(n, count, start);
    stop = add_overflow_safe(start, dist * 2);
    uint64_t prime;
    for (primesieve::iterator it(start, stop); count < n; count++)
      prime = it.next_prime();
    seconds_ = getWallTime() - t1;
    return prime;
  }
  catch (primesieve_error&) { }

  throw primesieve_error("nth prime > 2^64");
}

} // namespace
<commit_msg>Fix off by one error<commit_after>///
/// @file  nthPrime.cpp
///
/// Copyright (C) 2017 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primesieve/config.hpp>
#include <primesieve/PrimeSieve.hpp>
#include <primesieve/pmath.hpp>
#include <primesieve.hpp>

#include <stdint.h>
#include <algorithm>
#include <cassert>
#include <cmath>

using namespace std;
using namespace primesieve;

namespace {

void checkLimit(uint64_t start)
{
  if (start >= get_max_stop())
    throw primesieve_error("nth prime > 2^64");
}

void checkLowerLimit(uint64_t stop)
{
  if (stop == 0)
    throw primesieve_error("nth prime < 2 is impossible, n is too small");
}

bool sieveBackwards(int64_t n, int64_t count, uint64_t stop)
{
  return (count >= n) &&
        !(count == n && stop < 2);
}

// Prime count approximation
int64_t pix(int64_t n)
{
  double x = (double) n;
  double logx = log(max(4.0, x));
  double pix = x / logx;
  return (int64_t) pix;
}

uint64_t nthPrimeDist(int64_t n, int64_t count, uint64_t start)
{
  double x = (double) (n - count);

  x = abs(x);
  x = max(x, 4.0);

  // rough pi(x) approximation
  double logx = log(x);
  double loglogx = log(logx);
  double pix = x * (logx + loglogx - 1);

  // correct start if sieving backwards to get
  // a more accurate approximation
  if (count >= n)
    start -= (uint64_t) pix;

  // approximate the nth prime using:
  // start + n * log(start + pi(n) / loglog(n))
  double startPix = start + pix / loglogx;
  startPix = max(4.0, startPix);
  double logStartPix = log(startPix);
  double dist = max(pix, x * logStartPix);

  // ensure (start + dist) <= nth prime
  if (count < n) dist -= sqrt(dist) * log(logStartPix) * 2;
  // ensure (start + dist) >= nth prime
  if (count > n) dist += sqrt(dist) * log(logStartPix) * 2;

  // if n is very small:
  // ensure (start + dist) >= nth prime
  double maxPrimeGap = logStartPix * logStartPix;
  dist = max(dist, maxPrimeGap);

  return (uint64_t) dist;
}

} // namespace

namespace primesieve {

uint64_t PrimeSieve::nthPrime(uint64_t n)
{
  return nthPrime(0, n);
}

uint64_t PrimeSieve::nthPrime(int64_t n, uint64_t start)
{
  setStart(start);
  double t1 = getWallTime();

  if (n == 0)
    n = 1; // like Mathematica
  else if (n > 0)
    start = add_overflow_safe(start, 1);
  else if (n < 0)
    start = sub_underflow_safe(start, 1);

  uint64_t stop = start;
  uint64_t dist = nthPrimeDist(n, 0, start);
  uint64_t nthPrimeGuess = add_overflow_safe(start, dist);

  int64_t count = 0;
  int64_t tinyN = 100000;
  tinyN = max(tinyN, pix(isqrt(nthPrimeGuess)));

  while ((n - count) > tinyN ||
         sieveBackwards(n, count, stop))
  {
    if (count < n)
    {
      checkLimit(start);
      dist = nthPrimeDist(n, count, start);
      stop = add_overflow_safe(start, dist);
      count += countPrimes(start, stop);
      start = add_overflow_safe(stop, 1);
    }
    if (sieveBackwards(n, count, stop))
    {
      checkLowerLimit(stop);
      dist = nthPrimeDist(n, count, stop);
      start = sub_underflow_safe(start, dist);
      count -= countPrimes(start, stop);
      stop = sub_underflow_safe(start, 1);
    }
  }

  if (n < 0)
    count -= 1;

  // here start < nth prime,
  // hence we can sieve forward the remaining
  // distance and find the nth prime
  assert(count < n);

  try
  {
    checkLimit(start);
    dist = nthPrimeDist(n, count, start) * 2;
    start = sub_underflow_safe(start, 1);
    stop = add_overflow_safe(start, dist);
    uint64_t prime;
    for (primesieve::iterator it(start, stop); count < n; count++)
      prime = it.next_prime();
    seconds_ = getWallTime() - t1;
    return prime;
  }
  catch (primesieve_error&) { }

  throw primesieve_error("nth prime > 2^64");
}

} // namespace
<|endoftext|>


<commit_before>///
/// @file  PrimeSieve-nthPrime.cpp
///
/// Copyright (C) 2017 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primesieve/config.hpp>
#include <primesieve/cancel_callback.hpp>
#include <primesieve/PrimeSieve.hpp>
#include <primesieve/pmath.hpp>
#include <primesieve.hpp>

#include <stdint.h>
#include <algorithm>
#include <cmath>

using namespace std;
using namespace primesieve;

namespace {

void checkLimit(uint64_t start)
{
  if (start >= get_max_stop())
    throw primesieve_error("nth prime > 2^64");
}

void checkLowerLimit(uint64_t stop)
{
  if (stop == 0)
    throw primesieve_error("nth prime < 2 is impossible, negative n is too small");
}

void checkLowerLimit(uint64_t start, double dist)
{
  double s = static_cast<double>(start);

  if (max(1E4, s) / dist < 0.9)
    throw primesieve_error("nth prime < 2 is impossible, negative n is too small");
}

// Prime count approximation
int64_t pix(int64_t n)
{
  double x = static_cast<double>(n);
  double logx = log(max(4.0, x));
  double pix = x / logx;

  return static_cast<int64_t>(pix);
}

bool sieveBackwards(int64_t n, int64_t count, uint64_t stop)
{
  return (count >= n) &&
        !(count == n && stop < 2);
}

uint64_t nthPrimeDist(int64_t n, int64_t count, uint64_t start)
{
  double x = static_cast<double>(n - count);
  double s = static_cast<double>(start);

  x = abs(x);
  x = max(4.0, x);
  s = max(4.0, s);

  double logx = log(x);
  double loglogx = log(logx);
  double pix = x * (logx + loglogx - 1);

  // Correct start if sieving backwards
  if (count >= n)
    s -= pix;

  // Approximate the nth prime using
  // start + n * log(start + pi(n) / loglog(n))
  double startPix = s + pix / loglogx;
  double logStartPix = log(max(4.0, startPix));
  double dist = max(pix, x * logStartPix);
  double maxPrimeGap = logStartPix * logStartPix;
  double sign = (count < n) ? -2 : 2;

  // Make sure start + dist <= nth prime
  dist += sqrt(dist) * log(logStartPix) * sign;
  dist = max(dist, maxPrimeGap);

  if (count >= n)
    checkLowerLimit(start, dist);

  return static_cast<uint64_t>(dist);
}

/// This class is used to generate n primes and
/// then stop by throwing an exception.
///
class NthPrime : public Callback {
public:
  NthPrime() : n_(0), nthPrime_(0) { }
  void findNthPrime(uint64_t, uint64_t, uint64_t);
  void callback(uint64_t);
  uint64_t getNthPrime() const;
private:
  uint64_t n_;
  uint64_t nthPrime_;
};

void NthPrime::findNthPrime(uint64_t n, uint64_t start, uint64_t stop)
{
  n_ = n;
  PrimeSieve ps;
  try
  {
    ps.callbackPrimes(start, stop, this);
    if (stop < get_max_stop())
      ps.callbackPrimes(stop + 1, get_max_stop(), this);
    throw primesieve_error("nth prime > 2^64");
  }
  catch (cancel_callback&) { }
}

uint64_t NthPrime::getNthPrime() const
{
  return nthPrime_;
}

void NthPrime::callback(uint64_t prime)
{
  if (--n_ == 0)
  {
    nthPrime_ = prime;
    throw cancel_callback();
  }
}

} // namespace

namespace primesieve {

uint64_t PrimeSieve::nthPrime(uint64_t n)
{
  return nthPrime(0, n);
}

uint64_t PrimeSieve::nthPrime(int64_t n, uint64_t start)
{
  setStart(start);
  double t1 = getWallTime();

  if (n == 0)
    n = 1; // Like Mathematica
  else if (n > 0)
    start = add_overflow_safe(start, 1);
  else if (n < 0)
    start = sub_underflow_safe(start, 1);

  uint64_t stop = start;
  uint64_t dist = nthPrimeDist(n, 0, start);
  uint64_t nthPrimeGuess = add_overflow_safe(start, dist);

  int64_t count = 0;
  int64_t tinyN = 10000;
  tinyN = max(tinyN, pix(isqrt(nthPrimeGuess)));

  while ((n - count) > tinyN ||
         sieveBackwards(n, count, stop))
  {
    if (count < n)
    {
      checkLimit(start);
      dist = nthPrimeDist(n, count, start);
      stop = add_overflow_safe(start, dist);
      count += countPrimes(start, stop);
      start = add_overflow_safe(stop, 1);
    }
    if (sieveBackwards(n, count, stop))
    {
      checkLowerLimit(stop);
      dist = nthPrimeDist(n, count, stop);
      start = sub_underflow_safe(start, dist);
      count -= countPrimes(start, stop);
      stop = sub_underflow_safe(start, 1);
    }
  }

  if (n < 0)
    count -= 1;

  checkLimit(start);
  uint64_t overValue = 3;
  dist = nthPrimeDist(n, count, start) * overValue;
  stop = add_overflow_safe(start, dist);
  NthPrime np;
  np.findNthPrime(n - count, start, stop);
  seconds_ = getWallTime() - t1;

  return np.getNthPrime();
}

} // namespace
<commit_msg>Refactor<commit_after>///
/// @file  nthPrime.cpp
///
/// Copyright (C) 2017 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primesieve/config.hpp>
#include <primesieve/PrimeSieve.hpp>
#include <primesieve/pmath.hpp>
#include <primesieve.hpp>

#include <stdint.h>
#include <algorithm>
#include <cmath>

using namespace std;
using namespace primesieve;

namespace {

void checkLimit(uint64_t start)
{
  if (start >= get_max_stop())
    throw primesieve_error("nth prime > 2^64");
}

void checkLowerLimit(uint64_t stop)
{
  if (stop == 0)
    throw primesieve_error("nth prime < 2 is impossible, n is too small");
}

// Prime count approximation
int64_t pix(int64_t n)
{
  double x = (double) n;
  double logx = log(max(4.0, x));
  double pix = x / logx;
  return (int64_t) pix;
}

uint64_t nthPrimeDist(int64_t n, int64_t count, uint64_t start)
{
  double x = (double) (n - count);

  x = abs(x);
  x = max(x, 4.0);

  double logx = log(x);
  double loglogx = log(logx);
  double pix = x * (logx + loglogx - 1);

  // correct start if sieving backwards to get
  // a more accurate approximation
  if (count >= n)
    start -= (uint64_t) pix;

  // approximate the nth prime using:
  // start + n * log(start + pi(n) / loglog(n))
  double startPix = start + pix / loglogx;
  startPix = max(4.0, startPix);
  double logStartPix = log(startPix);
  double dist = max(pix, x * logStartPix);

  // ensure (start + dist) <= nth prime
  if (count < n)
    dist -= sqrt(dist) * log(logStartPix) * 2;

  // ensure (start + dist) >= nth prime
  if (count > n)
    dist += sqrt(dist) * log(logStartPix) * 2;

  // ensure (start + dist) >= nth prime
  // if n is very small
  double maxPrimeGap = logStartPix * logStartPix;
  dist = max(dist, maxPrimeGap);
  return (uint64_t) dist;
}

bool sieveBackwards(int64_t n, int64_t count, uint64_t stop)
{
  return (count >= n) &&
        !(count == n && stop < 2);
}

} // namespace

namespace primesieve {

uint64_t PrimeSieve::nthPrime(uint64_t n)
{
  return nthPrime(0, n);
}

uint64_t PrimeSieve::nthPrime(int64_t n, uint64_t start)
{
  setStart(start);
  double t1 = getWallTime();

  if (n == 0)
    n = 1; // Like Mathematica
  else if (n > 0)
    start = add_overflow_safe(start, 1);
  else if (n < 0)
    start = sub_underflow_safe(start, 1);

  uint64_t stop = start;
  uint64_t dist = nthPrimeDist(n, 0, start);
  uint64_t nthPrimeGuess = add_overflow_safe(start, dist);

  int64_t count = 0;
  int64_t tinyN = 100000;
  tinyN = max(tinyN, pix(isqrt(nthPrimeGuess)));

  while ((n - count) > tinyN ||
         sieveBackwards(n, count, stop))
  {
    if (count < n)
    {
      checkLimit(start);
      dist = nthPrimeDist(n, count, start);
      stop = add_overflow_safe(start, dist);
      count += countPrimes(start, stop);
      start = add_overflow_safe(stop, 1);
    }
    if (sieveBackwards(n, count, stop))
    {
      checkLowerLimit(stop);
      dist = nthPrimeDist(n, count, stop);
      start = sub_underflow_safe(start, dist);
      count -= countPrimes(start, stop);
      stop = sub_underflow_safe(start, 1);
    }
  }

  try
  {
    checkLimit(start);
    if (n < 0) count -= 1;
    dist = nthPrimeDist(n, count, start) * 2;
    stop = add_overflow_safe(start, dist);
    uint64_t prime;
    for (primesieve::iterator it(start, stop); count < n; count++)
      prime = it.next_prime();
    seconds_ = getWallTime() - t1;
    return prime;
  }
  catch (primesieve_error&) { }

  throw primesieve_error("nth prime > 2^64");
}

} // namespace
<|endoftext|>


<commit_before>/*******************************************************************************
 *
 * MIT License
 *
 * Copyright (c) 2017 Advanced Micro Devices, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 *******************************************************************************/
#ifndef GUARD_MIOPEN_DEVICE_NAME_HPP
#define GUARD_MIOPEN_DEVICE_NAME_HPP

#include <map>
#include <string>
#include <miopen/env.hpp>

MIOPEN_DECLARE_ENV_VAR(MIOPEN_DEBUG_ENFORCE_DEVICE)
MIOPEN_DECLARE_ENV_VAR(MIOPEN_DEVICE_ARCH)
MIOPEN_DECLARE_ENV_VAR(MIOPEN_DEVICE_CU)

namespace miopen {

std::string inline GetDeviceNameFromMap(const std::string& name)
{

    static std::map<std::string, std::string> device_name_map = {
        {"Ellesmere", "gfx803"},
        {"Baffin", "gfx803"},
        {"RacerX", "gfx803"},
        {"Polaris10", "gfx803"},
        {"Polaris11", "gfx803"},
        {"Tonga", "gfx803"},
        {"Fiji", "gfx803"},
        {"gfx800", "gfx803"},
        {"gfx802", "gfx803"},
        {"gfx803", "gfx803"},
        {"gfx804", "gfx803"},
        {"Vega10", "gfx900"},
        {"gfx900", "gfx900"},
        {"gfx901", "gfx900"},
        {"gfx906", "gfx906"},
        {"gfx908", "gfx908"},
    };

    std::string n(name);
    const char* const p_asciz = miopen::GetStringEnv(MIOPEN_DEBUG_ENFORCE_DEVICE{});
    if(p_asciz != nullptr && strlen(p_asciz) > 0)
    {
        n = p_asciz;
    }

    auto device_name_iterator = device_name_map.find(n);
    if(device_name_iterator != device_name_map.end())
    {
        return device_name_iterator->second;
    }
    else
    {
        return n;
    }
}

} // namespace miopen

#endif // GUARD_MIOPEN_DEVICE_NAME_HPP
<commit_msg>Add gfx10 to arch list (#498)<commit_after>/*******************************************************************************
 *
 * MIT License
 *
 * Copyright (c) 2017 Advanced Micro Devices, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 *******************************************************************************/
#ifndef GUARD_MIOPEN_DEVICE_NAME_HPP
#define GUARD_MIOPEN_DEVICE_NAME_HPP

#include <map>
#include <string>
#include <miopen/env.hpp>

MIOPEN_DECLARE_ENV_VAR(MIOPEN_DEBUG_ENFORCE_DEVICE)
MIOPEN_DECLARE_ENV_VAR(MIOPEN_DEVICE_ARCH)
MIOPEN_DECLARE_ENV_VAR(MIOPEN_DEVICE_CU)

namespace miopen {

std::string inline GetDeviceNameFromMap(const std::string& name)
{

    static std::map<std::string, std::string> device_name_map = {
        {"Ellesmere", "gfx803"},
        {"Baffin", "gfx803"},
        {"RacerX", "gfx803"},
        {"Polaris10", "gfx803"},
        {"Polaris11", "gfx803"},
        {"Tonga", "gfx803"},
        {"Fiji", "gfx803"},
        {"gfx800", "gfx803"},
        {"gfx802", "gfx803"},
        {"gfx803", "gfx803"},
        {"gfx804", "gfx803"},
        {"Vega10", "gfx900"},
        {"gfx900", "gfx900"},
        {"gfx901", "gfx900"},
        {"gfx906", "gfx906"},
        {"gfx908", "gfx908"},
        {"10.3.0 Sienna_Cichlid 18", "gfx1030"},
    };

    std::string n(name);
    const char* const p_asciz = miopen::GetStringEnv(MIOPEN_DEBUG_ENFORCE_DEVICE{});
    if(p_asciz != nullptr && strlen(p_asciz) > 0)
    {
        n = p_asciz;
    }

    auto device_name_iterator = device_name_map.find(n);
    if(device_name_iterator != device_name_map.end())
    {
        return device_name_iterator->second;
    }
    else
    {
        return n;
    }
}

} // namespace miopen

#endif // GUARD_MIOPEN_DEVICE_NAME_HPP
<|endoftext|>


<commit_before>#include "bar.hpp"
#include "registry.hpp"
#include "services/builder.hpp"
#include "utils/config.hpp"

#include "modules/backlight.hpp"
#include "modules/battery.hpp"
#include "modules/bspwm.hpp"
#include "modules/counter.hpp"
#include "modules/cpu.hpp"
#include "modules/date.hpp"
#include "modules/memory.hpp"
#include "modules/menu.hpp"
#include "modules/network.hpp"
#include "modules/script.hpp"
#include "modules/text.hpp"
#include "modules/torrent.hpp"
#ifdef ENABLE_I3
#include "modules/i3.hpp"
#endif
#ifdef ENABLE_MPD
#include "modules/mpd.hpp"
#endif
#ifdef ENABLE_ALSA
#include "modules/volume.hpp"
#endif

std::shared_ptr<Bar> bar;
std::shared_ptr<Bar> &get_bar()
{
  if (bar == nullptr)
    bar = std::make_shared<Bar>();
  return bar;
}

std::vector<std::unique_ptr<xlib::Monitor>> monitors;

const Options& bar_opts() {
  return *bar->opts.get();
}

/**
 * Bar constructor
 */
Bar::Bar()
{
  this->config_path = config::get_bar_path();

  struct Options defaults;

  this->opts = std::make_unique<Options>();

  try {
    this->opts->locale = config::get<std::string>(this->config_path, "locale");
    std::locale::global(std::locale(this->opts->locale.c_str()));
  } catch (config::MissingValueException &e) {}

  auto monitor_name = config::get<std::string>(this->config_path, "monitor", "");
  this->opts->monitor = std::make_unique<xlib::Monitor>();

  if (monitors.empty())
    monitors = xlib::get_sorted_monitorlist();

  // In case we're not connected to X, we'll just ignore the monitor
  if (!monitors.empty()) {
    if (monitor_name.empty() && !monitors.empty())
      monitor_name = monitors[0]->name;

    for (auto &&monitor : monitors) {
      if (monitor_name.compare(monitor->name) == 0) {
        this->opts->monitor->name = monitor->name;
        this->opts->monitor->index = monitor->index;
        this->opts->monitor->width = monitor->width;
        this->opts->monitor->height = monitor->height;
        this->opts->monitor->x = monitor->x;
        this->opts->monitor->y = monitor->y;
      }
    }

    if (this->opts->monitor->name.empty())
      throw ConfigurationError("Could not find monitor: "+ monitor_name);
  }

  this->opts->wm_name = "lemonbuddy-"+ this->config_path.substr(4);
  if (!this->opts->monitor->name.empty())
    this->opts->wm_name += "_"+ this->opts->monitor->name;
  this->opts->wm_name = config::get<std::string>(this->config_path, "wm_name", this->opts->wm_name);

  this->opts->offset_x = config::get<int>(this->config_path, "offset_x", defaults.offset_x);
  this->opts->offset_y = config::get<int>(this->config_path, "offset_y", defaults.offset_y);

  auto width = config::get<std::string>(this->config_path, "width", "100%");
  auto height = config::get<std::string>(this->config_path, "height", "30");

  if (width.find("%") != std::string::npos) {
    this->opts->width = this->opts->monitor->width * (std::atoi(width.c_str()) / 100.0) + 0.5;
    this->opts->width -= this->opts->offset_x * 2;
  } else {
    this->opts->width = std::atoi(width.c_str());
  }

  if (height.find("%") != std::string::npos) {
    this->opts->height = this->opts->monitor->height * (std::atoi(height.c_str()) / 100.0) + 0.5;
    this->opts->width -= this->opts->offset_y * 2;
  } else {
    this->opts->height = std::atoi(height.c_str());
  }

  this->opts->background = config::get<std::string>(this->config_path, "background", defaults.background);
  this->opts->foreground = config::get<std::string>(this->config_path, "foreground", defaults.foreground);
  this->opts->linecolor = config::get<std::string>(this->config_path, "linecolor", defaults.linecolor);

  this->opts->bottom = config::get<bool>(this->config_path, "bottom", defaults.bottom);
  this->opts->dock = config::get<bool>(this->config_path, "dock", defaults.dock);
  this->opts->clickareas = config::get<int>(this->config_path, "clickareas", defaults.clickareas);

  this->opts->separator = config::get<std::string>(this->config_path, "separator", defaults.separator);

  this->opts->spacing = config::get<int>(this->config_path, "spacing", defaults.spacing);
  this->opts->lineheight = config::get<int>(this->config_path, "lineheight", defaults.lineheight);

  this->opts->padding_left = config::get<int>(this->config_path, "padding_left", defaults.padding_left);
  this->opts->padding_right = config::get<int>(this->config_path, "padding_right", defaults.padding_right);

  this->opts->module_margin_left = config::get<int>(this->config_path, "module_margin_left", defaults.module_margin_left);
  this->opts->module_margin_right = config::get<int>(this->config_path, "module_margin_right", defaults.module_margin_right);

  for (auto f : config::get_list<std::string>(this->config_path, "font")) {
    std::vector<std::string> font;
    string::split_into(f, ';', font);
    this->opts->fonts.emplace_back(std::make_unique<Font>(font[0], std::stoi(font[1])));
  }
}

/**
 * Loads all modules configured for the current bar
 */
void Bar::load()
{
  auto add_modules = [&](std::string modlist, std::vector<std::string> &vec){
    std::vector<std::string> modules;
    string::split_into(modlist, ' ', modules);

    for (auto &&mod : modules) {
      std::unique_ptr<modules::ModuleInterface> module;
      auto type = config::get<std::string>("module/"+ mod, "type");

           if (type == "internal/counter")  module = std::make_unique<modules::CounterModule>(mod);
      else if (type == "internal/backlight")  module = std::make_unique<modules::BacklightModule>(mod);
      else if (type == "internal/battery")    module = std::make_unique<modules::BatteryModule>(mod);
      else if (type == "internal/bspwm")      module = std::make_unique<modules::BspwmModule>(mod, this->opts->monitor->name);
      else if (type == "internal/cpu")        module = std::make_unique<modules::CpuModule>(mod);
      else if (type == "internal/date")       module = std::make_unique<modules::DateModule>(mod);
      else if (type == "internal/memory")     module = std::make_unique<modules::MemoryModule>(mod);
      else if (type == "internal/network")    module = std::make_unique<modules::NetworkModule>(mod);
#ifdef ENABLE_I3
      else if (type == "internal/i3")         module = std::make_unique<modules::i3Module>(mod, this->opts->monitor->name);
#endif
#ifdef ENABLE_MPD
      else if (type == "internal/mpd")        module = std::make_unique<modules::MpdModule>(mod);
#endif
#ifdef ENABLE_ALSA
      else if (type == "internal/volume")     module = std::make_unique<modules::VolumeModule>(mod);
#endif
#if 0
      else if (type == "internal/rtorrent")   module = std::make_unique<modules::TorrentModule>(mod);
#endif
      else if (type == "custom/text")         module = std::make_unique<modules::TextModule>(mod);
      else if (type == "custom/script")       module = std::make_unique<modules::ScriptModule>(mod);
      else if (type == "custom/menu")         module = std::make_unique<modules::MenuModule>(mod);
      else throw ConfigurationError("Unknown module: "+ mod);

      vec.emplace_back(module->name());
      get_registry()->insert(std::move(module));
    }
  };

  add_modules(config::get<std::string>(this->config_path, "modules:left", ""), this->mod_left);
  add_modules(config::get<std::string>(this->config_path, "modules:center", ""), this->mod_center);
  add_modules(config::get<std::string>(this->config_path, "modules:right", ""), this->mod_right);

  if (this->mod_left.empty() && this->mod_center.empty() && this->mod_right.empty())
    throw ConfigurationError("The bar does not contain any modules...");
}

/**
 * Builds the output string by combining the output
 * of all added modules
 */
std::string Bar::get_output()
{
  auto builder = std::make_unique<Builder>();
  auto pad_left = std::string(this->opts->padding_left, ' ');
  auto pad_right = std::string(this->opts->padding_right, ' ');

  auto output_modules = [&](Builder::Alignment align, std::vector<std::string> &mods){
    if (!pad_left.empty() && !mods.empty() && align == Builder::ALIGN_LEFT)
      builder->append_module_output(align, pad_left, false, false);

    for (auto &mod_name : mods) {
      auto mod_output = get_registry()->get(mod_name);
      builder->append_module_output(align, mod_output,
          !(align == Builder::ALIGN_LEFT && mod_name == mods.front()),
          !(align == Builder::ALIGN_RIGHT && mod_name == mods.back()));

      if (!mod_output.empty() && !this->opts->separator.empty() && mod_name != mods.back())
        builder->append(this->opts->separator);
    }

    if (!pad_right.empty() && !mods.empty() && align == Builder::ALIGN_RIGHT)
      builder->append_module_output(align, pad_right, false, false);
  };

  output_modules(Builder::ALIGN_LEFT, this->mod_left);
  output_modules(Builder::ALIGN_CENTER, this->mod_center);
  output_modules(Builder::ALIGN_RIGHT, this->mod_right);

  auto data = builder->flush();

  return data;
}

/**
 * Builds the command line string used to execute
 * lemonbar using the specified bar
 */
std::string Bar::get_exec_line()
{
  std::stringstream buffer;

  buffer << "lemonbar -p";
  if (!this->opts->wm_name.empty())
    buffer << " -n " << this->opts->wm_name;
  if (!this->opts->background.empty())
    buffer << " -B " << this->opts->background;
  if (!this->opts->foreground.empty())
    buffer << " -F " << this->opts->foreground;
  if (!this->opts->linecolor.empty())
    buffer << " -U " << this->opts->linecolor;
  if (this->opts->bottom)
    buffer << " -b ";
  if (this->opts->dock)
    buffer << " -d ";

  for (auto &&font : this->opts->fonts) {
    buffer << " -f " << font->id;
    buffer << " -o " << font->offset;
  }

  buffer << " -u " << this->opts->lineheight;
  buffer << " -a " << this->opts->clickareas;
  buffer << " -g " << this->opts->get_geom();
  buffer << " " << this->opts->monitor->name;

  buffer.flush();

  return string::squeeze(buffer.str(), ' ');
}
<commit_msg>fix(fonts): Default offset to 0 if not specified<commit_after>#include "bar.hpp"
#include "registry.hpp"
#include "services/builder.hpp"
#include "utils/config.hpp"

#include "modules/backlight.hpp"
#include "modules/battery.hpp"
#include "modules/bspwm.hpp"
#include "modules/counter.hpp"
#include "modules/cpu.hpp"
#include "modules/date.hpp"
#include "modules/memory.hpp"
#include "modules/menu.hpp"
#include "modules/network.hpp"
#include "modules/script.hpp"
#include "modules/text.hpp"
#include "modules/torrent.hpp"
#ifdef ENABLE_I3
#include "modules/i3.hpp"
#endif
#ifdef ENABLE_MPD
#include "modules/mpd.hpp"
#endif
#ifdef ENABLE_ALSA
#include "modules/volume.hpp"
#endif

std::shared_ptr<Bar> bar;
std::shared_ptr<Bar> &get_bar()
{
  if (bar == nullptr)
    bar = std::make_shared<Bar>();
  return bar;
}

std::vector<std::unique_ptr<xlib::Monitor>> monitors;

const Options& bar_opts() {
  return *bar->opts.get();
}

/**
 * Bar constructor
 */
Bar::Bar()
{
  this->config_path = config::get_bar_path();

  struct Options defaults;

  this->opts = std::make_unique<Options>();

  try {
    this->opts->locale = config::get<std::string>(this->config_path, "locale");
    std::locale::global(std::locale(this->opts->locale.c_str()));
  } catch (config::MissingValueException &e) {}

  auto monitor_name = config::get<std::string>(this->config_path, "monitor", "");
  this->opts->monitor = std::make_unique<xlib::Monitor>();

  if (monitors.empty())
    monitors = xlib::get_sorted_monitorlist();

  // In case we're not connected to X, we'll just ignore the monitor
  if (!monitors.empty()) {
    if (monitor_name.empty() && !monitors.empty())
      monitor_name = monitors[0]->name;

    for (auto &&monitor : monitors) {
      if (monitor_name.compare(monitor->name) == 0) {
        this->opts->monitor->name = monitor->name;
        this->opts->monitor->index = monitor->index;
        this->opts->monitor->width = monitor->width;
        this->opts->monitor->height = monitor->height;
        this->opts->monitor->x = monitor->x;
        this->opts->monitor->y = monitor->y;
      }
    }

    if (this->opts->monitor->name.empty())
      throw ConfigurationError("Could not find monitor: "+ monitor_name);
  }

  this->opts->wm_name = "lemonbuddy-"+ this->config_path.substr(4);
  if (!this->opts->monitor->name.empty())
    this->opts->wm_name += "_"+ this->opts->monitor->name;
  this->opts->wm_name = config::get<std::string>(this->config_path, "wm_name", this->opts->wm_name);

  this->opts->offset_x = config::get<int>(this->config_path, "offset_x", defaults.offset_x);
  this->opts->offset_y = config::get<int>(this->config_path, "offset_y", defaults.offset_y);

  auto width = config::get<std::string>(this->config_path, "width", "100%");
  auto height = config::get<std::string>(this->config_path, "height", "30");

  if (width.find("%") != std::string::npos) {
    this->opts->width = this->opts->monitor->width * (std::atoi(width.c_str()) / 100.0) + 0.5;
    this->opts->width -= this->opts->offset_x * 2;
  } else {
    this->opts->width = std::atoi(width.c_str());
  }

  if (height.find("%") != std::string::npos) {
    this->opts->height = this->opts->monitor->height * (std::atoi(height.c_str()) / 100.0) + 0.5;
    this->opts->width -= this->opts->offset_y * 2;
  } else {
    this->opts->height = std::atoi(height.c_str());
  }

  this->opts->background = config::get<std::string>(this->config_path, "background", defaults.background);
  this->opts->foreground = config::get<std::string>(this->config_path, "foreground", defaults.foreground);
  this->opts->linecolor = config::get<std::string>(this->config_path, "linecolor", defaults.linecolor);

  this->opts->bottom = config::get<bool>(this->config_path, "bottom", defaults.bottom);
  this->opts->dock = config::get<bool>(this->config_path, "dock", defaults.dock);
  this->opts->clickareas = config::get<int>(this->config_path, "clickareas", defaults.clickareas);

  this->opts->separator = config::get<std::string>(this->config_path, "separator", defaults.separator);

  this->opts->spacing = config::get<int>(this->config_path, "spacing", defaults.spacing);
  this->opts->lineheight = config::get<int>(this->config_path, "lineheight", defaults.lineheight);

  this->opts->padding_left = config::get<int>(this->config_path, "padding_left", defaults.padding_left);
  this->opts->padding_right = config::get<int>(this->config_path, "padding_right", defaults.padding_right);

  this->opts->module_margin_left = config::get<int>(this->config_path, "module_margin_left", defaults.module_margin_left);
  this->opts->module_margin_right = config::get<int>(this->config_path, "module_margin_right", defaults.module_margin_right);

  for (auto f : config::get_list<std::string>(this->config_path, "font")) {
    std::vector<std::string> font;
    string::split_into(f, ';', font);
    if (font.size() < 2)
      font.emplace_back("0");
    this->opts->fonts.emplace_back(std::make_unique<Font>(font[0], std::stoi(font[1])));
  }
}

/**
 * Loads all modules configured for the current bar
 */
void Bar::load()
{
  auto add_modules = [&](std::string modlist, std::vector<std::string> &vec){
    std::vector<std::string> modules;
    string::split_into(modlist, ' ', modules);

    for (auto &&mod : modules) {
      std::unique_ptr<modules::ModuleInterface> module;
      auto type = config::get<std::string>("module/"+ mod, "type");

           if (type == "internal/counter")  module = std::make_unique<modules::CounterModule>(mod);
      else if (type == "internal/backlight")  module = std::make_unique<modules::BacklightModule>(mod);
      else if (type == "internal/battery")    module = std::make_unique<modules::BatteryModule>(mod);
      else if (type == "internal/bspwm")      module = std::make_unique<modules::BspwmModule>(mod, this->opts->monitor->name);
      else if (type == "internal/cpu")        module = std::make_unique<modules::CpuModule>(mod);
      else if (type == "internal/date")       module = std::make_unique<modules::DateModule>(mod);
      else if (type == "internal/memory")     module = std::make_unique<modules::MemoryModule>(mod);
      else if (type == "internal/network")    module = std::make_unique<modules::NetworkModule>(mod);
#ifdef ENABLE_I3
      else if (type == "internal/i3")         module = std::make_unique<modules::i3Module>(mod, this->opts->monitor->name);
#endif
#ifdef ENABLE_MPD
      else if (type == "internal/mpd")        module = std::make_unique<modules::MpdModule>(mod);
#endif
#ifdef ENABLE_ALSA
      else if (type == "internal/volume")     module = std::make_unique<modules::VolumeModule>(mod);
#endif
#if 0
      else if (type == "internal/rtorrent")   module = std::make_unique<modules::TorrentModule>(mod);
#endif
      else if (type == "custom/text")         module = std::make_unique<modules::TextModule>(mod);
      else if (type == "custom/script")       module = std::make_unique<modules::ScriptModule>(mod);
      else if (type == "custom/menu")         module = std::make_unique<modules::MenuModule>(mod);
      else throw ConfigurationError("Unknown module: "+ mod);

      vec.emplace_back(module->name());
      get_registry()->insert(std::move(module));
    }
  };

  add_modules(config::get<std::string>(this->config_path, "modules:left", ""), this->mod_left);
  add_modules(config::get<std::string>(this->config_path, "modules:center", ""), this->mod_center);
  add_modules(config::get<std::string>(this->config_path, "modules:right", ""), this->mod_right);

  if (this->mod_left.empty() && this->mod_center.empty() && this->mod_right.empty())
    throw ConfigurationError("The bar does not contain any modules...");
}

/**
 * Builds the output string by combining the output
 * of all added modules
 */
std::string Bar::get_output()
{
  auto builder = std::make_unique<Builder>();
  auto pad_left = std::string(this->opts->padding_left, ' ');
  auto pad_right = std::string(this->opts->padding_right, ' ');

  auto output_modules = [&](Builder::Alignment align, std::vector<std::string> &mods){
    if (!pad_left.empty() && !mods.empty() && align == Builder::ALIGN_LEFT)
      builder->append_module_output(align, pad_left, false, false);

    for (auto &mod_name : mods) {
      auto mod_output = get_registry()->get(mod_name);
      builder->append_module_output(align, mod_output,
          !(align == Builder::ALIGN_LEFT && mod_name == mods.front()),
          !(align == Builder::ALIGN_RIGHT && mod_name == mods.back()));

      if (!mod_output.empty() && !this->opts->separator.empty() && mod_name != mods.back())
        builder->append(this->opts->separator);
    }

    if (!pad_right.empty() && !mods.empty() && align == Builder::ALIGN_RIGHT)
      builder->append_module_output(align, pad_right, false, false);
  };

  output_modules(Builder::ALIGN_LEFT, this->mod_left);
  output_modules(Builder::ALIGN_CENTER, this->mod_center);
  output_modules(Builder::ALIGN_RIGHT, this->mod_right);

  auto data = builder->flush();

  return data;
}

/**
 * Builds the command line string used to execute
 * lemonbar using the specified bar
 */
std::string Bar::get_exec_line()
{
  std::stringstream buffer;

  buffer << "lemonbar -p";
  if (!this->opts->wm_name.empty())
    buffer << " -n " << this->opts->wm_name;
  if (!this->opts->background.empty())
    buffer << " -B " << this->opts->background;
  if (!this->opts->foreground.empty())
    buffer << " -F " << this->opts->foreground;
  if (!this->opts->linecolor.empty())
    buffer << " -U " << this->opts->linecolor;
  if (this->opts->bottom)
    buffer << " -b ";
  if (this->opts->dock)
    buffer << " -d ";

  for (auto &&font : this->opts->fonts) {
    buffer << " -f " << font->id;
    buffer << " -o " << font->offset;
  }

  buffer << " -u " << this->opts->lineheight;
  buffer << " -a " << this->opts->clickareas;
  buffer << " -g " << this->opts->get_geom();
  buffer << " " << this->opts->monitor->name;

  buffer.flush();

  return string::squeeze(buffer.str(), ' ');
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Build Suite.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "executorjob.h"

#include "buildgraph.h"
#include "command.h"
#include "jscommandexecutor.h"
#include "processcommandexecutor.h"
#include "transformer.h"

#include <QThread>

namespace qbs {

ExecutorJob::ExecutorJob(QObject *parent)
    : QObject(parent)
    , m_processCommandExecutor(new ProcessCommandExecutor(this))
    , m_jsCommandExecutor(new JsCommandExecutor(this))
{
    connect(m_processCommandExecutor, SIGNAL(error(QString)), SLOT(onCommandError(QString)));
    connect(m_processCommandExecutor, SIGNAL(finished()), SLOT(onCommandFinished()));
    connect(m_jsCommandExecutor, SIGNAL(error(QString)), SLOT(onCommandError(QString)));
    connect(m_jsCommandExecutor, SIGNAL(finished()), SLOT(onCommandFinished()));
    setInactive();
}

ExecutorJob::~ExecutorJob()
{
}

void ExecutorJob::setMainThreadScriptEngine(QScriptEngine *engine)
{
    m_processCommandExecutor->setMainThreadScriptEngine(engine);
    m_jsCommandExecutor->setMainThreadScriptEngine(engine);
}

void ExecutorJob::setDryRun(bool enabled)
{
    m_processCommandExecutor->setDryRunEnabled(enabled);
    m_jsCommandExecutor->setDryRunEnabled(enabled);
}

void ExecutorJob::run(Transformer *t, const BuildProduct *buildProduct)
{
    Q_ASSERT(m_currentCommandIdx == -1);

    if (t->commands.isEmpty()) {
        emit success();
        return;
    }

    m_processCommandExecutor->setProcessEnvironment(buildProduct->rProduct->buildEnvironment);

    m_transformer = t;
    runNextCommand();
}

void ExecutorJob::cancel()
{
    if (!m_transformer)
        return;
    m_currentCommandIdx = m_transformer->commands.count();
}

void ExecutorJob::waitForFinished()
{
    if (m_currentCommandExecutor)
        m_currentCommandExecutor->waitForFinished();
}

void ExecutorJob::runNextCommand()
{
    ++m_currentCommandIdx;
    Q_ASSERT(m_currentCommandIdx <= m_transformer->commands.count());
    if (m_currentCommandIdx == m_transformer->commands.count()) {
        setInactive();
        emit success();
        return;
    }

    const AbstractCommand * const command = m_transformer->commands.at(m_currentCommandIdx);
    switch (command->type()) {
    case AbstractCommand::ProcessCommandType:
        m_currentCommandExecutor = m_processCommandExecutor;
        break;
    case AbstractCommand::JavaScriptCommandType:
        m_currentCommandExecutor = m_jsCommandExecutor;
        break;
    default:
        qFatal("Missing implementation for command type %d", command->type());
    }

    m_currentCommandExecutor->start(m_transformer, command);
}

void ExecutorJob::onCommandError(QString errorString)
{
    setInactive();
    emit error(errorString);
}

void ExecutorJob::onCommandFinished()
{
    if (!m_transformer)
        return;
    runNextCommand();
}

void ExecutorJob::setInactive()
{
    m_transformer = 0;
    m_currentCommandExecutor = 0;
    m_currentCommandIdx = -1;
}

} // namespace qbs
<commit_msg>ExecutorJob: Fix assertion.<commit_after>/****************************************************************************
**
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Build Suite.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "executorjob.h"

#include "buildgraph.h"
#include "command.h"
#include "jscommandexecutor.h"
#include "processcommandexecutor.h"
#include "transformer.h"

#include <QThread>

namespace qbs {

ExecutorJob::ExecutorJob(QObject *parent)
    : QObject(parent)
    , m_processCommandExecutor(new ProcessCommandExecutor(this))
    , m_jsCommandExecutor(new JsCommandExecutor(this))
{
    connect(m_processCommandExecutor, SIGNAL(error(QString)), SLOT(onCommandError(QString)));
    connect(m_processCommandExecutor, SIGNAL(finished()), SLOT(onCommandFinished()));
    connect(m_jsCommandExecutor, SIGNAL(error(QString)), SLOT(onCommandError(QString)));
    connect(m_jsCommandExecutor, SIGNAL(finished()), SLOT(onCommandFinished()));
    setInactive();
}

ExecutorJob::~ExecutorJob()
{
}

void ExecutorJob::setMainThreadScriptEngine(QScriptEngine *engine)
{
    m_processCommandExecutor->setMainThreadScriptEngine(engine);
    m_jsCommandExecutor->setMainThreadScriptEngine(engine);
}

void ExecutorJob::setDryRun(bool enabled)
{
    m_processCommandExecutor->setDryRunEnabled(enabled);
    m_jsCommandExecutor->setDryRunEnabled(enabled);
}

void ExecutorJob::run(Transformer *t, const BuildProduct *buildProduct)
{
    Q_ASSERT(m_currentCommandIdx == -1);

    if (t->commands.isEmpty()) {
        emit success();
        return;
    }

    m_processCommandExecutor->setProcessEnvironment(buildProduct->rProduct->buildEnvironment);

    m_transformer = t;
    runNextCommand();
}

void ExecutorJob::cancel()
{
    if (!m_transformer)
        return;
    m_currentCommandIdx = m_transformer->commands.count();
}

void ExecutorJob::waitForFinished()
{
    if (m_currentCommandExecutor)
        m_currentCommandExecutor->waitForFinished();
}

void ExecutorJob::runNextCommand()
{
    Q_ASSERT(m_currentCommandIdx <= m_transformer->commands.count());
    ++m_currentCommandIdx;
    if (m_currentCommandIdx >= m_transformer->commands.count()) {
        setInactive();
        emit success();
        return;
    }

    const AbstractCommand * const command = m_transformer->commands.at(m_currentCommandIdx);
    switch (command->type()) {
    case AbstractCommand::ProcessCommandType:
        m_currentCommandExecutor = m_processCommandExecutor;
        break;
    case AbstractCommand::JavaScriptCommandType:
        m_currentCommandExecutor = m_jsCommandExecutor;
        break;
    default:
        qFatal("Missing implementation for command type %d", command->type());
    }

    m_currentCommandExecutor->start(m_transformer, command);
}

void ExecutorJob::onCommandError(QString errorString)
{
    setInactive();
    emit error(errorString);
}

void ExecutorJob::onCommandFinished()
{
    if (!m_transformer)
        return;
    runNextCommand();
}

void ExecutorJob::setInactive()
{
    m_transformer = 0;
    m_currentCommandExecutor = 0;
    m_currentCommandIdx = -1;
}

} // namespace qbs
<|endoftext|>