Skip to content

ttldtor/bits

Repository files navigation

bits

Library for bit manipulation.

Release License

Examples of usage

xmake

add_rules("mode.debug", "mode.release")

add_repositories("ttldtor https://github.com/ttldtor/xmake-repo.git")
add_requires("bits v1.0.0")

target("test_bits")
    set_kind("binary")
    add_packages("bits")
    add_files("src/*.cpp")
    set_languages("c++20")

CMake

cmake_minimum_required(VERSION 3.16)
project(test_bits LANGUAGES CXX)

include(FetchContent)
FetchContent_Declare(
        bits
        GIT_REPOSITORY https://github.com/ttldtor/bits.git
        GIT_TAG v1.0.0
)
FetchContent_MakeAvailable(bits)

add_executable(${PROJECT_NAME} src/main.cpp)
target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_20)
target_link_libraries(${PROJECT_NAME} PRIVATE bits)

Code

#include <iostream>
#include <bits/bits.hpp>

using namespace org::ttldtor::bits;

int main(int argc, char** argv) {
    std::cout << "hello world!" << std::endl;
    std::cout << shl(-5, 4) << std::endl;

    return 0;
}

A possibly complete, but probably not very useful example of using this library.

Color Manipulation Example
// Copyright (c) 2025 ttldtor.
// SPDX-License-Identifier: BSL-1.0

/**
 * @file colormanip.cpp
 * @brief Example demonstrating color manipulation using the `bits` library
 *
 * This example shows how to use the `bits` library for:
 * - Packing color components into a single integer
 * - Unpacking color components from an integer
 * - Manipulating individual color channels
 * - Converting between different color formats
 */

#include <bits/bits.hpp>
#include <cstdint>
#include <iomanip>
#include <iostream>

using namespace org::ttldtor::bits;

/**
 * @brief Represents an RGBA color with individual components
 */
struct Color {
  std::uint8_t red;    ///< Red channel (0-255)
  std::uint8_t green;  ///< Green channel (0-255)
  std::uint8_t blue;   ///< Blue channel (0-255)
  std::uint8_t alpha;  ///< Alpha channel (0-255, 0=transparent, 255=opaque)

  /**
   * @brief Packs color components into a 32-bit ARGB value
   * @return 32-bit integer in ARGB format `(Alpha << 24 | Red << 16 | Green << 8 | Blue)`
   *
   * <pre>
   * Layout: [AAAAAAAA][RRRRRRRR][GGGGGGGG][BBBBBBBB]
   *    bits    24-31    16-23      8-15       0-7
   * </pre>
   */
  [[nodiscard]] std::uint32_t pack() const {
    std::uint32_t result = 0;

    // Shift alpha to bits 24-31 and OR with the result
    result = orOp(result, shl(static_cast<std::uint32_t>(alpha), 24));

    // Shift red to bits 16-23 and OR with the result
    result = orOp(result, shl(static_cast<std::uint32_t>(red), 16));

    // Shift green to bits 8-15 and OR with the result
    result = orOp(result, shl(static_cast<std::uint32_t>(green), 8));

    // Blue occupies bits 0-7, no shift needed
    result = orOp(result, static_cast<std::uint32_t>(blue));

    return result;
  }

  /**
   * @brief Unpacks a 32-bit ARGB value into color components
   * @param packed 32-bit integer in ARGB format
   * @return Color struct with unpacked components
   */
  [[nodiscard]] static Color unpack(std::uint32_t packed) {
    Color color{};

    // Extract alpha from bits 24-31
    color.alpha = static_cast<std::uint8_t>(shr(packed, 24));

    // Extract red from bits 16-23
    color.red = static_cast<std::uint8_t>(shr(packed, 16));

    // Extract green from bits 8-15
    color.green = static_cast<std::uint8_t>(shr(packed, 8));

    // Extract blue from bits 0-7 (no shift needed, just mask)
    color.blue = static_cast<std::uint8_t>(packed);

    return color;
  }

  /**
   * @brief Modifies the alpha channel of a packed color
   * @param packed Original packed color value
   * @param alpha New alpha value (0-255)
   * @return New packed color with an updated alpha channel
   */
  [[nodiscard]] static std::uint32_t setAlpha(std::uint32_t packed, std::uint8_t alpha) {
    // Clear the alpha channel (bits 24-31)
    packed = resetBits(packed, 0xFF000000u);

    // Set a new alpha value
    return setBits(packed, shl(static_cast<std::uint32_t>(alpha), 24));
  }

