Skip to content

Miscellaneous refactoring#12

Open
Rangi42 wants to merge 1 commit intoaaaaaa123456789:developfrom
Rangi42:refactor
Open

Miscellaneous refactoring#12
Rangi42 wants to merge 1 commit intoaaaaaa123456789:developfrom
Rangi42:refactor

Conversation

@Rangi42
Copy link
Contributor

@Rangi42 Rangi42 commented Nov 29, 2023

Found some things while implementing QOI.

data = ctxmalloc(context, sizeof *data * context -> source -> width * context -> source -> height);
plum_convert_colors(data, context -> source -> data, (size_t) context -> source -> width * context -> source -> height,
PLUM_COLOR_32, context -> source -> color_format);
size_t size = (size_t) context -> source -> width * context -> source -> height;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Factoring out a common (size_t) context -> source -> width * context -> source -> height expression, as is done almost everywhere else.

rowsize += padding;
}
unsigned char * out = append_output_node(context, rowsize * context -> source -> height);
unsigned char * output = append_output_node(context, rowsize * context -> source -> height);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

output is a much more common name for this kind of variable elsewhere in the codebase.


void adjust_frame_boundaries (const struct plum_image * image, struct plum_rectangle * restrict boundaries) {
uint64_t empty_color = get_empty_color(image);
#define checkframe(type) do \
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here the palette code was so similar to the 16/32/64 color code that I wanted to use the existing checkframe macro for the palette as well.

index += (size_t) boundaries[frame].height * image -> width; \
for (size_t remaining = (size_t) (image -> height - boundaries[frame].top - boundaries[frame].height) * image -> width; remaining; remaining --) \
if (notempty(type)) goto done ## type; \
continue; \
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This continue is an alternative to a manually-checked bool adjust flag.

This control flow:

for (...) {
  bool adjust = true;
  if (various stuff) goto done;
  adjust = false;
  done:
  if (adjust) finish up;
}

was refactored to this:

for (...) {
  if (various stuff) goto done;
  continue;
  done:
  finish up;
}

} \
while (false)
#undef notempty
#define notempty(bits) (image -> data ## bits[index ++] != empty_color)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rgbds has already been converted to C++; next up, libplum, with templates and anonymous closures replacing all these macros. >:3

if (overall > 8) overall = 8;
header[4] = (overall - 1) << 4;
header[5] = header[6] = 0;
bytewrite(header + 4, (overall - 1) << 4, 0, 0);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using bytewrite for more than two values, same as elsewhere.

byteoutput(context, 0x3b);
}

#define checkboundaries(buffertype, buffer, frame) do { \
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The generate_GIF_data_with_palette and generate_GIF_frame_data cases were very similar, so I factored them out into this macro.

(I'm sure there are even more such cases, but I found the ones that I did in this PR by inspecting the remaining gotos again. It's probably not a coincidence that the most complex goto logic is mostly found inside this sort of repetitive code.) (Non-complex gotos are the ones used for skipping to a failure case, or breaking out of nested loops/switches.)

top = boundaries[frame].top; \
width = boundaries[frame].width; \
height = boundaries[frame].height; \
} else { \
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This else takes the place of an unnecessary goto.

This control flow:

if (boundaries) {
  if (various stuff) goto findbounds;
  we have the bounds;
  goto gotbounds;
}
findbounds:
more stuff;
gotbounds:

was refactored to this:

if (boundaries) {
  if (various stuff) goto findbounds;
  we have the bounds;
} else {
  findbounds:
  more stuff;
}

} \
} \
if (left || width != context -> source -> width) { \
buffertype * target = buffer; \
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There'd be no need for buffertype in C23, just do typeof(buffer) target = buffer;.

struct data_node * node = ctxmalloc(context, sizeof *node + size);
*node = (struct data_node) {.size = size, .previous = context -> output, .next = NULL};
if (context -> output) context -> output -> next = node;
if (node -> previous) node -> previous -> next = node;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is more appropriate, because it expresses the general case of replacing a doubly-linked list node, without hard-coding the thing that this one's previous node happens to be. Also it matches the resize_output_node function in the QOI PR.

score += length - 1;
if (score >= 16) break;
} else if (score > 0)
} else if (score)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

score is unsigned, and everywhere else you avoid doing unsigned > 0.

header[8] = (type < 4) ? 1 << type : (8 << (type >= 6));
header[9] = (type >= 4) ? 2 + 4 * (type & 1) : 3;
bytewrite(header + 10, 0, 0, 0);
bytewrite(header + 8, (type < 4) ? 1 << type : (8 << (type >= 6)), (type >= 4) ? 2 + 4 * (type & 1) : 3, 0, 0, 0);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using bytewrite for more than two values.

for (unsigned char * out = buffer; node; node = node -> next) {
memcpy(out, node -> data, node -> size);
out += node -> size;
for (unsigned char * output = buffer; node; node = node -> next) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only other out variable is a uint_fast32_t in bmpwrite.c, not any pointers to output buffers.


size_t get_total_output_size (struct context * context) {
size_t result = 0;
size_t output_size = 0;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same name it's assigned to above.

@Rangi42 Rangi42 changed the base branch from master to develop November 29, 2023 16:23
} else {
const uint32_t * sp = source;
convert(sp);
#define convert(frombits, tobits) do { \
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You already had the formatpair macro below, may as well use it here and save a couple of lines + make the to-from paired logic clearer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant