Kokkos Core Kernels Package  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends
Kokkos_Bitset.hpp
00001 /*
00002 //@HEADER
00003 // ************************************************************************
00004 //
00005 //   Kokkos: Manycore Performance-Portable Multidimensional Arrays
00006 //              Copyright (2012) Sandia Corporation
00007 //
00008 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
00009 // the U.S. Government retains certain rights in this software.
00010 //
00011 // Redistribution and use in source and binary forms, with or without
00012 // modification, are permitted provided that the following conditions are
00013 // met:
00014 //
00015 // 1. Redistributions of source code must retain the above copyright
00016 // notice, this list of conditions and the following disclaimer.
00017 //
00018 // 2. Redistributions in binary form must reproduce the above copyright
00019 // notice, this list of conditions and the following disclaimer in the
00020 // documentation and/or other materials provided with the distribution.
00021 //
00022 // 3. Neither the name of the Corporation nor the names of the
00023 // contributors may be used to endorse or promote products derived from
00024 // this software without specific prior written permission.
00025 //
00026 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
00027 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00028 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00029 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
00030 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00031 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00032 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00033 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00034 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00035 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00036 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00037 //
00038 // Questions? Contact  H. Carter Edwards (hcedwar@sandia.gov)
00039 //
00040 // ************************************************************************
00041 //@HEADER
00042 */
00043 
00044 #ifndef KOKKOS_BITSET_HPP
00045 #define KOKKOS_BITSET_HPP
00046 
00047 #include <Kokkos_Core.hpp>
00048 #include <Kokkos_Functional.hpp>
00049 
00050 #include <impl/Kokkos_Bitset_impl.hpp>
00051 
00052 #include <stdexcept>
00053 
00054 namespace Kokkos {
00055 
00056 template <typename Device = Kokkos::DefaultExecutionSpace >
00057 class Bitset;
00058 
00059 template <typename Device = Kokkos::DefaultExecutionSpace >
00060 class ConstBitset;
00061 
00062 template <typename DstDevice, typename SrcDevice>
00063 void deep_copy( Bitset<DstDevice> & dst, Bitset<SrcDevice> const& src);
00064 
00065 template <typename DstDevice, typename SrcDevice>
00066 void deep_copy( Bitset<DstDevice> & dst, ConstBitset<SrcDevice> const& src);
00067 
00068 template <typename DstDevice, typename SrcDevice>
00069 void deep_copy( ConstBitset<DstDevice> & dst, ConstBitset<SrcDevice> const& src);
00070 
00071 
00073 template <typename Device>
00074 class Bitset
00075 {
00076 public:
00077   typedef Device device_type;
00078   typedef unsigned size_type;
00079 
00080   enum { BIT_SCAN_REVERSE = 1u };
00081   enum { MOVE_HINT_BACKWARD = 2u };
00082 
00083   enum {
00084       BIT_SCAN_FORWARD_MOVE_HINT_FORWARD = 0u
00085     , BIT_SCAN_REVERSE_MOVE_HINT_FORWARD = BIT_SCAN_REVERSE
00086     , BIT_SCAN_FORWARD_MOVE_HINT_BACKWARD = MOVE_HINT_BACKWARD
00087     , BIT_SCAN_REVERSE_MOVE_HINT_BACKWARD = BIT_SCAN_REVERSE | MOVE_HINT_BACKWARD
00088   };
00089 
00090 private:
00091   enum { block_size = static_cast<unsigned>(sizeof(unsigned)*CHAR_BIT) };
00092   enum { block_mask = block_size-1u };
00093   enum { block_shift = static_cast<int>(Impl::power_of_two<block_size>::value) };
00094 
00095 public:
00096 
00097 
00100   Bitset(unsigned arg_size = 0u)
00101     : m_size(arg_size)
00102     , m_last_block_mask(0u)
00103     , m_blocks("Bitset", ((m_size + block_mask) >> block_shift) )
00104   {
00105     for (int i=0, end = static_cast<int>(m_size & block_mask); i < end; ++i) {
00106       m_last_block_mask |= 1u << i;
00107     }
00108   }
00109 
00111   Bitset<Device> & operator = (Bitset<Device> const & rhs)
00112   {
00113     this->m_size = rhs.m_size;
00114     this->m_last_block_mask = rhs.m_last_block_mask;
00115     this->m_blocks = rhs.m_blocks;
00116 
00117     return *this;
00118   }
00119 
00121   Bitset( Bitset<Device> const & rhs)
00122     : m_size( rhs.m_size )
00123     , m_last_block_mask( rhs.m_last_block_mask )
00124     , m_blocks( rhs.m_blocks )
00125   {}
00126 
00129   KOKKOS_FORCEINLINE_FUNCTION
00130   unsigned size() const
00131   { return m_size; }
00132 
00135   unsigned count() const
00136   {
00137     Impl::BitsetCount< Bitset<Device> > f(*this);
00138     return f.apply();
00139   }
00140 
00143   void set()
00144   {
00145     Kokkos::deep_copy(m_blocks, ~0u );
00146 
00147     if (m_last_block_mask) {
00148       //clear the unused bits in the last block
00149       typedef Kokkos::Impl::DeepCopy< typename device_type::memory_space, Kokkos::HostSpace > raw_deep_copy;
00150       raw_deep_copy( m_blocks.ptr_on_device() + (m_blocks.size() -1u), &m_last_block_mask, sizeof(unsigned));
00151     }
00152   }
00153 
00156   void reset()
00157   {
00158     Kokkos::deep_copy(m_blocks, 0u );
00159   }
00160 
00163   void clear()
00164   {
00165     Kokkos::deep_copy(m_blocks, 0u );
00166   }
00167 
00170   KOKKOS_FORCEINLINE_FUNCTION
00171   bool set( unsigned i ) const
00172   {
00173     if ( i < m_size ) {
00174       unsigned * block_ptr = &m_blocks[ i >> block_shift ];
00175       const unsigned mask = 1u << static_cast<int>( i & block_mask );
00176 
00177       return !( atomic_fetch_or( block_ptr, mask ) & mask );
00178     }
00179     return false;
00180   }
00181 
00184   KOKKOS_FORCEINLINE_FUNCTION
00185   bool reset( unsigned i ) const
00186   {
00187     if ( i < m_size ) {
00188       unsigned * block_ptr = &m_blocks[ i >> block_shift ];
00189       const unsigned mask = 1u << static_cast<int>( i & block_mask );
00190 
00191       return atomic_fetch_and( block_ptr, ~mask ) & mask;
00192     }
00193     return false;
00194   }
00195 
00198   KOKKOS_FORCEINLINE_FUNCTION
00199   bool test( unsigned i ) const
00200   {
00201     if ( i < m_size ) {
00202       const unsigned block = volatile_load(&m_blocks[ i >> block_shift ]);
00203       const unsigned mask = 1u << static_cast<int>( i & block_mask );
00204       return block & mask;
00205     }
00206     return false;
00207   }
00208 
00212   KOKKOS_FORCEINLINE_FUNCTION
00213   unsigned max_hint() const
00214   {
00215     return m_blocks.size();
00216   }
00217 
00221   KOKKOS_INLINE_FUNCTION
00222   Kokkos::pair<bool, unsigned> find_any_set_near( unsigned hint , unsigned scan_direction = BIT_SCAN_FORWARD_MOVE_HINT_FORWARD ) const
00223   {
00224     const unsigned block_idx = (hint >> block_shift) < m_blocks.size() ? (hint >> block_shift) : 0;
00225     const unsigned offset = hint & block_mask;
00226     unsigned block = volatile_load(&m_blocks[ block_idx ]);
00227     block = !m_last_block_mask || (block_idx < (m_blocks.size()-1)) ? block : block & m_last_block_mask ;
00228 
00229     return find_any_helper(block_idx, offset, block, scan_direction);
00230   }
00231 
00235   KOKKOS_INLINE_FUNCTION
00236   Kokkos::pair<bool, unsigned> find_any_unset_near( unsigned hint , unsigned scan_direction = BIT_SCAN_FORWARD_MOVE_HINT_FORWARD ) const
00237   {
00238     const unsigned block_idx = hint >> block_shift;
00239     const unsigned offset = hint & block_mask;
00240     unsigned block = volatile_load(&m_blocks[ block_idx ]);
00241     block = !m_last_block_mask || (block_idx < (m_blocks.size()-1) ) ? ~block : ~block & m_last_block_mask ;
00242 
00243     return find_any_helper(block_idx, offset, block, scan_direction);
00244   }
00245 
00246 private:
00247 
00248   KOKKOS_FORCEINLINE_FUNCTION
00249   Kokkos::pair<bool, unsigned> find_any_helper(unsigned block_idx, unsigned offset, unsigned block, unsigned scan_direction) const
00250   {
00251     Kokkos::pair<bool, unsigned> result( block > 0u, 0);
00252 
00253     if (!result.first) {
00254       result.second = update_hint( block_idx, offset, scan_direction );
00255     }
00256     else {
00257       result.second = scan_block(  (block_idx << block_shift)
00258                                  , offset
00259                                  , block
00260                                  , scan_direction
00261                                 );
00262     }
00263     return result;
00264   }
00265 
00266 
00267   KOKKOS_FORCEINLINE_FUNCTION
00268   unsigned scan_block(unsigned block_start, int offset, unsigned block, unsigned scan_direction ) const
00269   {
00270     offset = !(scan_direction & BIT_SCAN_REVERSE) ? offset : (offset + block_mask) & block_mask;
00271     block = Impl::rotate_right(block, offset);
00272     return ((( !(scan_direction & BIT_SCAN_REVERSE) ?
00273                Impl::bit_scan_forward(block) :
00274                Impl::bit_scan_reverse(block)
00275              ) + offset
00276             ) & block_mask
00277            ) + block_start;
00278   }
00279 
00280   KOKKOS_FORCEINLINE_FUNCTION
00281   unsigned update_hint( long long block_idx, unsigned offset, unsigned scan_direction ) const
00282   {
00283     block_idx += scan_direction & MOVE_HINT_BACKWARD ? -1 : 1;
00284     block_idx = block_idx >= 0 ? block_idx : m_blocks.size() - 1;
00285     block_idx = block_idx < static_cast<long long>(m_blocks.size()) ? block_idx : 0;
00286 
00287     return static_cast<unsigned>(block_idx)*block_size + offset;
00288   }
00289 
00290 private:
00291 
00292   unsigned m_size;
00293   unsigned m_last_block_mask;
00294   View< unsigned *, device_type, MemoryTraits<RandomAccess> > m_blocks;
00295 
00296 private:
00297   template <typename DDevice>
00298   friend class Bitset;
00299 
00300   template <typename DDevice>
00301   friend class ConstBitset;
00302 
00303   template <typename Bitset>
00304   friend struct Impl::BitsetCount;
00305 
00306   template <typename DstDevice, typename SrcDevice>
00307   friend void deep_copy( Bitset<DstDevice> & dst, Bitset<SrcDevice> const& src);
00308 
00309   template <typename DstDevice, typename SrcDevice>
00310   friend void deep_copy( Bitset<DstDevice> & dst, ConstBitset<SrcDevice> const& src);
00311 };
00312 
00315 template <typename Device>
00316 class ConstBitset
00317 {
00318 public:
00319   typedef Device device_type;
00320   typedef unsigned size_type;
00321 
00322 private:
00323   enum { block_size = static_cast<unsigned>(sizeof(unsigned)*CHAR_BIT) };
00324   enum { block_mask = block_size -1u };
00325   enum { block_shift = static_cast<int>(Impl::power_of_two<block_size>::value) };
00326 
00327 public:
00328   ConstBitset()
00329     : m_size (0)
00330   {}
00331 
00332   ConstBitset(Bitset<Device> const& rhs)
00333     : m_size(rhs.m_size)
00334     , m_blocks(rhs.m_blocks)
00335   {}
00336 
00337   ConstBitset(ConstBitset<Device> const& rhs)
00338     : m_size( rhs.m_size )
00339     , m_blocks( rhs.m_blocks )
00340   {}
00341 
00342   ConstBitset<Device> & operator = (Bitset<Device> const & rhs)
00343   {
00344     this->m_size = rhs.m_size;
00345     this->m_blocks = rhs.m_blocks;
00346 
00347     return *this;
00348   }
00349 
00350   ConstBitset<Device> & operator = (ConstBitset<Device> const & rhs)
00351   {
00352     this->m_size = rhs.m_size;
00353     this->m_blocks = rhs.m_blocks;
00354 
00355     return *this;
00356   }
00357 
00358 
00359   KOKKOS_FORCEINLINE_FUNCTION
00360   unsigned size() const
00361   {
00362     return m_size;
00363   }
00364 
00365   unsigned count() const
00366   {
00367     Impl::BitsetCount< ConstBitset<Device> > f(*this);
00368     return f.apply();
00369   }
00370 
00371   KOKKOS_FORCEINLINE_FUNCTION
00372   bool test( unsigned i ) const
00373   {
00374     if ( i < m_size ) {
00375       const unsigned block = m_blocks[ i >> block_shift ];
00376       const unsigned mask = 1u << static_cast<int>( i & block_mask );
00377       return block & mask;
00378     }
00379     return false;
00380   }
00381 
00382 private:
00383 
00384   unsigned m_size;
00385   View< const unsigned *, device_type, MemoryTraits<RandomAccess> > m_blocks;
00386 
00387 private:
00388   template <typename DDevice>
00389   friend class ConstBitset;
00390 
00391   template <typename Bitset>
00392   friend struct Impl::BitsetCount;
00393 
00394   template <typename DstDevice, typename SrcDevice>
00395   friend void deep_copy( Bitset<DstDevice> & dst, ConstBitset<SrcDevice> const& src);
00396 
00397   template <typename DstDevice, typename SrcDevice>
00398   friend void deep_copy( ConstBitset<DstDevice> & dst, ConstBitset<SrcDevice> const& src);
00399 };
00400 
00401 
00402 template <typename DstDevice, typename SrcDevice>
00403 void deep_copy( Bitset<DstDevice> & dst, Bitset<SrcDevice> const& src)
00404 {
00405   if (dst.size() != src.size()) {
00406     throw std::runtime_error("Error: Cannot deep_copy bitsets of different sizes!");
00407   }
00408 
00409   typedef Kokkos::Impl::DeepCopy< typename DstDevice::memory_space, typename SrcDevice::memory_space > raw_deep_copy;
00410   raw_deep_copy(dst.m_blocks.ptr_on_device(), src.m_blocks.ptr_on_device(), sizeof(unsigned)*src.m_blocks.size());
00411 }
00412 
00413 template <typename DstDevice, typename SrcDevice>
00414 void deep_copy( Bitset<DstDevice> & dst, ConstBitset<SrcDevice> const& src)
00415 {
00416   if (dst.size() != src.size()) {
00417     throw std::runtime_error("Error: Cannot deep_copy bitsets of different sizes!");
00418   }
00419 
00420   typedef Kokkos::Impl::DeepCopy< typename DstDevice::memory_space, typename SrcDevice::memory_space > raw_deep_copy;
00421   raw_deep_copy(dst.m_blocks.ptr_on_device(), src.m_blocks.ptr_on_device(), sizeof(unsigned)*src.m_blocks.size());
00422 }
00423 
00424 template <typename DstDevice, typename SrcDevice>
00425 void deep_copy( ConstBitset<DstDevice> & dst, ConstBitset<SrcDevice> const& src)
00426 {
00427   if (dst.size() != src.size()) {
00428     throw std::runtime_error("Error: Cannot deep_copy bitsets of different sizes!");
00429   }
00430 
00431   typedef Kokkos::Impl::DeepCopy< typename DstDevice::memory_space, typename SrcDevice::memory_space > raw_deep_copy;
00432   raw_deep_copy(dst.m_blocks.ptr_on_device(), src.m_blocks.ptr_on_device(), sizeof(unsigned)*src.m_blocks.size());
00433 }
00434 
00435 } // namespace Kokkos
00436 
00437 #endif //KOKKOS_BITSET_HPP
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends