Skip to content

File dense_2d.h

File List > dense > dense_2d.h

Go to the documentation of this file

#pragma once
#include <muda/viewer/viewer_base.h>

namespace muda
{
/*****************************************************************************
 *
 * Dense2D (2D array)
 * indexing (x,y)
 *  1) non-pitched:  x * dim_y + y 
 *  2) pitched:      x * pitch + y
 *
 * Note:
 *  1) y moves faster than x, which is the same as C/C++ 2d array
 *  2) as for CUDA Memory2D, x index into height, y index into width.
 *****************************************************************************/

template <bool IsConst, typename T>
class Dense2DBase : public ViewerBase<IsConst>  // TODO
{
    using Base = ViewerBase<IsConst>;

    MUDA_VIEWER_COMMON_NAME(Dense2DBase);


  protected:
    template <typename U>
    using auto_const_t = typename Base::template auto_const_t<U>;

    auto_const_t<T>* m_data;
    int2             m_offset;
    int2             m_dim;
    int              m_pitch_bytes;

  public:
    using value_type     = T;
    using ConstViewer    = Dense2DBase<true, T>;
    using NonConstViewer = Dense2DBase<false, T>;
    using ThisViewer     = Dense2DBase<IsConst, T>;


    MUDA_GENERIC Dense2DBase() MUDA_NOEXCEPT : m_data(nullptr) {}

    MUDA_GENERIC Dense2DBase(auto_const_t<T>* p, const int2& offset, const int2& dim, int pitch_bytes) MUDA_NOEXCEPT
        : m_data(p),
          m_offset(offset),
          m_dim(dim),
          m_pitch_bytes(pitch_bytes)
    {
    }

    MUDA_GENERIC auto as_const() const MUDA_NOEXCEPT
    {
        return ConstViewer{m_data, m_offset, m_dim, m_pitch_bytes};
    }

    MUDA_GENERIC operator ConstViewer() const MUDA_NOEXCEPT
    {
        return as_const();
    }


    MUDA_GENERIC auto_const_t<T>& operator()(int x, int y) MUDA_NOEXCEPT
    {
        check();
        check_range(x, y);

        x += m_offset.x;
        y += m_offset.y;
        auto height_begin =
            reinterpret_cast<auto_const_t<std::byte>*>(m_data) + x * m_pitch_bytes;
        return *((auto_const_t<T>*)(height_begin) + y);
    }

    MUDA_GENERIC auto_const_t<T>& operator()(const int2& xy) MUDA_NOEXCEPT
    {
        return operator()(xy.x, xy.y);
    }

    MUDA_GENERIC auto_const_t<T>& flatten(int i)
    {
        if constexpr(DEBUG_VIEWER)
        {
            MUDA_KERNEL_ASSERT(i >= 0 && i < total_size(),
                               "Dense2D[%s:%s]: out of range, index=%d, total_size=%d. %s(%d)",
                               this->name(),
                               this->kernel_name(),
                               i,
                               total_size(),
                               this->kernel_file(),
                               this->kernel_line());
        }
        auto x = i / m_dim.y;
        auto y = i % m_dim.y;
        return operator()(x, y);
    }

    MUDA_GENERIC auto_const_t<T>* data() MUDA_NOEXCEPT { return m_data; }


    MUDA_GENERIC const T& operator()(const int2& xy) const MUDA_NOEXCEPT
    {
        return remove_const(*this)(xy);
    }


    MUDA_GENERIC const T& operator()(int x, int y) const MUDA_NOEXCEPT
    {
        return remove_const(*this)(x, y);
    }

    MUDA_GENERIC const T& flatten(int i) const
    {
        return remove_const(*this).flatten(i);
    }

    MUDA_GENERIC const T* data() const MUDA_NOEXCEPT { return m_data; }

    MUDA_GENERIC auto total_size() const MUDA_NOEXCEPT
    {
        return m_dim.x * m_dim.y;
    }

    MUDA_GENERIC auto area() const MUDA_NOEXCEPT { return total_size(); }

    MUDA_GENERIC auto dim() const MUDA_NOEXCEPT { return m_dim; }

    MUDA_GENERIC auto pitch_bytes() const MUDA_NOEXCEPT
    {
        return m_pitch_bytes;
    }

  protected:
    MUDA_INLINE MUDA_GENERIC void check_range(int x, int y) const MUDA_NOEXCEPT
    {
        if constexpr(DEBUG_VIEWER)
            if(!(x >= 0 && x < m_dim.x && y >= 0 && y < m_dim.y))
            {
                MUDA_KERNEL_ERROR("Dense2D[%s:%s]: out of range, index=(%d,%d) dim=(%d,%d). %s(%d)",
                                  this->name(),
                                  this->kernel_name(),
                                  x,
                                  y,
                                  m_dim.x,
                                  m_dim.y,
                                  this->kernel_file(),
                                  this->kernel_line());
            }
    }

    MUDA_INLINE MUDA_GENERIC void check() const MUDA_NOEXCEPT
    {
        if constexpr(DEBUG_VIEWER)
        {
            MUDA_KERNEL_ASSERT(m_data,
                               "Dense2D[%s:%s]: m_data is null. %s(%d)",
                               this->name(),
                               this->kernel_name(),
                               this->kernel_file(),
                               this->kernel_line());
        }
    }
};

template <typename T>
using Dense2D = Dense2DBase<false, T>;

template <typename T>
using CDense2D = Dense2DBase<true, T>;


// viewer traits
template <typename T>
struct read_only_viewer<Dense2D<T>>
{
    using type = CDense2D<T>;
};

template <typename T>
struct read_write_viewer<CDense2D<T>>
{
    using type = Dense2D<T>;
};

// make functions
template <typename T>
MUDA_INLINE MUDA_GENERIC auto make_cdense_2d(const T* data, const int2& dim) MUDA_NOEXCEPT
{
    return CDense2D<T>{data, make_int2(0, 0), dim, static_cast<int>(dim.y * sizeof(T))};
}

template <typename T>
MUDA_INLINE MUDA_GENERIC auto make_dense_2d(T* data, const int2& dim) MUDA_NOEXCEPT
{
    return Dense2D<T>{data, make_int2(0, 0), dim, static_cast<int>(dim.y * sizeof(T))};
}

template <typename T>
MUDA_INLINE MUDA_GENERIC auto make_cdense_2d(const T* data, int dimx, int dimy) MUDA_NOEXCEPT
{
    return make_cdense_2d(data, make_int2(dimx, dimy));
}

template <typename T>
MUDA_INLINE MUDA_GENERIC auto make_dense_2d(T* data, int dimx, int dimy) MUDA_NOEXCEPT
{
    return make_dense_2d(data, make_int2(dimx, dimy));
}


}  // namespace muda