summaryrefslogtreecommitdiff
path: root/Build/source/texk/web2c/mfluadir/otfcc/lib/vf/vq.c
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/web2c/mfluadir/otfcc/lib/vf/vq.c')
-rw-r--r--Build/source/texk/web2c/mfluadir/otfcc/lib/vf/vq.c291
1 files changed, 291 insertions, 0 deletions
diff --git a/Build/source/texk/web2c/mfluadir/otfcc/lib/vf/vq.c b/Build/source/texk/web2c/mfluadir/otfcc/lib/vf/vq.c
new file mode 100644
index 00000000000..e23d8e2823f
--- /dev/null
+++ b/Build/source/texk/web2c/mfluadir/otfcc/lib/vf/vq.c
@@ -0,0 +1,291 @@
+#include "otfcc/vf/vq.h"
+#include "support/util.h"
+
+// Variation vector
+caryll_standardValType(pos_t, vq_iPosT);
+caryll_VectorImplFunctions(VV, pos_t, vq_iPosT);
+
+static VV createNeutralVV(tableid_t dimensions) {
+ VV vv;
+ iVV.initN(&vv, dimensions);
+ for (tableid_t j = 0; j < dimensions; j++) {
+ vv.items[j] = 0;
+ }
+ return vv;
+};
+caryll_VectorInterfaceTypeName(VV) iVV = {
+ caryll_VectorImplAssignments(VV, pos_t, vq_iPosT),
+ .neutral = createNeutralVV,
+};
+
+// VQS
+static INLINE void initVQSegment(vq_Segment *vqs) {
+ vqs->type = VQ_STILL;
+ vqs->val.still = 0;
+}
+static INLINE void copyVQSegment(vq_Segment *dst, const vq_Segment *src) {
+ dst->type = src->type;
+ switch (dst->type) {
+ case VQ_STILL:
+ dst->val.still = src->val.still;
+ break;
+ case VQ_DELTA:
+ dst->val.delta.quantity = src->val.delta.quantity;
+ dst->val.delta.region = src->val.delta.region;
+ }
+}
+static INLINE void disposeVQSegment(vq_Segment *vqs) {
+ switch (vqs->type) {
+ case VQ_DELTA:
+ break;
+ default:;
+ }
+ initVQSegment(vqs);
+}
+
+caryll_standardValTypeFn(vq_Segment, initVQSegment, copyVQSegment, disposeVQSegment);
+static vq_Segment vqsCreateStill(pos_t x) {
+ vq_Segment vqs;
+ vq_iSegment.init(&vqs);
+ vqs.val.still = x;
+ return vqs;
+}
+static vq_Segment vqsCreateDelta(pos_t delta, vq_Region *region) {
+ vq_Segment vqs;
+ vq_iSegment.init(&vqs);
+ vqs.type = VQ_DELTA;
+ vqs.val.delta.quantity = delta;
+ vqs.val.delta.region = region;
+ return vqs;
+}
+
+static int vqsCompare(const vq_Segment a, const vq_Segment b) {
+ if (a.type < b.type) return -1;
+ if (a.type > b.type) return 1;
+ switch (a.type) {
+ case VQ_STILL: {
+ if (a.val.still < b.val.still) return -1;
+ if (a.val.still > b.val.still) return 1;
+ return 0;
+ }
+ case VQ_DELTA: {
+ int vqrc = vq_compareRegion(a.val.delta.region, b.val.delta.region);
+ if (vqrc) return vqrc;
+ if (a.val.delta.quantity < b.val.delta.quantity) return -1;
+ if (a.val.delta.quantity > b.val.delta.quantity) return 1;
+ return 0;
+ }
+ default:
+ fprintf(stderr,"! warning: vqsCompare unknown a.type %u. Return -1.\n",a.type);
+ return -1;
+ }
+}
+caryll_OrdEqFns(vq_Segment, vqsCompare);
+static void showVQS(const vq_Segment x) {
+ switch (x.type) {
+ case VQ_STILL:
+ fprintf(stderr, "%g", x.val.still);
+ return;
+ case VQ_DELTA:
+ fprintf(stderr, "{%g%s", x.val.delta.quantity, x.val.delta.touched ? " " : "* ");
+ vq_showRegion(x.val.delta.region);
+ fprintf(stderr, "}\n");
+ return;
+
+ default:;
+ }
+}
+caryll_ShowFns(vq_Segment, showVQS);
+caryll_ElementInterfaceOf(vq_Segment) vq_iSegment = {
+ caryll_standardValTypeMethods(vq_Segment),
+ caryll_OrdEqAssigns(vq_Segment), // Ord and Eq
+ caryll_ShowAssigns(vq_Segment), // Show
+ // creating instances
+ .createStill = vqsCreateStill,
+ .createDelta = vqsCreateDelta,
+};
+
+caryll_standardVectorImpl(vq_SegList, vq_Segment, vq_iSegment, vq_iSegList);
+
+// Monoid
+
+static INLINE void vqInit(VQ *a) {
+ a->kernel = 0;
+ vq_iSegList.init(&a->shift);
+}
+static INLINE void vqCopy(VQ *a, const VQ *b) {
+ a->kernel = b->kernel;
+ vq_iSegList.copy(&a->shift, &b->shift);
+}
+static INLINE void vqDispose(VQ *a) {
+ a->kernel = 0;
+ vq_iSegList.dispose(&a->shift);
+}
+
+caryll_standardValTypeFn(VQ, vqInit, vqCopy, vqDispose);
+static VQ vqNeutral() {
+ return iVQ.createStill(0);
+}
+static bool vqsCompatible(const vq_Segment a, const vq_Segment b) {
+ if (a.type != b.type) return false;
+ switch (a.type) {
+ case VQ_STILL:
+ return true;
+ case VQ_DELTA:
+ return 0 == vq_compareRegion(a.val.delta.region, b.val.delta.region);
+ default:
+ fprintf(stderr,"! warning: vqsCompatible unknown a.type %u. Return false.\n",a.type);
+ return false;
+ }
+}
+static void simplifyVq(MODIFY VQ *x) {
+ if (!x->shift.length) return;
+ vq_iSegList.sort(&x->shift, vq_iSegment.compareRef);
+ size_t k = 0;
+ for (size_t j = 1; j < x->shift.length; j++) {
+ if (vqsCompatible(x->shift.items[k], x->shift.items[j])) {
+ switch (x->shift.items[k].type) {
+ case VQ_STILL:
+ x->shift.items[k].val.still += x->shift.items[j].val.still;
+ break;
+ case VQ_DELTA:
+ x->shift.items[k].val.delta.quantity += x->shift.items[j].val.delta.quantity;
+ break;
+ }
+ vq_iSegment.dispose(&x->shift.items[j]);
+ } else {
+ x->shift.items[k] = x->shift.items[j];
+ k++;
+ }
+ }
+ x->shift.length = k + 1;
+}
+static void vqInplacePlus(MODIFY VQ *a, const VQ b) {
+ a->kernel += b.kernel;
+ for (size_t p = 0; p < b.shift.length; p++) {
+ vq_Segment *k = &b.shift.items[p];
+ if (k->type == VQ_STILL) {
+ a->kernel += k->val.still;
+ } else {
+ vq_Segment s;
+ vq_iSegment.copy(&s, k);
+ vq_iSegList.push(&a->shift, s);
+ }
+ }
+ simplifyVq(a);
+}
+
+caryll_MonoidFns(VQ, vqNeutral, vqInplacePlus);
+
+// Module
+static void vqInplaceScale(MODIFY VQ *a, pos_t b) {
+ a->kernel *= b;
+ for (size_t j = 0; j < a->shift.length; j++) {
+ vq_Segment *s = &a->shift.items[j];
+ switch (s->type) {
+ case VQ_STILL:
+ s->val.still *= b;
+ break;
+ case VQ_DELTA:
+ s->val.delta.quantity *= b;
+ break;
+ }
+ }
+}
+
+// Group
+static void vqInplaceNegate(MODIFY VQ *a) {
+ vqInplaceScale(a, -1);
+}
+
+caryll_GroupFns(VQ, vqInplaceNegate);
+caryll_ModuleFns(VQ, pos_t, vqInplaceScale);
+
+// Ord
+static int vqCompare(const VQ a, const VQ b) {
+ if (a.shift.length < b.shift.length) return -1;
+ if (a.shift.length > b.shift.length) return 1;
+ for (size_t j = 0; j < a.shift.length; j++) {
+ int cr = vqsCompare(a.shift.items[j], b.shift.items[j]);
+ if (cr) return cr;
+ }
+ return a.kernel - b.kernel;
+}
+caryll_OrdEqFns(VQ, vqCompare);
+
+// Show
+static void showVQ(const VQ x) {
+ fprintf(stderr, "%g + {", x.kernel);
+ for (size_t j = 0; j < x.shift.length; j++) {
+ if (j) fprintf(stderr, " ");
+ vq_iSegment.show(x.shift.items[j]);
+ }
+ fprintf(stderr, "}\n");
+}
+caryll_ShowFns(VQ, showVQ);
+
+// Still instances
+static pos_t vqGetStill(const VQ v) {
+ pos_t result = v.kernel;
+ for (size_t j = 0; j < v.shift.length; j++) {
+ switch (v.shift.items[j].type) {
+ case VQ_STILL:
+ result += v.shift.items[j].val.still;
+ default:;
+ }
+ }
+ return result;
+}
+static VQ vqCreateStill(pos_t x) {
+ VQ vq;
+ iVQ.init(&vq);
+ vq.kernel = x;
+ return vq;
+}
+static bool vqIsStill(const VQ v) {
+ for (size_t j = 0; j < v.shift.length; j++) {
+ switch (v.shift.items[j].type) {
+ case VQ_STILL:
+ break;
+ default:
+ return false;
+ }
+ }
+ return true;
+}
+static bool vqIsZero(const VQ v, const pos_t err) {
+ return vqIsStill(v) && fabs(vqGetStill(v)) < err;
+}
+static void vqAddDelta(MODIFY VQ *v, const bool touched, const vq_Region *const r,
+ const pos_t quantity) {
+ if (!quantity) return;
+ vq_Segment nudge;
+ nudge.type = VQ_DELTA;
+ nudge.val.delta.region = r;
+ nudge.val.delta.touched = touched;
+ nudge.val.delta.quantity = quantity;
+ vq_iSegList.push(&v->shift, nudge);
+}
+
+// pointLinearTfm
+static VQ vqPointLinearTfm(const VQ ax, pos_t a, const VQ x, pos_t b, const VQ y) {
+ VQ targetX = iVQ.dup(ax);
+ iVQ.inplacePlusScale(&targetX, a, x);
+ iVQ.inplacePlusScale(&targetX, b, y);
+ return targetX;
+}
+
+caryll_VectorInterfaceTypeName(VQ) iVQ = {
+ caryll_standardValTypeMethods(VQ),
+ .getStill = vqGetStill,
+ .createStill = vqCreateStill,
+ .isStill = vqIsStill,
+ .isZero = vqIsZero,
+ caryll_MonoidAssigns(VQ), // Monoid
+ caryll_GroupAssigns(VQ), // Group
+ caryll_ModuleAssigns(VQ), // Module
+ caryll_OrdEqAssigns(VQ), // Eq-Ord
+ caryll_ShowAssigns(VQ), // Show
+ .pointLinearTfm = vqPointLinearTfm, // pointLinearTfm
+ .addDelta = vqAddDelta // addDelta
+};