File: gv_math.h

package info (click to toggle)
graphviz 14.0.5-2
  • links: PTS
  • area: main
  • in suites: forky, sid
  • size: 139,388 kB
  • sloc: ansic: 141,938; cpp: 11,957; python: 7,766; makefile: 4,043; yacc: 3,030; xml: 2,972; tcl: 2,495; sh: 1,388; objc: 1,159; java: 560; lex: 423; perl: 243; awk: 156; pascal: 139; php: 58; ruby: 49; cs: 31; sed: 1
file content (166 lines) | stat: -rw-r--r-- 5,887 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
/// \file
/// \brief Arithmetic helper functions
/// \ingroup cgraph_utils

#pragma once

#include <assert.h>
#include <float.h>
#include <limits.h>
#include <stdbool.h>
#include <stddef.h>
#include <string.h>

/// comparator for doubles
static inline int fcmp(double a, double b) {
  if (a < b) {
    return -1;
  }
  if (a > b) {
    return 1;
  }
  return 0;
}

/// maximum of two integers
static inline int imax(int a, int b) { return a > b ? a : b; }

/// maximum of two sizes
static inline size_t zmax(size_t a, size_t b) { return a > b ? a : b; }

/// minimum of two integers
static inline int imin(int a, int b) { return a < b ? a : b; }

/**
 * \brief are two values precisely the same?
 *
 * This function should only be used when you know you want comparison with no
 * tolerance, which is rare. Floating-point arithmetic accumulates imprecision,
 * so equality comparisons should generally include a non-zero tolerance to
 * account for this. In general, this function is only applicable for checking
 * things like “is this variable unchanged since a previous assignment from a
 * literal?”
 *
 * \param a First operand to comparison
 * \param b Second operand to comparison
 * \return True if the values are equal
 */
static inline bool is_exactly_equal(double a, double b) {
  return memcmp(&a, &b, sizeof(a)) == 0;
}

/**
 * \brief is a value precisely 0.0?
 *
 * This function should only be used when you know you want comparison with no
 * tolerance, which is rare. Floating-point arithmetic accumulates imprecision,
 * so equality comparisons should generally include a non-zero tolerance to
 * account for this. Valid `double` representations even include -0.0, for which
 * this function will return false. In general, this function is only applicable
 * for checking things like “is this variable unchanged since a previous
 * assignment from the literal `0`?” or “did this value we parsed from user
 * input originate from the string "0.0"?”
 *
 * \param v Value to check
 * \return True if the value is equal to exactly 0.0
 */
static inline bool is_exactly_zero(double v) { return is_exactly_equal(v, 0); }

/**
 * \brief scale up or down a non-negative integer, clamping to \p [0, INT_MAX]
 *
 * \param original Value to scale
 * \param scale Scale factor to apply
 * \return Clamped result
 */
static inline int scale_clamp(int original, double scale) {
  assert(original >= 0);

  if (scale < 0) {
    return 0;
  }

  if (scale > 1 && original > INT_MAX / scale) {
    return INT_MAX;
  }

  return (int)(original * scale);
}

/// byte length of data per pixel in image data buffers
enum { BYTES_PER_PIXEL = 4 };

/// in-place conversion of ARGB32 big endian to RGBA32 little endian
///
/// Image data originating from sources like Cairo comes in a 4-byte-per-pixel
/// format ordered {blue, green, red, alpha}. Some output libraries/devices
/// instead consume a 4-byte-per-pixel format ordered {red, green, blue, alpha}.
/// This function converts the former to the latter.
///
/// It is confusing to refer to these formats as ARGB32 and RGBA32 when the
/// first is big endian and the second is little endian, and thus the mappings
/// of letters in the acronym to bytes in memory are opposites. Nevertheless
/// that appears to be what is in common usage.
///
/// @param width Width of the image in pixels
/// @param height Height of the image in pixels
/// @param data [inout] Image data in ARGB32 format on entry and RGBA32 format
///   on exit
static inline void argb2rgba(size_t width, size_t height, unsigned char *data) {
  assert(data != NULL || (width == 0 && height == 0));

  // indices to color bytes in each format
  enum { Ba = 0, Ga = 1, Ra = 2, Aa = 3 };
  enum { Rb = 0, Gb = 1, Bb = 2, Ab = 3 };

  for (size_t y = 0; y < height; ++y) {
    for (size_t x = 0; x < width; ++x) {
      const unsigned char red = data[Ra];
      const unsigned char blue = data[Ba];
      data[Rb] = red;
      data[Bb] = blue;
      data += BYTES_PER_PIXEL;
    }
  }
}

/// swap data referenced by two pointers
///
/// You can think of this macro as having the following C type:
///
///   void SWAP(<t1> *a, <t1> *b);
///
/// Both `a` and `b` are expected to be pure expressions.
#define SWAP(a, b)                                                             \
  do {                                                                         \
    /* trigger a -Wcompare-distinct-pointer-types compiler warning if `a` */   \
    /* and `b` have differing types                                       */   \
    (void)((a) == (b));                                                        \
                                                                               \
    /* Swap their targets. Contemporary compilers will optimize the `memcpy`s  \
     * into direct writes for primitive types.                                 \
     */                                                                        \
    char tmp_[sizeof(*(a))];                                                   \
    memcpy(tmp_, (a), sizeof(*(a)));                                           \
    *(a) = *(b);                                                               \
    memcpy((b), tmp_, sizeof(*(b)));                                           \
  } while (0)

/// convert a double-precision floating-point to single-precision
///
/// Values below or above the range of representable floats are clamped. There
/// is loss of precision resulting from both this and that single-precision
/// space inherently has less resolution than double-precision space. The caller
/// should verify this loss of precision is acceptable/desirable.
///
/// @param v Double value to convert
/// @return Closest float value
static inline float d2f(double v) {
  if (v > FLT_MAX) {
    return FLT_MAX;
  }
  if (v < -FLT_MAX) {
    return -FLT_MAX;
  }
  return (float)v;
}