Skip to content

Instantly share code, notes, and snippets.

@zhirzh
Created March 27, 2018 09:21
Show Gist options
  • Save zhirzh/aa02be34407eebe8998d2ff35946cdc9 to your computer and use it in GitHub Desktop.
Save zhirzh/aa02be34407eebe8998d2ff35946cdc9 to your computer and use it in GitHub Desktop.
Negative Indexing Multi Arrays in C/++
const cppCode = document.getElementById("cpp-template").innerHTML;
document.getElementById("cpp").innerHTML = cppCode.replace(/\s{2,}/g, "");
const app = new Vue({
el: "#app",
data: {
counterMode: false,
dimensionCount: { value: 2, prevValue: 2 },
dimensionSizes: [{ value: 2, prevValue: 2 }, { value: 3, prevValue: 3 }],
defaultDimensionSize: { value: 2, prevValue: 2 },
queries: [{ value: 0, prevValue: 0 }, { value: 2, prevValue: 2 }],
defaultQuery: { value: 0, prevValue: 0 }
},
computed: {
cellCounts() {
// C_k = D_1 * D_2 ... D_k
// C_k = C_0 / S_k
return this.dimensionSizeValues
.slice(1)
.reduce((acc, x) => acc.concat(acc[acc.length - 1] * x), [
this.dimensionSizeValues[0]
]);
},
cellStrides() {
// S_k = D_(k+1) * D_(k+2) ... D_n
// S_k = C_0 / C_k
return this.cellCounts.map(count => this.dataCount / count);
},
dimensionSizeValues() {
return this.dimensionSizes.map(d => d.value);
},
numbers() {
const numbers = [];
for (let i = 0; i < this.dataCount; i++) {
numbers.push(10000 + (i + 1));
}
return numbers;
},
queryMatches() {
// M_k = ((Q_1 * S_1) + (Q_2 * S_2) ... (Q_k * S_k)) / S_k
return this.queries.map(q => q.value).reduce((acc, _, i) => {
return acc.concat(
this.queries
.slice(0, i + 1)
.reduce((acc2, q, j) => acc2 + q.value * this.cellStrides[j], 0) /
this.cellStrides[i]
);
}, []);
},
dataCount() {
// C_0 = D_1 * D_2 ... D_n
return this.dimensionSizeValues.reduce((acc, d) => acc * d);
}
},
methods: {
/**
* Convert input to a clamped number
* @param {string} x
* @param {number[]} range
* @param {string} range[].lo - Lower limit of range
* @param {string} range[].hi - Upper limit of range
*/
toNumberClamped(x, [lo, hi]) {
x = Number(x);
if (isNaN(x)) {
return null;
}
if (x < lo) {
return lo;
}
if (x > hi) {
return hi;
}
return x;
},
/**
* Update number of dimensionSizes
* @param {event} e
*/
updateDimensionCount(e) {
const currDimensionCount = this.dimensionCount;
const nextDimensionCountValue = this.toNumberClamped(
e.currentTarget.value,
[1, 5]
);
if (nextDimensionCountValue === null) {
currDimensionCount.value = currDimensionCount.prevValue;
} else {
currDimensionCount.prevValue = nextDimensionCountValue;
currDimensionCount.value = nextDimensionCountValue;
}
this.updateDimensionSizes();
this.updateQueries();
},
/**
* Update dimensionSizes
*/
updateDimensionSizes() {
const nextDimensions = [];
for (let i = 0; i < this.dimensionCount.value; i++) {
nextDimensions.push(
this.dimensionSizes[i] || Object.assign({}, this.defaultDimensionSize)
);
}
this.dimensionSizes = nextDimensions;
},
/**
* Update `ith` dimension
* @param {number} i - Index of dimension
* @param {event} e
*/
updateDimensionSize(i, e) {
const dimension = this.dimensionSizes[i];
const nextDimensionValue = this.toNumberClamped(e.currentTarget.value, [
1,
4
]);
if (nextDimensionValue === null) {
dimension.value = dimension.prevValue;
} else {
dimension.prevValue = nextDimensionValue;
dimension.value = nextDimensionValue;
}
},
/**
* Update queries
*/
updateQueries() {
const nextQueries = [];
for (let i = 0; i < this.dimensionCount.value; i++) {
nextQueries.push(
this.queries[i] || Object.assign({}, this.defaultQuery)
);
}
this.queries = nextQueries;
},
/**
* Update `ith` query
* @param {number} i - Index of query
* @param {event} e
*/
updateQuery(i, e) {
const query = this.queries[i];
console.log(e.currentTarget.value);
const nextQueryValue = this.toNumberClamped(e.currentTarget.value, [
-Infinity,
Infinity
]);
if (nextQueryValue === null) {
query.value = query.prevValue;
} else {
query.prevValue = nextQueryValue;
query.value = nextQueryValue;
}
}
}
});
<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<div id="app">
<!-- <form>
<div>
Counter Mode:
<input type="checkbox" onfocus="this.select()" v-model="counterMode" />
</div>
</form> -->
<div class="code">
<pre id="cpp"></pre>
</div>
<div class="memory-container">
<table class="memory">
<tr v-for="(count, i) in cellCounts">
<td
:class="['memory-cell', j-1 === queryMatches[i] && 'query']"
v-for="j in count" :colspan="cellStrides[i]"
>
<span v-if="counterMode">{{j}}</span>
<span v-else>{{(j-1) % dimensionSizeValues[i]}}</span>
</td>
</tr>
<tr>
<td
:class="['memory-cell', 'memory-data', i === queryMatches[dimensionCount.value - 1] && 'query']"
v-for="(x, i) in numbers">
{{x}}
</td>
</tr>
</table>
</div>
</div>
<template id="cpp-template">
// Enter number of dimensions
<br />
int N = <input
type="number"
min="1"
max="5"
onfocus="this.select()"
v-model.number="dimensionCount.value"
v-on:input="updateDimensionCount"
/>;
<br />
<br />
// Enter dimension sizes
<br /> int arr
<span v-for="(d, i) in dimensionSizes">
[
<input
type="number"
min="1"
max="5"
onfocus="this.select()"
v-model.number="d.value"
v-on:input="updateDimensionSize(i, $event)"
/>
]
</span> = {
<span v-if="numbers.length <= 5">
<span v-for="(n, i) in numbers">
<span>{{n}}</span>
<span v-if="i+1 < numbers.length">, </span>
</span>
};
</span>
<span v-else>
<span v-for="(n, i) in numbers.slice(0, 3)">
<span>{{n}}</span>
<span v-if="i+1 < numbers.length">, </span>
</span>
...
, <span>{{numbers[numbers.length - 1]}}</span>
};
</span>
<br />
<br />
// Run a query on the array
<br />
cout << arr
<span v-for="(q, i) in queries">
[
<input
type="number"
onfocus="this.select()"
v-model.number="q.value"
:style="{width: ((q.value.toString().length || 1) * 13) + 'px'}"
/>
]
</span>;
</template>
<script src="app.js"></script>
</body>
</html>
/* global */
* {
padding: 0;
margin: 0;
box-sizing: border-box;
font-family: sans-serif;
font-size: 20px;
}
input[type=number] {
box-sizing: content-box;
width: 13px;
border: none;
box-shadow: 0 2px 0 gray;
outline: none;
padding: 0 6px;
text-align: center;
}
input[type=number]::-webkit-outer-spin-button,
input[type=number]::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
input[type=number] {
-moz-appearance: textfield;
}
/* #app */
#app {
padding: 20px;
}
/* .code */
.code {
margin: 30px 0;
}
.code * {
font-family: monospace;
}
.code pre {
line-height: 32px;
}
.code input {
background-color: #f0f0f0;
}
/* .memory */
.memory-container {
overflow-x: auto;
}
.memory {
border-collapse: collapse;
}
.memory-cell {
/* text-align: center; */
padding: 10px;
background-color: #ccc;
border: 12px solid #eee;
}
.memory-cell.query {
background-color: #666;
color: white;
}
.memory-cell.memory-data {
background-color: #aaa;
}
.memory-cell.memory-data.query {
background-color: #222;
color: white;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment