Skip to content

Instantly share code, notes, and snippets.

@hubenchang0515
Last active July 12, 2021 07:21
Show Gist options
  • Save hubenchang0515/51a91fcddc28acb8061c68549c4cef64 to your computer and use it in GitHub Desktop.
Save hubenchang0515/51a91fcddc28acb8061c68549c4cef64 to your computer and use it in GitHub Desktop.
pixel template - 像素模板

利用常量表达式和模板元编程实现了各种类型颜色空间的像素

原本是打算实现成这样的:

using RGB24 = Pixel<"RGB">
using RGBA32 = Pixel<"RGBA32">

但是模板的非类型参数只能是整数或者指向具名变量的指针

而字符串字面量不属于具名变量,不能做模板参数。

因为两个同样的字符串字面量不一定具有相同的地址,因此下面两个变量不一定具有相同的类型:

Pixel<"RGB"> p1;
Pixel<"RGB"> p2;

只能退而求其次实现成这样了:

using RGB24 = _RGBPixel<ColorSpace::CS("RGB")>;
using BGR24 = _RGBPixel<ColorSpace::CS("BGR")>;

using RGBX32 = _RGBPixel<ColorSpace::CS("RGBX")>;
using XRGB32 = _RGBPixel<ColorSpace::CS("XRGB")>;
using BGRX32 = _RGBPixel<ColorSpace::CS("BGRX")>;
using XBGR32 = _RGBPixel<ColorSpace::CS("XBGR")>;

using RGBA32 = _RGBAPixel<ColorSpace::CS("RGBA")>;
using ARGB32 = _RGBAPixel<ColorSpace::CS("ARGB")>;
using BGRA32 = _RGBAPixel<ColorSpace::CS("BGRA")>;
using ABGR32 = _RGBAPixel<ColorSpace::CS("ABGR")>;
#ifndef LOLITA_PIXEL_HPP
#define LOLITA_PIXEL_HPP
#include <cstdint>
#include <cstddef>
#include <stdexcept>
namespace lolita
{
constexpr static inline size_t _stringLength(const char* str)
{
return *str != 0 ? 1 + _stringLength(str + 1) : 0;
}
constexpr static inline size_t _stringFind(const char* str, char ch, size_t index=0)
{
return *str == ch ? index : (*str == 0 ? SIZE_MAX : _stringFind(str+1, ch, index+1));
}
constexpr static inline bool _stringEqual(const char* str1, const char* str2)
{
return *str1 == 0 && *str2 == 0 ? true : (*str1 != *str2 ? false : (_stringEqual(str1+1, str2+1)));
}
constexpr static inline uint64_t _string2Uint64(const char* str, uint64_t n = 0, size_t index = 0)
{
return *str == 0 ? n : _string2Uint64(str+1, n | (static_cast<uint64_t>(*str) << (8 * index)), index+1);
}
constexpr static inline size_t _findCharInUint64(uint64_t n, char ch, size_t index = 0)
{
return n == 0 ? SIZE_MAX : ((n & 0xff) == ch ? index : _findCharInUint64(n >> 8, ch, index+1));
}
constexpr static inline size_t _uint64StringLength(uint64_t n, size_t len = 0)
{
return n == 0 ? len : _uint64StringLength(n >> 8, len+1);
}
namespace ColorSpace
{
constexpr const char RED = 'R';
constexpr const char GREEN = 'G';
constexpr const char BLUE = 'B';
constexpr const char ALPHA = 'A';
constexpr static inline uint64_t CS(const char* str)
{
return _string2Uint64(str);
}
constexpr static inline size_t CS_INDEX(uint64_t n, char ch)
{
return _findCharInUint64(n, ch);
}
constexpr static inline size_t CS_LENGTH(uint64_t n)
{
return _uint64StringLength(n);
}
};
namespace Pixel
{
template<uint64_t format>
class _RGBPixel
{
public:
uint8_t red() const
{
return m_get(ColorSpace::RED);
}
uint8_t green() const
{
return m_get(ColorSpace::GREEN);
}
uint8_t blue() const
{
return m_get(ColorSpace::BLUE);
}
void setRed(uint8_t v)
{
m_set(ColorSpace::RED, v);
}
void setGreen(uint8_t v)
{
m_set(ColorSpace::GREEN, v);
}
void setBlue(uint8_t v)
{
m_set(ColorSpace::BLUE, v);
}
private:
static const size_t length = ColorSpace::CS_LENGTH(format);
uint8_t m_data[ColorSpace::CS_LENGTH(format)];
uint8_t m_get(char color)
{
size_t i = ColorSpace::CS_INDEX(format, color);
if(i >= length)
{
throw std::out_of_range("_RGBPixel out of range");
}
return m_data[i];
}
void m_set(char color, uint8_t v)
{
size_t i = ColorSpace::CS_INDEX(format, color);
if(i >= length)
{
throw std::out_of_range("_RGBPixel out of range");
}
m_data[i] = v;
}
};
template<uint64_t format>
class _RGBAPixel
{
public:
uint8_t red() const
{
return m_get(ColorSpace::RED);
}
uint8_t green() const
{
return m_get(ColorSpace::GREEN);
}
uint8_t blue() const
{
return m_get(ColorSpace::BLUE);
}
uint8_t alpha() const
{
return m_get(ColorSpace::ALPHA);
}
void setRed(uint8_t v)
{
m_set(ColorSpace::RED, v);
}
void setGreen(uint8_t v)
{
m_set(ColorSpace::GREEN, v);
}
void setBlue(uint8_t v)
{
m_set(ColorSpace::BLUE, v);
}
void setAlpha(uint8_t v)
{
m_set(ColorSpace::ALPHA, v);
}
private:
static const size_t length = ColorSpace::CS_LENGTH(format);
uint8_t m_data[ColorSpace::CS_LENGTH(format)];
uint8_t m_get(char color)
{
size_t i = ColorSpace::CS_INDEX(format, color);
if(i >= length)
{
throw std::out_of_range("_RGBAPixel out of range");
}
return m_data[i];
}
void m_set(char color, uint8_t v)
{
size_t i = ColorSpace::CS_INDEX(format, color);
if(i >= length)
{
throw std::out_of_range("_RGBAPixel out of range");
}
m_data[i] = v;
}
};
using RGB24 = _RGBPixel<ColorSpace::CS("RGB")>;
using BGR24 = _RGBPixel<ColorSpace::CS("BGR")>;
using RGBX32 = _RGBPixel<ColorSpace::CS("RGBX")>;
using XRGB32 = _RGBPixel<ColorSpace::CS("XRGB")>;
using BGRX32 = _RGBPixel<ColorSpace::CS("BGRX")>;
using XBGR32 = _RGBPixel<ColorSpace::CS("XBGR")>;
using RGBA32 = _RGBAPixel<ColorSpace::CS("RGBA")>;
using ARGB32 = _RGBAPixel<ColorSpace::CS("ARGB")>;
using BGRA32 = _RGBAPixel<ColorSpace::CS("BGRA")>;
using ABGR32 = _RGBAPixel<ColorSpace::CS("ABGR")>;
}; // namespace Pixel
}; // namespace lolita
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment