Skip to content

Commit a832456

Browse files
committed
Docs
1 parent c40e8f3 commit a832456

22 files changed

+113
-71
lines changed

README.md

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ worldwide relationship table.
9999
Binary relations are everywhere
100100
-------------------------------
101101

102-
Once you get the hang of storing relationships outside of the object, you will
102+
Once you get the hang of storing relationships outside of the objects, you will
103103
find uses for it everywhere. For example, game objects can be member of multiple
104104
groups. That’s a many-to-many. Given the group’s handle, you can look up all its
105105
members. And when you have a game object, you can get a list of the groups it
@@ -134,15 +134,15 @@ The API
134134

135135
The library is located in the BinaryRelations directory. It consists of a single
136136
C++ header file. There are three class templates that you need to know of. The
137-
classes are: OneToMany, ManyToMany, and OneToOne.
137+
classes are: `OneToMany`, `ManyToMany`, and `OneToOne`.
138138

139139
Each binary relation type is a template, with type arguments `LeftType` and
140140
`RightType`. **Both types need to be small, hashable, and immutable.** I
141141
recommend that you only use simple types, such as `int` and `enum`, and possibly
142142
`std::string`.
143143

144-
This is the entire OneToMany API. OneToOne and ManyToMany are near identical.
145-
[Click here for the full
144+
This is the entire `OneToMany` API. `OneToOne` and `ManyToMany` are near
145+
identical. [Click here for the full
146146
documentation.](https://ronpieket.github.io/BinaryRelations)
147147

148148
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -246,23 +246,45 @@ Vehicles are:
246246
1
247247
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
248248

249-
Naming
250-
------
249+
How it works
250+
------------
251+
252+
This section is for those who want to venture into the code.
253+
254+
I will show you, and talk you through the structure of the `OneToMany` template
255+
class. The `OneToOne` and `ManyToMany` template classes are structured along the
256+
same lines.
257+
258+
![](one-to-many-diagram.png)
259+
260+
I used the above diagram to write the code. The `l2r_it` style labels refer to
261+
local variable names in the code. `m_LeftToRight` and `m_RightToLeft` are both
262+
hash tables. Each entry on the `m_LeftToRight` table contains an `std::pair`
263+
with a left value in the `first` slot, and a pointer to an `std::vector` in the
264+
`second`. The `vector` has one or more `right` values in it, sorted by value.
265+
The `m_RightToLeft` hash table contains `pair`s with a `right` value in the
266+
`first` slot, and a `left` value in the `second` slot.
267+
268+
When `findRight()` is called, the `OneToMany` is returns the pointer to the
269+
`vector` of `right` values from the `second` slot in the `m_LeftToRight` hash
270+
table. When `findLeft()` is called, it returns the `left` value from the
271+
`second` slot in the `m_RightToLeft` hash table.
251272

252-
This is a suggestion.
273+
Naming of template specializations
274+
----------------------------------
253275

254-
In the code example, note that the name of the OneToMany has the form of
255-
SingleToPlural”, like “VehicleToOccupants”. Similarly, ManyToMany names would
256-
be “PluralToPlural”, OneToOne would be “SingleToSingle”.
276+
In the code example, note that the name of the `OneToMany` has the form of
277+
SingularToPlural”, like “ParentToChildren”. Similarly, ManyToMany names would
278+
be “PluralToPlural”, OneToOne would be “SingularToSingular”.
257279

258280
Efficiency
259281
----------
260282

261283
The efficiency for lookup such as `FindLeft()` and `FindRight()` is constant
262-
time. All operations on a OneToOne are also constant.
284+
time. All operations on a `OneToOne` are also constant.
263285

264-
Things get more complicated with OneToMany and ManyToMany. They maintain sorted
265-
arrays. Insertion and removal of elements in an array involves shifting
286+
Things get more complicated with `OneToMany` and `ManyToMany`. They maintain
287+
sorted arrays. Insertion and removal of elements in an array involves shifting
266288
everything between the point of insertion/removal and the end of the array. In
267289
practice, at least in the context of our world editor, this has not been a
268290
problem. That’s probably because insert and remove operations are relatively

docs/index.html

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ <h1><a class="anchor" id="autotoc_md3"></a>
136136
<p>This is a key concept, and I want to emphasize it here: relations between objects (such as parent-child) are not stored in the objects, but in a separate worldwide relationship table.</p>
137137
<h1><a class="anchor" id="autotoc_md4"></a>
138138
Binary relations are everywhere</h1>
139-
<p>Once you get the hang of storing relationships outside of the object, you will find uses for it everywhere. For example, game objects can be member of multiple groups. That’s a many-to-many. Given the group’s handle, you can look up all its members. And when you have a game object, you can get a list of the groups it belongs to.</p>
139+
<p>Once you get the hang of storing relationships outside of the objects, you will find uses for it everywhere. For example, game objects can be member of multiple groups. That’s a many-to-many. Given the group’s handle, you can look up all its members. And when you have a game object, you can get a list of the groups it belongs to.</p>
140140
<p>Perhaps a more surprising example is this. Say you have an object type to classify people, vehicles, and buildings. This, too, is a binary relation. In this case it’s a one-to-many. Given an object handle, you can look up what type it is. Given an object type, you can get a list of all objects of that type.</p>
141141
<p>Here are some more use cases:</p>
142142
<div class="fragment"><div class="line">class World</div>
@@ -155,9 +155,9 @@ <h1><a class="anchor" id="autotoc_md4"></a>
155155
<div class="line">};</div>
156156
</div><!-- fragment --><h1><a class="anchor" id="autotoc_md5"></a>
157157
The API</h1>
158-
<p>The library is located in the BinaryRelations directory. It consists of a single C++ header file. There are three class templates that you need to know of. The classes are: OneToMany, ManyToMany, and OneToOne.</p>
158+
<p>The library is located in the BinaryRelations directory. It consists of a single C++ header file. There are three class templates that you need to know of. The classes are: <code>OneToMany</code>, <code>ManyToMany</code>, and <code>OneToOne</code>.</p>
159159
<p>Each binary relation type is a template, with type arguments <code>LeftType</code> and <code>RightType</code>. <b>Both types need to be small, hashable, and immutable.</b> I recommend that you only use simple types, such as <code>int</code> and <code>enum</code>, and possibly <code>std::string</code>.</p>
160-
<p>This is the entire OneToMany API. OneToOne and ManyToMany are near identical. <a href="https://ronpieket.github.io/BinaryRelations">Click here for the full documentation.</a></p>
160+
<p>This is the entire <code>OneToMany</code> API. <code>OneToOne</code> and <code>ManyToMany</code> are near identical. <a href="https://ronpieket.github.io/BinaryRelations">Click here for the full documentation.</a></p>
161161
<div class="fragment"><div class="line">OneToMany:</div>
162162
<div class="line"> </div>
163163
<div class="line">void insert(const Pair &amp;pair)</div>
@@ -244,17 +244,23 @@ <h1><a class="anchor" id="autotoc_md7"></a>
244244
<div class="line">2</div>
245245
<div class="line">1</div>
246246
</div><!-- fragment --><h1><a class="anchor" id="autotoc_md8"></a>
247-
Naming</h1>
248-
<p>This is a suggestion.</p>
249-
<p>In the code example, note that the name of the OneToMany has the form of “SingleToPlural”, like “VehicleToOccupants”. Similarly, ManyToMany names would be “PluralToPlural”, OneToOne would be “SingleToSingle”.</p>
247+
How it works</h1>
248+
<p>This section is for those who want to venture into the code.</p>
249+
<p>I will show you, and talk you through the structure of the <code>OneToMany</code> template class. The <code>OneToOne</code> and <code>ManyToMany</code> template classes are structured along the same lines.</p>
250+
<p><img src="one-to-many-diagram.png" alt="" class="inline"/></p>
251+
<p>I used the above diagram to write the code. The <code>l2r_it</code> style labels refer to local variable names in the code. <code>m_LeftToRight</code> and <code>m_RightToLeft</code> are both hash tables. Each entry on the <code>m_LeftToRight</code> table contains an <code>std::pair</code> with a left value in the <code>first</code> slot, and a pointer to an <code>std::vector</code> in the <code>second</code>. The <code>vector</code> has one or more <code>right</code> values in it, sorted by value. The <code>m_RightToLeft</code> hash table contains <code>pair</code>s with a <code>right</code> value in the <code>first</code> slot, and a <code>left</code> value in the <code>second</code> slot.</p>
252+
<p>When <code>findRight()</code> is called, the <code>OneToMany</code> is returns the pointer to the <code>vector</code> of <code>right</code> values from the <code>second</code> slot in the <code>m_LeftToRight</code> hash table. When <code>findLeft()</code> is called, it returns the <code>left</code> value from the <code>second</code> slot in the <code>m_RightToLeft</code> hash table.</p>
250253
<h1><a class="anchor" id="autotoc_md9"></a>
251-
Efficiency</h1>
252-
<p>The efficiency for lookup such as <code>FindLeft()</code> and <code>FindRight()</code> is constant time. All operations on a OneToOne are also constant.</p>
253-
<p>Things get more complicated with OneToMany and ManyToMany. They maintain sorted arrays. Insertion and removal of elements in an array involves shifting everything between the point of insertion/removal and the end of the array. In practice, at least in the context of our world editor, this has not been a problem. That’s probably because insert and remove operations are relatively infrequent when compared to lookups.</p>
254+
Naming of template specializations</h1>
255+
<p>In the code example, note that the name of the <code>OneToMany</code> has the form of “SingularToPlural”, like “ParentToChildren”. Similarly, ManyToMany names would be “PluralToPlural”, OneToOne would be “SingularToSingular”.</p>
254256
<h1><a class="anchor" id="autotoc_md10"></a>
257+
Efficiency</h1>
258+
<p>The efficiency for lookup such as <code>FindLeft()</code> and <code>FindRight()</code> is constant time. All operations on a <code>OneToOne</code> are also constant.</p>
259+
<p>Things get more complicated with <code>OneToMany</code> and <code>ManyToMany</code>. They maintain sorted arrays. Insertion and removal of elements in an array involves shifting everything between the point of insertion/removal and the end of the array. In practice, at least in the context of our world editor, this has not been a problem. That’s probably because insert and remove operations are relatively infrequent when compared to lookups.</p>
260+
<h1><a class="anchor" id="autotoc_md11"></a>
255261
Performance</h1>
256262
<p>Performance measurements in Xcode on an iMac M1.</p>
257-
<h2><a class="anchor" id="autotoc_md11"></a>
263+
<h2><a class="anchor" id="autotoc_md12"></a>
258264
Worst case insert</h2>
259265
<p>The “worst case” is inserting random numbers on the right with the same left value. Results in milliseconds.</p>
260266
<table class="markdownTable">
@@ -273,7 +279,7 @@ <h2><a class="anchor" id="autotoc_md11"></a>
273279
<tr class="markdownTableRowEven">
274280
<td class="markdownTableBodyNone">1,000,000 </td><td class="markdownTableBodyNone">48.9268 </td><td class="markdownTableBodyNone">19,656.3 </td><td class="markdownTableBodyNone">19,787.9 </td></tr>
275281
</table>
276-
<h2><a class="anchor" id="autotoc_md12"></a>
282+
<h2><a class="anchor" id="autotoc_md13"></a>
277283
Best case insert</h2>
278284
<p>The “best case” is inserting random numbers on both the left and right. Results in milliseconds.</p>
279285
<table class="markdownTable">
@@ -292,7 +298,7 @@ <h2><a class="anchor" id="autotoc_md12"></a>
292298
<tr class="markdownTableRowEven">
293299
<td class="markdownTableBodyNone">1,000,000 </td><td class="markdownTableBodyNone">454.936 </td><td class="markdownTableBodyNone">601.014 </td><td class="markdownTableBodyNone">780.828 </td></tr>
294300
</table>
295-
<h2><a class="anchor" id="autotoc_md13"></a>
301+
<h2><a class="anchor" id="autotoc_md14"></a>
296302
Lookup</h2>
297303
<p>This is the time it takes for a single lookup in tables of different sizes. Results microseconds.</p>
298304
<table class="markdownTable">
@@ -311,7 +317,7 @@ <h2><a class="anchor" id="autotoc_md13"></a>
311317
<tr class="markdownTableRowEven">
312318
<td class="markdownTableBodyNone">1,000,000 </td><td class="markdownTableBodyNone">0.0652959 </td><td class="markdownTableBodyNone">0.0715042 </td><td class="markdownTableBodyNone">0.0902375 </td></tr>
313319
</table>
314-
<h2><a class="anchor" id="autotoc_md14"></a>
320+
<h2><a class="anchor" id="autotoc_md15"></a>
315321
Thoughts on performance</h2>
316322
<p><code>std::unordered_map</code> is not the fastest hash map. I’m aware of faster ones, but all those I have found have a license that is more restrictive than the MIT license.</p>
317323
<p>The array insert operation, which requires shifting half the array on average, is definitely a performance liability. This can be improved by segmenting the array, so that you only have to shift half of the segment.</p>

docs/index.js

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,13 @@ var index =
88
[ "The API", "index.html#autotoc_md5", null ],
99
[ "Installation and usage", "index.html#autotoc_md6", null ],
1010
[ "Code example", "index.html#autotoc_md7", null ],
11-
[ "Naming", "index.html#autotoc_md8", null ],
12-
[ "Efficiency", "index.html#autotoc_md9", null ],
13-
[ "Performance", "index.html#autotoc_md10", [
14-
[ "Worst case insert", "index.html#autotoc_md11", null ],
15-
[ "Best case insert", "index.html#autotoc_md12", null ],
16-
[ "Lookup", "index.html#autotoc_md13", null ],
17-
[ "Thoughts on performance", "index.html#autotoc_md14", null ]
11+
[ "How it works", "index.html#autotoc_md8", null ],
12+
[ "Naming of template specializations", "index.html#autotoc_md9", null ],
13+
[ "Efficiency", "index.html#autotoc_md10", null ],
14+
[ "Performance", "index.html#autotoc_md11", [
15+
[ "Worst case insert", "index.html#autotoc_md12", null ],
16+
[ "Best case insert", "index.html#autotoc_md13", null ],
17+
[ "Lookup", "index.html#autotoc_md14", null ],
18+
[ "Thoughts on performance", "index.html#autotoc_md15", null ]
1819
] ]
1920
];

docs/navtreeindex0.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,11 @@ var NAVTREEINDEX0 =
9090
"index.html#autotoc_md0":[0,0],
9191
"index.html#autotoc_md1":[0,1],
9292
"index.html#autotoc_md10":[0,10],
93-
"index.html#autotoc_md11":[0,10,0],
94-
"index.html#autotoc_md12":[0,10,1],
95-
"index.html#autotoc_md13":[0,10,2],
96-
"index.html#autotoc_md14":[0,10,3],
93+
"index.html#autotoc_md11":[0,11],
94+
"index.html#autotoc_md12":[0,11,0],
95+
"index.html#autotoc_md13":[0,11,1],
96+
"index.html#autotoc_md14":[0,11,2],
97+
"index.html#autotoc_md15":[0,11,3],
9798
"index.html#autotoc_md2":[0,2],
9899
"index.html#autotoc_md3":[0,3],
99100
"index.html#autotoc_md4":[0,4],

docs/search/all_1.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
var searchData=
22
[
33
['begin_0',['begin',['../class_binary_relations_1_1_one_to_many.html#a41efacdf1796ef9bfc06fa1d27adba7e',1,'BinaryRelations::OneToMany::begin()'],['../class_binary_relations_1_1_many_to_many.html#a73d51aef2f025f86a22d4ab18545cf43',1,'BinaryRelations::ManyToMany::begin()'],['../class_binary_relations_1_1_one_to_one.html#ac311b9fdd7574769d16dbd9751a77150',1,'BinaryRelations::OneToOne::begin()']]],
4-
['best_20case_20insert_1',['Best case insert',['../index.html#autotoc_md12',1,'']]],
4+
['best_20case_20insert_1',['Best case insert',['../index.html#autotoc_md13',1,'']]],
55
['binary_20relations_20are_20everywhere_2',['Binary relations are everywhere',['../index.html',1,'Binary relations are everywhere'],['../index.html#autotoc_md4',1,'Binary relations are everywhere']]]
66
];

docs/search/all_10.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
var searchData=
2+
[
3+
['usage_0',['Installation and usage',['../index.html#autotoc_md6',1,'']]]
4+
];

docs/search/all_11.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
var searchData=
2+
[
3+
['what_20is_20this_0',['What is this?',['../index.html#autotoc_md0',1,'']]],
4+
['works_1',['How it works',['../index.html#autotoc_md8',1,'']]],
5+
['world_20examples_2',['Real world examples',['../index.html#autotoc_md3',1,'']]],
6+
['worst_20case_20insert_3',['Worst case insert',['../index.html#autotoc_md12',1,'']]]
7+
];

docs/search/all_2.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/search/all_3.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
var searchData=
22
[
3-
['efficiency_0',['Efficiency',['../index.html#autotoc_md9',1,'']]],
3+
['efficiency_0',['Efficiency',['../index.html#autotoc_md10',1,'']]],
44
['end_1',['end',['../class_binary_relations_1_1_one_to_many.html#afe852da0d0ea1b9bff955482b61c1255',1,'BinaryRelations::OneToMany::end()'],['../class_binary_relations_1_1_many_to_many.html#a398b2858b8b8c7a1eaededb6069fb6b7',1,'BinaryRelations::ManyToMany::end()'],['../class_binary_relations_1_1_one_to_one.html#a31142c4204c1c0f4e62c748e5be9c44e',1,'BinaryRelations::OneToOne::end()']]],
55
['everywhere_2',['Binary relations are everywhere',['../index.html',1,'']]],
66
['everywhere_3',['Binary relations are everywhere',['../index.html#autotoc_md4',1,'']]],

0 commit comments

Comments
 (0)