<commit_before>/*
 * Copyright © 2012 Intel Corporation
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
 *
 * Author: Benjamin Segovia <benjamin.segovia@intel.com>
 */

/**
 * \file alloc.hpp
 * \author Benjamin Segovia <benjamin.segovia@intel.com>
 */
#ifndef __GBE_ALLOC_HPP__
#define __GBE_ALLOC_HPP__

#include "sys/platform.hpp"
#include "sys/assert.hpp"
#include <algorithm>
#include <limits>

namespace gbe
{
  /*! regular allocation */
  void* memAlloc(size_t size);
  void  memFree(void *ptr);

  /*! Aligned allocation */
  void* alignedMalloc(size_t size, size_t align = 64);
  void  alignedFree(void* ptr);

  /*! Monitor memory allocations */
#if GBE_DEBUG_MEMORY
  void* MemDebuggerInsertAlloc(void*, const char*, const char*, int);
  void  MemDebuggerRemoveAlloc(void *ptr);
  void  MemDebuggerDumpAlloc(void);
  void  MemDebuggerInitializeMem(void *mem, size_t sz);
  void  MemDebuggerEnableMemoryInitialization(bool enabled);
#else
  INLINE void* MemDebuggerInsertAlloc(void *ptr, const char*, const char*, int) {return ptr;}
  INLINE void  MemDebuggerRemoveAlloc(void *ptr) {}
  INLINE void  MemDebuggerDumpAlloc(void) {}
  INLINE void  MemDebuggerInitializeMem(void *mem, size_t sz) {}
  INLINE void  MemDebuggerEnableMemoryInitialization(bool enabled) {}
#endif /* GBE_DEBUG_MEMORY */

  /*! Properly handle the allocated type */
  template <typename T>
  T* _MemDebuggerInsertAlloc(T *ptr, const char *file, const char *function, int line) {
    MemDebuggerInsertAlloc(ptr, file, function, line);
    return ptr;
  }
} /* namespace gbe */

/*! Declare a class with custom allocators */
#define GBE_CLASS(TYPE) \
  GBE_STRUCT(TYPE) \
private:

/*! Declare a structure with custom allocators */
#define GBE_STRUCT(TYPE) \
public: \
  void* operator new(size_t size) { \
    return gbe::alignedMalloc(size, GBE_DEFAULT_ALIGNMENT); \
  } \
  void  operator delete(void* ptr) { return gbe::alignedFree(ptr); } \
  void* operator new[](size_t size) { \
   return gbe::alignedMalloc(size, GBE_DEFAULT_ALIGNMENT); \
  } \
  void  operator delete[](void* ptr) { return gbe::alignedFree(ptr); } \
  void* operator new(size_t size, void *p) { return p; } \
  void  operator delete(void* ptr, void *p) {/*do nothing*/} \
  void* operator new[](size_t size, void *p) { return p; } \
  void  operator delete[](void* ptr, void *p) { /*do nothing*/ }

/*! Macros to handle allocation position */
#define GBE_NEW(T,...) \
  gbe::_MemDebuggerInsertAlloc(new T(__VA_ARGS__), __FILE__, __FUNCTION__, __LINE__)

#define GBE_NEW_NO_ARG(T) \
  gbe::_MemDebuggerInsertAlloc(new T, __FILE__, __FUNCTION__, __LINE__)

#define GBE_NEW_ARRAY(T,N,...) \
  gbe::_MemDebuggerInsertAlloc(new T[N](__VA_ARGS__), __FILE__, __FUNCTION__, __LINE__)

#define GBE_NEW_ARRAY_NO_ARG(T,N)\
  gbe::_MemDebuggerInsertAlloc(new T[N], __FILE__, __FUNCTION__, __LINE__)

#define GBE_NEW_P(T,X,...) \
  gbe::_MemDebuggerInsertAlloc(new (X) T(__VA_ARGS__), __FILE__, __FUNCTION__, __LINE__)

#define GBE_DELETE(X) \
  do { gbe::MemDebuggerRemoveAlloc(X); delete X; } while (0)

#define GBE_DELETE_ARRAY(X) \
  do { gbe::MemDebuggerRemoveAlloc(X); delete[] X; } while (0)

#define GBE_MALLOC(SZ) \
  gbe::MemDebuggerInsertAlloc(gbe::memAlloc(SZ),__FILE__, __FUNCTION__, __LINE__)

#define GBE_FREE(X) \
  do { gbe::MemDebuggerRemoveAlloc(X); gbe::memFree(X); } while (0)

#define GBE_ALIGNED_FREE(X) \
  do { gbe::MemDebuggerRemoveAlloc(X); gbe::alignedFree(X); } while (0)

#define GBE_ALIGNED_MALLOC(SZ,ALIGN) \
  gbe::MemDebuggerInsertAlloc(gbe::alignedMalloc(SZ,ALIGN),__FILE__, __FUNCTION__, __LINE__)

namespace gbe
{
  /*! STL compliant allocator to intercept all memory allocations */
  template<typename T>
  class Allocator {
  public:
    typedef T value_type;
    typedef value_type* pointer;
    typedef const value_type* const_pointer;
    typedef value_type& reference;
    typedef const value_type& const_reference;
    typedef std::size_t size_type;
    typedef std::ptrdiff_t difference_type;
    typedef typename std::allocator<void>::const_pointer void_allocator_ptr;
    template<typename U>
    struct rebind { typedef Allocator<U> other; };

    INLINE Allocator(void) {}
    INLINE ~Allocator(void) {}
    INLINE Allocator(Allocator const&) {}
    template<typename U>
    INLINE Allocator(Allocator<U> const&) {}
    INLINE pointer address(reference r) { return &r; }
    INLINE const_pointer address(const_reference r) { return &r; }
    INLINE pointer allocate(size_type n, void_allocator_ptr = 0) {
      if (ALIGNOF(T) > sizeof(uintptr_t))
        return (pointer) GBE_ALIGNED_MALLOC(n*sizeof(T), ALIGNOF(T));
      else
        return (pointer) GBE_MALLOC(n * sizeof(T));
    }
    INLINE void deallocate(pointer p, size_type) {
      if (ALIGNOF(T) > sizeof(uintptr_t))
        GBE_ALIGNED_FREE(p);
      else
        GBE_FREE(p);
    }
    INLINE size_type max_size(void) const {
      return std::numeric_limits<size_type>::max() / sizeof(T);
    }
    INLINE void construct(pointer p, const T& t = T()) { ::new(p) T(t); }
    INLINE void destroy(pointer p) { p->~T(); }
    INLINE bool operator==(Allocator const&) { return true; }
    INLINE bool operator!=(Allocator const& a) { return !operator==(a); }
  };

// Deactivate fast allocators
#ifndef GBE_DEBUG_SPECIAL_ALLOCATOR
#define GBE_DEBUG_SPECIAL_ALLOCATOR 0
#endif

  /*! A growing pool never gives memory to the system but chain free elements
   *  together such as deallocation can be quickly done
   */
  template <typename T>
  class GrowingPool
  {
  public:
    GrowingPool(uint32_t elemNum = 1) :
      curr(GBE_NEW(GrowingPoolElem, elemNum <= 1 ? 1 : elemNum)),
      free(NULL), full(NULL), freeList(NULL) {}
    ~GrowingPool(void) {
      GBE_SAFE_DELETE(curr);
      GBE_SAFE_DELETE(free);
      GBE_SAFE_DELETE(full);
    }
    void *allocate(void) {
#if GBE_DEBUG_SPECIAL_ALLOCATOR
      return GBE_ALIGNED_MALLOC(sizeof(T), ALIGNOF(T));
#else
      // Pick up an element from the free list
      if (this->freeList != NULL) {
        void *data = (void*) freeList;
        this->freeList = *(void**) freeList;
        return data;
      }

      // Pick up an element from the current block (if not full)
      if (this->curr->allocated < this->curr->maxElemNum) {
        void *data = (T*) curr->data + curr->allocated++;
        return data;
      }

      // Block is full
      this->curr->next = this->full;
      this->full = this->curr;

      // Try to pick up a free block
      if (this->free) this->getFreeBlock();

      // No free block we must allocate a new one
      else
        this->curr = GBE_NEW(GrowingPoolElem, 2 * this->curr->maxElemNum);

      void *data = (T*) curr->data + curr->allocated++;
      return data;
#endif /* GBE_DEBUG_SPECIAL_ALLOCATOR */
    }
    void deallocate(void *t) {
      if (t == NULL) return;
#if GBE_DEBUG_SPECIAL_ALLOCATOR
      GBE_ALIGNED_FREE(t);
#else
      *(void**) t = this->freeList;
      this->freeList = t;
#endif /* GBE_DEBUG_SPECIAL_ALLOCATOR */
    }
    void rewind(void) {
#if GBE_DEBUG_SPECIAL_ALLOCATOR == 0
      // All free elements return to their blocks
      this->freeList = NULL;

      // Put back current block in full list
      if (this->curr) {
        this->curr->next = this->full;
        this->full = this->curr;
        this->curr = NULL;
      }

      // Reverse the chain list and mark all blocks as empty
      while (this->full) {
        GrowingPoolElem *next = this->full->next;
        this->full->allocated = 0;
        this->full->next = this->free;
        this->free = this->full;
        this->full = next;
      }

      // Provide a valid current block
      this->getFreeBlock();
#endif /* GBE_DEBUG_SPECIAL_ALLOCATOR */
    }
  private:
    /*! Pick-up a free block */
    INLINE void getFreeBlock(void) {
      GBE_ASSERT(this->free);
      this->curr = this->free;
      this->free = this->free->next;
      this->curr->next = NULL;
    }
    /*! Chunk of elements to allocate */
    class GrowingPoolElem
    {
      friend class GrowingPool;
      GrowingPoolElem(size_t elemNum) {
        const size_t sz = std::max(sizeof(T), sizeof(void*));
        this->data = (T*) GBE_ALIGNED_MALLOC(elemNum * sz, ALIGNOF(T));
        this->next = NULL;
        this->maxElemNum = elemNum;
        this->allocated = 0;
      }
      ~GrowingPoolElem(void) {
        GBE_ALIGNED_FREE(this->data);
        if (this->next) GBE_DELETE(this->next);
      }
      T *data;
      GrowingPoolElem *next;
      size_t allocated, maxElemNum;
    };
    GrowingPoolElem *curr; //!< To get new element from
    GrowingPoolElem *free; //!< Blocks that can be reused (after rewind)
    GrowingPoolElem *full; //!< Blocks fully used
    void *freeList;        //!< Elements that have been deallocated
    GBE_CLASS(GrowingPool);
  };

/*! Helper macros to build and destroy objects with a growing pool */
#define DECL_POOL(TYPE, POOL) \
  GrowingPool<TYPE> POOL; \
  template <typename... Args> \
  TYPE *new##TYPE(Args&&... args) { \
    return new (POOL.allocate()) TYPE(args...); \
  } \
  void delete##TYPE(TYPE *ptr) { \
    ptr->~TYPE(); \
    POOL.deallocate(ptr); \
  }

  /*! A linear allocator just grows and does not reuse freed memory. It can
   *  however allocate objects of any size
   */
  class LinearAllocator
  {
  public:
    /*! Initiate the linear allocator (one segment is allocated) */
    LinearAllocator(size_t minSize = CACHE_LINE, size_t maxSize = 64*KB);
    /*! Free up everything */
    ~LinearAllocator(void);
    /*! Allocate size bytes */
    void *allocate(size_t size);
    /*! Nothing here */
    INLINE void deallocate(void *ptr) {
#if GBE_DEBUG_SPECIAL_ALLOCATOR
      if (ptr) GBE_ALIGNED_FREE(ptr);
#endif /* GBE_DEBUG_SPECIAL_ALLOCATOR */
    }
  private:
    /*! Helds an allocated segment of memory */
    struct Segment {
      /*! Allocate a new segment */
      Segment(size_t size);
      /*! Destroy the segment and the next ones */
      ~Segment(void);
      /* Size of the segment */
      size_t size;
      /*! Offset to the next free bytes (if any left) */
      size_t offset;
      /*! Pointer to valid data */
      void *data;
      /*! Pointer to the next segment */
      Segment *next;
      /*! Use internal allocator */
      GBE_STRUCT(Segment);
    };
    /*! Points to the current segment we can allocate from */
    Segment *curr;
    /*! Maximum segment size */
    size_t maxSize;
    /*! Use internal allocator */
    GBE_CLASS(LinearAllocator);
  };

} /* namespace gbe */

#endif /* __GBE_ALLOC_HPP__ */

<commit_msg>Android: derived the Allocator from std::allocator.<commit_after>/*
 * Copyright © 2012 Intel Corporation
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
 *
 * Author: Benjamin Segovia <benjamin.segovia@intel.com>
 */

/**
 * \file alloc.hpp
 * \author Benjamin Segovia <benjamin.segovia@intel.com>
 */
#ifndef __GBE_ALLOC_HPP__
#define __GBE_ALLOC_HPP__

#include "sys/platform.hpp"
#include "sys/assert.hpp"
#include <algorithm>
#include <limits>

namespace gbe
{
  /*! regular allocation */
  void* memAlloc(size_t size);
  void  memFree(void *ptr);

  /*! Aligned allocation */
  void* alignedMalloc(size_t size, size_t align = 64);
  void  alignedFree(void* ptr);

  /*! Monitor memory allocations */
#if GBE_DEBUG_MEMORY
  void* MemDebuggerInsertAlloc(void*, const char*, const char*, int);
  void  MemDebuggerRemoveAlloc(void *ptr);
  void  MemDebuggerDumpAlloc(void);
  void  MemDebuggerInitializeMem(void *mem, size_t sz);
  void  MemDebuggerEnableMemoryInitialization(bool enabled);
#else
  INLINE void* MemDebuggerInsertAlloc(void *ptr, const char*, const char*, int) {return ptr;}
  INLINE void  MemDebuggerRemoveAlloc(void *ptr) {}
  INLINE void  MemDebuggerDumpAlloc(void) {}
  INLINE void  MemDebuggerInitializeMem(void *mem, size_t sz) {}
  INLINE void  MemDebuggerEnableMemoryInitialization(bool enabled) {}
#endif /* GBE_DEBUG_MEMORY */

  /*! Properly handle the allocated type */
  template <typename T>
  T* _MemDebuggerInsertAlloc(T *ptr, const char *file, const char *function, int line) {
    MemDebuggerInsertAlloc(ptr, file, function, line);
    return ptr;
  }
} /* namespace gbe */

/*! Declare a class with custom allocators */
#define GBE_CLASS(TYPE) \
  GBE_STRUCT(TYPE) \
private:

/*! Declare a structure with custom allocators */
#define GBE_STRUCT(TYPE) \
public: \
  void* operator new(size_t size) { \
    return gbe::alignedMalloc(size, GBE_DEFAULT_ALIGNMENT); \
  } \
  void  operator delete(void* ptr) { return gbe::alignedFree(ptr); } \
  void* operator new[](size_t size) { \
   return gbe::alignedMalloc(size, GBE_DEFAULT_ALIGNMENT); \
  } \
  void  operator delete[](void* ptr) { return gbe::alignedFree(ptr); } \
  void* operator new(size_t size, void *p) { return p; } \
  void  operator delete(void* ptr, void *p) {/*do nothing*/} \
  void* operator new[](size_t size, void *p) { return p; } \
  void  operator delete[](void* ptr, void *p) { /*do nothing*/ }

/*! Macros to handle allocation position */
#define GBE_NEW(T,...) \
  gbe::_MemDebuggerInsertAlloc(new T(__VA_ARGS__), __FILE__, __FUNCTION__, __LINE__)

#define GBE_NEW_NO_ARG(T) \
  gbe::_MemDebuggerInsertAlloc(new T, __FILE__, __FUNCTION__, __LINE__)

#define GBE_NEW_ARRAY(T,N,...) \
  gbe::_MemDebuggerInsertAlloc(new T[N](__VA_ARGS__), __FILE__, __FUNCTION__, __LINE__)

#define GBE_NEW_ARRAY_NO_ARG(T,N)\
  gbe::_MemDebuggerInsertAlloc(new T[N], __FILE__, __FUNCTION__, __LINE__)

#define GBE_NEW_P(T,X,...) \
  gbe::_MemDebuggerInsertAlloc(new (X) T(__VA_ARGS__), __FILE__, __FUNCTION__, __LINE__)

#define GBE_DELETE(X) \
  do { gbe::MemDebuggerRemoveAlloc(X); delete X; } while (0)

#define GBE_DELETE_ARRAY(X) \
  do { gbe::MemDebuggerRemoveAlloc(X); delete[] X; } while (0)

#define GBE_MALLOC(SZ) \
  gbe::MemDebuggerInsertAlloc(gbe::memAlloc(SZ),__FILE__, __FUNCTION__, __LINE__)

#define GBE_FREE(X) \
  do { gbe::MemDebuggerRemoveAlloc(X); gbe::memFree(X); } while (0)

#define GBE_ALIGNED_FREE(X) \
  do { gbe::MemDebuggerRemoveAlloc(X); gbe::alignedFree(X); } while (0)

#define GBE_ALIGNED_MALLOC(SZ,ALIGN) \
  gbe::MemDebuggerInsertAlloc(gbe::alignedMalloc(SZ,ALIGN),__FILE__, __FUNCTION__, __LINE__)

namespace gbe
{
  /*! STL compliant allocator to intercept all memory allocations */
  template<typename T>
  class Allocator : public std::allocator<T>
  {
  public:
    typedef T value_type;
    typedef value_type* pointer;
    typedef const value_type* const_pointer;
    typedef value_type& reference;
    typedef const value_type& const_reference;
    typedef std::size_t size_type;
    typedef std::ptrdiff_t difference_type;
    typedef typename std::allocator<void>::const_pointer void_allocator_ptr;
    template<typename U>
    struct rebind { typedef Allocator<U> other; };

    INLINE Allocator(void) {}
    INLINE ~Allocator(void) {}
    INLINE Allocator(Allocator const&) {}
    template<typename U>
    INLINE Allocator(Allocator<U> const&) {}
    INLINE pointer address(reference r) { return &r; }
    INLINE const_pointer address(const_reference r) { return &r; }
    INLINE pointer allocate(size_type n, void_allocator_ptr = 0) {
      if (ALIGNOF(T) > sizeof(uintptr_t))
        return (pointer) GBE_ALIGNED_MALLOC(n*sizeof(T), ALIGNOF(T));
      else
        return (pointer) GBE_MALLOC(n * sizeof(T));
    }
    INLINE void deallocate(pointer p, size_type) {
      if (ALIGNOF(T) > sizeof(uintptr_t))
        GBE_ALIGNED_FREE(p);
      else
        GBE_FREE(p);
    }
    INLINE size_type max_size(void) const {
      return std::numeric_limits<size_type>::max() / sizeof(T);
    }
    INLINE void destroy(pointer p) { p->~T(); }
    INLINE bool operator==(Allocator const&) { return true; }
    INLINE bool operator!=(Allocator const& a) { return !operator==(a); }
  };

// Deactivate fast allocators
#ifndef GBE_DEBUG_SPECIAL_ALLOCATOR
#define GBE_DEBUG_SPECIAL_ALLOCATOR 0
#endif

  /*! A growing pool never gives memory to the system but chain free elements
   *  together such as deallocation can be quickly done
   */
  template <typename T>
  class GrowingPool
  {
  public:
    GrowingPool(uint32_t elemNum = 1) :
      curr(GBE_NEW(GrowingPoolElem, elemNum <= 1 ? 1 : elemNum)),
      free(NULL), full(NULL), freeList(NULL) {}
    ~GrowingPool(void) {
      GBE_SAFE_DELETE(curr);
      GBE_SAFE_DELETE(free);
      GBE_SAFE_DELETE(full);
    }
    void *allocate(void) {
#if GBE_DEBUG_SPECIAL_ALLOCATOR
      return GBE_ALIGNED_MALLOC(sizeof(T), ALIGNOF(T));
#else
      // Pick up an element from the free list
      if (this->freeList != NULL) {
        void *data = (void*) freeList;
        this->freeList = *(void**) freeList;
        return data;
      }

      // Pick up an element from the current block (if not full)
      if (this->curr->allocated < this->curr->maxElemNum) {
        void *data = (T*) curr->data + curr->allocated++;
        return data;
      }

      // Block is full
      this->curr->next = this->full;
      this->full = this->curr;

      // Try to pick up a free block
      if (this->free) this->getFreeBlock();

      // No free block we must allocate a new one
      else
        this->curr = GBE_NEW(GrowingPoolElem, 2 * this->curr->maxElemNum);

      void *data = (T*) curr->data + curr->allocated++;
      return data;
#endif /* GBE_DEBUG_SPECIAL_ALLOCATOR */
    }
    void deallocate(void *t) {
      if (t == NULL) return;
#if GBE_DEBUG_SPECIAL_ALLOCATOR
      GBE_ALIGNED_FREE(t);
#else
      *(void**) t = this->freeList;
      this->freeList = t;
#endif /* GBE_DEBUG_SPECIAL_ALLOCATOR */
    }
    void rewind(void) {
#if GBE_DEBUG_SPECIAL_ALLOCATOR == 0
      // All free elements return to their blocks
      this->freeList = NULL;

      // Put back current block in full list
      if (this->curr) {
        this->curr->next = this->full;
        this->full = this->curr;
        this->curr = NULL;
      }

      // Reverse the chain list and mark all blocks as empty
      while (this->full) {
        GrowingPoolElem *next = this->full->next;
        this->full->allocated = 0;
        this->full->next = this->free;
        this->free = this->full;
        this->full = next;
      }

      // Provide a valid current block
      this->getFreeBlock();
#endif /* GBE_DEBUG_SPECIAL_ALLOCATOR */
    }
  private:
    /*! Pick-up a free block */
    INLINE void getFreeBlock(void) {
      GBE_ASSERT(this->free);
      this->curr = this->free;
      this->free = this->free->next;
      this->curr->next = NULL;
    }
    /*! Chunk of elements to allocate */
    class GrowingPoolElem
    {
      friend class GrowingPool;
      GrowingPoolElem(size_t elemNum) {
        const size_t sz = std::max(sizeof(T), sizeof(void*));
        this->data = (T*) GBE_ALIGNED_MALLOC(elemNum * sz, ALIGNOF(T));
        this->next = NULL;
        this->maxElemNum = elemNum;
        this->allocated = 0;
      }
      ~GrowingPoolElem(void) {
        GBE_ALIGNED_FREE(this->data);
        if (this->next) GBE_DELETE(this->next);
      }
      T *data;
      GrowingPoolElem *next;
      size_t allocated, maxElemNum;
    };
    GrowingPoolElem *curr; //!< To get new element from
    GrowingPoolElem *free; //!< Blocks that can be reused (after rewind)
    GrowingPoolElem *full; //!< Blocks fully used
    void *freeList;        //!< Elements that have been deallocated
    GBE_CLASS(GrowingPool);
  };

/*! Helper macros to build and destroy objects with a growing pool */
#define DECL_POOL(TYPE, POOL) \
  GrowingPool<TYPE> POOL; \
  template <typename... Args> \
  TYPE *new##TYPE(Args&&... args) { \
    return new (POOL.allocate()) TYPE(args...); \
  } \
  void delete##TYPE(TYPE *ptr) { \
    ptr->~TYPE(); \
    POOL.deallocate(ptr); \
  }

  /*! A linear allocator just grows and does not reuse freed memory. It can
   *  however allocate objects of any size
   */
  class LinearAllocator
  {
  public:
    /*! Initiate the linear allocator (one segment is allocated) */
    LinearAllocator(size_t minSize = CACHE_LINE, size_t maxSize = 64*KB);
    /*! Free up everything */
    ~LinearAllocator(void);
    /*! Allocate size bytes */
    void *allocate(size_t size);
    /*! Nothing here */
    INLINE void deallocate(void *ptr) {
#if GBE_DEBUG_SPECIAL_ALLOCATOR
      if (ptr) GBE_ALIGNED_FREE(ptr);
#endif /* GBE_DEBUG_SPECIAL_ALLOCATOR */
    }
  private:
    /*! Helds an allocated segment of memory */
    struct Segment {
      /*! Allocate a new segment */
      Segment(size_t size);
      /*! Destroy the segment and the next ones */
      ~Segment(void);
      /* Size of the segment */
      size_t size;
      /*! Offset to the next free bytes (if any left) */
      size_t offset;
      /*! Pointer to valid data */
      void *data;
      /*! Pointer to the next segment */
      Segment *next;
      /*! Use internal allocator */
      GBE_STRUCT(Segment);
    };
    /*! Points to the current segment we can allocate from */
    Segment *curr;
    /*! Maximum segment size */
    size_t maxSize;
    /*! Use internal allocator */
    GBE_CLASS(LinearAllocator);
  };

} /* namespace gbe */

