<commit_before>// bslmt_semaphoreimpl_pthread.cpp                                    -*-C++-*-

// ----------------------------------------------------------------------------
//                                   NOTICE
//
// This component is not up to date with current BDE coding standards, and
// should not be used as an example for new development.
// ----------------------------------------------------------------------------

#include <bslmt_semaphoreimpl_pthread.h>

#include <bsls_ident.h>
BSLS_IDENT_RCSID(bslmt_semaphoreimpl_pthread_cpp,"$Id$ $CSID$")

#ifdef BSLMT_PLATFORM_POSIX_SEMAPHORE

#include <bslmt_lockguard.h>    // for testing only
#include <bslmt_mutex.h>        // for testing only
#include <bslmt_threadutil.h>   // for testing only

#include <bsl_c_errno.h>

namespace BloombergLP {

              // ---------------------------------------------
              // class SemaphoreImpl<Platform::PosixSemaphore>
              // ---------------------------------------------

// CREATORS
bslmt::SemaphoreImpl<bslmt::Platform::PosixSemaphore>::SemaphoreImpl(int count)
{
    int result = ::sem_init(&d_sem, 0, count);

    (void) result;
    BSLS_ASSERT(result == 0);
}

// MANIPULATORS
void bslmt::SemaphoreImpl<bslmt::Platform::PosixSemaphore>::post(int number)
{
    for (int i = 0; i < number; i++) {
        post();
    }
}

void
bslmt::SemaphoreImpl<bslmt::Platform::PosixSemaphore>::wait()
{
    sem_t * sem_p = &d_sem;
    int result = 0;

    do {
        result = ::sem_wait(sem_p);
    } while (result != 0 && errno == EINTR);

    BSLS_ASSERT(result == 0);
}

}  // close enterprise namespace

#endif  // BSLMT_PLATFORM_POSIX_THREADS

// ----------------------------------------------------------------------------
// Copyright 2015 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------
<commit_msg>Adopt commit 9853bde64 from master: Merge pull request #1304 from rkhlebnikov/bslmt_semaphoreimpl_pthread-drqs-61904468-fix-assert<commit_after>// bslmt_semaphoreimpl_pthread.cpp                                    -*-C++-*-

// ----------------------------------------------------------------------------
//                                   NOTICE
//
// This component is not up to date with current BDE coding standards, and
// should not be used as an example for new development.
// ----------------------------------------------------------------------------

#include <bslmt_semaphoreimpl_pthread.h>

#include <bsls_ident.h>
BSLS_IDENT_RCSID(bslmt_semaphoreimpl_pthread_cpp,"$Id$ $CSID$")

#ifdef BSLMT_PLATFORM_POSIX_SEMAPHORE

#include <bslmt_lockguard.h>    // for testing only
#include <bslmt_mutex.h>        // for testing only
#include <bslmt_threadutil.h>   // for testing only

#include <bsl_c_errno.h>

namespace BloombergLP {

              // ---------------------------------------------
              // class SemaphoreImpl<Platform::PosixSemaphore>
              // ---------------------------------------------

// CREATORS
bslmt::SemaphoreImpl<bslmt::Platform::PosixSemaphore>::SemaphoreImpl(int count)
{
    int result = ::sem_init(&d_sem, 0, count);

    (void) result;
    BSLS_ASSERT(result != -1);
}

// MANIPULATORS
void bslmt::SemaphoreImpl<bslmt::Platform::PosixSemaphore>::post(int number)
{
    for (int i = 0; i < number; i++) {
        post();
    }
}

void
bslmt::SemaphoreImpl<bslmt::Platform::PosixSemaphore>::wait()
{
    sem_t * sem_p = &d_sem;
    int result = 0;

    do {
        result = ::sem_wait(sem_p);
    } while (result != 0 && errno == EINTR);

    BSLS_ASSERT(result == 0);
}

}  // close enterprise namespace

#endif  // BSLMT_PLATFORM_POSIX_THREADS

// ----------------------------------------------------------------------------
// Copyright 2015 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------
<|endoftext|>


<commit_before>/*
    This file is part of KMail, the KDE mail client.
    Copyright (c) 2004 Till Adam <adam@kde.org>

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

    KMail is distributed in the hope that it will be useful, but
    WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

    In addition, as a special exception, the copyright holders give
    permission to link the code of this program with any edition of
    the Qt library by Trolltech AS, Norway (or with modified versions
    of Qt that use the same license as Qt), and distribute linked
    combinations including the two.  You must obey the GNU General
    Public License in all respects for all of the code used other than
    Qt.  If you modify this file, you may extend this exception to
    your version of the file, but you are not obligated to do so.  If
    you do not wish to do so, delete this exception statement from
    your version.
*/
#include "headerlistquicksearch.h"

#include <qapplication.h>
#include <qlabel.h>
#include <qcombobox.h>
#include <qtimer.h>

#include <kaction.h>
#include <kiconloader.h>
#include <klistview.h>
#include <klocale.h>

#include "kmheaders.h"
#include "kmsearchpattern.h"

namespace KMail {

HeaderListQuickSearch::HeaderListQuickSearch( QWidget *parent,
                                              KListView *listView,
                                              KActionCollection *actionCollection,
                                              const char *name )
  : KListViewSearchLine(parent, listView, name), mStatusCombo(0), mStatus(0)
{
  KAction *resetQuickSearch = new KAction( i18n( "Reset Quick Search" ),
                                           QApplication::reverseLayout()
                                           ? "clear_left"
                                           : "locationbar_erase",
                                           0, this,
                                           SLOT( reset() ),
                                           actionCollection,
                                           "reset_quicksearch" );
  resetQuickSearch->plug( parent );
  resetQuickSearch->setWhatsThis( i18n( "Reset Quick Search\n"
                                        "Resets the quick search so that "
                                        "all messages are shown again." ) );

  QLabel *label = new QLabel( i18n("Stat&us:"), parent, "kde toolbar widget" );

  mStatusCombo = new QComboBox( parent, "quick search status combo box" );
  mStatusCombo->insertItem( SmallIcon( "run" ), i18n("Any Status") );
  for ( int i = 0; i < KMail::StatusValueCount; i++ )
    mStatusCombo->insertItem( SmallIcon( KMail::StatusValues[ i ].icon ), i18n( KMail::StatusValues[ i ].text ) );
  mStatusCombo->setCurrentItem( 0 );
  connect( mStatusCombo, SIGNAL ( activated( int ) ),
           this, SLOT( slotStatusChanged( int ) ) );

  label->setBuddy( mStatusCombo );

  /* Disable the signal connected by KListViewSearchLine since it will call
   * itemAdded during KMHeaders::readSortOrder() which will in turn result
   * in getMsgBaseForItem( item ) wanting to access items which are no longer
   * there. Rather rely on KMHeaders::msgAdded and its signal. */
  disconnect(listView, SIGNAL(itemAdded(QListViewItem *)),
             this, SLOT(itemAdded(QListViewItem *)));
  KMHeaders *headers = static_cast<KMHeaders*>( listView );
  connect( headers, SIGNAL( itemAddedToListView( QListViewItem * ) ),
           this, SLOT( itemAdded( QListViewItem* ) ) );

}

HeaderListQuickSearch::~HeaderListQuickSearch()
{
}

bool HeaderListQuickSearch::itemMatches(const QListViewItem *item, const QString &s) const
{
  if ( mStatus != 0 ) {
    KMHeaders *headers = static_cast<KMHeaders*>( item->listView() );
    const KMMsgBase *msg = headers->getMsgBaseForItem( item );
    if ( !msg || ! ( msg->status() & mStatus ) )
      return false;
  }
  return KListViewSearchLine::itemMatches(item, s);
}

//-----------------------------------------------------------------------------
void HeaderListQuickSearch::reset()
{
  clear();
  mStatusCombo->setCurrentItem( 0 );
  slotStatusChanged( 0 );
}

void HeaderListQuickSearch::slotStatusChanged( int index )
{
  if ( index == 0 )
    mStatus = 0;
  else
    mStatus =
      KMSearchRuleStatus::statusFromEnglishName( KMail::StatusValues[ index - 1 ].text );
  updateSearch();
}

} // namespace KMail

#include "headerlistquicksearch.moc"
<commit_msg>Hook up an actually existing signal.<commit_after>/*
    This file is part of KMail, the KDE mail client.
    Copyright (c) 2004 Till Adam <adam@kde.org>

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

    KMail is distributed in the hope that it will be useful, but
    WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

    In addition, as a special exception, the copyright holders give
    permission to link the code of this program with any edition of
    the Qt library by Trolltech AS, Norway (or with modified versions
    of Qt that use the same license as Qt), and distribute linked
    combinations including the two.  You must obey the GNU General
    Public License in all respects for all of the code used other than
    Qt.  If you modify this file, you may extend this exception to
    your version of the file, but you are not obligated to do so.  If
    you do not wish to do so, delete this exception statement from
    your version.
*/
#include "headerlistquicksearch.h"

#include <qapplication.h>
#include <qlabel.h>
#include <qcombobox.h>
#include <qtimer.h>

#include <kaction.h>
#include <kiconloader.h>
#include <klistview.h>
#include <klocale.h>

#include "kmheaders.h"
#include "kmsearchpattern.h"

namespace KMail {

HeaderListQuickSearch::HeaderListQuickSearch( QWidget *parent,
                                              KListView *listView,
                                              KActionCollection *actionCollection,
                                              const char *name )
  : KListViewSearchLine(parent, listView, name), mStatusCombo(0), mStatus(0)
{
  KAction *resetQuickSearch = new KAction( i18n( "Reset Quick Search" ),
                                           QApplication::reverseLayout()
                                           ? "clear_left"
                                           : "locationbar_erase",
                                           0, this,
                                           SLOT( reset() ),
                                           actionCollection,
                                           "reset_quicksearch" );
  resetQuickSearch->plug( parent );
  resetQuickSearch->setWhatsThis( i18n( "Reset Quick Search\n"
                                        "Resets the quick search so that "
                                        "all messages are shown again." ) );

  QLabel *label = new QLabel( i18n("Stat&us:"), parent, "kde toolbar widget" );

  mStatusCombo = new QComboBox( parent, "quick search status combo box" );
  mStatusCombo->insertItem( SmallIcon( "run" ), i18n("Any Status") );
  for ( int i = 0; i < KMail::StatusValueCount; i++ )
    mStatusCombo->insertItem( SmallIcon( KMail::StatusValues[ i ].icon ), i18n( KMail::StatusValues[ i ].text ) );
  mStatusCombo->setCurrentItem( 0 );
  connect( mStatusCombo, SIGNAL ( activated( int ) ),
           this, SLOT( slotStatusChanged( int ) ) );

  label->setBuddy( mStatusCombo );

  /* Disable the signal connected by KListViewSearchLine since it will call
   * itemAdded during KMHeaders::readSortOrder() which will in turn result
   * in getMsgBaseForItem( item ) wanting to access items which are no longer
   * there. Rather rely on KMHeaders::msgAdded and its signal. */
  disconnect(listView, SIGNAL(itemAdded(QListViewItem *)),
             this, SLOT(itemAdded(QListViewItem *)));
  KMHeaders *headers = static_cast<KMHeaders*>( listView );
  connect( headers, SIGNAL( msgAddedToListView( KMail::HeaderItem* ) ),
           this, SLOT( itemAdded( QListViewItem* ) ) );

}

HeaderListQuickSearch::~HeaderListQuickSearch()
{
}

bool HeaderListQuickSearch::itemMatches(const QListViewItem *item, const QString &s) const
{
  if ( mStatus != 0 ) {
    KMHeaders *headers = static_cast<KMHeaders*>( item->listView() );
    const KMMsgBase *msg = headers->getMsgBaseForItem( item );
    if ( !msg || ! ( msg->status() & mStatus ) )
      return false;
  }
  return KListViewSearchLine::itemMatches(item, s);
}

//-----------------------------------------------------------------------------
void HeaderListQuickSearch::reset()
{
  clear();
  mStatusCombo->setCurrentItem( 0 );
  slotStatusChanged( 0 );
}

void HeaderListQuickSearch::slotStatusChanged( int index )
{
  if ( index == 0 )
    mStatus = 0;
  else
    mStatus =
      KMSearchRuleStatus::statusFromEnglishName( KMail::StatusValues[ index - 1 ].text );
  updateSearch();
}

} // namespace KMail

#include "headerlistquicksearch.moc"
<|endoftext|>


<commit_before>#pragma once

#include <vector>
#include <unordered_map>

using std::vector;
using std::unordered_map;

class Solution {
public:
  vector<int> twoSum(vector<int>& nums, int target) {

  }
};
<commit_msg>twosum solution<commit_after>#pragma once

#include <vector>
#include <unordered_map>

using std::vector;
using std::unordered_map;

class Solution {
public:
  vector<int> twoSum(const vector<int>& nums, const int target) {
    unordered_map<int, int> values;

    int delta;
    for (int idx = 0; idx < nums.size(); ++idx) {
      delta = target - nums[idx];

      // If condition is true, then we're done here
      if (values.find(delta) != values.cend()) {
        return vector<int>{values[delta], idx + 1};
      }

      values[nums[idx]] = idx + 1;
    }

    // Should not happen but it's here to satisfy the compiler
    return vector<int>{};
  }
};
<|endoftext|>


<commit_before>

//#if !defined(_MSC_VER) || defined(_M_AMD64)
//#define USE_PAGE_ALIGNED_ALLOCATION
//#endif

#ifdef USE_PAGE_ALIGNED_ALLOCATION

#ifdef _WIN32
#include <Windows.h>
#else
#include <pthread.h>
#include <unistd.h>
#include <malloc.h>
#include <cstring>
#endif
#endif

#include <nstd/Memory.h>
#include <nstd/Debug.h>

#ifdef USE_PAGE_ALIGNED_ALLOCATION

class _Memory
{
public:
    struct PageHeader
    {
      uint64_t checkValue;
      size_t size;
    };

    struct PageFooter
    {
      uint64_t checkValue;
    };

    struct FreePage : public PageHeader
    {
      FreePage* next;
    };

    static size_t pageSize;
    static FreePage* firstFreePage;
    static size_t freePageCount;
#ifdef _WIN32
    static CRITICAL_SECTION criticalSection; // TODO: is it possible to use atomic operations instead?
#else
    static pthread_mutex_t mutex;
#endif

    static const uint64_t headerCheckValue = 0x1235543212355432LL;
    static const uint64_t headerCheckValueUsed = 0x1235543212355433LL;
    static const uint64_t footerCheckValue = 0x1235543212355432LL;

    static const size_t maxFreePageCount = 64;

private:
    static _Memory memory;

    _Memory()
    {
#ifdef _WIN32
#ifndef __CYGWIN__
      InitializeCriticalSection(&criticalSection);
      SYSTEM_INFO si;
      GetSystemInfo(&si);
      pageSize = si.dwPageSize;
#endif
#else
      pageSize = sysconf(_SC_PAGESIZE);
#endif
    }
    ~_Memory()
    {
#ifdef _WIN32
      DeleteCriticalSection(&criticalSection);
#endif
    }
};

#ifdef _MSC_VER
#pragma warning(disable: 4073)
#pragma init_seg(lib)
_Memory _Memory::memory;
#else
_Memory _Memory::memory __attribute__ ((init_priority (101)));
#endif
size_t _Memory::pageSize;
_Memory::FreePage* _Memory::firstFreePage = 0;
size_t _Memory::freePageCount = 0;
#ifdef _WIN32
CRITICAL_SECTION _Memory::criticalSection;
#else
pthread_mutex_t _Memory::mutex = PTHREAD_MUTEX_INITIALIZER;
#endif

void_t* Memory::alloc(size_t size)
{
  size_t allocatedSize;
  return alloc(size, allocatedSize);
}

