<commit_before>#if !defined(DOUBLETAKE_XSYNC_H)
#define DOUBLETAKE_XSYNC_H

/*
 * @file   xsync.h
 * @brief  Mapping between pthread_t and internal thread information.
 * @author Tongping Liu <http://www.cs.umass.edu/~tonyliu>
 */

#include <assert.h>
#include <pthread.h>
#include <stddef.h>

#include "globalinfo.hh"
#include "hashfuncs.hh"
#include "hashmap.hh"
#include "internalheap.hh"
#include "list.hh"
#include "log.hh"
#include "mm.hh"
#include "recordentries.hh"
#include "semaphore.hh"
#include "spinlock.hh"
#include "synceventlist.hh"
#include "threadstruct.hh"
#include "xdefines.hh"

class xsync {

  struct SyncEntry {
    void* realEntry;
    SyncEventList* list;
  };

public:
  xsync() {}

  void initialize() {
    _syncvars.initialize(HashFuncs::hashAddr, HashFuncs::compareAddr, xdefines::SYNCMAP_SIZE);
  }

  void insertSyncMap(void* key, void* realentry, SyncEventList* list) {
    struct SyncEntry* entry =
        (struct SyncEntry*)InternalHeap::getInstance().malloc(sizeof(struct SyncEntry));
    entry->realEntry = realentry;
    entry->list = list;
    _syncvars.insert(key, sizeof(key), entry);

		PRINT("insertSyncMap entry %p entry %p\n", realentry, entry);
  }

  void deleteMap(void* key) {
    struct SyncEntry* entry;
    if(_syncvars.find(key, sizeof(key), &entry)) {
      InternalHeap::getInstance().free(entry);
    }
    _syncvars.erase(key, sizeof(void*));
  }

  // Signal next thread on the same synchronization variable.
  void signalNextThread(struct syncEvent* event) {
    thread_t* thread = (thread_t*)event->thread;

    // Whether this event is on the top of thread?
    if(isThreadNextEvent(event, thread)) {
      // If yes, signal to this thread. There is no difference between
      // current thread or other thread.
      signalThread(thread);
      PRINF("Thread %d actually signal next thread %d on event %p", current->index, thread->index,
            event);
    } else {
      PRINF("Thread %d adding pending event to next thread %d on event %p", current->index,
            thread->index, event);
      addPendingSyncEvent(event, thread);
    }
  }

  // Signal current thread if event is one of pending events.
  void signalCurrentThread(struct syncEvent* event) {
    thread_t* thread = (thread_t*)event->thread;
    list_t* eventlist = &thread->pendingSyncevents;

    assert(thread == current);

    // PRINF("singalCurrentThread: event %p on variable %p command %d", event,
    // event->eventlist->getSyncVariable(), event->eventlist->getSyncCmd());

    if(!isListEmpty(eventlist)) {
      //     PRINF("singalCurrentThread: event %p thread %p, pending list is not empty!!!\n", event,
      // thread);
      // Only signal itself when current event is first event of this thread.
      struct pendingSyncEvent* pe = NULL;

      // Search the whole list for given tid.
      pe = (struct pendingSyncEvent*)nextEntry(eventlist);
      while(true) {
        // We found this event
        if(pe->event == event) {
          PRINF("singalCurrentThread: signal myself, retrieve event %p pe->event %p", event,
                pe->event);
          // Remove this event from the list.
          listRemoveNode(&pe->list);

          // Release corresponding memory to avoid memory leakage.
          InternalHeap::getInstance().free(pe);

          // Now signal current thread.
          signalThread(thread);
          break;
        }

        // Update to the next thread.
        if(isListTail(&pe->list, eventlist)) {
          break;
        } else {
          pe = (struct pendingSyncEvent*)nextEntry(&pe->list);
        }
      } // while (true)
    } else {
      PRINF("thread pending list is empty now!!!");
    }
  }

  // Update the synchronization list.
  void advanceThreadSyncList() {
    struct syncEvent* nextEvent = NULL;

    global_lock();

    // Update next event of thread eventlist.
    nextEvent = current->syncevents.nextIterEntry();
    if(nextEvent != NULL) {
      signalCurrentThread(nextEvent);
    }
    global_unlock();
  }

  // peekSyncEvent return the saved event value for current synchronization.
  inline int peekSyncEvent() {
    int result = -1;
    struct syncEvent* event = (struct syncEvent*)current->syncevents.getEntry();
    if(event) {
      REQUIRE(event->thread == current,
              "Event %p belongs to thread %p, not the current thread (%p)", event, event->thread,
              current);
      result = event->ret;
    } else {
      // ERROR("Event not exising now at thread %p!!!!\n", current);
    }
    return result;
  }

  void cleanSyncEvents() {
    // Remove all events in the global map and event list.
    syncvarsHashMap::iterator i;

    for(i = _syncvars.begin(); i != _syncvars.end(); i++) {
			struct SyncEntry* entry = (struct SyncEntry*)i.getData();
      SyncEventList* eventlist = (SyncEventList*)entry->list;

			PRINT("cleaningup the eventlist %p\n", eventlist);
      eventlist->cleanup();
    }
  }

  inline void setSyncVariable(void** syncvariable, void* realvariable) {
    *syncvariable = realvariable;
  }

  /*
   Prepare rollback. Only one thread can call this function.
   It basically check every synchronization variable.
   If a synchronization variable is in the head of a thread, then
   we try to UP corresponding thread's semaphore.
   */
  void prepareRollback() {
    syncvarsHashMap::iterator i;
    struct SyncEntry* entry;
    SyncEventList* eventlist = NULL;
    void* syncvariable;

    for(i = _syncvars.begin(); i != _syncvars.end(); i++) {
      syncvariable = i.getkey();
      entry = (struct SyncEntry*)i.getData();
      if(syncvariable != entry) {
        // Setting the address
        setSyncVariable((void**)syncvariable, entry->realEntry);
      }

      eventlist = entry->list;
      prepareEventListRollback(eventlist);
    }
  }

  /*
    Prepare the rollback for an event list.
    It will check whether the first event in the event list is also the head of specific
    thread. If yes, then we will signal specific thread so that this thread can acquire
    the semaphore immediately.
   */
  inline void prepareEventListRollback(SyncEventList* eventlist) {
    struct syncEvent* event = eventlist->prepareRollback();

    if(event) {
      // Signal to next thread with the top event
      signalNextThread(event);
    }
  }

  // Add one synchronization event into the pending list of a thread.
  void addPendingSyncEvent(struct syncEvent* event, thread_t* thread) {
    struct pendingSyncEvent* pendingEvent = NULL;

    pendingEvent = (struct pendingSyncEvent*)InternalHeap::getInstance().malloc(
        sizeof(struct pendingSyncEvent));

    listInit(&pendingEvent->list);
    pendingEvent->event = event;

    // Add this pending event into corresponding thread.
    listInsertTail(&pendingEvent->list, &thread->pendingSyncevents);
  }

  // Check whether this event is the first event of corresponding thread.
  bool isThreadNextEvent(struct syncEvent* event, thread_t* thread) {
    return (event == thread->syncevents.firstIterEntry());
  }

  void signalThread(thread_t* thread) {
    semaphore* sema = &thread->sema;
    PRINF("Signal semaphore to thread%d (at %p)\n", thread->index, thread);
    sema->put();
  }

private:
  size_t getThreadSyncSeqNum() { return 0; }

  semaphore* getThreadSemaphore(thread_t* thread) { return &thread->sema; }

  // We are maintainning a private hash map for each thread.
  typedef HashMap<void*, struct SyncEntry*, spinlock, InternalHeapAllocator> syncvarsHashMap;

  // Synchronization related to different sync variable should be recorded into
  // the synchronization variable related list.
  syncvarsHashMap _syncvars;
};

#endif
<commit_msg>Fixing one bug of prepareRollback<commit_after>#if !defined(DOUBLETAKE_XSYNC_H)
#define DOUBLETAKE_XSYNC_H

/*
 * @file   xsync.h
 * @brief  Mapping between pthread_t and internal thread information.
 * @author Tongping Liu <http://www.cs.umass.edu/~tonyliu>
 */

#include <assert.h>
#include <pthread.h>
#include <stddef.h>

#include "globalinfo.hh"
#include "hashfuncs.hh"
#include "hashmap.hh"
#include "internalheap.hh"
#include "list.hh"
#include "log.hh"
#include "mm.hh"
#include "recordentries.hh"
#include "semaphore.hh"
#include "spinlock.hh"
#include "synceventlist.hh"
#include "threadstruct.hh"
#include "xdefines.hh"

class xsync {

  struct SyncEntry {
    void* realEntry;
    SyncEventList* list;
  };

public:
  xsync() {}

  void initialize() {
    _syncvars.initialize(HashFuncs::hashAddr, HashFuncs::compareAddr, xdefines::SYNCMAP_SIZE);
  }

  void insertSyncMap(void* key, void* realentry, SyncEventList* list) {
    struct SyncEntry* entry =
        (struct SyncEntry*)InternalHeap::getInstance().malloc(sizeof(struct SyncEntry));
    entry->realEntry = realentry;
    entry->list = list;
    _syncvars.insert(key, sizeof(key), entry);

		PRINT("insertSyncMap entry %p entry %p\n", realentry, entry);
  }

  void deleteMap(void* key) {
    struct SyncEntry* entry;
    if(_syncvars.find(key, sizeof(key), &entry)) {
      InternalHeap::getInstance().free(entry);
    }
    _syncvars.erase(key, sizeof(void*));
  }

  // Signal next thread on the same synchronization variable.
  void signalNextThread(struct syncEvent* event) {
    thread_t* thread = (thread_t*)event->thread;

    // Whether this event is on the top of thread?
    if(isThreadNextEvent(event, thread)) {
      // If yes, signal to this thread. There is no difference between
      // current thread or other thread.
      signalThread(thread);
      PRINF("Thread %d actually signal next thread %d on event %p", current->index, thread->index,
            event);
    } else {
      PRINF("Thread %d adding pending event to next thread %d on event %p", current->index,
            thread->index, event);
      addPendingSyncEvent(event, thread);
    }
  }

  // Signal current thread if event is one of pending events.
  void signalCurrentThread(struct syncEvent* event) {
    thread_t* thread = (thread_t*)event->thread;
    list_t* eventlist = &thread->pendingSyncevents;

    assert(thread == current);

    // PRINF("singalCurrentThread: event %p on variable %p command %d", event,
    // event->eventlist->getSyncVariable(), event->eventlist->getSyncCmd());

    if(!isListEmpty(eventlist)) {
      //     PRINF("singalCurrentThread: event %p thread %p, pending list is not empty!!!\n", event,
      // thread);
      // Only signal itself when current event is first event of this thread.
      struct pendingSyncEvent* pe = NULL;

      // Search the whole list for given tid.
      pe = (struct pendingSyncEvent*)nextEntry(eventlist);
      while(true) {
        // We found this event
        if(pe->event == event) {
          PRINF("singalCurrentThread: signal myself, retrieve event %p pe->event %p", event,
                pe->event);
          // Remove this event from the list.
          listRemoveNode(&pe->list);

          // Release corresponding memory to avoid memory leakage.
          InternalHeap::getInstance().free(pe);

          // Now signal current thread.
          signalThread(thread);
          break;
        }

        // Update to the next thread.
        if(isListTail(&pe->list, eventlist)) {
          break;
        } else {
          pe = (struct pendingSyncEvent*)nextEntry(&pe->list);
        }
      } // while (true)
    } else {
      PRINF("thread pending list is empty now!!!");
    }
  }

  // Update the synchronization list.
  void advanceThreadSyncList() {
    struct syncEvent* nextEvent = NULL;

    global_lock();

    // Update next event of thread eventlist.
    nextEvent = current->syncevents.nextIterEntry();
    if(nextEvent != NULL) {
      signalCurrentThread(nextEvent);
    }
    global_unlock();
  }

  // peekSyncEvent return the saved event value for current synchronization.
  inline int peekSyncEvent() {
    int result = -1;
    struct syncEvent* event = (struct syncEvent*)current->syncevents.getEntry();
    if(event) {
      REQUIRE(event->thread == current,
              "Event %p belongs to thread %p, not the current thread (%p)", event, event->thread,
              current);
      result = event->ret;
    } else {
      // ERROR("Event not exising now at thread %p!!!!\n", current);
    }
    return result;
  }

  void cleanSyncEvents() {
    // Remove all events in the global map and event list.
    syncvarsHashMap::iterator i;

    for(i = _syncvars.begin(); i != _syncvars.end(); i++) {
			struct SyncEntry* entry = (struct SyncEntry*)i.getData();
      SyncEventList* eventlist = (SyncEventList*)entry->list;

			PRINT("cleaningup the eventlist %p!!!\n", eventlist);
      eventlist->cleanup();
    }
  }

  inline void setSyncVariable(void** syncvariable, void* realvariable) {
    *syncvariable = realvariable;
  }

  /*
   Prepare rollback. Only one thread can call this function.
   It basically check every synchronization variable.
   If a synchronization variable is in the head of a thread, then
   we try to UP corresponding thread's semaphore.
   */
  void prepareRollback() {
    syncvarsHashMap::iterator i;
    struct SyncEntry* entry;
    SyncEventList* eventlist = NULL;
    void* syncvariable;

    for(i = _syncvars.begin(); i != _syncvars.end(); i++) {
      syncvariable = i.getkey();
			entry = (struct SyncEntry*)i.getData();

			PRINT("prepareRollback syncvariable %p pointintto %p entry %p realentry %p\n", syncvariable, (*((void **)syncvariable)), entry, entry->realEntry);
#if 1
			// If syncvariable is not equal to the entry->realEntry,
			// those are mutex locks, conditional variables or mutexlocks
			// Those variables are setted to 0 at epochBegin() or some non-valid variables.
			// We have to recove them and making them to pointing to actual entries.
      if((*((void **)syncvariable)) != entry->realEntry) {
        // Setting the address
        setSyncVariable((void**)syncvariable, entry->realEntry);
      }
#endif

      eventlist = entry->list;
      prepareEventListRollback(eventlist);
    }
  }

  /*
    Prepare the rollback for an event list.
    It will check whether the first event in the event list is also the head of specific
    thread. If yes, then we will signal specific thread so that this thread can acquire
    the semaphore immediately.
   */
  inline void prepareEventListRollback(SyncEventList* eventlist) {
    struct syncEvent* event = eventlist->prepareRollback();

    if(event) {
      // Signal to next thread with the top event
      signalNextThread(event);
    }
  }

  // Add one synchronization event into the pending list of a thread.
  void addPendingSyncEvent(struct syncEvent* event, thread_t* thread) {
    struct pendingSyncEvent* pendingEvent = NULL;

    pendingEvent = (struct pendingSyncEvent*)InternalHeap::getInstance().malloc(
        sizeof(struct pendingSyncEvent));

    listInit(&pendingEvent->list);
    pendingEvent->event = event;

    // Add this pending event into corresponding thread.
    listInsertTail(&pendingEvent->list, &thread->pendingSyncevents);
  }

  // Check whether this event is the first event of corresponding thread.
  bool isThreadNextEvent(struct syncEvent* event, thread_t* thread) {
    return (event == thread->syncevents.firstIterEntry());
  }

  void signalThread(thread_t* thread) {
    semaphore* sema = &thread->sema;
    PRINF("Signal semaphore to thread%d (at %p)\n", thread->index, thread);
    sema->put();
  }

private:
  size_t getThreadSyncSeqNum() { return 0; }

  semaphore* getThreadSemaphore(thread_t* thread) { return &thread->sema; }

  // We are maintainning a private hash map for each thread.
  typedef HashMap<void*, struct SyncEntry*, spinlock, InternalHeapAllocator> syncvarsHashMap;

  // Synchronization related to different sync variable should be recorded into
  // the synchronization variable related list.
  syncvarsHashMap _syncvars;
};

#endif
<|endoftext|>


<commit_before><commit_msg>Disable the email sending menu entries when sandboxed on OS X<commit_after><|endoftext|>


<commit_before>/*
    Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>

    This file is part of Magnum.

    Magnum is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License version 3
    only, as published by the Free Software Foundation.

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

#include "InterleaveTest.h"

#define NDEBUG

#include <sstream>
#include <QtTest/QTest>

#include "Utility/Endianness.h"
#include "Utility/Debug.h"
#include "MeshTools/Interleave.h"

QTEST_APPLESS_MAIN(Magnum::MeshTools::Test::InterleaveTest)

using namespace std;
using namespace Corrade::Utility;

namespace Magnum { namespace MeshTools { namespace Test {

void InterleaveTest::attributeCount() {
    stringstream ss;
    Error::setOutput(&ss);
    QCOMPARE((Interleave::attributeCount(vector<char>{0, 1, 2},
        vector<char>{0, 1, 2, 3, 4, 5})), size_t(0));
    QVERIFY(ss.str() == "MeshTools::Interleave: attribute arrays don't have the same length, nothing done.\n");

    QCOMPARE((Interleave::attributeCount(vector<char>{0, 1, 2},
        vector<char>{3, 4, 5})), size_t(3));
}

void InterleaveTest::stride() {
    QCOMPARE(Interleave::stride(vector<char>()), size_t(1));
    QCOMPARE(Interleave::stride(vector<int>()), size_t(4));
    QCOMPARE((Interleave::stride(vector<char>(), vector<int>())), size_t(5));
}

void InterleaveTest::write() {
    Interleave::Result data = MeshTools::interleave(
        vector<char>{0, 1, 2},
        vector<int>{3, 4, 5},
        vector<short>{6, 7, 8});

    QCOMPARE(data.attributeCount, size_t(3));
    QCOMPARE(data.stride, size_t(7));
    size_t size = data.attributeCount*data.stride;
    if(!Endianness::isBigEndian()) {
        QVERIFY((vector<char>(data.data, data.data+size) == vector<char>{
            0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00,
            0x01, 0x04, 0x00, 0x00, 0x00, 0x07, 0x00,
            0x02, 0x05, 0x00, 0x00, 0x00, 0x08, 0x00
        }));
    } else {
        QVERIFY((vector<char>(data.data, data.data+size) == vector<char>{
            0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x06,
            0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x07,
            0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x08
        }));
    }

    delete[] data.data;
}

}}}
<commit_msg>Don't redefine NDEBUG when building in release mode.<commit_after>/*
    Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>

    This file is part of Magnum.

    Magnum is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License version 3
    only, as published by the Free Software Foundation.

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

#include "InterleaveTest.h"

#ifndef NDEBUG
#define NDEBUG
#endif

#include <sstream>
#include <QtTest/QTest>

#include "Utility/Endianness.h"
#include "Utility/Debug.h"
#include "MeshTools/Interleave.h"

QTEST_APPLESS_MAIN(Magnum::MeshTools::Test::InterleaveTest)

using namespace std;
using namespace Corrade::Utility;

namespace Magnum { namespace MeshTools { namespace Test {

void InterleaveTest::attributeCount() {
    stringstream ss;
    Error::setOutput(&ss);
    QCOMPARE((Interleave::attributeCount(vector<char>{0, 1, 2},
        vector<char>{0, 1, 2, 3, 4, 5})), size_t(0));
    QVERIFY(ss.str() == "MeshTools::Interleave: attribute arrays don't have the same length, nothing done.\n");

    QCOMPARE((Interleave::attributeCount(vector<char>{0, 1, 2},
        vector<char>{3, 4, 5})), size_t(3));
}

void InterleaveTest::stride() {
    QCOMPARE(Interleave::stride(vector<char>()), size_t(1));
    QCOMPARE(Interleave::stride(vector<int>()), size_t(4));
    QCOMPARE((Interleave::stride(vector<char>(), vector<int>())), size_t(5));
}

void InterleaveTest::write() {
    Interleave::Result data = MeshTools::interleave(
        vector<char>{0, 1, 2},
        vector<int>{3, 4, 5},
        vector<short>{6, 7, 8});

    QCOMPARE(data.attributeCount, size_t(3));
    QCOMPARE(data.stride, size_t(7));
    size_t size = data.attributeCount*data.stride;
    if(!Endianness::isBigEndian()) {
        QVERIFY((vector<char>(data.data, data.data+size) == vector<char>{
            0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00,
            0x01, 0x04, 0x00, 0x00, 0x00, 0x07, 0x00,
            0x02, 0x05, 0x00, 0x00, 0x00, 0x08, 0x00
        }));
    } else {
        QVERIFY((vector<char>(data.data, data.data+size) == vector<char>{
            0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x06,
            0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x07,
            0x02, 0x00, 0x00, 0x00, 0x05, 0x00, 0x08
        }));
    }

    delete[] data.data;
}

}}}
<|endoftext|>


<commit_before>#ifndef STDAFX_H
#include <assert.h>
#include <algorithm>
#endif

#include "stdfnc.h"
#include "monitor.h"
#include "window_message.h"

#include "ids.h"
#include "list_item.h"
#include "profile.h"
#include "menu.h"
#include "control.h"
#include "filer.h"
#include "draw_list.h"
#include "loader.h"

namespace image_viewer {

CImageViewer::CImageViewer()
    : m_exitCode(0), isImageInvalidated(true)
{
    hook(this);
    profile.reset(new Profile);
    menu.reset(new ContextMenu(*this));
    control.reset(new Control(*this));
    filer.reset(new Filer(*this));
    list.reset(new CDrawList(*this));
    loader.reset(new Loader(*this));
}

CImageViewer::~CImageViewer()
{}

int CImageViewer::
onEvent(Window *win, Message msg, WPARAM wp, LPARAM) try
{
    assert(win == this);

    switch (msg) {
    case WM::CREATE:
        saveload(false);

        menu->initialize();
        if (menu->isSelected(ID::VIEW_FILELIST))
            list->show();

        m_captionConfirmDelete =
            profile->getTranslatedString(ID::FILE_DELETE);
        m_textConfirmDelete =
            profile->getTranslatedString(ID::CONFIRM_DELETE);
        updateTitleBar();
        DragAcceptFiles(*win, true);
        return 0;

    case WM::PAINT:
        m_exitCode = 0;
        return onPaint();

    case WM::COMMAND:
        return onCommand(wp);

    case WM::DROPFILES:
        activate();
        setForeground();
        setPath(::basis::GetDropFile(wp, 0));
        return 1;

    case WM::SIZE:
    case WM::SIZING:
        isImageInvalidated = true;
        win->update();
        return 0;

    case WM::ERASEBKGND:
        return 1;

    case WM::CONTEXTMENU: // Shift + F10
        menu->track({});
        return 1;

    case WM::CLOSE:
        if (profile->isEnable()) {
            menu->saveSettings();
            saveload(true);
        }
        destroy();
        m_exitCode = 0;
        return 1;

    case WM::DESTROY:
        PostQuitMessage(0);
        return 0;

    default:
        return 0;
    }
}
catch (std::exception &e)
{
    MessageBoxA(0, e.what(), "Exception", 0);
    throw e;
}

basis::CKey CImageViewer::getKey(ID id, int n)
{
    return control->getKey(id, n);
}

void CImageViewer::saveload(bool bSave)
{
    profile->general();
    if (!bSave)
        m_lastPath = profile->load(ID::LAST_PATH, nullptr);
    else if (m_dir.exist())
        profile->save(ID::LAST_PATH, m_dir.path().c_str());

    profile->window();
    if (profile->loadBoolean(ID::WINDOW_REMINDER, true) == false)
        return;

    if (profile->loadBoolean(ID::WINDOW_POSITION, false)) {
        Rect rc = place();
        if (bSave) {
            profile->save(ID::WINDOW_LEFT, rc.left);
            profile->save(ID::WINDOW_TOP, rc.top);
            profile->save(ID::WINDOW_RIGHT, rc.right);
            profile->save(ID::WINDOW_BOTTOM, rc.bottom);
        }
        else {
            rc.left = profile->load(ID::WINDOW_LEFT, rc.left);
            rc.top = profile->load(ID::WINDOW_TOP, rc.top);
            rc.right = profile->load(ID::WINDOW_RIGHT, rc.right);
            rc.bottom = profile->load(ID::WINDOW_BOTTOM, rc.bottom);
            place(rc);
        }
    }

    if (profile->loadBoolean(ID::WINDOW_ZOOMING, false)) {
        const ID id = ID::WINDOW_MAXIMIZE;
        if (bSave)
            profile->saveBoolean(id, isMaximized());
        else if (profile->loadBoolean(id, false))
            maximize();
    }

    if (profile->loadBoolean(ID::WINDOW_STYLE, false)) {
        const ID id = ID::VIEW_POPUP;
        if (bSave)
            profile->saveBoolean(id, menu->isSelected(id));
        else
            popup(profile->loadBoolean(id, false));
    }
}

// (iNext)Jgݒ肷^Cṽ[vɎgB
// ݒɐA܂͂łɒT(iLimit)łꍇfalseԂB
// sƗvf폜trueԂ̂ŁA
// ēxnă[v邱ƁB
bool CImageViewer::
helper_show_must_loop(iterator iNext, const_iterator iLimit)
{
    // TłȂ̂ŏIB
    if (iNext == filer->end()) {
        invalidate();
        return false;
    }

    // [hI
    if (setCurrent(iNext) == true) {
        return false;
    }

    // sāA[vp
    filer->erase(iNext);
    return true;
}

void CImageViewer::
showPrev()
{
    if (filer->current() == filer->begin())
        return;
    while (helper_show_must_loop(--filer->current(), filer->begin()))
        ; // noop
}

void CImageViewer::
showNext()
{
    if (filer->current() == filer->end())
        return;

    while (helper_show_must_loop(++filer->current(), filer->end()))
        ; // noop
}

void CImageViewer::
showFirst()
{
    while (helper_show_must_loop(filer->begin(), filer->end()))
        ; // noop
}

void CImageViewer::
showLast()
{
    while (helper_show_must_loop(filer->last(),
        filer->end()))
        ; // nop
}

bool CImageViewer::
setPath(FilePath path)
{
    if (loader->waitIfAnyImageIsLoading() == false) {
        MessageBox(0, TEXT("Loading thread wouldn't respond."
            "Operations are annulled."), 0, 0);
        return false;
    }

    if (!path.exist())
        return false;

    m_dir = (path.isDirectory()) ? path : path.getDir();

    filer->generate(m_dir.path().c_str());
    filer->sort();
    filer->setCurrent(filer->begin());

    if (path.isDirectory()) {
        showFirst();
        return true;
    }

    auto filename = path.getFileName();
    iterator itr = filer->search([filename](Element &p)->bool {
        return (filename == p->fileName());
    });
    setCurrent(itr);
    return true;
}

bool CImageViewer::
setCurrent(iterator itr)
{
    if (itr == filer->end())
        return false;

    // ͈͊ÕLbV폜
    loader->markToReleaseAround(filer->current());
    loader->unmarkAround(itr);
    loader->performReleaseAround(filer->current());

    if (loader->loadImage(itr, true) != Loader::Status::Finished)
        return false;

    // ړ
    filer->setCurrent(itr);
    loader->preloadAround(itr);

    // XV
    list->invalidate();
    updateTitleBar();

    m_offset.reset();
    invalidate_image();
    update();
    return true;
}

void CImageViewer::
reloadCurrent()
{
    if (filer->current() == filer->end())
        return;
    filer->current()->get()->unload();
    if (loader->loadImage(filer->current(), false) == Loader::Status::Finished)
        setCurrent(filer->current());
}

int CImageViewer::
onCommand(WPARAM wp)
{
    ID const id = static_cast<ID>(LOWORD(wp));
    menu->changeStatus(id);

    switch (id) {
    case ID::USE_PROFILE:
        if (menu->isSelected(id))
            profile->enable();
        else
            profile->disable();
        return 1;

    case ID::LAST_PATH:
        setPath(m_lastPath);
        break;

    case ID::FILE_BACK:
        showPrev();
        break;

    case ID::FILE_NEXT:
        showNext();
        break;

    case ID::FILE_FIRST:
        showFirst();
        break;

    case ID::FILE_LAST:
        showLast();
        break;

    case ID::FILE_RELOAD:
        reloadCurrent();
        break;

    case ID::FILE_DELETE:
    case ID::FILE_QUICK_DELETE:
    case ID::LIST_REMOVE:
        if (filer->isEmpty())
            break;
        if (id == ID::FILE_DELETE) {
            if (IDOK != MessageBox(*this, m_textConfirmDelete.c_str(),
                m_captionConfirmDelete.c_str(), MB_OKCANCEL))
                break;
        }
        loader->waitIfLoading(filer->current());
        if (id != ID::LIST_REMOVE &&
            (m_dir + filer->current()->get()->fileName()).trash() == false)
                break;
        filer->erase(filer->current());
        setCurrent(filer->current());
        break;

    case ID::VIEW_POPUP:
        popup(menu->isSelected(id));
        break;

    case ID::VIEW_FILENAME:
        updateTitleBar();
        break;

    case ID::VIEW_FILELIST:
        if (menu->isSelected(id))
            list->show();
        else
            list->hide();
        break;

    case ID::VIEW_UPSCALE:
    case ID::VIEW_DOWNSCALE:
    case ID::VIEW_CENTER:
        m_offset.reset();
        invalidate_image();
        break;

    case ID::LOADER_IMAGE_LOADED:
        list->invalidate();
        break;

    case ID::SCREEN_TOGGLE:
        toggleScreen();
        break;

    case ID::SORT_LESSER_WRITE:
    case ID::SORT_GREATER_WRITE:
    case ID::SORT_LESSER_ACCESS:
    case ID::SORT_GREATER_ACCESS:
    case ID::SORT_LESSER_CREATION:
    case ID::SORT_GREATER_CREATION:
        filer->sort();
        list->invalidate();
        break;

    case ID::WINDOW_CLOSE:
        post(WM::CLOSE, 0, 0);
        break;

    case ID::SHOW_PROPERTY:
        if (!filer->isEmpty()) {
            auto path = m_dir + filer->current()->get()->fileName();
            ShowProperty(*this, path.path().c_str());
        }
        break;

    default:
        return 0;
    } // switch

    return 1;
}

void CImageViewer::
update() const
{
    menu->updateStatus();
    Window::update();
    updateTitleBar();
}

bool CImageViewer::
updateTitleBar() const
{
    tstr title = (filer->isEmpty())
        ? NAME_VERSION
        : filer->current()->get()->fileName();

    int index = filer->isEmpty() ? 0 : filer->indexof(filer->current()) + 1;
    title += TEXT(" [") + basis::ToStr(index)
        + TEXT("/") + basis::ToStr(filer->size())
        + TEXT("]");

    return setTitle(title.c_str());
}

bool CImageViewer::
toggleScreen()
{
    if (!isMaximized()) {
        popup();
        maximize();
    }
    else if (!isMultiMaximized()) {
        popup();
        maximize_multi();
    }
    else {
        normalize();
        popup(menu->isSelected(ID::VIEW_POPUP));
    }
    m_offset.reset();
    invalidate();
    return true;
}

ID CImageViewer::getSortWay() const
{
    return menu->getSortWay();
}

bool CImageViewer::isMultiMaximized() const
{
    if (!isMaximized())
        return false;

    Rect vs = basis::Monitor::GetVirtualScreen();
    Rect rc = getRect();
    return (rc.width() >= vs.width() && rc.height() >= vs.height());
}

int CImageViewer::
onPaint()
{
    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(*this, &ps);

    if (m_backbuffer.compatible(hdc, getClientSize())) {
        invalidate(getClientRect());
        SetBkMode(m_backbuffer, TRANSPARENT);
        m_backbuffer.pen(GetStockObject(WHITE_PEN));
        m_backbuffer.brush(GetStockObject(WHITE_BRUSH));
        isImageInvalidated = true;
    }

    if (filer->isEmpty()) {
        m_backbuffer.rectangle(ps.rcPaint);
    }
    else {
        Rect image_rect;
        if (!filer->isEmpty())
            image_rect = filer->current()->get()->rect();
        Size drawing_size = getDrawSize(image_rect.size());

        Rect src = { 0, 0, drawing_size.x, drawing_size.y };
        if (m_offscreen.compatible(hdc, drawing_size) || isImageInvalidated) {
            isImageInvalidated = false;
            filer->current()->get()->draw(m_offscreen, src, image_rect);
        }

        m_drawingRect = getDrawRect(drawing_size);
        m_offscreen.transfer(m_backbuffer, m_drawingRect, src);
        ClearBackground(m_backbuffer, ps.rcPaint, m_drawingRect);
    }

    list->draw(&m_backbuffer);
    m_backbuffer.transfer(hdc, ps.rcPaint, ps.rcPaint);
    EndPaint(*this, &ps);
    return 1;
}

basis::Rect CImageViewer::
getDrawRect() const
{
    if (filer->isEmpty())
        return{};
    return getDrawRect(getDrawSize(filer->current()->get()->size()));
}

basis::Rect CImageViewer::
getDrawRect(const Size &size) const
{
    Rect rc{ 0, 0, size.x, size.y };
    rc.move(m_offset);
    if (menu->isSelected(ID::VIEW_CENTER))
        rc.move((getClientSize() - size) / 2);
    return rc;
}

basis::Size CImageViewer::
getDrawSize(const Size &image_size) const
{
    Size size = image_size;
    const auto client = getClientSize();

    if (!client.x || !client.y || !size.x || !size.y)
        return{};

    if (menu->isSelected((client.x > size.x && client.y > size.y)
        ? ID::VIEW_UPSCALE : ID::VIEW_DOWNSCALE))
    {
        if (static_cast<double>(size.x) / client.x
            > static_cast<double>(size.y) / client.y)
        {
            size.y = static_cast<int>(0.5 + size.y
                * static_cast<double>(client.x) / size.x);
            size.x = client.x;
        }
        else {
            size.x = static_cast<int>(0.5 + size.x
                * static_cast<double>(client.y) / size.y);
            size.y = client.y;
        }
    }
    return size;
}

void CImageViewer::
invalidate() const
{
    isImageInvalidated = true;
    Window::invalidate();
}

void CImageViewer::
invalidate_image() const
{
    isImageInvalidated = true;
    invalidate(m_drawingRect);
    invalidate(getDrawRect());
}

void CImageViewer::move_image(Size diff)
{
    m_offset += diff;
    invalidate(getDrawRect().unite(m_drawingRect));
}

}  // namespace
<commit_msg>To accept command line<commit_after>#ifndef STDAFX_H
#include <assert.h>
#include <algorithm>
#endif

#include "stdfnc.h"
#include "monitor.h"
#include "window_message.h"

#include "ids.h"
#include "list_item.h"
#include "profile.h"
#include "menu.h"
#include "control.h"
#include "filer.h"
#include "draw_list.h"
#include "loader.h"

namespace image_viewer {

CImageViewer::CImageViewer()
    : m_exitCode(0), isImageInvalidated(true)
{
    hook(this);
    profile.reset(new Profile);
    menu.reset(new ContextMenu(*this));
    control.reset(new Control(*this));
    filer.reset(new Filer(*this));
    list.reset(new CDrawList(*this));
    loader.reset(new Loader(*this));
}

CImageViewer::~CImageViewer()
{}

int CImageViewer::
onEvent(Window *win, Message msg, WPARAM wp, LPARAM) try
{
    assert(win == this);

    switch (msg) {
    case WM::CREATE:
        saveload(false);

        menu->initialize();
        if (menu->isSelected(ID::VIEW_FILELIST))
            list->show();

        m_captionConfirmDelete =
            profile->getTranslatedString(ID::FILE_DELETE);
        m_textConfirmDelete =
            profile->getTranslatedString(ID::CONFIRM_DELETE);
        updateTitleBar();
        setPath(::basis::GetCommandLine(1));
        DragAcceptFiles(*win, true);
        return 0;

    case WM::PAINT:
        m_exitCode = 0;
        return onPaint();

    case WM::COMMAND:
        return onCommand(wp);

    case WM::DROPFILES:
        activate();
        setForeground();
        setPath(::basis::GetDropFile(wp, 0));
        return 1;

    case WM::SIZE:
    case WM::SIZING:
        isImageInvalidated = true;
        win->update();
        return 0;

    case WM::ERASEBKGND:
        return 1;

    case WM::CONTEXTMENU: // Shift + F10
        menu->track({});
        return 1;

    case WM::CLOSE:
        if (profile->isEnable()) {
            menu->saveSettings();
            saveload(true);
        }
        destroy();
        m_exitCode = 0;
        return 1;

    case WM::DESTROY:
        PostQuitMessage(0);
        return 0;

    default:
        return 0;
    }
}
catch (std::exception &e)
{
    MessageBoxA(0, e.what(), "Exception", 0);
    throw e;
}

basis::CKey CImageViewer::getKey(ID id, int n)
{
    return control->getKey(id, n);
}

void CImageViewer::saveload(bool bSave)
{
    profile->general();
    if (!bSave)
        m_lastPath = profile->load(ID::LAST_PATH, nullptr);
    else if (m_dir.exist())
        profile->save(ID::LAST_PATH, m_dir.path().c_str());

    profile->window();
    if (profile->loadBoolean(ID::WINDOW_REMINDER, true) == false)
        return;

    if (profile->loadBoolean(ID::WINDOW_POSITION, false)) {
        Rect rc = place();
        if (bSave) {
            profile->save(ID::WINDOW_LEFT, rc.left);
            profile->save(ID::WINDOW_TOP, rc.top);
            profile->save(ID::WINDOW_RIGHT, rc.right);
            profile->save(ID::WINDOW_BOTTOM, rc.bottom);
        }
        else {
            rc.left = profile->load(ID::WINDOW_LEFT, rc.left);
            rc.top = profile->load(ID::WINDOW_TOP, rc.top);
            rc.right = profile->load(ID::WINDOW_RIGHT, rc.right);
            rc.bottom = profile->load(ID::WINDOW_BOTTOM, rc.bottom);
            place(rc);
        }
    }

    if (profile->loadBoolean(ID::WINDOW_ZOOMING, false)) {
        const ID id = ID::WINDOW_MAXIMIZE;
        if (bSave)
            profile->saveBoolean(id, isMaximized());
        else if (profile->loadBoolean(id, false))
            maximize();
    }

    if (profile->loadBoolean(ID::WINDOW_STYLE, false)) {
        const ID id = ID::VIEW_POPUP;
        if (bSave)
            profile->saveBoolean(id, menu->isSelected(id));
        else
            popup(profile->loadBoolean(id, false));
    }
}

// (iNext)Jgݒ肷^Cṽ[vɎgB
// ݒɐA܂͂łɒT(iLimit)łꍇfalseԂB
// sƗvf폜trueԂ̂ŁA
// ēxnă[v邱ƁB
bool CImageViewer::
helper_show_must_loop(iterator iNext, const_iterator iLimit)
{
    // TłȂ̂ŏIB
    if (iNext == filer->end()) {
        invalidate();
        return false;
    }

    // [hI
    if (setCurrent(iNext) == true) {
        return false;
    }

    // sāA[vp
    filer->erase(iNext);
    return true;
}

void CImageViewer::
showPrev()
{
    if (filer->current() == filer->begin())
        return;
    while (helper_show_must_loop(--filer->current(), filer->begin()))
        ; // noop
}

void CImageViewer::
showNext()
{
    if (filer->current() == filer->end())
        return;

    while (helper_show_must_loop(++filer->current(), filer->end()))
        ; // noop
}

void CImageViewer::
showFirst()
{
    while (helper_show_must_loop(filer->begin(), filer->end()))
        ; // noop
}

void CImageViewer::
showLast()
{
    while (helper_show_must_loop(filer->last(),
        filer->end()))
        ; // nop
}

bool CImageViewer::
setPath(FilePath path)
{
    if (loader->waitIfAnyImageIsLoading() == false) {
        MessageBox(0, TEXT("Loading thread wouldn't respond."
            "Operations are annulled."), 0, 0);
        return false;
    }

    if (!path.exist())
        return false;

    m_dir = (path.isDirectory()) ? path : path.getDir();

    filer->generate(m_dir.path().c_str());
    filer->sort();
    filer->setCurrent(filer->begin());

    if (path.isDirectory()) {
        showFirst();
        return true;
    }

    auto filename = path.getFileName();
    iterator itr = filer->search([filename](Element &p)->bool {
        return (filename == p->fileName());
    });
    setCurrent(itr);
    return true;
}

bool CImageViewer::
setCurrent(iterator itr)
{
    if (itr == filer->end())
        return false;

    // ͈͊ÕLbV폜
    loader->markToReleaseAround(filer->current());
    loader->unmarkAround(itr);
    loader->performReleaseAround(filer->current());

    if (loader->loadImage(itr, true) != Loader::Status::Finished)
        return false;

    // ړ
    filer->setCurrent(itr);
    loader->preloadAround(itr);

    // XV
    list->invalidate();
    updateTitleBar();

    m_offset.reset();
    invalidate_image();
    update();
    return true;
}

void CImageViewer::
reloadCurrent()
{
    if (filer->current() == filer->end())
        return;
    filer->current()->get()->unload();
    if (loader->loadImage(filer->current(), false) == Loader::Status::Finished)
        setCurrent(filer->current());
}

int CImageViewer::
onCommand(WPARAM wp)
{
    ID const id = static_cast<ID>(LOWORD(wp));
    menu->changeStatus(id);

    switch (id) {
    case ID::USE_PROFILE:
        if (menu->isSelected(id))
            profile->enable();
        else
            profile->disable();
        return 1;

    case ID::LAST_PATH:
        setPath(m_lastPath);
        break;

    case ID::FILE_BACK:
        showPrev();
        break;

    case ID::FILE_NEXT:
        showNext();
        break;

    case ID::FILE_FIRST:
        showFirst();
        break;

    case ID::FILE_LAST:
        showLast();
        break;

    case ID::FILE_RELOAD:
        reloadCurrent();
        break;

    case ID::FILE_DELETE:
    case ID::FILE_QUICK_DELETE:
    case ID::LIST_REMOVE:
        if (filer->isEmpty())
            break;
        if (id == ID::FILE_DELETE) {
            if (IDOK != MessageBox(*this, m_textConfirmDelete.c_str(),
                m_captionConfirmDelete.c_str(), MB_OKCANCEL))
                break;
        }
        loader->waitIfLoading(filer->current());
        if (id != ID::LIST_REMOVE &&
            (m_dir + filer->current()->get()->fileName()).trash() == false)
                break;
        filer->erase(filer->current());
        setCurrent(filer->current());
        break;

    case ID::VIEW_POPUP:
        popup(menu->isSelected(id));
        break;

    case ID::VIEW_FILENAME:
        updateTitleBar();
        break;

    case ID::VIEW_FILELIST:
        if (menu->isSelected(id))
            list->show();
        else
            list->hide();
        break;

    case ID::VIEW_UPSCALE:
    case ID::VIEW_DOWNSCALE:
    case ID::VIEW_CENTER:
        m_offset.reset();
        invalidate_image();
        break;

    case ID::LOADER_IMAGE_LOADED:
        list->invalidate();
        break;

    case ID::SCREEN_TOGGLE:
        toggleScreen();
        break;

    case ID::SORT_LESSER_WRITE:
    case ID::SORT_GREATER_WRITE:
    case ID::SORT_LESSER_ACCESS:
    case ID::SORT_GREATER_ACCESS:
    case ID::SORT_LESSER_CREATION:
    case ID::SORT_GREATER_CREATION:
        filer->sort();
        list->invalidate();
        break;

    case ID::WINDOW_CLOSE:
        post(WM::CLOSE, 0, 0);
        break;

    case ID::SHOW_PROPERTY:
        if (!filer->isEmpty()) {
            auto path = m_dir + filer->current()->get()->fileName();
            ShowProperty(*this, path.path().c_str());
        }
        break;

    default:
        return 0;
    } // switch

    return 1;
}

void CImageViewer::
update() const
{
    menu->updateStatus();
    Window::update();
    updateTitleBar();
}

bool CImageViewer::
updateTitleBar() const
{
    tstr title = (filer->isEmpty())
        ? NAME_VERSION
        : filer->current()->get()->fileName();

    int index = filer->isEmpty() ? 0 : filer->indexof(filer->current()) + 1;
    title += TEXT(" [") + basis::ToStr(index)
        + TEXT("/") + basis::ToStr(filer->size())
        + TEXT("]");

    return setTitle(title.c_str());
}

bool CImageViewer::
toggleScreen()
{
    if (!isMaximized()) {
        popup();
        maximize();
    }
    else if (!isMultiMaximized()) {
        popup();
        maximize_multi();
    }
    else {
        normalize();
        popup(menu->isSelected(ID::VIEW_POPUP));
    }
    m_offset.reset();
    invalidate();
    return true;
}

ID CImageViewer::getSortWay() const
{
    return menu->getSortWay();
}

bool CImageViewer::isMultiMaximized() const
{
    if (!isMaximized())
        return false;

    Rect vs = basis::Monitor::GetVirtualScreen();
    Rect rc = getRect();
    return (rc.width() >= vs.width() && rc.height() >= vs.height());
}

int CImageViewer::
onPaint()
{
    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(*this, &ps);

    if (m_backbuffer.compatible(hdc, getClientSize())) {
        invalidate(getClientRect());
        SetBkMode(m_backbuffer, TRANSPARENT);
        m_backbuffer.pen(GetStockObject(WHITE_PEN));
        m_backbuffer.brush(GetStockObject(WHITE_BRUSH));
        isImageInvalidated = true;
    }

    if (filer->isEmpty()) {
        m_backbuffer.rectangle(ps.rcPaint);
    }
    else {
        Rect image_rect;
        if (!filer->isEmpty())
            image_rect = filer->current()->get()->rect();
        Size drawing_size = getDrawSize(image_rect.size());

        Rect src = { 0, 0, drawing_size.x, drawing_size.y };
        if (m_offscreen.compatible(hdc, drawing_size) || isImageInvalidated) {
            isImageInvalidated = false;
            filer->current()->get()->draw(m_offscreen, src, image_rect);
        }

        m_drawingRect = getDrawRect(drawing_size);
        m_offscreen.transfer(m_backbuffer, m_drawingRect, src);
        ClearBackground(m_backbuffer, ps.rcPaint, m_drawingRect);
    }

    list->draw(&m_backbuffer);
    m_backbuffer.transfer(hdc, ps.rcPaint, ps.rcPaint);
    EndPaint(*this, &ps);
    return 1;
}

basis::Rect CImageViewer::
getDrawRect() const
{
    if (filer->isEmpty())
        return{};
    return getDrawRect(getDrawSize(filer->current()->get()->size()));
}

basis::Rect CImageViewer::
getDrawRect(const Size &size) const
{
    Rect rc{ 0, 0, size.x, size.y };
    rc.move(m_offset);
    if (menu->isSelected(ID::VIEW_CENTER))
        rc.move((getClientSize() - size) / 2);
    return rc;
}

basis::Size CImageViewer::
getDrawSize(const Size &image_size) const
{
    Size size = image_size;
    const auto client = getClientSize();

    if (!client.x || !client.y || !size.x || !size.y)
        return{};

    if (menu->isSelected((client.x > size.x && client.y > size.y)
        ? ID::VIEW_UPSCALE : ID::VIEW_DOWNSCALE))
    {
        if (static_cast<double>(size.x) / client.x
            > static_cast<double>(size.y) / client.y)
        {
            size.y = static_cast<int>(0.5 + size.y
                * static_cast<double>(client.x) / size.x);
            size.x = client.x;
        }
        else {
            size.x = static_cast<int>(0.5 + size.x
                * static_cast<double>(client.y) / size.y);
            size.y = client.y;
        }
    }
    return size;
}

void CImageViewer::
invalidate() const
{
    isImageInvalidated = true;
    Window::invalidate();
}

void CImageViewer::
invalidate_image() const
{
    isImageInvalidated = true;
    invalidate(m_drawingRect);
    invalidate(getDrawRect());
}

void CImageViewer::move_image(Size diff)
{
    m_offset += diff;
    invalidate(getDrawRect().unite(m_drawingRect));
}

}  // namespace
<|endoftext|>


<commit_before>#ifndef CPPNOTESMAIN_WORD_SEARCH_HPP
#define CPPNOTESMAIN_WORD_SEARCH_HPP

/*
https://leetcode.com/problems/word-search/
Given an m x n board and a word, find if the word exists in the grid.

The word can be constructed from letters of sequentially adjacent cells, where "adjacent" cells
are horizontally or vertically neighboring. The same letter cell may not be used more than once.

Example 1:
Input: board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED"
Output: true

Example 2:
Input: board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "SEE"
Output: true

Example 3:
Input: board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCB"
Output: false

Constraints:
* m == board.length
* n = board[i].length
* 1 <= m, n <= 200
* 1 <= word.length <= 103
* board and word consists only of lowercase and uppercase English letters.
*/

#include <vector>
#include <string>

namespace Algo::DS::Array {
    class WordSearch {
        const std::vector<int> r_shifts = {-1, 0, 1, 0};
        const std::vector<int> c_shifts = {0, 1, 0, -1};
        const char VC = '%';

        size_t m_max_r;
        size_t m_max_c;
        size_t m_w_pos;

        bool search(
            std::vector<std::vector<char>>& board, const std::string& word, size_t r, size_t c)
        {
            board[r][c] = VC;

            const auto cur_pos = m_w_pos;
            const auto next_w_pos = m_w_pos + 1;
            if (next_w_pos >= word.size()) { return true; }

            for (size_t i = 0; i < r_shifts.size(); ++i)  {
                const auto nr = r + r_shifts[i];
                const auto nc = c + c_shifts[i];
                if (nr >= m_max_r || nc >= m_max_c) { continue; }

                if (board[nr][nc] == word[next_w_pos]) {
                    m_w_pos = next_w_pos;
                    if (search(board, word, nr, nc)) { return true; }
                }
            }

            board[r][c] = word[m_w_pos];
            if (m_w_pos > 0) { --m_w_pos; }

            return false;
        }

    public:
        bool exist(std::vector<std::vector<char>>& board, const std::string& word) {
            if (word.empty()) { return true; }

            m_max_r = board.size();
            m_max_c = board.front().size();
            m_w_pos = 0;

            for (size_t r = 0; r < m_max_r; ++r) {
                for (size_t c = 0; c < m_max_c; ++c) {
                    if (board[r][c] == word.front()) {
                        if (search(board, word, r, c)) { return true; }
                    }
                }
            }

            return false;
        }
    };
}