#endif /* __GBE_ALLOC_HPP__ */

<|endoftext|>


<commit_before>// @(#)root/base:$Name:  $:$Id: TContextMenu.cxx,v 1.5 2002/04/05 11:39:21 rdm Exp $
// Author: Nenad Buncic   08/02/96

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TContextMenu                                                         //
//                                                                      //
// This class provides an interface to  context sensitive popup menus.  //
// These menus pop up when the user hits the right mouse button, and    //
// are destroyed when the menu pops downs.                              //
//                                                                      //
// Context Menus are automatically generated by ROOT using the          //
// following convention: if the string // *MENU* is found in the        //
// comment field of a member function. This function will be added to   //
// the list of items in the menu.                                       //
//                                                                      //
// The picture below shows a canvas with a pop-up menu.                 //
//                                                                      //
//Begin_Html  End_Html                      //
//                                                                      //
// The picture below shows a canvas with a pop-up menu and a dialog box.//
//                                                                      //
//Begin_Html  End_Html                    //
//////////////////////////////////////////////////////////////////////////

#include "TROOT.h"
#include "TContextMenu.h"
#include "TVirtualPad.h"
#include "TGuiFactory.h"
#include "TMethod.h"
#include "TMethodArg.h"
#include "TGlobal.h"
#include "TObjArray.h"
#include "TObjString.h"
#include "TToggle.h"
#include "TClassMenuItem.h"

ClassImp(TContextMenu)

//______________________________________________________________________________
TContextMenu::TContextMenu(const char *name, const char *title)
             : TNamed(name, title)
{
   // Create a context menu.

   fSelectedObject   = 0;
   fSelectedMethod   = 0;
   fBrowser          = 0;
   fSelectedPad      = 0;
   fSelectedCanvas   = 0;
   fSelectedMenuItem = 0;

   fContextMenuImp = gGuiFactory->CreateContextMenuImp(this, name, title);
}

//______________________________________________________________________________
TContextMenu::~TContextMenu()
{
   // Destroy a context menu.

   delete fContextMenuImp;

   fSelectedMethod   = 0;
   fSelectedObject   = 0;
   fSelectedMenuItem = 0;
   fContextMenuImp   = 0;
}

//______________________________________________________________________________
void TContextMenu::Action(TObject *object, TMethod *method)
{
   // Action to be performed when this menu item is selected.
   // If the selected method requires arguments we popup an
   // automatically generated dialog, otherwise the method is
   // directly executed.

   if (method) {
      SetMethod( method );
      SetSelectedMenuItem(0);
      SetCalledObject(object);

      if (method->GetListOfMethodArgs()->First())
          fContextMenuImp->Dialog(object, method);
      else {
#ifndef WIN32
          Execute(object, method, "");
#else
#ifdef GDK_WIN32
          Execute(object, method, "");
#else
          // It is a workaround of the "Dead lock under Windows
          char *cmd = Form("((TContextMenu *)0x%lx)->Execute((TObject *)0x%lx,"
                           "(TMethod *)0x%lx,(TObjArray *)0);",
                           (Long_t)this,(Long_t)object,(Long_t)method);
          //Printf("%s", cmd);
          gROOT->ProcessLine(cmd);
          //Execute( object, method, (TObjArray *)NULL );
#endif
#endif
      }
   }
}

//______________________________________________________________________________
void TContextMenu::Action(TClassMenuItem *menuitem)
{
   // Action to be performed when this menu item is selected.
   // If the selected method requires arguments we popup an
   // automatically generated dialog, otherwise the method is
   // directly executed.

   TObject* object;
   TMethod* method;

   SetSelectedMenuItem( menuitem );

   // Get the object to be called
   if (menuitem->IsCallSelf()) object=fSelectedObject;
   else object=menuitem->GetCalledObject();

   if (object) {
      // If object deleted, remove from popup and return
      if (!(object->TestBit(kNotDeleted))) {
         menuitem->SetType(TClassMenuItem::kPopupSeparator);
         menuitem->SetCall(0,"");
         return;
      }

      method = object->IsA()->GetMethodWithPrototype(menuitem->GetFunctionName(),menuitem->GetArgs());

   }
//    if (!menuitem->IsCallSelf()) {
//       funproto = menuitem->GetFunctionName();
//       funproto = funproto + "(" + menuitem->GetArgs() + ")";
//    }

   // calling object, call the method directly
   if (object) {
      if (method) {
         SetMethod(method);
         SetCalledObject(object);

         if ((method->GetListOfMethodArgs()->First()
                            && menuitem->GetSelfObjectPos() < 0 ) ||
              method->GetListOfMethodArgs()->GetSize() > 1)
            fContextMenuImp->Dialog(object, method);
         else {
            if (menuitem->GetSelfObjectPos() < 0) {
#ifndef WIN32
               Execute(object, method, "");
#else
                // It is a workaround of the "Dead lock under Windows
                char *cmd = Form("((TContextMenu *)0x%lx)->Execute((TObject *)0x%lx,"
                              "(TMethod *)0x%lx,(TObjArray *)0);",
                              (Long_t)this,(Long_t)object,(Long_t)method);
                //Printf("%s", cmd);
                gROOT->ProcessLine(cmd);
                //Execute( object, method, (TObjArray *)NULL );
#endif
             } else {
#ifndef WIN32
               Execute(object, method, Form("(TObject*)0x%lx",(Long_t)fSelectedObject));
#else
                // It is a workaround of the "Dead lock under Windows
                char *cmd = Form("((TContextMenu *)0x%lx)->Execute((TObject *)0x%lx,"
                              "(TMethod *)0x%lx,(TObjArray *)0);",
                              (Long_t)this,(Long_t)object,(Long_t)method);
                //Printf("%s", cmd);
                gROOT->ProcessLine(cmd);
                //Execute( object, method, (TObjArray *)NULL );
#endif
             }
         }
      }

   } else {
      // Calling a standalone global function
      TFunction* function = gROOT->GetGlobalFunctionWithPrototype(
                               menuitem->GetFunctionName());
                               //menuitem->GetArgs());
      if (function) {
         SetMethod(function);
         SetCalledObject(0);
         if ( (function->GetNargs() && menuitem->GetSelfObjectPos() < 0) ||
               function->GetNargs() > 1) {
            fContextMenuImp->Dialog(0,function);
         } else {
            char* cmd;
            if (menuitem->GetSelfObjectPos() < 0) {
               cmd = Form("%s();", menuitem->GetFunctionName());
            } else {
              cmd = Form("%s((TObject*)0x%lx);",
                     menuitem->GetFunctionName(), (Long_t)fSelectedObject);
            }
            gROOT->ProcessLine(cmd);
         }
      }
   }
}

//______________________________________________________________________________
void TContextMenu::Action(TObject *object, TToggle *toggle)
{
   // Action to be performed when this toggle menu item is selected.

   if (object && toggle) {
      TVirtualPad *savedPad = 0;

      gROOT->SetSelectedPrimitive(object);
      if (fSelectedPad) {
         savedPad = (TVirtualPad *) gPad;
         if (savedPad) fSelectedPad->cd();
      }

      gROOT->SetFromPopUp(kTRUE);
      toggle->Toggle();
      if (fSelectedCanvas && fSelectedCanvas->GetPadSave()->TestBit(kNotDeleted))
         fSelectedCanvas->GetPadSave()->Modified();
      if (fSelectedPad && fSelectedPad->TestBit(kNotDeleted))
         fSelectedPad->Modified();
      gROOT->SetFromPopUp(kFALSE);

      if (fSelectedPad && savedPad) {
         if (savedPad->TestBit(kNotDeleted)) savedPad->cd();
      }

      if (fSelectedCanvas && fSelectedCanvas->TestBit(kNotDeleted))
         fSelectedCanvas->Update();
      if (fSelectedCanvas && fSelectedCanvas->GetPadSave()->TestBit(kNotDeleted))
         fSelectedCanvas->GetPadSave()->Update();
   }
}

//______________________________________________________________________________
char *TContextMenu::CreateArgumentTitle(TMethodArg *argument)
{
   // Create string describing argument (for use in dialog box).

   static char argTitle[128];

   if (argument) {
      sprintf(argTitle, "(%s)  %s", argument->GetTitle(), argument->GetName());
      if (argument->GetDefault() && *(argument->GetDefault())) {
         strcat(argTitle, "  [default: ");
         strcat(argTitle, argument->GetDefault());
         strcat(argTitle, "]");
      }
   } else
      *argTitle = 0;

   return argTitle;
}

//______________________________________________________________________________
char *TContextMenu::CreateDialogTitle(TObject *object, TFunction *method)
{
   // Create title for dialog box retrieving argument values.

   static char methodTitle[128];

   if (object && method)
      sprintf(methodTitle, "%s::%s", object->ClassName(), method->GetName());
   else if (!object && method)
      sprintf(methodTitle, "%s", method->GetName());
   else
      *methodTitle = 0;

   return methodTitle;
}

//______________________________________________________________________________
char *TContextMenu::CreatePopupTitle(TObject *object)
{
   // Create title for popup menu.

   static char popupTitle[128];

   if (object) {
      if (!*(object->GetName()) || !strcmp(object->GetName(), object->ClassName())) {
         TGlobal *global = (TGlobal *) gROOT->GetGlobal(object);
         if (global && *(global->GetName()))
            sprintf(popupTitle, "  %s::%s  ", object->ClassName(), global->GetName());
         else
            sprintf(popupTitle, "  %s  ", object->ClassName());
      } else
         sprintf(popupTitle, "  %s::%s  ", object->ClassName(), object->GetName());
   } else
      *popupTitle = 0;

   return popupTitle;
}

//______________________________________________________________________________
void TContextMenu::Execute(TObject *object, TFunction *method, const char *params)
{
   // Execute method with specified arguments for specified object.

   if (method) {
      TVirtualPad *savedPad = 0;

      gROOT->SetSelectedPrimitive(object);
      if (fSelectedPad) {
         savedPad = (TVirtualPad *) gPad;
         if (savedPad) fSelectedPad->cd();
      }

      gROOT->SetFromPopUp(kTRUE);
//      if (fSelectedCanvas) fSelectedCanvas->GetPadSave()->cd();
      if (object) {
         object->Execute((char *) method->GetName(), params);
      } else {
         char *cmd = Form("%s(%s);", method->GetName(),params);
         gROOT->ProcessLine(cmd);
      }
      if (fSelectedCanvas && fSelectedCanvas->GetPadSave()->TestBit(kNotDeleted))
         fSelectedCanvas->GetPadSave()->Modified();
      if (fSelectedPad && fSelectedPad->TestBit(kNotDeleted))
         fSelectedPad->Modified();
      gROOT->SetFromPopUp( kFALSE );

      if (fSelectedPad && savedPad) {
//         fSelectedPad->Modified();
         if (savedPad->TestBit(kNotDeleted)) savedPad->cd();
      }

      if (fSelectedCanvas && fSelectedCanvas->TestBit(kNotDeleted))
         fSelectedCanvas->Update();
      if (fSelectedCanvas && fSelectedCanvas->GetPadSave()->TestBit(kNotDeleted))
         fSelectedCanvas->GetPadSave()->Update();
   }
}

//______________________________________________________________________________
void TContextMenu::Execute(TObject *object, TFunction *method, TObjArray *params)
{
   // Execute method with specified arguments for specified object.

   if (method) {
      TVirtualPad *savedPad = 0;

      gROOT->SetSelectedPrimitive(object);
      if (fSelectedPad) {
         savedPad = (TVirtualPad *) gPad;
         if (savedPad) fSelectedPad->cd();
      }

      gROOT->SetFromPopUp(kTRUE);
//      if (fSelectedCanvas) fSelectedCanvas->GetPadSave()->cd();
      if (object) {
         object->Execute((TMethod*)method, params);
      } else {
         TString args;
         TIter next(params);
         TObjString *s;
         while ((s = (TObjString*) next())) {
            if (!args.IsNull()) args += ",";
            args += s->String();
         }
         char *cmd = Form("%s(%s);", method->GetName(), args.Data());
         gROOT->ProcessLine(cmd);
      }
      if (fSelectedCanvas && fSelectedCanvas->GetPadSave()->TestBit(kNotDeleted))
         fSelectedCanvas->GetPadSave()->Modified();
      gROOT->SetFromPopUp( kFALSE );

      if (fSelectedPad && savedPad) {
//         fSelectedPad->Modified();
         if (savedPad->TestBit(kNotDeleted)) savedPad->cd();
      }

      if (fSelectedCanvas && fSelectedCanvas->TestBit(kNotDeleted))
         fSelectedCanvas->Update();
   }
}

//______________________________________________________________________________
void TContextMenu::Popup(Int_t x, Int_t y, TObject *obj, TVirtualPad *c, TVirtualPad *p)
{
   // Popup context menu at given location in canvas c and pad p for selected
   // object.

   SetBrowser(0);
   SetObject(obj);
   SetCanvas(c);
   SetPad(p);

   DisplayPopUp(x,y);
}

//______________________________________________________________________________
void TContextMenu::Popup(Int_t x, Int_t y, TObject *obj, TBrowser *b)
{
   // Popup context menu at given location in browser b for selected object.

   SetBrowser(b);
   SetObject(obj);
   SetCanvas(0);
   SetPad(0);

   DisplayPopUp(x,y);
}
<commit_msg>Set local variable method t zero  to avoid a compiler warning.<commit_after>// @(#)root/base:$Name:  $:$Id: TContextMenu.cxx,v 1.6 2002/04/08 15:06:08 rdm Exp $
// Author: Nenad Buncic   08/02/96

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TContextMenu                                                         //
//                                                                      //
// This class provides an interface to  context sensitive popup menus.  //
// These menus pop up when the user hits the right mouse button, and    //
// are destroyed when the menu pops downs.                              //
//                                                                      //
// Context Menus are automatically generated by ROOT using the          //
// following convention: if the string // *MENU* is found in the        //
// comment field of a member function. This function will be added to   //
// the list of items in the menu.                                       //
//                                                                      //
// The picture below shows a canvas with a pop-up menu.                 //
//                                                                      //
//Begin_Html  End_Html                      //
//                                                                      //
// The picture below shows a canvas with a pop-up menu and a dialog box.//
//                                                                      //
//Begin_Html  End_Html                    //
//////////////////////////////////////////////////////////////////////////

#include "TROOT.h"
#include "TContextMenu.h"
#include "TVirtualPad.h"
#include "TGuiFactory.h"
#include "TMethod.h"
#include "TMethodArg.h"
#include "TGlobal.h"
#include "TObjArray.h"
#include "TObjString.h"
#include "TToggle.h"
#include "TClassMenuItem.h"

ClassImp(TContextMenu)

//______________________________________________________________________________
TContextMenu::TContextMenu(const char *name, const char *title)
             : TNamed(name, title)
{
   // Create a context menu.

   fSelectedObject   = 0;
   fSelectedMethod   = 0;
   fBrowser          = 0;
   fSelectedPad      = 0;
   fSelectedCanvas   = 0;
   fSelectedMenuItem = 0;

   fContextMenuImp = gGuiFactory->CreateContextMenuImp(this, name, title);
}

//______________________________________________________________________________
TContextMenu::~TContextMenu()
{
   // Destroy a context menu.

   delete fContextMenuImp;

   fSelectedMethod   = 0;
   fSelectedObject   = 0;
   fSelectedMenuItem = 0;
   fContextMenuImp   = 0;
}

//______________________________________________________________________________
void TContextMenu::Action(TObject *object, TMethod *method)
{
   // Action to be performed when this menu item is selected.
   // If the selected method requires arguments we popup an
   // automatically generated dialog, otherwise the method is
   // directly executed.

   if (method) {
      SetMethod( method );
      SetSelectedMenuItem(0);
      SetCalledObject(object);

      if (method->GetListOfMethodArgs()->First())
          fContextMenuImp->Dialog(object, method);
      else {
#ifndef WIN32
          Execute(object, method, "");
#else
#ifdef GDK_WIN32
          Execute(object, method, "");
#else
          // It is a workaround of the "Dead lock under Windows
          char *cmd = Form("((TContextMenu *)0x%lx)->Execute((TObject *)0x%lx,"
                           "(TMethod *)0x%lx,(TObjArray *)0);",
                           (Long_t)this,(Long_t)object,(Long_t)method);
          //Printf("%s", cmd);
          gROOT->ProcessLine(cmd);
          //Execute( object, method, (TObjArray *)NULL );
#endif
#endif
      }
   }
}

//______________________________________________________________________________
void TContextMenu::Action(TClassMenuItem *menuitem)
{
   // Action to be performed when this menu item is selected.
   // If the selected method requires arguments we popup an
   // automatically generated dialog, otherwise the method is
   // directly executed.

   TObject* object;
   TMethod* method = 0;

   SetSelectedMenuItem( menuitem );

   // Get the object to be called
   if (menuitem->IsCallSelf()) object=fSelectedObject;
   else object=menuitem->GetCalledObject();

   if (object) {
      // If object deleted, remove from popup and return
      if (!(object->TestBit(kNotDeleted))) {
         menuitem->SetType(TClassMenuItem::kPopupSeparator);
         menuitem->SetCall(0,"");
         return;
      }

      method = object->IsA()->GetMethodWithPrototype(menuitem->GetFunctionName(),menuitem->GetArgs());

   }
//    if (!menuitem->IsCallSelf()) {
//       funproto = menuitem->GetFunctionName();
//       funproto = funproto + "(" + menuitem->GetArgs() + ")";
//    }

   // calling object, call the method directly
   if (object) {
      if (method) {
         SetMethod(method);
         SetCalledObject(object);

         if ((method->GetListOfMethodArgs()->First()
                            && menuitem->GetSelfObjectPos() < 0 ) ||
              method->GetListOfMethodArgs()->GetSize() > 1)
            fContextMenuImp->Dialog(object, method);
         else {
            if (menuitem->GetSelfObjectPos() < 0) {
#ifndef WIN32
               Execute(object, method, "");
#else
                // It is a workaround of the "Dead lock under Windows
                char *cmd = Form("((TContextMenu *)0x%lx)->Execute((TObject *)0x%lx,"
                              "(TMethod *)0x%lx,(TObjArray *)0);",
                              (Long_t)this,(Long_t)object,(Long_t)method);
                //Printf("%s", cmd);
                gROOT->ProcessLine(cmd);
                //Execute( object, method, (TObjArray *)NULL );
#endif
             } else {
#ifndef WIN32
               Execute(object, method, Form("(TObject*)0x%lx",(Long_t)fSelectedObject));
#else
                // It is a workaround of the "Dead lock under Windows
                char *cmd = Form("((TContextMenu *)0x%lx)->Execute((TObject *)0x%lx,"
                              "(TMethod *)0x%lx,(TObjArray *)0);",
                              (Long_t)this,(Long_t)object,(Long_t)method);
                //Printf("%s", cmd);
                gROOT->ProcessLine(cmd);
                //Execute( object, method, (TObjArray *)NULL );
#endif
             }
         }
      }

   } else {
      // Calling a standalone global function
      TFunction* function = gROOT->GetGlobalFunctionWithPrototype(
                               menuitem->GetFunctionName());
                               //menuitem->GetArgs());
      if (function) {
         SetMethod(function);
         SetCalledObject(0);
         if ( (function->GetNargs() && menuitem->GetSelfObjectPos() < 0) ||
               function->GetNargs() > 1) {
            fContextMenuImp->Dialog(0,function);
         } else {
            char* cmd;
            if (menuitem->GetSelfObjectPos() < 0) {
               cmd = Form("%s();", menuitem->GetFunctionName());
            } else {
              cmd = Form("%s((TObject*)0x%lx);",
                     menuitem->GetFunctionName(), (Long_t)fSelectedObject);
            }
            gROOT->ProcessLine(cmd);
         }
      }
   }
}

//______________________________________________________________________________
void TContextMenu::Action(TObject *object, TToggle *toggle)
{
   // Action to be performed when this toggle menu item is selected.

   if (object && toggle) {
      TVirtualPad *savedPad = 0;

      gROOT->SetSelectedPrimitive(object);
      if (fSelectedPad) {
         savedPad = (TVirtualPad *) gPad;
         if (savedPad) fSelectedPad->cd();
      }

      gROOT->SetFromPopUp(kTRUE);
      toggle->Toggle();
      if (fSelectedCanvas && fSelectedCanvas->GetPadSave()->TestBit(kNotDeleted))
         fSelectedCanvas->GetPadSave()->Modified();
      if (fSelectedPad && fSelectedPad->TestBit(kNotDeleted))
         fSelectedPad->Modified();
      gROOT->SetFromPopUp(kFALSE);

      if (fSelectedPad && savedPad) {
         if (savedPad->TestBit(kNotDeleted)) savedPad->cd();
      }

      if (fSelectedCanvas && fSelectedCanvas->TestBit(kNotDeleted))
         fSelectedCanvas->Update();
      if (fSelectedCanvas && fSelectedCanvas->GetPadSave()->TestBit(kNotDeleted))
         fSelectedCanvas->GetPadSave()->Update();
   }
}

//______________________________________________________________________________
char *TContextMenu::CreateArgumentTitle(TMethodArg *argument)
{
   // Create string describing argument (for use in dialog box).

   static char argTitle[128];

   if (argument) {
      sprintf(argTitle, "(%s)  %s", argument->GetTitle(), argument->GetName());
      if (argument->GetDefault() && *(argument->GetDefault())) {
         strcat(argTitle, "  [default: ");
         strcat(argTitle, argument->GetDefault());
         strcat(argTitle, "]");
      }
   } else
      *argTitle = 0;

   return argTitle;
}

//______________________________________________________________________________
char *TContextMenu::CreateDialogTitle(TObject *object, TFunction *method)
{
   // Create title for dialog box retrieving argument values.

   static char methodTitle[128];

   if (object && method)
      sprintf(methodTitle, "%s::%s", object->ClassName(), method->GetName());
   else if (!object && method)
      sprintf(methodTitle, "%s", method->GetName());
   else
      *methodTitle = 0;

   return methodTitle;
}

//______________________________________________________________________________
char *TContextMenu::CreatePopupTitle(TObject *object)
{
   // Create title for popup menu.

   static char popupTitle[128];

   if (object) {
      if (!*(object->GetName()) || !strcmp(object->GetName(), object->ClassName())) {
         TGlobal *global = (TGlobal *) gROOT->GetGlobal(object);
         if (global && *(global->GetName()))
            sprintf(popupTitle, "  %s::%s  ", object->ClassName(), global->GetName());
         else
            sprintf(popupTitle, "  %s  ", object->ClassName());
      } else
         sprintf(popupTitle, "  %s::%s  ", object->ClassName(), object->GetName());
   } else
      *popupTitle = 0;

   return popupTitle;
}

//______________________________________________________________________________
void TContextMenu::Execute(TObject *object, TFunction *method, const char *params)
{
   // Execute method with specified arguments for specified object.

   if (method) {
      TVirtualPad *savedPad = 0;

      gROOT->SetSelectedPrimitive(object);
      if (fSelectedPad) {
         savedPad = (TVirtualPad *) gPad;
         if (savedPad) fSelectedPad->cd();
      }

      gROOT->SetFromPopUp(kTRUE);
//      if (fSelectedCanvas) fSelectedCanvas->GetPadSave()->cd();
      if (object) {
         object->Execute((char *) method->GetName(), params);
      } else {
         char *cmd = Form("%s(%s);", method->GetName(),params);
         gROOT->ProcessLine(cmd);
      }
      if (fSelectedCanvas && fSelectedCanvas->GetPadSave()->TestBit(kNotDeleted))
         fSelectedCanvas->GetPadSave()->Modified();
      if (fSelectedPad && fSelectedPad->TestBit(kNotDeleted))
         fSelectedPad->Modified();
      gROOT->SetFromPopUp( kFALSE );

      if (fSelectedPad && savedPad) {
//         fSelectedPad->Modified();
         if (savedPad->TestBit(kNotDeleted)) savedPad->cd();
      }

      if (fSelectedCanvas && fSelectedCanvas->TestBit(kNotDeleted))
         fSelectedCanvas->Update();
      if (fSelectedCanvas && fSelectedCanvas->GetPadSave()->TestBit(kNotDeleted))
         fSelectedCanvas->GetPadSave()->Update();
   }
}

//______________________________________________________________________________
void TContextMenu::Execute(TObject *object, TFunction *method, TObjArray *params)
{
   // Execute method with specified arguments for specified object.

   if (method) {
      TVirtualPad *savedPad = 0;

      gROOT->SetSelectedPrimitive(object);
      if (fSelectedPad) {
         savedPad = (TVirtualPad *) gPad;
         if (savedPad) fSelectedPad->cd();
      }

      gROOT->SetFromPopUp(kTRUE);
//      if (fSelectedCanvas) fSelectedCanvas->GetPadSave()->cd();
      if (object) {
         object->Execute((TMethod*)method, params);
      } else {
         TString args;
         TIter next(params);
         TObjString *s;
         while ((s = (TObjString*) next())) {
            if (!args.IsNull()) args += ",";
            args += s->String();
         }
         char *cmd = Form("%s(%s);", method->GetName(), args.Data());
         gROOT->ProcessLine(cmd);
      }
      if (fSelectedCanvas && fSelectedCanvas->GetPadSave()->TestBit(kNotDeleted))
         fSelectedCanvas->GetPadSave()->Modified();
      gROOT->SetFromPopUp( kFALSE );

      if (fSelectedPad && savedPad) {
//         fSelectedPad->Modified();
         if (savedPad->TestBit(kNotDeleted)) savedPad->cd();
      }

      if (fSelectedCanvas && fSelectedCanvas->TestBit(kNotDeleted))
         fSelectedCanvas->Update();
   }
}

//______________________________________________________________________________
void TContextMenu::Popup(Int_t x, Int_t y, TObject *obj, TVirtualPad *c, TVirtualPad *p)
{
   // Popup context menu at given location in canvas c and pad p for selected
   // object.

   SetBrowser(0);
   SetObject(obj);
   SetCanvas(c);
   SetPad(p);

   DisplayPopUp(x,y);
}

//______________________________________________________________________________
void TContextMenu::Popup(Int_t x, Int_t y, TObject *obj, TBrowser *b)
{
   // Popup context menu at given location in browser b for selected object.

   SetBrowser(b);
   SetObject(obj);
   SetCanvas(0);
   SetPad(0);

   DisplayPopUp(x,y);
}
<|endoftext|>


<commit_before><commit_msg>fix windows DdePoke signature<commit_after><|endoftext|>


<commit_before><commit_msg>Added prototype functions for various C++ surface operations to be benchmarked.<commit_after>//
//
//
//

// extern "C"
// #ifdef _WIN32
// __declspec(dllexport)
// #endif

int fill_surf(int* array_data, int array_width, int array_height);
int fill_surf_memest(){ return 0; }
int copy_surf(){ return 0; }
int copy_surf_memcpy(){ return 0; }
int rgbflag_horiz(){ return 0; }
int rgbflag_vert(){ return 0; }
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/workarounds/wr_vref_workarounds.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file wr_vref_workarounds.C
/// @brief Workarounds for the WR VREF calibration logic
/// Workarounds are very deivce specific, so there is no attempt to generalize
/// this code in any way.
///
// *HWP HWP Owner: Stephen Glancy <sglancy@us.ibm.com>
// *HWP HWP Backup: Brian Silver <bsilver@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 2
// *HWP Consumed by: FSP:HB

#include <fapi2.H>
#include <lib/workarounds/dp16_workarounds.H>
#include <lib/workarounds/wr_vref_workarounds.H>

namespace mss
{

namespace workarounds
{

namespace wr_vref
{

///
/// @brief Executes WR VREF workarounds
/// @param[in] i_target the fapi2 target of the port
/// @param[in] i_rp - the rank pair to execute the override on
/// @param[out] o_vrefdq_train_range - training range value
/// @param[out] o_vrefdq_train_value - training value value
/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
///
fapi2::ReturnCode execute( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
                           const uint64_t& i_rp,
                           uint8_t& o_vrefdq_train_range,
                           uint8_t& o_vrefdq_train_value )
{
    // TODO RTC:160353 - Need module/chip rev EC support for workarounds
    FAPI_TRY(mss::workarounds::dp16::wr_vref::error_dram23(i_target));
    FAPI_TRY(mss::workarounds::dp16::wr_vref::setup_values(i_target, i_rp, o_vrefdq_train_range, o_vrefdq_train_value));

fapi_try_exit:
    return fapi2::current_err;
}

} // close namespace wr_vref
} // close namespace workarounds
} // close namespace mss
<commit_msg>Add EC feature levels to MSS workarounds<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/workarounds/wr_vref_workarounds.C $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file wr_vref_workarounds.C
/// @brief Workarounds for the WR VREF calibration logic
/// Workarounds are very deivce specific, so there is no attempt to generalize
/// this code in any way.
///
// *HWP HWP Owner: Stephen Glancy <sglancy@us.ibm.com>
// *HWP HWP Backup: Brian Silver <bsilver@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 2
// *HWP Consumed by: FSP:HB

#include <fapi2.H>
#include <lib/workarounds/dp16_workarounds.H>
#include <lib/workarounds/wr_vref_workarounds.H>

namespace mss
{

namespace workarounds
{

namespace wr_vref
{

///
/// @brief Executes WR VREF workarounds
/// @param[in] i_target the fapi2 target of the port
/// @param[in] i_rp - the rank pair to execute the override on
/// @param[out] o_vrefdq_train_range - training range value
/// @param[out] o_vrefdq_train_value - training value value
/// @return fapi2::ReturnCode FAPI2_RC_SUCCESS if ok
///
fapi2::ReturnCode execute( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
                           const uint64_t& i_rp,
                           uint8_t& o_vrefdq_train_range,
                           uint8_t& o_vrefdq_train_value )
{
    if (! mss::chip_ec_feature_mss_wr_vref(i_target) )
    {
        return fapi2::FAPI2_RC_SUCCESS;
    }

    FAPI_TRY(mss::workarounds::dp16::wr_vref::error_dram23(i_target));
    FAPI_TRY(mss::workarounds::dp16::wr_vref::setup_values(i_target, i_rp, o_vrefdq_train_range, o_vrefdq_train_value));

fapi_try_exit:
    return fapi2::current_err;
}

} // close namespace wr_vref
} // close namespace workarounds
} // close namespace mss
<|endoftext|>


<commit_before>/*
    Copyright 2012 <copyright holder> <email>

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
*/

#include "asset.hpp"
#include "manager.hpp"

#include <bithorded/lib/grandcentraldispatch.hpp>

using namespace bithorded::cache;

bithorded::cache::CachedAsset::CachedAsset(GrandCentralDispatch& gcd, const boost::filesystem::path& metaFolder) :
	StoredAsset(gcd, metaFolder, RandomAccessFile::READWRITE)
{
	setStatus(hasRootHash() ? bithorde::SUCCESS : bithorde::NOTFOUND);
}

bithorded::cache::CachedAsset::CachedAsset(GrandCentralDispatch& gcd, const boost::filesystem::path& metaFolder, uint64_t size) :
	StoredAsset(gcd, metaFolder, RandomAccessFile::READWRITE, size)
{
	setStatus(bithorde::SUCCESS);
}

void bithorded::cache::CachedAsset::inspect(bithorded::management::InfoList& target) const
{
	target.append("type") << "Cached";
}

void bithorded::cache::CachedAsset::write(uint64_t offset, const std::string& data, const std::function< void() > whenDone)
{
	auto job = boost::bind(&RandomAccessFile::write, &_file, offset, data);
	auto completion = boost::bind(&StoredAsset::notifyValidRange, shared_from_this(), offset, _1, whenDone);
	_gcd.submit(job, completion);
}

bithorded::cache::CachingAsset::CachingAsset(bithorded::cache::CacheManager& mgr, bithorded::router::ForwardedAsset::Ptr upstream, bithorded::cache::CachedAsset::Ptr cached) :
	_manager(mgr),
	_upstream(upstream),
	_upstreamTracker(_upstream->statusChange.connect(boost::bind(&CachingAsset::upstreamStatusChange, this, _1))),
	_cached(cached),
	_delayedCreation(false)
{
	setStatus(_upstream->status);
}

bithorded::cache::CachingAsset::~CachingAsset()
{
	disconnect();
}

void bithorded::cache::CachingAsset::inspect(bithorded::management::InfoList& target) const
{
	target.append("type") << "caching";
	if (_upstream)
		_upstream->inspect_upstreams(target);
}

void bithorded::cache::CachingAsset::async_read(uint64_t offset, size_t& size, uint32_t timeout, bithorded::IAsset::ReadCallback cb)
{
	auto cached_ = cached();
	if (cached_ && (cached_->can_read(offset, size) == size)) {
		cached_->async_read(offset, size, timeout, cb);
	} else if (_upstream) {
		_upstream->async_read(offset, size, timeout, boost::bind(&CachingAsset::upstreamDataArrived, shared_from_this(), cb, size, _1, _2));
	} else {
		cb(-1, "");
	}
}

bool bithorded::cache::CachingAsset::getIds(BitHordeIds& ids) const
{
	if (_upstream)
		return _upstream->getIds(ids);
	else if (_cached)
		return _cached->getIds(ids);
	else
		return false;
}

size_t bithorded::cache::CachingAsset::can_read(uint64_t offset, size_t size)
{
	if (_upstream)
		return _upstream->can_read(offset, size);
	else if (auto cached_ = cached())
		return (cached_->can_read(offset, size) == size) ? size : 0;
	else
		return 0;
}

uint64_t bithorded::cache::CachingAsset::size()
{
	if (auto cached_ = cached())
		return cached_->size();
	else if (_upstream)
		return _upstream->size();
	else
		return 0;
}

void bithorded::cache::CachingAsset::disconnect()
{
	_upstreamTracker.disconnect();
	_upstream.reset();
}

void bithorded::cache::CachingAsset::upstreamDataArrived(bithorded::IAsset::ReadCallback cb, std::size_t requested_size, int64_t offset, const std::string& data)
{
	auto cached_ = cached();
	if (data.size() >= requested_size) {
		cb(offset, data);
	} else if (cached_ && (cached_->can_read(offset, requested_size) == requested_size)) {
		cached_->async_read(offset, requested_size, 0, cb);
	}
	if (data.size() && cached_)
		cached_->write(offset, data, boost::bind(&CachingAsset::releaseIfCached, shared_from_this()));
}

void bithorded::cache::CachingAsset::upstreamStatusChange(bithorde::Status newStatus)
{
	if ((newStatus == bithorde::Status::SUCCESS) && !_cached && _upstream->size() > 0) {
		_delayedCreation = true;
	}
	if (_cached && _cached->hasRootHash())
		newStatus = bithorde::Status::SUCCESS;
	setStatus(newStatus);
}

void CachingAsset::releaseIfCached()
{
	auto cached_ = cached();
	if (cached_ && cached_->hasRootHash())
		disconnect();
}

bithorded::cache::CachedAsset::Ptr bithorded::cache::CachingAsset::cached()
{
	if (_delayedCreation && _upstream) {
		BitHordeIds ids;
		_delayedCreation = false;
		_upstream->getIds(ids);
		_cached = _manager.prepareUpload(_upstream->size(), ids);
	}
	return _cached;
}
<commit_msg>[bithorded/cache/asset]Don't forget to report failed reads.<commit_after>/*
    Copyright 2012 <copyright holder> <email>

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
*/

#include "asset.hpp"
#include "manager.hpp"

#include <bithorded/lib/grandcentraldispatch.hpp>

using namespace bithorded::cache;

bithorded::cache::CachedAsset::CachedAsset(GrandCentralDispatch& gcd, const boost::filesystem::path& metaFolder) :
	StoredAsset(gcd, metaFolder, RandomAccessFile::READWRITE)
{
	setStatus(hasRootHash() ? bithorde::SUCCESS : bithorde::NOTFOUND);
}

bithorded::cache::CachedAsset::CachedAsset(GrandCentralDispatch& gcd, const boost::filesystem::path& metaFolder, uint64_t size) :
	StoredAsset(gcd, metaFolder, RandomAccessFile::READWRITE, size)
{
	setStatus(bithorde::SUCCESS);
}

void bithorded::cache::CachedAsset::inspect(bithorded::management::InfoList& target) const
{
	target.append("type") << "Cached";
}

void bithorded::cache::CachedAsset::write(uint64_t offset, const std::string& data, const std::function< void() > whenDone)
{
	auto job = boost::bind(&RandomAccessFile::write, &_file, offset, data);
	auto completion = boost::bind(&StoredAsset::notifyValidRange, shared_from_this(), offset, _1, whenDone);
	_gcd.submit(job, completion);
}

bithorded::cache::CachingAsset::CachingAsset(bithorded::cache::CacheManager& mgr, bithorded::router::ForwardedAsset::Ptr upstream, bithorded::cache::CachedAsset::Ptr cached) :
	_manager(mgr),
	_upstream(upstream),
	_upstreamTracker(_upstream->statusChange.connect(boost::bind(&CachingAsset::upstreamStatusChange, this, _1))),
	_cached(cached),
	_delayedCreation(false)
{
	setStatus(_upstream->status);
}

bithorded::cache::CachingAsset::~CachingAsset()
{
	disconnect();
}

void bithorded::cache::CachingAsset::inspect(bithorded::management::InfoList& target) const
{
	target.append("type") << "caching";
	if (_upstream)
		_upstream->inspect_upstreams(target);
}

void bithorded::cache::CachingAsset::async_read(uint64_t offset, size_t& size, uint32_t timeout, bithorded::IAsset::ReadCallback cb)
{
	auto cached_ = cached();
	if (cached_ && (cached_->can_read(offset, size) == size)) {
		cached_->async_read(offset, size, timeout, cb);
	} else if (_upstream) {
		_upstream->async_read(offset, size, timeout, boost::bind(&CachingAsset::upstreamDataArrived, shared_from_this(), cb, size, _1, _2));
	} else {
		cb(-1, "");
	}
}

bool bithorded::cache::CachingAsset::getIds(BitHordeIds& ids) const
{
	if (_upstream)
		return _upstream->getIds(ids);
	else if (_cached)
		return _cached->getIds(ids);
	else
		return false;
}

size_t bithorded::cache::CachingAsset::can_read(uint64_t offset, size_t size)
{
	if (_upstream)
		return _upstream->can_read(offset, size);
	else if (auto cached_ = cached())
		return (cached_->can_read(offset, size) == size) ? size : 0;
	else
		return 0;
}

uint64_t bithorded::cache::CachingAsset::size()
{
	if (auto cached_ = cached())
		return cached_->size();
	else if (_upstream)
		return _upstream->size();
	else
		return 0;
}

void bithorded::cache::CachingAsset::disconnect()
{
	_upstreamTracker.disconnect();
	_upstream.reset();
}

void bithorded::cache::CachingAsset::upstreamDataArrived(bithorded::IAsset::ReadCallback cb, std::size_t requested_size, int64_t offset, const std::string& data)
{
	auto cached_ = cached();
	if (data.size() >= requested_size) {
		if (cached_) {
			cached_->write(offset, data, boost::bind(&CachingAsset::releaseIfCached, shared_from_this()));
		}
		cb(offset, data);
	} else if (cached_ && (cached_->can_read(offset, requested_size) == requested_size)) {
		cached_->async_read(offset, requested_size, 0, cb);
	} else {
		cb(offset, data);
	}
}

void bithorded::cache::CachingAsset::upstreamStatusChange(bithorde::Status newStatus)
{
	if ((newStatus == bithorde::Status::SUCCESS) && !_cached && _upstream->size() > 0) {
		_delayedCreation = true;
	}
	if (_cached && _cached->hasRootHash())
		newStatus = bithorde::Status::SUCCESS;
	setStatus(newStatus);
}

void CachingAsset::releaseIfCached()
{
	auto cached_ = cached();
	if (cached_ && cached_->hasRootHash())
		disconnect();
}

bithorded::cache::CachedAsset::Ptr bithorded::cache::CachingAsset::cached()
{
	if (_delayedCreation && _upstream) {
		BitHordeIds ids;
		_delayedCreation = false;
		_upstream->getIds(ids);
		_cached = _manager.prepareUpload(_upstream->size(), ids);
	}
	return _cached;
}
<|endoftext|>


<commit_before>/*
 *  yosys -- Yosys Open SYnthesis Suite
 *
 *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#include "kernel/yosys.h"
#include "kernel/sigtools.h"
#include "passes/techmap/simplemap.h"
#include <stdlib.h>
#include <stdio.h>

USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN

static SigBit get_bit_or_zero(const SigSpec &sig)
{
	if (GetSize(sig) == 0)
		return State::S0;
	return sig[0];
}

static void run_ice40_opts(Module *module)
{
	pool<SigBit> optimized_co;
	vector<Cell*> sb_lut_cells;
	SigMap sigmap(module);

	for (auto cell : module->selected_cells())
	{
		if (cell->type == "\\SB_LUT4")
		{
			sb_lut_cells.push_back(cell);
			continue;
		}

		if (cell->type == "\\SB_CARRY")
		{
			SigSpec non_const_inputs, replacement_output;
			int count_zeros = 0, count_ones = 0;

			SigBit inbit[3] = {
				get_bit_or_zero(cell->getPort("\\I0")),
				get_bit_or_zero(cell->getPort("\\I1")),
				get_bit_or_zero(cell->getPort("\\CI"))
			};
			for (int i = 0; i < 3; i++)
				if (inbit[i].wire == nullptr) {
					if (inbit[i] == State::S1)
						count_ones++;
					else
						count_zeros++;
				} else
					non_const_inputs.append(inbit[i]);

			if (count_zeros >= 2)
				replacement_output = State::S0;
			else if (count_ones >= 2)
				replacement_output = State::S1;
			else if (GetSize(non_const_inputs) == 1)
				replacement_output = non_const_inputs;

			if (GetSize(replacement_output)) {
				optimized_co.insert(sigmap(cell->getPort("\\CO")[0]));
				module->connect(cell->getPort("\\CO")[0], replacement_output);
				module->design->scratchpad_set_bool("opt.did_something", true);
				log("Optimized away SB_CARRY cell %s.%s: CO=%s\n",
						log_id(module), log_id(cell), log_signal(replacement_output));
				module->remove(cell);
			}
			continue;
		}

		if (cell->type == "$__ICE40_CARRY_LUT4")
		{
			SigSpec non_const_inputs, replacement_output;
			int count_zeros = 0, count_ones = 0;

			SigBit inbit[3] = {
				cell->getPort("\\A"),
				cell->getPort("\\B"),
				cell->getPort("\\CI")
			};
			for (int i = 0; i < 3; i++)
				if (inbit[i].wire == nullptr) {
					if (inbit[i] == State::S1)
						count_ones++;
					else
						count_zeros++;
				} else
					non_const_inputs.append(inbit[i]);

			if (count_zeros >= 2)
				replacement_output = State::S0;
			else if (count_ones >= 2)
				replacement_output = State::S1;
			else if (GetSize(non_const_inputs) == 1)
				replacement_output = non_const_inputs;

			if (GetSize(replacement_output)) {
				optimized_co.insert(sigmap(cell->getPort("\\CO")[0]));
				module->connect(cell->getPort("\\CO")[0], replacement_output);
				module->design->scratchpad_set_bool("opt.did_something", true);
				log("Optimized SB_CARRY from $__ICE40_CARRY_LUT4 cell (leaving behind SB_LUT4) %s.%s: CO=%s\n",
						log_id(module), log_id(cell), log_signal(replacement_output));
				cell->type = "\\SB_LUT4";
				cell->setPort("\\I0", RTLIL::S0);
				cell->setPort("\\I1", inbit[0]);
				cell->setPort("\\I2", inbit[1]);
				cell->setPort("\\I3", inbit[2]);
				cell->unsetPort("\\A");
				cell->unsetPort("\\B");
				cell->unsetPort("\\CI");
				cell->unsetPort("\\CO");
				cell->setParam("\\LUT_INIT", RTLIL::Const::from_string("0110100110010110"));
				sb_lut_cells.push_back(cell);
			}
			continue;
		}
	}

	for (auto cell : sb_lut_cells)
	{
		SigSpec inbits;

		inbits.append(get_bit_or_zero(cell->getPort("\\I0")));
		inbits.append(get_bit_or_zero(cell->getPort("\\I1")));
		inbits.append(get_bit_or_zero(cell->getPort("\\I2")));
		inbits.append(get_bit_or_zero(cell->getPort("\\I3")));
		sigmap.apply(inbits);

		if (optimized_co.count(inbits[0])) goto remap_lut;
		if (optimized_co.count(inbits[1])) goto remap_lut;
		if (optimized_co.count(inbits[2])) goto remap_lut;
		if (optimized_co.count(inbits[3])) goto remap_lut;

		if (!sigmap(inbits).is_fully_const())
			continue;

	remap_lut:
		module->design->scratchpad_set_bool("opt.did_something", true);
		log("Mapping SB_LUT4 cell %s.%s back to logic.\n", log_id(module), log_id(cell));

		cell->type ="$lut";
		cell->setParam("\\WIDTH", 4);
		cell->setParam("\\LUT", cell->getParam("\\LUT_INIT"));
		cell->unsetParam("\\LUT_INIT");

		cell->setPort("\\A", SigSpec({
			get_bit_or_zero(cell->getPort("\\I3")),
			get_bit_or_zero(cell->getPort("\\I2")),
			get_bit_or_zero(cell->getPort("\\I1")),
			get_bit_or_zero(cell->getPort("\\I0"))
		}));
		cell->setPort("\\Y", cell->getPort("\\O")[0]);
		cell->unsetPort("\\I0");
		cell->unsetPort("\\I1");
		cell->unsetPort("\\I2");
		cell->unsetPort("\\I3");
		cell->unsetPort("\\O");

		cell->check();
		simplemap_lut(module, cell);
		module->remove(cell);
	}
}

struct Ice40OptPass : public Pass {
	Ice40OptPass() : Pass("ice40_opt", "iCE40: perform simple optimizations") { }
	void help() YS_OVERRIDE
	{
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
		log("\n");
		log("    ice40_opt [options] [selection]\n");
		log("\n");
		log("This command executes the following script:\n");
		log("\n");
		log("    do\n");
		log("        <ice40 specific optimizations>\n");
		log("        opt_expr -mux_undef -undriven [-full]\n");
		log("        opt_merge\n");
		log("        opt_rmdff\n");
		log("        opt_clean\n");
		log("    while <changed design>\n");
		log("\n");
	}
	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
	{
		string opt_expr_args = "-mux_undef -undriven";

		log_header(design, "Executing ICE40_OPT pass (performing simple optimizations).\n");
		log_push();

		size_t argidx;
		for (argidx = 1; argidx < args.size(); argidx++) {
			if (args[argidx] == "-full") {
				opt_expr_args += " -full";
				continue;
			}
			break;
		}
		extra_args(args, argidx, design);

		while (1)
		{
			design->scratchpad_unset("opt.did_something");

			log_header(design, "Running ICE40 specific optimizations.\n");
			for (auto module : design->selected_modules())
				run_ice40_opts(module);

			Pass::call(design, "opt_expr " + opt_expr_args);
			Pass::call(design, "opt_merge");
			Pass::call(design, "opt_rmdff");
			Pass::call(design, "opt_clean");

			if (design->scratchpad_get_bool("opt.did_something") == false)
				break;

			log_header(design, "Rerunning OPT passes. (Removed registers in this run.)\n");
		}

		design->optimize();
		design->sort();
		design->check();

		log_header(design, "Finished OPT passes. (There is nothing left to do.)\n");
		log_pop();
	}
} Ice40OptPass;

PRIVATE_NAMESPACE_END
<commit_msg>ice40_opt to $__ICE40_CARRY_LUT4 into $lut not SB_LUT<commit_after>/*
 *  yosys -- Yosys Open SYnthesis Suite
 *
 *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#include "kernel/yosys.h"
#include "kernel/sigtools.h"
#include "passes/techmap/simplemap.h"
#include <stdlib.h>
#include <stdio.h>

USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN

static SigBit get_bit_or_zero(const SigSpec &sig)
{
	if (GetSize(sig) == 0)
		return State::S0;
	return sig[0];
}

static void run_ice40_opts(Module *module)
{
	pool<SigBit> optimized_co;
	vector<Cell*> sb_lut_cells;
	SigMap sigmap(module);

	for (auto cell : module->selected_cells())
	{
		if (cell->type == "\\SB_LUT4")
		{
			sb_lut_cells.push_back(cell);
			continue;
		}

		if (cell->type == "\\SB_CARRY")
		{
			SigSpec non_const_inputs, replacement_output;
			int count_zeros = 0, count_ones = 0;

			SigBit inbit[3] = {
				get_bit_or_zero(cell->getPort("\\I0")),
				get_bit_or_zero(cell->getPort("\\I1")),
				get_bit_or_zero(cell->getPort("\\CI"))
			};
			for (int i = 0; i < 3; i++)
				if (inbit[i].wire == nullptr) {
					if (inbit[i] == State::S1)
						count_ones++;
					else
						count_zeros++;
				} else
					non_const_inputs.append(inbit[i]);

			if (count_zeros >= 2)
				replacement_output = State::S0;
			else if (count_ones >= 2)
				replacement_output = State::S1;
			else if (GetSize(non_const_inputs) == 1)
				replacement_output = non_const_inputs;

			if (GetSize(replacement_output)) {
				optimized_co.insert(sigmap(cell->getPort("\\CO")[0]));
				module->connect(cell->getPort("\\CO")[0], replacement_output);
				module->design->scratchpad_set_bool("opt.did_something", true);
				log("Optimized away SB_CARRY cell %s.%s: CO=%s\n",
						log_id(module), log_id(cell), log_signal(replacement_output));
				module->remove(cell);
			}
			continue;
		}

		if (cell->type == "$__ICE40_CARRY_LUT4")
		{
			SigSpec non_const_inputs, replacement_output;
			int count_zeros = 0, count_ones = 0;

			SigBit inbit[3] = {
				cell->getPort("\\A"),
				cell->getPort("\\B"),
				cell->getPort("\\CI")
			};
			for (int i = 0; i < 3; i++)
				if (inbit[i].wire == nullptr) {
					if (inbit[i] == State::S1)
						count_ones++;
					else
						count_zeros++;
				} else
					non_const_inputs.append(inbit[i]);

			if (count_zeros >= 2)
				replacement_output = State::S0;
			else if (count_ones >= 2)
				replacement_output = State::S1;
			else if (GetSize(non_const_inputs) == 1)
				replacement_output = non_const_inputs;

			if (GetSize(replacement_output)) {
				optimized_co.insert(sigmap(cell->getPort("\\CO")[0]));
				module->connect(cell->getPort("\\CO")[0], replacement_output);
				module->design->scratchpad_set_bool("opt.did_something", true);
				log("Optimized $__ICE40_CARRY_LUT4 cell into $lut (without SB_CARRY) %s.%s: CO=%s\n",
						log_id(module), log_id(cell), log_signal(replacement_output));
				cell->type = "$lut";
				cell->setPort("\\A", { RTLIL::S0, inbit[0], inbit[1], inbit[2] });
				cell->setPort("\\Y", cell->getPort("\\O"));
				cell->unsetPort("\\B");
				cell->unsetPort("\\CI");
				cell->unsetPort("\\CO");
				cell->unsetPort("\\O");
				cell->setParam("\\LUT", RTLIL::Const::from_string("0110100110010110"));
				cell->setParam("\\WIDTH", 4);
			}
			continue;
		}
	}

	for (auto cell : sb_lut_cells)
	{
		SigSpec inbits;

		inbits.append(get_bit_or_zero(cell->getPort("\\I0")));
		inbits.append(get_bit_or_zero(cell->getPort("\\I1")));
		inbits.append(get_bit_or_zero(cell->getPort("\\I2")));
		inbits.append(get_bit_or_zero(cell->getPort("\\I3")));
		sigmap.apply(inbits);

		if (optimized_co.count(inbits[0])) goto remap_lut;
		if (optimized_co.count(inbits[1])) goto remap_lut;
		if (optimized_co.count(inbits[2])) goto remap_lut;
		if (optimized_co.count(inbits[3])) goto remap_lut;

		if (!sigmap(inbits).is_fully_const())
			continue;

	remap_lut:
		module->design->scratchpad_set_bool("opt.did_something", true);
		log("Mapping SB_LUT4 cell %s.%s back to logic.\n", log_id(module), log_id(cell));

		cell->type ="$lut";
		cell->setParam("\\WIDTH", 4);
		cell->setParam("\\LUT", cell->getParam("\\LUT_INIT"));
		cell->unsetParam("\\LUT_INIT");

		cell->setPort("\\A", SigSpec({
			get_bit_or_zero(cell->getPort("\\I3")),
			get_bit_or_zero(cell->getPort("\\I2")),
			get_bit_or_zero(cell->getPort("\\I1")),
			get_bit_or_zero(cell->getPort("\\I0"))
		}));
		cell->setPort("\\Y", cell->getPort("\\O")[0]);
		cell->unsetPort("\\I0");
		cell->unsetPort("\\I1");
		cell->unsetPort("\\I2");
		cell->unsetPort("\\I3");
		cell->unsetPort("\\O");

		cell->check();
		simplemap_lut(module, cell);
		module->remove(cell);
	}
}

struct Ice40OptPass : public Pass {
	Ice40OptPass() : Pass("ice40_opt", "iCE40: perform simple optimizations") { }
	void help() YS_OVERRIDE
	{
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
		log("\n");
		log("    ice40_opt [options] [selection]\n");
		log("\n");
		log("This command executes the following script:\n");
		log("\n");
		log("    do\n");
		log("        <ice40 specific optimizations>\n");
		log("        opt_expr -mux_undef -undriven [-full]\n");
		log("        opt_merge\n");
		log("        opt_rmdff\n");
		log("        opt_clean\n");
		log("    while <changed design>\n");
		log("\n");
	}
	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
	{
		string opt_expr_args = "-mux_undef -undriven";

		log_header(design, "Executing ICE40_OPT pass (performing simple optimizations).\n");
		log_push();

		size_t argidx;
		for (argidx = 1; argidx < args.size(); argidx++) {
			if (args[argidx] == "-full") {
				opt_expr_args += " -full";
				continue;
			}
			break;
		}
		extra_args(args, argidx, design);

		while (1)
		{
			design->scratchpad_unset("opt.did_something");

			log_header(design, "Running ICE40 specific optimizations.\n");
			for (auto module : design->selected_modules())
				run_ice40_opts(module);

			Pass::call(design, "opt_expr " + opt_expr_args);
			Pass::call(design, "opt_merge");
			Pass::call(design, "opt_rmdff");
			Pass::call(design, "opt_clean");

			if (design->scratchpad_get_bool("opt.did_something") == false)
				break;

			log_header(design, "Rerunning OPT passes. (Removed registers in this run.)\n");
		}

		design->optimize();
		design->sort();
		design->check();

		log_header(design, "Finished OPT passes. (There is nothing left to do.)\n");
		log_pop();
	}
} Ice40OptPass;

PRIVATE_NAMESPACE_END
<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "OpenwireCmsTemplateTest.h"
#include <integration/IntegrationCommon.h>

#include <decaf/lang/Thread.h>
#include <decaf/util/Properties.h>
#include <activemq/transport/TransportFactory.h>
#include <decaf/util/UUID.h>
#include <decaf/util/Properties.h>
#include <decaf/util/StringTokenizer.h>
#include <activemq/connector/ConnectorFactoryMap.h>
#include <decaf/net/SocketFactory.h>
#include <activemq/transport/TransportFactory.h>
#include <decaf/net/Socket.h>
#include <decaf/lang/exceptions/NullPointerException.h>
#include <activemq/core/ActiveMQConnectionFactory.h>
#include <activemq/core/ActiveMQConnection.h>
#include <activemq/core/ActiveMQConsumer.h>
#include <activemq/core/ActiveMQProducer.h>
#include <decaf/util/StringTokenizer.h>
#include <decaf/lang/Boolean.h>

#include <cms/Connection.h>
#include <cms/MessageConsumer.h>
#include <cms/MessageProducer.h>
#include <cms/MessageListener.h>
#include <cms/Startable.h>
#include <cms/Closeable.h>
#include <cms/MessageListener.h>
#include <cms/ExceptionListener.h>
#include <cms/Topic.h>
#include <cms/Queue.h>
#include <cms/TemporaryTopic.h>
#include <cms/TemporaryQueue.h>
#include <cms/Session.h>
#include <cms/BytesMessage.h>
#include <cms/TextMessage.h>
#include <cms/MapMessage.h>

using namespace activemq::transport;
using namespace std;
using namespace cms;
using namespace activemq;
using namespace activemq::core;
using namespace activemq::connector;
using namespace activemq::exceptions;
using namespace decaf::net;
using namespace activemq::transport;
using namespace decaf::util::concurrent;
using namespace decaf::lang;
using namespace decaf::util;

using namespace integration;
using namespace integration::connector::openwire;
using namespace activemq::cmsutil;

////////////////////////////////////////////////////////////////////////////////
void OpenwireCmsTemplateTest::setUp() {
}

////////////////////////////////////////////////////////////////////////////////
void OpenwireCmsTemplateTest::tearDown() {
}

////////////////////////////////////////////////////////////////////////////////
void OpenwireCmsTemplateTest::testBasics()
{
    try {
        const unsigned int NUM_MESSAGES = IntegrationCommon::defaultMsgCount;

        Receiver receiver( IntegrationCommon::getInstance().getOpenwireURL(),
                false,
                "testBasics1",
                NUM_MESSAGES);
        Thread rt(&receiver);
        rt.start();

        // Wait for receiver thread to start.
        decaf::lang::Thread::sleep(100);

        Sender sender( IntegrationCommon::getInstance().getOpenwireURL(),
                false,
                "testBasics1",
                NUM_MESSAGES);
        Thread st(&sender);
        st.start();

        st.join();
        rt.join();

        unsigned int numReceived = receiver.getNumReceived();
        if( IntegrationCommon::debug ) {
            printf("received: %d\n", numReceived );
        }
        CPPUNIT_ASSERT(
            numReceived == NUM_MESSAGES );
    } catch ( ActiveMQException e ) {
        e.printStackTrace();
        throw e;
    }
}

////////////////////////////////////////////////////////////////////////////////
void OpenwireCmsTemplateTest::testReceiveException()
{
    try {
        // First, try receiving from a bad url
        activemq::core::ActiveMQConnectionFactory cf("tcp://localhost:61666"); // Invalid URL (at least by default)
        activemq::cmsutil::CmsTemplate cmsTemplate(&cf);
        cmsTemplate.setDefaultDestinationName("testReceive1");
        try {
            cmsTemplate.receive();
            CPPUNIT_FAIL("failed to throw expected exception");
        }
        catch( ActiveMQException& ex) {
            // Expected.
        }

        // Now change to a good url and verify that we can reuse the same
        // CmsTemplate successfully.
        activemq::core::ActiveMQConnectionFactory cf2(IntegrationCommon::getInstance().getOpenwireURL());
        cmsTemplate.setConnectionFactory(&cf2);

        // Send 1 message.
        Sender sender( IntegrationCommon::getInstance().getOpenwireURL(),
                false,
                "testReceive1",
                1);
        Thread st(&sender);
        st.start();

        // Receive the message.
        cms::Message* message = cmsTemplate.receive();
        CPPUNIT_ASSERT(message != NULL);
        delete message;
    }
    catch ( ActiveMQException e ) {
        e.printStackTrace();
        throw e;
    }
}

////////////////////////////////////////////////////////////////////////////////
void OpenwireCmsTemplateTest::testSendException()
{
    try {
        // First, try sending to a bad url.
        activemq::core::ActiveMQConnectionFactory cf("tcp://localhost:61666"); // Invalid URL (at least by default)
        activemq::cmsutil::CmsTemplate cmsTemplate(&cf);
        cmsTemplate.setDefaultDestinationName("testSend1");
        try {
            TextMessageCreator msgCreator("hello world");
            cmsTemplate.send(&msgCreator);
            CPPUNIT_FAIL("failed to throw expected exception");
        }
        catch( ActiveMQException& ex) {
            // Expected.
        }

        // Now change to a good url and verify that we can reuse the same
        // CmsTemplate successfully.
        activemq::core::ActiveMQConnectionFactory cf2(IntegrationCommon::getInstance().getOpenwireURL());
        cmsTemplate.setConnectionFactory(&cf2);
        TextMessageCreator msgCreator("hello world");
        cmsTemplate.send(&msgCreator);
    } catch ( ActiveMQException e ) {
        e.printStackTrace();
        throw e;
    }
}
<commit_msg>Fix thread sync issues<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "OpenwireCmsTemplateTest.h"
#include <integration/IntegrationCommon.h>

#include <decaf/lang/Thread.h>
#include <decaf/util/Properties.h>
#include <activemq/transport/TransportFactory.h>
#include <decaf/util/UUID.h>
#include <decaf/util/Properties.h>
#include <decaf/util/StringTokenizer.h>
#include <activemq/connector/ConnectorFactoryMap.h>
#include <decaf/net/SocketFactory.h>
#include <activemq/transport/TransportFactory.h>
#include <decaf/net/Socket.h>
#include <decaf/lang/exceptions/NullPointerException.h>
#include <activemq/core/ActiveMQConnectionFactory.h>
#include <activemq/core/ActiveMQConnection.h>
#include <activemq/core/ActiveMQConsumer.h>
#include <activemq/core/ActiveMQProducer.h>
#include <decaf/util/StringTokenizer.h>
#include <decaf/lang/Boolean.h>

#include <cms/Connection.h>
#include <cms/MessageConsumer.h>
#include <cms/MessageProducer.h>
#include <cms/MessageListener.h>
#include <cms/Startable.h>
#include <cms/Closeable.h>
#include <cms/MessageListener.h>
#include <cms/ExceptionListener.h>
#include <cms/Topic.h>
#include <cms/Queue.h>
#include <cms/TemporaryTopic.h>
#include <cms/TemporaryQueue.h>
#include <cms/Session.h>
#include <cms/BytesMessage.h>
#include <cms/TextMessage.h>
#include <cms/MapMessage.h>

using namespace activemq::transport;
using namespace std;
using namespace cms;
using namespace activemq;
using namespace activemq::core;
using namespace activemq::connector;
using namespace activemq::exceptions;
using namespace decaf::net;
using namespace activemq::transport;
using namespace decaf::util::concurrent;
using namespace decaf::lang;
using namespace decaf::util;

using namespace integration;
using namespace integration::connector::openwire;
using namespace activemq::cmsutil;

////////////////////////////////////////////////////////////////////////////////
void OpenwireCmsTemplateTest::setUp() {
}

////////////////////////////////////////////////////////////////////////////////
void OpenwireCmsTemplateTest::tearDown() {
}

////////////////////////////////////////////////////////////////////////////////
void OpenwireCmsTemplateTest::testBasics()
{
    try {
        const unsigned int NUM_MESSAGES = IntegrationCommon::defaultMsgCount;

        Receiver receiver( IntegrationCommon::getInstance().getOpenwireURL(),
                false,
                "testBasics1",
                NUM_MESSAGES);
        Thread rt(&receiver);
        rt.start();

        // Wait for receiver thread to start.
        decaf::lang::Thread::sleep(100);

        Sender sender( IntegrationCommon::getInstance().getOpenwireURL(),
                false,
                "testBasics1",
                NUM_MESSAGES);
        Thread st(&sender);
        st.start();

        st.join();
        rt.join();

        unsigned int numReceived = receiver.getNumReceived();
        if( IntegrationCommon::debug ) {
            printf("received: %d\n", numReceived );
        }
        CPPUNIT_ASSERT(
            numReceived == NUM_MESSAGES );
    } catch ( ActiveMQException e ) {
        e.printStackTrace();
        throw e;
    }
}

////////////////////////////////////////////////////////////////////////////////
void OpenwireCmsTemplateTest::testReceiveException()
{
    try {
        // First, try receiving from a bad url
        activemq::core::ActiveMQConnectionFactory cf("tcp://localhost:61666"); // Invalid URL (at least by default)
        activemq::cmsutil::CmsTemplate cmsTemplate(&cf);
        cmsTemplate.setDefaultDestinationName("testReceive1");
        try {
            cmsTemplate.receive();
            CPPUNIT_FAIL("failed to throw expected exception");
        }
        catch( ActiveMQException& ex) {
            // Expected.
        }

        // Now change to a good url and verify that we can reuse the same
        // CmsTemplate successfully.
        activemq::core::ActiveMQConnectionFactory cf2(IntegrationCommon::getInstance().getOpenwireURL());
        cmsTemplate.setConnectionFactory(&cf2);

        // Send 1 message.
        Sender sender( IntegrationCommon::getInstance().getOpenwireURL(),
                false,
                "testReceive1",
                1);
        Thread st(&sender);
        st.start();
        st.join();

        // Receive the message.
        cms::Message* message = cmsTemplate.receive();
        CPPUNIT_ASSERT(message != NULL);
        delete message;
    }
    catch ( ActiveMQException e ) {
        e.printStackTrace();
        throw e;
    }
}

////////////////////////////////////////////////////////////////////////////////
void OpenwireCmsTemplateTest::testSendException()
{
    try {
        // First, try sending to a bad url.
        activemq::core::ActiveMQConnectionFactory cf("tcp://localhost:61666"); // Invalid URL (at least by default)
        activemq::cmsutil::CmsTemplate cmsTemplate(&cf);
        cmsTemplate.setDefaultDestinationName("testSend1");
        try {
            TextMessageCreator msgCreator("hello world");
            cmsTemplate.send(&msgCreator);
            CPPUNIT_FAIL("failed to throw expected exception");
        }
        catch( ActiveMQException& ex) {
            // Expected.
        }

        // Now change to a good url and verify that we can reuse the same
        // CmsTemplate successfully.
        activemq::core::ActiveMQConnectionFactory cf2(IntegrationCommon::getInstance().getOpenwireURL());
        cmsTemplate.setConnectionFactory(&cf2);
        TextMessageCreator msgCreator("hello world");
        cmsTemplate.send(&msgCreator);
    } catch ( ActiveMQException e ) {
        e.printStackTrace();
        throw e;
    }
}
<|endoftext|>