  /**
   * @brief Modifies the red channel of a packed color
   * @param packed Original packed color value
   * @param red New red value (0-255)
   * @return New packed color with an updated red channel
   */
  [[nodiscard]] static std::uint32_t setRed(std::uint32_t packed, std::uint8_t red) {
    // Clear the red channel (bits 16-23)
    packed = resetBits(packed, 0x00FF0000u);

    // Set a new red value
    return setBits(packed, shl(static_cast<std::uint32_t>(red), 16));
  }

  /**
   * @brief Modifies the green channel of a packed color
   * @param packed Original packed color value
   * @param green New green value (0-255)
   * @return New packed color with an updated green channel
   */
  [[nodiscard]] static std::uint32_t setGreen(std::uint32_t packed, std::uint8_t green) {
    // Clear the green channel (bits 8-15)
    packed = resetBits(packed, 0x0000FF00u);

    // Set a new green value
    return setBits(packed, shl(static_cast<std::uint32_t>(green), 8));
  }

  /**
   * @brief Modifies the blue channel of a packed color
   * @param packed Original packed color value
   * @param blue New blue value (0-255)
   * @return New packed color with an updated blue channel
   */
  [[nodiscard]] static std::uint32_t setBlue(std::uint32_t packed, std::uint8_t blue) {
    // Clear the blue channel (bits 0-7)
    packed = resetBits(packed, 0x000000FFu);

    // Set a new blue value
    return setBits(packed, static_cast<std::uint32_t>(blue));
  }

  /**
   * @brief Converts an ARGB format to RGBA format
   * @param argb Color in ARGB format (Alpha << 24 | Red << 16 | Green << 8 | Blue)
   * @return Color in RGBA format (Red << 24 | Green << 16 | Blue << 8 | Alpha)
   */
  [[nodiscard]] static std::uint32_t argbToRgba(std::uint32_t argb) {
    // Extract individual channels
    const auto alpha = static_cast<std::uint8_t>(shr(argb, 24));
    const auto red = static_cast<std::uint8_t>(shr(argb, 16));
    const auto green = static_cast<std::uint8_t>(shr(argb, 8));
    const auto blue = static_cast<std::uint8_t>(argb);

    // Repack in RGBA format
    std::uint32_t rgba = 0;
    rgba = orOp(rgba, shl(static_cast<std::uint32_t>(red), 24));
    rgba = orOp(rgba, shl(static_cast<std::uint32_t>(green), 16));
    rgba = orOp(rgba, shl(static_cast<std::uint32_t>(blue), 8));
    rgba = orOp(rgba, static_cast<std::uint32_t>(alpha));

    return rgba;
  }

  /**
   * @brief Blends two colors using alpha blending
   * @param foreground Foreground color (with alpha)
   * @param background Background color
   * @return Blended color
   *
   * Formula: `result = foreground * alpha + background * (1 - alpha)`
   */
  [[nodiscard]] static Color blend(const Color& foreground, const Color& background) {
    // Convert alpha from 0-255 to 0.0-1.0 range
    const float alpha = static_cast<float>(foreground.alpha) / 255.0f;
    const float invAlpha = 1.0f - alpha;

    Color result{};
    result.red = static_cast<std::uint8_t>(static_cast<float>(foreground.red) * alpha +
                                           static_cast<float>(background.red) * invAlpha);
    result.green = static_cast<std::uint8_t>(static_cast<float>(foreground.green) * alpha +
                                             static_cast<float>(background.green) * invAlpha);
    result.blue = static_cast<std::uint8_t>(static_cast<float>(foreground.blue) * alpha +
                                            static_cast<float>(background.blue) * invAlpha);
    result.alpha = 255;  // Result is fully opaque

    return result;
  }

  /**
   * @brief Checks if the color has an alpha channel (not fully opaque)
   * @param packed Packed color value
   * @return true if alpha < 255
   */
  [[nodiscard]] static bool hasTransparency(std::uint32_t packed) {
    // Extract the alpha channel and check if it's less than 255
    const auto alpha = static_cast<std::uint8_t>(shr(packed, 24));

    return alpha < 255;
  }

  /**
   * @brief Inverts the color (excluding an alpha channel)
   * @param packed Original color
   * @return Inverted color
   */
  [[nodiscard]] static std::uint32_t invert(std::uint32_t packed) {
    // XOR with 0x00FFFFFF to invert RGB channels, leaving alpha unchanged
    return xorOp(packed, 0x00FFFFFFu);
  }

  /**
   * @brief Prints color information
   */
  void print() const {
    std::cout << "RGBA(" << static_cast<int>(red) << ", " << static_cast<int>(green) << ", " << static_cast<int>(blue)
              << ", " << static_cast<int>(alpha) << ")";
  }
};

int main() {
  std::cout << "=== Color Manipulation Example ===" << std::endl;
  std::cout << std::hex << std::uppercase << std::setfill('0');

  // Example 1: Pack and unpack color
  std::cout << "\n--- Example 1: Pack and Unpack ---" << std::endl;
  Color color1{255, 128, 64, 200};
  std::cout << "Original color: ";
  color1.print();
  std::cout << std::endl;

  std::uint32_t packed = color1.pack();
  std::cout << "Packed (ARGB): 0x" << std::setw(8) << packed << std::endl;

  Color unpacked = Color::unpack(packed);
  std::cout << "Unpacked color: ";
  unpacked.print();
  std::cout << std::endl;

  // Example 2: Modify individual channels
  std::cout << "\n--- Example 2: Modify Channels ---" << std::endl;
  std::uint32_t color2 = Color{100, 150, 200, 255}.pack();
  std::cout << "Original: 0x" << std::setw(8) << color2 << " -> ";
  Color::unpack(color2).print();
  std::cout << std::endl;

  color2 = Color::setRed(color2, 255);
  std::cout << "After setRed(255): 0x" << std::setw(8) << color2 << " -> ";
  Color::unpack(color2).print();
  std::cout << std::endl;

  color2 = Color::setAlpha(color2, 128);
  std::cout << "After setAlpha(128): 0x" << std::setw(8) << color2 << " -> ";
  Color::unpack(color2).print();
  std::cout << std::endl;

  // Example 3: Format conversion
  std::cout << "\n--- Example 3: ARGB to RGBA ---" << std::endl;
  std::uint32_t argb = 0xC8FF8040u;  // A=200, R=255, G=128, B=64
  std::cout << "ARGB: 0x" << std::setw(8) << argb << std::endl;

  std::uint32_t rgba = Color::argbToRgba(argb);
  std::cout << "RGBA: 0x" << std::setw(8) << rgba << std::endl;

  // Example 4: Color blending
  std::cout << "\n--- Example 4: Alpha Blending ---" << std::endl;
  Color foreground{255, 0, 0, 128};  // Semi-transparent red
  Color background{0, 0, 255, 255};  // Opaque blue

  std::cout << "Foreground: ";
  foreground.print();
  std::cout << std::endl;

  std::cout << "Background: ";
  background.print();
  std::cout << std::endl;

  Color blended = Color::blend(foreground, background);
  std::cout << "Blended: ";
  blended.print();
  std::cout << std::endl;

  // Example 5: Transparency check
  std::cout << "\n--- Example 5: Transparency Check ---" << std::endl;
  const std::uint32_t opaqueColor = Color{255, 255, 255, 255}.pack();
  const std::uint32_t transparentColor = Color{255, 255, 255, 200}.pack();

  std::cout << "Opaque color (0x" << std::setw(8) << opaqueColor
            << ") has transparency: " << (Color::hasTransparency(opaqueColor) ? "YES" : "NO") << std::endl;
  std::cout << "Transparent color (0x" << std::setw(8) << transparentColor
            << ") has transparency: " << (Color::hasTransparency(transparentColor) ? "YES" : "NO") << std::endl;

  // Example 6: Color inversion
  std::cout << "\n--- Example 6: Color Inversion ---" << std::endl;

  constexpr Color original{255, 128, 64, 255};

  std::cout << "Original: 0x" << std::setw(8) << original.pack() << " -> ";
  original.print();
  std::cout << std::endl;

  const std::uint32_t inverted = Color::invert(original.pack());
  std::cout << "Inverted: 0x" << std::setw(8) << inverted << " -> ";
  Color::unpack(inverted).print();
  std::cout << std::endl;

  // Example 7: Grayscale conversion
  std::cout << "\n--- Example 7: Grayscale Conversion ---" << std::endl;

  constexpr Color colorful{200, 100, 50, 255};

  std::cout << "Colorful: ";
  colorful.print();
  std::cout << std::endl;

  // Convert to grayscale using weighted average
  constexpr auto gray =
    static_cast<std::uint8_t>(0.299f * colorful.red + 0.587f * colorful.green + 0.114f * colorful.blue);

  constexpr Color grayscale{gray, gray, gray, colorful.alpha};

  std::cout << "Grayscale: ";
  grayscale.print();
  std::cout << std::endl;

  return 0;
}

About

Library for bit manipulation.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors