diff options
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.c | 291 |
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 +}; |