void_t* Memory::alloc(size_t size, size_t& rsize)
{
#ifdef __CYGWIN__
  if(_Memory::pageSize == 0)
  {
      InitializeCriticalSection(&_Memory::criticalSection);
      SYSTEM_INFO si;
      GetSystemInfo(&si);
      _Memory::pageSize = si.dwPageSize;
  }
#else
  ASSERT(_Memory::pageSize > 0);
#endif
  size_t minAllocSize = size + (sizeof(_Memory::PageHeader) + sizeof(_Memory::PageFooter));
  if(minAllocSize <= _Memory::pageSize)
  {
#ifdef _WIN32
    EnterCriticalSection(&_Memory::criticalSection);
#else
    pthread_mutex_lock(&_Memory::mutex);
#endif
    if(_Memory::firstFreePage)
    {
      _Memory::PageHeader* header = _Memory::firstFreePage;
      _Memory::firstFreePage = _Memory::firstFreePage->next;
      --_Memory::freePageCount;
#ifdef _WIN32
      LeaveCriticalSection(&_Memory::criticalSection);
#else
      pthread_mutex_unlock(&_Memory::mutex);
#endif
      rsize = _Memory::pageSize - (sizeof(_Memory::PageHeader) + sizeof(_Memory::PageFooter));
      header->checkValue = _Memory::headerCheckValue;
      return (uint8_t*)header + sizeof(_Memory::PageHeader);
    }
    else
    {
#ifdef _WIN32
      LeaveCriticalSection(&_Memory::criticalSection);
#else
      pthread_mutex_unlock(&_Memory::mutex);
#endif
    }
  }
  size_t pageCount = (minAllocSize + _Memory::pageSize - 1) / _Memory::pageSize;
  size_t allocSize = pageCount * _Memory::pageSize;

  _Memory::PageHeader* header;
#ifdef _WIN32
  header = (_Memory::PageHeader*)VirtualAlloc(NULL, allocSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
#else
  header = (_Memory::PageHeader*)memalign(_Memory::pageSize, allocSize);
#endif
  if(!header) // out of memory?
  {
    Debug::printf(_T("Memory::alloc: error: Could not allocate %llu pages.\n"), (uint64_t)pageCount); TRAP();
    do // wait and try again...
    {
#ifdef _WIN32
      Sleep(5000);
      header = (_Memory::PageHeader*)VirtualAlloc(NULL, allocSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
#else
      sleep(5);
      header = (_Memory::PageHeader*)memalign(_Memory::pageSize, allocSize);
#endif
    } while(!header);
  }
  _Memory::PageFooter* footer = (_Memory::PageFooter*)((uint8_t*)header + allocSize - sizeof(_Memory::PageFooter));
  header->size = allocSize;
  header->checkValue = _Memory::headerCheckValue;
  footer->checkValue = _Memory::footerCheckValue;
  rsize = allocSize - (sizeof(_Memory::PageHeader) + sizeof(_Memory::PageFooter));
  return (void_t*)((uint8_t*)header + sizeof(_Memory::PageHeader));
}

size_t Memory::size(void_t* buffer)
{
  if(!buffer) return 0;
  _Memory::PageHeader* header = (_Memory::PageHeader*)((uint8_t*)buffer - sizeof(_Memory::PageHeader));
  if(header->checkValue != _Memory::headerCheckValue)
  {
    if(header->checkValue == _Memory::headerCheckValueUsed)
    {
      Debug::print(_T("Memory::size: error: The passed buffer was freed.\n")); TRAP();
      return 0;
    }
    Debug::print(_T("Memory::size: error: The passed buffer is invalid or corrupted.\n")); TRAP();
    return 0;
  }
  return header->size - (sizeof(_Memory::PageHeader) + sizeof(_Memory::PageFooter));
}
/*
size_t Memory::pageSize()
{
  return _Memory::pageSize;
}
*/
void_t Memory::free(void_t* buffer)
{
  if(!buffer) return;
  _Memory::PageHeader* header = (_Memory::PageHeader*)((uint8_t*)buffer - sizeof(_Memory::PageHeader));
  if(header->checkValue != _Memory::headerCheckValue)
  {
    if(header->checkValue == _Memory::headerCheckValueUsed)
    {
      Debug::print(_T("Memory::free: error: The passed buffer was already freed.\n")); TRAP();
      return;
    }
    Debug::print(_T("Memory::free: error: The passed buffer is invalid or corrupted.\n")); TRAP();
    return;
  }
  _Memory::PageFooter* footer = (_Memory::PageFooter*)((uint8_t*)header + header->size - sizeof(_Memory::PageFooter));
  if(footer->checkValue != _Memory::footerCheckValue)
  {
    Debug::print(_T("Memory::free: error: The passed buffer is corrupted.\n")); TRAP(); // buffer overrun?
    footer->checkValue = _Memory::footerCheckValue;
  }

  if(header->size > _Memory::pageSize || _Memory::freePageCount >= _Memory::maxFreePageCount)
  {
#ifdef _WIN32
    VERIFY(VirtualFree(header, 0, MEM_RELEASE));
#else
    ::free(header);
#endif
    return;
  }

  header->checkValue = _Memory::headerCheckValueUsed;
  ((_Memory::FreePage*)header)->next = 0;

#ifdef _WIN32
  EnterCriticalSection(&_Memory::criticalSection);
#else
  pthread_mutex_lock(&_Memory::mutex);
#endif
  ((_Memory::FreePage*)header)->next = _Memory::firstFreePage;
  _Memory::firstFreePage = (_Memory::FreePage*)header;
  ++_Memory::freePageCount;
#ifdef _WIN32
  LeaveCriticalSection(&_Memory::criticalSection);
#else
  pthread_mutex_unlock(&_Memory::mutex);
#endif
}

void_t* operator new(size_t size)
{
  size_t allocatedSize;
  return Memory::alloc(size, allocatedSize);
}

void_t* operator new [](size_t size)
{
  size_t allocatedSize;
  return Memory::alloc(size, allocatedSize);
}

void_t operator delete(void_t* buffer)
{
  Memory::free(buffer);
}

void_t operator delete[](void_t* buffer)
{
  Memory::free(buffer);
}

#else // !USE_PAGE_ALIGNED_ALLOCATION

#include <Windows.h>

class _Memory
{
public:
    struct PageHeader
    {
      uint64_t checkValue;
      size_t size;
    };

    struct PageFooter
    {
      uint64_t checkValue;
    };

    struct FreePage : public PageHeader
    {
      FreePage* next;
    };

    static const uint64_t headerCheckValue = 0x1235543212355432LL;
    static const uint64_t headerCheckValueUsed = 0x1235543212355433LL;
    static const uint64_t footerCheckValue = 0x1235543212355432LL;

#ifdef _WIN32
    static HANDLE processHeap;
#endif
private:
    static _Memory memory;

    _Memory()
    {
#ifdef _WIN32
      processHeap = GetProcessHeap();
#endif
    }
};

#ifdef _MSC_VER
#pragma warning(disable: 4073)
#pragma init_seg(lib)
_Memory _Memory::memory;
#else
_Memory _Memory::memory __attribute__ ((init_priority (101)));
#endif
#ifdef _WIN32
HANDLE _Memory::processHeap = 0;
#endif

void_t* Memory::alloc(size_t minSize, size_t& rsize)
{
#ifdef _WIN32
  ASSERT(_Memory::processHeap);
#endif
  size_t minAllocSize = minSize + (sizeof(_Memory::PageHeader) + sizeof(_Memory::PageFooter));
  _Memory::PageHeader* header;
#ifdef _WIN32
  header = (_Memory::PageHeader*)HeapAlloc(_Memory::processHeap, 0, minAllocSize);
#else
  header = (_Memory::PageHeader*)malloc(minAllocSize);
#endif
  if(!header) // out of memory?
  {
    Debug::printf(_T("Memory::alloc: error: Could not allocate %llu bytes.\n"), (uint64_t)minAllocSize); TRAP();
    do // wait and try again...
    {
      Sleep(5000);
#ifdef _WIN32
      header = (_Memory::PageHeader*)HeapAlloc(_Memory::processHeap, 0, minAllocSize);
#else
      header = (_Memory::PageHeader*)malloc(minAllocSize);
#endif
    } while(!header);
  }
  size_t allocSize;
#ifdef _WIN32
  allocSize = HeapSize(_Memory::processHeap, 0, header);
#else
  allocSize = malloc_usable_size(header);
#endif
  _Memory::PageFooter* footer = (_Memory::PageFooter*)((uint8_t*)header + allocSize - sizeof(_Memory::PageFooter));
  header->size = allocSize;
  header->checkValue = _Memory::headerCheckValue;
  footer->checkValue = _Memory::footerCheckValue;
  rsize = allocSize - (sizeof(_Memory::PageHeader) + sizeof(_Memory::PageFooter));
  return (void_t*)((uint8_t*)header + sizeof(_Memory::PageHeader));
}

void_t* Memory::alloc(size_t size)
{
  size_t allocatedSize;
  return alloc(size, allocatedSize);
}

size_t Memory::size(void_t* buffer)
{
  if(!buffer) return 0;
  _Memory::PageHeader* header = (_Memory::PageHeader*)((uint8_t*)buffer - sizeof(_Memory::PageHeader));
  if(header->checkValue != _Memory::headerCheckValue)
  {
    if(header->checkValue == _Memory::headerCheckValueUsed)
    {
      Debug::print(_T("Memory::size: error: The passed buffer was freed.\n")); TRAP();
      return 0;
    }
    Debug::print(_T("Memory::size: error: The passed buffer is invalid or corrupted.\n")); TRAP();
    return 0;
  }
  return header->size - (sizeof(_Memory::PageHeader) + sizeof(_Memory::PageFooter));
}

void_t Memory::free(void_t* buffer)
{
  if(!buffer) return;
  _Memory::PageHeader* header = (_Memory::PageHeader*)((uint8_t*)buffer - sizeof(_Memory::PageHeader));
  if(header->checkValue != _Memory::headerCheckValue)
  {
    if(header->checkValue == _Memory::headerCheckValueUsed)
    {
      Debug::print(_T("Memory::free: error: The passed buffer was already freed.\n")); TRAP();
      return;
    }
    Debug::print(_T("Memory::free: error: The passed buffer is invalid or corrupted.\n")); TRAP();
    return;
  }
  _Memory::PageFooter* footer = (_Memory::PageFooter*)((uint8_t*)header + header->size - sizeof(_Memory::PageFooter));
  if(footer->checkValue != _Memory::footerCheckValue)
  {
    Debug::print(_T("Memory::free: error: The passed buffer is corrupted.\n")); TRAP(); // buffer overrun?
    footer->checkValue = _Memory::footerCheckValue;
  }
#ifdef _WIN32
  VERIFY(HeapFree(_Memory::processHeap, 0, header));
#else
  free(header);
#endif
}

void_t* operator new(size_t size)
{
  size_t allocatedSize;
  return Memory::alloc(size, allocatedSize);
}

void_t* operator new [](size_t size)
{
  size_t allocatedSize;
  return Memory::alloc(size, allocatedSize);
}

void_t operator delete(void_t* buffer)
{
  Memory::free(buffer);
}

void_t operator delete[](void_t* buffer)
{
  Memory::free(buffer);
}

#endif // !USE_PAGE_ALIGNED_ALLOCATION

void_t Memory::copy(void_t* dest, const void_t* src, size_t length)
{
#ifdef _WIN32
  CopyMemory(dest, src, length);
#else
  memcpy(dest, src, length);
#endif
}

void_t Memory::move(void_t* dest, const void_t* src, size_t length)
{
#ifdef _WIN32
  MoveMemory(dest, src, length);
#else
  memmove(dest, src, length);
#endif
}

void_t Memory::fill(void_t* buffer, byte_t value, size_t size)
{
#ifdef _WIN32
  FillMemory(buffer, size, value);
#else
  memset(buffer, value, size);
#endif
}

void_t Memory::zero(void_t* buffer, size_t size)
{
#ifdef _WIN32
  ZeroMemory(buffer, size);
#else
  memset(buffer, 0, size);
#endif
}

int_t Memory::compare(const void_t* ptr1, const void_t* ptr2, size_t count)
{
  return memcmp(ptr1, ptr2, count);
}
<commit_msg>Memory: Fix Linux compilation errors<commit_after>

//#if !defined(_MSC_VER) || defined(_M_AMD64)
//#define USE_PAGE_ALIGNED_ALLOCATION
//#endif

#ifdef USE_PAGE_ALIGNED_ALLOCATION

#ifdef _WIN32
#include <Windows.h>
#else
#include <pthread.h>
#include <unistd.h>
#include <malloc.h>
#include <cstring>
#endif
#endif

#include <nstd/Memory.h>
#include <nstd/Debug.h>

#ifdef USE_PAGE_ALIGNED_ALLOCATION

class _Memory
{
public:
    struct PageHeader
    {
      uint64_t checkValue;
      size_t size;
    };

    struct PageFooter
    {
      uint64_t checkValue;
    };

    struct FreePage : public PageHeader
    {
      FreePage* next;
    };

    static size_t pageSize;
    static FreePage* firstFreePage;
    static size_t freePageCount;
#ifdef _WIN32
    static CRITICAL_SECTION criticalSection; // TODO: is it possible to use atomic operations instead?
#else
    static pthread_mutex_t mutex;
#endif

    static const uint64_t headerCheckValue = 0x1235543212355432LL;
    static const uint64_t headerCheckValueUsed = 0x1235543212355433LL;
    static const uint64_t footerCheckValue = 0x1235543212355432LL;

    static const size_t maxFreePageCount = 64;

private:
    static _Memory memory;

    _Memory()
    {
#ifdef _WIN32
#ifndef __CYGWIN__
      InitializeCriticalSection(&criticalSection);
      SYSTEM_INFO si;
      GetSystemInfo(&si);
      pageSize = si.dwPageSize;
#endif
#else
      pageSize = sysconf(_SC_PAGESIZE);
#endif
    }
    ~_Memory()
    {
#ifdef _WIN32
      DeleteCriticalSection(&criticalSection);
#endif
    }
};

#ifdef _MSC_VER
#pragma warning(disable: 4073)
#pragma init_seg(lib)
_Memory _Memory::memory;
#else
_Memory _Memory::memory __attribute__ ((init_priority (101)));
#endif
size_t _Memory::pageSize;
_Memory::FreePage* _Memory::firstFreePage = 0;
size_t _Memory::freePageCount = 0;
#ifdef _WIN32
CRITICAL_SECTION _Memory::criticalSection;
#else
pthread_mutex_t _Memory::mutex = PTHREAD_MUTEX_INITIALIZER;
#endif

void_t* Memory::alloc(size_t size)
{
  size_t allocatedSize;
  return alloc(size, allocatedSize);
}

void_t* Memory::alloc(size_t size, size_t& rsize)
{
#ifdef __CYGWIN__
  if(_Memory::pageSize == 0)
  {
      InitializeCriticalSection(&_Memory::criticalSection);
      SYSTEM_INFO si;
      GetSystemInfo(&si);
      _Memory::pageSize = si.dwPageSize;
  }
#else
  ASSERT(_Memory::pageSize > 0);
#endif
  size_t minAllocSize = size + (sizeof(_Memory::PageHeader) + sizeof(_Memory::PageFooter));
  if(minAllocSize <= _Memory::pageSize)
  {
#ifdef _WIN32
    EnterCriticalSection(&_Memory::criticalSection);
#else
    pthread_mutex_lock(&_Memory::mutex);
#endif
    if(_Memory::firstFreePage)
    {
      _Memory::PageHeader* header = _Memory::firstFreePage;
      _Memory::firstFreePage = _Memory::firstFreePage->next;
      --_Memory::freePageCount;
#ifdef _WIN32
      LeaveCriticalSection(&_Memory::criticalSection);
#else
      pthread_mutex_unlock(&_Memory::mutex);
#endif
      rsize = _Memory::pageSize - (sizeof(_Memory::PageHeader) + sizeof(_Memory::PageFooter));
      header->checkValue = _Memory::headerCheckValue;
      return (uint8_t*)header + sizeof(_Memory::PageHeader);
    }
    else
    {
#ifdef _WIN32
      LeaveCriticalSection(&_Memory::criticalSection);
#else
      pthread_mutex_unlock(&_Memory::mutex);
#endif
    }
  }
  size_t pageCount = (minAllocSize + _Memory::pageSize - 1) / _Memory::pageSize;
  size_t allocSize = pageCount * _Memory::pageSize;

  _Memory::PageHeader* header;
#ifdef _WIN32
  header = (_Memory::PageHeader*)VirtualAlloc(NULL, allocSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
#else
  header = (_Memory::PageHeader*)memalign(_Memory::pageSize, allocSize);
#endif
  if(!header) // out of memory?
  {
    Debug::printf(_T("Memory::alloc: error: Could not allocate %llu pages.\n"), (uint64_t)pageCount); TRAP();
    do // wait and try again...
    {
#ifdef _WIN32
      Sleep(5000);
      header = (_Memory::PageHeader*)VirtualAlloc(NULL, allocSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
#else
      sleep(5);
      header = (_Memory::PageHeader*)memalign(_Memory::pageSize, allocSize);
#endif
    } while(!header);
  }
  _Memory::PageFooter* footer = (_Memory::PageFooter*)((uint8_t*)header + allocSize - sizeof(_Memory::PageFooter));
  header->size = allocSize;
  header->checkValue = _Memory::headerCheckValue;
  footer->checkValue = _Memory::footerCheckValue;
  rsize = allocSize - (sizeof(_Memory::PageHeader) + sizeof(_Memory::PageFooter));
  return (void_t*)((uint8_t*)header + sizeof(_Memory::PageHeader));
}

size_t Memory::size(void_t* buffer)
{
  if(!buffer) return 0;
  _Memory::PageHeader* header = (_Memory::PageHeader*)((uint8_t*)buffer - sizeof(_Memory::PageHeader));
  if(header->checkValue != _Memory::headerCheckValue)
  {
    if(header->checkValue == _Memory::headerCheckValueUsed)
    {
      Debug::print(_T("Memory::size: error: The passed buffer was freed.\n")); TRAP();
      return 0;
    }
    Debug::print(_T("Memory::size: error: The passed buffer is invalid or corrupted.\n")); TRAP();
    return 0;
  }
  return header->size - (sizeof(_Memory::PageHeader) + sizeof(_Memory::PageFooter));
}
/*
size_t Memory::pageSize()
{
  return _Memory::pageSize;
}
*/
void_t Memory::free(void_t* buffer)
{
  if(!buffer) return;
  _Memory::PageHeader* header = (_Memory::PageHeader*)((uint8_t*)buffer - sizeof(_Memory::PageHeader));
  if(header->checkValue != _Memory::headerCheckValue)
  {
    if(header->checkValue == _Memory::headerCheckValueUsed)
    {
      Debug::print(_T("Memory::free: error: The passed buffer was already freed.\n")); TRAP();
      return;
    }
    Debug::print(_T("Memory::free: error: The passed buffer is invalid or corrupted.\n")); TRAP();
    return;
  }
  _Memory::PageFooter* footer = (_Memory::PageFooter*)((uint8_t*)header + header->size - sizeof(_Memory::PageFooter));
  if(footer->checkValue != _Memory::footerCheckValue)
  {
    Debug::print(_T("Memory::free: error: The passed buffer is corrupted.\n")); TRAP(); // buffer overrun?
    footer->checkValue = _Memory::footerCheckValue;
  }

  if(header->size > _Memory::pageSize || _Memory::freePageCount >= _Memory::maxFreePageCount)
  {
#ifdef _WIN32
    VERIFY(VirtualFree(header, 0, MEM_RELEASE));
#else
    ::free(header);
#endif
    return;
  }

  header->checkValue = _Memory::headerCheckValueUsed;
  ((_Memory::FreePage*)header)->next = 0;

#ifdef _WIN32
  EnterCriticalSection(&_Memory::criticalSection);
#else
  pthread_mutex_lock(&_Memory::mutex);
#endif
  ((_Memory::FreePage*)header)->next = _Memory::firstFreePage;
  _Memory::firstFreePage = (_Memory::FreePage*)header;
  ++_Memory::freePageCount;
#ifdef _WIN32
  LeaveCriticalSection(&_Memory::criticalSection);
#else
  pthread_mutex_unlock(&_Memory::mutex);
#endif
}

void_t* operator new(size_t size)
{
  size_t allocatedSize;
  return Memory::alloc(size, allocatedSize);
}

void_t* operator new [](size_t size)
{
  size_t allocatedSize;
  return Memory::alloc(size, allocatedSize);
}

void_t operator delete(void_t* buffer)
{
  Memory::free(buffer);
}

void_t operator delete[](void_t* buffer)
{
  Memory::free(buffer);
}

#else // !USE_PAGE_ALIGNED_ALLOCATION

#ifdef _WIN32
#include <Windows.h>
#else
#include <cstdlib>
#include <malloc.h>
#include <unistd.h>
#include <cstring>
#endif

class _Memory
{
public:
    struct PageHeader
    {
      uint64_t checkValue;
      size_t size;
    };

    struct PageFooter
    {
      uint64_t checkValue;
    };

    struct FreePage : public PageHeader
    {
      FreePage* next;
    };

    static const uint64_t headerCheckValue = 0x1235543212355432LL;
    static const uint64_t headerCheckValueUsed = 0x1235543212355433LL;
    static const uint64_t footerCheckValue = 0x1235543212355432LL;

#ifdef _WIN32
    static HANDLE processHeap;
#endif
private:
    static _Memory memory;

    _Memory()
    {
#ifdef _WIN32
      processHeap = GetProcessHeap();
#endif
    }
};

#ifdef _MSC_VER
#pragma warning(disable: 4073)
#pragma init_seg(lib)
_Memory _Memory::memory;
#else
_Memory _Memory::memory __attribute__ ((init_priority (101)));
#endif
#ifdef _WIN32
HANDLE _Memory::processHeap = 0;
#endif

void_t* Memory::alloc(size_t minSize, size_t& rsize)
{
#ifdef _WIN32
  ASSERT(_Memory::processHeap);
#endif
  size_t minAllocSize = minSize + (sizeof(_Memory::PageHeader) + sizeof(_Memory::PageFooter));
  _Memory::PageHeader* header;
#ifdef _WIN32
  header = (_Memory::PageHeader*)HeapAlloc(_Memory::processHeap, 0, minAllocSize);
#else
  header = (_Memory::PageHeader*)malloc(minAllocSize);
#endif
  if(!header) // out of memory?
  {
    Debug::printf(_T("Memory::alloc: error: Could not allocate %llu bytes.\n"), (uint64_t)minAllocSize); TRAP();
    do // wait and try again...
    {
#ifdef _WIN32
      Sleep(5000);
      header = (_Memory::PageHeader*)HeapAlloc(_Memory::processHeap, 0, minAllocSize);
#else
      sleep(5);
      header = (_Memory::PageHeader*)malloc(minAllocSize);
#endif
    } while(!header);
  }
  size_t allocSize;
#ifdef _WIN32
  allocSize = HeapSize(_Memory::processHeap, 0, header);
#else
  allocSize = malloc_usable_size(header);
#endif
  _Memory::PageFooter* footer = (_Memory::PageFooter*)((uint8_t*)header + allocSize - sizeof(_Memory::PageFooter));
  header->size = allocSize;
  header->checkValue = _Memory::headerCheckValue;
  footer->checkValue = _Memory::footerCheckValue;
  rsize = allocSize - (sizeof(_Memory::PageHeader) + sizeof(_Memory::PageFooter));
  return (void_t*)((uint8_t*)header + sizeof(_Memory::PageHeader));
}

void_t* Memory::alloc(size_t size)
{
  size_t allocatedSize;
  return alloc(size, allocatedSize);
}

size_t Memory::size(void_t* buffer)
{
  if(!buffer) return 0;
  _Memory::PageHeader* header = (_Memory::PageHeader*)((uint8_t*)buffer - sizeof(_Memory::PageHeader));
  if(header->checkValue != _Memory::headerCheckValue)
  {
    if(header->checkValue == _Memory::headerCheckValueUsed)
    {
      Debug::print(_T("Memory::size: error: The passed buffer was freed.\n")); TRAP();
      return 0;
    }
    Debug::print(_T("Memory::size: error: The passed buffer is invalid or corrupted.\n")); TRAP();
    return 0;
  }
  return header->size - (sizeof(_Memory::PageHeader) + sizeof(_Memory::PageFooter));
}

void_t Memory::free(void_t* buffer)
{
  if(!buffer) return;
  _Memory::PageHeader* header = (_Memory::PageHeader*)((uint8_t*)buffer - sizeof(_Memory::PageHeader));
  if(header->checkValue != _Memory::headerCheckValue)
  {
    if(header->checkValue == _Memory::headerCheckValueUsed)
    {
      Debug::print(_T("Memory::free: error: The passed buffer was already freed.\n")); TRAP();
      return;
    }
    Debug::print(_T("Memory::free: error: The passed buffer is invalid or corrupted.\n")); TRAP();
    return;
  }
  _Memory::PageFooter* footer = (_Memory::PageFooter*)((uint8_t*)header + header->size - sizeof(_Memory::PageFooter));
  if(footer->checkValue != _Memory::footerCheckValue)
  {
    Debug::print(_T("Memory::free: error: The passed buffer is corrupted.\n")); TRAP(); // buffer overrun?
    footer->checkValue = _Memory::footerCheckValue;
  }
#ifdef _WIN32
  VERIFY(HeapFree(_Memory::processHeap, 0, header));
#else
  free(header);
#endif
}

void_t* operator new(size_t size)
{
  size_t allocatedSize;
  return Memory::alloc(size, allocatedSize);
}

void_t* operator new [](size_t size)
{
  size_t allocatedSize;
  return Memory::alloc(size, allocatedSize);
}

void_t operator delete(void_t* buffer)
{
  Memory::free(buffer);
}

void_t operator delete[](void_t* buffer)
{
  Memory::free(buffer);
}

#endif // !USE_PAGE_ALIGNED_ALLOCATION

void_t Memory::copy(void_t* dest, const void_t* src, size_t length)
{
#ifdef _WIN32
  CopyMemory(dest, src, length);
#else
  memcpy(dest, src, length);
#endif
}

void_t Memory::move(void_t* dest, const void_t* src, size_t length)
{
#ifdef _WIN32
  MoveMemory(dest, src, length);
#else
  memmove(dest, src, length);
#endif
}

void_t Memory::fill(void_t* buffer, byte_t value, size_t size)
{
#ifdef _WIN32
  FillMemory(buffer, size, value);
#else
  memset(buffer, value, size);
#endif
}

void_t Memory::zero(void_t* buffer, size_t size)
{
#ifdef _WIN32
  ZeroMemory(buffer, size);
#else
  memset(buffer, 0, size);
#endif
}

int_t Memory::compare(const void_t* ptr1, const void_t* ptr2, size_t count)
{
  return memcmp(ptr1, ptr2, count);
}
<|endoftext|>


<commit_before>#pragma once

#include <fstream>
#include <iostream>
#include <vector>

#include "cppjit/cppjit.hpp"
#include "cppjit/function_traits.hpp"

#include "abstract_kernel.hpp"
#include "autotune_exception.hpp"
#include "continuous_parameter.hpp"
#include "fixed_set_parameter.hpp"
#include "parameter_value_set.hpp"

namespace autotune {

// base template for the following specialization
// required to do the pack-matching in the specialization
// (required for forwardings the "Args" argument)
template <typename... Args> struct cppjit_kernel;

template <typename R, typename... Args>
class cppjit_kernel<R, cppjit::detail::pack<Args...>>
    : public abstract_kernel<R, cppjit::detail::pack<Args...>> {
private:
  cppjit::kernel<R, cppjit::detail::pack<Args...>> internal_kernel;
  void (*set_meta_pointer)(thread_meta);

public:
  cppjit_kernel(const std::string &kernel_name)
      : abstract_kernel<R, cppjit::detail::pack<Args...>>(kernel_name),
        internal_kernel(kernel_name), set_meta_pointer(nullptr) {}

  cppjit_kernel(const std::string &kernel_name,
                const std::string &kernel_src_dir)
      : abstract_kernel<R, cppjit::detail::pack<Args...>>(kernel_name),
        internal_kernel(kernel_name, kernel_src_dir),
        set_meta_pointer(nullptr) {}

  cppjit_kernel(cppjit_kernel<R, cppjit::detail::pack<Args...>> &other)
      : abstract_kernel<R, cppjit::detail::pack<Args...>>(other),
        internal_kernel(other.internal_kernel), set_meta_pointer(nullptr) {}

  void set_source_inline(const std::string &source_) {
    internal_kernel.set_source_inline(source_);
  }

  void set_source_dir(const std::string &source_dir_) {
    internal_kernel.set_source_dir(source_dir_);
  }

  bool has_source() { return internal_kernel.has_source(); }

  bool has_inline_source() { return internal_kernel.has_inline_source(); }

  void *load_other_symbol(const std::string &symbol_name) {
    auto builder = internal_kernel.get_builder();
    void *uncasted_function = builder->load_other_symbol(symbol_name);
    if (uncasted_function == nullptr) {
      throw autotune_exception(std::string("unable to load symbol: \"") +
                               symbol_name + std::string("\""));
    }
    return uncasted_function;
  }

  virtual bool is_valid_parameter_combination() override {
    auto builder = internal_kernel.get_builder();
    void *uncasted_function =
        builder->load_other_symbol("is_valid_parameter_combination");
    if (uncasted_function == nullptr) {
      return true;
    }
    bool (*decider_pointer)() =
        reinterpret_cast<decltype(decider_pointer)>(uncasted_function);
    return decider_pointer();
  }

  virtual R operator()(Args... args) override {
    if (!is_compiled()) {
      compile();
    }
    return internal_kernel(std::forward<Args>(args)...);
  }

  // very useful overload for the kernel tuners, so that they don't have to
  // track source-related arguments
  void compile(const std::string &source_dir) {
    create_parameter_file();
    this->parameters_changed = false;
    internal_kernel.compile(source_dir);
  }

  void compile_inline(const std::string &source) {
    create_parameter_file();
    this->parameters_changed = false;
    internal_kernel.compile_inline(source);
  }

  virtual void compile() override {
    create_parameter_file();
    this->parameters_changed = false;
    internal_kernel.compile();
  }

  virtual bool is_compiled() override {
    std::cout << "parameters_changed: " << this->parameters_changed
              << std::endl;
    std::cout << "internal_kernel.is_compiled(): "
              << internal_kernel.is_compiled() << std::endl;
    return !this->parameters_changed && internal_kernel.is_compiled();
  }

  // TODO: add parameter_set argument?
  virtual void create_parameter_file() override {
    if (!has_source() || has_inline_source()) {
      throw autotune_exception("no source available");
    }

    std::shared_ptr<cppjit::builder::builder> builder = get_builder();
    // needed, otherwise cannot create parameter file at the right place
    builder->make_compile_dir();
    const std::string &compile_dir = builder->get_compile_dir();
    std::ofstream parameter_file(compile_dir + "parameters.hpp");
    parameter_file << "#pragma once" << std::endl;
    parameter_file << "#include \"autotune_kernel.hpp\"" << std::endl;

    for (auto &p : this->parameter_values) {
      parameter_file << "#define " << p.first << " " << p.second << "\n";
    }
    parameter_file.close();
    std::ofstream autotune_kernel_file(compile_dir + "autotune_kernel.hpp");
    autotune_kernel_file << "#pragma once" << std::endl;
    autotune_kernel_file << "#include \"cppjit_kernel.hpp\"" << std::endl;
    autotune_kernel_file << "#include \"parameters.hpp\"" << std::endl;
    autotune_kernel_file << "#define AUTOTUNE_EXPORT CPPJIT_EXPORT"
                         << std::endl;
    autotune_kernel_file.close();
  }

  void set_builder(std::shared_ptr<cppjit::builder::builder> builder_) {
    internal_kernel.set_builder(builder_);
  }

  std::shared_ptr<cppjit::builder::builder> get_builder() {
    return internal_kernel.get_builder();
  }

  template <typename builder_class> builder_class &get_builder() {
    return internal_kernel.template get_builder<builder_class>();
  }

  void clear() {
    abstract_kernel<R, cppjit::detail::pack<Args...>>::clear();
    internal_kernel.clear();
    this->verbose = false;
  }

  virtual void set_verbose(bool verbose) override {
    this->verbose = verbose;
    internal_kernel.set_verbose(verbose);
  }

  virtual abstract_kernel<R, cppjit::detail::pack<Args...>> *clone() override {
    return new cppjit_kernel<R, cppjit::detail::pack<Args...>>(*this);
  }

  virtual void set_meta(thread_meta meta) override {
    if (!is_compiled()) {
      compile();
    }
    if (!set_meta_pointer) {
      void *uncasted_function = load_other_symbol("set_meta");
      set_meta_pointer =
          reinterpret_cast<decltype(set_meta_pointer)>(uncasted_function);
    }
    std::cout << "set_meta pointer: "
              << reinterpret_cast<void *>(set_meta_pointer) << std::endl;
    set_meta_pointer(meta);
  };

  virtual thread_meta get_meta() {
    throw autotune_exception("not available for cppjit kernel");
  }
};
} // namespace autotune

#define AUTOTUNE_DECLARE_KERNEL(kernel_signature, kernel_name)                 \
  namespace autotune {                                                         \
  extern cppjit_kernel<                                                        \
      cppjit::detail::function_traits<kernel_signature>::return_type,          \
      cppjit::detail::function_traits<kernel_signature>::args_type>            \
      kernel_name;                                                             \
  } /* namespace autotune */

#define AUTOTUNE_DEFINE_KERNEL_NO_SRC(kernel_signature, kernel_name)           \
  namespace autotune {                                                         \
  cppjit_kernel<                                                               \
      cppjit::detail::function_traits<kernel_signature>::return_type,          \
      cppjit::detail::function_traits<kernel_signature>::args_type>            \
      kernel_name(#kernel_name);                                               \
  } /* namespace autotune */

#define AUTOTUNE_DEFINE_KERNEL(kernel_signature, kernel_name, kernel_src_dir)  \
  namespace autotune {                                                         \
  cppjit_kernel<                                                               \
      cppjit::detail::function_traits<kernel_signature>::return_type,          \
      cppjit::detail::function_traits<kernel_signature>::args_type>            \
      kernel_name(#kernel_name, kernel_src_dir);                               \
  } /* namespace autotune */

#define AUTOTUNE_KERNEL_NO_SRC(signature, kernel_name)                         \
  AUTOTUNE_DECLARE_KERNEL(signature, kernel_name)                              \
  AUTOTUNE_DEFINE_KERNEL_NO_SRC(signature, kernel_name)

#define AUTOTUNE_KERNEL(signature, kernel_name, kernel_src_dir)                \
  AUTOTUNE_DECLARE_KERNEL(signature, kernel_name)                              \
  AUTOTUNE_DEFINE_KERNEL(signature, kernel_name, kernel_src_dir)
<commit_msg>added bit of documentation<commit_after>#pragma once

#include <fstream>
#include <iostream>
#include <vector>

#include "cppjit/cppjit.hpp"
#include "cppjit/function_traits.hpp"

#include "abstract_kernel.hpp"
#include "autotune_exception.hpp"
#include "continuous_parameter.hpp"
#include "fixed_set_parameter.hpp"
#include "parameter_value_set.hpp"

namespace autotune {

// base template for the following specialization
// required to do the pack-matching in the specialization
// (required for forwardings the "Args" argument)
template <typename... Args> struct cppjit_kernel;

template <typename R, typename... Args>
class cppjit_kernel<R, cppjit::detail::pack<Args...>>
    : public abstract_kernel<R, cppjit::detail::pack<Args...>> {
private:
  cppjit::kernel<R, cppjit::detail::pack<Args...>> internal_kernel;
  void (*set_meta_pointer)(thread_meta);

public:
  cppjit_kernel(const std::string &kernel_name)
      : abstract_kernel<R, cppjit::detail::pack<Args...>>(kernel_name),
        internal_kernel(kernel_name), set_meta_pointer(nullptr) {}

  cppjit_kernel(const std::string &kernel_name,
                const std::string &kernel_src_dir)
      : abstract_kernel<R, cppjit::detail::pack<Args...>>(kernel_name),
        internal_kernel(kernel_name, kernel_src_dir),
        set_meta_pointer(nullptr) {}

  cppjit_kernel(cppjit_kernel<R, cppjit::detail::pack<Args...>> &other)
      : abstract_kernel<R, cppjit::detail::pack<Args...>>(other),
        internal_kernel(other.internal_kernel), set_meta_pointer(nullptr) {}

  void set_source_inline(const std::string &source_) {
    internal_kernel.set_source_inline(source_);
  }

  void set_source_dir(const std::string &source_dir_) {
    internal_kernel.set_source_dir(source_dir_);
  }

  bool has_source() { return internal_kernel.has_source(); }

  bool has_inline_source() { return internal_kernel.has_inline_source(); }

  void *load_other_symbol(const std::string &symbol_name) {
    auto builder = internal_kernel.get_builder();
    void *uncasted_function = builder->load_other_symbol(symbol_name);
    if (uncasted_function == nullptr) {
      throw autotune_exception(std::string("unable to load symbol: \"") +
                               symbol_name + std::string("\""));
    }
    return uncasted_function;
  }

  virtual bool is_valid_parameter_combination() override {
    auto builder = internal_kernel.get_builder();
    void *uncasted_function =
        builder->load_other_symbol("is_valid_parameter_combination");
    if (uncasted_function == nullptr) {
      return true;
    }
    bool (*decider_pointer)() =
        reinterpret_cast<decltype(decider_pointer)>(uncasted_function);
    return decider_pointer();
  }

  virtual R operator()(Args... args) override {
    if (!is_compiled()) {
      compile();
    }
    return internal_kernel(std::forward<Args>(args)...);
  }

  // very useful overload for the kernel tuners, so that they don't have to
  // track source-related arguments
  void compile(const std::string &source_dir) {
    create_parameter_file();
    this->parameters_changed = false;
    internal_kernel.compile(source_dir);
  }

  void compile_inline(const std::string &source) {
    create_parameter_file();
    this->parameters_changed = false;
    internal_kernel.compile_inline(source);
  }

  virtual void compile() override {
    create_parameter_file();
    this->parameters_changed = false;
    internal_kernel.compile();
  }

  virtual bool is_compiled() override {
    std::cout << "parameters_changed: " << this->parameters_changed
              << std::endl;
    std::cout << "internal_kernel.is_compiled(): "
              << internal_kernel.is_compiled() << std::endl;
    return !this->parameters_changed && internal_kernel.is_compiled();
  }

  // TODO: add parameter_set argument?
  virtual void create_parameter_file() override {
    if (!has_source() || has_inline_source()) {
      throw autotune_exception("no source available");
    }

    std::shared_ptr<cppjit::builder::builder> builder = get_builder();
    // needed, otherwise cannot create parameter file at the right place
    builder->make_compile_dir();
    const std::string &compile_dir = builder->get_compile_dir();
    std::ofstream parameter_file(compile_dir + "parameters.hpp");
    parameter_file << "#pragma once" << std::endl;
    parameter_file << "#include \"autotune_kernel.hpp\"" << std::endl;

    for (auto &p : this->parameter_values) {
      parameter_file << "#define " << p.first << " " << p.second << "\n";
    }
    parameter_file.close();
    std::ofstream autotune_kernel_file(compile_dir + "autotune_kernel.hpp");
    autotune_kernel_file << "#pragma once" << std::endl;
    autotune_kernel_file << "#include \"cppjit_kernel.hpp\"" << std::endl;
    autotune_kernel_file << "#include \"parameters.hpp\"" << std::endl;
    autotune_kernel_file << "#define AUTOTUNE_EXPORT CPPJIT_EXPORT"
                         << std::endl;
    autotune_kernel_file.close();
  }

  void set_builder(std::shared_ptr<cppjit::builder::builder> builder_) {
    internal_kernel.set_builder(builder_);
  }

  std::shared_ptr<cppjit::builder::builder> get_builder() {
    return internal_kernel.get_builder();
  }

  template <typename builder_class> builder_class &get_builder() {
    return internal_kernel.template get_builder<builder_class>();
  }

  void clear() {
    abstract_kernel<R, cppjit::detail::pack<Args...>>::clear();
    internal_kernel.clear();
    this->verbose = false;
  }

  virtual void set_verbose(bool verbose) override {
    this->verbose = verbose;
    internal_kernel.set_verbose(verbose);
  }

  virtual abstract_kernel<R, cppjit::detail::pack<Args...>> *clone() override {
    return new cppjit_kernel<R, cppjit::detail::pack<Args...>>(*this);
  }

  // important: will forget data in case of a recompile
  // due to data being stored within shared object which is unloaded and
  // replaced
  virtual void set_meta(thread_meta meta) override {
    if (!is_compiled()) {
      compile();
    }
    if (!set_meta_pointer) {
      void *uncasted_function = load_other_symbol("set_meta");
      set_meta_pointer =
          reinterpret_cast<decltype(set_meta_pointer)>(uncasted_function);
    }
    std::cout << "set_meta pointer: "
              << reinterpret_cast<void *>(set_meta_pointer) << std::endl;
    set_meta_pointer(meta);
  };

  virtual thread_meta get_meta() {
    throw autotune_exception("not available for cppjit kernel");
  }
};
} // namespace autotune

#define AUTOTUNE_DECLARE_KERNEL(kernel_signature, kernel_name)                 \
  namespace autotune {                                                         \
  extern cppjit_kernel<                                                        \
      cppjit::detail::function_traits<kernel_signature>::return_type,          \
      cppjit::detail::function_traits<kernel_signature>::args_type>            \
      kernel_name;                                                             \
  } /* namespace autotune */

#define AUTOTUNE_DEFINE_KERNEL_NO_SRC(kernel_signature, kernel_name)           \
  namespace autotune {                                                         \
  cppjit_kernel<                                                               \
      cppjit::detail::function_traits<kernel_signature>::return_type,          \
      cppjit::detail::function_traits<kernel_signature>::args_type>            \
      kernel_name(#kernel_name);                                               \
  } /* namespace autotune */

#define AUTOTUNE_DEFINE_KERNEL(kernel_signature, kernel_name, kernel_src_dir)  \
  namespace autotune {                                                         \
  cppjit_kernel<                                                               \
      cppjit::detail::function_traits<kernel_signature>::return_type,          \
      cppjit::detail::function_traits<kernel_signature>::args_type>            \
      kernel_name(#kernel_name, kernel_src_dir);                               \
  } /* namespace autotune */

#define AUTOTUNE_KERNEL_NO_SRC(signature, kernel_name)                         \
  AUTOTUNE_DECLARE_KERNEL(signature, kernel_name)                              \
  AUTOTUNE_DEFINE_KERNEL_NO_SRC(signature, kernel_name)

#define AUTOTUNE_KERNEL(signature, kernel_name, kernel_src_dir)                \
  AUTOTUNE_DECLARE_KERNEL(signature, kernel_name)                              \
  AUTOTUNE_DEFINE_KERNEL(signature, kernel_name, kernel_src_dir)
<|endoftext|>


<commit_before>/***************************************************************************
 *   Copyright (c) 2015 Eivind Kvedalen (eivind@kvedalen.name)             *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This file is based on the Qt spreadsheet example code.                *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2.1 of the License, or (at your option) any later version.    *
 *                                                                         *
 *   This library  is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"
#ifndef _PreComp_
#include <QItemDelegate>
#include <QLineEdit>
#endif

#include "SpreadsheetDelegate.h"
#include "LineEdit.h"
#include <App/DocumentObject.h>
#include <Mod/Spreadsheet/App/Sheet.h>
#include <Gui/ExpressionCompleter.h>

using namespace SpreadsheetGui;

SpreadsheetDelegate::SpreadsheetDelegate(Spreadsheet::Sheet * _sheet, QWidget *parent)
    : QItemDelegate(parent)
    , sheet(_sheet)
{
}

QWidget *SpreadsheetDelegate::createEditor(QWidget *parent,
                                          const QStyleOptionViewItem &,
                                          const QModelIndex &index) const
{
    SpreadsheetGui::LineEdit *editor = new SpreadsheetGui::LineEdit(parent);
    editor->setIndex(index);

    editor->setDocumentObject(sheet);
    // See https://forum.freecadweb.org/viewtopic.php?f=3&t=41694
    // It looks like the slot commitAndCloseEditor() is not needed any more and even
    // causes a crash when doing so because the LineEdit is still accessed after its destruction.
    //connect(editor, SIGNAL(returnPressed()), this, SLOT(commitAndCloseEditor()));
    return editor;
}

void SpreadsheetDelegate::commitAndCloseEditor()
{
    Gui::ExpressionLineEdit *editor = qobject_cast<Gui::ExpressionLineEdit *>(sender());
    if (editor->completerActive()) {
        editor->hideCompleter();
        return;
    }

    Q_EMIT commitData(editor);
    Q_EMIT closeEditor(editor);
}

void SpreadsheetDelegate::setEditorData(QWidget *editor,
    const QModelIndex &index) const
{
    QLineEdit *edit = qobject_cast<QLineEdit*>(editor);
    if (edit) {
        edit->setText(index.model()->data(index, Qt::EditRole).toString());
        return;
    }
}

void SpreadsheetDelegate::setModelData(QWidget *editor,
    QAbstractItemModel *model, const QModelIndex &index) const
{
    QLineEdit *edit = qobject_cast<QLineEdit *>(editor);
    if (edit) {
        model->setData(index, edit->text());
        return;
    }
}

QSize SpreadsheetDelegate::sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index) const
{
    Q_UNUSED(option);
    Q_UNUSED(index);
    return QSize();
}

#include "moc_SpreadsheetDelegate.cpp"

<commit_msg>Spreadsheet: [skip ci] fix regression when pressing Return/Enter when completion list is shown<commit_after>/***************************************************************************
 *   Copyright (c) 2015 Eivind Kvedalen (eivind@kvedalen.name)             *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This file is based on the Qt spreadsheet example code.                *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2.1 of the License, or (at your option) any later version.    *
 *                                                                         *
 *   This library  is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/

#include "PreCompiled.h"
#ifndef _PreComp_
#include <QItemDelegate>
#include <QLineEdit>
#endif

#include "SpreadsheetDelegate.h"
#include "LineEdit.h"
#include <App/DocumentObject.h>
#include <Mod/Spreadsheet/App/Sheet.h>
#include <Gui/ExpressionCompleter.h>

using namespace SpreadsheetGui;

SpreadsheetDelegate::SpreadsheetDelegate(Spreadsheet::Sheet * _sheet, QWidget *parent)
    : QItemDelegate(parent)
    , sheet(_sheet)
{
}

QWidget *SpreadsheetDelegate::createEditor(QWidget *parent,
                                          const QStyleOptionViewItem &,
                                          const QModelIndex &index) const
{
    SpreadsheetGui::LineEdit *editor = new SpreadsheetGui::LineEdit(parent);
    editor->setIndex(index);

    editor->setDocumentObject(sheet);
    connect(editor, SIGNAL(returnPressed()), this, SLOT(commitAndCloseEditor()));
    return editor;
}

void SpreadsheetDelegate::commitAndCloseEditor()
{
    Gui::ExpressionLineEdit *editor = qobject_cast<Gui::ExpressionLineEdit *>(sender());
    if (editor->completerActive()) {
        editor->hideCompleter();
        return;
    }

    // See https://forum.freecadweb.org/viewtopic.php?f=3&t=41694
    // It looks like the slot commitAndCloseEditor() is not needed any more and even
    // causes a crash when doing so because the LineEdit is still accessed after its destruction.
    //Q_EMIT commitData(editor);
    //Q_EMIT closeEditor(editor);
}

void SpreadsheetDelegate::setEditorData(QWidget *editor,
    const QModelIndex &index) const
{
    QLineEdit *edit = qobject_cast<QLineEdit*>(editor);
    if (edit) {
        edit->setText(index.model()->data(index, Qt::EditRole).toString());
        return;
    }
}

void SpreadsheetDelegate::setModelData(QWidget *editor,
    QAbstractItemModel *model, const QModelIndex &index) const
{
    QLineEdit *edit = qobject_cast<QLineEdit *>(editor);
    if (edit) {
        model->setData(index, edit->text());
        return;
    }
}

QSize SpreadsheetDelegate::sizeHint(const QStyleOptionViewItem & option, const QModelIndex & index) const
{
    Q_UNUSED(option);
    Q_UNUSED(index);
    return QSize();
}

#include "moc_SpreadsheetDelegate.cpp"

<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "internal/file.h"

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

#include <algorithm>
#include <cassert>
#include <cerrno>
#include <cstdlib>
#include <ios>
#include <iostream>
#include <memory>
#include <stdexcept>
#include <string>
#include <string_view>
#include <system_error>
#include <utility>

#include "absl/strings/string_view.h"

#include "internal/random.h"

namespace phst_rules_elisp {

file::file() { this->setp(put_.data(), put_.data() + put_.size()); }

file::file(std::string path, const file_mode mode) : file() {
  this->open(std::move(path), mode);
}

file::~file() noexcept {
  if (fd_ >= 0) std::clog << "file " << path_ << " still open" << std::endl;
}

void file::open(std::string path, const file_mode mode) {
  int fd = -1;
  while (true) {
    fd = ::open(path.c_str(), static_cast<int>(mode) | O_CLOEXEC,
                S_IRUSR | S_IWUSR);
    if (fd >= 0 || errno != EINTR) break;
  }
  if (fd < 0) {
    throw std::system_error(errno, std::system_category(),
                            "open(" + path + ')');
  }
  fd_ = fd;
  path_ = std::move(path);
}

std::FILE* file::open_c_file(const char* const mode) {
  const auto file = fdopen(fd_, mode);
  if (file == nullptr) {
    throw std::system_error(errno, std::system_category(), "fdopen");
  }
  return file;
}

void file::close() {
  if (fd_ < 0) return;
  if (!this->flush()) {
    throw std::ios::failure("error closing file " + path_);
  }
  int status = -1;
  while (true) {
    status = ::close(fd_);
    if (status == 0 || errno != EINTR) break;
  }
  if (status != 0) {
    throw std::system_error(errno, std::system_category(), "close");
  }
  fd_ = -1;
  this->do_close();
  path_.clear();
}

void file::do_close() {}

file::int_type file::overflow(const int_type ch) {
  assert(this->pptr() == this->epptr());
  if (!this->flush()) return traits_type::eof();
  if (traits_type::eq_int_type(ch, traits_type::eof())) {
    return traits_type::not_eof(0);
  }
  traits_type::assign(put_.front(), traits_type::to_char_type(ch));
  this->pbump(1);
  return ch;
}

std::streamsize file::xsputn(const char_type* const data,
                             const std::streamsize count) {
  if (!this->flush()) return 0;
  return this->write(data, count);
}

std::size_t file::write(const char* data, std::size_t count) {
  std::size_t written = 0;
  while (count > 0) {
    const auto n = ::write(fd_, data, count);
    if (n < 0) throw std::system_error(errno, std::system_category(), "write");
    if (n == 0) break;
    written += n;
    data += n;
    count -= n;
  }
  return written;
}

file::int_type file::underflow() {
  assert(this->gptr() == this->egptr());
  const auto read = this->read(get_.data(), get_.size());
  this->setg(get_.data(), get_.data(), get_.data() + read);
  if (read == 0) return traits_type::eof();
  assert(this->gptr() != nullptr);
  assert(this->gptr() != this->egptr());
  return traits_type::to_int_type(*this->gptr());
}

std::streamsize file::xsgetn(char_type* data, std::streamsize count) {
  if (count == 0) return 0;
  std::streamsize read = 0;
  if (this->gptr() != nullptr && this->egptr() != this->gptr()) {
    read = std::min(count, this->egptr() - this->gptr());
    traits_type::copy(data, this->gptr(), read);
    data += read;
    count -= read;
    this->setg(this->gptr(), this->gptr() + read, this->egptr());
  }
  return read + this->read(data, count);
}

std::size_t file::read(char* data, std::size_t count) {
  std::size_t read = 0;
  while (count > 0) {
    const auto n = ::read(fd_, data, count);
    if (n < 0) throw std::system_error(errno, std::system_category(), "read");
    if (n == 0) break;
    read += n;
    data += n;
    count -= n;
  }
  return read;
}

void file::imbue(const std::locale& locale) {
  if (locale != std::locale::classic()) {
    throw std::logic_error("this class only supports the C locale");
  }
}

[[noreturn]] file* file::setbuf(char* const, const std::streamsize) {
  throw std::logic_error("this class doesn’t support changing the buffer");
}

int file::sync() {
  if (!this->flush()) return -1;
  if (::fsync(fd_) < 0) {
    throw std::system_error(errno, std::system_category(), "fsync");
  }
  return 0;
}

[[nodiscard]] bool file::flush() {
  assert(this->pbase() != nullptr);
  assert(this->pptr() != nullptr);
  const auto signed_count = this->pptr() - this->pbase();
  assert(signed_count >= 0);
  const auto count = static_cast<std::size_t>(signed_count);
  const auto written = this->write(this->pbase(), count);
  assert(written <= count);
  if (written < count) return false;
  this->setp(put_.data(), put_.data() + put_.size());
  return true;
}

temp_file::temp_file(const std::string& directory, const absl::string_view tmpl,
                     random& random) {
  for (int i = 0; i < 10; i++) {
    auto name = join_path(directory, random.temp_name(tmpl));
    if (!file_exists(name)) {
      this->open(std::move(name),
                 file_mode::readwrite | file_mode::create | file_mode::excl);
      return;
    }
  }
  throw std::runtime_error("can’t create temporary file in directory " +
                           directory + " with template " + std::string(tmpl));
}

temp_file::~temp_file() noexcept {
  const auto& path = this->path();
  const auto code = this->remove();
  // Only print an error if removing the file failed (“false” return value), but
  // the file wasn’t already removed before (zero error code).
  if (code && code != std::errc::no_such_file_or_directory) {
    std::clog << "error removing temporary file " << path << ": " << code
              << ": " << code.message() << std::endl;
  }
}

void temp_file::do_close() {
  const auto code = this->remove();
  if (code) throw std::system_error(code);
}

[[nodiscard]] std::error_code temp_file::remove() noexcept {
  return remove_file(this->path());
}

static constexpr absl::string_view remove_prefix(const absl::string_view string,
                                                 const char prefix) noexcept {
  return (string.empty() || string.front() != prefix) ? string
                                                      : string.substr(1);
}

static constexpr absl::string_view remove_suffix(const absl::string_view string,
                                                 const char suffix) noexcept {
  return (string.empty() || string.back() != suffix)
             ? string
             : string.substr(0, string.size() - 1);
}

std::string join_path(const absl::string_view a, const absl::string_view b) {
  return std::string(remove_slash(a)) + '/' +
         std::string(remove_prefix(b, '/'));
}

std::string make_absolute(const absl::string_view name) {
  if (is_absolute(name)) return std::string(name);
  struct free {
    void operator()(void* const ptr) const noexcept { std::free(ptr); }
  };
  const std::unique_ptr<char, free> dir(get_current_dir_name());
  if (dir == nullptr) {
    throw std::system_error(errno, std::system_category(),
                            "get_current_dir_name");
  }
  return join_path(dir.get(), name);
}

[[nodiscard]] bool file_exists(const std::string& name) noexcept {
  struct stat info;
  return ::lstat(name.c_str(), &info) == 0;
}

[[nodiscard]] std::error_code remove_file(const std::string& name) noexcept {
  return std::error_code(::unlink(name.c_str()) == 0 ? 0 : errno,
                         std::system_category());
}

[[nodiscard]] std::string temp_dir() {
  const std::array<const char*, 2> vars = {"TEST_TMPDIR", "TMPDIR"};
  for (const auto var : vars) {
    const auto value = std::getenv(var);
    if (value != nullptr && *value != '\0') return value;
  }
  return "/tmp";
}

directory::directory(const std::string& name) : dir_(::opendir(name.c_str())) {
  if (dir_ == nullptr) {
    throw std::system_error(errno, std::system_category(),
                            "opendir(" + name + ')');
  }
}

directory::~directory() noexcept {
  const auto code = this->close();
  if (code) std::clog << code << ": " << code.message() << std::endl;
}

[[nodiscard]] std::error_code directory::close() noexcept {
  if (dir_ == nullptr) return std::error_code();
  const std::error_code code(::closedir(dir_) == 0 ? 0 : errno,
                             std::system_category());
  dir_ = nullptr;
  return code;
}

void directory::iterator::advance() {
  errno = 0;
  const auto entry = ::readdir(dir_);
  if (entry == nullptr) {
    dir_ = nullptr;
    if (errno != 0) {
      throw std::system_error(errno, std::system_category(), "readdir");
    }
    entry_.clear();
  } else {
    entry_ = entry->d_name;
  }
}

}  // phst_rules_elisp
<commit_msg>add some more assertions<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "internal/file.h"

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

#include <algorithm>
#include <cassert>
#include <cerrno>
#include <cstdlib>
#include <ios>
#include <iostream>
#include <memory>
#include <stdexcept>
#include <string>
#include <string_view>
#include <system_error>
#include <utility>

#include "absl/strings/string_view.h"

#include "internal/random.h"

namespace phst_rules_elisp {

file::file() { this->setp(put_.data(), put_.data() + put_.size()); }

file::file(std::string path, const file_mode mode) : file() {
  this->open(std::move(path), mode);
}

file::~file() noexcept {
  if (fd_ >= 0) std::clog << "file " << path_ << " still open" << std::endl;
}

void file::open(std::string path, const file_mode mode) {
  int fd = -1;
  while (true) {
    fd = ::open(path.c_str(), static_cast<int>(mode) | O_CLOEXEC,
                S_IRUSR | S_IWUSR);
    if (fd >= 0 || errno != EINTR) break;
  }
  if (fd < 0) {
    throw std::system_error(errno, std::system_category(),
                            "open(" + path + ')');
  }
  fd_ = fd;
  path_ = std::move(path);
}

std::FILE* file::open_c_file(const char* const mode) {
  const auto file = fdopen(fd_, mode);
  if (file == nullptr) {
    throw std::system_error(errno, std::system_category(), "fdopen");
  }
  return file;
}

void file::close() {
  if (fd_ < 0) return;
  if (!this->flush()) {
    throw std::ios::failure("error closing file " + path_);
  }
  int status = -1;
  while (true) {
    status = ::close(fd_);
    if (status == 0 || errno != EINTR) break;
  }
  if (status != 0) {
    throw std::system_error(errno, std::system_category(), "close");
  }
  fd_ = -1;
  this->do_close();
  path_.clear();
}

void file::do_close() {}

file::int_type file::overflow(const int_type ch) {
  assert(this->pptr() == this->epptr());
  if (!this->flush()) return traits_type::eof();
  if (traits_type::eq_int_type(ch, traits_type::eof())) {
    return traits_type::not_eof(0);
  }
  assert(this->pptr() == put_.data());
  assert(this->epptr() > put_.data());
  traits_type::assign(put_.front(), traits_type::to_char_type(ch));
  this->pbump(1);
  return ch;
}

std::streamsize file::xsputn(const char_type* const data,
                             const std::streamsize count) {
  if (!this->flush()) return 0;
  return this->write(data, count);
}

std::size_t file::write(const char* data, std::size_t count) {
  std::size_t written = 0;
  while (count > 0) {
    const auto n = ::write(fd_, data, count);
    if (n < 0) throw std::system_error(errno, std::system_category(), "write");
    if (n == 0) break;
    written += n;
    data += n;
    count -= n;
  }
  return written;
}

file::int_type file::underflow() {
  assert(this->gptr() == this->egptr());
  const auto read = this->read(get_.data(), get_.size());
  this->setg(get_.data(), get_.data(), get_.data() + read);
  if (read == 0) return traits_type::eof();
  assert(this->gptr() != nullptr);
  assert(this->gptr() != this->egptr());
  return traits_type::to_int_type(*this->gptr());
}

std::streamsize file::xsgetn(char_type* data, std::streamsize count) {
  if (count == 0) return 0;
  std::streamsize read = 0;
  if (this->gptr() != nullptr && this->egptr() != this->gptr()) {
    read = std::min(count, this->egptr() - this->gptr());
    traits_type::copy(data, this->gptr(), read);
    data += read;
    count -= read;
    this->setg(this->gptr(), this->gptr() + read, this->egptr());
  }
  return read + this->read(data, count);
}

std::size_t file::read(char* data, std::size_t count) {
  std::size_t read = 0;
  while (count > 0) {
    const auto n = ::read(fd_, data, count);
    if (n < 0) throw std::system_error(errno, std::system_category(), "read");
    if (n == 0) break;
    read += n;
    data += n;
    count -= n;
  }
  return read;
}

void file::imbue(const std::locale& locale) {
  if (locale != std::locale::classic()) {
    throw std::logic_error("this class only supports the C locale");
  }
}

[[noreturn]] file* file::setbuf(char* const, const std::streamsize) {
  throw std::logic_error("this class doesn’t support changing the buffer");
}

int file::sync() {
  if (!this->flush()) return -1;
  if (::fsync(fd_) < 0) {
    throw std::system_error(errno, std::system_category(), "fsync");
  }
  return 0;
}

[[nodiscard]] bool file::flush() {
  assert(this->pbase() != nullptr);
  assert(this->pptr() != nullptr);
  const auto signed_count = this->pptr() - this->pbase();
  assert(signed_count >= 0);
  const auto count = static_cast<std::size_t>(signed_count);
  const auto written = this->write(this->pbase(), count);
  assert(written <= count);
  if (written < count) return false;
  this->setp(put_.data(), put_.data() + put_.size());
  return true;
}

temp_file::temp_file(const std::string& directory, const absl::string_view tmpl,
                     random& random) {
  for (int i = 0; i < 10; i++) {
    auto name = join_path(directory, random.temp_name(tmpl));
    if (!file_exists(name)) {
      this->open(std::move(name),
                 file_mode::readwrite | file_mode::create | file_mode::excl);
      return;
    }
  }
  throw std::runtime_error("can’t create temporary file in directory " +
                           directory + " with template " + std::string(tmpl));
}

temp_file::~temp_file() noexcept {
  const auto& path = this->path();
  const auto code = this->remove();
  // Only print an error if removing the file failed (“false” return value), but
  // the file wasn’t already removed before (zero error code).
  if (code && code != std::errc::no_such_file_or_directory) {
    std::clog << "error removing temporary file " << path << ": " << code
              << ": " << code.message() << std::endl;
  }
}

void temp_file::do_close() {
  const auto code = this->remove();
  if (code) throw std::system_error(code);
}

[[nodiscard]] std::error_code temp_file::remove() noexcept {
  return remove_file(this->path());
}

static constexpr absl::string_view remove_prefix(const absl::string_view string,
                                                 const char prefix) noexcept {
  return (string.empty() || string.front() != prefix) ? string
                                                      : string.substr(1);
}

static constexpr absl::string_view remove_suffix(const absl::string_view string,
                                                 const char suffix) noexcept {
  return (string.empty() || string.back() != suffix)
             ? string
             : string.substr(0, string.size() - 1);
}

std::string join_path(const absl::string_view a, const absl::string_view b) {
  return std::string(remove_slash(a)) + '/' +
         std::string(remove_prefix(b, '/'));
}

std::string make_absolute(const absl::string_view name) {
  if (is_absolute(name)) return std::string(name);
  struct free {
    void operator()(void* const ptr) const noexcept { std::free(ptr); }
  };
  const std::unique_ptr<char, free> dir(get_current_dir_name());
  if (dir == nullptr) {
    throw std::system_error(errno, std::system_category(),
                            "get_current_dir_name");
  }
  return join_path(dir.get(), name);
}

[[nodiscard]] bool file_exists(const std::string& name) noexcept {
  struct stat info;
  return ::lstat(name.c_str(), &info) == 0;
}

[[nodiscard]] std::error_code remove_file(const std::string& name) noexcept {
  return std::error_code(::unlink(name.c_str()) == 0 ? 0 : errno,
                         std::system_category());
}

[[nodiscard]] std::string temp_dir() {
  const std::array<const char*, 2> vars = {"TEST_TMPDIR", "TMPDIR"};
  for (const auto var : vars) {
    const auto value = std::getenv(var);
    if (value != nullptr && *value != '\0') return value;
  }
  return "/tmp";
}

directory::directory(const std::string& name) : dir_(::opendir(name.c_str())) {
  if (dir_ == nullptr) {
    throw std::system_error(errno, std::system_category(),
                            "opendir(" + name + ')');
  }
}

directory::~directory() noexcept {
  const auto code = this->close();
  if (code) std::clog << code << ": " << code.message() << std::endl;
}

[[nodiscard]] std::error_code directory::close() noexcept {
  if (dir_ == nullptr) return std::error_code();
  const std::error_code code(::closedir(dir_) == 0 ? 0 : errno,
                             std::system_category());
  dir_ = nullptr;
  return code;
}

void directory::iterator::advance() {
  errno = 0;
  const auto entry = ::readdir(dir_);
  if (entry == nullptr) {
    dir_ = nullptr;
    if (errno != 0) {
      throw std::system_error(errno, std::system_category(), "readdir");
    }
    entry_.clear();
  } else {
    entry_ = entry->d_name;
  }
}

}  // phst_rules_elisp
<|endoftext|>