#endif //CPPNOTESMAIN_WORD_SEARCH_HPP
<commit_msg>Add new function to WordSearch class - find_words()<commit_after>#ifndef CPPNOTESMAIN_WORD_SEARCH_HPP
#define CPPNOTESMAIN_WORD_SEARCH_HPP

/*
https://leetcode.com/problems/word-search/
Given an m x n board and a word, find if the word exists in the grid.

The word can be constructed from letters of sequentially adjacent cells, where "adjacent" cells
are horizontally or vertically neighboring. The same letter cell may not be used more than once.

Example 1:
Input: board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED"
Output: true

Example 2:
Input: board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "SEE"
Output: true

Example 3:
Input: board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCB"
Output: false

Constraints:
* m == board.length
* n = board[i].length
* 1 <= m, n <= 200
* 1 <= word.length <= 103
* board and word consists only of lowercase and uppercase English letters.
*/

/*
https://leetcode.com/problems/word-search-ii/
Given an m x n board of characters and a list of strings words, return all words on the board.

Each word must be constructed from letters of sequentially adjacent cells, where adjacent cells
are horizontally or vertically neighboring. The same letter cell may not be used more than once
in a word.

Example 1:
Input: board = [["o","a","a","n"],["e","t","a","e"],["i","h","k","r"],["i","f","l","v"]],
words = ["oath","pea","eat","rain"]
Output: ["eat","oath"]

Example 2:
Input: board = [["a","b"],["c","d"]], words = ["abcb"]
Output: []

Constraints:
* m == board.length
* n == board[i].length
* 1 <= m, n <= 12
* board[i][j] is a lowercase English letter.
* 1 <= words.length <= 3 * 104
* 1 <= words[i].length <= 10
* words[i] consists of lowercase English letters.
* All the strings of words are unique.
*/

#include <vector>
#include <string>

namespace Algo::DS::Array {
    class WordSearch {
        const std::vector<int> r_shifts = {-1, 0, 1, 0};
        const std::vector<int> c_shifts = {0, 1, 0, -1};
        const char VC = '%';

        size_t m_max_r;
        size_t m_max_c;
        size_t m_w_pos;

        bool search(
            std::vector<std::vector<char>>& board, const std::string& word, size_t r, size_t c)
        {
            board[r][c] = VC;

            const auto cur_pos = m_w_pos;
            const auto next_w_pos = m_w_pos + 1;
            if (next_w_pos >= word.size()) { return true; }

            for (size_t i = 0; i < r_shifts.size(); ++i)  {
                const auto nr = r + r_shifts[i];
                const auto nc = c + c_shifts[i];
                if (nr >= m_max_r || nc >= m_max_c) { continue; }

                if (board[nr][nc] == word[next_w_pos]) {
                    m_w_pos = next_w_pos;
                    if (search(board, word, nr, nc)) { return true; }
                }
            }

            board[r][c] = word[m_w_pos];
            if (m_w_pos > 0) { --m_w_pos; }

            return false;
        }

    public:
        bool exist(std::vector<std::vector<char>>& board, const std::string& word) {
            if (word.empty()) { return true; }

            m_max_r = board.size();
            m_max_c = board.front().size();
            m_w_pos = 0;

            for (size_t r = 0; r < m_max_r; ++r) {
                for (size_t c = 0; c < m_max_c; ++c) {
                    if (board[r][c] == word.front()) {
                        if (search(board, word, r, c)) { return true; }
                    }
                }
            }

            return false;
        }

        std::vector<std::string> find_words(
            std::vector<std::vector<char>>& board, std::vector<std::string>& words)
        {
            std::vector<std::string> res;
            for (const auto& w : words) {
                const auto tmp_board = board;
                if (exist(tmp_board, w)) { res.push_back(w); }
            }

            return res;
        }
    };
}

#endif //CPPNOTESMAIN_WORD_SEARCH_HPP
<|endoftext|>


<commit_before>//#define LOG_AT_W  /* warning only */
#include "stinger_core/stinger_error.h"

#include "stinger_core/xmalloc.h"
#include "rapidjson/document.h"
#include "json_rpc_server.h"
#include "json_rpc.h"

using namespace gt::stinger;

int64_t
JSON_RPC_egonet::operator()(rapidjson::Value * params, rapidjson::Value & result, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> & allocator)
{
  int64_t source;
  bool strings;
  bool get_types;
  bool get_etypes;
  bool get_vtypes;
  bool incident_edges;

  rpc_params_t p[] = {
    {"source", TYPE_VERTEX, &source, false, 0},
    {"strings", TYPE_BOOL, &strings, true, 0},
    {"get_types", TYPE_BOOL, &get_types, true, 0},
    {"get_etypes", TYPE_BOOL, &get_etypes, true, 0},
    {"get_vtypes", TYPE_BOOL, &get_vtypes, true, 0},
    {"incident_edges", TYPE_BOOL, &incident_edges, true, 0},
    {NULL, TYPE_NONE, NULL, false, 0}
  };

  if (!contains_params(p, params)) {
    return json_rpc_error(-32602, result, allocator);
  }

  if(get_types) {
    get_etypes = true;
    get_vtypes = true;
  }

  stinger_t * S = server_state->get_stinger();
  if (!S) {
    LOG_E ("STINGER pointer is invalid");
    return json_rpc_error(-32603, result, allocator);
  }

  /* array to hold a single edge */
  rapidjson::Value val(rapidjson::kArrayType);

  /* array to hold all edges (virtually addressed) */
  rapidjson::Value edges(rapidjson::kArrayType);

  /* array to hold all edges (physically addressed) */
  rapidjson::Value edges_str(rapidjson::kArrayType);

  /* array to hold all vertices (virtually addressed) */
  rapidjson::Value vtx(rapidjson::kArrayType);

  /* array to hold all vertices (physically addressed) */
  rapidjson::Value vtx_str(rapidjson::kArrayType);

  /* values to hold vertex information */
  rapidjson::Value vtype, vtype_str;
  rapidjson::Value center, center_str;
  rapidjson::Value src, dst;
  rapidjson::Value src_str, dst_str;
  rapidjson::Value etype, etype_str;

  /* array to hold vertex types */
  rapidjson::Value vtypes(rapidjson::kArrayType);

  /* array to hold vertex type strings */
  rapidjson::Value vtypes_str(rapidjson::kArrayType);

  /* vertex has no edges -- this is easy */
  if (stinger_outdegree (S, source) == 0) {
    result.AddMember("egonet", edges, allocator);
    return 0;
  }

  /* this array will hold the neighbor set */
  int64_t nv = S->max_nv;
  int64_t * marks = (int64_t *) xmalloc (nv * sizeof(int64_t));
  for (int64_t i = 0; i < nv; i++) {
    marks[i] = 0;
  }

  /* mark and insert source if we are returning incident edges */
  if (incident_edges) {
    marks[source] = 1;
    center.SetInt64(source);
    vtx.PushBack(center, allocator);

    if (strings) {
      char * physID;
      uint64_t len;
      if (-1 == stinger_mapping_physid_direct(S, source, &physID, &len)) {
	physID = (char *) "";
	len = 0;
      }
      center_str.SetString(physID, len, allocator);
      vtx_str.PushBack(center_str, allocator);
    }

    if (get_vtypes) {
      int64_t source_type = stinger_vtype_get(S, source);
      vtype.SetInt64(source_type);
      vtypes.PushBack(vtype, allocator);

      if (strings) {
	char * name = NULL;
	uint64_t len = 0;
	char * vtype_name = stinger_vtype_names_lookup_name(S, source_type);
	vtype_str.SetString(vtype_name, strlen(vtype_name), allocator);
	vtypes_str.PushBack(vtype_str, allocator);
      }
    }
  }

  /* mark all neighbors of the source vertex */
  STINGER_FORALL_EDGES_OF_VTX_BEGIN (S, source) {
    int64_t u = STINGER_EDGE_DEST;
    marks[u] = 1;
    src.SetInt64(u);
    vtx.PushBack(src, allocator);

    if (strings) {
      char * physID;
      uint64_t len;
      if (-1 == stinger_mapping_physid_direct(S, u, &physID, &len)) {
	physID = (char *) "";
	len = 0;
      }
      src_str.SetString(physID, len, allocator);
      vtx_str.PushBack(src_str, allocator);
    }

    if (incident_edges) {
      src.SetInt64(source);
      dst.SetInt64(u);
      val.SetArray();
      val.PushBack(src, allocator);
      val.PushBack(dst, allocator);
      if (get_etypes) {
	etype.SetInt64(STINGER_EDGE_TYPE);
	val.PushBack(etype, allocator);
      }
      edges.PushBack(val, allocator);

      if (strings) {
	char * physID;
	uint64_t len;
	if (-1 == stinger_mapping_physid_direct(S, source, &physID, &len)) {
	  physID = (char *) "";
	  len = 0;
	}
	src_str.SetString(physID, len, allocator);

	if (-1 == stinger_mapping_physid_direct(S, u, &physID, &len)) {
	  physID = (char *) "";
	  len = 0;
	}
	dst_str.SetString(physID, len, allocator);

	val.SetArray();
	val.PushBack(src_str, allocator);
	val.PushBack(dst_str, allocator);
	if (get_etypes) {
	  char * etype_str_ptr = stinger_etype_names_lookup_name(S, STINGER_EDGE_TYPE);
	  etype_str.SetString(etype_str_ptr, strlen(etype_str_ptr), allocator);
	  val.PushBack(etype_str, allocator);
	}
	edges_str.PushBack(val, allocator);
      }
    }

    if (get_vtypes) {
      int64_t source_type = stinger_vtype_get(S, u);
      vtype.SetInt64(source_type);
      vtypes.PushBack(vtype, allocator);

      if (strings) {
	char * name = NULL;
	uint64_t len = 0;
	char * vtype_name = stinger_vtype_names_lookup_name(S, source_type);
	vtype_str.SetString(vtype_name, strlen(vtype_name), allocator);
	vtypes_str.PushBack(vtype_str, allocator);
      }
    }

  } STINGER_FORALL_EDGES_OF_VTX_END();

  /* now we will find all of the edges in common between the neighbors */
  STINGER_FORALL_EDGES_OF_VTX_BEGIN (S, source) {
    int64_t u = STINGER_EDGE_DEST;

    STINGER_FORALL_EDGES_OF_VTX_BEGIN (S, u) {
      int64_t v = STINGER_EDGE_DEST;

      if (marks[v]) {
	src.SetInt64(u);
	dst.SetInt64(v);
	val.SetArray();
	val.PushBack(src, allocator);
	val.PushBack(dst, allocator);
	if (get_etypes) {
	  etype.SetInt64(STINGER_EDGE_TYPE);
	  val.PushBack(etype, allocator);
	}
	edges.PushBack(val, allocator);

	if (strings) {
	  char * physID;
	  uint64_t len;
	  if (-1 == stinger_mapping_physid_direct(S, u, &physID, &len)) {
	    physID = (char *) "";
	    len = 0;
	  }
	  src_str.SetString(physID, len, allocator);

	  if (-1 == stinger_mapping_physid_direct(S, v, &physID, &len)) {
	    physID = (char *) "";
	    len = 0;
	  }
	  dst_str.SetString(physID, len, allocator);
	  val.SetArray();
	  val.PushBack(src_str, allocator);
	  val.PushBack(dst_str, allocator);
	  if (get_etypes) {
	    char * etype_str_ptr = stinger_etype_names_lookup_name(S, STINGER_EDGE_TYPE);
	    etype_str.SetString(etype_str_ptr, strlen(etype_str_ptr), allocator);
	    val.PushBack(etype_str, allocator);
	  }
	  edges_str.PushBack(val, allocator);
	}
      }

    } STINGER_FORALL_EDGES_OF_VTX_END();
  } STINGER_FORALL_EDGES_OF_VTX_END();

  result.AddMember("vertices", vtx, allocator);
  if (strings) {
    result.AddMember("vertices_str", vtx_str, allocator);
  }

  if (get_vtypes) {
    result.AddMember("vtypes", vtypes, allocator);
    if (strings) {
      result.AddMember("vtypes_str", vtypes_str, allocator);
    }
  }

  result.AddMember("egonet", edges, allocator);
  if (strings) {
    result.AddMember("egonet_str", edges_str, allocator);
  }

  free(marks);

  return 0;
}

<commit_msg>Breaking egonet to only show a random vertex with outdegree between 10 and 50.<commit_after>//#define LOG_AT_W  /* warning only */
#include "stinger_core/stinger_error.h"

#include "stinger_core/xmalloc.h"
#include "rapidjson/document.h"
#include "json_rpc_server.h"
#include "json_rpc.h"

using namespace gt::stinger;

int64_t
JSON_RPC_egonet::operator()(rapidjson::Value * params, rapidjson::Value & result, rapidjson::MemoryPoolAllocator<rapidjson::CrtAllocator> & allocator)
{
  int64_t source;
  bool strings;
  bool get_types;
  bool get_etypes;
  bool get_vtypes;
  bool incident_edges;

  rpc_params_t p[] = {
    {"source", TYPE_VERTEX, &source, false, 0},
    {"strings", TYPE_BOOL, &strings, true, 0},
    {"get_types", TYPE_BOOL, &get_types, true, 0},
    {"get_etypes", TYPE_BOOL, &get_etypes, true, 0},
    {"get_vtypes", TYPE_BOOL, &get_vtypes, true, 0},
    {"incident_edges", TYPE_BOOL, &incident_edges, true, 0},
    {NULL, TYPE_NONE, NULL, false, 0}
  };

  if (!contains_params(p, params)) {
    return json_rpc_error(-32602, result, allocator);
  }

  if(get_types) {
    get_etypes = true;
    get_vtypes = true;
  }

  stinger_t * S = server_state->get_stinger();
  if (!S) {
    LOG_E ("STINGER pointer is invalid");
    return json_rpc_error(-32603, result, allocator);
  }

  /* find a vertex with more than 10 edges and less than 50 */
  int64_t max_nv = S->max_nv;
  int64_t selected_vertex = -1;
  for (int64_t i = 0; i < max_nv; i++) {
    int64_t outdegree = stinger_outdegree(S, i);
    if (outdegree < 50 && outdegree > 10) {
      selected_vertex = i;
      break;
    }
  }
  source = selected_vertex;

  /* array to hold a single edge */
  rapidjson::Value val(rapidjson::kArrayType);

  /* array to hold all edges (virtually addressed) */
  rapidjson::Value edges(rapidjson::kArrayType);

  /* array to hold all edges (physically addressed) */
  rapidjson::Value edges_str(rapidjson::kArrayType);

  /* array to hold all vertices (virtually addressed) */
  rapidjson::Value vtx(rapidjson::kArrayType);

  /* array to hold all vertices (physically addressed) */
  rapidjson::Value vtx_str(rapidjson::kArrayType);

  /* values to hold vertex information */
  rapidjson::Value vtype, vtype_str;
  rapidjson::Value center, center_str;
  rapidjson::Value src, dst;
  rapidjson::Value src_str, dst_str;
  rapidjson::Value etype, etype_str;

  /* array to hold vertex types */
  rapidjson::Value vtypes(rapidjson::kArrayType);

  /* array to hold vertex type strings */
  rapidjson::Value vtypes_str(rapidjson::kArrayType);

  /* vertex has no edges -- this is easy */
  if (stinger_outdegree (S, source) == 0) {
    result.AddMember("egonet", edges, allocator);
    return 0;
  }

  /* this array will hold the neighbor set */
  int64_t nv = S->max_nv;
  int64_t * marks = (int64_t *) xmalloc (nv * sizeof(int64_t));
  for (int64_t i = 0; i < nv; i++) {
    marks[i] = 0;
  }

  /* mark and insert source if we are returning incident edges */
  if (incident_edges) {
    marks[source] = 1;
    center.SetInt64(source);
    vtx.PushBack(center, allocator);

    if (strings) {
      char * physID;
      uint64_t len;
      if (-1 == stinger_mapping_physid_direct(S, source, &physID, &len)) {
	physID = (char *) "";
	len = 0;
      }
      center_str.SetString(physID, len, allocator);
      vtx_str.PushBack(center_str, allocator);
    }

    if (get_vtypes) {
      int64_t source_type = stinger_vtype_get(S, source);
      vtype.SetInt64(source_type);
      vtypes.PushBack(vtype, allocator);

      if (strings) {
	char * name = NULL;
	uint64_t len = 0;
	char * vtype_name = stinger_vtype_names_lookup_name(S, source_type);
	vtype_str.SetString(vtype_name, strlen(vtype_name), allocator);
	vtypes_str.PushBack(vtype_str, allocator);
      }
    }
  }

  /* mark all neighbors of the source vertex */
  STINGER_FORALL_EDGES_OF_VTX_BEGIN (S, source) {
    int64_t u = STINGER_EDGE_DEST;
    marks[u] = 1;
    src.SetInt64(u);
    vtx.PushBack(src, allocator);

    if (strings) {
      char * physID;
      uint64_t len;
      if (-1 == stinger_mapping_physid_direct(S, u, &physID, &len)) {
	physID = (char *) "";
	len = 0;
      }
      src_str.SetString(physID, len, allocator);
      vtx_str.PushBack(src_str, allocator);
    }

    if (incident_edges) {
      src.SetInt64(source);
      dst.SetInt64(u);
      val.SetArray();
      val.PushBack(src, allocator);
      val.PushBack(dst, allocator);
      if (get_etypes) {
	etype.SetInt64(STINGER_EDGE_TYPE);
	val.PushBack(etype, allocator);
      }
      edges.PushBack(val, allocator);

      if (strings) {
	char * physID;
	uint64_t len;
	if (-1 == stinger_mapping_physid_direct(S, source, &physID, &len)) {
	  physID = (char *) "";
	  len = 0;
	}
	src_str.SetString(physID, len, allocator);

	if (-1 == stinger_mapping_physid_direct(S, u, &physID, &len)) {
	  physID = (char *) "";
	  len = 0;
	}
	dst_str.SetString(physID, len, allocator);

	val.SetArray();
	val.PushBack(src_str, allocator);
	val.PushBack(dst_str, allocator);
	if (get_etypes) {
	  char * etype_str_ptr = stinger_etype_names_lookup_name(S, STINGER_EDGE_TYPE);
	  etype_str.SetString(etype_str_ptr, strlen(etype_str_ptr), allocator);
	  val.PushBack(etype_str, allocator);
	}
	edges_str.PushBack(val, allocator);
      }
    }

    if (get_vtypes) {
      int64_t source_type = stinger_vtype_get(S, u);
      vtype.SetInt64(source_type);
      vtypes.PushBack(vtype, allocator);

      if (strings) {
	char * name = NULL;
	uint64_t len = 0;
	char * vtype_name = stinger_vtype_names_lookup_name(S, source_type);
	vtype_str.SetString(vtype_name, strlen(vtype_name), allocator);
	vtypes_str.PushBack(vtype_str, allocator);
      }
    }

  } STINGER_FORALL_EDGES_OF_VTX_END();

  /* now we will find all of the edges in common between the neighbors */
  STINGER_FORALL_EDGES_OF_VTX_BEGIN (S, source) {
    int64_t u = STINGER_EDGE_DEST;

    STINGER_FORALL_EDGES_OF_VTX_BEGIN (S, u) {
      int64_t v = STINGER_EDGE_DEST;

      if (marks[v]) {
	src.SetInt64(u);
	dst.SetInt64(v);
	val.SetArray();
	val.PushBack(src, allocator);
	val.PushBack(dst, allocator);
	if (get_etypes) {
	  etype.SetInt64(STINGER_EDGE_TYPE);
	  val.PushBack(etype, allocator);
	}
	edges.PushBack(val, allocator);

	if (strings) {
	  char * physID;
	  uint64_t len;
	  if (-1 == stinger_mapping_physid_direct(S, u, &physID, &len)) {
	    physID = (char *) "";
	    len = 0;
	  }
	  src_str.SetString(physID, len, allocator);

	  if (-1 == stinger_mapping_physid_direct(S, v, &physID, &len)) {
	    physID = (char *) "";
	    len = 0;
	  }
	  dst_str.SetString(physID, len, allocator);
	  val.SetArray();
	  val.PushBack(src_str, allocator);
	  val.PushBack(dst_str, allocator);
	  if (get_etypes) {
	    char * etype_str_ptr = stinger_etype_names_lookup_name(S, STINGER_EDGE_TYPE);
	    etype_str.SetString(etype_str_ptr, strlen(etype_str_ptr), allocator);
	    val.PushBack(etype_str, allocator);
	  }
	  edges_str.PushBack(val, allocator);
	}
      }

    } STINGER_FORALL_EDGES_OF_VTX_END();
  } STINGER_FORALL_EDGES_OF_VTX_END();

  result.AddMember("vertices", vtx, allocator);
  if (strings) {
    result.AddMember("vertices_str", vtx_str, allocator);
  }

  if (get_vtypes) {
    result.AddMember("vtypes", vtypes, allocator);
    if (strings) {
      result.AddMember("vtypes_str", vtypes_str, allocator);
    }
  }

  result.AddMember("egonet", edges, allocator);
  if (strings) {
    result.AddMember("egonet_str", edges_str, allocator);
  }

  free(marks);

  return 0;
}

<|endoftext|>


<commit_before>// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
/*
 * Ceph - scalable distributed file system
 *
 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
 *
 * This is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1, as published by the Free Software
 * Foundation.  See file COPYING.
 *
 */

/*
    FUSE: Filesystem in Userspace
    Copyright (C) 2001-2005  Miklos Szeredi <miklos@szeredi.hu>

    This program can be distributed under the terms of the GNU GPL.
    See the file COPYING.
*/

// fuse crap
#ifdef linux
/* For pread()/pwrite() */
#define _XOPEN_SOURCE 500
#endif

#define FUSE_USE_VERSION 26

#include <fuse.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <errno.h>
#include <sys/statvfs.h>

// ceph stuff
#include "include/types.h"

#include "Client.h"

#include "config.h"

// globals
static Client *client;     // the ceph client

// ------
// fuse hooks

static int ceph_getattr(const char *path, struct stat *stbuf)
{
  return client->lstat(path, stbuf);
}

static int ceph_readlink(const char *path, char *buf, size_t size)
{
  int res;

  res = client->readlink(path, buf, size - 1);
  if (res < 0) return res;

  buf[res] = '\0';
  return 0;
}

static int ceph_mknod(const char *path, mode_t mode, dev_t rdev)
{
  return client->mknod(path, mode);
}

static int ceph_mkdir(const char *path, mode_t mode)
{
  return client->mkdir(path, mode);
}

static int ceph_unlink(const char *path)
{
  return client->unlink(path);
}

static int ceph_rmdir(const char *path)
{
  return client->rmdir(path);
}

static int ceph_symlink(const char *from, const char *to)
{
  return client->symlink(from, to);
}

static int ceph_rename(const char *from, const char *to)
{
  return client->rename(from, to);
}

static int ceph_link(const char *from, const char *to)
{
  return client->link(from, to);
}

static int ceph_chmod(const char *path, mode_t mode)
{
  return client->chmod(path, mode);
}

static int ceph_chown(const char *path, uid_t uid, gid_t gid)
{
  return client->chown(path, uid, gid);
}

static int ceph_truncate(const char *path, off_t size)
{
  return client->truncate(path, size);
}

static int ceph_utime(const char *path, struct utimbuf *buf)
{
  return client->utime(path, buf);
}

// ------------------
// file i/o

static int ceph_open(const char *path, struct fuse_file_info *fi)
{
  int res;

  res = client->open(path, fi->flags, 0);
  if (res < 0) return res;
  fi->fh = res;
  return 0;  // fuse wants 0 onsucess
}

static int ceph_read(const char *path, char *buf, size_t size, off_t offset,
                     struct fuse_file_info *fi)
{
  fh_t fh = fi->fh;
  return client->read(fh, buf, size, offset);
}

static int ceph_write(const char *path, const char *buf, size_t size,
                     off_t offset, struct fuse_file_info *fi)
{
  fh_t fh = fi->fh;
  return client->write(fh, buf, size, offset);
}

static int ceph_flush(const char *path, struct fuse_file_info *fi)
{
//fh_t fh = fi->fh;
  //return client->flush(fh);
  return 0;
}

static int ceph_statfs(const char *path, struct statvfs *stbuf)
{
  return client->statfs(path, stbuf);
}

static int ceph_release(const char *path, struct fuse_file_info *fi)
{
  fh_t fh = fi->fh;
  int r = client->close(fh);  // close the file
  return r;
}

static int ceph_fsync(const char *path, int isdatasync,
                     struct fuse_file_info *fi)
{
  fh_t fh = fi->fh;
  return client->fsync(fh, isdatasync ? true:false);
}

// ---------------------
// directory i/o

static int ceph_opendir(const char *path, struct fuse_file_info *fi)
{
  DIR *dirp;
  int r = client->opendir(path, &dirp);
  if (r < 0) return r;
  fi->fh = (uint64_t)(void*)dirp;
  return 0;
}

static int ceph_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t off, fuse_file_info *fi)
{
  DIR *dirp = (DIR*)fi->fh;

  client->seekdir(dirp, off);

  int res = 0;
  struct dirent de;
  struct stat st;
  int stmask = 0;
  while (res == 0) {
    int r = client->readdirplus_r(dirp, &de, &st, &stmask);
    if (r != 0) break;
    int stneed = InodeStat::MASK_INO | InodeStat::MASK_TYPE;
    res = filler(buf,
                 de.d_name,
		 ((stmask & stneed) == stneed) ? &st:0,
		 client->telldir(dirp));
  }
  return 0;
}

