aaaaaa123456789 icon

Multibyte bitwise operations

aaaaaa123456789 | PRO | 01/02/16 05:37:43 AM UTC | 0 ⭐ | 492 👁️ | Never ⏰ | []
C |

5.85 KB

|

None

|

0 👍

/

0 👎

/*
   This code is hereby released to the public domain.
   ~aaaaaa123456789, 2016-01-02
*/
 
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
 
#define multibyte_is_zero(operand, size) ((int) (                                                                           \
                                           ((int) (size)) &&                                                                \
                                           !(*((const unsigned char *) (operand))) &&                                       \
                                           !memcmp(operand, ((const unsigned char *) (operand)) + 1, ((int) (size)) - 1)    \
                                         ))
 
#define multibyte_is_negative(operand, size) (((int) (((const unsigned char *) (operand))[((int) (size)) - 1])) & 0x80)
 
void multibyte_op (unsigned char * result, const unsigned char * operand0, const unsigned char * operand1, int op, unsigned size) {
  /*
    every two bits of op determine what to do with some intermediate result: 00 = nothing, 01 = subtract, 10 = add, 11 = add w/ negated shift
    bits 31-30: (operand0 AND operand1) >> shift amount, bits 29-28: (operand0 OR operand1) >> shift amount,
    bits 27-26: (operand0 AND operand1) << shift amount, bits 25-24: (operand0 OR operand1) << shift amount
    bits 23-0 of op indicate shift amount
    operand0 defaults to 0 if null, operand1 defaults to -1 if null
    
    EXAMPLE VALUES OF OP:
    0x80000000 = AND, 0x20000000 = OR, 0x60000000 = XOR, 0xa0000000 = addition
    0x60000000 with operand1 set to NULL = NOT, 0x10000000 with operand0 set to NULL = negate (-x)
    0x2300xxxx = rotate right by xxxx, 0x3200xxxx = rotate left by xxxx, 0x2000xxxx = shift right by xxxx, 0x0200xxxx = shift left by xxxx
    (set operand0 to NULL for rotations and shifts)
  */
  if (!(size && result)) return;
  if (!(op & 0xff000000)) {
    memset(result, 0, size);
    return;
  }
  char * op0 = NULL;
  char * op1 = NULL;
  if (!operand0) operand0 = op0 = calloc(size, 1);
  if (!operand1) operand1 = op1 = memset(malloc(size), -1, size);
  unsigned char * temp_and = NULL;
  unsigned char * temp_or = NULL;
  if (op & 0xcc000000) temp_and = malloc(size);
  if (op & 0x33000000) temp_or = malloc(size);
  const unsigned char * p0 = operand0;
  const unsigned char * p1 = operand1;
  unsigned char * p2 = temp_and;
  unsigned char * p3 = temp_or;
  unsigned rem;
  for (rem = size; rem >= sizeof(uint_fast8_t); rem -= sizeof(uint_fast8_t)) {
    if (temp_and) {
      *((uint_fast8_t *) p2) = *((const uint_fast8_t *) p0) & *((const uint_fast8_t *) p1);
      p2 += sizeof(uint_fast8_t);
    }
    if (temp_or) {
      *((uint_fast8_t *) p3) = *((const uint_fast8_t *) p0) | *((const uint_fast8_t *) p1);
      p3 += sizeof(uint_fast8_t);
    }
    p0 += sizeof(uint_fast8_t);
    p1 += sizeof(uint_fast8_t);
  }
  for (; rem; rem --) {
    if (temp_and) *(p2 ++) = *p0 & *p1;
    if (temp_or) *(p3 ++) = *p0 | *p1;
    p0 ++;
    p1 ++;
  }
  free(op0);
  free(op1);
  int shift_amount = op & 0xffffff;
  if (shift_amount & 0x800000) shift_amount -= 0x1000000;
  shift_amount %= size << 3;
  if (shift_amount < 0) shift_amount += size << 3;
  unsigned char ** partials = calloc(sizeof(unsigned char *), 4);
  int inverted_shift_amount = (size << 3) - shift_amount;
  unsigned pending_shift_list = 0;
  int temp, pos;
  if (shift_amount) {
    if (op & 0xc0000000) {
      *partials = calloc(size, 1);
      temp = ((op & 0xc0000000) == 0xc0000000) ? inverted_shift_amount : shift_amount;
      memcpy(*partials, temp_and + (temp >> 3), size - (temp >> 3));
      pending_shift_list |= temp & 7;
    }
    if (op & 0x30000000) {
      partials[1] = calloc(size, 1);
      temp = ((op & 0x30000000) == 0x30000000) ? inverted_shift_amount : shift_amount;
      memcpy(partials[1], temp_or + (temp >> 3), size - (temp >> 3));
      pending_shift_list |= (temp & 7) << 3;
    }
    if (op & 0xc000000) {
      partials[2] = calloc(size, 1);
      temp = ((op & 0xc000000) == 0xc000000) ? inverted_shift_amount : shift_amount;
      memcpy(partials[2] + (temp >> 3), temp_and, size - (temp >> 3));
      pending_shift_list |= (temp & 7) << 6;
    }
    if (op & 0x3000000) {
      partials[3] = calloc(size, 1);
      temp = ((op & 0x3000000) == 0x3000000) ? inverted_shift_amount : shift_amount;
      memcpy(partials[3] + (temp >> 3), temp_or, size - (temp >> 3));
      pending_shift_list |= (temp & 7) << 9;
    }
    unsigned current_shift;
    for (current_shift = 0; current_shift < 4; pending_shift_list >>= 3, current_shift ++) {
      shift_amount = pending_shift_list & 7;
      if (!shift_amount) continue;
      temp = 0;
      if (current_shift & 2)
        for (pos = 0; pos < size; pos ++) {
          temp |= partials[current_shift][pos] << shift_amount;
          partials[current_shift][pos] = temp & 0xff;
          temp >>= 8;
        }
      else
        for (pos = size - 1; pos >= 0; pos --) {
          temp = (temp << 8) | partials[current_shift][pos];
          partials[current_shift][pos] = (temp >> shift_amount) & 0xff;
        }
    }
  } else {
    if (op & 0xc0000000) *partials = memcpy(malloc(size), temp_and, size);
    if (op & 0x30000000) partials[1] = memcpy(malloc(size), temp_or, size);
    if (op & 0x0c000000) partials[2] = memcpy(malloc(size), temp_and, size);
    if (op & 0x03000000) partials[3] = memcpy(malloc(size), temp_or, size);
  }
  free(temp_and);
  free(temp_or);
  temp = 0;
  int cp;
  for (pos = 0; pos < size; pos ++) {
    for (cp = 0; cp < 4; cp ++)
      if (op & (1 << (31 - (cp << 1))))
        temp += (int) partials[cp][pos];
      else if (op & (1 << (30 - (cp << 1))))
        temp -= (int) partials[cp][pos];
    result[pos] = temp & 0xff;
    temp >>= 8;
  }
  for (cp = 0; cp < 4; cp ++) free(partials[cp]);
  free(partials);
}

Comments