static int ceph_releasedir(const char *path, struct fuse_file_info *fi)
{
  DIR *dirp = (DIR*)fi->fh;
  int r = client->closedir(dirp);  // close the file
  return r;
}

static struct fuse_operations ceph_oper = {
  getattr: ceph_getattr,
  readlink: ceph_readlink,
  getdir: 0,
  mknod: ceph_mknod,
  mkdir: ceph_mkdir,
  unlink: ceph_unlink,
  rmdir: ceph_rmdir,
  symlink: ceph_symlink,
  rename: ceph_rename,
  link: ceph_link,
  chmod: ceph_chmod,
  chown: ceph_chown,
  truncate: ceph_truncate,
  utime: ceph_utime,
  open: ceph_open,
  read: ceph_read,
  write: ceph_write,
  statfs: ceph_statfs,
  flush: ceph_flush,
  release: ceph_release,
  fsync: ceph_fsync,
  setxattr: 0,
  getxattr: 0,
  listxattr: 0,
  removexattr: 0,
  opendir: ceph_opendir,
  readdir: ceph_readdir,
  releasedir: ceph_releasedir
};

int ceph_fuse_main(Client *c, int argc, char *argv[])
{
  // init client
  client = c;

  // set up fuse argc/argv
  int newargc = 0;
  char **newargv = (char **) malloc((argc + 10) * sizeof(char *));
  newargv[newargc++] = argv[0];

  // allow other (all!) users to see my file system
  // NOTE: echo user_allow_other >> /etc/fuse.conf
  // NB: seems broken on Darwin
#ifndef DARWIN
  newargv[newargc++] = "-o";
  newargv[newargc++] = "allow_other";
#endif // DARWIN

  // use inos
  newargv[newargc++] = "-o";
  newargv[newargc++] = "use_ino";

  // large reads, direct_io (no kernel cachine)
  //newargv[newargc++] = "-o";
  //newargv[newargc++] = "large_read";
  if (g_conf.fuse_direct_io) {
    newargv[newargc++] = "-o";
    newargv[newargc++] = "direct_io";
  }

  // disable stupid fuse unlink hiding thing
  newargv[newargc++] = "-o";
  newargv[newargc++] = "hard_remove";

  // force into foreground
  //   -> we can watch stdout this way!!
  newargv[newargc++] = "-f";

  // copy rest of cmdline (hopefully, the mount point!)
  for (int argctr = 1; argctr < argc; argctr++) newargv[newargc++] = argv[argctr];

  // go fuse go
  cout << "ok, calling fuse_main" << endl;
  int r = fuse_main(newargc, newargv, &ceph_oper, 0);
  return r;
}
<commit_msg>stat mask rename fallout<commit_after>// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
/*
 * Ceph - scalable distributed file system
 *
 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
 *
 * This is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1, as published by the Free Software
 * Foundation.  See file COPYING.
 *
 */

/*
    FUSE: Filesystem in Userspace
    Copyright (C) 2001-2005  Miklos Szeredi <miklos@szeredi.hu>

    This program can be distributed under the terms of the GNU GPL.
    See the file COPYING.
*/

// fuse crap
#ifdef linux
/* For pread()/pwrite() */
#define _XOPEN_SOURCE 500
#endif

#define FUSE_USE_VERSION 26

#include <fuse.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <errno.h>
#include <sys/statvfs.h>

// ceph stuff
#include "include/types.h"

#include "Client.h"

#include "config.h"

// globals
static Client *client;     // the ceph client

// ------
// fuse hooks

static int ceph_getattr(const char *path, struct stat *stbuf)
{
  return client->lstat(path, stbuf);
}

static int ceph_readlink(const char *path, char *buf, size_t size)
{
  int res;

  res = client->readlink(path, buf, size - 1);
  if (res < 0) return res;

  buf[res] = '\0';
  return 0;
}

static int ceph_mknod(const char *path, mode_t mode, dev_t rdev)
{
  return client->mknod(path, mode);
}

static int ceph_mkdir(const char *path, mode_t mode)
{
  return client->mkdir(path, mode);
}

static int ceph_unlink(const char *path)
{
  return client->unlink(path);
}

static int ceph_rmdir(const char *path)
{
  return client->rmdir(path);
}

static int ceph_symlink(const char *from, const char *to)
{
  return client->symlink(from, to);
}

static int ceph_rename(const char *from, const char *to)
{
  return client->rename(from, to);
}

static int ceph_link(const char *from, const char *to)
{
  return client->link(from, to);
}

static int ceph_chmod(const char *path, mode_t mode)
{
  return client->chmod(path, mode);
}

static int ceph_chown(const char *path, uid_t uid, gid_t gid)
{
  return client->chown(path, uid, gid);
}

static int ceph_truncate(const char *path, off_t size)
{
  return client->truncate(path, size);
}

static int ceph_utime(const char *path, struct utimbuf *buf)
{
  return client->utime(path, buf);
}

// ------------------
// file i/o

static int ceph_open(const char *path, struct fuse_file_info *fi)
{
  int res;

  res = client->open(path, fi->flags, 0);
  if (res < 0) return res;
  fi->fh = res;
  return 0;  // fuse wants 0 onsucess
}

static int ceph_read(const char *path, char *buf, size_t size, off_t offset,
                     struct fuse_file_info *fi)
{
  fh_t fh = fi->fh;
  return client->read(fh, buf, size, offset);
}

static int ceph_write(const char *path, const char *buf, size_t size,
                     off_t offset, struct fuse_file_info *fi)
{
  fh_t fh = fi->fh;
  return client->write(fh, buf, size, offset);
}

static int ceph_flush(const char *path, struct fuse_file_info *fi)
{
//fh_t fh = fi->fh;
  //return client->flush(fh);
  return 0;
}

static int ceph_statfs(const char *path, struct statvfs *stbuf)
{
  return client->statfs(path, stbuf);
}

static int ceph_release(const char *path, struct fuse_file_info *fi)
{
  fh_t fh = fi->fh;
  int r = client->close(fh);  // close the file
  return r;
}

static int ceph_fsync(const char *path, int isdatasync,
                     struct fuse_file_info *fi)
{
  fh_t fh = fi->fh;
  return client->fsync(fh, isdatasync ? true:false);
}

// ---------------------
// directory i/o

static int ceph_opendir(const char *path, struct fuse_file_info *fi)
{
  DIR *dirp;
  int r = client->opendir(path, &dirp);
  if (r < 0) return r;
  fi->fh = (uint64_t)(void*)dirp;
  return 0;
}

static int ceph_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t off, fuse_file_info *fi)
{
  DIR *dirp = (DIR*)fi->fh;

  client->seekdir(dirp, off);

  int res = 0;
  struct dirent de;
  struct stat st;
  int stmask = 0;
  while (res == 0) {
    int r = client->readdirplus_r(dirp, &de, &st, &stmask);
    if (r != 0) break;
    int stneed = STAT_MASK_INO | STAT_MASK_TYPE;
    res = filler(buf,
                 de.d_name,
		 ((stmask & stneed) == stneed) ? &st:0,
		 client->telldir(dirp));
  }
  return 0;
}

static int ceph_releasedir(const char *path, struct fuse_file_info *fi)
{
  DIR *dirp = (DIR*)fi->fh;
  int r = client->closedir(dirp);  // close the file
  return r;
}

static struct fuse_operations ceph_oper = {
  getattr: ceph_getattr,
  readlink: ceph_readlink,
  getdir: 0,
  mknod: ceph_mknod,
  mkdir: ceph_mkdir,
  unlink: ceph_unlink,
  rmdir: ceph_rmdir,
  symlink: ceph_symlink,
  rename: ceph_rename,
  link: ceph_link,
  chmod: ceph_chmod,
  chown: ceph_chown,
  truncate: ceph_truncate,
  utime: ceph_utime,
  open: ceph_open,
  read: ceph_read,
  write: ceph_write,
  statfs: ceph_statfs,
  flush: ceph_flush,
  release: ceph_release,
  fsync: ceph_fsync,
  setxattr: 0,
  getxattr: 0,
  listxattr: 0,
  removexattr: 0,
  opendir: ceph_opendir,
  readdir: ceph_readdir,
  releasedir: ceph_releasedir
};

int ceph_fuse_main(Client *c, int argc, char *argv[])
{
  // init client
  client = c;

  // set up fuse argc/argv
  int newargc = 0;
  char **newargv = (char **) malloc((argc + 10) * sizeof(char *));
  newargv[newargc++] = argv[0];

  // allow other (all!) users to see my file system
  // NOTE: echo user_allow_other >> /etc/fuse.conf
  // NB: seems broken on Darwin
#ifndef DARWIN
  newargv[newargc++] = "-o";
  newargv[newargc++] = "allow_other";
#endif // DARWIN

  // use inos
  newargv[newargc++] = "-o";
  newargv[newargc++] = "use_ino";

  // large reads, direct_io (no kernel cachine)
  //newargv[newargc++] = "-o";
  //newargv[newargc++] = "large_read";
  if (g_conf.fuse_direct_io) {
    newargv[newargc++] = "-o";
    newargv[newargc++] = "direct_io";
  }

  // disable stupid fuse unlink hiding thing
  newargv[newargc++] = "-o";
  newargv[newargc++] = "hard_remove";

  // force into foreground
  //   -> we can watch stdout this way!!
  newargv[newargc++] = "-f";

  // copy rest of cmdline (hopefully, the mount point!)
  for (int argctr = 1; argctr < argc; argctr++) newargv[newargc++] = argv[argctr];

  // go fuse go
  cout << "ok, calling fuse_main" << endl;
  int r = fuse_main(newargc, newargv, &ceph_oper, 0);
  return r;
}
<|endoftext|>


<commit_before>// This file is part of the AliceVision project.
// This Source Code Form is subject to the terms of the Mozilla Public License,
// v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.

#include "uid.hpp"

#include <aliceVision/sfm/View.hpp>

namespace aliceVision {
namespace sfm {

std::size_t computeUID(const View& view)
{
  std::size_t uid = 0;

  if(view.hasMetadata("Exif:ImageUniqueID") ||
     view.hasMetadata("Exif:BodySerialNumber") ||
     view.hasMetadata("Exif:LensSerialNumber"))
  {
    stl::hash_combine(uid, view.getMetadataOrEmpty("Exif:ImageUniqueID"));
    stl::hash_combine(uid, view.getMetadataOrEmpty("Exif:BodySerialNumber"));
    stl::hash_combine(uid, view.getMetadataOrEmpty("Exif:LensSerialNumber"));
  }
  else
  {
    // No metadata to identify the image, fallback to the filename
    stl::hash_combine(uid, view.getImagePath());
  }

  if(view.hasMetadata("Exif:DateTimeOriginal"))
  {
    stl::hash_combine(uid, view.getMetadataOrEmpty("Exif:DateTimeOriginal"));
    stl::hash_combine(uid, view.getMetadataOrEmpty("Exif:SubsecTimeOriginal"));
  }
  else
  {
    // If no original date/time, fallback to the file date/time
    stl::hash_combine(uid, view.getMetadataOrEmpty("DateTime"));
  }

  stl::hash_combine(uid, view.getWidth());
  stl::hash_combine(uid, view.getHeight());

  // Limit to integer to maximize compatibility (like Alembic in Maya)
  uid = std::abs((int) uid);

  return uid;
}

void updateStructureWithNewUID(Landmarks &landmarks, const std::map<std::size_t, std::size_t> &oldIdToNew)
{
  // update the id in the visibility of each 3D point
  for(auto &iter : landmarks)
  {
    Landmark& currentLandmark = iter.second;

    // the new observations where to copy the existing ones
    // (needed as the key of the map is the idview)
    Observations newObservations;

    for(const auto &iterObs : currentLandmark.observations)
    {
      const auto idview = iterObs.first;
      const Observation &obs = iterObs.second;

      newObservations.emplace(oldIdToNew.at(idview), obs);
    }

    assert(currentLandmark.observations.size() == newObservations.size());
    currentLandmark.observations.swap(newObservations);
  }
}

void sanityCheckLandmarks(const Landmarks &landmarks, const Views &views)
{
  for(const auto &iter : landmarks)
  {
    const Landmark& currentLandmark = iter.second;
    for(const auto &iterObs : currentLandmark.observations)
    {
      const auto idview = iterObs.first;

      // there must be a view with that id (in the map) and the view must have
      // the same id (the member)
      assert(views.count(idview) == 1);
      assert(views.at(idview)->getViewId() == idview);
    }
  }
}

void regenerateUID(SfMData &sfmdata, std::map<std::size_t, std::size_t> &oldIdToNew, bool sanityCheck)
{
  // if the views are empty, nothing to be done.
  if(sfmdata.GetViews().empty())
    return;

  regenerateViewUIDs(sfmdata.views, oldIdToNew);

  if(!sanityCheck)
    return;

  sanityCheckLandmarks(sfmdata.GetLandmarks(), sfmdata.GetViews());

  sanityCheckLandmarks(sfmdata.GetControl_Points(), sfmdata.GetViews());

}

void regenerateViewUIDs(Views &views, std::map<std::size_t, std::size_t> &oldIdToNew)
{
  // if the views are empty, nothing to be done.
  if(views.empty())
    return;

  Views newViews;

  for(auto const &iter : views)
  {
    const View& currentView = *iter.second.get();

    // compute the view UID
    const std::size_t uid = computeUID(currentView);

    // update the mapping
    assert(oldIdToNew.count(currentView.getViewId()) == 0);
    oldIdToNew.emplace(currentView.getViewId(), uid);

    // add the view to the new map using the uid as key and change the id
    assert(newViews.count(uid) == 0);
    newViews.emplace(uid, iter.second);
    newViews[uid]->setViewId(uid);
  }

  assert(newViews.size() == views.size());
  views.swap(newViews);
}

}
}
<commit_msg>[sfm] View UID compatibility fix<commit_after>// This file is part of the AliceVision project.
// This Source Code Form is subject to the terms of the Mozilla Public License,
// v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.

#include "uid.hpp"

#include <aliceVision/sfm/View.hpp>

#include <boost/filesystem.hpp>

namespace fs = boost::filesystem;

namespace aliceVision {
namespace sfm {

std::size_t computeUID(const View& view)
{
  std::size_t uid = 0;

  if(view.hasMetadata("Exif:ImageUniqueID") ||
     view.hasMetadata("Exif:BodySerialNumber") ||
     view.hasMetadata("Exif:LensSerialNumber"))
  {
    stl::hash_combine(uid, view.getMetadataOrEmpty("Exif:ImageUniqueID"));
    stl::hash_combine(uid, view.getMetadataOrEmpty("Exif:BodySerialNumber"));
    stl::hash_combine(uid, view.getMetadataOrEmpty("Exif:LensSerialNumber"));
  }
  else
  {
    // no metadata to identify the image, fallback to the filename
    const fs::path imagePath = view.getImagePath();
    stl::hash_combine(uid, imagePath.stem().string() + imagePath.extension().string());
  }

  if(view.hasMetadata("Exif:DateTimeOriginal"))
  {
    stl::hash_combine(uid, view.getMetadataOrEmpty("Exif:DateTimeOriginal"));
    stl::hash_combine(uid, view.getMetadataOrEmpty("Exif:SubsecTimeOriginal"));
  }
  else
  {
    // if no original date/time, fallback to the file date/time
    stl::hash_combine(uid, view.getMetadataOrEmpty("DateTime"));
  }

  // can't use view.getWidth() and view.getHeight() directly
  // because ground truth tests and previous version datasets
  // view UID use EXIF width and height (or 0)

  if(view.hasMetadata("Exif:PixelXDimension"))
    stl::hash_combine(uid, std::stoi(view.getMetadata("Exif:PixelXDimension")));

  if(view.hasMetadata("Exif:PixelYDimension"))
    stl::hash_combine(uid, std::stoi(view.getMetadata("Exif:PixelYDimension")));

  // limit to integer to maximize compatibility (like Alembic in Maya)
  uid = std::abs((int) uid);

  return uid;
}

void updateStructureWithNewUID(Landmarks &landmarks, const std::map<std::size_t, std::size_t> &oldIdToNew)
{
  // update the id in the visibility of each 3D point
  for(auto &iter : landmarks)
  {
    Landmark& currentLandmark = iter.second;

    // the new observations where to copy the existing ones
    // (needed as the key of the map is the idview)
    Observations newObservations;

    for(const auto &iterObs : currentLandmark.observations)
    {
      const auto idview = iterObs.first;
      const Observation &obs = iterObs.second;

      newObservations.emplace(oldIdToNew.at(idview), obs);
    }

    assert(currentLandmark.observations.size() == newObservations.size());
    currentLandmark.observations.swap(newObservations);
  }
}

void sanityCheckLandmarks(const Landmarks &landmarks, const Views &views)
{
  for(const auto &iter : landmarks)
  {
    const Landmark& currentLandmark = iter.second;
    for(const auto &iterObs : currentLandmark.observations)
    {
      const auto idview = iterObs.first;

      // there must be a view with that id (in the map) and the view must have
      // the same id (the member)
      assert(views.count(idview) == 1);
      assert(views.at(idview)->getViewId() == idview);
    }
  }
}

void regenerateUID(SfMData &sfmdata, std::map<std::size_t, std::size_t> &oldIdToNew, bool sanityCheck)
{
  // if the views are empty, nothing to be done.
  if(sfmdata.GetViews().empty())
    return;

  regenerateViewUIDs(sfmdata.views, oldIdToNew);

  if(!sanityCheck)
    return;

  sanityCheckLandmarks(sfmdata.GetLandmarks(), sfmdata.GetViews());

  sanityCheckLandmarks(sfmdata.GetControl_Points(), sfmdata.GetViews());

}

void regenerateViewUIDs(Views &views, std::map<std::size_t, std::size_t> &oldIdToNew)
{
  // if the views are empty, nothing to be done.
  if(views.empty())
    return;

  Views newViews;

  for(auto const &iter : views)
  {
    const View& currentView = *iter.second.get();

    // compute the view UID
    const std::size_t uid = computeUID(currentView);

    // update the mapping
    assert(oldIdToNew.count(currentView.getViewId()) == 0);
    oldIdToNew.emplace(currentView.getViewId(), uid);

    // add the view to the new map using the uid as key and change the id
    assert(newViews.count(uid) == 0);
    newViews.emplace(uid, iter.second);
    newViews[uid]->setViewId(uid);
  }

  assert(newViews.size() == views.size());
  views.swap(newViews);
}

}
}
<|endoftext|>


<commit_before>/*
* Memory Mapping Allocator
* (C) 1999-2007 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <botan/internal/mmap_mem.h>
#include <vector>
#include <cstring>

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

#ifndef MAP_FAILED
   #define MAP_FAILED -1
#endif

namespace Botan {

namespace {

/*
* MemoryMapping_Allocator Exception
*/
class BOTAN_DLL MemoryMapping_Failed : public Exception
   {
   public:
      MemoryMapping_Failed(const std::string& msg) :
         Exception("MemoryMapping_Allocator: " + msg) {}
   };

}

/*
* Memory Map a File into Memory
*/
void* MemoryMapping_Allocator::alloc_block(u32bit n)
   {
   class TemporaryFile
      {
      public:
         int get_fd() const { return fd; }

         TemporaryFile(const std::string& base)
            {
            const std::string mkstemp_template = base + "XXXXXX";

            std::vector<char> filepath(mkstemp_template.begin(),
                                       mkstemp_template.end());
            filepath.push_back(0); // add terminating NULL

            mode_t old_umask = ::umask(077);
            fd = ::mkstemp(&filepath[0]);
            ::umask(old_umask);

            if(fd == -1)
               throw MemoryMapping_Failed("Temporary file allocation failed");

            if(::unlink(&filepath[0]) != 0)
               throw MemoryMapping_Failed("Could not unlink temporary file");
            }

         ~TemporaryFile()
            {
            /*
            * We can safely close here, because post-mmap the file
            * will continue to exist until the mmap is unmapped from
            * our address space upon deallocation.
            */
            if(fd != -1 && ::close(fd) == -1)
               throw MemoryMapping_Failed("Could not close file");
            }
      private:
         int fd;
      };

   TemporaryFile file("/tmp/botan_");

   if(file.get_fd() == -1)
      throw MemoryMapping_Failed("Could not create file");

   if(::lseek(file.get_fd(), n-1, SEEK_SET) < 0)
      throw MemoryMapping_Failed("Could not seek file");

   if(::write(file.get_fd(), "\0", 1) != 1)
      throw MemoryMapping_Failed("Could not write to file");

#ifndef MAP_NOSYNC
   #define MAP_NOSYNC 0
#endif

   void* ptr = ::mmap(0, n,
                      PROT_READ | PROT_WRITE,
                      MAP_SHARED | MAP_NOSYNC,
                      file.get_fd(), 0);

   if(ptr == static_cast<void*>(MAP_FAILED))
      throw MemoryMapping_Failed("Could not map file");

   return ptr;
   }

/*
* Remove a Memory Mapping
*/
void MemoryMapping_Allocator::dealloc_block(void* ptr, u32bit n)
   {
   if(ptr == 0)
      return;

   const byte PATTERNS[] = { 0x00, 0xFF, 0xAA, 0x55, 0x73, 0x8C, 0x5F, 0xA0,
                             0x6E, 0x91, 0x30, 0xCF, 0xD3, 0x2C, 0xAC, 0x00 };

   for(u32bit j = 0; j != sizeof(PATTERNS); j++)
      {
      std::memset(ptr, PATTERNS[j], n);

      if(::msync((char*)ptr, n, MS_SYNC))
         throw MemoryMapping_Failed("Sync operation failed");
      }

   if(::munmap((char*)ptr, n))
      throw MemoryMapping_Failed("Could not unmap file");
   }

}
<commit_msg>Use a full write instead of seek+write to create a sparse file. FreeBSD's man page for mmap warns that using NOSYNC with sparse files causes problems. Closes PR 30<commit_after>/*
* Memory Mapping Allocator
* (C) 1999-2010 Jack Lloyd
*
* Distributed under the terms of the Botan license
*/

#include <botan/internal/mmap_mem.h>
#include <vector>
#include <cstring>

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

#ifndef MAP_FAILED
   #define MAP_FAILED -1
#endif

namespace Botan {

namespace {

/*
* MemoryMapping_Allocator Exception
*/
class BOTAN_DLL MemoryMapping_Failed : public Exception
   {
   public:
      MemoryMapping_Failed(const std::string& msg) :
         Exception("MemoryMapping_Allocator: " + msg) {}
   };

}

/*
* Memory Map a File into Memory
*/
void* MemoryMapping_Allocator::alloc_block(u32bit n)
   {
   class TemporaryFile
      {
      public:
         int get_fd() const { return fd; }

         TemporaryFile(const std::string& base)
            {
            const std::string mkstemp_template = base + "XXXXXX";

            std::vector<char> filepath(mkstemp_template.begin(),
                                       mkstemp_template.end());
            filepath.push_back(0); // add terminating NULL

            mode_t old_umask = ::umask(077);
            fd = ::mkstemp(&filepath[0]);
            ::umask(old_umask);

            if(fd == -1)
               throw MemoryMapping_Failed("Temporary file allocation failed");

            if(::unlink(&filepath[0]) != 0)
               throw MemoryMapping_Failed("Could not unlink temporary file");
            }

         ~TemporaryFile()
            {
            /*
            * We can safely close here, because post-mmap the file
            * will continue to exist until the mmap is unmapped from
            * our address space upon deallocation (or process exit).
            */
            if(fd != -1 && ::close(fd) == -1)
               throw MemoryMapping_Failed("Could not close file");
            }
      private:
         int fd;
      };

   TemporaryFile file("/tmp/botan_");

   if(file.get_fd() == -1)
      throw MemoryMapping_Failed("Could not create file");

   std::vector<byte> zeros(n);

   if(::write(file.get_fd(), &zeros[0], zeros.size()) != zeros.size())
      throw MemoryMapping_Failed("Could not write to file");

#ifndef MAP_NOSYNC
   #define MAP_NOSYNC 0
#endif

   void* ptr = ::mmap(0, n,
                      PROT_READ | PROT_WRITE,
                      MAP_SHARED | MAP_NOSYNC,
                      file.get_fd(), 0);

   if(ptr == static_cast<void*>(MAP_FAILED))
      throw MemoryMapping_Failed("Could not map file");

   return ptr;
   }

/*
* Remove a Memory Mapping
*/
void MemoryMapping_Allocator::dealloc_block(void* ptr, u32bit n)
   {
   if(ptr == 0)
      return;

   const byte PATTERNS[] = { 0x00, 0xF5, 0x5A, 0xAF, 0x00 };

   for(size_t i = 0; i != sizeof(PATTERNS); ++i)
      {
      std::memset(ptr, PATTERNS[i], n);

      if(::msync((char*)ptr, n, MS_SYNC))
         throw MemoryMapping_Failed("Sync operation failed");
      }

   if(::munmap((char*)ptr, n))
      throw MemoryMapping_Failed("Could not unmap file");
   }

}
<|endoftext|>